diff --git a/packages/api/src/migrations/sync.ts b/packages/api/src/migrations/sync.ts new file mode 100644 index 000000000..2a469dfb7 --- /dev/null +++ b/packages/api/src/migrations/sync.ts @@ -0,0 +1,11 @@ +import Database from '@nocobase/database'; +import api from '../app'; + +(async () => { + await api.loadPlugins(); + const database: Database = api.database; + await database.sync({ + // tables: ['collections', 'fields', 'actions', 'views', 'tabs'], + }); + await database.close(); +})(); diff --git a/packages/client/src/constate/Collections.ts b/packages/client/src/constate/Collections.ts index 512e2c468..7d53b9e46 100644 --- a/packages/client/src/constate/Collections.ts +++ b/packages/client/src/constate/Collections.ts @@ -10,6 +10,12 @@ const [CollectionsProvider, useCollectionsContext] = constate(() => { findCollection(name) { return result?.data?.find((item) => item.name === name); }, + async loadCollections(field: any) { + return result?.data?.map((item: any) => ({ + label: item.title, + value: item.name, + })); + }, getFieldsByCollection(collectionName) { const collection = result?.data?.find((item) => item.name === collectionName); return collection?.generalFields; diff --git a/packages/client/src/schemas/add-new/index.tsx b/packages/client/src/schemas/add-new/index.tsx index 6135815a0..ba0546845 100644 --- a/packages/client/src/schemas/add-new/index.tsx +++ b/packages/client/src/schemas/add-new/index.tsx @@ -1370,6 +1370,7 @@ AddNew.FormItem = observer((props: any) => { const { schema, insertBefore, insertAfter, appendChild, deepRemove } = useDesignable(); const path = useSchemaPath(); + const { loadCollections } = useCollectionsContext(); const { collection, fields, refresh } = useCollectionContext(); const [visible, setVisible] = useState(false); const displayed = useDisplayedMapContext(); @@ -1562,7 +1563,7 @@ AddNew.FormItem = observer((props: any) => { const values = await FormDialog(`添加字段`, () => { return ( - + ); }).open({ diff --git a/packages/client/src/schemas/table/index.tsx b/packages/client/src/schemas/table/index.tsx index b5bd84b1a..f8ab0e596 100644 --- a/packages/client/src/schemas/table/index.tsx +++ b/packages/client/src/schemas/table/index.tsx @@ -405,6 +405,7 @@ const useTableColumns = () => { function AddColumn() { const [visible, setVisible] = useState(false); const { appendChild, remove } = useDesignable(); + const { loadCollections } = useCollectionsContext(); const { collection, fields, refresh } = useCollectionContext(); const displayed = useDisplayedMapContext(); const { service } = useTable(); @@ -592,7 +593,7 @@ function AddColumn() { const values = await FormDialog(`添加字段`, () => { return ( - + ); }).open({ diff --git a/packages/plugin-action-logs/src/server.ts b/packages/plugin-action-logs/src/server.ts index 9f46c66f9..1dc8346d4 100644 --- a/packages/plugin-action-logs/src/server.ts +++ b/packages/plugin-action-logs/src/server.ts @@ -18,40 +18,40 @@ export default async function() { addAll(database.getModel(table.options.name)); }); - const Collection = database.getModel('collections'); - Collection.addHook('afterCreate', async (model, options) => { - if (!model.get('logging')) { - return; - } + // const Collection = database.getModel('collections'); + // Collection.addHook('afterCreate', async (model, options) => { + // if (!model.get('logging')) { + // return; + // } - const { transaction = await model.sequelize.transaction() } = options; + // const { transaction = await model.sequelize.transaction() } = options; - const exists = await model.countFields({ - where: { - dataType: { [Op.iLike]: 'hasMany' }, - name: 'action_logs' - }, - transaction - }); + // const exists = await model.countFields({ + // where: { + // dataType: { [Op.iLike]: 'hasMany' }, + // name: 'action_logs' + // }, + // transaction + // }); - if (!exists) { - await model.createSystemField({ - interface: 'linkTo', - dataType: 'hasMany', - name: 'action_logs', - target: 'action_logs', - title: '数据动态', - foreignKey: 'index', - state: 0, - scope: { - collection_name: model.get('name') - }, - constraints: false - }, { transaction }); - } + // if (!exists) { + // await model.createSystemField({ + // interface: 'linkTo', + // dataType: 'hasMany', + // name: 'action_logs', + // target: 'action_logs', + // title: '数据动态', + // foreignKey: 'index', + // state: 0, + // scope: { + // collection_name: model.get('name') + // }, + // constraints: false + // }, { transaction }); + // } - if (!options.transaction) { - await transaction.commit(); - } - }); + // if (!options.transaction) { + // await transaction.commit(); + // } + // }); } diff --git a/packages/plugin-collections/src/actions/fields.ts b/packages/plugin-collections/src/actions/fields.ts index 15c0b2c01..048b834b7 100644 --- a/packages/plugin-collections/src/actions/fields.ts +++ b/packages/plugin-collections/src/actions/fields.ts @@ -6,6 +6,7 @@ import { cloneDeep, omit } from 'lodash'; export const create = async (ctx: actions.Context, next: actions.Next) => { await actions.common.create(ctx, async () => {}); const { associated } = ctx.action.params; + await ctx.body.generateReverseField(); await associated.migrate(); // console.log('associated.migrate'); await next(); diff --git a/packages/plugin-collections/src/actions/index.ts b/packages/plugin-collections/src/actions/index.ts index 063005edb..f2b2fc893 100644 --- a/packages/plugin-collections/src/actions/index.ts +++ b/packages/plugin-collections/src/actions/index.ts @@ -38,6 +38,17 @@ export const createOrUpdate = async (ctx: actions.Context, next: actions.Next) = }) } await collection.updateAssociations(values); + + const fields = await collection.getGeneralFields({ + where: { + interface: 'linkTo', + } + }); + + for (const field of fields) { + await field.generateReverseField(); + } + await collection.migrate(); } catch (error) { // console.log('error.errors', error.errors) diff --git a/packages/plugin-collections/src/collections/fields.ts b/packages/plugin-collections/src/collections/fields.ts index 747860845..81bb8ce25 100644 --- a/packages/plugin-collections/src/collections/fields.ts +++ b/packages/plugin-collections/src/collections/fields.ts @@ -46,12 +46,18 @@ export default { foreignKey: 'parentKey', }, { - interface: 'linkTo', type: 'belongsTo', name: 'collection', target: 'collections', targetKey: 'name', }, + { + type: 'belongsTo', + name: 'reverseField', + target: 'fields', + sourceKey: 'key', + foreignKey: 'reverseKey', + }, { type: 'belongsTo', name: 'uiSchema', diff --git a/packages/plugin-collections/src/models/field.ts b/packages/plugin-collections/src/models/field.ts index 793d24f53..e3f1d6fd0 100644 --- a/packages/plugin-collections/src/models/field.ts +++ b/packages/plugin-collections/src/models/field.ts @@ -48,4 +48,54 @@ export class Field extends Model { } return items; } + + async generateReverseField(opts: any = {}) { + const { migrate = true } = opts; + if (this.get('interface') !== 'linkTo') { + return; + } + if (this.get('reverseKey')) { + return; + } + const fieldCollection = await this.getCollection(); + const options: any = this.get('options') || {}; + const Collection = this.database.getModel('collections'); + let collection = await Collection.findOne({ + where: { + name: options.target, + }, + }); + if (!collection) { + return; + } + const reverseField = await collection.createField({ + interface: 'linkTo', + dataType: 'belongsToMany', + through: options.through, + foreignKey: options.otherKey, + otherKey: options.foreignKey, + sourceKey: options.targetKey, + targetKey: options.sourceKey, + target: this.get('collection_name'), + reverseKey: this.get('key'), + }); + await reverseField.updateAssociations({ + uiSchema: { + type: 'array', + title: `${fieldCollection?.title}`, + 'x-component': 'Select.Drawer', + 'x-component-props': { + multiple: true, + }, + 'x-decorator': 'FormItem', + 'x-designable-bar': 'Select.Drawer.DesignableBar', + } + }); + await this.update({ + reverseKey: reverseField.key, + }); + if (migrate) { + await collection.migrate(); + } + } } diff --git a/packages/plugin-collections/src/server.ts b/packages/plugin-collections/src/server.ts index b20a8f5b5..08b1a7df2 100644 --- a/packages/plugin-collections/src/server.ts +++ b/packages/plugin-collections/src/server.ts @@ -1,6 +1,6 @@ import path from 'path'; import { Application } from '@nocobase/server'; -import { registerModels, Table } from '@nocobase/database'; +import { registerModels, Table, uid } from '@nocobase/database'; import * as models from './models'; import { createOrUpdate, findAll } from './actions'; import { create } from './actions/fields'; @@ -27,6 +27,7 @@ export default async function (this: Application, options = {}) { } }); Field.beforeUpdate(async (model) => { + console.log('beforeUpdate', model.key); if (!model.get('collection_name') && model.get('parentKey')) { const field = await Field.findByPk(model.get('parentKey')); if (field) { @@ -37,8 +38,8 @@ export default async function (this: Application, options = {}) { } } }); - Field.afterCreate(async (model) => { - console.log('afterCreate'); + Field.afterCreate(async (model, options) => { + console.log('afterCreate', model.key, model.get('collection_name')); if (model.get('interface') !== 'subTable') { return; }