openyida 2026.5.27-beta.1 → 2026.5.27
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 +7 -1
- package/bin/yida.js +20 -0
- package/lib/aggregate-table/aggregate-table.js +594 -0
- package/lib/app/create-form.js +1226 -49
- package/lib/app/get-schema.js +49 -7
- package/lib/core/command-manifest.js +9 -0
- package/lib/core/locales/ar.js +102 -2
- package/lib/core/locales/de.js +102 -2
- package/lib/core/locales/en.js +102 -2
- package/lib/core/locales/es.js +102 -2
- package/lib/core/locales/fr.js +102 -2
- package/lib/core/locales/hi.js +102 -2
- package/lib/core/locales/ja.js +102 -2
- package/lib/core/locales/ko.js +102 -2
- package/lib/core/locales/pt.js +102 -2
- package/lib/core/locales/vi.js +102 -2
- package/lib/core/locales/zh-HK.js +102 -2
- package/lib/core/locales/zh.js +102 -2
- package/lib/core/query-data.js +171 -20
- package/lib/page-config/save-share-config.js +1 -1
- package/lib/page-config/verify-short-url.js +4 -4
- package/lib/process/ai-form-setting.js +783 -0
- package/package.json +1 -1
- package/yida-skills/SKILL.md +3 -0
- package/yida-skills/skills/yida-data-management/SKILL.md +14 -12
- package/yida-skills/skills/yida-page-config/SKILL.md +3 -2
package/README.md
CHANGED
|
@@ -312,9 +312,12 @@ For overseas apps, pass `--locale en_US` or `--locale ja_JP` on creation command
|
|
|
312
312
|
| `openyida create-form update <appType> <formUuid> <changes.json> [--locale zh_CN\|en_US\|ja_JP] [--open\|--no-open]` | Update a form page |
|
|
313
313
|
| `openyida create-form patch <appType> <formUuid> <patch.json> [--open\|--no-open]` | Apply controlled schema patches for designer-only form settings |
|
|
314
314
|
| `openyida create-form rule <appType> <formUuid> <rules.json> [--open\|--no-open]` | Configure field show/hide linkage and onChange auto-assignment rules |
|
|
315
|
+
| `openyida create-form validation <appType> <formUuid> <validations.json> [--open\|--no-open]` | Configure form validations using Yida-visible field `props.validation` rules and `customValidate` JSExpression functions for regex, bank card, cross-field, conditional, or async checks |
|
|
316
|
+
| `openyida add-validation <appType> <formUuid> --field <labelOrId> --type <phone\|regex\|idCard\|email\|...> [--message <text>]` | Add one smart validation rule without writing a JSON file |
|
|
315
317
|
| `openyida create-form bind-datasource <appType> <formUuid> <fieldLabelOrId> <datasource.json> [--open\|--no-open]` | Bind URL/search data sources to SelectField/MultiSelectField-style option fields |
|
|
316
318
|
| `openyida create-form add-option <appType> <formUuid> <fieldLabel> <option1> [option2] ...` | Append options to a SelectField/RadioField/CheckboxField/MultiSelectField |
|
|
317
319
|
| `openyida list-forms <appType> [--keyword <text>]` | List forms in an application |
|
|
320
|
+
| `openyida aggregate-table <list\|create-empty\|inspect\|preview\|save\|publish\|status> <appType> ...` | Manage Yida aggregate tables (`virtualView`) |
|
|
318
321
|
| `openyida get-schema <appType> <formUuid\|--all> [--field <labelOrFieldId>]` | Fetch one form schema, batch export all, or pick a single field's full props |
|
|
319
322
|
| `openyida create-page <appType> "<name>" [--mode dashboard] [--locale zh_CN\|en_US\|ja_JP] [--open\|--no-open]` | Create a custom display page; dashboard mode hides top/workbench chrome |
|
|
320
323
|
| `openyida generate-page <template> [--spec file]` | Generate custom page source from templates (`product-homepage`, `todo-mvc`) |
|
|
@@ -324,13 +327,15 @@ For overseas apps, pass `--locale en_US` or `--locale ja_JP` on creation command
|
|
|
324
327
|
| `openyida publish <sourceFile> <appType> <formUuid> [--compat] [--health-check] [--force] [--open\|--no-open]` | Compile and publish a custom display page; by default the target must be `formType=display` |
|
|
325
328
|
| `openyida update-form-config <appType> <formUuid> <isRenderNav> <title> [--locale zh_CN\|en_US\|ja_JP]` | Update page/form display configuration |
|
|
326
329
|
|
|
330
|
+
Form field definitions can include `alias` or `componentAlias` to populate Yida designer component aliases, stored as `pages[0].componentAlias.items`. Yida runtime resolves these aliases in page JS, so `this.$('phone')` can be used instead of `this.$('textField_xxx')`; OpenYida form rules, validations, and `openyida data ... --resolve-aliases` JSON inputs also accept aliases as field references. For server-side DingTalk OpenAPI calls, use `GET /v2.0/yida/forms/component/alias/{appType}/{formUuid}` to read the `{ fieldId, alias }` mapping, then translate aliases before sending form data/search JSON. That endpoint requires `systemToken`, `userId`, an access token, and the Yida form data read permission; grant that permission in DingTalk developer console API permissions and publish the DingTalk app. Yida app code and app secret are available under app settings > deployment/maintenance.
|
|
331
|
+
|
|
327
332
|
`openyida publish` preserves existing custom page data sources by default. Before saving the new compiled JSX Schema, it reads the current page Schema and merges the Page-level `dataSource` with the built-in `urlParams` and `timestamp` sources, so manually configured data sources are not deleted during republish.
|
|
328
333
|
|
|
329
334
|
### Data, Permissions, and Sharing
|
|
330
335
|
|
|
331
336
|
| Command | Description |
|
|
332
337
|
|---------|-------------|
|
|
333
|
-
| `openyida data <action> <resource> [args]` | Unified data management for forms, processes, tasks, and subforms; form queries support `--all
|
|
338
|
+
| `openyida data <action> <resource> [args]` | Unified data management for forms, processes, tasks, and subforms; form queries support `--all`, `--form-uuid` subform hydration, and `--resolve-aliases` for component alias JSON keys |
|
|
334
339
|
| `openyida data check <appType> <formUuid> <rules.json>` | Detect anomalous process-form records |
|
|
335
340
|
| `openyida task-center <type> [options]` | Query todo, created, processed, CC, or proxy-submitted tasks |
|
|
336
341
|
| `openyida agent-center <sub-command>` | Manage Yida process delegation and departure delegation |
|
|
@@ -351,6 +356,7 @@ For overseas apps, pass `--locale en_US` or `--locale ja_JP` on creation command
|
|
|
351
356
|
|---------|-------------|
|
|
352
357
|
| `openyida create-process <appType> ...` | Create a process form and configure workflow |
|
|
353
358
|
| `openyida configure-process <appType> ...` | Configure and publish process rules |
|
|
359
|
+
| `openyida ai-form-setting <get\|fields\|models\|enable\|disable\|save> <appType> ...` | Manage process-form AI approval prompts from `/settings/aiFormSetting` |
|
|
354
360
|
| `openyida process preview <appType> <processInstanceId> [--output <path>]` | Generate a visual process preview |
|
|
355
361
|
| `openyida create-report <appType> "<name>" <charts.json> [--open\|--no-open]` | Create a Yida report |
|
|
356
362
|
| `openyida append-chart <appType> <reportId> <charts.json> [--open\|--no-open]` | Append a chart to an existing report |
|
package/bin/yida.js
CHANGED
|
@@ -642,12 +642,24 @@ async function main() {
|
|
|
642
642
|
break;
|
|
643
643
|
}
|
|
644
644
|
|
|
645
|
+
case 'add-validation': {
|
|
646
|
+
process.argv = [process.argv[0], process.argv[1], 'validation', ...args];
|
|
647
|
+
require('../lib/app/create-form');
|
|
648
|
+
break;
|
|
649
|
+
}
|
|
650
|
+
|
|
645
651
|
case 'list-forms': {
|
|
646
652
|
const { run } = require('../lib/app/list-forms');
|
|
647
653
|
await run(args);
|
|
648
654
|
break;
|
|
649
655
|
}
|
|
650
656
|
|
|
657
|
+
case 'aggregate-table': {
|
|
658
|
+
const { run } = require('../lib/aggregate-table/aggregate-table');
|
|
659
|
+
await run(args);
|
|
660
|
+
break;
|
|
661
|
+
}
|
|
662
|
+
|
|
651
663
|
case 'get-schema': {
|
|
652
664
|
const { run } = require('../lib/app/get-schema');
|
|
653
665
|
await run(args);
|
|
@@ -881,6 +893,14 @@ async function main() {
|
|
|
881
893
|
break;
|
|
882
894
|
}
|
|
883
895
|
|
|
896
|
+
case 'ai-form-setting':
|
|
897
|
+
case 'ai-approve':
|
|
898
|
+
case 'aiFormSetting': {
|
|
899
|
+
const { run: runAIFormSetting } = require('../lib/process/ai-form-setting');
|
|
900
|
+
await runAIFormSetting(args);
|
|
901
|
+
break;
|
|
902
|
+
}
|
|
903
|
+
|
|
884
904
|
case 'process': {
|
|
885
905
|
const subCommand = args[0];
|
|
886
906
|
const subArgs = args.slice(1);
|
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const querystring = require('querystring');
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
loadCookieData,
|
|
8
|
+
triggerLogin,
|
|
9
|
+
resolveBaseUrl,
|
|
10
|
+
httpGet,
|
|
11
|
+
httpPost,
|
|
12
|
+
requestWithAutoLogin,
|
|
13
|
+
} = require('../core/utils');
|
|
14
|
+
const { t } = require('../core/i18n');
|
|
15
|
+
const { buildYidaTitleI18n, normalizeYidaLocale, resolveContentLocale } = require('../core/yida-i18n');
|
|
16
|
+
const { parseOpenOption, withBrowserHandoff } = require('../core/browser-handoff');
|
|
17
|
+
const { fetchFormPageList, resolveLocalizedText } = require('../app/form-navigation');
|
|
18
|
+
|
|
19
|
+
const FORM_TYPE_VIRTUAL_VIEW = 'virtualView';
|
|
20
|
+
const DESIGN_KEYS = [
|
|
21
|
+
'relationForms',
|
|
22
|
+
'relationships',
|
|
23
|
+
'aggregatedFields',
|
|
24
|
+
'auxFields',
|
|
25
|
+
'formulaFields',
|
|
26
|
+
'validators',
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
function hasHelpFlag(args) {
|
|
30
|
+
return (args || []).includes('--help') || (args || []).includes('-h');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function printUsage() {
|
|
34
|
+
process.stderr.write([
|
|
35
|
+
t('aggregate_table.usage'),
|
|
36
|
+
'',
|
|
37
|
+
t('aggregate_table.commands_title'),
|
|
38
|
+
` ${t('aggregate_table.cmd_list')}`,
|
|
39
|
+
` ${t('aggregate_table.cmd_create_empty')}`,
|
|
40
|
+
` ${t('aggregate_table.cmd_inspect')}`,
|
|
41
|
+
` ${t('aggregate_table.cmd_preview')}`,
|
|
42
|
+
` ${t('aggregate_table.cmd_save')}`,
|
|
43
|
+
` ${t('aggregate_table.cmd_publish')}`,
|
|
44
|
+
` ${t('aggregate_table.cmd_status')}`,
|
|
45
|
+
'',
|
|
46
|
+
t('aggregate_table.examples_title'),
|
|
47
|
+
` ${t('aggregate_table.example_list')}`,
|
|
48
|
+
` ${t('aggregate_table.example_create_empty')}`,
|
|
49
|
+
` ${t('aggregate_table.example_inspect')}`,
|
|
50
|
+
'',
|
|
51
|
+
].join('\n'));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function parseFlags(args) {
|
|
55
|
+
const openOption = parseOpenOption(args || []);
|
|
56
|
+
const positional = [];
|
|
57
|
+
const flags = {
|
|
58
|
+
json: false,
|
|
59
|
+
keyword: '',
|
|
60
|
+
locale: null,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
for (let index = 0; index < openOption.args.length; index++) {
|
|
64
|
+
const arg = openOption.args[index];
|
|
65
|
+
if (arg === '--json') {
|
|
66
|
+
flags.json = true;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (arg === '--keyword' && openOption.args[index + 1]) {
|
|
70
|
+
flags.keyword = openOption.args[++index];
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if ((arg === '--locale' || arg === '--content-locale' || arg === '--lang') && openOption.args[index + 1]) {
|
|
74
|
+
const locale = openOption.args[++index];
|
|
75
|
+
if (!normalizeYidaLocale(locale)) {
|
|
76
|
+
throw new Error(t('aggregate_table.unsupported_locale', locale));
|
|
77
|
+
}
|
|
78
|
+
flags.locale = locale;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
positional.push(arg);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
flags.openMode = openOption.mode;
|
|
85
|
+
return { positional, flags };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function unwrapContent(result) {
|
|
89
|
+
if (result && Object.prototype.hasOwnProperty.call(result, 'content')) {
|
|
90
|
+
return result.content;
|
|
91
|
+
}
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function assertSuccess(result, action) {
|
|
96
|
+
if (!result || result.success === false || result.__needLogin || result.__csrfExpired) {
|
|
97
|
+
const message = result
|
|
98
|
+
? result.errorMsg || result.error || result.message || t('common.unknown_error')
|
|
99
|
+
: t('common.request_failed');
|
|
100
|
+
throw new Error(`${action}: ${message}`);
|
|
101
|
+
}
|
|
102
|
+
return unwrapContent(result);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function createAuthRef() {
|
|
106
|
+
let cookieData = loadCookieData();
|
|
107
|
+
if (!cookieData) {
|
|
108
|
+
cookieData = await triggerLogin();
|
|
109
|
+
}
|
|
110
|
+
if (!cookieData || !cookieData.cookies) {
|
|
111
|
+
throw new Error(t('aggregate_table.no_login'));
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
csrfToken: cookieData.csrf_token,
|
|
115
|
+
cookies: cookieData.cookies,
|
|
116
|
+
baseUrl: resolveBaseUrl(cookieData),
|
|
117
|
+
cookieData,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function buildCreateEmptyPostData(csrfToken, title) {
|
|
122
|
+
return querystring.stringify({
|
|
123
|
+
_csrf_token: csrfToken,
|
|
124
|
+
formType: 'receipt',
|
|
125
|
+
isVirtualView: 'y',
|
|
126
|
+
title: JSON.stringify(buildYidaTitleI18n(title, {
|
|
127
|
+
en_US: title,
|
|
128
|
+
ja_JP: title,
|
|
129
|
+
})),
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function buildDesignPostData(csrfToken, formUuid, designInfo, gmtModified) {
|
|
134
|
+
const payload = {
|
|
135
|
+
_csrf_token: csrfToken,
|
|
136
|
+
formUuid,
|
|
137
|
+
designInfo: JSON.stringify(designInfo),
|
|
138
|
+
};
|
|
139
|
+
if (gmtModified !== undefined) {
|
|
140
|
+
payload.gmtModified = gmtModified === null ? '' : gmtModified;
|
|
141
|
+
}
|
|
142
|
+
return querystring.stringify(payload);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async function checkVirtualViewFeature(authRef, appType) {
|
|
146
|
+
return requestWithAutoLogin((auth) => {
|
|
147
|
+
return httpPost(
|
|
148
|
+
auth.baseUrl,
|
|
149
|
+
`/dingtalk/web/${appType}/query/virtualview/show.json`,
|
|
150
|
+
querystring.stringify({ _csrf_token: auth.csrfToken }),
|
|
151
|
+
auth.cookies
|
|
152
|
+
);
|
|
153
|
+
}, authRef);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async function createEmptyVirtualView(authRef, appType, title) {
|
|
157
|
+
return requestWithAutoLogin((auth) => {
|
|
158
|
+
return httpPost(
|
|
159
|
+
auth.baseUrl,
|
|
160
|
+
`/dingtalk/web/${appType}/query/formdesign/saveFormSchemaInfo.json`,
|
|
161
|
+
buildCreateEmptyPostData(auth.csrfToken, title),
|
|
162
|
+
auth.cookies
|
|
163
|
+
);
|
|
164
|
+
}, authRef);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async function getVirtualViewConfig(authRef, appType, formUuid) {
|
|
168
|
+
return requestWithAutoLogin((auth) => {
|
|
169
|
+
return httpGet(
|
|
170
|
+
auth.baseUrl,
|
|
171
|
+
`/alibaba/web/${appType}/query/virtualview/get.json`,
|
|
172
|
+
{ formUuid },
|
|
173
|
+
auth.cookies
|
|
174
|
+
);
|
|
175
|
+
}, authRef);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async function postVirtualViewDesign(authRef, appType, formUuid, designInfo, action, gmtModified) {
|
|
179
|
+
const endpointMap = {
|
|
180
|
+
preview: 'preview.json',
|
|
181
|
+
save: 'saveStashConfig.json',
|
|
182
|
+
publish: 'update.json',
|
|
183
|
+
};
|
|
184
|
+
const endpoint = endpointMap[action];
|
|
185
|
+
if (!endpoint) {
|
|
186
|
+
throw new Error(`Unknown aggregate table action: ${action}`);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return requestWithAutoLogin((auth) => {
|
|
190
|
+
return httpPost(
|
|
191
|
+
auth.baseUrl,
|
|
192
|
+
`/alibaba/web/${appType}/query/virtualview/${endpoint}`,
|
|
193
|
+
buildDesignPostData(auth.csrfToken, formUuid, designInfo, gmtModified),
|
|
194
|
+
auth.cookies
|
|
195
|
+
);
|
|
196
|
+
}, authRef);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
async function queryBuildState(authRef, appType, formUuid) {
|
|
200
|
+
return requestWithAutoLogin((auth) => {
|
|
201
|
+
return httpGet(
|
|
202
|
+
auth.baseUrl,
|
|
203
|
+
`/alibaba/web/${appType}/query/virtualview/queryBuildState.json`,
|
|
204
|
+
{ formUuid },
|
|
205
|
+
auth.cookies
|
|
206
|
+
);
|
|
207
|
+
}, authRef);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function isVirtualViewNode(node) {
|
|
211
|
+
return node && node.formType === FORM_TYPE_VIRTUAL_VIEW;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function filterAggregateTables(items, keyword) {
|
|
215
|
+
const aggregateTables = (items || []).filter(isVirtualViewNode);
|
|
216
|
+
if (!keyword) {
|
|
217
|
+
return aggregateTables;
|
|
218
|
+
}
|
|
219
|
+
const normalized = String(keyword).toLowerCase();
|
|
220
|
+
return aggregateTables.filter((item) => {
|
|
221
|
+
return [item.formName, item.formUuid, item.pathName]
|
|
222
|
+
.filter(Boolean)
|
|
223
|
+
.some((value) => String(value).toLowerCase().includes(normalized));
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function normalizeAggregateTableNode(node) {
|
|
228
|
+
return {
|
|
229
|
+
formUuid: node.formUuid,
|
|
230
|
+
aggregateTableId: node.formUuid,
|
|
231
|
+
name: node.formName || '',
|
|
232
|
+
formType: FORM_TYPE_VIRTUAL_VIEW,
|
|
233
|
+
pathName: node.pathName || '',
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function readJsonInput(input) {
|
|
238
|
+
if (!input) {
|
|
239
|
+
throw new Error(t('aggregate_table.design_required'));
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
let raw = input;
|
|
243
|
+
if (fs.existsSync(input)) {
|
|
244
|
+
raw = fs.readFileSync(input, 'utf8');
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
try {
|
|
248
|
+
return JSON.parse(raw);
|
|
249
|
+
} catch (err) {
|
|
250
|
+
throw new Error(t('aggregate_table.invalid_json', err.message));
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function normalizeDesignConfig(rawConfig, formUuid) {
|
|
255
|
+
let config = rawConfig;
|
|
256
|
+
|
|
257
|
+
if (config && typeof config.designInfo === 'string') {
|
|
258
|
+
config = JSON.parse(config.designInfo);
|
|
259
|
+
} else if (config && config.designInfo && typeof config.designInfo === 'object') {
|
|
260
|
+
config = config.designInfo;
|
|
261
|
+
} else if (config && config.viewDesignConfig) {
|
|
262
|
+
config = config.viewDesignConfig;
|
|
263
|
+
} else if (config && Object.prototype.hasOwnProperty.call(config, 'content')) {
|
|
264
|
+
config = config.content && config.content.viewDesignConfig
|
|
265
|
+
? config.content.viewDesignConfig
|
|
266
|
+
: config.content;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (!config || typeof config !== 'object' || Array.isArray(config)) {
|
|
270
|
+
throw new Error(t('aggregate_table.design_object_required'));
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const normalized = { formUuid };
|
|
274
|
+
for (const key of DESIGN_KEYS) {
|
|
275
|
+
normalized[key] = Array.isArray(config[key]) ? config[key] : [];
|
|
276
|
+
}
|
|
277
|
+
return normalized;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function summarizeDesignConfig(config) {
|
|
281
|
+
const safeConfig = config || {};
|
|
282
|
+
return {
|
|
283
|
+
formUuid: safeConfig.formUuid || '',
|
|
284
|
+
title: resolveLocalizedText(safeConfig.title, ''),
|
|
285
|
+
isStashConfig: safeConfig.isStashConfig || '',
|
|
286
|
+
gmtModified: safeConfig.gmtModified || null,
|
|
287
|
+
stashGmtModified: safeConfig.stashGmtModified || null,
|
|
288
|
+
counts: {
|
|
289
|
+
relationForms: Array.isArray(safeConfig.relationForms) ? safeConfig.relationForms.length : 0,
|
|
290
|
+
relationships: Array.isArray(safeConfig.relationships) ? safeConfig.relationships.length : 0,
|
|
291
|
+
aggregatedFields: Array.isArray(safeConfig.aggregatedFields) ? safeConfig.aggregatedFields.length : 0,
|
|
292
|
+
auxFields: Array.isArray(safeConfig.auxFields) ? safeConfig.auxFields.length : 0,
|
|
293
|
+
formulaFields: Array.isArray(safeConfig.formulaFields) ? safeConfig.formulaFields.length : 0,
|
|
294
|
+
validators: Array.isArray(safeConfig.validators) ? safeConfig.validators.length : 0,
|
|
295
|
+
},
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function buildDesignUrl(baseUrl, appType, formUuid, options = {}) {
|
|
300
|
+
const suffix = options.fromNew ? '&fromNew=true' : '';
|
|
301
|
+
return `${baseUrl}/alibaba/web/${appType}/design/virtualViewDesigner.html?formUuid=${formUuid}${suffix}`;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function buildWorkbenchUrl(baseUrl, appType, formUuid) {
|
|
305
|
+
return `${baseUrl}/${appType}/workbench/${formUuid}`;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function printSummary(title, rows) {
|
|
309
|
+
const { result } = require('../core/chalk');
|
|
310
|
+
result(true, title, rows);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
async function runList(args) {
|
|
314
|
+
const { positional, flags } = parseFlags(args);
|
|
315
|
+
const appType = positional[0];
|
|
316
|
+
if (!appType) {
|
|
317
|
+
const { error } = require('../core/chalk');
|
|
318
|
+
error(t('aggregate_table.list_usage'), { hint: t('aggregate_table.example_list') });
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const authRef = await createAuthRef();
|
|
323
|
+
const items = await fetchFormPageList(appType, authRef);
|
|
324
|
+
const aggregateTables = filterAggregateTables(items, flags.keyword).map(normalizeAggregateTableNode);
|
|
325
|
+
|
|
326
|
+
if (!flags.json) {
|
|
327
|
+
printSummary(t('aggregate_table.list_success'), [
|
|
328
|
+
['App', appType],
|
|
329
|
+
['Count', String(aggregateTables.length)],
|
|
330
|
+
]);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
console.log(JSON.stringify(aggregateTables, null, 2));
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
async function runCreateEmpty(args) {
|
|
337
|
+
const { positional, flags } = parseFlags(args);
|
|
338
|
+
const appType = positional[0];
|
|
339
|
+
const name = positional[1];
|
|
340
|
+
if (!appType || !name) {
|
|
341
|
+
const { error } = require('../core/chalk');
|
|
342
|
+
error(t('aggregate_table.create_empty_usage'), { hint: t('aggregate_table.example_create_empty') });
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const authRef = await createAuthRef();
|
|
347
|
+
const contentLocale = resolveContentLocale({ locale: flags.locale, baseUrl: authRef.baseUrl });
|
|
348
|
+
|
|
349
|
+
const featureResult = await checkVirtualViewFeature(authRef, appType);
|
|
350
|
+
const featureEnabled = assertSuccess(featureResult, t('aggregate_table.check_feature'));
|
|
351
|
+
if (featureEnabled !== true) {
|
|
352
|
+
throw new Error(t('aggregate_table.feature_disabled'));
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const createResult = await createEmptyVirtualView(authRef, appType, name);
|
|
356
|
+
const created = assertSuccess(createResult, t('aggregate_table.create_empty'));
|
|
357
|
+
const formUuid = (created && created.formUuid) || created;
|
|
358
|
+
const designUrl = buildDesignUrl(authRef.baseUrl, appType, formUuid, { fromNew: true });
|
|
359
|
+
const workbenchUrl = buildWorkbenchUrl(authRef.baseUrl, appType, formUuid);
|
|
360
|
+
|
|
361
|
+
printSummary(t('aggregate_table.create_empty_success'), [
|
|
362
|
+
['App', appType],
|
|
363
|
+
['Aggregate Table ID', formUuid],
|
|
364
|
+
['Locale', contentLocale],
|
|
365
|
+
['Design URL', designUrl],
|
|
366
|
+
]);
|
|
367
|
+
|
|
368
|
+
console.log(JSON.stringify(withBrowserHandoff({
|
|
369
|
+
success: true,
|
|
370
|
+
appType,
|
|
371
|
+
aggregateTableId: formUuid,
|
|
372
|
+
formUuid,
|
|
373
|
+
name,
|
|
374
|
+
formType: FORM_TYPE_VIRTUAL_VIEW,
|
|
375
|
+
locale: contentLocale,
|
|
376
|
+
designUrl,
|
|
377
|
+
workbenchUrl,
|
|
378
|
+
}, designUrl, { stage: 'aggregate_table_create_empty_success', title: name }, flags.openMode)));
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
async function runInspect(args) {
|
|
382
|
+
const { positional, flags } = parseFlags(args);
|
|
383
|
+
const appType = positional[0];
|
|
384
|
+
const formUuid = positional[1];
|
|
385
|
+
if (!appType || !formUuid) {
|
|
386
|
+
const { error } = require('../core/chalk');
|
|
387
|
+
error(t('aggregate_table.inspect_usage'), { hint: t('aggregate_table.example_inspect') });
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const authRef = await createAuthRef();
|
|
392
|
+
const result = await getVirtualViewConfig(authRef, appType, formUuid);
|
|
393
|
+
const config = assertSuccess(result, t('aggregate_table.inspect'));
|
|
394
|
+
const summary = summarizeDesignConfig(config);
|
|
395
|
+
|
|
396
|
+
if (!flags.json) {
|
|
397
|
+
printSummary(t('aggregate_table.inspect_success'), [
|
|
398
|
+
['App', appType],
|
|
399
|
+
['Aggregate Table ID', formUuid],
|
|
400
|
+
['Data Sources', String(summary.counts.relationForms)],
|
|
401
|
+
['Relationships', String(summary.counts.relationships)],
|
|
402
|
+
['Metrics', String(summary.counts.formulaFields)],
|
|
403
|
+
['Validators', String(summary.counts.validators)],
|
|
404
|
+
]);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
console.log(JSON.stringify({
|
|
408
|
+
success: true,
|
|
409
|
+
appType,
|
|
410
|
+
aggregateTableId: formUuid,
|
|
411
|
+
formUuid,
|
|
412
|
+
summary,
|
|
413
|
+
config,
|
|
414
|
+
}, null, 2));
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
async function loadDesignForMutation(authRef, appType, formUuid, input, action) {
|
|
418
|
+
const rawConfig = readJsonInput(input);
|
|
419
|
+
const designInfo = normalizeDesignConfig(rawConfig, formUuid);
|
|
420
|
+
const currentResult = await getVirtualViewConfig(authRef, appType, formUuid);
|
|
421
|
+
const currentConfig = assertSuccess(currentResult, t('aggregate_table.inspect'));
|
|
422
|
+
const gmtModified = action === 'save'
|
|
423
|
+
? currentConfig.stashGmtModified
|
|
424
|
+
: currentConfig.gmtModified;
|
|
425
|
+
return { designInfo, currentConfig, gmtModified };
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
async function runPreview(args) {
|
|
429
|
+
const { positional, flags } = parseFlags(args);
|
|
430
|
+
const appType = positional[0];
|
|
431
|
+
const formUuid = positional[1];
|
|
432
|
+
const input = positional[2];
|
|
433
|
+
if (!appType || !formUuid || !input) {
|
|
434
|
+
const { error } = require('../core/chalk');
|
|
435
|
+
error(t('aggregate_table.preview_usage'), { hint: t('aggregate_table.example_preview') });
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
const authRef = await createAuthRef();
|
|
440
|
+
const designInfo = normalizeDesignConfig(readJsonInput(input), formUuid);
|
|
441
|
+
const result = await postVirtualViewDesign(authRef, appType, formUuid, designInfo, 'preview');
|
|
442
|
+
const rows = assertSuccess(result, t('aggregate_table.preview'));
|
|
443
|
+
const rowCount = Array.isArray(rows) ? rows.length : 0;
|
|
444
|
+
|
|
445
|
+
if (!flags.json) {
|
|
446
|
+
printSummary(t('aggregate_table.preview_success'), [
|
|
447
|
+
['App', appType],
|
|
448
|
+
['Aggregate Table ID', formUuid],
|
|
449
|
+
['Rows', String(rowCount)],
|
|
450
|
+
]);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
console.log(JSON.stringify({
|
|
454
|
+
success: true,
|
|
455
|
+
appType,
|
|
456
|
+
aggregateTableId: formUuid,
|
|
457
|
+
formUuid,
|
|
458
|
+
rowCount,
|
|
459
|
+
rows,
|
|
460
|
+
}, null, 2));
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
async function runSaveOrPublish(args, action) {
|
|
464
|
+
const { positional, flags } = parseFlags(args);
|
|
465
|
+
const appType = positional[0];
|
|
466
|
+
const formUuid = positional[1];
|
|
467
|
+
const input = positional[2];
|
|
468
|
+
const isPublish = action === 'publish';
|
|
469
|
+
if (!appType || !formUuid || !input) {
|
|
470
|
+
const { error } = require('../core/chalk');
|
|
471
|
+
error(
|
|
472
|
+
isPublish ? t('aggregate_table.publish_usage') : t('aggregate_table.save_usage'),
|
|
473
|
+
{ hint: isPublish ? t('aggregate_table.example_publish') : t('aggregate_table.example_save') }
|
|
474
|
+
);
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const authRef = await createAuthRef();
|
|
479
|
+
const { designInfo, gmtModified } = await loadDesignForMutation(authRef, appType, formUuid, input, action);
|
|
480
|
+
if (isPublish && designInfo.relationForms.length === 0) {
|
|
481
|
+
throw new Error(t('aggregate_table.publish_requires_source'));
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
const result = await postVirtualViewDesign(authRef, appType, formUuid, designInfo, action, gmtModified);
|
|
485
|
+
const content = assertSuccess(result, isPublish ? t('aggregate_table.publish') : t('aggregate_table.save'));
|
|
486
|
+
const designUrl = buildDesignUrl(authRef.baseUrl, appType, formUuid);
|
|
487
|
+
const workbenchUrl = buildWorkbenchUrl(authRef.baseUrl, appType, formUuid);
|
|
488
|
+
|
|
489
|
+
if (!flags.json) {
|
|
490
|
+
printSummary(isPublish ? t('aggregate_table.publish_success') : t('aggregate_table.save_success'), [
|
|
491
|
+
['App', appType],
|
|
492
|
+
['Aggregate Table ID', formUuid],
|
|
493
|
+
['Design URL', designUrl],
|
|
494
|
+
]);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
console.log(JSON.stringify(withBrowserHandoff({
|
|
498
|
+
success: true,
|
|
499
|
+
action,
|
|
500
|
+
appType,
|
|
501
|
+
aggregateTableId: formUuid,
|
|
502
|
+
formUuid,
|
|
503
|
+
gmtModified: content && content.gmtModified,
|
|
504
|
+
response: content,
|
|
505
|
+
designUrl,
|
|
506
|
+
workbenchUrl,
|
|
507
|
+
}, designUrl, { stage: `aggregate_table_${action}_success`, title: formUuid }, flags.openMode), null, 2));
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
async function runStatus(args) {
|
|
511
|
+
const { positional, flags } = parseFlags(args);
|
|
512
|
+
const appType = positional[0];
|
|
513
|
+
const formUuid = positional[1];
|
|
514
|
+
if (!appType || !formUuid) {
|
|
515
|
+
const { error } = require('../core/chalk');
|
|
516
|
+
error(t('aggregate_table.status_usage'), { hint: t('aggregate_table.example_status') });
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
const authRef = await createAuthRef();
|
|
521
|
+
const result = await queryBuildState(authRef, appType, formUuid);
|
|
522
|
+
const content = assertSuccess(result, t('aggregate_table.status'));
|
|
523
|
+
|
|
524
|
+
if (!flags.json) {
|
|
525
|
+
printSummary(t('aggregate_table.status_success'), [
|
|
526
|
+
['App', appType],
|
|
527
|
+
['Aggregate Table ID', formUuid],
|
|
528
|
+
['Status', (content && content.status) || String(content || '')],
|
|
529
|
+
]);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
console.log(JSON.stringify({
|
|
533
|
+
success: true,
|
|
534
|
+
appType,
|
|
535
|
+
aggregateTableId: formUuid,
|
|
536
|
+
formUuid,
|
|
537
|
+
status: content && content.status,
|
|
538
|
+
result: content,
|
|
539
|
+
}, null, 2));
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
async function run(args) {
|
|
543
|
+
if (!args || args.length === 0 || hasHelpFlag(args)) {
|
|
544
|
+
printUsage();
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
const subCommand = args[0];
|
|
549
|
+
const subArgs = args.slice(1);
|
|
550
|
+
switch (subCommand) {
|
|
551
|
+
case 'list':
|
|
552
|
+
return runList(subArgs);
|
|
553
|
+
case 'create':
|
|
554
|
+
case 'create-empty':
|
|
555
|
+
return runCreateEmpty(subArgs);
|
|
556
|
+
case 'inspect':
|
|
557
|
+
case 'get':
|
|
558
|
+
return runInspect(subArgs);
|
|
559
|
+
case 'preview':
|
|
560
|
+
return runPreview(subArgs);
|
|
561
|
+
case 'save':
|
|
562
|
+
return runSaveOrPublish(subArgs, 'save');
|
|
563
|
+
case 'publish':
|
|
564
|
+
return runSaveOrPublish(subArgs, 'publish');
|
|
565
|
+
case 'status':
|
|
566
|
+
return runStatus(subArgs);
|
|
567
|
+
default: {
|
|
568
|
+
const { error } = require('../core/chalk');
|
|
569
|
+
error(t('aggregate_table.unknown_subcommand', subCommand), { hint: t('aggregate_table.usage') });
|
|
570
|
+
return null;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
module.exports = {
|
|
576
|
+
DESIGN_KEYS,
|
|
577
|
+
FORM_TYPE_VIRTUAL_VIEW,
|
|
578
|
+
buildCreateEmptyPostData,
|
|
579
|
+
buildDesignPostData,
|
|
580
|
+
filterAggregateTables,
|
|
581
|
+
normalizeAggregateTableNode,
|
|
582
|
+
normalizeDesignConfig,
|
|
583
|
+
parseFlags,
|
|
584
|
+
readJsonInput,
|
|
585
|
+
summarizeDesignConfig,
|
|
586
|
+
run,
|
|
587
|
+
__api__: {
|
|
588
|
+
checkVirtualViewFeature,
|
|
589
|
+
createEmptyVirtualView,
|
|
590
|
+
getVirtualViewConfig,
|
|
591
|
+
postVirtualViewDesign,
|
|
592
|
+
queryBuildState,
|
|
593
|
+
},
|
|
594
|
+
};
|