@nocobase/plugin-flow-engine 2.1.0-beta.41 → 2.1.0-beta.43

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.
@@ -39,24 +39,137 @@ __export(filter_group_exports, {
39
39
  FLOW_SURFACE_EMPTY_FILTER_GROUP: () => FLOW_SURFACE_EMPTY_FILTER_GROUP,
40
40
  FLOW_SURFACE_FILTER_GROUP_EXAMPLE: () => FLOW_SURFACE_FILTER_GROUP_EXAMPLE,
41
41
  assertFlowSurfaceFilterGroupShape: () => assertFlowSurfaceFilterGroupShape,
42
+ assertFlowSurfaceFilterOperator: () => assertFlowSurfaceFilterOperator,
43
+ normalizeFlowSurfaceFilterDateValue: () => normalizeFlowSurfaceFilterDateValue,
42
44
  normalizeFlowSurfaceFilterGroupValue: () => normalizeFlowSurfaceFilterGroupValue
43
45
  });
44
46
  module.exports = __toCommonJS(filter_group_exports);
47
+ var import_database = require("@nocobase/database");
45
48
  var import_utils = require("@nocobase/utils");
46
49
  var import_lodash = __toESM(require("lodash"));
50
+ var import_sequelize = require("sequelize");
47
51
  var import_errors = require("./errors");
48
52
  const FLOW_SURFACE_EMPTY_FILTER_GROUP = {
49
53
  logic: "$and",
50
54
  items: []
51
55
  };
52
56
  const FLOW_SURFACE_FILTER_GROUP_EXAMPLE = JSON.stringify(FLOW_SURFACE_EMPTY_FILTER_GROUP);
57
+ const FLOW_SURFACE_FILTER_OPERATOR_REPAIR_HINT = "FilterGroup operators must use NocoBase operator names such as $notIn and $dateBefore.";
58
+ const FLOW_SURFACE_FILTER_OPERATOR_REPAIR_EXAMPLE = {
59
+ logic: "$and",
60
+ items: [
61
+ {
62
+ path: "stage",
63
+ operator: "$notIn",
64
+ value: ["won", "lost"]
65
+ }
66
+ ]
67
+ };
68
+ const FLOW_SURFACE_DATE_FILTER_OPERATORS = /* @__PURE__ */ new Set([
69
+ "$dateOn",
70
+ "$dateNotOn",
71
+ "$dateBefore",
72
+ "$dateAfter",
73
+ "$dateNotBefore",
74
+ "$dateNotAfter",
75
+ "$dateBetween"
76
+ ]);
77
+ const FLOW_SURFACE_DATE_RANGE_TYPES = /* @__PURE__ */ new Set([
78
+ "today",
79
+ "yesterday",
80
+ "tomorrow",
81
+ "thisWeek",
82
+ "lastWeek",
83
+ "nextWeek",
84
+ "thisMonth",
85
+ "lastMonth",
86
+ "nextMonth",
87
+ "thisQuarter",
88
+ "lastQuarter",
89
+ "nextQuarter",
90
+ "thisYear",
91
+ "lastYear",
92
+ "nextYear",
93
+ "past",
94
+ "next"
95
+ ]);
96
+ const FLOW_SURFACE_DATE_RANGE_UNITS = /* @__PURE__ */ new Set(["day", "week", "month", "year"]);
97
+ const FLOW_SURFACE_DATE_VALUE_REPAIR_HINT = 'Date filter values must use NocoBase-supported date values such as "2026-05-17", ["2026-05-01","2026-05-31"], or UI relative date descriptors like {"type":"past","number":14,"unit":"day"}.';
98
+ const FLOW_SURFACE_DATE_VALUE_REPAIR_EXAMPLE = {
99
+ logic: "$and",
100
+ items: [
101
+ {
102
+ path: "lastFollowUpAt",
103
+ operator: "$dateBefore",
104
+ value: { type: "past", number: 14, unit: "day" }
105
+ }
106
+ ]
107
+ };
108
+ const FLOW_SURFACE_KNOWN_FILTER_OPERATORS = buildFlowSurfaceKnownFilterOperators();
109
+ function buildFlowSurfaceKnownFilterOperators() {
110
+ const operators = new Set(Object.keys(import_database.operators));
111
+ for (const key in import_sequelize.Op) {
112
+ operators.add(`$${key}`);
113
+ const underscored = import_sequelize.Utils.underscoredIf(key, true);
114
+ operators.add(`$${underscored}`);
115
+ operators.add(`$${underscored.replace(/_/g, "")}`);
116
+ }
117
+ return operators;
118
+ }
119
+ function getSuggestedFlowSurfaceFilterOperator(operator) {
120
+ if (operator.startsWith("$")) {
121
+ return void 0;
122
+ }
123
+ const suggestedOperator = `$${operator}`;
124
+ return FLOW_SURFACE_KNOWN_FILTER_OPERATORS.has(suggestedOperator) ? suggestedOperator : void 0;
125
+ }
126
+ function assertFlowSurfaceFilterOperator(operator, path) {
127
+ if (typeof operator !== "string" || !operator.trim()) {
128
+ (0, import_errors.throwBadRequest)(`${path} must be a non-empty operator string`, {
129
+ path,
130
+ ruleId: "filter-group-operator-invalid",
131
+ details: {
132
+ invalidOperator: operator,
133
+ repairHint: FLOW_SURFACE_FILTER_OPERATOR_REPAIR_HINT,
134
+ repairExample: FLOW_SURFACE_FILTER_OPERATOR_REPAIR_EXAMPLE
135
+ }
136
+ });
137
+ }
138
+ if (!operator.startsWith("$")) {
139
+ const suggestedOperator = getSuggestedFlowSurfaceFilterOperator(operator);
140
+ (0, import_errors.throwBadRequest)(
141
+ suggestedOperator ? `${path} must start with "$"; use "${suggestedOperator}" instead of "${operator}"` : `${path} must start with "$"`,
142
+ {
143
+ path,
144
+ ruleId: "filter-group-operator-missing-dollar",
145
+ details: {
146
+ invalidOperator: operator,
147
+ ...suggestedOperator ? { suggestedOperator } : {},
148
+ repairHint: FLOW_SURFACE_FILTER_OPERATOR_REPAIR_HINT,
149
+ repairExample: FLOW_SURFACE_FILTER_OPERATOR_REPAIR_EXAMPLE
150
+ }
151
+ }
152
+ );
153
+ }
154
+ }
155
+ function normalizeFlowSurfaceFilterDateValue(operator, value, path) {
156
+ if (typeof operator !== "string" || !FLOW_SURFACE_DATE_FILTER_OPERATORS.has(operator)) {
157
+ return value;
158
+ }
159
+ return normalizeFlowSurfaceDateValue(value, path);
160
+ }
53
161
  function normalizeFlowSurfaceFilterGroupValue(value, errorPrefix) {
54
162
  const normalized = value === null || import_lodash.default.isPlainObject(value) && !Object.keys(value).length ? import_lodash.default.cloneDeep(FLOW_SURFACE_EMPTY_FILTER_GROUP) : import_lodash.default.cloneDeep(value);
55
163
  try {
56
164
  assertFlowSurfaceFilterGroupShape(normalized);
165
+ assertFlowSurfaceFilterGroupOperators(normalized, errorPrefix);
166
+ normalizeFlowSurfaceFilterGroupDateValues(normalized, errorPrefix);
57
167
  (0, import_utils.transformFilter)(normalized);
58
168
  return normalized;
59
169
  } catch (error) {
170
+ if (error instanceof import_errors.FlowSurfaceBadRequestError) {
171
+ throw error;
172
+ }
60
173
  const reason = error instanceof Error ? error.message : String(error);
61
174
  (0, import_errors.throwBadRequest)(`${errorPrefix}: ${reason}`);
62
175
  }
@@ -85,10 +198,192 @@ function assertFlowSurfaceFilterGroupShape(filter) {
85
198
  throw new Error("Invalid filter item type");
86
199
  });
87
200
  }
201
+ function assertFlowSurfaceFilterGroupOperators(filter, errorPrefix) {
202
+ filter.items.forEach((item, index) => {
203
+ const itemPath = `${errorPrefix}.items[${index}]`;
204
+ if (import_lodash.default.isPlainObject(item) && "logic" in item && "items" in item) {
205
+ assertFlowSurfaceFilterGroupOperators(item, itemPath);
206
+ return;
207
+ }
208
+ assertFlowSurfaceFilterOperator(item.operator, `${itemPath}.operator`);
209
+ });
210
+ }
211
+ function normalizeFlowSurfaceFilterGroupDateValues(filter, errorPrefix) {
212
+ filter.items.forEach((item, index) => {
213
+ const itemPath = `${errorPrefix}.items[${index}]`;
214
+ if (import_lodash.default.isPlainObject(item) && "logic" in item && "items" in item) {
215
+ normalizeFlowSurfaceFilterGroupDateValues(item, itemPath);
216
+ return;
217
+ }
218
+ item.value = normalizeFlowSurfaceFilterDateValue(item.operator, item.value, `${itemPath}.value`);
219
+ });
220
+ }
221
+ function normalizeFlowSurfaceDateValue(value, path) {
222
+ if (import_lodash.default.isNil(value) || value === "") {
223
+ return value;
224
+ }
225
+ if (Array.isArray(value)) {
226
+ const normalized2 = normalizeFlowSurfaceDateArrayValue(value, path);
227
+ if (!hasTemplateDateValue(normalized2)) {
228
+ assertFlowSurfaceDateValueParsable(normalized2, path);
229
+ }
230
+ return normalized2;
231
+ }
232
+ const normalized = normalizeFlowSurfaceDateValuePart(value, path);
233
+ if (!hasTemplateDateValue(normalized)) {
234
+ assertFlowSurfaceDateValueParsable(normalized, path);
235
+ }
236
+ return normalized;
237
+ }
238
+ function normalizeFlowSurfaceDateArrayValue(value, path) {
239
+ if (value.length !== 2) {
240
+ throwInvalidFlowSurfaceDateValue(path, value, {
241
+ invalidReason: "date range arrays must contain exactly start and end values"
242
+ });
243
+ }
244
+ return value.map((item, index) => normalizeFlowSurfaceDateValuePart(item, `${path}[${index}]`));
245
+ }
246
+ function normalizeFlowSurfaceDateValuePart(value, path) {
247
+ if (import_lodash.default.isNil(value) || value === "" || isTemplateDateString(value) || value instanceof Date) {
248
+ return value;
249
+ }
250
+ if (typeof value === "string") {
251
+ const relative = normalizeRelativeDateShorthand(value, path);
252
+ if (relative) {
253
+ return relative;
254
+ }
255
+ assertFlowSurfaceDateValueParsable(value, path);
256
+ return value;
257
+ }
258
+ if (import_lodash.default.isPlainObject(value)) {
259
+ return normalizeRelativeDateDescriptor(value, path);
260
+ }
261
+ assertFlowSurfaceDateValueParsable(value, path);
262
+ return value;
263
+ }
264
+ function normalizeRelativeDateShorthand(value, path) {
265
+ const match = /^\s*([+-])(\d+)d\s*$/i.exec(value);
266
+ if (!match) {
267
+ return void 0;
268
+ }
269
+ return normalizeRelativeDateDescriptor(
270
+ {
271
+ type: match[1] === "-" ? "past" : "next",
272
+ number: Number(match[2]),
273
+ unit: "day"
274
+ },
275
+ path
276
+ );
277
+ }
278
+ function normalizeRelativeDateDescriptor(value, path) {
279
+ const rawType = value.type;
280
+ const type = typeof rawType === "string" ? rawType.trim() : "";
281
+ if (!isTemplateDateString(rawType) && !FLOW_SURFACE_DATE_RANGE_TYPES.has(type)) {
282
+ throwInvalidFlowSurfaceDateValue(path, value, {
283
+ invalidReason: type ? `unsupported relative date type "${type}"` : "relative date descriptor must include type"
284
+ });
285
+ }
286
+ const normalized = {
287
+ ...value,
288
+ type: isTemplateDateString(rawType) ? rawType : type
289
+ };
290
+ if (type === "past" || type === "next") {
291
+ if (import_lodash.default.isUndefined(value.number)) {
292
+ normalized.number = 1;
293
+ } else if (!isTemplateDateString(value.number)) {
294
+ const number = Number(value.number);
295
+ if (!Number.isFinite(number) || number <= 0) {
296
+ throwInvalidFlowSurfaceDateValue(path, value, {
297
+ invalidReason: "past/next relative date descriptor number must be greater than 0"
298
+ });
299
+ }
300
+ normalized.number = number;
301
+ }
302
+ if (import_lodash.default.isUndefined(value.unit)) {
303
+ normalized.unit = "day";
304
+ } else if (!isTemplateDateString(value.unit)) {
305
+ const unit = typeof value.unit === "string" ? value.unit.trim() : "";
306
+ if (!FLOW_SURFACE_DATE_RANGE_UNITS.has(unit)) {
307
+ throwInvalidFlowSurfaceDateValue(path, value, {
308
+ invalidReason: `unsupported relative date unit "${unit}"`
309
+ });
310
+ }
311
+ normalized.unit = unit;
312
+ }
313
+ } else {
314
+ if (!import_lodash.default.isUndefined(value.number) && !isTemplateDateString(value.number)) {
315
+ const number = Number(value.number);
316
+ if (!Number.isFinite(number) || number <= 0) {
317
+ throwInvalidFlowSurfaceDateValue(path, value, {
318
+ invalidReason: "relative date descriptor number must be greater than 0"
319
+ });
320
+ }
321
+ normalized.number = number;
322
+ }
323
+ if (!import_lodash.default.isUndefined(value.unit) && !isTemplateDateString(value.unit)) {
324
+ const unit = typeof value.unit === "string" ? value.unit.trim() : "";
325
+ if (!FLOW_SURFACE_DATE_RANGE_UNITS.has(unit)) {
326
+ throwInvalidFlowSurfaceDateValue(path, value, {
327
+ invalidReason: `unsupported relative date unit "${unit}"`
328
+ });
329
+ }
330
+ normalized.unit = unit;
331
+ }
332
+ }
333
+ if (!hasTemplateDateValue(normalized)) {
334
+ try {
335
+ (0, import_utils.getDayRangeByParams)(normalized);
336
+ } catch (error) {
337
+ throwInvalidFlowSurfaceDateValue(path, value, {
338
+ invalidReason: error instanceof Error ? error.message : String(error)
339
+ });
340
+ }
341
+ }
342
+ return normalized;
343
+ }
344
+ function isTemplateDateString(value) {
345
+ return typeof value === "string" && /^\s*\{\{[\s\S]*\}\}\s*$/.test(value);
346
+ }
347
+ function hasTemplateDateValue(value) {
348
+ if (isTemplateDateString(value)) {
349
+ return true;
350
+ }
351
+ if (Array.isArray(value)) {
352
+ return value.some((item) => hasTemplateDateValue(item));
353
+ }
354
+ if (import_lodash.default.isPlainObject(value)) {
355
+ return Object.values(value).some((item) => hasTemplateDateValue(item));
356
+ }
357
+ return false;
358
+ }
359
+ function assertFlowSurfaceDateValueParsable(value, path) {
360
+ try {
361
+ const parsed = (0, import_utils.parseDate)(value);
362
+ if (parsed) {
363
+ return;
364
+ }
365
+ } catch {
366
+ }
367
+ throwInvalidFlowSurfaceDateValue(path, value);
368
+ }
369
+ function throwInvalidFlowSurfaceDateValue(path, value, details = {}) {
370
+ (0, import_errors.throwBadRequest)(`${path} must be a valid date filter value`, {
371
+ path,
372
+ ruleId: "filter-group-date-value-invalid",
373
+ details: {
374
+ invalidValue: value,
375
+ ...details,
376
+ repairHint: FLOW_SURFACE_DATE_VALUE_REPAIR_HINT,
377
+ repairExample: FLOW_SURFACE_DATE_VALUE_REPAIR_EXAMPLE
378
+ }
379
+ });
380
+ }
88
381
  // Annotate the CommonJS export names for ESM import in node:
89
382
  0 && (module.exports = {
90
383
  FLOW_SURFACE_EMPTY_FILTER_GROUP,
91
384
  FLOW_SURFACE_FILTER_GROUP_EXAMPLE,
92
385
  assertFlowSurfaceFilterGroupShape,
386
+ assertFlowSurfaceFilterOperator,
387
+ normalizeFlowSurfaceFilterDateValue,
93
388
  normalizeFlowSurfaceFilterGroupValue
94
389
  });
@@ -166,7 +166,7 @@ class FlowSurfaceRouteSync {
166
166
  await this.removeRouteAnchorChildren(schemaUid, transaction);
167
167
  }
168
168
  async persistPageSettings(target, current, nextPayload, transaction) {
169
- var _a;
169
+ var _a, _b;
170
170
  const route = await this.hydrateRoute(target.pageRoute, transaction);
171
171
  const routeValues = this.buildPageRoutePatch(current, nextPayload, route);
172
172
  if (Object.keys(routeValues).length) {
@@ -175,8 +175,25 @@ class FlowSurfaceRouteSync {
175
175
  values: routeValues,
176
176
  transaction
177
177
  });
178
+ if (Object.prototype.hasOwnProperty.call(routeValues, "enableTabs")) {
179
+ const tabRouteHidden = !routeValues.enableTabs;
180
+ await Promise.all(
181
+ import_lodash.default.castArray(((_a = route == null ? void 0 : route.get) == null ? void 0 : _a.call(route, "children")) || (route == null ? void 0 : route.children) || []).map((tabRoute) => {
182
+ var _a2;
183
+ return ((_a2 = tabRoute == null ? void 0 : tabRoute.get) == null ? void 0 : _a2.call(tabRoute, "id")) ?? (tabRoute == null ? void 0 : tabRoute.id);
184
+ }).filter((routeId) => !import_lodash.default.isNil(routeId) && routeId !== "").map(
185
+ (routeId) => this.db.getRepository("desktopRoutes").update({
186
+ filterByTk: String(routeId),
187
+ values: {
188
+ hidden: tabRouteHidden
189
+ },
190
+ transaction
191
+ })
192
+ )
193
+ );
194
+ }
178
195
  }
179
- const pageSchemaUid = ((_a = route == null ? void 0 : route.get) == null ? void 0 : _a.call(route, "schemaUid")) || (route == null ? void 0 : route.schemaUid);
196
+ const pageSchemaUid = ((_b = route == null ? void 0 : route.get) == null ? void 0 : _b.call(route, "schemaUid")) || (route == null ? void 0 : route.schemaUid);
180
197
  const pageModel = target.pageModel || (pageSchemaUid ? await this.repository.findModelByParentId(pageSchemaUid, {
181
198
  transaction,
182
199
  subKey: "page",
@@ -625,7 +625,7 @@ function rethrowInlineConfigurationError(error, prefix) {
625
625
  if ((0, import_errors.isFlowSurfaceError)(error)) {
626
626
  const normalized = (0, import_errors.normalizeFlowSurfaceError)(error);
627
627
  if (normalized.type === "bad_request") {
628
- (0, import_errors.throwBadRequest)(message, normalized.code);
628
+ (0, import_errors.throwBadRequest)(message, normalized.code, normalized.options);
629
629
  }
630
630
  if (normalized.type === "conflict") {
631
631
  (0, import_errors.throwConflict)(message, normalized.code);
@@ -11,6 +11,7 @@ import _ from 'lodash';
11
11
  import FlowModelRepository from '../repository';
12
12
  import type { FlowSurfaceApplyBlueprintDocument } from './blueprint';
13
13
  import { SurfaceLocator } from './locator';
14
+ import { type FlowSurfaceEventFlowRegistry } from './event-flow-normalizer';
14
15
  import type { TemplateTranslate } from './template-display';
15
16
  import type { FlowSurfaceActionLinkageRule, FlowSurfaceBlockLinkageRule, FlowSurfaceFieldLinkageRule, FlowSurfaceFieldValueRule, FlowSurfaceGetReactionMetaResult, FlowSurfaceGetReactionMetaValues, FlowSurfaceReactionWriteResult, FlowSurfaceReactionWriteValues } from './reaction/types';
16
17
  import type { FlowSurfaceTemplateListPopupActionContext, FlowSurfaceTemplateListValues, FlowSurfaceTemplateRow } from './template-service-utils';
@@ -768,7 +769,7 @@ export declare class FlowSurfacesService {
768
769
  kind: import("./types").FlowSurfaceContainerKind;
769
770
  use: any;
770
771
  };
771
- flowRegistry: any;
772
+ flowRegistry: FlowSurfaceEventFlowRegistry;
772
773
  events: {
773
774
  direct: string[];
774
775
  object: string[];
@@ -839,6 +840,7 @@ export declare class FlowSurfacesService {
839
840
  }>;
840
841
  private resolveEventFlowTarget;
841
842
  private getEventFlowRegistry;
843
+ private normalizeEventFlowRegistry;
842
844
  private buildEventFlowFingerprint;
843
845
  private assertEventFlowFingerprint;
844
846
  private normalizeEventFlowKey;