* chore: skip yarn install in pm command * feat: dump sub app by sub app name * feat: dump & restore by sub app * chore: enable application name to edit * chore: field belongsTo uiSchema * test: drop schema * feat: uiSchema migrator * fix: test * fix: remove uiSchema * fix: rerun migration * chore: migrate fieldsHistory uiSchema * fix: set uiSchema options * chore: transaction params * fix: sql error in mysql * fix: sql compatibility * feat: collection group api * chore: restore & dump action template * chore: tmp commit * chore: collectionGroupAction * feat: dumpableCollection api * refactor: dump command * fix: remove uiSchemaUid * chore: get uiSchemaUid from tmp field * feat: return dumped file url in dumper.dump * feat: dump api * refactor: collection groyoup * chore: comment * feat: restore command force option * feat: dump with collection groups * refactor: restore command * feat: restore http api * fix: test * fix: test * fix: restore test * chore: volta pin * fix: sub app load collection options * fix: stop sub app * feat: add stopped status to application to prevent duplicate application stop * chore: tmp commit * test: upgrade * feat: pass upgrade event to sub app * fix: app manager client * fix: remove stopped status * fix: emit beforeStop event * feat: support dump & restore subApp through api * chore: dumpable collections api * refactor: getTableNameWithSchema * fix: schema name * feat: cname * refactor: collection 同步实现方式 * refactor: move collection group manager to database * fix: test * fix: remove uiSchema * fix: uiSchema * fix: remove settings * chore: plugin enable & disable event * feat: modal warning * fix: users_jobs namespace * fix: rolesUischemas namespace * fix: am snippet * feat: beforeSubAppInstall event * fix: improve NOCOBASE_LOCALE_KEY & NOCOBASE_ROLE_KEY --------- Co-authored-by: chenos <chenlinxh@gmail.com>
95 lines
2.7 KiB
TypeScript
95 lines
2.7 KiB
TypeScript
import { Application } from '@nocobase/server';
|
|
import { applyMixins, AsyncEmitter } from '@nocobase/utils';
|
|
import crypto from 'crypto';
|
|
import EventEmitter from 'events';
|
|
import fsPromises from 'fs/promises';
|
|
import lodash from 'lodash';
|
|
import * as os from 'os';
|
|
import path from 'path';
|
|
import { CollectionGroupManager } from './collection-group-manager';
|
|
|
|
export type AppMigratorOptions = {
|
|
workDir?: string;
|
|
};
|
|
abstract class AppMigrator extends EventEmitter {
|
|
protected workDir: string;
|
|
public app: Application;
|
|
|
|
abstract direction: 'restore' | 'dump';
|
|
|
|
declare emitAsync: (event: string | symbol, ...args: any[]) => Promise<boolean>;
|
|
|
|
constructor(app, options?: AppMigratorOptions) {
|
|
super();
|
|
|
|
this.app = app;
|
|
this.workDir = options?.workDir || this.tmpDir();
|
|
}
|
|
|
|
tmpDir() {
|
|
return path.resolve(os.tmpdir(), `nocobase-${crypto.randomUUID()}`);
|
|
}
|
|
|
|
getPluginCollections(plugins: string | string[]) {
|
|
return lodash
|
|
.castArray(plugins)
|
|
.map((pluginName) => {
|
|
return this.app.db.importedFrom.get(pluginName) || [];
|
|
})
|
|
.flat();
|
|
}
|
|
|
|
async getAppPlugins() {
|
|
const plugins = await this.app.db.getCollection('applicationPlugins').repository.find();
|
|
|
|
return lodash.uniq(['core', ...this.app.pm.plugins.keys(), ...plugins.map((plugin) => plugin.get('name'))]);
|
|
}
|
|
|
|
async getAppPluginCollectionGroups() {
|
|
const plugins = await this.getAppPlugins();
|
|
return CollectionGroupManager.collectionGroups.filter((collectionGroup) =>
|
|
plugins.includes(collectionGroup.namespace),
|
|
);
|
|
}
|
|
|
|
async getCustomCollections() {
|
|
const collections = await this.app.db.getCollection('collections').repository.find();
|
|
return collections.filter((collection) => !collection.get('isThrough')).map((collection) => collection.get('name'));
|
|
}
|
|
|
|
async rmDir(dir: string) {
|
|
await fsPromises.rm(dir, { recursive: true, force: true });
|
|
}
|
|
|
|
async clearWorkDir() {
|
|
await this.rmDir(this.workDir);
|
|
}
|
|
|
|
findThroughCollections(collections: string[]) {
|
|
return [
|
|
...new Set(
|
|
collections
|
|
.map((collectionName) => this.app.db.getCollection(collectionName))
|
|
.map((collection) =>
|
|
[...collection.fields.values()].filter((field) => field.through).map((field) => field.through),
|
|
)
|
|
.flat(),
|
|
),
|
|
];
|
|
}
|
|
|
|
findSequenceFields(collections: string[]) {
|
|
return [
|
|
...new Set(
|
|
collections
|
|
.map((collectionName) => this.app.db.getCollection(collectionName))
|
|
.map((collection) => [...collection.fields.values()].filter((field) => field.type === 'sequence'))
|
|
.flat(),
|
|
),
|
|
];
|
|
}
|
|
}
|
|
|
|
applyMixins(AppMigrator, [AsyncEmitter]);
|
|
export { AppMigrator };
|