@nocobase/plugin-client 2.1.0-alpha.10 → 2.1.0-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build.config.ts +6 -3
- package/dist/client/index.js +1 -1
- package/dist/externalVersion.js +5 -5
- package/dist/node_modules/cronstrue/package.json +1 -1
- package/dist/server/server.js +243 -1
- package/dist/swagger/index.d.ts +658 -14
- package/dist/swagger/index.js +501 -14
- package/package.json +2 -2
package/dist/server/server.js
CHANGED
|
@@ -62,6 +62,31 @@ async function getLang(ctx) {
|
|
|
62
62
|
}
|
|
63
63
|
return lang;
|
|
64
64
|
}
|
|
65
|
+
function getModelValue(record, key) {
|
|
66
|
+
if (!record) {
|
|
67
|
+
return void 0;
|
|
68
|
+
}
|
|
69
|
+
return typeof record.get === "function" ? record.get(key) : record[key];
|
|
70
|
+
}
|
|
71
|
+
function isManagedFlowRouteShell(record, schemaUid) {
|
|
72
|
+
const actualSchemaUid = String(getModelValue(record, "x-uid") ?? getModelValue(record, "uid") ?? "").trim();
|
|
73
|
+
const schema = getModelValue(record, "schema");
|
|
74
|
+
if (!import_lodash.default.isPlainObject(schema)) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
return actualSchemaUid === schemaUid && (schema == null ? void 0 : schema["x-component"]) === "FlowRoute" && String((schema == null ? void 0 : schema["x-uid"]) ?? "").trim() === schemaUid;
|
|
78
|
+
}
|
|
79
|
+
function isTransactionFinished(transaction) {
|
|
80
|
+
return !!(transaction == null ? void 0 : transaction.finished);
|
|
81
|
+
}
|
|
82
|
+
async function rollbackTransaction(transaction, options = {}) {
|
|
83
|
+
var _a, _b;
|
|
84
|
+
if (!transaction || isTransactionFinished(transaction)) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
await transaction.rollback();
|
|
88
|
+
await ((_b = (_a = options.flowModelsRepository) == null ? void 0 : _a.emitTransactionRollback) == null ? void 0 : _b.call(_a, transaction));
|
|
89
|
+
}
|
|
65
90
|
class PluginClientServer extends import_server.Plugin {
|
|
66
91
|
async beforeLoad() {
|
|
67
92
|
}
|
|
@@ -170,7 +195,9 @@ class PluginClientServer extends import_server.Plugin {
|
|
|
170
195
|
"desktopRoutes:update",
|
|
171
196
|
"desktopRoutes:move",
|
|
172
197
|
"desktopRoutes:destroy",
|
|
173
|
-
"desktopRoutes:updateOrCreate"
|
|
198
|
+
"desktopRoutes:updateOrCreate",
|
|
199
|
+
"desktopRoutes:createV2",
|
|
200
|
+
"desktopRoutes:destroyV2"
|
|
174
201
|
]
|
|
175
202
|
});
|
|
176
203
|
this.app.acl.registerSnippet({
|
|
@@ -328,6 +355,221 @@ class PluginClientServer extends import_server.Plugin {
|
|
|
328
355
|
}
|
|
329
356
|
await next();
|
|
330
357
|
});
|
|
358
|
+
this.app.resourceManager.registerActionHandler("desktopRoutes:createV2", async (ctx, next) => {
|
|
359
|
+
var _a, _b, _c, _d, _e;
|
|
360
|
+
const { values } = ctx.action.params;
|
|
361
|
+
const schemaUid = String((values == null ? void 0 : values.schemaUid) || "").trim();
|
|
362
|
+
const title = String((values == null ? void 0 : values.title) || "").trim();
|
|
363
|
+
const icon = values == null ? void 0 : values.icon;
|
|
364
|
+
const parentId = (values == null ? void 0 : values.parentId) ?? null;
|
|
365
|
+
if (!schemaUid) {
|
|
366
|
+
return ctx.throw(400, { code: "INVALID_PARAMS", message: "desktopRoutes:createV2 requires 'schemaUid'" });
|
|
367
|
+
}
|
|
368
|
+
if (!title) {
|
|
369
|
+
return ctx.throw(400, { code: "INVALID_PARAMS", message: "desktopRoutes:createV2 requires 'title'" });
|
|
370
|
+
}
|
|
371
|
+
const menuSchemaUid = `menu-${schemaUid}`;
|
|
372
|
+
const tabSchemaUid = `tabs-${schemaUid}`;
|
|
373
|
+
const tabSchemaName = `tab-${schemaUid}`;
|
|
374
|
+
const desktopRoutesRepository = ctx.db.getRepository("desktopRoutes");
|
|
375
|
+
const uiSchemasRepository = ctx.db.getRepository("uiSchemas");
|
|
376
|
+
const uiSchemasModel = (_a = ctx.db.getCollection("uiSchemas")) == null ? void 0 : _a.model;
|
|
377
|
+
const flowModelsRepository = ctx.db.getRepository("flowModels");
|
|
378
|
+
const transaction = await ctx.db.sequelize.transaction();
|
|
379
|
+
const pickPage = (record) => ({
|
|
380
|
+
id: record == null ? void 0 : record.id,
|
|
381
|
+
schemaUid: record == null ? void 0 : record.schemaUid,
|
|
382
|
+
title: record == null ? void 0 : record.title,
|
|
383
|
+
icon: record == null ? void 0 : record.icon,
|
|
384
|
+
parentId: (record == null ? void 0 : record.parentId) ?? null,
|
|
385
|
+
menuSchemaUid: record == null ? void 0 : record.menuSchemaUid
|
|
386
|
+
});
|
|
387
|
+
const pickTab = (record) => record ? {
|
|
388
|
+
id: record == null ? void 0 : record.id,
|
|
389
|
+
schemaUid: record == null ? void 0 : record.schemaUid,
|
|
390
|
+
tabSchemaName: record == null ? void 0 : record.tabSchemaName
|
|
391
|
+
} : null;
|
|
392
|
+
const isSameValue = (a, b) => String(a ?? "") === String(b ?? "");
|
|
393
|
+
try {
|
|
394
|
+
const existingPage = await desktopRoutesRepository.findOne({
|
|
395
|
+
filter: { type: "flowPage", schemaUid },
|
|
396
|
+
transaction
|
|
397
|
+
});
|
|
398
|
+
if (existingPage) {
|
|
399
|
+
const pageJson = ((_b = existingPage.toJSON) == null ? void 0 : _b.call(existingPage)) || existingPage;
|
|
400
|
+
const existingUiSchema = await uiSchemasRepository.findOne({
|
|
401
|
+
filterByTk: schemaUid,
|
|
402
|
+
transaction
|
|
403
|
+
});
|
|
404
|
+
if (existingUiSchema && !isManagedFlowRouteShell(existingUiSchema, schemaUid)) {
|
|
405
|
+
ctx.throw(409, {
|
|
406
|
+
code: "CONFLICT",
|
|
407
|
+
message: `desktopRoutes:createV2 schemaUid '${schemaUid}' is already occupied by a non-FlowRoute uiSchema`
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
const conflict = !isSameValue(pageJson == null ? void 0 : pageJson.title, title) || !isSameValue(pageJson == null ? void 0 : pageJson.icon, icon) || !isSameValue((pageJson == null ? void 0 : pageJson.parentId) ?? null, parentId ?? null);
|
|
411
|
+
if (conflict) {
|
|
412
|
+
ctx.throw(409, {
|
|
413
|
+
code: "CONFLICT",
|
|
414
|
+
message: `desktopRoutes:createV2 schemaUid '${schemaUid}' already exists with different fields`,
|
|
415
|
+
details: {
|
|
416
|
+
expected: { title, icon, parentId: parentId ?? null },
|
|
417
|
+
actual: { title: pageJson == null ? void 0 : pageJson.title, icon: pageJson == null ? void 0 : pageJson.icon, parentId: (pageJson == null ? void 0 : pageJson.parentId) ?? null }
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
const existingTab = await desktopRoutesRepository.findOne({
|
|
422
|
+
filter: { parentId: pageJson == null ? void 0 : pageJson.id, type: "tabs", hidden: true },
|
|
423
|
+
transaction
|
|
424
|
+
});
|
|
425
|
+
ctx.body = { page: pickPage(pageJson), defaultTab: pickTab(((_c = existingTab == null ? void 0 : existingTab.toJSON) == null ? void 0 : _c.call(existingTab)) || existingTab) };
|
|
426
|
+
await next();
|
|
427
|
+
await transaction.commit();
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
if (uiSchemasModel) {
|
|
431
|
+
const [uiSchemaMutex] = await uiSchemasModel.findOrCreate({
|
|
432
|
+
where: { "x-uid": schemaUid },
|
|
433
|
+
defaults: {
|
|
434
|
+
"x-uid": schemaUid,
|
|
435
|
+
schema: {
|
|
436
|
+
type: "void",
|
|
437
|
+
"x-component": "FlowRoute",
|
|
438
|
+
"x-uid": schemaUid
|
|
439
|
+
}
|
|
440
|
+
},
|
|
441
|
+
transaction
|
|
442
|
+
});
|
|
443
|
+
if (!isManagedFlowRouteShell(uiSchemaMutex, schemaUid)) {
|
|
444
|
+
ctx.throw(409, {
|
|
445
|
+
code: "CONFLICT",
|
|
446
|
+
message: `desktopRoutes:createV2 schemaUid '${schemaUid}' is already occupied by a non-FlowRoute uiSchema`
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
const dialect = ctx.db.sequelize.getDialect();
|
|
450
|
+
const supportsLock = dialect !== "sqlite";
|
|
451
|
+
const lockedUiSchema = await uiSchemasModel.findByPk(
|
|
452
|
+
schemaUid,
|
|
453
|
+
supportsLock ? { transaction, lock: transaction.LOCK.UPDATE } : { transaction }
|
|
454
|
+
);
|
|
455
|
+
if (lockedUiSchema && !isManagedFlowRouteShell(lockedUiSchema, schemaUid)) {
|
|
456
|
+
ctx.throw(409, {
|
|
457
|
+
code: "CONFLICT",
|
|
458
|
+
message: `desktopRoutes:createV2 schemaUid '${schemaUid}' is already occupied by a non-FlowRoute uiSchema`
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
const existingAfterLock = await desktopRoutesRepository.findOne({
|
|
463
|
+
filter: { type: "flowPage", schemaUid },
|
|
464
|
+
transaction
|
|
465
|
+
});
|
|
466
|
+
if (existingAfterLock) {
|
|
467
|
+
const pageJson = ((_d = existingAfterLock.toJSON) == null ? void 0 : _d.call(existingAfterLock)) || existingAfterLock;
|
|
468
|
+
const conflict = !isSameValue(pageJson == null ? void 0 : pageJson.title, title) || !isSameValue(pageJson == null ? void 0 : pageJson.icon, icon) || !isSameValue((pageJson == null ? void 0 : pageJson.parentId) ?? null, parentId ?? null);
|
|
469
|
+
if (conflict) {
|
|
470
|
+
ctx.throw(409, {
|
|
471
|
+
code: "CONFLICT",
|
|
472
|
+
message: `desktopRoutes:createV2 schemaUid '${schemaUid}' already exists with different fields`,
|
|
473
|
+
details: {
|
|
474
|
+
expected: { title, icon, parentId: parentId ?? null },
|
|
475
|
+
actual: { title: pageJson == null ? void 0 : pageJson.title, icon: pageJson == null ? void 0 : pageJson.icon, parentId: (pageJson == null ? void 0 : pageJson.parentId) ?? null }
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
const existingTab = await desktopRoutesRepository.findOne({
|
|
480
|
+
filter: { parentId: pageJson == null ? void 0 : pageJson.id, type: "tabs", hidden: true },
|
|
481
|
+
transaction
|
|
482
|
+
});
|
|
483
|
+
ctx.body = { page: pickPage(pageJson), defaultTab: pickTab(((_e = existingTab == null ? void 0 : existingTab.toJSON) == null ? void 0 : _e.call(existingTab)) || existingTab) };
|
|
484
|
+
await next();
|
|
485
|
+
await transaction.commit();
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
const createdPage = await desktopRoutesRepository.create({
|
|
489
|
+
transaction,
|
|
490
|
+
values: {
|
|
491
|
+
type: "flowPage",
|
|
492
|
+
schemaUid,
|
|
493
|
+
title,
|
|
494
|
+
icon,
|
|
495
|
+
parentId: parentId ?? null,
|
|
496
|
+
menuSchemaUid,
|
|
497
|
+
enableTabs: false
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
const createdTab = await desktopRoutesRepository.create({
|
|
501
|
+
transaction,
|
|
502
|
+
values: {
|
|
503
|
+
type: "tabs",
|
|
504
|
+
parentId: createdPage.get("id"),
|
|
505
|
+
schemaUid: tabSchemaUid,
|
|
506
|
+
tabSchemaName,
|
|
507
|
+
hidden: true
|
|
508
|
+
}
|
|
509
|
+
});
|
|
510
|
+
await flowModelsRepository.ensureModel(
|
|
511
|
+
{ parentId: schemaUid, subKey: "page", subType: "object", use: "RootPageModel", async: true },
|
|
512
|
+
{ transaction }
|
|
513
|
+
);
|
|
514
|
+
await flowModelsRepository.ensureModel(
|
|
515
|
+
{ parentId: tabSchemaUid, subKey: "grid", subType: "object", use: "BlockGridModel", async: true },
|
|
516
|
+
{ transaction }
|
|
517
|
+
);
|
|
518
|
+
ctx.body = {
|
|
519
|
+
page: pickPage(createdPage.toJSON()),
|
|
520
|
+
defaultTab: pickTab(createdTab.toJSON())
|
|
521
|
+
};
|
|
522
|
+
await next();
|
|
523
|
+
await transaction.commit();
|
|
524
|
+
} catch (error) {
|
|
525
|
+
await rollbackTransaction(transaction, { flowModelsRepository });
|
|
526
|
+
throw error;
|
|
527
|
+
}
|
|
528
|
+
});
|
|
529
|
+
this.app.resourceManager.registerActionHandler("desktopRoutes:destroyV2", async (ctx, next) => {
|
|
530
|
+
const { values } = ctx.action.params;
|
|
531
|
+
const schemaUid = String((values == null ? void 0 : values.schemaUid) || "").trim();
|
|
532
|
+
if (!schemaUid) {
|
|
533
|
+
return ctx.throw(400, { code: "INVALID_PARAMS", message: "desktopRoutes:destroyV2 requires 'schemaUid'" });
|
|
534
|
+
}
|
|
535
|
+
const desktopRoutesRepository = ctx.db.getRepository("desktopRoutes");
|
|
536
|
+
const uiSchemasRepository = ctx.db.getRepository("uiSchemas");
|
|
537
|
+
const transaction = await ctx.db.sequelize.transaction();
|
|
538
|
+
try {
|
|
539
|
+
const page = await desktopRoutesRepository.findOne({
|
|
540
|
+
filter: { type: "flowPage", schemaUid },
|
|
541
|
+
transaction
|
|
542
|
+
});
|
|
543
|
+
const uiSchema = await uiSchemasRepository.findOne({
|
|
544
|
+
filterByTk: schemaUid,
|
|
545
|
+
transaction
|
|
546
|
+
});
|
|
547
|
+
if (uiSchema && !isManagedFlowRouteShell(uiSchema, schemaUid)) {
|
|
548
|
+
ctx.throw(409, {
|
|
549
|
+
code: "CONFLICT",
|
|
550
|
+
message: `desktopRoutes:destroyV2 schemaUid '${schemaUid}' is occupied by a non-FlowRoute uiSchema`
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
if (page) {
|
|
554
|
+
await desktopRoutesRepository.destroy({
|
|
555
|
+
filterByTk: page.get("id"),
|
|
556
|
+
transaction
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
if (uiSchema) {
|
|
560
|
+
await uiSchemasRepository.destroy({
|
|
561
|
+
filterByTk: schemaUid,
|
|
562
|
+
transaction
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
ctx.body = { ok: true };
|
|
566
|
+
await next();
|
|
567
|
+
await transaction.commit();
|
|
568
|
+
} catch (error) {
|
|
569
|
+
await rollbackTransaction(transaction);
|
|
570
|
+
throw error;
|
|
571
|
+
}
|
|
572
|
+
});
|
|
331
573
|
this.app.resourceManager.registerActionHandler("roles.desktopRoutes:set", async (ctx, next) => {
|
|
332
574
|
let { values } = ctx.action.params;
|
|
333
575
|
if (values.length) {
|