Skip to content

Commit 7dda27d

Browse files
author
zsen.liao
committed
[feature] 增加右键菜单, 增加编辑时可导入数据结构 findyourmagic#17
s
1 parent 2e647fd commit 7dda27d

File tree

8 files changed

+160
-29
lines changed

8 files changed

+160
-29
lines changed

components/context_menu.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { Menu, Item, Separator, Submenu, theme } from 'react-contexify';
2+
import 'react-contexify/dist/ReactContexify.css';
3+
4+
export default function ContextMenu(props) {
5+
return (
6+
<Menu id={props.menuId} animation="fade" theme={props.theme === 'dark' ? theme.dark : theme.light}>
7+
<Item
8+
onClick={({ triggerEvent }) => {
9+
props.addTable({ x: triggerEvent.clientX - 40, y: triggerEvent.clientY - 100 });
10+
}}
11+
>
12+
Add New Table
13+
</Item>
14+
<Submenu label="Import">
15+
<Item onClick={() => props.setImportType('DBML')}>
16+
DBML
17+
</Item>
18+
<Item onClick={() => props.setImportType('PostgreSQL')}>
19+
PostgreSQL
20+
</Item>
21+
<Item onClick={() => props.setImportType('MySQL')}>
22+
MySQL
23+
</Item>
24+
<Item onClick={() => props.setImportType('MSSQL')}>
25+
MSSQL
26+
</Item>
27+
</Submenu>
28+
<Separator />
29+
<Item onClick={() => props.saveGraph()}>Save</Item>
30+
<Submenu label="Export">
31+
<Item onClick={() => props.setCommand('dbml')}>
32+
DBML
33+
</Item>
34+
<Item onClick={() => props.setCommand('')}>
35+
PostgreSQL
36+
</Item>
37+
<Item onClick={() => props.setCommand('mysql')}>
38+
MySQL
39+
</Item>
40+
<Item onClick={() => props.setCommand('mssql')}>
41+
MSSQL
42+
</Item>
43+
</Submenu>
44+
</Menu>
45+
);
46+
}

components/import_modal.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,14 @@ const save = async ({
3838
* It's a modal that allows you to import a graph from a string
3939
* @returns Modal component
4040
*/
41-
export default function ImportModal({ importType, setImportType, addGraph, theme }) {
41+
export default function ImportModal({ importType, setImportType, addGraph, theme, handlerImportTable }) {
4242
const [value, setValue] = useState('');
4343

4444
const handleOk = async () => {
45-
if (!value) return;
45+
if (!value) {
46+
setImportType('');
47+
return;
48+
}
4649
try {
4750
const result = await Parser.parse(value, importType.toLowerCase());
4851
const graph = result.schemas[0];
@@ -54,7 +57,7 @@ export default function ImportModal({ importType, setImportType, addGraph, theme
5457
id,
5558
name: table.name,
5659
note: table.note,
57-
x: index * 220,
60+
x: index * 260,
5861
y: 20,
5962
fields: table.fields.map(field => {
6063
const fieldId = nanoid();
@@ -90,6 +93,14 @@ export default function ImportModal({ importType, setImportType, addGraph, theme
9093
}),
9194
};
9295
});
96+
97+
if (handlerImportTable) {
98+
handlerImportTable({ tableDict, linkDict });
99+
setValue('');
100+
setImportType('');
101+
return;
102+
}
103+
93104
const graphId = nanoid();
94105
await save({
95106
id: graphId,
@@ -131,6 +142,7 @@ export default function ImportModal({ importType, setImportType, addGraph, theme
131142
cancelText="Close"
132143
onCancel={() => setImportType('')}
133144
style={{ width: 'auto' }}
145+
unmountOnExit
134146
>
135147
<Editor
136148
language={importType === 'DBML' ? 'apex' : 'sql'}

components/link_path.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ export default function LinkPath(props) {
8989
const midX = x1 - (x1 - x) / 2;
9090
const midY = y1 - (y1 - y) / 2;
9191

92+
const handlerContextMenu = e => {
93+
e.preventDefault();
94+
e.stopPropagation();
95+
};
96+
9297
return (
9398
<>
9499
<path
@@ -111,6 +116,7 @@ export default function LinkPath(props) {
111116
fieldId: source.fieldId,
112117
});
113118
}}
119+
onContextMenu={handlerContextMenu}
114120
>
115121
<div
116122
style={{ cursor: 'pointer', userSelect: 'none' }}
@@ -130,6 +136,7 @@ export default function LinkPath(props) {
130136
fieldId: target.fieldId,
131137
});
132138
}}
139+
onContextMenu={handlerContextMenu}
133140
>
134141
<div
135142
style={{ cursor: 'pointer', userSelect: 'none' }}

components/nav.js

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,27 +20,6 @@ import { db } from '../data/db';
2020
* @returns A Nav component that takes in a title, a save button, a demo button, a clear button, an export button
2121
*/
2222
export default function Nav(props) {
23-
const save = async () => {
24-
const id = new URLSearchParams(global.location.search).get('id');
25-
try {
26-
await db.graphs.put({
27-
id,
28-
tableDict: props.tableDict,
29-
linkDict: props.linkDict,
30-
box: props.box,
31-
name: props.name,
32-
updatedAt: new Date().valueOf(),
33-
});
34-
Notification.success({
35-
title: 'Save success',
36-
});
37-
} catch (e) {
38-
Notification.error({
39-
title: 'Save failed',
40-
});
41-
}
42-
};
43-
4423
return (
4524
<nav className="nav">
4625
<div>
@@ -61,7 +40,7 @@ export default function Nav(props) {
6140
}}
6241
/>
6342
<Button
64-
onClick={save}
43+
onClick={() => props.saveGraph()}
6544
type="primary"
6645
status="success"
6746
size="mini"

components/table.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ export default function Table(props) {
2727
handlerRemoveField,
2828
} = props;
2929

30+
const handlerContextMenu = e => {
31+
e.preventDefault();
32+
e.stopPropagation();
33+
};
34+
3035
const RenderTableTips = ({ field }) => (
3136
<div className="table-tips">
3237
<div className="head">
@@ -63,6 +68,7 @@ export default function Table(props) {
6368
// onMouseUp={(e) => {
6469
// tableMouseUpHandler(e, table);
6570
// }}
71+
onContextMenu={handlerContextMenu}
6672
>
6773
<div className="table" style={{ borderColor: table.theme }}>
6874
<div className="table-title" style={{ background: table.theme }}>

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"next": "12.2.2",
2020
"npm": "^8.7.0",
2121
"react": "18.2.0",
22+
"react-contexify": "^5.0.0",
2223
"react-dom": "18.2.0",
2324
"sass": "^1.50.0"
2425
},

pages/graphs/detail.js

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,30 @@
11
import Head from 'next/head';
22
import dynamic from 'next/dynamic';
33
import { useState, useRef, useMemo } from 'react';
4-
import { Drawer, Modal, Tag } from '@arco-design/web-react';
4+
import { Drawer, Modal, Notification, Tag } from '@arco-design/web-react';
55
import { nanoid } from 'nanoid';
6+
import { useContextMenu } from 'react-contexify';
7+
68
import TableForm from '../../components/table_form';
79
import FieldForm from '../../components/field_form';
810
import LinkPath from '../../components/link_path';
911
import LinkModal from '../../components/link_modal';
1012
import Nav from '../../components/nav';
1113
import Table from '../../components/table';
14+
import ContextMenu from '../../components/context_menu';
1215
import useGraphState from '../../hooks/use-graph-state';
16+
import { db } from '../../data/db';
17+
import exportSQL from '../../utils/export-sql';
1318

1419
const ExportModal = dynamic(() => import('../../components/export_modal'), {
1520
ssr: false,
1621
});
22+
const ImportModal = dynamic(() => import('../../components/import_modal'), {
23+
ssr: false,
24+
});
25+
26+
27+
const MENU_ID = 'svg-menu';
1728

1829
export default function Home() {
1930
const {
@@ -61,6 +72,17 @@ export default function Home() {
6172
}
6273
};
6374

75+
const [importType, setImportType] = useState('');
76+
77+
const { show } = useContextMenu({
78+
id: MENU_ID,
79+
});
80+
81+
const contextMenuHandler = e => {
82+
e.preventDefault();
83+
show(e);
84+
};
85+
6486
/**
6587
* It sets the moving table to the table that was clicked on, and sets the mode to moving
6688
* @param e - the event object
@@ -239,19 +261,43 @@ export default function Home() {
239261
});
240262
};
241263

264+
const saveGraph = async () => {
265+
const id = new URLSearchParams(global.location.search).get('id');
266+
try {
267+
await db.graphs.put({
268+
id,
269+
tableDict,
270+
linkDict,
271+
box,
272+
name,
273+
updatedAt: new Date().valueOf(),
274+
});
275+
Notification.success({
276+
title: 'Save success',
277+
});
278+
} catch (e) {
279+
Notification.error({
280+
title: 'Save failed',
281+
});
282+
}
283+
};
284+
242285
/**
243286
* It creates a new table object and adds it to the table dictionary
244287
*/
245-
const addTable = () => {
288+
const addTable = ({
289+
x = box.x + box.w / 2 - 200 + tables.length * 20,
290+
y = box.y + box.h / 2 - 200 + tables.length * 20
291+
}) => {
246292
setTableDict(state => {
247293
const id = nanoid();
248294
return {
249295
...state,
250296
[id]: {
251297
id,
252298
name: `Table Name ${tables.length + 1}`,
253-
x: box.x + box.w / 2 - 200 + tables.length * 20,
254-
y: box.y + box.h / 2 - 200 + tables.length * 20,
299+
x,
300+
y,
255301
fields: [
256302
{
257303
id: nanoid(),
@@ -430,6 +476,17 @@ export default function Home() {
430476
});
431477
};
432478

479+
const handlerImportTable = ({ tableDict, linkDict }) => {
480+
setTableDict(state => ({
481+
...state,
482+
...tableDict,
483+
}));
484+
setLinkDict(state => ({
485+
...state,
486+
...linkDict,
487+
}));
488+
};
489+
433490
return (
434491
<div className="graph">
435492
<Head>
@@ -457,13 +514,15 @@ export default function Home() {
457514
setCommand={setCommand}
458515
theme={theme}
459516
setTheme={setTheme}
517+
saveGraph={saveGraph}
460518
/>
461519
<svg
462520
className="main"
463521
viewBox={`${box.x} ${box.y} ${box.w} ${box.h}`}
464522
onMouseDown={mouseDownHandler}
465523
onMouseUp={mouseUpHandler}
466524
onMouseMove={mouseMoveHandler}
525+
onContextMenu={contextMenuHandler}
467526
onWheel={wheelHandler}
468527
ref={svg}
469528
>
@@ -584,6 +643,23 @@ export default function Home() {
584643
setEditingLink={setEditingLink}
585644
setLinkDict={setLinkDict}
586645
/>
646+
<ImportModal
647+
handlerImportTable={handlerImportTable}
648+
importType={importType}
649+
setImportType={setImportType}
650+
theme={theme}
651+
/>
652+
<ContextMenu
653+
theme={theme}
654+
menuId={MENU_ID}
655+
addTable={addTable}
656+
setImportType={setImportType}
657+
saveGraph={saveGraph}
658+
setCommand={val => {
659+
const sql = exportSQL(tableDict, linkDict, val);
660+
setCommand(sql);
661+
}}
662+
/>
587663
</div>
588664
);
589665
}

styles/globals.sass

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,10 @@ label
241241
width: 55px
242242
display: inline-block
243243

244+
.react-contexify__theme--dark
245+
.react-contexify__separator
246+
background-color: var(--color-border-2) !important
247+
244248
.index-bg
245249
padding: 8rem 0 12rem 0
246250
background-color: var(--color-primary-light-1)

0 commit comments

Comments
 (0)