openyida 2026.7.18 → 2026.7.21
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/README.md +37 -2
- package/bin/yida.js +113 -18
- package/docs/capabilities.md +202 -0
- package/lib/agent-center/agent-center.js +2 -3
- package/lib/app/app-list.js +3 -4
- package/lib/app/build-page.js +13 -6
- package/lib/app/check-page.js +16 -6
- package/lib/app/compile.js +17 -7
- package/lib/app/create-app.js +14 -2
- package/lib/app/create-form/api-path.js +25 -0
- package/lib/app/create-form/args.js +13 -0
- package/lib/app/create-form/commands.js +4 -0
- package/lib/app/create-form/definition-reader.js +23 -23
- package/lib/app/create-form/field-normalizers.js +26 -7
- package/lib/app/create-form/schema-patch.js +4 -1
- package/lib/app/create-form.js +155 -68
- package/lib/app/create-page.js +47 -10
- package/lib/app/generate-page.js +20 -1
- package/lib/app/get-form-config.js +2 -1
- package/lib/app/get-schema.js +67 -15
- package/lib/app/import-app.js +94 -42
- package/lib/app/list-forms.js +4 -8
- package/lib/app/page-ir.js +140 -0
- package/lib/app/publish.js +289 -556
- package/lib/app/schema-field-resolution.js +370 -0
- package/lib/app/services/app-reader.js +85 -0
- package/lib/app/services/app-service.js +235 -0
- package/lib/app/services/canvas-page-compiler.js +91 -0
- package/lib/app/services/canvas-page-schema-builder.js +149 -0
- package/lib/app/services/field-bindings.js +68 -0
- package/lib/app/services/form-compiler.js +1922 -0
- package/lib/app/services/form-mode-service.js +182 -0
- package/lib/app/services/form-schema-patcher.js +333 -0
- package/lib/app/services/form-schema-reader.js +59 -0
- package/lib/app/services/form-service.js +379 -0
- package/lib/app/services/form-validation.js +562 -0
- package/lib/app/services/native-page-compiler.js +92 -0
- package/lib/app/services/native-page-schema-builder.js +428 -0
- package/lib/app/services/page-resource-service.js +185 -0
- package/lib/app/update-app.js +22 -9
- package/lib/app/update-form-config.js +4 -2
- package/lib/asset/asset-cmd.js +19 -6
- package/lib/auth/oauth-loopback.js +376 -15
- package/lib/auth/token-auth.js +34 -3
- package/lib/auth/token-store.js +22 -4
- package/lib/basic-info/basic-info.js +2 -1
- package/lib/bridge/bridge.js +43 -18
- package/lib/core/agent-capabilities.js +5 -3
- package/lib/core/command-errors.js +38 -0
- package/lib/core/command-manifest.js +59 -1
- package/lib/core/copy.js +12 -0
- package/lib/core/doctor.js +15 -4
- package/lib/core/env-cmd.js +1 -1
- package/lib/core/env.js +7 -6
- package/lib/core/i18n.js +66 -8
- package/lib/core/legacy-schema-guard.js +408 -0
- package/lib/core/locales/en.js +38 -46
- package/lib/core/locales/zh.js +30 -46
- package/lib/core/sample.js +12 -2
- package/lib/core/utils.js +334 -66
- package/lib/core/yida-client.js +108 -5
- package/lib/corp-efficiency/corp-efficiency.js +2 -2
- package/lib/corp-manager/corp-manager.js +3 -3
- package/lib/formula/evaluate.js +11 -68
- package/lib/formula/field-refs.js +83 -0
- package/lib/i18n-management/i18n-management.js +2 -3
- package/lib/process/configure-process.js +44 -1992
- package/lib/process/create-process.js +54 -87
- package/lib/process/preview-process.js +20 -8
- package/lib/process/services/process-compiler.js +2056 -0
- package/lib/process/services/process-reader.js +232 -0
- package/lib/process/services/process-resource-service.js +571 -0
- package/lib/process/services/process-service.js +122 -0
- package/lib/process/services/process-stage-checkpoint.js +246 -0
- package/lib/report/append.js +7 -26
- package/lib/report/http.js +31 -5
- package/lib/report/index.js +10 -2
- package/lib/samples/yida-canvas-custom-page/business-list.canvas.jsx +63 -14
- package/lib/samples/yida-canvas-custom-page/dashboard-overview.canvas.jsx +176 -32
- package/lib/samples/yida-canvas-custom-page/dashboard-starter.canvas.jsx +5 -2
- package/lib/samples/yida-canvas-custom-page/data-management.canvas.jsx +228 -14
- package/lib/samples/yida-canvas-custom-page/portal-shell-home.canvas.jsx +2 -2
- package/lib/samples/yida-canvas-custom-page/split-pane-detail.canvas.jsx +206 -10
- package/lib/samples/yida-custom-page/data-management.oyd.jsx +14 -3
- package/lib/samples/yida-custom-page/design-tokens.js +2 -2
- package/lib/samples/yida-custom-page/detail-profile.oyd.jsx +1 -1
- package/lib/samples/yida-custom-page/portal-shell-home.oyd.jsx +7 -2
- package/lib/samples/yida-custom-page/split-pane-detail.oyd.jsx +2 -1
- package/lib/schema/adapters/app-adapter.js +210 -0
- package/lib/schema/adapters/form-adapter.js +1362 -0
- package/lib/schema/adapters/keys.js +19 -0
- package/lib/schema/adapters/page-adapter.js +566 -0
- package/lib/schema/adapters/process-adapter.js +519 -0
- package/lib/schema/applier.js +1878 -0
- package/lib/schema/apply-store.js +1083 -0
- package/lib/schema/command.js +645 -0
- package/lib/schema/dependency-graph.js +83 -0
- package/lib/schema/errors.js +481 -0
- package/lib/schema/hash.js +9 -0
- package/lib/schema/manifest-limits.js +177 -0
- package/lib/schema/manifest-loader.js +309 -0
- package/lib/schema/manifest-schema-v1.json +193 -0
- package/lib/schema/normalize-manifest.js +281 -0
- package/lib/schema/page-canvas-foundation.js +447 -0
- package/lib/schema/page-data-source-builder.js +561 -0
- package/lib/schema/page-foundation.js +556 -0
- package/lib/schema/page-source-loader.js +314 -0
- package/lib/schema/planner.js +691 -0
- package/lib/schema/remote-dispatch-boundary.js +39 -0
- package/lib/schema/remote-missing.js +21 -0
- package/lib/schema/remote-reader.js +189 -0
- package/lib/schema/resource-registry.js +157 -0
- package/lib/schema/server-revision.js +71 -0
- package/lib/schema/sort.js +28 -0
- package/lib/schema/state-store.js +589 -0
- package/package.json +10 -8
- package/scripts/check-release-risks.js +254 -0
- package/scripts/generate-command-docs.js +6 -1
- package/scripts/i18n-baseline.json +11 -11
- package/scripts/postinstall.js +8 -12
- package/scripts/validate-ci.sh +15 -11
- package/scripts/validate-i18n.js +30 -9
- package/scripts/validate-package-size.js +5 -2
- package/scripts/validate-skills.js +4 -0
- package/scripts/validate-structure.js +15 -0
- package/yida-skills/SKILL.md +117 -30
- package/yida-skills/references/schema-as-code-phase1.md +99 -0
- package/yida-skills/references/setup-and-env.md +59 -59
- package/yida-skills/references/task-retrospective.md +6 -6
- package/yida-skills/skills/yida-app/SKILL.md +78 -17
- package/yida-skills/skills/yida-canvas-custom-page/SKILL.md +18 -7
- package/yida-skills/skills/yida-canvas-custom-page/references/data-bridge-guide.md +3 -3
- package/yida-skills/skills/yida-canvas-custom-page/references/page-generation-guide.md +15 -0
- package/yida-skills/skills/yida-create-app/SKILL.md +21 -3
- package/yida-skills/skills/yida-create-form-page/SKILL.md +19 -1
- package/yida-skills/skills/yida-create-page/SKILL.md +16 -3
- package/yida-skills/skills/yida-create-process/SKILL.md +100 -4
- package/yida-skills/skills/yida-custom-page/SKILL.md +19 -4
- package/yida-skills/skills/yida-dashboard/SKILL.md +1 -1
- package/yida-skills/skills/yida-dashboard/references/pitfalls.md +1 -1
- package/yida-skills/skills/yida-get-schema/SKILL.md +49 -5
- package/yida-skills/skills/yida-i18n/SKILL.md +1 -1
- package/yida-skills/skills/yida-integration/SKILL.md +7 -1
- package/yida-skills/skills/yida-login/SKILL.md +50 -99
- package/yida-skills/skills/yida-page-config/SKILL.md +7 -1
- package/yida-skills/skills/yida-page-uiux/references/app/blueprint.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/app/navigation-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/app/role-journey.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/app-blueprint.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/chart-contracts.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/component-contracts.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/layout-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/theme-recipes.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/detail/object-narrative.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/detail/section-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/detail/timeline-and-related.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/landing/assets-workflow.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/landing/industry-playbooks.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/landing/research-levels.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/landing/section-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/list/drawer-detail.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/list/empty-loading-error.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/list/filter-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/list/table-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/scenes/screen.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/workbench/entry-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/workbench/portal-layouts.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/workbench/task-feed.md +0 -1
- package/yida-skills/skills/yida-page-uiux/workflow/output-decision-block.md +1 -1
- package/yida-skills/skills/yida-process-rule/SKILL.md +35 -1
- package/yida-skills/skills/yida-publish-page/SKILL.md +46 -4
- package/yida-skills/skills/yida-report/SKILL.md +9 -235
- package/yida-skills/skills/yida-report/references/schema-builder-details.md +239 -0
- package/yida-skills/skills/yida-skill-evaluator/SKILL.md +170 -0
- package/yida-skills/skills-index.json +238 -54
- package/lib/core/locales/ar.js +0 -834
- package/lib/core/locales/de.js +0 -834
- package/lib/core/locales/es.js +0 -834
- package/lib/core/locales/fr.js +0 -834
- package/lib/core/locales/hi.js +0 -834
- package/lib/core/locales/ja.js +0 -1227
- package/lib/core/locales/ko.js +0 -836
- package/lib/core/locales/pt.js +0 -834
- package/lib/core/locales/vi.js +0 -834
- package/lib/core/locales/zh-HK.js +0 -1263
- package/project/pages/src/demo-birthday-game.oyd.jsx +0 -832
- package/project/pages/src/demo-chip-insight.oyd.jsx +0 -983
- package/project/pages/src/demo-compat-smoke.oyd.jsx +0 -58
- package/project/pages/src/demo-crm-batch-entry.oyd.jsx +0 -805
- package/project/pages/src/demo-crm-dashboard.oyd.jsx +0 -677
- package/project/pages/src/demo-future-vision-2026.oyd.jsx +0 -1102
- package/project/pages/src/demo-ppt.oyd.jsx +0 -1192
- package/project/pages/src/demo-salary-calculator.oyd.jsx +0 -904
- package/project/pages/src/openyida-knowledge-doc.oyd.jsx +0 -1714
- package/yida-skills/skills/large-file-write/SKILL.md +0 -93
- package/yida-skills/skills/large-file-write/references/write-patterns.md +0 -147
- package/yida-skills/skills/large-file-write/scripts/write.js +0 -157
- package/yida-skills/skills/sls-log-workbench/SKILL.md +0 -134
- package/yida-skills/skills/sls-log-workbench/references/workbench-reference.md +0 -130
- package/yida-skills/skills/sls-log-workbench/sls-query.js +0 -295
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { schemaError } = require('../../schema/errors');
|
|
4
|
+
|
|
5
|
+
const PROCESS_STAGES = Object.freeze([
|
|
6
|
+
'draft_created',
|
|
7
|
+
'saved',
|
|
8
|
+
'published',
|
|
9
|
+
'readback_verified',
|
|
10
|
+
'completed',
|
|
11
|
+
]);
|
|
12
|
+
const ADAPTER_CHECKPOINT_STAGES = new Set(PROCESS_STAGES.slice(0, 3));
|
|
13
|
+
const STAGE_CHECKPOINT_KEYS = new Set([
|
|
14
|
+
'stage',
|
|
15
|
+
'processCode',
|
|
16
|
+
'processId',
|
|
17
|
+
'processVersion',
|
|
18
|
+
'nodeBindings',
|
|
19
|
+
'desiredManagedHash',
|
|
20
|
+
'observedManagedHash',
|
|
21
|
+
]);
|
|
22
|
+
const ADAPTER_PARTIAL_KEYS = new Set([
|
|
23
|
+
'processCode',
|
|
24
|
+
'processId',
|
|
25
|
+
'processVersion',
|
|
26
|
+
'nodeBindings',
|
|
27
|
+
]);
|
|
28
|
+
const NODE_BINDING_KEYS = new Set(['nodeId', 'componentName']);
|
|
29
|
+
const HASH_PATTERN = /^sha256:[a-f0-9]{64}$/;
|
|
30
|
+
const SEMANTIC_KEY_PATTERN = /^[A-Za-z][A-Za-z0-9_]*$/;
|
|
31
|
+
|
|
32
|
+
function validateProcessStageCheckpoint(checkpoint, options = {}) {
|
|
33
|
+
assertObject(checkpoint);
|
|
34
|
+
assertAllowedKeys(checkpoint, STAGE_CHECKPOINT_KEYS);
|
|
35
|
+
if (!PROCESS_STAGES.includes(checkpoint.stage)) {
|
|
36
|
+
invalidCheckpoint();
|
|
37
|
+
}
|
|
38
|
+
assertHash(checkpoint.desiredManagedHash);
|
|
39
|
+
if (options.desiredManagedHash !== undefined && checkpoint.desiredManagedHash !== options.desiredManagedHash) {
|
|
40
|
+
invalidCheckpoint();
|
|
41
|
+
}
|
|
42
|
+
if (stageIndex(checkpoint.stage) >= stageIndex('readback_verified')) {
|
|
43
|
+
assertHash(checkpoint.observedManagedHash);
|
|
44
|
+
} else if (checkpoint.observedManagedHash !== undefined) {
|
|
45
|
+
invalidCheckpoint();
|
|
46
|
+
}
|
|
47
|
+
for (const property of ['processCode', 'processId']) {
|
|
48
|
+
if (checkpoint[property] !== undefined && !isNonEmptyString(checkpoint[property])) {
|
|
49
|
+
invalidCheckpoint();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (
|
|
53
|
+
checkpoint.processVersion !== undefined &&
|
|
54
|
+
(!Number.isInteger(checkpoint.processVersion) || checkpoint.processVersion < 0)
|
|
55
|
+
) {
|
|
56
|
+
invalidCheckpoint();
|
|
57
|
+
}
|
|
58
|
+
if (checkpoint.nodeBindings !== undefined) {
|
|
59
|
+
validateNodeBindings(checkpoint.nodeBindings);
|
|
60
|
+
}
|
|
61
|
+
if (options.operation === 'stateRepair') {
|
|
62
|
+
invalidCheckpoint();
|
|
63
|
+
}
|
|
64
|
+
if (checkpoint.stage === 'completed' && options.operationStatus !== undefined && options.operationStatus !== 'completed') {
|
|
65
|
+
invalidCheckpoint();
|
|
66
|
+
}
|
|
67
|
+
if (options.operationStatus === 'completed' && checkpoint.stage !== 'completed') {
|
|
68
|
+
invalidCheckpoint();
|
|
69
|
+
}
|
|
70
|
+
return checkpoint;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function advanceProcessStagedCheckpoint(previous, event, input = {}) {
|
|
74
|
+
assertObject(input);
|
|
75
|
+
if (event === 'adapterCheckpoint') {
|
|
76
|
+
assertAllowedKeys(input, new Set(['desiredManagedHash', 'partial', 'stage']));
|
|
77
|
+
assertAdapterCheckpointStage(input.stage);
|
|
78
|
+
return advanceProcessStageCheckpoint(previous, input.stage, input.partial || {}, {
|
|
79
|
+
desiredManagedHash: input.desiredManagedHash,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
if (event === 'reconciledRemoteComplete') {
|
|
83
|
+
assertAllowedKeys(input, new Set(['desiredManagedHash']));
|
|
84
|
+
let checkpoint = previous;
|
|
85
|
+
let index = checkpoint ? stageIndex(checkpoint.stage) : -1;
|
|
86
|
+
const publishedIndex = stageIndex('published');
|
|
87
|
+
while (index < publishedIndex) {
|
|
88
|
+
index += 1;
|
|
89
|
+
checkpoint = advanceProcessStageCheckpoint(checkpoint, PROCESS_STAGES[index], {}, {
|
|
90
|
+
desiredManagedHash: input.desiredManagedHash,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
return checkpoint;
|
|
94
|
+
}
|
|
95
|
+
if (event === 'readbackVerified') {
|
|
96
|
+
assertAllowedKeys(input, new Set(['desiredManagedHash', 'observedManagedHash']));
|
|
97
|
+
if (previous && previous.stage === 'readback_verified') {
|
|
98
|
+
validateProcessStageCheckpoint(previous, { desiredManagedHash: input.desiredManagedHash });
|
|
99
|
+
if (previous.observedManagedHash !== input.observedManagedHash) {
|
|
100
|
+
invalidCheckpoint();
|
|
101
|
+
}
|
|
102
|
+
return clonePlain(previous);
|
|
103
|
+
}
|
|
104
|
+
return advanceProcessStageCheckpoint(previous, 'readback_verified', {}, input);
|
|
105
|
+
}
|
|
106
|
+
if (event === 'completed') {
|
|
107
|
+
assertAllowedKeys(input, new Set(['desiredManagedHash']));
|
|
108
|
+
return advanceProcessStageCheckpoint(previous, 'completed', {}, {
|
|
109
|
+
desiredManagedHash: input.desiredManagedHash,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
invalidCheckpoint();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function isProcessStageCheckpointRemoteComplete(checkpoint, options = {}) {
|
|
116
|
+
if (!checkpoint) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
validateProcessStageCheckpoint(checkpoint, options);
|
|
120
|
+
return stageIndex(checkpoint.stage) >= stageIndex('published');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function advanceProcessStageCheckpoint(previous, stage, partial = {}, options = {}) {
|
|
124
|
+
if (previous !== undefined && previous !== null) {
|
|
125
|
+
validateProcessStageCheckpoint(previous, {
|
|
126
|
+
desiredManagedHash: options.desiredManagedHash,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
assertObject(partial);
|
|
130
|
+
assertAllowedKeys(partial, ADAPTER_PARTIAL_KEYS);
|
|
131
|
+
const expectedIndex = previous ? stageIndex(previous.stage) + 1 : 0;
|
|
132
|
+
if (PROCESS_STAGES[expectedIndex] !== stage) {
|
|
133
|
+
invalidCheckpoint();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const next = clonePlain(previous) || {};
|
|
137
|
+
next.stage = stage;
|
|
138
|
+
mergeIdentityProperty(next, partial, 'processCode');
|
|
139
|
+
mergeIdentityProperty(next, partial, 'processId');
|
|
140
|
+
mergeIdentityProperty(next, partial, 'processVersion');
|
|
141
|
+
mergeNodeBindings(next, partial.nodeBindings);
|
|
142
|
+
next.desiredManagedHash = options.desiredManagedHash;
|
|
143
|
+
if (options.observedManagedHash !== undefined) {
|
|
144
|
+
next.observedManagedHash = options.observedManagedHash;
|
|
145
|
+
}
|
|
146
|
+
return validateProcessStageCheckpoint(next, {
|
|
147
|
+
desiredManagedHash: options.desiredManagedHash,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function assertAdapterCheckpointStage(stage) {
|
|
152
|
+
if (!ADAPTER_CHECKPOINT_STAGES.has(stage)) {
|
|
153
|
+
invalidCheckpoint();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function mergeIdentityProperty(target, source, property) {
|
|
158
|
+
if (source[property] === undefined) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (target[property] !== undefined && target[property] !== source[property]) {
|
|
162
|
+
invalidCheckpoint();
|
|
163
|
+
}
|
|
164
|
+
target[property] = source[property];
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function mergeNodeBindings(target, incoming) {
|
|
168
|
+
if (incoming === undefined) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
validateNodeBindings(incoming);
|
|
172
|
+
const merged = Object.create(null);
|
|
173
|
+
for (const [key, binding] of Object.entries(target.nodeBindings || {})) {
|
|
174
|
+
merged[key] = clonePlain(binding);
|
|
175
|
+
}
|
|
176
|
+
for (const [key, binding] of Object.entries(incoming)) {
|
|
177
|
+
if (Object.prototype.hasOwnProperty.call(merged, key)) {
|
|
178
|
+
if (
|
|
179
|
+
merged[key].nodeId !== binding.nodeId ||
|
|
180
|
+
merged[key].componentName !== binding.componentName
|
|
181
|
+
) {
|
|
182
|
+
invalidCheckpoint();
|
|
183
|
+
}
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
merged[key] = clonePlain(binding);
|
|
187
|
+
}
|
|
188
|
+
target.nodeBindings = merged;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function validateNodeBindings(value) {
|
|
192
|
+
assertObject(value);
|
|
193
|
+
for (const [key, binding] of Object.entries(value)) {
|
|
194
|
+
if (!SEMANTIC_KEY_PATTERN.test(key)) {
|
|
195
|
+
invalidCheckpoint();
|
|
196
|
+
}
|
|
197
|
+
assertObject(binding);
|
|
198
|
+
assertAllowedKeys(binding, NODE_BINDING_KEYS);
|
|
199
|
+
if (!isNonEmptyString(binding.nodeId) || !isNonEmptyString(binding.componentName)) {
|
|
200
|
+
invalidCheckpoint();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function assertObject(value) {
|
|
206
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
207
|
+
invalidCheckpoint();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function assertAllowedKeys(value, allowed) {
|
|
212
|
+
for (const key of Object.keys(value)) {
|
|
213
|
+
if (!allowed.has(key)) {
|
|
214
|
+
invalidCheckpoint();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function assertHash(value) {
|
|
220
|
+
if (typeof value !== 'string' || !HASH_PATTERN.test(value)) {
|
|
221
|
+
invalidCheckpoint();
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function stageIndex(stage) {
|
|
226
|
+
return PROCESS_STAGES.indexOf(stage);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function isNonEmptyString(value) {
|
|
230
|
+
return typeof value === 'string' && value.trim().length > 0;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function clonePlain(value) {
|
|
234
|
+
return value === undefined ? undefined : JSON.parse(JSON.stringify(value));
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function invalidCheckpoint() {
|
|
238
|
+
throw schemaError('SCHEMA_APPLY_JOURNAL_INVALID', 'Schema staged apply checkpoint is invalid.');
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
module.exports = {
|
|
242
|
+
advanceProcessStageCheckpoint,
|
|
243
|
+
advanceProcessStagedCheckpoint,
|
|
244
|
+
isProcessStageCheckpointRemoteComplete,
|
|
245
|
+
validateProcessStageCheckpoint,
|
|
246
|
+
};
|
package/lib/report/append.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
const fs = require('fs');
|
|
17
17
|
|
|
18
18
|
const { CliError } = require('../core/cli-error');
|
|
19
|
-
const { createAuthRef,
|
|
19
|
+
const { createAuthRef, isAuthRefReady } = require('../core/yida-client');
|
|
20
20
|
const { CHART_COMPONENT_MAP } = require('./constants');
|
|
21
21
|
const {
|
|
22
22
|
buildDataSetModelMap,
|
|
@@ -32,32 +32,12 @@ const {
|
|
|
32
32
|
const { genNodeId, genFieldId, randomId } = require('./constants');
|
|
33
33
|
const { warn } = require('../core/chalk');
|
|
34
34
|
const { parseOpenOption, withBrowserHandoff } = require('../core/browser-handoff');
|
|
35
|
+
const { getReportSchema, saveReportSchema } = require('./http');
|
|
36
|
+
const { requireSchemaServerRevision } = require('../schema/server-revision');
|
|
35
37
|
|
|
36
38
|
// ── HTTP:获取已有报表 Schema ─────────────────────────
|
|
37
39
|
// GET 用 /alibaba/web/ 路径
|
|
38
40
|
|
|
39
|
-
async function getReportSchema(authRef, appType, reportId) {
|
|
40
|
-
return createYidaClient({ authRef }).get(
|
|
41
|
-
`/alibaba/web/${appType}/_view/query/formdesign/getFormSchema.json`,
|
|
42
|
-
{ formUuid: reportId, schemaVersion: 'V5' }
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// ── HTTP:保存报表 Schema ─────────────────────────────
|
|
47
|
-
// SAVE 用 /dingtalk/web/ 路径
|
|
48
|
-
|
|
49
|
-
async function saveSchema(authRef, appType, reportId, schema) {
|
|
50
|
-
return createYidaClient({ authRef }).postForm(
|
|
51
|
-
`/dingtalk/web/${appType}/_view/query/formdesign/saveFormSchema.json`,
|
|
52
|
-
{
|
|
53
|
-
formUuid: reportId,
|
|
54
|
-
content: JSON.stringify(schema),
|
|
55
|
-
schemaVersion: 'V5',
|
|
56
|
-
importSchema: 'true',
|
|
57
|
-
}
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
41
|
function ensureSession() {
|
|
62
42
|
const authRef = createAuthRef();
|
|
63
43
|
if (!isAuthRefReady(authRef)) {
|
|
@@ -189,7 +169,7 @@ async function main(args) {
|
|
|
189
169
|
// Step 1: 读取登录态
|
|
190
170
|
warn('\n[Step 1] 读取登录态...');
|
|
191
171
|
const authRef = ensureSession();
|
|
192
|
-
const corpId = authRef.corpId ||
|
|
172
|
+
const corpId = authRef.corpId || authRef.cookieData.corp_id || '';
|
|
193
173
|
warn('登录态就绪,域名:', authRef.baseUrl);
|
|
194
174
|
|
|
195
175
|
// Step 2: 读取图表定义
|
|
@@ -228,6 +208,7 @@ async function main(args) {
|
|
|
228
208
|
const schema = typeof getResult.content === 'string'
|
|
229
209
|
? JSON.parse(getResult.content)
|
|
230
210
|
: getResult.content;
|
|
211
|
+
const serverRevision = requireSchemaServerRevision(getResult);
|
|
231
212
|
|
|
232
213
|
const page = schema.pages[0];
|
|
233
214
|
const rootContent = page.componentsTree[0].children.find(
|
|
@@ -305,7 +286,7 @@ async function main(args) {
|
|
|
305
286
|
|
|
306
287
|
// Step 6: 保存 Schema
|
|
307
288
|
warn('\n[Step 5] 保存 Schema...');
|
|
308
|
-
const saveResult = await
|
|
289
|
+
const saveResult = await saveReportSchema(authRef, appType, reportId, schema, serverRevision);
|
|
309
290
|
|
|
310
291
|
if (!saveResult || !saveResult.success) {
|
|
311
292
|
const errorMsg = saveResult ? saveResult.errorMsg || '未知错误' : '请求失败';
|
|
@@ -352,5 +333,5 @@ module.exports = {
|
|
|
352
333
|
parseArgs,
|
|
353
334
|
readChartsDefinition,
|
|
354
335
|
getReportSchema,
|
|
355
|
-
saveSchema,
|
|
336
|
+
saveSchema: saveReportSchema,
|
|
356
337
|
};
|
package/lib/report/http.js
CHANGED
|
@@ -2,30 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
const { createYidaClient } = require('../core/yida-client');
|
|
4
4
|
const { buildYidaI18n } = require('../core/yida-i18n');
|
|
5
|
+
const { requireSchemaServerRevision } = require('../schema/server-revision');
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* 调用 saveFormSchemaInfo 创建空白报表
|
|
8
9
|
*/
|
|
9
10
|
async function createBlankReport(authRef, appType, reportTitle) {
|
|
10
|
-
return createYidaClient({ authRef }).postForm(`/dingtalk/web/${appType}/query/formdesign/saveFormSchemaInfo.json`, {
|
|
11
|
+
return createYidaClient({ authRef }).postForm(`/dingtalk/web/${appType}/query/formdesign/saveFormSchemaInfo.json`, auth => ({
|
|
12
|
+
_csrf_token: auth.csrfToken,
|
|
11
13
|
formType: 'report',
|
|
12
14
|
title: JSON.stringify(buildYidaI18n(reportTitle, { en_US: reportTitle, ja_JP: reportTitle })),
|
|
13
|
-
});
|
|
15
|
+
}));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async function getReportSchema(authRef, appType, reportId) {
|
|
19
|
+
const result = await createYidaClient({ authRef }).get(
|
|
20
|
+
`/alibaba/web/${appType}/_view/query/formdesign/getFormSchema.json`,
|
|
21
|
+
{ formUuid: reportId, schemaVersion: 'V5' }
|
|
22
|
+
);
|
|
23
|
+
if (result && result.success !== false) {
|
|
24
|
+
requireSchemaServerRevision(result, createRevisionError);
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
14
27
|
}
|
|
15
28
|
|
|
16
29
|
/**
|
|
17
30
|
* 调用 saveFormSchema 保存报表 Schema
|
|
18
31
|
*/
|
|
19
|
-
async function saveReportSchema(authRef, appType, reportId, schema) {
|
|
20
|
-
|
|
32
|
+
async function saveReportSchema(authRef, appType, reportId, schema, serverRevision) {
|
|
33
|
+
const gmtModified = requireSchemaServerRevision(
|
|
34
|
+
{ gmtModified: serverRevision },
|
|
35
|
+
createRevisionError
|
|
36
|
+
);
|
|
37
|
+
return createYidaClient({ authRef }).postFormOnce(`/dingtalk/web/${appType}/_view/query/formdesign/saveFormSchema.json`, auth => ({
|
|
38
|
+
_csrf_token: auth.csrfToken,
|
|
21
39
|
formUuid: reportId,
|
|
22
40
|
content: JSON.stringify(schema),
|
|
23
41
|
schemaVersion: 'V5',
|
|
24
42
|
importSchema: 'true',
|
|
25
|
-
|
|
43
|
+
gmtModified,
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function createRevisionError() {
|
|
48
|
+
const error = new Error('Report Schema revision is missing or invalid.');
|
|
49
|
+
error.code = 'REPORT_SCHEMA_REVISION_INVALID';
|
|
50
|
+
return error;
|
|
26
51
|
}
|
|
27
52
|
|
|
28
53
|
module.exports = {
|
|
29
54
|
createBlankReport,
|
|
55
|
+
getReportSchema,
|
|
30
56
|
saveReportSchema,
|
|
31
57
|
};
|
package/lib/report/index.js
CHANGED
|
@@ -16,7 +16,8 @@ const {
|
|
|
16
16
|
const { genFieldId } = require('./constants');
|
|
17
17
|
|
|
18
18
|
const { warn } = require('../core/chalk');
|
|
19
|
-
const { createBlankReport, saveReportSchema } = require('./http');
|
|
19
|
+
const { createBlankReport, getReportSchema, saveReportSchema } = require('./http');
|
|
20
|
+
const { requireSchemaServerRevision } = require('../schema/server-revision');
|
|
20
21
|
const { parseOpenOption, withBrowserHandoff } = require('../core/browser-handoff');
|
|
21
22
|
|
|
22
23
|
// ── 参数解析 ──────────────────────────────────────────
|
|
@@ -284,6 +285,13 @@ async function main(args) {
|
|
|
284
285
|
const reportId = createResult.content.formUuid || createResult.content;
|
|
285
286
|
warn('报表创建成功,ID:', reportId);
|
|
286
287
|
|
|
288
|
+
const shellResult = await getReportSchema(authRef, appType, reportId);
|
|
289
|
+
if (!shellResult || shellResult.success === false) {
|
|
290
|
+
const errorMsg = shellResult ? shellResult.errorMsg || '未知错误' : '请求失败';
|
|
291
|
+
throw new CliError(errorMsg, { code: 'CREATE_REPORT_GET_SCHEMA_FAILED' });
|
|
292
|
+
}
|
|
293
|
+
const serverRevision = requireSchemaServerRevision(shellResult);
|
|
294
|
+
|
|
287
295
|
// Step 4: 构建报表 Schema
|
|
288
296
|
warn('\n[Step 4] 构建报表 Schema...');
|
|
289
297
|
const schema = buildReportSchema(reportTitle, charts, reportId, corpId);
|
|
@@ -416,7 +424,7 @@ async function main(args) {
|
|
|
416
424
|
|
|
417
425
|
// Step 5: 保存报表 Schema
|
|
418
426
|
warn('\n[Step 5] 保存报表 Schema...');
|
|
419
|
-
const saveResult = await saveReportSchema(authRef, appType, reportId, schema);
|
|
427
|
+
const saveResult = await saveReportSchema(authRef, appType, reportId, schema, serverRevision);
|
|
420
428
|
|
|
421
429
|
if (!saveResult || !saveResult.success) {
|
|
422
430
|
const errorMsg = saveResult
|
|
@@ -136,7 +136,12 @@ const DEFAULT_INSIGHTS = [
|
|
|
136
136
|
suggestion: '高频批量动作固定在列表底部,选中记录后右侧展示下一步。',
|
|
137
137
|
},
|
|
138
138
|
];
|
|
139
|
-
const DEFAULT_DATA_BINDING = { enabled: false, mode: 'seed' };
|
|
139
|
+
const DEFAULT_DATA_BINDING = { enabled: false, mode: 'seed', seedStrategy: 'sample-only' };
|
|
140
|
+
const EMPTY_METRICS = [
|
|
141
|
+
{ label: '真实记录', value: '0', hint: '未接入表单数据' },
|
|
142
|
+
{ label: '数据来源', value: '未接入', hint: '请在 page-spec.json 配置 dataBinding' },
|
|
143
|
+
{ label: '演示记录', value: '0', hint: '演示记录需先写入真实表单' },
|
|
144
|
+
];
|
|
140
145
|
const BACKGROUND_IMAGES = {
|
|
141
146
|
hero: 'https://images.unsplash.com/photo-1566346654781-14e3ef6ee988?auto=format&fit=crop&w=1400&q=80',
|
|
142
147
|
card: 'https://images.unsplash.com/photo-1759884247160-27b8465544b6?auto=format&fit=crop&w=1200&q=80',
|
|
@@ -268,6 +273,11 @@ function isDataBindingEnabled(binding) {
|
|
|
268
273
|
return Boolean(binding && binding.enabled && binding.mode && binding.mode !== 'seed');
|
|
269
274
|
}
|
|
270
275
|
|
|
276
|
+
function isSampleSeedPreview(binding) {
|
|
277
|
+
const mode = binding && binding.mode ? binding.mode : 'seed';
|
|
278
|
+
return RESEARCH_LEVEL === 'sample' && !isDataBindingEnabled(binding) && mode === 'seed';
|
|
279
|
+
}
|
|
280
|
+
|
|
271
281
|
function getCsrfToken() {
|
|
272
282
|
try {
|
|
273
283
|
return (window.g_config && (window.g_config._csrf_token || window.g_config.csrfToken)) || '';
|
|
@@ -393,7 +403,7 @@ function normalizeBoundRows(rows, binding) {
|
|
|
393
403
|
}
|
|
394
404
|
|
|
395
405
|
function useYidaData(binding) {
|
|
396
|
-
const [state, setState] = React.useState({ loading:
|
|
406
|
+
const [state, setState] = React.useState(() => ({ loading: isDataBindingEnabled(binding), error: '', rows: [], totalCount: null }));
|
|
397
407
|
React.useEffect(() => {
|
|
398
408
|
if (!isDataBindingEnabled(binding)) { return undefined; }
|
|
399
409
|
const controller = new AbortController();
|
|
@@ -446,7 +456,9 @@ function YidaComp() {
|
|
|
446
456
|
period: index % 2 === 0 ? 'week' : 'month',
|
|
447
457
|
})), []);
|
|
448
458
|
const dataState = useYidaData(DATA_BINDING);
|
|
449
|
-
const
|
|
459
|
+
const usesSeedRows = isSampleSeedPreview(DATA_BINDING);
|
|
460
|
+
const metricItems = usesSeedRows || isDataBindingEnabled(DATA_BINDING) ? METRICS : EMPTY_METRICS;
|
|
461
|
+
const rows = dataState.rows.length ? dataState.rows : (usesSeedRows ? seedRows : []);
|
|
450
462
|
const filteredRows = useMemo(() => {
|
|
451
463
|
const kw = (filters.keyword || '').trim().toLowerCase();
|
|
452
464
|
return rows.filter((row) => {
|
|
@@ -547,6 +559,11 @@ function YidaComp() {
|
|
|
547
559
|
.oy-list-insight { padding: 12px 14px; margin: 0 0 16px; border-radius: 14px; border: 1px solid color-mix(in srgb, var(--oy-brand), transparent 70%); background: #EFF6FF; }
|
|
548
560
|
.oy-list-brief { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: 10px; }
|
|
549
561
|
.oy-data-status { margin: 0 0 12px; padding: 10px 12px; border-radius: 8px; border: 1px solid var(--oy-line); background: var(--oy-surface-soft); display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
|
|
562
|
+
.oy-list-empty-state { min-height: 278px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; padding: 32px 22px; text-align: center; border: 1px dashed var(--oy-line); border-radius: 14px; background: color-mix(in srgb, var(--oy-brand-soft), #fff 58%); }
|
|
563
|
+
.oy-list-empty-state h4 { margin: 0; color: var(--oy-text); }
|
|
564
|
+
.oy-list-empty-state .ant-typography { max-width: 540px; }
|
|
565
|
+
.oy-list-empty-actions { display: flex; gap: 10px; flex-wrap: wrap; justify-content: center; margin-top: 8px; }
|
|
566
|
+
.oy-list-empty-detail { min-height: 360px; display: flex; flex-direction: column; justify-content: center; padding: 8px; }
|
|
550
567
|
@media (max-width: 960px) {
|
|
551
568
|
.oy-business-list { padding: 20px; }
|
|
552
569
|
.oy-list-grid, .oy-list-metrics, .oy-list-filter, .oy-list-hero { grid-template-columns: 1fr; }
|
|
@@ -573,7 +590,7 @@ function YidaComp() {
|
|
|
573
590
|
</header>
|
|
574
591
|
|
|
575
592
|
<section className="oy-list-metrics">
|
|
576
|
-
{
|
|
593
|
+
{metricItems.slice(0, 3).map((item) => (
|
|
577
594
|
<div className="oy-list-metric" key={item.label}>
|
|
578
595
|
<Text>{item.label}</Text>
|
|
579
596
|
<div className="oy-list-number">{item.value}</div>
|
|
@@ -594,15 +611,39 @@ function YidaComp() {
|
|
|
594
611
|
{dataState.error || (dataState.loading ? '正在读取真实数据' : '真实数据已接入' + (dataState.totalCount === null ? '' : ':' + dataState.totalCount + ' 条'))}
|
|
595
612
|
</Text>
|
|
596
613
|
</div>
|
|
597
|
-
) :
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
614
|
+
) : (
|
|
615
|
+
<div className="oy-data-status">
|
|
616
|
+
<Tag color={usesSeedRows ? 'warning' : 'default'}>{usesSeedRows ? 'Sample seed' : '未接数据'}</Tag>
|
|
617
|
+
<Text type="secondary">
|
|
618
|
+
{usesSeedRows ? '当前为 sample/seed 预览数据,未接真实表单。' : '未配置真实表单 dataBinding,当前不显示前端 seed 列表。'}
|
|
619
|
+
</Text>
|
|
620
|
+
</div>
|
|
621
|
+
)}
|
|
622
|
+
{filteredRows.length ? (
|
|
623
|
+
<Table
|
|
624
|
+
columns={columns}
|
|
625
|
+
dataSource={filteredRows}
|
|
626
|
+
pagination={false}
|
|
627
|
+
size="middle"
|
|
628
|
+
rowClassName={(_, index) => index === activeIndex ? 'is-selected-row' : ''}
|
|
629
|
+
onRow={(_, index) => ({ onClick: () => setSelected(index || 0) })}
|
|
630
|
+
/>
|
|
631
|
+
) : (
|
|
632
|
+
<div className="oy-list-empty-state">
|
|
633
|
+
<Title level={4}>{dataState.loading ? '正在读取真实表单数据' : isDataBindingEnabled(DATA_BINDING) ? '暂无真实表单记录' : usesSeedRows ? '暂无匹配的 sample 记录' : '未接入真实表单数据'}</Title>
|
|
634
|
+
<Paragraph type="secondary">
|
|
635
|
+
{isDataBindingEnabled(DATA_BINDING)
|
|
636
|
+
? '当前数据源已接入宜搭表单。若需要演示内容,请先通过表单数据写入链路创建 demo records,再刷新本页读取。'
|
|
637
|
+
: usesSeedRows
|
|
638
|
+
? '这是模板原样发布的 sample/seed 数据,仅用于离线预览模板结构。'
|
|
639
|
+
: '完整应用交付页不会用前端 seedRows 冒充业务记录。请在 page-spec.json 写入 dataBinding.mode=form,或先登记真实表单记录。'}
|
|
640
|
+
</Paragraph>
|
|
641
|
+
<div className="oy-list-empty-actions">
|
|
642
|
+
<Button type="primary">{PAGE.primaryCta || '登记记录'}</Button>
|
|
643
|
+
<Button>刷新数据</Button>
|
|
644
|
+
</div>
|
|
645
|
+
</div>
|
|
646
|
+
)}
|
|
606
647
|
</div>
|
|
607
648
|
<BulkActionBar actions={INTERACTION_PROFILE.bulkActions} count={filteredRows.length} />
|
|
608
649
|
</section>
|
|
@@ -613,7 +654,15 @@ function YidaComp() {
|
|
|
613
654
|
<Text strong>{insight.suggestion}</Text>
|
|
614
655
|
</div>
|
|
615
656
|
) : null}
|
|
616
|
-
|
|
657
|
+
{filteredRows.length ? (
|
|
658
|
+
<DetailPreview active={active} page={PAGE} roadmap={ROADMAP} />
|
|
659
|
+
) : (
|
|
660
|
+
<div className="oy-list-empty-detail">
|
|
661
|
+
<Tag color="default">空态入口</Tag>
|
|
662
|
+
<Title level={4} style={{ marginTop: 14 }}>等待真实记录</Title>
|
|
663
|
+
<Paragraph type="secondary">接入表单后,选中列表记录将在这里展示摘要、负责人、状态和处理路径。</Paragraph>
|
|
664
|
+
</div>
|
|
665
|
+
)}
|
|
617
666
|
</aside>
|
|
618
667
|
</div>
|
|
619
668
|
</div>
|