From 6228887843f58973f3bd10c1138fb0d99e70489b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Thu, 24 Oct 2024 17:11:17 +0200 Subject: [PATCH] Proof of concept: hierarchical data --- .../src/dataviews-layouts/table/index.tsx | 136 +++++++++++++++++- .../src/dataviews-layouts/table/style.scss | 5 + packages/dataviews/src/types.ts | 5 + .../sidebar-dataviews/default-views.js | 3 + 4 files changed, 148 insertions(+), 1 deletion(-) diff --git a/packages/dataviews/src/dataviews-layouts/table/index.tsx b/packages/dataviews/src/dataviews-layouts/table/index.tsx index 7f93a4c14a7dd..7df010b83b33f 100644 --- a/packages/dataviews/src/dataviews-layouts/table/index.tsx +++ b/packages/dataviews/src/dataviews-layouts/table/index.tsx @@ -43,6 +43,8 @@ interface TableColumnFieldProps< Item > { item: Item; isItemClickable: ( item: Item ) => boolean; onClickItem: ( item: Item ) => void; + parent?: string; + level?: number; } interface TableColumnCombinedProps< Item > { @@ -59,6 +61,8 @@ interface TableColumnProps< Item > { primaryField?: NormalizedField< Item >; fields: NormalizedField< Item >[]; item: Item; + parent?: string; + level?: number; column: string; view: ViewTableType; isItemClickable: ( item: Item ) => boolean; @@ -68,6 +72,8 @@ interface TableColumnProps< Item > { interface TableRowProps< Item > { hasBulkActions: boolean; item: Item; + parent?: string; + level?: number; actions: Action< Item >[]; fields: NormalizedField< Item >[]; id: string; @@ -109,6 +115,8 @@ function TableColumn< Item >( { function TableColumnField< Item >( { primaryField, + parent, + level, item, field, isItemClickable, @@ -131,9 +139,17 @@ function TableColumnField< Item >( { 'dataviews-view-table__primary-field': isPrimaryField, } ) } > + { isPrimaryField && level !== undefined && ( + + { '— '.repeat( level ) } + + ) }
+ { isPrimaryField && parent && ( + { `Parent: ${ parent }` } + ) } ); } @@ -159,6 +175,8 @@ function TableColumnCombined< Item >( { function TableRow< Item >( { hasBulkActions, item, + parent, + level, actions, fields, id, @@ -247,6 +265,8 @@ function TableRow< Item >( { onClickItem={ onClickItem } fields={ fields } item={ item } + parent={ parent } + level={ level } column={ column } view={ view } /> @@ -329,6 +349,118 @@ function ViewTable< Item >( { ( field ) => field.id === view.layout?.primaryField ); + const getPrimaryFieldValue = ( item: Item ) => { + return primaryField?.getValue( { item } ); + }; + + const getAllDescendants = ( + index: number, + children: { [ key: number ]: Item[] }, + levels: number[], + levelIndex: number + ): Item[] => { + const nested: Item[] = []; + + if ( children.hasOwnProperty( index ) ) { + children[ index ]?.forEach( ( child: Item ) => { + const itemId = +getItemId( child ); + nested.push( child ); + levels[ itemId ] = levelIndex; + nested.push( + ...getAllDescendants( + itemId, + children, + levels, + levelIndex + 1 + ) + ); + } ); + } + + return nested; + }; + + const rows: Item[] = []; + const topLevelItemIds: number[] = []; + const nestedItemIds: number[] = []; + const orphans: number[] = []; + const children: { [ key: number ]: Item[] } = {}; + const primaryFieldValues: string[] = []; + const levels: number[] = []; + if ( !! view.layout?.hierarchical ) { + const hierarchicalField = view.layout?.hierarchical; + data.forEach( ( item: Item ) => { + const parentId = ( item as Record< string, number > )[ + hierarchicalField + ]; + const itemId = +getItemId( item ); + if ( parentId === 0 ) { + topLevelItemIds.push( itemId ); + primaryFieldValues[ itemId ] = getPrimaryFieldValue( item ); + } else { + if ( ! children.hasOwnProperty( parentId ) ) { + children[ parentId ] = []; + } + nestedItemIds.push( itemId ); + children[ parentId ].push( item ); + primaryFieldValues[ itemId ] = getPrimaryFieldValue( item ); + } + } ); + const allIds = [ ...topLevelItemIds, ...nestedItemIds ]; + Object.keys( children ).forEach( ( key: string ) => { + const numericKey = +key; + if ( ! allIds.includes( numericKey ) ) { + children[ numericKey ].forEach( ( child ) => { + orphans.push( +getItemId( child ) ); + } ); + } + } ); + + data.forEach( ( item ) => { + const itemId = +getItemId( item ); + if ( + topLevelItemIds.includes( itemId ) || + orphans.includes( itemId ) + ) { + rows.push( item ); + levels[ itemId ] = 0; + rows.push( + ...getAllDescendants( itemId, children, levels, 1 ) + ); + } + } ); + } else { + rows.push( ...data ); + } + + const getItemLevel = ( item: Item ) => { + if ( ! view.layout?.hierarchical ) { + return; + } + + return levels[ +getItemId( item ) ]; + }; + + const getItemParent = ( item: Item ) => { + if ( ! view.layout?.hierarchical ) { + return; + } + + const parent = ( item as Record< string, any > )?.[ + view.layout?.hierarchical + ]; + + if ( parent === 0 ) { + return; + } + + if ( ! primaryFieldValues[ parent ] ) { + return; + } + + return primaryFieldValues[ parent ]; + }; + return ( <> ( { { hasData && - data.map( ( item, index ) => ( + rows.map( ( item, index ) => (