From 3143edf232e3f39c0e39195cd0e09e9268156930 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 21 Feb 2026 01:41:44 +0000 Subject: [PATCH 1/4] Initial plan From 21be7d5877c5a7d1885f0d80bb2964d38600e8ee Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 21 Feb 2026 01:48:33 +0000 Subject: [PATCH 2/4] feat(i18n): add save and discard translations to all locale files Add 'save' and 'discard' i18n keys to de, es, fr, ja, ko, pt, ru, zh, and ar locale files in the objectView section. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- packages/i18n/src/locales/ar.ts | 2 ++ packages/i18n/src/locales/de.ts | 2 ++ packages/i18n/src/locales/es.ts | 2 ++ packages/i18n/src/locales/fr.ts | 2 ++ packages/i18n/src/locales/ja.ts | 2 ++ packages/i18n/src/locales/ko.ts | 2 ++ packages/i18n/src/locales/pt.ts | 2 ++ packages/i18n/src/locales/ru.ts | 2 ++ packages/i18n/src/locales/zh.ts | 2 ++ 9 files changed, 18 insertions(+) diff --git a/packages/i18n/src/locales/ar.ts b/packages/i18n/src/locales/ar.ts index a6f9b6d923..f4711b60e4 100644 --- a/packages/i18n/src/locales/ar.ts +++ b/packages/i18n/src/locales/ar.ts @@ -208,6 +208,8 @@ const ar = { noDescription: 'لا يوجد وصف', none: 'لا شيء', columnsConfigured: '{{count}} أعمدة', + save: 'حفظ', + discard: 'تجاهل', }, localeSwitcher: { label: 'اللغة', diff --git a/packages/i18n/src/locales/de.ts b/packages/i18n/src/locales/de.ts index 0e9d2ce7d4..9cd28e7104 100644 --- a/packages/i18n/src/locales/de.ts +++ b/packages/i18n/src/locales/de.ts @@ -212,6 +212,8 @@ const de = { noDescription: 'Keine Beschreibung', none: 'Keine', columnsConfigured: '{{count}} Spalten', + save: 'Speichern', + discard: 'Verwerfen', }, localeSwitcher: { label: 'Sprache', diff --git a/packages/i18n/src/locales/es.ts b/packages/i18n/src/locales/es.ts index 4009d84651..9757d1ce58 100644 --- a/packages/i18n/src/locales/es.ts +++ b/packages/i18n/src/locales/es.ts @@ -207,6 +207,8 @@ const es = { noDescription: 'Sin descripción', none: 'Ninguno', columnsConfigured: '{{count}} columnas', + save: 'Guardar', + discard: 'Descartar', }, localeSwitcher: { label: 'Idioma', diff --git a/packages/i18n/src/locales/fr.ts b/packages/i18n/src/locales/fr.ts index 092b03adcf..30d20b6c02 100644 --- a/packages/i18n/src/locales/fr.ts +++ b/packages/i18n/src/locales/fr.ts @@ -212,6 +212,8 @@ const fr = { noDescription: 'Aucune description', none: 'Aucun', columnsConfigured: '{{count}} colonnes', + save: 'Enregistrer', + discard: 'Annuler', }, localeSwitcher: { label: 'Langue', diff --git a/packages/i18n/src/locales/ja.ts b/packages/i18n/src/locales/ja.ts index 0d445dd041..a3a6c563d3 100644 --- a/packages/i18n/src/locales/ja.ts +++ b/packages/i18n/src/locales/ja.ts @@ -207,6 +207,8 @@ const ja = { noDescription: '説明なし', none: 'なし', columnsConfigured: '{{count}} 列', + save: '保存', + discard: '破棄', }, localeSwitcher: { label: '言語', diff --git a/packages/i18n/src/locales/ko.ts b/packages/i18n/src/locales/ko.ts index bc478ca44e..4c70883d0f 100644 --- a/packages/i18n/src/locales/ko.ts +++ b/packages/i18n/src/locales/ko.ts @@ -207,6 +207,8 @@ const ko = { noDescription: '설명 없음', none: '없음', columnsConfigured: '{{count}}개 열', + save: '저장', + discard: '취소', }, localeSwitcher: { label: '언어', diff --git a/packages/i18n/src/locales/pt.ts b/packages/i18n/src/locales/pt.ts index 79c4bb657a..5183c758b3 100644 --- a/packages/i18n/src/locales/pt.ts +++ b/packages/i18n/src/locales/pt.ts @@ -207,6 +207,8 @@ const pt = { noDescription: 'Sem descrição', none: 'Nenhum', columnsConfigured: '{{count}} colunas', + save: 'Salvar', + discard: 'Descartar', }, localeSwitcher: { label: 'Idioma', diff --git a/packages/i18n/src/locales/ru.ts b/packages/i18n/src/locales/ru.ts index fa85f6f176..da7808da10 100644 --- a/packages/i18n/src/locales/ru.ts +++ b/packages/i18n/src/locales/ru.ts @@ -207,6 +207,8 @@ const ru = { noDescription: 'Нет описания', none: 'Нет', columnsConfigured: '{{count}} столбцов', + save: 'Сохранить', + discard: 'Отменить', }, localeSwitcher: { label: 'Язык', diff --git a/packages/i18n/src/locales/zh.ts b/packages/i18n/src/locales/zh.ts index 21af88de80..6db20be51f 100644 --- a/packages/i18n/src/locales/zh.ts +++ b/packages/i18n/src/locales/zh.ts @@ -212,6 +212,8 @@ const zh = { noDescription: '无描述', none: '无', columnsConfigured: '{{count}} 列', + save: '保存', + discard: '丢弃', }, localeSwitcher: { label: '语言', From 987b9ee921832dbe1867dc3033a31112aec59c2e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 21 Feb 2026 01:51:16 +0000 Subject: [PATCH 3/4] feat: implement ViewConfigPanel full interaction support (Airtable-style) - Replace read-only ToggleIndicator with interactive Switch components - Add inline-edit Input for view title - Add ViewType select dropdown for switching view types - Make Columns/Filters/Sort rows clickable with onOpenEditor callback - Add local draft state with Save/Discard buttons - Wire up ObjectView with draft state and onSave/onViewUpdate/onOpenEditor callbacks - Add i18n keys (save/discard) in all 10 locales - Add 27 tests covering all interactive features Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- .../src/__tests__/ViewConfigPanel.test.tsx | 327 +++++++++++++++++- apps/console/src/components/ObjectView.tsx | 28 +- .../src/components/ViewConfigPanel.tsx | 222 +++++++++--- packages/i18n/src/locales/en.ts | 2 + 4 files changed, 511 insertions(+), 68 deletions(-) diff --git a/apps/console/src/__tests__/ViewConfigPanel.test.tsx b/apps/console/src/__tests__/ViewConfigPanel.test.tsx index 9bc031992f..cfd07c2cda 100644 --- a/apps/console/src/__tests__/ViewConfigPanel.test.tsx +++ b/apps/console/src/__tests__/ViewConfigPanel.test.tsx @@ -2,6 +2,8 @@ * ViewConfigPanel Tests * * Tests for the Airtable-style inline view configuration panel. + * Covers: read-only display, interactive editing (Switch, Input, Select), + * draft state, save/discard, open editor callbacks, and ARIA accessibility. */ import { describe, it, expect, vi } from 'vitest'; @@ -24,6 +26,23 @@ vi.mock('@object-ui/components', () => ({ Button: ({ children, onClick, title, ...props }: any) => ( ), + Switch: ({ checked, onCheckedChange, ...props }: any) => ( + + + + )} ); } diff --git a/packages/i18n/src/locales/en.ts b/packages/i18n/src/locales/en.ts index 8b5d886e01..f6fde1052f 100644 --- a/packages/i18n/src/locales/en.ts +++ b/packages/i18n/src/locales/en.ts @@ -212,6 +212,8 @@ const en = { noDescription: 'No description', none: 'None', columnsConfigured: '{{count}} columns', + save: 'Save', + discard: 'Discard', }, localeSwitcher: { label: 'Language', From 84a3b22c168e59f16c3195715ec7a39983845dad Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 21 Feb 2026 01:59:21 +0000 Subject: [PATCH 4/4] fix: address code review - revert description to plain text, remove empty callback Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- ROADMAP.md | 2 +- ROADMAP_CONSOLE.md | 6 +++--- apps/console/src/__tests__/ViewConfigPanel.test.tsx | 11 ++++------- apps/console/src/components/ObjectView.tsx | 5 ----- apps/console/src/components/ViewConfigPanel.tsx | 10 +++------- 5 files changed, 11 insertions(+), 23 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index cb273f3c54..b12c9c40eb 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -49,7 +49,7 @@ Everything below has been built, tested, and verified. These items are stable an - **Animation:** 7 presets, reduced-motion aware, page transitions (9 types with View Transitions API). - **Notifications:** Toast/banner/snackbar with full CRUD integration. - **View Enhancements:** Gallery, column summary, grouping, row color, density modes, view sharing, ViewTabBar (reorder, pin, context menu, type-switch, personal/shared grouping). -- **Inline View Config Panel:** Airtable-style right sidebar for view configuration (Page, Data, Appearance, User Filters, Actions, Advanced), breadcrumb header, record count footer, responsive mobile overlay, ARIA accessibility, auto-close on view switch — no page navigation required. +- **Inline View Config Panel:** Airtable-style right sidebar for view configuration (Page, Data, Appearance, User Filters, Actions, Advanced), breadcrumb header, record count footer, responsive mobile overlay, ARIA accessibility, auto-close on view switch — no page navigation required. Full interactive editing support: inline title editing, Switch toggles for all boolean settings, ViewType select, clickable rows to open sub-editors (columns/filters/sort), local draft state with Save/Discard workflow, i18n in all 10 locales. ### Enterprise Features ✅ diff --git a/ROADMAP_CONSOLE.md b/ROADMAP_CONSOLE.md index dfac2923b7..186bc5779a 100644 --- a/ROADMAP_CONSOLE.md +++ b/ROADMAP_CONSOLE.md @@ -1021,7 +1021,7 @@ These were the initial tasks to bring the console prototype to production-qualit | **Global Undo/Redo (Ctrl+Z)** | ✅ Done (global UndoManager + batch ops + persistent stack) | Post v1.0 | Phase 16 (L1+L2) | | Notification center | ✅ Partial (ActivityFeed with filter preferences) | Post v1.0 | Phase 17 (L2) | | Activity feed | ✅ Done | Post v1.0 | Phase 17 (L1) | -| **Inline View Config Panel** | ✅ Done (Airtable-style right sidebar, breadcrumb header, record count footer, responsive mobile overlay, ARIA accessibility, auto-close on view switch) | Post v1.0 | Phase 20 | +| **Inline View Config Panel** | ✅ Done (Airtable-style right sidebar, breadcrumb header, record count footer, responsive mobile overlay, ARIA accessibility, auto-close on view switch, full interactive editing: Switch toggles, inline title edit, ViewType select, clickable sub-editor rows, draft state with Save/Discard) | Post v1.0 | Phase 20 | ### 5.5 Kanban & Visual Views @@ -1103,7 +1103,7 @@ These were the initial tasks to bring the console prototype to production-qualit 2027 Q1+ — v2.1: INLINE VIEW DESIGNER (✅ Complete) ═══════════════════════════════════════════════════════════ - Phase 20: Inline ViewConfigPanel ██████████████ ✅ Complete: Airtable-style right sidebar, breadcrumb header, record count footer, responsive mobile overlay, ARIA accessibility, auto-close on view switch + Phase 20: Inline ViewConfigPanel ██████████████ ✅ Complete: Airtable-style right sidebar, full interactive editing (Switch toggles, inline title, ViewType select, sub-editor rows, draft Save/Discard), ARIA accessibility ``` ### Milestone Summary @@ -1118,7 +1118,7 @@ These were the initial tasks to bring the console prototype to production-qualit | **v1.1** | v1.1.0 | ✅ Complete | Kanban + Forms + Import/Export (Phases 13-15); all L1 ✅ | | **v1.2** | v1.2.0 | ✅ L1 Complete | Undo/Redo + Collaboration (Phases 16-17); L1 integrated into console | | **v2.0** | v2.0.0 | ✅ L2 Complete | All L2 features: batch undo, expression formatting, conditional triggers, multi-step actions, swimlane persistence, keyboard nav, file validation, thread resolution, notification prefs | -| **v2.1** | v2.1.0 | ✅ Complete | Inline ViewConfigPanel (Phase 20): Airtable-style right sidebar for view configuration | +| **v2.1** | v2.1.0 | ✅ Complete | Inline ViewConfigPanel (Phase 20): Airtable-style right sidebar with full interactive editing support | --- diff --git a/apps/console/src/__tests__/ViewConfigPanel.test.tsx b/apps/console/src/__tests__/ViewConfigPanel.test.tsx index cfd07c2cda..c1fd75a928 100644 --- a/apps/console/src/__tests__/ViewConfigPanel.test.tsx +++ b/apps/console/src/__tests__/ViewConfigPanel.test.tsx @@ -114,7 +114,7 @@ describe('ViewConfigPanel', () => { expect(titleInput).toHaveValue('All Records'); }); - it('displays object description in readonly input', () => { + it('displays object description as plain text', () => { render( { /> ); - const descInput = screen.getByTestId('view-description-input'); - expect(descInput).toHaveValue('Track sales pipeline and deals'); - expect(descInput).toHaveAttribute('readOnly'); + expect(screen.getByText('Track sales pipeline and deals')).toBeInTheDocument(); }); - it('shows placeholder when object has no description', () => { + it('shows "no description" when object has no description', () => { render( { /> ); - const descInput = screen.getByTestId('view-description-input'); - expect(descInput).toHaveAttribute('placeholder', 'console.objectView.noDescription'); + expect(screen.getByText('console.objectView.noDescription')).toBeInTheDocument(); }); it('displays column count', () => { diff --git a/apps/console/src/components/ObjectView.tsx b/apps/console/src/components/ObjectView.tsx index dbe069776c..441455e2b4 100644 --- a/apps/console/src/components/ObjectView.tsx +++ b/apps/console/src/components/ObjectView.tsx @@ -69,10 +69,6 @@ export function ObjectView({ dataSource, objects, onEdit, onRowClick }: any) { // Draft state for view config edits — cached locally, saved on demand const [viewDraft, setViewDraft] = useState | null>(null); - const handleViewConfigUpdate = useCallback((field: string, value: any) => { - // Buffered locally — ViewConfigPanel manages its own draft - }, []); - const handleViewConfigSave = useCallback((draft: Record) => { setViewDraft(draft); setRefreshKey(k => k + 1); @@ -505,7 +501,6 @@ export function ObjectView({ dataSource, objects, onEdit, onRowClick }: any) { activeView={activeView} objectDef={objectDef} recordCount={recordCount} - onViewUpdate={handleViewConfigUpdate} onOpenEditor={handleOpenEditor} onSave={handleViewConfigSave} /> diff --git a/apps/console/src/components/ViewConfigPanel.tsx b/apps/console/src/components/ViewConfigPanel.tsx index b209e5c3e5..cf92f46077 100644 --- a/apps/console/src/components/ViewConfigPanel.tsx +++ b/apps/console/src/components/ViewConfigPanel.tsx @@ -208,13 +208,9 @@ export function ViewConfigPanel({ open, onClose, activeView, objectDef, onViewUp /> - + + {objectDef.description || t('console.objectView.noDescription')} +