@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.
Files changed (64) hide show
  1. package/LICENSE +201 -0
  2. package/client.d.ts +4 -0
  3. package/client.js +30 -0
  4. package/lib/client/SnapshotBlock/SnapshotBlockInitializers/SnapshotBlockInitializers.d.ts +1 -0
  5. package/lib/client/SnapshotBlock/SnapshotBlockInitializers/SnapshotBlockInitializers.js +99 -0
  6. package/lib/client/SnapshotBlock/SnapshotBlockInitializers/SnapshotBlockInitializersDetailItem.d.ts +57 -0
  7. package/lib/client/SnapshotBlock/SnapshotBlockInitializers/SnapshotBlockInitializersDetailItem.js +190 -0
  8. package/lib/client/SnapshotBlock/SnapshotBlockProvider.d.ts +1 -0
  9. package/lib/client/SnapshotBlock/SnapshotBlockProvider.js +160 -0
  10. package/lib/client/SnapshotHistoryCollectionProvider.d.ts +4 -0
  11. package/lib/client/SnapshotHistoryCollectionProvider.js +72 -0
  12. package/lib/client/SnapshotRecordPicker.d.ts +1 -0
  13. package/lib/client/SnapshotRecordPicker.js +99 -0
  14. package/lib/client/index.d.ts +3 -0
  15. package/lib/client/index.js +71 -0
  16. package/lib/client/interface.d.ts +2 -0
  17. package/lib/client/interface.js +148 -0
  18. package/lib/client/locale/en-US.d.ts +10 -0
  19. package/lib/client/locale/en-US.js +16 -0
  20. package/lib/client/locale/index.d.ts +3 -0
  21. package/lib/client/locale/index.js +63 -0
  22. package/lib/client/locale/ja-JP.d.ts +2 -0
  23. package/lib/client/locale/ja-JP.js +8 -0
  24. package/lib/client/locale/ru-RU.d.ts +2 -0
  25. package/lib/client/locale/ru-RU.js +8 -0
  26. package/lib/client/locale/tr-TR.d.ts +2 -0
  27. package/lib/client/locale/tr-TR.js +8 -0
  28. package/lib/client/locale/zh-CN.d.ts +10 -0
  29. package/lib/client/locale/zh-CN.js +16 -0
  30. package/lib/index.d.ts +1 -0
  31. package/lib/index.js +15 -0
  32. package/lib/server/collections/collectionsHistory.d.ts +3 -0
  33. package/lib/server/collections/collectionsHistory.js +52 -0
  34. package/lib/server/collections/fieldsHistory.d.ts +3 -0
  35. package/lib/server/collections/fieldsHistory.js +66 -0
  36. package/lib/server/fields/snapshot-field.d.ts +8 -0
  37. package/lib/server/fields/snapshot-field.js +35 -0
  38. package/lib/server/index.d.ts +1 -0
  39. package/lib/server/index.js +15 -0
  40. package/lib/server/plugin.d.ts +11 -0
  41. package/lib/server/plugin.js +190 -0
  42. package/package.json +10 -0
  43. package/server.d.ts +4 -0
  44. package/server.js +30 -0
  45. package/src/client/SnapshotBlock/SnapshotBlockInitializers/SnapshotBlockInitializers.tsx +78 -0
  46. package/src/client/SnapshotBlock/SnapshotBlockInitializers/SnapshotBlockInitializersDetailItem.tsx +121 -0
  47. package/src/client/SnapshotBlock/SnapshotBlockProvider.tsx +105 -0
  48. package/src/client/SnapshotHistoryCollectionProvider.tsx +42 -0
  49. package/src/client/SnapshotRecordPicker.tsx +52 -0
  50. package/src/client/index.tsx +50 -0
  51. package/src/client/interface.ts +102 -0
  52. package/src/client/locale/en-US.ts +10 -0
  53. package/src/client/locale/index.ts +24 -0
  54. package/src/client/locale/ja-JP.ts +1 -0
  55. package/src/client/locale/ru-RU.ts +1 -0
  56. package/src/client/locale/tr-TR.ts +1 -0
  57. package/src/client/locale/zh-CN.ts +9 -0
  58. package/src/index.ts +1 -0
  59. package/src/server/collections/.gitkeep +0 -0
  60. package/src/server/collections/collectionsHistory.ts +55 -0
  61. package/src/server/collections/fieldsHistory.ts +73 -0
  62. package/src/server/fields/snapshot-field.ts +12 -0
  63. package/src/server/index.ts +1 -0
  64. package/src/server/plugin.ts +110 -0
@@ -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 {};
@@ -0,0 +1,9 @@
1
+ export default {
2
+ Detail: '详情',
3
+ Snapshot: '快照',
4
+ 'Add block': '创建区块',
5
+ 'Snapshot to description': '用于创建表的快照,保存指向的表的当前数据,仅在其所属的记录创建时保存,后续不再更新。',
6
+ 'View record': '查看数据',
7
+ 'Allow linking to multiple records': '允许关联多条记录',
8
+ 'Related collection': '关系表',
9
+ };
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';