directus-template-cli 0.5.0-beta.8 → 0.5.0
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/README.md +186 -17
- package/dist/commands/apply.d.ts +25 -3
- package/dist/commands/apply.js +78 -121
- package/dist/commands/extract.d.ts +29 -1
- package/dist/commands/extract.js +72 -50
- package/dist/flags/common.d.ts +7 -0
- package/dist/flags/common.js +41 -0
- package/dist/lib/extract/extract-access.js +5 -3
- package/dist/lib/extract/extract-assets.d.ts +0 -414
- package/dist/lib/extract/extract-assets.js +29 -25
- package/dist/lib/extract/extract-collections.js +5 -4
- package/dist/lib/extract/extract-content.d.ts +0 -2
- package/dist/lib/extract/extract-content.js +16 -15
- package/dist/lib/extract/extract-dashboards.js +8 -6
- package/dist/lib/extract/extract-extensions.js +5 -3
- package/dist/lib/extract/extract-fields.js +4 -2
- package/dist/lib/extract/extract-files.js +5 -3
- package/dist/lib/extract/extract-flows.js +8 -6
- package/dist/lib/extract/extract-folders.js +5 -3
- package/dist/lib/extract/extract-permissions.js +5 -3
- package/dist/lib/extract/extract-policies.js +5 -3
- package/dist/lib/extract/extract-presets.js +5 -3
- package/dist/lib/extract/extract-relations.js +5 -3
- package/dist/lib/extract/extract-roles.js +5 -3
- package/dist/lib/extract/extract-schema.js +6 -8
- package/dist/lib/extract/extract-settings.js +5 -3
- package/dist/lib/extract/extract-translations.js +6 -6
- package/dist/lib/extract/extract-users.js +6 -6
- package/dist/lib/load/apply-flags.d.ts +22 -0
- package/dist/lib/load/apply-flags.js +67 -0
- package/dist/lib/load/index.js +9 -5
- package/dist/lib/load/load-access.js +45 -37
- package/dist/lib/load/load-collections.js +20 -2
- package/dist/lib/load/load-dashboards.js +27 -25
- package/dist/lib/load/load-data.js +3 -3
- package/dist/lib/load/load-files.js +42 -46
- package/dist/lib/load/load-flows.js +33 -32
- package/dist/lib/load/load-folders.js +32 -30
- package/dist/lib/load/load-permissions.js +14 -12
- package/dist/lib/load/load-policies.js +21 -19
- package/dist/lib/load/load-presets.js +25 -23
- package/dist/lib/load/load-relations.js +17 -15
- package/dist/lib/load/load-roles.js +43 -41
- package/dist/lib/load/load-translations.js +22 -20
- package/dist/lib/load/load-users.js +42 -39
- package/dist/lib/load/update-required-fields.d.ts +1 -0
- package/dist/lib/load/update-required-fields.js +24 -0
- package/dist/lib/sdk.d.ts +20 -2
- package/dist/lib/sdk.js +124 -9
- package/dist/lib/utils/auth.d.ts +26 -0
- package/dist/lib/utils/auth.js +48 -4
- package/dist/lib/utils/catch-error.d.ts +15 -2
- package/dist/lib/utils/catch-error.js +31 -25
- package/oclif.manifest.json +74 -28
- package/package.json +2 -2
- package/dist/lib/interfaces.d.ts +0 -8
- package/dist/lib/interfaces.js +0 -2
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface ApplyFlags {
|
|
2
|
+
content: boolean;
|
|
3
|
+
dashboards: boolean;
|
|
4
|
+
directusToken: string;
|
|
5
|
+
directusUrl: string;
|
|
6
|
+
extensions: boolean;
|
|
7
|
+
files: boolean;
|
|
8
|
+
flows: boolean;
|
|
9
|
+
partial: boolean;
|
|
10
|
+
permissions: boolean;
|
|
11
|
+
programmatic: boolean;
|
|
12
|
+
schema: boolean;
|
|
13
|
+
settings: boolean;
|
|
14
|
+
templateLocation: string;
|
|
15
|
+
templateType: 'community' | 'github' | 'local';
|
|
16
|
+
userEmail: string;
|
|
17
|
+
userPassword: string;
|
|
18
|
+
users: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare const loadFlags: readonly ["content", "dashboards", "extensions", "files", "flows", "permissions", "schema", "settings", "users"];
|
|
21
|
+
export declare function validateProgrammaticFlags(flags: ApplyFlags): ApplyFlags;
|
|
22
|
+
export declare function validateInteractiveFlags(flags: ApplyFlags): ApplyFlags;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateInteractiveFlags = exports.validateProgrammaticFlags = exports.loadFlags = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const core_1 = require("@oclif/core");
|
|
6
|
+
const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
|
|
7
|
+
exports.loadFlags = [
|
|
8
|
+
'content',
|
|
9
|
+
'dashboards',
|
|
10
|
+
'extensions',
|
|
11
|
+
'files',
|
|
12
|
+
'flows',
|
|
13
|
+
'permissions',
|
|
14
|
+
'schema',
|
|
15
|
+
'settings',
|
|
16
|
+
'users',
|
|
17
|
+
];
|
|
18
|
+
function validateProgrammaticFlags(flags) {
|
|
19
|
+
const { directusToken, directusUrl, templateLocation, userEmail, userPassword } = flags;
|
|
20
|
+
if (!directusUrl)
|
|
21
|
+
core_1.ux.error('Directus URL is required for programmatic mode.');
|
|
22
|
+
if (!directusToken && (!userEmail || !userPassword))
|
|
23
|
+
core_1.ux.error('Either Directus token or email and password are required for programmatic mode.');
|
|
24
|
+
if (!templateLocation)
|
|
25
|
+
core_1.ux.error('Template location is required for programmatic mode.');
|
|
26
|
+
return flags.partial ? handlePartialFlags(flags) : setAllFlagsTrue(flags);
|
|
27
|
+
}
|
|
28
|
+
exports.validateProgrammaticFlags = validateProgrammaticFlags;
|
|
29
|
+
function validateInteractiveFlags(flags) {
|
|
30
|
+
return flags.partial ? handlePartialFlags(flags) : setAllFlagsTrue(flags);
|
|
31
|
+
}
|
|
32
|
+
exports.validateInteractiveFlags = validateInteractiveFlags;
|
|
33
|
+
function handlePartialFlags(flags) {
|
|
34
|
+
const enabledFlags = exports.loadFlags.filter(flag => flags[flag] === true);
|
|
35
|
+
const disabledFlags = exports.loadFlags.filter(flag => flags[flag] === false);
|
|
36
|
+
if (enabledFlags.length > 0) {
|
|
37
|
+
for (const flag of exports.loadFlags)
|
|
38
|
+
flags[flag] = enabledFlags.includes(flag);
|
|
39
|
+
}
|
|
40
|
+
else if (disabledFlags.length > 0) {
|
|
41
|
+
for (const flag of exports.loadFlags)
|
|
42
|
+
flags[flag] = !disabledFlags.includes(flag);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
setAllFlagsTrue(flags);
|
|
46
|
+
}
|
|
47
|
+
handleDependencies(flags);
|
|
48
|
+
if (!exports.loadFlags.some(flag => flags[flag])) {
|
|
49
|
+
(0, catch_error_1.default)(new Error('When using --partial, at least one component must be loaded.'), { fatal: true });
|
|
50
|
+
}
|
|
51
|
+
return flags;
|
|
52
|
+
}
|
|
53
|
+
function handleDependencies(flags) {
|
|
54
|
+
if (flags.content && (!flags.schema || !flags.files)) {
|
|
55
|
+
flags.schema = flags.files = true;
|
|
56
|
+
core_1.ux.warn('Content loading requires schema and files. Enabling schema and files flags.');
|
|
57
|
+
}
|
|
58
|
+
if (flags.users && !flags.permissions) {
|
|
59
|
+
flags.permissions = true;
|
|
60
|
+
core_1.ux.warn('User loading requires permissions. Enabling permissions flag.');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function setAllFlagsTrue(flags) {
|
|
64
|
+
for (const flag of exports.loadFlags)
|
|
65
|
+
flags[flag] = true;
|
|
66
|
+
return flags;
|
|
67
|
+
}
|
package/dist/lib/load/index.js
CHANGED
|
@@ -19,6 +19,7 @@ const load_roles_1 = tslib_1.__importDefault(require("./load-roles"));
|
|
|
19
19
|
const load_settings_1 = tslib_1.__importDefault(require("./load-settings"));
|
|
20
20
|
const load_translations_1 = tslib_1.__importDefault(require("./load-translations"));
|
|
21
21
|
const load_users_1 = tslib_1.__importDefault(require("./load-users"));
|
|
22
|
+
const update_required_fields_1 = tslib_1.__importDefault(require("./update-required-fields"));
|
|
22
23
|
async function apply(dir, flags) {
|
|
23
24
|
const source = dir + '/src';
|
|
24
25
|
const isTemplateOk = await (0, check_template_1.default)(source);
|
|
@@ -29,14 +30,14 @@ async function apply(dir, flags) {
|
|
|
29
30
|
await (0, load_collections_1.default)(source);
|
|
30
31
|
await (0, load_relations_1.default)(source);
|
|
31
32
|
}
|
|
32
|
-
if (flags.permissions) {
|
|
33
|
+
if (flags.permissions || flags.users) {
|
|
33
34
|
await (0, load_roles_1.default)(source);
|
|
34
35
|
await (0, load_policies_1.default)(source);
|
|
35
|
-
await (0, load_access_1.default)(source);
|
|
36
36
|
await (0, load_permissions_1.default)(source);
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
if (flags.users) {
|
|
38
|
+
await (0, load_users_1.default)(source);
|
|
39
|
+
}
|
|
40
|
+
await (0, load_access_1.default)(source);
|
|
40
41
|
}
|
|
41
42
|
if (flags.files) {
|
|
42
43
|
await (0, load_folders_1.default)(source);
|
|
@@ -45,6 +46,9 @@ async function apply(dir, flags) {
|
|
|
45
46
|
if (flags.content) {
|
|
46
47
|
await (0, load_data_1.default)(source);
|
|
47
48
|
}
|
|
49
|
+
if (flags.schema) {
|
|
50
|
+
await (0, update_required_fields_1.default)(source);
|
|
51
|
+
}
|
|
48
52
|
if (flags.dashboards) {
|
|
49
53
|
await (0, load_dashboards_1.default)(source);
|
|
50
54
|
}
|
|
@@ -5,49 +5,57 @@ const core_1 = require("@oclif/core");
|
|
|
5
5
|
const constants_1 = require("../constants");
|
|
6
6
|
const sdk_1 = require("../sdk");
|
|
7
7
|
const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
|
|
8
|
+
const get_role_ids_1 = tslib_1.__importDefault(require("../utils/get-role-ids"));
|
|
8
9
|
const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
9
10
|
async function loadAccess(dir) {
|
|
10
11
|
const access = (0, read_file_1.default)('access', dir);
|
|
11
12
|
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${access.length} accesses`));
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
13
|
+
if (access && access.length > 0) {
|
|
14
|
+
// Fetch existing accesses
|
|
15
|
+
const existingAccesses = await sdk_1.api.client.request(() => ({
|
|
16
|
+
method: 'GET',
|
|
17
|
+
params: {
|
|
18
|
+
limit: -1,
|
|
19
|
+
},
|
|
20
|
+
path: '/access',
|
|
21
|
+
}));
|
|
22
|
+
const { legacyAdminRoleId, newAdminRoleId } = await (0, get_role_ids_1.default)(dir);
|
|
23
|
+
const existingAccessById = new Map(existingAccesses.map(acc => [acc.id, acc]));
|
|
24
|
+
const existingAccessByCompositeKey = new Map(existingAccesses.map(acc => [getCompositeKey(acc), acc]));
|
|
25
|
+
for await (const acc of access) {
|
|
26
|
+
try {
|
|
27
|
+
if (existingAccessById.has(acc.id)) {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const compositeKey = getCompositeKey(acc);
|
|
31
|
+
if (existingAccessByCompositeKey.has(compositeKey)) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
// If the role is null, delete the role key to avoid errors
|
|
35
|
+
if (acc.role === null) {
|
|
36
|
+
delete acc.role;
|
|
37
|
+
}
|
|
38
|
+
// If the role is the legacy admin role, update it to the new admin role
|
|
39
|
+
if (acc.role === legacyAdminRoleId) {
|
|
40
|
+
acc.role = newAdminRoleId;
|
|
41
|
+
}
|
|
42
|
+
await sdk_1.api.client.request(() => ({
|
|
43
|
+
body: JSON.stringify(acc),
|
|
44
|
+
method: 'POST',
|
|
45
|
+
path: '/access',
|
|
46
|
+
}));
|
|
47
|
+
// Add the new access to our maps
|
|
48
|
+
existingAccessById.set(acc.id, acc);
|
|
49
|
+
existingAccessByCompositeKey.set(compositeKey, acc);
|
|
26
50
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
51
|
+
catch (error) {
|
|
52
|
+
(0, catch_error_1.default)(error, {
|
|
53
|
+
context: {
|
|
54
|
+
access: acc,
|
|
55
|
+
operation: 'createAccess',
|
|
56
|
+
},
|
|
57
|
+
});
|
|
30
58
|
}
|
|
31
|
-
// If the role is null, delete the role key to avoid errors
|
|
32
|
-
if (acc.role === null) {
|
|
33
|
-
delete acc.role;
|
|
34
|
-
}
|
|
35
|
-
await sdk_1.api.client.request(() => ({
|
|
36
|
-
body: JSON.stringify(acc),
|
|
37
|
-
method: 'POST',
|
|
38
|
-
path: '/access',
|
|
39
|
-
}));
|
|
40
|
-
// Add the new access to our maps
|
|
41
|
-
existingAccessById.set(acc.id, acc);
|
|
42
|
-
existingAccessByCompositeKey.set(compositeKey, acc);
|
|
43
|
-
}
|
|
44
|
-
catch (error) {
|
|
45
|
-
(0, catch_error_1.default)(error, {
|
|
46
|
-
context: {
|
|
47
|
-
access: acc,
|
|
48
|
-
operation: 'createAccess',
|
|
49
|
-
},
|
|
50
|
-
});
|
|
51
59
|
}
|
|
52
60
|
}
|
|
53
61
|
core_1.ux.action.stop();
|
|
@@ -33,8 +33,24 @@ async function processCollections(collectionsToAdd, fieldsToAdd) {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
+
const removeRequiredorIsNullable = (field) => {
|
|
37
|
+
var _a, _b, _c;
|
|
38
|
+
if (((_a = field.meta) === null || _a === void 0 ? void 0 : _a.required) === true) {
|
|
39
|
+
field.meta.required = false;
|
|
40
|
+
}
|
|
41
|
+
if (((_b = field.schema) === null || _b === void 0 ? void 0 : _b.is_nullable) === false) {
|
|
42
|
+
// eslint-disable-next-line camelcase
|
|
43
|
+
field.schema.is_nullable = true;
|
|
44
|
+
}
|
|
45
|
+
if (((_c = field.schema) === null || _c === void 0 ? void 0 : _c.is_unique) === true) {
|
|
46
|
+
// eslint-disable-next-line camelcase
|
|
47
|
+
field.schema.is_unique = false;
|
|
48
|
+
}
|
|
49
|
+
return field;
|
|
50
|
+
};
|
|
36
51
|
async function addNewCollectionWithFields(collection, allFields) {
|
|
37
|
-
const collectionFields = allFields.filter(field => field.collection === collection.collection)
|
|
52
|
+
const collectionFields = allFields.filter(field => field.collection === collection.collection)
|
|
53
|
+
.map(field => removeRequiredorIsNullable(field));
|
|
38
54
|
const collectionWithoutGroup = {
|
|
39
55
|
...collection,
|
|
40
56
|
fields: collectionFields,
|
|
@@ -44,7 +60,8 @@ async function addNewCollectionWithFields(collection, allFields) {
|
|
|
44
60
|
await sdk_2.api.client.request((0, sdk_1.createCollection)(collectionWithoutGroup));
|
|
45
61
|
}
|
|
46
62
|
async function addNewFieldsToExistingCollection(collectionName, fieldsToAdd, existingFields) {
|
|
47
|
-
const collectionFieldsToAdd = fieldsToAdd.filter(field => field.collection === collectionName)
|
|
63
|
+
const collectionFieldsToAdd = fieldsToAdd.filter(field => field.collection === collectionName)
|
|
64
|
+
.map(field => removeRequiredorIsNullable(field));
|
|
48
65
|
const existingCollectionFields = existingFields.filter((field) => field.collection === collectionName);
|
|
49
66
|
for await (const field of collectionFieldsToAdd) {
|
|
50
67
|
if (!existingCollectionFields.some((existingField) => existingField.field === field.field)) {
|
|
@@ -82,6 +99,7 @@ async function addCustomFieldsOnSystemCollections(fields) {
|
|
|
82
99
|
try {
|
|
83
100
|
const fieldExists = existingFields.some((existingField) => existingField.collection === field.collection && existingField.field === field.field);
|
|
84
101
|
if (!fieldExists) {
|
|
102
|
+
// @ts-expect-error string
|
|
85
103
|
await sdk_2.api.client.request((0, sdk_1.createField)(field.collection, field));
|
|
86
104
|
}
|
|
87
105
|
}
|
|
@@ -11,31 +11,33 @@ const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
|
11
11
|
async function loadDashboards(dir) {
|
|
12
12
|
const dashboards = (0, read_file_1.default)('dashboards', dir);
|
|
13
13
|
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${dashboards.length} dashboards`));
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
14
|
+
if (dashboards && dashboards.length > 0) {
|
|
15
|
+
// Fetch existing dashboards
|
|
16
|
+
const existingDashboards = await sdk_2.api.client.request((0, sdk_1.readDashboards)({
|
|
17
|
+
limit: -1,
|
|
18
|
+
}));
|
|
19
|
+
const existingDashboardIds = new Set(existingDashboards.map(dashboard => dashboard.id));
|
|
20
|
+
const filteredDashboards = dashboards.filter(dashboard => {
|
|
21
|
+
if (existingDashboardIds.has(dashboard.id)) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
return true;
|
|
25
|
+
}).map(dash => {
|
|
26
|
+
const newDash = { ...dash };
|
|
27
|
+
delete newDash.panels;
|
|
28
|
+
return newDash;
|
|
29
|
+
});
|
|
30
|
+
await Promise.all(filteredDashboards.map(async (dashboard) => {
|
|
31
|
+
try {
|
|
32
|
+
await sdk_2.api.client.request((0, sdk_1.createDashboard)(dashboard));
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
(0, catch_error_1.default)(error);
|
|
36
|
+
}
|
|
37
|
+
}));
|
|
38
|
+
await loadPanels(dir);
|
|
39
|
+
core_1.ux.action.stop();
|
|
40
|
+
}
|
|
39
41
|
}
|
|
40
42
|
exports.default = loadDashboards;
|
|
41
43
|
async function loadPanels(dir) {
|
|
@@ -37,12 +37,12 @@ async function loadSkeletonRecords(dir) {
|
|
|
37
37
|
// Filter out existing records
|
|
38
38
|
const newData = data.filter(entry => !existingPrimaryKeys.has(entry[primaryKeyField]));
|
|
39
39
|
if (newData.length === 0) {
|
|
40
|
-
|
|
40
|
+
// ux.log(`${ux.colorize('dim', '--')} Skipping ${name}: No new records to add`)
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
43
43
|
const batches = (0, chunk_array_1.chunkArray)(newData, BATCH_SIZE).map(batch => batch.map(entry => ({ [primaryKeyField]: entry[primaryKeyField] })));
|
|
44
44
|
await Promise.all(batches.map(batch => uploadBatch(name, batch, sdk_1.createItems)));
|
|
45
|
-
|
|
45
|
+
// ux.log(`${ux.colorize('dim', '--')} Added ${newData.length} new skeleton records to ${name}`)
|
|
46
46
|
}));
|
|
47
47
|
core_1.ux.action.status = 'Loaded skeleton records';
|
|
48
48
|
}
|
|
@@ -108,8 +108,8 @@ async function loadSingletons(dir) {
|
|
|
108
108
|
const sourceDir = node_path_1.default.resolve(dir, 'content');
|
|
109
109
|
const data = (0, read_file_1.default)(name, sourceDir);
|
|
110
110
|
try {
|
|
111
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
112
111
|
const { user_created, user_updated, ...cleanedData } = data;
|
|
112
|
+
// @ts-expect-error
|
|
113
113
|
await sdk_2.api.client.request((0, sdk_1.updateSingleton)(name, cleanedData));
|
|
114
114
|
}
|
|
115
115
|
catch (error) {
|
|
@@ -13,52 +13,48 @@ const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
|
13
13
|
async function loadFiles(dir) {
|
|
14
14
|
const files = (0, read_file_1.default)('files', dir);
|
|
15
15
|
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${files.length} files`));
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
form.append('
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}));
|
|
59
|
-
}
|
|
60
|
-
catch (error) {
|
|
61
|
-
(0, catch_error_1.default)(error);
|
|
16
|
+
if (files && files.length > 0) {
|
|
17
|
+
try {
|
|
18
|
+
// Fetch only the files we're interested in
|
|
19
|
+
const existingFiles = await sdk_2.api.client.request((0, sdk_1.readFiles)({
|
|
20
|
+
fields: ['id', 'filename_disk'],
|
|
21
|
+
limit: -1,
|
|
22
|
+
}));
|
|
23
|
+
const existingFileIds = new Set(existingFiles.map(file => file.id));
|
|
24
|
+
const existingFileNames = new Set(existingFiles.map(file => file.filename_disk));
|
|
25
|
+
const filesToUpload = files.filter(file => {
|
|
26
|
+
if (existingFileIds.has(file.id)) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
if (existingFileNames.has(file.filename_disk)) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
return true;
|
|
33
|
+
});
|
|
34
|
+
await Promise.all(filesToUpload.map(async (asset) => {
|
|
35
|
+
const fileName = asset.filename_disk;
|
|
36
|
+
const assetPath = node_path_1.default.resolve(dir, 'assets', fileName);
|
|
37
|
+
const fileStream = new Blob([(0, node_fs_1.readFileSync)(assetPath)], { type: asset.type });
|
|
38
|
+
const form = new formdata_node_1.FormData();
|
|
39
|
+
form.append('id', asset.id);
|
|
40
|
+
if (asset.title)
|
|
41
|
+
form.append('title', asset.title);
|
|
42
|
+
if (asset.description)
|
|
43
|
+
form.append('description', asset.description);
|
|
44
|
+
if (asset.folder)
|
|
45
|
+
form.append('folder', asset.folder);
|
|
46
|
+
form.append('file', fileStream, fileName);
|
|
47
|
+
try {
|
|
48
|
+
await sdk_2.api.client.request((0, sdk_1.uploadFiles)(form));
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
(0, catch_error_1.default)(error);
|
|
52
|
+
}
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
(0, catch_error_1.default)(error);
|
|
57
|
+
}
|
|
62
58
|
}
|
|
63
59
|
core_1.ux.action.stop();
|
|
64
60
|
}
|
|
@@ -10,47 +10,48 @@ const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
|
|
|
10
10
|
const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
11
11
|
async function loadFlows(dir) {
|
|
12
12
|
const flows = (0, read_file_1.default)('flows', dir);
|
|
13
|
+
const allOperations = (0, read_file_1.default)('operations', dir);
|
|
13
14
|
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${flows.length} flows`));
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
else {
|
|
32
|
-
(0, catch_error_1.default)(result.reason);
|
|
15
|
+
if (flows && flows.length > 0) {
|
|
16
|
+
try {
|
|
17
|
+
// Fetch existing flows
|
|
18
|
+
const existingFlows = await sdk_2.api.client.request((0, sdk_1.readFlows)({
|
|
19
|
+
limit: -1,
|
|
20
|
+
}));
|
|
21
|
+
const existingFlowIds = new Set(existingFlows.map(flow => flow.id));
|
|
22
|
+
const newFlows = flows.filter(flow => !existingFlowIds.has(flow.id));
|
|
23
|
+
const results = await Promise.allSettled(newFlows.map(flow => sdk_2.api.client.request((0, sdk_1.createFlow)(flow))));
|
|
24
|
+
const createdFlowIds = new Set();
|
|
25
|
+
for (const [index, result] of results.entries()) {
|
|
26
|
+
if (result.status === 'fulfilled') {
|
|
27
|
+
createdFlowIds.add(newFlows[index].id);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
(0, catch_error_1.default)(result.reason);
|
|
31
|
+
}
|
|
33
32
|
}
|
|
33
|
+
// Filter operations for newly created flows
|
|
34
|
+
const newOperations = allOperations.filter(operation => createdFlowIds.has(operation.flow));
|
|
35
|
+
await loadOperations(newOperations);
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
(0, catch_error_1.default)(error);
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
core_1.ux.action.stop();
|
|
34
42
|
}
|
|
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();
|
|
46
43
|
}
|
|
47
44
|
}
|
|
48
45
|
exports.default = loadFlows;
|
|
49
46
|
async function loadOperations(operations) {
|
|
50
47
|
core_1.ux.action.status = `Loading ${operations.length} operations`;
|
|
51
48
|
try {
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
const opsIds = operations.map(operation => {
|
|
50
|
+
const opCopy = { ...operation };
|
|
51
|
+
delete opCopy.reject;
|
|
52
|
+
delete opCopy.resolve;
|
|
53
|
+
return opCopy;
|
|
54
|
+
});
|
|
54
55
|
await sdk_2.api.client.request((0, sdk_1.createOperations)(opsIds));
|
|
55
56
|
const results = await Promise.allSettled(operations.map(operation => sdk_2.api.client.request((0, sdk_1.updateOperation)(operation.id, {
|
|
56
57
|
reject: operation.reject,
|
|
@@ -10,40 +10,42 @@ const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
|
10
10
|
async function loadFolders(dir) {
|
|
11
11
|
const folders = (0, read_file_1.default)('folders', dir);
|
|
12
12
|
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${folders.length} folders`));
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const existingFolderIds = new Set(existingFolders.map(folder => folder.id));
|
|
19
|
-
const foldersToAdd = folders.filter(folder => {
|
|
20
|
-
if (existingFolderIds.has(folder.id)) {
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
return true;
|
|
24
|
-
});
|
|
25
|
-
if (foldersToAdd.length > 0) {
|
|
26
|
-
const folderSkeleton = foldersToAdd.map(folder => ({ id: folder.id, name: folder.name }));
|
|
27
|
-
// Create the folders
|
|
28
|
-
await sdk_2.api.client.request((0, sdk_1.createFolders)(folderSkeleton));
|
|
29
|
-
// Update the folders with relationships concurrently
|
|
30
|
-
await Promise.all(foldersToAdd.map(async (folder) => {
|
|
31
|
-
const { id, ...rest } = folder;
|
|
32
|
-
try {
|
|
33
|
-
await sdk_2.api.client.request((0, sdk_1.updateFolder)(id, rest));
|
|
34
|
-
}
|
|
35
|
-
catch (error) {
|
|
36
|
-
(0, catch_error_1.default)(error);
|
|
37
|
-
}
|
|
13
|
+
if (folders && folders.length > 0) {
|
|
14
|
+
try {
|
|
15
|
+
// Fetch existing folders
|
|
16
|
+
const existingFolders = await sdk_2.api.client.request((0, sdk_1.readFolders)({
|
|
17
|
+
limit: -1,
|
|
38
18
|
}));
|
|
19
|
+
const existingFolderIds = new Set(existingFolders.map(folder => folder.id));
|
|
20
|
+
const foldersToAdd = folders.filter(folder => {
|
|
21
|
+
if (existingFolderIds.has(folder.id)) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
return true;
|
|
25
|
+
});
|
|
26
|
+
if (foldersToAdd.length > 0) {
|
|
27
|
+
const folderSkeleton = foldersToAdd.map(folder => ({ id: folder.id, name: folder.name }));
|
|
28
|
+
// Create the folders
|
|
29
|
+
await sdk_2.api.client.request((0, sdk_1.createFolders)(folderSkeleton));
|
|
30
|
+
// Update the folders with relationships concurrently
|
|
31
|
+
await Promise.all(foldersToAdd.map(async (folder) => {
|
|
32
|
+
const { id, ...rest } = folder;
|
|
33
|
+
try {
|
|
34
|
+
await sdk_2.api.client.request((0, sdk_1.updateFolder)(id, rest));
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
(0, catch_error_1.default)(error);
|
|
38
|
+
}
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
// ux.info('-- No new folders to create')
|
|
43
|
+
}
|
|
39
44
|
}
|
|
40
|
-
|
|
41
|
-
|
|
45
|
+
catch (error) {
|
|
46
|
+
(0, catch_error_1.default)(error);
|
|
42
47
|
}
|
|
43
48
|
}
|
|
44
|
-
catch (error) {
|
|
45
|
-
(0, catch_error_1.default)(error);
|
|
46
|
-
}
|
|
47
49
|
core_1.ux.action.stop();
|
|
48
50
|
}
|
|
49
51
|
exports.default = loadFolders;
|
|
@@ -10,19 +10,21 @@ const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
|
10
10
|
async function loadPermissions(dir) {
|
|
11
11
|
const permissions = (0, read_file_1.default)('permissions', dir);
|
|
12
12
|
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${permissions.length} permissions`));
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
if (permissions && permissions.length > 0) {
|
|
14
|
+
try {
|
|
15
|
+
const existingPermissions = await sdk_2.api.client.request((0, sdk_1.readPermissions)({
|
|
16
|
+
limit: -1,
|
|
17
|
+
}));
|
|
18
|
+
const existingPermissionKeys = new Set(existingPermissions.map(p => `${p.collection}:${p.action}:${p.policy}`));
|
|
19
|
+
// Filter out duplicates
|
|
20
|
+
const newPermissions = permissions.filter(newPerm => !existingPermissionKeys.has(`${newPerm.collection}:${newPerm.action}:${newPerm.policy}`));
|
|
21
|
+
if (newPermissions.length > 0) {
|
|
22
|
+
await sdk_2.api.client.request((0, sdk_1.createPermissions)(newPermissions));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
(0, catch_error_1.default)(error);
|
|
22
27
|
}
|
|
23
|
-
}
|
|
24
|
-
catch (error) {
|
|
25
|
-
(0, catch_error_1.default)(error);
|
|
26
28
|
}
|
|
27
29
|
core_1.ux.action.stop();
|
|
28
30
|
}
|