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 4e49e3c7f2 [ZEPPELIN-6588] Use theme colors in the pivot and scatter 
settings panels
4e49e3c7f2 is described below

commit 4e49e3c7f262ddb5e82081160d49355d6e93f88b
Author: κΉ€μ˜ˆλ‚˜ <[email protected]>
AuthorDate: Sun Sep 27 17:27:21 2026 +0900

    [ZEPPELIN-6588] Use theme colors in the pivot and scatter settings panels
    
    ### What is this PR for?
    
    In dark mode the Pivot and Scatter visualization settings panels were 
unreadable. Both components hard-coded light backgrounds on their cards 
(`#fff`) and card headers (`#fafafa`), but the card titles take the theme's 
heading color. So in dark mode the titles were near-white text on a white 
background. The field labels (`.drag-tag`, defined in `global.less`) also 
stayed light.
    
    This PR replaces those values with the existing theme variables. It adds no 
new colors, and the light theme resolves to the same values as before.
    
    | Element | Before | After |
    |---|---|---|
    | Card background | `#fff` | `<at>component-background` |
    | Card header background | `#fafafa` | `<at>background-color-light` |
    | Field label text / background / border | `rgba(0,0,0,.65)` / `#fafafa` / 
`#d9d9d9` | `<at>text-color` / `<at>background-color-light` / 
`<at>border-color-base` |
    
    The cards already sit inside `.themeMixin(...)`, so their fix is a one-line 
swap in each file. The field label styles are only used by these two panels, 
but they stay in `global.less`. The CDK drag preview is appended to `<body>`, 
outside the component host, so a component-scoped rule would not reach the 
label being dragged. Dark values are applied under `html.dark .drag-tag { 
<at>import 'theme-dark'; ... }`, the same pattern `antd-dark.less` uses.
    
    Computed styles measured in the browser, before and after 
(`/#/notebook/...` with a `%sh` table paragraph, Pivot through the Bar Chart 
and Scatter through the Scatter Chart):
    
    | Dark theme | Before | After |
    |---|---|---|
    | Card | `rgb(255, 255, 255)` | `rgb(31, 31, 31)` |
    | Card header | `rgb(250, 250, 250)` | `rgb(38, 38, 38)` |
    | Card title | `rgba(255, 255, 255, 0.95)` (on white) | `rgba(255, 255, 
255, 0.95)` |
    | Field label bg / text | `rgb(250, 250, 250)` / `rgba(0, 0, 0, 0.65)` | 
`rgb(38, 38, 38)` / `rgba(255, 255, 255, 0.85)` |
    | Drag preview (child of `<body>`) | same as field label, light | `rgb(38, 
38, 38)` / `rgba(255, 255, 255, 0.85)` |
    
    The "before" row matches the values in the Jira report. In the light theme, 
every value above is identical before and after, including the drag preview. 
The compiled `.drag-tag` rule is character-for-character the same as before.
    
    ### What type of PR is it?
    
    Bug Fix
    
    ### Todos
    
    * [x] Use theme variables for the Pivot and Scatter settings card and 
header backgrounds
    * [x] Theme the field labels, including the drag preview
    * [x] Add Playwright coverage for both panels in both themes
    
    ### What is the Jira issue?
    
    [ZEPPELIN-6588](https://issues.apache.org/jira/browse/ZEPPELIN-6588)
    
    ### How should this be tested?
    
    Done:
    
    * New spec `e2e/tests/theme/visualization-settings-theme.spec.ts`: Pivot 
and Scatter, each in light and dark (4 tests). Each test checks every card, 
card header and card title, plus a field label, against the theme's resolved 
colors. The table paragraph fixture moved to `notebook-visualization-page.ts`, 
so this spec and `visualization-rendering.spec.ts` share it.
    * Ran the new spec against the unfixed styles. The two dark tests fail on 
the card background (expected `rgb(31, 31, 31)`, received `rgb(255, 255, 
255)`), and the two light tests pass. With only the `global.less` change 
reverted, the dark tests get past the cards and fail on the field label 
(expected `rgb(38, 38, 38)`, received `rgb(250, 250, 250)`). So both assertions 
catch the defect.
    * With the fix, the new spec plus `visualization-rendering.spec.ts` pass on 
chromium, firefox and webkit: 19 passed, no retries.
    * `npm run test:shell`: 131 passed. `npm run lint`: exit 0, with the same 
warning count as master.
    * Manual check on a local server in both themes: card titles and field 
labels are readable, dragging a field between Keys/Groups/Values still works, 
and the light theme looks unchanged.
    
    Notes:
    
    * Not tagged with `<at>NB-PARITY-060` (theme). That scenario's action is 
changing the theme while a notebook is mounted, but this spec sets the theme in 
localStorage and reloads. Tagging it would also mean updating the registry 
coverage that ZEPPELIN-6640 tracks.
    * Drag-and-drop was checked by hand but has no new automated coverage. 
Behavior coverage for these panels is ZEPPELIN-6514.
    * Unrelated existing behavior found while testing, present on master too: 
reload a note whose saved mode is Scatter, switch to Bar and back to Scatter, 
and the Scatter settings panel stays hidden while `Setting` shows it as open. 
Each test here uses a fresh note, so it does not hit this.
    
    ### Screenshots (if appropriate)
    
    N/A. The computed-style tables above record the before/after values.
    
    ### Questions:
    
    * Does the license files need to update? No. The new spec has the ASF 
header.
    * Is there breaking changes for older versions? No. Light theme output is 
unchanged.
    * Does this needs documentation? No.
    
    πŸ€– Generated with [Claude Code](https://claude.com/claude-code)
    
    
    Closes #5504 from kimyenac/ZEPPELIN-6588.
    
    Signed-off-by: ChanHo Lee <[email protected]>
---
 .../e2e/models/notebook-visualization-page.ts      |  29 +++++
 .../paragraph/visualization-rendering.spec.ts      |   4 +-
 .../theme/visualization-settings-theme.spec.ts     | 137 +++++++++++++++++++++
 .../pivot-setting/pivot-setting.component.less     |   4 +-
 .../scatter-setting/scatter-setting.component.less |   4 +-
 zeppelin-web-angular/src/styles/global.less        |  15 ++-
 6 files changed, 183 insertions(+), 10 deletions(-)

diff --git a/zeppelin-web-angular/e2e/models/notebook-visualization-page.ts 
b/zeppelin-web-angular/e2e/models/notebook-visualization-page.ts
index a223398462..6d7c6ec585 100644
--- a/zeppelin-web-angular/e2e/models/notebook-visualization-page.ts
+++ b/zeppelin-web-angular/e2e/models/notebook-visualization-page.ts
@@ -15,6 +15,9 @@
 import { Locator, Page } from '@playwright/test';
 import { BasePage } from './base-page';
 
+export const TABLE_PARAGRAPH = `%sh
+printf '%%table 
city\\tsales\\tcost\\nSeoul\\t30\\t12\\nBusan\\t20\\t8\\nIncheon\\t10\\t5\\n'`;
+
 export class NotebookVisualizationPage extends BasePage {
   readonly tableMode: Locator;
   readonly barChartMode: Locator;
@@ -30,6 +33,9 @@ export class NotebookVisualizationPage extends BasePage {
   readonly lineChartCanvas: Locator;
   readonly areaChartCanvas: Locator;
   readonly scatterChartCanvas: Locator;
+  readonly settingTrigger: Locator;
+  readonly pivotSetting: Locator;
+  readonly scatterSetting: Locator;
   private readonly resultDisplay: Locator;
 
   constructor(page: Page) {
@@ -49,6 +55,29 @@ export class NotebookVisualizationPage extends BasePage {
     this.lineChartCanvas = 
this.resultDisplay.locator('zeppelin-line-chart-visualization canvas');
     this.areaChartCanvas = 
this.resultDisplay.locator('zeppelin-area-chart-visualization canvas');
     this.scatterChartCanvas = 
this.resultDisplay.locator('zeppelin-scatter-chart-visualization canvas');
+    this.settingTrigger = this.resultDisplay.getByText('Setting', { exact: 
true });
+    this.pivotSetting = 
this.resultDisplay.locator('zeppelin-visualization-pivot-setting');
+    this.scatterSetting = 
this.resultDisplay.locator('zeppelin-visualization-scatter-setting');
+  }
+
+  modeRadio(mode: Locator): Locator {
+    return mode.locator('input[type="radio"]');
+  }
+
+  settingCards(setting: Locator): Locator {
+    return setting.locator('.ant-card');
+  }
+
+  settingCardHeads(setting: Locator): Locator {
+    return setting.locator('.ant-card-head');
+  }
+
+  settingCardTitles(setting: Locator): Locator {
+    return setting.locator('.ant-card-head-title');
+  }
+
+  settingFieldTags(setting: Locator): Locator {
+    return setting.locator('.drag-tag');
   }
 
   async renderedPixelCount(canvas: Locator): Promise<number> {
diff --git 
a/zeppelin-web-angular/e2e/tests/notebook/paragraph/visualization-rendering.spec.ts
 
b/zeppelin-web-angular/e2e/tests/notebook/paragraph/visualization-rendering.spec.ts
index dd96106086..c76433d7b6 100644
--- 
a/zeppelin-web-angular/e2e/tests/notebook/paragraph/visualization-rendering.spec.ts
+++ 
b/zeppelin-web-angular/e2e/tests/notebook/paragraph/visualization-rendering.spec.ts
@@ -14,7 +14,7 @@
 
 import { expect, Locator, test } from '@playwright/test';
 import { NotebookParagraphPage } from 'e2e/models/notebook-paragraph-page';
-import { NotebookVisualizationPage } from 
'e2e/models/notebook-visualization-page';
+import { NotebookVisualizationPage, TABLE_PARAGRAPH } from 
'e2e/models/notebook-visualization-page';
 import {
   addPageAnnotation,
   addPageAnnotationBeforeEach,
@@ -25,8 +25,6 @@ import {
   waitForZeppelinReady
 } from '../../../utils';
 
-const TABLE_PARAGRAPH = `%sh
-printf '%%table 
city\\tsales\\tcost\\nSeoul\\t30\\t12\\nBusan\\t20\\t8\\nIncheon\\t10\\t5\\n'`;
 const TABLE_HEADERS = ['city', 'sales', 'cost'];
 const TABLE_CELLS = ['Seoul', '30', '12', 'Busan', '20', '8', 'Incheon', '10', 
'5'];
 
diff --git 
a/zeppelin-web-angular/e2e/tests/theme/visualization-settings-theme.spec.ts 
b/zeppelin-web-angular/e2e/tests/theme/visualization-settings-theme.spec.ts
new file mode 100644
index 0000000000..bb0865f445
--- /dev/null
+++ b/zeppelin-web-angular/e2e/tests/theme/visualization-settings-theme.spec.ts
@@ -0,0 +1,137 @@
+/*
+ * 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 { expect, test } from '@playwright/test';
+import { DarkModePage } from 'e2e/models/dark-mode-page';
+import { NotebookParagraphPage } from 'e2e/models/notebook-paragraph-page';
+import { NotebookVisualizationPage, TABLE_PARAGRAPH } from 
'e2e/models/notebook-visualization-page';
+import {
+  addPageAnnotationBeforeEach,
+  createTestNotebook,
+  PAGES,
+  performLoginIfRequired,
+  setParagraphText,
+  waitForZeppelinReady
+} from '../../utils';
+
+// Resolved values of the theme variables the panels use: 
@component-background,
+// @background-color-light, @heading-color, @text-color and @border-color-base.
+const THEMES = [
+  {
+    theme: 'light',
+    card: 'rgb(255, 255, 255)',
+    head: 'rgb(250, 250, 250)',
+    title: 'rgba(0, 0, 0, 0.85)',
+    tagBackground: 'rgb(250, 250, 250)',
+    tagText: 'rgba(0, 0, 0, 0.65)',
+    tagBorder: 'rgb(217, 217, 217)'
+  },
+  {
+    theme: 'dark',
+    card: 'rgb(31, 31, 31)',
+    head: 'rgb(38, 38, 38)',
+    title: 'rgba(255, 255, 255, 0.95)',
+    tagBackground: 'rgb(38, 38, 38)',
+    tagText: 'rgba(255, 255, 255, 0.85)',
+    tagBorder: 'rgb(67, 67, 67)'
+  }
+] as const;
+
+const PANELS = [
+  {
+    name: 'Pivot',
+    page: PAGES.VISUALIZATIONS.COMMON.PIVOT_SETTING,
+    titles: ['Available Fields', 'Keys', 'Groups', 'Values'],
+    chartMode: (visualizationPage: NotebookVisualizationPage) => 
visualizationPage.barChartMode,
+    setting: (visualizationPage: NotebookVisualizationPage) => 
visualizationPage.pivotSetting
+  },
+  {
+    name: 'Scatter',
+    page: PAGES.VISUALIZATIONS.COMMON.SCATTER_SETTING,
+    titles: ['Available Fields', 'XAxis', 'YAxis', 'Group', 'Size'],
+    chartMode: (visualizationPage: NotebookVisualizationPage) => 
visualizationPage.scatterChartMode,
+    setting: (visualizationPage: NotebookVisualizationPage) => 
visualizationPage.scatterSetting
+  }
+];
+
+for (const panel of PANELS) {
+  test.describe(`${panel.name} Settings Theme`, () => {
+    addPageAnnotationBeforeEach(panel.page);
+
+    let darkModePage: DarkModePage;
+    let paragraphPage: NotebookParagraphPage;
+    let visualizationPage: NotebookVisualizationPage;
+
+    test.beforeEach(async ({ page }) => {
+      await test.step('Given a notebook paragraph with deterministic table 
output', async () => {
+        await page.goto('/#/');
+        await waitForZeppelinReady(page);
+        await performLoginIfRequired(page);
+
+        const { noteId, paragraphId } = await createTestNotebook(page);
+        await setParagraphText(page, noteId, paragraphId, TABLE_PARAGRAPH);
+
+        darkModePage = new DarkModePage(page);
+        paragraphPage = new NotebookParagraphPage(page);
+        visualizationPage = new NotebookVisualizationPage(page);
+        await page.goto(`/#/notebook/${noteId}`);
+        await expect(paragraphPage.paragraphContainer).toBeVisible({ timeout: 
30000 });
+
+        await paragraphPage.runParagraph();
+        await expect(visualizationPage.dataTable).toBeVisible({ timeout: 30000 
});
+      });
+    });
+
+    for (const colors of THEMES) {
+      test(`uses the ${colors.theme} theme colors for card headers and field 
labels`, async ({ page }) => {
+        const setting = panel.setting(visualizationPage);
+
+        await test.step(`Given the ${colors.theme} theme`, async () => {
+          await darkModePage.setThemeInLocalStorage(colors.theme);
+          await page.reload();
+          await waitForZeppelinReady(page);
+          await expect(darkModePage.rootElement).toHaveAttribute('data-theme', 
colors.theme);
+          await expect(visualizationPage.dataTable).toBeVisible({ timeout: 
30000 });
+        });
+
+        await test.step(`When opening the ${panel.name} settings`, async () => 
{
+          const chartMode = panel.chartMode(visualizationPage);
+          await expect(async () => {
+            await chartMode.click();
+            await expect(visualizationPage.modeRadio(chartMode)).toBeChecked({ 
timeout: 1000 });
+          }).toPass({ timeout: 10000 });
+          await visualizationPage.settingTrigger.click();
+          await expect(setting).toBeVisible();
+        });
+
+        await test.step('Then every card and its header use the theme colors', 
async () => {
+          await 
expect(visualizationPage.settingCardTitles(setting)).toHaveText(panel.titles);
+          for (let index = 0; index < panel.titles.length; index++) {
+            await 
expect(visualizationPage.settingCards(setting).nth(index)).toHaveCSS('background-color',
 colors.card);
+            await 
expect(visualizationPage.settingCardHeads(setting).nth(index)).toHaveCSS(
+              'background-color',
+              colors.head
+            );
+            await 
expect(visualizationPage.settingCardTitles(setting).nth(index)).toHaveCSS('color',
 colors.title);
+          }
+        });
+
+        await test.step('And the field labels use the theme colors', async () 
=> {
+          const fieldTag = 
visualizationPage.settingFieldTags(setting).filter({ hasText: 'city' }).first();
+          await expect(fieldTag).toHaveCSS('background-color', 
colors.tagBackground);
+          await expect(fieldTag).toHaveCSS('color', colors.tagText);
+          await expect(fieldTag).toHaveCSS('border-top-color', 
colors.tagBorder);
+        });
+      });
+    }
+  });
+}
diff --git 
a/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.less
 
b/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.less
index 9091c36775..bddd2b24a2 100644
--- 
a/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.less
+++ 
b/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.less
@@ -22,11 +22,11 @@
     min-height: 23px;
   }
   nz-card {
-    background: #fff;
+    background: @component-background;
     ::ng-deep {
       .ant-card-head {
         padding: 0 12px;
-        background: #fafafa;
+        background: @background-color-light;
       }
     }
   }
diff --git 
a/zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.less
 
b/zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.less
index 35d9c4e389..368c813146 100644
--- 
a/zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.less
+++ 
b/zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.less
@@ -22,11 +22,11 @@
     min-height: 23px;
   }
   nz-card {
-    background: #fff;
+    background: @component-background;
     ::ng-deep {
       .ant-card-head {
         padding: 0 12px;
-        background: #fafafa;
+        background: @background-color-light;
       }
     }
   }
diff --git a/zeppelin-web-angular/src/styles/global.less 
b/zeppelin-web-angular/src/styles/global.less
index b72478b783..1ad743597a 100644
--- a/zeppelin-web-angular/src/styles/global.less
+++ b/zeppelin-web-angular/src/styles/global.less
@@ -53,9 +53,11 @@
   opacity: 0.5;
 }
 
+// Global rather than per component: the CDK drag preview is appended to 
<body>.
 .drag-tag {
+  @import 'theme-light';
   box-sizing: border-box;
-  color: rgba(0, 0, 0, 0.65);
+  color: @text-color;
   font-variant: tabular-nums;
   list-style: none;
   font-feature-settings: 'tnum';
@@ -66,8 +68,8 @@
   font-size: 12px;
   line-height: 20px;
   white-space: nowrap;
-  background: #fafafa;
-  border: 1px solid #d9d9d9;
+  background: @background-color-light;
+  border: 1px solid @border-color-base;
   border-radius: 0px;
   cursor: pointer;
   opacity: 1;
@@ -81,6 +83,13 @@
   }
 }
 
+html.dark .drag-tag {
+  @import 'theme-dark';
+  color: @text-color;
+  background: @background-color-light;
+  border-color: @border-color-base;
+}
+
 .interpreter-box {
   margin-bottom: 12px;
   line-height: 32px;

Reply via email to