@acorex-platform/framework-client 0.0.15 → 0.0.18

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 (34) hide show
  1. package/fesm2022/acorex-platform-framework-client-auth.mjs.map +1 -1
  2. package/fesm2022/acorex-platform-framework-client-common.mjs +25 -211
  3. package/fesm2022/acorex-platform-framework-client-common.mjs.map +1 -1
  4. package/fesm2022/acorex-platform-framework-client-core.mjs +8 -104
  5. package/fesm2022/acorex-platform-framework-client-core.mjs.map +1 -1
  6. package/fesm2022/acorex-platform-framework-client-layout-builder.mjs +57 -12
  7. package/fesm2022/acorex-platform-framework-client-layout-builder.mjs.map +1 -1
  8. package/fesm2022/acorex-platform-framework-client-layout-components.mjs +494 -561
  9. package/fesm2022/acorex-platform-framework-client-layout-components.mjs.map +1 -1
  10. package/fesm2022/acorex-platform-framework-client-layout-designer.mjs +8 -8
  11. package/fesm2022/acorex-platform-framework-client-layout-designer.mjs.map +1 -1
  12. package/fesm2022/acorex-platform-framework-client-layout-entity.mjs +1333 -1023
  13. package/fesm2022/acorex-platform-framework-client-layout-entity.mjs.map +1 -1
  14. package/fesm2022/acorex-platform-framework-client-layout-views.mjs +51 -9
  15. package/fesm2022/acorex-platform-framework-client-layout-views.mjs.map +1 -1
  16. package/fesm2022/acorex-platform-framework-client-layout-widget-core.mjs +29 -9
  17. package/fesm2022/acorex-platform-framework-client-layout-widget-core.mjs.map +1 -1
  18. package/fesm2022/acorex-platform-framework-client-layout-widgets.mjs +48 -15
  19. package/fesm2022/acorex-platform-framework-client-layout-widgets.mjs.map +1 -1
  20. package/fesm2022/acorex-platform-framework-client-themes-default.mjs +41 -26
  21. package/fesm2022/acorex-platform-framework-client-themes-default.mjs.map +1 -1
  22. package/fesm2022/acorex-platform-framework-client-themes-shared.mjs +4 -4
  23. package/fesm2022/acorex-platform-framework-client-themes-shared.mjs.map +1 -1
  24. package/fesm2022/acorex-platform-framework-client-workflow.mjs.map +1 -1
  25. package/package.json +7 -7
  26. package/types/acorex-platform-framework-client-auth.d.ts +2 -2
  27. package/types/acorex-platform-framework-client-common.d.ts +12 -125
  28. package/types/acorex-platform-framework-client-core.d.ts +5 -22
  29. package/types/acorex-platform-framework-client-layout-builder.d.ts +10 -0
  30. package/types/acorex-platform-framework-client-layout-components.d.ts +17 -68
  31. package/types/acorex-platform-framework-client-layout-entity.d.ts +80 -7
  32. package/types/acorex-platform-framework-client-layout-views.d.ts +11 -6
  33. package/types/acorex-platform-framework-client-layout-widgets.d.ts +1 -1
  34. package/types/acorex-platform-framework-client-workflow.d.ts +1 -2
@@ -2676,6 +2676,8 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
2676
2676
  this.aggregateAndEvaluateActions();
2677
2677
  }, DIALOG_WIDGET_COUNT_STABLE_DELAY_MS);
2678
2678
  }, ...(ngDevMode ? [{ debugName: "#widgetActionsEffect" }] : /* istanbul ignore next */ []));
2679
+ // --- Actions aggregation & evaluation ---
2680
+ this.footerActionsEvalSeq = 0;
2679
2681
  }
2680
2682
  /**
2681
2683
  * Registers footer shortcuts on the platform registry at modal priority so they win over page
@@ -2845,9 +2847,7 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
2845
2847
  },
2846
2848
  metadata: meta,
2847
2849
  patchContext: (partial) => {
2848
- const merged = merge({}, this.context(), partial);
2849
- this.context.set(merged);
2850
- this.layoutRenderer()?.updateContext(merged);
2850
+ this.applyDialogContextPatch(partial);
2851
2851
  },
2852
2852
  setLoading: (loading) => this.isDialogLoading.set(loading),
2853
2853
  };
@@ -3012,17 +3012,49 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
3012
3012
  close: (res) => {
3013
3013
  void this.closeWithOptionalSkipValidate(res);
3014
3014
  },
3015
- context: () => this.context(),
3015
+ context: () => {
3016
+ const store = this.getWidgetContainer()?.contextService;
3017
+ return (store?.data() ?? this.context());
3018
+ },
3016
3019
  action: () => actionCmd,
3017
3020
  setLoading: (loading) => this.isDialogLoading.set(loading),
3018
3021
  patchContext: (partial) => {
3019
- const merged = merge({}, this.context(), partial);
3020
- this.context.set(merged);
3021
- this.layoutRenderer()?.updateContext(merged);
3022
+ this.applyDialogContextPatch(partial);
3022
3023
  },
3023
3024
  invokeWidget: (widgetName, method, opts) => this.invokeWidget(widgetName, method, opts ?? {}),
3024
3025
  };
3025
3026
  }
3027
+ /**
3028
+ * Merges into the live widget-container store (not a possibly-stale dialog signal),
3029
+ * and forces persisted root `id` onto the store for create-wizard related steps.
3030
+ */
3031
+ applyDialogContextPatch(partial) {
3032
+ const store = this.getWidgetContainer()?.contextService;
3033
+ const live = (store?.data() ?? this.context() ?? {});
3034
+ const merged = merge({}, live, partial);
3035
+ if (store) {
3036
+ const nextId = merged['id'] ?? merged['_id'];
3037
+ const currentId = store.data()['id'] ?? store.data()['_id'];
3038
+ const hasNext = (typeof nextId === 'string' && nextId.length > 0) ||
3039
+ (typeof nextId === 'number' && !Number.isNaN(nextId));
3040
+ const hasCurrent = (typeof currentId === 'string' && currentId.length > 0) ||
3041
+ (typeof currentId === 'number' && !Number.isNaN(currentId));
3042
+ if (hasNext && !hasCurrent) {
3043
+ const identity = { id: nextId };
3044
+ if (merged['_id'] !== undefined) {
3045
+ identity['_id'] = merged['_id'];
3046
+ }
3047
+ store.patch(identity, { updateSaved: true });
3048
+ }
3049
+ else {
3050
+ store.patch(partial, { updateSaved: false });
3051
+ }
3052
+ }
3053
+ this.context.set(merged);
3054
+ // Prefer identity-only sync via [context] binding + syncExternalContext identity path.
3055
+ // Passing the full merged object after updateSaved can clearWidgets and reset the wizard.
3056
+ this.layoutRenderer()?.updateContext(merged);
3057
+ }
3026
3058
  async closeWithOptionalSkipValidate(result) {
3027
3059
  if (result && typeof result === 'object' && result.skipValidate) {
3028
3060
  this.result.emit(result);
@@ -3094,12 +3126,16 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
3094
3126
  }
3095
3127
  super.close(result);
3096
3128
  }
3097
- // --- Actions aggregation & evaluation ---
3098
3129
  async aggregateAndEvaluateActions() {
3130
+ const seq = ++this.footerActionsEvalSeq;
3099
3131
  const widgetActions = await this.collectWidgetActions();
3100
3132
  const dialogActions = this.collectDialogActionsFromConfig();
3101
3133
  const all = [...widgetActions, ...dialogActions];
3102
3134
  const evaluated = await this.evaluatePredicates(all);
3135
+ // Drop stale runs (e.g. nested Assign create triggers overlapping context refreshes).
3136
+ if (seq !== this.footerActionsEvalSeq) {
3137
+ return;
3138
+ }
3103
3139
  const visible = evaluated.filter((a) => a.hidden !== true);
3104
3140
  const prefix = visible.filter((a) => (a.zone ?? 'footer') === 'footer' && (a.placement ?? 'suffix') === 'prefix');
3105
3141
  const suffix = visible.filter((a) => (a.zone ?? 'footer') === 'footer' && (a.placement ?? 'suffix') === 'suffix');
@@ -3157,23 +3193,32 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
3157
3193
  dialog: { context: this.context() },
3158
3194
  context: this.context(),
3159
3195
  };
3160
- const disabled = await this.evalBool(a.disabled, scope);
3161
- const hidden = await this.evalBool(a.hidden, scope);
3196
+ const hiddenNeedsApi = typeof a.hidden === 'string' && /\bapi\b/.test(a.hidden);
3197
+ const disabledNeedsApi = typeof a.disabled === 'string' && /\bapi\b/.test(a.disabled);
3198
+ // Fail closed: missing wizard api must not reveal step-scoped footer actions (Done / Continue).
3199
+ const disabled = disabledNeedsApi && !api ? true : await this.evalBool(a.disabled, scope, false);
3200
+ const hidden = hiddenNeedsApi && !api ? true : await this.evalBool(a.hidden, scope, true);
3162
3201
  const resolvedTitle = (await this.evalActionTitle(a.title, scope)) ?? a.title;
3163
3202
  out.push({ ...a, disabled, hidden, title: resolvedTitle });
3164
3203
  }
3165
3204
  return out;
3166
3205
  }
3167
- async evalBool(value, scope) {
3206
+ /**
3207
+ * @param failClosed When evaluation throws / returns an error sentinel, use this value.
3208
+ * Footer `hidden` should fail closed (`true`) so step actions do not leak.
3209
+ */
3210
+ async evalBool(value, scope, failClosed) {
3168
3211
  if (typeof value === 'boolean')
3169
3212
  return value;
3170
3213
  if (typeof value === 'string') {
3171
3214
  try {
3172
3215
  const result = await this.expressionEvaluator.evaluate(value, scope);
3216
+ // Expression evaluator swallows errors and returns false — treat that as failClosed
3217
+ // only when the expression references api and api is missing (handled by caller).
3173
3218
  return !!result;
3174
3219
  }
3175
3220
  catch {
3176
- return false;
3221
+ return failClosed;
3177
3222
  }
3178
3223
  }
3179
3224
  return value;