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