Skip to content

Commit

Permalink
Proof of concept: hierarchical data
Browse files Browse the repository at this point in the history
  • Loading branch information
oandregal committed Nov 26, 2024
1 parent 8cd0c17 commit 6228887
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 1 deletion.
136 changes: 135 additions & 1 deletion packages/dataviews/src/dataviews-layouts/table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ interface TableColumnFieldProps< Item > {
item: Item;
isItemClickable: ( item: Item ) => boolean;
onClickItem: ( item: Item ) => void;
parent?: string;
level?: number;
}

interface TableColumnCombinedProps< Item > {
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -109,6 +115,8 @@ function TableColumn< Item >( {

function TableColumnField< Item >( {
primaryField,
parent,
level,
item,
field,
isItemClickable,
Expand All @@ -131,9 +139,17 @@ function TableColumnField< Item >( {
'dataviews-view-table__primary-field': isPrimaryField,
} ) }
>
{ isPrimaryField && level !== undefined && (
<span className="dataviews-view-table__level">
{ '— '.repeat( level ) }
</span>
) }
<div { ...clickableProps }>
<field.render { ...{ item } } />
</div>
{ isPrimaryField && parent && (
<span className="dataviews-view-table__parent">{ `Parent: ${ parent }` }</span>
) }
</div>
);
}
Expand All @@ -159,6 +175,8 @@ function TableColumnCombined< Item >( {
function TableRow< Item >( {
hasBulkActions,
item,
parent,
level,
actions,
fields,
id,
Expand Down Expand Up @@ -247,6 +265,8 @@ function TableRow< Item >( {
onClickItem={ onClickItem }
fields={ fields }
item={ item }
parent={ parent }
level={ level }
column={ column }
view={ view }
/>
Expand Down Expand Up @@ -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 (
<>
<table
Expand Down Expand Up @@ -418,10 +550,12 @@ function ViewTable< Item >( {
</thead>
<tbody>
{ hasData &&
data.map( ( item, index ) => (
rows.map( ( item, index ) => (
<TableRow
key={ getItemId( item ) }
item={ item }
parent={ getItemParent( item ) }
level={ getItemLevel( item ) }
hasBulkActions={ hasBulkActions }
actions={ actions }
fields={ fields }
Expand Down
5 changes: 5 additions & 0 deletions packages/dataviews/src/dataviews-layouts/table/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,11 @@
}
}
}

.dataviews-view-table__parent {
margin-left: $grid-unit-10;
background-color: #f0f0f0;
}
}

/* stylelint-disable-next-line scss/at-rule-no-unknown -- '@container' not globally permitted */
Expand Down
5 changes: 5 additions & 0 deletions packages/dataviews/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,11 @@ export interface ViewTable extends ViewBase {
* The density of the view.
*/
density?: Density;

/**
* The field to visualize hierarchical data.
*/
hierarchical?: string;
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const defaultLayouts = {
[ LAYOUT_TABLE ]: {
layout: {
primaryField: 'title',
hierarchical: 'parent',
styles: {
title: {
maxWidth: 300,
Expand All @@ -41,12 +42,14 @@ export const defaultLayouts = {
layout: {
mediaField: 'featured_media',
primaryField: 'title',
hierarchical: 'parent', // TODO: remove this
},
},
[ LAYOUT_LIST ]: {
layout: {
primaryField: 'title',
mediaField: 'featured_media',
hierarchical: 'parent', // TODO: remove this
},
},
};
Expand Down

0 comments on commit 6228887

Please sign in to comment.