@@ -51,6 +51,56 @@ describe('DashboardContainer schema', () => {
5151 } ) . success ,
5252 ) . toBe ( false ) ;
5353 } ) ;
54+
55+ it ( 'validates a tab container' , ( ) => {
56+ const result = DashboardContainerSchema . safeParse ( {
57+ id : 'tab-1' ,
58+ type : 'tab' ,
59+ title : 'Overview Tabs' ,
60+ collapsed : false ,
61+ } ) ;
62+ expect ( result . success ) . toBe ( true ) ;
63+ if ( result . success ) {
64+ expect ( result . data . type ) . toBe ( 'tab' ) ;
65+ }
66+ } ) ;
67+
68+ it ( 'validates a group container' , ( ) => {
69+ const result = DashboardContainerSchema . safeParse ( {
70+ id : 'group-1' ,
71+ type : 'group' ,
72+ title : 'Key Metrics' ,
73+ collapsed : false ,
74+ } ) ;
75+ expect ( result . success ) . toBe ( true ) ;
76+ if ( result . success ) {
77+ expect ( result . data . type ) . toBe ( 'group' ) ;
78+ }
79+ } ) ;
80+
81+ it ( 'validates a tab container with activeTabId' , ( ) => {
82+ const result = DashboardContainerSchema . safeParse ( {
83+ id : 'tab-1' ,
84+ type : 'tab' ,
85+ title : 'Tabs' ,
86+ collapsed : false ,
87+ activeTabId : 'sub-tab-1' ,
88+ } ) ;
89+ expect ( result . success ) . toBe ( true ) ;
90+ if ( result . success ) {
91+ expect ( result . data . activeTabId ) . toBe ( 'sub-tab-1' ) ;
92+ }
93+ } ) ;
94+
95+ it ( 'rejects an invalid container type' , ( ) => {
96+ const result = DashboardContainerSchema . safeParse ( {
97+ id : 'c-1' ,
98+ type : 'invalid' ,
99+ title : 'Bad Type' ,
100+ collapsed : false ,
101+ } ) ;
102+ expect ( result . success ) . toBe ( false ) ;
103+ } ) ;
54104} ) ;
55105
56106describe ( 'Tile schema with containerId' , ( ) => {
@@ -525,4 +575,105 @@ describe('section authoring operations', () => {
525575 expect ( result . tiles [ 0 ] . containerId ) . toBeUndefined ( ) ;
526576 } ) ;
527577 } ) ;
578+
579+ describe ( 'reorder sections' , ( ) => {
580+ function reorderSections (
581+ dashboard : SimpleDashboard ,
582+ fromIndex : number ,
583+ toIndex : number ,
584+ ) {
585+ if ( ! dashboard . containers ) return dashboard ;
586+ const containers = [ ...dashboard . containers ] ;
587+ const [ removed ] = containers . splice ( fromIndex , 1 ) ;
588+ containers . splice ( toIndex , 0 , removed ) ;
589+ return { ...dashboard , containers } ;
590+ }
591+
592+ it ( 'moves a section from first to last' , ( ) => {
593+ const dashboard : SimpleDashboard = {
594+ tiles : [ ] ,
595+ containers : [
596+ { id : 's1' , title : 'First' , collapsed : false } ,
597+ { id : 's2' , title : 'Second' , collapsed : false } ,
598+ { id : 's3' , title : 'Third' , collapsed : false } ,
599+ ] ,
600+ } ;
601+ const result = reorderSections ( dashboard , 0 , 2 ) ;
602+ expect ( result . containers ! . map ( c => c . id ) ) . toEqual ( [ 's2' , 's3' , 's1' ] ) ;
603+ } ) ;
604+
605+ it ( 'moves a section from last to first' , ( ) => {
606+ const dashboard : SimpleDashboard = {
607+ tiles : [ ] ,
608+ containers : [
609+ { id : 's1' , title : 'First' , collapsed : false } ,
610+ { id : 's2' , title : 'Second' , collapsed : false } ,
611+ { id : 's3' , title : 'Third' , collapsed : false } ,
612+ ] ,
613+ } ;
614+ const result = reorderSections ( dashboard , 2 , 0 ) ;
615+ expect ( result . containers ! . map ( c => c . id ) ) . toEqual ( [ 's3' , 's1' , 's2' ] ) ;
616+ } ) ;
617+
618+ it ( 'does not affect tiles when sections are reordered' , ( ) => {
619+ const dashboard : SimpleDashboard = {
620+ tiles : [
621+ { id : 'a' , containerId : 's1' } ,
622+ { id : 'b' , containerId : 's2' } ,
623+ ] ,
624+ containers : [
625+ { id : 's1' , title : 'First' , collapsed : false } ,
626+ { id : 's2' , title : 'Second' , collapsed : false } ,
627+ ] ,
628+ } ;
629+ const result = reorderSections ( dashboard , 0 , 1 ) ;
630+ expect ( result . tiles ) . toEqual ( dashboard . tiles ) ;
631+ expect ( result . containers ! . map ( c => c . id ) ) . toEqual ( [ 's2' , 's1' ] ) ;
632+ } ) ;
633+ } ) ;
634+
635+ describe ( 'group selected tiles' , ( ) => {
636+ function groupTilesIntoSection (
637+ dashboard : SimpleDashboard ,
638+ tileIds : string [ ] ,
639+ newSection : SimpleSection ,
640+ ) {
641+ const containers = [ ...( dashboard . containers ?? [ ] ) , newSection ] ;
642+ const tiles = dashboard . tiles . map ( t =>
643+ tileIds . includes ( t . id ) ? { ...t , containerId : newSection . id } : t ,
644+ ) ;
645+ return { ...dashboard , containers, tiles } ;
646+ }
647+
648+ it ( 'groups selected tiles into a new section' , ( ) => {
649+ const dashboard : SimpleDashboard = {
650+ tiles : [ { id : 'a' } , { id : 'b' } , { id : 'c' } ] ,
651+ } ;
652+ const result = groupTilesIntoSection ( dashboard , [ 'a' , 'c' ] , {
653+ id : 'new-s' ,
654+ title : 'New Section' ,
655+ collapsed : false ,
656+ } ) ;
657+ expect ( result . containers ) . toHaveLength ( 1 ) ;
658+ expect ( result . tiles . find ( t => t . id === 'a' ) ?. containerId ) . toBe ( 'new-s' ) ;
659+ expect ( result . tiles . find ( t => t . id === 'b' ) ?. containerId ) . toBeUndefined ( ) ;
660+ expect ( result . tiles . find ( t => t . id === 'c' ) ?. containerId ) . toBe ( 'new-s' ) ;
661+ } ) ;
662+
663+ it ( 'preserves existing sections when grouping' , ( ) => {
664+ const dashboard : SimpleDashboard = {
665+ tiles : [ { id : 'a' , containerId : 's1' } , { id : 'b' } , { id : 'c' } ] ,
666+ containers : [ { id : 's1' , title : 'Existing' , collapsed : false } ] ,
667+ } ;
668+ const result = groupTilesIntoSection ( dashboard , [ 'b' , 'c' ] , {
669+ id : 'new-s' ,
670+ title : 'Grouped' ,
671+ collapsed : false ,
672+ } ) ;
673+ expect ( result . containers ) . toHaveLength ( 2 ) ;
674+ expect ( result . tiles . find ( t => t . id === 'a' ) ?. containerId ) . toBe ( 's1' ) ;
675+ expect ( result . tiles . find ( t => t . id === 'b' ) ?. containerId ) . toBe ( 'new-s' ) ;
676+ expect ( result . tiles . find ( t => t . id === 'c' ) ?. containerId ) . toBe ( 'new-s' ) ;
677+ } ) ;
678+ } ) ;
528679} ) ;
0 commit comments