Skip to content

Commit 356d017

Browse files
authored
Merge pull request #817 from objectstack-ai/copilot/fix-invalid-config-items
2 parents 26d4d7f + f43a480 commit 356d017

File tree

4 files changed

+280
-226
lines changed

4 files changed

+280
-226
lines changed

ROADMAP.md

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -412,9 +412,9 @@ ObjectUI is a universal Server-Driven UI (SDUI) engine built on React + Tailwind
412412

413413
**Phase 2 — Schema Factory (All Sections):**
414414
- [x] Page Config section: label, description, viewType, toolbar toggles (7 switches), navigation mode/width/openNewTab, selection, addRecord sub-editor, export + sub-config, showRecordCount, allowPrinting
415-
- [x] Data section: source, sortBy (expandable), groupBy, prefixField, columns selector (expandable w/ reorder), filterBy (expandable), pagination, searchable/filterable/hidden fields (expandable), quickFilters (expandable), virtualScroll, type-specific options (kanban/calendar/map/gallery/timeline/gantt)
416-
- [x] Appearance section: color, fieldTextColor, rowHeight (icon group), wrapHeaders, showDescription, collapseAllByDefault, striped, bordered, resizable, densityMode, conditionalFormatting (expandable), emptyState (title/message/icon)
417-
- [x] User Actions section: inlineEdit, addDeleteRecordsInline, rowActions (expandable), bulkActions (expandable)
415+
- [x] Data section: source, sortBy (expandable), groupBy (grid/gallery), columns selector (expandable w/ reorder), filterBy (expandable), pagination, searchable/filterable/hidden fields (expandable), quickFilters (expandable), virtualScroll (grid only), type-specific options (kanban/calendar/map/gallery/timeline/gantt)
416+
- [x] Appearance section: color (grid/calendar/timeline/gantt), rowHeight (icon group, grid only), wrapHeaders (grid only), showDescription, striped/bordered (grid only), resizable (grid only), conditionalFormatting (expandable, grid/kanban), emptyState (title/message/icon)
417+
- [x] User Actions section: inlineEdit (grid only), addDeleteRecordsInline (grid only), rowActions/bulkActions (expandable, grid/kanban)
418418
- [x] Sharing section: sharingEnabled, sharingVisibility (visibleWhen: sharing.enabled)
419419
- [x] Accessibility section: ariaLabel, ariaDescribedBy, ariaLive
420420
- [x] `ExpandableWidget` component for hook-safe expandable sub-sections within custom render functions
@@ -443,6 +443,23 @@ ObjectUI is a universal Server-Driven UI (SDUI) engine built on React + Tailwind
443443
- [x] Add `helpText` to navigation-dependent fields (width/openNewTab) with i18n hints (all 11 locales)
444444
- [x] 24 new tests: expandedSections override (3), disabledWhen evaluation (2), grid-only disabledWhen predicates (16), helpText validation (2), description spec alignment (1)
445445

446+
**Phase 6 — Config Panel Cleanup (Invalid Items Fix):**
447+
- [x] Remove `densityMode` field from appearance section (redundant with `rowHeight` which provides finer 5-value granularity)
448+
- [x] Remove `prefixField` from data section (not consumed by any runtime renderer)
449+
- [x] Remove `collapseAllByDefault` from appearance section (not consumed by any runtime renderer)
450+
- [x] Remove `fieldTextColor` from appearance section (not consumed by any runtime renderer)
451+
- [x] Remove `clickIntoRecordDetails` from userActions section (controlled implicitly via navigation mode, not directly consumed)
452+
- [x] Add view-type-aware `visibleWhen` to toolbar toggles: `showGroup` (grid/kanban/gallery), `showColor` (grid/calendar/timeline/gantt), `showDensity` (grid only), `showRecordCount` (grid only), `allowPrinting` (grid only)
453+
- [x] Add view-type-aware `visibleWhen` to data fields: `_groupBy` (grid/gallery — kanban uses dedicated type-specific option), `virtualScroll` (grid only)
454+
- [x] Add view-type-aware `visibleWhen` to appearance fields: `striped`/`bordered`/`wrapHeaders`/`resizable`/`rowHeight` (grid only, changed from disabledWhen to visibleWhen), `color` (grid/calendar/timeline/gantt), `conditionalFormatting` (grid/kanban)
455+
- [x] Add view-type-aware `visibleWhen` to userActions fields: `inlineEdit`/`addDeleteRecordsInline` (grid only), `rowActions`/`bulkActions` (grid/kanban)
456+
- [x] Correct `searchableFields`/`filterableFields`/`quickFilters`/`showDescription` to universal (all view types) — data fetch/toolbar features not view-specific
457+
- [x] Extend `buildSwitchField` and `buildFieldMultiSelect` helpers to accept `visibleWhen` parameter
458+
- [x] Define semantic predicates: `supportsGrouping`, `supportsColorField`, `supportsConditionalFormatting`, `supportsRowActions`, `supportsGenericGroupBy`
459+
- [x] 103 schema tests pass (updated field key lists, visibleWhen predicates for all view types, removed field verification)
460+
- [x] 136 ViewConfigPanel interaction tests pass (removed tests for deleted fields)
461+
- [x] 10 config-sync integration tests pass
462+
446463
**Code Reduction:** ~1655 lines imperative → ~170 lines declarative wrapper + ~1100 lines schema factory + ~180 lines shared utils = **>50% net reduction in component code** with significantly improved maintainability
447464

448465
### P1.9 Console — Content Area Layout & Responsiveness

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

Lines changed: 6 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,21 +1250,19 @@ describe('ViewConfigPanel', () => {
12501250

12511251
// ── Appearance fields tests ──
12521252

1253-
it('renders new appearance fields: color, fieldTextColor, rowHeight, wrapHeaders, collapseAllByDefault', () => {
1253+
it('renders new appearance fields: color, rowHeight, wrapHeaders', () => {
12541254
render(
12551255
<ViewConfigPanel
12561256
open={true}
12571257
onClose={vi.fn()}
1258-
activeView={mockActiveView}
1258+
activeView={{ ...mockActiveView, groupBy: 'stage' }}
12591259
objectDef={mockObjectDef}
12601260
/>
12611261
);
12621262

12631263
expect(screen.getByTestId('appearance-color')).toBeInTheDocument();
1264-
expect(screen.getByTestId('appearance-fieldTextColor')).toBeInTheDocument();
12651264
expect(screen.getByTestId('appearance-rowHeight')).toBeInTheDocument();
12661265
expect(screen.getByTestId('toggle-wrapHeaders')).toBeInTheDocument();
1267-
expect(screen.getByTestId('toggle-collapseAllByDefault')).toBeInTheDocument();
12681266
});
12691267

12701268
it('changes row height via icon buttons', () => {
@@ -1346,16 +1344,15 @@ describe('ViewConfigPanel', () => {
13461344
);
13471345

13481346
expect(screen.getByTestId('data-groupBy')).toBeInTheDocument();
1349-
expect(screen.getByTestId('data-prefixField')).toBeInTheDocument();
13501347
});
13511348

1352-
it('changes groupBy and propagates to kanban type option', () => {
1349+
it('changes groupBy for grid view', () => {
13531350
const onViewUpdate = vi.fn();
13541351
render(
13551352
<ViewConfigPanel
13561353
open={true}
13571354
onClose={vi.fn()}
1358-
activeView={{ ...mockActiveView, type: 'kanban' }}
1355+
activeView={{ ...mockActiveView, type: 'grid' }}
13591356
objectDef={mockObjectDef}
13601357
onViewUpdate={onViewUpdate}
13611358
/>
@@ -1365,7 +1362,6 @@ describe('ViewConfigPanel', () => {
13651362
fireEvent.change(groupBySelect, { target: { value: 'stage' } });
13661363

13671364
expect(onViewUpdate).toHaveBeenCalledWith('groupBy', 'stage');
1368-
expect(onViewUpdate).toHaveBeenCalledWith('kanban', expect.objectContaining({ groupByField: 'stage' }));
13691365
});
13701366

13711367
// ── Calendar endDateField test ──
@@ -2014,34 +2010,7 @@ describe('ViewConfigPanel', () => {
20142010
expect(onViewUpdate).toHaveBeenCalledWith('resizable', true);
20152011
});
20162012

2017-
it('renders density mode select in appearance section', () => {
2018-
render(
2019-
<ViewConfigPanel
2020-
open={true}
2021-
onClose={vi.fn()}
2022-
activeView={mockActiveView}
2023-
objectDef={mockObjectDef}
2024-
/>
2025-
);
2026-
2027-
expect(screen.getByTestId('select-densityMode')).toBeInTheDocument();
2028-
});
2029-
2030-
it('changes densityMode and calls onViewUpdate', () => {
2031-
const onViewUpdate = vi.fn();
2032-
render(
2033-
<ViewConfigPanel
2034-
open={true}
2035-
onClose={vi.fn()}
2036-
activeView={mockActiveView}
2037-
objectDef={mockObjectDef}
2038-
onViewUpdate={onViewUpdate}
2039-
/>
2040-
);
2041-
2042-
fireEvent.change(screen.getByTestId('select-densityMode'), { target: { value: 'compact' } });
2043-
expect(onViewUpdate).toHaveBeenCalledWith('densityMode', 'compact');
2044-
});
2013+
// densityMode tests removed — densityMode field was removed (redundant with rowHeight)
20452014

20462015
it('renders conditional formatting editor when expanded', () => {
20472016
render(
@@ -2436,22 +2405,6 @@ describe('ViewConfigPanel', () => {
24362405

24372406
// ── Spec alignment: toggle interaction tests for all switch fields ──
24382407

2439-
it('toggles collapseAllByDefault and calls onViewUpdate', () => {
2440-
const onViewUpdate = vi.fn();
2441-
render(
2442-
<ViewConfigPanel
2443-
open={true}
2444-
onClose={vi.fn()}
2445-
activeView={mockActiveView}
2446-
objectDef={mockObjectDef}
2447-
onViewUpdate={onViewUpdate}
2448-
/>
2449-
);
2450-
2451-
fireEvent.click(screen.getByTestId('toggle-collapseAllByDefault'));
2452-
expect(onViewUpdate).toHaveBeenCalledWith('collapseAllByDefault', true);
2453-
});
2454-
24552408
it('toggles showDescription and calls onViewUpdate', () => {
24562409
const onViewUpdate = vi.fn();
24572410
render(
@@ -2468,22 +2421,6 @@ describe('ViewConfigPanel', () => {
24682421
expect(onViewUpdate).toHaveBeenCalledWith('showDescription', false);
24692422
});
24702423

2471-
it('toggles clickIntoRecordDetails and calls onViewUpdate', () => {
2472-
const onViewUpdate = vi.fn();
2473-
render(
2474-
<ViewConfigPanel
2475-
open={true}
2476-
onClose={vi.fn()}
2477-
activeView={mockActiveView}
2478-
objectDef={mockObjectDef}
2479-
onViewUpdate={onViewUpdate}
2480-
/>
2481-
);
2482-
2483-
fireEvent.click(screen.getByTestId('toggle-clickIntoRecordDetails'));
2484-
expect(onViewUpdate).toHaveBeenCalledWith('clickIntoRecordDetails', false);
2485-
});
2486-
24872424
it('toggles addDeleteRecordsInline and calls onViewUpdate', () => {
24882425
const onViewUpdate = vi.fn();
24892426
render(
@@ -2693,26 +2630,7 @@ describe('ViewConfigPanel', () => {
26932630
}));
26942631
});
26952632

2696-
// ── Boundary: densityMode enum selection ──
2697-
2698-
it('changes densityMode to all enum values', () => {
2699-
const onViewUpdate = vi.fn();
2700-
render(
2701-
<ViewConfigPanel
2702-
open={true}
2703-
onClose={vi.fn()}
2704-
activeView={mockActiveView}
2705-
objectDef={mockObjectDef}
2706-
onViewUpdate={onViewUpdate}
2707-
/>
2708-
);
2709-
2710-
const select = screen.getByTestId('select-densityMode');
2711-
['compact', 'comfortable', 'spacious'].forEach((mode) => {
2712-
fireEvent.change(select, { target: { value: mode } });
2713-
expect(onViewUpdate).toHaveBeenCalledWith('densityMode', mode);
2714-
});
2715-
});
2633+
// densityMode enum test removed — densityMode field was removed (redundant with rowHeight)
27162634

27172635
// ── Conditional rendering: addRecord sub-editor hidden when not enabled ──
27182636

0 commit comments

Comments
 (0)