@shwfed/config 2.8.0 → 2.9.0

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 (110) hide show
  1. package/dist/mcp.mjs +61 -10
  2. package/dist/module.json +1 -1
  3. package/dist/preview/assets/{badge-BI1mdo92.js → badge-Ddz0ExD-.js} +1 -1
  4. package/dist/preview/assets/{config-XgVqueyq.js → config---5_lEKG.js} +1 -1
  5. package/dist/preview/assets/{config-OrJljNWU.js → config-5qIYVWZh.js} +1 -1
  6. package/dist/preview/assets/config-B8zbFg3y.js +1 -0
  7. package/dist/preview/assets/{config-DqUnpWZk.js → config-Bn619USg.js} +1 -1
  8. package/dist/preview/assets/{config-DuzQXHvg.js → config-CUeBTyLb.js} +1 -1
  9. package/dist/preview/assets/config-DN_3WauN.js +1 -0
  10. package/dist/preview/assets/config-U-3fWb-2.js +1 -0
  11. package/dist/preview/assets/config-q5VV9rp7.js +1 -0
  12. package/dist/preview/assets/config-vePqHFvZ.js +1 -0
  13. package/dist/preview/assets/{definition.vue_vue_type_script_setup_true_lang-lEhYVEcN.js → definition.vue_vue_type_script_setup_true_lang-fQa65UMX.js} +1 -1
  14. package/dist/preview/assets/index-BKaqQGb-.js +688 -0
  15. package/dist/preview/assets/index-Bj8xIK5h.js +1 -0
  16. package/dist/preview/assets/index-BlHAyQdm.css +1 -0
  17. package/dist/preview/assets/{index-BvLLQuQr.js → index-CzWhSvDG.js} +1 -1
  18. package/dist/preview/assets/{item-DMtXi_cx.js → item-DHarupON.js} +1 -1
  19. package/dist/preview/assets/{runtime-CA58Mif7.js → runtime-560tuaHv.js} +1 -1
  20. package/dist/preview/assets/{runtime-CjJBU_e1.js → runtime-C2rQ3L3-.js} +1 -1
  21. package/dist/preview/assets/{runtime-DeUmGsM_.js → runtime-CKghL8I_.js} +1 -1
  22. package/dist/preview/assets/runtime-CMsaNery.js +1 -0
  23. package/dist/preview/assets/runtime-CMuCGJZm.js +1 -0
  24. package/dist/preview/assets/{runtime-wVZ1xP8L.js → runtime-DOM_La4X.js} +1 -1
  25. package/dist/preview/assets/{runtime-BUPuX-Gq.js → runtime-DQHb9t0r.js} +1 -1
  26. package/dist/preview/assets/{runtime-DnXoWy2A.js → runtime-Dgl3wVfD.js} +1 -1
  27. package/dist/preview/assets/{runtime-CWqQzWuc.js → runtime-aLgWVLET.js} +1 -1
  28. package/dist/preview/index.html +2 -2
  29. package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json/config.d.vue.ts +8 -0
  30. package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json/config.vue +28 -0
  31. package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json/config.vue.d.ts +8 -0
  32. package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json/runtime.vue +17 -17
  33. package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json/schema.d.ts +4 -0
  34. package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json/schema.js +8 -0
  35. package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json.confirm/config.d.vue.ts +8 -0
  36. package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json.confirm/config.vue +25 -0
  37. package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json.confirm/config.vue.d.ts +8 -0
  38. package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json.confirm/runtime.vue +2 -7
  39. package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json.confirm/schema.d.ts +4 -0
  40. package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json.confirm/schema.js +8 -0
  41. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.multi/runtime.vue +13 -2
  42. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.multi/schema.d.ts +1 -0
  43. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.multi/schema.js +4 -1
  44. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.single/runtime.vue +10 -2
  45. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.single/schema.d.ts +1 -0
  46. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.single/schema.js +4 -1
  47. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.multi/runtime.vue +16 -0
  48. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.multi/schema.d.ts +1 -0
  49. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.multi/schema.js +4 -1
  50. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.single/runtime.vue +13 -5
  51. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.single/schema.d.ts +1 -0
  52. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.single/schema.js +4 -1
  53. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/runtime.vue +25 -5
  54. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/schema.d.ts +1 -0
  55. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/schema.js +4 -1
  56. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/runtime.vue +18 -8
  57. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/schema.d.ts +1 -0
  58. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/schema.js +4 -1
  59. package/dist/runtime/components/form/index.vue +11 -3
  60. package/dist/runtime/components/form/schema.d.ts +4 -0
  61. package/dist/runtime/components/form/schema.js +1 -0
  62. package/dist/runtime/components/form/unit-config.vue +6 -1
  63. package/dist/runtime/components/form/utils/form-vars.js +2 -0
  64. package/dist/runtime/components/form/utils/resolve.d.ts +10 -0
  65. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/runtime.vue +13 -2
  66. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/schema.d.ts +1 -0
  67. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/schema.js +4 -1
  68. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/runtime.vue +10 -2
  69. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/schema.d.ts +1 -0
  70. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/schema.js +4 -1
  71. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-multi/runtime.vue +16 -0
  72. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-multi/schema.d.ts +1 -0
  73. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-multi/schema.js +3 -1
  74. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-single/runtime.vue +13 -5
  75. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-single/schema.d.ts +1 -0
  76. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-single/schema.js +3 -1
  77. package/dist/runtime/components/table/config.vue +5 -1
  78. package/dist/runtime/components/table/row-provider.vue +8 -0
  79. package/dist/runtime/components/table/utils/resolve.d.ts +7 -0
  80. package/dist/runtime/components/table/utils/shared.js +4 -0
  81. package/dist/runtime/components/ui/expression-editor/CodeMirrorInput.d.vue.ts +1 -0
  82. package/dist/runtime/components/ui/expression-editor/CodeMirrorInput.vue +9 -1
  83. package/dist/runtime/components/ui/expression-editor/CodeMirrorInput.vue.d.ts +1 -0
  84. package/dist/runtime/components/ui/expression-editor/ExpressionEditor.d.vue.ts +2 -2
  85. package/dist/runtime/components/ui/expression-editor/ExpressionEditor.vue +33 -4
  86. package/dist/runtime/components/ui/expression-editor/ExpressionEditor.vue.d.ts +2 -2
  87. package/dist/runtime/components/ui/expression-editor/picker-entries.d.ts +3 -2
  88. package/dist/runtime/components/ui/expression-editor/picker-entries.js +14 -3
  89. package/dist/runtime/components/ui/expression-editor/selection-chip-extension.d.ts +4 -0
  90. package/dist/runtime/components/ui/expression-editor/selection-chip-extension.js +119 -0
  91. package/dist/runtime/components/ui/expression-editor/selection-refs.d.ts +8 -0
  92. package/dist/runtime/components/ui/expression-editor/selection-refs.js +29 -0
  93. package/dist/runtime/share/event-bus.d.ts +12 -12
  94. package/dist/runtime/utils/cel-context.d.ts +22 -0
  95. package/dist/runtime/utils/cel-context.js +8 -0
  96. package/dist/runtime/utils/selections-registry.d.ts +77 -0
  97. package/dist/runtime/utils/selections-registry.js +49 -0
  98. package/package.json +1 -1
  99. package/dist/preview/assets/config-BNF2r9jW.js +0 -1
  100. package/dist/preview/assets/config-BxuGYvER.js +0 -1
  101. package/dist/preview/assets/config-Cy5w3JWQ.js +0 -1
  102. package/dist/preview/assets/config-Du5SuNSb.js +0 -1
  103. package/dist/preview/assets/config-ggyCcWNZ.js +0 -1
  104. package/dist/preview/assets/index-DsMR5NfK.css +0 -1
  105. package/dist/preview/assets/index-Yv78vz4W.js +0 -680
  106. package/dist/preview/assets/index-yrBKwEfk.js +0 -1
  107. package/dist/preview/assets/runtime-2S3Yr051.js +0 -1
  108. package/dist/preview/assets/runtime-C4jFTZ4Z.js +0 -1
  109. package/dist/runtime/share/form-validate.d.ts +0 -18
  110. package/dist/runtime/share/form-validate.js +0 -8
@@ -1,7 +1,7 @@
1
- import { type ScopeAncestor } from '../../../utils/cel-context.js';
1
+ import { type ScopeAncestor, type SelectionFieldRef } from '../../../utils/cel-context.js';
2
2
  export type PickEntry = {
3
3
  id: string;
4
- group: 'var' | 'scope';
4
+ group: 'var' | 'scope' | 'selection';
5
5
  insert: string;
6
6
  display: string;
7
7
  label: string;
@@ -14,4 +14,5 @@ export type PickVarMeta = {
14
14
  description?: string;
15
15
  };
16
16
  export declare function buildVarEntries(celContext: Record<string, PickVarMeta>, extraVars?: Record<string, PickVarMeta>): PickEntry[];
17
+ export declare function buildSelectionEntries(roster: ReadonlyArray<SelectionFieldRef>): PickEntry[];
17
18
  export declare function buildScopeEntries(ancestry: ReadonlyArray<ScopeAncestor>): PickEntry[];
@@ -1,19 +1,30 @@
1
- import { SCOPE_ADDRESS_VAR } from "../../../utils/cel-context.js";
1
+ import { SCOPE_ADDRESS_VAR, SELECTIONS_VAR } from "../../../utils/cel-context.js";
2
2
  import { scopeOrigin } from "./scope-refs.js";
3
+ const SUPPRESSED_VARS = /* @__PURE__ */ new Set([SCOPE_ADDRESS_VAR, SELECTIONS_VAR]);
3
4
  export function buildVarEntries(celContext, extraVars) {
4
5
  const out = [];
5
6
  const seen = /* @__PURE__ */ new Set();
6
7
  for (const [name, meta] of Object.entries(celContext)) {
7
- if (name === SCOPE_ADDRESS_VAR) continue;
8
+ if (SUPPRESSED_VARS.has(name)) continue;
8
9
  seen.add(name);
9
10
  out.push({ id: name, group: "var", insert: name, display: name, label: meta.label, type: meta.type, description: meta.description });
10
11
  }
11
12
  for (const [name, meta] of Object.entries(extraVars ?? {})) {
12
- if (seen.has(name) || name === SCOPE_ADDRESS_VAR) continue;
13
+ if (seen.has(name) || SUPPRESSED_VARS.has(name)) continue;
13
14
  out.push({ id: name, group: "var", insert: name, display: name, label: meta.label, type: meta.type, description: meta.description });
14
15
  }
15
16
  return out;
16
17
  }
18
+ export function buildSelectionEntries(roster) {
19
+ return roster.map((field) => ({
20
+ id: `selection:${field.id}`,
21
+ group: "selection",
22
+ insert: `${SELECTIONS_VAR}[${JSON.stringify(field.id)}]`,
23
+ display: field.name,
24
+ label: "\u9009\u4E2D\u9879",
25
+ type: "dyn"
26
+ }));
27
+ }
17
28
  export function buildScopeEntries(ancestry) {
18
29
  const out = [];
19
30
  for (const ancestor of ancestry) {
@@ -0,0 +1,4 @@
1
+ import { type Extension, Facet } from '@codemirror/state';
2
+ export declare const selectionLookupFacet: Facet<Map<string, string>, Map<string, string>>;
3
+ /** The full selection inline-chip extension: decoration plugin + theme. */
4
+ export declare function selectionChips(): Extension;
@@ -0,0 +1,119 @@
1
+ import { Facet, RangeSetBuilder } from "@codemirror/state";
2
+ import {
3
+ Decoration,
4
+ EditorView,
5
+ ViewPlugin,
6
+ WidgetType
7
+ } from "@codemirror/view";
8
+ import { scanSelectionRefs } from "./selection-refs.js";
9
+ export const selectionLookupFacet = Facet.define({
10
+ combine: (values) => values.length > 0 ? values[values.length - 1] : /* @__PURE__ */ new Map()
11
+ });
12
+ class SelectionChipWidget extends WidgetType {
13
+ constructor(id, name) {
14
+ super();
15
+ this.id = id;
16
+ this.name = name;
17
+ }
18
+ eq(other) {
19
+ return other.id === this.id && other.name === this.name;
20
+ }
21
+ toDOM() {
22
+ const chip = document.createElement("span");
23
+ chip.className = "cm-selection-chip";
24
+ chip.setAttribute("data-selection-id", this.id);
25
+ const tag = document.createElement("span");
26
+ tag.className = "cm-selection-chip-tag";
27
+ tag.textContent = "\u9009\u4E2D\u9879";
28
+ chip.appendChild(tag);
29
+ const text = document.createElement("span");
30
+ text.className = "cm-selection-chip-label";
31
+ if (this.name !== null) {
32
+ text.textContent = this.name;
33
+ chip.title = `\u9009\u4E2D\u9879 \xB7 ${this.name}`;
34
+ } else {
35
+ chip.classList.add("cm-selection-chip-dangling");
36
+ const short = this.id.length > 8 ? `${this.id.slice(0, 8)}\u2026` : this.id;
37
+ text.textContent = short;
38
+ chip.title = `\u672A\u77E5\u5B57\u6BB5 ${this.id}`;
39
+ }
40
+ chip.appendChild(text);
41
+ return chip;
42
+ }
43
+ ignoreEvent() {
44
+ return false;
45
+ }
46
+ }
47
+ function buildChips(view) {
48
+ const lookup = view.state.facet(selectionLookupFacet);
49
+ const builder = new RangeSetBuilder();
50
+ for (const ref of scanSelectionRefs(view.state.doc.toString())) {
51
+ const name = lookup.get(ref.id) ?? null;
52
+ builder.add(
53
+ ref.from,
54
+ ref.to,
55
+ Decoration.replace({ widget: new SelectionChipWidget(ref.id, name) })
56
+ );
57
+ }
58
+ return builder.finish();
59
+ }
60
+ const chipPlugin = ViewPlugin.fromClass(
61
+ class {
62
+ decorations;
63
+ constructor(view) {
64
+ this.decorations = buildChips(view);
65
+ }
66
+ update(update) {
67
+ if (update.docChanged || update.viewportChanged || update.startState.facet(selectionLookupFacet) !== update.state.facet(selectionLookupFacet)) {
68
+ this.decorations = buildChips(update.view);
69
+ }
70
+ }
71
+ },
72
+ {
73
+ decorations: (plugin) => plugin.decorations,
74
+ // Atomic so the caret steps over a chip and Backspace removes the whole
75
+ // `selections["id"]` at once — matching the scope chip's delete-as-unit feel.
76
+ provide: (plugin) => EditorView.atomicRanges.of((view) => view.plugin(plugin)?.decorations ?? Decoration.none)
77
+ }
78
+ );
79
+ const chipTheme = EditorView.theme({
80
+ ".cm-selection-chip": {
81
+ display: "inline-flex",
82
+ alignItems: "center",
83
+ gap: "0.25rem",
84
+ margin: "0 1px",
85
+ padding: "0.125rem 0.25rem",
86
+ borderRadius: "0.25rem",
87
+ background: "#f0fdfa",
88
+ border: "1px solid #99f6e4",
89
+ color: "#0f766e",
90
+ fontFamily: "ui-sans-serif, system-ui, sans-serif",
91
+ verticalAlign: "baseline",
92
+ cursor: "default",
93
+ whiteSpace: "nowrap"
94
+ },
95
+ ".cm-selection-chip-dangling": {
96
+ background: "#fef2f2",
97
+ borderColor: "#fecaca",
98
+ color: "#b91c1c"
99
+ },
100
+ ".cm-selection-chip-tag": {
101
+ borderRadius: "0.125rem",
102
+ background: "#ccfbf1",
103
+ padding: "0.05rem 0.2rem",
104
+ fontSize: "9px",
105
+ lineHeight: "1",
106
+ color: "#0d9488"
107
+ },
108
+ ".cm-selection-chip-dangling .cm-selection-chip-tag": {
109
+ background: "#fee2e2",
110
+ color: "#b91c1c"
111
+ },
112
+ ".cm-selection-chip-label": {
113
+ fontSize: "0.75rem",
114
+ lineHeight: "1.1"
115
+ }
116
+ });
117
+ export function selectionChips() {
118
+ return [chipPlugin, chipTheme];
119
+ }
@@ -0,0 +1,8 @@
1
+ import { type SelectionFieldRef } from '../../../utils/cel-context.js';
2
+ export type SelectionRef = {
3
+ from: number;
4
+ to: number;
5
+ id: string;
6
+ };
7
+ export declare function scanSelectionRefs(text: string): SelectionRef[];
8
+ export declare function buildSelectionLookup(roster: ReadonlyArray<SelectionFieldRef>): Map<string, string>;
@@ -0,0 +1,29 @@
1
+ import { SELECTIONS_VAR } from "../../../utils/cel-context.js";
2
+ const SELECTION_REF_RE = new RegExp(
3
+ `(?<![\\w$.])${SELECTIONS_VAR}\\[("(?:[^"\\\\]|\\\\.)*")\\]`,
4
+ "g"
5
+ );
6
+ export function scanSelectionRefs(text) {
7
+ const out = [];
8
+ SELECTION_REF_RE.lastIndex = 0;
9
+ let match;
10
+ while ((match = SELECTION_REF_RE.exec(text)) !== null) {
11
+ let id;
12
+ try {
13
+ id = JSON.parse(match[1]);
14
+ } catch {
15
+ continue;
16
+ }
17
+ out.push({
18
+ from: match.index,
19
+ to: match.index + match[0].length,
20
+ id
21
+ });
22
+ }
23
+ return out;
24
+ }
25
+ export function buildSelectionLookup(roster) {
26
+ const lookup = /* @__PURE__ */ new Map();
27
+ for (const field of roster) lookup.set(field.id, field.name);
28
+ return lookup;
29
+ }
@@ -51,19 +51,19 @@ export type EventChannel = Readonly<{
51
51
  * A handler MAY still *halt* the chain — the "guard" shape: stop everything
52
52
  * queued after it. `dispatchTriggers` runs the list with `Effect.forEach`,
53
53
  * which short-circuits the moment one request's effect aborts, so triggers
54
- * after the guard never dispatch. The page's `close` op is the canonical case
55
- * (it halts unconditionally — nothing should run after a close). It halts with
56
- * `Effect.die`, not `Effect.fail`: a defect aborts the chain without widening
57
- * the `void` error channel here (and `ActionEffect`'s `catchTags` union over in
58
- * `actions/components/group.vue`). The defect propagates to that runner's
59
- * `runPromise`, whose outer try/catch absorbs it silently `catchTags` only
60
- * intercepts typed failures, so no toast.
54
+ * after the guard never dispatch. Two ops use this: the page's `close` (halts
55
+ * unconditionally — nothing should run after a close) and the form's `validate`
56
+ * (halts only when an `error`-severity result remains, gating a submit). Both
57
+ * halt with `Effect.die`, not `Effect.fail`: a defect aborts the chain without
58
+ * widening the `void` error channel here (and `ActionEffect`'s `catchTags`
59
+ * union over in `actions/components/group.vue`). The defect propagates to that
60
+ * runner's `runPromise`, whose outer try/catch absorbs it silently — `catchTags`
61
+ * only intercepts typed failures, so no toast.
61
62
  *
62
- * Pre-submit form validation is the same guard shape but doesn't run over this
63
- * bus yet it injects the separate `share/form-validate` seam. The intended
64
- * end state folds it in as a fallible `validate` operation here, at which point
65
- * the error channel widens to carry a typed validation failure (see the note in
66
- * `form-validate.ts`).
63
+ * Pre-submit form validation rides this bus as that `validate` guard: a
64
+ * submit-style button (e.g. the HTTP-request buttons) puts it first in its own
65
+ * pre-request trigger list, so validation is explicit and configured rather
66
+ * than an implicit host gate.
67
67
  */
68
68
  export type OperationHandlers = Readonly<Record<string, () => Effect.Effect<void>>>;
69
69
  export declare const EVENT_CHANNEL_KEY: InjectionKey<EventChannel>;
@@ -7,6 +7,7 @@ export type CELVar = {
7
7
  };
8
8
  export type CELContext = Record<string, CELVar>;
9
9
  export declare const SCOPE_ADDRESS_VAR = "__scopes__";
10
+ export declare const SELECTIONS_VAR = "selections";
10
11
  export type ScopeAccessor = Record<string, () => unknown>;
11
12
  export declare function provideCELContext(context: CELContext): void;
12
13
  export declare function injectCELContext(): CELContext;
@@ -43,4 +44,25 @@ export declare function provideScopeAncestor(ancestor: Ref<ScopeAncestor | null>
43
44
  * first. Empty when nothing up the config tree exposes an addressable scope.
44
45
  */
45
46
  export declare function useScopeAncestry(): Ref<ReadonlyArray<ScopeAncestor>>;
47
+ /** One selection-like field in the editing form, as the picker/chip surfaces it. */
48
+ export type SelectionFieldRef = Readonly<{
49
+ /** Field uuid keyed into `selections["<id>"]` — the registry/publish key. */
50
+ id: string;
51
+ /** The field's designer-facing name, shown instead of the raw uuid. */
52
+ name: string;
53
+ }>;
54
+ /**
55
+ * Advertise the form's selection-like fields to every descendant
56
+ * ExpressionEditor, so it can render `selections["<id>"]` as the field's name
57
+ * and list those fields in the variable picker. Design-time only — the runtime
58
+ * counterpart is `provideSelectionsRegistry` (utils/selections-registry). A form
59
+ * host provides the whole roster; a nested form overrides with its own (a field
60
+ * references its own form's siblings, not an outer form's).
61
+ */
62
+ export declare function provideSelectionRoster(roster: Ref<ReadonlyArray<SelectionFieldRef>>): void;
63
+ /**
64
+ * The selection-like fields of the enclosing form, or empty when the editor
65
+ * sits outside any form (a table column expression, a standalone editor).
66
+ */
67
+ export declare function useSelectionRoster(): Ref<ReadonlyArray<SelectionFieldRef>>;
46
68
  export declare function celBindings(context: CELContext): Record<string, unknown>;
@@ -1,6 +1,7 @@
1
1
  import { computed, inject, provide, shallowRef } from "vue";
2
2
  import { injectLocal, provideLocal } from "@vueuse/core";
3
3
  export const SCOPE_ADDRESS_VAR = "__scopes__";
4
+ export const SELECTIONS_VAR = "selections";
4
5
  const CEL_CONTEXT_KEY = Symbol("cel-context");
5
6
  export function provideCELContext(context) {
6
7
  const parent = injectLocal(CEL_CONTEXT_KEY, {});
@@ -46,6 +47,13 @@ export function provideScopeAncestor(ancestor) {
46
47
  export function useScopeAncestry() {
47
48
  return inject(SCOPE_ANCESTRY_KEY, void 0) ?? shallowRef([]);
48
49
  }
50
+ const SELECTION_ROSTER_KEY = Symbol("cel-selection-roster");
51
+ export function provideSelectionRoster(roster) {
52
+ provide(SELECTION_ROSTER_KEY, roster);
53
+ }
54
+ export function useSelectionRoster() {
55
+ return inject(SELECTION_ROSTER_KEY, void 0) ?? shallowRef([]);
56
+ }
49
57
  export function celBindings(context) {
50
58
  const out = {};
51
59
  for (const [name, entry] of Object.entries(context)) {
@@ -0,0 +1,77 @@
1
+ import type { ShallowRef } from 'vue';
2
+ /**
3
+ * Host-owned map of `field-uuid → the field's currently-resolved full option`.
4
+ *
5
+ * Selection-like fields (combobox, tree-select, …) persist only a *key* — the
6
+ * scalar `optionValue` / `nodeKey` extracts from the chosen option. The rest of
7
+ * the option object (a backend record's `code`, `label`, …) is in hand while the
8
+ * field resolves the selection but is otherwise dropped. A *sibling* expression
9
+ * — say a related select whose request needs the chosen option's `code` — has no
10
+ * way to reach it: siblings share only the form state (the `form` CEL var), and
11
+ * the persisted key deliberately doesn't carry the rest.
12
+ *
13
+ * This registry is that missing channel. The common host (the form root; a table
14
+ * row) owns one and exposes it as the `selections` CEL variable; each select-like
15
+ * field publishes its resolved option here under its own uuid. A sibling reads
16
+ * `selections["<field-uuid>"].code`. It is NOT form state, so it never rides
17
+ * along in the submit payload — that separation is the whole point.
18
+ *
19
+ * Keyed by field uuid, not by binding: a table cell's value lives in row data
20
+ * (no form binding) while a form field's lives in form state, but the uuid is the
21
+ * one identity both share — and the one the expression editor surfaces as a
22
+ * field-name chip so the designer never sees the raw uuid.
23
+ */
24
+ export type SelectionsRegistry = {
25
+ /**
26
+ * Live uuid → resolved-option map. Read by the host's `selections` thunk. A
27
+ * `shallowRef`, deliberately: the stored options are opaque snapshots a
28
+ * sibling expression reads but never the registry mutates, so deep-proxying
29
+ * them is wasted work — and worse, it would replace the references we store
30
+ * with reactive proxies, defeating the identity-based de-dup in `set`.
31
+ * Reactivity rides on the `.value` swap alone (every `set`/`clear` replaces
32
+ * the whole map), which is exactly what a `shallowRef` tracks.
33
+ */
34
+ entries: ShallowRef<Record<string, unknown>>;
35
+ /** Publish (or replace) the resolved option for a field. */
36
+ set: (uuid: string, option: unknown) => void;
37
+ /** Drop a field's entry — on clear, or when the field unmounts. */
38
+ clear: (uuid: string) => void;
39
+ };
40
+ /**
41
+ * Create a registry and provide it to descendants. Called once per host (the
42
+ * form root; later, a table row). The returned `entries` ref is what the host
43
+ * overlays as the `selections` CEL thunk.
44
+ */
45
+ export declare function provideSelectionsRegistry(): SelectionsRegistry;
46
+ /**
47
+ * Inject the nearest registry, or `undefined` when there's no providing host
48
+ * (an uncontrolled field, a unit test). Callers must tolerate the absent case —
49
+ * publishing is best-effort.
50
+ */
51
+ export declare function useSelectionsRegistry(): SelectionsRegistry | undefined;
52
+ /**
53
+ * Wire a selection field's publish lifecycle to the nearest registry. Call once
54
+ * in setup; it injects the host registry (tolerating absence), watches the
55
+ * resolved selection, and clears on unmount.
56
+ *
57
+ * The de-dup is the whole point. A field's resolved-option computed re-mints on
58
+ * every re-evaluation — and `cel.ts`'s `unwrapCelValue` deep-copies every CEL
59
+ * result, so a remote option's backend record is a brand-new object on each
60
+ * pass even when the underlying data is unchanged. Worse, `celBindings` reads
61
+ * the `selections` map on every `$cel` call, so any publish re-triggers every
62
+ * selectable's own option resolution. Publishing on each re-mint would replace
63
+ * the map, re-trigger resolution, re-mint, and re-publish without bound — the
64
+ * "Maximum recursive updates exceeded" loop. So we key on a STABLE selection
65
+ * identity (the persisted key, or the ordered keys for multi), never the option
66
+ * payload: the data is irrelevant to identity and is swept wholesale whenever
67
+ * the selection actually changes. An unchanged selection is a no-op, which
68
+ * keeps the `selections` reference stable and cuts the feedback at the source.
69
+ *
70
+ * `resolved` returns the value to publish, or `undefined` when nothing resolves
71
+ * (cleared). `identity` projects that value to its stable selection key;
72
+ * `raw` projects it to the payload stored for siblings to read.
73
+ */
74
+ export declare function publishSelection<T>(key: string, resolved: () => T | undefined, project: {
75
+ identity: (value: T) => string;
76
+ raw: (value: T) => unknown;
77
+ }): void;
@@ -0,0 +1,49 @@
1
+ import { inject, onUnmounted, provide, shallowRef, watch } from "vue";
2
+ const SELECTIONS_KEY = Symbol("shwfed-selections");
3
+ function sameSelection(a, b) {
4
+ if (Object.is(a, b)) return true;
5
+ if (Array.isArray(a) && Array.isArray(b)) {
6
+ if (a.length !== b.length) return false;
7
+ return a.every((item, i) => Object.is(item, b[i]));
8
+ }
9
+ return false;
10
+ }
11
+ export function provideSelectionsRegistry() {
12
+ const entries = shallowRef({});
13
+ const registry = {
14
+ entries,
15
+ set: (uuid, option) => {
16
+ if (uuid in entries.value && sameSelection(entries.value[uuid], option)) return;
17
+ entries.value = { ...entries.value, [uuid]: option };
18
+ },
19
+ clear: (uuid) => {
20
+ if (!(uuid in entries.value)) return;
21
+ entries.value = Object.fromEntries(
22
+ Object.entries(entries.value).filter(([key]) => key !== uuid)
23
+ );
24
+ }
25
+ };
26
+ provide(SELECTIONS_KEY, registry);
27
+ return registry;
28
+ }
29
+ export function useSelectionsRegistry() {
30
+ return inject(SELECTIONS_KEY, void 0);
31
+ }
32
+ export function publishSelection(key, resolved, project) {
33
+ const registry = useSelectionsRegistry();
34
+ const NONE = "\0:none";
35
+ let last = "\0:init";
36
+ watch(
37
+ resolved,
38
+ (value) => {
39
+ if (!registry) return;
40
+ const id = value === void 0 ? NONE : project.identity(value);
41
+ if (id === last) return;
42
+ last = id;
43
+ if (value === void 0) registry.clear(key);
44
+ else registry.set(key, project.raw(value));
45
+ },
46
+ { immediate: true }
47
+ );
48
+ onUnmounted(() => registry?.clear(key));
49
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shwfed/config",
3
- "version": "2.8.0",
3
+ "version": "2.9.0",
4
4
  "description": "Configurable UI for SHWFED",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -1 +0,0 @@
1
- import{d as v,Q as S,aD as h,a as V,z as k,I as s,H as l,b as t,U as r,V as u,W as d,X as p,J as m,Y as T,T as f,a2 as y,a3 as z,a4 as w}from"./index-Yv78vz4W.js";const D={class:"flex flex-col gap-3"},b=v({name:"ShwfedStateWriteActionConfig",__name:"config",props:{modelValue:{required:!0},modelModifiers:{}},emits:["update:modelValue"],setup(_){const o=S(_,"modelValue"),i=h(()=>{}),c=e=>z(i,e)??e,n=e=>w(i,e);function g(e){const a={...o.value};e.length===0?Reflect.deleteProperty(a,"onSuccess"):a.onSuccess=e,o.value=a}return(e,a)=>(V(),k("div",D,[s(t(f),{orientation:"vertical"},{default:l(()=>[s(t(r),{class:"text-xs text-zinc-500"},u({default:l(()=>[d(" "+p(c("expression")),1)]),_:2},[n("expression")?{name:"tooltip",fn:l(()=>[s(t(m),{source:n("expression"),block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),key:"0"}:void 0]),1024),s(t(T),{"model-value":o.value.expression,multiline:"",placeholder:"例:{ invoices: rows, totalAmount: rows.map(r, r.amount).sum() }","result-type":"map",class:"min-h-16","onUpdate:modelValue":a[0]||(a[0]=x=>o.value={...o.value,expression:x})},null,8,["model-value"])]),_:1}),s(t(f),{orientation:"vertical"},{default:l(()=>[s(t(r),{class:"text-xs text-zinc-500"},u({default:l(()=>[d(" "+p(c("onSuccess")),1)]),_:2},[n("onSuccess")?{name:"tooltip",fn:l(()=>[s(t(m),{source:n("onSuccess"),block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),key:"0"}:void 0]),1024),s(y,{triggers:o.value.onSuccess??[],"onUpdate:triggers":g},null,8,["triggers"])]),_:1})]))}});export{b as default};
@@ -1 +0,0 @@
1
- import{d as y,Q as U,a5 as w,z as v,I as e,H as n,b as s,S as _,K as F,a1 as H,a as E,U as c,V as u,W as d,X as p,J as m,Y as f,T as x,a2 as N,a3 as R,a4 as j}from"./index-Yv78vz4W.js";const k={class:"flex flex-col gap-3"},D={class:"flex items-start gap-2"},$={class:"grid grid-cols-2 gap-3"},B=y({name:"ShwfedHttpRequestActionConfig",__name:"config",props:{modelValue:{required:!0},modelModifiers:{}},emits:["update:modelValue"],setup(h){const o=U(h,"modelValue"),g=w(()=>{}),i=t=>R(g,t)??t,r=t=>j(g,t),S=["onSuccess","onWarning","onError","onInfo"];function T(t){const l={...o.value};t.length===0?delete l.messageExpression:l.messageExpression=t,o.value=l}function b(t){const l={...o.value};t.length===0?delete l.resultExpression:l.resultExpression=t,o.value=l}function V(t,l){const a={...o.value};l.length===0?Reflect.deleteProperty(a,t):a[t]=l,o.value=a}return(t,l)=>(E(),v("div",k,[e(s(x),{orientation:"vertical"},{default:n(()=>[e(s(c),{class:"text-xs text-zinc-500"},u({default:n(()=>[d(" "+p(i("expression")),1)]),_:2},[r("expression")?{name:"tooltip",fn:n(()=>[e(s(m),{source:r("expression"),block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),key:"0"}:void 0]),1024),e(s(f),{"model-value":o.value.expression,multiline:"",placeholder:"例:http.post('/api/foo').body({ id: row.id })","result-type":"HttpRequest",class:"min-h-16","onUpdate:modelValue":l[0]||(l[0]=a=>o.value={...o.value,expression:a})},null,8,["model-value"])]),_:1}),_("div",D,[e(s(x),{orientation:"vertical",class:"flex-1 basis-0 min-w-0"},{default:n(()=>[e(s(c),{class:"text-xs text-zinc-500"},u({default:n(()=>[d(" "+p(i("messageExpression")),1)]),_:2},[r("messageExpression")?{name:"tooltip",fn:n(()=>[e(s(m),{source:r("messageExpression"),block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),key:"0"}:void 0]),1024),e(s(f),{"model-value":o.value.messageExpression??"",placeholder:"例:string(json.message)","result-type":"string","extra-vars":{json:{type:"dyn",label:"HTTP 响应体(已解析 JSON)"}},"onUpdate:modelValue":T},null,8,["model-value"])]),_:1}),e(s(x),{orientation:"vertical",class:"flex-1 basis-0 min-w-0"},{default:n(()=>[e(s(c),{class:"text-xs text-zinc-500"},u({default:n(()=>[d(" "+p(i("resultExpression")),1)]),_:2},[r("resultExpression")?{name:"tooltip",fn:n(()=>[e(s(m),{source:r("resultExpression"),block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),key:"0"}:void 0]),1024),e(s(f),{"model-value":o.value.resultExpression??"",placeholder:"例:json.code == 0 ? 'success' : 'error'","result-type":"string","extra-vars":{json:{type:"dyn",label:"HTTP 响应体(已解析 JSON)"}},"onUpdate:modelValue":b},null,8,["model-value"])]),_:1})]),_("div",$,[(E(),v(F,null,H(S,a=>e(s(x),{key:a,orientation:"vertical",class:"min-w-0"},{default:n(()=>[e(s(c),{class:"text-xs text-zinc-500"},u({default:n(()=>[d(" "+p(i(a)),1)]),_:2},[r(a)?{name:"tooltip",fn:n(()=>[e(s(m),{source:r(a),block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),key:"0"}:void 0]),1024),e(N,{triggers:o.value[a]??[],"onUpdate:triggers":z=>V(a,z)},null,8,["triggers","onUpdate:triggers"])]),_:2},1024)),64))])]))}});export{B as default};
@@ -1 +0,0 @@
1
- import{d as U,Q as k,aB as y,z as w,S as x,I as t,H as n,b as s,K as D,a1 as C,a as z,U as i,W as u,J as c,Y as d,T as p,aC as g,V as f,X as _,a2 as F,a3 as H,a4 as B,e as S}from"./index-Yv78vz4W.js";const L={class:"flex flex-col gap-3"},N={class:"grid grid-cols-2 gap-3"},$={class:"flex items-start gap-2"},I={class:"grid grid-cols-2 gap-3"},A=U({name:"ShwfedHttpDownloadActionConfig",__name:"config",props:{modelValue:{required:!0},modelModifiers:{}},emits:["update:modelValue"],setup(q){const l=k(q,"modelValue"),E=y(()=>{}),m=a=>H(E,a)??a,r=a=>B(E,a),T=["onSuccess","onWarning","onError","onInfo"],h=S({get:()=>l.value.template?.request??"",set:a=>{l.value={...l.value,template:{...l.value.template,request:a}}}}),V=S({get:()=>l.value.template?.download??"",set:a=>{const e=l.value.template??{request:""};if(a.length===0){const{download:o,...v}=e;l.value={...l.value,template:v}}else l.value={...l.value,template:{...e,download:a}}}});function b(a){const e={...l.value};a.length===0?delete e.messageExpression:e.messageExpression=a,l.value=e}function j(a){const e={...l.value};a.length===0?delete e.resultExpression:e.resultExpression=a,l.value=e}function R(a,e){const o={...l.value};e.length===0?Reflect.deleteProperty(o,a):o[a]=e,l.value=o}return(a,e)=>(z(),w("div",L,[x("div",N,[t(s(p),{orientation:"vertical"},{default:n(()=>[t(s(i),{class:"text-xs text-zinc-500"},{tooltip:n(()=>[t(s(c),{source:r("template")??"返回 `HttpRequest` 的 CEL 表达式;未配置「下载请求」时直接下载其响应",block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),default:n(()=>[e[2]||(e[2]=u(" 请求 ",-1))]),_:1}),t(s(d),{"model-value":h.value,multiline:"",placeholder:"例:http.get('https://api.example.com/files/123')","result-type":"HttpRequest",class:"min-h-16","onUpdate:modelValue":e[0]||(e[0]=o=>h.value=o)},null,8,["model-value"])]),_:1}),t(s(p),{orientation:"vertical"},{default:n(()=>[t(s(i),{class:"text-xs text-zinc-500"},{tooltip:n(()=>[t(s(c),{source:"可选的第二步:用第一步响应 `json` 中的凭据构造真正的下载请求,例如 `json.data.key`",block:"",class:"prose prose-sm prose-zinc"})]),default:n(()=>[e[3]||(e[3]=u(" 下载请求 ",-1))]),_:1}),t(s(d),{"model-value":V.value,multiline:"",placeholder:"例:http.get('https://api.example.com/download').query('key', json.data.key)","result-type":"HttpRequest","extra-vars":{json:s(g)},class:"min-h-16","onUpdate:modelValue":e[1]||(e[1]=o=>V.value=o)},null,8,["model-value","extra-vars"])]),_:1})]),x("div",$,[t(s(p),{orientation:"vertical",class:"flex-1 basis-0 min-w-0"},{default:n(()=>[t(s(i),{class:"text-xs text-zinc-500"},f({default:n(()=>[u(" "+_(m("messageExpression")),1)]),_:2},[r("messageExpression")?{name:"tooltip",fn:n(()=>[t(s(c),{source:r("messageExpression"),block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),key:"0"}:void 0]),1024),t(s(d),{"model-value":l.value.messageExpression??"",placeholder:"例:string(json.message)","result-type":"string","extra-vars":{json:s(g)},"onUpdate:modelValue":b},null,8,["model-value","extra-vars"])]),_:1}),t(s(p),{orientation:"vertical",class:"flex-1 basis-0 min-w-0"},{default:n(()=>[t(s(i),{class:"text-xs text-zinc-500"},f({default:n(()=>[u(" "+_(m("resultExpression")),1)]),_:2},[r("resultExpression")?{name:"tooltip",fn:n(()=>[t(s(c),{source:r("resultExpression"),block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),key:"0"}:void 0]),1024),t(s(d),{"model-value":l.value.resultExpression??"",placeholder:"例:json.code == 0 ? 'success' : 'error'","result-type":"string","extra-vars":{json:s(g)},"onUpdate:modelValue":j},null,8,["model-value","extra-vars"])]),_:1})]),x("div",I,[(z(),w(D,null,C(T,o=>t(s(p),{key:o,orientation:"vertical",class:"min-w-0"},{default:n(()=>[t(s(i),{class:"text-xs text-zinc-500"},f({default:n(()=>[u(" "+_(m(o)),1)]),_:2},[r(o)?{name:"tooltip",fn:n(()=>[t(s(c),{source:r(o),block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),key:"0"}:void 0]),1024),t(F,{triggers:l.value[o]??[],"onUpdate:triggers":v=>R(o,v)},null,8,["triggers","onUpdate:triggers"])]),_:2},1024)),64))])]))}});export{A as default};
@@ -1 +0,0 @@
1
- import{d as g,Q as d,a3 as u,aA as f,z as m,I as s,H as i,b as r,a as p,U as _,W as v,X as x,a2 as h,T,e as V}from"./index-Yv78vz4W.js";const C={class:"flex flex-col gap-3"},k=g({name:"ShwfedEventDispatchActionConfig",__name:"config",props:{modelValue:{required:!0},modelModifiers:{}},emits:["update:modelValue"],setup(l){const t=d(l,"modelValue"),o=u(f(),"triggers")??"触发的操作",n=V(()=>t.value.triggers??[]);function c(a){const e={...t.value};a.length===0?Reflect.deleteProperty(e,"triggers"):e.triggers=a,t.value=e}return(a,e)=>(p(),m("div",C,[s(r(T),{orientation:"vertical"},{default:i(()=>[s(r(_),{class:"text-xs text-zinc-500"},{default:i(()=>[v(x(r(o)),1)]),_:1}),s(h,{triggers:n.value,"onUpdate:triggers":c},null,8,["triggers"])]),_:1})]))}});export{k as default};
@@ -1 +0,0 @@
1
- import{d as y,a as z,z as E,x as V,O as T,b as e,P as U,Q as $,R as j,c as F,H as l,S as v,I as s,T as d,U as u,V as p,W as m,X as f,J as g,Y as b,Z as h,$ as B,a0 as C,K as H,a1 as N,a2 as O,a3 as R,a4 as D}from"./index-Yv78vz4W.js";const P=y({__name:"FieldGroup",props:{class:{type:[Boolean,null,String,Object,Array]}},setup(_){const r=_;return(x,i)=>(z(),E("div",{"data-slot":"field-group",class:T(e(U)("group/field-group @container/field-group flex w-full flex-col gap-7 data-[slot=checkbox-group]:gap-3 *:data-[slot=field-group]:gap-4",r.class))},[V(x.$slots,"default")],2))}}),q={class:"grid grid-cols-2 gap-4"},I={class:"grid grid-cols-2 gap-4"},J={class:"flex items-start gap-2"},L={class:"grid grid-cols-2 gap-3"},M=y({name:"ShwfedHttpRequestConfirmActionConfig",__name:"config",props:{modelValue:{required:!0},modelModifiers:{}},emits:["update:modelValue"],setup(_){const r=$(_,"modelValue"),x=j(()=>{}),i=n=>R(x,n)??n,a=n=>D(x,n);function c(n){const t={...r.value,...n};for(const[o,k]of Object.entries(n))k===void 0&&Reflect.deleteProperty(t,o);r.value=t}const S=["onSuccess","onWarning","onError","onInfo"];function w(n,t){c({[n]:t.length===0?void 0:t})}return(n,t)=>(z(),F(e(P),null,{default:l(()=>[v("div",q,[s(e(d),{orientation:"vertical"},{default:l(()=>[s(e(u),{class:"text-xs text-zinc-500"},p({default:l(()=>[m(" "+f(i("expression")),1)]),_:2},[a("expression")?{name:"tooltip",fn:l(()=>[s(e(g),{source:a("expression"),block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),key:"0"}:void 0]),1024),s(e(b),{"model-value":r.value.expression,multiline:"",placeholder:"例:http.post('/api/foo').body({ id: row.id })","result-type":"HttpRequest",class:"min-h-16","onUpdate:modelValue":t[0]||(t[0]=o=>c({expression:o}))},null,8,["model-value"])]),_:1}),s(e(d),{orientation:"vertical"},{default:l(()=>[s(e(u),{class:"text-xs text-zinc-500"},p({default:l(()=>[m(" "+f(i("markdown")),1)]),_:2},[a("markdown")?{name:"tooltip",fn:l(()=>[s(e(g),{source:a("markdown"),block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),key:"0"}:void 0]),1024),s(e(h),{markdown:"","model-value":r.value.markdown,"onUpdate:modelValue":t[1]||(t[1]=o=>c({markdown:o}))},null,8,["model-value"])]),_:1})]),v("div",I,[s(e(d),{orientation:"vertical"},{default:l(()=>[s(e(u),{class:"text-xs text-zinc-500"},p({default:l(()=>[m(" "+f(i("icon")),1)]),_:2},[a("icon")?{name:"tooltip",fn:l(()=>[s(e(g),{source:a("icon"),block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),key:"0"}:void 0]),1024),s(e(B),{"model-value":r.value.icon??"","onUpdate:modelValue":t[2]||(t[2]=o=>c(o.trim()===""?{icon:void 0}:{icon:o}))},null,8,["model-value"])]),_:1}),s(e(d),{orientation:"vertical"},{default:l(()=>[s(e(u),{class:"text-xs text-zinc-500"},p({default:l(()=>[m(" "+f(i("color")),1)]),_:2},[a("color")?{name:"tooltip",fn:l(()=>[s(e(g),{source:a("color"),block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),key:"0"}:void 0]),1024),s(e(C),{"model-value":r.value.color??"","onUpdate:modelValue":t[3]||(t[3]=o=>c(o.trim()===""?{color:void 0}:{color:o}))},null,8,["model-value"])]),_:1})]),v("div",J,[s(e(d),{orientation:"vertical",class:"flex-1 basis-0 min-w-0"},{default:l(()=>[s(e(u),{class:"text-xs text-zinc-500"},p({default:l(()=>[m(" "+f(i("messageExpression")),1)]),_:2},[a("messageExpression")?{name:"tooltip",fn:l(()=>[s(e(g),{source:a("messageExpression"),block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),key:"0"}:void 0]),1024),s(e(b),{"model-value":r.value.messageExpression??"",placeholder:"例:string(json.message)","result-type":"string","extra-vars":{json:{type:"dyn",label:"HTTP 响应体(已解析 JSON)"}},"onUpdate:modelValue":t[4]||(t[4]=o=>c({messageExpression:o===""?void 0:o}))},null,8,["model-value"])]),_:1}),s(e(d),{orientation:"vertical",class:"flex-1 basis-0 min-w-0"},{default:l(()=>[s(e(u),{class:"text-xs text-zinc-500"},p({default:l(()=>[m(" "+f(i("resultExpression")),1)]),_:2},[a("resultExpression")?{name:"tooltip",fn:l(()=>[s(e(g),{source:a("resultExpression"),block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),key:"0"}:void 0]),1024),s(e(b),{"model-value":r.value.resultExpression??"",placeholder:"例:json.code == 0 ? 'success' : 'error'","result-type":"string","extra-vars":{json:{type:"dyn",label:"HTTP 响应体(已解析 JSON)"}},"onUpdate:modelValue":t[5]||(t[5]=o=>c({resultExpression:o===""?void 0:o}))},null,8,["model-value"])]),_:1})]),v("div",L,[(z(),E(H,null,N(S,o=>s(e(d),{key:o,orientation:"vertical",class:"min-w-0"},{default:l(()=>[s(e(u),{class:"text-xs text-zinc-500"},p({default:l(()=>[m(" "+f(i(o)),1)]),_:2},[a(o)?{name:"tooltip",fn:l(()=>[s(e(g),{source:a(o),block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),key:"0"}:void 0]),1024),s(O,{triggers:r.value[o]??[],"onUpdate:triggers":k=>w(o,k)},null,8,["triggers","onUpdate:triggers"])]),_:2},1024)),64))])]),_:1}))}});export{M as default};