openyida 2026.7.19 → 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 +14 -0
- package/bin/yida.js +107 -18
- package/lib/app/create-app.js +12 -1
- package/lib/app/create-form/args.js +13 -0
- package/lib/app/create-form.js +154 -67
- package/lib/app/create-page.js +45 -9
- package/lib/app/get-schema.js +65 -14
- package/lib/app/import-app.js +92 -41
- 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 +18 -6
- package/lib/auth/token-auth.js +34 -3
- package/lib/auth/token-store.js +22 -4
- package/lib/bridge/bridge.js +37 -5
- package/lib/core/agent-capabilities.js +5 -3
- package/lib/core/command-manifest.js +40 -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/legacy-schema-guard.js +408 -0
- package/lib/core/locales/en.js +8 -46
- package/lib/core/locales/zh.js +8 -46
- package/lib/core/sample.js +1 -1
- package/lib/core/utils.js +334 -66
- package/lib/core/yida-client.js +104 -3
- package/lib/formula/evaluate.js +8 -66
- package/lib/formula/field-refs.js +83 -0
- package/lib/process/configure-process.js +44 -1992
- package/lib/process/create-process.js +54 -87
- 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/data-management.canvas.jsx +228 -14
- package/lib/samples/yida-canvas-custom-page/split-pane-detail.canvas.jsx +204 -8
- 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 +2 -2
- package/scripts/postinstall.js +8 -12
- package/scripts/validate-package-size.js +1 -1
- package/yida-skills/SKILL.md +114 -29
- 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 +60 -14
- 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 +7 -1
- 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 +7 -1
- package/yida-skills/skills-index.json +14 -46
- 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
package/lib/app/create-page.js
CHANGED
|
@@ -16,21 +16,39 @@ const { t } = require('../core/i18n');
|
|
|
16
16
|
const { buildYidaI18n, buildYidaTitleI18n, normalizeYidaLocale, resolveContentLocale } = require('../core/yida-i18n');
|
|
17
17
|
const { parseOpenOption, withBrowserHandoff } = require('../core/browser-handoff');
|
|
18
18
|
const { throwCommandError } = require('../core/command-errors');
|
|
19
|
+
const {
|
|
20
|
+
assertLegacyDirectWriteAllowed,
|
|
21
|
+
extractLegacyGuardArgs,
|
|
22
|
+
} = require('../core/legacy-schema-guard');
|
|
19
23
|
|
|
20
24
|
function parseArgs(args) {
|
|
21
25
|
const openOption = parseOpenOption(args);
|
|
26
|
+
const guardSplit = extractLegacyGuardArgs(openOption.args);
|
|
22
27
|
const filteredArgs = [];
|
|
23
28
|
let mode = 'default';
|
|
24
29
|
let locale = null;
|
|
25
30
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
if (guardSplit.args.includes('--help') || guardSplit.args.includes('-h')) {
|
|
32
|
+
return {
|
|
33
|
+
args: [],
|
|
34
|
+
appType: null,
|
|
35
|
+
pageName: null,
|
|
36
|
+
mode,
|
|
37
|
+
locale,
|
|
38
|
+
help: true,
|
|
39
|
+
openMode: openOption.mode,
|
|
40
|
+
legacyGuardOptions: guardSplit.guardOptions,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
for (let i = 0; i < guardSplit.args.length; i++) {
|
|
45
|
+
const arg = guardSplit.args[i];
|
|
46
|
+
if (arg === '--mode' && guardSplit.args[i + 1]) {
|
|
47
|
+
mode = guardSplit.args[++i];
|
|
30
48
|
continue;
|
|
31
49
|
}
|
|
32
|
-
if ((arg === '--locale' || arg === '--content-locale' || arg === '--lang') &&
|
|
33
|
-
locale =
|
|
50
|
+
if ((arg === '--locale' || arg === '--content-locale' || arg === '--lang') && guardSplit.args[i + 1]) {
|
|
51
|
+
locale = guardSplit.args[++i];
|
|
34
52
|
if (!normalizeYidaLocale(locale)) {
|
|
35
53
|
throw new Error(`Unsupported locale: ${locale}`);
|
|
36
54
|
}
|
|
@@ -46,10 +64,11 @@ function parseArgs(args) {
|
|
|
46
64
|
mode,
|
|
47
65
|
locale,
|
|
48
66
|
openMode: openOption.mode,
|
|
67
|
+
legacyGuardOptions: guardSplit.guardOptions,
|
|
49
68
|
};
|
|
50
69
|
}
|
|
51
70
|
|
|
52
|
-
function buildPageInfoPostData(formUuid, pageName, isRenderNav) {
|
|
71
|
+
function buildPageInfoPostData(formUuid, pageName, isRenderNav, csrfToken) {
|
|
53
72
|
const titleJson = JSON.stringify(buildYidaTitleI18n(pageName, {
|
|
54
73
|
en_US: pageName,
|
|
55
74
|
ja_JP: pageName,
|
|
@@ -57,6 +76,7 @@ function buildPageInfoPostData(formUuid, pageName, isRenderNav) {
|
|
|
57
76
|
|
|
58
77
|
return querystring.stringify({
|
|
59
78
|
_api: 'Form.updateFormSchemaInfo',
|
|
79
|
+
_csrf_token: csrfToken,
|
|
60
80
|
_locale_time_zone_offset: '28800000',
|
|
61
81
|
formUuid,
|
|
62
82
|
serialSwitch: 'n',
|
|
@@ -90,7 +110,8 @@ async function configureDashboardMode(authRef, appType, pageId, pageName) {
|
|
|
90
110
|
return httpPost(
|
|
91
111
|
auth.baseUrl,
|
|
92
112
|
`/dingtalk/web/${appType}/query/formdesign/updateFormSchemaInfo.json`,
|
|
93
|
-
buildPageInfoPostData(pageId, pageName, false)
|
|
113
|
+
buildPageInfoPostData(pageId, pageName, false, auth.csrfToken),
|
|
114
|
+
auth.cookies
|
|
94
115
|
);
|
|
95
116
|
}, authRef);
|
|
96
117
|
}
|
|
@@ -104,6 +125,13 @@ async function run(args) {
|
|
|
104
125
|
chalkError(err.message, { hint: t('create_page.usage') });
|
|
105
126
|
}
|
|
106
127
|
|
|
128
|
+
if (options.help) {
|
|
129
|
+
const { usage, hint } = require('../core/chalk');
|
|
130
|
+
usage(t('create_page.usage'), t('create_page.example'));
|
|
131
|
+
hint(t('create_page.mode_hint'));
|
|
132
|
+
return options;
|
|
133
|
+
}
|
|
134
|
+
|
|
107
135
|
if (options.args.length < 2) {
|
|
108
136
|
const { error: chalkError } = require('../core/chalk');
|
|
109
137
|
chalkError(t('create_page.usage'), { hint: t('create_page.example') });
|
|
@@ -112,6 +140,12 @@ async function run(args) {
|
|
|
112
140
|
const appType = options.appType;
|
|
113
141
|
const pageName = options.pageName;
|
|
114
142
|
const mode = options.mode;
|
|
143
|
+
assertLegacyDirectWriteAllowed({
|
|
144
|
+
command: 'create-page',
|
|
145
|
+
resourceType: 'page',
|
|
146
|
+
action: 'create',
|
|
147
|
+
appType,
|
|
148
|
+
}, { guardOptions: options.legacyGuardOptions });
|
|
115
149
|
if (mode !== 'default' && mode !== 'dashboard') {
|
|
116
150
|
const { error: chalkError } = require('../core/chalk');
|
|
117
151
|
chalkError(t('create_page.err_mode_invalid', mode), { hint: t('create_page.mode_hint') });
|
|
@@ -138,13 +172,15 @@ async function run(args) {
|
|
|
138
172
|
|
|
139
173
|
const response = await requestWithAutoLogin((auth) => {
|
|
140
174
|
const postData = querystring.stringify({
|
|
175
|
+
_csrf_token: auth.csrfToken,
|
|
141
176
|
formType: 'display',
|
|
142
177
|
title: JSON.stringify(buildYidaI18n(pageName, { en_US: pageName, ja_JP: pageName })),
|
|
143
178
|
});
|
|
144
179
|
return httpPost(
|
|
145
180
|
auth.baseUrl,
|
|
146
181
|
`/dingtalk/web/${appType}/query/formdesign/saveFormSchemaInfo.json`,
|
|
147
|
-
postData
|
|
182
|
+
postData,
|
|
183
|
+
auth.cookies
|
|
148
184
|
);
|
|
149
185
|
}, authRef);
|
|
150
186
|
|
package/lib/app/get-schema.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* get-schema.js - 宜搭表单 Schema 获取命令
|
|
3
3
|
*
|
|
4
4
|
* 用法:
|
|
5
|
+
* openyida get-schema <appType> <formUuid> [--compact] [--resolve-fields <labelOrFieldId,...>]
|
|
5
6
|
* openyida get-schema <appType> <formUuid> [--summary-json|--field-map-json]
|
|
6
7
|
* openyida get-schema <appType> --all [--summary-json] [--output-dir <dir>] [--concurrency N] [--retries N]
|
|
7
8
|
*/
|
|
@@ -20,6 +21,7 @@ const {
|
|
|
20
21
|
const { t } = require('../core/i18n');
|
|
21
22
|
const { throwCommandError } = require('../core/command-errors');
|
|
22
23
|
const { fetchFormPageList } = require('./form-navigation');
|
|
24
|
+
const { buildFieldResolution } = require('./schema-field-resolution');
|
|
23
25
|
|
|
24
26
|
// 需要在报表 fieldCode 中加 _value 后缀的字段类型
|
|
25
27
|
const FIELD_TYPES_NEEDING_VALUE_SUFFIX = new Set([
|
|
@@ -202,8 +204,9 @@ function parseArgs(args) {
|
|
|
202
204
|
concurrency: 3,
|
|
203
205
|
retries: 1,
|
|
204
206
|
keyword: '',
|
|
205
|
-
|
|
206
|
-
|
|
207
|
+
compact: false,
|
|
208
|
+
fields: [],
|
|
209
|
+
// 保留已有单字段参数,作为 --fields 的单值兼容别名。
|
|
207
210
|
field: '',
|
|
208
211
|
json: false,
|
|
209
212
|
summaryJson: false,
|
|
@@ -225,7 +228,15 @@ function parseArgs(args) {
|
|
|
225
228
|
} else if (arg === '--keyword' && args[index + 1]) {
|
|
226
229
|
parsed.keyword = args[index + 1];
|
|
227
230
|
index++;
|
|
228
|
-
} else if (arg === '--
|
|
231
|
+
} else if (arg === '--compact') {
|
|
232
|
+
parsed.compact = true;
|
|
233
|
+
} else if (arg === '--resolve-fields') {
|
|
234
|
+
parsed.compact = true;
|
|
235
|
+
if (args[index + 1] && !args[index + 1].startsWith('--')) {
|
|
236
|
+
appendFieldQueries(parsed.fields, args[index + 1]);
|
|
237
|
+
index++;
|
|
238
|
+
}
|
|
239
|
+
} else if (arg === '--field' && args[index + 1] && !args[index + 1].startsWith('--')) {
|
|
229
240
|
parsed.field = args[index + 1];
|
|
230
241
|
index++;
|
|
231
242
|
} else if (arg === '--json') {
|
|
@@ -240,15 +251,27 @@ function parseArgs(args) {
|
|
|
240
251
|
return parsed;
|
|
241
252
|
}
|
|
242
253
|
|
|
254
|
+
function appendFieldQueries(target, value) {
|
|
255
|
+
String(value || '')
|
|
256
|
+
.split(/[,,]/)
|
|
257
|
+
.map(item => item.trim())
|
|
258
|
+
.filter(Boolean)
|
|
259
|
+
.forEach((item) => {
|
|
260
|
+
if (!target.includes(item)) {
|
|
261
|
+
target.push(item);
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
243
266
|
function ensureUsage(parsed) {
|
|
244
267
|
if (!parsed.appType || (!parsed.all && !parsed.formUuid)) {
|
|
245
268
|
const { error: chalkError } = require('../core/chalk');
|
|
246
269
|
chalkError(t('get_schema.usage'), { hint: t('get_schema.example') });
|
|
247
270
|
}
|
|
248
|
-
//
|
|
249
|
-
if (parsed.field && parsed.all) {
|
|
271
|
+
// contract v1 的 resource 对应单个 form,不与 --all 批量模式混用。
|
|
272
|
+
if ((parsed.compact || parsed.field) && parsed.all) {
|
|
250
273
|
const { error: chalkError } = require('../core/chalk');
|
|
251
|
-
chalkError('
|
|
274
|
+
chalkError(t('get_schema.usage'), { hint: t('get_schema.example') });
|
|
252
275
|
}
|
|
253
276
|
}
|
|
254
277
|
|
|
@@ -503,21 +526,37 @@ async function runSingle(parsed, authRef) {
|
|
|
503
526
|
banner(t('get_schema.title'));
|
|
504
527
|
label('App', parsed.appType);
|
|
505
528
|
label('Form', parsed.formUuid);
|
|
506
|
-
if (parsed.field) {
|
|
529
|
+
if (parsed.field) {
|
|
530
|
+
label('Field', parsed.field);
|
|
531
|
+
} else if (parsed.fields.length > 0) {
|
|
532
|
+
label('Fields', parsed.fields.join(', '));
|
|
533
|
+
}
|
|
507
534
|
|
|
508
535
|
// Step 2: 获取表单 Schema
|
|
509
536
|
step(2, t('get_schema.step_get'));
|
|
510
537
|
info(t('get_schema.sending'));
|
|
511
538
|
|
|
512
|
-
|
|
539
|
+
let result;
|
|
540
|
+
try {
|
|
541
|
+
result = await fetchSchema(parsed.appType, parsed.formUuid, authRef);
|
|
542
|
+
} catch (error) {
|
|
543
|
+
if (!parsed.compact) {
|
|
544
|
+
throw error;
|
|
545
|
+
}
|
|
546
|
+
chalkResult(false, t('get_schema.failed', t('common.request_failed')));
|
|
547
|
+
process.exit(1);
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
513
550
|
|
|
514
551
|
if (!isSuccessfulSchemaResult(result)) {
|
|
515
|
-
const errorMsg =
|
|
552
|
+
const errorMsg = parsed.compact
|
|
553
|
+
? t('common.request_failed')
|
|
554
|
+
: result ? result.errorMsg || t('common.unknown_error') : t('common.request_failed');
|
|
516
555
|
chalkResult(false, t('get_schema.failed', errorMsg));
|
|
517
556
|
throwCommandError(errorMsg);
|
|
518
557
|
}
|
|
519
558
|
|
|
520
|
-
// --field
|
|
559
|
+
// 保留既有 --field 返回结构;新 contract 仅由 --compact / --resolve-fields 触发。
|
|
521
560
|
if (parsed.field) {
|
|
522
561
|
const allFieldNodes = collectFieldNodes(result);
|
|
523
562
|
const aliasMaps = buildComponentAliasMaps(result);
|
|
@@ -531,18 +570,29 @@ async function runSingle(parsed, authRef) {
|
|
|
531
570
|
}
|
|
532
571
|
const props = matched.props || {};
|
|
533
572
|
const labelRaw = props.label;
|
|
534
|
-
const
|
|
573
|
+
const fieldLabel = labelRaw
|
|
535
574
|
? (typeof labelRaw === 'object' ? (labelRaw.zh_CN || labelRaw.en_US || '') : String(labelRaw))
|
|
536
575
|
: '';
|
|
537
|
-
const
|
|
576
|
+
const legacyField = {
|
|
538
577
|
componentName: matched.componentName,
|
|
539
578
|
fieldId: props.fieldId || '',
|
|
540
579
|
alias: aliasMaps.aliasByFieldId[props.fieldId] || '',
|
|
541
|
-
label,
|
|
580
|
+
label: fieldLabel,
|
|
542
581
|
props,
|
|
543
582
|
};
|
|
544
583
|
chalkSuccess(t('get_schema.success'));
|
|
545
|
-
console.log(JSON.stringify(
|
|
584
|
+
console.log(JSON.stringify(legacyField, null, 2));
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
if (parsed.compact) {
|
|
589
|
+
chalkSuccess(t('get_schema.success'));
|
|
590
|
+
console.log(JSON.stringify(buildFieldResolution(
|
|
591
|
+
parsed.appType,
|
|
592
|
+
parsed.formUuid,
|
|
593
|
+
result,
|
|
594
|
+
parsed.fields
|
|
595
|
+
), null, 2));
|
|
546
596
|
return;
|
|
547
597
|
}
|
|
548
598
|
|
|
@@ -631,6 +681,7 @@ module.exports = {
|
|
|
631
681
|
buildSchemaSummary,
|
|
632
682
|
buildComponentAliasMaps,
|
|
633
683
|
parseArgs,
|
|
684
|
+
appendFieldQueries,
|
|
634
685
|
filterForms,
|
|
635
686
|
mapLimit,
|
|
636
687
|
fetchSchemaRecord,
|
package/lib/app/import-app.js
CHANGED
|
@@ -15,32 +15,37 @@ const {
|
|
|
15
15
|
httpPost,
|
|
16
16
|
requestWithAutoLogin,
|
|
17
17
|
} = require('../core/utils');
|
|
18
|
-
const { createAuthRef } = require('../core/yida-client');
|
|
18
|
+
const { createAuthRef, isTokenAuthRef } = require('../core/yida-client');
|
|
19
19
|
const { t } = require('../core/i18n');
|
|
20
20
|
const { buildYidaI18n, resolveContentLocale } = require('../core/yida-i18n');
|
|
21
21
|
const { banner, step, label, success, fail, warn, info, error, result, usage, hint } = require('../core/chalk');
|
|
22
22
|
const { throwUsage } = require('../core/command-errors');
|
|
23
|
+
const { getSchemaServerRevision } = require('../schema/server-revision');
|
|
24
|
+
const {
|
|
25
|
+
assertLegacyDirectWriteAllowed,
|
|
26
|
+
extractLegacyGuardArgs,
|
|
27
|
+
} = require('../core/legacy-schema-guard');
|
|
23
28
|
|
|
24
29
|
// ── 创建新应用 ────────────────────────────────────────
|
|
25
30
|
|
|
26
31
|
async function createApp(appName, authRef) {
|
|
27
32
|
const contentLocale = resolveContentLocale({ baseUrl: authRef.baseUrl });
|
|
28
|
-
const postData = querystring.stringify({
|
|
29
|
-
appName: JSON.stringify(buildYidaI18n(appName, { en_US: appName, ja_JP: appName })),
|
|
30
|
-
description: JSON.stringify(buildYidaI18n(appName, { en_US: appName, ja_JP: appName })),
|
|
31
|
-
icon: 'xian-yingyong%%#0089FF',
|
|
32
|
-
iconUrl: 'xian-yingyong%%#0089FF',
|
|
33
|
-
colour: 'blue',
|
|
34
|
-
defaultLanguage: contentLocale,
|
|
35
|
-
openExclusive: 'n',
|
|
36
|
-
openPhysicColumn: 'n',
|
|
37
|
-
openIsolationDatabase: 'n',
|
|
38
|
-
openExclusiveUnit: 'n',
|
|
39
|
-
group: 'ALL',
|
|
40
|
-
});
|
|
41
|
-
|
|
42
33
|
const result = await requestWithAutoLogin((auth) => {
|
|
43
|
-
|
|
34
|
+
const postData = querystring.stringify({
|
|
35
|
+
_csrf_token: auth.csrfToken,
|
|
36
|
+
appName: JSON.stringify(buildYidaI18n(appName, { en_US: appName, ja_JP: appName })),
|
|
37
|
+
description: JSON.stringify(buildYidaI18n(appName, { en_US: appName, ja_JP: appName })),
|
|
38
|
+
icon: 'xian-yingyong%%#0089FF',
|
|
39
|
+
iconUrl: 'xian-yingyong%%#0089FF',
|
|
40
|
+
colour: 'blue',
|
|
41
|
+
defaultLanguage: contentLocale,
|
|
42
|
+
openExclusive: 'n',
|
|
43
|
+
openPhysicColumn: 'n',
|
|
44
|
+
openIsolationDatabase: 'n',
|
|
45
|
+
openExclusiveUnit: 'n',
|
|
46
|
+
group: 'ALL',
|
|
47
|
+
});
|
|
48
|
+
return httpPost(auth.baseUrl, '/query/app/registerApp.json', postData, auth.cookies);
|
|
44
49
|
}, authRef);
|
|
45
50
|
|
|
46
51
|
if (!result || !result.success || !result.content) {
|
|
@@ -58,22 +63,30 @@ function normalizeImportFormType(formType) {
|
|
|
58
63
|
return normalized;
|
|
59
64
|
}
|
|
60
65
|
|
|
61
|
-
function
|
|
62
|
-
return
|
|
66
|
+
function buildCreateFormPayload(formTitle, formType = 'receipt') {
|
|
67
|
+
return {
|
|
63
68
|
formType: normalizeImportFormType(formType),
|
|
64
69
|
title: JSON.stringify(buildYidaI18n(formTitle, { en_US: formTitle, ja_JP: formTitle })),
|
|
65
|
-
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function buildCreateFormPostData(formTitle, formType = 'receipt') {
|
|
74
|
+
return querystring.stringify(buildCreateFormPayload(formTitle, formType));
|
|
66
75
|
}
|
|
67
76
|
|
|
68
77
|
// ── 创建空白表单/页面/报表 ──────────────────────────────
|
|
69
78
|
|
|
70
79
|
async function createBlankForm(appType, formTitle, authRef, formType = 'receipt') {
|
|
71
|
-
const postData = buildCreateFormPostData(formTitle, formType);
|
|
72
80
|
const result = await requestWithAutoLogin((auth) => {
|
|
81
|
+
const postData = querystring.stringify({
|
|
82
|
+
_csrf_token: auth.csrfToken,
|
|
83
|
+
...buildCreateFormPayload(formTitle, formType),
|
|
84
|
+
});
|
|
73
85
|
return httpPost(
|
|
74
86
|
auth.baseUrl,
|
|
75
87
|
`/dingtalk/web/${appType}/query/formdesign/saveFormSchemaInfo.json`,
|
|
76
|
-
postData
|
|
88
|
+
postData,
|
|
89
|
+
auth.cookies
|
|
77
90
|
);
|
|
78
91
|
}, authRef);
|
|
79
92
|
|
|
@@ -87,44 +100,72 @@ async function createBlankForm(appType, formTitle, authRef, formType = 'receipt'
|
|
|
87
100
|
|
|
88
101
|
// ── 保存表单 Schema ───────────────────────────────────
|
|
89
102
|
|
|
90
|
-
async function saveFormSchema(appType, formUuid, schema, authRef, formType = 'receipt') {
|
|
103
|
+
async function saveFormSchema(appType, formUuid, schema, authRef, formType = 'receipt', serverRevision) {
|
|
104
|
+
const tokenReady = isTokenAuthRef(authRef);
|
|
105
|
+
const cookieReady = !!(
|
|
106
|
+
authRef &&
|
|
107
|
+
typeof authRef.csrfToken === 'string' &&
|
|
108
|
+
authRef.csrfToken &&
|
|
109
|
+
Array.isArray(authRef.cookies)
|
|
110
|
+
);
|
|
111
|
+
if (!authRef || !authRef.baseUrl || (!tokenReady && !cookieReady)) {
|
|
112
|
+
const err = new Error('Import schema save requires an authenticated request context.');
|
|
113
|
+
err.code = 'IMPORT_SCHEMA_WRITE_PRECHECK_FAILED';
|
|
114
|
+
throw err;
|
|
115
|
+
}
|
|
116
|
+
if (!schema || typeof schema !== 'object' || !Array.isArray(schema.pages)) {
|
|
117
|
+
const err = new Error('Imported schema content must include a pages array before writing.');
|
|
118
|
+
err.code = 'SCHEMA_REMOTE_READ_FAILED';
|
|
119
|
+
throw err;
|
|
120
|
+
}
|
|
121
|
+
if (!Number.isFinite(serverRevision) || serverRevision < 0) {
|
|
122
|
+
const err = new Error('Imported schema revision is missing or invalid.');
|
|
123
|
+
err.code = 'SCHEMA_REMOTE_READ_FAILED';
|
|
124
|
+
throw err;
|
|
125
|
+
}
|
|
126
|
+
|
|
91
127
|
const payload = {
|
|
92
128
|
appType,
|
|
93
129
|
formUuid,
|
|
94
130
|
content: JSON.stringify(schema),
|
|
95
131
|
schemaVersion: 'V5',
|
|
132
|
+
gmtModified: serverRevision,
|
|
96
133
|
};
|
|
97
134
|
if (normalizeImportFormType(formType) === 'report') {
|
|
98
135
|
payload.importSchema = 'true';
|
|
99
136
|
}
|
|
100
|
-
const postData = querystring.stringify(payload);
|
|
101
|
-
|
|
102
|
-
const result = await requestWithAutoLogin((auth) => {
|
|
103
|
-
return httpPost(
|
|
104
|
-
auth.baseUrl,
|
|
105
|
-
`/alibaba/web/${appType}/_view/query/formdesign/saveFormSchema.json`,
|
|
106
|
-
postData
|
|
107
|
-
);
|
|
108
|
-
}, authRef);
|
|
109
137
|
|
|
110
|
-
|
|
138
|
+
const postData = querystring.stringify(Object.assign(
|
|
139
|
+
{},
|
|
140
|
+
authRef.csrfToken ? { _csrf_token: authRef.csrfToken } : {},
|
|
141
|
+
payload
|
|
142
|
+
));
|
|
143
|
+
const authOptions = { projectRoot: authRef.projectRoot };
|
|
144
|
+
return httpPost(
|
|
145
|
+
authRef.baseUrl,
|
|
146
|
+
`/alibaba/web/${appType}/_view/query/formdesign/saveFormSchema.json`,
|
|
147
|
+
postData,
|
|
148
|
+
Array.isArray(authRef.cookies) ? authRef.cookies : authOptions,
|
|
149
|
+
Array.isArray(authRef.cookies) ? authOptions : undefined
|
|
150
|
+
);
|
|
111
151
|
}
|
|
112
152
|
|
|
113
153
|
// ── 更新表单配置(发布表单)─────────────────────────────
|
|
114
154
|
|
|
115
155
|
async function updateFormConfig(appType, formUuid, authRef) {
|
|
116
|
-
const postData = querystring.stringify({
|
|
117
|
-
appType,
|
|
118
|
-
formUuid,
|
|
119
|
-
setting: JSON.stringify({ MINI_RESOURCE: 0 }),
|
|
120
|
-
version: 1,
|
|
121
|
-
});
|
|
122
|
-
|
|
123
156
|
const result = await requestWithAutoLogin((auth) => {
|
|
157
|
+
const postData = querystring.stringify({
|
|
158
|
+
_csrf_token: auth.csrfToken,
|
|
159
|
+
appType,
|
|
160
|
+
formUuid,
|
|
161
|
+
setting: JSON.stringify({ MINI_RESOURCE: 0 }),
|
|
162
|
+
version: 1,
|
|
163
|
+
});
|
|
124
164
|
return httpPost(
|
|
125
165
|
auth.baseUrl,
|
|
126
166
|
`/dingtalk/web/${appType}/query/formdesign/updateFormConfig.json`,
|
|
127
|
-
postData
|
|
167
|
+
postData,
|
|
168
|
+
auth.cookies
|
|
128
169
|
);
|
|
129
170
|
}, authRef);
|
|
130
171
|
|
|
@@ -178,6 +219,8 @@ function extractSchemaContent(schemaResult) {
|
|
|
178
219
|
// ── 主逻辑 ────────────────────────────────────────────
|
|
179
220
|
|
|
180
221
|
async function run(args) {
|
|
222
|
+
const guardSplit = extractLegacyGuardArgs(args || []);
|
|
223
|
+
args = guardSplit.args;
|
|
181
224
|
if (args.length < 1) {
|
|
182
225
|
usage(t('import.usage'));
|
|
183
226
|
hint(t('import.example1'));
|
|
@@ -216,6 +259,11 @@ async function run(args) {
|
|
|
216
259
|
step(2, t('common.step_login_label'));
|
|
217
260
|
const authRef = createAuthRef();
|
|
218
261
|
success(t('common.login_ready', authRef.baseUrl));
|
|
262
|
+
assertLegacyDirectWriteAllowed({
|
|
263
|
+
command: 'import-app',
|
|
264
|
+
resourceType: 'app',
|
|
265
|
+
action: 'create',
|
|
266
|
+
}, { guardOptions: guardSplit.guardOptions });
|
|
219
267
|
|
|
220
268
|
step(3, t('import.step_create_app'));
|
|
221
269
|
let newAppType;
|
|
@@ -288,9 +336,10 @@ async function run(args) {
|
|
|
288
336
|
oldFormUuid,
|
|
289
337
|
newFormUuid
|
|
290
338
|
);
|
|
339
|
+
const serverRevision = getSchemaServerRevision(formSchemaResult);
|
|
291
340
|
|
|
292
341
|
// 4.3 保存 Schema
|
|
293
|
-
const saveResult = await saveFormSchema(newAppType, newFormUuid, adaptedSchema, authRef, formType);
|
|
342
|
+
const saveResult = await saveFormSchema(newAppType, newFormUuid, adaptedSchema, authRef, formType, serverRevision);
|
|
294
343
|
if (!saveResult || !saveResult.success) {
|
|
295
344
|
const errorMsg = saveResult ? saveResult.errorMsg || t('common.unknown_error') : t('common.request_failed');
|
|
296
345
|
fail(t('import.save_schema_failed', errorMsg));
|
|
@@ -369,7 +418,9 @@ module.exports = {
|
|
|
369
418
|
run,
|
|
370
419
|
__test__: {
|
|
371
420
|
normalizeImportFormType,
|
|
421
|
+
buildCreateFormPayload,
|
|
372
422
|
buildCreateFormPostData,
|
|
423
|
+
saveFormSchema,
|
|
373
424
|
adaptSchemaIdentifiers,
|
|
374
425
|
extractSchemaContent,
|
|
375
426
|
},
|