Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add nodeData attribute to Tree rows #1537

Merged
merged 2 commits into from
Nov 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion vuu-ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export class TreeDataSource extends BaseDataSource {
this._config = {
...this._config,
columns,
groupBy: columns,
groupBy: columns.slice(1),
};
}
}
Expand Down
27 changes: 26 additions & 1 deletion vuu-ui/packages/vuu-datatable/src/tree-table/TreeTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@ import { Table } from "@finos/vuu-table";
import { TreeDataSource } from "@finos/vuu-data-local";
import { useEffect, useMemo, useRef } from "react";
import { TableConfig } from "@finos/vuu-table-types";
import { TreeSourceNode } from "@finos/vuu-utils";
import {
isRowSelected,
metadataKeys,
type RowToObjectMapper,
type TreeSourceNode,
} from "@finos/vuu-utils";

const { DEPTH, IS_LEAF, KEY, IDX } = metadataKeys;

export interface TreeTableProps
extends Omit<TableProps, "config" | "dataSource"> {
Expand All @@ -14,6 +21,23 @@ export interface TreeTableProps
source: TreeSourceNode[];
}

const rowToTreeNodeObject: RowToObjectMapper = (row, columnMap) => {
const { [IS_LEAF]: isLeaf, [KEY]: key, [IDX]: index, [DEPTH]: depth } = row;
const firstColIdx = columnMap.nodeData;
const labelColIdx = firstColIdx + depth;

return {
key,
index,
isGroupRow: !isLeaf,
isSelected: isRowSelected(row),
data: {
label: row[labelColIdx],
nodeData: row[firstColIdx],
},
};
};

export const TreeTable = ({
config,
source: sourceProp,
Expand Down Expand Up @@ -54,6 +78,7 @@ export const TreeTable = ({
dataSource={dataSourceRef.current}
groupToggleTarget="toggle-icon"
navigationStyle="tree"
rowToObject={rowToTreeNodeObject}
showColumnHeaderMenus={false}
selectionModel="single"
selectionBookendWidth={0}
Expand Down
17 changes: 16 additions & 1 deletion vuu-ui/packages/vuu-table/src/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
dragStrategy,
reduceSizeHeight,
} from "@finos/vuu-ui-controls";
import { metadataKeys, useId } from "@finos/vuu-utils";
import { metadataKeys, RowToObjectMapper, useId } from "@finos/vuu-utils";
import { useForkRef } from "@salt-ds/core";
import { useComponentCssInjection } from "@salt-ds/styles";
import { useWindow } from "@salt-ds/window";
Expand Down Expand Up @@ -174,6 +174,17 @@ export interface TableProps
onSelectionChange?: SelectionChangeHandler;
renderBufferSize?: number;

/**
* When a row is selected and onSelect provided, onSelect will be invoked with a
* DataSourceRowObject, derived from the internal representation of a data row,
* DataSourceRow. The data attribute of DataSourceRowObject is a simple map of
* column.name : value.
* This prop allows a custom function to be provided to make the conversion from
* DataSourceRow to DataSourceRowObject. It will very rarely be needed. It is
* used by the Treetable.
*/
rowToObject?: RowToObjectMapper;

/**
* Only applicable to grouped data. If there are selected rows which are not top-level
* items and group items above are not already expanded, expand all group items in
Expand Down Expand Up @@ -267,6 +278,7 @@ const TableCore = ({
renderBufferSize = 0,
revealSelected,
rowHeight,
rowToObject,
scrollingApiRef,
selectionBookendWidth = 0,
selectionModel = "extended",
Expand Down Expand Up @@ -339,6 +351,7 @@ const TableCore = ({
renderBufferSize,
revealSelected,
rowHeight,
rowToObject,
scrollingApiRef,
selectionBookendWidth,
selectionModel,
Expand Down Expand Up @@ -511,6 +524,7 @@ export const Table = forwardRef(function Table(
renderBufferSize,
revealSelected,
rowHeight: rowHeightProp,
rowToObject,
scrollingApiRef,
selectionBookendWidth = 4,
selectionModel,
Expand Down Expand Up @@ -656,6 +670,7 @@ export const Table = forwardRef(function Table(
}
revealSelected={revealSelected}
rowHeight={rowHeight}
rowToObject={rowToObject}
scrollingApiRef={scrollingApiRef}
selectionBookendWidth={selectionBookendWidth}
selectionModel={selectionModel}
Expand Down
10 changes: 6 additions & 4 deletions vuu-ui/packages/vuu-table/src/useTable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export interface TableHookProps
| "onRowClick"
| "renderBufferSize"
| "revealSelected"
| "rowToObject"
| "scrollingApiRef"
| "selectionBookendWidth"
| "showColumnHeaders"
Expand Down Expand Up @@ -173,6 +174,7 @@ export const useTable = ({
renderBufferSize = 0,
revealSelected,
rowHeight = 20,
rowToObject = asDataSourceRowObject,
scrollingApiRef,
selectionBookendWidth,
selectionModel,
Expand Down Expand Up @@ -666,10 +668,10 @@ export const useTable = ({
const handleSelect = useCallback<TableRowSelectHandlerInternal>(
(row) => {
if (onSelect) {
onSelect(row === null ? null : asDataSourceRowObject(row, columnMap));
onSelect(row === null ? null : rowToObject(row, columnMap));
}
},
[columnMap, onSelect],
[columnMap, onSelect, rowToObject],
);

const {
Expand Down Expand Up @@ -707,9 +709,9 @@ export const useTable = ({
const handleRowClick = useCallback<TableRowClickHandlerInternal>(
(evt, row, rangeSelect, keepExistingSelection) => {
selectionHookOnRowClick(evt, row, rangeSelect, keepExistingSelection);
onRowClickProp?.(evt, asDataSourceRowObject(row, columnMap));
onRowClickProp?.(evt, rowToObject(row, columnMap));
},
[columnMap, onRowClickProp, selectionHookOnRowClick],
[columnMap, onRowClickProp, rowToObject, selectionHookOnRowClick],
);

const handleKeyDown = useCallback(
Expand Down
7 changes: 6 additions & 1 deletion vuu-ui/packages/vuu-utils/src/row-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,14 @@ export const virtualRowPositioning = (
true,
];

export const asDataSourceRowObject = (
export type RowToObjectMapper = (
row: DataSourceRow,
columnMap: ColumnMap,
) => DataSourceRowObject;

export const asDataSourceRowObject: RowToObjectMapper = (
row,
columnMap,
): DataSourceRowObject => {
const { [IS_LEAF]: isLeaf, [KEY]: key, [IDX]: index } = row;

Expand Down
16 changes: 3 additions & 13 deletions vuu-ui/packages/vuu-utils/src/tree-types.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,8 @@
export interface TreeSourceNode {
export interface TreeSourceNode<T = unknown> {
nodeData?: T;
id: string;
icon?: string;
header?: boolean;
label: string;
childNodes?: TreeSourceNode[];
}
export interface NormalisedTreeSourceNode extends TreeSourceNode {
childNodes?: NormalisedTreeSourceNode[];
count: number;
expanded?: boolean;
index: number;
level: number;
}

export interface NonLeafNode extends NormalisedTreeSourceNode {
childNodes: NormalisedTreeSourceNode[];
childNodes?: TreeSourceNode<T>[];
}
8 changes: 6 additions & 2 deletions vuu-ui/packages/vuu-utils/src/tree-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ export const treeToDataSourceRows = (
const columns: ColumnDescriptor[] = [];

columns.push(
{
name: "nodeData",
type: "json",
},
{
getIcon: iconProvider?.getIcon,
name: "Level 1",
Expand Down Expand Up @@ -52,11 +56,11 @@ const addChildValues = (
});
}
for (let i = 0; i < treeSourceNodes.length; i++, index.value += 1) {
const { childNodes, icon, label } = treeSourceNodes[i];
const { childNodes, icon, label, nodeData } = treeSourceNodes[i];
const blanks = Array(depth - 1).fill("");
const fullKey = `${keyBase}|${label}`;
// prettier-ignore
const row = [index.value, index.value, false,false,depth,0,fullKey,0, ...blanks, label ] as DataSourceRow;
const row = [index.value, index.value, false,false,depth,0,fullKey,0, nodeData, ...blanks, label ] as DataSourceRow;
if (icon) {
iconProvider?.setIcon(fullKey, icon);
}
Expand Down
34 changes: 34 additions & 0 deletions vuu-ui/showcase/src/examples/DataTable/TreeTable.examples.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { TreeTable } from "@finos/vuu-datatable";

import showcaseData from "./Tree.data";
import { useMemo } from "react";
import { TreeSourceNode } from "@finos/vuu-utils";
import { TableRowSelectHandler } from "@finos/vuu-table-types";

let displaySequence = 1;

Expand Down Expand Up @@ -45,3 +48,34 @@ export const ShowcaseTreeSelectedAutoReveal = () => {
);
};
ShowcaseTreeSelectedAutoReveal.displaySequence = displaySequence++;

const addDataNodes = (
treeNodes: TreeSourceNode[],
index = { value: 0 },
): Array<TreeSourceNode<string>> => {
return treeNodes?.map<TreeSourceNode<string>>(({ childNodes, ...rest }) => ({
...rest,
nodeData: `node-${index.value++}`,
childNodes: childNodes ? addDataNodes(childNodes, index) : undefined,
}));
};

export const ShowcaseTreeNodeOptions = () => {
const source = useMemo(() => {
return addDataNodes(showcaseData);
}, []);

const onSelect: TableRowSelectHandler = (row) => {
console.log({ row });
};

return (
<TreeTable
onSelect={onSelect}
rowHeight={30}
showColumnHeaders={false}
source={source}
/>
);
};
ShowcaseTreeNodeOptions.displaySequence = displaySequence++;
4 changes: 2 additions & 2 deletions vuu-ui/tools/vuu-showcase/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { IFrame } from "./components";
import {
ExamplesModule,
byDisplaySequence,
keyFromPath,
keysFromPath,
loadTheme,
pathFromKey,
} from "./showcase-utils";
Expand Down Expand Up @@ -148,7 +148,7 @@ export const App = ({ stories }: AppProps) => {
className="ShowcaseNav"
data-resizeable
rowHeight={30}
defaultSelectedKeyValues={[keyFromPath(pathname)]}
defaultSelectedKeyValues={keysFromPath(pathname)}
// selected={[pathname.slice(1)]}
showColumnHeaders={false}
onSelect={handleChange}
Expand Down
9 changes: 7 additions & 2 deletions vuu-ui/tools/vuu-showcase/src/showcase-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,13 @@ export const byDisplaySequence = ([, f1]: VuuTuple, [, f2]: VuuTuple) => {
};

export const pathFromKey = (key: string) => key.slice(5).split("|").join("/");
export const keyFromPath = (path: string) =>
`$root${path.split("/").join("|")}`;
export const keysFromPath = (path: string) => {
if (path === "/") {
return undefined;
} else {
return [`$root${path.split("/").join("|")}`];
}
};

export const pathToExample = (path: string): [string[], string] => {
const endOfImportPath = path.lastIndexOf("/");
Expand Down
Loading