mirror of
https://github.com/20kaushik02/spotify-manager-web.git
synced 2025-12-06 08:54:07 +00:00
mmm
This commit is contained in:
parent
4baedc3e60
commit
e15575ce80
@ -271,92 +271,97 @@ const Graph = () => {
|
|||||||
type getLayoutedElementsOpts = {
|
type getLayoutedElementsOpts = {
|
||||||
direction: rankdirType;
|
direction: rankdirType;
|
||||||
};
|
};
|
||||||
const getLayoutedElements = (
|
const getLayoutedElements = useCallback(
|
||||||
nodes: Node[],
|
(nodes: Node[], edges: Edge[], options: getLayoutedElementsOpts) => {
|
||||||
edges: Edge[],
|
const g = new Dagre.graphlib.Graph();
|
||||||
options: getLayoutedElementsOpts
|
g.setDefaultEdgeLabel(() => ({}));
|
||||||
) => {
|
g.setGraph({
|
||||||
const g = new Dagre.graphlib.Graph();
|
rankdir: options.direction,
|
||||||
g.setDefaultEdgeLabel(() => ({}));
|
nodesep: 100,
|
||||||
g.setGraph({
|
edgesep: 100,
|
||||||
rankdir: options.direction,
|
ranksep: 100,
|
||||||
nodesep: 100,
|
|
||||||
edgesep: 100,
|
|
||||||
ranksep: 100,
|
|
||||||
});
|
|
||||||
|
|
||||||
edges.forEach((edge) => g.setEdge(edge.source, edge.target));
|
|
||||||
|
|
||||||
const connectedNodesID = new Set(
|
|
||||||
edges.flatMap((edge) => [edge.source, edge.target])
|
|
||||||
);
|
|
||||||
const connectedNodes = nodes.filter((node) =>
|
|
||||||
connectedNodesID.has(node.id)
|
|
||||||
);
|
|
||||||
const unconnectedNodes = nodes.filter(
|
|
||||||
(node) => !connectedNodesID.has(node.id)
|
|
||||||
);
|
|
||||||
|
|
||||||
nodes.forEach((node) => {
|
|
||||||
g.setNode(node.id, {
|
|
||||||
...node,
|
|
||||||
width: node.measured?.width ?? 0,
|
|
||||||
height: node.measured?.height ?? 0,
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
Dagre.layout(g);
|
edges.forEach((edge) => g.setEdge(edge.source, edge.target));
|
||||||
|
|
||||||
let finalLayout: { nodes: Node[]; edges: Edge[] } = {
|
const connectedNodesID = new Set(
|
||||||
nodes: [],
|
edges.flatMap((edge) => [edge.source, edge.target])
|
||||||
edges: [],
|
);
|
||||||
};
|
const connectedNodes = nodes.filter((node) =>
|
||||||
|
connectedNodesID.has(node.id)
|
||||||
|
);
|
||||||
|
const unconnectedNodes = nodes.filter(
|
||||||
|
(node) => !connectedNodesID.has(node.id)
|
||||||
|
);
|
||||||
|
|
||||||
finalLayout.edges = [...edges];
|
nodes.forEach((node) => {
|
||||||
finalLayout.nodes.push(
|
g.setNode(node.id, {
|
||||||
...connectedNodes.map((node) => {
|
...node,
|
||||||
const position = g.node(node.id);
|
width: node.measured?.width ?? 0,
|
||||||
// We are shifting the dagre node position (anchor=center center) to the top left
|
height: node.measured?.height ?? 0,
|
||||||
// so it matches the React Flow node anchor point (top left).
|
});
|
||||||
const x = position.x - (node.measured?.width ?? 0) / 2;
|
});
|
||||||
const y = position.y - (node.measured?.height ?? 0) / 2;
|
|
||||||
|
|
||||||
return { ...node, position: { x, y } };
|
Dagre.layout(g);
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
finalLayout.nodes.push(
|
let finalLayout: { nodes: Node[]; edges: Edge[] } = {
|
||||||
...unconnectedNodes.map((node, idx) => {
|
nodes: [],
|
||||||
const position = {
|
edges: [],
|
||||||
x:
|
};
|
||||||
nodeOffsets.unconnected.origin.x +
|
|
||||||
Math.floor(idx / 20) * nodeOffsets.unconnected.scaling.x,
|
|
||||||
y:
|
|
||||||
nodeOffsets.unconnected.origin.y +
|
|
||||||
Math.floor(idx % 20) * nodeOffsets.unconnected.scaling.y,
|
|
||||||
};
|
|
||||||
const x = position.x - (node.measured?.width ?? 0) / 2;
|
|
||||||
const y = position.y - (node.measured?.height ?? 0) / 2;
|
|
||||||
|
|
||||||
return { ...node, position: { x, y } };
|
finalLayout.edges = [...edges];
|
||||||
})
|
finalLayout.nodes.push(
|
||||||
);
|
...connectedNodes.map((node) => {
|
||||||
|
const position = g.node(node.id);
|
||||||
|
// We are shifting the dagre node position (anchor=center center) to the top left
|
||||||
|
// so it matches the React Flow node anchor point (top left).
|
||||||
|
const x = position.x - (node.measured?.width ?? 0) / 2;
|
||||||
|
const y = position.y - (node.measured?.height ?? 0) / 2;
|
||||||
|
|
||||||
console.debug("layout generated");
|
return { ...node, position: { x, y } };
|
||||||
return finalLayout;
|
})
|
||||||
};
|
);
|
||||||
|
|
||||||
const arrangeLayout = (direction: rankdirType) => {
|
finalLayout.nodes.push(
|
||||||
const layouted = getLayoutedElements(playlistNodes, linkEdges, {
|
...unconnectedNodes.map((node, idx) => {
|
||||||
direction,
|
const position = {
|
||||||
});
|
x:
|
||||||
|
nodeOffsets.unconnected.origin.x +
|
||||||
|
Math.floor(idx / 20) * nodeOffsets.unconnected.scaling.x,
|
||||||
|
y:
|
||||||
|
nodeOffsets.unconnected.origin.y +
|
||||||
|
Math.floor(idx % 20) * nodeOffsets.unconnected.scaling.y,
|
||||||
|
};
|
||||||
|
const x = position.x - (node.measured?.width ?? 0) / 2;
|
||||||
|
const y = position.y - (node.measured?.height ?? 0) / 2;
|
||||||
|
|
||||||
setPlaylistNodes([...layouted.nodes]);
|
return { ...node, position: { x, y } };
|
||||||
setLinkEdges([...layouted.edges]);
|
})
|
||||||
|
);
|
||||||
|
|
||||||
setTimeout(flowInstance.fitView);
|
console.debug("layout generated");
|
||||||
console.debug("layout applied");
|
return finalLayout;
|
||||||
};
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
const arrangeLayout = useCallback(
|
||||||
|
(direction: rankdirType) => {
|
||||||
|
// TODO: race condition
|
||||||
|
// states not updated in time inside other functions that call this before they call this
|
||||||
|
// fix that
|
||||||
|
const layouted = getLayoutedElements(playlistNodes, linkEdges, {
|
||||||
|
direction,
|
||||||
|
});
|
||||||
|
|
||||||
|
setPlaylistNodes([...layouted.nodes]);
|
||||||
|
setLinkEdges([...layouted.edges]);
|
||||||
|
|
||||||
|
setTimeout(flowInstance.fitView);
|
||||||
|
console.debug("layout applied");
|
||||||
|
},
|
||||||
|
[playlistNodes, linkEdges, flowInstance, getLayoutedElements]
|
||||||
|
);
|
||||||
|
|
||||||
const fetchGraph = useCallback(async () => {
|
const fetchGraph = useCallback(async () => {
|
||||||
const resp = await APIWrapper({ apiFn: apiFetchGraph, refreshAuth });
|
const resp = await APIWrapper({ apiFn: apiFetchGraph, refreshAuth });
|
||||||
@ -364,7 +369,7 @@ const Graph = () => {
|
|||||||
`graph fetched with ${resp?.data.playlists?.length} nodes and ${resp?.data.links?.length} edges`
|
`graph fetched with ${resp?.data.playlists?.length} nodes and ${resp?.data.links?.length} edges`
|
||||||
);
|
);
|
||||||
// place playlist nodes
|
// place playlist nodes
|
||||||
setPlaylistNodes(
|
const newNodes =
|
||||||
resp?.data.playlists?.map((pl, idx) => {
|
resp?.data.playlists?.map((pl, idx) => {
|
||||||
return {
|
return {
|
||||||
id: `${pl.playlistID}`,
|
id: `${pl.playlistID}`,
|
||||||
@ -383,18 +388,18 @@ const Graph = () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}) ?? []
|
}) ?? [];
|
||||||
);
|
setPlaylistNodes(newNodes);
|
||||||
// connect links
|
// connect links
|
||||||
setLinkEdges(
|
const newEdges =
|
||||||
resp?.data.links?.map((link, idx) => {
|
resp?.data.links?.map((link, idx) => {
|
||||||
return {
|
return {
|
||||||
id: `${link.from}->${link.to}`,
|
id: `${link.from}->${link.to}`,
|
||||||
source: link.from,
|
source: link.from,
|
||||||
target: link.to,
|
target: link.to,
|
||||||
};
|
};
|
||||||
}) ?? []
|
}) ?? [];
|
||||||
);
|
setLinkEdges(newEdges);
|
||||||
showInfoToastNotification("Graph updated.");
|
showInfoToastNotification("Graph updated.");
|
||||||
}, [refreshAuth]);
|
}, [refreshAuth]);
|
||||||
|
|
||||||
@ -403,7 +408,7 @@ const Graph = () => {
|
|||||||
apiFn: apiUpdateUserData,
|
apiFn: apiUpdateUserData,
|
||||||
refreshAuth,
|
refreshAuth,
|
||||||
});
|
});
|
||||||
showInfoToastNotification("Spotify synced.");
|
showInfoToastNotification(resp?.data.message);
|
||||||
if (resp?.data.removedLinks)
|
if (resp?.data.removedLinks)
|
||||||
showWarnToastNotification(
|
showWarnToastNotification(
|
||||||
"Some links with deleted playlists were removed."
|
"Some links with deleted playlists were removed."
|
||||||
@ -413,7 +418,6 @@ const Graph = () => {
|
|||||||
|
|
||||||
const refreshGraph = async () => {
|
const refreshGraph = async () => {
|
||||||
await fetchGraph();
|
await fetchGraph();
|
||||||
arrangeLayout("TB");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user