Skip to content

Commit c259e3a

Browse files
committed
added the auto organize button
1 parent d428a2c commit c259e3a

File tree

4 files changed

+116
-1
lines changed

4 files changed

+116
-1
lines changed

package-lock.json

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"@vercel/speed-insights": "^1.2.0",
2222
"axios": "^1.12.0",
2323
"classnames": "^2.5.1",
24+
"dagre": "^0.8.5",
2425
"dexie": "^3.2.4",
2526
"dexie-react-hooks": "^1.1.7",
2627
"file-saver": "^2.0.5",

src/components/EditorHeader/ControlPanel.jsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ export default function ControlPanel({
119119
addRelationship,
120120
deleteRelationship,
121121
updateRelationship,
122+
autoArrangeTables,
122123
database,
123124
setDatabase,
124125
} = useDiagram();
@@ -253,6 +254,10 @@ export default function ControlPanel({
253254
});
254255
} else if (a.component === "self") {
255256
updateTable(a.tid, a.undo);
257+
} else if (a.component === "auto_arrange") {
258+
a.data.oldTables.forEach((oldTable) => {
259+
updateTable(oldTable.id, { x: oldTable.x, y: oldTable.y });
260+
});
256261
}
257262
} else if (a.element === ObjectType.RELATIONSHIP) {
258263
updateRelationship(a.rid, a.undo);
@@ -431,6 +436,10 @@ export default function ControlPanel({
431436
});
432437
} else if (a.component === "self") {
433438
updateTable(a.tid, a.redo, false);
439+
} else if (a.component === "auto_arrange") {
440+
a.data.newTables.forEach((newTable) => {
441+
updateTable(newTable.id, { x: newTable.x, y: newTable.y });
442+
});
434443
}
435444
} else if (a.element === ObjectType.RELATIONSHIP) {
436445
updateRelationship(a.rid, a.redo);
@@ -1820,6 +1829,14 @@ export default function ControlPanel({
18201829
<i className="fa-solid fa-circle-half-stroke" />
18211830
</button>
18221831
</Tooltip>
1832+
<Tooltip content={t("Auto_arrange")} position="bottom">
1833+
<button
1834+
className="py-1 px-2 hover-2 rounded-sm text-xl -mt-0.5"
1835+
onClick={autoArrangeTables}
1836+
>
1837+
<i className="fa-solid fa-table-cells" />
1838+
</button>
1839+
</Tooltip>
18231840
</div>
18241841
<button
18251842
onClick={() => invertLayout("header")}

src/context/DiagramContext.jsx

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
11
import { createContext, useState } from "react";
2-
import { Action, DB, ObjectType, defaultBlue } from "../data/constants";
2+
import {
3+
Action,
4+
DB,
5+
ObjectType,
6+
defaultBlue,
7+
tableWidth,
8+
tableFieldHeight,
9+
tableHeaderHeight,
10+
tableColorStripHeight,
11+
} from "../data/constants";
312
import { useTransform, useUndoRedo, useSelect } from "../hooks";
413
import { Toast } from "@douyinfe/semi-ui";
514
import { useTranslation } from "react-i18next";
615
import { nanoid } from "nanoid";
16+
import dagre from "dagre";
717

818
export const DiagramContext = createContext(null);
919

@@ -228,6 +238,72 @@ export default function DiagramContextProvider({ children }) {
228238
);
229239
};
230240

241+
const autoArrangeTables = () => {
242+
if (tables.length === 0) return;
243+
244+
const newGraph = new dagre.graphlib.Graph();
245+
246+
newGraph.setGraph({
247+
rankdir: "TB",
248+
nodesep: 100,
249+
ranksep: 120,
250+
marginx: 50,
251+
marginy: 50,
252+
});
253+
254+
newGraph.setDefaultEdgeLabel(() => ({}));
255+
256+
tables.forEach((table) => {
257+
const height =
258+
table.fields.length * tableFieldHeight +
259+
tableHeaderHeight +
260+
tableColorStripHeight;
261+
newGraph.setNode(table.id, {
262+
label: table.name,
263+
width: tableWidth,
264+
height: height,
265+
});
266+
});
267+
268+
relationships.forEach((rel) => {
269+
newGraph.setEdge(rel.startTableId, rel.endTableId);
270+
});
271+
272+
dagre.layout(newGraph);
273+
274+
const arrangedTables = tables.map((table) => {
275+
const node = newGraph.node(table.id);
276+
return {
277+
...table,
278+
x: Math.round(node.x - tableWidth / 2),
279+
y: Math.round(node.y - node.height / 2),
280+
};
281+
});
282+
283+
setTables(arrangedTables);
284+
285+
setUndoStack((prev) => [
286+
...prev,
287+
{
288+
action: Action.EDIT,
289+
element: ObjectType.TABLE,
290+
component: "auto_arrange",
291+
data: {
292+
oldTables: tables.map((t) => ({ id: t.id, x: t.x, y: t.y })),
293+
newTables: arrangedTables.map((t) => ({
294+
id: t.id,
295+
x: t.x,
296+
y: t.y,
297+
})),
298+
},
299+
message: t("auto_arrange_tables") || "Auto-arrange tables",
300+
},
301+
]);
302+
setRedoStack([]);
303+
304+
Toast.success(t("tables_arranged") || "Tables arranged successfully!");
305+
};
306+
231307
return (
232308
<DiagramContext.Provider
233309
value={{
@@ -243,6 +319,7 @@ export default function DiagramContextProvider({ children }) {
243319
addRelationship,
244320
deleteRelationship,
245321
updateRelationship,
322+
autoArrangeTables,
246323
database,
247324
setDatabase,
248325
tablesCount: tables.length,

0 commit comments

Comments
 (0)