directus-template-cli 0.5.0-beta.7 → 0.5.0-beta.8
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/apply.d.ts +16 -15
- package/dist/commands/apply.js +41 -12
- package/dist/commands/extract.js +4 -4
- package/dist/lib/constants.d.ts +3 -0
- package/dist/lib/constants.js +6 -0
- package/dist/lib/load/load-access.js +2 -4
- package/dist/lib/load/load-collections.js +43 -17
- package/dist/lib/load/load-dashboards.js +3 -5
- package/dist/lib/load/load-data.js +45 -9
- package/dist/lib/load/load-extensions.js +49 -46
- package/dist/lib/load/load-files.js +2 -5
- package/dist/lib/load/load-flows.d.ts +1 -1
- package/dist/lib/load/load-flows.js +47 -42
- package/dist/lib/load/load-folders.js +3 -5
- package/dist/lib/load/load-permissions.js +2 -6
- package/dist/lib/load/load-policies.js +3 -3
- package/dist/lib/load/load-presets.js +3 -4
- package/dist/lib/load/load-relations.js +2 -3
- package/dist/lib/load/load-roles.js +2 -4
- package/dist/lib/load/load-settings.js +39 -2
- package/dist/lib/load/load-translations.js +3 -5
- package/dist/lib/load/load-users.js +14 -7
- package/dist/lib/utils/auth.js +1 -1
- package/dist/lib/utils/catch-error.js +2 -2
- package/dist/lib/utils/get-template.d.ts +1 -0
- package/dist/lib/utils/get-template.js +42 -1
- package/dist/lib/utils/read-templates.js +4 -2
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
package/dist/commands/apply.d.ts
CHANGED
|
@@ -3,26 +3,27 @@ export default class ApplyCommand extends Command {
|
|
|
3
3
|
static description: string;
|
|
4
4
|
static examples: string[];
|
|
5
5
|
static flags: {
|
|
6
|
-
content: import("@oclif/core/lib/interfaces
|
|
7
|
-
dashboards: import("@oclif/core/lib/interfaces
|
|
8
|
-
directusToken: import("@oclif/core/lib/interfaces
|
|
9
|
-
directusUrl: import("@oclif/core/lib/interfaces
|
|
10
|
-
extensions: import("@oclif/core/lib/interfaces
|
|
11
|
-
files: import("@oclif/core/lib/interfaces
|
|
12
|
-
flows: import("@oclif/core/lib/interfaces
|
|
13
|
-
partial: import("@oclif/core/lib/interfaces
|
|
14
|
-
permissions: import("@oclif/core/lib/interfaces
|
|
15
|
-
programmatic: import("@oclif/core/lib/interfaces
|
|
16
|
-
schema: import("@oclif/core/lib/interfaces
|
|
17
|
-
settings: import("@oclif/core/lib/interfaces
|
|
18
|
-
templateLocation: import("@oclif/core/lib/interfaces
|
|
19
|
-
templateType: import("@oclif/core/lib/interfaces
|
|
20
|
-
users: import("@oclif/core/lib/interfaces
|
|
6
|
+
content: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
7
|
+
dashboards: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
directusToken: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
9
|
+
directusUrl: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
10
|
+
extensions: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
11
|
+
files: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
12
|
+
flows: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
partial: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
14
|
+
permissions: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
15
|
+
programmatic: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
16
|
+
schema: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
17
|
+
settings: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
18
|
+
templateLocation: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
19
|
+
templateType: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
20
|
+
users: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
21
21
|
};
|
|
22
22
|
run(): Promise<void>;
|
|
23
23
|
private initializeDirectusApi;
|
|
24
24
|
private redirectToDirectusPlus;
|
|
25
25
|
private runInteractive;
|
|
26
26
|
private runProgrammatic;
|
|
27
|
+
private selectLocalTemplate;
|
|
27
28
|
private validateFlags;
|
|
28
29
|
}
|
package/dist/commands/apply.js
CHANGED
|
@@ -4,13 +4,14 @@ const tslib_1 = require("tslib");
|
|
|
4
4
|
const sdk_1 = require("@directus/sdk");
|
|
5
5
|
const core_1 = require("@oclif/core");
|
|
6
6
|
const inquirer = tslib_1.__importStar(require("inquirer"));
|
|
7
|
+
const constants_1 = require("../lib/constants");
|
|
7
8
|
const index_js_1 = tslib_1.__importDefault(require("../lib/load/index.js"));
|
|
8
9
|
const sdk_2 = require("../lib/sdk");
|
|
9
10
|
const auth_1 = require("../lib/utils/auth");
|
|
10
11
|
const catch_error_1 = tslib_1.__importDefault(require("../lib/utils/catch-error"));
|
|
11
12
|
const get_template_1 = require("../lib/utils/get-template");
|
|
13
|
+
const logger_1 = require("../lib/utils/logger");
|
|
12
14
|
const open_url_1 = tslib_1.__importDefault(require("../lib/utils/open-url"));
|
|
13
|
-
const separator = '------------------';
|
|
14
15
|
class ApplyCommand extends core_1.Command {
|
|
15
16
|
// MAIN FUNCTION
|
|
16
17
|
async run() {
|
|
@@ -23,10 +24,10 @@ class ApplyCommand extends core_1.Command {
|
|
|
23
24
|
try {
|
|
24
25
|
sdk_2.api.setAuthToken(flags.directusToken);
|
|
25
26
|
const response = await sdk_2.api.client.request((0, sdk_1.readMe)());
|
|
26
|
-
core_1.ux.log(
|
|
27
|
+
core_1.ux.log(`-- Logged in as ${response.first_name} ${response.last_name}`);
|
|
27
28
|
}
|
|
28
29
|
catch {
|
|
29
|
-
(0, catch_error_1.default)('Invalid Directus token. Please check your credentials.', {
|
|
30
|
+
(0, catch_error_1.default)('-- Invalid Directus token. Please check your credentials.', {
|
|
30
31
|
fatal: true,
|
|
31
32
|
});
|
|
32
33
|
}
|
|
@@ -38,6 +39,7 @@ class ApplyCommand extends core_1.Command {
|
|
|
38
39
|
}
|
|
39
40
|
async runInteractive(flags) {
|
|
40
41
|
const validatedFlags = this.validateFlags(flags);
|
|
42
|
+
core_1.ux.styledHeader(core_1.ux.colorize(constants_1.DIRECTUS_PURPLE, 'Welcome to the Directus Template CLI'));
|
|
41
43
|
const templateType = await inquirer.prompt([
|
|
42
44
|
{
|
|
43
45
|
choices: [
|
|
@@ -68,7 +70,7 @@ class ApplyCommand extends core_1.Command {
|
|
|
68
70
|
}
|
|
69
71
|
case 'local': {
|
|
70
72
|
const localTemplateDir = await core_1.ux.prompt('What is the local template directory?');
|
|
71
|
-
template = await
|
|
73
|
+
template = await this.selectLocalTemplate(localTemplateDir);
|
|
72
74
|
break;
|
|
73
75
|
}
|
|
74
76
|
case 'github': {
|
|
@@ -80,19 +82,19 @@ class ApplyCommand extends core_1.Command {
|
|
|
80
82
|
this.redirectToDirectusPlus();
|
|
81
83
|
}
|
|
82
84
|
}
|
|
83
|
-
core_1.ux.log(`You selected ${template.templateName}`);
|
|
84
|
-
core_1.ux.log(
|
|
85
|
+
core_1.ux.log(`You selected ${core_1.ux.colorize(constants_1.DIRECTUS_PINK, template.templateName)}`);
|
|
86
|
+
core_1.ux.log(constants_1.SEPARATOR);
|
|
85
87
|
// Get Directus URL and token
|
|
86
88
|
const directusUrl = await (0, auth_1.getDirectusUrl)();
|
|
87
89
|
const directusToken = await (0, auth_1.getDirectusToken)(directusUrl);
|
|
88
90
|
flags.directusUrl = directusUrl;
|
|
89
91
|
flags.directusToken = directusToken;
|
|
90
92
|
if (template) {
|
|
91
|
-
core_1.ux.
|
|
93
|
+
core_1.ux.styledHeader(core_1.ux.colorize(constants_1.DIRECTUS_PURPLE, `Applying template - ${template.templateName} to ${directusUrl}`));
|
|
92
94
|
await (0, index_js_1.default)(template.directoryPath, validatedFlags);
|
|
93
95
|
core_1.ux.action.stop();
|
|
94
|
-
core_1.ux.log(
|
|
95
|
-
core_1.ux.
|
|
96
|
+
core_1.ux.log(constants_1.SEPARATOR);
|
|
97
|
+
core_1.ux.info('Template applied successfully.');
|
|
96
98
|
core_1.ux.exit(0);
|
|
97
99
|
}
|
|
98
100
|
}
|
|
@@ -120,13 +122,40 @@ class ApplyCommand extends core_1.Command {
|
|
|
120
122
|
}
|
|
121
123
|
}
|
|
122
124
|
await this.initializeDirectusApi(validatedFlags);
|
|
123
|
-
|
|
125
|
+
const logMessage = `Applying template - ${template.templateName} to ${validatedFlags.directusUrl}`;
|
|
126
|
+
core_1.ux.styledHeader(logMessage);
|
|
127
|
+
logger_1.logger.log('info', logMessage);
|
|
124
128
|
await (0, index_js_1.default)(template.directoryPath, validatedFlags);
|
|
125
129
|
core_1.ux.action.stop();
|
|
126
|
-
core_1.ux.log(
|
|
127
|
-
core_1.ux.
|
|
130
|
+
core_1.ux.log(constants_1.SEPARATOR);
|
|
131
|
+
core_1.ux.info('Template applied successfully.');
|
|
128
132
|
core_1.ux.exit(0);
|
|
129
133
|
}
|
|
134
|
+
async selectLocalTemplate(localTemplateDir) {
|
|
135
|
+
try {
|
|
136
|
+
const templates = await (0, get_template_1.getInteractiveLocalTemplate)(localTemplateDir);
|
|
137
|
+
if (templates.length === 1) {
|
|
138
|
+
return templates[0];
|
|
139
|
+
}
|
|
140
|
+
const { selectedTemplate } = await inquirer.prompt([
|
|
141
|
+
{
|
|
142
|
+
choices: templates.map(t => ({ name: `${t.templateName} (${core_1.ux.colorize('dim', t.directoryPath)})`, value: t })),
|
|
143
|
+
message: 'Multiple templates found. Please select one:',
|
|
144
|
+
name: 'selectedTemplate',
|
|
145
|
+
type: 'list',
|
|
146
|
+
},
|
|
147
|
+
]);
|
|
148
|
+
return selectedTemplate;
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
if (error instanceof Error) {
|
|
152
|
+
core_1.ux.error(error.message);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
core_1.ux.error('An unknown error occurred while getting the local template.');
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
130
159
|
validateFlags(flags) {
|
|
131
160
|
if (flags.programmatic) {
|
|
132
161
|
if (!flags.directusUrl || !flags.directusToken) {
|
package/dist/commands/extract.js
CHANGED
|
@@ -6,12 +6,12 @@ const core_1 = require("@oclif/core");
|
|
|
6
6
|
const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
|
|
7
7
|
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
8
8
|
const slugify_1 = tslib_1.__importDefault(require("slugify"));
|
|
9
|
+
const constants_1 = require("../lib/constants");
|
|
9
10
|
const extract_1 = tslib_1.__importDefault(require("../lib/extract/"));
|
|
10
11
|
const sdk_2 = require("../lib/sdk");
|
|
11
12
|
const auth_1 = require("../lib/utils/auth");
|
|
12
13
|
const catch_error_1 = tslib_1.__importDefault(require("../lib/utils/catch-error"));
|
|
13
14
|
const template_defaults_1 = require("../lib/utils/template-defaults");
|
|
14
|
-
const separator = '------------------';
|
|
15
15
|
class ExtractCommand extends core_1.Command {
|
|
16
16
|
async run() {
|
|
17
17
|
const { flags } = await this.parse(ExtractCommand);
|
|
@@ -33,11 +33,11 @@ class ExtractCommand extends core_1.Command {
|
|
|
33
33
|
catch (error) {
|
|
34
34
|
core_1.ux.error(`Failed to create directory or write files: ${error.message}`);
|
|
35
35
|
}
|
|
36
|
-
core_1.ux.log(
|
|
36
|
+
core_1.ux.log(constants_1.SEPARATOR);
|
|
37
37
|
core_1.ux.action.start(`Extracting template - from ${flags.directusUrl} to ${directory}`);
|
|
38
38
|
await (0, extract_1.default)(directory);
|
|
39
39
|
core_1.ux.action.stop();
|
|
40
|
-
core_1.ux.log(
|
|
40
|
+
core_1.ux.log(constants_1.SEPARATOR);
|
|
41
41
|
core_1.ux.log('Template extracted successfully.');
|
|
42
42
|
this.exit(0);
|
|
43
43
|
}
|
|
@@ -46,7 +46,7 @@ class ExtractCommand extends core_1.Command {
|
|
|
46
46
|
try {
|
|
47
47
|
sdk_2.api.setAuthToken(flags.directusToken);
|
|
48
48
|
const response = await sdk_2.api.client.request((0, sdk_1.readMe)());
|
|
49
|
-
core_1.ux.log(
|
|
49
|
+
core_1.ux.log(`-- Logged in as ${response.first_name} ${response.last_name}`);
|
|
50
50
|
}
|
|
51
51
|
catch {
|
|
52
52
|
(0, catch_error_1.default)('Invalid Directus token. Please check your credentials.', {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SEPARATOR = exports.DIRECTUS_PINK = exports.DIRECTUS_PURPLE = void 0;
|
|
4
|
+
exports.DIRECTUS_PURPLE = '#6644ff';
|
|
5
|
+
exports.DIRECTUS_PINK = '#FF99DD';
|
|
6
|
+
exports.SEPARATOR = '------------------';
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const core_1 = require("@oclif/core");
|
|
5
|
+
const constants_1 = require("../constants");
|
|
5
6
|
const sdk_1 = require("../sdk");
|
|
6
7
|
const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
|
|
7
8
|
const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
8
9
|
async function loadAccess(dir) {
|
|
9
10
|
const access = (0, read_file_1.default)('access', dir);
|
|
10
|
-
core_1.ux.action.start(`Loading ${access.length} accesses`);
|
|
11
|
+
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${access.length} accesses`));
|
|
11
12
|
// Fetch existing accesses
|
|
12
13
|
const existingAccesses = await sdk_1.api.client.request(() => ({
|
|
13
14
|
method: 'GET',
|
|
@@ -21,12 +22,10 @@ async function loadAccess(dir) {
|
|
|
21
22
|
for await (const acc of access) {
|
|
22
23
|
try {
|
|
23
24
|
if (existingAccessById.has(acc.id)) {
|
|
24
|
-
core_1.ux.log(`Skipping existing access with ID: ${acc.id}`);
|
|
25
25
|
continue;
|
|
26
26
|
}
|
|
27
27
|
const compositeKey = getCompositeKey(acc);
|
|
28
28
|
if (existingAccessByCompositeKey.has(compositeKey)) {
|
|
29
|
-
core_1.ux.log(`Skipping existing access with composite key: ${compositeKey}`);
|
|
30
29
|
continue;
|
|
31
30
|
}
|
|
32
31
|
// If the role is null, delete the role key to avoid errors
|
|
@@ -52,7 +51,6 @@ async function loadAccess(dir) {
|
|
|
52
51
|
}
|
|
53
52
|
}
|
|
54
53
|
core_1.ux.action.stop();
|
|
55
|
-
core_1.ux.log('Loaded Accesses');
|
|
56
54
|
}
|
|
57
55
|
exports.default = loadAccess;
|
|
58
56
|
// Helper function to generate a composite key for each access
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const sdk_1 = require("@directus/sdk");
|
|
5
5
|
const core_1 = require("@oclif/core");
|
|
6
|
+
const constants_1 = require("../constants");
|
|
6
7
|
const sdk_2 = require("../sdk");
|
|
7
8
|
const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
|
|
8
9
|
const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
@@ -10,32 +11,53 @@ const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
|
10
11
|
* Load collections into the Directus instance
|
|
11
12
|
*/
|
|
12
13
|
async function loadCollections(dir) {
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
core_1.ux.action.start(`Loading ${
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return col;
|
|
20
|
-
});
|
|
21
|
-
await addCollections(removedGroupKey, fields);
|
|
22
|
-
await updateCollections(collections);
|
|
23
|
-
await addCustomFieldsOnSystemCollections(fields);
|
|
14
|
+
const collectionsToAdd = (0, read_file_1.default)('collections', dir);
|
|
15
|
+
const fieldsToAdd = (0, read_file_1.default)('fields', dir);
|
|
16
|
+
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${collectionsToAdd.length} collections and ${fieldsToAdd.length} fields`));
|
|
17
|
+
await processCollections(collectionsToAdd, fieldsToAdd);
|
|
18
|
+
await updateCollections(collectionsToAdd);
|
|
19
|
+
await addCustomFieldsOnSystemCollections(fieldsToAdd);
|
|
24
20
|
core_1.ux.action.stop();
|
|
25
|
-
core_1.ux.log('Loaded collections and fields.');
|
|
26
21
|
}
|
|
27
22
|
exports.default = loadCollections;
|
|
28
|
-
async function
|
|
29
|
-
|
|
23
|
+
async function processCollections(collectionsToAdd, fieldsToAdd) {
|
|
24
|
+
const existingCollections = await sdk_2.api.client.request((0, sdk_1.readCollections)());
|
|
25
|
+
const existingFields = await sdk_2.api.client.request((0, sdk_1.readFields)());
|
|
26
|
+
for await (const collection of collectionsToAdd) {
|
|
30
27
|
try {
|
|
31
|
-
|
|
32
|
-
await
|
|
28
|
+
const existingCollection = existingCollections.find((c) => c.collection === collection.collection);
|
|
29
|
+
await (existingCollection ? addNewFieldsToExistingCollection(collection.collection, fieldsToAdd, existingFields) : addNewCollectionWithFields(collection, fieldsToAdd));
|
|
33
30
|
}
|
|
34
31
|
catch (error) {
|
|
35
32
|
(0, catch_error_1.default)(error);
|
|
36
33
|
}
|
|
37
34
|
}
|
|
38
35
|
}
|
|
36
|
+
async function addNewCollectionWithFields(collection, allFields) {
|
|
37
|
+
const collectionFields = allFields.filter(field => field.collection === collection.collection);
|
|
38
|
+
const collectionWithoutGroup = {
|
|
39
|
+
...collection,
|
|
40
|
+
fields: collectionFields,
|
|
41
|
+
meta: { ...collection.meta },
|
|
42
|
+
};
|
|
43
|
+
delete collectionWithoutGroup.meta.group;
|
|
44
|
+
await sdk_2.api.client.request((0, sdk_1.createCollection)(collectionWithoutGroup));
|
|
45
|
+
}
|
|
46
|
+
async function addNewFieldsToExistingCollection(collectionName, fieldsToAdd, existingFields) {
|
|
47
|
+
const collectionFieldsToAdd = fieldsToAdd.filter(field => field.collection === collectionName);
|
|
48
|
+
const existingCollectionFields = existingFields.filter((field) => field.collection === collectionName);
|
|
49
|
+
for await (const field of collectionFieldsToAdd) {
|
|
50
|
+
if (!existingCollectionFields.some((existingField) => existingField.field === field.field)) {
|
|
51
|
+
try {
|
|
52
|
+
// @ts-ignore
|
|
53
|
+
await sdk_2.api.client.request((0, sdk_1.createField)(collectionName, field));
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
(0, catch_error_1.default)(error);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
39
61
|
async function updateCollections(collections) {
|
|
40
62
|
for await (const collection of collections) {
|
|
41
63
|
try {
|
|
@@ -55,9 +77,13 @@ async function updateCollections(collections) {
|
|
|
55
77
|
}
|
|
56
78
|
async function addCustomFieldsOnSystemCollections(fields) {
|
|
57
79
|
const customFields = fields.filter((field) => field.collection.startsWith('directus_'));
|
|
80
|
+
const existingFields = await sdk_2.api.client.request((0, sdk_1.readFields)());
|
|
58
81
|
for await (const field of customFields) {
|
|
59
82
|
try {
|
|
60
|
-
|
|
83
|
+
const fieldExists = existingFields.some((existingField) => existingField.collection === field.collection && existingField.field === field.field);
|
|
84
|
+
if (!fieldExists) {
|
|
85
|
+
await sdk_2.api.client.request((0, sdk_1.createField)(field.collection, field));
|
|
86
|
+
}
|
|
61
87
|
}
|
|
62
88
|
catch (error) {
|
|
63
89
|
(0, catch_error_1.default)(error);
|
|
@@ -4,12 +4,13 @@ exports.loadPanels = void 0;
|
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const sdk_1 = require("@directus/sdk");
|
|
6
6
|
const core_1 = require("@oclif/core");
|
|
7
|
+
const constants_1 = require("../constants");
|
|
7
8
|
const sdk_2 = require("../sdk");
|
|
8
9
|
const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
|
|
9
10
|
const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
10
11
|
async function loadDashboards(dir) {
|
|
11
12
|
const dashboards = (0, read_file_1.default)('dashboards', dir);
|
|
12
|
-
core_1.ux.action.start(`Loading ${dashboards.length} dashboards`);
|
|
13
|
+
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${dashboards.length} dashboards`));
|
|
13
14
|
// Fetch existing dashboards
|
|
14
15
|
const existingDashboards = await sdk_2.api.client.request((0, sdk_1.readDashboards)({
|
|
15
16
|
limit: -1,
|
|
@@ -17,7 +18,6 @@ async function loadDashboards(dir) {
|
|
|
17
18
|
const existingDashboardIds = new Set(existingDashboards.map(dashboard => dashboard.id));
|
|
18
19
|
const filteredDashboards = dashboards.filter(dashboard => {
|
|
19
20
|
if (existingDashboardIds.has(dashboard.id)) {
|
|
20
|
-
core_1.ux.log(`Skipping existing dashboard: ${dashboard.name}`);
|
|
21
21
|
return false;
|
|
22
22
|
}
|
|
23
23
|
return true;
|
|
@@ -36,12 +36,11 @@ async function loadDashboards(dir) {
|
|
|
36
36
|
}));
|
|
37
37
|
await loadPanels(dir);
|
|
38
38
|
core_1.ux.action.stop();
|
|
39
|
-
core_1.ux.log('Loaded dashboards');
|
|
40
39
|
}
|
|
41
40
|
exports.default = loadDashboards;
|
|
42
41
|
async function loadPanels(dir) {
|
|
43
42
|
const panels = (0, read_file_1.default)('panels', dir);
|
|
44
|
-
core_1.ux.
|
|
43
|
+
core_1.ux.action.status = `Loading ${panels.length} panels`;
|
|
45
44
|
// Fetch existing panels
|
|
46
45
|
const existingPanels = await sdk_2.api.client.request((0, sdk_1.readPanels)({
|
|
47
46
|
limit: -1,
|
|
@@ -49,7 +48,6 @@ async function loadPanels(dir) {
|
|
|
49
48
|
const existingPanelIds = new Set(existingPanels.map(panel => panel.id));
|
|
50
49
|
const filteredPanels = panels.filter(panel => {
|
|
51
50
|
if (existingPanelIds.has(panel.id)) {
|
|
52
|
-
core_1.ux.log(`Skipping existing panel: ${panel.id}`);
|
|
53
51
|
return false;
|
|
54
52
|
}
|
|
55
53
|
return true;
|
|
@@ -4,6 +4,7 @@ const tslib_1 = require("tslib");
|
|
|
4
4
|
const sdk_1 = require("@directus/sdk");
|
|
5
5
|
const core_1 = require("@oclif/core");
|
|
6
6
|
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
7
|
+
const constants_1 = require("../constants");
|
|
7
8
|
const sdk_2 = require("../sdk");
|
|
8
9
|
const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
|
|
9
10
|
const chunk_array_1 = require("../utils/chunk-array");
|
|
@@ -11,16 +12,15 @@ const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
|
11
12
|
const BATCH_SIZE = 50;
|
|
12
13
|
async function loadData(dir) {
|
|
13
14
|
const collections = (0, read_file_1.default)('collections', dir);
|
|
14
|
-
core_1.ux.action.start(`Loading data for ${collections.length} collections`);
|
|
15
|
+
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading data for ${collections.length} collections`));
|
|
15
16
|
await loadSkeletonRecords(dir);
|
|
16
17
|
await loadFullData(dir);
|
|
17
18
|
await loadSingletons(dir);
|
|
18
19
|
core_1.ux.action.stop();
|
|
19
|
-
core_1.ux.log('Loaded data.');
|
|
20
20
|
}
|
|
21
21
|
exports.default = loadData;
|
|
22
22
|
async function loadSkeletonRecords(dir) {
|
|
23
|
-
core_1.ux.
|
|
23
|
+
core_1.ux.action.status = 'Loading skeleton records';
|
|
24
24
|
const collections = (0, read_file_1.default)('collections', dir);
|
|
25
25
|
const primaryKeyMap = await getCollectionPrimaryKeys(dir);
|
|
26
26
|
const userCollections = collections
|
|
@@ -32,10 +32,46 @@ async function loadSkeletonRecords(dir) {
|
|
|
32
32
|
const primaryKeyField = getPrimaryKey(primaryKeyMap, name);
|
|
33
33
|
const sourceDir = node_path_1.default.resolve(dir, 'content');
|
|
34
34
|
const data = (0, read_file_1.default)(name, sourceDir);
|
|
35
|
-
|
|
35
|
+
// Fetch existing primary keys
|
|
36
|
+
const existingPrimaryKeys = await getExistingPrimaryKeys(name, primaryKeyField);
|
|
37
|
+
// Filter out existing records
|
|
38
|
+
const newData = data.filter(entry => !existingPrimaryKeys.has(entry[primaryKeyField]));
|
|
39
|
+
if (newData.length === 0) {
|
|
40
|
+
core_1.ux.log(`${core_1.ux.colorize('dim', '--')} Skipping ${name}: No new records to add`);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const batches = (0, chunk_array_1.chunkArray)(newData, BATCH_SIZE).map(batch => batch.map(entry => ({ [primaryKeyField]: entry[primaryKeyField] })));
|
|
36
44
|
await Promise.all(batches.map(batch => uploadBatch(name, batch, sdk_1.createItems)));
|
|
45
|
+
core_1.ux.log(`${core_1.ux.colorize('dim', '--')} Added ${newData.length} new skeleton records to ${name}`);
|
|
37
46
|
}));
|
|
38
|
-
core_1.ux.
|
|
47
|
+
core_1.ux.action.status = 'Loaded skeleton records';
|
|
48
|
+
}
|
|
49
|
+
async function getExistingPrimaryKeys(collection, primaryKeyField) {
|
|
50
|
+
const existingKeys = new Set();
|
|
51
|
+
let page = 1;
|
|
52
|
+
const limit = 1000; // Adjust based on your needs and API limits
|
|
53
|
+
while (true) {
|
|
54
|
+
try {
|
|
55
|
+
// @ts-expect-error string
|
|
56
|
+
const response = await sdk_2.api.client.request((0, sdk_1.readItems)(collection, {
|
|
57
|
+
fields: [primaryKeyField],
|
|
58
|
+
limit,
|
|
59
|
+
page,
|
|
60
|
+
}));
|
|
61
|
+
if (response.length === 0)
|
|
62
|
+
break;
|
|
63
|
+
for (const item of response)
|
|
64
|
+
existingKeys.add(item[primaryKeyField]);
|
|
65
|
+
if (response.length < limit)
|
|
66
|
+
break;
|
|
67
|
+
page++;
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
(0, catch_error_1.default)(error);
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return existingKeys;
|
|
39
75
|
}
|
|
40
76
|
async function uploadBatch(collection, batch, method) {
|
|
41
77
|
try {
|
|
@@ -46,7 +82,7 @@ async function uploadBatch(collection, batch, method) {
|
|
|
46
82
|
}
|
|
47
83
|
}
|
|
48
84
|
async function loadFullData(dir) {
|
|
49
|
-
core_1.ux.
|
|
85
|
+
core_1.ux.action.status = 'Updating records with full data';
|
|
50
86
|
const collections = (0, read_file_1.default)('collections', dir);
|
|
51
87
|
const userCollections = collections
|
|
52
88
|
.filter(item => !item.collection.startsWith('directus_', 0))
|
|
@@ -59,10 +95,10 @@ async function loadFullData(dir) {
|
|
|
59
95
|
const batches = (0, chunk_array_1.chunkArray)(data, BATCH_SIZE).map(batch => batch.map(({ user_created, user_updated, ...cleanedRow }) => cleanedRow));
|
|
60
96
|
await Promise.all(batches.map(batch => uploadBatch(name, batch, sdk_1.updateItemsBatch)));
|
|
61
97
|
}));
|
|
62
|
-
core_1.ux.
|
|
98
|
+
core_1.ux.action.status = 'Updated records with full data';
|
|
63
99
|
}
|
|
64
100
|
async function loadSingletons(dir) {
|
|
65
|
-
core_1.ux.
|
|
101
|
+
core_1.ux.action.status = 'Loading data for singleton collections';
|
|
66
102
|
const collections = (0, read_file_1.default)('collections', dir);
|
|
67
103
|
const singletonCollections = collections
|
|
68
104
|
.filter(item => !item.collection.startsWith('directus_', 0))
|
|
@@ -80,7 +116,7 @@ async function loadSingletons(dir) {
|
|
|
80
116
|
(0, catch_error_1.default)(error);
|
|
81
117
|
}
|
|
82
118
|
}));
|
|
83
|
-
core_1.ux.
|
|
119
|
+
core_1.ux.action.status = 'Loaded data for singleton collections';
|
|
84
120
|
}
|
|
85
121
|
async function getCollectionPrimaryKeys(dir) {
|
|
86
122
|
var _a;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const sdk_1 = require("@directus/sdk");
|
|
5
5
|
const core_1 = require("@oclif/core");
|
|
6
|
+
const constants_1 = require("../constants");
|
|
6
7
|
const sdk_2 = require("../sdk");
|
|
7
8
|
const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
|
|
8
9
|
const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
@@ -17,56 +18,58 @@ async function installExtension(extension) {
|
|
|
17
18
|
}));
|
|
18
19
|
}
|
|
19
20
|
async function loadExtensions(dir) {
|
|
20
|
-
core_1.ux.action.start('Loading extensions');
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
21
|
+
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, 'Loading extensions'));
|
|
22
|
+
try {
|
|
23
|
+
const extensions = (0, read_file_1.default)('extensions', dir);
|
|
24
|
+
if (extensions && extensions.length > 0) {
|
|
25
|
+
const installedExtensions = await sdk_2.api.client.request((0, sdk_1.readExtensions)());
|
|
26
|
+
const registryExtensions = extensions.filter(ext => { var _a; return ((_a = ext.meta) === null || _a === void 0 ? void 0 : _a.source) === 'registry' && !ext.bundle; });
|
|
27
|
+
const bundles = [...new Set(extensions.filter(ext => ext.bundle).map(ext => ext.bundle))];
|
|
28
|
+
const localExtensions = extensions.filter(ext => { var _a; return ((_a = ext.meta) === null || _a === void 0 ? void 0 : _a.source) === 'local'; });
|
|
29
|
+
const extensionsToInstall = extensions.filter(ext => {
|
|
30
|
+
var _a;
|
|
31
|
+
return ((_a = ext.meta) === null || _a === void 0 ? void 0 : _a.source) === 'registry'
|
|
32
|
+
&& !ext.bundle
|
|
33
|
+
// @ts-expect-error
|
|
34
|
+
&& !installedExtensions.some(installed => installed.id === ext.id);
|
|
35
|
+
});
|
|
36
|
+
core_1.ux.log(`Found ${extensions.length} extensions total: ${registryExtensions.length} registry extensions (including ${bundles.length} bundles), and ${localExtensions.length} local extensions`);
|
|
37
|
+
if (extensionsToInstall.length > 0) {
|
|
38
|
+
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Installing ${extensionsToInstall.length} extensions`));
|
|
39
|
+
const results = await Promise.allSettled(extensionsToInstall.map(async (ext) => {
|
|
40
|
+
var _a, _b, _c;
|
|
41
|
+
try {
|
|
42
|
+
await installExtension({
|
|
43
|
+
id: ext.id,
|
|
44
|
+
// The extension version UUID is the folder name
|
|
45
|
+
version: (_a = ext.meta) === null || _a === void 0 ? void 0 : _a.folder,
|
|
46
|
+
});
|
|
47
|
+
return `-- Installed ${(_b = ext.schema) === null || _b === void 0 ? void 0 : _b.name}`;
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
(0, catch_error_1.default)(error);
|
|
51
|
+
return `-- Failed to install ${(_c = ext.schema) === null || _c === void 0 ? void 0 : _c.name}`;
|
|
52
|
+
}
|
|
53
|
+
}));
|
|
54
|
+
for (const result of results) {
|
|
55
|
+
if (result.status === 'fulfilled') {
|
|
56
|
+
core_1.ux.log(result.value);
|
|
57
|
+
}
|
|
55
58
|
}
|
|
59
|
+
core_1.ux.action.stop();
|
|
60
|
+
core_1.ux.log('Finished installing extensions');
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
// All extensions are already installed
|
|
64
|
+
core_1.ux.log('All extensions are already installed');
|
|
65
|
+
}
|
|
66
|
+
if (localExtensions.length > 0) {
|
|
67
|
+
core_1.ux.log(`Note: ${localExtensions.length} local extensions need to be installed manually.`);
|
|
56
68
|
}
|
|
57
|
-
core_1.ux.action.stop();
|
|
58
|
-
core_1.ux.log('Finished installing extensions');
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
// All extensions are already installed
|
|
62
|
-
core_1.ux.log('All extensions are already installed');
|
|
63
|
-
}
|
|
64
|
-
if (localExtensions.length > 0) {
|
|
65
|
-
core_1.ux.log(`Note: ${localExtensions.length} local extensions need to be installed manually.`);
|
|
66
69
|
}
|
|
67
70
|
}
|
|
68
|
-
|
|
69
|
-
core_1.ux.log('No extensions found or extensions file is empty. Skipping extension installation
|
|
71
|
+
catch {
|
|
72
|
+
core_1.ux.log(`${core_1.ux.colorize('dim', '--')} No extensions found or extensions file is empty. Skipping extension installation.`);
|
|
70
73
|
}
|
|
71
74
|
core_1.ux.action.stop();
|
|
72
75
|
}
|
|
@@ -6,12 +6,13 @@ const core_1 = require("@oclif/core");
|
|
|
6
6
|
const formdata_node_1 = require("formdata-node");
|
|
7
7
|
const node_fs_1 = require("node:fs");
|
|
8
8
|
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
9
|
+
const constants_1 = require("../constants");
|
|
9
10
|
const sdk_2 = require("../sdk");
|
|
10
11
|
const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
|
|
11
12
|
const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
12
13
|
async function loadFiles(dir) {
|
|
13
14
|
const files = (0, read_file_1.default)('files', dir);
|
|
14
|
-
core_1.ux.action.start(`Loading ${files.length} files`);
|
|
15
|
+
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${files.length} files`));
|
|
15
16
|
try {
|
|
16
17
|
const fileIds = files.map(file => file.id);
|
|
17
18
|
// Fetch only the files we're interested in
|
|
@@ -28,11 +29,9 @@ async function loadFiles(dir) {
|
|
|
28
29
|
const existingFileNames = new Set(existingFiles.map(file => file.filename_disk));
|
|
29
30
|
const filesToUpload = files.filter(file => {
|
|
30
31
|
if (existingFileIds.has(file.id)) {
|
|
31
|
-
core_1.ux.log(`Skipping existing file with ID: ${file.id}`);
|
|
32
32
|
return false;
|
|
33
33
|
}
|
|
34
34
|
if (existingFileNames.has(file.filename_disk)) {
|
|
35
|
-
core_1.ux.log(`Skipping existing file with name: ${file.filename_disk}`);
|
|
36
35
|
return false;
|
|
37
36
|
}
|
|
38
37
|
return true;
|
|
@@ -57,12 +56,10 @@ async function loadFiles(dir) {
|
|
|
57
56
|
(0, catch_error_1.default)(error);
|
|
58
57
|
}
|
|
59
58
|
}));
|
|
60
|
-
core_1.ux.log(`Uploaded ${filesToUpload.length} new files`);
|
|
61
59
|
}
|
|
62
60
|
catch (error) {
|
|
63
61
|
(0, catch_error_1.default)(error);
|
|
64
62
|
}
|
|
65
63
|
core_1.ux.action.stop();
|
|
66
|
-
core_1.ux.log('Finished loading files');
|
|
67
64
|
}
|
|
68
65
|
exports.default = loadFiles;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export default function loadFlows(dir: string): Promise<void>;
|
|
2
|
-
export declare function loadOperations(
|
|
2
|
+
export declare function loadOperations(operations: any[]): Promise<void>;
|
|
@@ -4,61 +4,66 @@ exports.loadOperations = void 0;
|
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const sdk_1 = require("@directus/sdk");
|
|
6
6
|
const core_1 = require("@oclif/core");
|
|
7
|
+
const constants_1 = require("../constants");
|
|
7
8
|
const sdk_2 = require("../sdk");
|
|
8
9
|
const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
|
|
9
10
|
const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
10
11
|
async function loadFlows(dir) {
|
|
11
12
|
const flows = (0, read_file_1.default)('flows', dir);
|
|
12
|
-
core_1.ux.action.start(`Loading ${flows.length} flows`);
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
13
|
+
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${flows.length} flows`));
|
|
14
|
+
try {
|
|
15
|
+
// Fetch existing flows
|
|
16
|
+
const existingFlows = await sdk_2.api.client.request((0, sdk_1.readFlows)({
|
|
17
|
+
limit: -1,
|
|
18
|
+
}));
|
|
19
|
+
const existingFlowIds = new Set(existingFlows.map(flow => flow.id));
|
|
20
|
+
const cleanedUpFlows = flows.map(flow => {
|
|
21
|
+
const { operations, ...cleanFlow } = flow;
|
|
22
|
+
return { cleanFlow, operations };
|
|
23
|
+
});
|
|
24
|
+
const newFlows = cleanedUpFlows.filter(({ cleanFlow }) => !existingFlowIds.has(cleanFlow.id));
|
|
25
|
+
const results = await Promise.allSettled(newFlows.map(({ cleanFlow }) => sdk_2.api.client.request((0, sdk_1.createFlow)(cleanFlow))));
|
|
26
|
+
const createdFlowIds = new Set();
|
|
27
|
+
for (const [index, result] of results.entries()) {
|
|
28
|
+
if (result.status === 'fulfilled') {
|
|
29
|
+
createdFlowIds.add(newFlows[index].cleanFlow.id);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
(0, catch_error_1.default)(result.reason);
|
|
28
33
|
}
|
|
29
|
-
await sdk_2.api.client.request((0, sdk_1.createFlow)(flow));
|
|
30
|
-
existingFlowIds.add(flow.id);
|
|
31
|
-
}
|
|
32
|
-
catch (error) {
|
|
33
|
-
(0, catch_error_1.default)(error);
|
|
34
34
|
}
|
|
35
|
+
// Only load operations for newly created flows
|
|
36
|
+
const newOperations = newFlows
|
|
37
|
+
.filter(({ cleanFlow }) => createdFlowIds.has(cleanFlow.id))
|
|
38
|
+
.flatMap(({ operations }) => operations);
|
|
39
|
+
await loadOperations(newOperations);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
(0, catch_error_1.default)(error);
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
core_1.ux.action.stop();
|
|
35
46
|
}
|
|
36
|
-
await loadOperations(dir);
|
|
37
|
-
core_1.ux.action.stop();
|
|
38
|
-
core_1.ux.log('Loaded Flows');
|
|
39
47
|
}
|
|
40
48
|
exports.default = loadFlows;
|
|
41
|
-
async function loadOperations(
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return del;
|
|
49
|
-
});
|
|
50
|
-
await sdk_2.api.client.request((0, sdk_1.createOperations)(opsIds));
|
|
51
|
-
for (const operation of operations) {
|
|
52
|
-
const pl = {
|
|
49
|
+
async function loadOperations(operations) {
|
|
50
|
+
core_1.ux.action.status = `Loading ${operations.length} operations`;
|
|
51
|
+
try {
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
53
|
+
const opsIds = operations.map(({ reject, resolve, ...rest }) => rest);
|
|
54
|
+
await sdk_2.api.client.request((0, sdk_1.createOperations)(opsIds));
|
|
55
|
+
const results = await Promise.allSettled(operations.map(operation => sdk_2.api.client.request((0, sdk_1.updateOperation)(operation.id, {
|
|
53
56
|
reject: operation.reject,
|
|
54
57
|
resolve: operation.resolve,
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
(0, catch_error_1.default)(error);
|
|
58
|
+
}))));
|
|
59
|
+
for (const [index, result] of results.entries()) {
|
|
60
|
+
if (result.status === 'rejected') {
|
|
61
|
+
(0, catch_error_1.default)(result.reason);
|
|
62
|
+
}
|
|
61
63
|
}
|
|
62
64
|
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
(0, catch_error_1.default)(error);
|
|
67
|
+
}
|
|
63
68
|
}
|
|
64
69
|
exports.loadOperations = loadOperations;
|
|
@@ -3,12 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const sdk_1 = require("@directus/sdk");
|
|
5
5
|
const core_1 = require("@oclif/core");
|
|
6
|
+
const constants_1 = require("../constants");
|
|
6
7
|
const sdk_2 = require("../sdk");
|
|
7
8
|
const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
|
|
8
9
|
const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
9
10
|
async function loadFolders(dir) {
|
|
10
11
|
const folders = (0, read_file_1.default)('folders', dir);
|
|
11
|
-
core_1.ux.action.start(`Loading ${folders.length} folders`);
|
|
12
|
+
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${folders.length} folders`));
|
|
12
13
|
try {
|
|
13
14
|
// Fetch existing folders
|
|
14
15
|
const existingFolders = await sdk_2.api.client.request((0, sdk_1.readFolders)({
|
|
@@ -17,7 +18,6 @@ async function loadFolders(dir) {
|
|
|
17
18
|
const existingFolderIds = new Set(existingFolders.map(folder => folder.id));
|
|
18
19
|
const foldersToAdd = folders.filter(folder => {
|
|
19
20
|
if (existingFolderIds.has(folder.id)) {
|
|
20
|
-
core_1.ux.log(`Skipping existing folder: ${folder.name}`);
|
|
21
21
|
return false;
|
|
22
22
|
}
|
|
23
23
|
return true;
|
|
@@ -26,7 +26,6 @@ async function loadFolders(dir) {
|
|
|
26
26
|
const folderSkeleton = foldersToAdd.map(folder => ({ id: folder.id, name: folder.name }));
|
|
27
27
|
// Create the folders
|
|
28
28
|
await sdk_2.api.client.request((0, sdk_1.createFolders)(folderSkeleton));
|
|
29
|
-
core_1.ux.log(`Created ${foldersToAdd.length} new folders`);
|
|
30
29
|
// Update the folders with relationships concurrently
|
|
31
30
|
await Promise.all(foldersToAdd.map(async (folder) => {
|
|
32
31
|
const { id, ...rest } = folder;
|
|
@@ -39,13 +38,12 @@ async function loadFolders(dir) {
|
|
|
39
38
|
}));
|
|
40
39
|
}
|
|
41
40
|
else {
|
|
42
|
-
|
|
41
|
+
// ux.info('-- No new folders to create')
|
|
43
42
|
}
|
|
44
43
|
}
|
|
45
44
|
catch (error) {
|
|
46
45
|
(0, catch_error_1.default)(error);
|
|
47
46
|
}
|
|
48
47
|
core_1.ux.action.stop();
|
|
49
|
-
core_1.ux.log('Loaded folders');
|
|
50
48
|
}
|
|
51
49
|
exports.default = loadFolders;
|
|
@@ -3,12 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const sdk_1 = require("@directus/sdk");
|
|
5
5
|
const core_1 = require("@oclif/core");
|
|
6
|
+
const constants_1 = require("../constants");
|
|
6
7
|
const sdk_2 = require("../sdk");
|
|
7
8
|
const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
|
|
8
9
|
const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
9
10
|
async function loadPermissions(dir) {
|
|
10
11
|
const permissions = (0, read_file_1.default)('permissions', dir);
|
|
11
|
-
core_1.ux.action.start(`Loading ${permissions.length} permissions`);
|
|
12
|
+
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${permissions.length} permissions`));
|
|
12
13
|
try {
|
|
13
14
|
const existingPermissions = await sdk_2.api.client.request((0, sdk_1.readPermissions)({
|
|
14
15
|
limit: -1,
|
|
@@ -18,16 +19,11 @@ async function loadPermissions(dir) {
|
|
|
18
19
|
const newPermissions = permissions.filter(newPerm => !existingPermissionKeys.has(`${newPerm.collection}:${newPerm.action}:${newPerm.policy}`));
|
|
19
20
|
if (newPermissions.length > 0) {
|
|
20
21
|
await sdk_2.api.client.request((0, sdk_1.createPermissions)(newPermissions));
|
|
21
|
-
core_1.ux.log(`Created ${newPermissions.length} new permissions`);
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
core_1.ux.log('No new permissions to create');
|
|
25
22
|
}
|
|
26
23
|
}
|
|
27
24
|
catch (error) {
|
|
28
25
|
(0, catch_error_1.default)(error);
|
|
29
26
|
}
|
|
30
27
|
core_1.ux.action.stop();
|
|
31
|
-
core_1.ux.log('Loaded permissions');
|
|
32
28
|
}
|
|
33
29
|
exports.default = loadPermissions;
|
|
@@ -3,12 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const sdk_1 = require("@directus/sdk");
|
|
5
5
|
const core_1 = require("@oclif/core");
|
|
6
|
+
const constants_1 = require("../constants");
|
|
6
7
|
const sdk_2 = require("../sdk");
|
|
7
8
|
const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
|
|
8
9
|
const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
9
10
|
async function loadPolicies(dir) {
|
|
10
11
|
const policies = (0, read_file_1.default)('policies', dir);
|
|
11
|
-
core_1.ux.action.start(`Loading ${policies.length} policies`);
|
|
12
|
+
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${policies.length} policies`));
|
|
12
13
|
// Fetch existing policies
|
|
13
14
|
const existingPolicies = await sdk_2.api.client.request((0, sdk_1.readPolicies)({
|
|
14
15
|
limit: -1,
|
|
@@ -19,7 +20,7 @@ async function loadPolicies(dir) {
|
|
|
19
20
|
for await (const policy of policiesWithoutPublic) {
|
|
20
21
|
try {
|
|
21
22
|
if (existingPolicyIds.has(policy.id)) {
|
|
22
|
-
core_1.ux.
|
|
23
|
+
core_1.ux.action.status = `Skipping existing policy: ${policy.name}`;
|
|
23
24
|
continue;
|
|
24
25
|
}
|
|
25
26
|
// Create new policy
|
|
@@ -32,6 +33,5 @@ async function loadPolicies(dir) {
|
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
35
|
core_1.ux.action.stop();
|
|
35
|
-
core_1.ux.log('Loaded policies');
|
|
36
36
|
}
|
|
37
37
|
exports.default = loadPolicies;
|
|
@@ -3,12 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const sdk_1 = require("@directus/sdk");
|
|
5
5
|
const core_1 = require("@oclif/core");
|
|
6
|
+
const constants_1 = require("../constants");
|
|
6
7
|
const sdk_2 = require("../sdk");
|
|
7
8
|
const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
|
|
8
9
|
const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
9
10
|
async function loadPresets(dir) {
|
|
10
11
|
const presets = (0, read_file_1.default)('presets', dir);
|
|
11
|
-
core_1.ux.action.start(`Loading ${presets.length} presets`);
|
|
12
|
+
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${presets.length} presets`));
|
|
12
13
|
// Fetch existing presets
|
|
13
14
|
const existingPresets = await sdk_2.api.client.request((0, sdk_1.readPresets)({
|
|
14
15
|
limit: -1,
|
|
@@ -27,16 +28,14 @@ async function loadPresets(dir) {
|
|
|
27
28
|
if (presetsToAdd.length > 0) {
|
|
28
29
|
try {
|
|
29
30
|
await sdk_2.api.client.request((0, sdk_1.createPresets)(presetsToAdd));
|
|
30
|
-
core_1.ux.log(`Created ${presetsToAdd.length} new presets`);
|
|
31
31
|
}
|
|
32
32
|
catch (error) {
|
|
33
33
|
(0, catch_error_1.default)(error);
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
else {
|
|
37
|
-
|
|
37
|
+
// ux.info('-- No new presets to create')
|
|
38
38
|
}
|
|
39
39
|
core_1.ux.action.stop();
|
|
40
|
-
core_1.ux.log('Loaded presets');
|
|
41
40
|
}
|
|
42
41
|
exports.default = loadPresets;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const sdk_1 = require("@directus/sdk");
|
|
5
5
|
const core_1 = require("@oclif/core");
|
|
6
|
+
const constants_1 = require("../constants");
|
|
6
7
|
const sdk_2 = require("../sdk");
|
|
7
8
|
const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
|
|
8
9
|
const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
@@ -11,14 +12,13 @@ const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
|
11
12
|
*/
|
|
12
13
|
async function loadRelations(dir) {
|
|
13
14
|
const relations = (0, read_file_1.default)('relations', dir);
|
|
14
|
-
core_1.ux.action.start(`Loading ${relations.length} relations`);
|
|
15
|
+
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${relations.length} relations`));
|
|
15
16
|
// Fetch existing relations
|
|
16
17
|
const existingRelations = await sdk_2.api.client.request((0, sdk_1.readRelations)());
|
|
17
18
|
const existingRelationKeys = new Set(existingRelations.map(relation => `${relation.collection}:${relation.field}:${relation.related_collection}`));
|
|
18
19
|
const relationsToAdd = relations.filter(relation => {
|
|
19
20
|
const key = `${relation.collection}:${relation.field}:${relation.related_collection}`;
|
|
20
21
|
if (existingRelationKeys.has(key)) {
|
|
21
|
-
core_1.ux.log(`Skipping existing relation: ${key}`);
|
|
22
22
|
return false;
|
|
23
23
|
}
|
|
24
24
|
return true;
|
|
@@ -29,7 +29,6 @@ async function loadRelations(dir) {
|
|
|
29
29
|
});
|
|
30
30
|
await addRelations(relationsToAdd);
|
|
31
31
|
core_1.ux.action.stop();
|
|
32
|
-
core_1.ux.log('Loaded relations');
|
|
33
32
|
}
|
|
34
33
|
exports.default = loadRelations;
|
|
35
34
|
async function addRelations(relations) {
|
|
@@ -3,13 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const sdk_1 = require("@directus/sdk");
|
|
5
5
|
const core_1 = require("@oclif/core");
|
|
6
|
+
const constants_1 = require("../constants");
|
|
6
7
|
const sdk_2 = require("../sdk");
|
|
7
8
|
const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
|
|
8
9
|
const get_role_ids_1 = tslib_1.__importDefault(require("../utils/get-role-ids"));
|
|
9
10
|
const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
10
11
|
async function loadRoles(dir) {
|
|
11
12
|
const roles = (0, read_file_1.default)('roles', dir);
|
|
12
|
-
core_1.ux.action.start(`Loading ${roles.length} roles`);
|
|
13
|
+
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${roles.length} roles`));
|
|
13
14
|
const { legacyAdminRoleId, newAdminRoleId } = await (0, get_role_ids_1.default)(dir);
|
|
14
15
|
// Fetch existing roles
|
|
15
16
|
const existingRoles = await sdk_2.api.client.request((0, sdk_1.readRoles)({
|
|
@@ -29,7 +30,6 @@ async function loadRoles(dir) {
|
|
|
29
30
|
for await (const role of cleanedUpRoles) {
|
|
30
31
|
try {
|
|
31
32
|
if (existingRoleIds.has(role.id)) {
|
|
32
|
-
core_1.ux.log(`Skipping existing role: ${role.name}`);
|
|
33
33
|
continue;
|
|
34
34
|
}
|
|
35
35
|
// Create new role
|
|
@@ -52,13 +52,11 @@ async function loadRoles(dir) {
|
|
|
52
52
|
}
|
|
53
53
|
const simplifiedRole = { parent: role.parent };
|
|
54
54
|
await sdk_2.api.client.request((0, sdk_1.updateRole)(role.id, simplifiedRole));
|
|
55
|
-
core_1.ux.log(`Updated parent for role: ${role.name}`);
|
|
56
55
|
}
|
|
57
56
|
catch (error) {
|
|
58
57
|
(0, catch_error_1.default)(error);
|
|
59
58
|
}
|
|
60
59
|
}
|
|
61
60
|
core_1.ux.action.stop();
|
|
62
|
-
core_1.ux.log('Loaded roles');
|
|
63
61
|
}
|
|
64
62
|
exports.default = loadRoles;
|
|
@@ -2,20 +2,57 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const sdk_1 = require("@directus/sdk");
|
|
5
|
+
const core_1 = require("@oclif/core");
|
|
5
6
|
const defu_1 = require("defu");
|
|
7
|
+
const constants_1 = require("../constants");
|
|
6
8
|
const sdk_2 = require("../sdk");
|
|
7
9
|
const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
|
|
8
10
|
const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
11
|
+
const customDefu = (0, defu_1.createDefu)((obj, key, value) => {
|
|
12
|
+
if (Array.isArray(obj[key]) && Array.isArray(value)) {
|
|
13
|
+
// @ts-expect-error
|
|
14
|
+
obj[key] = mergeArrays(key, obj[key], value);
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
if (typeof obj[key] === 'string' && typeof value === 'string') {
|
|
18
|
+
// @ts-expect-error
|
|
19
|
+
obj[key] = mergeJsonStrings(obj[key], value);
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
function mergeArrays(key, current, incoming) {
|
|
24
|
+
const mergeKeys = {
|
|
25
|
+
/* eslint-disable camelcase */
|
|
26
|
+
basemaps: ['key'],
|
|
27
|
+
custom_aspect_ratios: ['key'],
|
|
28
|
+
module_bar: ['id', 'type'],
|
|
29
|
+
storage_asset_presets: ['key'],
|
|
30
|
+
/* eslint-enable camelcase */
|
|
31
|
+
};
|
|
32
|
+
const keys = mergeKeys[key];
|
|
33
|
+
if (!keys)
|
|
34
|
+
return [...new Set([...current, ...incoming])];
|
|
35
|
+
return current.concat(incoming.filter(item => !current.some(currentItem => keys.every(k => currentItem[k] === item[k]))));
|
|
36
|
+
}
|
|
37
|
+
function mergeJsonStrings(current, incoming) {
|
|
38
|
+
try {
|
|
39
|
+
return JSON.stringify(customDefu(JSON.parse(current), JSON.parse(incoming)));
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return incoming; // If not valid JSON, return the incoming value
|
|
43
|
+
}
|
|
44
|
+
}
|
|
9
45
|
async function loadSettings(dir) {
|
|
46
|
+
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, 'Loading settings'));
|
|
10
47
|
const settings = (0, read_file_1.default)('settings', dir);
|
|
11
48
|
try {
|
|
12
|
-
// Get the current settings and merge them with current settings as defaults. To prevent overriding any logos, themes, etc.
|
|
13
49
|
const currentSettings = await sdk_2.api.client.request((0, sdk_1.readSettings)());
|
|
14
|
-
const mergedSettings = (
|
|
50
|
+
const mergedSettings = customDefu(currentSettings, settings);
|
|
15
51
|
await sdk_2.api.client.request((0, sdk_1.updateSettings)(mergedSettings));
|
|
16
52
|
}
|
|
17
53
|
catch (error) {
|
|
18
54
|
(0, catch_error_1.default)(error);
|
|
19
55
|
}
|
|
56
|
+
core_1.ux.action.stop();
|
|
20
57
|
}
|
|
21
58
|
exports.default = loadSettings;
|
|
@@ -3,12 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const sdk_1 = require("@directus/sdk");
|
|
5
5
|
const core_1 = require("@oclif/core");
|
|
6
|
+
const constants_1 = require("../constants");
|
|
6
7
|
const sdk_2 = require("../sdk");
|
|
7
8
|
const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
|
|
8
9
|
const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
9
10
|
async function loadTranslations(dir) {
|
|
10
|
-
core_1.ux.action.start('Loading translations');
|
|
11
11
|
const translations = (0, read_file_1.default)('translations', dir);
|
|
12
|
+
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${translations.length} translations`));
|
|
12
13
|
// Fetch existing translations
|
|
13
14
|
const existingTranslations = await sdk_2.api.client.request((0, sdk_1.readTranslations)({
|
|
14
15
|
limit: -1,
|
|
@@ -17,7 +18,6 @@ async function loadTranslations(dir) {
|
|
|
17
18
|
const newTranslations = translations.filter(t => {
|
|
18
19
|
const key = `${t.language}_${t.key}`;
|
|
19
20
|
if (existingTranslationKeys.has(key)) {
|
|
20
|
-
core_1.ux.log(`Skipping existing translation: ${key}`);
|
|
21
21
|
return false;
|
|
22
22
|
}
|
|
23
23
|
return true;
|
|
@@ -25,16 +25,14 @@ async function loadTranslations(dir) {
|
|
|
25
25
|
if (newTranslations.length > 0) {
|
|
26
26
|
try {
|
|
27
27
|
await sdk_2.api.client.request((0, sdk_1.createTranslations)(newTranslations));
|
|
28
|
-
core_1.ux.log(`Created ${newTranslations.length} new translations`);
|
|
29
28
|
}
|
|
30
29
|
catch (error) {
|
|
31
30
|
(0, catch_error_1.default)(error);
|
|
32
31
|
}
|
|
33
32
|
}
|
|
34
33
|
else {
|
|
35
|
-
|
|
34
|
+
// ux.info('-- No new translations to create')
|
|
36
35
|
}
|
|
37
36
|
core_1.ux.action.stop();
|
|
38
|
-
core_1.ux.log('Loaded translations');
|
|
39
37
|
}
|
|
40
38
|
exports.default = loadTranslations;
|
|
@@ -3,20 +3,23 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const sdk_1 = require("@directus/sdk");
|
|
5
5
|
const core_1 = require("@oclif/core");
|
|
6
|
+
const constants_1 = require("../constants");
|
|
6
7
|
const sdk_2 = require("../sdk");
|
|
7
8
|
const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
|
|
8
9
|
const get_role_ids_1 = tslib_1.__importDefault(require("../utils/get-role-ids"));
|
|
9
10
|
const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
10
11
|
async function loadUsers(dir) {
|
|
11
12
|
const users = (0, read_file_1.default)('users', dir);
|
|
12
|
-
core_1.ux.action.start(`Loading ${users.length} users`);
|
|
13
|
+
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${users.length} users`));
|
|
13
14
|
const { legacyAdminRoleId, newAdminRoleId } = await (0, get_role_ids_1.default)(dir);
|
|
14
15
|
const incomingUserEmails = users.map(user => user.email);
|
|
16
|
+
const incomingUserIds = users.map(user => user.id).filter(Boolean);
|
|
15
17
|
const existingUsers = await sdk_2.api.client.request((0, sdk_1.readUsers)({
|
|
16
18
|
filter: {
|
|
17
|
-
|
|
18
|
-
_in: incomingUserEmails,
|
|
19
|
-
|
|
19
|
+
_or: [
|
|
20
|
+
{ email: { _in: incomingUserEmails } },
|
|
21
|
+
{ id: { _in: incomingUserIds } },
|
|
22
|
+
],
|
|
20
23
|
},
|
|
21
24
|
limit: -1,
|
|
22
25
|
}));
|
|
@@ -33,9 +36,14 @@ async function loadUsers(dir) {
|
|
|
33
36
|
return user;
|
|
34
37
|
});
|
|
35
38
|
for await (const user of filteredUsers) {
|
|
36
|
-
|
|
37
|
-
if (
|
|
39
|
+
const existingUser = existingUsers.find(existing => existing.email === user.email || existing.id === user.id);
|
|
40
|
+
if (existingUser) {
|
|
41
|
+
// If user already exists, we'll skip creating a new one
|
|
38
42
|
delete user.email;
|
|
43
|
+
delete user.id;
|
|
44
|
+
// You might want to update the existing user here instead
|
|
45
|
+
// await api.client.request(updateUser(existingUser.id, user))
|
|
46
|
+
continue;
|
|
39
47
|
}
|
|
40
48
|
try {
|
|
41
49
|
await sdk_2.api.client.request((0, sdk_1.createUser)(user));
|
|
@@ -45,6 +53,5 @@ async function loadUsers(dir) {
|
|
|
45
53
|
}
|
|
46
54
|
}
|
|
47
55
|
core_1.ux.action.stop();
|
|
48
|
-
core_1.ux.log('Loaded users');
|
|
49
56
|
}
|
|
50
57
|
exports.default = loadUsers;
|
package/dist/lib/utils/auth.js
CHANGED
|
@@ -24,7 +24,7 @@ async function getDirectusToken(directusUrl) {
|
|
|
24
24
|
try {
|
|
25
25
|
sdk_2.api.setAuthToken(directusToken);
|
|
26
26
|
const response = await sdk_2.api.client.request((0, sdk_1.readMe)());
|
|
27
|
-
core_1.ux.log(
|
|
27
|
+
core_1.ux.log(`-- Logged in as ${response.first_name} ${response.last_name}`);
|
|
28
28
|
return directusToken;
|
|
29
29
|
}
|
|
30
30
|
catch (error) {
|
|
@@ -5,14 +5,14 @@ const logger_1 = require("./logger");
|
|
|
5
5
|
function catchError(error, options = {}, logToFile = true) {
|
|
6
6
|
const errorMessage = isDirectusError(error) ? formatDirectusError(error)
|
|
7
7
|
: (error instanceof Error ? formatGenericError(error)
|
|
8
|
-
:
|
|
8
|
+
: `${JSON.stringify(error)}`);
|
|
9
9
|
const contextString = options.context
|
|
10
10
|
? Object.entries(options.context)
|
|
11
11
|
.map(([key, value]) => `${key}: ${JSON.stringify(value)}`)
|
|
12
12
|
.join(', ') : '';
|
|
13
13
|
const formattedMessage = [
|
|
14
|
-
contextString && `Context: ${contextString}`,
|
|
15
14
|
errorMessage,
|
|
15
|
+
contextString && `Context: ${contextString}`,
|
|
16
16
|
].filter(Boolean).join('\n');
|
|
17
17
|
options.fatal ? core_1.ux.error(formattedMessage) : core_1.ux.warn(formattedMessage);
|
|
18
18
|
if (logToFile) {
|
|
@@ -4,5 +4,6 @@ interface Template {
|
|
|
4
4
|
}
|
|
5
5
|
export declare function getCommunityTemplates(): Promise<Template[]>;
|
|
6
6
|
export declare function getLocalTemplate(localTemplateDir: string): Promise<Template>;
|
|
7
|
+
export declare function getInteractiveLocalTemplate(localTemplateDir: string): Promise<Template[]>;
|
|
7
8
|
export declare function getGithubTemplate(ghTemplateUrl: string): Promise<Template>;
|
|
8
9
|
export {};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getGithubTemplate = exports.getLocalTemplate = exports.getCommunityTemplates = void 0;
|
|
3
|
+
exports.getGithubTemplate = exports.getInteractiveLocalTemplate = exports.getLocalTemplate = exports.getCommunityTemplates = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const giget_1 = require("giget");
|
|
6
|
+
const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
|
|
6
7
|
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
7
8
|
const path_1 = tslib_1.__importDefault(require("./path"));
|
|
8
9
|
const read_templates_1 = require("./read-templates");
|
|
@@ -33,6 +34,46 @@ async function getLocalTemplate(localTemplateDir) {
|
|
|
33
34
|
return (0, read_templates_1.readTemplate)(resolvedDir);
|
|
34
35
|
}
|
|
35
36
|
exports.getLocalTemplate = getLocalTemplate;
|
|
37
|
+
async function getInteractiveLocalTemplate(localTemplateDir) {
|
|
38
|
+
const resolvedDir = (0, path_1.default)(localTemplateDir);
|
|
39
|
+
if (!resolvedDir) {
|
|
40
|
+
throw new Error('Directory does not exist.');
|
|
41
|
+
}
|
|
42
|
+
const directTemplate = await (0, read_templates_1.readTemplate)(resolvedDir);
|
|
43
|
+
if (directTemplate) {
|
|
44
|
+
return [directTemplate];
|
|
45
|
+
}
|
|
46
|
+
const templates = await (0, read_templates_1.readAllTemplates)(resolvedDir);
|
|
47
|
+
if (templates.length === 0) {
|
|
48
|
+
// If no templates found, search nested directories
|
|
49
|
+
const nestedTemplates = await findNestedTemplates(resolvedDir, 2);
|
|
50
|
+
if (nestedTemplates.length === 0) {
|
|
51
|
+
throw new Error('No valid templates found in the specified directory or its subdirectories.');
|
|
52
|
+
}
|
|
53
|
+
return nestedTemplates;
|
|
54
|
+
}
|
|
55
|
+
return templates;
|
|
56
|
+
}
|
|
57
|
+
exports.getInteractiveLocalTemplate = getInteractiveLocalTemplate;
|
|
58
|
+
async function findNestedTemplates(dir, depth) {
|
|
59
|
+
if (depth === 0)
|
|
60
|
+
return [];
|
|
61
|
+
const templates = [];
|
|
62
|
+
const entries = await node_fs_1.default.promises.readdir(dir, { withFileTypes: true });
|
|
63
|
+
for (const entry of entries) {
|
|
64
|
+
if (entry.isDirectory()) {
|
|
65
|
+
const fullPath = node_path_1.default.join(dir, entry.name);
|
|
66
|
+
const dirTemplates = await (0, read_templates_1.readAllTemplates)(fullPath);
|
|
67
|
+
templates.push(...dirTemplates);
|
|
68
|
+
if (dirTemplates.length === 0 && depth > 1) {
|
|
69
|
+
// If no templates found and we can go deeper, search subdirectories
|
|
70
|
+
const nestedTemplates = await findNestedTemplates(fullPath, depth - 1);
|
|
71
|
+
templates.push(...nestedTemplates);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return templates;
|
|
76
|
+
}
|
|
36
77
|
async function getGithubTemplate(ghTemplateUrl) {
|
|
37
78
|
try {
|
|
38
79
|
const ghString = await (0, transform_github_url_1.transformGitHubUrl)(ghTemplateUrl);
|
|
@@ -17,8 +17,10 @@ async function readTemplate(directoryPath) {
|
|
|
17
17
|
}
|
|
18
18
|
return null;
|
|
19
19
|
}
|
|
20
|
-
catch
|
|
21
|
-
console.error(
|
|
20
|
+
catch {
|
|
21
|
+
// console.error(
|
|
22
|
+
// `Failed to read package.json file in directory ${directoryPath}: ${error}`,
|
|
23
|
+
// )
|
|
22
24
|
return null;
|
|
23
25
|
}
|
|
24
26
|
}
|
package/oclif.manifest.json
CHANGED