@shwfed/config 2.11.0 → 2.11.4

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 +1458 -1216
  2. package/dist/module.json +1 -1
  3. package/dist/preview/assets/{FieldGroup.vue_vue_type_script_setup_true_lang-UfhMyymD.js → FieldGroup.vue_vue_type_script_setup_true_lang-BE68tZWF.js} +1 -1
  4. package/dist/preview/assets/{badge-CJ9IQ3Jx.js → badge-CGMjdhLX.js} +1 -1
  5. package/dist/preview/assets/config-B7TZ-128.js +1 -0
  6. package/dist/preview/assets/{config-uUF-UHPt.js → config-BSym_jQg.js} +1 -1
  7. package/dist/preview/assets/{config-DIsAIc7H.js → config-ByCFJbd-.js} +1 -1
  8. package/dist/preview/assets/{config--Vx4fL61.js → config-C4cv2S64.js} +1 -1
  9. package/dist/preview/assets/{config-BYktCefJ.js → config-ChrJHusi.js} +1 -1
  10. package/dist/preview/assets/config-CxbYENZ0.js +1 -0
  11. package/dist/preview/assets/{config-5PPug5mk.js → config-DFS2XL3-.js} +1 -1
  12. package/dist/preview/assets/{config-DpLMetys.js → config-DWj1CTai.js} +1 -1
  13. package/dist/preview/assets/{config-CQrDCzYN.js → config-DZI21_UB.js} +1 -1
  14. package/dist/preview/assets/{config-C_g-FYCR.js → config-D_O4ACtH.js} +1 -1
  15. package/dist/preview/assets/{config-BldsYfGM.js → config-DjA8bfLm.js} +1 -1
  16. package/dist/preview/assets/{config-7V1qHjUk.js → config-DwPGLI3R.js} +1 -1
  17. package/dist/preview/assets/{config-N-FdgfwK.js → config-dkVvsr4h.js} +1 -1
  18. package/dist/preview/assets/{config-BeRYF_cz.js → config-hsH0bSZh.js} +1 -1
  19. package/dist/preview/assets/{config-IMd4FZi8.js → config-xrfje67L.js} +1 -1
  20. package/dist/preview/assets/{definition.vue_vue_type_script_setup_true_lang-B_PKfe3G.js → definition.vue_vue_type_script_setup_true_lang-BGk00yfB.js} +1 -1
  21. package/dist/preview/assets/index-B4oT9ZrQ.js +1 -0
  22. package/dist/preview/assets/{index-BCl1NN6k.js → index-BSQlKkJR.js} +214 -202
  23. package/dist/preview/assets/{index-DKWp47QP.js → index-CzQKNngS.js} +1 -1
  24. package/dist/preview/assets/index-DPFQgj9g.css +1 -0
  25. package/dist/preview/assets/{item-XsW7swFt.js → item-D4gmvDO-.js} +1 -1
  26. package/dist/preview/assets/{runtime-JxBzvGnw.js → runtime--e0UxK6b.js} +1 -1
  27. package/dist/preview/assets/runtime-BWH8ForT.js +1 -0
  28. package/dist/preview/assets/runtime-BgO2briD.js +1 -0
  29. package/dist/preview/assets/{runtime-BiFFwOIl.js → runtime-BmEP7xID.js} +1 -1
  30. package/dist/preview/assets/runtime-C66GF-2d.js +1 -0
  31. package/dist/preview/assets/{runtime-BeHohaOZ.js → runtime-CJCOS6D_.js} +1 -1
  32. package/dist/preview/assets/{runtime-ByArW-jJ.js → runtime-CREolKJd.js} +1 -1
  33. package/dist/preview/assets/runtime-CjU46djh.js +1 -0
  34. package/dist/preview/assets/{runtime-Dn172S7t.js → runtime-e59FkBkL.js} +1 -1
  35. package/dist/preview/assets/runtime-pYLX1Bb-.js +1 -0
  36. package/dist/preview/assets/{runtime-bq0hmEXY.js → runtime-wvP7jhBK.js} +1 -1
  37. package/dist/preview/assets/{schema-meta-CZ9yXnsa.js → schema-meta-C4Ttq3eE.js} +1 -1
  38. package/dist/preview/index.html +2 -2
  39. package/dist/runtime/components/actions/buttons/2026-06-25/com.shwfed.actions.button.state.write/config.d.vue.ts +39 -0
  40. package/dist/runtime/components/actions/buttons/2026-06-25/com.shwfed.actions.button.state.write/config.vue +127 -0
  41. package/dist/runtime/components/actions/buttons/2026-06-25/com.shwfed.actions.button.state.write/config.vue.d.ts +39 -0
  42. package/dist/runtime/components/actions/buttons/2026-06-25/com.shwfed.actions.button.state.write/runtime.d.vue.ts +8 -0
  43. package/dist/runtime/components/actions/buttons/2026-06-25/com.shwfed.actions.button.state.write/runtime.vue +62 -0
  44. package/dist/runtime/components/actions/buttons/2026-06-25/com.shwfed.actions.button.state.write/runtime.vue.d.ts +8 -0
  45. package/dist/runtime/components/actions/buttons/2026-06-25/com.shwfed.actions.button.state.write/schema.d.ts +25 -0
  46. package/dist/runtime/components/actions/buttons/2026-06-25/com.shwfed.actions.button.state.write/schema.js +41 -0
  47. package/dist/runtime/components/config/blocks/2026-06-17/com.shwfed.block.tree.single/runtime.vue +5 -22
  48. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/config.d.vue.ts +70 -0
  49. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/config.vue +349 -0
  50. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/config.vue.d.ts +70 -0
  51. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/loop-item.d.vue.ts +33 -0
  52. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/loop-item.vue +37 -0
  53. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/loop-item.vue.d.ts +33 -0
  54. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/loop-scope-provider.d.vue.ts +13 -0
  55. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/loop-scope-provider.vue +22 -0
  56. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/loop-scope-provider.vue.d.ts +13 -0
  57. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/runtime.d.vue.ts +70 -0
  58. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/runtime.vue +62 -0
  59. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/runtime.vue.d.ts +70 -0
  60. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/schema.d.ts +85 -0
  61. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/schema.js +60 -0
  62. package/dist/runtime/components/form/fields/2026-04-22/com.shwfed.form.field.text/schema.js +10 -1
  63. package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.number/schema.js +10 -1
  64. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/runtime.vue +2 -19
  65. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/runtime.vue +5 -22
  66. package/dist/runtime/components/operations/2026-06-15/com.shwfed.operation.http.download/config.d.vue.ts +2 -0
  67. package/dist/runtime/components/operations/2026-06-15/com.shwfed.operation.http.download/config.vue +49 -22
  68. package/dist/runtime/components/operations/2026-06-15/com.shwfed.operation.http.download/config.vue.d.ts +2 -0
  69. package/dist/runtime/components/operations/2026-06-15/com.shwfed.operation.http.download/runtime.js +17 -10
  70. package/dist/runtime/components/operations/2026-06-15/com.shwfed.operation.http.download/schema.d.ts +1 -0
  71. package/dist/runtime/components/operations/2026-06-15/com.shwfed.operation.http.download/schema.js +25 -3
  72. package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.number-input/schema.js +10 -1
  73. package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.text-input/schema.js +10 -1
  74. package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-remote/config.d.vue.ts +2 -2
  75. package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-remote/config.vue.d.ts +2 -2
  76. package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-static/config.d.vue.ts +2 -2
  77. package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-static/config.vue.d.ts +2 -2
  78. package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-remote/config.d.vue.ts +2 -2
  79. package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-remote/config.vue.d.ts +2 -2
  80. package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-static/config.d.vue.ts +2 -2
  81. package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-static/config.vue.d.ts +2 -2
  82. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-multi.remote/config.d.vue.ts +2 -2
  83. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-multi.remote/config.vue.d.ts +2 -2
  84. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-single.remote/config.d.vue.ts +2 -2
  85. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-single.remote/config.vue.d.ts +2 -2
  86. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/config.d.vue.ts +2 -2
  87. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/config.vue.d.ts +2 -2
  88. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/config.d.vue.ts +2 -2
  89. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/config.vue.d.ts +2 -2
  90. package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.combobox-multi/config.d.vue.ts +2 -2
  91. package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.combobox-multi/config.vue.d.ts +2 -2
  92. package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.combobox-single/config.d.vue.ts +2 -2
  93. package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.combobox-single/config.vue.d.ts +2 -2
  94. package/dist/runtime/components/table/columns/2026-06-22/com.shwfed.table.column.date-range-input/schema.js +2 -1
  95. package/dist/runtime/components/ui/date-picker/DatePickerInput.vue +9 -2
  96. package/dist/runtime/components/ui/date-range-picker/DateRangePickerInput.vue +13 -4
  97. package/dist/runtime/components/ui/expression-editor/ExpressionEditor.vue +1 -1
  98. package/dist/runtime/share/loop-item-var.d.ts +21 -0
  99. package/dist/runtime/share/loop-item-var.js +13 -0
  100. package/dist/runtime/vendor/cel-js/CLAUDE.md +1 -1
  101. package/dist/runtime/vendor/cel-js/lib/http-builder.d.ts +38 -3
  102. package/dist/runtime/vendor/cel-js/lib/http-builder.js +33 -0
  103. package/package.json +1 -1
  104. package/dist/preview/assets/config-DPX7vGqV.js +0 -1
  105. package/dist/preview/assets/index-8Ph-sFDI.css +0 -1
  106. package/dist/preview/assets/index-Core7vRW.js +0 -1
  107. package/dist/preview/assets/runtime-B-ABO0r0.js +0 -1
  108. package/dist/preview/assets/runtime-CpVTGNFZ.js +0 -1
  109. package/dist/preview/assets/runtime-DQ1TnQ7n.js +0 -1
  110. package/dist/preview/assets/runtime-DY7hr7v1.js +0 -1
@@ -0,0 +1,62 @@
1
+ <script setup>
2
+ import { computed } from "vue";
3
+ import { Effect } from "effect";
4
+ import { cel } from "../../../../../utils/cel";
5
+ import { celBindings, injectCELContext } from "../../../../../utils/cel-context";
6
+ import LoopItem from "./loop-item.vue";
7
+ defineOptions({ name: "ShwfedBlockLoopRuntime" });
8
+ const block = defineModel("block", { type: null, ...{ required: true } });
9
+ const props = defineProps({
10
+ configure: { type: Function, required: false }
11
+ });
12
+ const configure = computed(() => props.configure ?? (() => {
13
+ }));
14
+ const inheritedContext = injectCELContext();
15
+ function baseContext() {
16
+ return celBindings(inheritedContext);
17
+ }
18
+ const items = computed(() => {
19
+ const expr = block.value.items;
20
+ if (!expr || expr.trim().length === 0) return [];
21
+ try {
22
+ const result = Effect.runSync(cel(expr, baseContext()));
23
+ return Array.isArray(result) ? result : [];
24
+ } catch (err) {
25
+ console.warn("[shwfed-loop] items evaluation failed", err);
26
+ return [];
27
+ }
28
+ });
29
+ function evalStyle(expression) {
30
+ if (!expression) return void 0;
31
+ try {
32
+ const r = Effect.runSync(cel(expression, baseContext()));
33
+ if (r === null || r === void 0) return void 0;
34
+ if (typeof r === "string") return r;
35
+ if (typeof r === "object") return r;
36
+ return String(r);
37
+ } catch {
38
+ return void 0;
39
+ }
40
+ }
41
+ const styleValue = computed(() => evalStyle(block.value.style));
42
+ function updateSlot(next) {
43
+ block.value = { ...block.value, slot: next };
44
+ }
45
+ </script>
46
+
47
+ <template>
48
+ <div
49
+ class="flex flex-col gap-2"
50
+ :style="styleValue"
51
+ >
52
+ <LoopItem
53
+ v-for="(item, index) in items"
54
+ :key="index"
55
+ :item="item"
56
+ :index="index"
57
+ :slot-value="block.slot"
58
+ :configure="configure"
59
+ @update:slot-value="updateSlot"
60
+ />
61
+ </div>
62
+ </template>
@@ -0,0 +1,70 @@
1
+ import type { Environment } from '../../../../../vendor/cel-js/lib/index.js';
2
+ import type { Value } from './schema.js';
3
+ type __VLS_Props = {
4
+ configure?: (env: Environment) => void;
5
+ };
6
+ type __VLS_ModelProps = {
7
+ 'block': Value;
8
+ };
9
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
10
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
11
+ "update:block": (value: {
12
+ readonly type: "com.shwfed.block.loop";
13
+ readonly style?: string | undefined;
14
+ readonly id: string;
15
+ readonly slot: {
16
+ readonly blocks: readonly any[];
17
+ readonly layouts: readonly {
18
+ readonly name: string;
19
+ readonly layout: {
20
+ readonly style?: string | undefined;
21
+ readonly columns: number;
22
+ readonly gap?: number | undefined;
23
+ readonly rows?: number | undefined;
24
+ readonly placements: {
25
+ readonly [x: string]: {
26
+ readonly area: readonly [readonly [number, number], readonly [number, number]];
27
+ readonly v?: "stretch" | "center" | "end" | "start" | undefined;
28
+ readonly h?: "stretch" | "center" | "end" | "start" | undefined;
29
+ };
30
+ };
31
+ };
32
+ readonly media?: string | undefined;
33
+ }[];
34
+ };
35
+ readonly displayName?: string | undefined;
36
+ readonly compatibilityDate: "2026-06-25";
37
+ readonly items: string;
38
+ }) => any;
39
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
40
+ "onUpdate:block"?: ((value: {
41
+ readonly type: "com.shwfed.block.loop";
42
+ readonly style?: string | undefined;
43
+ readonly id: string;
44
+ readonly slot: {
45
+ readonly blocks: readonly any[];
46
+ readonly layouts: readonly {
47
+ readonly name: string;
48
+ readonly layout: {
49
+ readonly style?: string | undefined;
50
+ readonly columns: number;
51
+ readonly gap?: number | undefined;
52
+ readonly rows?: number | undefined;
53
+ readonly placements: {
54
+ readonly [x: string]: {
55
+ readonly area: readonly [readonly [number, number], readonly [number, number]];
56
+ readonly v?: "stretch" | "center" | "end" | "start" | undefined;
57
+ readonly h?: "stretch" | "center" | "end" | "start" | undefined;
58
+ };
59
+ };
60
+ };
61
+ readonly media?: string | undefined;
62
+ }[];
63
+ };
64
+ readonly displayName?: string | undefined;
65
+ readonly compatibilityDate: "2026-06-25";
66
+ readonly items: string;
67
+ }) => any) | undefined;
68
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
69
+ declare const _default: typeof __VLS_export;
70
+ export default _default;
@@ -0,0 +1,85 @@
1
+ import { Schema } from 'effect';
2
+ import type { Environment } from '../../../../../vendor/cel-js/lib/index.js';
3
+ export { getStructFieldDescription, getStructFieldTitle } from '../../../../table/utils/schema-meta.js';
4
+ type AnySchema = Schema.Schema<any, any, never>;
5
+ type Configure = (env: Environment) => void;
6
+ export declare const type: "com.shwfed.block.loop";
7
+ export declare const compatibilityDate: "2026-06-25";
8
+ export declare const metadata: {
9
+ readonly name: "循环";
10
+ readonly icon: "fluent:arrow-repeat-all-20-regular";
11
+ readonly w: {
12
+ readonly initial: 12;
13
+ readonly min: 4;
14
+ readonly max: number;
15
+ };
16
+ readonly h: {
17
+ readonly initial: 6;
18
+ readonly min: 4;
19
+ readonly max: number;
20
+ readonly grow: true;
21
+ };
22
+ };
23
+ export declare function schema(configure: Configure, blockRef: AnySchema): Schema.Struct<{
24
+ id: Schema.refine<string, typeof Schema.String>;
25
+ type: Schema.tag<"com.shwfed.block.loop">;
26
+ compatibilityDate: Schema.tag<"2026-06-25">;
27
+ displayName: Schema.optional<Schema.SchemaClass<string, string, never>>;
28
+ items: Schema.Schema<string, string, never>;
29
+ style: Schema.optional<Schema.Schema<string, string, never>>;
30
+ slot: Schema.refine<{
31
+ readonly blocks: readonly any[];
32
+ readonly layouts: readonly {
33
+ readonly name: string;
34
+ readonly layout: {
35
+ readonly style?: string | undefined;
36
+ readonly columns: number;
37
+ readonly gap?: number | undefined;
38
+ readonly rows?: number | undefined;
39
+ readonly placements: {
40
+ readonly [x: string]: {
41
+ readonly area: readonly [readonly [number, number], readonly [number, number]];
42
+ readonly v?: "stretch" | "center" | "end" | "start" | undefined;
43
+ readonly h?: "stretch" | "center" | "end" | "start" | undefined;
44
+ };
45
+ };
46
+ };
47
+ readonly media?: string | undefined;
48
+ }[];
49
+ }, Schema.Struct<{
50
+ blocks: Schema.Array$<Schema.Schema<any, any, never>>;
51
+ layouts: Schema.refine<readonly {
52
+ readonly name: string;
53
+ readonly layout: {
54
+ readonly style?: string | undefined;
55
+ readonly columns: number;
56
+ readonly gap?: number | undefined;
57
+ readonly rows?: number | undefined;
58
+ readonly placements: {
59
+ readonly [x: string]: {
60
+ readonly area: readonly [readonly [number, number], readonly [number, number]];
61
+ readonly v?: "stretch" | "center" | "end" | "start" | undefined;
62
+ readonly h?: "stretch" | "center" | "end" | "start" | undefined;
63
+ };
64
+ };
65
+ };
66
+ readonly media?: string | undefined;
67
+ }[], Schema.Array$<Schema.Struct<{
68
+ name: Schema.SchemaClass<string, string, never>;
69
+ media: Schema.optional<Schema.Schema<string, string, never>>;
70
+ layout: Schema.Struct<{
71
+ columns: Schema.refine<number, Schema.filter<typeof Schema.Number>>;
72
+ rows: Schema.optional<Schema.refine<number, Schema.filter<typeof Schema.Number>>>;
73
+ gap: Schema.optional<Schema.refine<number, Schema.filter<typeof Schema.Number>>>;
74
+ style: Schema.optional<Schema.SchemaClass<string, string, never>>;
75
+ placements: Schema.Record$<typeof Schema.String, Schema.Struct<{
76
+ area: Schema.refine<readonly [readonly [number, number], readonly [number, number]], Schema.Tuple2<Schema.Tuple2<Schema.filter<Schema.filter<typeof Schema.Number>>, Schema.filter<Schema.filter<typeof Schema.Number>>>, Schema.Tuple2<Schema.filter<Schema.filter<typeof Schema.Number>>, Schema.filter<Schema.filter<typeof Schema.Number>>>>>;
77
+ h: Schema.optional<Schema.Literal<["start", "center", "end", "stretch"]>>;
78
+ v: Schema.optional<Schema.Literal<["start", "center", "end", "stretch"]>>;
79
+ }>>;
80
+ }>;
81
+ }>>>;
82
+ }>>;
83
+ }>;
84
+ export declare function defaultBody(): Record<string, unknown>;
85
+ export type Value = Schema.Schema.Type<ReturnType<typeof schema>>;
@@ -0,0 +1,60 @@
1
+ import { Schema } from "effect";
2
+ import { Expression } from "../../../../../share/expression.js";
3
+ import { Slot, defaultSlot } from "../../../../../share/layout.js";
4
+ import { registerLoopVariablesIfAbsent } from "../../../../../share/loop-item-var.js";
5
+ export { getStructFieldDescription, getStructFieldTitle } from "../../../../table/utils/schema-meta.js";
6
+ export const type = "com.shwfed.block.loop";
7
+ export const compatibilityDate = "2026-06-25";
8
+ export const metadata = {
9
+ name: "\u5FAA\u73AF",
10
+ icon: "fluent:arrow-repeat-all-20-regular",
11
+ w: { initial: 12, min: 4, max: Infinity },
12
+ // `grow: true`: the loop's height is content-driven (N rendered items), so its
13
+ // row escapes the grid's `1fr` equal-share (bare `auto`) and the loop grows
14
+ // top-anchored — more items reveal below instead of repositioning the whole
15
+ // block inside an oversized track. See `config/utils/resolve.ts`
16
+ // `BlockSizeRange.grow` and the `tree.single` precedent.
17
+ h: { initial: 6, min: 4, max: Infinity, grow: true }
18
+ };
19
+ export function schema(configure, blockRef) {
20
+ const itemConfigure = (env) => {
21
+ configure(env);
22
+ registerLoopVariablesIfAbsent(env);
23
+ };
24
+ const LoopSlot = Slot(blockRef, itemConfigure);
25
+ const CelItems = Expression({
26
+ configure,
27
+ resultType: (t) => t === "dyn" || t.startsWith("list") || t.startsWith("optional")
28
+ });
29
+ const CelStyle = Expression({
30
+ configure,
31
+ resultType: (t) => t === "string" || t === "dyn" || t.startsWith("map") || t.startsWith("optional")
32
+ });
33
+ return Schema.Struct({
34
+ id: Schema.UUID.annotations({ description: "\u5757\u552F\u4E00\u6807\u8BC6" }),
35
+ type: Schema.tag(type),
36
+ compatibilityDate: Schema.tag(compatibilityDate),
37
+ displayName: Schema.optional(Schema.String.annotations({
38
+ title: "\u5185\u90E8\u540D\u79F0",
39
+ description: "\u4EC5\u5728\u7F16\u8F91\u5668\u5185\u53EF\u89C1\u7684\u5757\u540D\uFF0C\u7528\u4E8E\u5728\u4FA7\u8FB9\u680F\u548C\u5E03\u5C40\u7F16\u8F91\u5668\u4E2D\u8BC6\u522B\u5757\uFF1B\u8FD0\u884C\u65F6\u4E0D\u5C55\u793A"
40
+ })),
41
+ items: CelItems.annotations({
42
+ title: "\u5217\u8868",
43
+ description: "\u8FD4\u56DE\u5217\u8868\u7684 CEL \u8868\u8FBE\u5F0F\uFF1B\u5217\u8868\u4E2D\u6BCF\u4E00\u9879\u90FD\u4F1A\u6309\u4E0B\u65B9\u5E03\u5C40\u6E32\u67D3\u4E00\u6B21\uFF0C\u6E32\u67D3\u5185\u5BB9\u53EF\u8BBF\u95EE `item`\uFF08\u5F53\u524D\u9879\uFF09\u4E0E `index`\uFF08\u5E8F\u53F7\uFF0C\u4ECE 0 \u5F00\u59CB\uFF09\u3002\u8FD4\u56DE `none` / \u975E\u5217\u8868\u65F6\u4E0D\u6E32\u67D3\u4EFB\u4F55\u9879"
44
+ }),
45
+ style: Schema.optional(CelStyle).annotations({
46
+ title: "\u6837\u5F0F",
47
+ description: "\u8FD4\u56DE\u5E94\u7528\u5728\u5FAA\u73AF\u5916\u5C42\u5BB9\u5668\u4E0A\u7684\u6837\u5F0F\u7684 CEL \u8868\u8FBE\u5F0F\uFF0C\u53EF\u8FD4\u56DE CSS \u5B57\u7B26\u4E32\uFF08\u5982 `'gap: 1.5rem'`\uFF09\u6216\u6837\u5F0F\u5BF9\u8C61\uFF08\u5982 `{'gap': '1.5rem'}`\uFF09\uFF1B\u5E38\u7528\u4E8E\u8C03\u6574\u5404\u9879\u4E4B\u95F4\u7684\u95F4\u8DDD\u3002\u7559\u7A7A\u5219\u4F7F\u7528\u9ED8\u8BA4\u95F4\u8DDD"
48
+ }),
49
+ slot: LoopSlot.annotations({
50
+ title: "\u5185\u5BB9",
51
+ description: "\u6BCF\u4E2A\u5217\u8868\u9879\u6E32\u67D3\u7684\u5757\u4E0E\u5E03\u5C40\uFF1B\u5176\u4E2D\u7684\u8868\u8FBE\u5F0F\u53EF\u8BBF\u95EE `item` \u4E0E `index`"
52
+ })
53
+ }).annotations({
54
+ title: "\u5FAA\u73AF\u5757",
55
+ description: "\u5BF9\u4E00\u4E2A CEL \u5217\u8868\u9010\u9879\u6E32\u67D3\u540C\u4E00\u5957\u5185\u90E8\u5E03\u5C40\uFF0C\u6BCF\u9879\u53EF\u8BBF\u95EE `item` / `index`\uFF1B\u652F\u6301\u4EFB\u610F\u5C42\u7EA7\u5D4C\u5957"
56
+ });
57
+ }
58
+ export function defaultBody() {
59
+ return { items: "[]", slot: defaultSlot() };
60
+ }
@@ -54,7 +54,16 @@ export function schema(configure) {
54
54
  description: "\u8FD4\u56DE `true` \u65F6\u4EC5\u4EE5\u7EAF\u6587\u672C\u5C55\u793A\u5F53\u524D\u503C"
55
55
  })),
56
56
  derived: derivedField(configure, "string"),
57
- addon: Schema.optional(AddonActions(configure))
57
+ // `Schema.optional` rebuilds the struct's union member, and because the
58
+ // `optionalWith`-default fields make `AddonActions` a `Transformation`, the
59
+ // inner struct's `title`/`description` don't survive onto the rebuilt
60
+ // member. The config editor's `getStructFieldTitle('addon')` would then fall
61
+ // back to the raw key "addon". Re-state them on the property signature,
62
+ // which the meta reader checks before the field type.
63
+ addon: Schema.optional(AddonActions(configure)).annotations({
64
+ title: "\u8F93\u5165\u6846\u5185\u6309\u94AE",
65
+ description: "\u5728\u8F93\u5165\u6846\u53F3\u4FA7\u5185\u5D4C\u4E00\u7EC4\u64CD\u4F5C\u6309\u94AE"
66
+ })
58
67
  }).annotations({
59
68
  title: "TextField",
60
69
  description: "\u5355\u884C\u6587\u672C\u8F93\u5165"
@@ -79,7 +79,16 @@ export function schema(configure) {
79
79
  title: "\u6700\u5927\u503C",
80
80
  description: "\u5141\u8BB8\u8F93\u5165\u7684\u6700\u5927\u503C\u8868\u8FBE\u5F0F\uFF1B\u7559\u7A7A\u65F6\u4E0D\u9650\u5236\u4E0A\u9650"
81
81
  })),
82
- addon: Schema.optional(AddonActions(configure))
82
+ // `Schema.optional` rebuilds the struct's union member, and because the
83
+ // `optionalWith`-default fields make `AddonActions` a `Transformation`, the
84
+ // inner struct's `title`/`description` don't survive onto the rebuilt
85
+ // member. The config editor's `getStructFieldTitle('addon')` would then fall
86
+ // back to the raw key "addon". Re-state them on the property signature,
87
+ // which the meta reader checks before the field type.
88
+ addon: Schema.optional(AddonActions(configure)).annotations({
89
+ title: "\u8F93\u5165\u6846\u5185\u6309\u94AE",
90
+ description: "\u5728\u8F93\u5165\u6846\u53F3\u4FA7\u5185\u5D4C\u4E00\u7EC4\u64CD\u4F5C\u6309\u94AE"
91
+ })
83
92
  }).annotations({
84
93
  title: "NumberField",
85
94
  description: "\u6570\u503C\u8F93\u5165"
@@ -30,22 +30,16 @@ const { locale, t } = useI18n({
30
30
  zh: {
31
31
  "tree-multi-search-label": "\u641C\u7D22",
32
32
  "tree-multi-search-clear": "\u6E05\u9664\u641C\u7D22",
33
- "tree-multi-load-error": "\u52A0\u8F7D\u5931\u8D25",
34
- "tree-multi-empty": "\u65E0\u53EF\u9009\u9879",
35
33
  "tree-multi-readonly-separator": "\u3001"
36
34
  },
37
35
  en: {
38
36
  "tree-multi-search-label": "Search",
39
37
  "tree-multi-search-clear": "Clear search",
40
- "tree-multi-load-error": "Failed to load",
41
- "tree-multi-empty": "No options",
42
38
  "tree-multi-readonly-separator": ", "
43
39
  },
44
40
  ja: {
45
41
  "tree-multi-search-label": "\u691C\u7D22",
46
42
  "tree-multi-search-clear": "\u691C\u7D22\u3092\u30AF\u30EA\u30A2",
47
- "tree-multi-load-error": "\u8AAD\u307F\u8FBC\u307F\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
48
- "tree-multi-empty": "\u9078\u629E\u80A2\u306A\u3057",
49
43
  "tree-multi-readonly-separator": "\u3001"
50
44
  }
51
45
  }
@@ -98,7 +92,6 @@ const model = computed({
98
92
  });
99
93
  const roots = ref([]);
100
94
  const loading = ref(false);
101
- const fetchError = ref(null);
102
95
  async function fetchTree() {
103
96
  const dataSource = props.config.dataSource;
104
97
  if (!dataSource) {
@@ -133,10 +126,8 @@ async function fetchTree() {
133
126
  try {
134
127
  const result = await Effect.runPromise(Effect.provide(program, Fetch.layer));
135
128
  roots.value = result;
136
- fetchError.value = null;
137
129
  } catch (e) {
138
130
  console.warn("[shwfed-form] tree dataSource fetch failed", e);
139
- fetchError.value = e;
140
131
  }
141
132
  }
142
133
  watch(
@@ -360,13 +351,7 @@ const readonlyText = computed(() => {
360
351
  </Field>
361
352
 
362
353
  <div
363
- v-if="fetchError && roots.length === 0"
364
- class="min-h-9 py-1.5 text-sm text-red-500"
365
- >
366
- {{ t("tree-multi-load-error") }}
367
- </div>
368
- <div
369
- v-else-if="loading && roots.length === 0"
354
+ v-if="loading && roots.length === 0"
370
355
  class="flex flex-col gap-1.5 py-1"
371
356
  aria-busy="true"
372
357
  >
@@ -419,9 +404,7 @@ const readonlyText = computed(() => {
419
404
  </template>
420
405
 
421
406
  <template #empty>
422
- <div class="min-h-9 py-1.5 text-sm text-zinc-400">
423
- {{ t("tree-multi-empty") }}
424
- </div>
407
+ <span />
425
408
  </template>
426
409
  </UiTree>
427
410
  </template>
@@ -28,21 +28,15 @@ const { locale, t } = useI18n({
28
28
  messages: {
29
29
  zh: {
30
30
  "tree-single-search-label": "\u641C\u7D22",
31
- "tree-single-search-clear": "\u6E05\u9664\u641C\u7D22",
32
- "tree-single-load-error": "\u52A0\u8F7D\u5931\u8D25",
33
- "tree-single-empty": "\u65E0\u53EF\u9009\u9879"
31
+ "tree-single-search-clear": "\u6E05\u9664\u641C\u7D22"
34
32
  },
35
33
  en: {
36
34
  "tree-single-search-label": "Search",
37
- "tree-single-search-clear": "Clear search",
38
- "tree-single-load-error": "Failed to load",
39
- "tree-single-empty": "No options"
35
+ "tree-single-search-clear": "Clear search"
40
36
  },
41
37
  ja: {
42
38
  "tree-single-search-label": "\u691C\u7D22",
43
- "tree-single-search-clear": "\u691C\u7D22\u3092\u30AF\u30EA\u30A2",
44
- "tree-single-load-error": "\u8AAD\u307F\u8FBC\u307F\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
45
- "tree-single-empty": "\u9078\u629E\u80A2\u306A\u3057"
39
+ "tree-single-search-clear": "\u691C\u7D22\u3092\u30AF\u30EA\u30A2"
46
40
  }
47
41
  }
48
42
  });
@@ -94,7 +88,6 @@ const model = computed({
94
88
  });
95
89
  const roots = ref([]);
96
90
  const loading = ref(false);
97
- const fetchError = ref(null);
98
91
  async function fetchTree() {
99
92
  const dataSource = props.config.dataSource;
100
93
  if (!dataSource) {
@@ -129,10 +122,8 @@ async function fetchTree() {
129
122
  try {
130
123
  const result = await Effect.runPromise(Effect.provide(program, Fetch.layer));
131
124
  roots.value = result;
132
- fetchError.value = null;
133
125
  } catch (e) {
134
126
  console.warn("[shwfed-form] tree dataSource fetch failed", e);
135
- fetchError.value = e;
136
127
  }
137
128
  }
138
129
  watch(
@@ -347,13 +338,7 @@ const readonlyText = computed(() => {
347
338
  </Field>
348
339
 
349
340
  <div
350
- v-if="fetchError && roots.length === 0"
351
- class="min-h-9 py-1.5 text-sm text-red-500"
352
- >
353
- {{ t("tree-single-load-error") }}
354
- </div>
355
- <div
356
- v-else-if="loading && roots.length === 0"
341
+ v-if="loading && roots.length === 0"
357
342
  class="flex flex-col gap-1.5 py-1"
358
343
  aria-busy="true"
359
344
  >
@@ -404,9 +389,7 @@ const readonlyText = computed(() => {
404
389
  </template>
405
390
 
406
391
  <template #empty>
407
- <div class="min-h-9 py-1.5 text-sm text-zinc-400">
408
- {{ t("tree-single-empty") }}
409
- </div>
392
+ <span />
410
393
  </template>
411
394
  </UiTree>
412
395
  </template>
@@ -11,6 +11,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
11
11
  readonly locale: "en" | "ja" | "ko";
12
12
  readonly message: string;
13
13
  }[]] | undefined;
14
+ readonly resultExpression?: string | undefined;
14
15
  readonly expression: string;
15
16
  readonly titleExpression?: string | undefined;
16
17
  }) => any;
@@ -23,6 +24,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
23
24
  readonly locale: "en" | "ja" | "ko";
24
25
  readonly message: string;
25
26
  }[]] | undefined;
27
+ readonly resultExpression?: string | undefined;
26
28
  readonly expression: string;
27
29
  readonly titleExpression?: string | undefined;
28
30
  }) => any) | undefined;
@@ -11,7 +11,9 @@ const opSchema = schema(() => {
11
11
  });
12
12
  const fieldTitle = (f) => getStructFieldTitle(opSchema, f) ?? f;
13
13
  const fieldDescription = (f) => getStructFieldDescription(opSchema, f);
14
+ const JSON_VAR = { json: { type: "dyn", label: "\u54CD\u5E94\uFF08JSON\uFF09" } };
14
15
  const OUTCOME_VARS = {
16
+ json: { type: "dyn", label: "\u54CD\u5E94\uFF08JSON\uFF09" },
15
17
  result: { type: "string", label: "\u6267\u884C\u7ED3\u679C" }
16
18
  };
17
19
  function patch(patchValue) {
@@ -56,28 +58,53 @@ function patchDescription(v) {
56
58
  />
57
59
  </Field>
58
60
 
59
- <Field orientation="vertical">
60
- <FieldLabel class="text-xs text-zinc-500">
61
- <template
62
- v-if="fieldDescription('titleExpression')"
63
- #tooltip
64
- >
65
- <Markdown
66
- :source="fieldDescription('titleExpression')"
67
- block
68
- class="prose prose-sm prose-zinc"
69
- />
70
- </template>
71
- {{ fieldTitle("titleExpression") }}
72
- </FieldLabel>
73
- <ExpressionEditor
74
- :model-value="value.titleExpression ?? ''"
75
- placeholder="例:result == 'error' ? '下载失败' : '下载成功'"
76
- result-type="string"
77
- :extra-vars="OUTCOME_VARS"
78
- @update:model-value="(v) => patchOptionalExpression('titleExpression', v)"
79
- />
80
- </Field>
61
+ <div class="grid grid-cols-2 gap-4">
62
+ <Field orientation="vertical">
63
+ <FieldLabel class="text-xs text-zinc-500">
64
+ <template
65
+ v-if="fieldDescription('resultExpression')"
66
+ #tooltip
67
+ >
68
+ <Markdown
69
+ :source="fieldDescription('resultExpression')"
70
+ block
71
+ class="prose prose-sm prose-zinc"
72
+ />
73
+ </template>
74
+ {{ fieldTitle("resultExpression") }}
75
+ </FieldLabel>
76
+ <ExpressionEditor
77
+ :model-value="value.resultExpression ?? ''"
78
+ placeholder="例:json.code == 0 ? 'success' : 'error'"
79
+ result-type="string"
80
+ :extra-vars="JSON_VAR"
81
+ @update:model-value="(v) => patchOptionalExpression('resultExpression', v)"
82
+ />
83
+ </Field>
84
+
85
+ <Field orientation="vertical">
86
+ <FieldLabel class="text-xs text-zinc-500">
87
+ <template
88
+ v-if="fieldDescription('titleExpression')"
89
+ #tooltip
90
+ >
91
+ <Markdown
92
+ :source="fieldDescription('titleExpression')"
93
+ block
94
+ class="prose prose-sm prose-zinc"
95
+ />
96
+ </template>
97
+ {{ fieldTitle("titleExpression") }}
98
+ </FieldLabel>
99
+ <ExpressionEditor
100
+ :model-value="value.titleExpression ?? ''"
101
+ placeholder="例:result == 'error' ? '下载失败' : '下载成功'"
102
+ result-type="string"
103
+ :extra-vars="OUTCOME_VARS"
104
+ @update:model-value="(v) => patchOptionalExpression('titleExpression', v)"
105
+ />
106
+ </Field>
107
+ </div>
81
108
 
82
109
  <Field orientation="vertical">
83
110
  <FieldLabel class="text-xs text-zinc-500">
@@ -11,6 +11,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
11
11
  readonly locale: "en" | "ja" | "ko";
12
12
  readonly message: string;
13
13
  }[]] | undefined;
14
+ readonly resultExpression?: string | undefined;
14
15
  readonly expression: string;
15
16
  readonly titleExpression?: string | undefined;
16
17
  }) => any;
@@ -23,6 +24,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
23
24
  readonly locale: "en" | "ja" | "ko";
24
25
  readonly message: string;
25
26
  }[]] | undefined;
27
+ readonly resultExpression?: string | undefined;
26
28
  readonly expression: string;
27
29
  readonly titleExpression?: string | undefined;
28
30
  }) => any) | undefined;
@@ -10,6 +10,7 @@ class HttpRequestHalted {
10
10
  }
11
11
  _tag = "HttpRequestHalted";
12
12
  }
13
+ const TOAST_STYLES = /* @__PURE__ */ new Set(["success", "error", "warning", "info"]);
13
14
  function saveFile(file) {
14
15
  const url = URL.createObjectURL(file);
15
16
  const a = document.createElement("a");
@@ -21,28 +22,34 @@ function saveFile(file) {
21
22
  URL.revokeObjectURL(url);
22
23
  }
23
24
  export const handler = (params, ctx) => {
24
- const { expression, titleExpression, description } = params ?? {};
25
+ const { expression, resultExpression, titleExpression, description } = params ?? {};
25
26
  if (!expression || expression.trim().length === 0) return Effect.void;
26
27
  const program = Effect.gen(function* () {
27
28
  const steps = ctx.step?.outputs() ?? {};
28
29
  const evaluated = yield* ctx.cel(expression, { steps });
29
30
  const request = asRequest(evaluated);
30
31
  if (Option.isNone(request)) return;
31
- const outcome = yield* Effect.either(request.value.file());
32
- const result = Either.isLeft(outcome) ? "error" : "success";
32
+ const outcome = yield* Effect.either(request.value.fileOrJson());
33
+ const json = Either.isRight(outcome) && outcome.right._tag === "json" ? outcome.right.json : null;
34
+ const result = Either.isLeft(outcome) ? "error" : outcome.right._tag === "file" ? "success" : resultExpression === void 0 ? "error" : yield* ctx.cel(resultExpression, { json, steps });
35
+ const kind = TOAST_STYLES.has(result) ? result : "success";
33
36
  if (titleExpression !== void 0) {
34
- const title = yield* ctx.cel(titleExpression, { result, steps });
37
+ const title = yield* ctx.cel(titleExpression, { json, result, steps });
35
38
  if (title.length > 0) {
36
39
  const raw = getLocalizedText(description, ctx.locale()) ?? "";
37
- const body = raw.length === 0 ? void 0 : interpolateMarkdown(raw, ctx.cel, { result, steps });
38
- toast[result === "error" ? "error" : "success"](title, body === void 0 ? void 0 : { description: body });
40
+ const body = raw.length === 0 ? void 0 : interpolateMarkdown(raw, ctx.cel, { json, result, steps });
41
+ toast[kind](title, body === void 0 ? void 0 : { description: body });
39
42
  }
40
43
  }
41
44
  if (Either.isLeft(outcome)) {
42
45
  if (import.meta.dev) console.warn("[shwfed-operations] http download failed", outcome.left);
43
46
  return yield* Effect.die(new HttpRequestHalted(outcome.left));
44
47
  }
45
- yield* Effect.sync(() => saveFile(outcome.right));
48
+ if (kind === "error") return yield* Effect.die(new HttpRequestHalted("error result"));
49
+ if (outcome.right._tag === "file") {
50
+ const { file } = outcome.right;
51
+ yield* Effect.sync(() => saveFile(file));
52
+ }
46
53
  });
47
54
  return program.pipe(
48
55
  // The bus's handler contract has no requirements channel, so the host can't
@@ -50,9 +57,9 @@ export const handler = (params, ctx) => {
50
57
  // button runner uses.
51
58
  Effect.provide(Fetch.layer),
52
59
  // What remains on the error channel is CEL evaluation failure (request /
53
- // title expression) — a config bug, not a runtime outcome. Mirror the
54
- // request op: silent in prod, console in dev; the chain still halts so later
55
- // operations don't fire off a broken step.
60
+ // result / title expression) — a config bug, not a runtime outcome. Mirror
61
+ // the request op: silent in prod, console in dev; the chain still halts so
62
+ // later operations don't fire off a broken step.
56
63
  Effect.catchAll((error) => Effect.zipRight(
57
64
  Effect.sync(() => {
58
65
  if (import.meta.dev) console.warn("[shwfed-operations] http download op failed", error);
@@ -8,6 +8,7 @@ export declare const metadata: {
8
8
  };
9
9
  export declare function schema(configure: (env: Environment) => void): Schema.Struct<{
10
10
  expression: Schema.Schema<string, string, never>;
11
+ resultExpression: Schema.optional<Schema.Schema<string, string, never>>;
11
12
  titleExpression: Schema.optional<Schema.Schema<string, string, never>>;
12
13
  description: Schema.optional<Schema.TupleType<readonly [Schema.Struct<{
13
14
  locale: Schema.Literal<["zh"]>;