@nocobase/cli 2.2.0-test.16 → 2.2.1

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.
Files changed (44) hide show
  1. package/dist/commands/api/resource/create.js +11 -2
  2. package/dist/commands/app/start.js +1 -21
  3. package/dist/commands/config/set.js +0 -1
  4. package/dist/commands/init.js +3 -120
  5. package/dist/commands/install.js +4 -121
  6. package/dist/commands/source/dev.js +1 -1
  7. package/dist/lib/api-client.js +7 -0
  8. package/dist/lib/auth-store.js +1 -3
  9. package/dist/lib/browser.js +29 -0
  10. package/dist/lib/cli-config.js +1 -20
  11. package/dist/lib/env-config.js +0 -3
  12. package/dist/lib/env-proxy.js +1 -65
  13. package/dist/lib/generated-command.js +81 -0
  14. package/dist/lib/managed-init-env.js +1 -6
  15. package/dist/lib/naming.js +9 -0
  16. package/dist/lib/plugin-import.js +30 -8
  17. package/dist/lib/resource-command.js +18 -2
  18. package/dist/lib/resource-request.js +8 -0
  19. package/dist/lib/run-npm.js +16 -17
  20. package/dist/lib/runtime-generator.js +28 -1
  21. package/dist/lib/ui.js +1 -28
  22. package/dist/locale/en-US.json +0 -154
  23. package/dist/locale/zh-CN.json +0 -154
  24. package/nocobase-ctl.config.json +111 -0
  25. package/package.json +3 -5
  26. package/dist/commands/portal/create.js +0 -104
  27. package/dist/commands/portal/deploy.js +0 -81
  28. package/dist/commands/portal/destroy.js +0 -104
  29. package/dist/commands/portal/dev.js +0 -71
  30. package/dist/commands/portal/index.js +0 -20
  31. package/dist/commands/portal/info.js +0 -82
  32. package/dist/commands/portal/list.js +0 -98
  33. package/dist/commands/portal/pull.js +0 -77
  34. package/dist/commands/portal/push.js +0 -79
  35. package/dist/lib/portal-command-env.js +0 -31
  36. package/dist/lib/portal-create.js +0 -488
  37. package/dist/lib/portal-deploy.js +0 -275
  38. package/dist/lib/portal-destroy.js +0 -100
  39. package/dist/lib/portal-dev.js +0 -79
  40. package/dist/lib/portal-env-files.js +0 -53
  41. package/dist/lib/portal-info.js +0 -31
  42. package/dist/lib/portal-list.js +0 -197
  43. package/dist/lib/portal-source.js +0 -416
  44. package/dist/lib/portal-template.js +0 -190
@@ -1,10 +1,19 @@
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
+ */
1
9
  import { Command } from '@oclif/core';
2
10
  import { buildCreateArgs, createFlags, runResourceCommand } from '../../../lib/resource-command.js';
3
11
  export default class ResourceCreate extends Command {
4
- static summary = 'Create a record in a resource';
5
- static description = 'Create a record in a generic resource. Pass record content through --values as a JSON object.';
12
+ static summary = 'Create one or more records in a resource';
13
+ static description = 'Create records in a generic resource. Pass record content through --values as a JSON object, or as a JSON array of objects to create multiple records in a single request.';
6
14
  static examples = [
7
15
  `<%= config.bin %> <%= command.id %> --resource users --values '{"nickname":"Ada"}'`,
16
+ `<%= config.bin %> <%= command.id %> --resource users --values '[{"nickname":"Ada"},{"nickname":"Grace"}]'`,
8
17
  `<%= config.bin %> <%= command.id %> --resource posts.comments --source-id 1 --values '{"content":"Hello"}'`,
9
18
  ];
10
19
  static flags = createFlags;
@@ -14,7 +14,6 @@ import { AppHealthCheckError, formatAppUrl, isAppReady, resolveManagedAppApiBase
14
14
  import { ensureBuiltinDbReady, ensureLocalPostinstall, ensureSavedLocalSource, recreateSavedDockerApp, } from '../../lib/app-managed-resources.js';
15
15
  import { clearEnvRootSetup, getEnv, upsertEnv } from '../../lib/auth-store.js';
16
16
  import { buildInitAppEnvVarsFromConfig, isPreparedSetupState } from '../../lib/managed-init-env.js';
17
- import { prepareInitialPortalTemplate } from '../../lib/portal-template.js';
18
17
  import { resolveAppUrlFromApiBaseUrl } from '../env/shared.js';
19
18
  import { readManagedRuntimeEnvValues } from '../../lib/managed-env-file.js';
20
19
  import { run } from '../../lib/run-npm.js';
@@ -182,19 +181,6 @@ async function finalizePreparedEnv(envName) {
182
181
  setupState: 'installed',
183
182
  });
184
183
  }
185
- async function prepareInitialPortalForRuntime(runtime, verbose) {
186
- await prepareInitialPortalTemplate({
187
- developmentMode: runtime.env.config?.developmentMode,
188
- portalName: runtime.env.config?.portalName,
189
- portalTemplate: runtime.env.config?.portalTemplate,
190
- npmRegistry: runtime.env.config?.npmRegistry,
191
- storagePath: runtime.env.storagePath || runtime.env.config?.storagePath,
192
- verbose,
193
- onStartTask: startTask,
194
- onSucceedTask: succeedTask,
195
- onFailTask: failTask,
196
- });
197
- }
198
184
  export default class AppStart extends Command {
199
185
  static hidden = false;
200
186
  static description = 'Start NocoBase for the selected env. When applicable, the CLI synchronizes licensed commercial plugins first, then prepares and starts the app or recreates the saved Docker container.';
@@ -263,7 +249,7 @@ export default class AppStart extends Command {
263
249
  }
264
250
  const daemonFlagWasProvided = argvHasToken(this.argv, ['--daemon', '--no-daemon']);
265
251
  const runtime = await resolveManagedAppRuntime(requestedEnv);
266
- const preparedInitEnvVars = buildInitAppEnvVarsFromConfig(runtime?.env.config, { includePortal: false });
252
+ const preparedInitEnvVars = buildInitAppEnvVarsFromConfig(runtime?.env.config);
267
253
  const isPreparedEnv = isPreparedSetupState(runtime?.env.config?.setupState);
268
254
  const hookCommand = resolveHookCommand(flags['hook-command']);
269
255
  const hookPhase = resolveAppStartHookPhase({
@@ -336,9 +322,6 @@ export default class AppStart extends Command {
336
322
  command: hookCommand,
337
323
  });
338
324
  }
339
- if (isPreparedEnv) {
340
- await prepareInitialPortalForRuntime(runtime, flags.verbose);
341
- }
342
325
  await recreateSavedDockerApp(runtime, {
343
326
  initEnvVars: isPreparedEnv ? preparedInitEnvVars : undefined,
344
327
  verbose: flags.verbose,
@@ -487,9 +470,6 @@ export default class AppStart extends Command {
487
470
  command: hookCommand,
488
471
  });
489
472
  }
490
- if (isPreparedEnv) {
491
- await prepareInitialPortalForRuntime(runtime, flags.verbose);
492
- }
493
473
  await runLocalNocoBaseCommand(runtime, npmArgs, {
494
474
  env: startEnv,
495
475
  stdio: commandStdio,
@@ -14,7 +14,6 @@ export default class ConfigSet extends Command {
14
14
  static description = 'Set a CLI configuration value for a supported configuration key.';
15
15
  static examples = [
16
16
  '<%= config.bin %> <%= command.id %> locale zh-CN',
17
- '<%= config.bin %> <%= command.id %> default-portal-template git@github.com:nocobase/admin-starter.git',
18
17
  '<%= config.bin %> <%= command.id %> update.policy prompt',
19
18
  '<%= config.bin %> <%= command.id %> docker.network nocobase',
20
19
  '<%= config.bin %> <%= command.id %> docker.container-prefix nb',
@@ -32,12 +32,8 @@ import EnvAdd from "./env/add.js";
32
32
  import Install, { defaultDbPortForDialect } from "./install.js";
33
33
  const DEFAULT_INIT_API_BASE_URL = 'http://localhost:13000/api';
34
34
  const DEFAULT_INIT_APP_NAME = 'local';
35
- const DEFAULT_INIT_DEVELOPMENT_MODE = 'no-code';
36
- const DEFAULT_INIT_PORTAL_NAME = 'admin';
37
- const DEFAULT_INIT_PORTAL_TEMPLATE = 'git@github.com:nocobase/admin-starter.git';
38
35
  const DOWNLOAD_OUTPUT_DIR_PROMPT = Download.prompts.outputDir;
39
36
  const INIT_SETUP_MODES = ['install-new', 'manage-local', 'connect-remote'];
40
- const INIT_DEVELOPMENT_MODES = ['no-code', 'vibe-coding'];
41
37
  const INIT_ENV_ADD_FLAG_NAMES = [
42
38
  'locale',
43
39
  'default-api-base-url',
@@ -84,9 +80,6 @@ function isInstallNewSetupMode(values) {
84
80
  function isInstallLikeSetupMode(values) {
85
81
  return !isRemoteSetupMode(values);
86
82
  }
87
- function isVibeCodingMode(values) {
88
- return String(values.developmentMode ?? DEFAULT_INIT_DEVELOPMENT_MODE).trim() === 'vibe-coding';
89
- }
90
83
  function remoteConnectionOnly(def) {
91
84
  return withExtraHidden(def, (values) => !isRemoteSetupMode(values));
92
85
  }
@@ -394,43 +387,6 @@ Prompt modes:
394
387
  devDependencies: installLikeDownloadExecutionOnly(Download.prompts.devDependencies),
395
388
  build: installLikeDownloadExecutionOnly(Download.prompts.build),
396
389
  buildDts: installLikeDownloadExecutionOnly(Download.prompts.buildDts),
397
- developmentMode: installNewOnly({
398
- type: 'select',
399
- variant: 'radio',
400
- message: initText('prompts.developmentMode.message'),
401
- options: [
402
- {
403
- value: 'no-code',
404
- label: initText('prompts.developmentMode.noCodeLabel'),
405
- hint: initText('prompts.developmentMode.noCodeHint'),
406
- },
407
- {
408
- value: 'vibe-coding',
409
- label: initText('prompts.developmentMode.vibeCodingLabel'),
410
- hint: initText('prompts.developmentMode.vibeCodingHint'),
411
- },
412
- ],
413
- initialValue: DEFAULT_INIT_DEVELOPMENT_MODE,
414
- yesInitialValue: DEFAULT_INIT_DEVELOPMENT_MODE,
415
- required: true,
416
- }),
417
- portalName: installNewOnly({
418
- type: 'text',
419
- message: initText('prompts.portalName.message'),
420
- placeholder: DEFAULT_INIT_PORTAL_NAME,
421
- initialValue: DEFAULT_INIT_PORTAL_NAME,
422
- yesInitialValue: DEFAULT_INIT_PORTAL_NAME,
423
- hidden: (values) => !isVibeCodingMode(values),
424
- required: true,
425
- }),
426
- portalTemplate: installNewOnly({
427
- type: 'text',
428
- message: initText('prompts.portalTemplate.message'),
429
- placeholder: DEFAULT_INIT_PORTAL_TEMPLATE,
430
- yesInitialValue: DEFAULT_INIT_PORTAL_TEMPLATE,
431
- hidden: (values) => !isVibeCodingMode(values),
432
- required: true,
433
- }),
434
390
  dbDialect: installLikeOnly(Install.dbPrompts.dbDialect),
435
391
  builtinDb: installLikeOnly(Install.dbPrompts.builtinDb),
436
392
  builtinDbImage: installLikeOnly(Install.dbPrompts.builtinDbImage),
@@ -456,13 +412,6 @@ Prompt modes:
456
412
  ...Init.prompts,
457
413
  installApiBaseUrl: createInstallConnectionApiBaseUrlPrompt(options.defaultApiHost),
458
414
  };
459
- const defaultPortalTemplate = String(options.defaultPortalTemplate ?? '').trim();
460
- if (defaultPortalTemplate) {
461
- prompts.portalTemplate = {
462
- ...prompts.portalTemplate,
463
- yesInitialValue: defaultPortalTemplate,
464
- };
465
- }
466
415
  if (flags['skip-auth']) {
467
416
  const accessTokenPrompt = {
468
417
  ...EnvAdd.prompts.accessToken,
@@ -512,16 +461,6 @@ Prompt modes:
512
461
  description: 'Setup mode: install a new app, manage a local app by reusing its database, or connect a remote app',
513
462
  options: [...INIT_SETUP_MODES],
514
463
  }),
515
- 'development-mode': Flags.string({
516
- description: 'Initial development mode: no-code or vibe-coding',
517
- options: [...INIT_DEVELOPMENT_MODES],
518
- }),
519
- 'portal-name': Flags.string({
520
- description: 'Initial portal name when --development-mode vibe-coding is used',
521
- }),
522
- 'portal-template': Flags.string({
523
- description: 'Initial portal template Git URL or local path when --development-mode vibe-coding is used',
524
- }),
525
464
  ui: Flags.boolean({
526
465
  description: 'Open the guided setup flow in a local browser form (not valid with --yes)',
527
466
  default: false,
@@ -639,8 +578,7 @@ Prompt modes:
639
578
  const dynamicInitialValues = await Init.buildDynamicInitialValuesForInstall(normalizedFlags, presetValues);
640
579
  const defaultUiHost = await resolveDefaultUiHost();
641
580
  const defaultApiHost = await resolveDefaultApiHost();
642
- const defaultPortalTemplate = String(dynamicInitialValues.portalTemplate ?? '').trim();
643
- const promptCatalog = this.buildPromptCatalog(normalizedFlags, { defaultApiHost, defaultPortalTemplate });
581
+ const promptCatalog = this.buildPromptCatalog(normalizedFlags, { defaultApiHost });
644
582
  if (useBrowserUi) {
645
583
  presetValues = await runPromptCatalogWebUI({
646
584
  stages: Init.buildWebUiStages(promptCatalog),
@@ -669,7 +607,6 @@ Prompt modes:
669
607
  ? { setupMode: normalizeInitSetupMode(presetValues.hasNocobase) }
670
608
  : {}),
671
609
  },
672
- yesInitialValues: pickKeys(dynamicInitialValues, ['portalTemplate']),
673
610
  values: presetValues,
674
611
  yes: normalizedFlags.yes || useBrowserUi || !interactive,
675
612
  hooks: {
@@ -742,9 +679,7 @@ Prompt modes:
742
679
  }
743
680
  static async buildDynamicInitialValuesForInstall(flags, presetValues) {
744
681
  const out = {};
745
- const shouldResolveAppInitialValues = !Object.prototype.hasOwnProperty.call(presetValues, 'appPort') ||
746
- !Object.prototype.hasOwnProperty.call(presetValues, 'portalTemplate');
747
- if (shouldResolveAppInitialValues) {
682
+ if (!Object.prototype.hasOwnProperty.call(presetValues, 'appPort')) {
748
683
  const appInitialValues = await Install.buildAppPromptInitialValues({
749
684
  envName: String(presetValues.appName ?? '').trim(),
750
685
  flags: {
@@ -752,20 +687,12 @@ Prompt modes:
752
687
  'app-path': flags['app-path'] ?? '',
753
688
  'app-root-path': flags['app-root-path'] ?? '',
754
689
  'storage-path': flags['storage-path'] ?? '',
755
- 'portal-template': flags['portal-template'] ??
756
- (Object.prototype.hasOwnProperty.call(presetValues, 'portalTemplate')
757
- ? String(presetValues.portalTemplate ?? '')
758
- : undefined),
759
690
  },
760
691
  warnOnPortFallback: false,
761
692
  });
762
- if (appInitialValues.appPort !== undefined && !Object.prototype.hasOwnProperty.call(presetValues, 'appPort')) {
693
+ if (appInitialValues.appPort !== undefined) {
763
694
  out.appPort = appInitialValues.appPort;
764
695
  }
765
- if (appInitialValues.portalTemplate !== undefined &&
766
- !Object.prototype.hasOwnProperty.call(presetValues, 'portalTemplate')) {
767
- out.portalTemplate = appInitialValues.portalTemplate;
768
- }
769
696
  }
770
697
  const downloadSeed = { ...presetValues };
771
698
  if (flags.yes && !Object.prototype.hasOwnProperty.call(downloadSeed, 'source')) {
@@ -844,13 +771,6 @@ Prompt modes:
844
771
  buildDts: c.buildDts,
845
772
  },
846
773
  },
847
- {
848
- sectionTitle: initText('webUi.developmentMode.title'),
849
- sectionDescription: initText('webUi.developmentMode.description'),
850
- catalog: {
851
- developmentMode: c.developmentMode,
852
- },
853
- },
854
774
  {
855
775
  sectionTitle: initText('webUi.configureDatabase.title'),
856
776
  sectionDescription: initText('webUi.configureDatabase.description'),
@@ -951,15 +871,6 @@ Prompt modes:
951
871
  if (flags['app-public-path'] !== undefined && String(flags['app-public-path']).trim() !== '') {
952
872
  preset.appPublicPath = String(flags['app-public-path']).trim();
953
873
  }
954
- if (flags['development-mode'] !== undefined && String(flags['development-mode']).trim() !== '') {
955
- preset.developmentMode = String(flags['development-mode']).trim();
956
- }
957
- if (flags['portal-name'] !== undefined && String(flags['portal-name']).trim() !== '') {
958
- preset.portalName = String(flags['portal-name']).trim();
959
- }
960
- if (flags['portal-template'] !== undefined && String(flags['portal-template']).trim() !== '') {
961
- preset.portalTemplate = String(flags['portal-template']).trim();
962
- }
963
874
  if (flags['root-username'] !== undefined) {
964
875
  preset.rootUsername = String(flags['root-username'] ?? '').trim();
965
876
  }
@@ -1097,9 +1008,6 @@ Prompt modes:
1097
1008
  const existingEnv = await getEnv(envName, { scope: resolveDefaultConfigScope() });
1098
1009
  const appPort = String(results.appPort ?? '').trim();
1099
1010
  const appPublicPath = String(results.appPublicPath ?? '').trim();
1100
- const developmentMode = String(results.developmentMode ?? '').trim();
1101
- const portalName = String(results.portalName ?? '').trim();
1102
- const portalTemplate = String(results.portalTemplate ?? '').trim();
1103
1011
  const source = String(results.source ?? '').trim();
1104
1012
  const version = resolveInitDownloadVersion(results);
1105
1013
  const dockerRegistry = String(results.dockerRegistry ?? '').trim();
@@ -1172,9 +1080,6 @@ Prompt modes:
1172
1080
  ...(storagePath && !areConfiguredPathsEquivalent(storagePath, derivedStoragePath) ? { storagePath } : {}),
1173
1081
  ...(appPort ? { appPort } : {}),
1174
1082
  ...(appPublicPath ? { appPublicPath } : {}),
1175
- ...(developmentMode && developmentMode !== DEFAULT_INIT_DEVELOPMENT_MODE ? { developmentMode } : {}),
1176
- ...(portalName ? { portalName } : {}),
1177
- ...(portalTemplate ? { portalTemplate } : {}),
1178
1083
  ...(appKey ? { appKey } : {}),
1179
1084
  ...(timeZone ? { timezone: timeZone } : {}),
1180
1085
  ...(!skipDownload && results.devDependencies !== undefined
@@ -1299,18 +1204,6 @@ Prompt modes:
1299
1204
  if (appPublicPath) {
1300
1205
  argv.push('--app-public-path', appPublicPath);
1301
1206
  }
1302
- const developmentMode = String(results.developmentMode ?? '').trim();
1303
- if (developmentMode && developmentMode !== DEFAULT_INIT_DEVELOPMENT_MODE) {
1304
- argv.push('--development-mode', developmentMode);
1305
- }
1306
- const portalName = String(results.portalName ?? '').trim();
1307
- if (portalName) {
1308
- argv.push('--portal-name', portalName);
1309
- }
1310
- const portalTemplate = String(results.portalTemplate ?? '').trim();
1311
- if (portalTemplate) {
1312
- argv.push('--portal-template', portalTemplate);
1313
- }
1314
1207
  if (flags.force) {
1315
1208
  argv.push('--force');
1316
1209
  }
@@ -1508,16 +1401,6 @@ Prompt modes:
1508
1401
  delete normalized.rootPassword;
1509
1402
  delete normalized.rootNickname;
1510
1403
  }
1511
- const developmentMode = normalizeConnectionString(normalized.developmentMode) || DEFAULT_INIT_DEVELOPMENT_MODE;
1512
- normalized.developmentMode = developmentMode;
1513
- if (developmentMode === 'vibe-coding') {
1514
- normalized.portalName = normalizeConnectionString(normalized.portalName) || DEFAULT_INIT_PORTAL_NAME;
1515
- normalized.portalTemplate = normalizeConnectionString(normalized.portalTemplate);
1516
- }
1517
- else {
1518
- delete normalized.portalName;
1519
- delete normalized.portalTemplate;
1520
- }
1521
1404
  delete normalized.installApiBaseUrl;
1522
1405
  delete normalized.installAuthType;
1523
1406
  delete normalized.installUsername;
@@ -29,7 +29,6 @@ import { buildStoredEnvConfig } from '../lib/env-config.js';
29
29
  import { resolveDockerEnvFileArg } from "../lib/docker-env-file.js";
30
30
  import { startDockerLogFollower } from '../lib/docker-log-stream.js';
31
31
  import { buildInitAppEnvVarsFromConfig } from '../lib/managed-init-env.js';
32
- import { prepareInitialPortalTemplate } from '../lib/portal-template.js';
33
32
  import { buildHookContext, persistHookScript, resolveHookScriptPath, runHookScriptHook, } from '../lib/hook-script.js';
34
33
  import { areConfiguredPathsEquivalent, deriveConfiguredSourcePath, deriveConfiguredStoragePath, inferConfiguredAppPathFromLegacyConfig, } from '../lib/env-paths.js';
35
34
  import Download from './download.js';
@@ -54,10 +53,6 @@ const DEFAULT_INSTALL_ROOT_EMAIL = 'admin@nocobase.com';
54
53
  const DEFAULT_INSTALL_ROOT_PASSWORD = 'admin123';
55
54
  const DEFAULT_INSTALL_ROOT_NICKNAME = 'Super Admin';
56
55
  const DEFAULT_INSTALL_API_HOST = '127.0.0.1';
57
- const DEFAULT_INSTALL_DEVELOPMENT_MODE = 'no-code';
58
- const DEFAULT_INSTALL_PORTAL_NAME = 'admin';
59
- const DEFAULT_INSTALL_PORTAL_TEMPLATE = 'git@github.com:nocobase/admin-starter.git';
60
- const INSTALL_DEVELOPMENT_MODES = ['no-code', 'vibe-coding'];
61
56
  function toOptionalPromptString(value) {
62
57
  const text = String(value ?? '').trim();
63
58
  return text || undefined;
@@ -185,9 +180,6 @@ function defaultBuiltinDbImageForDialect(value, options) {
185
180
  function defaultDbDatabaseForDialect(value) {
186
181
  return String(value ?? '').trim() === 'kingbase' ? 'kingbase' : DEFAULT_INSTALL_DB_DATABASE;
187
182
  }
188
- function isVibeCodingMode(values) {
189
- return String(values.developmentMode ?? DEFAULT_INSTALL_DEVELOPMENT_MODE).trim() === 'vibe-coding';
190
- }
191
183
  function supportsDbSchemaPrompt(value) {
192
184
  const dialect = String(value ?? '').trim();
193
185
  return dialect === 'postgres' || dialect === 'kingbase';
@@ -412,16 +404,6 @@ export default class Install extends Command {
412
404
  'app-public-path': Flags.string({
413
405
  description: 'Public path for the local app, for example / or /console/',
414
406
  }),
415
- 'development-mode': Flags.string({
416
- description: 'Initial development mode for the installed app',
417
- options: [...INSTALL_DEVELOPMENT_MODES],
418
- }),
419
- 'portal-name': Flags.string({
420
- description: 'Initial portal name when --development-mode vibe-coding is used',
421
- }),
422
- 'portal-template': Flags.string({
423
- description: 'Initial portal template Git URL or local path when --development-mode vibe-coding is used',
424
- }),
425
407
  'root-username': Flags.string({
426
408
  description: 'Initial admin username for the installed app',
427
409
  required: false,
@@ -531,42 +513,6 @@ export default class Install extends Command {
531
513
  yesInitialValue: '/',
532
514
  validate: validateAppPublicPath,
533
515
  },
534
- developmentMode: {
535
- type: 'select',
536
- message: installText('prompts.developmentMode.message'),
537
- options: [
538
- {
539
- value: 'no-code',
540
- label: installText('prompts.developmentMode.noCodeLabel'),
541
- hint: installText('prompts.developmentMode.noCodeHint'),
542
- },
543
- {
544
- value: 'vibe-coding',
545
- label: installText('prompts.developmentMode.vibeCodingLabel'),
546
- hint: installText('prompts.developmentMode.vibeCodingHint'),
547
- },
548
- ],
549
- initialValue: DEFAULT_INSTALL_DEVELOPMENT_MODE,
550
- yesInitialValue: DEFAULT_INSTALL_DEVELOPMENT_MODE,
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
- hidden: (values) => !isVibeCodingMode(values),
560
- required: true,
561
- },
562
- portalTemplate: {
563
- type: 'text',
564
- message: installText('prompts.portalTemplate.message'),
565
- placeholder: DEFAULT_INSTALL_PORTAL_TEMPLATE,
566
- yesInitialValue: DEFAULT_INSTALL_PORTAL_TEMPLATE,
567
- hidden: (values) => !isVibeCodingMode(values),
568
- required: true,
569
- },
570
516
  };
571
517
  }
572
518
  static dbPrompts = {
@@ -826,24 +772,6 @@ export default class Install extends Command {
826
772
  preset.appPublicPath = v;
827
773
  }
828
774
  }
829
- if (flags['development-mode'] !== undefined) {
830
- const v = String(flags['development-mode'] ?? '').trim();
831
- if (v) {
832
- preset.developmentMode = v;
833
- }
834
- }
835
- if (flags['portal-name'] !== undefined) {
836
- const v = String(flags['portal-name'] ?? '').trim();
837
- if (v) {
838
- preset.portalName = v;
839
- }
840
- }
841
- if (flags['portal-template'] !== undefined) {
842
- const v = String(flags['portal-template'] ?? '').trim();
843
- if (v) {
844
- preset.portalTemplate = v;
845
- }
846
- }
847
775
  if (flags['root-username'] !== undefined) {
848
776
  preset.rootUsername = String(flags['root-username'] ?? '').trim();
849
777
  }
@@ -935,9 +863,6 @@ export default class Install extends Command {
935
863
  'appPort',
936
864
  'storagePath',
937
865
  'appPublicPath',
938
- 'developmentMode',
939
- 'portalName',
940
- 'portalTemplate',
941
866
  ]);
942
867
  }
943
868
  static buildDbPresetValuesFromFlags(flags, argv = process.argv.slice(2)) {
@@ -1187,9 +1112,6 @@ export default class Install extends Command {
1187
1112
  const rootPassword = Install.toOptionalPromptString(config.rootPassword);
1188
1113
  const rootNickname = Install.toOptionalPromptString(config.rootNickname);
1189
1114
  const lang = Install.toOptionalPromptString(config.lang);
1190
- const developmentMode = Install.toOptionalPromptString(config.developmentMode);
1191
- const portalName = Install.toOptionalPromptString(config.portalName);
1192
- const portalTemplate = Install.toOptionalPromptString(config.portalTemplate);
1193
1115
  const auth = config.auth;
1194
1116
  const savedAuthType = Install.toOptionalPromptString(config.authType) ?? Install.toOptionalPromptString(auth?.type);
1195
1117
  const appPreset = {
@@ -1199,9 +1121,6 @@ export default class Install extends Command {
1199
1121
  ...(appPort ? { appPort } : {}),
1200
1122
  ...(storagePath ? { storagePath } : {}),
1201
1123
  ...(appPublicPath ? { appPublicPath } : {}),
1202
- ...(developmentMode ? { developmentMode } : {}),
1203
- ...(portalName ? { portalName } : {}),
1204
- ...(portalTemplate ? { portalTemplate } : {}),
1205
1124
  ...(hookScript ? { hookScript } : {}),
1206
1125
  };
1207
1126
  const downloadPreset = {
@@ -1344,12 +1263,6 @@ export default class Install extends Command {
1344
1263
  warn: params.warnOnPortFallback ?? true,
1345
1264
  });
1346
1265
  }
1347
- if (params.flags['portal-template'] === undefined) {
1348
- const defaultPortalTemplate = Install.toOptionalPromptString(await getCliConfigValue('default-portal-template'));
1349
- if (defaultPortalTemplate) {
1350
- initialValues.portalTemplate = defaultPortalTemplate;
1351
- }
1352
- }
1353
1266
  return initialValues;
1354
1267
  }
1355
1268
  static shouldPublishBuiltinDbPortForValues(values) {
@@ -1517,17 +1430,14 @@ export default class Install extends Command {
1517
1430
  static buildDockerAppContainerName(envName, containerPrefix) {
1518
1431
  return Install.sanitizeDockerResourceName(`${Install.buildBuiltinDbContainerPrefix(containerPrefix)}-${envName}-app`);
1519
1432
  }
1520
- static buildInitAppEnvVars(params, options = {}) {
1433
+ static buildInitAppEnvVars(params) {
1521
1434
  return buildInitAppEnvVarsFromConfig({
1522
1435
  lang: String(params.appResults.lang ?? ''),
1523
1436
  rootUsername: String(params.rootResults.rootUsername ?? ''),
1524
1437
  rootEmail: String(params.rootResults.rootEmail ?? ''),
1525
1438
  rootPassword: String(params.rootResults.rootPassword ?? ''),
1526
1439
  rootNickname: String(params.rootResults.rootNickname ?? ''),
1527
- developmentMode: String(params.appResults.developmentMode ?? ''),
1528
- portalName: String(params.appResults.portalName ?? ''),
1529
- portalTemplate: String(params.appResults.portalTemplate ?? ''),
1530
- }, options);
1440
+ });
1531
1441
  }
1532
1442
  static shouldPublishBuiltinDbPort(source) {
1533
1443
  return String(source ?? '').trim() !== 'docker';
@@ -1882,7 +1792,7 @@ export default class Install extends Command {
1882
1792
  const initEnvVars = Install.buildInitAppEnvVars({
1883
1793
  appResults: params.appResults,
1884
1794
  rootResults: params.rootResults,
1885
- }, { includePortal: false });
1795
+ });
1886
1796
  const containerPort = resolveDockerImageContainerPort(imageRef);
1887
1797
  const args = [
1888
1798
  'run',
@@ -2159,7 +2069,7 @@ export default class Install extends Command {
2159
2069
  ...Install.buildInitAppEnvVars({
2160
2070
  appResults: params.appResults,
2161
2071
  rootResults: params.rootResults,
2162
- }, { includePortal: false }),
2072
+ }),
2163
2073
  };
2164
2074
  setOptionalEnvVar(env, 'APP_PUBLIC_PATH', Install.toOptionalPromptString(params.appResults.appPublicPath));
2165
2075
  setOptionalEnvVar(env, 'DB_SCHEMA', optionalEnvString(params.dbResults.dbSchema));
@@ -2356,19 +2266,6 @@ export default class Install extends Command {
2356
2266
  }
2357
2267
  return argv;
2358
2268
  }
2359
- async prepareInitialPortalIfNeeded(params) {
2360
- await prepareInitialPortalTemplate({
2361
- developmentMode: Install.toOptionalPromptString(params.appResults.developmentMode),
2362
- portalName: Install.toOptionalPromptString(params.appResults.portalName),
2363
- portalTemplate: Install.toOptionalPromptString(params.appResults.portalTemplate),
2364
- npmRegistry: Install.toOptionalPromptString(params.appResults.npmRegistry),
2365
- storagePath: Install.resolveAbsoluteStoragePath(params.envName, params.appResults),
2366
- verbose: params.verbose,
2367
- onStartTask: (message) => this.logStage(message),
2368
- onSucceedTask: (message) => printInfo(message),
2369
- onFailTask: (message) => printWarning(message),
2370
- });
2371
- }
2372
2269
  async runInstallHookIfNeeded(params) {
2373
2270
  const appPath = Install.resolveAbsoluteAppPath(params.envName, params.appResults);
2374
2271
  const savedHookScript = Install.toOptionalPromptString(params.appResults.hookScript);
@@ -2412,9 +2309,6 @@ export default class Install extends Command {
2412
2309
  const appRootPath = Install.toOptionalPromptString(params.appResults.appRootPath);
2413
2310
  const storagePath = Install.toOptionalPromptString(params.appResults.storagePath);
2414
2311
  const appPublicPath = Install.toOptionalPromptString(params.appResults.appPublicPath);
2415
- const developmentMode = Install.toOptionalPromptString(params.appResults.developmentMode);
2416
- const portalName = Install.toOptionalPromptString(params.appResults.portalName);
2417
- const portalTemplate = Install.toOptionalPromptString(params.appResults.portalTemplate);
2418
2312
  const derivedAppRootPath = appPath ? deriveConfiguredSourcePath(appPath) : undefined;
2419
2313
  const derivedStoragePath = appPath ? deriveConfiguredStoragePath(appPath) : undefined;
2420
2314
  const appPort = String(params.appResults.appPort ?? DEFAULT_INSTALL_APP_PORT).trim() || DEFAULT_INSTALL_APP_PORT;
@@ -2449,9 +2343,6 @@ export default class Install extends Command {
2449
2343
  ...(appPublicPath ? { appPublicPath } : {}),
2450
2344
  ...(envFile ? { envFile } : {}),
2451
2345
  lang: params.appResults.lang,
2452
- developmentMode,
2453
- portalName,
2454
- portalTemplate,
2455
2346
  appKey: params.appResults.appKey,
2456
2347
  timezone: params.appResults.timeZone,
2457
2348
  builtinDb: params.dbResults.builtinDb,
@@ -2503,7 +2394,6 @@ export default class Install extends Command {
2503
2394
  'app-root-path': parsed['app-root-path'] ?? Install.toOptionalPromptString(appPreset.appRootPath),
2504
2395
  'app-port': parsed['app-port'] ?? Install.toOptionalPromptString(appPreset.appPort),
2505
2396
  'storage-path': parsed['storage-path'] ?? Install.toOptionalPromptString(appPreset.storagePath),
2506
- 'portal-template': parsed['portal-template'] ?? Install.toOptionalPromptString(appPreset.portalTemplate),
2507
2397
  },
2508
2398
  }),
2509
2399
  values: appPreset,
@@ -2742,13 +2632,6 @@ export default class Install extends Command {
2742
2632
  envAddResults,
2743
2633
  });
2744
2634
  }
2745
- if (shouldStartApp) {
2746
- await this.prepareInitialPortalIfNeeded({
2747
- envName,
2748
- appResults,
2749
- verbose: parsed.verbose,
2750
- });
2751
- }
2752
2635
  if (shouldStartApp) {
2753
2636
  this.logStage('Starting NocoBase');
2754
2637
  await this.config.runCommand('app:start', this.buildAppStartArgv({ envName, verbose: parsed.verbose }));
@@ -140,7 +140,7 @@ export default class SourceDev extends Command {
140
140
  : `Run \`nb app stop --env ${runtime.envName}\` before starting dev mode, or choose another dev port with --port.`,
141
141
  ].join('\n'));
142
142
  }
143
- const npmArgs = ['dev', '--rsbuild', '--quickstart'];
143
+ const npmArgs = ['dev', '--rsbuild'];
144
144
  if (flags['db-sync']) {
145
145
  npmArgs.push('--db-sync');
146
146
  }
@@ -199,6 +199,13 @@ async function createMultipartBody(flags, operation) {
199
199
  if (value === undefined) {
200
200
  continue;
201
201
  }
202
+ if (Array.isArray(value)) {
203
+ for (const item of value) {
204
+ formData.append(parameter.name, typeof item === 'object' ? JSON.stringify(item) : String(item));
205
+ }
206
+ hasValues = hasValues || value.length > 0;
207
+ continue;
208
+ }
202
209
  formData.append(parameter.name, typeof value === 'object' ? JSON.stringify(value) : String(value));
203
210
  hasValues = true;
204
211
  }
@@ -97,7 +97,6 @@ function normalizeAuthConfig(config) {
97
97
  const locale = normalizeOptionalCliLocale(settings.locale);
98
98
  const defaultUiHost = normalizeOptionalString(settings.init?.defaultUiHost);
99
99
  const defaultApiHost = normalizeOptionalString(settings.init?.defaultApiHost);
100
- const defaultPortalTemplate = normalizeOptionalString(settings.init?.defaultPortalTemplate);
101
100
  const updatePolicy = normalizeOptionalCliUpdatePolicy(settings.update?.policy);
102
101
  const logRetentionDays = typeof settings.log?.retentionDays === 'number' && Number.isInteger(settings.log.retentionDays)
103
102
  ? settings.log.retentionDays
@@ -118,12 +117,11 @@ function normalizeAuthConfig(config) {
118
117
  name: config.name || config.dockerResourcePrefix,
119
118
  settings: {
120
119
  ...(locale ? { locale } : {}),
121
- ...(defaultUiHost || defaultApiHost || defaultPortalTemplate
120
+ ...(defaultUiHost || defaultApiHost
122
121
  ? {
123
122
  init: {
124
123
  ...(defaultUiHost ? { defaultUiHost } : {}),
125
124
  ...(defaultApiHost ? { defaultApiHost } : {}),
126
- ...(defaultPortalTemplate ? { defaultPortalTemplate } : {}),
127
125
  },
128
126
  }
129
127
  : {}),
@@ -0,0 +1,29 @@
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
+ import { spawn } from 'node:child_process';
10
+ export async function openUrlInDefaultBrowser(url) {
11
+ const [command, args, options] = process.platform === 'darwin'
12
+ ? ['open', [url], { detached: true, stdio: 'ignore' }]
13
+ : process.platform === 'win32'
14
+ ? ['cmd', ['/c', 'start', '', url], { detached: true, stdio: 'ignore', windowsHide: true }]
15
+ : ['xdg-open', [url], { detached: true, stdio: 'ignore' }];
16
+ return new Promise((resolve) => {
17
+ try {
18
+ const child = spawn(command, args, options);
19
+ child.once('error', () => resolve(false));
20
+ child.once('spawn', () => {
21
+ child.unref();
22
+ resolve(true);
23
+ });
24
+ }
25
+ catch {
26
+ resolve(false);
27
+ }
28
+ });
29
+ }