Skip to content

Commit d477093

Browse files
authored
Merge pull request #1240 from merico-dev/1239-able-to-download-view-schema-and-import-a-view-with-its-schema
1239 able to download view schema and import a view with its schema
2 parents 4ae7875 + 0e665ba commit d477093

File tree

14 files changed

+187
-30
lines changed

14 files changed

+187
-30
lines changed

api/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@devtable/api",
3-
"version": "10.45.2",
3+
"version": "10.46.0",
44
"description": "",
55
"main": "index.js",
66
"scripts": {

dashboard/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@devtable/dashboard",
3-
"version": "10.45.2",
3+
"version": "10.46.0",
44
"license": "Apache-2.0",
55
"publishConfig": {
66
"access": "public",
@@ -41,7 +41,8 @@
4141
"popmotion": "^11.0.3",
4242
"rc-select": "14.1.0",
4343
"rc-tree-select": "5.5.5",
44-
"reactflow": "^11.5.3"
44+
"reactflow": "^11.5.3",
45+
"uuid": "9.0.1"
4546
},
4647
"devDependencies": {
4748
"@emotion/babel-plugin": "11.11.0",
@@ -83,6 +84,7 @@
8384
"@types/react": "^18.0.0",
8485
"@types/react-dom": "^18.0.0",
8586
"@types/react-grid-layout": "^1.3.2",
87+
"@types/uuid": "9.0.5",
8688
"ahooks": "^3.3.11",
8789
"ajv": "8.12.0",
8890
"axios": "^0.27.2",

dashboard/src/dashboard-editor/model/content/index.ts

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { FiltersModel } from '../filters';
1818
import { QueriesModel } from '../queries';
1919
import { SQLSnippetsModel } from '../sql-snippets';
2020

21+
import { v4 as uuidv4 } from 'uuid';
2122
import { TAdditionalQueryInfo } from '~/api-caller/request';
2223
import {
2324
formatSQLSnippet,
@@ -281,24 +282,45 @@ const _ContentModel = types
281282
self.views.findByID(viewID)?.removePanelID(panelID);
282283
},
283284
addANewPanel(viewID: string) {
284-
const id = new Date().getTime().toString();
285+
const id = uuidv4();
285286
self.panels.append(getNewPanel(id));
286287
self.views.findByID(viewID)?.appendPanelID(id);
287288
},
288289
applyJSONSchema(partialSchema: AnyObject) {
289-
const { panels, filters, definition = {} } = partialSchema;
290+
const { views, panels, filters, definition = {} } = partialSchema;
290291
const { queries, sqlSnippets, mock_context } = definition;
292+
const panelIDMap: Map<string, string> = new Map(); // old -> new
291293

292294
// PANELS
293295
if (Array.isArray(panels)) {
294-
const newPanels = panels.map((p) => ({
295-
...p,
296-
id: new Date().getTime().toString(),
297-
}));
296+
const newPanels = panels.map((p) => {
297+
const newID = uuidv4();
298+
panelIDMap.set(p.id, newID);
299+
return {
300+
...p,
301+
id: newID,
302+
};
303+
});
298304
self.panels.appendMultiple(newPanels);
299305

300-
const panelIDs = newPanels.map((p) => p.id);
301-
self.views.VIE?.appendPanelIDs(panelIDs);
306+
// import panels to current view
307+
if (!Array.isArray(views) || views.length === 0) {
308+
const panelIDs = newPanels.map((p) => p.id);
309+
self.views.VIE?.appendPanelIDs(panelIDs);
310+
}
311+
}
312+
313+
// VIEWS
314+
if (Array.isArray(views)) {
315+
const newViews = views.map((v) => {
316+
const panelIDs = v.panelIDs.map((oldID: string) => panelIDMap.get(oldID) ?? oldID);
317+
return {
318+
...v,
319+
id: uuidv4(),
320+
panelIDs,
321+
};
322+
});
323+
self.views.appendMultiple(newViews);
302324
}
303325

304326
// FILTERS

dashboard/src/dashboard-editor/model/views/index.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ import { IDashboardView } from '~/types';
44
import { PanelsModelInstance } from '../panels';
55

66
import { ViewDivisionConfigSnapshotIn, ViewMetaInstance, ViewModalConfigSnapshotIn } from '~/model';
7+
import { ViewModel, ViewModelInstance } from './view';
78

89
export const ViewsModel = types
910
.compose(
1011
'ViewsModel',
1112
ViewsRenderModel,
1213
types.model({
14+
current: types.optional(types.array(ViewModel), []),
1315
idOfVIE: types.string, // VIE: view in edit
1416
}),
1517
)
@@ -21,7 +23,7 @@ export const ViewsModel = types
2123
return self.current[0].id === self.idOfVIE;
2224
},
2325
get VIE() {
24-
return self.current.find(({ id }) => id === self.idOfVIE);
26+
return self.current.find(({ id }) => id === self.idOfVIE) as ViewModelInstance;
2527
},
2628
get options() {
2729
return self.current.map((v) => ({
@@ -70,6 +72,13 @@ export const ViewsModel = types
7072
append(item: ViewRenderModelInstance) {
7173
self.current.push(item);
7274
},
75+
appendMultiple(items: ViewRenderModelInstance[]) {
76+
if (items.length === 0) {
77+
return;
78+
}
79+
80+
self.current.push(...items);
81+
},
7382
remove(index: number) {
7483
self.current.splice(index, 1);
7584
},
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import _ from 'lodash';
2+
import { Instance, SnapshotIn } from 'mobx-state-tree';
3+
import { EViewComponentType, ViewRenderModel } from '~/model';
4+
import { AnyObject } from '~/types';
5+
import { downloadJSON } from '~/utils/download';
6+
7+
export const ViewModel = ViewRenderModel.actions((self) => ({
8+
getSchema() {
9+
const view = self.json;
10+
const panels: AnyObject[] = [];
11+
const queries: AnyObject[] = [];
12+
self.panels.forEach((p: any) => {
13+
const ps = p.getSchema();
14+
panels.push(ps.panel);
15+
if (ps.queries.length > 0) {
16+
queries.push(...ps.queries);
17+
}
18+
});
19+
20+
const ret = {
21+
views: [view],
22+
panels: panels,
23+
definition: {
24+
queries: _.uniqBy(queries, (q) => q.id),
25+
},
26+
};
27+
return ret;
28+
},
29+
downloadSchema() {
30+
if (self.type === EViewComponentType.Tabs) {
31+
console.error(new Error('Please choose a tab first'));
32+
return;
33+
}
34+
const schema = JSON.stringify(this.getSchema(), null, 2);
35+
const filename = self.name;
36+
downloadJSON(filename, schema);
37+
},
38+
}));
39+
40+
export type ViewModelInstance = Instance<typeof ViewModel>;
41+
export type ViewModelSnapshotIn = SnapshotIn<ViewModelInstance>;
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { Button, Sx, Tooltip } from '@mantine/core';
2+
import { IconCode, IconPlaylistAdd } from '@tabler/icons-react';
3+
import { observer } from 'mobx-react-lite';
4+
import { useEditContentModelContext } from '~/contexts';
5+
import { EViewComponentType } from '~/model';
6+
7+
const ButtonSx: Sx = {
8+
height: '30px',
9+
borderRight: 'none',
10+
borderTop: 'none',
11+
borderLeft: '1px solid #e9ecef',
12+
borderBottom: '1px solid #e9ecef',
13+
};
14+
15+
export const DownloadThisView = observer(() => {
16+
const contentModel = useEditContentModelContext();
17+
const cant = contentModel.views.VIE?.type === EViewComponentType.Tabs;
18+
const download = () => contentModel.views.VIE?.downloadSchema();
19+
if (cant) {
20+
return (
21+
<Tooltip label="Please choose a tab first">
22+
<Button
23+
variant="outline"
24+
color="gray"
25+
radius={0}
26+
size="xs"
27+
leftIcon={<IconCode size={16} />}
28+
sx={{
29+
...ButtonSx,
30+
transform: 'none !important',
31+
}}
32+
>
33+
Download this View
34+
</Button>
35+
</Tooltip>
36+
);
37+
}
38+
39+
return (
40+
<Button
41+
variant="outline"
42+
color="blue"
43+
radius={0}
44+
size="xs"
45+
onClick={download}
46+
leftIcon={<IconCode size={16} />}
47+
sx={{
48+
...ButtonSx,
49+
// background: 'rgb(231, 245, 255)',
50+
}}
51+
>
52+
Download this View
53+
</Button>
54+
);
55+
});

dashboard/src/dashboard-editor/ui/header/import-with-schema/explain-json-schema.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ const SQLSnippets = ({ content }: Props) => {
165165

166166
const MockContext = ({ content }: Props) => {
167167
const list = Object.keys(content.definition?.mock_context ?? {});
168-
if (!list) {
168+
if (list.length === 0) {
169169
return null;
170170
}
171171

dashboard/src/dashboard-editor/ui/header/import-with-schema/index.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ import { useBoolean } from 'ahooks';
99

1010
const ButtonSx: Sx = {
1111
height: '30px',
12-
borderRight: 'none',
12+
borderLeft: 'none',
1313
borderTop: 'none',
14-
borderLeft: '1px solid #e9ecef',
14+
borderRight: '1px solid #e9ecef',
1515
borderBottom: '1px solid #e9ecef',
1616
};
1717

@@ -35,7 +35,7 @@ export const ImportWithSchema = observer(() => {
3535
transform: 'none !important',
3636
}}
3737
>
38-
Import
38+
Import...
3939
</Button>
4040
</Tooltip>
4141
);
@@ -52,10 +52,10 @@ export const ImportWithSchema = observer(() => {
5252
leftIcon={<IconFileImport size={16} />}
5353
sx={{
5454
...ButtonSx,
55-
background: 'rgb(231, 245, 255)',
55+
// background: 'rgb(231, 245, 255)',
5656
}}
5757
>
58-
Import
58+
Import...
5959
</Button>
6060
<Modal
6161
opened={opened}

dashboard/src/dashboard-editor/ui/header/sub-header.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Box, Group, Sx } from '@mantine/core';
22
import { observer } from 'mobx-react-lite';
33
import { AddAPanel } from './add-a-panel';
44
import { ImportWithSchema } from './import-with-schema';
5+
import { DownloadThisView } from './download-this-view';
56

67
const SubHeaderSx: Sx = {
78
position: 'fixed',
@@ -18,9 +19,14 @@ export const SubHeader = observer(() => {
1819
return (
1920
<Box sx={SubHeaderSx} pl={{ base: 200, xs: 200, sm: 200, md: 220, lg: 240, xl: 260 }}>
2021
<Group position="apart" align="center" sx={{ height: '30px' }}>
21-
<AddAPanel />
22+
<Group position="left" spacing={0}>
23+
<AddAPanel />
24+
<ImportWithSchema />
25+
</Group>
2226
<Box />
23-
<ImportWithSchema />
27+
<Group position="right" spacing={0}>
28+
<DownloadThisView />
29+
</Group>
2430
</Group>
2531
</Box>
2632
);

dashboard/src/model/render-model/dashboard/content/panels/panel.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,18 +73,22 @@ export const PanelRenderModel = PanelMeta.views((self) => ({
7373
__TRIGGERS: {},
7474
};
7575

76-
const ret = {
76+
return {
77+
panel,
78+
queries: self.queries.map((q) => q.json),
79+
};
80+
},
81+
downloadSchema() {
82+
const { panel, queries } = this.getSchema();
83+
const schema = {
7784
panels: [panel],
7885
definition: {
79-
queries: self.queries.map((q) => q.json),
86+
queries,
8087
},
8188
};
82-
return ret;
83-
},
84-
downloadSchema() {
85-
const schema = JSON.stringify(this.getSchema(), null, 2);
89+
const schemaStr = JSON.stringify(schema, null, 2);
8690
const filename = self.name;
87-
downloadJSON(filename, schema);
91+
downloadJSON(filename, schemaStr);
8892
},
8993
}));
9094

0 commit comments

Comments
 (0)