Skip to content

Commit

Permalink
feat: Render database tree #1841 (#2017)
Browse files Browse the repository at this point in the history
### What problem does this PR solve?

feat: Render database tree #1841

### Type of change

- [x] New Feature (non-breaking change which adds functionality)
  • Loading branch information
cike8899 authored Oct 11, 2024
1 parent fc3c067 commit 2e4c4a9
Show file tree
Hide file tree
Showing 15 changed files with 481 additions and 17 deletions.
12 changes: 3 additions & 9 deletions gui/app/(dashboard)/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,7 @@ export const showTable = async ({

export const showConfigs = async () => {
try {
const x = await get(
`${ApiUrl.configs}`
);
const x = await get(`${ApiUrl.configs}`);
return x;
} catch (error) {
console.log('🚀 ~ error:', error);
Expand All @@ -144,9 +142,7 @@ export const showConfigs = async () => {

export const showVariables = async () => {
try {
const x = await get(
`${ApiUrl.variables}/global`
);
const x = await get(`${ApiUrl.variables}/global`);
return x;
} catch (error) {
console.log('🚀 ~ error:', error);
Expand All @@ -155,9 +151,7 @@ export const showVariables = async () => {

export const showCurrentNode = async () => {
try {
const x = await get(
`${ApiUrl.variables}/global`
);
const x = await get(`${ApiUrl.variables}/global`);
return x;
} catch (error) {
console.log('🚀 ~ error:', error);
Expand Down
57 changes: 57 additions & 0 deletions gui/app/(dashboard)/database/constants.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import ColumnIcon from '/public/column.svg';
import IndexIcon from '/public/index.svg';
import SegmentIcon from '/public/segment.svg';

export enum Leaf {
Columns = 'Columns',
Index = 'Index',
Segments = 'Segments'
}

export const LeafIconMap = {
[Leaf.Columns]: <ColumnIcon className="h-4 w-4"></ColumnIcon>,
[Leaf.Index]: <IndexIcon className="h-4 w-4"></IndexIcon>,
[Leaf.Segments]: <SegmentIcon className="h-4 w-4"></SegmentIcon>
};

export const initialData = [
{
name: '',
id: 0,
children: [1, 2, 3],
parent: null
},
{
name: 'Fruits',
children: [],
id: 1,
parent: 0,
isBranch: true
},
{
name: 'Drinks',
children: [4, 5],
id: 2,
parent: 0,
isBranch: true
},
{
name: 'Vegetables',
children: [],
id: 3,
parent: 0,
isBranch: true
},
{
name: 'Pine colada',
children: [],
id: 4,
parent: 2
},
{
name: 'Water',
children: [],
id: 5,
parent: 2
}
];
144 changes: 144 additions & 0 deletions gui/app/(dashboard)/database/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { useRouter } from 'next/navigation';
import { useCallback, useEffect, useRef, useState } from 'react';
import { listDatabase, listTable } from '../actions';
import { initialData } from './constants';
import { TreeNode, TreeParentId } from './interface';
import { buildLeafData, getParentIdById, updateTreeData } from './utils';

export const useHandleClickTreeName = () => {
const router = useRouter();

const handleClickTreeName = useCallback(
({
level,
name,
parent,
data
}: {
level: number;
name: string;
parent: TreeParentId;
data: TreeNode[];
}) =>
() => {
if (level === 3) {
const databaseId = getParentIdById(data, parent);
if (databaseId) {
router.push(`/database/${databaseId}/table/${parent}?tab=${name}`);
}
}
},
[]
);

return { handleClickTreeName };
};

export const useBuildTreeData = () => {
const loadedAlertElement = useRef(null);
const [data, setData] = useState<TreeNode[]>(initialData);
const [nodesAlreadyLoaded, setNodesAlreadyLoaded] = useState<any[]>([]);

const fetchDatabases = useCallback(async () => {
const ret = await listDatabase();
if (ret.databases.length > 0) {
setData((value) =>
updateTreeData(
value,
0,
ret.databases.map((x: string) => ({
name: x,
children: [],
id: x,
parent: 0,
isBranch: true
}))
)
);
}
}, []);

const fetchTables = useCallback(async (databaseName: string) => {
const ret = await listTable(databaseName);
if (ret?.tables?.length > 0) {
setData((value) => {
const tablePropertyList: TreeNode[] = [];
const tableList = ret.tables.map((x: string) => {
const leafs = buildLeafData(x);
tablePropertyList.push(...leafs);

return {
name: x,
children: leafs.map((x) => x.id),
id: x,
parent: databaseName,
isBranch: true
};
});

return [
...updateTreeData(value, databaseName, tableList),
...tablePropertyList
];
});
}
}, []);

useEffect(() => {
fetchDatabases();
}, [fetchDatabases]);

const onLoadData = async ({ element }: { element: TreeNode }) => {
if (element.children.length > 0) {
return;
}

await fetchTables(element.id as string);

return undefined;
// return new Promise((resolve) => {
// setTimeout(() => {
// setData((value) =>
// updateTreeData(value, element.id, [
// {
// name: `Child Node ${value.length}`,
// children: [],
// id: value.length,
// parent: element.id,
// isBranch: true
// },
// {
// name: 'Another child Node',
// children: [],
// id: value.length + 1,
// parent: element.id
// }
// ])
// );
// resolve(undefined);
// }, 1000);
// });
};

const wrappedOnLoadData = async (props: any) => {
const nodeHasNoChildData = props.element.children.length === 0;
const nodeHasAlreadyBeenLoaded = nodesAlreadyLoaded.find(
(e) => e.id === props.element.id
);

await onLoadData(props);

if (nodeHasNoChildData && !nodeHasAlreadyBeenLoaded) {
const el: any = loadedAlertElement.current;
setNodesAlreadyLoaded([...nodesAlreadyLoaded, props.element]);
el && (el.innerHTML = `${props.element.name} loaded`);

// Clearing aria-live region so loaded node alerts no longer appear in DOM
setTimeout(() => {
el && (el.innerHTML = '');
}, 5000);
}
};

return { wrappedOnLoadData, data, loadedAlertElement };
};
9 changes: 9 additions & 0 deletions gui/app/(dashboard)/database/interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export type TreeParentId = string | number | null;

export interface TreeNode {
name: string;
id: string | number;
children: Array<string | number>;
parent: TreeParentId;
isBranch?: boolean;
}
13 changes: 7 additions & 6 deletions gui/app/(dashboard)/database/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import SideMenu, { MenuItem } from '@/components/ui/side-menu';
import { MenuItem } from '@/components/ui/side-menu';
import {
Table,
TableBody,
Expand All @@ -8,7 +8,7 @@ import {
TableRow
} from '@/components/ui/table';
import { listDatabase, listTable } from '../actions';
import { InfinityContextMenuContent } from '../tables/context-menu';
import AsyncTree from './tree';

async function InfinityTable() {
const tables = await listTable('default_db');
Expand Down Expand Up @@ -70,16 +70,17 @@ export default async function DatabaseLayout({
}

return (
<div className="flex divide-x ">
<section className="w-40">
<SideMenu
<div className="flex divide-x h-full">
<section className="w-1/4">
{/* <SideMenu
items={items}
contextMenuContent={(key: string) => (
<InfinityContextMenuContent
databaseName={key}
></InfinityContextMenuContent>
)}
></SideMenu>
></SideMenu> */}
<AsyncTree></AsyncTree>
</section>
<section className="flex-1 text-center">{children}</section>
</div>
Expand Down
2 changes: 1 addition & 1 deletion gui/app/(dashboard)/database/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export default async function DatabasePage() {
return <div>DatabasePage</div>;
return <div className="w-1/4 overflow-auto">DatabasePage</div>;
}
47 changes: 47 additions & 0 deletions gui/app/(dashboard)/database/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
@keyframes spinner {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}

.loading-icon {
animation: spinner 1.5s linear infinite;
margin-left: 5px;
}

.visually-hidden {
position: absolute;
clip-path: circle(0);
border: 0;
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
width: 1px;
white-space: nowrap;
}

.tree-node {
display: flex;
align-items: center;
cursor: pointer;
}

.tree-node:hover {
background: rgba(255, 255, 255, 0.1);
}

.tree-node--focused {
background-color: #d7d7d7;
}

.arrow--open {
transform: rotate(90deg);
}

.name {
margin-left: 6px;
}
Loading

0 comments on commit 2e4c4a9

Please sign in to comment.