dsh-plugin-prompt-tool 2.0.0 → 2.0.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.
- package/lib/client.js +848 -217
- package/lib/client.js.map +1 -1
- package/package.json +1 -1
- package/engine/trigger-editor-meta.mjs +0 -29
package/lib/client.js
CHANGED
|
@@ -1240,7 +1240,7 @@ window.__ModuleLoader__.load({
|
|
|
1240
1240
|
...typeof config.sequence === "number" ? { sequence: config.sequence } : {}
|
|
1241
1241
|
};
|
|
1242
1242
|
}
|
|
1243
|
-
const asRecord$
|
|
1243
|
+
const asRecord$2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
1244
1244
|
const readString = (source, key) => {
|
|
1245
1245
|
const value = source[key];
|
|
1246
1246
|
return typeof value === "string" ? value : void 0;
|
|
@@ -1312,8 +1312,8 @@ window.__ModuleLoader__.load({
|
|
|
1312
1312
|
}
|
|
1313
1313
|
function fieldsFromView(res) {
|
|
1314
1314
|
const ns = res.ok ? res.value : void 0;
|
|
1315
|
-
const value = asRecord$
|
|
1316
|
-
const base = asRecord$
|
|
1315
|
+
const value = asRecord$2(ns?.value);
|
|
1316
|
+
const base = asRecord$2(ns?.base);
|
|
1317
1317
|
return {
|
|
1318
1318
|
...EMPTY_FIELDS,
|
|
1319
1319
|
promptText: readString(value, "promptText") ?? readString(base, "promptText") ?? "",
|
|
@@ -3104,6 +3104,23 @@ window.__ModuleLoader__.load({
|
|
|
3104
3104
|
stroke: "currentColor"
|
|
3105
3105
|
})
|
|
3106
3106
|
});
|
|
3107
|
+
/** 关闭/移除:官方 IconCloseFill 的复制件(同一 artwork,14px,1px 描边)。 */
|
|
3108
|
+
const IconCloseFillRegular = (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
3109
|
+
width: "14",
|
|
3110
|
+
height: "14",
|
|
3111
|
+
viewBox: "0 0 16 16",
|
|
3112
|
+
fill: "none",
|
|
3113
|
+
strokeWidth: 1,
|
|
3114
|
+
"aria-hidden": "true",
|
|
3115
|
+
...props,
|
|
3116
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
3117
|
+
d: "M3.5 3.5L12.5 12.5",
|
|
3118
|
+
stroke: "currentColor"
|
|
3119
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
3120
|
+
d: "M12.5 3.5L3.5 12.5",
|
|
3121
|
+
stroke: "currentColor"
|
|
3122
|
+
})]
|
|
3123
|
+
});
|
|
3107
3124
|
const IconSearchOutlineRegular = (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
3108
3125
|
width: "16",
|
|
3109
3126
|
height: "16",
|
|
@@ -6947,7 +6964,7 @@ window.__ModuleLoader__.load({
|
|
|
6947
6964
|
className: controls_module_css_default.tagChipRemove,
|
|
6948
6965
|
"aria-label": `移除 ${tag}`,
|
|
6949
6966
|
onClick: () => remove(tag),
|
|
6950
|
-
children:
|
|
6967
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconCloseFillRegular, {})
|
|
6951
6968
|
})]
|
|
6952
6969
|
}, tag)), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6953
6970
|
id,
|
|
@@ -9430,11 +9447,8 @@ window.__ModuleLoader__.load({
|
|
|
9430
9447
|
}
|
|
9431
9448
|
//#endregion
|
|
9432
9449
|
//#region \0dsh-css:D:\AI\GitHub\dsh-plugin-prompt-tool\src\client\features\prompts\rules.module.css.mjs
|
|
9433
|
-
sheets.push(".pt_nDoCUG_workspace{min-width:0;color:var(--dsw-alias-label-primary);font-feature-settings:\"cv01\", \"ss03\";flex-direction:column;gap:12px;font:12px/18px system-ui,sans-serif;display:flex}.pt_nDoCUG_row
|
|
9450
|
+
sheets.push(".pt_nDoCUG_workspace{min-width:0;color:var(--dsw-alias-label-primary);font-feature-settings:\"cv01\", \"ss03\";flex-direction:column;gap:12px;font:12px/18px system-ui,sans-serif;display:flex}.pt_nDoCUG_row{flex-wrap:wrap;align-items:center;gap:8px 12px;min-width:0;display:flex}.pt_nDoCUG_cardPanel{min-width:0}.pt_nDoCUG_headerActions{flex:none;align-items:center;gap:6px;max-width:100%;display:inline-flex}.pt_nDoCUG_headerActions .pt_nDoCUG_row{flex-wrap:nowrap;gap:4px}.pt_nDoCUG_body{border-top:.5px solid var(--dsw-alias-border-l2);flex-direction:column;gap:16px;min-width:0;padding:16px;display:flex;container:pt_nDoCUG_rule-editor/inline-size}.pt_nDoCUG_fields{flex-wrap:wrap;align-items:flex-start;gap:8px 12px;min-width:0;display:flex}.pt_nDoCUG_fields>*{flex:0 auto;min-width:0;max-width:100%}.pt_nDoCUG_fields>.pt_nDoCUG_full,.pt_nDoCUG_fields>.pt_nDoCUG_parameterGroup{flex-basis:100%}.pt_nDoCUG_fields>.pt_nDoCUG_exclusiveGroup{align-items:flex-start;gap:12px;display:inline-flex}.pt_nDoCUG_exclusiveGroup>:first-child{min-width:0}.pt_nDoCUG_full,.pt_nDoCUG_parameterGroup{width:100%;min-width:0}.pt_nDoCUG_parameterGroup{flex-direction:column;gap:8px;display:flex}.pt_nDoCUG_parameterGroup h5,.pt_nDoCUG_section h3{color:var(--dsw-alias-label-primary);margin:0;font:500 13px/20px system-ui,sans-serif}.pt_nDoCUG_control{min-width:0;max-width:100%}.pt_nDoCUG_body textarea{resize:vertical;width:100%;min-width:0;font:12px/18px system-ui,sans-serif}.pt_nDoCUG_body .pt_nDoCUG_listControl{width:24ch;max-width:100%;min-height:46px}.pt_nDoCUG_section{flex-direction:column;gap:12px;min-width:0;display:flex}.pt_nDoCUG_section+.pt_nDoCUG_section{border-top:.5px solid var(--dsw-alias-border-l2);padding-top:16px}.pt_nDoCUG_toggle{flex-direction:column;align-items:flex-start;gap:4px;min-width:0;font:12px/18px system-ui,sans-serif;display:flex}.pt_nDoCUG_switchLine{flex:none;align-items:center;height:28px;min-height:28px;display:inline-flex}.pt_nDoCUG_condition,.pt_nDoCUG_conditions{flex-direction:column;gap:8px;min-width:0;display:flex}.pt_nDoCUG_conditionHead{flex-wrap:wrap;align-items:flex-end;gap:8px;min-width:0;display:flex}.pt_nDoCUG_conditionHead>div{min-width:0;max-width:100%}.pt_nDoCUG_conditionOrdinal{height:28px;color:var(--dsw-alias-label-secondary);align-items:center;display:inline-flex}.pt_nDoCUG_conditions>button,.pt_nDoCUG_condition>button{align-self:flex-start}.pt_nDoCUG_conditionChild{border-inline-start:2px solid var(--dsw-alias-border-l2);flex-direction:column;gap:8px;min-width:0;padding-inline-start:12px;display:flex}.pt_nDoCUG_status{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;margin:0;font:12px/18px system-ui,sans-serif}.pt_nDoCUG_error{color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere}.pt_nDoCUG_body [hidden]{display:none!important}.pt_nDoCUG_steps{flex-direction:column;gap:8px;min-width:0;display:flex}.pt_nDoCUG_stepCard{border:.5px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:10px;flex-direction:column;min-width:0;display:flex}.pt_nDoCUG_stepCard:hover,.pt_nDoCUG_stepCardOpen{border-color:var(--dsw-alias-border-l3)}.pt_nDoCUG_stepHead{align-items:center;gap:6px;min-width:0;padding:2px 6px 2px 8px;display:flex}.pt_nDoCUG_stepToggle{appearance:none;min-width:0;min-height:28px;color:inherit;font:inherit;text-align:start;cursor:pointer;background:0 0;border:0;border-radius:6px;flex:auto;align-items:center;gap:8px;padding:2px 0;display:flex}.pt_nDoCUG_stepToggle:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.pt_nDoCUG_stepKind{border:.5px solid var(--dsw-alias-border-l2);corner-shape:round;color:var(--dsw-alias-label-secondary);white-space:nowrap;border-radius:999px;flex:none;padding:1px 8px;font:11px/16px system-ui,sans-serif}.pt_nDoCUG_stepSummary{min-width:0;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;flex:auto;font:12px/18px system-ui,sans-serif;overflow:hidden}.pt_nDoCUG_stepActions{flex:none;align-items:center;gap:4px;display:inline-flex}.pt_nDoCUG_stepClose{color:var(--dsw-alias-label-tertiary)}.pt_nDoCUG_stepClose:disabled{cursor:default;opacity:.4}.pt_nDoCUG_stepBody{border-top:.5px solid var(--dsw-alias-border-l2);flex-direction:column;gap:8px;min-width:0;padding:8px 8px 10px 12px;display:flex}.pt_nDoCUG_stepScope{border-inline-start:2px solid var(--dsw-alias-border-l2);flex-direction:column;gap:8px;min-width:0;padding-inline-start:10px;display:flex}.pt_nDoCUG_scopeHead{align-items:center;gap:8px;min-width:0;display:flex}.pt_nDoCUG_stepSlot{color:var(--dsw-alias-label-secondary);margin:0;font:11px/16px system-ui,sans-serif}.pt_nDoCUG_stepAdd{flex-wrap:wrap;align-items:center;gap:6px;min-width:0;display:flex}.pt_nDoCUG_stepHint{color:var(--dsw-alias-label-tertiary);font:12px/18px system-ui,sans-serif}@container pt_nDoCUG_rule-editor (width<=480px){.pt_nDoCUG_conditionChild,.pt_nDoCUG_stepBody{padding-inline-start:8px}.pt_nDoCUG_stepScope{padding-inline-start:6px}}@media (pointer:coarse){.pt_nDoCUG_switchLine,.pt_nDoCUG_conditionOrdinal,.pt_nDoCUG_stepToggle{height:44px;min-height:44px}}");
|
|
9434
9451
|
var rules_module_css_default = {
|
|
9435
|
-
"action": "pt_nDoCUG_action",
|
|
9436
|
-
"actionHead": "pt_nDoCUG_actionHead",
|
|
9437
|
-
"actions": "pt_nDoCUG_actions",
|
|
9438
9452
|
"body": "pt_nDoCUG_body",
|
|
9439
9453
|
"cardPanel": "pt_nDoCUG_cardPanel",
|
|
9440
9454
|
"condition": "pt_nDoCUG_condition",
|
|
@@ -9452,8 +9466,23 @@ window.__ModuleLoader__.load({
|
|
|
9452
9466
|
"parameterGroup": "pt_nDoCUG_parameterGroup",
|
|
9453
9467
|
"row": "pt_nDoCUG_row",
|
|
9454
9468
|
"rule-editor": "pt_nDoCUG_rule-editor",
|
|
9469
|
+
"scopeHead": "pt_nDoCUG_scopeHead",
|
|
9455
9470
|
"section": "pt_nDoCUG_section",
|
|
9456
9471
|
"status": "pt_nDoCUG_status",
|
|
9472
|
+
"stepActions": "pt_nDoCUG_stepActions",
|
|
9473
|
+
"stepAdd": "pt_nDoCUG_stepAdd",
|
|
9474
|
+
"stepBody": "pt_nDoCUG_stepBody",
|
|
9475
|
+
"stepCard": "pt_nDoCUG_stepCard",
|
|
9476
|
+
"stepCardOpen": "pt_nDoCUG_stepCardOpen",
|
|
9477
|
+
"stepClose": "pt_nDoCUG_stepClose",
|
|
9478
|
+
"stepHead": "pt_nDoCUG_stepHead",
|
|
9479
|
+
"stepHint": "pt_nDoCUG_stepHint",
|
|
9480
|
+
"stepKind": "pt_nDoCUG_stepKind",
|
|
9481
|
+
"stepScope": "pt_nDoCUG_stepScope",
|
|
9482
|
+
"stepSlot": "pt_nDoCUG_stepSlot",
|
|
9483
|
+
"stepSummary": "pt_nDoCUG_stepSummary",
|
|
9484
|
+
"stepToggle": "pt_nDoCUG_stepToggle",
|
|
9485
|
+
"steps": "pt_nDoCUG_steps",
|
|
9457
9486
|
"switchLine": "pt_nDoCUG_switchLine",
|
|
9458
9487
|
"toggle": "pt_nDoCUG_toggle",
|
|
9459
9488
|
"workspace": "pt_nDoCUG_workspace"
|
|
@@ -9475,6 +9504,7 @@ window.__ModuleLoader__.load({
|
|
|
9475
9504
|
fill: "form.fill.label",
|
|
9476
9505
|
order: "form.order.label"
|
|
9477
9506
|
};
|
|
9507
|
+
/** 清掉某个字段前缀下的原始草稿(含嵌套键)。 */
|
|
9478
9508
|
const cleared = (fields, prefix) => {
|
|
9479
9509
|
for (const key of fields.keys()) if (key === prefix || key.startsWith(prefix + ":")) fields.delete(key);
|
|
9480
9510
|
};
|
|
@@ -9789,172 +9819,717 @@ window.__ModuleLoader__.load({
|
|
|
9789
9819
|
]
|
|
9790
9820
|
});
|
|
9791
9821
|
}
|
|
9792
|
-
|
|
9793
|
-
|
|
9794
|
-
|
|
9795
|
-
|
|
9796
|
-
|
|
9797
|
-
const
|
|
9798
|
-
|
|
9799
|
-
|
|
9800
|
-
|
|
9801
|
-
|
|
9822
|
+
//#endregion
|
|
9823
|
+
//#region src/client/features/prompts/rule-steps.ts
|
|
9824
|
+
const asRecord$1 = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
9825
|
+
/** 动作节点的判据只有 `kind`;分支与无法识别的节点都没有它。 */
|
|
9826
|
+
const isActionNode = (node) => {
|
|
9827
|
+
const kind = asRecord$1(node).kind;
|
|
9828
|
+
return typeof kind === "string" && kind.length > 0;
|
|
9829
|
+
};
|
|
9830
|
+
const isBranchNode = (node) => !isActionNode(node) && Array.isArray(asRecord$1(node).then);
|
|
9831
|
+
const nodeList = (value) => Array.isArray(value) ? value : [];
|
|
9832
|
+
/** 摘要里的枚举上限:超过就退化成「前两项 等 N 项」,卡头永远单行。 */
|
|
9833
|
+
const SUMMARY_LIMIT = 2;
|
|
9834
|
+
/** 值以内联标签显示的技术键;缺省时按原值显示。 */
|
|
9835
|
+
const VALUE_LABEL_KEYS = {
|
|
9836
|
+
subject: SUBJECT_LABEL_KEYS,
|
|
9837
|
+
audience: AUDIENCE_LABEL_KEYS,
|
|
9838
|
+
modelScope: MODEL_SCOPE_LABEL_KEYS,
|
|
9839
|
+
layer: LAYER_LABEL_KEYS,
|
|
9840
|
+
strategy: STRATEGY_LABEL_KEYS,
|
|
9841
|
+
position: POSITION_LABEL_KEYS,
|
|
9842
|
+
promotion: PROMOTION_LABEL_KEYS
|
|
9843
|
+
};
|
|
9844
|
+
function clipped(t, items, separator) {
|
|
9845
|
+
if (items.length <= SUMMARY_LIMIT) return items.join(separator);
|
|
9846
|
+
return t("rules.steps.more", {
|
|
9847
|
+
head: items.slice(0, SUMMARY_LIMIT).join(separator),
|
|
9848
|
+
count: items.length
|
|
9849
|
+
});
|
|
9850
|
+
}
|
|
9851
|
+
function valueText(t, key, value) {
|
|
9852
|
+
if (typeof value === "boolean") return value ? t("rules.steps.yes") : t("rules.steps.no");
|
|
9853
|
+
if (typeof value === "number") return String(value);
|
|
9854
|
+
if (typeof value === "string") {
|
|
9855
|
+
const keys = VALUE_LABEL_KEYS[key];
|
|
9856
|
+
return keys === void 0 ? value : translateLabel(t, keys, value);
|
|
9857
|
+
}
|
|
9858
|
+
if (Array.isArray(value)) return clipped(t, value.map((item) => valueText(t, key, item)), t("rules.steps.listSeparator"));
|
|
9859
|
+
const entries = Object.entries(asRecord$1(value));
|
|
9860
|
+
if (entries.length === 0) return "";
|
|
9861
|
+
return clipped(t, entries.map(([field, item]) => `${triggerLabel(t, field)}=${valueText(t, field, item)}`), t("rules.steps.listSeparator"));
|
|
9862
|
+
}
|
|
9863
|
+
/** 单个条件(含组合递归)的摘要;畸形条件退化为项数,不猜结构。 */
|
|
9864
|
+
function conditionSummary(t, condition) {
|
|
9865
|
+
if (condition === void 0) return t("triggers.unconditional");
|
|
9866
|
+
const record = asRecord$1(condition);
|
|
9867
|
+
const kinds = Object.keys(record);
|
|
9868
|
+
if (kinds.length !== 1) return t("rules.steps.complex", { count: kinds.length });
|
|
9869
|
+
const kind = kinds[0];
|
|
9870
|
+
const value = record[kind];
|
|
9871
|
+
if (kind === "not") return t("rules.steps.not", { value: conditionSummary(t, asRecord$1(value)) });
|
|
9872
|
+
if (kind === "all" || kind === "any" || kind === "notAny") {
|
|
9873
|
+
const children = nodeList(value).map((child) => conditionSummary(t, asRecord$1(child)));
|
|
9874
|
+
if (children.length === 0) return triggerLabel(t, kind);
|
|
9875
|
+
if (kind === "all") return clipped(t, children, ` ${t("rules.steps.and")} `);
|
|
9876
|
+
const joined = clipped(t, children, ` ${t("rules.steps.or")} `);
|
|
9877
|
+
return kind === "any" ? joined : t("rules.steps.not", { value: joined });
|
|
9878
|
+
}
|
|
9879
|
+
const detail = valueText(t, kind, value);
|
|
9880
|
+
return detail.length === 0 ? triggerLabel(t, kind) : t("rules.steps.condition", {
|
|
9881
|
+
kind: triggerLabel(t, kind),
|
|
9882
|
+
detail
|
|
9883
|
+
});
|
|
9884
|
+
}
|
|
9885
|
+
/** 注入正文的首行摘要:去掉 Markdown 标题记号与空行,超长截断。 */
|
|
9886
|
+
function textLead(text) {
|
|
9887
|
+
for (const raw of text.split("\n")) {
|
|
9888
|
+
const line = raw.replace(/^[#>\s*-]+/, "").trim();
|
|
9889
|
+
if (line.length > 0) return line.length > 28 ? `${line.slice(0, 28)}…` : line;
|
|
9890
|
+
}
|
|
9891
|
+
return "";
|
|
9892
|
+
}
|
|
9893
|
+
/** 动作摘要:类型 + 执行层 + 策略 + 正文首行(或 request-params 的覆盖项)。 */
|
|
9894
|
+
function actionSummary(t, action) {
|
|
9895
|
+
const config = asRecord$1(action.config);
|
|
9896
|
+
const parts = [triggerLabel(t, String(action.kind))];
|
|
9897
|
+
if (typeof config.layer === "string" && config.layer.length > 0) parts.push(translateLabel(t, LAYER_LABEL_KEYS, config.layer));
|
|
9898
|
+
if (typeof config.strategy === "string" && config.strategy.length > 0) parts.push(translateLabel(t, STRATEGY_LABEL_KEYS, config.strategy));
|
|
9899
|
+
const lead = typeof config.text === "string" ? textLead(config.text) : "";
|
|
9900
|
+
if (lead.length > 0) parts.push(lead);
|
|
9901
|
+
else {
|
|
9902
|
+
const entries = Object.entries(asRecord$1(config.patch)).filter(([, value]) => value !== void 0 && value !== "");
|
|
9903
|
+
if (entries.length > 0) parts.push(clipped(t, entries.map(([key, value]) => `${key}=${valueText(t, key, value)}`), t("rules.steps.listSeparator")));
|
|
9904
|
+
}
|
|
9905
|
+
return parts.join(" · ");
|
|
9906
|
+
}
|
|
9907
|
+
/** 分支卡头:`当 ⟨条件⟩ → ⟨动作⟩`;单个动作时直接写该动作,多动作写条数。 */
|
|
9908
|
+
function branchSummary(t, branch) {
|
|
9909
|
+
const then = nodeList(branch.then);
|
|
9910
|
+
const otherwise = nodeList(branch.else);
|
|
9911
|
+
const lead = then.length === 1 && otherwise.length === 0 && isActionNode(then[0]) ? actionSummary(t, then[0]) : t("rules.steps.actionCount", { count: then.length });
|
|
9912
|
+
return t("rules.steps.branch", {
|
|
9913
|
+
condition: conditionSummary(t, branch.if),
|
|
9914
|
+
actions: lead
|
|
9915
|
+
});
|
|
9916
|
+
}
|
|
9917
|
+
function nodeSummary(t, node) {
|
|
9918
|
+
if (isActionNode(node)) return actionSummary(t, node);
|
|
9919
|
+
if (isBranchNode(node)) return branchSummary(t, node);
|
|
9920
|
+
return t("rules.steps.unknown");
|
|
9921
|
+
}
|
|
9922
|
+
/** 递归统计生效动作数与分支数(卡头摘要用)。 */
|
|
9923
|
+
function countNodes(nodes) {
|
|
9924
|
+
return nodes.reduce((total, node) => {
|
|
9925
|
+
if (!isBranchNode(node)) return {
|
|
9926
|
+
actions: total.actions + 1,
|
|
9927
|
+
branches: total.branches
|
|
9928
|
+
};
|
|
9929
|
+
const then = countNodes(nodeList(node.then));
|
|
9930
|
+
const otherwise = countNodes(nodeList(node.else));
|
|
9931
|
+
return {
|
|
9932
|
+
actions: total.actions + then.actions + otherwise.actions,
|
|
9933
|
+
branches: total.branches + 1 + then.branches + otherwise.branches
|
|
9934
|
+
};
|
|
9935
|
+
}, {
|
|
9936
|
+
actions: 0,
|
|
9937
|
+
branches: 0
|
|
9938
|
+
});
|
|
9939
|
+
}
|
|
9940
|
+
/** 整条规则已用的动作 id:嵌套后新建动作必须在**全规则**范围内唯一(引擎拒绝重复 id)。 */
|
|
9941
|
+
function collectActionIds(nodes, into = /* @__PURE__ */ new Set()) {
|
|
9942
|
+
for (const node of nodes) if (isActionNode(node)) into.add(node.id);
|
|
9943
|
+
else if (isBranchNode(node)) {
|
|
9944
|
+
collectActionIds(nodeList(node.then), into);
|
|
9945
|
+
collectActionIds(nodeList(node.else), into);
|
|
9946
|
+
}
|
|
9947
|
+
return into;
|
|
9948
|
+
}
|
|
9949
|
+
/** 叶子节点数(含组合条件展开)与作用域条件计数,供卡头摘要。 */
|
|
9950
|
+
function countConditions(condition) {
|
|
9951
|
+
if (condition === void 0) return 0;
|
|
9952
|
+
const record = asRecord$1(condition);
|
|
9953
|
+
const kind = Object.keys(record)[0];
|
|
9954
|
+
if (kind === "all" || kind === "any" || kind === "notAny") return nodeList(record[kind]).reduce((total, child) => total + countConditions(asRecord$1(child)), 0);
|
|
9955
|
+
if (kind === "not") return countConditions(asRecord$1(record.not));
|
|
9956
|
+
return 1;
|
|
9957
|
+
}
|
|
9958
|
+
/** 路径上带条件的叶子动作:这些动作必须是 event 生命周期,否则引擎拒绝(rule-spec.mjs:143)。 */
|
|
9959
|
+
function conditionalActions(nodes, inherited = false, into = []) {
|
|
9960
|
+
for (const node of nodes) {
|
|
9961
|
+
if (isActionNode(node)) {
|
|
9962
|
+
if (inherited) into.push(node);
|
|
9963
|
+
continue;
|
|
9964
|
+
}
|
|
9965
|
+
if (isBranchNode(node)) {
|
|
9966
|
+
const inner = inherited || node.if !== void 0;
|
|
9967
|
+
conditionalActions(nodeList(node.then), inner, into);
|
|
9968
|
+
conditionalActions(nodeList(node.else), inner, into);
|
|
9969
|
+
}
|
|
9970
|
+
}
|
|
9971
|
+
return into;
|
|
9972
|
+
}
|
|
9973
|
+
/**
|
|
9974
|
+
* JSON 面板的结构门槛:动作要有非空 `id` + `kind`,分支要有 `then` 数组(可递归嵌套)。
|
|
9975
|
+
* 分支节点没有 `kind`,不能再用「每个 then 项都必须是动作」判定,否则合法规则被报成非法 JSON。
|
|
9976
|
+
*/
|
|
9977
|
+
function isValidNode(node) {
|
|
9978
|
+
if (isBranchNode(node)) {
|
|
9979
|
+
const record = asRecord$1(node);
|
|
9980
|
+
return nodeList(record.then).every(isValidNode) && nodeList(record.else).every(isValidNode);
|
|
9981
|
+
}
|
|
9982
|
+
const record = asRecord$1(node);
|
|
9983
|
+
return isActionNode(node) && typeof record.id === "string" && record.id.length > 0;
|
|
9984
|
+
}
|
|
9985
|
+
/** 生效条件链:从根到该节点的所有条件用「且」连接,放进卡头提示逐字可读。 */
|
|
9986
|
+
function conditionChain(t, chain) {
|
|
9987
|
+
return t("rules.steps.chain", { chain: chain.map((item) => conditionSummary(t, item)).join(` ${t("rules.steps.and")} `) });
|
|
9988
|
+
}
|
|
9989
|
+
//#endregion
|
|
9990
|
+
//#region src/client/features/prompts/RuleSteps.tsx
|
|
9991
|
+
/**
|
|
9992
|
+
* 规则卡内部的条件卡视图(「一个条件一张卡,对应它的动作」)。
|
|
9993
|
+
*
|
|
9994
|
+
* 结构对应引擎真值(engine/branch.mjs#expandActions):
|
|
9995
|
+
* IF 卡 = 规则级条件,卡内是它的直属动作;
|
|
9996
|
+
* 分支卡 = `then` 里的分支节点 `{if, then, else}`,卡头即「当 ⟨条件⟩ → ⟨动作⟩」;
|
|
9997
|
+
* 动作卡 = 叶子动作,可展开改字段;
|
|
9998
|
+
* 否则卡 = 规则级 `else`。
|
|
9999
|
+
* 每张卡都是 TagInput 式的小卡:卡头单行摘要,展开才编辑,右侧 ↑↓ 与 × 。
|
|
10000
|
+
*/
|
|
10001
|
+
/** 注册制层没有逐轮求值时机,引擎拒绝带条件的动作(engine/rule-spec.mjs:79,143)。 */
|
|
10002
|
+
const REGISTRATION_LAYERS = ["system-section", "runtime-context"];
|
|
10003
|
+
/** 关闭按钮:与 TagInput 的 chip 删除同形态,图标是官方 IconClose 的复制件。 */
|
|
10004
|
+
function CloseButton(props) {
|
|
10005
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HintTooltip, {
|
|
10006
|
+
label: props.label,
|
|
10007
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10008
|
+
type: "button",
|
|
10009
|
+
className: clsx(controls_module_css_default.tagChipRemove, rules_module_css_default.stepClose),
|
|
10010
|
+
"aria-label": props.label,
|
|
10011
|
+
disabled: props.disabled,
|
|
10012
|
+
onClick: props.onClick,
|
|
10013
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconCloseFillRegular, {})
|
|
10014
|
+
})
|
|
10015
|
+
});
|
|
10016
|
+
}
|
|
10017
|
+
/** 一张小卡:卡头是一整行摘要(点开才编辑),右侧是这张卡自己的操作。 */
|
|
10018
|
+
function StepCard(props) {
|
|
10019
|
+
const panelId = (0, react.useId)();
|
|
10020
|
+
const toggleRef = (0, react.useRef)(null);
|
|
10021
|
+
const bodyRef = (0, react.useRef)(null);
|
|
10022
|
+
const toggle = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
10023
|
+
ref: toggleRef,
|
|
10024
|
+
type: "button",
|
|
10025
|
+
className: rules_module_css_default.stepToggle,
|
|
10026
|
+
"aria-expanded": props.open,
|
|
10027
|
+
"aria-controls": panelId,
|
|
10028
|
+
onClick: () => {
|
|
10029
|
+
if (props.open && bodyRef.current !== null && bodyRef.current.contains(document.activeElement)) toggleRef.current?.focus();
|
|
10030
|
+
props.onToggle();
|
|
10031
|
+
},
|
|
10032
|
+
children: [
|
|
10033
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconChevronDownOutlineRegular, { className: clsx(controls_module_css_default.chevron, props.open && controls_module_css_default.chevronOpen) }),
|
|
10034
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10035
|
+
className: rules_module_css_default.stepKind,
|
|
10036
|
+
children: props.kindLabel
|
|
10037
|
+
}),
|
|
10038
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10039
|
+
className: rules_module_css_default.stepSummary,
|
|
10040
|
+
children: props.summary
|
|
10041
|
+
})
|
|
10042
|
+
]
|
|
10043
|
+
});
|
|
10044
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
10045
|
+
className: clsx(rules_module_css_default.stepCard, props.open && rules_module_css_default.stepCardOpen),
|
|
10046
|
+
"data-step": props.kind,
|
|
10047
|
+
"data-open": props.open || void 0,
|
|
10048
|
+
"data-level": props.level,
|
|
10049
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10050
|
+
className: rules_module_css_default.stepHead,
|
|
10051
|
+
children: [props.hint === void 0 ? toggle : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HintTooltip, {
|
|
10052
|
+
label: props.hint,
|
|
10053
|
+
children: toggle
|
|
10054
|
+
}), props.actions !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10055
|
+
className: rules_module_css_default.stepActions,
|
|
10056
|
+
children: props.actions
|
|
10057
|
+
})]
|
|
10058
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10059
|
+
id: panelId,
|
|
10060
|
+
ref: bodyRef,
|
|
10061
|
+
hidden: !props.open,
|
|
10062
|
+
className: rules_module_css_default.stepBody,
|
|
10063
|
+
children: props.open && props.children
|
|
10064
|
+
})]
|
|
10065
|
+
});
|
|
10066
|
+
}
|
|
10067
|
+
/** 作用域头:只声明「下面这批动作属于哪个条件」,本身没有可编辑内容。 */
|
|
10068
|
+
function ScopeHead(props) {
|
|
9802
10069
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9803
|
-
className: rules_module_css_default.
|
|
9804
|
-
children: [
|
|
9805
|
-
|
|
9806
|
-
|
|
9807
|
-
|
|
9808
|
-
|
|
9809
|
-
|
|
9810
|
-
|
|
9811
|
-
|
|
9812
|
-
|
|
9813
|
-
|
|
9814
|
-
|
|
9815
|
-
|
|
9816
|
-
|
|
9817
|
-
|
|
9818
|
-
|
|
9819
|
-
|
|
9820
|
-
|
|
9821
|
-
|
|
9822
|
-
|
|
9823
|
-
|
|
9824
|
-
|
|
9825
|
-
|
|
9826
|
-
|
|
10070
|
+
className: rules_module_css_default.scopeHead,
|
|
10071
|
+
children: [
|
|
10072
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10073
|
+
className: rules_module_css_default.stepKind,
|
|
10074
|
+
children: props.kindLabel
|
|
10075
|
+
}),
|
|
10076
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10077
|
+
className: rules_module_css_default.stepSummary,
|
|
10078
|
+
children: props.summary
|
|
10079
|
+
}),
|
|
10080
|
+
props.onRemove !== void 0 && props.removeLabel !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10081
|
+
className: rules_module_css_default.stepActions,
|
|
10082
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CloseButton, {
|
|
10083
|
+
label: props.removeLabel,
|
|
10084
|
+
disabled: props.disabled,
|
|
10085
|
+
onClick: props.onRemove
|
|
10086
|
+
})
|
|
10087
|
+
})
|
|
10088
|
+
]
|
|
10089
|
+
});
|
|
10090
|
+
}
|
|
10091
|
+
/** 移动 / 删除两个按钮:动作卡与分支卡共用。 */
|
|
10092
|
+
function NodeActions(props) {
|
|
10093
|
+
const { t } = props;
|
|
10094
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
10095
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(HintTooltip, {
|
|
10096
|
+
label: t("rules.moveUp", { id: props.id }),
|
|
10097
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
10098
|
+
shape: "pill",
|
|
10099
|
+
variant: "outline",
|
|
10100
|
+
icon: true,
|
|
10101
|
+
"aria-label": t("rules.moveUp", { id: props.id }),
|
|
10102
|
+
disabled: props.disabled || props.index === 0,
|
|
10103
|
+
onClick: () => props.onMove(-1),
|
|
10104
|
+
children: "↑"
|
|
10105
|
+
})
|
|
10106
|
+
}),
|
|
10107
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(HintTooltip, {
|
|
10108
|
+
label: t("rules.moveDown", { id: props.id }),
|
|
10109
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
10110
|
+
shape: "pill",
|
|
10111
|
+
variant: "outline",
|
|
10112
|
+
icon: true,
|
|
10113
|
+
"aria-label": t("rules.moveDown", { id: props.id }),
|
|
10114
|
+
disabled: props.disabled || props.index === props.total - 1,
|
|
10115
|
+
onClick: () => props.onMove(1),
|
|
10116
|
+
children: "↓"
|
|
10117
|
+
})
|
|
10118
|
+
}),
|
|
10119
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CloseButton, {
|
|
10120
|
+
label: t("rules.steps.remove", { id: props.id }),
|
|
10121
|
+
disabled: props.disabled,
|
|
10122
|
+
onClick: props.onRemove
|
|
10123
|
+
})
|
|
10124
|
+
] });
|
|
10125
|
+
}
|
|
10126
|
+
const rowKey = (context, path) => `${context.prefix}:${path}`;
|
|
10127
|
+
const rowOpen = (context, path) => context.expanded.get(rowKey(context, path)) === true;
|
|
10128
|
+
function toggleRow(context, path) {
|
|
10129
|
+
context.expanded.set(rowKey(context, path), !rowOpen(context, path));
|
|
10130
|
+
context.onDraft();
|
|
10131
|
+
}
|
|
10132
|
+
/** 叶子动作卡:卡头是动作摘要,展开是该动作的全部字段。 */
|
|
10133
|
+
function ActionCard(props) {
|
|
10134
|
+
const { context, action } = props;
|
|
10135
|
+
const { t } = context;
|
|
10136
|
+
const entry = context.meta.actions.find((item) => item.kind === action.kind);
|
|
10137
|
+
const fieldKey = `${props.path}:${action.id}`;
|
|
10138
|
+
const config = asTriggerRecord(action.config), params = asTriggerRecord(config.params);
|
|
10139
|
+
const layer = String(config.layer ?? "pre-step"), policy = context.engineMeta.layerFieldPolicies[layer];
|
|
10140
|
+
const staticAudience = layer === "system-section" && (params.complete === true || params.suppressRuntimeContext === true);
|
|
10141
|
+
const example = action.kind === "request-params" ? {
|
|
10142
|
+
...entry?.example,
|
|
10143
|
+
patch: {
|
|
10144
|
+
provider: "",
|
|
10145
|
+
model: "",
|
|
10146
|
+
reasoningEffort: "",
|
|
10147
|
+
temperature: void 0,
|
|
10148
|
+
maxTokens: void 0
|
|
10149
|
+
}
|
|
10150
|
+
} : action.kind === "inject-text" ? {
|
|
10151
|
+
...entry?.example,
|
|
10152
|
+
config: {
|
|
10153
|
+
strategy: "static",
|
|
10154
|
+
configKind: "ordered",
|
|
10155
|
+
...policy?.merge ? { mergeMode: "separate" } : {},
|
|
10156
|
+
...policy?.position ? { position: "after-user" } : {},
|
|
10157
|
+
...staticAudience ? { audience: "" } : {},
|
|
10158
|
+
...asTriggerRecord(entry?.example.config)
|
|
10159
|
+
}
|
|
10160
|
+
} : entry?.example;
|
|
10161
|
+
const chainLabel = props.chain.length > 0 ? conditionChain(t, props.chain) : void 0;
|
|
10162
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StepCard, {
|
|
10163
|
+
kind: "action",
|
|
10164
|
+
kindLabel: triggerLabel(t, String(action.kind)),
|
|
10165
|
+
summary: actionSummary(t, action),
|
|
10166
|
+
hint: chainLabel,
|
|
10167
|
+
level: 2,
|
|
10168
|
+
open: rowOpen(context, props.path),
|
|
10169
|
+
onToggle: () => toggleRow(context, props.path),
|
|
10170
|
+
actions: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NodeActions, {
|
|
10171
|
+
t,
|
|
10172
|
+
id: action.id,
|
|
10173
|
+
index: props.index,
|
|
10174
|
+
total: props.total,
|
|
10175
|
+
disabled: context.disabled,
|
|
10176
|
+
onMove: props.onMove,
|
|
10177
|
+
onRemove: props.onRemove
|
|
10178
|
+
}),
|
|
10179
|
+
children: entry === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10180
|
+
role: "note",
|
|
10181
|
+
children: t("rules.unknown")
|
|
10182
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TriggerJsonField, {
|
|
10183
|
+
...context,
|
|
10184
|
+
label: t("rules.rawAction"),
|
|
10185
|
+
shape: "object",
|
|
10186
|
+
value: action,
|
|
10187
|
+
fieldKey,
|
|
10188
|
+
onChange: (next) => props.onChange(asTriggerRecord(next))
|
|
10189
|
+
})] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10190
|
+
className: rules_module_css_default.row,
|
|
10191
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MenuSelect, {
|
|
10192
|
+
compact: true,
|
|
10193
|
+
ariaLabel: t("triggers.actionType"),
|
|
10194
|
+
value: action.kind,
|
|
10195
|
+
disabled: context.disabled,
|
|
10196
|
+
options: (props.scopeConditional ? context.meta.actions.filter((item) => item.supportsWhen) : context.meta.actions).map((item) => ({
|
|
10197
|
+
value: item.kind,
|
|
10198
|
+
label: triggerLabel(t, item.kind)
|
|
10199
|
+
})),
|
|
10200
|
+
onChange: (kind) => {
|
|
10201
|
+
const next = context.meta.actions.find((item) => item.kind === kind);
|
|
10202
|
+
if (next === void 0) return;
|
|
10203
|
+
cleared(context.fields, fieldKey);
|
|
10204
|
+
props.onChange({
|
|
10205
|
+
...structuredClone(next.example),
|
|
10206
|
+
id: action.id,
|
|
10207
|
+
kind
|
|
10208
|
+
});
|
|
9827
10209
|
}
|
|
9828
|
-
}
|
|
9829
|
-
|
|
9830
|
-
|
|
9831
|
-
|
|
9832
|
-
|
|
9833
|
-
|
|
9834
|
-
|
|
9835
|
-
|
|
9836
|
-
|
|
9837
|
-
|
|
9838
|
-
|
|
9839
|
-
|
|
9840
|
-
|
|
9841
|
-
|
|
9842
|
-
|
|
9843
|
-
|
|
9844
|
-
|
|
9845
|
-
|
|
9846
|
-
|
|
9847
|
-
|
|
9848
|
-
|
|
9849
|
-
|
|
9850
|
-
|
|
9851
|
-
|
|
9852
|
-
|
|
9853
|
-
|
|
9854
|
-
|
|
9855
|
-
|
|
9856
|
-
|
|
9857
|
-
|
|
9858
|
-
|
|
9859
|
-
|
|
9860
|
-
|
|
9861
|
-
|
|
9862
|
-
|
|
9863
|
-
|
|
9864
|
-
|
|
9865
|
-
|
|
9866
|
-
|
|
9867
|
-
|
|
9868
|
-
|
|
9869
|
-
|
|
9870
|
-
|
|
9871
|
-
|
|
9872
|
-
|
|
9873
|
-
|
|
9874
|
-
|
|
9875
|
-
|
|
9876
|
-
|
|
9877
|
-
|
|
9878
|
-
|
|
9879
|
-
|
|
9880
|
-
|
|
9881
|
-
|
|
9882
|
-
|
|
9883
|
-
|
|
9884
|
-
|
|
9885
|
-
|
|
9886
|
-
|
|
9887
|
-
|
|
9888
|
-
|
|
9889
|
-
|
|
9890
|
-
|
|
9891
|
-
|
|
9892
|
-
|
|
9893
|
-
|
|
9894
|
-
|
|
10210
|
+
})
|
|
10211
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10212
|
+
className: rules_module_css_default.fields,
|
|
10213
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RuleParameterFields, {
|
|
10214
|
+
...context,
|
|
10215
|
+
fieldKey,
|
|
10216
|
+
value: action,
|
|
10217
|
+
requestPatch: action.kind === "request-params",
|
|
10218
|
+
example,
|
|
10219
|
+
omit: [
|
|
10220
|
+
"id",
|
|
10221
|
+
"kind",
|
|
10222
|
+
...action.kind === "request-params" ? ["audience", "modelScope"] : []
|
|
10223
|
+
],
|
|
10224
|
+
configOmit: action.kind === "inject-text" ? [
|
|
10225
|
+
"modelScope",
|
|
10226
|
+
"promotion",
|
|
10227
|
+
"subject",
|
|
10228
|
+
"match",
|
|
10229
|
+
...staticAudience ? [] : ["audience"]
|
|
10230
|
+
] : void 0,
|
|
10231
|
+
onChange: (next) => props.onChange({
|
|
10232
|
+
...next,
|
|
10233
|
+
id: action.id,
|
|
10234
|
+
kind: String(next.kind ?? action.kind)
|
|
10235
|
+
})
|
|
10236
|
+
})
|
|
10237
|
+
})] })
|
|
10238
|
+
});
|
|
10239
|
+
}
|
|
10240
|
+
/** 分支卡:卡头即「当 ⟨条件⟩ → ⟨动作⟩」,卡内是本层条件 + 它的 then / else 动作。 */
|
|
10241
|
+
function BranchCard(props) {
|
|
10242
|
+
const { context, branch } = props;
|
|
10243
|
+
const { t } = context;
|
|
10244
|
+
const branchChain = [...props.chain, ...branch.if === void 0 ? [] : [branch.if]];
|
|
10245
|
+
const elseChain = [...props.chain, ...branch.if === void 0 ? [] : [{ not: branch.if }]];
|
|
10246
|
+
const patch = (next) => props.onChange({
|
|
10247
|
+
...branch,
|
|
10248
|
+
...next
|
|
10249
|
+
});
|
|
10250
|
+
const ordinal = String(props.index + 1);
|
|
10251
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(StepCard, {
|
|
10252
|
+
kind: "branch",
|
|
10253
|
+
kindLabel: t("rules.steps.branchLabel"),
|
|
10254
|
+
summary: branchSummary(t, branch),
|
|
10255
|
+
hint: conditionChain(t, branchChain),
|
|
10256
|
+
level: 1,
|
|
10257
|
+
open: rowOpen(context, props.path),
|
|
10258
|
+
onToggle: () => toggleRow(context, props.path),
|
|
10259
|
+
actions: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NodeActions, {
|
|
10260
|
+
t,
|
|
10261
|
+
id: ordinal,
|
|
10262
|
+
index: props.index,
|
|
10263
|
+
total: props.total,
|
|
10264
|
+
disabled: context.disabled,
|
|
10265
|
+
onMove: props.onMove,
|
|
10266
|
+
onRemove: props.onRemove
|
|
10267
|
+
}),
|
|
10268
|
+
children: [
|
|
10269
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(RuleConditionFields, {
|
|
10270
|
+
...context,
|
|
10271
|
+
fieldKey: `${props.path}:if`,
|
|
10272
|
+
meta: context.meta,
|
|
10273
|
+
value: branch.if,
|
|
10274
|
+
onChange: (condition) => patch({ if: condition })
|
|
10275
|
+
}),
|
|
10276
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10277
|
+
className: rules_module_css_default.stepSlot,
|
|
10278
|
+
children: t("rules.steps.then")
|
|
10279
|
+
}),
|
|
10280
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10281
|
+
className: rules_module_css_default.stepScope,
|
|
10282
|
+
"data-step-scope": "then",
|
|
10283
|
+
children: props.renderList(nodeList(branch.then), `${props.path}:then`, branchChain, true, (nodes) => patch({ then: nodes }))
|
|
10284
|
+
}),
|
|
10285
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10286
|
+
className: rules_module_css_default.stepSlot,
|
|
10287
|
+
children: t("rules.steps.else")
|
|
10288
|
+
}),
|
|
10289
|
+
branch.else === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10290
|
+
className: rules_module_css_default.stepAdd,
|
|
10291
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
10292
|
+
shape: "pill",
|
|
10293
|
+
variant: "outline",
|
|
10294
|
+
disabled: context.disabled,
|
|
10295
|
+
onClick: () => patch({ else: [] }),
|
|
10296
|
+
children: t("rules.steps.addElse")
|
|
10297
|
+
})
|
|
10298
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10299
|
+
className: rules_module_css_default.stepScope,
|
|
10300
|
+
"data-step-scope": "else",
|
|
10301
|
+
children: props.renderList(nodeList(branch.else), `${props.path}:else`, elseChain, true, (nodes) => patch({ else: nodes }))
|
|
10302
|
+
})
|
|
10303
|
+
]
|
|
10304
|
+
});
|
|
10305
|
+
}
|
|
10306
|
+
/**
|
|
10307
|
+
* 规则卡的条件/动作编辑面:一个条件作用域一张卡,卡内是它对应的动作。
|
|
10308
|
+
* 添加沿用「选择后添加」的 tag 式交互;`then` 里的分支节点在这里成为一等公民。
|
|
10309
|
+
*/
|
|
10310
|
+
function RuleStepsPanel(props) {
|
|
10311
|
+
const { t, rule, meta } = props;
|
|
10312
|
+
const [addActionKind, setAddActionKind] = (0, react.useState)("inject-text");
|
|
10313
|
+
const [addConditionKind, setAddConditionKind] = (0, react.useState)("");
|
|
10314
|
+
const disabled = props.disabled === true;
|
|
10315
|
+
const then = nodeList(rule.then), otherwise = nodeList(rule.else);
|
|
10316
|
+
const usedIds = collectActionIds([...then, ...otherwise]);
|
|
10317
|
+
const conditional = rule.if !== void 0;
|
|
10318
|
+
const branchAllowed = !REGISTRATION_LAYERS.includes(rule.layer ?? "pre-step");
|
|
10319
|
+
const context = {
|
|
10320
|
+
t,
|
|
10321
|
+
meta,
|
|
10322
|
+
engineMeta: props.engineMeta,
|
|
10323
|
+
fields: props.fields,
|
|
10324
|
+
expanded: props.expanded,
|
|
10325
|
+
prefix: props.prefix,
|
|
10326
|
+
disabled,
|
|
10327
|
+
onDraft: props.onDraft
|
|
10328
|
+
};
|
|
10329
|
+
const patch = (next) => {
|
|
10330
|
+
if (!disabled) props.onChange({
|
|
10331
|
+
...rule,
|
|
10332
|
+
...next
|
|
10333
|
+
});
|
|
10334
|
+
};
|
|
10335
|
+
const setNodes = (next) => patch({ then: next });
|
|
10336
|
+
const nextActionId = () => {
|
|
10337
|
+
let number = 1;
|
|
10338
|
+
while (usedIds.has(`action-${number}`)) number++;
|
|
10339
|
+
return `action-${number}`;
|
|
10340
|
+
};
|
|
10341
|
+
const actionSelectable = (scopeConditional) => scopeConditional ? meta.actions.filter((action) => action.supportsWhen) : meta.actions;
|
|
10342
|
+
/** 列表渲染器:动作卡与分支卡递归共用(分支内可再嵌分支)。 */
|
|
10343
|
+
const renderList = (nodes, path, chain, scopeConditional, onChange) => {
|
|
10344
|
+
const setAt = (index, next) => onChange(nodes.map((node, at) => at === index ? next : node));
|
|
10345
|
+
const move = (index, offset) => {
|
|
10346
|
+
const next = [...nodes], target = index + offset;
|
|
10347
|
+
if (target < 0 || target >= next.length) return;
|
|
10348
|
+
[next[index], next[target]] = [next[target], next[index]];
|
|
10349
|
+
onChange(next);
|
|
10350
|
+
};
|
|
10351
|
+
const candidates = actionSelectable(scopeConditional);
|
|
10352
|
+
const selected = candidates.find((action) => action.kind === addActionKind) ?? candidates[0];
|
|
10353
|
+
const addAction = () => {
|
|
10354
|
+
if (selected !== void 0) onChange([...nodes, {
|
|
10355
|
+
...structuredClone(selected.example),
|
|
10356
|
+
id: nextActionId(),
|
|
10357
|
+
kind: selected.kind
|
|
10358
|
+
}]);
|
|
10359
|
+
};
|
|
10360
|
+
const addBranch = () => {
|
|
10361
|
+
const predicate = meta.predicates.find((item) => item.kind === addConditionKind) ?? meta.predicates.find((item) => !meta.composites.includes(item.kind));
|
|
10362
|
+
const action = actionSelectable(true).find((item) => item.kind === addActionKind) ?? actionSelectable(true)[0];
|
|
10363
|
+
if (predicate === void 0 || action === void 0) return;
|
|
10364
|
+
onChange([...nodes, {
|
|
10365
|
+
if: structuredClone(predicate.example),
|
|
10366
|
+
then: [{
|
|
10367
|
+
...structuredClone(action.example),
|
|
10368
|
+
id: nextActionId(),
|
|
10369
|
+
kind: action.kind
|
|
10370
|
+
}]
|
|
10371
|
+
}]);
|
|
10372
|
+
};
|
|
10373
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [nodes.map((node, index) => {
|
|
10374
|
+
const nodePath = `${path}:${index}`;
|
|
10375
|
+
if (isActionNode(node)) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActionCard, {
|
|
10376
|
+
context,
|
|
10377
|
+
action: node,
|
|
10378
|
+
path: nodePath,
|
|
10379
|
+
chain,
|
|
10380
|
+
scopeConditional,
|
|
10381
|
+
index,
|
|
10382
|
+
total: nodes.length,
|
|
10383
|
+
onMove: (offset) => move(index, offset),
|
|
10384
|
+
onRemove: () => {
|
|
10385
|
+
cleared(props.fields, nodePath);
|
|
10386
|
+
onChange(nodes.filter((_, at) => at !== index));
|
|
10387
|
+
},
|
|
10388
|
+
onChange: (next) => setAt(index, next)
|
|
10389
|
+
}, nodePath);
|
|
10390
|
+
if (isBranchNode(node)) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BranchCard, {
|
|
10391
|
+
context,
|
|
10392
|
+
branch: node,
|
|
10393
|
+
path: nodePath,
|
|
10394
|
+
chain,
|
|
10395
|
+
index,
|
|
10396
|
+
total: nodes.length,
|
|
10397
|
+
onMove: (offset) => move(index, offset),
|
|
10398
|
+
onRemove: () => {
|
|
10399
|
+
cleared(props.fields, nodePath);
|
|
10400
|
+
onChange(nodes.filter((_, at) => at !== index));
|
|
10401
|
+
},
|
|
10402
|
+
onChange: (next) => setAt(index, next),
|
|
10403
|
+
renderList
|
|
10404
|
+
}, nodePath);
|
|
10405
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(StepCard, {
|
|
10406
|
+
kind: "unknown",
|
|
10407
|
+
kindLabel: t("rules.steps.unknown"),
|
|
10408
|
+
summary: nodeSummary(t, node),
|
|
10409
|
+
level: 1,
|
|
10410
|
+
open: rowOpen(context, nodePath),
|
|
10411
|
+
onToggle: () => toggleRow(context, nodePath),
|
|
10412
|
+
actions: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NodeActions, {
|
|
10413
|
+
t,
|
|
10414
|
+
id: String(index + 1),
|
|
10415
|
+
index,
|
|
10416
|
+
total: nodes.length,
|
|
10417
|
+
disabled,
|
|
10418
|
+
onMove: (offset) => move(index, offset),
|
|
10419
|
+
onRemove: () => onChange(nodes.filter((_, at) => at !== index))
|
|
10420
|
+
}),
|
|
10421
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9895
10422
|
role: "note",
|
|
9896
10423
|
children: t("rules.unknown")
|
|
9897
10424
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TriggerJsonField, {
|
|
9898
|
-
...
|
|
9899
|
-
fieldKey,
|
|
10425
|
+
...context,
|
|
9900
10426
|
label: t("rules.rawAction"),
|
|
9901
10427
|
shape: "object",
|
|
9902
|
-
value:
|
|
9903
|
-
|
|
9904
|
-
|
|
9905
|
-
className: rules_module_css_default.fields,
|
|
9906
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RuleParameterFields, {
|
|
9907
|
-
...props,
|
|
9908
|
-
fieldKey,
|
|
9909
|
-
value: action,
|
|
9910
|
-
requestPatch: action.kind === "request-params",
|
|
9911
|
-
example,
|
|
9912
|
-
omit: [
|
|
9913
|
-
"id",
|
|
9914
|
-
"kind",
|
|
9915
|
-
...action.kind === "request-params" ? ["audience", "modelScope"] : []
|
|
9916
|
-
],
|
|
9917
|
-
configOmit: action.kind === "inject-text" ? [
|
|
9918
|
-
"modelScope",
|
|
9919
|
-
"promotion",
|
|
9920
|
-
"subject",
|
|
9921
|
-
"match",
|
|
9922
|
-
...staticAudience ? [] : ["audience"]
|
|
9923
|
-
] : void 0,
|
|
9924
|
-
onChange: patch
|
|
9925
|
-
})
|
|
10428
|
+
value: node,
|
|
10429
|
+
fieldKey: nodePath,
|
|
10430
|
+
onChange: (next) => setAt(index, asTriggerRecord(next))
|
|
9926
10431
|
})]
|
|
9927
|
-
},
|
|
10432
|
+
}, nodePath);
|
|
9928
10433
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9929
|
-
className: rules_module_css_default.
|
|
9930
|
-
|
|
9931
|
-
|
|
9932
|
-
|
|
9933
|
-
|
|
9934
|
-
|
|
9935
|
-
|
|
9936
|
-
|
|
9937
|
-
|
|
9938
|
-
|
|
9939
|
-
|
|
9940
|
-
|
|
9941
|
-
|
|
9942
|
-
|
|
9943
|
-
|
|
9944
|
-
|
|
9945
|
-
|
|
9946
|
-
|
|
9947
|
-
|
|
9948
|
-
|
|
9949
|
-
|
|
9950
|
-
|
|
9951
|
-
|
|
9952
|
-
|
|
9953
|
-
|
|
9954
|
-
|
|
9955
|
-
|
|
9956
|
-
|
|
9957
|
-
|
|
10434
|
+
className: rules_module_css_default.stepAdd,
|
|
10435
|
+
"data-step-add": true,
|
|
10436
|
+
children: [
|
|
10437
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MenuSelect, {
|
|
10438
|
+
compact: true,
|
|
10439
|
+
ariaLabel: t("rules.steps.addConditionType"),
|
|
10440
|
+
value: addConditionKind,
|
|
10441
|
+
disabled: disabled || candidates.length === 0,
|
|
10442
|
+
options: [{
|
|
10443
|
+
value: "",
|
|
10444
|
+
label: t("triggers.unconditional")
|
|
10445
|
+
}, ...meta.predicates.map((item) => ({
|
|
10446
|
+
value: item.kind,
|
|
10447
|
+
label: triggerLabel(t, item.kind)
|
|
10448
|
+
}))],
|
|
10449
|
+
onChange: setAddConditionKind
|
|
10450
|
+
}),
|
|
10451
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MenuSelect, {
|
|
10452
|
+
compact: true,
|
|
10453
|
+
ariaLabel: t("rules.steps.addActionType"),
|
|
10454
|
+
value: selected?.kind ?? "",
|
|
10455
|
+
disabled: disabled || candidates.length === 0,
|
|
10456
|
+
options: candidates.map((item) => ({
|
|
10457
|
+
value: item.kind,
|
|
10458
|
+
label: triggerLabel(t, item.kind)
|
|
10459
|
+
})),
|
|
10460
|
+
onChange: setAddActionKind
|
|
10461
|
+
}),
|
|
10462
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
10463
|
+
shape: "pill",
|
|
10464
|
+
variant: "outline",
|
|
10465
|
+
disabled: disabled || !branchAllowed || addConditionKind.length === 0 || candidates.length === 0,
|
|
10466
|
+
onClick: addBranch,
|
|
10467
|
+
children: t("rules.steps.addBranch")
|
|
10468
|
+
}),
|
|
10469
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
10470
|
+
shape: "pill",
|
|
10471
|
+
variant: "outline",
|
|
10472
|
+
disabled: disabled || selected === void 0,
|
|
10473
|
+
onClick: addAction,
|
|
10474
|
+
children: t("rules.addAction")
|
|
10475
|
+
}),
|
|
10476
|
+
!branchAllowed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10477
|
+
className: rules_module_css_default.stepHint,
|
|
10478
|
+
children: t("rules.steps.branchUnsupported")
|
|
10479
|
+
})
|
|
10480
|
+
]
|
|
10481
|
+
})] });
|
|
10482
|
+
};
|
|
10483
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10484
|
+
className: rules_module_css_default.steps,
|
|
10485
|
+
"data-rule-steps": true,
|
|
10486
|
+
children: [
|
|
10487
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StepCard, {
|
|
10488
|
+
kind: "if",
|
|
10489
|
+
kindLabel: t("rules.steps.ifLabel"),
|
|
10490
|
+
summary: conditionSummary(t, rule.if),
|
|
10491
|
+
level: 0,
|
|
10492
|
+
open: rowOpen(context, `${props.fieldKey}:if`),
|
|
10493
|
+
onToggle: () => toggleRow(context, `${props.fieldKey}:if`),
|
|
10494
|
+
actions: rule.if === void 0 ? void 0 : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CloseButton, {
|
|
10495
|
+
label: t("rules.clearCondition"),
|
|
10496
|
+
disabled,
|
|
10497
|
+
onClick: () => patch({ if: void 0 })
|
|
10498
|
+
}),
|
|
10499
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RuleConditionFields, {
|
|
10500
|
+
...context,
|
|
10501
|
+
fieldKey: `${props.fieldKey}:if`,
|
|
10502
|
+
meta,
|
|
10503
|
+
value: rule.if,
|
|
10504
|
+
onChange: (condition) => patch({ if: condition })
|
|
10505
|
+
})
|
|
10506
|
+
}),
|
|
10507
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10508
|
+
className: rules_module_css_default.stepScope,
|
|
10509
|
+
"data-step-scope": "then",
|
|
10510
|
+
children: renderList(then, `${props.fieldKey}:then`, rule.if === void 0 ? [] : [rule.if], conditional, setNodes)
|
|
10511
|
+
}),
|
|
10512
|
+
rule.else === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10513
|
+
className: rules_module_css_default.stepAdd,
|
|
10514
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
10515
|
+
shape: "pill",
|
|
10516
|
+
variant: "outline",
|
|
10517
|
+
disabled,
|
|
10518
|
+
onClick: () => patch({ else: [] }),
|
|
10519
|
+
children: t("rules.steps.addElse")
|
|
10520
|
+
})
|
|
10521
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10522
|
+
className: rules_module_css_default.stepScope,
|
|
10523
|
+
"data-step-scope": "else",
|
|
10524
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScopeHead, {
|
|
10525
|
+
kindLabel: t("rules.steps.elseLabel"),
|
|
10526
|
+
summary: t("rules.steps.actionCount", { count: otherwise.length }),
|
|
10527
|
+
disabled,
|
|
10528
|
+
removeLabel: t("rules.steps.removeElse"),
|
|
10529
|
+
onRemove: () => patch({ else: void 0 })
|
|
10530
|
+
}), renderList(otherwise, `${props.fieldKey}:else`, rule.if === void 0 ? [] : [{ not: rule.if }], rule.if !== void 0, (nodes) => patch({ else: nodes }))]
|
|
10531
|
+
})
|
|
10532
|
+
]
|
|
9958
10533
|
});
|
|
9959
10534
|
}
|
|
9960
10535
|
//#endregion
|
|
@@ -9964,7 +10539,17 @@ window.__ModuleLoader__.load({
|
|
|
9964
10539
|
const panelId = (0, react.useId)(), ownsFocus = (0, react.useRef)(false);
|
|
9965
10540
|
const [confirming, setConfirming] = (0, react.useState)(false);
|
|
9966
10541
|
const disabled = props.disabled === true || draft.busy === "save";
|
|
9967
|
-
const
|
|
10542
|
+
const nodes = [...nodeList(rule.then), ...nodeList(rule.else)];
|
|
10543
|
+
const unsupported = conditionalActions(nodes, rule.if !== void 0).some((action) => draft.meta?.actions.find((item) => item.kind === action.kind)?.supportsWhen === false);
|
|
10544
|
+
const totals = countNodes(nodes);
|
|
10545
|
+
const summary = totals.branches === 0 ? t("rules.summary", {
|
|
10546
|
+
conditions: countConditions(rule.if),
|
|
10547
|
+
actions: totals.actions
|
|
10548
|
+
}) : t("rules.summary.branches", {
|
|
10549
|
+
conditions: countConditions(rule.if),
|
|
10550
|
+
actions: totals.actions,
|
|
10551
|
+
branches: totals.branches
|
|
10552
|
+
});
|
|
9968
10553
|
const patch = (next) => {
|
|
9969
10554
|
if (!disabled) editor.patch(entry.key, {
|
|
9970
10555
|
...entry.value,
|
|
@@ -9984,7 +10569,7 @@ window.__ModuleLoader__.load({
|
|
|
9984
10569
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(CollapsibleCard, {
|
|
9985
10570
|
id: panelId,
|
|
9986
10571
|
title: rule.name || rule.id,
|
|
9987
|
-
meta: (props.source ? t("rules.source", { module: props.source }) + " · " : "") + (rule.layer === void 0 ? t("rules.module") : translateLabel(t, LAYER_LABEL_KEYS, rule.layer)) + " · " +
|
|
10572
|
+
meta: (props.source ? t("rules.source", { module: props.source }) + " · " : "") + (rule.layer === void 0 ? t("rules.module") : translateLabel(t, LAYER_LABEL_KEYS, rule.layer)) + " · " + summary,
|
|
9988
10573
|
expanded: props.expanded,
|
|
9989
10574
|
onToggle: () => {
|
|
9990
10575
|
if (props.expanded) save();
|
|
@@ -10100,56 +10685,45 @@ window.__ModuleLoader__.load({
|
|
|
10100
10685
|
"aria-label": t("rules.settings"),
|
|
10101
10686
|
children: props.renderSettings?.(rule)
|
|
10102
10687
|
}) : void 0,
|
|
10103
|
-
children: [
|
|
10104
|
-
|
|
10105
|
-
|
|
10106
|
-
|
|
10107
|
-
|
|
10108
|
-
|
|
10109
|
-
|
|
10110
|
-
|
|
10111
|
-
|
|
10112
|
-
|
|
10113
|
-
|
|
10114
|
-
|
|
10115
|
-
|
|
10116
|
-
|
|
10117
|
-
|
|
10118
|
-
|
|
10119
|
-
|
|
10120
|
-
|
|
10121
|
-
|
|
10122
|
-
|
|
10123
|
-
|
|
10124
|
-
|
|
10125
|
-
|
|
10126
|
-
|
|
10127
|
-
|
|
10128
|
-
|
|
10129
|
-
|
|
10130
|
-
|
|
10131
|
-
|
|
10132
|
-
|
|
10133
|
-
|
|
10134
|
-
|
|
10135
|
-
|
|
10136
|
-
fieldKey: entry.key + ":full",
|
|
10137
|
-
label: t("triggers.advanced"),
|
|
10138
|
-
shape: "object",
|
|
10139
|
-
value: rule,
|
|
10140
|
-
onChange: (value) => {
|
|
10141
|
-
const candidate = asTriggerRecord(value);
|
|
10142
|
-
if (typeof candidate.id !== "string" || !Array.isArray(candidate.then) || candidate.then.some((action) => typeof asTriggerRecord(action).id !== "string" || typeof asTriggerRecord(action).kind !== "string")) {
|
|
10143
|
-
const raw = draft.fields.get(entry.key + ":full");
|
|
10144
|
-
if (raw) raw.error = t("triggers.invalidJson");
|
|
10145
|
-
return;
|
|
10146
|
-
}
|
|
10147
|
-
for (const key of draft.fields.keys()) if (key.startsWith(entry.key + ":") && key !== entry.key + ":full") draft.fields.delete(key);
|
|
10148
|
-
editor.patch(entry.key, candidate);
|
|
10688
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
|
|
10689
|
+
"data-config-panel": "rule",
|
|
10690
|
+
"aria-label": t("rules.stepsTab"),
|
|
10691
|
+
className: rules_module_css_default.section,
|
|
10692
|
+
children: draft.meta && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RuleStepsPanel, {
|
|
10693
|
+
t,
|
|
10694
|
+
rule,
|
|
10695
|
+
meta: draft.meta,
|
|
10696
|
+
engineMeta: props.meta,
|
|
10697
|
+
fields: draft.fields,
|
|
10698
|
+
expanded: props.expandedRows,
|
|
10699
|
+
prefix: props.source ?? rule.id,
|
|
10700
|
+
fieldKey: entry.key,
|
|
10701
|
+
disabled,
|
|
10702
|
+
onDraft: editor.changed,
|
|
10703
|
+
onChange: (next) => patch(next)
|
|
10704
|
+
})
|
|
10705
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
|
|
10706
|
+
"data-config-panel": "definition",
|
|
10707
|
+
"aria-label": t("rules.jsonTab"),
|
|
10708
|
+
className: rules_module_css_default.section,
|
|
10709
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TriggerJsonField, {
|
|
10710
|
+
...fieldContext,
|
|
10711
|
+
fieldKey: entry.key + ":full",
|
|
10712
|
+
label: t("triggers.advanced"),
|
|
10713
|
+
shape: "object",
|
|
10714
|
+
value: rule,
|
|
10715
|
+
onChange: (value) => {
|
|
10716
|
+
const candidate = asTriggerRecord(value);
|
|
10717
|
+
if (typeof candidate.id !== "string" || !Array.isArray(candidate.then) || !candidate.then.every(isValidNode) || candidate.else !== void 0 && !nodeList(candidate.else).every(isValidNode)) {
|
|
10718
|
+
const raw = draft.fields.get(entry.key + ":full");
|
|
10719
|
+
if (raw) raw.error = t("triggers.invalidJson");
|
|
10720
|
+
return;
|
|
10149
10721
|
}
|
|
10150
|
-
|
|
10722
|
+
for (const key of draft.fields.keys()) if (key.startsWith(entry.key + ":") && key !== entry.key + ":full") draft.fields.delete(key);
|
|
10723
|
+
editor.patch(entry.key, candidate);
|
|
10724
|
+
}
|
|
10151
10725
|
})
|
|
10152
|
-
]
|
|
10726
|
+
})]
|
|
10153
10727
|
}),
|
|
10154
10728
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10155
10729
|
className: rules_module_css_default.row,
|
|
@@ -10519,6 +11093,7 @@ window.__ModuleLoader__.load({
|
|
|
10519
11093
|
expanded: expanded === key,
|
|
10520
11094
|
onToggle: () => toggle(key),
|
|
10521
11095
|
onDuplicate: () => duplicate(row, entry.value),
|
|
11096
|
+
expandedRows: store.editorDrafts.expanded,
|
|
10522
11097
|
headerActions: orderEntry && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10523
11098
|
type: "button",
|
|
10524
11099
|
className: controls_module_css_default.dragHandle,
|
|
@@ -16397,7 +16972,35 @@ window.__ModuleLoader__.load({
|
|
|
16397
16972
|
"rules.rawAction": "动作 JSON",
|
|
16398
16973
|
"rules.settings": "本层共享设置",
|
|
16399
16974
|
"rules.expand": "展开 {name}",
|
|
16400
|
-
"rules.collapse": "收起 {name}"
|
|
16975
|
+
"rules.collapse": "收起 {name}",
|
|
16976
|
+
"rules.stepsTab": "规则",
|
|
16977
|
+
"rules.summary": "{conditions} 条件 · {actions} 动作",
|
|
16978
|
+
"rules.summary.branches": "{conditions} 条件 · {actions} 动作 · {branches} 分支",
|
|
16979
|
+
"rules.steps.ifLabel": "当",
|
|
16980
|
+
"rules.steps.then": "则",
|
|
16981
|
+
"rules.steps.else": "否则",
|
|
16982
|
+
"rules.steps.branchLabel": "分支",
|
|
16983
|
+
"rules.steps.elseLabel": "否则",
|
|
16984
|
+
"rules.steps.addBranch": "添加条件分支",
|
|
16985
|
+
"rules.steps.addElse": "添加否则分支",
|
|
16986
|
+
"rules.steps.addConditionType": "条件类型",
|
|
16987
|
+
"rules.steps.addActionType": "动作类型",
|
|
16988
|
+
"rules.steps.remove": "删除 {id}",
|
|
16989
|
+
"rules.steps.removeElse": "删除否则分支",
|
|
16990
|
+
"rules.steps.branch": "当 {condition} → {actions}",
|
|
16991
|
+
"rules.steps.actionCount": "{count} 个动作",
|
|
16992
|
+
"rules.steps.condition": "{kind}:{detail}",
|
|
16993
|
+
"rules.steps.complex": "{count} 项条件",
|
|
16994
|
+
"rules.steps.unknown": "无法识别的节点",
|
|
16995
|
+
"rules.steps.not": "非({value})",
|
|
16996
|
+
"rules.steps.and": "且",
|
|
16997
|
+
"rules.steps.or": "或",
|
|
16998
|
+
"rules.steps.more": "{head} 等 {count} 项",
|
|
16999
|
+
"rules.steps.listSeparator": "、",
|
|
17000
|
+
"rules.steps.yes": "是",
|
|
17001
|
+
"rules.steps.no": "否",
|
|
17002
|
+
"rules.steps.chain": "生效条件:{chain}",
|
|
17003
|
+
"rules.steps.branchUnsupported": "该层是注册制层(装配时注册一次),没有逐轮求值时机,不能使用条件分支;请改用 pre-step、subagent、tool-pipeline 或 turn-stop 层。"
|
|
16401
17004
|
};
|
|
16402
17005
|
const RULES_EN = {
|
|
16403
17006
|
"rules.title": "Rules",
|
|
@@ -16450,7 +17053,35 @@ window.__ModuleLoader__.load({
|
|
|
16450
17053
|
"rules.rawAction": "Action JSON",
|
|
16451
17054
|
"rules.settings": "Shared layer settings",
|
|
16452
17055
|
"rules.expand": "Expand {name}",
|
|
16453
|
-
"rules.collapse": "Collapse {name}"
|
|
17056
|
+
"rules.collapse": "Collapse {name}",
|
|
17057
|
+
"rules.stepsTab": "Rule",
|
|
17058
|
+
"rules.summary": "{conditions} conditions · {actions} actions",
|
|
17059
|
+
"rules.summary.branches": "{conditions} conditions · {actions} actions · {branches} branches",
|
|
17060
|
+
"rules.steps.ifLabel": "If",
|
|
17061
|
+
"rules.steps.then": "Then",
|
|
17062
|
+
"rules.steps.else": "Else",
|
|
17063
|
+
"rules.steps.branchLabel": "Branch",
|
|
17064
|
+
"rules.steps.elseLabel": "Else",
|
|
17065
|
+
"rules.steps.addBranch": "Add conditional branch",
|
|
17066
|
+
"rules.steps.addElse": "Add else branch",
|
|
17067
|
+
"rules.steps.addConditionType": "Condition type",
|
|
17068
|
+
"rules.steps.addActionType": "Action type",
|
|
17069
|
+
"rules.steps.remove": "Remove {id}",
|
|
17070
|
+
"rules.steps.removeElse": "Remove else branch",
|
|
17071
|
+
"rules.steps.branch": "If {condition} → {actions}",
|
|
17072
|
+
"rules.steps.actionCount": "{count} actions",
|
|
17073
|
+
"rules.steps.condition": "{kind}: {detail}",
|
|
17074
|
+
"rules.steps.complex": "{count} conditions",
|
|
17075
|
+
"rules.steps.unknown": "Unrecognized node",
|
|
17076
|
+
"rules.steps.not": "not ({value})",
|
|
17077
|
+
"rules.steps.and": "and",
|
|
17078
|
+
"rules.steps.or": "or",
|
|
17079
|
+
"rules.steps.more": "{head} +{count} more",
|
|
17080
|
+
"rules.steps.listSeparator": ", ",
|
|
17081
|
+
"rules.steps.yes": "yes",
|
|
17082
|
+
"rules.steps.no": "no",
|
|
17083
|
+
"rules.steps.chain": "Effective condition: {chain}",
|
|
17084
|
+
"rules.steps.branchUnsupported": "This layer registers once at assembly time and has no per-turn evaluation point, so conditional branches are unavailable here. Use pre-step, subagent, tool-pipeline, or turn-stop instead."
|
|
16454
17085
|
};
|
|
16455
17086
|
//#endregion
|
|
16456
17087
|
//#region src/client/locales.ts
|