diff --git a/ui100/package-lock.json b/ui100/package-lock.json
index afb9a6083..0c70c742b 100644
--- a/ui100/package-lock.json
+++ b/ui100/package-lock.json
@@ -15,6 +15,7 @@
"@mui/x-charts": "^7.23.2",
"@xyflow/react": "^12.3.5",
"d3-hierarchy": "^3.1.2",
+ "material-react-table": "^3.1.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router": "^7.0.1",
@@ -1414,6 +1415,73 @@
"robust-predicates": "^3.0.2"
}
},
+ "node_modules/@mui/x-date-pickers": {
+ "version": "7.23.3",
+ "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.23.3.tgz",
+ "integrity": "sha512-bjTYX/QzD5ZhVZNNnastMUS3j2Hy4p4IXmJgPJ0vKvQBvUdfEO+ZF42r3PJNNde0FVT1MmTzkmdTlz0JZ6ukdw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.25.7",
+ "@mui/utils": "^5.16.6 || ^6.0.0",
+ "@mui/x-internals": "7.23.0",
+ "@types/react-transition-group": "^4.4.11",
+ "clsx": "^2.1.1",
+ "prop-types": "^15.8.1",
+ "react-transition-group": "^4.4.5"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.9.0",
+ "@emotion/styled": "^11.8.1",
+ "@mui/material": "^5.15.14 || ^6.0.0",
+ "@mui/system": "^5.15.14 || ^6.0.0",
+ "date-fns": "^2.25.0 || ^3.2.0 || ^4.0.0",
+ "date-fns-jalali": "^2.13.0-0 || ^3.2.0-0",
+ "dayjs": "^1.10.7",
+ "luxon": "^3.0.2",
+ "moment": "^2.29.4",
+ "moment-hijri": "^2.1.2 || ^3.0.0",
+ "moment-jalaali": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/react": {
+ "optional": true
+ },
+ "@emotion/styled": {
+ "optional": true
+ },
+ "date-fns": {
+ "optional": true
+ },
+ "date-fns-jalali": {
+ "optional": true
+ },
+ "dayjs": {
+ "optional": true
+ },
+ "luxon": {
+ "optional": true
+ },
+ "moment": {
+ "optional": true
+ },
+ "moment-hijri": {
+ "optional": true
+ },
+ "moment-jalaali": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@mui/x-internals": {
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-7.23.0.tgz",
@@ -1806,6 +1874,82 @@
"win32"
]
},
+ "node_modules/@tanstack/match-sorter-utils": {
+ "version": "8.19.4",
+ "resolved": "https://registry.npmjs.org/@tanstack/match-sorter-utils/-/match-sorter-utils-8.19.4.tgz",
+ "integrity": "sha512-Wo1iKt2b9OT7d+YGhvEPD3DXvPv2etTusIMhMUoG7fbhmxcXCtIjJDEygy91Y2JFlwGyjqiBPRozme7UD8hoqg==",
+ "license": "MIT",
+ "dependencies": {
+ "remove-accents": "0.5.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ }
+ },
+ "node_modules/@tanstack/react-table": {
+ "version": "8.20.6",
+ "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.20.6.tgz",
+ "integrity": "sha512-w0jluT718MrOKthRcr2xsjqzx+oEM7B7s/XXyfs19ll++hlId3fjTm+B2zrR3ijpANpkzBAr15j1XGVOMxpggQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@tanstack/table-core": "8.20.5"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ },
+ "peerDependencies": {
+ "react": ">=16.8",
+ "react-dom": ">=16.8"
+ }
+ },
+ "node_modules/@tanstack/react-virtual": {
+ "version": "3.11.2",
+ "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.11.2.tgz",
+ "integrity": "sha512-OuFzMXPF4+xZgx8UzJha0AieuMihhhaWG0tCqpp6tDzlFwOmNBPYMuLOtMJ1Tr4pXLHmgjcWhG6RlknY2oNTdQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@tanstack/virtual-core": "3.11.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/@tanstack/table-core": {
+ "version": "8.20.5",
+ "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.20.5.tgz",
+ "integrity": "sha512-P9dF7XbibHph2PFRz8gfBKEXEY/HJPOhym8CHmjF8y3q5mWpKx9xtZapXQUWCgkqvsK0R46Azuz+VaxD4Xl+Tg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ }
+ },
+ "node_modules/@tanstack/virtual-core": {
+ "version": "3.11.2",
+ "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.11.2.tgz",
+ "integrity": "sha512-vTtpNt7mKCiZ1pwU9hfKPhpdVO2sVzFQsxoVBGtOSHxlrRRzYr8iQ2TlwbAcRYCcEiZ9ECAM8kBzH0v2+VzfKw==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ }
+ },
"node_modules/@types/babel__core": {
"version": "7.20.5",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
@@ -3337,6 +3481,16 @@
"node": ">= 0.4"
}
},
+ "node_modules/highlight-words": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/highlight-words/-/highlight-words-2.0.0.tgz",
+ "integrity": "sha512-If5n+IhSBRXTScE7wl16VPmd+44Vy7kof24EdqhjsZsDuHikpv1OCagVcJFpB4fS4UPUniedlWqrjIO8vWOsIQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 20",
+ "npm": ">= 9"
+ }
+ },
"node_modules/hoist-non-react-statics": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
@@ -3604,6 +3758,34 @@
"yallist": "^3.0.2"
}
},
+ "node_modules/material-react-table": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/material-react-table/-/material-react-table-3.1.0.tgz",
+ "integrity": "sha512-/zPn38QhxQE7mkwLex4CojX3UP2+/+/u7NVq7CHS5d6P8LdTteJPVYXVzym/uhaXzAzFB1ojsbP7zI/y6iUdtQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@tanstack/match-sorter-utils": "8.19.4",
+ "@tanstack/react-table": "8.20.6",
+ "@tanstack/react-virtual": "3.11.2",
+ "highlight-words": "2.0.0"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/kevinvandy"
+ },
+ "peerDependencies": {
+ "@emotion/react": ">=11.13",
+ "@emotion/styled": ">=11.13",
+ "@mui/icons-material": ">=6",
+ "@mui/material": ">=6",
+ "@mui/x-date-pickers": ">=7.15",
+ "react": ">=18.0",
+ "react-dom": ">=18.0"
+ }
+ },
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@@ -3997,6 +4179,12 @@
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
"license": "MIT"
},
+ "node_modules/remove-accents": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz",
+ "integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==",
+ "license": "MIT"
+ },
"node_modules/resolve": {
"version": "1.22.8",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
diff --git a/ui100/package.json b/ui100/package.json
index ed724f3cc..be0d86b1f 100644
--- a/ui100/package.json
+++ b/ui100/package.json
@@ -17,6 +17,7 @@
"@mui/x-charts": "^7.23.2",
"@xyflow/react": "^12.3.5",
"d3-hierarchy": "^3.1.2",
+ "material-react-table": "^3.1.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router": "^7.0.1",
diff --git a/ui100/src/ApiConsole.tsx b/ui100/src/ApiConsole.tsx
index 8c44020f3..6efa45656 100644
--- a/ui100/src/ApiConsole.tsx
+++ b/ui100/src/ApiConsole.tsx
@@ -9,7 +9,7 @@ import EnvironmentPanel from "./EnvironmentPanel.tsx";
import SharePanel from "./SharePanel.tsx";
import AccessPanel from "./AccessPanel.tsx";
import useStore from "./model/store.ts";
-import SearchPanel from "./SearchPanel.tsx";
+import TabularView from "./TabularView.tsx";
interface ApiConsoleProps {
logout: () => void;
@@ -32,7 +32,7 @@ const ApiConsole = ({ logout }: ApiConsoleProps) => {
if(showVisualizer) {
setMainPanel();
} else {
- setMainPanel();
+ setMainPanel();
}
}
}, []);
diff --git a/ui100/src/SearchPanel.tsx b/ui100/src/SearchPanel.tsx
deleted file mode 100644
index 6b70a8053..000000000
--- a/ui100/src/SearchPanel.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import {Paper} from "@mui/material";
-
-const SearchPanel = () => {
- return (
-
- SearchPanel
-
- );
-};
-
-export default SearchPanel;
\ No newline at end of file
diff --git a/ui100/src/TabularView.tsx b/ui100/src/TabularView.tsx
new file mode 100644
index 000000000..a6ad2295f
--- /dev/null
+++ b/ui100/src/TabularView.tsx
@@ -0,0 +1,42 @@
+import {Box, Paper} from "@mui/material";
+import useStore from "./model/store.ts";
+import {MaterialReactTable, type MRT_ColumnDef, useMaterialReactTable} from "material-react-table";
+import {useMemo} from "react";
+import {Node} from "@xyflow/react";
+
+const data: Node[] = [];
+
+const TabularView = () => {
+ const overview = useStore((state) => state.overview);
+
+ const columns = useMemo[]>(
+ () => [
+ {
+ accessorKey: 'data.label',
+ header: 'Label'
+ },
+ {
+ accessorKey: 'type',
+ header: 'Type',
+ }
+ ],
+ [],
+ );
+
+ const table = useMaterialReactTable({
+ columns: columns,
+ data: overview.nodes,
+ });
+
+ console.log(overview.nodes);
+
+ return (
+
+
+
+
+
+ );
+};
+
+export default TabularView;
\ No newline at end of file
diff --git a/ui100/src/Visualizer.tsx b/ui100/src/Visualizer.tsx
index ff2fd5e98..0d0aa8beb 100644
--- a/ui100/src/Visualizer.tsx
+++ b/ui100/src/Visualizer.tsx
@@ -8,7 +8,8 @@ import {
ReactFlow,
ReactFlowProvider,
useEdgesState,
- useNodesState
+ useNodesState,
+ useStore as xyStore
} from "@xyflow/react";
import {VisualOverview} from "./model/visualizer.ts";
import {useEffect} from "react";
@@ -30,8 +31,15 @@ const nodeTypes = {
const Visualizer = () => {
const overview = useStore((state) => state.overview);
const updateSelectedNode = useStore((state) => state.updateSelectedNode);
+ const viewport = useStore((state) => state.viewport);
+ const updateViewport = useStore((state) => state.updateViewport);
const [nodes, setNodes, onNodesChange] = useNodesState([]);
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
+ const transform = xyStore((store) => store.transform);
+
+ useEffect(() => {
+ updateViewport(transform);
+ }, [transform]);
const onSelectionChange = ({ nodes }) => {
if(nodes.length > 0) {
@@ -77,6 +85,12 @@ const Visualizer = () => {
}
}, [overview]);
+ const defaultViewport = {
+ x: viewport[0],
+ y: viewport[1],
+ zoom: viewport[2],
+ }
+
return (
{
onEdgesChange={onEdgesChange}
onSelectionChange={onSelectionChange}
nodesDraggable={false}
- fitView
+ defaultViewport={defaultViewport}
>
diff --git a/ui100/src/model/store.ts b/ui100/src/model/store.ts
index d7af47538..e04beab47 100644
--- a/ui100/src/model/store.ts
+++ b/ui100/src/model/store.ts
@@ -9,13 +9,15 @@ type StoreState = {
environments: Array;
overview: VisualOverview;
selectedNode: Node;
+ viewport: Array;
};
type StoreAction = {
updateUser: (user: StoreState['user']) => void,
updateOverview: (vov: StoreState['overview']) => void,
updateEnvironments: (environments: StoreState['environments']) => void,
- updateSelectedNode: (selectedNode: StoreState['selectedNode']) => void
+ updateSelectedNode: (selectedNode: StoreState['selectedNode']) => void,
+ updateViewport: (viewport: StoreState['viewport']) => void,
};
const useStore = create((set) => ({
@@ -23,10 +25,12 @@ const useStore = create((set) => ({
overview: new VisualOverview(),
environments: new Array(),
selectedNode: null,
+ viewport: [0, 0, 1.5],
updateUser: (user) => set({user: user}),
updateOverview: (vov) => set({overview: vov}),
updateEnvironments: (environments) => set({environments: environments}),
- updateSelectedNode: (selectedNode) => set({selectedNode: selectedNode})
+ updateSelectedNode: (selectedNode) => set({selectedNode: selectedNode}),
+ updateViewport: (viewport) => set({viewport: viewport})
}));
export default useStore;