@nocobase/cli 3.0.0-alpha.6 → 3.0.0-alpha.7
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/dist/commands/env/add.js +6 -0
- package/dist/commands/env/update.js +13 -0
- package/dist/commands/init.js +49 -0
- package/dist/commands/install.js +18 -62
- package/dist/lib/app-client-entry-mode.js +28 -0
- package/dist/lib/app-managed-resources.js +2 -0
- package/dist/lib/auth-store.js +1 -0
- package/dist/lib/env-auth.js +1 -35
- package/dist/lib/env-command-config.js +1 -0
- package/dist/lib/env-config.js +5 -2
- package/dist/lib/env-proxy.js +1 -1
- package/dist/lib/managed-env-file.js +57 -1
- package/dist/lib/managed-init-env.js +0 -2
- package/dist/lib/prompt-catalog-core.js +2 -2
- package/dist/lib/prompt-catalog-terminal.js +4 -5
- package/dist/lib/prompt-web-ui.js +8 -1
- package/dist/locale/en-US.json +10 -1
- package/dist/locale/zh-CN.json +10 -1
- package/package.json +2 -2
package/dist/commands/env/add.js
CHANGED
|
@@ -11,6 +11,7 @@ import { setCurrentEnv, upsertEnv } from '../../lib/auth-store.js';
|
|
|
11
11
|
import { resolveDefaultConfigScope } from '../../lib/cli-home.js';
|
|
12
12
|
import { ENV_BOOLEAN_CONFIG_FLAG_MAP, ENV_STRING_CONFIG_FLAG_MAP } from '../../lib/env-command-config.js';
|
|
13
13
|
import { buildStoredEnvConfig } from '../../lib/env-config.js';
|
|
14
|
+
import { PUBLIC_APP_CLIENT_ENTRY_MODES } from '../../lib/app-client-entry-mode.js';
|
|
14
15
|
import { runPromptCatalog, } from '../../lib/prompt-catalog.js';
|
|
15
16
|
import { applyCliLocale, CLI_LOCALE_FLAG_DESCRIPTION, CLI_LOCALE_FLAG_OPTIONS, localeText, } from '../../lib/cli-locale.js';
|
|
16
17
|
import { validateApiBaseUrl } from '../../lib/prompt-validators.js';
|
|
@@ -172,6 +173,11 @@ export default class EnvAdd extends Command {
|
|
|
172
173
|
hidden: true,
|
|
173
174
|
description: 'Docker env file saved with this env',
|
|
174
175
|
}),
|
|
176
|
+
'app-client-entry-mode': Flags.string({
|
|
177
|
+
hidden: true,
|
|
178
|
+
description: 'UI entry mode saved with this env',
|
|
179
|
+
options: [...PUBLIC_APP_CLIENT_ENTRY_MODES],
|
|
180
|
+
}),
|
|
175
181
|
'app-port': Flags.string({
|
|
176
182
|
hidden: true,
|
|
177
183
|
description: 'Application HTTP port saved with this env',
|
|
@@ -16,6 +16,8 @@ import { appendDiagnosticLogPath } from '../../lib/cli-entry-error.js';
|
|
|
16
16
|
import { getActiveCommandLogFile } from '../../lib/command-log.js';
|
|
17
17
|
import { ENV_BOOLEAN_CONFIG_FLAG_MAP, ENV_STRING_CONFIG_FLAG_MAP } from '../../lib/env-command-config.js';
|
|
18
18
|
import { buildStoredEnvConfig } from '../../lib/env-config.js';
|
|
19
|
+
import { PUBLIC_APP_CLIENT_ENTRY_MODES } from '../../lib/app-client-entry-mode.js';
|
|
20
|
+
import { upsertManagedEnvFileValues } from '../../lib/managed-env-file.js';
|
|
19
21
|
import { validateApiBaseUrl } from '../../lib/prompt-validators.js';
|
|
20
22
|
import { failTask, printInfo, printVerbose, printWarningBlock, setVerboseMode, startTask, stopTask, succeedTask, } from '../../lib/ui.js';
|
|
21
23
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -35,6 +37,7 @@ const UPDATE_STRING_FLAGS = [
|
|
|
35
37
|
'app-public-path',
|
|
36
38
|
'cdn-base-url',
|
|
37
39
|
'env-file',
|
|
40
|
+
'app-client-entry-mode',
|
|
38
41
|
'app-port',
|
|
39
42
|
'app-key',
|
|
40
43
|
'timezone',
|
|
@@ -68,6 +71,7 @@ const APP_RESTART_FIELDS = new Set([
|
|
|
68
71
|
'storage-path',
|
|
69
72
|
'app-public-path',
|
|
70
73
|
'env-file',
|
|
74
|
+
'app-client-entry-mode',
|
|
71
75
|
'app-port',
|
|
72
76
|
'app-key',
|
|
73
77
|
'timezone',
|
|
@@ -255,6 +259,10 @@ export default class EnvUpdate extends Command {
|
|
|
255
259
|
hidden: true,
|
|
256
260
|
description: 'Saved Docker --env-file path for this env',
|
|
257
261
|
}),
|
|
262
|
+
'app-client-entry-mode': Flags.string({
|
|
263
|
+
description: 'Saved UI entry mode for this env',
|
|
264
|
+
options: [...PUBLIC_APP_CLIENT_ENTRY_MODES],
|
|
265
|
+
}),
|
|
258
266
|
'app-port': Flags.string({
|
|
259
267
|
description: 'Saved application HTTP port for this env',
|
|
260
268
|
}),
|
|
@@ -423,6 +431,11 @@ export default class EnvUpdate extends Command {
|
|
|
423
431
|
startTask(`Saving env config: ${envName}`);
|
|
424
432
|
try {
|
|
425
433
|
await replaceEnvConfig(envName, nextConfig, { scope: resolveDefaultConfigScope() });
|
|
434
|
+
if (providedFields.has('app-client-entry-mode') && nextConfig.appClientEntryMode) {
|
|
435
|
+
await upsertManagedEnvFileValues(envName, nextConfig, {
|
|
436
|
+
APP_CLIENT_ENTRY_MODE: nextConfig.appClientEntryMode,
|
|
437
|
+
});
|
|
438
|
+
}
|
|
426
439
|
succeedTask(`Saved env config for "${envName}".`);
|
|
427
440
|
}
|
|
428
441
|
catch (error) {
|
package/dist/commands/init.js
CHANGED
|
@@ -13,6 +13,7 @@ import { existsSync } from 'node:fs';
|
|
|
13
13
|
import path from 'node:path';
|
|
14
14
|
import { stdin as stdinStream, stdout as stdoutStream } from 'node:process';
|
|
15
15
|
import { getEnv, upsertEnv } from "../lib/auth-store.js";
|
|
16
|
+
import { defaultAppClientEntryModeForDownloadVersion, normalizePublicAppClientEntryMode, PUBLIC_APP_CLIENT_ENTRY_MODES, } from '../lib/app-client-entry-mode.js';
|
|
16
17
|
import { runPromptCatalog, } from "../lib/prompt-catalog.js";
|
|
17
18
|
import { applyCliLocale, localeText, translateCli } from "../lib/cli-locale.js";
|
|
18
19
|
import { resolveConfiguredEnvPath, resolveDefaultConfigScope, resolveEnvRelativePath } from '../lib/cli-home.js';
|
|
@@ -47,6 +48,23 @@ const INIT_ENV_ADD_FLAG_NAMES = [
|
|
|
47
48
|
'skip-auth',
|
|
48
49
|
];
|
|
49
50
|
const initText = (key, values) => localeText(`commands.init.${key}`, values);
|
|
51
|
+
const PUBLIC_APP_CLIENT_ENTRY_MODE_OPTIONS = [
|
|
52
|
+
{
|
|
53
|
+
value: 'modern-only',
|
|
54
|
+
label: initText('prompts.appClientEntryMode.modernOnlyLabel'),
|
|
55
|
+
hint: initText('prompts.appClientEntryMode.modernOnlyHint'),
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
value: 'modern-default',
|
|
59
|
+
label: initText('prompts.appClientEntryMode.modernDefaultLabel'),
|
|
60
|
+
hint: initText('prompts.appClientEntryMode.modernDefaultHint'),
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
value: 'legacy-default',
|
|
64
|
+
label: initText('prompts.appClientEntryMode.legacyDefaultLabel'),
|
|
65
|
+
hint: initText('prompts.appClientEntryMode.legacyDefaultHint'),
|
|
66
|
+
},
|
|
67
|
+
];
|
|
50
68
|
function withExtraHidden(def, extraHidden) {
|
|
51
69
|
if (def.type === 'run') {
|
|
52
70
|
return def;
|
|
@@ -106,6 +124,11 @@ function resolveInitDownloadVersion(results) {
|
|
|
106
124
|
}
|
|
107
125
|
return preset;
|
|
108
126
|
}
|
|
127
|
+
function resolveInitAppClientEntryMode(results, explicitValue) {
|
|
128
|
+
return (normalizePublicAppClientEntryMode(explicitValue) ??
|
|
129
|
+
normalizePublicAppClientEntryMode(results.appClientEntryMode) ??
|
|
130
|
+
defaultAppClientEntryModeForDownloadVersion(resolveInitDownloadVersion(results)));
|
|
131
|
+
}
|
|
109
132
|
function initVersionPromptValue(version) {
|
|
110
133
|
return version === 'latest' || version === 'beta' || version === 'alpha' ? version : 'other';
|
|
111
134
|
}
|
|
@@ -366,6 +389,15 @@ Prompt modes:
|
|
|
366
389
|
source: installLikeOnly(Download.prompts.source),
|
|
367
390
|
version: installLikeOnly(Download.prompts.version),
|
|
368
391
|
otherVersion: installLikeOnly(Download.prompts.otherVersion),
|
|
392
|
+
appClientEntryMode: installLikeOnly({
|
|
393
|
+
type: 'select',
|
|
394
|
+
message: initText('prompts.appClientEntryMode.message'),
|
|
395
|
+
options: [...PUBLIC_APP_CLIENT_ENTRY_MODE_OPTIONS],
|
|
396
|
+
variant: 'radio',
|
|
397
|
+
hidden: (values) => resolveInitDownloadVersion(values) === 'latest',
|
|
398
|
+
initialValue: (values) => defaultAppClientEntryModeForDownloadVersion(values.version),
|
|
399
|
+
required: true,
|
|
400
|
+
}),
|
|
369
401
|
dockerRegistry: installLikeOnly(Download.prompts.dockerRegistry),
|
|
370
402
|
dockerPlatform: installLikeOnly(Download.prompts.dockerPlatform),
|
|
371
403
|
dockerSave: installLikeDownloadExecutionOnly(Download.prompts.dockerSave),
|
|
@@ -490,6 +522,10 @@ Prompt modes:
|
|
|
490
522
|
description: 'Skip installing NocoBase AI coding skills during init',
|
|
491
523
|
default: false,
|
|
492
524
|
}),
|
|
525
|
+
'app-client-entry-mode': Flags.string({
|
|
526
|
+
description: 'UI entry mode for this app env: modern-only, modern-default, or legacy-default',
|
|
527
|
+
options: [...PUBLIC_APP_CLIENT_ENTRY_MODES],
|
|
528
|
+
}),
|
|
493
529
|
'ui-host': Flags.string({
|
|
494
530
|
description: 'Browser-accessible host for the --ui setup page URL (default: 127.0.0.1)',
|
|
495
531
|
}),
|
|
@@ -778,6 +814,7 @@ Prompt modes:
|
|
|
778
814
|
source: c.source,
|
|
779
815
|
version: c.version,
|
|
780
816
|
otherVersion: c.otherVersion,
|
|
817
|
+
appClientEntryMode: c.appClientEntryMode,
|
|
781
818
|
dockerRegistry: c.dockerRegistry,
|
|
782
819
|
dockerPlatform: c.dockerPlatform,
|
|
783
820
|
dockerSave: c.dockerSave,
|
|
@@ -890,6 +927,9 @@ Prompt modes:
|
|
|
890
927
|
if (flags['app-public-path'] !== undefined && String(flags['app-public-path']).trim() !== '') {
|
|
891
928
|
preset.appPublicPath = String(flags['app-public-path']).trim();
|
|
892
929
|
}
|
|
930
|
+
if (flags['app-client-entry-mode'] !== undefined && String(flags['app-client-entry-mode']).trim() !== '') {
|
|
931
|
+
preset.appClientEntryMode = String(flags['app-client-entry-mode']).trim();
|
|
932
|
+
}
|
|
893
933
|
if (flags['root-username'] !== undefined) {
|
|
894
934
|
preset.rootUsername = String(flags['root-username'] ?? '').trim();
|
|
895
935
|
}
|
|
@@ -1027,6 +1067,7 @@ Prompt modes:
|
|
|
1027
1067
|
const existingEnv = await getEnv(envName, { scope: resolveDefaultConfigScope() });
|
|
1028
1068
|
const appPort = String(results.appPort ?? '').trim();
|
|
1029
1069
|
const appPublicPath = String(results.appPublicPath ?? '').trim();
|
|
1070
|
+
const appClientEntryMode = resolveInitAppClientEntryMode(results, flags['app-client-entry-mode']);
|
|
1030
1071
|
const source = String(results.source ?? '').trim();
|
|
1031
1072
|
const version = resolveInitDownloadVersion(results);
|
|
1032
1073
|
const dockerRegistry = String(results.dockerRegistry ?? '').trim();
|
|
@@ -1100,6 +1141,7 @@ Prompt modes:
|
|
|
1100
1141
|
...(storagePath && !areConfiguredPathsEquivalent(storagePath, derivedStoragePath) ? { storagePath } : {}),
|
|
1101
1142
|
...(appPort ? { appPort } : {}),
|
|
1102
1143
|
...(appPublicPath ? { appPublicPath } : {}),
|
|
1144
|
+
...(appClientEntryMode ? { appClientEntryMode } : {}),
|
|
1103
1145
|
...(appKey ? { appKey } : {}),
|
|
1104
1146
|
...(timeZone ? { timezone: timeZone } : {}),
|
|
1105
1147
|
...(!skipDownload && results.devDependencies !== undefined
|
|
@@ -1228,6 +1270,13 @@ Prompt modes:
|
|
|
1228
1270
|
if (appPublicPath) {
|
|
1229
1271
|
argv.push('--app-public-path', appPublicPath);
|
|
1230
1272
|
}
|
|
1273
|
+
const appClientEntryMode = normalizePublicAppClientEntryMode(flags['app-client-entry-mode']) ||
|
|
1274
|
+
(results.setupMode === 'install-new' && results.hasNocobase === undefined
|
|
1275
|
+
? resolveInitAppClientEntryMode(results)
|
|
1276
|
+
: undefined);
|
|
1277
|
+
if (appClientEntryMode) {
|
|
1278
|
+
argv.push('--app-client-entry-mode', appClientEntryMode);
|
|
1279
|
+
}
|
|
1231
1280
|
if (flags.force) {
|
|
1232
1281
|
argv.push('--force');
|
|
1233
1282
|
}
|
package/dist/commands/install.js
CHANGED
|
@@ -25,6 +25,7 @@ import { commandOutput, commandSucceeds, ensureDockerDaemonRunning, run, runNoco
|
|
|
25
25
|
import { printInfo, printStage, printVerbose, printWarning, setVerboseMode } from '../lib/ui.js';
|
|
26
26
|
import { omitKeys, upperFirst } from "../lib/object-utils.js";
|
|
27
27
|
import { clearEnvRootSetup, getEnv, setCurrentEnv, upsertEnv } from '../lib/auth-store.js';
|
|
28
|
+
import { defaultAppClientEntryModeForDownloadVersion, normalizePublicAppClientEntryMode, PUBLIC_APP_CLIENT_ENTRY_MODES, } from '../lib/app-client-entry-mode.js';
|
|
28
29
|
import { buildStoredEnvConfig } from '../lib/env-config.js';
|
|
29
30
|
import { resolveDockerEnvFileArg } from "../lib/docker-env-file.js";
|
|
30
31
|
import { startDockerLogFollower } from '../lib/docker-log-stream.js';
|
|
@@ -54,10 +55,7 @@ const DEFAULT_INSTALL_ROOT_EMAIL = 'admin@nocobase.com';
|
|
|
54
55
|
const DEFAULT_INSTALL_ROOT_PASSWORD = 'admin123';
|
|
55
56
|
const DEFAULT_INSTALL_ROOT_NICKNAME = 'Super Admin';
|
|
56
57
|
const DEFAULT_INSTALL_API_HOST = '127.0.0.1';
|
|
57
|
-
const DEFAULT_INSTALL_PORTAL_TYPE = 'ai';
|
|
58
|
-
const DEFAULT_INSTALL_PORTAL_NAME = 'main';
|
|
59
58
|
const DEFAULT_INSTALL_PORTAL_TEMPLATE = '@nocobase/portal-template-default';
|
|
60
|
-
const INSTALL_PORTAL_TYPES = ['no-code', 'ai'];
|
|
61
59
|
function toOptionalPromptString(value) {
|
|
62
60
|
const text = String(value ?? '').trim();
|
|
63
61
|
return text || undefined;
|
|
@@ -185,9 +183,6 @@ function defaultBuiltinDbImageForDialect(value, options) {
|
|
|
185
183
|
function defaultDbDatabaseForDialect(value) {
|
|
186
184
|
return String(value ?? '').trim() === 'kingbase' ? 'kingbase' : DEFAULT_INSTALL_DB_DATABASE;
|
|
187
185
|
}
|
|
188
|
-
function isAiMode(values) {
|
|
189
|
-
return String(values.portalType ?? DEFAULT_INSTALL_PORTAL_TYPE).trim() === 'ai';
|
|
190
|
-
}
|
|
191
186
|
function supportsDbSchemaPrompt(value) {
|
|
192
187
|
const dialect = String(value ?? '').trim();
|
|
193
188
|
return dialect === 'postgres' || dialect === 'kingbase';
|
|
@@ -412,15 +407,12 @@ export default class Install extends Command {
|
|
|
412
407
|
'app-public-path': Flags.string({
|
|
413
408
|
description: 'Public path for the local app, for example / or /console/',
|
|
414
409
|
}),
|
|
415
|
-
'
|
|
416
|
-
description: '
|
|
417
|
-
options: [...
|
|
418
|
-
}),
|
|
419
|
-
'portal-name': Flags.string({
|
|
420
|
-
description: 'Initial portal name',
|
|
410
|
+
'app-client-entry-mode': Flags.string({
|
|
411
|
+
description: 'UI entry mode for this app env: modern-only, modern-default, or legacy-default',
|
|
412
|
+
options: [...PUBLIC_APP_CLIENT_ENTRY_MODES],
|
|
421
413
|
}),
|
|
422
414
|
'portal-template': Flags.string({
|
|
423
|
-
description: '
|
|
415
|
+
description: 'Template npm package or local path for the default AI Portal "main"',
|
|
424
416
|
}),
|
|
425
417
|
'root-username': Flags.string({
|
|
426
418
|
description: 'Initial admin username for the installed app',
|
|
@@ -531,39 +523,12 @@ export default class Install extends Command {
|
|
|
531
523
|
yesInitialValue: '/',
|
|
532
524
|
validate: validateAppPublicPath,
|
|
533
525
|
},
|
|
534
|
-
portalType: {
|
|
535
|
-
type: 'select',
|
|
536
|
-
message: installText('prompts.portalType.message'),
|
|
537
|
-
options: [
|
|
538
|
-
{
|
|
539
|
-
value: 'no-code',
|
|
540
|
-
label: installText('prompts.portalType.noCodeLabel'),
|
|
541
|
-
hint: installText('prompts.portalType.noCodeHint'),
|
|
542
|
-
},
|
|
543
|
-
{
|
|
544
|
-
value: 'ai',
|
|
545
|
-
label: installText('prompts.portalType.aiLabel'),
|
|
546
|
-
hint: installText('prompts.portalType.aiHint'),
|
|
547
|
-
},
|
|
548
|
-
],
|
|
549
|
-
initialValue: DEFAULT_INSTALL_PORTAL_TYPE,
|
|
550
|
-
yesInitialValue: DEFAULT_INSTALL_PORTAL_TYPE,
|
|
551
|
-
required: true,
|
|
552
|
-
},
|
|
553
|
-
portalName: {
|
|
554
|
-
type: 'text',
|
|
555
|
-
message: installText('prompts.portalName.message'),
|
|
556
|
-
placeholder: DEFAULT_INSTALL_PORTAL_NAME,
|
|
557
|
-
initialValue: DEFAULT_INSTALL_PORTAL_NAME,
|
|
558
|
-
yesInitialValue: DEFAULT_INSTALL_PORTAL_NAME,
|
|
559
|
-
required: true,
|
|
560
|
-
},
|
|
561
526
|
portalTemplate: {
|
|
562
527
|
type: 'text',
|
|
563
528
|
message: installText('prompts.portalTemplate.message'),
|
|
564
529
|
placeholder: DEFAULT_INSTALL_PORTAL_TEMPLATE,
|
|
530
|
+
initialValue: DEFAULT_INSTALL_PORTAL_TEMPLATE,
|
|
565
531
|
yesInitialValue: DEFAULT_INSTALL_PORTAL_TEMPLATE,
|
|
566
|
-
hidden: (values) => !isAiMode(values),
|
|
567
532
|
required: true,
|
|
568
533
|
},
|
|
569
534
|
};
|
|
@@ -825,16 +790,10 @@ export default class Install extends Command {
|
|
|
825
790
|
preset.appPublicPath = v;
|
|
826
791
|
}
|
|
827
792
|
}
|
|
828
|
-
if (flags['
|
|
829
|
-
const v =
|
|
830
|
-
if (v) {
|
|
831
|
-
preset.portalType = v;
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
if (flags['portal-name'] !== undefined) {
|
|
835
|
-
const v = String(flags['portal-name'] ?? '').trim();
|
|
793
|
+
if (flags['app-client-entry-mode'] !== undefined) {
|
|
794
|
+
const v = normalizePublicAppClientEntryMode(flags['app-client-entry-mode']);
|
|
836
795
|
if (v) {
|
|
837
|
-
preset.
|
|
796
|
+
preset.appClientEntryMode = v;
|
|
838
797
|
}
|
|
839
798
|
}
|
|
840
799
|
if (flags['portal-template'] !== undefined) {
|
|
@@ -934,8 +893,7 @@ export default class Install extends Command {
|
|
|
934
893
|
'appPort',
|
|
935
894
|
'storagePath',
|
|
936
895
|
'appPublicPath',
|
|
937
|
-
'
|
|
938
|
-
'portalName',
|
|
896
|
+
'appClientEntryMode',
|
|
939
897
|
'portalTemplate',
|
|
940
898
|
]);
|
|
941
899
|
}
|
|
@@ -1186,8 +1144,6 @@ export default class Install extends Command {
|
|
|
1186
1144
|
const rootPassword = Install.toOptionalPromptString(config.rootPassword);
|
|
1187
1145
|
const rootNickname = Install.toOptionalPromptString(config.rootNickname);
|
|
1188
1146
|
const lang = Install.toOptionalPromptString(config.lang);
|
|
1189
|
-
const portalType = Install.toOptionalPromptString(config.portalType);
|
|
1190
|
-
const portalName = Install.toOptionalPromptString(config.portalName);
|
|
1191
1147
|
const portalTemplate = Install.toOptionalPromptString(config.portalTemplate);
|
|
1192
1148
|
const auth = config.auth;
|
|
1193
1149
|
const savedAuthType = Install.toOptionalPromptString(config.authType) ?? Install.toOptionalPromptString(auth?.type);
|
|
@@ -1198,8 +1154,6 @@ export default class Install extends Command {
|
|
|
1198
1154
|
...(appPort ? { appPort } : {}),
|
|
1199
1155
|
...(storagePath ? { storagePath } : {}),
|
|
1200
1156
|
...(appPublicPath ? { appPublicPath } : {}),
|
|
1201
|
-
...(portalType ? { portalType } : {}),
|
|
1202
|
-
...(portalName ? { portalName } : {}),
|
|
1203
1157
|
...(portalTemplate ? { portalTemplate } : {}),
|
|
1204
1158
|
...(hookScript ? { hookScript } : {}),
|
|
1205
1159
|
};
|
|
@@ -1523,8 +1477,6 @@ export default class Install extends Command {
|
|
|
1523
1477
|
rootEmail: String(params.rootResults.rootEmail ?? ''),
|
|
1524
1478
|
rootPassword: String(params.rootResults.rootPassword ?? ''),
|
|
1525
1479
|
rootNickname: String(params.rootResults.rootNickname ?? ''),
|
|
1526
|
-
portalType: String(params.appResults.portalType ?? ''),
|
|
1527
|
-
portalName: String(params.appResults.portalName ?? ''),
|
|
1528
1480
|
portalTemplate: String(params.appResults.portalTemplate ?? ''),
|
|
1529
1481
|
}, options);
|
|
1530
1482
|
}
|
|
@@ -1874,6 +1826,7 @@ export default class Install extends Command {
|
|
|
1874
1826
|
const extractClientAssets = resolveExtractClientAssetsDefaultEnabled(process.env.NOCOBASE_EXTRACT_CLIENT_ASSETS);
|
|
1875
1827
|
const appKey = Install.resolveManagedAppKey(params.appResults.appKey);
|
|
1876
1828
|
const appPublicPath = Install.toOptionalPromptString(params.appResults.appPublicPath);
|
|
1829
|
+
const appClientEntryMode = Install.toOptionalPromptString(params.appResults.appClientEntryMode);
|
|
1877
1830
|
const timeZone = Install.resolveManagedTimeZone(params.appResults.timeZone);
|
|
1878
1831
|
const containerName = Install.buildDockerAppContainerName(params.envName, params.dockerContainerPrefix ?? params.workspaceName);
|
|
1879
1832
|
const configuredEnvFile = String(params.appResults.envFile ?? '').trim();
|
|
@@ -1901,6 +1854,7 @@ export default class Install extends Command {
|
|
|
1901
1854
|
}
|
|
1902
1855
|
args.push('-e', `APP_KEY=${appKey}`, '-e', `DB_DIALECT=${dbDialect}`, '-e', `DB_HOST=${dbHost}`, '-e', `DB_PORT=${dbPort}`, '-e', `DB_DATABASE=${dbDatabase}`, '-e', `DB_USER=${dbUser}`, '-e', `DB_PASSWORD=${dbPassword}`, '-e', `TZ=${timeZone}`, '-v', `${storagePath}:/app/nocobase/storage`);
|
|
1903
1856
|
pushOptionalEnvArg(args, 'APP_PUBLIC_PATH', appPublicPath);
|
|
1857
|
+
pushOptionalEnvArg(args, 'APP_CLIENT_ENTRY_MODE', appClientEntryMode);
|
|
1904
1858
|
pushOptionalEnvArg(args, 'DB_SCHEMA', dbSchema);
|
|
1905
1859
|
pushOptionalEnvArg(args, 'DB_TABLE_PREFIX', dbTablePrefix);
|
|
1906
1860
|
pushOptionalEnvArg(args, 'DB_UNDERSCORED', dbUnderscored);
|
|
@@ -2161,6 +2115,7 @@ export default class Install extends Command {
|
|
|
2161
2115
|
}),
|
|
2162
2116
|
};
|
|
2163
2117
|
setOptionalEnvVar(env, 'APP_PUBLIC_PATH', Install.toOptionalPromptString(params.appResults.appPublicPath));
|
|
2118
|
+
setOptionalEnvVar(env, 'APP_CLIENT_ENTRY_MODE', Install.toOptionalPromptString(params.appResults.appClientEntryMode));
|
|
2164
2119
|
setOptionalEnvVar(env, 'DB_SCHEMA', optionalEnvString(params.dbResults.dbSchema));
|
|
2165
2120
|
setOptionalEnvVar(env, 'DB_TABLE_PREFIX', optionalEnvString(params.dbResults.dbTablePrefix));
|
|
2166
2121
|
setOptionalEnvVar(env, 'DB_UNDERSCORED', optionalEnvBoolean(params.dbResults.dbUnderscored));
|
|
@@ -2402,8 +2357,7 @@ export default class Install extends Command {
|
|
|
2402
2357
|
const appRootPath = Install.toOptionalPromptString(params.appResults.appRootPath);
|
|
2403
2358
|
const storagePath = Install.toOptionalPromptString(params.appResults.storagePath);
|
|
2404
2359
|
const appPublicPath = Install.toOptionalPromptString(params.appResults.appPublicPath);
|
|
2405
|
-
const
|
|
2406
|
-
const portalName = Install.toOptionalPromptString(params.appResults.portalName);
|
|
2360
|
+
const appClientEntryMode = Install.toOptionalPromptString(params.appResults.appClientEntryMode);
|
|
2407
2361
|
const portalTemplate = Install.toOptionalPromptString(params.appResults.portalTemplate);
|
|
2408
2362
|
const derivedAppRootPath = appPath ? deriveConfiguredSourcePath(appPath) : undefined;
|
|
2409
2363
|
const derivedStoragePath = appPath ? deriveConfiguredStoragePath(appPath) : undefined;
|
|
@@ -2437,10 +2391,9 @@ export default class Install extends Command {
|
|
|
2437
2391
|
appPort,
|
|
2438
2392
|
...(storagePath && !areConfiguredPathsEquivalent(storagePath, derivedStoragePath) ? { storagePath } : {}),
|
|
2439
2393
|
...(appPublicPath ? { appPublicPath } : {}),
|
|
2394
|
+
...(appClientEntryMode ? { appClientEntryMode } : {}),
|
|
2440
2395
|
...(envFile ? { envFile } : {}),
|
|
2441
2396
|
lang: params.appResults.lang,
|
|
2442
|
-
portalType,
|
|
2443
|
-
portalName,
|
|
2444
2397
|
portalTemplate,
|
|
2445
2398
|
appKey: params.appResults.appKey,
|
|
2446
2399
|
timezone: params.appResults.timeZone,
|
|
@@ -2512,6 +2465,9 @@ export default class Install extends Command {
|
|
|
2512
2465
|
};
|
|
2513
2466
|
downloadOpts.yes = yes;
|
|
2514
2467
|
const downloadResults = await runPromptCatalog(Download.prompts, downloadOpts);
|
|
2468
|
+
appResults.appClientEntryMode =
|
|
2469
|
+
normalizePublicAppClientEntryMode(appResults.appClientEntryMode) ??
|
|
2470
|
+
defaultAppClientEntryModeForDownloadVersion(downloadResultsValue(downloadResults, 'version'));
|
|
2515
2471
|
if (parsed['skip-download']) {
|
|
2516
2472
|
delete downloadResults.outputDir;
|
|
2517
2473
|
delete downloadResults.replace;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
export const APP_CLIENT_ENTRY_MODES = [
|
|
10
|
+
'legacy-default',
|
|
11
|
+
'modern-default',
|
|
12
|
+
'modern-only',
|
|
13
|
+
'settings-default',
|
|
14
|
+
];
|
|
15
|
+
export const PUBLIC_APP_CLIENT_ENTRY_MODES = ['legacy-default', 'modern-default', 'modern-only'];
|
|
16
|
+
export function normalizeAppClientEntryMode(value) {
|
|
17
|
+
const text = String(value ?? '').trim();
|
|
18
|
+
return APP_CLIENT_ENTRY_MODES.includes(text) ? text : undefined;
|
|
19
|
+
}
|
|
20
|
+
export function normalizePublicAppClientEntryMode(value) {
|
|
21
|
+
const text = String(value ?? '').trim();
|
|
22
|
+
return PUBLIC_APP_CLIENT_ENTRY_MODES.includes(text)
|
|
23
|
+
? text
|
|
24
|
+
: undefined;
|
|
25
|
+
}
|
|
26
|
+
export function defaultAppClientEntryModeForDownloadVersion(version) {
|
|
27
|
+
return String(version ?? '').trim() === 'latest' ? 'legacy-default' : 'modern-only';
|
|
28
|
+
}
|
|
@@ -186,6 +186,7 @@ export async function buildSavedDockerRunArgs(runtime, options) {
|
|
|
186
186
|
const dbTablePrefix = trimValue(config.dbTablePrefix);
|
|
187
187
|
const dbUnderscored = typeof config.dbUnderscored === 'boolean' ? config.dbUnderscored : undefined;
|
|
188
188
|
const extractClientAssets = resolveDockerClientAssetsExtractEnabled(process.env.NOCOBASE_EXTRACT_CLIENT_ASSETS);
|
|
189
|
+
const appClientEntryMode = trimValue(config.appClientEntryMode);
|
|
189
190
|
const dockerRegistry = trimValue(config.dockerRegistry) || DEFAULT_DOCKER_REGISTRY;
|
|
190
191
|
const version = trimValue(config.downloadVersion) || DEFAULT_DOCKER_VERSION;
|
|
191
192
|
const imageRef = resolveDockerImageRef(dockerRegistry, version, {
|
|
@@ -245,6 +246,7 @@ export async function buildSavedDockerRunArgs(runtime, options) {
|
|
|
245
246
|
const lifecycleEnvVars = managedAppLifecycleEnvVars();
|
|
246
247
|
args.push('-e', `APP_ENV=${lifecycleEnvVars.APP_ENV}`, '-e', `NODE_ENV=${lifecycleEnvVars.NODE_ENV}`, '-e', `APP_KEY=${appKey}`, '-e', `DB_DIALECT=${dbDialect}`, '-e', `DB_HOST=${dbHost}`, '-e', `DB_PORT=${dbPort}`, '-e', `DB_DATABASE=${dbDatabase}`, '-e', `DB_USER=${dbUser}`, '-e', `DB_PASSWORD=${dbPassword}`, '-e', `TZ=${timeZone}`, '-v', `${storagePath}:${DOCKER_APP_STORAGE_DESTINATION}`);
|
|
247
248
|
pushOptionalEnvArg(args, 'APP_PUBLIC_PATH', appPublicPath ? resolveAppPublicPath(appPublicPath) : undefined);
|
|
249
|
+
pushOptionalEnvArg(args, 'APP_CLIENT_ENTRY_MODE', appClientEntryMode);
|
|
248
250
|
pushOptionalEnvArg(args, 'DB_SCHEMA', dbSchema || undefined);
|
|
249
251
|
pushOptionalEnvArg(args, 'DB_TABLE_PREFIX', dbTablePrefix || undefined);
|
|
250
252
|
pushOptionalEnvArg(args, 'DB_UNDERSCORED', dbUnderscored);
|
package/dist/lib/auth-store.js
CHANGED
|
@@ -335,6 +335,7 @@ export class Env {
|
|
|
335
335
|
put('APP_PORT', this.appPort);
|
|
336
336
|
put('APP_PUBLIC_PATH', this.config.appPublicPath ? resolveAppPublicPath(this.config.appPublicPath) : undefined);
|
|
337
337
|
put('CDN_BASE_URL', this.config.cdnBaseUrl);
|
|
338
|
+
put('APP_CLIENT_ENTRY_MODE', this.config.appClientEntryMode);
|
|
338
339
|
put('APP_KEY', this.config.appKey);
|
|
339
340
|
put('TZ', this.config.timezone);
|
|
340
341
|
put('DB_DIALECT', this.config.dbDialect);
|
package/dist/lib/env-auth.js
CHANGED
|
@@ -27,40 +27,6 @@ const DEFAULT_DEVICE_POLL_INTERVAL_SECONDS = 5;
|
|
|
27
27
|
function normalizeBaseUrl(baseUrl) {
|
|
28
28
|
return baseUrl.replace(/\/+$/, '');
|
|
29
29
|
}
|
|
30
|
-
function buildDeviceVerificationPathFromApiBaseUrl(apiBaseUrl) {
|
|
31
|
-
const url = new URL(apiBaseUrl);
|
|
32
|
-
const subappMatch = url.pathname.match(/^(.*)\/api\/__app\/([^/]+)\/?$/);
|
|
33
|
-
if (subappMatch) {
|
|
34
|
-
const publicPath = (subappMatch[1] || '').replace(/\/+$/, '');
|
|
35
|
-
return `${publicPath}/settings/apps/${subappMatch[2]}/idpOAuth/device`;
|
|
36
|
-
}
|
|
37
|
-
const appMatch = url.pathname.match(/^(.*)\/api\/?$/);
|
|
38
|
-
if (appMatch) {
|
|
39
|
-
const publicPath = (appMatch[1] || '').replace(/\/+$/, '');
|
|
40
|
-
return `${publicPath}/settings/idpOAuth/device`;
|
|
41
|
-
}
|
|
42
|
-
return undefined;
|
|
43
|
-
}
|
|
44
|
-
export function resolveDeviceVerificationUrlForApiBaseUrl(verificationUrl, apiBaseUrl) {
|
|
45
|
-
try {
|
|
46
|
-
const devicePath = buildDeviceVerificationPathFromApiBaseUrl(apiBaseUrl);
|
|
47
|
-
if (!devicePath) {
|
|
48
|
-
return verificationUrl;
|
|
49
|
-
}
|
|
50
|
-
const originalUrl = new URL(verificationUrl);
|
|
51
|
-
if (!originalUrl.pathname.endsWith('/idpOAuth/device')) {
|
|
52
|
-
return verificationUrl;
|
|
53
|
-
}
|
|
54
|
-
const publicUrl = new URL(apiBaseUrl);
|
|
55
|
-
publicUrl.pathname = devicePath;
|
|
56
|
-
publicUrl.search = originalUrl.search;
|
|
57
|
-
publicUrl.hash = originalUrl.hash;
|
|
58
|
-
return publicUrl.toString();
|
|
59
|
-
}
|
|
60
|
-
catch {
|
|
61
|
-
return verificationUrl;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
30
|
export function getOauthMetadataUrl(baseUrl) {
|
|
65
31
|
return `${normalizeBaseUrl(baseUrl)}/.well-known/oauth-authorization-server`;
|
|
66
32
|
}
|
|
@@ -1051,7 +1017,7 @@ async function authenticateEnvWithOauthDevice(options) {
|
|
|
1051
1017
|
baseUrl: options.baseUrl,
|
|
1052
1018
|
});
|
|
1053
1019
|
stopTask();
|
|
1054
|
-
const verificationUrl =
|
|
1020
|
+
const verificationUrl = deviceAuthorization.verification_uri_complete || deviceAuthorization.verification_uri;
|
|
1055
1021
|
const browser = await browserOpener(verificationUrl);
|
|
1056
1022
|
cleanupBrowserOpenTarget = browser.cleanup;
|
|
1057
1023
|
if (!browser.opened) {
|
|
@@ -19,6 +19,7 @@ export const ENV_STRING_CONFIG_FLAG_MAP = {
|
|
|
19
19
|
'app-public-path': 'appPublicPath',
|
|
20
20
|
'cdn-base-url': 'cdnBaseUrl',
|
|
21
21
|
'env-file': 'envFile',
|
|
22
|
+
'app-client-entry-mode': 'appClientEntryMode',
|
|
22
23
|
'app-port': 'appPort',
|
|
23
24
|
'app-key': 'appKey',
|
|
24
25
|
timezone: 'timezone',
|
package/dist/lib/env-config.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
|
+
import { normalizeAppClientEntryMode } from './app-client-entry-mode.js';
|
|
9
10
|
import { normalizeEnvProxyConfig } from './env-proxy-config.js';
|
|
10
11
|
import { resolveAppPublicPath } from './app-public-path.js';
|
|
11
12
|
import { normalizeEnvPortalsConfig } from './env-portal-config.js';
|
|
@@ -37,8 +38,6 @@ const STRING_ENV_CONFIG_KEYS = [
|
|
|
37
38
|
'dbSchema',
|
|
38
39
|
'dbTablePrefix',
|
|
39
40
|
'lang',
|
|
40
|
-
'portalType',
|
|
41
|
-
'portalName',
|
|
42
41
|
'portalTemplate',
|
|
43
42
|
'rootUsername',
|
|
44
43
|
'rootEmail',
|
|
@@ -87,6 +86,10 @@ export function buildStoredEnvConfig(input) {
|
|
|
87
86
|
envConfig[key] = key === 'appPublicPath' ? resolveAppPublicPath(value) : value;
|
|
88
87
|
}
|
|
89
88
|
}
|
|
89
|
+
const appClientEntryMode = normalizeAppClientEntryMode(input.appClientEntryMode);
|
|
90
|
+
if (appClientEntryMode) {
|
|
91
|
+
envConfig.appClientEntryMode = appClientEntryMode;
|
|
92
|
+
}
|
|
90
93
|
const setupState = resolveSetupState(input.setupState);
|
|
91
94
|
if (setupState) {
|
|
92
95
|
envConfig.setupState = setupState;
|
package/dist/lib/env-proxy.js
CHANGED
|
@@ -22,7 +22,7 @@ const DEFAULT_PLUGIN_STATICS_PATH = '/static/plugins/';
|
|
|
22
22
|
const DEFAULT_MODERN_CLIENT_PREFIX = 'v';
|
|
23
23
|
const SETTINGS_CLIENT_PREFIX = 'settings';
|
|
24
24
|
const DEFAULT_APP_CLIENT_ENTRY_MODE = 'legacy-default';
|
|
25
|
-
const APP_CLIENT_ENTRY_MODES = new Set(['legacy-default', 'modern-default', 'modern-only']);
|
|
25
|
+
const APP_CLIENT_ENTRY_MODES = new Set(['legacy-default', 'modern-default', 'modern-only', 'settings-default']);
|
|
26
26
|
const DEFAULT_API_CLIENT_STORAGE_PREFIX = 'NOCOBASE_';
|
|
27
27
|
const DEFAULT_API_CLIENT_STORAGE_TYPE = 'localStorage';
|
|
28
28
|
const DEFAULT_ESM_CDN_BASE_URL = 'https://esm.sh';
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
10
10
|
import path from 'node:path';
|
|
11
|
+
import { normalizeAppClientEntryMode } from './app-client-entry-mode.js';
|
|
11
12
|
import { resolveEnvKind } from './auth-store.js';
|
|
12
13
|
import { resolveConfiguredEnvPath } from './cli-home.js';
|
|
13
14
|
import { resolveDockerEnvFileArg, resolveDockerEnvFilePath } from "./docker-env-file.js";
|
|
@@ -17,6 +18,14 @@ export const DEFAULT_MANAGED_ENV_FILE_VALUES = {
|
|
|
17
18
|
APP_PROCESS_ADAPTER: 'local',
|
|
18
19
|
APP_CLIENT_ENTRY_MODE: 'modern-only',
|
|
19
20
|
};
|
|
21
|
+
function buildManagedEnvFileDefaults(config, defaults = DEFAULT_MANAGED_ENV_FILE_VALUES) {
|
|
22
|
+
return {
|
|
23
|
+
...defaults,
|
|
24
|
+
APP_CLIENT_ENTRY_MODE: normalizeAppClientEntryMode(config?.appClientEntryMode) ??
|
|
25
|
+
trimValue(defaults.APP_CLIENT_ENTRY_MODE) ??
|
|
26
|
+
DEFAULT_MANAGED_ENV_FILE_VALUES.APP_CLIENT_ENTRY_MODE,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
20
29
|
function trimValue(value) {
|
|
21
30
|
const text = String(value ?? '').trim();
|
|
22
31
|
return text || undefined;
|
|
@@ -36,6 +45,29 @@ function stripWrappingQuotes(value) {
|
|
|
36
45
|
}
|
|
37
46
|
return value;
|
|
38
47
|
}
|
|
48
|
+
function escapeRegExp(value) {
|
|
49
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
50
|
+
}
|
|
51
|
+
function upsertSimpleEnvContent(content, values) {
|
|
52
|
+
let nextContent = content;
|
|
53
|
+
const missingEntries = new Map(Object.entries(values).filter(([, value]) => trimValue(value)));
|
|
54
|
+
for (const key of Array.from(missingEntries.keys())) {
|
|
55
|
+
const pattern = new RegExp(`^\\s*(?:export\\s+)?${escapeRegExp(key)}\\s*=.*$`, 'gm');
|
|
56
|
+
if (!pattern.test(nextContent)) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
nextContent = nextContent.replace(pattern, `${key}=${values[key]}`);
|
|
60
|
+
missingEntries.delete(key);
|
|
61
|
+
}
|
|
62
|
+
if (missingEntries.size === 0) {
|
|
63
|
+
return nextContent;
|
|
64
|
+
}
|
|
65
|
+
const separator = nextContent && !nextContent.endsWith('\n') ? '\n' : '';
|
|
66
|
+
const appended = Array.from(missingEntries.entries())
|
|
67
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
68
|
+
.join('\n');
|
|
69
|
+
return `${nextContent}${separator}${appended}\n`;
|
|
70
|
+
}
|
|
39
71
|
export function parseSimpleEnvFile(content) {
|
|
40
72
|
const values = {};
|
|
41
73
|
for (const rawLine of content.split(/\r?\n/)) {
|
|
@@ -112,7 +144,8 @@ export async function ensureManagedEnvFileDefaults(envName, config, defaults = D
|
|
|
112
144
|
}
|
|
113
145
|
}
|
|
114
146
|
const existing = parseSimpleEnvFile(content);
|
|
115
|
-
const
|
|
147
|
+
const resolvedDefaults = buildManagedEnvFileDefaults(config, defaults);
|
|
148
|
+
const missingEntries = Object.entries(resolvedDefaults).filter(([key, value]) => trimValue(value) && !existing[key]);
|
|
116
149
|
if (missingEntries.length === 0) {
|
|
117
150
|
return envFilePath;
|
|
118
151
|
}
|
|
@@ -122,6 +155,29 @@ export async function ensureManagedEnvFileDefaults(envName, config, defaults = D
|
|
|
122
155
|
await writeFile(envFilePath, nextContent, 'utf8');
|
|
123
156
|
return envFilePath;
|
|
124
157
|
}
|
|
158
|
+
export async function upsertManagedEnvFileValues(envName, config, values) {
|
|
159
|
+
const envFilePath = resolveManagedEnvFilePathFromConfig(envName, config);
|
|
160
|
+
if (!envFilePath) {
|
|
161
|
+
return undefined;
|
|
162
|
+
}
|
|
163
|
+
let content = '';
|
|
164
|
+
try {
|
|
165
|
+
content = await readFile(envFilePath, 'utf8');
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
const code = error && typeof error === 'object' && 'code' in error ? String(error.code) : '';
|
|
169
|
+
if (code !== 'ENOENT') {
|
|
170
|
+
throw error;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
const nextContent = upsertSimpleEnvContent(content, values);
|
|
174
|
+
if (nextContent === content) {
|
|
175
|
+
return envFilePath;
|
|
176
|
+
}
|
|
177
|
+
await mkdir(path.dirname(envFilePath), { recursive: true });
|
|
178
|
+
await writeFile(envFilePath, nextContent, 'utf8');
|
|
179
|
+
return envFilePath;
|
|
180
|
+
}
|
|
125
181
|
export async function resolveManagedRuntimeEnvFilePath(runtime) {
|
|
126
182
|
if (runtime.kind === 'local') {
|
|
127
183
|
return resolveManagedLocalEnvFilePath(runtime);
|
|
@@ -29,8 +29,6 @@ export function buildInitAppEnvVarsFromConfig(config, options = {}) {
|
|
|
29
29
|
put('INIT_ROOT_PASSWORD', config?.rootPassword);
|
|
30
30
|
put('INIT_ROOT_NICKNAME', config?.rootNickname);
|
|
31
31
|
if (options.includePortal !== false) {
|
|
32
|
-
put('INIT_PORTAL_TYPE', config?.portalType);
|
|
33
|
-
put('INIT_PORTAL_NAME', config?.portalName);
|
|
34
32
|
put('INIT_PORTAL_TEMPLATE', config?.portalTemplate);
|
|
35
33
|
}
|
|
36
34
|
return out;
|
|
@@ -60,7 +60,7 @@ export function mergedBoolean(key, def, iv, useYesInitial) {
|
|
|
60
60
|
}
|
|
61
61
|
return def.initialValue ?? true;
|
|
62
62
|
}
|
|
63
|
-
export function mergedSelect(key, def, iv, useYesInitial) {
|
|
63
|
+
export function mergedSelect(key, def, iv, useYesInitial, valuesSoFar = {}) {
|
|
64
64
|
const enabledValueList = enabledSelectOptionValues(def.options);
|
|
65
65
|
if (hasIvKey(iv, key)) {
|
|
66
66
|
const s = String(iv[key]);
|
|
@@ -72,7 +72,7 @@ export function mergedSelect(key, def, iv, useYesInitial) {
|
|
|
72
72
|
if (useYesInitial && def.yesInitialValue !== undefined && enabledValueList.includes(def.yesInitialValue)) {
|
|
73
73
|
return def.yesInitialValue;
|
|
74
74
|
}
|
|
75
|
-
const d = def.initialValue;
|
|
75
|
+
const d = typeof def.initialValue === 'function' ? def.initialValue(valuesSoFar) : def.initialValue;
|
|
76
76
|
if (d !== undefined && enabledValueList.includes(d)) {
|
|
77
77
|
return d;
|
|
78
78
|
}
|
|
@@ -221,11 +221,12 @@ export async function runPromptCatalog(catalog, options = {}) {
|
|
|
221
221
|
if (def.type === 'select') {
|
|
222
222
|
const message = resolvePromptText(def.message, locale, key);
|
|
223
223
|
const valueList = selectOptionValues(def.options);
|
|
224
|
+
const valuesSoFar = { ...computationSeed, ...out };
|
|
224
225
|
if (def.required && def.options.length === 0) {
|
|
225
226
|
hooks.onMissingNonInteractive(t('promptCatalog.nonInteractive.selectRequiredNoOptions', { key }));
|
|
226
227
|
}
|
|
227
228
|
if (!interactive) {
|
|
228
|
-
const merged = mergedSelect(key, def, resolveIv, useYesInitial);
|
|
229
|
+
const merged = mergedSelect(key, def, resolveIv, useYesInitial, valuesSoFar);
|
|
229
230
|
if (merged === undefined || !valueList.includes(merged)) {
|
|
230
231
|
const bad = hasIvKey(resolveIv, key) && !valueList.includes(String(resolveIv[key]))
|
|
231
232
|
? String(resolveIv[key])
|
|
@@ -243,10 +244,8 @@ export async function runPromptCatalog(catalog, options = {}) {
|
|
|
243
244
|
}
|
|
244
245
|
continue;
|
|
245
246
|
}
|
|
246
|
-
const merged = mergedSelect(key, def, promptIv, false);
|
|
247
|
-
const uiInitial = merged ??
|
|
248
|
-
(def.initialValue && valueList.includes(def.initialValue) ? def.initialValue : undefined) ??
|
|
249
|
-
valueList[0];
|
|
247
|
+
const merged = mergedSelect(key, def, promptIv, false, valuesSoFar);
|
|
248
|
+
const uiInitial = merged ?? valueList[0];
|
|
250
249
|
if (uiInitial === undefined || !valueList.includes(uiInitial)) {
|
|
251
250
|
const hint = def.required
|
|
252
251
|
? t('promptCatalog.nonInteractive.selectRequiredInteractive', { key })
|
|
@@ -34,6 +34,13 @@ function resolveTextDefault(def, out) {
|
|
|
34
34
|
}
|
|
35
35
|
return String(iv ?? '');
|
|
36
36
|
}
|
|
37
|
+
function resolveSelectDefault(def, out) {
|
|
38
|
+
const iv = def.initialValue;
|
|
39
|
+
if (typeof iv === 'function') {
|
|
40
|
+
return iv(out);
|
|
41
|
+
}
|
|
42
|
+
return iv;
|
|
43
|
+
}
|
|
37
44
|
function resolvePasswordDefault(def, out) {
|
|
38
45
|
const iv = def.initialValue;
|
|
39
46
|
if (typeof iv === 'function') {
|
|
@@ -98,7 +105,7 @@ function defaultValueForInput(key, def, out) {
|
|
|
98
105
|
const first = def.options
|
|
99
106
|
.find((o) => typeof o === 'string' || o.disabled !== true);
|
|
100
107
|
const firstValue = typeof first === 'string' ? first : first?.value;
|
|
101
|
-
const i = def
|
|
108
|
+
const i = resolveSelectDefault(def, out);
|
|
102
109
|
const enabledValues = def.options
|
|
103
110
|
.filter((o) => typeof o === 'string' || o.disabled !== true)
|
|
104
111
|
.map((o) => (typeof o === 'string' ? o : o.value));
|
package/dist/locale/en-US.json
CHANGED
|
@@ -468,7 +468,7 @@
|
|
|
468
468
|
"betaLabel": "beta",
|
|
469
469
|
"betaHint": "Preview release. Good for trying upcoming features before general release.",
|
|
470
470
|
"alphaLabel": "alpha",
|
|
471
|
-
"alphaHint": "
|
|
471
|
+
"alphaHint": "Choose this version to try the new features in 3.0.",
|
|
472
472
|
"otherLabel": "Other",
|
|
473
473
|
"otherHint": "Enter another package version, Docker tag, or Git ref manually, such as a branch name."
|
|
474
474
|
},
|
|
@@ -657,6 +657,15 @@
|
|
|
657
657
|
"skipDownload": {
|
|
658
658
|
"message": "Skip downloading NocoBase and reuse existing local app files or Docker images"
|
|
659
659
|
},
|
|
660
|
+
"appClientEntryMode": {
|
|
661
|
+
"message": "App client entry mode",
|
|
662
|
+
"modernOnlyLabel": "Modern UI only",
|
|
663
|
+
"modernOnlyHint": "Only the modern UI is available; the legacy UI cannot be accessed.",
|
|
664
|
+
"modernDefaultLabel": "Modern UI by default",
|
|
665
|
+
"modernDefaultHint": "Open the modern UI by default while keeping the legacy UI available.",
|
|
666
|
+
"legacyDefaultLabel": "Legacy UI by default",
|
|
667
|
+
"legacyDefaultHint": "Open the legacy UI by default while keeping the modern UI available."
|
|
668
|
+
},
|
|
660
669
|
"portalType": {
|
|
661
670
|
"message": "Portal type",
|
|
662
671
|
"noCodeLabel": "No-code portal",
|
package/dist/locale/zh-CN.json
CHANGED
|
@@ -468,7 +468,7 @@
|
|
|
468
468
|
"betaLabel": "beta",
|
|
469
469
|
"betaHint": "测试版。包含即将发布的新功能,适合提前体验和反馈。",
|
|
470
470
|
"alphaLabel": "alpha",
|
|
471
|
-
"alphaHint": "
|
|
471
|
+
"alphaHint": "如果要体验 3.0 新功能,选择这个版本。",
|
|
472
472
|
"otherLabel": "其他",
|
|
473
473
|
"otherHint": "手动填写其他版本号、Docker tag 或 Git ref,例如分支名。"
|
|
474
474
|
},
|
|
@@ -657,6 +657,15 @@
|
|
|
657
657
|
"skipDownload": {
|
|
658
658
|
"message": "跳过下载 NocoBase,直接复用已有的本地应用文件或 Docker 镜像"
|
|
659
659
|
},
|
|
660
|
+
"appClientEntryMode": {
|
|
661
|
+
"message": "应用界面入口",
|
|
662
|
+
"modernOnlyLabel": "仅使用新版界面",
|
|
663
|
+
"modernOnlyHint": "只能进入新版界面,不可进入旧版界面。",
|
|
664
|
+
"modernDefaultLabel": "默认进入新版界面",
|
|
665
|
+
"modernDefaultHint": "默认进入新版界面,同时保留旧版界面入口。",
|
|
666
|
+
"legacyDefaultLabel": "默认进入旧版界面",
|
|
667
|
+
"legacyDefaultHint": "默认进入旧版界面,也可以进入新版界面。"
|
|
668
|
+
},
|
|
660
669
|
"portalType": {
|
|
661
670
|
"message": "Portal 类型",
|
|
662
671
|
"noCodeLabel": "无代码 Portal",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/cli",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.7",
|
|
4
4
|
"description": "NocoBase Command Line Tool",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/generated/command-registry.js",
|
|
@@ -147,5 +147,5 @@
|
|
|
147
147
|
"type": "git",
|
|
148
148
|
"url": "git+https://github.com/nocobase/nocobase.git"
|
|
149
149
|
},
|
|
150
|
-
"gitHead": "
|
|
150
|
+
"gitHead": "19cd28c710f3b3c614ebe2fd7d5a415d527ee559"
|
|
151
151
|
}
|