feat: add namespace and duplicator parameters for collection options (#1449)
* feat: add namespace and duplicator parameters for collection options * fix: duplicator:getDict
This commit is contained in:
parent
2cfdfd2084
commit
e5e503fe87
@ -7,7 +7,7 @@ import {
|
||||
QueryInterfaceDropTableOptions,
|
||||
SyncOptions,
|
||||
Transactionable,
|
||||
Utils,
|
||||
Utils
|
||||
} from 'sequelize';
|
||||
import { Database } from './database';
|
||||
import { Field, FieldOptions } from './fields';
|
||||
@ -307,6 +307,7 @@ export class Collection<
|
||||
updateOptions(options: CollectionOptions, mergeOptions?: any) {
|
||||
let newOptions = lodash.cloneDeep(options);
|
||||
newOptions = merge(this.options, newOptions, mergeOptions);
|
||||
this.options = newOptions;
|
||||
|
||||
this.context.database.emit('beforeUpdateCollection', this, newOptions);
|
||||
|
||||
|
@ -15,7 +15,7 @@ import {
|
||||
Sequelize,
|
||||
SyncOptions,
|
||||
Transactionable,
|
||||
Utils,
|
||||
Utils
|
||||
} from 'sequelize';
|
||||
import { SequelizeStorage, Umzug } from 'umzug';
|
||||
import { Collection, CollectionOptions, RepositoryType } from './collection';
|
||||
@ -58,7 +58,7 @@ import {
|
||||
SyncListener,
|
||||
UpdateListener,
|
||||
UpdateWithAssociationsListener,
|
||||
ValidateListener,
|
||||
ValidateListener
|
||||
} from './types';
|
||||
|
||||
export interface MergeOptions extends merge.Options {}
|
||||
@ -250,6 +250,8 @@ export class Database extends EventEmitter implements AsyncEmitter {
|
||||
name: 'migrations',
|
||||
autoGenId: false,
|
||||
timestamps: false,
|
||||
namespace: 'core',
|
||||
duplicator: 'required',
|
||||
fields: [{ type: 'string', name: 'name' }],
|
||||
});
|
||||
|
||||
@ -612,6 +614,7 @@ export class Database extends EventEmitter implements AsyncEmitter {
|
||||
}
|
||||
|
||||
extendCollection(collectionOptions: CollectionOptions, mergeOptions?: MergeOptions) {
|
||||
collectionOptions = lodash.cloneDeep(collectionOptions);
|
||||
const collectionName = collectionOptions.name;
|
||||
const existCollection = this.getCollection(collectionName);
|
||||
if (existCollection) {
|
||||
|
@ -101,6 +101,8 @@ export class ApplicationVersion {
|
||||
if (!app.db.hasCollection('applicationVersion')) {
|
||||
app.db.collection({
|
||||
name: 'applicationVersion',
|
||||
namespace: 'core',
|
||||
duplicator: 'required',
|
||||
timestamps: false,
|
||||
fields: [{ name: 'value', type: 'string' }],
|
||||
});
|
||||
|
@ -1,5 +1,7 @@
|
||||
export default {
|
||||
name: 'applicationPlugins',
|
||||
namespace: 'core',
|
||||
duplicator: 'required',
|
||||
repository: 'PluginManagerRepository',
|
||||
fields: [
|
||||
{ type: 'string', name: 'name', unique: true },
|
||||
|
@ -2,5 +2,7 @@ import { CollectionOptions } from '@nocobase/database';
|
||||
|
||||
export default {
|
||||
name: 'rolesUsers',
|
||||
duplicator: 'optional',
|
||||
namespace: 'acl',
|
||||
fields: [{ type: 'boolean', name: 'default' }],
|
||||
} as CollectionOptions;
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { CollectionOptions } from '@nocobase/database';
|
||||
|
||||
export default {
|
||||
namespace: 'acl',
|
||||
duplicator: 'required',
|
||||
name: 'roles',
|
||||
title: '{{t("Roles")}}',
|
||||
autoGenId: false,
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { CollectionOptions } from '@nocobase/database';
|
||||
|
||||
export default {
|
||||
namespace: 'acl',
|
||||
duplicator: 'required',
|
||||
name: 'rolesResources',
|
||||
model: 'RoleResourceModel',
|
||||
indexes: [
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { CollectionOptions } from '@nocobase/database';
|
||||
|
||||
export default {
|
||||
namespace: 'acl',
|
||||
duplicator: 'required',
|
||||
name: 'rolesResourcesActions',
|
||||
model: 'RoleResourceActionModel',
|
||||
fields: [
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { CollectionOptions } from '@nocobase/database';
|
||||
|
||||
export default {
|
||||
namespace: 'acl',
|
||||
duplicator: 'required',
|
||||
name: 'rolesResourcesScopes',
|
||||
fields: [
|
||||
{
|
||||
|
@ -772,6 +772,11 @@ export class PluginACL extends Plugin {
|
||||
|
||||
async load() {
|
||||
await this.importCollections(resolve(__dirname, 'collections'));
|
||||
this.db.extendCollection({
|
||||
name: 'rolesUischemas',
|
||||
namespace: 'acl',
|
||||
duplicator: 'required',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { defineCollection } from '@nocobase/database';
|
||||
|
||||
export default defineCollection({
|
||||
namespace: 'audit-logs',
|
||||
duplicator: 'optional',
|
||||
name: 'auditChanges',
|
||||
title: '变动值',
|
||||
createdBy: false,
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { defineCollection } from '@nocobase/database';
|
||||
|
||||
export default defineCollection({
|
||||
namespace: 'audit-logs',
|
||||
duplicator: 'optional',
|
||||
name: 'auditLogs',
|
||||
createdBy: false,
|
||||
updatedBy: false,
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { defineCollection } from '@nocobase/database';
|
||||
|
||||
export default defineCollection({
|
||||
namespace: 'china-region',
|
||||
duplicator: 'skip',
|
||||
name: 'chinaRegions',
|
||||
title: '中国行政区划',
|
||||
autoGenId: false,
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { CollectionOptions } from '@nocobase/database';
|
||||
|
||||
export default {
|
||||
namespace: 'collection-manager',
|
||||
duplicator: 'required',
|
||||
name: 'collectionCategories',
|
||||
autoGenId: true,
|
||||
sortable: true,
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { CollectionOptions } from '@nocobase/database';
|
||||
|
||||
export default {
|
||||
namespace: 'collection-manager',
|
||||
duplicator: 'required',
|
||||
name: 'collections',
|
||||
title: '数据表配置',
|
||||
sortable: 'sort',
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { CollectionOptions } from '@nocobase/database';
|
||||
|
||||
export default {
|
||||
namespace: 'collection-manager',
|
||||
duplicator: 'required',
|
||||
name: 'fields',
|
||||
autoGenId: false,
|
||||
model: 'FieldModel',
|
||||
|
@ -245,6 +245,12 @@ export class CollectionManagerPlugin extends Plugin {
|
||||
}
|
||||
await next();
|
||||
});
|
||||
|
||||
this.app.db.extendCollection({
|
||||
name: 'collectionCategory',
|
||||
namespace: 'collection-manager',
|
||||
duplicator: 'required',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { Application } from '@nocobase/server';
|
||||
import lodash from 'lodash';
|
||||
import { Restorer } from './restorer';
|
||||
|
||||
@ -70,7 +69,7 @@ CollectionGroupManager.registerCollectionGroup({
|
||||
CollectionGroupManager.registerCollectionGroup({
|
||||
pluginName: 'collection-manager',
|
||||
function: 'collections',
|
||||
collections: ['collections', 'fields'],
|
||||
collections: ['collections', 'fields', 'collectionCategories', 'collectionCategory'],
|
||||
dumpable: 'required',
|
||||
});
|
||||
|
||||
@ -252,5 +251,5 @@ CollectionGroupManager.registerCollectionGroup({
|
||||
pluginName: 'iframe-block',
|
||||
function: 'iframe html storage',
|
||||
collections: ['iframeHtml'],
|
||||
dumpable: 'optional',
|
||||
dumpable: 'required',
|
||||
});
|
||||
|
@ -11,4 +11,48 @@ export default class Duplicator extends Plugin {
|
||||
addDumpCommand(this.app);
|
||||
addRestoreCommand(this.app);
|
||||
}
|
||||
|
||||
async load() {
|
||||
this.app.resourcer.define({
|
||||
name: 'duplicator',
|
||||
actions: {
|
||||
getDict: async (ctx, next) => {
|
||||
ctx.withoutDataWrapping = true;
|
||||
let collectionNames = await this.db.getRepository('collections').find();
|
||||
collectionNames = collectionNames.map((item) => item.get('name'));
|
||||
const collections: any[] = [];
|
||||
for (const [name, collection] of this.db.collections) {
|
||||
const columns: any[] = [];
|
||||
for (const key in collection.model.rawAttributes) {
|
||||
if (Object.prototype.hasOwnProperty.call(collection.model.rawAttributes, key)) {
|
||||
const attribute = collection.model.rawAttributes[key];
|
||||
columns.push({
|
||||
realName: attribute.field,
|
||||
name: key,
|
||||
});
|
||||
}
|
||||
}
|
||||
const item = {
|
||||
name,
|
||||
title: collection.options.title,
|
||||
namespace: collection.options.namespace,
|
||||
duplicator: collection.options.duplicator,
|
||||
// columns,
|
||||
};
|
||||
if (!item.namespace && collectionNames.includes(name)) {
|
||||
item.namespace = 'collection-manager';
|
||||
if (!item.duplicator) {
|
||||
item.duplicator = 'optional';
|
||||
}
|
||||
}
|
||||
collections.push(item);
|
||||
}
|
||||
ctx.body = collections;
|
||||
await next();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
this.app.acl.allow('duplicator', 'getDict');
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { CollectionOptions } from '@nocobase/database';
|
||||
|
||||
export default {
|
||||
namespace: 'file-manager',
|
||||
duplicator: 'optional',
|
||||
name: 'attachments',
|
||||
title: '文件管理器',
|
||||
createdBy: true,
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { CollectionOptions } from '@nocobase/database';
|
||||
|
||||
export default {
|
||||
namespace: 'file-manager',
|
||||
duplicator: 'optional',
|
||||
name: 'storages',
|
||||
title: '存储引擎',
|
||||
fields: [
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { defineCollection } from '@nocobase/database';
|
||||
|
||||
export default defineCollection({
|
||||
namespace: 'graph-collection-manager',
|
||||
duplicator: 'required',
|
||||
name: 'graphPositions',
|
||||
fields: [
|
||||
{
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { CollectionOptions } from '@nocobase/database';
|
||||
|
||||
export default {
|
||||
namespace: 'iframe-block',
|
||||
duplicator: 'required',
|
||||
name: 'iframeHtml',
|
||||
createdBy: true,
|
||||
updatedBy: true,
|
||||
|
@ -2,6 +2,8 @@ import { CollectionOptions } from "@nocobase/client";
|
||||
import { MapConfigurationCollectionName } from "../constants";
|
||||
|
||||
export default {
|
||||
namespace: 'map',
|
||||
duplicator: 'optional',
|
||||
name: MapConfigurationCollectionName,
|
||||
title: '{{t("Map Manager")}}',
|
||||
fields: [
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { defineCollection } from '@nocobase/database';
|
||||
|
||||
export default defineCollection({
|
||||
namespace: 'multi-app-manager',
|
||||
duplicator: 'optional',
|
||||
name: 'applications',
|
||||
model: 'ApplicationModel',
|
||||
autoGenId: false,
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { CollectionOptions } from '@nocobase/database';
|
||||
|
||||
export default {
|
||||
namespace: 'oidc',
|
||||
duplicator: 'optional',
|
||||
name: 'oidcProviders',
|
||||
title: '{{t("OIDC Providers")}}',
|
||||
fields: [
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { CollectionOptions } from '@nocobase/database';
|
||||
|
||||
export default {
|
||||
namespace: 'saml',
|
||||
duplicator: 'optional',
|
||||
name: 'samlProviders',
|
||||
title: '{{t("SAML Providers")}}',
|
||||
fields: [
|
||||
|
@ -1,4 +1,6 @@
|
||||
export default {
|
||||
namespace: 'sequence-field',
|
||||
duplicator: 'required',
|
||||
name: 'sequences',
|
||||
fields: [
|
||||
{
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { CollectionOptions } from '@nocobase/database';
|
||||
|
||||
export default {
|
||||
namespace: 'snapshot-field',
|
||||
duplicator: 'required',
|
||||
name: 'collectionsHistory',
|
||||
title: '数据表历史',
|
||||
sortable: 'sort',
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { CollectionOptions } from '@nocobase/database';
|
||||
|
||||
export default {
|
||||
namespace: 'snapshot-field',
|
||||
duplicator: 'required',
|
||||
name: 'fieldsHistory',
|
||||
title: '{{t("Fields history")}}',
|
||||
autoGenId: false,
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { defineCollection } from '@nocobase/database';
|
||||
|
||||
export default defineCollection({
|
||||
namespace: 'system-settings',
|
||||
duplicator: 'optional',
|
||||
name: 'systemSettings',
|
||||
fields: [
|
||||
{
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { defineCollection } from '@nocobase/database';
|
||||
|
||||
export default defineCollection({
|
||||
namespace: 'ui-routes-storage',
|
||||
duplicator: 'required',
|
||||
name: 'uiRoutes',
|
||||
title: '前端路由表',
|
||||
model: 'MagicAttributeModel',
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { CollectionOptions } from '@nocobase/database';
|
||||
|
||||
export default {
|
||||
namespace: 'ui-schema-storage',
|
||||
duplicator: 'required',
|
||||
name: 'uiSchemaServerHooks',
|
||||
model: 'ServerHookModel',
|
||||
// autoGenId: false,
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { defineCollection } from '@nocobase/database';
|
||||
|
||||
export default defineCollection({
|
||||
namespace: 'ui-schema-storage',
|
||||
duplicator: 'required',
|
||||
name: 'uiSchemaTemplates',
|
||||
autoGenId: false,
|
||||
fields: [
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { CollectionOptions } from '@nocobase/database';
|
||||
|
||||
export default {
|
||||
namespace: 'ui-schema-storage',
|
||||
duplicator: 'required',
|
||||
name: 'uiSchemaTreePath',
|
||||
autoGenId: false,
|
||||
timestamps: false,
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { CollectionOptions } from '@nocobase/database';
|
||||
|
||||
export default {
|
||||
namespace: 'ui-schema-storage',
|
||||
duplicator: 'required',
|
||||
name: 'uiSchemas',
|
||||
title: '字段配置',
|
||||
autoGenId: false,
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { CollectionOptions } from '@nocobase/database';
|
||||
|
||||
export default {
|
||||
namespace: 'users',
|
||||
duplicator: 'optional',
|
||||
name: 'users',
|
||||
title: '{{t("Users")}}',
|
||||
sortable: 'sort',
|
||||
|
@ -1,4 +1,6 @@
|
||||
export default {
|
||||
namespace: 'verification',
|
||||
duplicator: 'optional',
|
||||
name: 'verifications',
|
||||
fields: [
|
||||
{
|
||||
|
@ -1,4 +1,6 @@
|
||||
export default {
|
||||
namespace: 'verification',
|
||||
duplicator: 'optional',
|
||||
name: 'verifications_providers',
|
||||
fields: [
|
||||
{
|
||||
|
@ -15,7 +15,6 @@ import WorkflowModel from './models/Workflow';
|
||||
import Processor from './Processor';
|
||||
import initTriggers, { Trigger } from './triggers';
|
||||
|
||||
|
||||
type Pending = [ExecutionModel, JobModel?];
|
||||
export default class WorkflowPlugin extends Plugin {
|
||||
instructions: Registry<Instruction> = new Registry();
|
||||
@ -34,9 +33,9 @@ export default class WorkflowPlugin extends Plugin {
|
||||
} else if (!instance.current) {
|
||||
const count = await Model.count({
|
||||
where: {
|
||||
key: instance.key
|
||||
key: instance.key,
|
||||
},
|
||||
transaction: options.transaction
|
||||
transaction: options.transaction,
|
||||
});
|
||||
if (!count) {
|
||||
instance.set('current', true);
|
||||
@ -52,18 +51,21 @@ export default class WorkflowPlugin extends Plugin {
|
||||
key: instance.key,
|
||||
current: true,
|
||||
id: {
|
||||
[Op.ne]: instance.id
|
||||
}
|
||||
[Op.ne]: instance.id,
|
||||
},
|
||||
},
|
||||
transaction: options.transaction
|
||||
transaction: options.transaction,
|
||||
});
|
||||
|
||||
if (previous) {
|
||||
// NOTE: set to `null` but not `false` will not violate the unique index
|
||||
await previous.update({ enabled: false, current: null }, {
|
||||
transaction: options.transaction,
|
||||
hooks: false
|
||||
});
|
||||
await previous.update(
|
||||
{ enabled: false, current: null },
|
||||
{
|
||||
transaction: options.transaction,
|
||||
hooks: false,
|
||||
},
|
||||
);
|
||||
|
||||
this.toggle(previous, false);
|
||||
}
|
||||
@ -185,24 +187,29 @@ export default class WorkflowPlugin extends Plugin {
|
||||
// NOTE: no transaction here for read-uncommitted execution
|
||||
const existed = await workflow.countExecutions({
|
||||
where: {
|
||||
id: options.context.executionId
|
||||
}
|
||||
id: options.context.executionId,
|
||||
},
|
||||
});
|
||||
|
||||
if (existed) {
|
||||
this.app.logger.warn(`[Workflow] workflow ${workflow.id} has already been triggered in same execution (${options.context.executionId}), and newly triggering will be skipped.`);
|
||||
this.app.logger.warn(
|
||||
`[Workflow] workflow ${workflow.id} has already been triggered in same execution (${options.context.executionId}), and newly triggering will be skipped.`,
|
||||
);
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
const execution = await this.db.sequelize.transaction(async transaction => {
|
||||
const execution = await workflow.createExecution({
|
||||
context,
|
||||
key: workflow.key,
|
||||
status: EXECUTION_STATUS.CREATED,
|
||||
useTransaction: workflow.useTransaction,
|
||||
}, { transaction });
|
||||
const execution = await this.db.sequelize.transaction(async (transaction) => {
|
||||
const execution = await workflow.createExecution(
|
||||
{
|
||||
context,
|
||||
key: workflow.key,
|
||||
status: EXECUTION_STATUS.CREATED,
|
||||
useTransaction: workflow.useTransaction,
|
||||
},
|
||||
{ transaction },
|
||||
);
|
||||
|
||||
const executed = await workflow.countExecutions({ transaction });
|
||||
|
||||
@ -211,19 +218,22 @@ export default class WorkflowPlugin extends Plugin {
|
||||
|
||||
const allExecuted = await (<typeof ExecutionModel>execution.constructor).count({
|
||||
where: {
|
||||
key: workflow.key
|
||||
key: workflow.key,
|
||||
},
|
||||
transaction
|
||||
transaction,
|
||||
});
|
||||
await (<typeof WorkflowModel>workflow.constructor).update({
|
||||
allExecuted
|
||||
}, {
|
||||
where: {
|
||||
key: workflow.key
|
||||
await (<typeof WorkflowModel>workflow.constructor).update(
|
||||
{
|
||||
allExecuted,
|
||||
},
|
||||
individualHooks: true,
|
||||
transaction
|
||||
});
|
||||
{
|
||||
where: {
|
||||
key: workflow.key,
|
||||
},
|
||||
individualHooks: true,
|
||||
transaction,
|
||||
},
|
||||
);
|
||||
|
||||
execution.workflow = workflow;
|
||||
|
||||
@ -243,7 +253,7 @@ export default class WorkflowPlugin extends Plugin {
|
||||
} else {
|
||||
this.dispatch();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public async resume(job) {
|
||||
if (!job.execution) {
|
||||
@ -264,16 +274,16 @@ export default class WorkflowPlugin extends Plugin {
|
||||
if (this.pending.length) {
|
||||
next = this.pending.shift() as Pending;
|
||||
} else {
|
||||
const execution = await this.db.getRepository('executions').findOne({
|
||||
const execution = (await this.db.getRepository('executions').findOne({
|
||||
filter: {
|
||||
status: EXECUTION_STATUS.CREATED
|
||||
status: EXECUTION_STATUS.CREATED,
|
||||
},
|
||||
sort: 'createdAt'
|
||||
}) as ExecutionModel;
|
||||
sort: 'createdAt',
|
||||
})) as ExecutionModel;
|
||||
if (execution) {
|
||||
next = [execution];
|
||||
}
|
||||
};
|
||||
}
|
||||
if (next) {
|
||||
this.process(...next);
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { CollectionOptions } from '@nocobase/database';
|
||||
|
||||
export default {
|
||||
namespace: 'workflow',
|
||||
duplicator: 'optional',
|
||||
name: 'executions',
|
||||
fields: [
|
||||
{
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { CollectionOptions } from '@nocobase/database';
|
||||
|
||||
export default {
|
||||
namespace: 'workflow',
|
||||
duplicator: 'required',
|
||||
name: 'flow_nodes',
|
||||
// model: 'FlowNodeModel',
|
||||
title: 'Workflow Nodes',
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { CollectionOptions } from '@nocobase/database';
|
||||
|
||||
export default {
|
||||
namespace: 'workflow',
|
||||
duplicator: 'optional',
|
||||
name: 'jobs',
|
||||
fields: [
|
||||
{
|
||||
|
@ -2,6 +2,8 @@ import { CollectionOptions } from '@nocobase/database';
|
||||
|
||||
export default function () {
|
||||
return {
|
||||
namespace: 'workflow',
|
||||
duplicator: 'required',
|
||||
name: 'workflows',
|
||||
fields: [
|
||||
{
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { CollectionOptions } from '@nocobase/database';
|
||||
|
||||
export default {
|
||||
namespace: 'workflow',
|
||||
name: 'users_jobs',
|
||||
duplicator: 'optional',
|
||||
fields: [
|
||||
{
|
||||
type: 'bigInt',
|
||||
|
Loading…
Reference in New Issue
Block a user