@nocobase/plugin-workflow-custom-action-trigger 2.1.0-beta.15 → 2.1.0-beta.17

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.
Files changed (45) hide show
  1. package/dist/client/CustomActionTrigger.d.ts +39 -2
  2. package/dist/client/index.js +1 -1
  3. package/dist/externalVersion.js +11 -10
  4. package/dist/node_modules/joi/dist/joi-browser.min.js +1 -0
  5. package/dist/node_modules/joi/lib/annotate.js +175 -0
  6. package/dist/node_modules/joi/lib/base.js +1069 -0
  7. package/dist/node_modules/joi/lib/cache.js +143 -0
  8. package/dist/node_modules/joi/lib/common.js +216 -0
  9. package/dist/node_modules/joi/lib/compile.js +283 -0
  10. package/dist/node_modules/joi/lib/errors.js +271 -0
  11. package/dist/node_modules/joi/lib/extend.js +312 -0
  12. package/dist/node_modules/joi/lib/index.d.ts +2365 -0
  13. package/dist/node_modules/joi/lib/index.js +1 -0
  14. package/dist/node_modules/joi/lib/manifest.js +476 -0
  15. package/dist/node_modules/joi/lib/messages.js +178 -0
  16. package/dist/node_modules/joi/lib/modify.js +267 -0
  17. package/dist/node_modules/joi/lib/ref.js +414 -0
  18. package/dist/node_modules/joi/lib/schemas.js +302 -0
  19. package/dist/node_modules/joi/lib/state.js +166 -0
  20. package/dist/node_modules/joi/lib/template.js +463 -0
  21. package/dist/node_modules/joi/lib/trace.js +346 -0
  22. package/dist/node_modules/joi/lib/types/alternatives.js +364 -0
  23. package/dist/node_modules/joi/lib/types/any.js +174 -0
  24. package/dist/node_modules/joi/lib/types/array.js +809 -0
  25. package/dist/node_modules/joi/lib/types/binary.js +100 -0
  26. package/dist/node_modules/joi/lib/types/boolean.js +150 -0
  27. package/dist/node_modules/joi/lib/types/date.js +233 -0
  28. package/dist/node_modules/joi/lib/types/function.js +93 -0
  29. package/dist/node_modules/joi/lib/types/keys.js +1067 -0
  30. package/dist/node_modules/joi/lib/types/link.js +168 -0
  31. package/dist/node_modules/joi/lib/types/number.js +363 -0
  32. package/dist/node_modules/joi/lib/types/object.js +22 -0
  33. package/dist/node_modules/joi/lib/types/string.js +850 -0
  34. package/dist/node_modules/joi/lib/types/symbol.js +102 -0
  35. package/dist/node_modules/joi/lib/validator.js +750 -0
  36. package/dist/node_modules/joi/lib/values.js +263 -0
  37. package/dist/node_modules/joi/node_modules/@hapi/topo/lib/index.d.ts +60 -0
  38. package/dist/node_modules/joi/node_modules/@hapi/topo/lib/index.js +225 -0
  39. package/dist/node_modules/joi/node_modules/@hapi/topo/package.json +30 -0
  40. package/dist/node_modules/joi/package.json +1 -0
  41. package/dist/server/CustomActionTrigger.d.ts +16 -4
  42. package/dist/server/CustomActionTrigger.js +58 -8
  43. package/dist/server/migrations/20260416000000-grant-trigger-action-to-roles.d.ts +40 -0
  44. package/dist/server/migrations/20260416000000-grant-trigger-action-to-roles.js +120 -0
  45. package/package.json +5 -2
@@ -39,6 +39,7 @@ __export(CustomActionTrigger_exports, {
39
39
  default: () => CustomActionTrigger
40
40
  });
41
41
  module.exports = __toCommonJS(CustomActionTrigger_exports);
42
+ var import_joi = __toESM(require("joi"));
42
43
  var import_plugin_error_handler = __toESM(require("@nocobase/plugin-error-handler"));
43
44
  var import_plugin_workflow = require("@nocobase/plugin-workflow");
44
45
  var import_data_source_manager = require("@nocobase/data-source-manager");
@@ -54,6 +55,25 @@ class CustomActionInterceptionError extends Error {
54
55
  }
55
56
  class CustomActionTrigger extends import_plugin_workflow.Trigger {
56
57
  static TYPE = import_constants.EVENT_TYPE;
58
+ configSchema = import_joi.default.object({
59
+ type: import_joi.default.number().valid(import_constants.CONTEXT_TYPE.SINGLE_RECORD, import_constants.CONTEXT_TYPE.MULTIPLE_RECORDS, import_constants.CONTEXT_TYPE.GLOBAL).required(),
60
+ collection: import_joi.default.when("type", {
61
+ is: import_joi.default.valid(import_constants.CONTEXT_TYPE.SINGLE_RECORD, import_constants.CONTEXT_TYPE.MULTIPLE_RECORDS),
62
+ then: import_joi.default.string().required().messages({ "any.required": "Collection is required for record-based context" }),
63
+ otherwise: import_joi.default.string().allow(null, "")
64
+ }),
65
+ appends: import_joi.default.array().items(import_joi.default.string()).optional()
66
+ });
67
+ validateConfig(config) {
68
+ const errors = super.validateConfig(config);
69
+ if (errors) {
70
+ return errors;
71
+ }
72
+ if (config.collection) {
73
+ return (0, import_plugin_workflow.validateCollectionField)(config.collection, this.workflow.app.dataSourceManager);
74
+ }
75
+ return null;
76
+ }
57
77
  async globalTriggerAction(context, next) {
58
78
  var _a, _b;
59
79
  const { triggerWorkflows, values = {} } = context.action.params;
@@ -84,8 +104,7 @@ class CustomActionTrigger extends import_plugin_workflow.Trigger {
84
104
  const syncGroup = [];
85
105
  const asyncGroup = [];
86
106
  for (const workflow of workflows) {
87
- const event = [workflow];
88
- event.push({ data: values, ...userInfo });
107
+ const event = [workflow, { data: values, ...userInfo }];
89
108
  (workflow.sync ? syncGroup : asyncGroup).push(event);
90
109
  }
91
110
  await this.processEvents({
@@ -95,7 +114,7 @@ class CustomActionTrigger extends import_plugin_workflow.Trigger {
95
114
  });
96
115
  }
97
116
  triggerAction = async (context, next) => {
98
- var _a;
117
+ var _a, _b, _c;
99
118
  const {
100
119
  resourceName,
101
120
  params: { filterByTk, values, triggerWorkflows = "", associatedIndex }
@@ -137,22 +156,26 @@ class CustomActionTrigger extends import_plugin_workflow.Trigger {
137
156
  workflows.push(workflow);
138
157
  }
139
158
  }
159
+ const scopeFilter = (_c = (_b = context.permission) == null ? void 0 : _b.parsedParams) == null ? void 0 : _c.filter;
140
160
  const syncGroup = [];
141
161
  const asyncGroup = [];
142
162
  for (const workflow of workflows) {
143
- const event = [workflow];
163
+ const event = [workflow, {}];
144
164
  const { appends = [] } = workflow.config;
145
165
  const dataPath = triggerWorkflowsMap.get(workflow.key);
146
166
  const formData = dataPath ? (0, import_lodash.get)(values, dataPath) : values;
147
167
  let data = formData;
148
168
  if (filterByTk != null) {
149
169
  if (Array.isArray(filterByTk)) {
150
- data = (await repository.find({ filterByTk, appends, context })).map(
170
+ data = (await repository.find({ filterByTk, appends, context, filter: scopeFilter })).map(
151
171
  (item) => Object.assign(item.toJSON(), formData)
152
172
  );
153
173
  } else {
154
- data = await repository.findOne({ filterByTk, appends, context });
174
+ data = await repository.findOne({ filterByTk, appends, context, filter: scopeFilter });
155
175
  if (!data) {
176
+ if (scopeFilter) {
177
+ return context.throw(403, "No permissions");
178
+ }
156
179
  continue;
157
180
  }
158
181
  if (typeof data.toJSON === "function") {
@@ -161,7 +184,7 @@ class CustomActionTrigger extends import_plugin_workflow.Trigger {
161
184
  }
162
185
  }
163
186
  }
164
- event.push({ data, ...userInfo });
187
+ event[1] = { data, ...userInfo };
165
188
  (workflow.sync ? syncGroup : asyncGroup).push(event);
166
189
  }
167
190
  await this.processEvents({
@@ -174,7 +197,34 @@ class CustomActionTrigger extends import_plugin_workflow.Trigger {
174
197
  super(workflow);
175
198
  this.workflow.app.dataSourceManager.afterAddDataSource((dataSource) => {
176
199
  dataSource.resourceManager.registerActionHandler("trigger", this.triggerAction);
177
- dataSource.acl.allow("*", ["trigger"], "loggedIn");
200
+ dataSource.acl.setAvailableAction("trigger", {
201
+ displayName: `{{t("Trigger workflow", { ns: "${import_constants.NAMESPACE}" })}}`
202
+ });
203
+ dataSource.acl.setAvailableAction("triggerNew", {
204
+ displayName: `{{t("Trigger workflow", { ns: "${import_constants.NAMESPACE}" })}}`,
205
+ onNewRecord: true
206
+ });
207
+ dataSource.resourceManager.use(
208
+ async (ctx, next) => {
209
+ const { resourceName, actionName, params } = ctx.action ?? {};
210
+ if (actionName === "trigger" && resourceName !== "workflows" && (params == null ? void 0 : params.filterByTk) == null) {
211
+ ctx.action.actionName = "triggerNew";
212
+ ctx.state.__customActionTriggerRenamed = true;
213
+ }
214
+ await next();
215
+ },
216
+ { tag: "customActionTriggerRename", before: "acl", after: "auth" }
217
+ );
218
+ dataSource.resourceManager.use(
219
+ async (ctx, next) => {
220
+ if (ctx.state.__customActionTriggerRenamed) {
221
+ ctx.action.actionName = "trigger";
222
+ }
223
+ await next();
224
+ },
225
+ { tag: "customActionTriggerRestore", after: "acl" }
226
+ );
227
+ dataSource.acl.allow("workflows", ["trigger"], "loggedIn");
178
228
  });
179
229
  workflow.app.pm.get(import_plugin_error_handler.default).errorHandler.register(
180
230
  (err) => err.name === "CustomActionInterceptionError",
@@ -0,0 +1,40 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+ import { Migration } from '@nocobase/server';
10
+ /**
11
+ * Grant `trigger` / `triggerNew` action permissions for every role, mirroring the role's
12
+ * existing `view` / `create` permissions.
13
+ *
14
+ * Background: The `trigger` action on collection resources was previously allowed for all
15
+ * logged-in users via `acl.allow('*', ['trigger'], 'loggedIn')`. After that global bypass
16
+ * was removed, `trigger` goes through normal ACL checks. Custom-action trigger is now
17
+ * modelled as two ACL actions:
18
+ * - `trigger` — invoked on an existing record; follows `view` (with data scope).
19
+ * - `triggerNew` — invoked on a form that hasn't been persisted yet; follows `create`.
20
+ *
21
+ * 1. Per-data-source strategy (`dataSourcesRoles.strategy.actions`, an array):
22
+ * - `trigger` mirrors `view` (including scope suffix like `:own`). No `view` → no trigger.
23
+ * - `triggerNew` is added (unrestricted) if the strategy contains any `create*` entry.
24
+ * No `create` → no triggerNew. Scope suffixes on `create` are ignored because new-data
25
+ * actions have no data scope.
26
+ *
27
+ * 2. Specific resource configs (`dataSourcesRolesResources` with `usingActionsConfig: true`):
28
+ * - If the resource has a `view` action, create a matching `trigger` action that reuses
29
+ * the same `scopeId`. Skip if `trigger` already exists.
30
+ * - If the resource has a `create` action, create a matching `triggerNew` action
31
+ * (scopeId: null — new-data actions carry no scope). Skip if `triggerNew` already
32
+ * exists.
33
+ *
34
+ * This migration runs only during upgrades (appVersion < 2.0.40), not on fresh installs.
35
+ */
36
+ export default class extends Migration {
37
+ appVersion: string;
38
+ on: string;
39
+ up(): Promise<void>;
40
+ }
@@ -0,0 +1,120 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ var __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+ var grant_trigger_action_to_roles_exports = {};
28
+ __export(grant_trigger_action_to_roles_exports, {
29
+ default: () => grant_trigger_action_to_roles_default
30
+ });
31
+ module.exports = __toCommonJS(grant_trigger_action_to_roles_exports);
32
+ var import_server = require("@nocobase/server");
33
+ class grant_trigger_action_to_roles_default extends import_server.Migration {
34
+ appVersion = "<2.1.0-alpha.21";
35
+ on = "afterSync";
36
+ async up() {
37
+ const { db } = this.context;
38
+ await db.sequelize.transaction(async (transaction) => {
39
+ const dsRoles = await db.getRepository("dataSourcesRoles").find({ transaction });
40
+ for (const dsRole of dsRoles) {
41
+ const strategy = dsRole.get("strategy") || {};
42
+ const actions = strategy.actions;
43
+ if (!Array.isArray(actions)) {
44
+ continue;
45
+ }
46
+ let nextActions = null;
47
+ const ensureNextActions = () => {
48
+ if (!nextActions) nextActions = [...actions];
49
+ return nextActions;
50
+ };
51
+ const viewEntry = actions.find((a) => a === "view" || a.startsWith("view:"));
52
+ if (viewEntry) {
53
+ const targetTrigger = viewEntry === "view" ? "trigger" : `trigger:${viewEntry.slice("view:".length)}`;
54
+ const existingIndex = actions.findIndex((a) => a === "trigger" || a.startsWith("trigger:"));
55
+ if (existingIndex === -1) {
56
+ ensureNextActions().push(targetTrigger);
57
+ } else if (actions[existingIndex] !== targetTrigger) {
58
+ ensureNextActions()[existingIndex] = targetTrigger;
59
+ }
60
+ }
61
+ const hasCreate = actions.some((a) => a === "create" || a.startsWith("create:"));
62
+ if (hasCreate) {
63
+ const existingIndex = actions.findIndex((a) => a === "triggerNew" || a.startsWith("triggerNew:"));
64
+ if (existingIndex === -1) {
65
+ ensureNextActions().push("triggerNew");
66
+ } else if (actions[existingIndex] !== "triggerNew") {
67
+ ensureNextActions()[existingIndex] = "triggerNew";
68
+ }
69
+ }
70
+ if (nextActions) {
71
+ await db.getRepository("dataSourcesRoles").update({
72
+ filter: {
73
+ roleName: dsRole.get("roleName"),
74
+ dataSourceKey: dsRole.get("dataSourceKey")
75
+ },
76
+ values: {
77
+ strategy: { ...strategy, actions: nextActions }
78
+ },
79
+ hooks: false,
80
+ transaction
81
+ });
82
+ }
83
+ }
84
+ const resources = await db.getRepository("dataSourcesRolesResources").find({
85
+ filter: { usingActionsConfig: true },
86
+ appends: ["actions"],
87
+ transaction
88
+ });
89
+ for (const resource of resources) {
90
+ const actions = resource.get("actions") || [];
91
+ const viewAction = actions.find((a) => a.get("name") === "view");
92
+ const hasTrigger = actions.some((a) => a.get("name") === "trigger");
93
+ if (viewAction && !hasTrigger) {
94
+ await db.getRepository("dataSourcesRolesResourcesActions").create({
95
+ values: {
96
+ rolesResourceId: resource.get("id"),
97
+ name: "trigger",
98
+ scopeId: viewAction.get("scopeId") ?? null,
99
+ fields: []
100
+ },
101
+ transaction
102
+ });
103
+ }
104
+ const createAction = actions.find((a) => a.get("name") === "create");
105
+ const hasTriggerNew = actions.some((a) => a.get("name") === "triggerNew");
106
+ if (createAction && !hasTriggerNew) {
107
+ await db.getRepository("dataSourcesRolesResourcesActions").create({
108
+ values: {
109
+ rolesResourceId: resource.get("id"),
110
+ name: "triggerNew",
111
+ scopeId: null,
112
+ fields: []
113
+ },
114
+ transaction
115
+ });
116
+ }
117
+ }
118
+ });
119
+ }
120
+ }
package/package.json CHANGED
@@ -1,11 +1,14 @@
1
1
  {
2
2
  "name": "@nocobase/plugin-workflow-custom-action-trigger",
3
- "version": "2.1.0-beta.15",
3
+ "version": "2.1.0-beta.17",
4
4
  "displayName": "Workflow: Custom action event",
5
5
  "displayName.zh-CN": "工作流:自定义操作事件",
6
6
  "description": "Triggers after click a custom action button.",
7
7
  "description.zh-CN": "在点击绑定了自定义事件的按钮后触发。适用于对数据行的自定义操作编排。",
8
8
  "main": "./dist/server/index.js",
9
+ "devDependencies": {
10
+ "joi": "^17.13.3"
11
+ },
9
12
  "homepage": "https://docs.nocobase.com/handbook/workflow-custom-action-trigger",
10
13
  "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/workflow-custom-action-trigger",
11
14
  "peerDependencies": {
@@ -27,6 +30,6 @@
27
30
  ],
28
31
  "editionLevel": 0
29
32
  },
30
- "gitHead": "dc1aceea6357e6ab149976c2a236fc4b6bee1370",
33
+ "gitHead": "227d625e47174ab7b3a90170e7c6c67bbdf36e23",
31
34
  "license": "Apache-2.0"
32
35
  }