directus-template-cli 0.7.0-beta.3 → 0.7.0-beta.5
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/bin/dev +2 -3
- package/bin/dev.js +3 -0
- package/bin/run +0 -1
- package/bin/run.js +5 -0
- package/dist/commands/apply.d.ts +17 -17
- package/dist/commands/apply.js +160 -173
- package/dist/commands/extract.d.ts +13 -7
- package/dist/commands/extract.js +89 -73
- package/dist/commands/init.d.ts +7 -7
- package/dist/commands/init.js +78 -80
- package/dist/flags/common.d.ts +7 -7
- package/dist/flags/common.js +8 -11
- package/dist/index.js +1 -5
- package/dist/lib/constants.js +6 -9
- package/dist/lib/extract/extract-access.js +11 -15
- package/dist/lib/extract/extract-assets.js +20 -25
- package/dist/lib/extract/extract-collections.js +12 -16
- package/dist/lib/extract/extract-content.js +14 -19
- package/dist/lib/extract/extract-dashboards.js +22 -28
- package/dist/lib/extract/extract-extensions.js +12 -16
- package/dist/lib/extract/extract-fields.js +13 -17
- package/dist/lib/extract/extract-files.js +15 -19
- package/dist/lib/extract/extract-flows.js +22 -28
- package/dist/lib/extract/extract-folders.js +15 -19
- package/dist/lib/extract/extract-permissions.js +12 -16
- package/dist/lib/extract/extract-policies.js +12 -16
- package/dist/lib/extract/extract-presets.js +12 -16
- package/dist/lib/extract/extract-relations.js +14 -18
- package/dist/lib/extract/extract-roles.js +15 -19
- package/dist/lib/extract/extract-schema.js +17 -21
- package/dist/lib/extract/extract-settings.js +12 -16
- package/dist/lib/extract/extract-translations.js +12 -16
- package/dist/lib/extract/extract-users.js +15 -19
- package/dist/lib/extract/index.js +47 -51
- package/dist/lib/init/config.d.ts +1 -1
- package/dist/lib/init/config.js +2 -5
- package/dist/lib/init/index.js +54 -59
- package/dist/lib/init/types.js +1 -2
- package/dist/lib/init.d.ts +1 -0
- package/dist/lib/init.js +2 -0
- package/dist/lib/load/apply-flags.js +17 -23
- package/dist/lib/load/index.js +40 -44
- package/dist/lib/load/load-access.js +15 -20
- package/dist/lib/load/load-collections.js +27 -32
- package/dist/lib/load/load-dashboards.js +19 -25
- package/dist/lib/load/load-data.js +43 -49
- package/dist/lib/load/load-extensions.js +30 -38
- package/dist/lib/load/load-files.js +20 -24
- package/dist/lib/load/load-flows.js +23 -29
- package/dist/lib/load/load-folders.js +16 -20
- package/dist/lib/load/load-permissions.js +13 -17
- package/dist/lib/load/load-policies.js +14 -18
- package/dist/lib/load/load-presets.js +14 -18
- package/dist/lib/load/load-relations.d.ts +2 -0
- package/dist/lib/load/load-relations.js +16 -18
- package/dist/lib/load/load-roles.js +19 -23
- package/dist/lib/load/load-settings.js +18 -21
- package/dist/lib/load/load-translations.js +14 -18
- package/dist/lib/load/load-users.js +21 -25
- package/dist/lib/load/update-required-fields.js +13 -17
- package/dist/lib/sdk.d.ts +1 -2
- package/dist/lib/sdk.js +27 -27
- package/dist/lib/types/extension.js +1 -2
- package/dist/lib/utils/animated-bunny.js +9 -14
- package/dist/lib/utils/auth.d.ts +2 -2
- package/dist/lib/utils/auth.js +32 -33
- package/dist/lib/utils/catch-error.js +8 -11
- package/dist/lib/utils/check-template.js +4 -8
- package/dist/lib/utils/chunk-array.js +1 -5
- package/dist/lib/utils/ensure-dir.js +7 -12
- package/dist/lib/utils/filter-fields.js +1 -4
- package/dist/lib/utils/get-role-ids.d.ts +1 -1
- package/dist/lib/utils/get-role-ids.js +7 -12
- package/dist/lib/utils/get-template.js +33 -37
- package/dist/lib/utils/logger.js +11 -13
- package/dist/lib/utils/open-url.js +5 -8
- package/dist/lib/utils/parse-github-url.js +4 -9
- package/dist/lib/utils/path.js +6 -10
- package/dist/lib/utils/protected-domains.js +1 -4
- package/dist/lib/utils/read-file.js +8 -12
- package/dist/lib/utils/read-templates.js +9 -15
- package/dist/lib/utils/system-fields.js +19 -22
- package/dist/lib/utils/template-defaults.d.ts +1 -1
- package/dist/lib/utils/template-defaults.js +5 -14
- package/dist/lib/utils/transform-github-url.js +1 -5
- package/dist/lib/utils/validate-url.js +3 -6
- package/dist/lib/utils/wait.js +1 -5
- package/dist/lib/utils/write-to-file.js +8 -11
- package/dist/services/docker.js +19 -24
- package/dist/services/github.d.ts +1 -1
- package/dist/services/github.js +8 -12
- package/oclif.manifest.json +4 -4
- package/package.json +36 -32
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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 = [
|
|
1
|
+
import { ux } from '@oclif/core';
|
|
2
|
+
import catchError from '../utils/catch-error.js';
|
|
3
|
+
export const loadFlags = [
|
|
8
4
|
'content',
|
|
9
5
|
'dashboards',
|
|
10
6
|
'extensions',
|
|
@@ -15,53 +11,51 @@ exports.loadFlags = [
|
|
|
15
11
|
'settings',
|
|
16
12
|
'users',
|
|
17
13
|
];
|
|
18
|
-
function validateProgrammaticFlags(flags) {
|
|
14
|
+
export function validateProgrammaticFlags(flags) {
|
|
19
15
|
const { directusToken, directusUrl, templateLocation, userEmail, userPassword } = flags;
|
|
20
16
|
if (!directusUrl)
|
|
21
|
-
|
|
17
|
+
ux.error('Directus URL is required for programmatic mode.');
|
|
22
18
|
if (!directusToken && (!userEmail || !userPassword))
|
|
23
|
-
|
|
19
|
+
ux.error('Either Directus token or email and password are required for programmatic mode.');
|
|
24
20
|
if (!templateLocation)
|
|
25
|
-
|
|
21
|
+
ux.error('Template location is required for programmatic mode.');
|
|
26
22
|
return flags.partial ? handlePartialFlags(flags) : setAllFlagsTrue(flags);
|
|
27
23
|
}
|
|
28
|
-
|
|
29
|
-
function validateInteractiveFlags(flags) {
|
|
24
|
+
export function validateInteractiveFlags(flags) {
|
|
30
25
|
return flags.partial ? handlePartialFlags(flags) : setAllFlagsTrue(flags);
|
|
31
26
|
}
|
|
32
|
-
exports.validateInteractiveFlags = validateInteractiveFlags;
|
|
33
27
|
function handlePartialFlags(flags) {
|
|
34
|
-
const enabledFlags =
|
|
35
|
-
const disabledFlags =
|
|
28
|
+
const enabledFlags = loadFlags.filter(flag => flags[flag] === true);
|
|
29
|
+
const disabledFlags = loadFlags.filter(flag => flags[flag] === false);
|
|
36
30
|
if (enabledFlags.length > 0) {
|
|
37
|
-
for (const flag of
|
|
31
|
+
for (const flag of loadFlags)
|
|
38
32
|
flags[flag] = enabledFlags.includes(flag);
|
|
39
33
|
}
|
|
40
34
|
else if (disabledFlags.length > 0) {
|
|
41
|
-
for (const flag of
|
|
35
|
+
for (const flag of loadFlags)
|
|
42
36
|
flags[flag] = !disabledFlags.includes(flag);
|
|
43
37
|
}
|
|
44
38
|
else {
|
|
45
39
|
setAllFlagsTrue(flags);
|
|
46
40
|
}
|
|
47
41
|
handleDependencies(flags);
|
|
48
|
-
if (!
|
|
49
|
-
(
|
|
42
|
+
if (!loadFlags.some(flag => flags[flag])) {
|
|
43
|
+
catchError(new Error('When using --partial, at least one component must be loaded.'), { fatal: true });
|
|
50
44
|
}
|
|
51
45
|
return flags;
|
|
52
46
|
}
|
|
53
47
|
function handleDependencies(flags) {
|
|
54
48
|
if (flags.content && (!flags.schema || !flags.files)) {
|
|
55
49
|
flags.schema = flags.files = true;
|
|
56
|
-
|
|
50
|
+
ux.warn('Content loading requires schema and files. Enabling schema and files flags.');
|
|
57
51
|
}
|
|
58
52
|
if (flags.users && !flags.permissions) {
|
|
59
53
|
flags.permissions = true;
|
|
60
|
-
|
|
54
|
+
ux.warn('User loading requires permissions. Enabling permissions flag.');
|
|
61
55
|
}
|
|
62
56
|
}
|
|
63
57
|
function setAllFlagsTrue(flags) {
|
|
64
|
-
for (const flag of
|
|
58
|
+
for (const flag of loadFlags)
|
|
65
59
|
flags[flag] = true;
|
|
66
60
|
return flags;
|
|
67
61
|
}
|
package/dist/lib/load/index.js
CHANGED
|
@@ -1,68 +1,64 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
async function apply(dir, flags) {
|
|
24
|
-
const source = dir + '/src';
|
|
25
|
-
const isTemplateOk = await (0, check_template_1.default)(source);
|
|
1
|
+
import { ux } from '@oclif/core';
|
|
2
|
+
import checkTemplate from '../utils/check-template.js';
|
|
3
|
+
import loadAccess from './load-access.js';
|
|
4
|
+
import loadCollections from './load-collections.js';
|
|
5
|
+
import loadDashboards from './load-dashboards.js';
|
|
6
|
+
import loadData from './load-data.js';
|
|
7
|
+
import loadExtensions from './load-extensions.js';
|
|
8
|
+
import loadFiles from './load-files.js';
|
|
9
|
+
import loadFlows from './load-flows.js';
|
|
10
|
+
import loadFolders from './load-folders.js';
|
|
11
|
+
import loadPermissions from './load-permissions.js';
|
|
12
|
+
import loadPolicies from './load-policies.js';
|
|
13
|
+
import loadPresets from './load-presets.js';
|
|
14
|
+
import loadRelations from './load-relations.js';
|
|
15
|
+
import loadRoles from './load-roles.js';
|
|
16
|
+
import loadSettings from './load-settings.js';
|
|
17
|
+
import loadTranslations from './load-translations.js';
|
|
18
|
+
import loadUsers from './load-users.js';
|
|
19
|
+
import updateRequiredFields from './update-required-fields.js';
|
|
20
|
+
export default async function apply(dir, flags) {
|
|
21
|
+
const source = `${dir}/src`;
|
|
22
|
+
const isTemplateOk = await checkTemplate(source);
|
|
26
23
|
if (!isTemplateOk) {
|
|
27
|
-
|
|
24
|
+
ux.error('The template is missing the collections, fields, or relations files. Older templates are not supported in v0.4 of directus-template-cli. Try using v0.3 to load older templates npx directus-template-cli@0.3 apply or extract the template using latest version before applying. Exiting...');
|
|
28
25
|
}
|
|
29
26
|
if (flags.schema) {
|
|
30
|
-
await (
|
|
31
|
-
await (
|
|
27
|
+
await loadCollections(source);
|
|
28
|
+
await loadRelations(source);
|
|
32
29
|
}
|
|
33
30
|
if (flags.permissions || flags.users) {
|
|
34
|
-
await (
|
|
35
|
-
await (
|
|
36
|
-
await (
|
|
31
|
+
await loadRoles(source);
|
|
32
|
+
await loadPolicies(source);
|
|
33
|
+
await loadPermissions(source);
|
|
37
34
|
if (flags.users) {
|
|
38
|
-
await (
|
|
35
|
+
await loadUsers(source);
|
|
39
36
|
}
|
|
40
|
-
await (
|
|
37
|
+
await loadAccess(source);
|
|
41
38
|
}
|
|
42
39
|
if (flags.files) {
|
|
43
|
-
await (
|
|
44
|
-
await (
|
|
40
|
+
await loadFolders(source);
|
|
41
|
+
await loadFiles(source);
|
|
45
42
|
}
|
|
46
43
|
if (flags.content) {
|
|
47
|
-
await (
|
|
44
|
+
await loadData(source);
|
|
48
45
|
}
|
|
49
46
|
if (flags.schema) {
|
|
50
|
-
await (
|
|
47
|
+
await updateRequiredFields(source);
|
|
51
48
|
}
|
|
52
49
|
if (flags.dashboards) {
|
|
53
|
-
await (
|
|
50
|
+
await loadDashboards(source);
|
|
54
51
|
}
|
|
55
52
|
if (flags.flows) {
|
|
56
|
-
await (
|
|
53
|
+
await loadFlows(source);
|
|
57
54
|
}
|
|
58
55
|
if (flags.settings) {
|
|
59
|
-
await (
|
|
60
|
-
await (
|
|
61
|
-
await (
|
|
56
|
+
await loadSettings(source);
|
|
57
|
+
await loadTranslations(source);
|
|
58
|
+
await loadPresets(source);
|
|
62
59
|
}
|
|
63
60
|
if (flags.extensions) {
|
|
64
|
-
await (
|
|
61
|
+
await loadExtensions(source);
|
|
65
62
|
}
|
|
66
63
|
return {};
|
|
67
64
|
}
|
|
68
|
-
exports.default = apply;
|
|
@@ -1,25 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
async function loadAccess(dir) {
|
|
11
|
-
const access = (0, read_file_1.default)('access', dir);
|
|
12
|
-
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${access.length} accesses`));
|
|
1
|
+
import { ux } from '@oclif/core';
|
|
2
|
+
import { DIRECTUS_PINK } from '../constants.js';
|
|
3
|
+
import { api } from '../sdk.js';
|
|
4
|
+
import catchError from '../utils/catch-error.js';
|
|
5
|
+
import getRoleIds from '../utils/get-role-ids.js';
|
|
6
|
+
import readFile from '../utils/read-file.js';
|
|
7
|
+
export default async function loadAccess(dir) {
|
|
8
|
+
const access = readFile('access', dir);
|
|
9
|
+
ux.action.start(ux.colorize(DIRECTUS_PINK, `Loading ${access.length} accesses`));
|
|
13
10
|
if (access && access.length > 0) {
|
|
14
11
|
// Fetch existing accesses
|
|
15
|
-
const existingAccesses = await
|
|
12
|
+
const existingAccesses = await api.client.request(() => ({
|
|
16
13
|
method: 'GET',
|
|
17
14
|
params: {
|
|
18
15
|
limit: -1,
|
|
19
16
|
},
|
|
20
17
|
path: '/access',
|
|
21
18
|
}));
|
|
22
|
-
const { legacyAdminRoleId, newAdminRoleId } = await (
|
|
19
|
+
const { legacyAdminRoleId, newAdminRoleId } = await getRoleIds(dir);
|
|
23
20
|
const existingAccessById = new Map(existingAccesses.map(acc => [acc.id, acc]));
|
|
24
21
|
const existingAccessByCompositeKey = new Map(existingAccesses.map(acc => [getCompositeKey(acc), acc]));
|
|
25
22
|
for await (const acc of access) {
|
|
@@ -39,7 +36,7 @@ async function loadAccess(dir) {
|
|
|
39
36
|
if (acc.role === legacyAdminRoleId) {
|
|
40
37
|
acc.role = newAdminRoleId;
|
|
41
38
|
}
|
|
42
|
-
await
|
|
39
|
+
await api.client.request(() => ({
|
|
43
40
|
body: JSON.stringify(acc),
|
|
44
41
|
method: 'POST',
|
|
45
42
|
path: '/access',
|
|
@@ -49,7 +46,7 @@ async function loadAccess(dir) {
|
|
|
49
46
|
existingAccessByCompositeKey.set(compositeKey, acc);
|
|
50
47
|
}
|
|
51
48
|
catch (error) {
|
|
52
|
-
(
|
|
49
|
+
catchError(error, {
|
|
53
50
|
context: {
|
|
54
51
|
access: acc,
|
|
55
52
|
operation: 'createAccess',
|
|
@@ -58,11 +55,9 @@ async function loadAccess(dir) {
|
|
|
58
55
|
}
|
|
59
56
|
}
|
|
60
57
|
}
|
|
61
|
-
|
|
58
|
+
ux.action.stop();
|
|
62
59
|
}
|
|
63
|
-
exports.default = loadAccess;
|
|
64
60
|
// Helper function to generate a composite key for each access
|
|
65
61
|
function getCompositeKey(acc) {
|
|
66
|
-
|
|
67
|
-
return `${(_a = acc.role) !== null && _a !== void 0 ? _a : 'null'}-${(_b = acc.user) !== null && _b !== void 0 ? _b : 'null'}-${acc.policy}`;
|
|
62
|
+
return `${acc.role ?? 'null'}-${acc.user ?? 'null'}-${acc.policy}`;
|
|
68
63
|
}
|
|
@@ -1,50 +1,45 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const sdk_2 = require("../sdk");
|
|
8
|
-
const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
|
|
9
|
-
const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
1
|
+
import { createCollection, createField, readCollections, readFields, updateCollection, } from '@directus/sdk';
|
|
2
|
+
import { ux } from '@oclif/core';
|
|
3
|
+
import { DIRECTUS_PINK } from '../constants.js';
|
|
4
|
+
import { api } from '../sdk.js';
|
|
5
|
+
import catchError from '../utils/catch-error.js';
|
|
6
|
+
import readFile from '../utils/read-file.js';
|
|
10
7
|
/**
|
|
11
8
|
* Load collections into the Directus instance
|
|
12
9
|
* @param dir - The directory to read the collections and fields from
|
|
13
10
|
* @returns {Promise<void>} - Returns nothing
|
|
14
11
|
*/
|
|
15
|
-
async function loadCollections(dir) {
|
|
16
|
-
const collectionsToAdd = (
|
|
17
|
-
const fieldsToAdd = (
|
|
18
|
-
|
|
12
|
+
export default async function loadCollections(dir) {
|
|
13
|
+
const collectionsToAdd = readFile('collections', dir);
|
|
14
|
+
const fieldsToAdd = readFile('fields', dir);
|
|
15
|
+
ux.action.start(ux.colorize(DIRECTUS_PINK, `Loading ${collectionsToAdd.length} collections and ${fieldsToAdd.length} fields`));
|
|
19
16
|
await processCollections(collectionsToAdd, fieldsToAdd);
|
|
20
17
|
await updateCollections(collectionsToAdd);
|
|
21
18
|
await addCustomFieldsOnSystemCollections(fieldsToAdd);
|
|
22
|
-
|
|
19
|
+
ux.action.stop();
|
|
23
20
|
}
|
|
24
|
-
exports.default = loadCollections;
|
|
25
21
|
async function processCollections(collectionsToAdd, fieldsToAdd) {
|
|
26
|
-
const existingCollections = await
|
|
27
|
-
const existingFields = await
|
|
22
|
+
const existingCollections = await api.client.request(readCollections());
|
|
23
|
+
const existingFields = await api.client.request(readFields());
|
|
28
24
|
for await (const collection of collectionsToAdd) {
|
|
29
25
|
try {
|
|
30
26
|
const existingCollection = existingCollections.find((c) => c.collection === collection.collection);
|
|
31
27
|
await (existingCollection ? addNewFieldsToExistingCollection(collection.collection, fieldsToAdd, existingFields) : addNewCollectionWithFields(collection, fieldsToAdd));
|
|
32
28
|
}
|
|
33
29
|
catch (error) {
|
|
34
|
-
(
|
|
30
|
+
catchError(error);
|
|
35
31
|
}
|
|
36
32
|
}
|
|
37
33
|
}
|
|
38
34
|
const removeRequiredorIsNullable = (field) => {
|
|
39
|
-
|
|
40
|
-
if (((_a = field.meta) === null || _a === void 0 ? void 0 : _a.required) === true) {
|
|
35
|
+
if (field.meta?.required === true) {
|
|
41
36
|
field.meta.required = false;
|
|
42
37
|
}
|
|
43
|
-
if (
|
|
38
|
+
if (field.schema?.is_nullable === false) {
|
|
44
39
|
// eslint-disable-next-line camelcase
|
|
45
40
|
field.schema.is_nullable = true;
|
|
46
41
|
}
|
|
47
|
-
if (
|
|
42
|
+
if (field.schema?.is_unique === true) {
|
|
48
43
|
// eslint-disable-next-line camelcase
|
|
49
44
|
field.schema.is_unique = false;
|
|
50
45
|
}
|
|
@@ -59,7 +54,7 @@ async function addNewCollectionWithFields(collection, allFields) {
|
|
|
59
54
|
meta: { ...collection.meta },
|
|
60
55
|
};
|
|
61
56
|
delete collectionWithoutGroup.meta.group;
|
|
62
|
-
await
|
|
57
|
+
await api.client.request(createCollection(collectionWithoutGroup));
|
|
63
58
|
}
|
|
64
59
|
async function addNewFieldsToExistingCollection(collectionName, fieldsToAdd, existingFields) {
|
|
65
60
|
const collectionFieldsToAdd = fieldsToAdd.filter(field => field.collection === collectionName)
|
|
@@ -68,11 +63,11 @@ async function addNewFieldsToExistingCollection(collectionName, fieldsToAdd, exi
|
|
|
68
63
|
for await (const field of collectionFieldsToAdd) {
|
|
69
64
|
if (!existingCollectionFields.some((existingField) => existingField.field === field.field)) {
|
|
70
65
|
try {
|
|
71
|
-
// @ts-ignore
|
|
72
|
-
await
|
|
66
|
+
// @ts-ignore - ignore
|
|
67
|
+
await api.client.request(createField(collectionName, field));
|
|
73
68
|
}
|
|
74
69
|
catch (error) {
|
|
75
|
-
(
|
|
70
|
+
catchError(error);
|
|
76
71
|
}
|
|
77
72
|
}
|
|
78
73
|
}
|
|
@@ -86,27 +81,27 @@ async function updateCollections(collections) {
|
|
|
86
81
|
group: collection.meta.group,
|
|
87
82
|
},
|
|
88
83
|
};
|
|
89
|
-
await
|
|
84
|
+
await api.client.request(updateCollection(collection.collection, pl));
|
|
90
85
|
}
|
|
91
86
|
}
|
|
92
87
|
catch (error) {
|
|
93
|
-
(
|
|
88
|
+
catchError(error);
|
|
94
89
|
}
|
|
95
90
|
}
|
|
96
91
|
}
|
|
97
92
|
async function addCustomFieldsOnSystemCollections(fields) {
|
|
98
93
|
const customFields = fields.filter((field) => field.collection.startsWith('directus_'));
|
|
99
|
-
const existingFields = await
|
|
94
|
+
const existingFields = await api.client.request(readFields());
|
|
100
95
|
for await (const field of customFields) {
|
|
101
96
|
try {
|
|
102
97
|
const fieldExists = existingFields.some((existingField) => existingField.collection === field.collection && existingField.field === field.field);
|
|
103
98
|
if (!fieldExists) {
|
|
104
|
-
// @ts-
|
|
105
|
-
await
|
|
99
|
+
// @ts-ignore
|
|
100
|
+
await api.client.request(createField(field.collection, field));
|
|
106
101
|
}
|
|
107
102
|
}
|
|
108
103
|
catch (error) {
|
|
109
|
-
(
|
|
104
|
+
catchError(error);
|
|
110
105
|
}
|
|
111
106
|
}
|
|
112
107
|
}
|
|
@@ -1,19 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
11
|
-
async function loadDashboards(dir) {
|
|
12
|
-
const dashboards = (0, read_file_1.default)('dashboards', dir);
|
|
13
|
-
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${dashboards.length} dashboards`));
|
|
1
|
+
import { createDashboard, createPanel, readDashboards, readPanels } from '@directus/sdk';
|
|
2
|
+
import { ux } from '@oclif/core';
|
|
3
|
+
import { DIRECTUS_PINK } from '../constants.js';
|
|
4
|
+
import { api } from '../sdk.js';
|
|
5
|
+
import catchError from '../utils/catch-error.js';
|
|
6
|
+
import readFile from '../utils/read-file.js';
|
|
7
|
+
export default async function loadDashboards(dir) {
|
|
8
|
+
const dashboards = readFile('dashboards', dir);
|
|
9
|
+
ux.action.start(ux.colorize(DIRECTUS_PINK, `Loading ${dashboards.length} dashboards`));
|
|
14
10
|
if (dashboards && dashboards.length > 0) {
|
|
15
11
|
// Fetch existing dashboards
|
|
16
|
-
const existingDashboards = await
|
|
12
|
+
const existingDashboards = await api.client.request(readDashboards({
|
|
17
13
|
limit: -1,
|
|
18
14
|
}));
|
|
19
15
|
const existingDashboardIds = new Set(existingDashboards.map(dashboard => dashboard.id));
|
|
@@ -29,22 +25,21 @@ async function loadDashboards(dir) {
|
|
|
29
25
|
});
|
|
30
26
|
await Promise.all(filteredDashboards.map(async (dashboard) => {
|
|
31
27
|
try {
|
|
32
|
-
await
|
|
28
|
+
await api.client.request(createDashboard(dashboard));
|
|
33
29
|
}
|
|
34
30
|
catch (error) {
|
|
35
|
-
(
|
|
31
|
+
catchError(error);
|
|
36
32
|
}
|
|
37
33
|
}));
|
|
38
34
|
await loadPanels(dir);
|
|
39
|
-
|
|
35
|
+
ux.action.stop();
|
|
40
36
|
}
|
|
41
37
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
core_1.ux.action.status = `Loading ${panels.length} panels`;
|
|
38
|
+
export async function loadPanels(dir) {
|
|
39
|
+
const panels = readFile('panels', dir);
|
|
40
|
+
ux.action.status = `Loading ${panels.length} panels`;
|
|
46
41
|
// Fetch existing panels
|
|
47
|
-
const existingPanels = await
|
|
42
|
+
const existingPanels = await api.client.request(readPanels({
|
|
48
43
|
limit: -1,
|
|
49
44
|
}));
|
|
50
45
|
const existingPanelIds = new Set(existingPanels.map(panel => panel.id));
|
|
@@ -56,11 +51,10 @@ async function loadPanels(dir) {
|
|
|
56
51
|
});
|
|
57
52
|
await Promise.all(filteredPanels.map(async (panel) => {
|
|
58
53
|
try {
|
|
59
|
-
await
|
|
54
|
+
await api.client.request(createPanel(panel));
|
|
60
55
|
}
|
|
61
56
|
catch (error) {
|
|
62
|
-
(
|
|
57
|
+
catchError(error);
|
|
63
58
|
}
|
|
64
59
|
}));
|
|
65
60
|
}
|
|
66
|
-
exports.loadPanels = loadPanels;
|
|
@@ -1,27 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
|
|
10
|
-
const chunk_array_1 = require("../utils/chunk-array");
|
|
11
|
-
const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
1
|
+
import { createItems, readItems, updateItemsBatch, updateSingleton } from '@directus/sdk';
|
|
2
|
+
import { ux } from '@oclif/core';
|
|
3
|
+
import path from 'pathe';
|
|
4
|
+
import { DIRECTUS_PINK } from '../constants.js';
|
|
5
|
+
import { api } from '../sdk.js';
|
|
6
|
+
import catchError from '../utils/catch-error.js';
|
|
7
|
+
import { chunkArray } from '../utils/chunk-array.js';
|
|
8
|
+
import readFile from '../utils/read-file.js';
|
|
12
9
|
const BATCH_SIZE = 50;
|
|
13
|
-
async function loadData(dir) {
|
|
14
|
-
const collections = (
|
|
15
|
-
|
|
10
|
+
export default async function loadData(dir) {
|
|
11
|
+
const collections = readFile('collections', dir);
|
|
12
|
+
ux.action.start(ux.colorize(DIRECTUS_PINK, `Loading data for ${collections.length} collections`));
|
|
16
13
|
await loadSkeletonRecords(dir);
|
|
17
14
|
await loadFullData(dir);
|
|
18
15
|
await loadSingletons(dir);
|
|
19
|
-
|
|
16
|
+
ux.action.stop();
|
|
20
17
|
}
|
|
21
|
-
exports.default = loadData;
|
|
22
18
|
async function loadSkeletonRecords(dir) {
|
|
23
|
-
|
|
24
|
-
const collections = (
|
|
19
|
+
ux.action.status = 'Loading skeleton records';
|
|
20
|
+
const collections = readFile('collections', dir);
|
|
25
21
|
const primaryKeyMap = await getCollectionPrimaryKeys(dir);
|
|
26
22
|
const userCollections = collections
|
|
27
23
|
.filter(item => !item.collection.startsWith('directus_', 0))
|
|
@@ -30,21 +26,21 @@ async function loadSkeletonRecords(dir) {
|
|
|
30
26
|
await Promise.all(userCollections.map(async (collection) => {
|
|
31
27
|
const name = collection.collection;
|
|
32
28
|
const primaryKeyField = getPrimaryKey(primaryKeyMap, name);
|
|
33
|
-
const sourceDir =
|
|
34
|
-
const data = (
|
|
29
|
+
const sourceDir = path.resolve(dir, 'content');
|
|
30
|
+
const data = readFile(name, sourceDir);
|
|
35
31
|
// Fetch existing primary keys
|
|
36
32
|
const existingPrimaryKeys = await getExistingPrimaryKeys(name, primaryKeyField);
|
|
37
33
|
// Filter out existing records
|
|
38
34
|
const newData = data.filter(entry => !existingPrimaryKeys.has(entry[primaryKeyField]));
|
|
39
35
|
if (newData.length === 0) {
|
|
40
|
-
// ux.
|
|
36
|
+
// ux.stdout(`${ux.colorize('dim', '--')} Skipping ${name}: No new records to add`)
|
|
41
37
|
return;
|
|
42
38
|
}
|
|
43
|
-
const batches =
|
|
44
|
-
await Promise.all(batches.map(batch => uploadBatch(name, batch,
|
|
45
|
-
// ux.
|
|
39
|
+
const batches = chunkArray(newData, BATCH_SIZE).map(batch => batch.map(entry => ({ [primaryKeyField]: entry[primaryKeyField] })));
|
|
40
|
+
await Promise.all(batches.map(batch => uploadBatch(name, batch, createItems)));
|
|
41
|
+
// ux.stdout(`${ux.colorize('dim', '--')} Added ${newData.length} new skeleton records to ${name}`)
|
|
46
42
|
}));
|
|
47
|
-
|
|
43
|
+
ux.action.status = 'Loaded skeleton records';
|
|
48
44
|
}
|
|
49
45
|
async function getExistingPrimaryKeys(collection, primaryKeyField) {
|
|
50
46
|
const existingKeys = new Set();
|
|
@@ -52,8 +48,8 @@ async function getExistingPrimaryKeys(collection, primaryKeyField) {
|
|
|
52
48
|
const limit = 1000; // Adjust based on your needs and API limits
|
|
53
49
|
while (true) {
|
|
54
50
|
try {
|
|
55
|
-
// @ts-
|
|
56
|
-
const response = await
|
|
51
|
+
// @ts-ignore
|
|
52
|
+
const response = await api.client.request(readItems(collection, {
|
|
57
53
|
fields: [primaryKeyField],
|
|
58
54
|
limit,
|
|
59
55
|
page,
|
|
@@ -67,7 +63,7 @@ async function getExistingPrimaryKeys(collection, primaryKeyField) {
|
|
|
67
63
|
page++;
|
|
68
64
|
}
|
|
69
65
|
catch (error) {
|
|
70
|
-
(
|
|
66
|
+
catchError(error);
|
|
71
67
|
break;
|
|
72
68
|
}
|
|
73
69
|
}
|
|
@@ -75,55 +71,53 @@ async function getExistingPrimaryKeys(collection, primaryKeyField) {
|
|
|
75
71
|
}
|
|
76
72
|
async function uploadBatch(collection, batch, method) {
|
|
77
73
|
try {
|
|
78
|
-
await
|
|
74
|
+
await api.client.request(method(collection, batch));
|
|
79
75
|
}
|
|
80
76
|
catch (error) {
|
|
81
|
-
(
|
|
77
|
+
catchError(error);
|
|
82
78
|
}
|
|
83
79
|
}
|
|
84
80
|
async function loadFullData(dir) {
|
|
85
|
-
|
|
86
|
-
const collections = (
|
|
81
|
+
ux.action.status = 'Updating records with full data';
|
|
82
|
+
const collections = readFile('collections', dir);
|
|
87
83
|
const userCollections = collections
|
|
88
84
|
.filter(item => !item.collection.startsWith('directus_', 0))
|
|
89
85
|
.filter(item => item.schema !== null)
|
|
90
86
|
.filter(item => !item.meta.singleton);
|
|
91
87
|
await Promise.all(userCollections.map(async (collection) => {
|
|
92
88
|
const name = collection.collection;
|
|
93
|
-
const sourceDir =
|
|
94
|
-
const data = (
|
|
95
|
-
const batches =
|
|
96
|
-
await Promise.all(batches.map(batch => uploadBatch(name, batch,
|
|
89
|
+
const sourceDir = path.resolve(dir, 'content');
|
|
90
|
+
const data = readFile(name, sourceDir);
|
|
91
|
+
const batches = chunkArray(data, BATCH_SIZE).map(batch => batch.map(({ user_created, user_updated, ...cleanedRow }) => cleanedRow));
|
|
92
|
+
await Promise.all(batches.map(batch => uploadBatch(name, batch, updateItemsBatch)));
|
|
97
93
|
}));
|
|
98
|
-
|
|
94
|
+
ux.action.status = 'Updated records with full data';
|
|
99
95
|
}
|
|
100
96
|
async function loadSingletons(dir) {
|
|
101
|
-
|
|
102
|
-
const collections = (
|
|
97
|
+
ux.action.status = 'Loading data for singleton collections';
|
|
98
|
+
const collections = readFile('collections', dir);
|
|
103
99
|
const singletonCollections = collections
|
|
104
100
|
.filter(item => !item.collection.startsWith('directus_', 0))
|
|
105
101
|
.filter(item => item.meta.singleton);
|
|
106
102
|
await Promise.all(singletonCollections.map(async (collection) => {
|
|
107
103
|
const name = collection.collection;
|
|
108
|
-
const sourceDir =
|
|
109
|
-
const data = (
|
|
104
|
+
const sourceDir = path.resolve(dir, 'content');
|
|
105
|
+
const data = readFile(name, sourceDir);
|
|
110
106
|
try {
|
|
111
107
|
const { user_created, user_updated, ...cleanedData } = data;
|
|
112
|
-
|
|
113
|
-
await sdk_2.api.client.request((0, sdk_1.updateSingleton)(name, cleanedData));
|
|
108
|
+
await api.client.request(updateSingleton(name, cleanedData));
|
|
114
109
|
}
|
|
115
110
|
catch (error) {
|
|
116
|
-
(
|
|
111
|
+
catchError(error);
|
|
117
112
|
}
|
|
118
113
|
}));
|
|
119
|
-
|
|
114
|
+
ux.action.status = 'Loaded data for singleton collections';
|
|
120
115
|
}
|
|
121
116
|
async function getCollectionPrimaryKeys(dir) {
|
|
122
|
-
|
|
123
|
-
const fields = (0, read_file_1.default)('fields', dir);
|
|
117
|
+
const fields = readFile('fields', dir);
|
|
124
118
|
const primaryKeys = {};
|
|
125
119
|
for (const field of fields) {
|
|
126
|
-
if (field.schema &&
|
|
120
|
+
if (field.schema && field.schema?.is_primary_key) {
|
|
127
121
|
primaryKeys[field.collection] = field.field;
|
|
128
122
|
}
|
|
129
123
|
}
|
|
@@ -131,7 +125,7 @@ async function getCollectionPrimaryKeys(dir) {
|
|
|
131
125
|
}
|
|
132
126
|
function getPrimaryKey(collectionsMap, collection) {
|
|
133
127
|
if (!collectionsMap[collection]) {
|
|
134
|
-
(
|
|
128
|
+
catchError(`Collection ${collection} not found in collections map`);
|
|
135
129
|
}
|
|
136
130
|
return collectionsMap[collection];
|
|
137
131
|
}
|