diff --git a/frontend/src/components/DataGrid.layout.test.tsx b/frontend/src/components/DataGrid.layout.test.tsx index d1a730e9..560a375d 100644 --- a/frontend/src/components/DataGrid.layout.test.tsx +++ b/frontend/src/components/DataGrid.layout.test.tsx @@ -1327,6 +1327,10 @@ describe('DataGrid layout', () => { css.indexOf('body[data-ui-version="v2"] .gn-v2-data-grid .gn-v2-commit-button:disabled {'), css.indexOf('body[data-ui-version="v2"] .gn-v2-data-grid .gn-v2-commit-button .gn-v2-toolbar-kbd {'), ); + const resultViewSelectionCss = css.slice( + css.indexOf('body[data-ui-version="v2"] .gn-v2-data-grid-result-switcher .ant-segmented-item-selected,'), + css.indexOf('body[data-ui-version="v2"] .gn-v2-data-grid-page-find-overlay {'), + ); expect(iconActionCss).toContain('width: 28px !important;'); expect(iconActionCss).toContain('min-width: 28px !important;'); expect(iconActionCss).toContain('padding-inline: 0 !important;'); @@ -1336,6 +1340,10 @@ describe('DataGrid layout', () => { expect(commitDisabledCss).toContain('background: var(--gn-bg-active) !important;'); expect(commitDisabledCss).toContain('color: var(--gn-fg-5) !important;'); expect(commitDisabledCss).not.toContain('var(--gn-accent-soft)'); + expect(resultViewSelectionCss).toContain('background: var(--gn-accent-strong, var(--gn-accent)) !important;'); + expect(resultViewSelectionCss).toContain('border: 0 !important;'); + expect(resultViewSelectionCss).toContain('box-shadow: none !important;'); + expect(resultViewSelectionCss).toContain('color: var(--gn-on-accent, #fff) !important;'); expect(css).toContain( 'body[data-ui-version="v2"] .gn-v2-data-grid-statusbar .gn-v2-data-grid-toolbar-action.ant-btn {', ); @@ -1654,7 +1662,7 @@ describe('DataGrid layout', () => { expect(markup.match(/data-grid-query-copy-action="true"/g)?.length).toBe(1); }); - it('renders a quick WHERE condition editor when table filters are visible', () => { + it('renders a manual query condition editor when table filters are visible', () => { const markup = renderDataGridWithI18n( { expect(markup).toContain('data-grid-quick-where="true"'); expect(markup).toContain('data-grid-quick-where-input="true"'); - expect(markup).toContain('WHERE'); + expect(markup).toContain('data-grid-quick-where-label="true"'); + expect(markup).toContain('手动查询条件'); + const manualConditionLabel = markup.match(/]*)>/)?.[1] ?? ''; + expect(manualConditionLabel).not.toContain('border'); + expect(manualConditionLabel).not.toContain('background'); const englishMarkup = renderDataGridWithI18n( { { preference: 'en-US' }, ); - expect(englishMarkup).toContain('Enter the condition after WHERE'); - expect(englishMarkup).not.toContain('输入 WHERE 后面的条件'); + expect(englishMarkup).toContain('Manual query condition'); + expect(englishMarkup).toContain('Enter a query condition'); + expect(englishMarkup).not.toContain('Enter the condition after WHERE'); + expect(englishMarkup).not.toContain('输入查询条件'); }); it('keeps quick WHERE input clipboard editing isolated from grid shortcuts', () => { @@ -1708,6 +1722,35 @@ describe('DataGrid layout', () => { expect(css).toContain('user-select: text !important;'); }); + it('keeps V2 filter controls on the query workbench theme surface', () => { + const css = readV2ThemeCss(); + const toolbarCss = css.slice( + css.indexOf('body[data-ui-version="v2"] .gn-v2-data-grid-toolbar-frame'), + css.indexOf('body[data-ui-version="v2"] .gn-v2-data-grid-toolbar-title'), + ); + const filterCss = css.slice( + css.indexOf('body[data-ui-version="v2"] .gn-v2-smart-filter-panel'), + css.indexOf('body[data-ui-version="v2"] .gn-v2-data-grid-table-shell'), + ); + const tableSurfaceCss = css.slice( + css.indexOf('body[data-ui-version="v2"] .gn-v2-data-grid-table-shell'), + css.indexOf('body[data-ui-version="v2"] .gn-v2-data-grid .ant-table-thead'), + ); + + expect(toolbarCss).toContain('background: var(--gn-query-workbench-bg, var(--gn-bg-panel-2)) !important;'); + expect(filterCss).toContain('background: var(--gn-query-workbench-bg, var(--gn-bg-panel-2)) !important;'); + expect(filterCss).toContain('padding-inline: 0 !important;'); + expect(filterCss).toContain('.gn-v2-smart-filter-manual-input'); + expect(filterCss).toContain('max-width: 680px !important;'); + expect(filterCss).toContain('.gn-v2-smart-filter-panel .ant-select-selector'); + expect(filterCss).toContain('.gn-v2-smart-filter-panel .ant-input-affix-wrapper'); + expect(filterCss).not.toContain('background: var(--gn-bg-input)'); + expect(filterCss).toContain('[data-grid-quick-where="true"] {\n min-height: 38px;\n padding-inline: 0 !important;\n margin-bottom: 8px !important;\n border: 0 !important;\n border-radius: 0 !important;'); + expect(tableSurfaceCss).toContain('background: var(--gn-query-workbench-bg, var(--gn-bg-panel-2)) !important;'); + expect(tableSurfaceCss).toContain('.gn-v2-data-grid .ant-table-container'); + expect(tableSurfaceCss).toContain('.gn-v2-data-grid .ant-table-tbody-virtual-holder'); + }); + it('keeps DataGrid scroll synchronization throttled to animation frames', () => { const source = readDataGridSource(); const secondaryActionsSource = readFileSync(new URL('./DataGridSecondaryActions.tsx', import.meta.url), 'utf8'); diff --git a/frontend/src/components/DataGridToolbarFrame.tsx b/frontend/src/components/DataGridToolbarFrame.tsx index 2efa90cb..9eac5940 100644 --- a/frontend/src/components/DataGridToolbarFrame.tsx +++ b/frontend/src/components/DataGridToolbarFrame.tsx @@ -687,25 +687,21 @@ const DataGridToolbarFrame: React.FC = ({ }} > - WHERE + {translate('data_grid.filter.manual_query_condition')} readFileSync( + new URL('../styles/v2-theme-workbench.css', import.meta.url), + 'utf8', +); + +const readV2ThemeCss = (): string => readFileSync( + new URL('../v2-theme.css', import.meta.url), + 'utf8', +); + +const readSection = (css: string, startMarker: string, endMarker: string): string => { + const start = css.indexOf(startMarker); + const end = css.indexOf(endMarker, start + startMarker.length); + expect(start).toBeGreaterThanOrEqual(0); + expect(end).toBeGreaterThan(start); + return css.slice(start, end); +}; + +describe('V2 workbench theme surfaces', () => { + it('keeps Redis and Nacos workbench backgrounds on the secondary theme panel', () => { + const css = readWorkbenchCss(); + const v2ThemeCss = readV2ThemeCss(); + const redisRootCss = readSection( + v2ThemeCss, + 'body[data-ui-version="v2"] .redis-viewer-workbench', + 'body[data-ui-version="v2"] .redis-tree-expander-button:hover', + ); + const redisCss = readSection( + css, + '/* ─── V2 Redis workbench ─ */', + '/* ─── V2 Nacos workbench', + ); + const nacosCss = readSection( + css, + '/* ─── V2 Nacos workbench', + '/* ─── Nacos service discovery:', + ); + + expect(redisCss).toContain('background: var(--gn-bg-panel-2)'); + expect(redisCss).not.toMatch(/background:\s*var\(--gn-bg-panel\)(?:\s*!important)?;/); + expect(redisRootCss).toContain('background: var(--gn-bg-panel-2) !important;'); + expect(redisRootCss).not.toContain('background: var(--gn-bg-app) !important;'); + expect(nacosCss).toContain('background: var(--gn-bg-panel-2)'); + expect(nacosCss).not.toMatch(/background:\s*var\(--gn-bg-panel\)(?:\s*!important)?;/); + }); + + it('keeps sidebar and Nacos filter inputs on their surrounding theme surface', () => { + const css = readWorkbenchCss(); + const v2ThemeCss = readV2ThemeCss(); + const explorerSearchCss = readSection( + v2ThemeCss, + 'body[data-ui-version="v2"] .gn-v2-explorer-search', + 'body[data-ui-version="v2"] .gn-v2-explorer-filter-tabs', + ); + const nacosFilterCss = readSection( + css, + '/* Filter row: grow with left pane width so long DataId/Group names fit better */', + '.gn-nacos-selection-toolbar', + ); + + expect(explorerSearchCss).toContain('background: var(--gn-bg-panel-2)'); + expect(explorerSearchCss).not.toContain('background: var(--gn-bg-input)'); + expect(nacosFilterCss).toContain('background: var(--gn-bg-panel-2) !important;'); + }); +}); diff --git a/frontend/src/styles/v2-theme-workbench.css b/frontend/src/styles/v2-theme-workbench.css index 87359050..4a100071 100644 --- a/frontend/src/styles/v2-theme-workbench.css +++ b/frontend/src/styles/v2-theme-workbench.css @@ -801,7 +801,7 @@ body[data-ui-version="v2"] .gn-v2-redis-workbench { grid-template-rows: max-content minmax(0, 1fr); gap: 0 !important; padding: 0 !important; - background: var(--gn-bg-panel) !important; + background: var(--gn-bg-panel-2) !important; } body[data-ui-version="v2"] .gn-v2-redis-sidebar { @@ -812,7 +812,7 @@ body[data-ui-version="v2"] .gn-v2-redis-sidebar { width: 100% !important; min-width: 0 !important; gap: 0 !important; - background: var(--gn-bg-panel) !important; + background: var(--gn-bg-panel-2) !important; } body[data-ui-version="v2"] .gn-v2-redis-header, @@ -822,7 +822,7 @@ body[data-ui-version="v2"] .gn-v2-redis-value-card, body[data-ui-version="v2"] .gn-v2-redis-empty-value { border: 0 !important; border-radius: 0 !important; - background: var(--gn-bg-panel) !important; + background: var(--gn-bg-panel-2) !important; box-shadow: none !important; backdrop-filter: none !important; -webkit-backdrop-filter: none !important; @@ -859,13 +859,13 @@ body[data-ui-version="v2"] .gn-v2-redis-workbench .ant-tree-checkbox { body[data-ui-version="v2"] .gn-v2-redis-value-pane { display: contents !important; min-width: 360px !important; - background: var(--gn-bg-panel) !important; + background: var(--gn-bg-panel-2) !important; } body[data-ui-version="v2"] .gn-v2-redis-value-layout { display: contents !important; gap: 0 !important; - background: var(--gn-bg-panel) !important; + background: var(--gn-bg-panel-2) !important; } body[data-ui-version="v2"] .gn-v2-redis-value-top { @@ -875,7 +875,7 @@ body[data-ui-version="v2"] .gn-v2-redis-value-top { height: 100%; min-height: 0; gap: 0 !important; - background: var(--gn-bg-panel); + background: var(--gn-bg-panel-2); } body[data-ui-version="v2"] .gn-v2-redis-value-header { @@ -895,7 +895,7 @@ body[data-ui-version="v2"] .gn-v2-redis-value-subtoolbar, body[data-ui-version="v2"] .gn-v2-redis-value-actionbar { border: 0 !important; border-radius: 0 !important; - background: var(--gn-bg-panel) !important; + background: var(--gn-bg-panel-2) !important; box-shadow: none !important; } @@ -957,7 +957,7 @@ body[data-ui-version="v2"] .gn-v2-nacos-workbench { flex-direction: column !important; padding: 0 !important; gap: 0 !important; - background: var(--gn-bg-panel) !important; + background: var(--gn-bg-panel-2) !important; color: var(--gn-fg-1); } @@ -1064,7 +1064,7 @@ body[data-ui-version="v2"] .gn-v2-nacos-split { flex: 1 1 auto !important; min-height: 0 !important; gap: 0 !important; - background: var(--gn-bg-panel) !important; + background: var(--gn-bg-panel-2) !important; } body[data-ui-version="v2"] .gn-v2-nacos-list-pane { @@ -1080,7 +1080,7 @@ body[data-ui-version="v2"] .gn-v2-nacos-list-pane { border: 0 !important; border-radius: 0 !important; box-shadow: none !important; - background: var(--gn-bg-panel) !important; + background: var(--gn-bg-panel-2) !important; backdrop-filter: none !important; -webkit-backdrop-filter: none !important; } @@ -1095,7 +1095,7 @@ body[data-ui-version="v2"] .gn-v2-nacos-detail-pane { border: 0 !important; border-radius: 0 !important; box-shadow: none !important; - background: var(--gn-bg-panel) !important; + background: var(--gn-bg-panel-2) !important; backdrop-filter: none !important; -webkit-backdrop-filter: none !important; } @@ -1115,7 +1115,7 @@ body[data-ui-version="v2"] .gn-v2-nacos-pane-header { border: 0 !important; border-bottom: 1px solid var(--gn-br-1) !important; border-radius: 0 !important; - background: var(--gn-bg-panel) !important; + background: var(--gn-bg-panel-2) !important; box-shadow: none !important; } @@ -1146,6 +1146,11 @@ body[data-ui-version="v2"] .gn-nacos-filter-row .ant-select-selector { width: 100% !important; } +/* Keep the filter fields continuous with the flat Nacos workbench surface. */ +body[data-ui-version="v2"] .gn-nacos-filter-row .ant-select-selector { + background: var(--gn-bg-panel-2) !important; +} + .gn-nacos-selection-toolbar { min-height: 32px; padding: 8px 4px 0; @@ -1216,7 +1221,7 @@ body[data-ui-version="v2"] .gn-v2-nacos-pane-body { display: flex; flex-direction: column; padding: 10px 12px !important; - background: var(--gn-bg-panel) !important; + background: var(--gn-bg-panel-2) !important; } /* Full-height 1px divider like Redis */ diff --git a/frontend/src/v2-theme.css b/frontend/src/v2-theme.css index 1fca192a..f03c3ce0 100644 --- a/frontend/src/v2-theme.css +++ b/frontend/src/v2-theme.css @@ -1867,7 +1867,7 @@ body[data-ui-version="v2"] .ant-modal-body input[type="number"] { inline styles can't reach. */ body[data-ui-version="v2"] .redis-viewer-workbench { - background: var(--gn-bg-app) !important; + background: var(--gn-bg-panel-2) !important; /* the inner cards still read workbenchTheme — those return v2 palette once the workbench theme files honor uiVersion */ } @@ -2403,7 +2403,7 @@ body[data-ui-version="v2"] .gn-v2-explorer-command-trigger { border: 0.5px solid var(--gn-br-2); border-radius: 7px; padding: 0 8px; - background: var(--gn-bg-input); + background: var(--gn-bg-panel-2); color: var(--gn-fg-4); cursor: text; font-size: 12px; @@ -2434,7 +2434,7 @@ body[data-ui-version="v2"] .gn-v2-explorer-filter-action { justify-content: center; border: 0.5px solid var(--gn-br-2); border-radius: 7px; - background: var(--gn-bg-input); + background: var(--gn-bg-panel-2); color: var(--gn-fg-4); cursor: pointer; } @@ -2739,7 +2739,7 @@ body[data-ui-version="v2"] .gn-v2-explorer-search .ant-input-affix-wrapper { border-radius: 7px !important; border: 0.5px solid var(--gn-br-2) !important; padding: 0 8px !important; - background: var(--gn-bg-input) !important; + background: var(--gn-bg-panel-2) !important; color: var(--gn-fg-2) !important; font-size: 12px !important; font-weight: 500 !important; @@ -4064,14 +4064,14 @@ body[data-ui-version="v2"] .gn-v2-data-grid-toolbar-frame { border-width: 0 0 0.5px !important; border-color: var(--gn-br-1) !important; border-radius: 0 !important; - background: var(--gn-bg-panel) !important; + background: var(--gn-query-workbench-bg, var(--gn-bg-panel-2)) !important; } body[data-ui-version="v2"] .gn-v2-data-grid .data-grid-toolbar-scroll { min-height: 44px; padding: 7px 12px !important; gap: 4px !important; - background: var(--gn-bg-panel) !important; + background: var(--gn-query-workbench-bg, var(--gn-bg-panel-2)) !important; } body[data-ui-version="v2"] .gn-v2-data-grid .data-grid-toolbar-scroll .ant-btn { @@ -4245,17 +4245,37 @@ body[data-ui-version="v2"] .gn-v2-data-grid .gn-v2-query-result-toolbar-hide:hov } body[data-ui-version="v2"] .gn-v2-smart-filter-panel { - background: var(--gn-bg-panel-2) !important; + background: var(--gn-query-workbench-bg, var(--gn-bg-panel-2)) !important; border-top: 0.5px solid var(--gn-br-1); font-size: var(--gn-font-size, 14px); } body[data-ui-version="v2"] .gn-v2-smart-filter-panel [data-grid-quick-where="true"] { min-height: 38px; + padding-inline: 0 !important; margin-bottom: 8px !important; - border: 0.5px solid var(--gn-br-2) !important; - border-radius: 8px !important; - background: var(--gn-bg-panel) !important; + border: 0 !important; + border-radius: 0 !important; + background: var(--gn-query-workbench-bg, var(--gn-bg-panel-2)) !important; +} + +/* Keep manual query entry aligned with the condition checkbox and compact on wide screens. */ +body[data-ui-version="v2"] .gn-v2-smart-filter-panel .gn-v2-smart-filter-manual-input { + flex: 1 1 360px !important; + max-width: 680px !important; +} + +/* Filter controls stay on the result workbench surface instead of the global input well. */ +body[data-ui-version="v2"] .gn-v2-smart-filter-panel .ant-input, +body[data-ui-version="v2"] .gn-v2-smart-filter-panel .ant-input-affix-wrapper, +body[data-ui-version="v2"] .gn-v2-smart-filter-panel .ant-input-textarea, +body[data-ui-version="v2"] .gn-v2-smart-filter-panel .ant-select-selector { + background: var(--gn-query-workbench-bg, var(--gn-bg-panel-2)) !important; +} + +body[data-ui-version="v2"] .gn-v2-smart-filter-panel .ant-input-affix-wrapper > input.ant-input, +body[data-ui-version="v2"] .gn-v2-smart-filter-panel .ant-input-affix-wrapper .ant-input { + background: transparent !important; } body[data-ui-version="v2"] .gn-v2-smart-filter-panel [data-grid-quick-where="true"], @@ -4289,11 +4309,19 @@ body[data-ui-version="v2"] .gn-v2-smart-filter-panel [data-grid-quick-where-inpu body[data-ui-version="v2"] .gn-v2-data-grid-table-shell { border: none !important; border-radius: 0 !important; - background: var(--gn-bg-panel) !important; + background: var(--gn-query-workbench-bg, var(--gn-bg-panel-2)) !important; } body[data-ui-version="v2"] .gn-v2-data-grid-table-wrap { - background: var(--gn-bg-panel); + background: var(--gn-query-workbench-bg, var(--gn-bg-panel-2)); +} + +body[data-ui-version="v2"] .gn-v2-data-grid .ant-table, +body[data-ui-version="v2"] .gn-v2-data-grid .ant-table-container, +body[data-ui-version="v2"] .gn-v2-data-grid .ant-table-content, +body[data-ui-version="v2"] .gn-v2-data-grid .ant-table-tbody-virtual-holder, +body[data-ui-version="v2"] .gn-v2-data-grid .rc-virtual-list-holder { + background: var(--gn-query-workbench-bg, var(--gn-bg-panel-2)) !important; } body[data-ui-version="v2"] .gn-v2-data-grid .ant-table-thead > tr > th { @@ -4788,8 +4816,19 @@ body[data-ui-version="v2"] .gn-v2-data-grid-visually-hidden { border: 0 !important; } -body[data-ui-version="v2"] .gn-v2-data-grid-result-switcher .ant-segmented-item-selected .ant-segmented-item-label { - color: var(--gn-fg-1); +/* Result format is a mode switch, so its selected segment uses the theme accent + without a border or floating-card treatment. */ +body[data-ui-version="v2"] .gn-v2-data-grid-result-switcher .ant-segmented-item-selected, +body[data-ui-version="v2"] .gn-v2-data-grid-result-switcher .ant-segmented-thumb { + background: var(--gn-accent-strong, var(--gn-accent)) !important; + border: 0 !important; + border-radius: 5px !important; + box-shadow: none !important; +} + +body[data-ui-version="v2"] .gn-v2-data-grid-result-switcher .ant-segmented-item-selected .ant-segmented-item-label, +body[data-ui-version="v2"] .gn-v2-data-grid-result-switcher .ant-segmented-item-selected .anticon { + color: var(--gn-on-accent, #fff) !important; } body[data-ui-version="v2"] .gn-v2-data-grid-page-find-overlay {