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

feat: Added Treeview feature #558

Merged
merged 3 commits into from
Mar 7, 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
152 changes: 140 additions & 12 deletions package-lock.json

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

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
"type": "commonjs",
"dependencies": {
"@applitools/eyes-playwright": "^1.23.6",
"@types/git-username": "^1.0.5",
"@emotion/react": "^11.11.3",
"@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.15.12",
"@mui/lab": "^5.0.0-alpha.167",
"@mui/material": "^5.15.11",
"@mui/x-date-pickers": "^6.19.5",
"@mui/x-tree-view": "^6.17.0",
"@types/git-username": "^1.0.5",
"@types/leaflet.markercluster": "^1.5.2",
"@vitejs/plugin-react-swc": "^3.6.0",
"antd": "^5.14.2",
Expand Down
91 changes: 91 additions & 0 deletions src/pages/components/CustomTreeView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { TreeView } from '@mui/x-tree-view/TreeView';

Check failure on line 1 in src/pages/components/CustomTreeView.tsx

View workflow job for this annotation

GitHub Actions / lint

Delete `;`
import { TreeItem } from '@mui/x-tree-view/TreeItem';

Check failure on line 2 in src/pages/components/CustomTreeView.tsx

View workflow job for this annotation

GitHub Actions / lint

Delete `;`
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';

Check failure on line 3 in src/pages/components/CustomTreeView.tsx

View workflow job for this annotation

GitHub Actions / lint

Delete `;`
import ChevronRightIcon from '@mui/icons-material/ChevronRight';

Check failure on line 4 in src/pages/components/CustomTreeView.tsx

View workflow job for this annotation

GitHub Actions / lint

Delete `;`

interface BaseTreeNode {
id: string;

Check failure on line 7 in src/pages/components/CustomTreeView.tsx

View workflow job for this annotation

GitHub Actions / lint

Delete `;`
name: string;

Check failure on line 8 in src/pages/components/CustomTreeView.tsx

View workflow job for this annotation

GitHub Actions / lint

Delete `;`
}

// Generic TreeNode interface with additional properties
interface TreeNode<T extends BaseTreeNode> extends BaseTreeNode {
children?: TreeNode<T>[];

Check failure on line 13 in src/pages/components/CustomTreeView.tsx

View workflow job for this annotation

GitHub Actions / lint

Delete `;`
// You can now include additional properties from T
}

// Generic CustomTreeViewProps interface
interface CustomTreeViewProps<T> {
data: T;

Check failure on line 19 in src/pages/components/CustomTreeView.tsx

View workflow job for this annotation

GitHub Actions / lint

Delete `;`
name: string;

Check failure on line 20 in src/pages/components/CustomTreeView.tsx

View workflow job for this annotation

GitHub Actions / lint

Delete `;`
id: string;

Check failure on line 21 in src/pages/components/CustomTreeView.tsx

View workflow job for this annotation

GitHub Actions / lint

Delete `;`
}

// A utility function to transform any object into a TreeNode structure
const objectToTreeNode = (
obj: any,

Check warning on line 26 in src/pages/components/CustomTreeView.tsx

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
key: string = 'root',
nodeId: string = '0'
): TreeNode<BaseTreeNode> => {
const isPrimitive = (value: any) => value !== Object(value) || value === null;

Check warning on line 30 in src/pages/components/CustomTreeView.tsx

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type

const children = Object.keys(obj).map((k, index) => {
const value = obj[k];
if (isPrimitive(value)) {
// Handle primitive types directly
return {
id: `${nodeId}-${index}`,
name: `${k}: ${value}`,
};
} else if (Array.isArray(value)) {
// If it's an array, create a node that lists all elements
return {
id: `${nodeId}-${index}`,
name: k,
children: value.map((item, itemIndex) => {
// Handle primitive items in the array directly
if (isPrimitive(item)) {
return {
id: `${nodeId}-${index}-${itemIndex}`,
name: `${item}`,
};
}
// Recursively handle objects in the array
return objectToTreeNode(item, k, `${nodeId}-${index}-${itemIndex}`);
}),
};
} else {
// Recursively handle objects
return objectToTreeNode(value, k, `${nodeId}-${index}`);
}
});

return {
id: nodeId,
name: obj.name || key,
children: children.length ? children : undefined,
};
};

// Render tree function utilizing the TreeNode interface
const renderTree = <T extends BaseTreeNode>(nodes: TreeNode<T>): JSX.Element => (
<TreeItem key={nodes.id} nodeId={nodes.id} label={nodes.name}>
{nodes.children?.map((node) => renderTree(node))}
</TreeItem>
);

// CustomTreeView component using TypeScript
const CustomTreeView = <T,>({ data, name, id }: CustomTreeViewProps<T>) => {
const dataAsTreeNode = objectToTreeNode({ id, name, children: [data] });
return (
<TreeView
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
defaultEndIcon={<div style={{ width: 24 }} />}
>
{renderTree(dataAsTreeNode)}
</TreeView>
);
};

export default CustomTreeView;
50 changes: 50 additions & 0 deletions src/pages/components/CutomTreeView.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// CustomTreeView.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import CustomTreeView from './CustomTreeView';
import '../../shared/shared.css'; // Assuming you have some shared styles

// Define a base type for your tree nodes, considering the object structure you provided earlier
interface CustomTreeNode {
id: string;
name: string;
children?: CustomTreeNode[];
}

// Example data for the story
const exampleData = {
id: 'root',
name: 'Root Node',
children: [
{
id: '1',
name: 'Child Node 1',
children: [
{ id: '1-1', name: 'Grandchild Node 1-1' },
{ id: '1-2', name: 'Grandchild Node 1-2' },
],
},
{
id: '2',
name: 'Child Node 2',
},
],
};

const meta: Meta<typeof CustomTreeView> = {
title: 'Components/CustomTreeView',
component: CustomTreeView,
parameters: {
layout: 'centered',
},
tags: ['tree', 'view', 'react', 'mui'], // Adjust tags as needed
} satisfies Meta<typeof CustomTreeView>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Default: Story = {
args: {
data: exampleData, // Using the example data for the default story
},
};
Loading
Loading