diff --git a/ROADMAP.md b/ROADMAP.md index 5cb01af7..cb273f3c 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 — 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. ### Enterprise Features ✅ diff --git a/ROADMAP_CONSOLE.md b/ROADMAP_CONSOLE.md index a340a7ac..dfac2923 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) | 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) | Post v1.0 | Phase 20 | ### 5.5 Kanban & Visual Views @@ -1100,6 +1100,10 @@ These were the initial tasks to bring the console prototype to production-qualit 2027 Q1+ — v2.0: AUTOMATION & WORKFLOWS (✅ L1 Complete) ═══════════════════════════════════════════════════════════ Phase 18: Automation & Workflows ██████████████ ✅ L1 Complete: AutomationBuilder, AutomationRunHistory, registered in ComponentRegistry + +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 ``` ### Milestone Summary @@ -1114,6 +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 | --- diff --git a/apps/console/src/__tests__/ViewConfigPanel.test.tsx b/apps/console/src/__tests__/ViewConfigPanel.test.tsx index f6afff27..9bc03199 100644 --- a/apps/console/src/__tests__/ViewConfigPanel.test.tsx +++ b/apps/console/src/__tests__/ViewConfigPanel.test.tsx @@ -218,4 +218,37 @@ describe('ViewConfigPanel', () => { const noneTexts = screen.getAllByText('console.objectView.none'); expect(noneTexts.length).toBeGreaterThanOrEqual(2); }); + + it('has correct ARIA attributes when open', () => { + render( + + ); + + const panel = screen.getByTestId('view-config-panel'); + expect(panel).toHaveAttribute('role', 'complementary'); + expect(panel).toHaveAttribute('aria-label', 'console.objectView.configureView'); + }); + + it('is full-width on mobile via CSS classes', () => { + render( + + ); + + const panel = screen.getByTestId('view-config-panel'); + // On mobile: absolute full-width overlay; on desktop: relative w-72 + expect(panel.className).toContain('w-full'); + expect(panel.className).toContain('sm:w-72'); + expect(panel.className).toContain('absolute'); + expect(panel.className).toContain('sm:relative'); + }); }); diff --git a/apps/console/src/components/ObjectView.tsx b/apps/console/src/components/ObjectView.tsx index 231e2cee..84797df5 100644 --- a/apps/console/src/components/ObjectView.tsx +++ b/apps/console/src/components/ObjectView.tsx @@ -123,6 +123,8 @@ export function ObjectView({ dataSource, objects, onEdit, onRowClick }: any) { // The plugin ObjectView returns the view ID directly via onViewChange const matchedView = views.find((v: any) => v.id === newViewId); if (!matchedView) return; + // Auto-close the config panel when switching views + setShowViewConfigPanel(false); if (viewId) { navigate(`../${matchedView.id}`, { relative: "path" }); } else { diff --git a/apps/console/src/components/ViewConfigPanel.tsx b/apps/console/src/components/ViewConfigPanel.tsx index 486d3b73..b3a809a0 100644 --- a/apps/console/src/components/ViewConfigPanel.tsx +++ b/apps/console/src/components/ViewConfigPanel.tsx @@ -9,7 +9,7 @@ * following the same pattern as MetadataPanel. */ -import { useMemo } from 'react'; +import { useMemo, useEffect, useRef } from 'react'; import { Button } from '@object-ui/components'; import { X, ChevronRight } from 'lucide-react'; import { useObjectTranslation } from '@object-ui/i18n'; @@ -96,6 +96,14 @@ function ToggleIndicator({ enabled }: { enabled: boolean }) { export function ViewConfigPanel({ open, onClose, activeView, objectDef }: ViewConfigPanelProps) { const { t } = useObjectTranslation(); + const panelRef = useRef(null); + + // Focus the panel when it opens for keyboard accessibility + useEffect(() => { + if (open && panelRef.current) { + panelRef.current.focus(); + } + }, [open]); const viewLabel = activeView.label || activeView.id; const viewType = activeView.type || 'grid'; @@ -124,8 +132,12 @@ export function ViewConfigPanel({ open, onClose, activeView, objectDef }: ViewCo return (
{/* Panel Header */}
diff --git a/examples/crm/objectstack.config.ts b/examples/crm/objectstack.config.ts index 43f01d2d..5b829a6a 100644 --- a/examples/crm/objectstack.config.ts +++ b/examples/crm/objectstack.config.ts @@ -767,4 +767,4 @@ export default defineStack({ }, plugins: [], -}); +}, { strict: false }); // Defer validation to `objectstack compile` CLI to avoid Zod double-parse transform bug on form.sections.columns