@@ -43,6 +43,42 @@ vi.mock('@object-ui/components', () => ({
4343 { ...props }
4444 />
4545 ) ,
46+ Checkbox : ( { checked, onCheckedChange, ...props } : any ) => (
47+ < input
48+ type = "checkbox"
49+ checked = { ! ! checked }
50+ onChange = { ( ) => onCheckedChange ?.( ! checked ) }
51+ { ...props }
52+ />
53+ ) ,
54+ FilterBuilder : ( { fields, value, onChange, ...props } : any ) => {
55+ let counter = 0 ;
56+ return (
57+ < div data-testid = "mock-filter-builder" data-field-count = { fields ?. length || 0 } data-condition-count = { value ?. conditions ?. length || 0 } >
58+ < button data-testid = "filter-builder-add" onClick = { ( ) => {
59+ const newConditions = [ ...( value ?. conditions || [ ] ) , { id : `mock-filter-${ Date . now ( ) } -${ ++ counter } ` , field : fields ?. [ 0 ] ?. value || '' , operator : 'equals' , value : '' } ] ;
60+ onChange ?.( { ...value , conditions : newConditions } ) ;
61+ } } > Add filter</ button >
62+ { value ?. conditions ?. map ( ( c : any , i : number ) => (
63+ < span key = { c . id || i } data-testid = { `filter-condition-${ i } ` } > { c . field } { c . operator } { String ( c . value ) } </ span >
64+ ) ) }
65+ </ div >
66+ ) ;
67+ } ,
68+ SortBuilder : ( { fields, value, onChange, ...props } : any ) => {
69+ let counter = 0 ;
70+ return (
71+ < div data-testid = "mock-sort-builder" data-field-count = { fields ?. length || 0 } data-sort-count = { value ?. length || 0 } >
72+ < button data-testid = "sort-builder-add" onClick = { ( ) => {
73+ const newItems = [ ...( value || [ ] ) , { id : `mock-sort-${ Date . now ( ) } -${ ++ counter } ` , field : fields ?. [ 0 ] ?. value || '' , order : 'asc' } ] ;
74+ onChange ?.( newItems ) ;
75+ } } > Add sort</ button >
76+ { value ?. map ( ( s : any , i : number ) => (
77+ < span key = { s . id || i } data-testid = { `sort-item-${ i } ` } > { s . field } { s . order } </ span >
78+ ) ) }
79+ </ div >
80+ ) ;
81+ } ,
4682} ) ) ;
4783
4884const mockActiveView = {
@@ -140,7 +176,7 @@ describe('ViewConfigPanel', () => {
140176 expect ( screen . getByText ( 'console.objectView.noDescription' ) ) . toBeInTheDocument ( ) ;
141177 } ) ;
142178
143- it ( 'displays column count ' , ( ) => {
179+ it ( 'displays column checkboxes for each field ' , ( ) => {
144180 render (
145181 < ViewConfigPanel
146182 open = { true }
@@ -150,8 +186,15 @@ describe('ViewConfigPanel', () => {
150186 />
151187 ) ;
152188
153- // 3 columns configured
154- expect ( screen . getByText ( 'console.objectView.columnsConfigured' . replace ( '{{count}}' , '3' ) ) ) . toBeInTheDocument ( ) ;
189+ // 3 fields → 3 checkboxes
190+ expect ( screen . getByTestId ( 'column-selector' ) ) . toBeInTheDocument ( ) ;
191+ expect ( screen . getByTestId ( 'col-checkbox-name' ) ) . toBeInTheDocument ( ) ;
192+ expect ( screen . getByTestId ( 'col-checkbox-stage' ) ) . toBeInTheDocument ( ) ;
193+ expect ( screen . getByTestId ( 'col-checkbox-amount' ) ) . toBeInTheDocument ( ) ;
194+ // Columns in activeView should be checked
195+ expect ( screen . getByTestId ( 'col-checkbox-name' ) ) . toBeChecked ( ) ;
196+ expect ( screen . getByTestId ( 'col-checkbox-stage' ) ) . toBeChecked ( ) ;
197+ expect ( screen . getByTestId ( 'col-checkbox-amount' ) ) . toBeChecked ( ) ;
155198 } ) ;
156199
157200 it ( 'displays object source name' , ( ) => {
@@ -225,7 +268,7 @@ describe('ViewConfigPanel', () => {
225268 expect ( screen . getByTestId ( 'view-type-select' ) ) . toHaveValue ( 'kanban' ) ;
226269 } ) ;
227270
228- it ( 'shows "None" for empty filters and columns ' , ( ) => {
271+ it ( 'shows inline builders with zero items for empty view ' , ( ) => {
229272 render (
230273 < ViewConfigPanel
231274 open = { true }
@@ -235,9 +278,10 @@ describe('ViewConfigPanel', () => {
235278 />
236279 ) ;
237280
238- // Should show "None" for columns, filters
239- const noneTexts = screen . getAllByText ( 'console.objectView.none' ) ;
240- expect ( noneTexts . length ) . toBeGreaterThanOrEqual ( 2 ) ;
281+ // FilterBuilder should have 0 conditions
282+ expect ( screen . getByTestId ( 'mock-filter-builder' ) ) . toHaveAttribute ( 'data-condition-count' , '0' ) ;
283+ // SortBuilder should have 0 items
284+ expect ( screen . getByTestId ( 'mock-sort-builder' ) ) . toHaveAttribute ( 'data-sort-count' , '0' ) ;
241285 } ) ;
242286
243287 it ( 'has correct ARIA attributes when open' , ( ) => {
@@ -403,62 +447,85 @@ describe('ViewConfigPanel', () => {
403447 expect ( onViewUpdate ) . toHaveBeenCalledWith ( 'type' , 'kanban' ) ;
404448 } ) ;
405449
406- it ( 'calls onOpenEditor when clicking columns row' , ( ) => {
407- const onOpenEditor = vi . fn ( ) ;
450+ it ( 'renders inline FilterBuilder with correct conditions from activeView' , ( ) => {
408451 render (
409452 < ViewConfigPanel
410453 open = { true }
411454 onClose = { vi . fn ( ) }
412455 activeView = { mockActiveView }
413456 objectDef = { mockObjectDef }
414- onOpenEditor = { onOpenEditor }
415457 />
416458 ) ;
417459
418- // Click the columns row — it's a button with the columns label
419- const columnsRow = screen . getByText ( 'console.objectView.columns' ) . closest ( 'button' ) ;
420- expect ( columnsRow ) . toBeTruthy ( ) ;
421- fireEvent . click ( columnsRow ! ) ;
422-
423- expect ( onOpenEditor ) . toHaveBeenCalledWith ( 'columns' ) ;
460+ const fb = screen . getByTestId ( 'mock-filter-builder' ) ;
461+ expect ( fb ) . toHaveAttribute ( 'data-condition-count' , '1' ) ;
462+ expect ( fb ) . toHaveAttribute ( 'data-field-count' , '3' ) ;
463+ expect ( screen . getByTestId ( 'filter-condition-0' ) ) . toHaveTextContent ( 'stage = active' ) ;
424464 } ) ;
425465
426- it ( 'calls onOpenEditor when clicking filters row' , ( ) => {
427- const onOpenEditor = vi . fn ( ) ;
466+ it ( 'renders inline SortBuilder with correct items from activeView' , ( ) => {
428467 render (
429468 < ViewConfigPanel
430469 open = { true }
431470 onClose = { vi . fn ( ) }
432471 activeView = { mockActiveView }
433472 objectDef = { mockObjectDef }
434- onOpenEditor = { onOpenEditor }
435473 />
436474 ) ;
437475
438- const filterRow = screen . getByText ( 'console.objectView.filterBy' ) . closest ( 'button' ) ;
439- expect ( filterRow ) . toBeTruthy ( ) ;
440- fireEvent . click ( filterRow ! ) ;
476+ const sb = screen . getByTestId ( 'mock-sort-builder' ) ;
477+ expect ( sb ) . toHaveAttribute ( 'data-sort-count' , '1' ) ;
478+ expect ( sb ) . toHaveAttribute ( 'data-field-count' , '3' ) ;
479+ expect ( screen . getByTestId ( 'sort-item-0' ) ) . toHaveTextContent ( 'name asc' ) ;
480+ } ) ;
441481
442- expect ( onOpenEditor ) . toHaveBeenCalledWith ( 'filters' ) ;
482+ it ( 'updates draft when adding a filter via FilterBuilder' , ( ) => {
483+ const onViewUpdate = vi . fn ( ) ;
484+ render (
485+ < ViewConfigPanel
486+ open = { true }
487+ onClose = { vi . fn ( ) }
488+ activeView = { { id : 'empty' , label : 'Empty' , type : 'grid' } }
489+ objectDef = { mockObjectDef }
490+ onViewUpdate = { onViewUpdate }
491+ />
492+ ) ;
493+
494+ fireEvent . click ( screen . getByTestId ( 'filter-builder-add' ) ) ;
495+ expect ( onViewUpdate ) . toHaveBeenCalledWith ( 'filter' , expect . any ( Array ) ) ;
443496 } ) ;
444497
445- it ( 'calls onOpenEditor when clicking sort row ' , ( ) => {
446- const onOpenEditor = vi . fn ( ) ;
498+ it ( 'updates draft when adding a sort via SortBuilder ' , ( ) => {
499+ const onViewUpdate = vi . fn ( ) ;
447500 render (
448501 < ViewConfigPanel
449502 open = { true }
450503 onClose = { vi . fn ( ) }
451- activeView = { mockActiveView }
504+ activeView = { { id : 'empty' , label : 'Empty' , type : 'grid' } }
452505 objectDef = { mockObjectDef }
453- onOpenEditor = { onOpenEditor }
506+ onViewUpdate = { onViewUpdate }
454507 />
455508 ) ;
456509
457- const sortRow = screen . getByText ( 'console.objectView.sortBy' ) . closest ( 'button' ) ;
458- expect ( sortRow ) . toBeTruthy ( ) ;
459- fireEvent . click ( sortRow ! ) ;
510+ fireEvent . click ( screen . getByTestId ( 'sort-builder-add' ) ) ;
511+ expect ( onViewUpdate ) . toHaveBeenCalledWith ( 'sort' , expect . any ( Array ) ) ;
512+ } ) ;
513+
514+ it ( 'toggles column checkbox and calls onViewUpdate with updated columns' , ( ) => {
515+ const onViewUpdate = vi . fn ( ) ;
516+ render (
517+ < ViewConfigPanel
518+ open = { true }
519+ onClose = { vi . fn ( ) }
520+ activeView = { mockActiveView }
521+ objectDef = { mockObjectDef }
522+ onViewUpdate = { onViewUpdate }
523+ />
524+ ) ;
460525
461- expect ( onOpenEditor ) . toHaveBeenCalledWith ( 'sort' ) ;
526+ // Uncheck the 'stage' column
527+ fireEvent . click ( screen . getByTestId ( 'col-checkbox-stage' ) ) ;
528+ expect ( onViewUpdate ) . toHaveBeenCalledWith ( 'columns' , [ 'name' , 'amount' ] ) ;
462529 } ) ;
463530
464531 it ( 'saves draft via onSave when Save button is clicked' , ( ) => {
0 commit comments