@stalfh233/omc-cli 0.0.0-stage → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +304 -3
- package/coverage/m1-coverage-manifest-v1.json +1278 -0
- package/dist/approval-token.js +102 -0
- package/dist/args.js +25 -0
- package/dist/artifacts.js +119 -0
- package/dist/bench/call-face-eval.js +256 -0
- package/dist/bench/context-attribution.js +151 -0
- package/dist/bench/discovery-cost-eval.js +230 -0
- package/dist/bench/driver.js +81 -0
- package/dist/bench/evals.js +236 -0
- package/dist/bench/fake-http-server.js +65 -0
- package/dist/bench/instrument.js +87 -0
- package/dist/bench/intent-face-eval.js +343 -0
- package/dist/bench/run.js +166 -0
- package/dist/bench/scenario.js +343 -0
- package/dist/bench/types.js +76 -0
- package/dist/bi-wire.js +41 -0
- package/dist/bizservice-config.js +581 -0
- package/dist/call.js +153 -0
- package/dist/capability-absences.js +23 -0
- package/dist/capability-overview.js +492 -0
- package/dist/capability-shape.js +154 -0
- package/dist/cli-contract.js +70 -0
- package/dist/cli-output.js +73 -0
- package/dist/cli.js +1418 -0
- package/dist/code-rules.js +69 -0
- package/dist/command-transport.js +155 -0
- package/dist/config-store.js +195 -0
- package/dist/context.js +21 -0
- package/dist/contract-consistency.js +66 -0
- package/dist/contract-resources.js +62 -0
- package/dist/coverage-consistency.js +62 -0
- package/dist/coverage-registry.js +76 -0
- package/dist/coverage.js +130 -0
- package/dist/data-list-filter.js +114 -0
- package/dist/discovery.js +390 -0
- package/dist/endpoints.js +154 -0
- package/dist/environment-policy.js +26 -0
- package/dist/execution-metadata.js +1092 -0
- package/dist/fake/app.js +45 -0
- package/dist/fake/b2-registration.js +594 -0
- package/dist/fake/businessrule.js +242 -0
- package/dist/fake/datarule.js +72 -0
- package/dist/fake/dictionary.js +108 -0
- package/dist/fake/environment.js +30 -0
- package/dist/fake/field.js +167 -0
- package/dist/fake/form.js +101 -0
- package/dist/fake/index.js +121 -0
- package/dist/fake/list-view.js +289 -0
- package/dist/fake/model.js +136 -0
- package/dist/fake/online-js.js +18 -0
- package/dist/fake/report.js +253 -0
- package/dist/fake/routes.js +47 -0
- package/dist/fake/rule-lifecycle.js +37 -0
- package/dist/fake/runtime-data.js +367 -0
- package/dist/fake/state.js +67 -0
- package/dist/fake/workflow.js +364 -0
- package/dist/field-change.js +200 -0
- package/dist/field-families.js +896 -0
- package/dist/form-layout.js +111 -0
- package/dist/form-support.js +821 -0
- package/dist/goal-routes.js +468 -0
- package/dist/governed-execution.js +87 -0
- package/dist/human-summary.js +212 -0
- package/dist/identity.js +62 -0
- package/dist/intent/baseline.js +57 -0
- package/dist/intent/capabilities/bizservice.js +274 -0
- package/dist/intent/capabilities/businessrule.js +493 -0
- package/dist/intent/capabilities/datarule.js +187 -0
- package/dist/intent/capabilities/field.js +545 -0
- package/dist/intent/capabilities/form.js +136 -0
- package/dist/intent/capabilities/index.js +64 -0
- package/dist/intent/capabilities/listview.js +157 -0
- package/dist/intent/capabilities/model.js +100 -0
- package/dist/intent/capabilities/onlinejs.js +108 -0
- package/dist/intent/capabilities/report.js +355 -0
- package/dist/intent/capabilities/workflow.js +458 -0
- package/dist/intent/capability.js +6 -0
- package/dist/intent/cli.js +91 -0
- package/dist/intent/compare.js +56 -0
- package/dist/intent/compiler.js +79 -0
- package/dist/intent/dsl.js +129 -0
- package/dist/intent/plan-file.js +63 -0
- package/dist/intent/readback.js +65 -0
- package/dist/intent/schema.js +158 -0
- package/dist/intent/validation.js +30 -0
- package/dist/intent/yaml.js +315 -0
- package/dist/json-column.js +68 -0
- package/dist/lanes/app-contract.js +95 -0
- package/dist/lanes/app-coverage.js +16 -0
- package/dist/lanes/app.js +174 -0
- package/dist/lanes/apply-changes.js +231 -0
- package/dist/lanes/b2-registration-contract.js +292 -0
- package/dist/lanes/b2-registration-coverage.js +48 -0
- package/dist/lanes/b2-registration.js +1187 -0
- package/dist/lanes/businessrule-contract.js +232 -0
- package/dist/lanes/businessrule-coverage.js +16 -0
- package/dist/lanes/businessrule.js +221 -0
- package/dist/lanes/contract-support.js +65 -0
- package/dist/lanes/coverage-declaration.js +9 -0
- package/dist/lanes/datarule-contract.js +155 -0
- package/dist/lanes/datarule-coverage.js +19 -0
- package/dist/lanes/datarule-protocol.js +308 -0
- package/dist/lanes/datarule.js +818 -0
- package/dist/lanes/dictionary-contract.js +78 -0
- package/dist/lanes/dictionary-coverage.js +24 -0
- package/dist/lanes/dictionary.js +235 -0
- package/dist/lanes/environment-contract.js +70 -0
- package/dist/lanes/environment-coverage.js +14 -0
- package/dist/lanes/environment.js +163 -0
- package/dist/lanes/field-contract.js +223 -0
- package/dist/lanes/field-coverage.js +27 -0
- package/dist/lanes/field.js +374 -0
- package/dist/lanes/form-contract.js +97 -0
- package/dist/lanes/form-coverage.js +16 -0
- package/dist/lanes/form.js +185 -0
- package/dist/lanes/lane-ids.js +34 -0
- package/dist/lanes/list-view-contract.js +175 -0
- package/dist/lanes/list-view-coverage.js +20 -0
- package/dist/lanes/list-view-shapes.js +1207 -0
- package/dist/lanes/list-view.js +578 -0
- package/dist/lanes/meta-contract.js +85 -0
- package/dist/lanes/meta.js +255 -0
- package/dist/lanes/model-contract.js +168 -0
- package/dist/lanes/model-coverage.js +20 -0
- package/dist/lanes/model.js +986 -0
- package/dist/lanes/online-js-contract.js +99 -0
- package/dist/lanes/online-js-coverage.js +28 -0
- package/dist/lanes/online-js.js +127 -0
- package/dist/lanes/report-contract.js +144 -0
- package/dist/lanes/report-coverage.js +21 -0
- package/dist/lanes/report.js +476 -0
- package/dist/lanes/rule-graph.js +1846 -0
- package/dist/lanes/rule-lifecycle-contract.js +92 -0
- package/dist/lanes/rule-lifecycle-coverage.js +20 -0
- package/dist/lanes/rule-lifecycle.js +176 -0
- package/dist/lanes/runtime-data-contract.js +264 -0
- package/dist/lanes/runtime-data-coverage.js +25 -0
- package/dist/lanes/runtime-data.js +1054 -0
- package/dist/lanes/workflow-contract.js +223 -0
- package/dist/lanes/workflow-coverage.js +40 -0
- package/dist/lanes/workflow.js +1813 -0
- package/dist/online-js-layout.js +58 -0
- package/dist/online-js-source.js +276 -0
- package/dist/package-tool.js +51 -0
- package/dist/package.js +73 -0
- package/dist/plan.js +73 -0
- package/dist/read.js +144 -0
- package/dist/redact.js +28 -0
- package/dist/rule-support.js +587 -0
- package/dist/runtime-support.js +134 -0
- package/dist/server.js +92 -0
- package/dist/session-manager.js +30 -0
- package/dist/session.js +149 -0
- package/dist/skills.js +112 -0
- package/dist/support.js +98 -0
- package/dist/tool-types.js +127 -0
- package/dist/tools.js +59 -0
- package/dist/usage-log.js +197 -0
- package/dist/wire.js +287 -0
- package/dist/workflow-support.js +99 -0
- package/dist/write-lease.js +26 -0
- package/dist/write-lock.js +109 -0
- package/dist/write.js +176 -0
- package/dist/zip.js +156 -0
- package/docs/tool-surface-map.md +42 -0
- package/package.json +71 -6
- package/skills/omc-acceptance-criteria.md +47 -0
- package/skills/omc-business-configuration.md +257 -0
- package/skills/omc-capabilities.md +197 -0
- package/skills/omc-capability-scouting.md +55 -0
- package/skills/omc-config-draft-review.md +171 -0
- package/skills/omc-five-piece-flow.md +35 -0
- package/skills/omc-glossary.md +86 -0
- package/skills/omc-refusals.md +110 -0
- package/skills/omc-requirement-analysis.md +161 -0
- package/skills/omc-requirement-vocabulary.md +51 -0
- package/skills/omc-start-here.md +82 -0
- package/skills/omc-tool-selection.md +119 -0
- package/skills/omc-write-hazards.md +87 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { ENDPOINTS } from "../endpoints.js";
|
|
3
|
+
import { executeFormDraftWrite, executeFormPublishWrite, validateHtmlRender } from "../form-support.js";
|
|
4
|
+
import { capabilityArg, environmentArg } from "../args.js";
|
|
5
|
+
import { governedRead } from "../read.js";
|
|
6
|
+
import { writeTool } from "../write.js";
|
|
7
|
+
import { registerPackageTool } from "../package-tool.js";
|
|
8
|
+
import { writeSummary } from "../human-summary.js";
|
|
9
|
+
import { defineTool } from "../tool-types.js";
|
|
10
|
+
import { wireCall } from "../wire.js";
|
|
11
|
+
import { FORM_LANE_CONTRACT } from "./form-contract.js";
|
|
12
|
+
const FORM_LANE = FORM_LANE_CONTRACT.lane;
|
|
13
|
+
const FORM_TOOLS = FORM_LANE_CONTRACT.tools;
|
|
14
|
+
/**
|
|
15
|
+
* The default form slot is named after the model: every observed
|
|
16
|
+
* `configure_form`/`form.draft`/`form.publish` success used sheetCode ===
|
|
17
|
+
* schemaCode, and an agent that omits `sheetCode` is asking for that default
|
|
18
|
+
* slot (bench9: 3 wasted invalid-input calls for the omitted arg). Only the
|
|
19
|
+
* explicit case is a real caller decision; omitting means "the model's default
|
|
20
|
+
* sheet". Multi-sheet models still pass sheetCode explicitly.
|
|
21
|
+
*/
|
|
22
|
+
function resolveSheetCode(schemaCode, sheetCode) {
|
|
23
|
+
return sheetCode ?? schemaCode;
|
|
24
|
+
}
|
|
25
|
+
/** Control codes present in a form attributes JSON face (sorted, stable). */
|
|
26
|
+
function parseControlCodes(face) {
|
|
27
|
+
if (typeof face !== "string")
|
|
28
|
+
return [];
|
|
29
|
+
try {
|
|
30
|
+
const parsed = JSON.parse(face);
|
|
31
|
+
return Object.keys(parsed).sort();
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export function registerFormLane(tools) {
|
|
38
|
+
tools.push(defineTool({
|
|
39
|
+
name: "form.get",
|
|
40
|
+
layer: "low",
|
|
41
|
+
kind: "read",
|
|
42
|
+
lane: FORM_LANE,
|
|
43
|
+
scope: FORM_TOOLS["form.get"].scope,
|
|
44
|
+
description: FORM_TOOLS["form.get"].description,
|
|
45
|
+
inputSchema: {
|
|
46
|
+
environment: environmentArg,
|
|
47
|
+
schemaCode: z.string().min(1),
|
|
48
|
+
sheetCode: z.string().min(1).optional().describe("表单槽位码;省略时默认 = schemaCode(模型码即默认表单槽位);多表单模型显式传"),
|
|
49
|
+
controls: z
|
|
50
|
+
.union([z.boolean(), z.array(z.string().min(1))])
|
|
51
|
+
.optional()
|
|
52
|
+
.describe("控件定义投影:true = 返回全部控件的 draft/published 定义;字符串数组 = 只返回这些控件码的定义;省略 = 只回控件码清单"),
|
|
53
|
+
full: z.boolean().optional().describe("返回全部六份布局 JSON 原文(大体积)"),
|
|
54
|
+
capability: capabilityArg,
|
|
55
|
+
},
|
|
56
|
+
handler: async (ctx, args, self) => governedRead(ctx, self, args, async (session) => {
|
|
57
|
+
const sheetCode = resolveSheetCode(args.schemaCode, args.sheetCode);
|
|
58
|
+
const sheet = (await wireCall(session, { path: ENDPOINTS.sheetGet, query: { schemaCode: args.schemaCode, sheetCode } })).data;
|
|
59
|
+
if (!sheet)
|
|
60
|
+
return { schemaCode: args.schemaCode, sheetCode, present: false };
|
|
61
|
+
const base = {
|
|
62
|
+
schemaCode: args.schemaCode,
|
|
63
|
+
sheetCode,
|
|
64
|
+
present: true,
|
|
65
|
+
published: sheet.published === true,
|
|
66
|
+
existDraft: sheet.existDraft === true,
|
|
67
|
+
};
|
|
68
|
+
if (args.full === true)
|
|
69
|
+
return {
|
|
70
|
+
...base,
|
|
71
|
+
draftViewJson: sheet.draftViewJson ?? null,
|
|
72
|
+
draftAttributesJson: sheet.draftAttributesJson ?? null,
|
|
73
|
+
draftHtmlJson: sheet.draftHtmlJson ?? null,
|
|
74
|
+
// Ticket 100: real bizsheet columns (BizForm.java:95-100) the
|
|
75
|
+
// designer writes (save → draftActionsJson; publish → both). They
|
|
76
|
+
// were previously dropped by this projection, which is why the
|
|
77
|
+
// 2026-09-14 fwb readback "saw no top-level actions field".
|
|
78
|
+
draftActionsJson: sheet.draftActionsJson ?? null,
|
|
79
|
+
publishedViewJson: sheet.publishedViewJson ?? null,
|
|
80
|
+
publishedAttributesJson: sheet.publishedAttributesJson ?? null,
|
|
81
|
+
publishedHtmlJson: sheet.publishedHtmlJson ?? null,
|
|
82
|
+
publishedActionsJson: sheet.publishedActionsJson ?? null,
|
|
83
|
+
// Ticket 109 — render compatibility: the Online JS panel resolves
|
|
84
|
+
// generateCodeType(e) whose first line is `if(!e||!e.tagName)
|
|
85
|
+
// return ""` and then does o[type].push(...) (54286.fbbb415f.js)
|
|
86
|
+
// — an element missing tagName (or with a non-array attrs) throws
|
|
87
|
+
// TypeError and kills rendering while the data layer stays green.
|
|
88
|
+
// The full readback reports per-face violations instead of a
|
|
89
|
+
// silent "data ok".
|
|
90
|
+
htmlRenderCompat: {
|
|
91
|
+
draft: validateHtmlRender(sheet.draftHtmlJson),
|
|
92
|
+
published: validateHtmlRender(sheet.publishedHtmlJson),
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
const draftControls = parseControlCodes(sheet.draftAttributesJson);
|
|
96
|
+
const publishedControls = parseControlCodes(sheet.publishedAttributesJson);
|
|
97
|
+
// `controls:true` (dogfood R2: the caller sent a boolean and got
|
|
98
|
+
// `controls: Expected array`) means "all controls" — it is the natural
|
|
99
|
+
// shorthand and maps to the full control-code list.
|
|
100
|
+
const wanted = args.controls === true ? [...new Set([...draftControls, ...publishedControls])].sort() : args.controls;
|
|
101
|
+
const pick = (face) => {
|
|
102
|
+
if (!wanted || typeof face !== "string")
|
|
103
|
+
return undefined;
|
|
104
|
+
let parsed;
|
|
105
|
+
try {
|
|
106
|
+
parsed = JSON.parse(face);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
return Object.fromEntries(wanted.filter((code) => code in parsed).map((code) => [code, parsed[code]]));
|
|
112
|
+
};
|
|
113
|
+
return {
|
|
114
|
+
...base,
|
|
115
|
+
draftControlCodes: draftControls,
|
|
116
|
+
publishedControlCodes: publishedControls,
|
|
117
|
+
...(wanted ? { draftControls: pick(sheet.draftAttributesJson), publishedControls: pick(sheet.publishedAttributesJson) } : {}),
|
|
118
|
+
};
|
|
119
|
+
}),
|
|
120
|
+
}));
|
|
121
|
+
writeTool(tools, "form.draft", FORM_LANE, FORM_TOOLS["form.draft"].scope, FORM_TOOLS["form.draft"].description, {
|
|
122
|
+
schemaCode: z.string().min(1),
|
|
123
|
+
sheetCode: z.string().min(1).optional().describe("表单槽位码;省略时默认 = schemaCode(模型码即默认表单槽位)"),
|
|
124
|
+
draftViewJson: z.string().optional(),
|
|
125
|
+
draftAttributesJson: z.string().optional(),
|
|
126
|
+
draftHtmlJson: z.string().optional(),
|
|
127
|
+
fieldCodes: z.array(z.string().min(1)).optional().describe("脚手架绑定的已发布字段(按此顺序);由 configure_form/intent 显式传入"),
|
|
128
|
+
rebuild: z.boolean().optional().describe("true 时丢弃现有草稿布局,按已发布字段重新生成(新增字段/子表要用它;默认保留现有草稿)"),
|
|
129
|
+
allowEmptyLayout: z.boolean().optional().describe("显式放行空布局(\"[]\"/\"{}\")写入;默认拒绝(form-empty-layout),防设计器 Save 清空后照写丢控件"),
|
|
130
|
+
}, async (session, args) => executeFormDraftWrite(session, { ...args, sheetCode: resolveSheetCode(args.schemaCode, args.sheetCode) }));
|
|
131
|
+
writeTool(tools, "form.publish", FORM_LANE, FORM_TOOLS["form.publish"].scope, FORM_TOOLS["form.publish"].description, {
|
|
132
|
+
schemaCode: z.string().min(1),
|
|
133
|
+
sheetCode: z.string().min(1).optional().describe("表单槽位码;省略时默认 = schemaCode(模型码即默认表单槽位)"),
|
|
134
|
+
publishRemarks: z.string().optional(),
|
|
135
|
+
force: z.boolean().optional().describe("强制重新提拔(跳过 already-published 短路);重写草稿后的再发布需要它"),
|
|
136
|
+
allowDegrade: z.boolean().optional().describe("显式放行降级提拔(草稿控件数 < 已发布面);默认拒绝(form-publish-degrade),防把空/残草稿提拔成发布版"),
|
|
137
|
+
}, async (session, args) => executeFormPublishWrite(session, { ...args, sheetCode: resolveSheetCode(args.schemaCode, args.sheetCode) }));
|
|
138
|
+
registerPackageTool(tools, {
|
|
139
|
+
name: "configure_form",
|
|
140
|
+
lane: FORM_LANE,
|
|
141
|
+
scope: FORM_TOOLS["configure_form"].scope,
|
|
142
|
+
description: FORM_TOOLS["configure_form"].description,
|
|
143
|
+
inputSchema: {
|
|
144
|
+
schemaCode: z.string().min(1),
|
|
145
|
+
sheetCode: z.string().min(1).optional().describe("表单槽位码;省略时默认 = schemaCode(模型码即默认表单槽位)"),
|
|
146
|
+
fieldCodes: z
|
|
147
|
+
.array(z.string().min(1))
|
|
148
|
+
.optional()
|
|
149
|
+
.describe("表单要绑定的已发布字段(按此顺序);省略则脚手架绑定全部已发布字段;未知 code 拒绝(form-fieldcodes-unknown)"),
|
|
150
|
+
rebuild: z.boolean().optional().describe("true 时丢弃现有草稿布局,按已发布字段重新生成(新增字段/子表要用它;默认保留现有草稿)"),
|
|
151
|
+
draftHtmlJson: z.string().optional(),
|
|
152
|
+
},
|
|
153
|
+
plan: (args) => ({
|
|
154
|
+
summary: writeSummary("configure_form", args, undefined, "plan"),
|
|
155
|
+
actions: [
|
|
156
|
+
{ tool: "form.draft", args: { schemaCode: args.schemaCode, sheetCode: resolveSheetCode(args.schemaCode, args.sheetCode), ...(args.fieldCodes ? { fieldCodes: args.fieldCodes } : {}), ...(args.rebuild === true ? { rebuild: true } : {}), ...(typeof args.draftHtmlJson === "string" ? { draftHtmlJson: args.draftHtmlJson } : {}) } },
|
|
157
|
+
{ tool: "form.publish", args: { schemaCode: args.schemaCode, sheetCode: resolveSheetCode(args.schemaCode, args.sheetCode) } },
|
|
158
|
+
],
|
|
159
|
+
}),
|
|
160
|
+
execute: async (session, args) => {
|
|
161
|
+
const results = [];
|
|
162
|
+
const sheetCode = resolveSheetCode(args.schemaCode, args.sheetCode);
|
|
163
|
+
// configure_form MUST delegate to the proven form.draft/form.publish
|
|
164
|
+
// paths so the real empty-form scaffold and draftHtmlJson are written;
|
|
165
|
+
// never shortcut with {schemaCode,sheetCode,fieldCodes}-only bodies.
|
|
166
|
+
const draftOutcome = await executeFormDraftWrite(session, {
|
|
167
|
+
schemaCode: args.schemaCode,
|
|
168
|
+
sheetCode,
|
|
169
|
+
...(args.fieldCodes ? { fieldCodes: args.fieldCodes } : {}),
|
|
170
|
+
...(args.rebuild === true ? { rebuild: true } : {}),
|
|
171
|
+
...(typeof args.draftHtmlJson === "string" ? { draftHtmlJson: args.draftHtmlJson } : {}),
|
|
172
|
+
});
|
|
173
|
+
results.push({ step: "form.draft", errcode: draftOutcome.performed.errcode });
|
|
174
|
+
const publishOutcome = await executeFormPublishWrite(session, {
|
|
175
|
+
schemaCode: args.schemaCode,
|
|
176
|
+
sheetCode,
|
|
177
|
+
});
|
|
178
|
+
results.push({ step: "form.publish", errcode: publishOutcome.performed.errcode });
|
|
179
|
+
const published = await wireCall(session, { path: ENDPOINTS.sheetGet, query: { schemaCode: args.schemaCode, sheetCode } });
|
|
180
|
+
return { steps: results, readback: { formPublished: (published.data ?? {}).published === true, publishedHtmlJsonPresent: typeof (published.data ?? {}).publishedHtmlJson === "string" } };
|
|
181
|
+
},
|
|
182
|
+
summarize: (args, _outcome, phase) => writeSummary("configure_form", args, undefined, phase),
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=form.js.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single source of lane identity. Every lane declaration and every tool
|
|
3
|
+
* registration draws its lane from this frozen map, so a lane typo is a
|
|
4
|
+
* compile-time error (`LaneId`) rather than a runtime coverage refusal.
|
|
5
|
+
*
|
|
6
|
+
* The values are the manifest lane strings the M1 coverage ledger already
|
|
7
|
+
* uses; `assertCoverageConsistency()` proves every registered tool's lane is
|
|
8
|
+
* declared, and the manifest generator injects the declared tool/scope sets
|
|
9
|
+
* into the matching manifest items. `meta` is the governance surface (approval
|
|
10
|
+
* / setup / status) that has no coverage declaration and no lane-bound tools.
|
|
11
|
+
*/
|
|
12
|
+
export const LANES = Object.freeze({
|
|
13
|
+
meta: "meta-governance",
|
|
14
|
+
environment: "environment-governance",
|
|
15
|
+
app: "app-management",
|
|
16
|
+
dictionary: "dictionary-management",
|
|
17
|
+
model: "model-management",
|
|
18
|
+
field: "field-families",
|
|
19
|
+
dataRule: "G1-datarule",
|
|
20
|
+
form: "form-publish-chain",
|
|
21
|
+
businessrule: "B1-businessrule",
|
|
22
|
+
ruleLifecycle: "S25-rule-lifecycle",
|
|
23
|
+
runtimeData: "M2-runtime-data",
|
|
24
|
+
workflow: "W7-S29-greenfield",
|
|
25
|
+
onlineJs: "online-js",
|
|
26
|
+
b2: "B2-registration",
|
|
27
|
+
listView: "W1-list-view",
|
|
28
|
+
report: "R1-report",
|
|
29
|
+
});
|
|
30
|
+
export const LANE_IDS = Object.freeze(Object.values(LANES));
|
|
31
|
+
export function isLaneId(value) {
|
|
32
|
+
return LANE_IDS.includes(value);
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=lane-ids.js.map
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { assertDescriptionCarries, assertLaneContract, behaviorBinding, CONTRACT_FAMILY, CONTRACT_REFERENCE_VERSION } from "./contract-support.js";
|
|
2
|
+
import { LANES } from "./lane-ids.js";
|
|
3
|
+
import { mergeActions, PLATFORM_DEFAULT_LIST_ACTIONS } from "./list-view-shapes.js";
|
|
4
|
+
/**
|
|
5
|
+
* W1 list-view design-time wire facts (live-proven). The forced create
|
|
6
|
+
* defaults, the column configuration, and the header-absence readback are the
|
|
7
|
+
* single source for the handler descriptions and the coverage declarations.
|
|
8
|
+
*/
|
|
9
|
+
export const LIST_VIEW_WIRE = Object.freeze({
|
|
10
|
+
createBody: "query/create body {schemaCode, name, code, type:'LIST', showOnPc:false, published:false} (forced design-time defaults)",
|
|
11
|
+
createReadback: "query/get_header readback",
|
|
12
|
+
configureDefault: "code omitted means the default view (code=schemaCode)",
|
|
13
|
+
configureColumns: "query/get then query/update: for each fieldCodes entry, append a missing column as visible, or repair an existing column's name/propertyType/displayFormat/visible in place (never skip an already-present column), then query/get readback; propertyType comes from published field metadata; NUMERICAL displayFormat is derived from the field's 0-based `options.scale` (0=integer,1=1dp,2=2dp,3=3dp…8=8dp) through the platform parseNumber table ({0:1,1:2,2:3,3:11,4:12,23:…, percent 0..:4/5/6/13/14/27..30, currency ¥ 2dp..:7/15/16/31..34} — verified live: scale 2 → displayFormat 3 = 2 decimals) and DATE displayFormat from options.format (1=yyyy-MM-dd,2=datetime,3=minute,4=yyyy-MM); the readback columns array carries {propertyCode,propertyType,displayFormat,visible,sumType} and added/updated name the fieldCodes touched",
|
|
14
|
+
configureSorts: "sorts -> querySorts [{propertyCode,propertyType,direction,sortKey,clientType}]; direction SortDirectionType numeric ASC(1)/DESC(2); omitted leaves the existing sorts untouched, provided replaces them",
|
|
15
|
+
configureConditions: "conditions -> queryConditions [{propertyCode,propertyType,displayType,filterType,defaultValue,options,startValue,endValue,shortcutFilter,choiceType,dateType,accurateSearch,showNull,includeSubData,buildTreeBy,visible}]; filterType is the comparison OPERATOR (QueryFilterType STRING enum: Eq/NotEq/Gt/Lt/Gte/Lte/Like/NotLike/IsNull/IsNotNull/In/NotIn/Between/NotBetween/Of/NotOf/…; omitted → the platform default for the propertyType; aliases operator/op); displayType INPUT(0)/RADIO(1)/CHECKBOX(2)/SELECT(3)/RANGE(4); choiceType SELECT(1)/POPUP(2)/TREE_LEFT(3); options is a JSON string (decoded on readback)",
|
|
16
|
+
configureConditionMap: "queryConditionMap {<schemaCode>: queryConditions[]} is read-derived (query/get with a formCode child-table filter); BizQueryDetailConfig persists queryConditions/querySorts only, so the map is not a configure input",
|
|
17
|
+
configureActions: "actions -> queryActions [{actionCode,name,icon,queryActionType,systemAction,serviceCode,serviceMethod,customService,associationCode,associationType,sortKey}]; queryActionType QueryActionType numeric QUERY(1)/ADD(2)/.../BATCH_SUBMIT(23); associationType QueryActionRelativeType numeric BIZSHEET(0)/WORKFLOW(1); associationCode/associationType are the JSON names of the DTO fields relativeCode/queryActionRelativeType (@JsonProperty); omitted leaves the existing actions untouched, provided MERGES into the effective set by actionCode (live 2026-09-17: query/update replaces-then-re-adds the submitted list, so a merge keeps the platform's built-in 新增/删除/导入/导出 and updates a matching actionCode — replaceActions:true restores the authoritative full set, defaultActions:true re-seeds the platform default set); query/get auto-injects default actions (qr_code/batch_print/batch_update/import_attachment/export_attachment/batch_submit) and query/update resets sortKey to i+1",
|
|
18
|
+
configurePresentation: "presentation -> queryPresentation {clientType,htmlJson,actionsJson,columnsJson,queryViewDataSource,schemaRelations,options}; htmlJson/actionsJson/columnsJson JSON strings are decoded once before render-shape validation (html element tagName+attrs, action actionCode/name/icon, column propertyCode/propertyType); invalid input refuses with listview-presentation-render-invalid before wire and is never double-encoded; clientType is forced to PC by query/update; schemaRelations is platform-derived from the queryColumns tree (resolveRelations) and overwrites your input; a non-empty htmlJson updates the environment record, which query/delete cleans up; omitted leaves the existing presentation untouched (the read-face object must be echoed, because saveBizQueryDetail removes every presentation whose clientType matches before re-adding), provided replaces it",
|
|
19
|
+
configureButtons: "buttons -> customButtons [{code,name,useLocation,bindAction,operateType,showPermCode,showPermType,hint,targetCode,targetObjCode,description,actionConfig}]; actionConfig is fail-closed for rendering: SCRIPT requires scriptData, BUSINESS_RULE/FLOW requires targetCode, ADD_DATA/FORM requires expanded schemaCodeVal/formListData/configureList; invalid input refuses before wire; readback includes buttonsRenderCompat; sent as the query/update body customButtonJson JSON array string; BizButtonFacadeImpl.addBizButtonList(String,...) runs only when customButtonJson is a JSON array, then batchDeleteByTrigger over the schema and its published child-table codes and re-adds (so provided replaces every button under the QUERY trigger, while omitted/absent customButtonJson changes nothing); triggerType is forced to QUERY, triggerCode to the view code, schemaCode backfilled, sortKey reset to the array index; name/code/useLocation/bindAction/operateType are required; bindAction ButtonBindAction name LIST(1)/FORM(2)/ADD_DATA(3)/FLOW(4)/BUSINESS_RULE(5)/SCRIPT(6)/CUSTOM_PAGE(7)/WORKFLOW_CENTER_PAGE(8)/FRONT_EVENT(9)/AGENT(10); useLocation ButtonUseLocation name LIST(1)/FORM(2)/ROW(3); operateType ButtonOperateType name WITH_VIEW(1)/WITH_OUT_VIEW(2); showPermType ButtonShowPermType name BIND_SYS_BUTTON(1)/BIND_BUSINESS_RULE(2)/BIND_FRONT_EVENT_BUTTON(3); duplicate code fails BIZ_QUERY_ACTION_CODE_EXIST; query/get returns customButtons[] (non-admin users are filtered by the permission combination); ModelManagementFacadeImpl.removeBizQuery deletes QUERY buttons for the schema and its child tables on query/delete",
|
|
20
|
+
buttonsActionConfig: "ticket 75: an ADD_DATA/FORM button's model/form target binding lives in actionConfig — schemaCodeVal (target model object {code,id:<app-tree node id>,name,type:'BizModel',appCode,appName,published}) + formListData[] (target forms, sheetType 0 默认表单 only evidenced) + configureList[] (data assignments; isConst is STRING 'true'/'false', operator key is OptionType capital O, only 'Eq' evidenced, constant-value key not evidenced/unimplemented; currentDataItem/targetDataItem are array-wrapped inline field copies) — while targetCode/targetObjCode are measured always-null and NOT consumed for these bind actions (refused as listview-button-target-ineffective; FLOW keeps them); high-level button params targetModel/targetForm/configureList expand into that shape from authoritative readback (app tree node, bizsheet/get, published field rows) and fail closed (listview-button-target-unresolved) before any query/update",
|
|
21
|
+
configureOptions: "options -> the query header BizQueryModel.options String column (h_biz_query.options TEXT), parsed by the platform as BizQueryOption {pagingSetting:{pageSize,showTotal}, listViewModeSetting:{mode,canSwitch}} (8.6.26 defaultOption = pageSize 20 / showTotal true / mode \"spreadsheet\" / canSwitch false); a raw JSON string is sent verbatim, an object is JSON-stringified; rowColorSetting has no 8.6.26 class so the object form refuses unknown keys; BizQueryController.update sets publish=TRUE before updateBizQuery, so after the first configure only the name/options-diff branch (ModelManagementFacadeImpl:1966-1973) persists options: an omitted body key (null) would overwrite a non-null stored value, so omitted must echo the read-face options (the tool spreads query/get) while provided replaces the whole string; BizQueryFacadeImpl.getBizQuery copies options from the entity on readback (no controller parse); BizObjectFacadeImpl.getShowTotal reads pagingSetting.showTotal (so pagingSetting must not be null)",
|
|
22
|
+
configurePresentationType: "presentationType -> the query header BizQueryHeaderModel.queryPresentationType QueryPresentationType enum; sent as the name LIST/BOARD/CALENDAR/GANTT (@JsonValue getIndex() whose index equals the name, @JsonCreator get(String) parses); updateBizQuery always assigns it (:1955, not gated by publish or any diff), so an omitted body key (null) would overwrite a stored type and the tool must echo the read-face value (query/get inherits it via BeanUtils.copyProperties at BizQueryFacadeImpl:346); gantt -> queryGanttModel BizQueryGanttModel {queryId,schemaCode,startTimePropertyCode,endTimePropertyCode,progressPropertyCode,titlePropertyCode,preDependencyPropertyCode,endDependencyPropertyCode,levelPropertyCode,milepostCode,sortKey,configJson,liableManCode,statusCode,defaultPrecision}; saveBizQueryDetail only swaps the gantt when the submitted model is non-null (:178-183), so an omitted gantt leaves the stored one untouched; when presentationType is GANTT the controller requires the gantt with non-null startTimePropertyCode/endTimePropertyCode/titlePropertyCode (validateNotEmptyGantt :1121-1136); updateBizQuery forces levelPropertyCode=parentId for TREE models (:1999-2001) and saveBizQueryDetail backfills queryId (:179-181); addBizQuery allows at most one GANTT view per schema (BIZ_QUERY_GANTT_EXIST :1787)",
|
|
23
|
+
configureLayer: "queryLayer -> BizQueryModel.queryLayer List<BizQueryLayer> (name,layerType,fieldCode,displayField[],layerFieldList[{schemaCode,schemaName,fieldCode,fieldName,displayField[],children[]}]); a real JSON array (not a String column), sent as an array; multiTableHeaderConfig -> BizQueryModel.multiTableHeaderConfig String (HeaderConfig[] JSON {type,name,field,propertyType,children[]} parsed by EasyExcelUtils/DefaultDataIEFileOperateServiceImpl via JSONObject.parseArray); a raw JSON string is sent verbatim, an array is JSON-stringified; saveBizQueryDetail assigns both unconditionally (:184-186, unlike the gantt non-null guard), so an omitted key would overwrite the stored value and the tool must echo the read-face values (BizQueryFacadeImpl.getBizQuery always carries them: queryLayer from the detail config or null, multiTableHeaderConfig from the config or \"\", :283-293/344-345); provided replaces the whole value. NOTE: \"按字段分组\" (field grouping) is NOT a proven capability on this surface — queryLayer is a passthrough (no schema/enum validation) and every real 8.6.26 view read back an empty queryLayer, so layerType semantics/grouping behavior are UNVERIFIED; do not guess-write queryLayer to satisfy a grouping requirement (2026-10-06 sandbox: agent correctly refused to fabricate it).",
|
|
24
|
+
configureNotFound: 302025,
|
|
25
|
+
deleteBody: "query/delete?schemaCode=&code=; query/get_header confirms exact absence",
|
|
26
|
+
});
|
|
27
|
+
const LIST_VIEW_SCOPE = "create list readback header forced defaults delete";
|
|
28
|
+
export const LIST_VIEW_LANE_CONTRACT = Object.freeze({
|
|
29
|
+
lane: LANES.listView,
|
|
30
|
+
family: CONTRACT_FAMILY,
|
|
31
|
+
referenceVersion: CONTRACT_REFERENCE_VERSION,
|
|
32
|
+
endpoints: Object.freeze({
|
|
33
|
+
create: "listQueryCreate",
|
|
34
|
+
get: "listQueryGet",
|
|
35
|
+
update: "listQueryUpdate",
|
|
36
|
+
getHeader: "listQueryGetHeader",
|
|
37
|
+
delete: "listQueryDelete",
|
|
38
|
+
fieldList: "fieldList",
|
|
39
|
+
}),
|
|
40
|
+
wire: Object.freeze({
|
|
41
|
+
createBody: LIST_VIEW_WIRE.createBody,
|
|
42
|
+
createReadback: LIST_VIEW_WIRE.createReadback,
|
|
43
|
+
configureDefault: LIST_VIEW_WIRE.configureDefault,
|
|
44
|
+
configureColumns: LIST_VIEW_WIRE.configureColumns,
|
|
45
|
+
configureSorts: LIST_VIEW_WIRE.configureSorts,
|
|
46
|
+
configureConditions: LIST_VIEW_WIRE.configureConditions,
|
|
47
|
+
configureConditionMap: LIST_VIEW_WIRE.configureConditionMap,
|
|
48
|
+
configureActions: LIST_VIEW_WIRE.configureActions,
|
|
49
|
+
buttonsActionConfig: LIST_VIEW_WIRE.buttonsActionConfig,
|
|
50
|
+
configurePresentation: LIST_VIEW_WIRE.configurePresentation,
|
|
51
|
+
configureButtons: LIST_VIEW_WIRE.configureButtons,
|
|
52
|
+
configureOptions: LIST_VIEW_WIRE.configureOptions,
|
|
53
|
+
configurePresentationType: LIST_VIEW_WIRE.configurePresentationType,
|
|
54
|
+
configureLayer: LIST_VIEW_WIRE.configureLayer,
|
|
55
|
+
configureNotFound: LIST_VIEW_WIRE.configureNotFound,
|
|
56
|
+
deleteBody: LIST_VIEW_WIRE.deleteBody,
|
|
57
|
+
}),
|
|
58
|
+
wireBindings: Object.freeze({
|
|
59
|
+
configureActions: Object.freeze([
|
|
60
|
+
Object.freeze({
|
|
61
|
+
kind: "emitter-constant",
|
|
62
|
+
ref: "lanes/list-view-shapes.PLATFORM_DEFAULT_LIST_ACTIONS",
|
|
63
|
+
verify: () => {
|
|
64
|
+
const codes = PLATFORM_DEFAULT_LIST_ACTIONS.map((action) => action.actionCode);
|
|
65
|
+
for (const required of ["add", "delete", "import", "export", "editowner"]) {
|
|
66
|
+
if (!codes.includes(required))
|
|
67
|
+
throw new Error(`platform default PC LIST action ${required} is missing`);
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
}),
|
|
71
|
+
Object.freeze({
|
|
72
|
+
kind: "emitter-constant",
|
|
73
|
+
ref: "lanes/list-view-shapes.mergeActions",
|
|
74
|
+
verify: () => {
|
|
75
|
+
const merged = mergeActions([{ actionCode: "add" }], [{ actionCode: "custom", name: "自定义" }]);
|
|
76
|
+
if (!merged.some((action) => action.actionCode === "add"))
|
|
77
|
+
throw new Error("mergeActions must preserve an existing action (add)");
|
|
78
|
+
if (!merged.some((action) => action.actionCode === "custom"))
|
|
79
|
+
throw new Error("mergeActions must append an incoming action");
|
|
80
|
+
},
|
|
81
|
+
}),
|
|
82
|
+
Object.freeze({
|
|
83
|
+
kind: "behavior-test",
|
|
84
|
+
ref: "test/list-view-configure.test.ts#listview.configure actions MERGE by default",
|
|
85
|
+
verify: () => {
|
|
86
|
+
const merged = mergeActions([{ actionCode: "add", name: "新增" }], [{ actionCode: "add", name: "覆盖" }]);
|
|
87
|
+
const add = merged.find((action) => action.actionCode === "add");
|
|
88
|
+
if (add?.name !== "覆盖")
|
|
89
|
+
throw new Error("mergeActions must let an incoming actionCode update the existing row in place");
|
|
90
|
+
},
|
|
91
|
+
}),
|
|
92
|
+
]),
|
|
93
|
+
createBody: Object.freeze([behaviorBinding("test/ticket-81-timeout-idempotent-recovery.test.ts#ticket 81: listview.create on a duplicate code", assertListViewContract)]),
|
|
94
|
+
createReadback: Object.freeze([behaviorBinding("test/ticket-81-timeout-idempotent-recovery.test.ts#ticket 81: listview.create on a duplicate code", assertListViewContract)]),
|
|
95
|
+
configureDefault: Object.freeze([behaviorBinding("test/lane-contracts.test.ts#list-view lane contract pins the forced defaults/column config", assertListViewContract)]),
|
|
96
|
+
configureColumns: Object.freeze([behaviorBinding("test/list-view-configure.test.ts#listview.configure repairs an existing column instead of skipping it", assertListViewContract)]),
|
|
97
|
+
configureSorts: Object.freeze([behaviorBinding("test/list-view-configure.test.ts#listview.configure sorts+conditions", assertListViewContract)]),
|
|
98
|
+
configureConditions: Object.freeze([behaviorBinding("test/list-view-configure.test.ts#listview.configure sorts+conditions", assertListViewContract)]),
|
|
99
|
+
configureConditionMap: Object.freeze([behaviorBinding("test/lane-contracts.test.ts#list-view lane contract pins the forced defaults/column config", assertListViewContract)]),
|
|
100
|
+
buttonsActionConfig: Object.freeze([behaviorBinding("test/ticket-75-listview-button-action-config.test.ts#ticket 75: targetModel/targetForm/configureList expand into the authoritative actionConfig shape", assertListViewContract)]),
|
|
101
|
+
configurePresentation: Object.freeze([behaviorBinding("test/list-view-configure.test.ts#listview.configure presentation", assertListViewContract)]),
|
|
102
|
+
configureButtons: Object.freeze([behaviorBinding("test/list-view-configure.test.ts#listview.configure buttons", assertListViewContract)]),
|
|
103
|
+
configureOptions: Object.freeze([behaviorBinding("test/list-view-configure.test.ts#listview.configure options", assertListViewContract)]),
|
|
104
|
+
configurePresentationType: Object.freeze([behaviorBinding("test/list-view-configure.test.ts#listview.configure presentationType+gantt", assertListViewContract)]),
|
|
105
|
+
configureLayer: Object.freeze([behaviorBinding("test/list-view-configure.test.ts#listview.configure queryLayer+multiTableHeaderConfig", assertListViewContract)]),
|
|
106
|
+
configureNotFound: Object.freeze([behaviorBinding("test/lane-contracts.test.ts#list-view lane contract pins the forced defaults/column config", assertListViewContract)]),
|
|
107
|
+
deleteBody: Object.freeze([behaviorBinding("test/write-preflight-governance.test.ts#listview.delete is absent-idempotent", assertListViewContract)]),
|
|
108
|
+
}),
|
|
109
|
+
evidence: Object.freeze([
|
|
110
|
+
".scratch/omc-route-wayfinder/research/list-view-static-scout.md",
|
|
111
|
+
"packages/omc-cli/src/lanes/list-view.ts",
|
|
112
|
+
".scratch/omc-app-management/issues/07-datalist-projection-hint.md",
|
|
113
|
+
]),
|
|
114
|
+
tools: Object.freeze({
|
|
115
|
+
"listview.get": Object.freeze({
|
|
116
|
+
scope: LIST_VIEW_SCOPE,
|
|
117
|
+
description: "读取一个列表视图(query/get,clientType PC)的紧凑清单:present、name、published、presentationType、列(propertyCode/propertyType/displayFormat/visible)、排序、条件数、动作码、按钮数与 options;`code` 省略时用默认视图(=schemaCode,与 listview.configure 同款解析)。`full:true` 返回 query/get 原始报文。本工具只读,不触发写锁;视图不存在返回 present:false(302025 语义)。",
|
|
118
|
+
}),
|
|
119
|
+
"listview.list": Object.freeze({
|
|
120
|
+
scope: LIST_VIEW_SCOPE,
|
|
121
|
+
description: "列出模型下的列表视图(query/list,clientType PC):每个视图的 code/name/type/published。用于在一个模型可能有多视图时先定位 code,再用 listview.get 读单个。只读。",
|
|
122
|
+
}),
|
|
123
|
+
"listview.create": Object.freeze({
|
|
124
|
+
scope: LIST_VIEW_SCOPE,
|
|
125
|
+
description: "创建自定义列表视图(query/create,强制 LIST/showOnPc/unpublished 默认)。**业务展示的默认入口就是自定义视图**:平台在 model.create 时自动生成的默认视图(code = schemaCode,系统自带)**不作为业务展示用**——列别在默认视图上堆、也别带系统字段;按需求建自定义视图(listview.create 命名业务视图),列**只用业务字段**,筛选条件**按需求选少数几个**(不要照搬全部字段/默认条件)。readback 见 get_header。",
|
|
126
|
+
}),
|
|
127
|
+
"listview.configure": Object.freeze({
|
|
128
|
+
scope: LIST_VIEW_SCOPE,
|
|
129
|
+
description: "(**列汇总**:数值列 `sumType` wire 为整数——0=不统计/1=求和/2=平均/3=最小/4=最大/5=计数,写进 presentation.columnsJson 的列对象,8.6.26 反编译 SumType 实证)配置列表视图(code 指向**自定义业务视图**——业务展示用 listview.create 建的自定义视图,**不在系统自动生成的默认视图(code=schemaCode)上配业务列/筛选**;仅当明确要改默认视图时才省略 code)。在既有(默认)列表视图上配置列、排序、查询条件、行/列表按钮、呈现、自定义按钮、视图头扩展选项与视图类型:读回 query,按 `fieldCodes` 追加缺失列或**原地修正**已存在列的 name/propertyType/displayFormat/visible(不再跳过既有列),置为可见;数值列 displayFormat 由字段 0 基 `options.scale` 推导(0=整数,1=1位,2=2位,3=3位…8=8位;实测 scale 2 → displayFormat 3 = 两位小数)、日期列由 `options.format` 推导(1/2/3/4),回显 `columns` 为完整列对象并给出 `added`/`updated`;`sorts`→querySorts(direction ASC/DESC)、`conditions`→queryConditions(**比较符是 `filterType`(QueryFilterType 字符串枚举 Eq/NotEq/…;别名 operator/op;省略时按 propertyType 取平台默认)**、displayType/choiceType/options 字符串解码;写后条件回读等价校验给出 conditionReadback)、`actions`→queryActions(queryActionType QUERY(1)…BATCH_SUBMIT(23)、associationType BIZSHEET(0)/WORKFLOW(1))、`presentation`→queryPresentation(htmlJson/actionsJson/columnsJson/queryViewDataSource/schemaRelations/options 均为 JSON 字符串,合法 JSON 读回解码)、`buttons`→customButtons(写面 customButtonJson JSON 数组字符串;bindAction/useLocation/operateType/showPermType 以枚举名发送;triggerType 强制 QUERY、triggerCode=视图 code、sortKey 按数组位,缺省回传读面 customButtons 有效集;ADD_DATA/FORM 目标绑定走 actionConfig——schemaCodeVal+formListData+configureList,targetCode/targetObjCode 对其无效会被拒;高层参数 targetModel/targetForm/configureList 从读回元数据展开,未解析即 listview-button-target-unresolved 零副作用拒)、`options`→视图头 BizQueryOption(`pagingSetting`{pageSize,showTotal} 分页、`listViewModeSetting`{mode,canSwitch} 列表模式,缺省回传读面有效 options、提供时整体替换,rowColorSetting 无 8.6.26 类证据故对象形态拒绝)与 `presentationType`→QueryPresentationType(LIST/BOARD/CALENDAR/GANTT,缺省回传读面有效值;GANTT 必须同时提供 `gantt`→queryGanttModel 且 startTimePropertyCode/endTimePropertyCode/titlePropertyCode 非空,缺省不触碰既有 gantt)与 `queryLayer`→层级展示(BizQueryLayer[] 数组原样发送)及 `multiTableHeaderConfig`→多级表头(HeaderConfig[] JSON 字符串;缺省回传读面有效值、提供时整体替换)省略时不触碰既有值,提供时整体替换并经出门前 dry-lint;`query/update` 后回读(`query/get` 自动注入的默认动作、平台 sortKey 重排与 schemaRelations 派生需还原)。`code` 省略时用默认视图(=schemaCode)。`queryConditionMap` 为只读派生(query/get 带 formCode 子表条件时才出现),非配置输入。**发布语义**:`query/update` 自动置 publish=TRUE——视图无草稿/发布两态、无需独立发布步骤(与表单/规则的 draft→publish 不同)。**依赖顺序**:视图与表单脚手架都依赖**已发布字段**,规范顺序 model.create → field.create → field.publish(模型级)→ form.draft → form.publish → listview.create(自定义业务视图)→ listview.configure(code 指向它)→ rule.save → rule.enable → workflow。",
|
|
130
|
+
}),
|
|
131
|
+
"listview.delete": Object.freeze({
|
|
132
|
+
scope: LIST_VIEW_SCOPE,
|
|
133
|
+
description: "Delete a design-time list view (query/delete) with exact absence readback.",
|
|
134
|
+
}),
|
|
135
|
+
}),
|
|
136
|
+
});
|
|
137
|
+
export function assertListViewContract() {
|
|
138
|
+
assertLaneContract(LIST_VIEW_LANE_CONTRACT);
|
|
139
|
+
if (LIST_VIEW_WIRE.configureNotFound !== 302025)
|
|
140
|
+
throw new Error("list-view contract pins the missing-view errcode to 302025");
|
|
141
|
+
if (!LIST_VIEW_WIRE.createBody.includes("query/create"))
|
|
142
|
+
throw new Error("list-view contract must pin the create endpoint");
|
|
143
|
+
if (!LIST_VIEW_WIRE.createReadback.includes("query/get_header"))
|
|
144
|
+
throw new Error("list-view contract must pin the header readback");
|
|
145
|
+
if (!LIST_VIEW_WIRE.configureDefault.includes("default view"))
|
|
146
|
+
throw new Error("list-view contract must pin the default-view resolution");
|
|
147
|
+
if (!LIST_VIEW_WIRE.configureColumns.includes("query/update"))
|
|
148
|
+
throw new Error("list-view contract must pin the column configure write");
|
|
149
|
+
if (!LIST_VIEW_WIRE.configureSorts.includes("querySorts"))
|
|
150
|
+
throw new Error("list-view contract must pin querySorts");
|
|
151
|
+
if (!LIST_VIEW_WIRE.configureConditions.includes("queryConditions"))
|
|
152
|
+
throw new Error("list-view contract must pin queryConditions");
|
|
153
|
+
if (!LIST_VIEW_WIRE.configureConditionMap.includes("queryConditionMap"))
|
|
154
|
+
throw new Error("list-view contract must pin the condition-map read derivation");
|
|
155
|
+
if (!LIST_VIEW_WIRE.buttonsActionConfig.includes("actionConfig"))
|
|
156
|
+
throw new Error("list-view contract must pin the button actionConfig shape");
|
|
157
|
+
if (!LIST_VIEW_WIRE.configurePresentation.includes("queryPresentation"))
|
|
158
|
+
throw new Error("list-view contract must pin queryPresentation");
|
|
159
|
+
if (!LIST_VIEW_WIRE.configureButtons.includes("customButtons"))
|
|
160
|
+
throw new Error("list-view contract must pin customButtons");
|
|
161
|
+
if (!LIST_VIEW_WIRE.configureOptions.includes("pagingSetting"))
|
|
162
|
+
throw new Error("list-view contract must pin the options shape");
|
|
163
|
+
if (!LIST_VIEW_WIRE.configurePresentationType.includes("QueryPresentationType"))
|
|
164
|
+
throw new Error("list-view contract must pin the presentation-type enum");
|
|
165
|
+
if (!LIST_VIEW_WIRE.configureLayer.includes("queryLayer"))
|
|
166
|
+
throw new Error("list-view contract must pin queryLayer");
|
|
167
|
+
if (!LIST_VIEW_WIRE.deleteBody.includes("query/delete"))
|
|
168
|
+
throw new Error("list-view contract must pin the delete endpoint");
|
|
169
|
+
assertDescriptionCarries(LIST_VIEW_LANE_CONTRACT, "listview.create", ["query/create", "LIST", "get_header"]);
|
|
170
|
+
assertDescriptionCarries(LIST_VIEW_LANE_CONTRACT, "listview.get", ["query/get", "code", "默认视图", "present"]);
|
|
171
|
+
assertDescriptionCarries(LIST_VIEW_LANE_CONTRACT, "listview.list", ["query/list", "code"]);
|
|
172
|
+
assertDescriptionCarries(LIST_VIEW_LANE_CONTRACT, "listview.configure", ["query/update", "fieldCodes", "默认视图", "querySorts", "queryConditions", "queryActions", "queryActionType", "associationType", "options", "queryPresentation", "htmlJson", "schemaRelations", "customButtons", "customButtonJson", "bindAction", "useLocation", "operateType", "showPermType", "QUERY", "pagingSetting", "listViewModeSetting", "presentationType", "queryGanttModel", "GANTT", "queryLayer", "multiTableHeaderConfig", "publish=TRUE", "field.publish", "rule.enable", "actionConfig", "targetModel", "listview-button-target-unresolved"]);
|
|
173
|
+
assertDescriptionCarries(LIST_VIEW_LANE_CONTRACT, "listview.delete", ["query/delete", "absence"]);
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=list-view-contract.js.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { claim, declareLaneCoverage } from "./coverage-declaration.js";
|
|
2
|
+
import { LIST_VIEW_LANE_CONTRACT } from "./list-view-contract.js";
|
|
3
|
+
const T = LIST_VIEW_LANE_CONTRACT.tools;
|
|
4
|
+
export const LIST_VIEW_COVERAGE = declareLaneCoverage(LIST_VIEW_LANE_CONTRACT.lane, [
|
|
5
|
+
{
|
|
6
|
+
capability: "W1 list-view design-time header lifecycle",
|
|
7
|
+
evidence: [
|
|
8
|
+
".scratch/omc-route-wayfinder/research/list-view-static-scout.md",
|
|
9
|
+
"packages/omc-cli/src/lanes/list-view.ts",
|
|
10
|
+
],
|
|
11
|
+
tools: [
|
|
12
|
+
claim("listview.get", T["listview.get"].scope),
|
|
13
|
+
claim("listview.list", T["listview.list"].scope),
|
|
14
|
+
claim("listview.create", T["listview.create"].scope),
|
|
15
|
+
claim("listview.configure", T["listview.configure"].scope),
|
|
16
|
+
claim("listview.delete", T["listview.delete"].scope),
|
|
17
|
+
],
|
|
18
|
+
},
|
|
19
|
+
]);
|
|
20
|
+
//# sourceMappingURL=list-view-coverage.js.map
|