openyida 2026.7.30 → 2026.8.3
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 +12 -9
- package/bin/yida.js +6 -1
- package/docs/capabilities.md +10 -5
- package/lib/ai/ai.js +2 -2
- package/lib/app/canvas-compile.js +5 -7
- package/lib/app/create-app.js +6 -6
- package/lib/app/create-form/args.js +18 -0
- package/lib/app/create-form.js +37 -16
- package/lib/app/create-page.js +32 -5
- package/lib/app/generate-page.js +123 -2
- package/lib/app/nav-group.js +117 -0
- package/lib/app/page-ir.js +64 -38
- package/lib/app/publish.js +25 -4
- package/lib/app/theme-presets.js +96 -1
- package/lib/bridge/bridge.js +28 -4
- package/lib/core/browser-handoff.js +1 -1
- package/lib/core/command-contract.js +558 -0
- package/lib/core/command-manifest.js +107 -9
- package/lib/core/doctor.js +2 -2
- package/lib/core/env-cmd.js +1 -1
- package/lib/core/env.js +1 -0
- package/lib/core/locales/en.js +20 -16
- package/lib/core/locales/zh.js +22 -18
- package/lib/core/utils.js +17 -1
- package/lib/flash-note/build-flash-note-prompt.js +1 -1
- package/lib/samples/yida-canvas-custom-page/business-list.canvas.jsx +71 -4
- package/lib/samples/yida-canvas-custom-page/dashboard-overview.canvas.jsx +71 -4
- package/lib/samples/yida-canvas-custom-page/data-management.canvas.jsx +81 -14
- package/lib/samples/yida-canvas-custom-page/data-screen.canvas.jsx +151 -68
- package/lib/samples/yida-canvas-custom-page/native-components-smoke.canvas.jsx +22 -9
- package/lib/samples/yida-canvas-custom-page/official-homepage.canvas.jsx +115 -115
- package/lib/samples/yida-canvas-custom-page/portal-native-components.canvas.jsx +18 -4
- package/lib/samples/yida-canvas-custom-page/portal-shell-home.canvas.jsx +31 -13
- package/lib/samples/yida-canvas-custom-page/split-pane-detail.canvas.jsx +71 -4
- package/lib/samples/yida-canvas-custom-page/workbench-home.canvas.jsx +47 -17
- package/lib/samples/yida-custom-page/workbench-home.oyd.jsx +1 -1
- package/package.json +1 -1
- package/scripts/postinstall.js +23 -4
- package/yida-skills/SKILL.md +35 -35
- package/yida-skills/references/development-rules.md +1 -1
- package/yida-skills/references/setup-and-env.md +4 -4
- package/yida-skills/references/task-retrospective.md +3 -3
- package/yida-skills/skills/yida-app/SKILL.md +52 -44
- package/yida-skills/skills/yida-app/references/app-build-contract.md +114 -0
- package/yida-skills/skills/yida-app/references/ui-guidance-by-mode.md +77 -0
- package/yida-skills/skills/yida-app-uiux/SKILL.md +4 -2
- package/yida-skills/skills/yida-canvas-custom-page/SKILL.md +26 -23
- package/yida-skills/skills/yida-canvas-custom-page/references/canvas-authoring-examples.md +3 -3
- package/yida-skills/skills/yida-canvas-custom-page/references/canvas-design-system.md +14 -12
- package/yida-skills/skills/yida-canvas-custom-page/references/component-library-guide.md +1 -1
- package/yida-skills/skills/yida-canvas-custom-page/references/data-bridge-guide.md +27 -9
- package/yida-skills/skills/yida-canvas-custom-page/references/dependencies-and-cdn.md +4 -4
- package/yida-skills/skills/yida-canvas-custom-page/references/employeefield-verification.md +12 -4
- package/yida-skills/skills/yida-canvas-custom-page/references/native-components-bridge.md +14 -12
- package/yida-skills/skills/yida-canvas-custom-page/references/navigation-and-entry-guide.md +100 -0
- package/yida-skills/skills/yida-canvas-custom-page/references/page-generation-guide.md +8 -4
- package/yida-skills/skills/yida-canvas-data-binding/SKILL.md +33 -13
- package/yida-skills/skills/yida-canvas-table-form/SKILL.md +1 -1
- package/yida-skills/skills/yida-chart/references/echarts-design-spec.md +3 -2
- package/yida-skills/skills/yida-create-app/SKILL.md +21 -35
- package/yida-skills/skills/yida-create-form-page/SKILL.md +7 -3
- package/yida-skills/skills/yida-create-form-page/references/form-field-properties.md +13 -4
- package/yida-skills/skills/yida-create-page/SKILL.md +6 -3
- package/yida-skills/skills/yida-custom-page/SKILL.md +3 -3
- package/yida-skills/skills/yida-custom-page/references/coding-guide.md +3 -3
- package/yida-skills/skills/yida-custom-page/references/component-jsx-guide.md +3 -3
- package/yida-skills/skills/yida-custom-page/references/design-system.md +5 -3
- package/yida-skills/skills/yida-dashboard/SKILL.md +5 -5
- package/yida-skills/skills/yida-dashboard/references/interaction-patterns.md +2 -2
- package/yida-skills/skills/yida-dashboard/references/pitfalls.md +3 -3
- package/yida-skills/skills/yida-dashboard/references/structure-and-layout.md +1 -1
- package/yida-skills/skills/yida-dashboard/references/theme-presets.md +11 -8
- package/yida-skills/skills/yida-form-detail/SKILL.md +33 -4
- package/yida-skills/skills/yida-login/SKILL.md +12 -10
- package/yida-skills/skills/yida-nav-group/SKILL.md +5 -1
- package/yida-skills/skills/yida-nav-shell/SKILL.md +4 -3
- package/yida-skills/skills/yida-nav-shell/references/nav-shell-patterns.md +3 -3
- package/yida-skills/skills/yida-page-config/SKILL.md +1 -1
- package/yida-skills/skills/yida-page-uiux/SKILL.md +14 -10
- package/yida-skills/skills/yida-page-uiux/references/app/blueprint.md +1 -1
- package/yida-skills/skills/yida-page-uiux/references/app/navigation-patterns.md +4 -2
- package/yida-skills/skills/yida-page-uiux/references/dashboard/theme-recipes.md +3 -2
- package/yida-skills/skills/yida-page-uiux/references/landing/realistic-brand-homepage.md +2 -2
- package/yida-skills/skills/yida-page-uiux/references/scenes/screen.md +3 -2
- package/yida-skills/skills/yida-page-uiux/references/scenes/workbench.md +3 -0
- package/yida-skills/skills/yida-page-uiux/references/visual-decision-engine.md +6 -6
- package/yida-skills/skills/yida-page-uiux/references/workbench/entry-patterns.md +2 -0
- package/yida-skills/skills/yida-page-uiux/workflow/output-decision-block.md +13 -2
- package/yida-skills/skills/yida-page-uiux/workflow/step-0-nav-shape.md +16 -12
- package/yida-skills/skills/yida-page-uiux/workflow/step-1-page-type.md +2 -2
- package/yida-skills/skills/yida-page-uiux/workflow/step-3-scene-routing.md +2 -2
- package/yida-skills/skills/yida-page-uiux/workflow/step-4-visual-decision.md +16 -4
- package/yida-skills/skills/yida-page-uiux/workflow/step-6-deai-selfcheck.md +1 -1
- package/yida-skills/skills/yida-ppt-slider/references/dark-tech-theme.md +2 -0
- package/yida-skills/skills/yida-publish-page/SKILL.md +3 -2
- package/yida-skills/skills/yida-report/SKILL.md +2 -2
- package/yida-skills/skills/yida-report/references/report-api-guide.md +3 -3
- package/yida-skills/skills/yida-skill-evaluator/SKILL.md +2 -2
- package/yida-skills/skills/yida-table-form/SKILL.md +1 -1
- package/yida-skills/skills/yida-theme/SKILL.md +36 -42
- package/yida-skills/skills/yida-theme/references/theme-token-presets.md +135 -0
- package/yida-skills/skills-index.json +13 -8
package/lib/app/generate-page.js
CHANGED
|
@@ -101,7 +101,80 @@ const TEMPLATES = {
|
|
|
101
101
|
},
|
|
102
102
|
};
|
|
103
103
|
|
|
104
|
+
const SAMPLE_RESIDUE_TOKENS = {
|
|
105
|
+
'official-homepage': [
|
|
106
|
+
'Luma Roast',
|
|
107
|
+
'Luma',
|
|
108
|
+
'coffee',
|
|
109
|
+
'Coffee',
|
|
110
|
+
'豆单',
|
|
111
|
+
'烘焙',
|
|
112
|
+
'冷萃',
|
|
113
|
+
'手冲',
|
|
114
|
+
'吧台',
|
|
115
|
+
'杯测',
|
|
116
|
+
'生豆',
|
|
117
|
+
'门店',
|
|
118
|
+
'订阅',
|
|
119
|
+
'Shanghai',
|
|
120
|
+
'Seasonal roast',
|
|
121
|
+
'Visit Luma',
|
|
122
|
+
'oy-coffee',
|
|
123
|
+
'COFFEE_',
|
|
124
|
+
],
|
|
125
|
+
'product-homepage': [
|
|
126
|
+
'演示预约正在同步到客户表单',
|
|
127
|
+
'线索表单、产品演示和客户回访',
|
|
128
|
+
],
|
|
129
|
+
'workbench-home': [
|
|
130
|
+
'清理高优先级待办',
|
|
131
|
+
'核对客户回访结果',
|
|
132
|
+
'同步异常与负责人',
|
|
133
|
+
],
|
|
134
|
+
'business-list': [
|
|
135
|
+
'SO-240716',
|
|
136
|
+
'PRJ-240716',
|
|
137
|
+
'CL-240717',
|
|
138
|
+
],
|
|
139
|
+
'detail-profile': [
|
|
140
|
+
'采购负责人李青',
|
|
141
|
+
'苏州仓库存',
|
|
142
|
+
],
|
|
143
|
+
'portal-shell-home': [
|
|
144
|
+
'Red Portal Shell',
|
|
145
|
+
],
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
function normalizeSearchText(value) {
|
|
149
|
+
return String(value || '').toLowerCase();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function collectTextDeep(value, output) {
|
|
153
|
+
if (value === undefined || value === null) {
|
|
154
|
+
return output;
|
|
155
|
+
}
|
|
156
|
+
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
|
157
|
+
output.push(String(value));
|
|
158
|
+
return output;
|
|
159
|
+
}
|
|
160
|
+
if (Array.isArray(value)) {
|
|
161
|
+
value.forEach((item) => collectTextDeep(item, output));
|
|
162
|
+
return output;
|
|
163
|
+
}
|
|
164
|
+
if (typeof value === 'object') {
|
|
165
|
+
Object.keys(value).forEach((key) => collectTextDeep(value[key], output));
|
|
166
|
+
}
|
|
167
|
+
return output;
|
|
168
|
+
}
|
|
169
|
+
|
|
104
170
|
function collectSpecText(spec) {
|
|
171
|
+
if (!spec || typeof spec !== 'object') {
|
|
172
|
+
return '';
|
|
173
|
+
}
|
|
174
|
+
return collectTextDeep(spec, []).join(' ');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function collectRoutingText(spec) {
|
|
105
178
|
if (!spec || typeof spec !== 'object') {
|
|
106
179
|
return '';
|
|
107
180
|
}
|
|
@@ -130,6 +203,43 @@ function collectSpecText(spec) {
|
|
|
130
203
|
.join(' ');
|
|
131
204
|
}
|
|
132
205
|
|
|
206
|
+
function stripFallbackSource(source) {
|
|
207
|
+
return String(source || '')
|
|
208
|
+
.replace(/'data:image\/[^']*'/g, "''")
|
|
209
|
+
.replace(/"data:image\/[^"]*"/g, '""')
|
|
210
|
+
.replace(/const\s+[A-Z0-9_]*IMAGE\s*=\s*['"][\s\S]*?['"];\n/g, '')
|
|
211
|
+
.replace(/applyPageFallbacks\(\{[\s\S]*?\n\}\);\n/g, '')
|
|
212
|
+
.replace(/const\s+DEFAULT_[A-Z0-9_]+\s*=\s*[\s\S]*?;\n/g, '');
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function findSampleResidues(source, templateName, spec) {
|
|
216
|
+
const tokens = SAMPLE_RESIDUE_TOKENS[templateName] || [];
|
|
217
|
+
if (!tokens.length) {
|
|
218
|
+
return [];
|
|
219
|
+
}
|
|
220
|
+
const searchableSource = normalizeSearchText(stripFallbackSource(source));
|
|
221
|
+
const specText = normalizeSearchText(collectSpecText(spec || {}));
|
|
222
|
+
const residues = tokens.filter((token) => {
|
|
223
|
+
const normalizedToken = normalizeSearchText(token);
|
|
224
|
+
return searchableSource.includes(normalizedToken) && !specText.includes(normalizedToken);
|
|
225
|
+
});
|
|
226
|
+
return Array.from(new Set(residues));
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function assertNoSampleResidueInDomainReadyOutput(source, templateName, spec, ir) {
|
|
230
|
+
const fidelity = ir && ir.domainFidelity;
|
|
231
|
+
if (!fidelity || fidelity.status !== 'domain-ready') {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const residues = findSampleResidues(source, templateName, spec);
|
|
235
|
+
if (!residues.length) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
fidelity.status = 'draft-needs-domain-spec';
|
|
239
|
+
fidelity.sampleFallbacks = Array.from(new Set([...(fidelity.sampleFallbacks || []), ...residues.map((item) => `source:${item}`)]));
|
|
240
|
+
throwCommandError(`生成页仍残留 sample 内容,已停止写入/发布:${residues.join(', ')}。请把这些文案、行业词、配图说明或样式命名替换为当前业务自己的内容。`);
|
|
241
|
+
}
|
|
242
|
+
|
|
133
243
|
function inferTemplateName(options, spec) {
|
|
134
244
|
if (options.template) {
|
|
135
245
|
return options.template;
|
|
@@ -138,7 +248,7 @@ function inferTemplateName(options, spec) {
|
|
|
138
248
|
return spec.template;
|
|
139
249
|
}
|
|
140
250
|
|
|
141
|
-
const text =
|
|
251
|
+
const text = collectRoutingText(spec);
|
|
142
252
|
if (/数据大屏|大屏|实时监控|预警系统|态势|指挥舱|监测预警|screen/i.test(text)) {
|
|
143
253
|
return 'data-screen';
|
|
144
254
|
}
|
|
@@ -484,7 +594,7 @@ function reportNavigationConfig(ir) {
|
|
|
484
594
|
if (!blueprint || blueprint.renderNav !== false) {
|
|
485
595
|
return;
|
|
486
596
|
}
|
|
487
|
-
hint('
|
|
597
|
+
hint('检测到显式隐藏平台导航,发布后应设置 isRenderNav=false:openyida update-form-config <appType> <formUuid> false "<页面标题>"');
|
|
488
598
|
}
|
|
489
599
|
|
|
490
600
|
function ensureOutputDir(outputPath) {
|
|
@@ -604,6 +714,7 @@ async function run(args) {
|
|
|
604
714
|
artifact: outputPath,
|
|
605
715
|
code: 'OPENYIDA_GENERATED_PAGE_EMOJI_FORBIDDEN',
|
|
606
716
|
});
|
|
717
|
+
assertNoSampleResidueInDomainReadyOutput(outputSource, templateName, spec, ir);
|
|
607
718
|
|
|
608
719
|
ensureOutputDir(outputPath);
|
|
609
720
|
fs.writeFileSync(outputPath, outputSource, 'utf-8');
|
|
@@ -636,6 +747,10 @@ async function run(args) {
|
|
|
636
747
|
['Archetype', ir.archetype],
|
|
637
748
|
['Visual profile', ir.visualProfile && ir.visualProfile.name],
|
|
638
749
|
['Theme profile', ir.themeProfile && ir.themeProfile.name],
|
|
750
|
+
['Theme source', ir.themeProfile && ir.themeProfile.themeColorSource],
|
|
751
|
+
['Theme color', ir.themeProfile && ir.themeProfile.themeColor],
|
|
752
|
+
['Nav theme', ir.themeProfile && (ir.themeProfile.navTheme || 'light')],
|
|
753
|
+
['Theme color mode', ir.themeProfile && ir.themeProfile.colorMode],
|
|
639
754
|
['Theme scope', ir.themeScope],
|
|
640
755
|
['Yida nav', ir.appBlueprint && ir.appBlueprint.renderNav === false ? 'hide (isRenderNav=false)' : 'render'],
|
|
641
756
|
['Imported modules', importedModules.join(', ')],
|
|
@@ -676,6 +791,10 @@ async function run(args) {
|
|
|
676
791
|
['Archetype', ir.archetype],
|
|
677
792
|
['Visual profile', ir.visualProfile && ir.visualProfile.name],
|
|
678
793
|
['Theme profile', ir.themeProfile && ir.themeProfile.name],
|
|
794
|
+
['Theme source', ir.themeProfile && ir.themeProfile.themeColorSource],
|
|
795
|
+
['Theme color', ir.themeProfile && ir.themeProfile.themeColor],
|
|
796
|
+
['Nav theme', ir.themeProfile && (ir.themeProfile.navTheme || 'light')],
|
|
797
|
+
['Theme color mode', ir.themeProfile && ir.themeProfile.colorMode],
|
|
679
798
|
['Theme scope', ir.themeScope],
|
|
680
799
|
['Yida nav', ir.appBlueprint && ir.appBlueprint.renderNav === false ? 'hide (isRenderNav=false)' : 'render'],
|
|
681
800
|
['Blocks', ir.blocks.map((block) => block.type).join(', ')],
|
|
@@ -695,4 +814,6 @@ module.exports = {
|
|
|
695
814
|
normalizeOutputPathForProjectCwd,
|
|
696
815
|
inferMode,
|
|
697
816
|
inferTemplateName,
|
|
817
|
+
findSampleResidues,
|
|
818
|
+
assertNoSampleResidueInDomainReadyOutput,
|
|
698
819
|
};
|
package/lib/app/nav-group.js
CHANGED
|
@@ -347,6 +347,81 @@ function reorderRootNodes(list, values) {
|
|
|
347
347
|
};
|
|
348
348
|
}
|
|
349
349
|
|
|
350
|
+
function normalizeComparableText(value) {
|
|
351
|
+
return String(value || '').trim().toLowerCase();
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function getNavigationPriority(node) {
|
|
355
|
+
const name = normalizeComparableText(getNodeName(node));
|
|
356
|
+
const formType = normalizeComparableText(node.formType);
|
|
357
|
+
const navType = normalizeComparableText(node.navType);
|
|
358
|
+
|
|
359
|
+
if (navType === 'system') {
|
|
360
|
+
return 99;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (/门户|首页|主页|工作台|入口|总览|概览|home|homepage|portal|workspace|overview/.test(name)) {
|
|
364
|
+
return 0;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (formType === 'display') {
|
|
368
|
+
return 1;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (formType === 'process') {
|
|
372
|
+
return 2;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
if (['receipt', 'form'].includes(formType)) {
|
|
376
|
+
return 3;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (navType === 'nav') {
|
|
380
|
+
return 4;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return 5;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function compareNavigationNodes(a, b) {
|
|
387
|
+
const priorityDiff = getNavigationPriority(a) - getNavigationPriority(b);
|
|
388
|
+
if (priorityDiff !== 0) {
|
|
389
|
+
return priorityDiff;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const orderA = Number.isFinite(Number(a.listOrder)) ? Number(a.listOrder) : Number.MAX_SAFE_INTEGER;
|
|
393
|
+
const orderB = Number.isFinite(Number(b.listOrder)) ? Number(b.listOrder) : Number.MAX_SAFE_INTEGER;
|
|
394
|
+
if (orderA !== orderB) {
|
|
395
|
+
return orderA - orderB;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
return String(a.id || a.navUuid || '').localeCompare(String(b.id || b.navUuid || ''));
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function autoOrderRootNodes(list) {
|
|
402
|
+
const { roots } = buildMutableForest(list);
|
|
403
|
+
const systemRoots = roots.filter((node) => node.navType === 'SYSTEM');
|
|
404
|
+
const sortableRoots = roots
|
|
405
|
+
.filter((node) => node.navType !== 'SYSTEM')
|
|
406
|
+
.slice()
|
|
407
|
+
.sort(compareNavigationNodes);
|
|
408
|
+
|
|
409
|
+
const orderedRoots = systemRoots.concat(sortableRoots);
|
|
410
|
+
|
|
411
|
+
return {
|
|
412
|
+
roots: orderedRoots,
|
|
413
|
+
ids: flattenTreeIds(orderedRoots),
|
|
414
|
+
orderedNavUuids: sortableRoots.map((node) => node.navUuid),
|
|
415
|
+
orderedNodes: sortableRoots.map((node) => ({
|
|
416
|
+
navUuid: node.navUuid,
|
|
417
|
+
formUuid: node.formUuid || null,
|
|
418
|
+
name: getNodeName(node),
|
|
419
|
+
formType: node.formType || '',
|
|
420
|
+
priority: getNavigationPriority(node),
|
|
421
|
+
})),
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
|
|
350
425
|
function countChildren(list, navUuid) {
|
|
351
426
|
return (list || []).filter((node) => node.parentNavUuid === navUuid).length;
|
|
352
427
|
}
|
|
@@ -595,6 +670,41 @@ async function orderRootNodes(appType, values, authRef) {
|
|
|
595
670
|
};
|
|
596
671
|
}
|
|
597
672
|
|
|
673
|
+
async function autoOrderNavigation(appType, authRef) {
|
|
674
|
+
const list = await fetchNavigationList(appType, authRef);
|
|
675
|
+
const ordered = autoOrderRootNodes(list);
|
|
676
|
+
if (!ordered.orderedNavUuids.length) {
|
|
677
|
+
return {
|
|
678
|
+
success: true,
|
|
679
|
+
appType,
|
|
680
|
+
action: 'auto-order',
|
|
681
|
+
targetParentNavUuid: ROOT_NAV_UUID,
|
|
682
|
+
orderedNavUuids: [],
|
|
683
|
+
orderedNodes: [],
|
|
684
|
+
skipped: true,
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
const firstNode = resolveNode(list, ordered.orderedNavUuids[0], { excludeSystem: true });
|
|
689
|
+
await postNavAction(appType, 'updateOrderNew', {
|
|
690
|
+
currentId: firstNode.id,
|
|
691
|
+
parentNavUuid: ROOT_NAV_UUID,
|
|
692
|
+
navType: firstNode.navType,
|
|
693
|
+
ids: ordered.ids.join(','),
|
|
694
|
+
}, authRef);
|
|
695
|
+
|
|
696
|
+
const updatedList = await fetchNavigationList(appType, authRef);
|
|
697
|
+
const updatedOrdered = autoOrderRootNodes(updatedList);
|
|
698
|
+
return {
|
|
699
|
+
success: true,
|
|
700
|
+
appType,
|
|
701
|
+
action: 'auto-order',
|
|
702
|
+
targetParentNavUuid: ROOT_NAV_UUID,
|
|
703
|
+
orderedNavUuids: updatedOrdered.orderedNavUuids,
|
|
704
|
+
orderedNodes: updatedOrdered.orderedNodes,
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
|
|
598
708
|
async function setVisibility(appType, value, hidden, authRef) {
|
|
599
709
|
if (!value) {
|
|
600
710
|
throw new Error('Usage: openyida nav-group <hide|show> <appType> <navUuid|formUuid|name>');
|
|
@@ -630,6 +740,7 @@ Usage:
|
|
|
630
740
|
openyida nav-group delete <appType> <groupNavUuid|groupName> [--force]
|
|
631
741
|
openyida nav-group move <appType> <navUuid|formUuid|name> --to <groupNavUuid|groupName|root> [--before <node>] [--after <node>]
|
|
632
742
|
openyida nav-group order <appType> <navUuid|formUuid|name> [more items...]
|
|
743
|
+
openyida nav-group auto-order <appType>
|
|
633
744
|
openyida nav-group hide <appType> <navUuid|formUuid|name>
|
|
634
745
|
openyida nav-group show <appType> <navUuid|formUuid|name>
|
|
635
746
|
`);
|
|
@@ -664,6 +775,8 @@ async function run(args) {
|
|
|
664
775
|
result = await moveNode(appType, positional[1], flags, authRef);
|
|
665
776
|
} else if (subCommand === 'order' || subCommand === 'reorder') {
|
|
666
777
|
result = await orderRootNodes(appType, positional.slice(1), authRef);
|
|
778
|
+
} else if (subCommand === 'auto-order' || subCommand === 'autoorder' || subCommand === 'sort') {
|
|
779
|
+
result = await autoOrderNavigation(appType, authRef);
|
|
667
780
|
} else if (subCommand === 'hide') {
|
|
668
781
|
result = await setVisibility(appType, positional[1], true, authRef);
|
|
669
782
|
} else if (subCommand === 'show') {
|
|
@@ -677,10 +790,14 @@ async function run(args) {
|
|
|
677
790
|
|
|
678
791
|
module.exports = {
|
|
679
792
|
ROOT_NAV_UUID,
|
|
793
|
+
autoOrderNavigation,
|
|
794
|
+
autoOrderRootNodes,
|
|
680
795
|
buildI18nTitle,
|
|
681
796
|
buildNavigationTree,
|
|
797
|
+
compareNavigationNodes,
|
|
682
798
|
flattenTreeIds,
|
|
683
799
|
flattenTreeNodes,
|
|
800
|
+
getNavigationPriority,
|
|
684
801
|
moveNodeInTree,
|
|
685
802
|
normalizeNavNode,
|
|
686
803
|
orderRootNodes,
|
package/lib/app/page-ir.js
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const {
|
|
4
|
+
APP_THEME_TOKEN_PRESETS,
|
|
5
|
+
APP_THEME_TOKEN_PRESET_KEYS,
|
|
6
|
+
isPresetThemeKey,
|
|
7
|
+
} = require('./theme-presets');
|
|
8
|
+
|
|
3
9
|
const IR_VERSION = '1.0';
|
|
4
10
|
|
|
5
11
|
const PRODUCT_HOMEPAGE_TEMPLATE = 'product-homepage';
|
|
@@ -16,6 +22,7 @@ const TODO_MVC_TEMPLATE = 'todo-mvc';
|
|
|
16
22
|
const PAGE_SCENES = ['workbench', 'dashboard', 'list', 'detail', 'landing', 'screen'];
|
|
17
23
|
const THEME_SCOPES = ['page', 'app'];
|
|
18
24
|
const RESEARCH_LEVELS = ['none', 'light', 'enhanced', 'deep'];
|
|
25
|
+
const DEFAULT_THEME_PROFILE_KEY = 'podBlue';
|
|
19
26
|
|
|
20
27
|
const CANVAS_CONTROL_RESET_CSS = `
|
|
21
28
|
:where(.oy-page, .oy-workbench-home, .oy-dashboard-overview, .oy-business-list, .oy-data-management, .oy-detail-profile, .oy-split-pane-detail, .oy-portal-shell-home, .oy-official, .oy-screen, .oy-todo-os, .oy-native-portal, .oy-smoke-page) {
|
|
@@ -128,30 +135,19 @@ const DEFAULT_VISUAL_PROFILES = {
|
|
|
128
135
|
},
|
|
129
136
|
screen: {
|
|
130
137
|
name: 'yida-app-theme',
|
|
131
|
-
tone: '
|
|
138
|
+
tone: 'light-command',
|
|
132
139
|
density: 'screen-dense',
|
|
133
|
-
neutral: '
|
|
140
|
+
neutral: 'light-blue-gray',
|
|
134
141
|
corner: 'layered',
|
|
135
|
-
accent: '
|
|
142
|
+
accent: 'brand-signal',
|
|
136
143
|
typography: 'tabular-numeric',
|
|
137
144
|
motif: ['command-map', 'glow-kpi', 'radar-panel', 'rank-feed'],
|
|
138
145
|
},
|
|
139
146
|
};
|
|
140
147
|
|
|
148
|
+
// Application theme token profiles work as the default page-level theme suggestions.
|
|
149
|
+
// Only platform-supported theme keys are mirrored into appThemeKey.
|
|
141
150
|
const DEFAULT_THEME_PROFILES = {
|
|
142
|
-
'yida-pod-business': {
|
|
143
|
-
name: 'yida-app-theme',
|
|
144
|
-
followRuntimeTheme: true,
|
|
145
|
-
themeColorSource: 'runtime-css-vars',
|
|
146
|
-
themeColor: '#6B7CAB',
|
|
147
|
-
themeColorDeep: '#435480',
|
|
148
|
-
themeColorSoft: '#F3F5FB',
|
|
149
|
-
themeColorTint: 'rgba(107, 124, 171, 0.2)',
|
|
150
|
-
navTheme: 'light',
|
|
151
|
-
mode: 'color_color',
|
|
152
|
-
colorMode: 'gradient',
|
|
153
|
-
mobileNavStyle: 'top',
|
|
154
|
-
},
|
|
155
151
|
'yida-app-theme': {
|
|
156
152
|
name: 'yida-app-theme',
|
|
157
153
|
followRuntimeTheme: true,
|
|
@@ -167,18 +163,36 @@ const DEFAULT_THEME_PROFILES = {
|
|
|
167
163
|
},
|
|
168
164
|
};
|
|
169
165
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
166
|
+
function registerTokenThemeProfiles(presetKeys, tokenPresets, options = {}) {
|
|
167
|
+
presetKeys.forEach((presetName) => {
|
|
168
|
+
const tokens = tokenPresets[presetName];
|
|
169
|
+
DEFAULT_THEME_PROFILES[presetName] = {
|
|
170
|
+
name: presetName,
|
|
171
|
+
appThemeKey: options.appThemeKeyFor ? options.appThemeKeyFor(presetName) : (options.appThemeKey === false ? '' : presetName),
|
|
172
|
+
followRuntimeTheme: false,
|
|
173
|
+
themeColorSource: options.themeColorSource || 'theme-token-preset',
|
|
174
|
+
themeColor: tokens['--color-brand1-6'],
|
|
175
|
+
themeColorDeep: tokens['--color-brand1-9'],
|
|
176
|
+
themeColorSoft: tokens['--color-brand1-2'],
|
|
177
|
+
themeColorTint: tokens['--color-brand1-3'],
|
|
178
|
+
navTheme: 'light',
|
|
179
|
+
mode: 'color_color',
|
|
180
|
+
colorMode: 'gradient',
|
|
181
|
+
mobileNavStyle: 'top',
|
|
182
|
+
};
|
|
183
|
+
});
|
|
184
|
+
}
|
|
173
185
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
186
|
+
registerTokenThemeProfiles(APP_THEME_TOKEN_PRESET_KEYS, APP_THEME_TOKEN_PRESETS, {
|
|
187
|
+
themeColorSource: 'application-theme',
|
|
188
|
+
appThemeKeyFor: (presetName) => (isPresetThemeKey(presetName) ? presetName : ''),
|
|
189
|
+
});
|
|
177
190
|
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
191
|
+
const VISUAL_NEUTRAL_ALIASES = {};
|
|
192
|
+
|
|
193
|
+
const VISUAL_CORNER_ALIASES = {};
|
|
194
|
+
|
|
195
|
+
const VISUAL_MOTIF_ALIASES = {};
|
|
182
196
|
|
|
183
197
|
const DEFAULT_PRODUCT_HOMEPAGE = {
|
|
184
198
|
meta: {
|
|
@@ -707,7 +721,7 @@ function getThemeProfileInput(spec) {
|
|
|
707
721
|
}
|
|
708
722
|
|
|
709
723
|
function normalizeThemeProfile(rawProfile) {
|
|
710
|
-
const defaults = DEFAULT_THEME_PROFILES[
|
|
724
|
+
const defaults = DEFAULT_THEME_PROFILES[DEFAULT_THEME_PROFILE_KEY];
|
|
711
725
|
const profile = typeof rawProfile === 'string'
|
|
712
726
|
? { name: rawProfile }
|
|
713
727
|
: isPlainObject(rawProfile)
|
|
@@ -716,7 +730,8 @@ function normalizeThemeProfile(rawProfile) {
|
|
|
716
730
|
|
|
717
731
|
const name = valueOrDefault(profile.name || profile.profile, defaults.name);
|
|
718
732
|
const preset = DEFAULT_THEME_PROFILES[name] || defaults;
|
|
719
|
-
const
|
|
733
|
+
const isKnownProfile = Boolean(DEFAULT_THEME_PROFILES[name]);
|
|
734
|
+
const normalizedName = isKnownProfile ? preset.name : name;
|
|
720
735
|
const hasExplicit = (...keys) => keys.some((key) => (
|
|
721
736
|
Object.prototype.hasOwnProperty.call(profile, key)
|
|
722
737
|
&& profile[key] !== undefined
|
|
@@ -732,10 +747,15 @@ function normalizeThemeProfile(rawProfile) {
|
|
|
732
747
|
? Boolean(preset.followRuntimeTheme && !hasExplicitColorFamily)
|
|
733
748
|
: profile.followRuntimeTheme !== false;
|
|
734
749
|
|
|
735
|
-
|
|
750
|
+
const normalized = {
|
|
736
751
|
name: normalizedName,
|
|
737
752
|
followRuntimeTheme,
|
|
738
|
-
themeColorSource: followRuntimeTheme
|
|
753
|
+
themeColorSource: followRuntimeTheme
|
|
754
|
+
? 'runtime-css-vars'
|
|
755
|
+
: valueOrDefault(
|
|
756
|
+
profile.themeColorSource || profile.colorSource,
|
|
757
|
+
hasExplicitColorFamily ? 'profile' : (preset.themeColorSource || 'profile')
|
|
758
|
+
),
|
|
739
759
|
themeColor: valueOrDefault(profile.themeColor || profile.color || profile.brandColor, preset.themeColor),
|
|
740
760
|
themeColorDeep: valueOrDefault(profile.themeColorDeep || profile.brandDeep, preset.themeColorDeep),
|
|
741
761
|
themeColorSoft: valueOrDefault(profile.themeColorSoft || profile.brandSoft, preset.themeColorSoft),
|
|
@@ -745,6 +765,13 @@ function normalizeThemeProfile(rawProfile) {
|
|
|
745
765
|
colorMode: valueOrDefault(profile.colorMode, preset.colorMode),
|
|
746
766
|
mobileNavStyle: valueOrDefault(profile.mobileNavStyle, preset.mobileNavStyle),
|
|
747
767
|
};
|
|
768
|
+
|
|
769
|
+
const appThemeKey = valueOrDefault(profile.appThemeKey || profile.themeKey, isKnownProfile ? preset.appThemeKey : '');
|
|
770
|
+
if (appThemeKey) {
|
|
771
|
+
normalized.appThemeKey = appThemeKey;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
return normalized;
|
|
748
775
|
}
|
|
749
776
|
|
|
750
777
|
function getThemeScopeInput(spec) {
|
|
@@ -920,10 +947,10 @@ function inferPageLevelNavigation(templateName, source) {
|
|
|
920
947
|
if (explicit !== null) {
|
|
921
948
|
return explicit;
|
|
922
949
|
}
|
|
923
|
-
return
|
|
950
|
+
return false;
|
|
924
951
|
}
|
|
925
952
|
|
|
926
|
-
function inferHideAppNav(source
|
|
953
|
+
function inferHideAppNav(source) {
|
|
927
954
|
const explicitHide = normalizeOptionalBoolean(
|
|
928
955
|
firstDefined(
|
|
929
956
|
source.hideAppNav,
|
|
@@ -948,10 +975,7 @@ function inferHideAppNav(source, scene, templateName, hasPageNavigation) {
|
|
|
948
975
|
return !explicitRender;
|
|
949
976
|
}
|
|
950
977
|
|
|
951
|
-
|
|
952
|
-
return true;
|
|
953
|
-
}
|
|
954
|
-
return hasPageNavigation;
|
|
978
|
+
return false;
|
|
955
979
|
}
|
|
956
980
|
|
|
957
981
|
function normalizeAppBlueprint(spec, scene, templateName, meta) {
|
|
@@ -966,7 +990,7 @@ function normalizeAppBlueprint(spec, scene, templateName, meta) {
|
|
|
966
990
|
const shell = valueOrDefault(source.shell || source.shellType || spec.shell || spec.shellType, scene === 'screen' ? 'no_shell' : 'single_page');
|
|
967
991
|
const navigation = normalizeStringList(source.navigation || source.navGroups || spec.navigation || spec.navGroups);
|
|
968
992
|
const hasPageNavigation = inferPageLevelNavigation(templateName, source);
|
|
969
|
-
const hideAppNav = inferHideAppNav(source
|
|
993
|
+
const hideAppNav = inferHideAppNav(source);
|
|
970
994
|
const renderNav = !hideAppNav;
|
|
971
995
|
const defaultPage = {
|
|
972
996
|
name: meta && (meta.brandName || meta.title) ? (meta.brandName || meta.title) : templateName,
|
|
@@ -988,7 +1012,7 @@ function normalizeAppBlueprint(spec, scene, templateName, meta) {
|
|
|
988
1012
|
navConfig: {
|
|
989
1013
|
isRenderNav: renderNav,
|
|
990
1014
|
reason: hideAppNav
|
|
991
|
-
? '
|
|
1015
|
+
? 'explicit hide navigation request'
|
|
992
1016
|
: 'use Yida application navigation',
|
|
993
1017
|
},
|
|
994
1018
|
};
|
|
@@ -1159,6 +1183,8 @@ function normalizeMediaAssets(spec, defaults) {
|
|
|
1159
1183
|
return {
|
|
1160
1184
|
heroImage: valueOrDefault(source.heroImage || source.hero || spec.heroImage || spec.hero_image, fallback.heroImage || ''),
|
|
1161
1185
|
heroImageAlt: valueOrDefault(source.heroImageAlt || source.heroAlt || spec.heroImageAlt || spec.hero_image_alt, fallback.heroImageAlt || ''),
|
|
1186
|
+
storyImage: valueOrDefault(source.storyImage || source.story || spec.storyImage || spec.story_image, fallback.storyImage || ''),
|
|
1187
|
+
storyImageAlt: valueOrDefault(source.storyImageAlt || source.storyAlt || spec.storyImageAlt || spec.story_image_alt, fallback.storyImageAlt || ''),
|
|
1162
1188
|
productImages: productImages.length ? productImages : clone(fallback.productImages || []),
|
|
1163
1189
|
materialStrategy: valueOrDefault(source.materialStrategy || spec.materialStrategy, fallback.materialStrategy || 'visual-anchor-required'),
|
|
1164
1190
|
// 素材完成度:final(可交付最终版) / draft(仅草稿) / none(无素材) / unknown(尚未预检)
|
package/lib/app/publish.js
CHANGED
|
@@ -97,8 +97,9 @@ function parseArgs(argv = process.argv.slice(2)) {
|
|
|
97
97
|
const compat = args.includes('--compat') || args.includes('--modern');
|
|
98
98
|
const force = args.includes('--force');
|
|
99
99
|
const canvas = args.includes('--canvas');
|
|
100
|
+
const autoNavOrder = args.includes('--auto-nav-order');
|
|
100
101
|
const help = args.includes('--help') || args.includes('-h');
|
|
101
|
-
const filteredArgs = args.filter(arg => arg !== '--skip-lint' && arg !== '--health-check' && arg !== '--check' && arg !== '--compat' && arg !== '--modern' && arg !== '--force' && arg !== '--canvas' && arg !== '--json' && arg !== '--help' && arg !== '-h');
|
|
102
|
+
const filteredArgs = args.filter(arg => arg !== '--skip-lint' && arg !== '--health-check' && arg !== '--check' && arg !== '--compat' && arg !== '--modern' && arg !== '--force' && arg !== '--canvas' && arg !== '--auto-nav-order' && arg !== '--json' && arg !== '--help' && arg !== '-h');
|
|
102
103
|
|
|
103
104
|
if (help) {
|
|
104
105
|
usage(t('publish.usage'), t('publish.example'));
|
|
@@ -119,6 +120,7 @@ function parseArgs(argv = process.argv.slice(2)) {
|
|
|
119
120
|
compat,
|
|
120
121
|
force,
|
|
121
122
|
canvas,
|
|
123
|
+
autoNavOrder,
|
|
122
124
|
browserOpenMode: openOption.mode,
|
|
123
125
|
};
|
|
124
126
|
}
|
|
@@ -735,7 +737,7 @@ async function runMain(argv) {
|
|
|
735
737
|
if (options.help) {
|
|
736
738
|
return options;
|
|
737
739
|
}
|
|
738
|
-
const { appType, formUuid, sourceFile, skipLint, healthCheck, compat, force, canvas: canvasFlag, browserOpenMode } = options;
|
|
740
|
+
const { appType, formUuid, sourceFile, skipLint, healthCheck, compat, force, canvas: canvasFlag, autoNavOrder, browserOpenMode } = options;
|
|
739
741
|
|
|
740
742
|
let sourcePath = path.resolve(sourceFile);
|
|
741
743
|
if (!fs.existsSync(sourcePath)) {
|
|
@@ -876,6 +878,8 @@ async function runMain(argv) {
|
|
|
876
878
|
|
|
877
879
|
const pageUrl = `${baseUrl}/${appType}/workbench/${savedFormUuid}`;
|
|
878
880
|
let healthCheckResult = null;
|
|
881
|
+
let navOrderResult = null;
|
|
882
|
+
let navOrderWarning = null;
|
|
879
883
|
if (healthCheck) {
|
|
880
884
|
step(5, t('publish.step_health_check'));
|
|
881
885
|
try {
|
|
@@ -894,6 +898,23 @@ async function runMain(argv) {
|
|
|
894
898
|
}
|
|
895
899
|
}
|
|
896
900
|
|
|
901
|
+
if (autoNavOrder) {
|
|
902
|
+
step(healthCheck ? 6 : 5, t('publish.step_nav_order'));
|
|
903
|
+
try {
|
|
904
|
+
const { autoOrderNavigation } = require('./nav-group');
|
|
905
|
+
navOrderResult = await autoOrderNavigation(appType, authRef);
|
|
906
|
+
const orderedNames = (navOrderResult.orderedNodes || [])
|
|
907
|
+
.slice(0, 6)
|
|
908
|
+
.map((node) => node.name || node.formUuid || node.navUuid)
|
|
909
|
+
.filter(Boolean)
|
|
910
|
+
.join(' > ');
|
|
911
|
+
success(t('publish.nav_order_ok', orderedNames || '-'));
|
|
912
|
+
} catch (navOrderError) {
|
|
913
|
+
navOrderWarning = navOrderError && navOrderError.message ? navOrderError.message : t('common.unknown_error');
|
|
914
|
+
warn(t('publish.nav_order_failed', navOrderWarning));
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
|
|
897
918
|
if (configResponse && configResponse.success) {
|
|
898
919
|
result(true, t('publish.success'), [
|
|
899
920
|
['Form UUID', savedFormUuid],
|
|
@@ -901,7 +922,7 @@ async function runMain(argv) {
|
|
|
901
922
|
['URL', pageUrl],
|
|
902
923
|
]);
|
|
903
924
|
console.log(JSON.stringify(withBrowserHandoff(
|
|
904
|
-
{ success: true, appType, formUuid: savedFormUuid, version, url: pageUrl, healthCheck: healthCheckResult },
|
|
925
|
+
{ success: true, appType, formUuid: savedFormUuid, version, url: pageUrl, healthCheck: healthCheckResult, navOrder: navOrderResult, navOrderWarning },
|
|
905
926
|
pageUrl,
|
|
906
927
|
{ stage: 'publish_page_success', title: savedFormUuid },
|
|
907
928
|
browserOpenMode
|
|
@@ -915,7 +936,7 @@ async function runMain(argv) {
|
|
|
915
936
|
]);
|
|
916
937
|
hint(t('publish.schema_ok_config_failed'));
|
|
917
938
|
console.log(JSON.stringify(withBrowserHandoff(
|
|
918
|
-
{ success: true, appType, formUuid: savedFormUuid, version, url: pageUrl, configWarning: configErrorMsg, healthCheck: healthCheckResult },
|
|
939
|
+
{ success: true, appType, formUuid: savedFormUuid, version, url: pageUrl, configWarning: configErrorMsg, healthCheck: healthCheckResult, navOrder: navOrderResult, navOrderWarning },
|
|
919
940
|
pageUrl,
|
|
920
941
|
{ stage: 'publish_page_success', title: savedFormUuid },
|
|
921
942
|
browserOpenMode
|