This is an automated email from the ASF dual-hosted git repository.

voidmatcha pushed a commit to branch pr5339-rebase
in repository https://gitbox.apache.org/repos/asf/zeppelin.git

commit ec2c90dd85568a74e7bb7562ee3f90f837531d6b
Author: YONGJAE LEE <[email protected]>
AuthorDate: Sun Aug 23 17:24:02 2026 +0900

    Share query flag parsing across feature flags
---
 .../src/app/services/inline-completion.service.ts  | 11 ++++-----
 .../src/app/services/query-flag.util.spec.ts       | 28 ++++++++++++++++++++++
 .../src/app/services/query-flag.util.ts            | 22 +++++++++++++++++
 .../src/app/services/react-feature.service.ts      | 19 ++-------------
 4 files changed, 57 insertions(+), 23 deletions(-)

diff --git a/zeppelin-web-angular/src/app/services/inline-completion.service.ts 
b/zeppelin-web-angular/src/app/services/inline-completion.service.ts
index a1295d614c..7e9bd477c0 100644
--- a/zeppelin-web-angular/src/app/services/inline-completion.service.ts
+++ b/zeppelin-web-angular/src/app/services/inline-completion.service.ts
@@ -12,6 +12,7 @@
 
 import { Injectable } from '@angular/core';
 import { editor, IDisposable, IRange, languages, Position } from 
'monaco-editor';
+import { parseBooleanFlag } from './query-flag.util';
 
 const MIN_PREFIX_LENGTH = 3;
 const LOCAL_WINDOW_LINES = 400;
@@ -65,12 +66,10 @@ export class InlineCompletionService {
       const searchParams = new URLSearchParams(window.location.search);
       const hashQuery = window.location.hash.split('?')[1] ?? '';
       const hashParams = new URLSearchParams(hashQuery);
-      const isEnabled = (params: URLSearchParams) => {
-        const value = params.get('aiInlineComplete');
-        return value === 'true' || value === '';
-      };
-
-      return isEnabled(searchParams) || isEnabled(hashParams);
+      return (
+        parseBooleanFlag(searchParams.get('aiInlineComplete')) === true ||
+        parseBooleanFlag(hashParams.get('aiInlineComplete')) === true
+      );
     } catch {
       return false;
     }
diff --git a/zeppelin-web-angular/src/app/services/query-flag.util.spec.ts 
b/zeppelin-web-angular/src/app/services/query-flag.util.spec.ts
new file mode 100644
index 0000000000..298ff80d6d
--- /dev/null
+++ b/zeppelin-web-angular/src/app/services/query-flag.util.spec.ts
@@ -0,0 +1,28 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { describe, expect, it } from 'vitest';
+import { parseBooleanFlag } from './query-flag.util';
+
+describe('parseBooleanFlag', () => {
+  it.each([
+    ['', true],
+    ['true', true],
+    ['false', false],
+    [undefined, null],
+    [null, null],
+    ['1', null],
+    ['TRUE', null]
+  ])('parses %s as %s', (value, expected) => {
+    expect(parseBooleanFlag(value)).toBe(expected);
+  });
+});
diff --git a/zeppelin-web-angular/src/app/services/query-flag.util.ts 
b/zeppelin-web-angular/src/app/services/query-flag.util.ts
new file mode 100644
index 0000000000..22b11788ca
--- /dev/null
+++ b/zeppelin-web-angular/src/app/services/query-flag.util.ts
@@ -0,0 +1,22 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** Returns the boolean value of a query flag, or null when it is 
unset/invalid. */
+export const parseBooleanFlag = (value: string | null | undefined): boolean | 
null => {
+  if (value === '' || value === 'true') {
+    return true;
+  }
+  if (value === 'false') {
+    return false;
+  }
+  return null;
+};
diff --git a/zeppelin-web-angular/src/app/services/react-feature.service.ts 
b/zeppelin-web-angular/src/app/services/react-feature.service.ts
index 0d79bd9e6e..e921eacd8a 100644
--- a/zeppelin-web-angular/src/app/services/react-feature.service.ts
+++ b/zeppelin-web-angular/src/app/services/react-feature.service.ts
@@ -11,6 +11,7 @@
  */
 
 import { Injectable } from '@angular/core';
+import { parseBooleanFlag } from './query-flag.util';
 
 export type ReactSurface = 'publishedParagraph' | 'paragraphFooter';
 
@@ -44,27 +45,11 @@ export class ReactFeatureService {
   isEnabled(surface: ReactSurface, source?: FlagSource | null): boolean {
     const config = SURFACES[surface];
 
-    const fromQuery = this.parseFlag(source?.get(config.queryParam));
+    const fromQuery = parseBooleanFlag(source?.get(config.queryParam));
     if (fromQuery !== null) {
       return fromQuery;
     }
 
     return config.defaultEnabled;
   }
-
-  /**
-   * A bare flag (`?react`) or `=true` enables, `=false` disables. Anything 
else, including an absent flag, is unset.
-   */
-  private parseFlag(value: string | null | undefined): boolean | null {
-    if (value === undefined || value === null) {
-      return null;
-    }
-    if (value === 'true' || value === '') {
-      return true;
-    }
-    if (value === 'false') {
-      return false;
-    }
-    return null;
-  }
 }

Reply via email to