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; - } }
