@nocobase/cli 2.2.0-test.16 → 3.0.0-alpha.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.
- package/dist/commands/app/start.js +1 -21
- package/dist/commands/config/set.js +1 -1
- package/dist/commands/init.js +12 -121
- package/dist/commands/install.js +39 -55
- package/dist/commands/portal/config.js +88 -0
- package/dist/commands/portal/create.js +7 -6
- package/dist/commands/portal/deploy.js +2 -2
- package/dist/commands/portal/destroy.js +6 -6
- package/dist/commands/portal/dev.js +3 -3
- package/dist/commands/portal/index.js +1 -1
- package/dist/commands/portal/info.js +3 -3
- package/dist/commands/portal/list.js +5 -5
- package/dist/commands/portal/pull.js +11 -4
- package/dist/commands/portal/push.js +4 -4
- package/dist/lib/api-client.js +7 -0
- package/dist/lib/env-auth.js +2 -2
- package/dist/lib/env-config.js +1 -1
- package/dist/lib/env-proxy.js +68 -6
- package/dist/lib/managed-env-file.js +58 -2
- package/dist/lib/managed-init-env.js +1 -1
- package/dist/lib/naming.js +9 -0
- package/dist/lib/portal-config.js +133 -0
- package/dist/lib/portal-configure.js +117 -0
- package/dist/lib/portal-create.js +24 -79
- package/dist/lib/portal-deploy.js +23 -15
- package/dist/lib/portal-destroy.js +3 -3
- package/dist/lib/portal-dev.js +3 -3
- package/dist/lib/portal-info.js +2 -2
- package/dist/lib/portal-list.js +32 -18
- package/dist/lib/portal-source.js +150 -43
- package/dist/lib/proxy-caddy.js +2 -0
- package/dist/lib/proxy-nginx.js +1 -0
- package/dist/locale/en-US.json +67 -43
- package/dist/locale/zh-CN.json +59 -35
- package/nocobase-ctl.config.json +111 -0
- package/package.json +4 -3
- package/dist/lib/portal-template.js +0 -190
|
@@ -14,9 +14,12 @@ import path from 'node:path';
|
|
|
14
14
|
import * as tar from 'tar';
|
|
15
15
|
import { executeApiRequest } from './api-client.js';
|
|
16
16
|
import { translateCli } from './cli-locale.js';
|
|
17
|
+
import { buildPortalConfig, buildPortalConfigFromOptions, DEFAULT_PORTAL_GIT_PATH, readPortalConfig, syncPortalConfigToRemote, writePortalConfig, } from './portal-config.js';
|
|
18
|
+
import { buildPortalCommandEnv } from './portal-command-env.js';
|
|
17
19
|
import { buildPortalBasePath, resolvePortalAppFromApiBaseUrl, resolvePortalStoragePath, validatePortalSlug, } from './portal-create.js';
|
|
18
20
|
import { listPortalWorkspaces } from './portal-list.js';
|
|
19
21
|
import { findPortalListItem } from './portal-info.js';
|
|
22
|
+
import { run } from './run-npm.js';
|
|
20
23
|
const execFileAsync = promisify(execFile);
|
|
21
24
|
const portalSourceText = (key, values, fallback) => translateCli(`commands.portalSource.${key}`, values, { fallback });
|
|
22
25
|
const PULL_SOURCE_OPERATION = {
|
|
@@ -85,8 +88,18 @@ async function pathExists(target) {
|
|
|
85
88
|
return false;
|
|
86
89
|
}
|
|
87
90
|
}
|
|
91
|
+
async function isFile(target) {
|
|
92
|
+
try {
|
|
93
|
+
return (await stat(target)).isFile();
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
88
99
|
function shouldPackPortalSourceEntry(entryName) {
|
|
89
|
-
return !entryName
|
|
100
|
+
return !entryName
|
|
101
|
+
.split('/')
|
|
102
|
+
.some((segment) => segment.startsWith('._') || ['.git', 'node_modules', 'dist', '.DS_Store'].includes(segment));
|
|
90
103
|
}
|
|
91
104
|
function validatePortalSourceTarEntry(entryPath, entry) {
|
|
92
105
|
if (path.isAbsolute(entryPath) || entryPath.split(/[\\/]+/).includes('..')) {
|
|
@@ -118,7 +131,7 @@ async function packPortalSource(portalDir) {
|
|
|
118
131
|
async function replacePortalSourceFromArchive(params) {
|
|
119
132
|
const targetExists = await pathExists(params.portalDir);
|
|
120
133
|
if (targetExists && !params.force) {
|
|
121
|
-
throw new Error(portalSourceText('errors.workspaceExists', { portalDir: params.portalDir }, `Portal
|
|
134
|
+
throw new Error(portalSourceText('errors.workspaceExists', { portalDir: params.portalDir }, `Portal already exists: ${params.portalDir}\nPass --force to delete it and pull again.`));
|
|
122
135
|
}
|
|
123
136
|
const parentDir = path.dirname(params.portalDir);
|
|
124
137
|
const tempDir = await mkdtemp(path.join(parentDir, `.${path.basename(params.portalDir)}-pull-`));
|
|
@@ -142,7 +155,7 @@ async function replacePortalSourceFromArchive(params) {
|
|
|
142
155
|
async function replacePortalSourceFromDirectory(params) {
|
|
143
156
|
const targetExists = await pathExists(params.portalDir);
|
|
144
157
|
if (targetExists && !params.force) {
|
|
145
|
-
throw new Error(portalSourceText('errors.workspaceExists', { portalDir: params.portalDir }, `Portal
|
|
158
|
+
throw new Error(portalSourceText('errors.workspaceExists', { portalDir: params.portalDir }, `Portal already exists: ${params.portalDir}\nPass --force to delete it and pull again.`));
|
|
146
159
|
}
|
|
147
160
|
const parentDir = path.dirname(params.portalDir);
|
|
148
161
|
const tempDir = await mkdtemp(path.join(parentDir, `.${path.basename(params.portalDir)}-pull-`));
|
|
@@ -167,6 +180,31 @@ async function runGit(args, cwd) {
|
|
|
167
180
|
maxBuffer: 10 * 1024 * 1024,
|
|
168
181
|
});
|
|
169
182
|
}
|
|
183
|
+
async function installPortalDependencies(params) {
|
|
184
|
+
if (params.installDependencies === false) {
|
|
185
|
+
return {
|
|
186
|
+
dependenciesInstalled: false,
|
|
187
|
+
installSkipped: true,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
if (!(await isFile(path.join(params.portalDir, 'package.json')))) {
|
|
191
|
+
return {
|
|
192
|
+
dependenciesInstalled: false,
|
|
193
|
+
installSkipped: true,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
const runCommand = params.runCommand ?? run;
|
|
197
|
+
await runCommand('pnpm', ['install'], {
|
|
198
|
+
cwd: params.portalDir,
|
|
199
|
+
env: buildPortalCommandEnv(),
|
|
200
|
+
envMode: 'replace',
|
|
201
|
+
errorName: 'pnpm install',
|
|
202
|
+
});
|
|
203
|
+
return {
|
|
204
|
+
dependenciesInstalled: true,
|
|
205
|
+
installSkipped: false,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
170
208
|
function readSourceRevision(data) {
|
|
171
209
|
if (!data || typeof data !== 'object' || Array.isArray(data)) {
|
|
172
210
|
return undefined;
|
|
@@ -186,7 +224,7 @@ async function resolvePortalSourceContext(options) {
|
|
|
186
224
|
const portalBase = buildPortalBasePath({ app, appPublicPath, portal });
|
|
187
225
|
const mode = options.env.kind;
|
|
188
226
|
if (mode !== 'local' && mode !== 'docker' && mode !== 'http') {
|
|
189
|
-
throw new Error(portalSourceText('errors.unsupportedEnvKind', { kind: mode }, `Cannot sync
|
|
227
|
+
throw new Error(portalSourceText('errors.unsupportedEnvKind', { kind: mode }, `Cannot sync portal source for ${mode} envs in the first version.`));
|
|
190
228
|
}
|
|
191
229
|
const list = await listPortalWorkspaces({
|
|
192
230
|
env: options.env,
|
|
@@ -207,7 +245,30 @@ async function resolvePortalSourceContext(options) {
|
|
|
207
245
|
sourceStorage: item.sourceStorage || 'nocobase',
|
|
208
246
|
gitRepo: item.gitRepo,
|
|
209
247
|
gitBranch: item.gitBranch || 'main',
|
|
210
|
-
gitPath: item.gitPath ||
|
|
248
|
+
gitPath: item.gitPath || DEFAULT_PORTAL_GIT_PATH,
|
|
249
|
+
options: item.options,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
function buildPortalConfigFromContext(context) {
|
|
253
|
+
if (Object.keys(context.options).length > 0) {
|
|
254
|
+
return buildPortalConfigFromOptions(context.options, context.portal);
|
|
255
|
+
}
|
|
256
|
+
const sourceStorage = context.sourceStorage || 'nocobase';
|
|
257
|
+
return buildPortalConfig({
|
|
258
|
+
portal: context.portal,
|
|
259
|
+
sourceStorage,
|
|
260
|
+
gitRepo: sourceStorage === 'git' ? context.gitRepo : undefined,
|
|
261
|
+
gitBranch: sourceStorage === 'git' ? context.gitBranch : undefined,
|
|
262
|
+
gitPath: sourceStorage === 'git' ? context.gitPath : undefined,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
function applyPortalConfigToContext(context, config) {
|
|
266
|
+
return {
|
|
267
|
+
...context,
|
|
268
|
+
sourceStorage: config.sourceStorage,
|
|
269
|
+
gitRepo: config.git?.repo ?? '',
|
|
270
|
+
gitBranch: config.git?.branch ?? 'main',
|
|
271
|
+
gitPath: config.git?.path ?? DEFAULT_PORTAL_GIT_PATH,
|
|
211
272
|
};
|
|
212
273
|
}
|
|
213
274
|
function assertGitSourceConfig(context) {
|
|
@@ -217,9 +278,33 @@ function assertGitSourceConfig(context) {
|
|
|
217
278
|
return {
|
|
218
279
|
repo: context.gitRepo,
|
|
219
280
|
branch: context.gitBranch || 'main',
|
|
220
|
-
gitPath: context.gitPath ||
|
|
281
|
+
gitPath: context.gitPath || DEFAULT_PORTAL_GIT_PATH,
|
|
221
282
|
};
|
|
222
283
|
}
|
|
284
|
+
function isGitRepositoryRootPath(gitPath) {
|
|
285
|
+
return gitPath === DEFAULT_PORTAL_GIT_PATH;
|
|
286
|
+
}
|
|
287
|
+
async function copyPortalSourceToGitPath(params) {
|
|
288
|
+
if (isGitRepositoryRootPath(params.gitPath)) {
|
|
289
|
+
const existingEntries = await readdir(params.repoDir);
|
|
290
|
+
await Promise.all(existingEntries
|
|
291
|
+
.filter((entry) => entry !== '.git')
|
|
292
|
+
.map((entry) => rm(path.join(params.repoDir, entry), { recursive: true, force: true })));
|
|
293
|
+
const sourceEntries = (await readdir(params.portalDir)).filter(shouldPackPortalSourceEntry);
|
|
294
|
+
await Promise.all(sourceEntries.map((entry) => cp(path.join(params.portalDir, entry), path.join(params.repoDir, entry), {
|
|
295
|
+
recursive: true,
|
|
296
|
+
filter: (source) => shouldPackPortalSourceEntry(path.relative(params.portalDir, source)),
|
|
297
|
+
})));
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
const targetDir = path.join(params.repoDir, params.gitPath);
|
|
301
|
+
await rm(targetDir, { recursive: true, force: true });
|
|
302
|
+
await mkdir(path.dirname(targetDir), { recursive: true });
|
|
303
|
+
await cp(params.portalDir, targetDir, {
|
|
304
|
+
recursive: true,
|
|
305
|
+
filter: (source) => shouldPackPortalSourceEntry(path.relative(params.portalDir, source)),
|
|
306
|
+
});
|
|
307
|
+
}
|
|
223
308
|
async function cloneGitSource(params) {
|
|
224
309
|
const repoDir = path.join(params.cwd, 'repo');
|
|
225
310
|
try {
|
|
@@ -267,13 +352,12 @@ async function pushGitPortalSource(params) {
|
|
|
267
352
|
repo: git.repo,
|
|
268
353
|
branch: git.branch,
|
|
269
354
|
cwd: tempDir,
|
|
355
|
+
createBranch: true,
|
|
270
356
|
});
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
recursive: true,
|
|
276
|
-
filter: (source) => shouldPackPortalSourceEntry(path.relative(params.context.portalDir, source)),
|
|
357
|
+
await copyPortalSourceToGitPath({
|
|
358
|
+
portalDir: params.context.portalDir,
|
|
359
|
+
repoDir,
|
|
360
|
+
gitPath: git.gitPath,
|
|
277
361
|
});
|
|
278
362
|
await runGit(['add', git.gitPath], repoDir);
|
|
279
363
|
const status = await runGit(['status', '--porcelain', '--', git.gitPath], repoDir);
|
|
@@ -299,24 +383,33 @@ async function pushGitPortalSource(params) {
|
|
|
299
383
|
}
|
|
300
384
|
export async function pullPortalSource(options) {
|
|
301
385
|
const context = await resolvePortalSourceContext(options);
|
|
302
|
-
|
|
386
|
+
const portalConfig = buildPortalConfigFromContext(context);
|
|
387
|
+
const sourceContext = applyPortalConfigToContext(context, portalConfig);
|
|
388
|
+
if (sourceContext.sourceStorage === 'git') {
|
|
303
389
|
await pullGitPortalSource({
|
|
304
|
-
context,
|
|
390
|
+
context: sourceContext,
|
|
305
391
|
force: options.force,
|
|
306
392
|
});
|
|
393
|
+
await writePortalConfig(sourceContext.portalDir, portalConfig);
|
|
394
|
+
const installResult = await installPortalDependencies({
|
|
395
|
+
portalDir: sourceContext.portalDir,
|
|
396
|
+
installDependencies: options.installDependencies,
|
|
397
|
+
runCommand: options.runCommand,
|
|
398
|
+
});
|
|
307
399
|
return {
|
|
308
|
-
...
|
|
400
|
+
...sourceContext,
|
|
309
401
|
changed: true,
|
|
402
|
+
...installResult,
|
|
310
403
|
};
|
|
311
404
|
}
|
|
312
|
-
if (
|
|
313
|
-
throw new Error(portalSourceText('errors.unsupportedSourceStorage', { sourceStorage:
|
|
405
|
+
if (sourceContext.sourceStorage !== 'nocobase') {
|
|
406
|
+
throw new Error(portalSourceText('errors.unsupportedSourceStorage', { sourceStorage: sourceContext.sourceStorage }, `Unsupported portal source storage: ${sourceContext.sourceStorage}`));
|
|
314
407
|
}
|
|
315
|
-
if (
|
|
408
|
+
if (sourceContext.mode === 'local' || sourceContext.mode === 'docker') {
|
|
316
409
|
return {
|
|
317
|
-
...
|
|
410
|
+
...sourceContext,
|
|
318
411
|
changed: false,
|
|
319
|
-
noopReason:
|
|
412
|
+
noopReason: sourceContext.mode === 'local'
|
|
320
413
|
? portalSourceText('messages.localPullNoop', undefined, 'Portal source is already local.')
|
|
321
414
|
: portalSourceText('messages.dockerPullNoop', undefined, 'Portal source is already available through the Docker volume.'),
|
|
322
415
|
};
|
|
@@ -329,8 +422,8 @@ export async function pullPortalSource(options) {
|
|
|
329
422
|
cliVersion: options.cliVersion ?? '',
|
|
330
423
|
envName: options.envName,
|
|
331
424
|
flags: {
|
|
332
|
-
app:
|
|
333
|
-
portal:
|
|
425
|
+
app: sourceContext.app,
|
|
426
|
+
portal: sourceContext.portal,
|
|
334
427
|
output: archivePath,
|
|
335
428
|
},
|
|
336
429
|
operation: PULL_SOURCE_OPERATION,
|
|
@@ -338,15 +431,22 @@ export async function pullPortalSource(options) {
|
|
|
338
431
|
if (!response.ok) {
|
|
339
432
|
throw new Error(portalSourceText('errors.pullFailed', { status: response.status, details: JSON.stringify(response.data, null, 2) }, `Portal source pull failed with status ${response.status}\n${JSON.stringify(response.data, null, 2)}`));
|
|
340
433
|
}
|
|
341
|
-
await mkdir(path.dirname(
|
|
434
|
+
await mkdir(path.dirname(sourceContext.portalDir), { recursive: true });
|
|
342
435
|
await replacePortalSourceFromArchive({
|
|
343
436
|
archivePath,
|
|
344
|
-
portalDir:
|
|
437
|
+
portalDir: sourceContext.portalDir,
|
|
345
438
|
force: options.force,
|
|
346
439
|
});
|
|
440
|
+
await writePortalConfig(sourceContext.portalDir, portalConfig);
|
|
441
|
+
const installResult = await installPortalDependencies({
|
|
442
|
+
portalDir: sourceContext.portalDir,
|
|
443
|
+
installDependencies: options.installDependencies,
|
|
444
|
+
runCommand: options.runCommand,
|
|
445
|
+
});
|
|
347
446
|
return {
|
|
348
|
-
...
|
|
447
|
+
...sourceContext,
|
|
349
448
|
changed: true,
|
|
449
|
+
...installResult,
|
|
350
450
|
};
|
|
351
451
|
}
|
|
352
452
|
finally {
|
|
@@ -355,16 +455,26 @@ export async function pullPortalSource(options) {
|
|
|
355
455
|
}
|
|
356
456
|
export async function pushPortalSource(options) {
|
|
357
457
|
const context = await resolvePortalSourceContext(options);
|
|
358
|
-
if (context.
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
458
|
+
if (!(await pathExists(context.portalDir))) {
|
|
459
|
+
throw new Error(portalSourceText('errors.workspaceMissing', { portalDir: context.portalDir, portal: context.portal }, `Portal does not exist: ${context.portalDir}\nRun \`nb portal create ${context.portal}\` first.`));
|
|
460
|
+
}
|
|
461
|
+
const portalConfig = await readPortalConfig(context.portalDir);
|
|
462
|
+
await syncPortalConfigToRemote({
|
|
463
|
+
portal: context.portal,
|
|
464
|
+
config: portalConfig,
|
|
465
|
+
currentOptions: context.options,
|
|
466
|
+
envName: options.envName,
|
|
467
|
+
cliVersion: options.cliVersion,
|
|
468
|
+
apiRequest: options.apiRequest,
|
|
469
|
+
});
|
|
470
|
+
const sourceContext = applyPortalConfigToContext(context, portalConfig);
|
|
471
|
+
if (sourceContext.sourceStorage === 'git') {
|
|
362
472
|
const revision = await pushGitPortalSource({
|
|
363
|
-
context,
|
|
473
|
+
context: sourceContext,
|
|
364
474
|
message: options.message,
|
|
365
475
|
});
|
|
366
476
|
return {
|
|
367
|
-
...
|
|
477
|
+
...sourceContext,
|
|
368
478
|
changed: Boolean(revision),
|
|
369
479
|
sourceRevision: revision,
|
|
370
480
|
noopReason: revision
|
|
@@ -372,22 +482,19 @@ export async function pushPortalSource(options) {
|
|
|
372
482
|
: portalSourceText('messages.gitPushNoop', undefined, 'No local source changes to push.'),
|
|
373
483
|
};
|
|
374
484
|
}
|
|
375
|
-
if (
|
|
376
|
-
throw new Error(portalSourceText('errors.unsupportedSourceStorage', { sourceStorage:
|
|
485
|
+
if (sourceContext.sourceStorage !== 'nocobase') {
|
|
486
|
+
throw new Error(portalSourceText('errors.unsupportedSourceStorage', { sourceStorage: sourceContext.sourceStorage }, `Unsupported portal source storage: ${sourceContext.sourceStorage}`));
|
|
377
487
|
}
|
|
378
|
-
if (
|
|
488
|
+
if (sourceContext.mode === 'local' || sourceContext.mode === 'docker') {
|
|
379
489
|
return {
|
|
380
|
-
...
|
|
490
|
+
...sourceContext,
|
|
381
491
|
changed: false,
|
|
382
|
-
noopReason:
|
|
492
|
+
noopReason: sourceContext.mode === 'local'
|
|
383
493
|
? portalSourceText('messages.localPushNoop', undefined, 'Portal source is already local.')
|
|
384
494
|
: portalSourceText('messages.dockerPushNoop', undefined, 'Portal source is already available through the Docker volume.'),
|
|
385
495
|
};
|
|
386
496
|
}
|
|
387
|
-
|
|
388
|
-
throw new Error(portalSourceText('errors.workspaceMissing', { portalDir: context.portalDir, portal: context.portal }, `Portal workspace does not exist: ${context.portalDir}\nRun \`nb portal create ${context.portal}\` first.`));
|
|
389
|
-
}
|
|
390
|
-
const archive = await packPortalSource(context.portalDir);
|
|
497
|
+
const archive = await packPortalSource(sourceContext.portalDir);
|
|
391
498
|
const apiRequest = options.apiRequest ?? executeApiRequest;
|
|
392
499
|
try {
|
|
393
500
|
const response = await apiRequest({
|
|
@@ -395,8 +502,8 @@ export async function pushPortalSource(options) {
|
|
|
395
502
|
envName: options.envName,
|
|
396
503
|
flags: {
|
|
397
504
|
file: archive.archivePath,
|
|
398
|
-
app:
|
|
399
|
-
portal:
|
|
505
|
+
app: sourceContext.app,
|
|
506
|
+
portal: sourceContext.portal,
|
|
400
507
|
message: options.message,
|
|
401
508
|
},
|
|
402
509
|
operation: PUSH_SOURCE_OPERATION,
|
|
@@ -405,7 +512,7 @@ export async function pushPortalSource(options) {
|
|
|
405
512
|
throw new Error(portalSourceText('errors.pushFailed', { status: response.status, details: JSON.stringify(response.data, null, 2) }, `Portal source push failed with status ${response.status}\n${JSON.stringify(response.data, null, 2)}`));
|
|
406
513
|
}
|
|
407
514
|
return {
|
|
408
|
-
...
|
|
515
|
+
...sourceContext,
|
|
409
516
|
changed: true,
|
|
410
517
|
sourceRevision: readSourceRevision(response.data),
|
|
411
518
|
};
|
package/dist/lib/proxy-caddy.js
CHANGED
|
@@ -79,6 +79,7 @@ export async function writeCaddyProxyBundle(runtime, appEntryOptions, runtimeCon
|
|
|
79
79
|
writeFile(bundle.appConfigPath, nextAppConfigContent, 'utf8'),
|
|
80
80
|
writeFile(bundle.indexV1Path, bundle.indexV1Content, 'utf8'),
|
|
81
81
|
writeFile(bundle.indexV2Path, bundle.indexV2Content, 'utf8'),
|
|
82
|
+
writeFile(bundle.indexSettingsPath, bundle.indexSettingsContent, 'utf8'),
|
|
82
83
|
writeFile(bundle.mainConfigPath, bundle.mainConfigContent, 'utf8'),
|
|
83
84
|
]);
|
|
84
85
|
return {
|
|
@@ -100,6 +101,7 @@ export async function writeManualCaddyProxyBundle(input, appEntryOptions, runtim
|
|
|
100
101
|
writeFile(bundle.appConfigPath, nextAppConfigContent, 'utf8'),
|
|
101
102
|
writeFile(bundle.indexV1Path, bundle.indexV1Content, 'utf8'),
|
|
102
103
|
writeFile(bundle.indexV2Path, bundle.indexV2Content, 'utf8'),
|
|
104
|
+
writeFile(bundle.indexSettingsPath, bundle.indexSettingsContent, 'utf8'),
|
|
103
105
|
writeFile(bundle.mainConfigPath, bundle.mainConfigContent, 'utf8'),
|
|
104
106
|
]);
|
|
105
107
|
return {
|
package/dist/lib/proxy-nginx.js
CHANGED
|
@@ -107,6 +107,7 @@ async function writeResolvedNginxProxyBundle(bundle, appEntryOptions, options) {
|
|
|
107
107
|
writeFile(bundle.appConfigPath, nextAppConfigContent, 'utf8'),
|
|
108
108
|
writeFile(bundle.indexV1Path, bundle.indexV1Content, 'utf8'),
|
|
109
109
|
writeFile(bundle.indexV2Path, bundle.indexV2Content, 'utf8'),
|
|
110
|
+
writeFile(bundle.indexSettingsPath, bundle.indexSettingsContent, 'utf8'),
|
|
110
111
|
writeFile(bundle.mainConfigPath, bundle.mainConfigContent, 'utf8'),
|
|
111
112
|
syncEnvProxyNginxSnippets(),
|
|
112
113
|
]);
|
package/dist/locale/en-US.json
CHANGED
|
@@ -175,33 +175,57 @@
|
|
|
175
175
|
"templateInvalidDirectory": "Portal template \"{{source}}\" is invalid: expected a directory.",
|
|
176
176
|
"localTemplateMissing": "Portal template directory does not exist: {{source}}",
|
|
177
177
|
"templateUnresolved": "Portal template \"{{source}}\" could not be resolved. {{details}}",
|
|
178
|
-
"templateDownloadFailed": "Failed to download
|
|
179
|
-
"templateExtractFailed": "Failed to extract
|
|
178
|
+
"templateDownloadFailed": "Failed to download portal template \"{{source}}\" with npm pack. {{details}}",
|
|
179
|
+
"templateExtractFailed": "Failed to extract portal template \"{{source}}\": {{details}}",
|
|
180
180
|
"templateMissingPackageJson": "Portal template \"{{source}}\" is invalid: package.json is missing.",
|
|
181
181
|
"npmPackNoTarball": "npm pack did not produce a local tarball for {{source}}.",
|
|
182
182
|
"npmPackMultipleTarballs": "npm pack produced multiple tarballs for {{source}}.",
|
|
183
|
-
"invalidPortalName": "Invalid
|
|
184
|
-
"invalidPortalAppName": "Invalid
|
|
185
|
-
"missingApiBaseUrl": "Cannot create a
|
|
186
|
-
"outsideParent": "Refusing to modify a
|
|
187
|
-
"sshUnsupported": "Cannot create a
|
|
188
|
-
"workspaceExists": "Portal
|
|
183
|
+
"invalidPortalName": "Invalid portal name \"{{value}}\". Use lowercase letters, numbers, underscores, or hyphens, and start with a lowercase letter or number.",
|
|
184
|
+
"invalidPortalAppName": "Invalid portal app name \"{{value}}\" from apiBaseUrl. Use letters, numbers, underscores, or hyphens, and start with a letter or number.",
|
|
185
|
+
"missingApiBaseUrl": "Cannot create a portal because the selected env has no apiBaseUrl.",
|
|
186
|
+
"outsideParent": "Refusing to modify a portal outside {{parentDir}}: {{portalDir}}",
|
|
187
|
+
"sshUnsupported": "Cannot create a portal for ssh envs in the first version.",
|
|
188
|
+
"workspaceExists": "Portal already exists: {{portalDir}}\nPass --force to delete it and create a new portal."
|
|
189
189
|
},
|
|
190
190
|
"messages": {
|
|
191
191
|
"skipInstall": "Skipped pnpm install because package.json was not found in {{portalDir}}.",
|
|
192
192
|
"created": "Portal \"{{portal}}\" created at {{portalDir}}.",
|
|
193
193
|
"app": "App: {{app}}",
|
|
194
|
-
"base": "Base: {{base}}"
|
|
194
|
+
"base": "Base: {{base}}",
|
|
195
|
+
"sourceStorage": "Source storage: {{sourceStorage}}"
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
"portalConfig": {
|
|
199
|
+
"errors": {
|
|
200
|
+
"invalidSourceStorage": "Invalid source storage \"{{value}}\". Use \"nocobase\" or \"git\".",
|
|
201
|
+
"invalidGitPath": "--git-path must be a relative path inside the Git repository.",
|
|
202
|
+
"gitOptionsForNocobaseStorage": "--git-repo, --git-branch, and --git-path can only be used with --source-storage git.",
|
|
203
|
+
"gitRepoRequired": "--git-repo is required when --source-storage is git.",
|
|
204
|
+
"gitRepoInvalid": "--git-repo must be a full Git remote URL.",
|
|
205
|
+
"updateFailed": "Portal config update failed with status {{status}}\n{{details}}"
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
"portalConfigure": {
|
|
209
|
+
"errors": {
|
|
210
|
+
"envNotConfigured": "Env \"{{envName}}\" is not configured. Run `nb env add {{envName}} --api-base-url <url>` first.",
|
|
211
|
+
"noEnvConfigured": "No NocoBase env is configured yet. Run `nb init --ui` to create one first.",
|
|
212
|
+
"noChanges": "No portal configuration changes were provided. Pass --source-storage or a --git-* flag.",
|
|
213
|
+
"workspaceMissing": "Portal does not exist: {{portalDir}}\nRun `nb portal create {{portal}}` or `nb portal pull {{portal}}` first."
|
|
214
|
+
},
|
|
215
|
+
"messages": {
|
|
216
|
+
"updated": "Portal \"{{portal}}\" configuration updated at {{portalDir}}/portal.config.json.",
|
|
217
|
+
"remoteSynced": "Remote portal record: synced",
|
|
218
|
+
"remoteSkipped": "Remote portal record: not found; local config only"
|
|
195
219
|
}
|
|
196
220
|
},
|
|
197
221
|
"portalDeploy": {
|
|
198
222
|
"errors": {
|
|
199
223
|
"envNotConfigured": "Env \"{{envName}}\" is not configured. Run `nb env add {{envName}} --api-base-url <url>` first.",
|
|
200
224
|
"noEnvConfigured": "No NocoBase env is configured yet. Run `nb init --ui` to create one first.",
|
|
201
|
-
"workspaceMissing": "Portal
|
|
202
|
-
"packageJsonMissing": "Portal
|
|
225
|
+
"workspaceMissing": "Portal does not exist: {{portalDir}}\nRun `nb portal create {{portal}}` first.",
|
|
226
|
+
"packageJsonMissing": "Portal is invalid: package.json is missing in {{portalDir}}.",
|
|
203
227
|
"distMissing": "Portal build did not produce {{distDir}}/index.html.",
|
|
204
|
-
"unsupportedEnvKind": "Cannot deploy a
|
|
228
|
+
"unsupportedEnvKind": "Cannot deploy a portal for {{kind}} envs in the first version.",
|
|
205
229
|
"uploadFailed": "Portal dist upload failed with status {{status}}\n{{details}}",
|
|
206
230
|
"recordSyncFailed": "Portal record sync failed with status {{status}}\n{{details}}"
|
|
207
231
|
},
|
|
@@ -220,16 +244,16 @@
|
|
|
220
244
|
"errors": {
|
|
221
245
|
"envNotConfigured": "Env \"{{envName}}\" is not configured. Run `nb env add {{envName}} --api-base-url <url>` first.",
|
|
222
246
|
"noEnvConfigured": "No NocoBase env is configured yet. Run `nb init --ui` to create one first.",
|
|
223
|
-
"unsupportedEnvKind": "Cannot list
|
|
247
|
+
"unsupportedEnvKind": "Cannot list portals for {{kind}} envs in the first version.",
|
|
224
248
|
"listFailed": "Portal list failed with status {{status}}\n{{details}}"
|
|
225
249
|
},
|
|
226
250
|
"messages": {
|
|
227
|
-
"empty": "No
|
|
251
|
+
"empty": "No portal records found."
|
|
228
252
|
},
|
|
229
253
|
"table": {
|
|
230
254
|
"name": "Name",
|
|
231
255
|
"url": "URL",
|
|
232
|
-
"
|
|
256
|
+
"portalType": "Portal type",
|
|
233
257
|
"path": "Local path",
|
|
234
258
|
"enabled": "Enabled",
|
|
235
259
|
"localSynced": "Local synced"
|
|
@@ -244,7 +268,7 @@
|
|
|
244
268
|
"fields": {
|
|
245
269
|
"name": "Name",
|
|
246
270
|
"url": "URL",
|
|
247
|
-
"
|
|
271
|
+
"portalType": "Portal type",
|
|
248
272
|
"path": "Local path",
|
|
249
273
|
"enabled": "Enabled",
|
|
250
274
|
"localSynced": "Local synced"
|
|
@@ -254,14 +278,14 @@
|
|
|
254
278
|
"errors": {
|
|
255
279
|
"envNotConfigured": "Env \"{{envName}}\" is not configured. Run `nb env add {{envName}} --api-base-url <url>` first.",
|
|
256
280
|
"noEnvConfigured": "No NocoBase env is configured yet. Run `nb init --ui` to create one first.",
|
|
257
|
-
"confirmationRequired": "Refusing to destroy a
|
|
258
|
-
"outsideParent": "Refusing to delete a
|
|
259
|
-
"workspaceMissing": "Portal
|
|
260
|
-
"unsupportedEnvKind": "Cannot destroy a
|
|
281
|
+
"confirmationRequired": "Refusing to destroy a portal in non-interactive mode without --yes.",
|
|
282
|
+
"outsideParent": "Refusing to delete a portal outside {{parentDir}}: {{portalDir}}",
|
|
283
|
+
"workspaceMissing": "Portal does not exist: {{portalDir}}\nPass --force to ignore missing local files.",
|
|
284
|
+
"unsupportedEnvKind": "Cannot destroy a portal for {{kind}} envs in the first version.",
|
|
261
285
|
"recordDestroyFailed": "Portal record destroy failed with status {{status}}\n{{details}}"
|
|
262
286
|
},
|
|
263
287
|
"prompts": {
|
|
264
|
-
"confirm": "Destroy
|
|
288
|
+
"confirm": "Destroy portal \"{{portal}}\" and delete its storage directory?"
|
|
265
289
|
},
|
|
266
290
|
"messages": {
|
|
267
291
|
"destroyed": "Portal \"{{portal}}\" destroyed.",
|
|
@@ -269,19 +293,19 @@
|
|
|
269
293
|
"app": "App: {{app}}",
|
|
270
294
|
"base": "Base: {{base}}",
|
|
271
295
|
"record": "Record: {{status}}",
|
|
272
|
-
"workspace": "
|
|
296
|
+
"workspace": "Portal files: {{status}} ({{dir}})"
|
|
273
297
|
}
|
|
274
298
|
},
|
|
275
299
|
"portalDev": {
|
|
276
300
|
"errors": {
|
|
277
301
|
"envNotConfigured": "Env \"{{envName}}\" is not configured. Run `nb env add {{envName}} --api-base-url <url>` first.",
|
|
278
302
|
"noEnvConfigured": "No NocoBase env is configured yet. Run `nb init --ui` to create one first.",
|
|
279
|
-
"workspaceMissing": "Portal
|
|
280
|
-
"packageJsonMissing": "Portal
|
|
281
|
-
"sshUnsupported": "Cannot start a
|
|
303
|
+
"workspaceMissing": "Portal does not exist: {{portalDir}}\nRun `nb portal create {{portal}}` first.",
|
|
304
|
+
"packageJsonMissing": "Portal is invalid: package.json is missing in {{portalDir}}.",
|
|
305
|
+
"sshUnsupported": "Cannot start a portal in dev mode for ssh envs in the first version."
|
|
282
306
|
},
|
|
283
307
|
"messages": {
|
|
284
|
-
"starting": "Starting
|
|
308
|
+
"starting": "Starting portal \"{{portal}}\"...",
|
|
285
309
|
"mode": "Mode: {{mode}}",
|
|
286
310
|
"app": "App: {{app}}",
|
|
287
311
|
"base": "Base: {{base}}",
|
|
@@ -461,15 +485,15 @@
|
|
|
461
485
|
"message": "App subpath (for example, /nocobase/)",
|
|
462
486
|
"placeholder": "/ or /nocobase/"
|
|
463
487
|
},
|
|
464
|
-
"
|
|
465
|
-
"message": "
|
|
466
|
-
"noCodeLabel": "
|
|
467
|
-
"noCodeHint": "
|
|
468
|
-
"
|
|
469
|
-
"
|
|
488
|
+
"portalType": {
|
|
489
|
+
"message": "Portal type",
|
|
490
|
+
"noCodeLabel": "No-code portal",
|
|
491
|
+
"noCodeHint": "Create with visual configuration. AI can help adjust the configuration. Path: /v/<name>",
|
|
492
|
+
"aiLabel": "AI portal",
|
|
493
|
+
"aiHint": "Create with AI Agent and code. Users can request changes in natural language. Path: /x/<name>"
|
|
470
494
|
},
|
|
471
495
|
"portalName": {
|
|
472
|
-
"message": "
|
|
496
|
+
"message": "Portal name",
|
|
473
497
|
"placeholder": "admin"
|
|
474
498
|
},
|
|
475
499
|
"portalTemplate": {
|
|
@@ -576,15 +600,15 @@
|
|
|
576
600
|
"skipDownload": {
|
|
577
601
|
"message": "Skip downloading NocoBase and reuse existing local app files or Docker images"
|
|
578
602
|
},
|
|
579
|
-
"
|
|
580
|
-
"message": "
|
|
581
|
-
"noCodeLabel": "
|
|
582
|
-
"noCodeHint": "
|
|
583
|
-
"
|
|
584
|
-
"
|
|
603
|
+
"portalType": {
|
|
604
|
+
"message": "Portal type",
|
|
605
|
+
"noCodeLabel": "No-code portal",
|
|
606
|
+
"noCodeHint": "Create with visual configuration. AI can help adjust the configuration. Path: /v/<name>",
|
|
607
|
+
"aiLabel": "AI portal",
|
|
608
|
+
"aiHint": "Create with AI Agent and code. Users can request changes in natural language. Path: /x/<name>"
|
|
585
609
|
},
|
|
586
610
|
"portalName": {
|
|
587
|
-
"message": "
|
|
611
|
+
"message": "Portal name",
|
|
588
612
|
"placeholder": "admin"
|
|
589
613
|
},
|
|
590
614
|
"portalTemplate": {
|
|
@@ -612,9 +636,9 @@
|
|
|
612
636
|
"title": "App source and version",
|
|
613
637
|
"description": "Choose how to get the app and which source and version to use."
|
|
614
638
|
},
|
|
615
|
-
"
|
|
616
|
-
"title": "
|
|
617
|
-
"description": "
|
|
639
|
+
"portalType": {
|
|
640
|
+
"title": "Configure portal",
|
|
641
|
+
"description": "Set the default portal name and type."
|
|
618
642
|
},
|
|
619
643
|
"configureDatabase": {
|
|
620
644
|
"title": "Configure the database",
|