@shwfed/config 2.12.0 → 2.12.1

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 (90) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.table/config.d.vue.ts +68 -68
  3. package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.table/config.vue.d.ts +68 -68
  4. package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.table/runtime.d.vue.ts +68 -68
  5. package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.table/runtime.vue.d.ts +68 -68
  6. package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.table/schema.d.ts +34 -34
  7. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.date/config.d.vue.ts +2 -0
  8. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.date/config.vue +22 -0
  9. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.date/config.vue.d.ts +2 -0
  10. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.date/runtime.vue +5 -0
  11. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.date/schema.d.ts +1 -0
  12. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.date/schema.js +12 -0
  13. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.d.vue.ts +2 -0
  14. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.vue +22 -0
  15. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.vue.d.ts +2 -0
  16. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/runtime.vue +5 -0
  17. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/schema.d.ts +1 -0
  18. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/schema.js +12 -0
  19. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetime/config.d.vue.ts +2 -0
  20. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetime/config.vue +22 -0
  21. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetime/config.vue.d.ts +2 -0
  22. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetime/runtime.vue +5 -0
  23. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetime/schema.d.ts +1 -0
  24. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetime/schema.js +12 -0
  25. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.d.vue.ts +2 -0
  26. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.vue +22 -0
  27. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.vue.d.ts +2 -0
  28. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/runtime.vue +5 -0
  29. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/schema.d.ts +1 -0
  30. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/schema.js +12 -0
  31. package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.month/config.d.vue.ts +2 -0
  32. package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.month/config.vue +22 -0
  33. package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.month/config.vue.d.ts +2 -0
  34. package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.month/runtime.vue +5 -0
  35. package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.month/schema.d.ts +1 -0
  36. package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.month/schema.js +12 -0
  37. package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.monthrange/config.d.vue.ts +2 -0
  38. package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.monthrange/config.vue +22 -0
  39. package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.monthrange/config.vue.d.ts +2 -0
  40. package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.monthrange/runtime.vue +5 -0
  41. package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.monthrange/schema.d.ts +1 -0
  42. package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.monthrange/schema.js +12 -0
  43. package/dist/runtime/components/form/utils/ai-field-tools.d.ts +11 -0
  44. package/dist/runtime/components/form/utils/ai-field-tools.js +282 -0
  45. package/dist/runtime/components/form/utils/resolve.d.ts +15 -0
  46. package/dist/runtime/components/form/utils/resolve.js +13 -0
  47. package/dist/runtime/components/table/ai-generate.system.md +6 -0
  48. package/dist/runtime/components/table/ai-generate.vue +18 -17
  49. package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-remote/config.d.vue.ts +2 -2
  50. package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-remote/config.vue.d.ts +2 -2
  51. package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-static/config.d.vue.ts +2 -2
  52. package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-static/config.vue.d.ts +2 -2
  53. package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-remote/config.d.vue.ts +2 -2
  54. package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-remote/config.vue.d.ts +2 -2
  55. package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-static/config.d.vue.ts +2 -2
  56. package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-static/config.vue.d.ts +2 -2
  57. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-multi.remote/config.d.vue.ts +2 -2
  58. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-multi.remote/config.vue.d.ts +2 -2
  59. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-single.remote/config.d.vue.ts +2 -2
  60. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-single.remote/config.vue.d.ts +2 -2
  61. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/config.d.vue.ts +2 -2
  62. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/config.vue.d.ts +2 -2
  63. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/config.d.vue.ts +2 -2
  64. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/config.vue.d.ts +2 -2
  65. package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.combobox-multi/config.d.vue.ts +2 -2
  66. package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.combobox-multi/config.vue.d.ts +2 -2
  67. package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.combobox-single/config.d.vue.ts +2 -2
  68. package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.combobox-single/config.vue.d.ts +2 -2
  69. package/dist/runtime/components/table/columns/2026-06-17/com.shwfed.table.column.date-input/config.vue +33 -0
  70. package/dist/runtime/components/table/columns/2026-06-17/com.shwfed.table.column.date-input/runtime.vue +5 -0
  71. package/dist/runtime/components/table/columns/2026-06-17/com.shwfed.table.column.date-input/schema.d.ts +1 -0
  72. package/dist/runtime/components/table/columns/2026-06-17/com.shwfed.table.column.date-input/schema.js +6 -1
  73. package/dist/runtime/components/table/columns/2026-06-22/com.shwfed.table.column.date-range-input/config.vue +33 -0
  74. package/dist/runtime/components/table/columns/2026-06-22/com.shwfed.table.column.date-range-input/runtime.vue +5 -0
  75. package/dist/runtime/components/table/columns/2026-06-22/com.shwfed.table.column.date-range-input/schema.d.ts +1 -0
  76. package/dist/runtime/components/table/columns/2026-06-22/com.shwfed.table.column.date-range-input/schema.js +6 -1
  77. package/dist/runtime/components/table/schema.d.ts +68 -68
  78. package/dist/runtime/components/table/utils/ai-tools.js +50 -1
  79. package/dist/runtime/components/table/utils/shared.d.ts +1 -0
  80. package/dist/runtime/components/table/utils/shared.js +10 -0
  81. package/dist/runtime/components/ui/alert-dialog/AlertDialogCancel.vue +1 -1
  82. package/dist/runtime/components/ui/chat/ChatPrompt.d.vue.ts +11 -1
  83. package/dist/runtime/components/ui/chat/ChatPrompt.vue +10 -0
  84. package/dist/runtime/components/ui/chat/ChatPrompt.vue.d.ts +11 -1
  85. package/dist/runtime/share/disabled-date.d.ts +34 -0
  86. package/dist/runtime/share/disabled-date.js +13 -0
  87. package/dist/runtime/utils/ai/index.js +24 -1
  88. package/dist/runtime/utils/disabled-date.d.ts +26 -0
  89. package/dist/runtime/utils/disabled-date.js +21 -0
  90. package/package.json +1 -1
@@ -2,6 +2,7 @@
2
2
  import { Icon } from "@iconify/vue";
3
3
  import { computed } from "vue";
4
4
  import { format as formatDate } from "date-fns";
5
+ import { DISABLE_DATE_EDITOR_RESULT, INPUT_DATE_VARS } from "../../../../../share/disabled-date";
5
6
  import { Button } from "../../../../ui/button";
6
7
  import { ExpressionEditor } from "../../../../ui/expression-editor";
7
8
  import DerivedValueEditor from "../../../DerivedValueEditor.vue";
@@ -492,6 +493,27 @@ const valueFormatExample = computed(() => previewFormat(value.value.valueFormat
492
493
  </Field>
493
494
  </div>
494
495
 
496
+ <Field orientation="vertical">
497
+ <FieldLabel class="text-xs text-zinc-500">
498
+ <template #tooltip>
499
+ <Markdown
500
+ :source="fieldDescription('disabledDate')"
501
+ block
502
+ class="prose prose-sm prose-zinc"
503
+ />
504
+ </template>
505
+ {{ fieldTitle("disabledDate") }}
506
+ </FieldLabel>
507
+ <ExpressionEditor
508
+ :model-value="value.disabledDate ?? ''"
509
+ placeholder="例:input < now"
510
+ :result-type="[...DISABLE_DATE_EDITOR_RESULT]"
511
+ :extra-vars="INPUT_DATE_VARS"
512
+ class="min-h-10"
513
+ @update:model-value="(v) => value = { ...value, disabledDate: v.length > 0 ? v : void 0 }"
514
+ />
515
+ </Field>
516
+
495
517
  <Field orientation="vertical">
496
518
  <FieldLabel class="text-xs text-zinc-500">
497
519
  <template #tooltip>
@@ -41,6 +41,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
41
41
  } | undefined;
42
42
  readonly format?: string | undefined;
43
43
  readonly valueFormat?: string | undefined;
44
+ readonly disabledDate?: string | undefined;
44
45
  readonly validations?: readonly {
45
46
  readonly message: readonly [{
46
47
  readonly locale: "zh";
@@ -103,6 +104,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
103
104
  } | undefined;
104
105
  readonly format?: string | undefined;
105
106
  readonly valueFormat?: string | undefined;
107
+ readonly disabledDate?: string | undefined;
106
108
  readonly validations?: readonly {
107
109
  readonly message: readonly [{
108
110
  readonly locale: "zh";
@@ -5,6 +5,7 @@ import { computed, ref } from "vue";
5
5
  import { useI18n } from "vue-i18n";
6
6
  import { cel as _rawCel } from "../../../../../utils/cel";
7
7
  import { celBindings, injectCELContext } from "../../../../../utils/cel-context";
8
+ import { makeDisabledDatePredicate } from "../../../../../utils/disabled-date";
8
9
  import { getLocalizedText } from "../../../../../share/locale";
9
10
  import { DatePicker, DATE_PICKER_DEFAULT_FORMATS } from "../../../../ui/date-picker";
10
11
  import { Field, FieldLabel, FieldMessages } from "../../../../ui/field";
@@ -70,6 +71,9 @@ const shortcuts = computed(() => {
70
71
  }
71
72
  }));
72
73
  });
74
+ const disabledDate = computed(
75
+ () => makeDisabledDatePredicate(props.config.disabledDate, (input) => Effect.runSync($cel(props.config.disabledDate, { form: formScope.state.value ?? {}, input })))
76
+ );
73
77
  const uncontrolled = ref(void 0);
74
78
  const model = computed({
75
79
  get: () => {
@@ -130,6 +134,7 @@ const model = computed({
130
134
  :value-format="config.valueFormat"
131
135
  :placeholder="placeholderText"
132
136
  :disabled="isDisabled"
137
+ :disabled-date="disabledDate"
133
138
  :shortcuts="shortcuts"
134
139
  />
135
140
  <FieldMessages
@@ -77,6 +77,7 @@ export declare function schema(configure: (env: Environment) => void): Schema.St
77
77
  binding: Schema.optional<Schema.refine<string, typeof Schema.String>>;
78
78
  disabled: Schema.optional<Schema.Schema<string, string, never>>;
79
79
  readonly: Schema.optional<Schema.Schema<string, string, never>>;
80
+ disabledDate: Schema.optional<Schema.Schema<string, string, never>>;
80
81
  derived: Schema.optional<Schema.Struct<{
81
82
  mode: Schema.Literal<["formula", "prefill"]>;
82
83
  expression: Schema.Schema<string, string, never>;
@@ -1,4 +1,5 @@
1
1
  import { Schema } from "effect";
2
+ import { DISABLE_DATE_RESULT, registerInputDateIfAbsent } from "../../../../../share/disabled-date.js";
2
3
  import { Expression } from "../../../../../share/expression.js";
3
4
  import { Locale } from "../../../../../share/locale.js";
4
5
  import { commonFieldFields, derivedField, FieldOrientationSchema } from "../../../utils/common.js";
@@ -28,6 +29,13 @@ export function presetSchema(configure) {
28
29
  }
29
30
  export function schema(configure) {
30
31
  const CelBool = Expression({ configure, resultType: "bool" });
32
+ const DisabledDate = Expression({
33
+ configure: (env) => {
34
+ configure(env);
35
+ registerInputDateIfAbsent(env);
36
+ },
37
+ resultType: DISABLE_DATE_RESULT
38
+ });
31
39
  const Preset = presetSchema(configure);
32
40
  return Schema.Struct({
33
41
  type: Schema.Literal(type),
@@ -58,6 +66,10 @@ export function schema(configure) {
58
66
  title: "\u53EA\u8BFB\u6761\u4EF6",
59
67
  description: "\u8FD4\u56DE `true` \u65F6\u4EC5\u4EE5\u7EAF\u6587\u672C\u5C55\u793A\u5F53\u524D\u503C"
60
68
  })),
69
+ disabledDate: Schema.optional(DisabledDate.annotations({
70
+ title: "\u7981\u7528\u65E5\u671F",
71
+ description: "\u9010\u4E2A\u65E5\u671F\u5224\u5B9A\u662F\u5426\u53EF\u9009\uFF1B\u53D8\u91CF `input` \u4E3A\u5019\u9009\u6708\u4EFD\uFF08\u8BE5\u6708 1 \u53F7\uFF09\u3002\u8FD4\u56DE `true` \u65F6\u7981\u7528\uFF0C\u8FD4\u56DE `false`\u3001\u7A7A\u503C\u6216\u4E0D\u586B\u65F6\u53EF\u9009"
72
+ })),
61
73
  derived: derivedField(configure, "string"),
62
74
  format: Schema.optional(Schema.String.pipe(Schema.minLength(1)).annotations({
63
75
  title: "\u5C55\u793A\u683C\u5F0F",
@@ -34,6 +34,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
34
34
  } | undefined;
35
35
  readonly format?: string | undefined;
36
36
  readonly valueFormat?: string | undefined;
37
+ readonly disabledDate?: string | undefined;
37
38
  readonly rangeSeparatorIcon?: string | undefined;
38
39
  readonly startPlaceholder?: readonly [{
39
40
  readonly locale: "zh";
@@ -105,6 +106,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
105
106
  } | undefined;
106
107
  readonly format?: string | undefined;
107
108
  readonly valueFormat?: string | undefined;
109
+ readonly disabledDate?: string | undefined;
108
110
  readonly rangeSeparatorIcon?: string | undefined;
109
111
  readonly startPlaceholder?: readonly [{
110
112
  readonly locale: "zh";
@@ -2,6 +2,7 @@
2
2
  import { Icon } from "@iconify/vue";
3
3
  import { format as formatDate } from "date-fns";
4
4
  import { computed } from "vue";
5
+ import { DISABLE_DATE_EDITOR_RESULT, INPUT_DATE_VARS } from "../../../../../share/disabled-date";
5
6
  import { Button } from "../../../../ui/button";
6
7
  import { ExpressionEditor } from "../../../../ui/expression-editor";
7
8
  import DerivedValueEditor from "../../../DerivedValueEditor.vue";
@@ -644,6 +645,27 @@ const valueFormatExample = computed(() => previewFormat(value.value.valueFormat
644
645
  </Field>
645
646
  </div>
646
647
 
648
+ <Field orientation="vertical">
649
+ <FieldLabel class="text-xs text-zinc-500">
650
+ <template #tooltip>
651
+ <Markdown
652
+ :source="fieldDescription('disabledDate')"
653
+ block
654
+ class="prose prose-sm prose-zinc"
655
+ />
656
+ </template>
657
+ {{ fieldTitle("disabledDate") }}
658
+ </FieldLabel>
659
+ <ExpressionEditor
660
+ :model-value="value.disabledDate ?? ''"
661
+ placeholder="例:input < now"
662
+ :result-type="[...DISABLE_DATE_EDITOR_RESULT]"
663
+ :extra-vars="INPUT_DATE_VARS"
664
+ class="min-h-10"
665
+ @update:model-value="(v) => value = { ...value, disabledDate: v.length > 0 ? v : void 0 }"
666
+ />
667
+ </Field>
668
+
647
669
  <Field orientation="vertical">
648
670
  <FieldLabel class="text-xs text-zinc-500">
649
671
  <template #tooltip>
@@ -34,6 +34,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
34
34
  } | undefined;
35
35
  readonly format?: string | undefined;
36
36
  readonly valueFormat?: string | undefined;
37
+ readonly disabledDate?: string | undefined;
37
38
  readonly rangeSeparatorIcon?: string | undefined;
38
39
  readonly startPlaceholder?: readonly [{
39
40
  readonly locale: "zh";
@@ -105,6 +106,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
105
106
  } | undefined;
106
107
  readonly format?: string | undefined;
107
108
  readonly valueFormat?: string | undefined;
109
+ readonly disabledDate?: string | undefined;
108
110
  readonly rangeSeparatorIcon?: string | undefined;
109
111
  readonly startPlaceholder?: readonly [{
110
112
  readonly locale: "zh";
@@ -5,6 +5,7 @@ import { computed, ref } from "vue";
5
5
  import { useI18n } from "vue-i18n";
6
6
  import { cel as _rawCel } from "../../../../../utils/cel";
7
7
  import { celBindings, injectCELContext } from "../../../../../utils/cel-context";
8
+ import { makeDisabledDatePredicate } from "../../../../../utils/disabled-date";
8
9
  import { getLocalizedText } from "../../../../../share/locale";
9
10
  import { DATE_RANGE_PICKER_DEFAULT_FORMATS, DateRangePicker } from "../../../../ui/date-range-picker";
10
11
  import { Field, FieldLabel, FieldMessages } from "../../../../ui/field";
@@ -77,6 +78,9 @@ const shortcuts = computed(() => {
77
78
  }
78
79
  }));
79
80
  });
81
+ const disabledDate = computed(
82
+ () => makeDisabledDatePredicate(props.config.disabledDate, (input) => Effect.runSync($cel(props.config.disabledDate, { form: formScope.state.value ?? {}, input })))
83
+ );
80
84
  function asRange(raw) {
81
85
  if (!Array.isArray(raw) || raw.length !== 2) return void 0;
82
86
  const [a, b] = raw;
@@ -162,6 +166,7 @@ const readonlyText = computed(() => {
162
166
  :end-placeholder="endPlaceholderText"
163
167
  :range-separator-icon="config.rangeSeparatorIcon"
164
168
  :disabled="isDisabled"
169
+ :disabled-date="disabledDate"
165
170
  :shortcuts="shortcuts"
166
171
  />
167
172
  <FieldMessages
@@ -91,6 +91,7 @@ export declare function schema(configure: (env: Environment) => void): Schema.St
91
91
  binding: Schema.optional<Schema.Union<[Schema.filter<typeof Schema.String>, Schema.filter<Schema.Tuple2<Schema.filter<typeof Schema.String>, Schema.filter<typeof Schema.String>>>]>>;
92
92
  disabled: Schema.optional<Schema.Schema<string, string, never>>;
93
93
  readonly: Schema.optional<Schema.Schema<string, string, never>>;
94
+ disabledDate: Schema.optional<Schema.Schema<string, string, never>>;
94
95
  derived: Schema.optional<Schema.Struct<{
95
96
  mode: Schema.Literal<["formula", "prefill"]>;
96
97
  expression: Schema.Schema<string, string, never>;
@@ -1,4 +1,5 @@
1
1
  import { Schema } from "effect";
2
+ import { DISABLE_DATE_RESULT, registerInputDateIfAbsent } from "../../../../../share/disabled-date.js";
2
3
  import { Expression } from "../../../../../share/expression.js";
3
4
  import { Locale } from "../../../../../share/locale.js";
4
5
  import { commonFieldFields, derivedField, FieldOrientationSchema } from "../../../utils/common.js";
@@ -42,6 +43,13 @@ export function presetSchema(configure) {
42
43
  }
43
44
  export function schema(configure) {
44
45
  const CelBool = Expression({ configure, resultType: "bool" });
46
+ const DisabledDate = Expression({
47
+ configure: (env) => {
48
+ configure(env);
49
+ registerInputDateIfAbsent(env);
50
+ },
51
+ resultType: DISABLE_DATE_RESULT
52
+ });
45
53
  const Preset = presetSchema(configure);
46
54
  return Schema.Struct({
47
55
  type: Schema.Literal(type),
@@ -73,6 +81,10 @@ export function schema(configure) {
73
81
  title: "\u53EA\u8BFB\u6761\u4EF6",
74
82
  description: "\u8FD4\u56DE `true` \u65F6\u4EC5\u4EE5\u7EAF\u6587\u672C\u5C55\u793A\u5F53\u524D\u503C"
75
83
  })),
84
+ disabledDate: Schema.optional(DisabledDate.annotations({
85
+ title: "\u7981\u7528\u65E5\u671F",
86
+ description: "\u9010\u4E2A\u65E5\u671F\u5224\u5B9A\u662F\u5426\u53EF\u9009\uFF1B\u53D8\u91CF `input` \u4E3A\u5019\u9009\u6708\u4EFD\uFF08\u8BE5\u6708 1 \u53F7\uFF09\u3002\u8FD4\u56DE `true` \u65F6\u7981\u7528\uFF0C\u8FD4\u56DE `false`\u3001\u7A7A\u503C\u6216\u4E0D\u586B\u65F6\u53EF\u9009"
87
+ })),
76
88
  derived: derivedField(configure, "dyn"),
77
89
  format: Schema.optional(Schema.String.pipe(Schema.minLength(1)).annotations({
78
90
  title: "\u5C55\u793A\u683C\u5F0F",
@@ -0,0 +1,11 @@
1
+ import type { Environment } from '../../../vendor/cel-js/lib/index.js';
2
+ import type { AgenticTool } from '../../../utils/ai/index.js';
3
+ type AnyRecord = Record<string, any>;
4
+ export interface QueryFieldToolDeps {
5
+ readonly read: () => AnyRecord | undefined;
6
+ readonly write: (next: AnyRecord) => void;
7
+ readonly configure: (env: Environment) => void;
8
+ readonly genUuid: () => string;
9
+ }
10
+ export declare function createQueryFieldTools(deps: QueryFieldToolDeps): AgenticTool[];
11
+ export {};
@@ -0,0 +1,282 @@
1
+ import { JSONSchema, ParseResult, Schema } from "effect";
2
+ import { coerceFromString } from "../../../share/coerce-from-string.js";
3
+ import { Area } from "../../../share/layout.js";
4
+ import { defaultFormConfig } from "../schema.js";
5
+ import { registerFormVariablesIfAbsent } from "./form-vars.js";
6
+ import { activeFields } from "./resolve.js";
7
+ const HARNESS_KEYS = ["id", "compatibilityDate"];
8
+ const PlaceInput = Schema.Struct({
9
+ id: Schema.String.pipe(Schema.minLength(1)),
10
+ area: Area
11
+ });
12
+ function formScope(configure) {
13
+ return (env) => {
14
+ registerFormVariablesIfAbsent(env);
15
+ configure(env);
16
+ };
17
+ }
18
+ function publicFieldSchema(entry, configure) {
19
+ return entry.schema(formScope(configure)).pipe(Schema.omit(...HARNESS_KEYS));
20
+ }
21
+ function decode(schema, input) {
22
+ const result = Schema.decodeUnknownEither(schema)(coerceFromString(input, schema));
23
+ if (result._tag === "Right") return { ok: true, value: result.right };
24
+ const issues = ParseResult.ArrayFormatter.formatErrorSync(result.left);
25
+ const report = issues.map((i) => `- ${i.path.map(String).join(".") || "(root)"}: ${i.message}`).join("\n");
26
+ return { ok: false, report };
27
+ }
28
+ function overlaps(a, b) {
29
+ return a[0][0] < b[1][0] && a[1][0] > b[0][0] && a[0][1] < b[1][1] && a[1][1] > b[0][1];
30
+ }
31
+ function growColumns(layout) {
32
+ let maxCol = typeof layout.columns === "number" ? layout.columns : 1;
33
+ const placements = layout.placements ?? {};
34
+ for (const p of Object.values(placements)) {
35
+ const x2 = p.area[1][0];
36
+ if (x2 - 1 > maxCol) maxCol = x2 - 1;
37
+ }
38
+ layout.columns = Math.max(1, maxCol);
39
+ }
40
+ function ensureFormConfig(deps) {
41
+ return deps.read() ?? defaultFormConfig();
42
+ }
43
+ export function createQueryFieldTools(deps) {
44
+ return [
45
+ // ---- 信息获取 ----
46
+ {
47
+ name: "list_available_query_field_types",
48
+ description: "List the form field types you can insert into the table's search-condition form. Returns each type's name. Use this first to discover what fields exist; for a field's full field contract and defaults, follow up with `describe_specific_query_field_type`. Deprecated types are hidden.",
49
+ inputJsonSchema: {
50
+ type: "object",
51
+ properties: {},
52
+ additionalProperties: false
53
+ },
54
+ execute: () => activeFields().map((f) => {
55
+ const entry = { type: f.type, name: f.metadata.name };
56
+ const description = f.metadata.description;
57
+ if (description !== void 0) entry.description = description;
58
+ return entry;
59
+ })
60
+ },
61
+ {
62
+ name: "describe_specific_query_field_type",
63
+ description: "Return, for one search-condition field type: the JSON Schema (without `id`/`compatibilityDate` \u2014 managed by the harness), the default values, and the default placement size `w`/`h` (each `{ initial, min, max }`; `w` is in grid columns, `h` in rows). Call this before `insert_query_field` / `place_query_field` to learn the field contract and how big to place it \u2014 use `w.initial` / `h.initial` as the placed area's width / height. Deprecated types are not accepted.",
64
+ inputJsonSchema: {
65
+ type: "object",
66
+ properties: {
67
+ type: { type: "string", description: "A `type` value from `list_available_query_field_types`." }
68
+ },
69
+ required: ["type"],
70
+ additionalProperties: false
71
+ },
72
+ execute: (input) => {
73
+ const { type } = input ?? {};
74
+ if (typeof type !== "string" || type.length === 0) {
75
+ return "describe failed: `type` must be a non-empty string.";
76
+ }
77
+ const entry = activeFields().find((f) => f.type === type);
78
+ if (!entry) {
79
+ return `describe failed: query field type "${type}" is not available. Call list_available_query_field_types to see what is.`;
80
+ }
81
+ const publicSchema = publicFieldSchema(entry, deps.configure);
82
+ let jsonSchema;
83
+ try {
84
+ jsonSchema = JSONSchema.make(publicSchema);
85
+ } catch {
86
+ jsonSchema = "(schema unavailable)";
87
+ }
88
+ return {
89
+ schema: jsonSchema,
90
+ defaults: entry.defaults?.() ?? null,
91
+ // Default placement size from the field's registry metadata. The
92
+ // system prompt requires the model to use `w.initial` / `h.initial`
93
+ // as the placed area's width / height; `min`/`max` bound what it may
94
+ // adjust to. (`place_query_field` itself only guards overlap — the
95
+ // "use the initial size" rule lives in the prompt, not the tool.)
96
+ w: entry.metadata.w,
97
+ h: entry.metadata.h
98
+ };
99
+ }
100
+ },
101
+ {
102
+ name: "list_query_fields",
103
+ description: "Return the search-condition form's current fields (each with its `id`) joined with its placement: `placement` is the field's grid area `[[x1,y1],[x2,y2]]`, or `null` when the field exists but has NOT been placed yet (unplaced fields are not rendered). `grid` reports the layout's current column count. Use this to discover ids, see what still needs placing, and find a free area before calling `place_query_field`.",
104
+ inputJsonSchema: {
105
+ type: "object",
106
+ properties: {},
107
+ additionalProperties: false
108
+ },
109
+ execute: () => {
110
+ const fc = deps.read();
111
+ if (!fc) return { fields: [], grid: null };
112
+ const fields = Array.isArray(fc.fields) ? fc.fields : [];
113
+ const layout = Array.isArray(fc.layouts) ? fc.layouts[0]?.layout : void 0;
114
+ const placements = layout?.placements ?? {};
115
+ return {
116
+ fields: fields.map((f) => ({
117
+ ...f,
118
+ placement: placements[f.id]?.area ?? null
119
+ })),
120
+ grid: layout ? { columns: layout.columns ?? null } : null
121
+ };
122
+ }
123
+ },
124
+ // ---- 配置 ----
125
+ {
126
+ name: "insert_query_field",
127
+ description: "Insert one new field into the table's search-condition form. Provide `type` (from `list_available_query_field_types`) plus the field's fields as described by `describe_specific_query_field_type`. Do NOT include `id` or `compatibilityDate` \u2014 the harness assigns them. The field is created UNPLACED: it exists but is not rendered until you place it with `place_query_field`. On validation failure the tool returns the issues; fix them and call again.",
128
+ inputJsonSchema: {
129
+ type: "object",
130
+ properties: {
131
+ type: { type: "string", description: "The field type to insert." }
132
+ },
133
+ required: ["type"],
134
+ additionalProperties: true
135
+ },
136
+ execute: (input) => {
137
+ const raw = input ?? {};
138
+ const { type, ...rest } = raw;
139
+ if (typeof type !== "string" || type.length === 0) {
140
+ return "insert failed: `type` must be a non-empty string.";
141
+ }
142
+ for (const k of HARNESS_KEYS) {
143
+ if (k in rest) {
144
+ return `insert failed: do not pass \`${k}\` \u2014 the harness assigns it.`;
145
+ }
146
+ }
147
+ const entry = activeFields().find((f) => f.type === type);
148
+ if (!entry) {
149
+ return `insert failed: query field type "${type}" is not available. Call list_available_query_field_types to see what is.`;
150
+ }
151
+ const publicSchema = publicFieldSchema(entry, deps.configure);
152
+ const verdict = decode(publicSchema, raw);
153
+ if (!verdict.ok) {
154
+ return `insert failed for type "${type}". Fix these and call insert_query_field again:
155
+ ${verdict.report}`;
156
+ }
157
+ const fc = ensureFormConfig(deps);
158
+ const fields = Array.isArray(fc.fields) ? fc.fields : [];
159
+ const newField = {
160
+ id: deps.genUuid(),
161
+ compatibilityDate: entry.compatibilityDate,
162
+ ...verdict.value
163
+ };
164
+ fc.fields = [...fields, newField];
165
+ deps.write(fc);
166
+ return { id: newField.id, type };
167
+ }
168
+ },
169
+ {
170
+ name: "delete_query_fields",
171
+ description: "Delete one or more search-condition fields by id. Call `list_query_fields` first to obtain ids. Fields are matched by id only. On any unknown id the call is rejected without writing; fix and call again. Deleting a field also removes it from the layout (its placement is stripped).",
172
+ inputJsonSchema: {
173
+ type: "object",
174
+ properties: {
175
+ ids: {
176
+ type: "array",
177
+ items: { type: "string", minLength: 1 },
178
+ minItems: 1,
179
+ description: "Field ids to delete. Get them from `list_query_fields` first."
180
+ }
181
+ },
182
+ required: ["ids"],
183
+ additionalProperties: false
184
+ },
185
+ execute: (input) => {
186
+ const raw = input ?? {};
187
+ const ids = raw.ids;
188
+ if (!Array.isArray(ids) || ids.length === 0) {
189
+ return "delete failed: `ids` must be a non-empty array of field ids.";
190
+ }
191
+ for (const id of ids) {
192
+ if (typeof id !== "string" || id.length === 0) {
193
+ return "delete failed: every `ids` entry must be a non-empty string.";
194
+ }
195
+ }
196
+ const seen = /* @__PURE__ */ new Set();
197
+ for (const id of ids) {
198
+ if (seen.has(id)) {
199
+ return `delete failed: duplicate id "${id}" in input \u2014 dedupe and call again.`;
200
+ }
201
+ seen.add(id);
202
+ }
203
+ const fc = deps.read();
204
+ const fields = fc && Array.isArray(fc.fields) ? fc.fields : [];
205
+ const existing = new Set(fields.map((f) => f.id));
206
+ for (const id of ids) {
207
+ if (!existing.has(id)) {
208
+ return `delete failed: query field id "${id}" is not present. Call list_query_fields to see current ids.`;
209
+ }
210
+ }
211
+ const cfg = fc;
212
+ const deleted = new Set(ids);
213
+ cfg.fields = fields.filter((f) => !deleted.has(f.id));
214
+ if (Array.isArray(cfg.layouts)) {
215
+ cfg.layouts = cfg.layouts.map((ls) => {
216
+ const placements = ls?.layout?.placements;
217
+ if (!placements) return ls;
218
+ const next = Object.fromEntries(
219
+ Object.entries(placements).filter(([pid]) => !deleted.has(pid))
220
+ );
221
+ return { ...ls, layout: { ...ls.layout, placements: next } };
222
+ });
223
+ }
224
+ deps.write(cfg);
225
+ return { deleted: ids, count: ids.length };
226
+ }
227
+ },
228
+ {
229
+ name: "place_query_field",
230
+ description: "Place a field into the search-condition layout at grid coordinates you choose. `area` is `[[x1,y1],[x2,y2]]` using 1-based grid lines (top-left inclusive, bottom-right exclusive); e.g. a field occupying columns 1\u20132 on row 1 is `[[1,1],[3,2]]`. The field must already exist (call `insert_query_field` first). The harness rejects an `area` that overlaps another field \u2014 pick a free spot (use `list_query_fields` to see current placements) and call again. Placing an already-placed field MOVES it. The layout column count grows to fit your placements; how many columns the search bar uses is up to you and the guidance you were given.",
231
+ inputJsonSchema: {
232
+ type: "object",
233
+ properties: {
234
+ id: { type: "string", description: "The field id to place (from `list_query_fields`)." },
235
+ area: {
236
+ type: "array",
237
+ description: "Grid area `[[x1,y1],[x2,y2]]`, 1-based grid lines, bottom-right exclusive.",
238
+ items: { type: "array", items: { type: "integer", minimum: 1 }, minItems: 2, maxItems: 2 },
239
+ minItems: 2,
240
+ maxItems: 2
241
+ }
242
+ },
243
+ required: ["id", "area"],
244
+ additionalProperties: false
245
+ },
246
+ execute: (input) => {
247
+ const verdict = decode(PlaceInput, input ?? {});
248
+ if (!verdict.ok) {
249
+ return `place failed. Fix these and call place_query_field again:
250
+ ${verdict.report}`;
251
+ }
252
+ const { id, area } = verdict.value;
253
+ const fc = deps.read();
254
+ if (!fc) {
255
+ return "place failed: there is no query form yet. Call insert_query_field first.";
256
+ }
257
+ const fields = Array.isArray(fc.fields) ? fc.fields : [];
258
+ if (!fields.some((f) => f.id === id)) {
259
+ return `place failed: query field id "${id}" is not present. Call list_query_fields to see ids.`;
260
+ }
261
+ const layouts = Array.isArray(fc.layouts) ? fc.layouts : [];
262
+ const ls = layouts[0];
263
+ if (!ls || !ls.layout) {
264
+ return "place failed: the query form has no layout to place into.";
265
+ }
266
+ const placements = { ...ls.layout.placements ?? {} };
267
+ for (const [pid, p] of Object.entries(placements)) {
268
+ if (pid === id) continue;
269
+ if (overlaps(area, p.area)) {
270
+ return `place failed: area overlaps field "${pid}" at ${JSON.stringify(p.area)}. Pick a free area (see list_query_fields) and call again.`;
271
+ }
272
+ }
273
+ placements[id] = { area };
274
+ const nextLayout = { ...ls.layout, placements };
275
+ growColumns(nextLayout);
276
+ fc.layouts = [{ ...ls, layout: nextLayout }, ...layouts.slice(1)];
277
+ deps.write(fc);
278
+ return { id, area, columns: nextLayout.columns };
279
+ }
280
+ }
281
+ ];
282
+ }
@@ -118,6 +118,21 @@ export type FieldEntry = Readonly<{
118
118
  }>;
119
119
  export declare const FIELDS: ReadonlyArray<FieldEntry>;
120
120
  export declare function allFieldSchemas(configure: (env: Environment) => void): ReadonlyArray<AnySchema>;
121
+ export declare function latestFieldByType(): ReadonlyArray<FieldEntry>;
122
+ /**
123
+ * AI 工具可见的字段集合:按 `type` 取最新版本 + 排除 `deprecated`。镜像
124
+ * `table/utils/resolve.ts` 的 `activeColumns()`。
125
+ *
126
+ * 两层过滤的原因:
127
+ * (a) `latestFieldByType()` 解决同 `type` 多版本时只留最新版——避免 AI 拿到
128
+ * 已被新版本替代的旧 `compatibilityDate`(我们对 AI 隐藏 compDate);
129
+ * (b) `!deprecated` 同时屏蔽两类情况:同 type 旧日期(已由 (a) 消除),以及
130
+ * 跨类型迁移的源条目(`deriveEntryExtras` 给被 `migrateFrom` 指名的源都
131
+ * 打了 `deprecated: true`)。
132
+ *
133
+ * 人类 picker 仍走 `FIELDS`(含废弃)—— picker 要让用户选到旧字段再触发迁移。
134
+ */
135
+ export declare function activeFields(): ReadonlyArray<FieldEntry>;
121
136
  export declare function findField(type: string, compatibilityDate: string): FieldEntry | undefined;
122
137
  /**
123
138
  * Finds the registry entry that has declared `(type, compatibilityDate)` as a
@@ -120,6 +120,19 @@ export function allFieldSchemas(configure) {
120
120
  identifier: `${entry.type}@${entry.compatibilityDate}`
121
121
  }));
122
122
  }
123
+ export function latestFieldByType() {
124
+ const byType = /* @__PURE__ */ new Map();
125
+ for (const r of getFields()) {
126
+ const prev = byType.get(r.type);
127
+ if (!prev || r.compatibilityDate > prev.compatibilityDate) {
128
+ byType.set(r.type, r);
129
+ }
130
+ }
131
+ return [...byType.values()];
132
+ }
133
+ export function activeFields() {
134
+ return latestFieldByType().filter((e) => !e.deprecated);
135
+ }
123
136
  export function findField(type, compatibilityDate) {
124
137
  return getFields().find((f) => f.type === type && f.compatibilityDate === compatibilityDate);
125
138
  }
@@ -93,3 +93,9 @@ http
93
93
  对于日期、时间类型的字段:使用日期类型的列;对于时间,设置列宽为 140;对于日期,设置列宽为 120;将其 `align` 设置为 `center`。
94
94
 
95
95
  对于用户名、ID、各种类型等较短字段,酌情将其 `align` 设置为 `center`。
96
+
97
+ ### 配置搜索条件
98
+
99
+ 你应该根据 API 文档配置其支持的搜索条件。搜索条件应该排除分页、排序相关信息,仅包含业务逻辑。
100
+
101
+ 你应该首要考虑文本输入、数字输入、数字范围输入、日期范围输入、日期时间范围输入。如果你遇到了从多个值中选取一个或多个,考虑单选或者多选。如果你不能确定单选和多选的选项,向用户提问。当你不确定选项时,向用户所要配置选项的相关信息。
@@ -125,22 +125,6 @@ function stop() {
125
125
  rather than growing the editor pane; the fixed outer height is what lets
126
126
  the inner `flex-1` message area bound and scroll. -->
127
127
  <div class="flex h-[48rem] flex-col bg-transparent">
128
- <!-- New-conversation control: a quiet ghost button pinned top-right that
129
- clears the dialogue (and its sessionStorage). Disabled while a turn
130
- streams or when there's nothing to clear. -->
131
- <div class="flex items-center justify-end pb-1">
132
- <Button
133
- type="button"
134
- variant="ghost"
135
- size="sm"
136
- :disabled="!canClear"
137
- @click="newConversation"
138
- >
139
- <Icon icon="fluent:add-20-regular" />
140
- 新对话
141
- </Button>
142
- </div>
143
-
144
128
  <ChatMessages
145
129
  :messages="displayMessages"
146
130
  :pending="pending"
@@ -165,7 +149,24 @@ function stop() {
165
149
  :status="status"
166
150
  @submit="send"
167
151
  @stop="stop"
168
- />
152
+ >
153
+ <!-- New-conversation control lives at the composer's block-end left
154
+ edge (beside the send button): a quiet ghost button that clears
155
+ the dialogue (and its sessionStorage). Disabled while a turn
156
+ streams or when there's nothing to clear. -->
157
+ <template #actions>
158
+ <Button
159
+ type="button"
160
+ variant="ghost"
161
+ size="sm"
162
+ :disabled="!canClear"
163
+ @click="newConversation"
164
+ >
165
+ <Icon icon="fluent:add-20-regular" />
166
+ 新对话
167
+ </Button>
168
+ </template>
169
+ </ChatPrompt>
169
170
  </div>
170
171
  </div>
171
172
  </div>