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

tbonelee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git


The following commit(s) were added to refs/heads/master by this push:
     new ece5393fc3 [ZEPPELIN-6581] Match interpreter search queries literally 
instead of as regex
ece5393fc3 is described below

commit ece5393fc3500386f2c78e382272a3be50a5cb1d
Author: κΉ€μ˜ˆλ‚˜ <[email protected]>
AuthorDate: Sun Sep 27 16:53:04 2026 +0900

    [ZEPPELIN-6581] Match interpreter search queries literally instead of as 
regex
    
    ### What is this PR for?
    
    The New UI interpreter page filters settings by name as the user types, but 
`filterInterpreters()` compiled the raw query with `new RegExp(value, 'i')`. So 
the search box took regular-expression syntax:
    
    * An incomplete metacharacter such as `(`, `[`, `*` or a trailing `\` threw 
an uncaught `SyntaxError: Invalid regular expression`. The list was not 
updated, so it kept showing the results of the previous query.
    * A valid metacharacter changed what matched. `.` matched every 
interpreter, and `sp.rk` matched `spark`.
    
    This PR filters with a case-insensitive literal substring match 
(`name.toLowerCase().includes(query.toLowerCase())`). That keeps the 
case-insensitive behavior ZEPPELIN-6147 added, which was the only reason the 
`RegExp` was introduced. ZEPPELIN-6535 (#5320) fixed the same coercion in the 
Table visualization column filter. This is a separate code path.
    
    Checked in the browser before and after the change (`/#/interpreter`, 22 
settings, anonymous mode):
    
    | Query | Before | After |
    |---|---|---|
    | `(` | `SyntaxError: ... /(/i: Unterminated group`, list unchanged | 0 
items, no error |
    | `[`, `*`, `\` | `SyntaxError`, list left on the previous query's results 
| 0 items, no error |
    | `.` | all 22 | 0 items |
    | `sp.rk` | 2 | 0 items |
    | `spark` / `SPARK` | 2 | 2 |
    | cleared | 22 | 22 |
    
    A note on scope. `InterpreterSettingManager` rejects new setting names 
outside `^[-_a-zA-Z0-9]+$`, and every bundled interpreter group fits that set. 
So in practice a metacharacter query now matches nothing, where before it threw 
or matched too much. The test fixtures stay inside that character set, so they 
do not rely on names the server would reject.
    
    ### What type of PR is it?
    
    Bug Fix
    
    ### Todos
    
    * [x] Match interpreter search queries literally instead of compiling them 
as a `RegExp`
    * [x] Add unit tests for `InterpreterComponent.filterInterpreters`
    
    ### What is the Jira issue?
    
    [ZEPPELIN-6581](https://issues.apache.org/jira/browse/ZEPPELIN-6581)
    
    ### How should this be tested?
    
    Done:
    
    * `cd zeppelin-web-angular && npm run test:shell -- 
src/app/pages/workspace/interpreter/`: 8 passed. The new spec covers every 
acceptance criterion: `(`, `[`, `*`, `.` and `\` without throwing, literal 
matching, case-insensitive matching, and restoring the full list when the query 
is cleared.
    * Ran the same spec against the unfixed component. The 6 tests for this bug 
fail for the reason the issue describes: 4 with `SyntaxError: Invalid regular 
expression`, and 2 because `.` and `sp.rk` still match as patterns. The 2 tests 
for existing behavior (case-insensitive matching, clearing) pass both before 
and after.
    * `npm run test:shell`: 21 files, 139 tests passed.
    * `npm run lint`: exit 0. `interpreter.component.ts` has one 
`member-ordering` warning about the constructor's position, and master has the 
same warning.
    * Manual reproduction from the issue: ran a local Zeppelin server with `ng 
serve` and drove `/#/interpreter` with Playwright, before and after. Results 
are in the table above. Typing `sp(ar[k*` one key at a time also produces no 
console errors. The other console errors and warnings on page load 
(`codicon.ttf` load failure, `NG8107`, `NG0912`) appear identically on master.
    
    Not done:
    
    * No Playwright e2e spec was added. The behavior is a pure filter function, 
so per `zeppelin-web-angular/AGENTS.md` it belongs in a unit test. The template 
and debounce wiring are unchanged.
    
    ### Screenshots (if appropriate)
    
    N/A. The before/after table above records the browser run.
    
    ### Questions:
    
    * Does the license files need to update? No. The new spec file has the ASF 
header.
    * Is there breaking changes for older versions? Only for anyone who relied 
on regular-expression syntax in the interpreter search box, which was never 
documented. ZEPPELIN-6147 introduced the `RegExp` only to make the search 
case-insensitive.
    * Does this needs documentation? No.
    
    πŸ€– Generated with [Claude Code](https://claude.com/claude-code)
    
    
    Closes #5503 from kimyenac/ZEPPELIN-6581.
    
    Signed-off-by: ChanHo Lee <[email protected]>
---
 .../interpreter/interpreter.component.spec.ts      | 75 ++++++++++++++++++++++
 .../workspace/interpreter/interpreter.component.ts |  5 +-
 2 files changed, 77 insertions(+), 3 deletions(-)

diff --git 
a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.spec.ts
 
b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.spec.ts
new file mode 100644
index 0000000000..d261b00d82
--- /dev/null
+++ 
b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.spec.ts
@@ -0,0 +1,75 @@
+/*
+ * 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 { ChangeDetectorRef } from '@angular/core';
+import { NzMessageService } from 'ng-zorro-antd/message';
+import { NzModalService } from 'ng-zorro-antd/modal';
+import { describe, expect, it, vi } from 'vitest';
+
+import { Interpreter } from '@zeppelin/interfaces';
+import { InterpreterService } from '@zeppelin/services';
+
+import { InterpreterComponent } from './interpreter.component';
+
+// InterpreterSettingManager rejects new setting names outside 
^[-_a-zA-Z0-9]+$, and every bundled
+// interpreter group fits it, so the fixtures stay within that set.
+const NAMES = ['spark', 'spark-sql', 'python', 'jdbc', 'md'];
+
+const createComponent = () => {
+  const cdr = { markForCheck: vi.fn() } as unknown as ChangeDetectorRef;
+  const component = new InterpreterComponent(
+    {} as InterpreterService,
+    cdr,
+    {} as NzModalService,
+    {} as NzMessageService
+  );
+  component.interpreterSettings = NAMES.map(name => ({ name }) as Interpreter);
+  component.filteredInterpreterSettings = component.interpreterSettings;
+  return component;
+};
+
+const filteredNames = (component: InterpreterComponent) => 
component.filteredInterpreterSettings.map(e => e.name);
+
+describe('InterpreterComponent.filterInterpreters', () => {
+  it.each(['(', '[', '*', '.', '\\'])('matches the metacharacter %s literally 
without throwing', query => {
+    const component = createComponent();
+
+    expect(() => component.filterInterpreters(query)).not.toThrow();
+    expect(filteredNames(component)).toEqual([]);
+  });
+
+  it('does not treat the query as a pattern', () => {
+    const component = createComponent();
+
+    // As a pattern, `.` matches any character and `sp.rk` matches `spark`.
+    component.filterInterpreters('sp.rk');
+
+    expect(filteredNames(component)).toEqual([]);
+  });
+
+  it('matches names case-insensitively', () => {
+    const component = createComponent();
+
+    component.filterInterpreters('SPARK');
+
+    expect(filteredNames(component)).toEqual(['spark', 'spark-sql']);
+  });
+
+  it('restores the full list when the query is cleared', () => {
+    const component = createComponent();
+    component.filterInterpreters('jdbc');
+
+    component.filterInterpreters('');
+
+    expect(filteredNames(component)).toEqual(NAMES);
+  });
+});
diff --git 
a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts
 
b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts
index 0c31e2a752..d04ce62c97 100644
--- 
a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts
+++ 
b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts
@@ -55,9 +55,8 @@ export class InterpreterComponent implements OnInit, 
OnDestroy {
   }
 
   filterInterpreters(value: string) {
-    this.filteredInterpreterSettings = this.interpreterSettings.filter(
-      e => e.name.search(new RegExp(value, 'i')) !== -1
-    );
+    const query = value.toLowerCase();
+    this.filteredInterpreterSettings = this.interpreterSettings.filter(e => 
e.name.toLowerCase().includes(query));
 
     this.cdr.markForCheck();
   }

Reply via email to