openxiangda 1.0.109 → 1.0.111
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/lib/cli.js +172 -9
- package/lib/design-gates.js +1 -0
- package/openxiangda-skills/SKILL.md +3 -3
- package/openxiangda-skills/skills/openxiangda-core/SKILL.md +1 -0
- package/openxiangda-skills/skills/openxiangda-workflow-automation/SKILL.md +1 -1
- package/package.json +1 -1
- package/packages/sdk/src/build-source/scripts/sync-schema.mjs +7 -0
- package/packages/sdk/src/build-source/scripts/utils/form-api.mjs +7 -0
- package/templates/openxiangda-react-spa/AGENTS.md +1 -1
- package/templates/openxiangda-react-spa/scripts/guard-publish.mjs +2 -1
package/lib/cli.js
CHANGED
|
@@ -132,7 +132,7 @@ Usage:
|
|
|
132
132
|
openxiangda menu update|sort [--json-file file] [--write-manifest]
|
|
133
133
|
openxiangda menu bind <menuCode> --menu-id <id>
|
|
134
134
|
openxiangda workflow compile <workflow.ts> [--check] [--stdout] [--out-definition file] [--out-preview file]
|
|
135
|
-
openxiangda workflow list [--profile name] [--form-code code] [--json]
|
|
135
|
+
openxiangda workflow list [--profile name] [--form-code code] [--json] [--all]
|
|
136
136
|
openxiangda workflow create <workflowCode> --form-code <formCode> --definition-json <file>
|
|
137
137
|
openxiangda workflow bind <workflowCode> --workflow-id <id>
|
|
138
138
|
openxiangda workflow publish <workflowCode|workflowId>
|
|
@@ -171,6 +171,7 @@ JS_CODE V2 使用 trusted_node;AI 源码必须写在 src/js-code-nodes/<script
|
|
|
171
171
|
}
|
|
172
172
|
|
|
173
173
|
const SUBCOMMAND_BOOLEAN_FLAGS = new Set([
|
|
174
|
+
'--all',
|
|
174
175
|
'--dry-run',
|
|
175
176
|
'--enabled',
|
|
176
177
|
'--force',
|
|
@@ -1377,7 +1378,7 @@ async function workspace(args) {
|
|
|
1377
1378
|
const [subcommand, ...rest] = args;
|
|
1378
1379
|
const { flags, positional } = parseArgs(rest);
|
|
1379
1380
|
if (wantsSubcommandHelp(subcommand, flags)) {
|
|
1380
|
-
|
|
1381
|
+
printWorkspaceHelp();
|
|
1381
1382
|
return;
|
|
1382
1383
|
}
|
|
1383
1384
|
const config = loadConfig();
|
|
@@ -1483,7 +1484,25 @@ async function workspace(args) {
|
|
|
1483
1484
|
profileName,
|
|
1484
1485
|
`/openxiangda-api/v1/apps/${encodeURIComponent(bound.appType)}/snapshot`
|
|
1485
1486
|
);
|
|
1486
|
-
|
|
1487
|
+
const reactSpaWorkspace = isReactSpaWorkspace();
|
|
1488
|
+
if (reactSpaWorkspace && !publishOptions.legacyFormBundle) {
|
|
1489
|
+
if (publishOptions.targetForm && !publishOptions.targetPage && !publishOptions.only && !publishOptions.changed) {
|
|
1490
|
+
runReactSpaFormSchemaPublish(profileName, profile, bound.appType, publishOptions);
|
|
1491
|
+
} else {
|
|
1492
|
+
fail(
|
|
1493
|
+
[
|
|
1494
|
+
'React SPA 工作区不使用 workspace publish 发布前端页面。',
|
|
1495
|
+
'如需发布表单 schema,请运行:',
|
|
1496
|
+
` openxiangda workspace publish --profile ${profileName} --form <formCode>`,
|
|
1497
|
+
'如需发布资源和前端运行时,请运行:',
|
|
1498
|
+
` openxiangda resource publish --profile ${profileName}`,
|
|
1499
|
+
` openxiangda runtime deploy --profile ${profileName}`,
|
|
1500
|
+
].join('\n')
|
|
1501
|
+
);
|
|
1502
|
+
}
|
|
1503
|
+
} else {
|
|
1504
|
+
runWorkspacePublish(profileName, profile, bound.appType, publishOptions.workspaceArgs);
|
|
1505
|
+
}
|
|
1487
1506
|
if (publishOptions.includeResources) {
|
|
1488
1507
|
if (publishOptions.dryRun) {
|
|
1489
1508
|
const manifest = loadWorkspaceResources();
|
|
@@ -1509,6 +1528,34 @@ async function workspace(args) {
|
|
|
1509
1528
|
fail('用法: openxiangda workspace init|bind|publish [--changed [--since ref]|--form code|--page code|--only list] [--dry-run] [--force] [--resources|--skip-resources]');
|
|
1510
1529
|
}
|
|
1511
1530
|
|
|
1531
|
+
function printWorkspaceHelp() {
|
|
1532
|
+
print(`OpenXiangda workspace
|
|
1533
|
+
|
|
1534
|
+
Usage:
|
|
1535
|
+
openxiangda workspace init [dir] [--name package-name] [--runtime legacy|react-spa] [--install] [--force]
|
|
1536
|
+
openxiangda workspace init [dir] --profile <name> --app-name <app-name> [--runtime legacy|react-spa] [--description text] [--install] [--force]
|
|
1537
|
+
openxiangda workspace init [dir] --profile <name> --app-type <APP_XXX> [--runtime legacy|react-spa] [--install] [--force]
|
|
1538
|
+
openxiangda workspace bind --profile <name> --app-type <APP_XXX>
|
|
1539
|
+
openxiangda workspace publish --profile <name> [--changed [--since ref]|--form code|--page code|--only list] [--dry-run] [--force] [--resources|--skip-resources] [--prune]
|
|
1540
|
+
|
|
1541
|
+
React SPA:
|
|
1542
|
+
openxiangda workspace publish --profile <name> --form <formCode> # sync form schema only
|
|
1543
|
+
openxiangda resource publish --profile <name>
|
|
1544
|
+
openxiangda runtime deploy --profile <name>
|
|
1545
|
+
|
|
1546
|
+
Options:
|
|
1547
|
+
--runtime legacy|react-spa Workspace template/runtime mode.
|
|
1548
|
+
--app-name <name> Create and bind a new platform app.
|
|
1549
|
+
--app-type <APP_XXX> Bind an existing platform app.
|
|
1550
|
+
--form <code> Publish one form schema/page.
|
|
1551
|
+
--page <code> Publish one classic page.
|
|
1552
|
+
--only pages/a,forms/b Publish selected classic resources.
|
|
1553
|
+
--changed [--since ref] Publish changed classic resources.
|
|
1554
|
+
--dry-run Show planned work without writing.
|
|
1555
|
+
--resources / --skip-resources Include or skip src/resources publish.
|
|
1556
|
+
--legacy-form-bundle Force legacy workspace publish in React SPA workspaces.`);
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1512
1559
|
async function app(args) {
|
|
1513
1560
|
const [subcommand, ...rest] = args;
|
|
1514
1561
|
const { flags, positional } = parseArgs(rest);
|
|
@@ -1962,7 +2009,7 @@ async function workflow(args) {
|
|
|
1962
2009
|
const { subcommand, rest } = parseSubcommandArgs(args);
|
|
1963
2010
|
const { flags, positional } = parseArgs(rest);
|
|
1964
2011
|
if (wantsSubcommandHelp(subcommand, flags)) {
|
|
1965
|
-
|
|
2012
|
+
printWorkflowHelp();
|
|
1966
2013
|
return;
|
|
1967
2014
|
}
|
|
1968
2015
|
const config = loadConfig();
|
|
@@ -2023,8 +2070,9 @@ async function workflow(args) {
|
|
|
2023
2070
|
}
|
|
2024
2071
|
)
|
|
2025
2072
|
);
|
|
2026
|
-
|
|
2027
|
-
|
|
2073
|
+
const output = flags.all ? data : filterManifestBackedWorkflows(data);
|
|
2074
|
+
if (flags.json) return writeJson(output);
|
|
2075
|
+
print(JSON.stringify(output, null, 2));
|
|
2028
2076
|
return;
|
|
2029
2077
|
}
|
|
2030
2078
|
|
|
@@ -2066,8 +2114,8 @@ async function workflow(args) {
|
|
|
2066
2114
|
body: {
|
|
2067
2115
|
formUuid,
|
|
2068
2116
|
definitionJson,
|
|
2069
|
-
...(flags['view-json']
|
|
2070
|
-
? { viewJson: readJsonArg(flags['view-json'], '
|
|
2117
|
+
...(flags['preview-json'] || flags['view-json']
|
|
2118
|
+
? { viewJson: readJsonArg(flags['preview-json'] || flags['view-json'], 'preview-json') }
|
|
2071
2119
|
: {}),
|
|
2072
2120
|
},
|
|
2073
2121
|
}
|
|
@@ -2174,6 +2222,49 @@ async function workflow(args) {
|
|
|
2174
2222
|
fail('用法: openxiangda workflow compile|list|create|bind|pull|publish|delete|validate');
|
|
2175
2223
|
}
|
|
2176
2224
|
|
|
2225
|
+
function printWorkflowHelp() {
|
|
2226
|
+
print(`OpenXiangda workflow
|
|
2227
|
+
|
|
2228
|
+
Usage:
|
|
2229
|
+
openxiangda workflow compile <workflow.ts> [--check] [--stdout|--json] [--out-definition file] [--out-preview file]
|
|
2230
|
+
openxiangda workflow list [--profile name] [--form-code code|--form-uuid FORM_XXX] [--published true|false] [--page n] [--page-size n] [--json] [--all]
|
|
2231
|
+
openxiangda workflow create <workflowCode> --form-code <formCode> --definition-json <file> [--preview-json file] [--publish]
|
|
2232
|
+
openxiangda workflow bind <workflowCode> --workflow-id <id> [--form-code code|--form-uuid FORM_XXX]
|
|
2233
|
+
openxiangda workflow pull <workflowCode|workflowId> [--out file] [--json]
|
|
2234
|
+
openxiangda workflow publish <workflowCode|workflowId> [--profile name]
|
|
2235
|
+
openxiangda workflow delete <workflowCode|workflowId> [--yes]
|
|
2236
|
+
openxiangda workflow validate --definition-json <file> [--strict] [--publish]
|
|
2237
|
+
|
|
2238
|
+
Notes:
|
|
2239
|
+
- Prefer semantic DSL: src/workflows/<code>/workflow.ts + defineWorkflow().
|
|
2240
|
+
- Run workspace publish --form <formCode> before publishing workflow resources for React SPA process forms.
|
|
2241
|
+
- workflow list hides platform shell workflows with empty resourceCode by default; pass --all to inspect raw platform rows.`);
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2244
|
+
function filterManifestBackedWorkflows(data) {
|
|
2245
|
+
const shouldKeep = item => item && String(item.resourceCode || '').trim();
|
|
2246
|
+
if (Array.isArray(data)) {
|
|
2247
|
+
return data.filter(shouldKeep);
|
|
2248
|
+
}
|
|
2249
|
+
if (!data || typeof data !== 'object') return data;
|
|
2250
|
+
for (const key of ['data', 'items', 'list', 'records']) {
|
|
2251
|
+
if (Array.isArray(data[key])) {
|
|
2252
|
+
const filtered = data[key].filter(shouldKeep);
|
|
2253
|
+
return {
|
|
2254
|
+
...data,
|
|
2255
|
+
[key]: filtered,
|
|
2256
|
+
totalCount: Object.prototype.hasOwnProperty.call(data, 'totalCount')
|
|
2257
|
+
? filtered.length
|
|
2258
|
+
: data.totalCount,
|
|
2259
|
+
total: Object.prototype.hasOwnProperty.call(data, 'total')
|
|
2260
|
+
? filtered.length
|
|
2261
|
+
: data.total,
|
|
2262
|
+
};
|
|
2263
|
+
}
|
|
2264
|
+
}
|
|
2265
|
+
return data;
|
|
2266
|
+
}
|
|
2267
|
+
|
|
2177
2268
|
async function automation(args) {
|
|
2178
2269
|
const { subcommand, rest } = parseSubcommandArgs(args);
|
|
2179
2270
|
const { flags, positional } = parseArgs(rest);
|
|
@@ -3649,7 +3740,9 @@ async function resource(args) {
|
|
|
3649
3740
|
return;
|
|
3650
3741
|
}
|
|
3651
3742
|
|
|
3743
|
+
const target = getWorkspaceTarget(config, profileName, flags);
|
|
3652
3744
|
const validation = validateWorkspaceResources(manifest);
|
|
3745
|
+
validateWorkspaceResourceBindings(manifest, target.bound, validation);
|
|
3653
3746
|
await validateCompiledWorkflowResources(manifest, validation);
|
|
3654
3747
|
if (subcommand === 'validate') {
|
|
3655
3748
|
if (flags.json) return writeJson(validation);
|
|
@@ -3663,7 +3756,6 @@ async function resource(args) {
|
|
|
3663
3756
|
fail(`资源配置校验失败: ${validation.errors[0]}`);
|
|
3664
3757
|
}
|
|
3665
3758
|
|
|
3666
|
-
const target = getWorkspaceTarget(config, profileName, flags);
|
|
3667
3759
|
const dryRun = subcommand === 'publish' && Boolean(flags['dry-run']);
|
|
3668
3760
|
if (subcommand === 'plan' || dryRun) {
|
|
3669
3761
|
const plan = await buildResourcePlan(config, target, manifest);
|
|
@@ -5358,6 +5450,34 @@ function validateWorkspaceResources(manifest) {
|
|
|
5358
5450
|
};
|
|
5359
5451
|
}
|
|
5360
5452
|
|
|
5453
|
+
function validateWorkspaceResourceBindings(manifest, bound, validation) {
|
|
5454
|
+
for (const item of manifest.workflows || []) {
|
|
5455
|
+
if (!item.formCode && !item.form) continue;
|
|
5456
|
+
const formCode = item.formCode || item.form;
|
|
5457
|
+
const formBinding = bound?.resources?.forms?.[formCode];
|
|
5458
|
+
const formUuid = formBinding?.formUuid;
|
|
5459
|
+
if (!formUuid) {
|
|
5460
|
+
validation.errors.push(
|
|
5461
|
+
`${resourceLabel('workflow', item)}: formCode ${formCode} 未绑定。请先运行 openxiangda workspace publish --profile <name> --form ${formCode}`
|
|
5462
|
+
);
|
|
5463
|
+
continue;
|
|
5464
|
+
}
|
|
5465
|
+
const localSchemaPath = path.join(process.cwd(), 'src', 'forms', formCode, 'schema.ts');
|
|
5466
|
+
if (fs.existsSync(localSchemaPath) && !formBinding.schemaSyncedAt) {
|
|
5467
|
+
validation.errors.push(
|
|
5468
|
+
`${resourceLabel('workflow', item)}: formCode ${formCode} 已绑定但本地 schema 尚未同步。请先运行 openxiangda workspace publish --profile <name> --form ${formCode}`
|
|
5469
|
+
);
|
|
5470
|
+
}
|
|
5471
|
+
if (formBinding.formType && formBinding.formType !== 'process') {
|
|
5472
|
+
validation.errors.push(
|
|
5473
|
+
`${resourceLabel('workflow', item)}: formCode ${formCode} 当前 formType=${formBinding.formType},流程表单需要 process`
|
|
5474
|
+
);
|
|
5475
|
+
}
|
|
5476
|
+
}
|
|
5477
|
+
validation.valid = validation.errors.length === 0;
|
|
5478
|
+
return validation;
|
|
5479
|
+
}
|
|
5480
|
+
|
|
5361
5481
|
async function validateCompiledWorkflowResources(manifest, validation) {
|
|
5362
5482
|
for (const item of manifest.workflows || []) {
|
|
5363
5483
|
if (!item.workflowFile) continue;
|
|
@@ -9663,6 +9783,7 @@ function normalizeWorkspacePublishOptions(flags) {
|
|
|
9663
9783
|
if (since) workspaceArgs.push('--since', since);
|
|
9664
9784
|
if (dryRun) workspaceArgs.push('--dry-run');
|
|
9665
9785
|
if (force) workspaceArgs.push('--force');
|
|
9786
|
+
if (flags['legacy-form-bundle']) workspaceArgs.push('--legacy-form-bundle');
|
|
9666
9787
|
|
|
9667
9788
|
const targeted = Boolean(targetForm || targetPage || only || changed);
|
|
9668
9789
|
const includeResources =
|
|
@@ -9671,6 +9792,11 @@ function normalizeWorkspacePublishOptions(flags) {
|
|
|
9671
9792
|
return {
|
|
9672
9793
|
workspaceArgs,
|
|
9673
9794
|
dryRun,
|
|
9795
|
+
targetForm,
|
|
9796
|
+
targetPage,
|
|
9797
|
+
only,
|
|
9798
|
+
changed,
|
|
9799
|
+
legacyFormBundle: Boolean(flags['legacy-form-bundle']),
|
|
9674
9800
|
includeResources,
|
|
9675
9801
|
quietResourceSkip: !targeted || skipResources,
|
|
9676
9802
|
};
|
|
@@ -9708,6 +9834,43 @@ function runWorkspacePublish(profileName, profile, appType, publishArgs = []) {
|
|
|
9708
9834
|
}
|
|
9709
9835
|
}
|
|
9710
9836
|
|
|
9837
|
+
function isReactSpaWorkspace() {
|
|
9838
|
+
const configFile = path.join(process.cwd(), 'app-workspace.config.ts');
|
|
9839
|
+
if (!fs.existsSync(configFile)) return false;
|
|
9840
|
+
const content = fs.readFileSync(configFile, 'utf8');
|
|
9841
|
+
return /runtimeMode\s*:\s*['"]react-spa['"]/.test(content);
|
|
9842
|
+
}
|
|
9843
|
+
|
|
9844
|
+
function runReactSpaFormSchemaPublish(profileName, profile, appType, publishOptions) {
|
|
9845
|
+
const packageFile = path.join(process.cwd(), 'package.json');
|
|
9846
|
+
if (!fs.existsSync(packageFile)) {
|
|
9847
|
+
fail('当前目录没有 package.json,无法识别工作区发布脚本');
|
|
9848
|
+
}
|
|
9849
|
+
const pkg = JSON.parse(fs.readFileSync(packageFile, 'utf8'));
|
|
9850
|
+
const scripts = pkg.scripts || {};
|
|
9851
|
+
const usePnpm = fs.existsSync(path.join(process.cwd(), 'pnpm-lock.yaml'));
|
|
9852
|
+
const command = usePnpm ? 'pnpm' : 'npm';
|
|
9853
|
+
const syncArgs = ['--form', publishOptions.targetForm];
|
|
9854
|
+
if (publishOptions.dryRun) syncArgs.push('--dry-run');
|
|
9855
|
+
const args = scripts['sync-schema']
|
|
9856
|
+
? ['run', 'sync-schema', '--', ...syncArgs]
|
|
9857
|
+
: usePnpm
|
|
9858
|
+
? ['exec', 'lowcode-workspace', 'sync-schema', ...syncArgs]
|
|
9859
|
+
: ['exec', '--', 'lowcode-workspace', 'sync-schema', ...syncArgs];
|
|
9860
|
+
print(
|
|
9861
|
+
`React SPA 表单 schema 发布${publishOptions.dryRun ? ' (dry-run)' : ''}: ${publishOptions.targetForm}`
|
|
9862
|
+
);
|
|
9863
|
+
const globalEnv = loadGlobalEnv();
|
|
9864
|
+
const result = spawnSync(command, args, {
|
|
9865
|
+
cwd: process.cwd(),
|
|
9866
|
+
stdio: 'inherit',
|
|
9867
|
+
env: buildWorkspacePublishEnv(profileName, profile, appType, globalEnv),
|
|
9868
|
+
});
|
|
9869
|
+
if (result.status !== 0) {
|
|
9870
|
+
process.exit(result.status || 1);
|
|
9871
|
+
}
|
|
9872
|
+
}
|
|
9873
|
+
|
|
9711
9874
|
function buildWorkspacePublishEnv(profileName, profile, appType, globalEnv) {
|
|
9712
9875
|
const env = { ...process.env };
|
|
9713
9876
|
const injectedGlobalKeys = [];
|
package/lib/design-gates.js
CHANGED
|
@@ -498,6 +498,7 @@ const RESOURCE_EXPLAINS = {
|
|
|
498
498
|
enable: true,
|
|
499
499
|
},
|
|
500
500
|
commands: [
|
|
501
|
+
'openxiangda workspace publish --profile <name> --form expense_request',
|
|
501
502
|
'openxiangda workflow compile src/workflows/expense_approval/workflow.ts --check',
|
|
502
503
|
'openxiangda workflow compile src/workflows/expense_approval/workflow.ts --out-definition src/generated/workflows/expense_approval/definition.v3.json --out-preview src/generated/workflows/expense_approval/preview.json',
|
|
503
504
|
'openxiangda resource validate workflow',
|
|
@@ -38,7 +38,7 @@ OpenXiangda supports two workspace modes. Classic `sy-lowcode-app-workspace` pub
|
|
|
38
38
|
|
|
39
39
|
### Hard rules — always
|
|
40
40
|
|
|
41
|
-
- ✅ Publish classic workspaces through `openxiangda workspace publish --profile <name>`; publish React SPA
|
|
41
|
+
- ✅ Publish classic workspaces through `openxiangda workspace publish --profile <name>`; publish React SPA forms first with `openxiangda workspace publish --form <formCode>`, then resources/runtime through `openxiangda resource validate` → `openxiangda resource publish --dry-run` → `openxiangda resource publish` → `openxiangda runtime deploy`.
|
|
42
42
|
- ✅ Architecture-class requests are plan-gated by default. For 新应用、复杂页面、登录注册、公开访问、权限数据范围、流程自动化、连接器/通知、外部集成, first run `openxiangda doctor --json` when a workspace exists and `openxiangda design gates --topic <code> --json`; then ask the user to confirm the design. Before confirmation, only read files, inspect/snapshot, dry-run, ask questions, and write/output design docs. Do not edit source files, write platform resources, send notifications, publish, or deploy.
|
|
43
43
|
- ✅ `runtime deploy` defaults to staged multipart `dist/` uploads plus a final manifest. Use `--upload-mode legacy-json` only for old platform servers.
|
|
44
44
|
- ✅ User token lives in `~/.openxiangda/profiles.json`; project state in `.openxiangda/state.json` (IDs only).
|
|
@@ -162,8 +162,8 @@ When the user provides a root domain such as `https://yida.wisejob.cn/`, use it
|
|
|
162
162
|
- Use JS_CODE for node-local cross-form data queries, create/update/batch update operations, process termination, platform API calls, external HTTP calls, and backend trigger orchestration. For logic that pages, automations, and workflows should reuse through a stable backend entry, prefer App Function. Do not use JS_CODE for simple UI interactions, ordinary form validation, or display-only page behavior.
|
|
163
163
|
- For workflow/automation JS_CODE nodes, prefer V2 `runtimeMode: "trusted_node"`. AI-authored source must be TypeScript under `src/js-code-nodes/<scriptCode>/index.ts`, `src/automations/<resourceCode>/index.ts`, or `src/functions/<functionCode>/index.ts`. `pnpm build-js-code --script <scriptCode>` runs TypeScript validation before bundling, and `sourceFile.localPath` should point to the TS source; the CLI builds, uploads, and replaces it with snapshot metadata during validate/create.
|
|
164
164
|
- Form permission group resources must have stable local codes. Use unique `code` values such as `ticket_reporter_view` and `ticket_repairer_view`; do not rely on the form code when one form has multiple groups.
|
|
165
|
-
- Workflow resources should prefer `workflowFile` + `defineWorkflow` semantic DSL over hand-written raw JSON.
|
|
166
|
-
- Workflow resources can be created as drafts. After resource publish, verify `openxiangda workflow list --profile <name> --json` and run `openxiangda workflow publish <workflowCode> --profile <name>` until `isPublished: true` is visible.
|
|
165
|
+
- Workflow resources should prefer `workflowFile` + `defineWorkflow` semantic DSL over hand-written raw JSON. For workflows bound by `formCode`, run `openxiangda workspace publish --form <formCode>` first so the process form schema/table is initialized, then run `openxiangda workflow compile <workflow.ts> --check` and `openxiangda resource publish --dry-run --profile <name>` before publish; use `sdk.process.resolveCapabilities(...)` or `ProcessActionBar` / `ProcessTimeline` from `openxiangda/runtime/react` for runtime buttons and timelines instead of hard-coded operation lists.
|
|
166
|
+
- Workflow resources can be created as drafts. After resource publish, verify `openxiangda workflow list --profile <name> --json` and run `openxiangda workflow publish <workflowCode> --profile <name>` until `isPublished: true` is visible. `workflow list` hides platform shell workflows with empty `resourceCode` by default; pass `--all` only when diagnosing raw platform rows.
|
|
167
167
|
|
|
168
168
|
## Subskills
|
|
169
169
|
|
|
@@ -37,6 +37,7 @@ openxiangda workspace publish --profile <name>
|
|
|
37
37
|
For Phase 6 React SPA workspaces (`workspace init --runtime react-spa`), do not use `workspace publish` for frontend routes. Publish in two explicit steps:
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
|
+
openxiangda workspace publish --profile <name> --form <formCode> # required for forms/workflows
|
|
40
41
|
openxiangda resource validate --profile <name>
|
|
41
42
|
openxiangda resource plan --profile <name>
|
|
42
43
|
openxiangda resource publish --profile <name> --dry-run
|
|
@@ -93,7 +93,7 @@ openxiangda form bind customer --form-uuid FORM_XXX --profile dev
|
|
|
93
93
|
openxiangda workflow list --profile dev --json
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
-
Use `workflow pull` to inspect the live definition. Use `workflow list --json` after publishing and confirm the target shows `isPublished: true`; resource publish can create/update a draft without activating it. Use logical workflow codes locally; never copy a workflow ID from one profile to another.
|
|
96
|
+
Use `workflow pull` to inspect the live definition. Use `workflow list --json` after publishing and confirm the target shows `isPublished: true`; resource publish can create/update a draft without activating it. `workflow list` hides platform shell workflows with empty `resourceCode` by default; use `--all` only for raw platform diagnostics. Use logical workflow codes locally; never copy a workflow ID from one profile to another.
|
|
97
97
|
|
|
98
98
|
## JS_CODE V2
|
|
99
99
|
|
package/package.json
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
ensureSchemaFormUuid,
|
|
23
23
|
getOpenApiAccessToken,
|
|
24
24
|
isOpenXiangdaMode,
|
|
25
|
+
markWorkspaceFormSchemaSynced,
|
|
25
26
|
} from "./utils/form-api.mjs";
|
|
26
27
|
import {
|
|
27
28
|
assertSchemaSyncResult,
|
|
@@ -305,6 +306,12 @@ async function main() {
|
|
|
305
306
|
} else {
|
|
306
307
|
try {
|
|
307
308
|
const response = await sendToApi(apiPayload, config, accessToken);
|
|
309
|
+
markWorkspaceFormSchemaSynced(config, form.name, apiPayload.formUuid, {
|
|
310
|
+
title: schema.formMeta?.title || form.name,
|
|
311
|
+
formType: apiPayload.formType || schema.formMeta?.formType || "receipt",
|
|
312
|
+
fieldCount: apiPayload.fieldCount,
|
|
313
|
+
tableName: response?.data?.tableName,
|
|
314
|
+
});
|
|
308
315
|
console.log(` ✅ 同步成功,tableName=${response.data.tableName}`);
|
|
309
316
|
results.push({ name: form.name, success: true, response });
|
|
310
317
|
} catch (error) {
|
|
@@ -116,6 +116,13 @@ function saveWorkspaceFormBinding(config, formName, formUuid, extra = {}) {
|
|
|
116
116
|
return true;
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
export function markWorkspaceFormSchemaSynced(config, formName, formUuid, extra = {}) {
|
|
120
|
+
return saveWorkspaceFormBinding(config, formName, formUuid, {
|
|
121
|
+
...extra,
|
|
122
|
+
schemaSyncedAt: new Date().toISOString(),
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
119
126
|
function readExportedStringConstant(filePath, exportName) {
|
|
120
127
|
if (!filePath || !fs.existsSync(filePath)) return "";
|
|
121
128
|
const content = fs.readFileSync(filePath, "utf-8");
|
|
@@ -33,7 +33,7 @@ openxiangda runtime deploy --profile <name>
|
|
|
33
33
|
openxiangda commands --json
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
`pnpm deploy -- --profile <name>` 会按顺序执行 `openxiangda resource publish --profile <name>` 与 `openxiangda runtime deploy --profile <name
|
|
36
|
+
`pnpm deploy -- --profile <name>` 会按顺序执行 `openxiangda resource publish --profile <name>` 与 `openxiangda runtime deploy --profile <name>`。如果应用包含 `src/forms/<formCode>/schema.ts`,先执行 `openxiangda workspace publish --profile <name> --form <formCode>` 初始化表单 schema/table。不要直接运行 `pnpm publish:all`、`pnpm openxiangda:publish` 或 `lowcode-workspace publish-all`;这些是 legacy classic workspace 的内部发布入口,会被 `scripts/guard-publish.mjs` 拦截。
|
|
37
37
|
|
|
38
38
|
完整发布顺序:
|
|
39
39
|
|
|
@@ -4,7 +4,8 @@ const lines = [
|
|
|
4
4
|
'',
|
|
5
5
|
'错误:React SPA 工作区不要直接调用 lowcode-workspace publish-all。',
|
|
6
6
|
'',
|
|
7
|
-
'React SPA
|
|
7
|
+
'React SPA 的发布入口必须显式指定 profile:',
|
|
8
|
+
' openxiangda workspace publish --profile <name> --form <formCode> # 仅同步表单 schema',
|
|
8
9
|
' openxiangda resource publish --profile <name>',
|
|
9
10
|
' openxiangda runtime deploy --profile <name>',
|
|
10
11
|
'',
|