Skip to content

Commit f494b6e

Browse files
authored
Merge pull request #663 from objectstack-ai/copilot/optimize-edit-view-page
2 parents ddb01d3 + 8d97719 commit f494b6e

6 files changed

Lines changed: 57 additions & 5 deletions

File tree

ROADMAP.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ Everything below has been built, tested, and verified. These items are stable an
4949
- **Animation:** 7 presets, reduced-motion aware, page transitions (9 types with View Transitions API).
5050
- **Notifications:** Toast/banner/snackbar with full CRUD integration.
5151
- **View Enhancements:** Gallery, column summary, grouping, row color, density modes, view sharing, ViewTabBar (reorder, pin, context menu, type-switch, personal/shared grouping).
52-
- **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.
52+
- **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.
5353

5454
### Enterprise Features ✅
5555

ROADMAP_CONSOLE.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1021,7 +1021,7 @@ These were the initial tasks to bring the console prototype to production-qualit
10211021
| **Global Undo/Redo (Ctrl+Z)** | ✅ Done (global UndoManager + batch ops + persistent stack) | Post v1.0 | Phase 16 (L1+L2) |
10221022
| Notification center | ✅ Partial (ActivityFeed with filter preferences) | Post v1.0 | Phase 17 (L2) |
10231023
| Activity feed | ✅ Done | Post v1.0 | Phase 17 (L1) |
1024-
| **Inline View Config Panel** | ✅ Done (Airtable-style right sidebar, breadcrumb header, record count footer) | Post v1.0 | Phase 20 |
1024+
| **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 |
10251025

10261026
### 5.5 Kanban & Visual Views
10271027

@@ -1100,6 +1100,10 @@ These were the initial tasks to bring the console prototype to production-qualit
11001100
2027 Q1+ — v2.0: AUTOMATION & WORKFLOWS (✅ L1 Complete)
11011101
═══════════════════════════════════════════════════════════
11021102
Phase 18: Automation & Workflows ██████████████ ✅ L1 Complete: AutomationBuilder, AutomationRunHistory, registered in ComponentRegistry
1103+
1104+
2027 Q1+ — v2.1: INLINE VIEW DESIGNER (✅ Complete)
1105+
═══════════════════════════════════════════════════════════
1106+
Phase 20: Inline ViewConfigPanel ██████████████ ✅ Complete: Airtable-style right sidebar, breadcrumb header, record count footer, responsive mobile overlay, ARIA accessibility, auto-close on view switch
11031107
```
11041108

11051109
### Milestone Summary
@@ -1114,6 +1118,7 @@ These were the initial tasks to bring the console prototype to production-qualit
11141118
| **v1.1** | v1.1.0 | ✅ Complete | Kanban + Forms + Import/Export (Phases 13-15); all L1 ✅ |
11151119
| **v1.2** | v1.2.0 | ✅ L1 Complete | Undo/Redo + Collaboration (Phases 16-17); L1 integrated into console |
11161120
| **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 |
1121+
| **v2.1** | v2.1.0 | ✅ Complete | Inline ViewConfigPanel (Phase 20): Airtable-style right sidebar for view configuration |
11171122

11181123
---
11191124

apps/console/src/__tests__/ViewConfigPanel.test.tsx

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,4 +218,37 @@ describe('ViewConfigPanel', () => {
218218
const noneTexts = screen.getAllByText('console.objectView.none');
219219
expect(noneTexts.length).toBeGreaterThanOrEqual(2);
220220
});
221+
222+
it('has correct ARIA attributes when open', () => {
223+
render(
224+
<ViewConfigPanel
225+
open={true}
226+
onClose={vi.fn()}
227+
activeView={mockActiveView}
228+
objectDef={mockObjectDef}
229+
/>
230+
);
231+
232+
const panel = screen.getByTestId('view-config-panel');
233+
expect(panel).toHaveAttribute('role', 'complementary');
234+
expect(panel).toHaveAttribute('aria-label', 'console.objectView.configureView');
235+
});
236+
237+
it('is full-width on mobile via CSS classes', () => {
238+
render(
239+
<ViewConfigPanel
240+
open={true}
241+
onClose={vi.fn()}
242+
activeView={mockActiveView}
243+
objectDef={mockObjectDef}
244+
/>
245+
);
246+
247+
const panel = screen.getByTestId('view-config-panel');
248+
// On mobile: absolute full-width overlay; on desktop: relative w-72
249+
expect(panel.className).toContain('w-full');
250+
expect(panel.className).toContain('sm:w-72');
251+
expect(panel.className).toContain('absolute');
252+
expect(panel.className).toContain('sm:relative');
253+
});
221254
});

apps/console/src/components/ObjectView.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ export function ObjectView({ dataSource, objects, onEdit, onRowClick }: any) {
123123
// The plugin ObjectView returns the view ID directly via onViewChange
124124
const matchedView = views.find((v: any) => v.id === newViewId);
125125
if (!matchedView) return;
126+
// Auto-close the config panel when switching views
127+
setShowViewConfigPanel(false);
126128
if (viewId) {
127129
navigate(`../${matchedView.id}`, { relative: "path" });
128130
} else {

apps/console/src/components/ViewConfigPanel.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* following the same pattern as MetadataPanel.
1010
*/
1111

12-
import { useMemo } from 'react';
12+
import { useMemo, useEffect, useRef } from 'react';
1313
import { Button } from '@object-ui/components';
1414
import { X, ChevronRight } from 'lucide-react';
1515
import { useObjectTranslation } from '@object-ui/i18n';
@@ -96,6 +96,14 @@ function ToggleIndicator({ enabled }: { enabled: boolean }) {
9696

9797
export function ViewConfigPanel({ open, onClose, activeView, objectDef }: ViewConfigPanelProps) {
9898
const { t } = useObjectTranslation();
99+
const panelRef = useRef<HTMLDivElement>(null);
100+
101+
// Focus the panel when it opens for keyboard accessibility
102+
useEffect(() => {
103+
if (open && panelRef.current) {
104+
panelRef.current.focus();
105+
}
106+
}, [open]);
99107

100108
const viewLabel = activeView.label || activeView.id;
101109
const viewType = activeView.type || 'grid';
@@ -124,8 +132,12 @@ export function ViewConfigPanel({ open, onClose, activeView, objectDef }: ViewCo
124132

125133
return (
126134
<div
135+
ref={panelRef}
127136
data-testid="view-config-panel"
128-
className="w-72 lg:w-80 border-l bg-background flex flex-col shrink-0 z-20 transition-all overflow-hidden"
137+
role="complementary"
138+
aria-label={t('console.objectView.configureView')}
139+
tabIndex={-1}
140+
className="absolute inset-y-0 right-0 w-full sm:w-72 lg:w-80 sm:relative sm:inset-auto border-l bg-background flex flex-col shrink-0 z-20 transition-all overflow-hidden"
129141
>
130142
{/* Panel Header */}
131143
<div className="px-4 py-3 border-b flex items-center justify-between shrink-0">

examples/crm/objectstack.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -767,4 +767,4 @@ export default defineStack({
767767

768768
},
769769
plugins: [],
770-
});
770+
}, { strict: false }); // Defer validation to `objectstack compile` CLI to avoid Zod double-parse transform bug on form.sections.columns

0 commit comments

Comments
 (0)