@nocobase/plugin-snapshot-field 0.8.1-alpha.3
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/LICENSE +201 -0
- package/client.d.ts +4 -0
- package/client.js +30 -0
- package/lib/client/SnapshotBlock/SnapshotBlockInitializers/SnapshotBlockInitializers.d.ts +1 -0
- package/lib/client/SnapshotBlock/SnapshotBlockInitializers/SnapshotBlockInitializers.js +99 -0
- package/lib/client/SnapshotBlock/SnapshotBlockInitializers/SnapshotBlockInitializersDetailItem.d.ts +57 -0
- package/lib/client/SnapshotBlock/SnapshotBlockInitializers/SnapshotBlockInitializersDetailItem.js +190 -0
- package/lib/client/SnapshotBlock/SnapshotBlockProvider.d.ts +1 -0
- package/lib/client/SnapshotBlock/SnapshotBlockProvider.js +160 -0
- package/lib/client/SnapshotHistoryCollectionProvider.d.ts +4 -0
- package/lib/client/SnapshotHistoryCollectionProvider.js +72 -0
- package/lib/client/SnapshotRecordPicker.d.ts +1 -0
- package/lib/client/SnapshotRecordPicker.js +99 -0
- package/lib/client/index.d.ts +3 -0
- package/lib/client/index.js +71 -0
- package/lib/client/interface.d.ts +2 -0
- package/lib/client/interface.js +148 -0
- package/lib/client/locale/en-US.d.ts +10 -0
- package/lib/client/locale/en-US.js +16 -0
- package/lib/client/locale/index.d.ts +3 -0
- package/lib/client/locale/index.js +63 -0
- package/lib/client/locale/ja-JP.d.ts +2 -0
- package/lib/client/locale/ja-JP.js +8 -0
- package/lib/client/locale/ru-RU.d.ts +2 -0
- package/lib/client/locale/ru-RU.js +8 -0
- package/lib/client/locale/tr-TR.d.ts +2 -0
- package/lib/client/locale/tr-TR.js +8 -0
- package/lib/client/locale/zh-CN.d.ts +10 -0
- package/lib/client/locale/zh-CN.js +16 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +15 -0
- package/lib/server/collections/collectionsHistory.d.ts +3 -0
- package/lib/server/collections/collectionsHistory.js +52 -0
- package/lib/server/collections/fieldsHistory.d.ts +3 -0
- package/lib/server/collections/fieldsHistory.js +66 -0
- package/lib/server/fields/snapshot-field.d.ts +8 -0
- package/lib/server/fields/snapshot-field.js +35 -0
- package/lib/server/index.d.ts +1 -0
- package/lib/server/index.js +15 -0
- package/lib/server/plugin.d.ts +11 -0
- package/lib/server/plugin.js +190 -0
- package/package.json +10 -0
- package/server.d.ts +4 -0
- package/server.js +30 -0
- package/src/client/SnapshotBlock/SnapshotBlockInitializers/SnapshotBlockInitializers.tsx +78 -0
- package/src/client/SnapshotBlock/SnapshotBlockInitializers/SnapshotBlockInitializersDetailItem.tsx +121 -0
- package/src/client/SnapshotBlock/SnapshotBlockProvider.tsx +105 -0
- package/src/client/SnapshotHistoryCollectionProvider.tsx +42 -0
- package/src/client/SnapshotRecordPicker.tsx +52 -0
- package/src/client/index.tsx +50 -0
- package/src/client/interface.ts +102 -0
- package/src/client/locale/en-US.ts +10 -0
- package/src/client/locale/index.ts +24 -0
- package/src/client/locale/ja-JP.ts +1 -0
- package/src/client/locale/ru-RU.ts +1 -0
- package/src/client/locale/tr-TR.ts +1 -0
- package/src/client/locale/zh-CN.ts +9 -0
- package/src/index.ts +1 -0
- package/src/server/collections/.gitkeep +0 -0
- package/src/server/collections/collectionsHistory.ts +55 -0
- package/src/server/collections/fieldsHistory.ts +73 -0
- package/src/server/fields/snapshot-field.ts +12 -0
- package/src/server/index.ts +1 -0
- package/src/server/plugin.ts +110 -0
package/src/client/SnapshotBlock/SnapshotBlockInitializers/SnapshotBlockInitializersDetailItem.tsx
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { FormOutlined } from '@ant-design/icons';
|
|
3
|
+
import {
|
|
4
|
+
SchemaInitializer,
|
|
5
|
+
useBlockAssociationContext,
|
|
6
|
+
useCollection,
|
|
7
|
+
useSchemaTemplateManager,
|
|
8
|
+
useRecordCollectionDataSourceItems,
|
|
9
|
+
useBlockRequestContext,
|
|
10
|
+
} from '@nocobase/client';
|
|
11
|
+
import { ISchema } from '@formily/react';
|
|
12
|
+
import { uid } from '@formily/shared';
|
|
13
|
+
|
|
14
|
+
export const createSnapshotBlockSchema = (options) => {
|
|
15
|
+
const {
|
|
16
|
+
formItemInitializers = 'ReadPrettyFormItemInitializers',
|
|
17
|
+
actionInitializers = 'ReadPrettyFormActionInitializers',
|
|
18
|
+
collection,
|
|
19
|
+
association,
|
|
20
|
+
resource,
|
|
21
|
+
template,
|
|
22
|
+
...others
|
|
23
|
+
} = options;
|
|
24
|
+
const resourceName = resource || association || collection;
|
|
25
|
+
const schema: ISchema = {
|
|
26
|
+
type: 'void',
|
|
27
|
+
'x-acl-action': `${resourceName}:get`,
|
|
28
|
+
'x-decorator': 'SnapshotBlockProvider',
|
|
29
|
+
'x-decorator-props': {
|
|
30
|
+
resource: resourceName,
|
|
31
|
+
collection,
|
|
32
|
+
association,
|
|
33
|
+
readPretty: true,
|
|
34
|
+
action: 'get',
|
|
35
|
+
useParams: '{{ useParamsFromRecord }}',
|
|
36
|
+
...others,
|
|
37
|
+
},
|
|
38
|
+
'x-designer': 'FormV2.ReadPrettyDesigner',
|
|
39
|
+
'x-component': 'CardItem',
|
|
40
|
+
properties: {
|
|
41
|
+
[uid()]: {
|
|
42
|
+
type: 'void',
|
|
43
|
+
'x-component': 'FormV2',
|
|
44
|
+
'x-read-pretty': true,
|
|
45
|
+
'x-component-props': {
|
|
46
|
+
useProps: '{{ useFormBlockProps }}',
|
|
47
|
+
},
|
|
48
|
+
properties: {
|
|
49
|
+
grid: template || {
|
|
50
|
+
type: 'void',
|
|
51
|
+
'x-component': 'Grid',
|
|
52
|
+
'x-initializer': formItemInitializers,
|
|
53
|
+
properties: {},
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
console.log(JSON.stringify(schema, null, 2));
|
|
60
|
+
return schema;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const SnapshotBlockInitializersDetailItem = (props) => {
|
|
64
|
+
const {
|
|
65
|
+
onCreateBlockSchema,
|
|
66
|
+
componentType,
|
|
67
|
+
createBlockSchema,
|
|
68
|
+
insert,
|
|
69
|
+
icon = true,
|
|
70
|
+
targetCollection,
|
|
71
|
+
...others
|
|
72
|
+
} = props;
|
|
73
|
+
const { getTemplateSchemaByMode } = useSchemaTemplateManager();
|
|
74
|
+
const collection = targetCollection || useCollection();
|
|
75
|
+
const association = useBlockAssociationContext();
|
|
76
|
+
const { block } = useBlockRequestContext();
|
|
77
|
+
const actionInitializers =
|
|
78
|
+
block !== 'TableField' ? props.actionInitializers || 'ReadPrettyFormActionInitializers' : null;
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<SchemaInitializer.Item
|
|
82
|
+
icon={icon && <FormOutlined />}
|
|
83
|
+
{...others}
|
|
84
|
+
key={'snapshotDetail'}
|
|
85
|
+
onClick={async ({ item }) => {
|
|
86
|
+
if (item.template) {
|
|
87
|
+
const s = await getTemplateSchemaByMode(item);
|
|
88
|
+
if (item.template.componentName === 'ReadPrettyFormItem') {
|
|
89
|
+
const blockSchema = createSnapshotBlockSchema({
|
|
90
|
+
actionInitializers,
|
|
91
|
+
association,
|
|
92
|
+
collection: collection.name,
|
|
93
|
+
action: 'get',
|
|
94
|
+
useSourceId: '{{ useSourceIdFromParentRecord }}',
|
|
95
|
+
useParams: '{{ useParamsFromRecord }}',
|
|
96
|
+
template: s,
|
|
97
|
+
});
|
|
98
|
+
if (item.mode === 'reference') {
|
|
99
|
+
blockSchema['x-template-key'] = item.template.key;
|
|
100
|
+
}
|
|
101
|
+
insert(blockSchema);
|
|
102
|
+
} else {
|
|
103
|
+
insert(s);
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
insert(
|
|
107
|
+
createSnapshotBlockSchema({
|
|
108
|
+
actionInitializers,
|
|
109
|
+
association,
|
|
110
|
+
collection: collection.name,
|
|
111
|
+
action: 'get',
|
|
112
|
+
useSourceId: '{{ useSourceIdFromParentRecord }}',
|
|
113
|
+
useParams: '{{ useParamsFromRecord }}',
|
|
114
|
+
}),
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
}}
|
|
118
|
+
items={useRecordCollectionDataSourceItems('ReadPrettyFormItem')}
|
|
119
|
+
/>
|
|
120
|
+
);
|
|
121
|
+
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import React, { useContext, useMemo, useRef } from 'react';
|
|
2
|
+
import { createForm } from '@formily/core';
|
|
3
|
+
import { useField } from '@formily/react';
|
|
4
|
+
import {
|
|
5
|
+
BlockAssociationContext,
|
|
6
|
+
BlockRequestContext,
|
|
7
|
+
BlockResourceContext,
|
|
8
|
+
FormBlockContext,
|
|
9
|
+
MaybeCollectionProvider,
|
|
10
|
+
RecordProvider,
|
|
11
|
+
useBlockRequestContext,
|
|
12
|
+
useBlockResource,
|
|
13
|
+
useCollectionManager,
|
|
14
|
+
useDesignable,
|
|
15
|
+
useRecord,
|
|
16
|
+
useResource,
|
|
17
|
+
} from '@nocobase/client';
|
|
18
|
+
import { Spin } from 'antd';
|
|
19
|
+
|
|
20
|
+
const InternalFormBlockProvider = (props) => {
|
|
21
|
+
const { action, readPretty } = props;
|
|
22
|
+
const field = useField();
|
|
23
|
+
const form = useMemo(
|
|
24
|
+
() =>
|
|
25
|
+
createForm({
|
|
26
|
+
readPretty,
|
|
27
|
+
}),
|
|
28
|
+
[],
|
|
29
|
+
);
|
|
30
|
+
const { resource, service } = useBlockRequestContext();
|
|
31
|
+
const formBlockRef = useRef();
|
|
32
|
+
if (service.loading) {
|
|
33
|
+
return <Spin />;
|
|
34
|
+
}
|
|
35
|
+
return (
|
|
36
|
+
<FormBlockContext.Provider
|
|
37
|
+
value={{
|
|
38
|
+
action,
|
|
39
|
+
form,
|
|
40
|
+
field,
|
|
41
|
+
service,
|
|
42
|
+
resource,
|
|
43
|
+
updateAssociationValues: [],
|
|
44
|
+
formBlockRef,
|
|
45
|
+
}}
|
|
46
|
+
>
|
|
47
|
+
{readPretty ? (
|
|
48
|
+
<RecordProvider record={service?.data?.data}>
|
|
49
|
+
<div ref={formBlockRef}>{props.children}</div>
|
|
50
|
+
</RecordProvider>
|
|
51
|
+
) : (
|
|
52
|
+
<div ref={formBlockRef}>{props.children}</div>
|
|
53
|
+
)}
|
|
54
|
+
</FormBlockContext.Provider>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const BlockRequestProvider = (props) => {
|
|
59
|
+
const field = useField();
|
|
60
|
+
const resource = useBlockResource();
|
|
61
|
+
const service = {
|
|
62
|
+
loading: false,
|
|
63
|
+
data: {
|
|
64
|
+
data: useRecord(),
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
const __parent = useContext(BlockRequestContext);
|
|
68
|
+
return (
|
|
69
|
+
<BlockRequestContext.Provider value={{ block: props.block, props, field, service, resource, __parent }}>
|
|
70
|
+
{props.children}
|
|
71
|
+
</BlockRequestContext.Provider>
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const BlockProvider = (props) => {
|
|
76
|
+
const { collection, association } = props;
|
|
77
|
+
const resource = useResource(props);
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<MaybeCollectionProvider collection={collection}>
|
|
81
|
+
<BlockAssociationContext.Provider value={association}>
|
|
82
|
+
<BlockResourceContext.Provider value={resource}>
|
|
83
|
+
<BlockRequestProvider {...props}>{props.children}</BlockRequestProvider>
|
|
84
|
+
</BlockResourceContext.Provider>
|
|
85
|
+
</BlockAssociationContext.Provider>
|
|
86
|
+
</MaybeCollectionProvider>
|
|
87
|
+
);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export const SnapshotBlockProvider = (props) => {
|
|
91
|
+
const record = useRecord();
|
|
92
|
+
const { __tableName } = record;
|
|
93
|
+
const { getInheritCollections } = useCollectionManager();
|
|
94
|
+
const inheritCollections = getInheritCollections(__tableName);
|
|
95
|
+
const { designable } = useDesignable();
|
|
96
|
+
const flag =
|
|
97
|
+
!designable && __tableName && !inheritCollections.includes(props.collection) && __tableName !== props.collection;
|
|
98
|
+
return (
|
|
99
|
+
!flag && (
|
|
100
|
+
<BlockProvider {...props}>
|
|
101
|
+
<InternalFormBlockProvider {...props} />
|
|
102
|
+
</BlockProvider>
|
|
103
|
+
)
|
|
104
|
+
);
|
|
105
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { CollectionManagerContext, useHistoryCollectionsByNames } from '@nocobase/client';
|
|
2
|
+
import React, { useContext } from 'react';
|
|
3
|
+
|
|
4
|
+
export const SnapshotHistoryCollectionProvider: React.FC<{ collectionName: string }> = (props) => {
|
|
5
|
+
const { collectionName } = props;
|
|
6
|
+
const { collections: allCollections, ...rest } = useContext(CollectionManagerContext);
|
|
7
|
+
|
|
8
|
+
// 目标表
|
|
9
|
+
const snapshotTargetCollection = useHistoryCollectionsByNames([collectionName])?.[0];
|
|
10
|
+
// 目标如果是继承表则获取继承表
|
|
11
|
+
const inheritCollections = useHistoryCollectionsByNames(snapshotTargetCollection?.inherits ?? []);
|
|
12
|
+
// 目标表内关联字段的表
|
|
13
|
+
const associationFieldTargetCollections = useHistoryCollectionsByNames(
|
|
14
|
+
snapshotTargetCollection?.fields.filter((i) => i.interface !== 'snapshot').map((i) => i.target) ?? [],
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
// 替换表的集合
|
|
18
|
+
const finallyHistoryCollecionts = [
|
|
19
|
+
snapshotTargetCollection,
|
|
20
|
+
...associationFieldTargetCollections,
|
|
21
|
+
...inheritCollections,
|
|
22
|
+
].filter((i) => i);
|
|
23
|
+
|
|
24
|
+
// 过滤出不需要替换的表
|
|
25
|
+
const filterdAllCollection = allCollections.filter(
|
|
26
|
+
(c) => !finallyHistoryCollecionts.map((i) => i.name).includes(c.name),
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
// 最终替换后的表
|
|
30
|
+
const overridedCollections = [...filterdAllCollection, ...finallyHistoryCollecionts];
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<CollectionManagerContext.Provider
|
|
34
|
+
value={{
|
|
35
|
+
...rest,
|
|
36
|
+
collections: overridedCollections,
|
|
37
|
+
}}
|
|
38
|
+
>
|
|
39
|
+
{props.children}
|
|
40
|
+
</CollectionManagerContext.Provider>
|
|
41
|
+
);
|
|
42
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { connect, mapReadPretty, useFieldSchema } from '@formily/react';
|
|
3
|
+
import {
|
|
4
|
+
InputRecordPicker,
|
|
5
|
+
ReadPrettyRecordPicker,
|
|
6
|
+
useActionContext,
|
|
7
|
+
useCollection,
|
|
8
|
+
useCollectionHistory,
|
|
9
|
+
} from '@nocobase/client';
|
|
10
|
+
import { SnapshotHistoryCollectionProvider } from './SnapshotHistoryCollectionProvider';
|
|
11
|
+
|
|
12
|
+
const useSnapshotFieldTargetCollectionName = () => {
|
|
13
|
+
const fieldSchema = useFieldSchema();
|
|
14
|
+
const { getField } = useCollection();
|
|
15
|
+
const collectionField = getField(fieldSchema.name);
|
|
16
|
+
const { historyCollections } = useCollectionHistory();
|
|
17
|
+
return historyCollections.find((i) => i.name === collectionField.target)?.name;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const ReadPrettyRecordPickerWrapper = (props) => {
|
|
21
|
+
const collectionName = useSnapshotFieldTargetCollectionName();
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<SnapshotHistoryCollectionProvider collectionName={collectionName}>
|
|
25
|
+
<ReadPrettyRecordPicker {...props} />
|
|
26
|
+
</SnapshotHistoryCollectionProvider>
|
|
27
|
+
);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const SnapshotRecordPickerInner: any = connect(
|
|
31
|
+
(props) => {
|
|
32
|
+
const actionCtx = useActionContext();
|
|
33
|
+
|
|
34
|
+
const isUpdateAction = actionCtx.fieldSchema['x-action'] === 'update';
|
|
35
|
+
|
|
36
|
+
return isUpdateAction ? <ReadPrettyRecordPickerWrapper {...props} /> : <InputRecordPicker {...props} />;
|
|
37
|
+
},
|
|
38
|
+
// mapProps(mapSuffixProps),
|
|
39
|
+
mapReadPretty(ReadPrettyRecordPickerWrapper),
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
export const SnapshotRecordPicker = (props) => {
|
|
43
|
+
const { value, onChange, ...restProps } = props;
|
|
44
|
+
|
|
45
|
+
const newProps = {
|
|
46
|
+
...restProps,
|
|
47
|
+
value: value?.data,
|
|
48
|
+
onChange: (value) => onChange({ data: value }),
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
return <SnapshotRecordPickerInner {...newProps} />;
|
|
52
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CollectionHistoryProvider,
|
|
3
|
+
CollectionManagerProvider,
|
|
4
|
+
registerField,
|
|
5
|
+
SchemaComponentOptions,
|
|
6
|
+
SchemaInitializerContext,
|
|
7
|
+
SchemaInitializerProvider,
|
|
8
|
+
} from '@nocobase/client';
|
|
9
|
+
import React, { useContext, useState, useEffect } from 'react';
|
|
10
|
+
import { useSnapshotInterface } from './interface';
|
|
11
|
+
import { SnapshotRecordPicker } from './SnapshotRecordPicker';
|
|
12
|
+
import { SnapshotBlockInitializers } from './SnapshotBlock/SnapshotBlockInitializers/SnapshotBlockInitializers';
|
|
13
|
+
import { SnapshotBlockInitializersDetailItem } from './SnapshotBlock/SnapshotBlockInitializers/SnapshotBlockInitializersDetailItem';
|
|
14
|
+
import { SnapshotBlockProvider } from './SnapshotBlock/SnapshotBlockProvider';
|
|
15
|
+
|
|
16
|
+
export default React.memo((props) => {
|
|
17
|
+
const initializers = useContext(SchemaInitializerContext);
|
|
18
|
+
const snapshot = useSnapshotInterface();
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
registerField(snapshot.group, snapshot.name as string, snapshot);
|
|
22
|
+
}, []);
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<CollectionManagerProvider
|
|
26
|
+
interfaces={{
|
|
27
|
+
snapshot,
|
|
28
|
+
}}
|
|
29
|
+
>
|
|
30
|
+
<CollectionHistoryProvider>
|
|
31
|
+
<SchemaInitializerProvider
|
|
32
|
+
initializers={{
|
|
33
|
+
...initializers,
|
|
34
|
+
SnapshotBlockInitializers,
|
|
35
|
+
}}
|
|
36
|
+
>
|
|
37
|
+
<SchemaComponentOptions
|
|
38
|
+
components={{
|
|
39
|
+
SnapshotRecordPicker,
|
|
40
|
+
SnapshotBlockProvider,
|
|
41
|
+
SnapshotBlockInitializersDetailItem,
|
|
42
|
+
}}
|
|
43
|
+
>
|
|
44
|
+
{props.children}
|
|
45
|
+
</SchemaComponentOptions>
|
|
46
|
+
</SchemaInitializerProvider>
|
|
47
|
+
</CollectionHistoryProvider>
|
|
48
|
+
</CollectionManagerProvider>
|
|
49
|
+
);
|
|
50
|
+
});
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { ISchema } from '@formily/react';
|
|
2
|
+
import { IField } from '@nocobase/client';
|
|
3
|
+
import { cloneDeep } from 'lodash';
|
|
4
|
+
import { interfacesProperties } from '@nocobase/client';
|
|
5
|
+
import { useSnapshotTranslation } from './locale';
|
|
6
|
+
import { useMemo } from 'react';
|
|
7
|
+
|
|
8
|
+
const { defaultProps, recordPickerSelector } = interfacesProperties;
|
|
9
|
+
|
|
10
|
+
export const useSnapshotInterface = () => {
|
|
11
|
+
const { t } = useSnapshotTranslation();
|
|
12
|
+
|
|
13
|
+
const recordPickerViewer = {
|
|
14
|
+
type: 'void',
|
|
15
|
+
title: t('View record'),
|
|
16
|
+
'x-component': 'RecordPicker.Viewer',
|
|
17
|
+
'x-component-props': {
|
|
18
|
+
className: 'nb-action-popup',
|
|
19
|
+
},
|
|
20
|
+
properties: {
|
|
21
|
+
tabs: {
|
|
22
|
+
type: 'void',
|
|
23
|
+
'x-component': 'Tabs',
|
|
24
|
+
'x-component-props': {},
|
|
25
|
+
// 'x-initializer': 'TabPaneInitializers',
|
|
26
|
+
properties: {
|
|
27
|
+
tab1: {
|
|
28
|
+
type: 'void',
|
|
29
|
+
title: t('Detail'),
|
|
30
|
+
'x-component': 'Tabs.TabPane',
|
|
31
|
+
'x-designer': 'Tabs.Designer',
|
|
32
|
+
'x-component-props': {},
|
|
33
|
+
properties: {
|
|
34
|
+
grid: {
|
|
35
|
+
type: 'void',
|
|
36
|
+
'x-component': 'Grid',
|
|
37
|
+
'x-initializer': 'SnapshotBlockInitializers',
|
|
38
|
+
properties: {},
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const snapshot: IField = {
|
|
48
|
+
name: 'snapshot',
|
|
49
|
+
type: 'object',
|
|
50
|
+
group: 'advanced',
|
|
51
|
+
title: t('Snapshot'),
|
|
52
|
+
description: t('Snapshot to description'),
|
|
53
|
+
default: {
|
|
54
|
+
type: 'snapshot',
|
|
55
|
+
// name,
|
|
56
|
+
uiSchema: {
|
|
57
|
+
// title,
|
|
58
|
+
'x-component': 'SnapshotRecordPicker',
|
|
59
|
+
'x-component-props': {
|
|
60
|
+
// mode: 'tags',
|
|
61
|
+
multiple: true,
|
|
62
|
+
fieldNames: {
|
|
63
|
+
label: 'id',
|
|
64
|
+
value: 'id',
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
schemaInitialize(schema: ISchema, { field, readPretty, action, block }) {
|
|
70
|
+
if (readPretty || action === 'update') {
|
|
71
|
+
schema['properties'] = {
|
|
72
|
+
viewer: cloneDeep(recordPickerViewer),
|
|
73
|
+
};
|
|
74
|
+
} else {
|
|
75
|
+
schema['properties'] = {
|
|
76
|
+
selector: cloneDeep(recordPickerSelector),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
initialize: (values: any) => {},
|
|
81
|
+
properties: {
|
|
82
|
+
...defaultProps,
|
|
83
|
+
target: {
|
|
84
|
+
type: 'string',
|
|
85
|
+
title: t('Related collection'),
|
|
86
|
+
required: true,
|
|
87
|
+
'x-reactions': ['{{useAsyncDataSource(loadCollections)}}'],
|
|
88
|
+
'x-decorator': 'FormItem',
|
|
89
|
+
'x-component': 'Select',
|
|
90
|
+
'x-disabled': '{{ !createOnly }}',
|
|
91
|
+
},
|
|
92
|
+
'uiSchema.x-component-props.multiple': {
|
|
93
|
+
type: 'boolean',
|
|
94
|
+
'x-content': t('Allow linking to multiple records'),
|
|
95
|
+
'x-decorator': 'FormItem',
|
|
96
|
+
'x-component': 'Checkbox',
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
return useMemo<IField>(() => snapshot, [t]);
|
|
102
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
Detail: 'Detail',
|
|
3
|
+
Snapshot: 'Snapshot',
|
|
4
|
+
'View record': 'View record',
|
|
5
|
+
'Add block': 'Add block',
|
|
6
|
+
'Allow linking to multiple records': 'Allow linking to multiple records',
|
|
7
|
+
'Snapshot to description':
|
|
8
|
+
'It is used to create a snapshot of the table, save the current data of the pointed table, and save it only when the record to which it belongs is created, and will not be updated later.',
|
|
9
|
+
'Related collection': 'Related collection',
|
|
10
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { i18n } from '@nocobase/client';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
|
|
4
|
+
import enUS from './en-US';
|
|
5
|
+
import jaJP from './ja-JP';
|
|
6
|
+
import ruRU from './ru-RU';
|
|
7
|
+
import trTR from './tr-TR';
|
|
8
|
+
import zhCN from './zh-CN';
|
|
9
|
+
|
|
10
|
+
export const NAMESPACE = 'snapshot-field';
|
|
11
|
+
|
|
12
|
+
i18n.addResources('zh-CN', NAMESPACE, zhCN);
|
|
13
|
+
i18n.addResources('en-US', NAMESPACE, enUS);
|
|
14
|
+
i18n.addResources('ja-JP', NAMESPACE, jaJP);
|
|
15
|
+
i18n.addResources('ru-RU', NAMESPACE, ruRU);
|
|
16
|
+
i18n.addResources('tr-TR', NAMESPACE, trTR);
|
|
17
|
+
|
|
18
|
+
export function lang(key: string) {
|
|
19
|
+
return i18n.t(key, { ns: NAMESPACE });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function useSnapshotTranslation() {
|
|
23
|
+
return useTranslation(NAMESPACE);
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default {};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './server';
|
|
File without changes
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { CollectionOptions } from '@nocobase/database';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
name: 'collectionsHistory',
|
|
5
|
+
title: '数据表历史',
|
|
6
|
+
sortable: 'sort',
|
|
7
|
+
autoGenId: false,
|
|
8
|
+
model: 'CollectionModel',
|
|
9
|
+
repository: 'CollectionRepository',
|
|
10
|
+
timestamps: false,
|
|
11
|
+
filterTargetKey: 'name',
|
|
12
|
+
fields: [
|
|
13
|
+
{
|
|
14
|
+
type: 'uid',
|
|
15
|
+
name: 'key',
|
|
16
|
+
primaryKey: true,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
type: 'uid',
|
|
20
|
+
name: 'name',
|
|
21
|
+
unique: true,
|
|
22
|
+
prefix: 't_',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
type: 'string',
|
|
26
|
+
name: 'title',
|
|
27
|
+
required: true,
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
type: 'boolean',
|
|
31
|
+
name: 'inherit',
|
|
32
|
+
defaultValue: false,
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
type: 'boolean',
|
|
36
|
+
name: 'hidden',
|
|
37
|
+
defaultValue: false,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
type: 'json',
|
|
41
|
+
name: 'options',
|
|
42
|
+
defaultValue: {},
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
type: 'hasMany',
|
|
46
|
+
name: 'fields',
|
|
47
|
+
target: 'fieldsHistory',
|
|
48
|
+
sourceKey: 'name',
|
|
49
|
+
targetKey: 'name',
|
|
50
|
+
foreignKey: 'collectionName',
|
|
51
|
+
onDelete: 'CASCADE',
|
|
52
|
+
sortBy: 'sort',
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
} as CollectionOptions;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { CollectionOptions } from '@nocobase/database';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
name: 'fieldsHistory',
|
|
5
|
+
title: '{{t("Fields history")}}',
|
|
6
|
+
autoGenId: false,
|
|
7
|
+
model: 'FieldModel',
|
|
8
|
+
timestamps: false,
|
|
9
|
+
sortable: {
|
|
10
|
+
name: 'sort',
|
|
11
|
+
scopeKey: 'collectionName',
|
|
12
|
+
},
|
|
13
|
+
indexes: [
|
|
14
|
+
{
|
|
15
|
+
type: 'UNIQUE',
|
|
16
|
+
fields: ['collectionName', 'name'],
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
fields: [
|
|
20
|
+
{
|
|
21
|
+
type: 'uid',
|
|
22
|
+
name: 'key',
|
|
23
|
+
primaryKey: true,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
type: 'uid',
|
|
27
|
+
name: 'name',
|
|
28
|
+
prefix: 'f_',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
type: 'string',
|
|
32
|
+
name: 'type',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
type: 'string',
|
|
36
|
+
name: 'interface',
|
|
37
|
+
allowNull: true,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
type: 'belongsTo',
|
|
41
|
+
name: 'collection',
|
|
42
|
+
target: 'collectionsHistory',
|
|
43
|
+
foreignKey: 'collectionName',
|
|
44
|
+
targetKey: 'name',
|
|
45
|
+
onDelete: 'CASCADE',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
type: 'hasMany',
|
|
49
|
+
name: 'children',
|
|
50
|
+
target: 'fieldsHistory',
|
|
51
|
+
sourceKey: 'key',
|
|
52
|
+
foreignKey: 'parentKey',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
type: 'hasOne',
|
|
56
|
+
name: 'reverseField',
|
|
57
|
+
target: 'fieldsHistory',
|
|
58
|
+
sourceKey: 'key',
|
|
59
|
+
foreignKey: 'reverseKey',
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
type: 'belongsTo',
|
|
63
|
+
name: 'uiSchema',
|
|
64
|
+
target: 'uiSchemas',
|
|
65
|
+
foreignKey: 'uiSchemaUid',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
type: 'json',
|
|
69
|
+
name: 'options',
|
|
70
|
+
defaultValue: {},
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
} as CollectionOptions;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Field, BaseColumnFieldOptions } from '@nocobase/database';
|
|
2
|
+
import { DataTypes } from 'sequelize';
|
|
3
|
+
|
|
4
|
+
export class SnapshotField extends Field {
|
|
5
|
+
get dataType() {
|
|
6
|
+
return DataTypes.JSON;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface SnapshotFieldOptions extends BaseColumnFieldOptions {
|
|
11
|
+
type: 'snapshot';
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './plugin';
|