mirror of
https://github.com/20kaushik02/spotify-manager-web.git
synced 2025-12-06 07:54:07 +00:00
mmm
This commit is contained in:
parent
6733a3be8e
commit
090ba0b085
9
package-lock.json
generated
9
package-lock.json
generated
@ -18,6 +18,7 @@
|
||||
"axios": "^1.7.9",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-icons": "^5.4.0",
|
||||
"react-router-dom": "^7.1.1",
|
||||
"react-toastify": "^11.0.2",
|
||||
"web-vitals": "^4.2.4"
|
||||
@ -14582,6 +14583,14 @@
|
||||
"integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/react-icons": {
|
||||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.4.0.tgz",
|
||||
"integrity": "sha512-7eltJxgVt7X64oHh6wSWNwwbKTCtMfK35hcjvJS0yxEAhPM8oUKdS3+kqaW1vicIltw+kR2unHaa12S9pPALoQ==",
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
"axios": "^1.7.9",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-icons": "^5.4.0",
|
||||
"react-router-dom": "^7.1.1",
|
||||
"react-toastify": "^11.0.2",
|
||||
"web-vitals": "^4.2.4"
|
||||
|
||||
@ -1,4 +1,8 @@
|
||||
.btn_wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: var(--mb-2);
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import React, { useCallback, useContext, useEffect } from "react";
|
||||
import React, { useCallback, useContext, useEffect, useState } from "react";
|
||||
import {
|
||||
ReactFlow,
|
||||
Controls,
|
||||
Background,
|
||||
useNodesState,
|
||||
useEdgesState,
|
||||
addEdge,
|
||||
applyNodeChanges,
|
||||
applyEdgeChanges,
|
||||
useReactFlow,
|
||||
MarkerType,
|
||||
BackgroundVariant,
|
||||
@ -15,6 +15,8 @@ import {
|
||||
type ReactFlowInstance,
|
||||
type Node,
|
||||
type Edge,
|
||||
type OnNodesChange,
|
||||
type OnEdgesChange,
|
||||
type OnConnect,
|
||||
} from "@xyflow/react";
|
||||
import Dagre, { type GraphLabel } from "@dagrejs/dagre";
|
||||
@ -22,6 +24,9 @@ import Dagre, { type GraphLabel } from "@dagrejs/dagre";
|
||||
import "@xyflow/react/dist/style.css";
|
||||
import styles from "./Graph.module.css";
|
||||
|
||||
import { IoIosGitNetwork } from "react-icons/io";
|
||||
import { WiCloudRefresh } from "react-icons/wi";
|
||||
|
||||
import {
|
||||
showErrorToastNotification,
|
||||
showInfoToastNotification,
|
||||
@ -77,20 +82,31 @@ const proOptions: ProOptions = { hideAttribution: true };
|
||||
const Graph = () => {
|
||||
const refreshAuth = useContext(RefreshAuthContext);
|
||||
const flowInstance = useReactFlow();
|
||||
const [playlistNodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
||||
const [linkEdges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
||||
const [playlistNodes, setPlaylistNodes] = useState<Node[]>(initialNodes);
|
||||
const [linkEdges, setLinkEdges] = useState<Edge[]>(initialEdges);
|
||||
|
||||
const onFlowInit = (instance: ReactFlowInstance) => {
|
||||
const onFlowInit = (_instance: ReactFlowInstance) => {
|
||||
console.debug("flow loaded");
|
||||
};
|
||||
|
||||
const onNodesChange: OnNodesChange = useCallback(
|
||||
(changes) => setPlaylistNodes((nds) => applyNodeChanges(changes, nds)),
|
||||
[setPlaylistNodes]
|
||||
);
|
||||
const onEdgesChange: OnEdgesChange = useCallback(
|
||||
(changes) => setLinkEdges((eds) => applyEdgeChanges(changes, eds)),
|
||||
[setLinkEdges]
|
||||
);
|
||||
|
||||
const onConnect: OnConnect = useCallback(
|
||||
(params) => {
|
||||
setEdges((eds) => addEdge(params, eds));
|
||||
console.debug("new connection");
|
||||
console.debug(params);
|
||||
(connection) => {
|
||||
setLinkEdges((eds) => addEdge(connection, eds));
|
||||
console.debug(
|
||||
`new connection: ${connection.source} -> ${connection.target}`
|
||||
);
|
||||
// call API to create link
|
||||
},
|
||||
[setEdges]
|
||||
[setLinkEdges]
|
||||
);
|
||||
|
||||
type getLayoutedElementsOpts = {
|
||||
@ -137,7 +153,7 @@ const Graph = () => {
|
||||
edges: [],
|
||||
};
|
||||
|
||||
finalLayout.edges = edges;
|
||||
finalLayout.edges = [...edges];
|
||||
finalLayout.nodes.push(
|
||||
...connectedNodes.map((node) => {
|
||||
const position = g.node(node.id);
|
||||
@ -176,23 +192,25 @@ const Graph = () => {
|
||||
direction,
|
||||
});
|
||||
|
||||
setNodes([...layouted.nodes]);
|
||||
setEdges([...layouted.edges]);
|
||||
setPlaylistNodes([...layouted.nodes]);
|
||||
setLinkEdges([...layouted.edges]);
|
||||
|
||||
setTimeout(flowInstance.fitView);
|
||||
console.debug("layout applied");
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const fetchGraph = async () => {
|
||||
const fetchGraph = useCallback(async () => {
|
||||
const resp = await apiFetchGraph();
|
||||
if (resp === undefined) {
|
||||
showErrorToastNotification("Please try again after sometime");
|
||||
return;
|
||||
}
|
||||
if (resp.status === 200) {
|
||||
console.debug(
|
||||
`graph fetched with ${resp.data.playlists?.length} nodes and ${resp.data.links?.length} edges`
|
||||
);
|
||||
// place playlist nodes
|
||||
setNodes(
|
||||
setPlaylistNodes(
|
||||
resp.data.playlists?.map((pl, idx) => {
|
||||
return {
|
||||
id: `${pl.playlistID}`,
|
||||
@ -214,7 +232,7 @@ const Graph = () => {
|
||||
}) ?? []
|
||||
);
|
||||
// connect links
|
||||
setEdges(
|
||||
setLinkEdges(
|
||||
resp.data.links?.map((link, idx) => {
|
||||
return {
|
||||
id: `${idx}`,
|
||||
@ -231,13 +249,26 @@ const Graph = () => {
|
||||
return;
|
||||
}
|
||||
if (resp.status === 401) {
|
||||
refreshAuth();
|
||||
await refreshAuth();
|
||||
}
|
||||
showErrorToastNotification(resp.data.message);
|
||||
return;
|
||||
}, [refreshAuth]);
|
||||
|
||||
const onArrange = () => {
|
||||
arrangeLayout("TB");
|
||||
};
|
||||
|
||||
const onRefresh = async () => {
|
||||
await fetchGraph();
|
||||
arrangeLayout("TB");
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchGraph();
|
||||
}, [refreshAuth, setEdges, setNodes]);
|
||||
// TODO: how to invoke async and sync fns in order correctly inside useEffect?
|
||||
// onRefresh();
|
||||
}, [fetchGraph]);
|
||||
|
||||
return (
|
||||
<div className={styles.graph_wrapper}>
|
||||
@ -262,7 +293,14 @@ const Graph = () => {
|
||||
{/* </Panel> */}
|
||||
</ReactFlow>
|
||||
<div className={styles.operations_wrapper}>
|
||||
<Button onClickMethod={() => arrangeLayout("TB")}>Arrange</Button>
|
||||
<Button onClickMethod={onRefresh}>
|
||||
<WiCloudRefresh size={36} />
|
||||
Refresh
|
||||
</Button>
|
||||
<Button onClickMethod={onArrange}>
|
||||
<IoIosGitNetwork size={36} />
|
||||
Arrange
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user