diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index 58e06fe30..75aecc112 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -35,9 +35,9 @@ const api = new Server({ }); const plugins = [ - '@nocobase/plugin-collections', '@nocobase/plugin-ui-router', '@nocobase/plugin-ui-schema', + '@nocobase/plugin-collections', '@nocobase/plugin-users', '@nocobase/plugin-action-logs', '@nocobase/plugin-file-manager', diff --git a/packages/app/package.json b/packages/app/package.json index 529e8ce4d..f44da2545 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -36,7 +36,7 @@ "@nocobase/plugin-ui-router": "^0.4.0-alpha.7", "@nocobase/plugin-ui-schema": "^0.4.0-alpha.7", "@nocobase/plugin-users": "^0.4.0-alpha.7", - "@nocobase/plugin-saas": "^0.4.0-alpha.7", + "@nocobase/plugin-multi-apps": "^0.4.0-alpha.7", "@nocobase/server": "^0.4.0-alpha.7", "@umijs/preset-react": "1.x", "koa-mount": "^4.0.0", diff --git a/packages/app/src/apis/index.ts b/packages/app/src/apis/index.ts index bdb3a2c2f..5aede5b64 100644 --- a/packages/app/src/apis/index.ts +++ b/packages/app/src/apis/index.ts @@ -41,9 +41,9 @@ const api = new Server({ }); const plugins = [ - '@nocobase/plugin-saas', - '@nocobase/plugin-ui-schema', + '@nocobase/plugin-multi-apps', '@nocobase/plugin-ui-router', + '@nocobase/plugin-ui-schema', '@nocobase/plugin-collections', '@nocobase/plugin-users', '@nocobase/plugin-action-logs', diff --git a/packages/app/src/pages/index.tsx b/packages/app/src/pages/index.tsx index be4e3c722..62595b2b8 100644 --- a/packages/app/src/pages/index.tsx +++ b/packages/app/src/pages/index.tsx @@ -8,8 +8,9 @@ import { AdminLayout, AuthLayout, RouteSchemaRenderer, + ConfigProvider, + ClientSDK, } from '@nocobase/client'; -import { UseRequestProvider } from 'ahooks'; import { extend } from 'umi-request'; const request = extend({ @@ -26,6 +27,8 @@ request.use(async (ctx, next) => { await next(); }); +const client = new ClientSDK({ request }); + const RouteSwitch = createRouteSwitch({ components: { AdminLayout, @@ -52,12 +55,8 @@ const App = () => { export default function IndexPage() { return ( - request(service), - }} - > + - + ); } diff --git a/packages/collections/src/database.ts b/packages/collections/src/database.ts index 5aae72e00..64acf66de 100644 --- a/packages/collections/src/database.ts +++ b/packages/collections/src/database.ts @@ -133,7 +133,15 @@ export class Database extends EventEmitter { } async sync(options?: SyncOptions) { - return this.sequelize.sync(options); + const isMySQL = this.sequelize.getDialect() === 'mysql'; + if (isMySQL) { + await this.sequelize.query('SET FOREIGN_KEY_CHECKS = 0', null); + } + const result = await this.sequelize.sync(options); + if (isMySQL) { + await this.sequelize.query('SET FOREIGN_KEY_CHECKS = 1', null); + } + return result; } async close() { diff --git a/packages/database/src/database.ts b/packages/database/src/database.ts index eee4f26d9..d9ad5782a 100644 --- a/packages/database/src/database.ts +++ b/packages/database/src/database.ts @@ -465,6 +465,33 @@ type HookType = return this.sequelize.close(); } + /** + * 添加 hook + * + * @param hookType + * @param fn + */ + public addHook(hookType: HookType | string, fn: Function) { + const hooks = this.hooks[hookType] || []; + hooks.push(fn); + this.hooks[hookType] = hooks; + } + + /** + * 运行 hook + * + * @param hookType + * @param args + */ + public async runHooks(hookType: HookType | string, ...args) { + const hooks = this.hooks[hookType] || []; + for (const hook of hooks) { + if (typeof hook === 'function') { + await hook(...args); + } + } + } + public getFieldByPath(fieldPath: string) { const [tableName, fieldName] = fieldPath.split('.'); return this.getTable(tableName).getField(fieldName); diff --git a/packages/database/src/model.ts b/packages/database/src/model.ts index 0caffbe97..0d734adcf 100644 --- a/packages/database/src/model.ts +++ b/packages/database/src/model.ts @@ -534,8 +534,6 @@ export abstract class Model extends SequelizeModel { ...options, transaction, }); - // @ts-ignore - // await this.sequelize.runHooks('afterUpdateAssociations', this, options); if (!options.transaction) { await transaction.commit(); diff --git a/packages/database/src/table.ts b/packages/database/src/table.ts index c2d3e007d..47d54c59c 100644 --- a/packages/database/src/table.ts +++ b/packages/database/src/table.ts @@ -139,6 +139,7 @@ export class Table { constructor(options: TableOptions, context: TabelContext) { const { database } = context; + database.runHooks('beforeTableInit', options); database.emit('beforeTableInit', options); const { model, @@ -158,6 +159,7 @@ export class Table { this.setFields(fields); this.initSortable(); database.emit('afterTableInit', this); + database.runHooks('afterTableInit', this); } public initSortable() { @@ -313,6 +315,7 @@ export class Table { * @param reinitialize */ public addField(options: FieldOptions, reinitialize: Reinitialize = true) { + this.database.runHooks('beforeAddField', options, this); this.database.emit('beforeAddField', options, this); const { name, index } = options; const field = buildField(options, { @@ -350,6 +353,7 @@ export class Table { } this.modelInit(reinitialize); this.database.emit('afterAddField', field, this); + this.database.runHooks('afterAddField', field, this); return field; } diff --git a/packages/plugin-collections/src/server.ts b/packages/plugin-collections/src/server.ts index b9a53eed8..5ff485d1b 100644 --- a/packages/plugin-collections/src/server.ts +++ b/packages/plugin-collections/src/server.ts @@ -5,31 +5,40 @@ import * as models from './models'; import { createOrUpdate, findAll } from './actions'; import { create } from './actions/fields'; +registerModels(models); + export default { name: 'collections', async load(this: Plugin) { const database = this.app.db; - registerModels(models); - database.import({ directory: path.resolve(__dirname, 'collections'), }); this.app.on('beforeStart', async () => { - await database.getModel('collections').load(); + await database.getModel('collections').load({ + skipExisting: true, + }); }); this.app.on('db.init', async () => { - const userTable = database.getTable('users'); - const config = userTable.getOptions(); + const tableNames = ['users', 'applications']; const Collection = database.getModel('collections'); - const collection = await Collection.create(config); - await collection.updateAssociations({ - generalFields: config.fields.filter((field) => field.state !== 0), - systemFields: config.fields.filter((field) => field.state === 0), - }); - await collection.migrate(); + for (const tableName of tableNames) { + const table = database.getTable(tableName); + console.log(tableName, table); + if (!table) { + continue; + } + const config = table.getOptions(); + const collection = await Collection.create(config); + await collection.updateAssociations({ + generalFields: config.fields.filter((field) => field.state !== 0), + systemFields: config.fields.filter((field) => field.state === 0), + }); + // await collection.migrate(); + } }); const [Collection, Field] = database.getModels(['collections', 'fields']); diff --git a/packages/plugin-saas/.gitignore b/packages/plugin-multi-apps/.gitignore similarity index 100% rename from packages/plugin-saas/.gitignore rename to packages/plugin-multi-apps/.gitignore diff --git a/packages/plugin-saas/.npmignore b/packages/plugin-multi-apps/.npmignore similarity index 100% rename from packages/plugin-saas/.npmignore rename to packages/plugin-multi-apps/.npmignore diff --git a/packages/plugin-saas/package.json b/packages/plugin-multi-apps/package.json similarity index 89% rename from packages/plugin-saas/package.json rename to packages/plugin-multi-apps/package.json index ac9f3792d..e47d03ede 100644 --- a/packages/plugin-saas/package.json +++ b/packages/plugin-multi-apps/package.json @@ -1,5 +1,5 @@ { - "name": "@nocobase/plugin-saas", + "name": "@nocobase/plugin-multi-apps", "version": "0.4.0-alpha.7", "main": "lib/index.js", "license": "MIT", diff --git a/packages/plugin-saas/src/index.ts b/packages/plugin-multi-apps/src/index.ts similarity index 100% rename from packages/plugin-saas/src/index.ts rename to packages/plugin-multi-apps/src/index.ts diff --git a/packages/plugin-saas/src/server.ts b/packages/plugin-multi-apps/src/server.ts similarity index 82% rename from packages/plugin-saas/src/server.ts rename to packages/plugin-multi-apps/src/server.ts index 8a77572a7..5ae7a5d4f 100644 --- a/packages/plugin-saas/src/server.ts +++ b/packages/plugin-multi-apps/src/server.ts @@ -31,6 +31,7 @@ function createApp(opts) { }, }, }, + // 不能再 bodyParser,会卡死 bodyParser: false, // dataWrapping: false, resourcer: { @@ -40,9 +41,8 @@ function createApp(opts) { const app = new Application(options); app.db.sequelize.beforeDefine((model, options) => { - options.tableName = `saas_${name}_${ - options.tableName || options.name.plural - }`; + options.tableName = `saas_${name}_${options.tableName || options.name.plural + }`; }); app.resource({ @@ -126,9 +126,19 @@ export default { this.app['apps'] = new Map(); this.app.collection({ name: 'applications', + title: '应用', fields: [ - { type: 'string', name: 'name', unique: true }, - { type: 'belongsTo', name: 'user' }, + { + type: 'string', + name: 'name', + interface: 'string', + unique: true, + uiSchema: { + type: 'string', + title: '名称', + 'x-component': 'Input', + }, + }, ], }); this.app.use( @@ -138,6 +148,23 @@ export default { }, }), ); + this.app.db.on('applications.afterCreate', async (model) => { + const name = model.get('name'); + const app = createApp({ + name, + }); + (async () => { + await app.load(); + await app.db.sync({ + force: true, + alter: { + drop: true, + }, + }); + await app.emitAsync('db.init'); + await app.destroy(); + })() + }); this.app .command('app:create') .argument('')