@nocobase/plugin-graph-collection-manager 0.10.1-alpha.1 → 0.11.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client.d.ts +2 -3
- package/client.js +1 -30
- package/lib/client/GraphCollectionProvider.js +1 -14
- package/lib/client/GraphCollectionShortcut.js +2 -9
- package/lib/client/GraphDrawPage.js +44 -45
- package/lib/client/action-hooks.js +6 -7
- package/lib/client/components/EditCollectionAction.js +1 -8
- package/lib/client/components/Entity.js +16 -23
- package/lib/client/components/FieldSummary.d.ts +1 -1
- package/lib/client/components/FieldSummary.js +9 -16
- package/lib/client/index.d.ts +5 -1
- package/lib/client/index.js +21 -6
- package/lib/client/style.js +12 -12
- package/lib/client/utils.d.ts +2 -1
- package/lib/client/utils.js +15 -11
- package/package.json +27 -6
- package/server.d.ts +2 -3
- package/server.js +1 -30
- package/src/client/GraphCollectionProvider.tsx +33 -0
- package/src/client/GraphCollectionShortcut.tsx +141 -0
- package/src/client/GraphDrawPage.tsx +1375 -0
- package/src/client/action-hooks.tsx +232 -0
- package/src/client/components/AddCollectionAction.tsx +28 -0
- package/src/client/components/AddFieldAction.tsx +37 -0
- package/src/client/components/CollectionNodeProvder.tsx +28 -0
- package/src/client/components/EditCollectionAction.tsx +33 -0
- package/src/client/components/EditFieldAction.tsx +30 -0
- package/src/client/components/Entity.tsx +510 -0
- package/src/client/components/FieldSummary.tsx +42 -0
- package/src/client/components/OverrideFieldAction.tsx +30 -0
- package/src/client/components/ViewFieldAction.tsx +12 -0
- package/src/client/components/ViewNode.tsx +22 -0
- package/src/client/index.tsx +10 -0
- package/src/client/locale/en-US.ts +15 -0
- package/src/client/locale/es-ES.ts +15 -0
- package/src/client/locale/index.ts +3 -0
- package/src/client/locale/ja-JP.ts +13 -0
- package/src/client/locale/pt-BR.ts +15 -0
- package/src/client/locale/zh-CN.ts +16 -0
- package/src/client/style.tsx +206 -0
- package/src/client/utils.tsx +548 -0
- package/src/index.ts +1 -0
- package/src/server/actions/.gitkeep +0 -0
- package/src/server/collections/.gitkeep +0 -0
- package/src/server/collections/graphPositions.ts +22 -0
- package/src/server/index.ts +13 -0
- package/src/server/models/.gitkeep +0 -0
- package/src/server/repositories/.gitkeep +0 -0
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
import { DeleteOutlined, DownOutlined, EditOutlined, UpOutlined } from '@ant-design/icons';
|
|
2
|
+
import '@antv/x6-react-shape';
|
|
3
|
+
import { uid } from '@formily/shared';
|
|
4
|
+
import {
|
|
5
|
+
Action,
|
|
6
|
+
Checkbox,
|
|
7
|
+
collection,
|
|
8
|
+
CollectionCategroriesContext,
|
|
9
|
+
CollectionField,
|
|
10
|
+
CollectionProvider,
|
|
11
|
+
css,
|
|
12
|
+
cx,
|
|
13
|
+
Form,
|
|
14
|
+
FormItem,
|
|
15
|
+
Formula,
|
|
16
|
+
Grid,
|
|
17
|
+
Input,
|
|
18
|
+
InputNumber,
|
|
19
|
+
Radio,
|
|
20
|
+
ResourceActionProvider,
|
|
21
|
+
SchemaComponent,
|
|
22
|
+
SchemaComponentProvider,
|
|
23
|
+
Select,
|
|
24
|
+
useCollectionManager,
|
|
25
|
+
useCompile,
|
|
26
|
+
useCurrentAppInfo,
|
|
27
|
+
useRecord,
|
|
28
|
+
} from '@nocobase/client';
|
|
29
|
+
import { lodash } from '@nocobase/utils/client';
|
|
30
|
+
import { Badge, Dropdown, Popover, Tag } from 'antd';
|
|
31
|
+
import React, { useContext, useRef, useState } from 'react';
|
|
32
|
+
import {
|
|
33
|
+
useAsyncDataSource,
|
|
34
|
+
useCancelAction,
|
|
35
|
+
useDestroyActionAndRefreshCM,
|
|
36
|
+
useDestroyFieldActionAndRefreshCM,
|
|
37
|
+
useUpdateCollectionActionAndRefreshCM,
|
|
38
|
+
useValuesFromRecord,
|
|
39
|
+
} from '../action-hooks';
|
|
40
|
+
import { collectiionPopoverClass, entityContainer, headClass, tableBtnClass, tableNameClass } from '../style';
|
|
41
|
+
import { getPopupContainer, useGCMTranslation } from '../utils';
|
|
42
|
+
import { AddFieldAction } from './AddFieldAction';
|
|
43
|
+
import { CollectionNodeProvder } from './CollectionNodeProvder';
|
|
44
|
+
import { EditCollectionAction } from './EditCollectionAction';
|
|
45
|
+
import { EditFieldAction } from './EditFieldAction';
|
|
46
|
+
import { FieldSummary } from './FieldSummary';
|
|
47
|
+
import { OverrideFieldAction } from './OverrideFieldAction';
|
|
48
|
+
import { ViewFieldAction } from './ViewFieldAction';
|
|
49
|
+
|
|
50
|
+
const Entity: React.FC<{
|
|
51
|
+
node?: Node | any;
|
|
52
|
+
setTargetNode: Function | any;
|
|
53
|
+
targetGraph: any;
|
|
54
|
+
}> = (props) => {
|
|
55
|
+
const { node, setTargetNode, targetGraph } = props;
|
|
56
|
+
const {
|
|
57
|
+
store: {
|
|
58
|
+
data: { title, name, item, attrs, select },
|
|
59
|
+
},
|
|
60
|
+
id,
|
|
61
|
+
} = node;
|
|
62
|
+
const database = useCurrentAppInfo();
|
|
63
|
+
const collectionData = useRef();
|
|
64
|
+
const categoryData = useContext(CollectionCategroriesContext);
|
|
65
|
+
collectionData.current = { ...item, title, inherits: item.inherits && new Proxy(item.inherits, {}) };
|
|
66
|
+
const { category } = item;
|
|
67
|
+
const compile = useCompile();
|
|
68
|
+
const loadCollections = async (field: any) => {
|
|
69
|
+
return targetGraph.collections?.map((collection: any) => ({
|
|
70
|
+
label: compile(collection.title),
|
|
71
|
+
value: collection.name,
|
|
72
|
+
}));
|
|
73
|
+
};
|
|
74
|
+
const loadCategories = async () => {
|
|
75
|
+
return categoryData?.data.map((item: any) => ({
|
|
76
|
+
label: compile(item.name),
|
|
77
|
+
value: item.id,
|
|
78
|
+
}));
|
|
79
|
+
};
|
|
80
|
+
const portsProps = {
|
|
81
|
+
targetGraph,
|
|
82
|
+
collectionData,
|
|
83
|
+
setTargetNode,
|
|
84
|
+
node,
|
|
85
|
+
loadCollections,
|
|
86
|
+
};
|
|
87
|
+
return (
|
|
88
|
+
<div
|
|
89
|
+
className={cx(entityContainer)}
|
|
90
|
+
style={{ boxShadow: attrs?.boxShadow, border: select ? '2px dashed #f5a20a' : 0 }}
|
|
91
|
+
>
|
|
92
|
+
{category.map((v, index) => {
|
|
93
|
+
return (
|
|
94
|
+
<Badge.Ribbon
|
|
95
|
+
color={v.color}
|
|
96
|
+
style={{ width: '103%', height: '3px', marginTop: index * 5 - 8, borderRadius: 0 }}
|
|
97
|
+
placement="start"
|
|
98
|
+
/>
|
|
99
|
+
);
|
|
100
|
+
})}
|
|
101
|
+
<div
|
|
102
|
+
className={headClass}
|
|
103
|
+
style={{ background: attrs?.hightLight ? '#1890ff' : null, paddingTop: category.length * 3 }}
|
|
104
|
+
>
|
|
105
|
+
<span className={tableNameClass}>{compile(title)}</span>
|
|
106
|
+
|
|
107
|
+
<div className={tableBtnClass}>
|
|
108
|
+
<SchemaComponentProvider>
|
|
109
|
+
<CollectionNodeProvder setTargetNode={setTargetNode} node={node}>
|
|
110
|
+
<CollectionProvider collection={collection}>
|
|
111
|
+
<SchemaComponent
|
|
112
|
+
scope={{
|
|
113
|
+
useUpdateCollectionActionAndRefreshCM,
|
|
114
|
+
useCancelAction,
|
|
115
|
+
loadCollections,
|
|
116
|
+
loadCategories,
|
|
117
|
+
useAsyncDataSource,
|
|
118
|
+
Action,
|
|
119
|
+
DeleteOutlined,
|
|
120
|
+
enableInherits: database?.dialect === 'postgres',
|
|
121
|
+
}}
|
|
122
|
+
components={{
|
|
123
|
+
Action,
|
|
124
|
+
EditOutlined,
|
|
125
|
+
FormItem,
|
|
126
|
+
CollectionField,
|
|
127
|
+
Input,
|
|
128
|
+
Form,
|
|
129
|
+
Select,
|
|
130
|
+
EditCollectionAction,
|
|
131
|
+
Checkbox,
|
|
132
|
+
}}
|
|
133
|
+
schema={{
|
|
134
|
+
type: 'object',
|
|
135
|
+
properties: {
|
|
136
|
+
update: {
|
|
137
|
+
type: 'void',
|
|
138
|
+
title: '{{ t("Edit") }}',
|
|
139
|
+
'x-component': 'EditCollectionAction',
|
|
140
|
+
'x-component-props': {
|
|
141
|
+
type: 'primary',
|
|
142
|
+
item: collectionData.current,
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
delete: {
|
|
146
|
+
type: 'void',
|
|
147
|
+
'x-action': 'destroy',
|
|
148
|
+
'x-component': 'Action',
|
|
149
|
+
'x-component-props': {
|
|
150
|
+
component: DeleteOutlined,
|
|
151
|
+
icon: 'DeleteOutlined',
|
|
152
|
+
className: css`
|
|
153
|
+
background-color: rgb(255 236 232);
|
|
154
|
+
border-color: transparent;
|
|
155
|
+
color: #e31c1c;
|
|
156
|
+
height: 20px;
|
|
157
|
+
padding: 5px;
|
|
158
|
+
&:hover {
|
|
159
|
+
background-color: rgb(253 205 197);
|
|
160
|
+
}
|
|
161
|
+
`,
|
|
162
|
+
|
|
163
|
+
confirm: {
|
|
164
|
+
title: "{{t('Delete record')}}",
|
|
165
|
+
getContainer: getPopupContainer,
|
|
166
|
+
collectionConten: "{{t('Are you sure you want to delete it?')}}",
|
|
167
|
+
},
|
|
168
|
+
useAction: () => useDestroyActionAndRefreshCM({ name, id }),
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
}}
|
|
173
|
+
/>
|
|
174
|
+
</CollectionProvider>
|
|
175
|
+
</CollectionNodeProvder>
|
|
176
|
+
</SchemaComponentProvider>
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
|
|
180
|
+
<PortsCom {...portsProps} />
|
|
181
|
+
</div>
|
|
182
|
+
);
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const PortsCom = React.memo<any>(({ targetGraph, collectionData, setTargetNode, node, loadCollections }) => {
|
|
186
|
+
const {
|
|
187
|
+
store: {
|
|
188
|
+
data: { title, name, item, ports, data, sourcePort, associated, targetPort },
|
|
189
|
+
},
|
|
190
|
+
} = node;
|
|
191
|
+
const [collapse, setCollapse] = useState(false);
|
|
192
|
+
const { t } = useGCMTranslation();
|
|
193
|
+
const compile = useCompile();
|
|
194
|
+
const database = useCurrentAppInfo();
|
|
195
|
+
const portsData = lodash.groupBy(ports.items, (v) => {
|
|
196
|
+
if (
|
|
197
|
+
v.isForeignKey ||
|
|
198
|
+
v.primaryKey ||
|
|
199
|
+
['obo', 'oho', 'o2o', 'o2m', 'm2o', 'm2m', 'linkTo', 'id'].includes(v.interface)
|
|
200
|
+
) {
|
|
201
|
+
return 'initPorts';
|
|
202
|
+
} else {
|
|
203
|
+
return 'morePorts';
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
const useNewId = (prefix) => {
|
|
207
|
+
return `${prefix || ''}${uid()}`;
|
|
208
|
+
};
|
|
209
|
+
const CollectionConten = (data) => {
|
|
210
|
+
const { type, name, primaryKey, allowNull, autoIncrement } = data;
|
|
211
|
+
return (
|
|
212
|
+
<div className={cx(collectiionPopoverClass)}>
|
|
213
|
+
<div className="field-content">
|
|
214
|
+
<div>
|
|
215
|
+
<span>name</span>: <span className="field-type">{name}</span>
|
|
216
|
+
</div>
|
|
217
|
+
<div>
|
|
218
|
+
<span>type</span>: <span className="field-type">{type}</span>
|
|
219
|
+
</div>
|
|
220
|
+
</div>
|
|
221
|
+
<p>
|
|
222
|
+
{primaryKey && <Tag color="green">PRIMARY</Tag>}
|
|
223
|
+
{allowNull && <Tag color="geekblue">ALLOWNULL</Tag>}
|
|
224
|
+
{autoIncrement && <Tag color="purple">AUTOINCREMENT</Tag>}
|
|
225
|
+
</p>
|
|
226
|
+
</div>
|
|
227
|
+
);
|
|
228
|
+
};
|
|
229
|
+
const typeColor = (v) => {
|
|
230
|
+
if (v.isForeignKey || v.primaryKey || v.interface === 'id') {
|
|
231
|
+
return 'red';
|
|
232
|
+
} else if (['obo', 'oho', 'o2o', 'o2m', 'm2o', 'm2m', 'linkTo'].includes(v.interface)) {
|
|
233
|
+
return 'orange';
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
const OperationButton = ({ property }) => {
|
|
238
|
+
const isInheritField = !(property.collectionName !== name);
|
|
239
|
+
return (
|
|
240
|
+
<div className="field-operator">
|
|
241
|
+
<SchemaComponentProvider
|
|
242
|
+
components={{
|
|
243
|
+
FormItem,
|
|
244
|
+
CollectionField,
|
|
245
|
+
Input,
|
|
246
|
+
Form,
|
|
247
|
+
ResourceActionProvider,
|
|
248
|
+
Select: (props) => (
|
|
249
|
+
<Select popupMatchSelectWidth={false} {...props} getPopupContainer={getPopupContainer} />
|
|
250
|
+
),
|
|
251
|
+
Checkbox,
|
|
252
|
+
Radio,
|
|
253
|
+
InputNumber,
|
|
254
|
+
Grid,
|
|
255
|
+
FieldSummary,
|
|
256
|
+
Action,
|
|
257
|
+
EditOutlined,
|
|
258
|
+
DeleteOutlined,
|
|
259
|
+
AddFieldAction,
|
|
260
|
+
OverrideFieldAction,
|
|
261
|
+
ViewFieldAction,
|
|
262
|
+
Dropdown,
|
|
263
|
+
Formula,
|
|
264
|
+
}}
|
|
265
|
+
scope={{
|
|
266
|
+
useAsyncDataSource,
|
|
267
|
+
loadCollections,
|
|
268
|
+
useCancelAction,
|
|
269
|
+
useNewId,
|
|
270
|
+
useCurrentFields,
|
|
271
|
+
useValuesFromRecord,
|
|
272
|
+
useUpdateCollectionActionAndRefreshCM,
|
|
273
|
+
isInheritField,
|
|
274
|
+
}}
|
|
275
|
+
>
|
|
276
|
+
<CollectionNodeProvder
|
|
277
|
+
record={collectionData.current}
|
|
278
|
+
setTargetNode={setTargetNode}
|
|
279
|
+
node={node}
|
|
280
|
+
handelOpenPorts={() => handelOpenPorts(true)}
|
|
281
|
+
>
|
|
282
|
+
<SchemaComponent
|
|
283
|
+
scope={useCancelAction}
|
|
284
|
+
schema={{
|
|
285
|
+
type: 'object',
|
|
286
|
+
properties: {
|
|
287
|
+
create: {
|
|
288
|
+
type: 'void',
|
|
289
|
+
'x-action': 'create',
|
|
290
|
+
'x-component': 'AddFieldAction',
|
|
291
|
+
'x-visible': '{{isInheritField}}',
|
|
292
|
+
'x-component-props': {
|
|
293
|
+
item: {
|
|
294
|
+
...property,
|
|
295
|
+
title,
|
|
296
|
+
},
|
|
297
|
+
database,
|
|
298
|
+
},
|
|
299
|
+
},
|
|
300
|
+
update: {
|
|
301
|
+
type: 'void',
|
|
302
|
+
'x-action': 'update',
|
|
303
|
+
'x-component': EditFieldAction,
|
|
304
|
+
'x-visible': '{{isInheritField}}',
|
|
305
|
+
'x-component-props': {
|
|
306
|
+
item: {
|
|
307
|
+
...property,
|
|
308
|
+
title,
|
|
309
|
+
__parent: collectionData.current,
|
|
310
|
+
},
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
delete: {
|
|
314
|
+
type: 'void',
|
|
315
|
+
'x-action': 'destroy',
|
|
316
|
+
'x-component': 'Action',
|
|
317
|
+
'x-visible': '{{isInheritField}}',
|
|
318
|
+
'x-component-props': {
|
|
319
|
+
component: DeleteOutlined,
|
|
320
|
+
icon: 'DeleteOutlined',
|
|
321
|
+
className: css`
|
|
322
|
+
background-color: rgb(255 236 232);
|
|
323
|
+
border-color: transparent;
|
|
324
|
+
color: #e31c1c;
|
|
325
|
+
height: 20px;
|
|
326
|
+
width: 20px;
|
|
327
|
+
padding: 5px;
|
|
328
|
+
&:hover {
|
|
329
|
+
background-color: rgb(253 205 197);
|
|
330
|
+
}
|
|
331
|
+
`,
|
|
332
|
+
confirm: {
|
|
333
|
+
title: "{{t('Delete record')}}",
|
|
334
|
+
getContainer: getPopupContainer,
|
|
335
|
+
collectionConten: "{{t('Are you sure you want to delete it?')}}",
|
|
336
|
+
},
|
|
337
|
+
useAction: () =>
|
|
338
|
+
useDestroyFieldActionAndRefreshCM({
|
|
339
|
+
collectionName: property.collectionName,
|
|
340
|
+
name: property.name,
|
|
341
|
+
}),
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
override: {
|
|
345
|
+
type: 'void',
|
|
346
|
+
'x-action': 'create',
|
|
347
|
+
'x-visible': '{{!isInheritField}}',
|
|
348
|
+
'x-component': 'OverrideFieldAction',
|
|
349
|
+
'x-component-props': {
|
|
350
|
+
icon: 'ReconciliationOutlined',
|
|
351
|
+
item: {
|
|
352
|
+
...property,
|
|
353
|
+
title,
|
|
354
|
+
__parent: collectionData.current,
|
|
355
|
+
targetCollection: name,
|
|
356
|
+
},
|
|
357
|
+
},
|
|
358
|
+
},
|
|
359
|
+
view: {
|
|
360
|
+
type: 'void',
|
|
361
|
+
'x-action': 'view',
|
|
362
|
+
'x-visible': '{{!isInheritField}}',
|
|
363
|
+
'x-component': 'ViewFieldAction',
|
|
364
|
+
'x-component-props': {
|
|
365
|
+
icon: 'ReconciliationOutlined',
|
|
366
|
+
item: {
|
|
367
|
+
...property,
|
|
368
|
+
title,
|
|
369
|
+
__parent: collectionData.current,
|
|
370
|
+
},
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
}}
|
|
375
|
+
/>
|
|
376
|
+
</CollectionNodeProvder>
|
|
377
|
+
</SchemaComponentProvider>
|
|
378
|
+
</div>
|
|
379
|
+
);
|
|
380
|
+
};
|
|
381
|
+
const { getInterface } = useCollectionManager();
|
|
382
|
+
// 获取当前字段列表
|
|
383
|
+
const useCurrentFields = () => {
|
|
384
|
+
const record = useRecord();
|
|
385
|
+
const { getCollectionFields } = useCollectionManager();
|
|
386
|
+
const fields = getCollectionFields(record.collectionName || record.name) as any[];
|
|
387
|
+
return fields;
|
|
388
|
+
};
|
|
389
|
+
const handelOpenPorts = (isCollapse?) => {
|
|
390
|
+
targetGraph.getCellById(item.name)?.toFront();
|
|
391
|
+
setCollapse(isCollapse);
|
|
392
|
+
const collapseNodes = targetGraph.collapseNodes || [];
|
|
393
|
+
collapseNodes.push({
|
|
394
|
+
[item.name]: isCollapse,
|
|
395
|
+
});
|
|
396
|
+
targetGraph.collapseNodes = collapseNodes;
|
|
397
|
+
targetGraph.getCellById(item.name).setData({ collapse: true });
|
|
398
|
+
};
|
|
399
|
+
const isCollapse = collapse && data?.collapse;
|
|
400
|
+
return (
|
|
401
|
+
<div className="body">
|
|
402
|
+
{portsData['initPorts']?.map((property) => {
|
|
403
|
+
return (
|
|
404
|
+
property.uiSchema && (
|
|
405
|
+
<Popover
|
|
406
|
+
content={CollectionConten(property)}
|
|
407
|
+
getPopupContainer={getPopupContainer}
|
|
408
|
+
mouseLeaveDelay={0}
|
|
409
|
+
zIndex={100}
|
|
410
|
+
title={
|
|
411
|
+
<div>
|
|
412
|
+
{compile(property.uiSchema?.title)}
|
|
413
|
+
<span style={{ color: '#ffa940', float: 'right' }}>
|
|
414
|
+
{compile(getInterface(property.interface)?.title)}
|
|
415
|
+
</span>
|
|
416
|
+
</div>
|
|
417
|
+
}
|
|
418
|
+
key={property.id}
|
|
419
|
+
placement="right"
|
|
420
|
+
>
|
|
421
|
+
<div
|
|
422
|
+
className="body-item"
|
|
423
|
+
key={property.id}
|
|
424
|
+
id={property.id}
|
|
425
|
+
style={{
|
|
426
|
+
background:
|
|
427
|
+
targetPort || sourcePort === property.id || associated?.includes(property.name) ? '#e6f7ff' : null,
|
|
428
|
+
}}
|
|
429
|
+
>
|
|
430
|
+
<div className="name">
|
|
431
|
+
<Badge color={typeColor(property)} />
|
|
432
|
+
{compile(property.uiSchema?.title)}
|
|
433
|
+
</div>
|
|
434
|
+
<div className={`type field_type`}>{compile(getInterface(property.interface)?.title)}</div>
|
|
435
|
+
<OperationButton property={property} />
|
|
436
|
+
</div>
|
|
437
|
+
</Popover>
|
|
438
|
+
)
|
|
439
|
+
);
|
|
440
|
+
})}
|
|
441
|
+
<div className="morePorts">
|
|
442
|
+
{isCollapse &&
|
|
443
|
+
portsData['morePorts']?.map((property) => {
|
|
444
|
+
return (
|
|
445
|
+
property.uiSchema && (
|
|
446
|
+
<Popover
|
|
447
|
+
content={CollectionConten(property)}
|
|
448
|
+
getPopupContainer={getPopupContainer}
|
|
449
|
+
mouseLeaveDelay={0}
|
|
450
|
+
zIndex={100}
|
|
451
|
+
title={
|
|
452
|
+
<div>
|
|
453
|
+
{compile(property.uiSchema?.title)}
|
|
454
|
+
<span style={{ color: '#ffa940', float: 'right' }}>
|
|
455
|
+
{compile(getInterface(property.interface)?.title)}
|
|
456
|
+
</span>
|
|
457
|
+
</div>
|
|
458
|
+
}
|
|
459
|
+
key={property.id}
|
|
460
|
+
placement="right"
|
|
461
|
+
>
|
|
462
|
+
<div
|
|
463
|
+
className="body-item"
|
|
464
|
+
key={property.id}
|
|
465
|
+
id={property.id}
|
|
466
|
+
style={{
|
|
467
|
+
background:
|
|
468
|
+
targetPort || sourcePort === property.id || associated?.includes(property.name)
|
|
469
|
+
? '#e6f7ff'
|
|
470
|
+
: null,
|
|
471
|
+
}}
|
|
472
|
+
>
|
|
473
|
+
<div className="name">
|
|
474
|
+
<Badge color="green" />
|
|
475
|
+
{compile(property.uiSchema?.title)}
|
|
476
|
+
</div>
|
|
477
|
+
<div className={`type field_type`}>{compile(getInterface(property.interface)?.title)}</div>
|
|
478
|
+
<OperationButton property={property} />
|
|
479
|
+
</div>
|
|
480
|
+
</Popover>
|
|
481
|
+
)
|
|
482
|
+
);
|
|
483
|
+
})}
|
|
484
|
+
</div>
|
|
485
|
+
<a
|
|
486
|
+
className={css`
|
|
487
|
+
display: block;
|
|
488
|
+
color: #958f8f;
|
|
489
|
+
padding: 10px 5px;
|
|
490
|
+
&:hover {
|
|
491
|
+
color: rgb(99 90 88);
|
|
492
|
+
}
|
|
493
|
+
`}
|
|
494
|
+
onClick={() => handelOpenPorts(!isCollapse)}
|
|
495
|
+
>
|
|
496
|
+
{isCollapse
|
|
497
|
+
? [
|
|
498
|
+
<UpOutlined style={{ margin: '0px 8px 0px 5px' }} key="icon" />,
|
|
499
|
+
<span key="associate">{t('Association Fields')}</span>,
|
|
500
|
+
]
|
|
501
|
+
: [
|
|
502
|
+
<DownOutlined style={{ margin: '0px 8px 0px 5px' }} key="icon" />,
|
|
503
|
+
<span key="all">{t('All Fields')}</span>,
|
|
504
|
+
]}
|
|
505
|
+
</a>
|
|
506
|
+
</div>
|
|
507
|
+
);
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
export default Entity;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { observer } from '@formily/react';
|
|
2
|
+
import { css, useCollectionManager, useCompile } from '@nocobase/client';
|
|
3
|
+
import { Tag } from 'antd';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
|
|
7
|
+
export const FieldSummary = observer(
|
|
8
|
+
(props: any) => {
|
|
9
|
+
const { schemaKey } = props;
|
|
10
|
+
const { getInterface } = useCollectionManager();
|
|
11
|
+
const compile = useCompile();
|
|
12
|
+
const { t } = useTranslation();
|
|
13
|
+
const schema = getInterface(schemaKey);
|
|
14
|
+
|
|
15
|
+
if (!schema) return null;
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<div
|
|
19
|
+
className={css`
|
|
20
|
+
background: #f6f6f6;
|
|
21
|
+
margin-bottom: 24px;
|
|
22
|
+
padding: 16px;
|
|
23
|
+
`}
|
|
24
|
+
>
|
|
25
|
+
<div className={css``}>
|
|
26
|
+
{t('Field interface')}: <Tag>{compile(schema.title)}</Tag>
|
|
27
|
+
</div>
|
|
28
|
+
{schema.description ? (
|
|
29
|
+
<div
|
|
30
|
+
className={css`
|
|
31
|
+
margin-top: 8px;
|
|
32
|
+
color: rgba(0, 0, 0, 0.45);
|
|
33
|
+
`}
|
|
34
|
+
>
|
|
35
|
+
{compile(schema.description)}
|
|
36
|
+
</div>
|
|
37
|
+
) : null}
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
},
|
|
41
|
+
{ displayName: 'FieldSummary' },
|
|
42
|
+
);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { CopyOutlined } from '@ant-design/icons';
|
|
2
|
+
import { OverridingFieldAction as OverridingCollectionFieldAction } from '@nocobase/client';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { useCancelAction, useCreateAction } from '../action-hooks';
|
|
5
|
+
import { getPopupContainer } from '../utils';
|
|
6
|
+
|
|
7
|
+
const useOverridingCollectionField = (record) => {
|
|
8
|
+
const collectionName = record.targetCollection;
|
|
9
|
+
const { run } = useCreateAction(collectionName);
|
|
10
|
+
return {
|
|
11
|
+
async run() {
|
|
12
|
+
await run();
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const OverrideFieldAction = ({ item: record }) => {
|
|
18
|
+
return (
|
|
19
|
+
<OverridingCollectionFieldAction
|
|
20
|
+
item={{ ...record }}
|
|
21
|
+
scope={{
|
|
22
|
+
useCancelAction,
|
|
23
|
+
useOverridingCollectionField: () => useOverridingCollectionField(record),
|
|
24
|
+
}}
|
|
25
|
+
getContainer={getPopupContainer}
|
|
26
|
+
>
|
|
27
|
+
<CopyOutlined className="btn-override" />
|
|
28
|
+
</OverridingCollectionFieldAction>
|
|
29
|
+
);
|
|
30
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { EyeOutlined } from '@ant-design/icons';
|
|
2
|
+
import { ViewFieldAction as ViewCollectionFieldAction } from '@nocobase/client';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { getPopupContainer } from '../utils';
|
|
5
|
+
|
|
6
|
+
export const ViewFieldAction = ({ item: record }) => {
|
|
7
|
+
return (
|
|
8
|
+
<ViewCollectionFieldAction item={{ ...record }} getContainer={getPopupContainer}>
|
|
9
|
+
<EyeOutlined className="btn-view" />
|
|
10
|
+
</ViewCollectionFieldAction>
|
|
11
|
+
);
|
|
12
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { NodeView } from '@antv/x6';
|
|
2
|
+
|
|
3
|
+
export class SimpleNodeView extends NodeView {
|
|
4
|
+
protected renderMarkup() {
|
|
5
|
+
return this.renderJSONMarkup({
|
|
6
|
+
tagName: 'rect',
|
|
7
|
+
selector: 'body',
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
update() {
|
|
12
|
+
const attrs = this.cell.getAttrs();
|
|
13
|
+
const fill = attrs.hightLight ? '#1890ff' : 'gray';
|
|
14
|
+
super.update({
|
|
15
|
+
body: {
|
|
16
|
+
refWidth: '50px',
|
|
17
|
+
refHeight: '100px',
|
|
18
|
+
fill: fill,
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Plugin } from '@nocobase/client';
|
|
2
|
+
import { GraphCollectionProvider } from './GraphCollectionProvider';
|
|
3
|
+
|
|
4
|
+
export class GraphCollectionPlugin extends Plugin {
|
|
5
|
+
async load() {
|
|
6
|
+
this.app.use(GraphCollectionProvider);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default GraphCollectionPlugin;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
'Graph Collection': 'Graph Collection',
|
|
3
|
+
'Collection List': 'Collection List',
|
|
4
|
+
'Full Screen': 'Full Screen',
|
|
5
|
+
'Collection Search': 'Collection Search',
|
|
6
|
+
'Create Collection': 'Create Collection',
|
|
7
|
+
'All Fields': 'All Fields',
|
|
8
|
+
'Association Fields': 'Association Fields',
|
|
9
|
+
'Choices fields': 'Choices fields',
|
|
10
|
+
'All relationships': 'All relationships',
|
|
11
|
+
'Entity relationship only': 'Entity relationship only',
|
|
12
|
+
'Inheritance relationship only': 'Inheritance relationship only',
|
|
13
|
+
'Graphical interface': 'Graphical interface',
|
|
14
|
+
Selection: 'Selection',
|
|
15
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
"Graph Collection": "Colección de gráficos",
|
|
3
|
+
"Collection List": "Lista de colecciones",
|
|
4
|
+
"Full Screen": "Vista completa",
|
|
5
|
+
"Collection Search": "Búsqueda de colecciones",
|
|
6
|
+
"Create Collection": "Crear colección",
|
|
7
|
+
"All Fields": "Todos los campos",
|
|
8
|
+
"Association Fields": "Campos de asociación",
|
|
9
|
+
"Optional fields": "Campos opcionales",
|
|
10
|
+
"All relationships": "Todas las relaciones",
|
|
11
|
+
"Entity relationship only": "Sólo relaciones de entidad",
|
|
12
|
+
"Inheritance relationship only": "Sólo relaciones de herencia",
|
|
13
|
+
"Graphical interface": "Interfaz gráfica",
|
|
14
|
+
"Selection": "Selección"
|
|
15
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
'Graph Collection': 'グラフ化データテーブル',
|
|
3
|
+
'Collection List': 'データテーブルリスト',
|
|
4
|
+
'Full Screen': 'フルスクリーン',
|
|
5
|
+
'Collection Search': '表フィルタ',
|
|
6
|
+
'Create Collection': 'データテーブルの作成',
|
|
7
|
+
'All Fields': 'すべて',
|
|
8
|
+
'Associations Fields': '関係フィールド',
|
|
9
|
+
'All relationships': 'すべての関係',
|
|
10
|
+
'Entity relationship only': 'エンティティ関係',
|
|
11
|
+
'Inheritance relationship only': '継承関係',
|
|
12
|
+
Selection: 'せんたく',
|
|
13
|
+
};
|