From 69da6a340fcb621b78d5105202ab6cef3b88a659 Mon Sep 17 00:00:00 2001 From: chenos Date: Sat, 30 Apr 2022 23:41:01 +0800 Subject: [PATCH] feat: improve code (#350) --- packages/app/client/src/pages/index.tsx | 4 ++++ .../__tests__/multiple-application.test.ts | 5 ++++ packages/core/server/src/app-manager.ts | 21 +++++++++++++---- .../src/collections/applications.ts | 15 ++++++++++++ .../src/models/application.ts | 23 +++++++++++++++---- .../plugins/multi-app-manager/src/server.ts | 10 ++++++-- 6 files changed, 68 insertions(+), 10 deletions(-) diff --git a/packages/app/client/src/pages/index.tsx b/packages/app/client/src/pages/index.tsx index 8e3631246..b914c081e 100644 --- a/packages/app/client/src/pages/index.tsx +++ b/packages/app/client/src/pages/index.tsx @@ -45,6 +45,10 @@ import apiClient from './apiClient'; apiClient.axios.interceptors.response.use( (response) => response, (error) => { + const redirectTo = error?.response?.data?.redirectTo; + if (redirectTo) { + return window.location.href = redirectTo; + } notification.error({ message: error?.response?.data?.errors?.map?.((error: any) => { return
{error.message}
; diff --git a/packages/core/server/src/__tests__/multiple-application.test.ts b/packages/core/server/src/__tests__/multiple-application.test.ts index 49d546b1a..fd173753a 100644 --- a/packages/core/server/src/__tests__/multiple-application.test.ts +++ b/packages/core/server/src/__tests__/multiple-application.test.ts @@ -99,5 +99,10 @@ describe('multiple application', () => { app: 'sub2', }); expect(response.statusCode).toEqual(200); + + response = await app.agent().resource('test').test({ + app: 'sub3', + }); + expect(response.statusCode).toEqual(404); }); }); diff --git a/packages/core/server/src/app-manager.ts b/packages/core/server/src/app-manager.ts index 31b4def7f..2a0187c68 100644 --- a/packages/core/server/src/app-manager.ts +++ b/packages/core/server/src/app-manager.ts @@ -1,6 +1,6 @@ import { applyMixins, AsyncEmitter } from '@nocobase/utils'; import EventEmitter from 'events'; -import http, { IncomingMessage } from 'http'; +import http, { IncomingMessage, ServerResponse } from 'http'; import Application, { ApplicationOptions } from './application'; type AppSelector = (req: IncomingMessage) => Application | string | undefined | null; @@ -62,11 +62,24 @@ export class AppManager extends EventEmitter { } callback() { - return async (req, res) => { - let handleApp = this.appSelector(req) || this.app; + return async (req: IncomingMessage, res: ServerResponse) => { + let handleApp: any = this.appSelector(req) || this.app; if (typeof handleApp === 'string') { - handleApp = (await this.getApplication(handleApp)) || this.app; + handleApp = await this.getApplication(handleApp); + if (!handleApp) { + res.statusCode = 404; + return res.end( + JSON.stringify({ + redirectTo: process.env.APP_NOT_FOUND_REDIRECT_TO, + errors: [ + { + message: 'Not Found', + }, + ], + }), + ); + } } handleApp.callback()(req, res); diff --git a/packages/plugins/multi-app-manager/src/collections/applications.ts b/packages/plugins/multi-app-manager/src/collections/applications.ts index 969fb3e32..e98ac6e17 100644 --- a/packages/plugins/multi-app-manager/src/collections/applications.ts +++ b/packages/plugins/multi-app-manager/src/collections/applications.ts @@ -21,6 +21,21 @@ export default defineCollection({ 'x-read-pretty': true, }, }, + { + type: 'string', + name: 'status', + interface: 'radioGroup', + defaultValue: 'pending', + uiSchema: { + type: 'string', + title: '{{t("Application status")}}', + 'x-component': 'Radio.Group', + enum: [ + { label: '创建中', value: 'pending' }, + { label: '运行中', value: 'running' }, + ], + }, + }, { type: 'json', name: 'options', diff --git a/packages/plugins/multi-app-manager/src/models/application.ts b/packages/plugins/multi-app-manager/src/models/application.ts index da449e59b..56a269398 100644 --- a/packages/plugins/multi-app-manager/src/models/application.ts +++ b/packages/plugins/multi-app-manager/src/models/application.ts @@ -30,14 +30,16 @@ export class ApplicationModel extends Model { const appName = this.get('name') as string; const appOptions = (this.get('options') as any) || {}; + const AppModel = this.constructor as typeof ApplicationModel; + const app = mainApp.appManager.createApplication(appName, { - ...ApplicationModel.initOptions(appName, mainApp), + ...AppModel.initOptions(appName, mainApp), ...appOptions, }); // create database before installation if it not exists app.on('beforeInstall', async function createDatabase() { - const { host, port, username, password, database, dialect } = ApplicationModel.getDatabaseConfig(app); + const { host, port, username, password, database, dialect } = AppModel.getDatabaseConfig(app); if (dialect === 'mysql') { const mysql = require('mysql2/promise'); @@ -66,11 +68,24 @@ export class ApplicationModel extends Model { } }); - await ApplicationModel.handleAppStart(app, options); + await AppModel.handleAppStart(app, options); + + await AppModel.update( + { + status: 'running', + }, + { + transaction: options.transaction, + where: { + [AppModel.primaryKeyAttribute]: this.get(AppModel.primaryKeyAttribute), + }, + hooks: false, + }, + ); } static initOptions(appName: string, mainApp: Application) { - const rawDatabaseOptions = ApplicationModel.getDatabaseConfig(mainApp); + const rawDatabaseOptions = this.getDatabaseConfig(mainApp); if (rawDatabaseOptions.dialect === 'sqlite') { const mainAppStorage = rawDatabaseOptions.storage; diff --git a/packages/plugins/multi-app-manager/src/server.ts b/packages/plugins/multi-app-manager/src/server.ts index e19f00025..eeca27b1b 100644 --- a/packages/plugins/multi-app-manager/src/server.ts +++ b/packages/plugins/multi-app-manager/src/server.ts @@ -1,13 +1,19 @@ -import { Plugin } from '@nocobase/server'; +import { AppManager, InstallOptions, Plugin } from '@nocobase/server'; import { resolve } from 'path'; import { ApplicationModel } from './models/application'; -import { AppManager } from '@nocobase/server'; export class PluginMultiAppManager extends Plugin { getName(): string { return this.getPackageName(__dirname); } + async install(options?: InstallOptions) { + const repo = this.db.getRepository('collections'); + if (repo) { + await repo.db2cm('applications'); + } + } + async load() { this.db.registerModels({ ApplicationModel,