directus-template-cli 0.7.0-beta.4 → 0.7.0-beta.6
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.js +6 -0
- package/bin/run.js +5 -0
- package/dist/commands/apply.d.ts +17 -17
- package/dist/commands/apply.js +163 -173
- package/dist/commands/base.d.ts +15 -0
- package/dist/commands/base.js +45 -0
- package/dist/commands/extract.d.ts +16 -7
- package/dist/commands/extract.js +80 -73
- package/dist/commands/init.d.ts +20 -15
- package/dist/commands/init.js +189 -126
- package/dist/flags/common.d.ts +8 -7
- package/dist/flags/common.js +13 -11
- package/dist/index.js +1 -5
- package/dist/lib/constants.d.ts +3 -5
- package/dist/lib/constants.js +8 -13
- 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 +3 -6
- package/dist/lib/init/index.d.ts +5 -9
- package/dist/lib/init/index.js +105 -85
- package/dist/lib/init/types.js +1 -2
- package/dist/lib/load/apply-flags.js +17 -23
- package/dist/lib/load/index.d.ts +1 -12
- 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/types.d.ts +18 -0
- package/dist/lib/types.js +1 -0
- package/dist/lib/utils/animated-bunny.js +9 -14
- package/dist/lib/utils/auth.d.ts +8 -6
- package/dist/lib/utils/auth.js +48 -39
- 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.d.ts +10 -5
- package/dist/lib/utils/parse-github-url.js +80 -45
- 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/sanitize-flags.d.ts +3 -0
- package/dist/lib/utils/sanitize-flags.js +4 -0
- package/dist/lib/utils/system-fields.js +19 -22
- package/dist/lib/utils/template-config.d.ts +16 -0
- package/dist/lib/utils/template-config.js +34 -0
- 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 +68 -21
- package/dist/services/github.d.ts +1 -1
- package/dist/services/github.js +53 -22
- package/dist/services/posthog.d.ts +37 -0
- package/dist/services/posthog.js +104 -0
- package/oclif.manifest.json +32 -13
- package/package.json +38 -33
- package/bin/dev +0 -17
- package/bin/run +0 -5
|
@@ -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
|
}
|
|
@@ -1,14 +1,11 @@
|
|
|
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 { customEndpoint, readExtensions } 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
|
async function installExtension(extension) {
|
|
11
|
-
await
|
|
8
|
+
await api.client.request(customEndpoint({
|
|
12
9
|
body: JSON.stringify({
|
|
13
10
|
extension: extension.id,
|
|
14
11
|
version: extension.version,
|
|
@@ -17,60 +14,55 @@ async function installExtension(extension) {
|
|
|
17
14
|
path: '/extensions/registry/install',
|
|
18
15
|
}));
|
|
19
16
|
}
|
|
20
|
-
async function loadExtensions(dir) {
|
|
21
|
-
|
|
17
|
+
export default async function loadExtensions(dir) {
|
|
18
|
+
ux.action.start(ux.colorize(DIRECTUS_PINK, 'Loading extensions'));
|
|
22
19
|
try {
|
|
23
|
-
const extensions = (
|
|
20
|
+
const extensions = readFile('extensions', dir);
|
|
24
21
|
if (extensions && extensions.length > 0) {
|
|
25
|
-
const installedExtensions = await
|
|
26
|
-
const registryExtensions = extensions.filter(ext =>
|
|
22
|
+
const installedExtensions = await api.client.request(readExtensions());
|
|
23
|
+
const registryExtensions = extensions.filter(ext => ext.meta?.source === 'registry' && !ext.bundle);
|
|
27
24
|
const bundles = [...new Set(extensions.filter(ext => ext.bundle).map(ext => ext.bundle))];
|
|
28
|
-
const localExtensions = extensions.filter(ext =>
|
|
29
|
-
const extensionsToInstall = extensions.filter(ext =>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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`);
|
|
25
|
+
const localExtensions = extensions.filter(ext => ext.meta?.source === 'local');
|
|
26
|
+
const extensionsToInstall = extensions.filter(ext => ext.meta?.source === 'registry'
|
|
27
|
+
&& !ext.bundle
|
|
28
|
+
// @ts-ignore - ignore
|
|
29
|
+
&& !installedExtensions.some(installed => installed.id === ext.id));
|
|
30
|
+
ux.stdout(`Found ${extensions.length} extensions total: ${registryExtensions.length} registry extensions (including ${bundles.length} bundles), and ${localExtensions.length} local extensions`);
|
|
37
31
|
if (extensionsToInstall.length > 0) {
|
|
38
|
-
|
|
32
|
+
ux.action.start(ux.colorize(DIRECTUS_PINK, `Installing ${extensionsToInstall.length} extensions`));
|
|
39
33
|
const results = await Promise.allSettled(extensionsToInstall.map(async (ext) => {
|
|
40
|
-
var _a, _b, _c;
|
|
41
34
|
try {
|
|
42
35
|
await installExtension({
|
|
43
36
|
id: ext.id,
|
|
44
37
|
// The extension version UUID is the folder name
|
|
45
|
-
version:
|
|
38
|
+
version: ext.meta?.folder,
|
|
46
39
|
});
|
|
47
|
-
return `-- Installed ${
|
|
40
|
+
return `-- Installed ${ext.schema?.name}`;
|
|
48
41
|
}
|
|
49
42
|
catch (error) {
|
|
50
|
-
(
|
|
51
|
-
return `-- Failed to install ${
|
|
43
|
+
catchError(error);
|
|
44
|
+
return `-- Failed to install ${ext.schema?.name}`;
|
|
52
45
|
}
|
|
53
46
|
}));
|
|
54
47
|
for (const result of results) {
|
|
55
48
|
if (result.status === 'fulfilled') {
|
|
56
|
-
|
|
49
|
+
ux.stdout(result.value);
|
|
57
50
|
}
|
|
58
51
|
}
|
|
59
|
-
|
|
60
|
-
|
|
52
|
+
ux.action.stop();
|
|
53
|
+
ux.stdout('Finished installing extensions');
|
|
61
54
|
}
|
|
62
55
|
else {
|
|
63
56
|
// All extensions are already installed
|
|
64
|
-
|
|
57
|
+
ux.stdout('All extensions are already installed');
|
|
65
58
|
}
|
|
66
59
|
if (localExtensions.length > 0) {
|
|
67
|
-
|
|
60
|
+
ux.stdout(`Note: ${localExtensions.length} local extensions need to be installed manually.`);
|
|
68
61
|
}
|
|
69
62
|
}
|
|
70
63
|
}
|
|
71
64
|
catch {
|
|
72
|
-
|
|
65
|
+
ux.stdout(`${ux.colorize('dim', '--')} No extensions found or extensions file is empty. Skipping extension installation.`);
|
|
73
66
|
}
|
|
74
|
-
|
|
67
|
+
ux.action.stop();
|
|
75
68
|
}
|
|
76
|
-
exports.default = loadExtensions;
|
|
@@ -1,22 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
async function loadFiles(dir) {
|
|
14
|
-
const files = (0, read_file_1.default)('files', dir);
|
|
15
|
-
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${files.length} files`));
|
|
1
|
+
import { readFiles, uploadFiles } from '@directus/sdk';
|
|
2
|
+
import { ux } from '@oclif/core';
|
|
3
|
+
import { FormData } from 'formdata-node';
|
|
4
|
+
import { readFileSync } from 'node:fs';
|
|
5
|
+
import path from 'pathe';
|
|
6
|
+
import { DIRECTUS_PINK } from '../constants.js';
|
|
7
|
+
import { api } from '../sdk.js';
|
|
8
|
+
import catchError from '../utils/catch-error.js';
|
|
9
|
+
import readFile from '../utils/read-file.js';
|
|
10
|
+
export default async function loadFiles(dir) {
|
|
11
|
+
const files = readFile('files', dir);
|
|
12
|
+
ux.action.start(ux.colorize(DIRECTUS_PINK, `Loading ${files.length} files`));
|
|
16
13
|
if (files && files.length > 0) {
|
|
17
14
|
try {
|
|
18
15
|
// Fetch only the files we're interested in
|
|
19
|
-
const existingFiles = await
|
|
16
|
+
const existingFiles = await api.client.request(readFiles({
|
|
20
17
|
fields: ['id', 'filename_disk'],
|
|
21
18
|
limit: -1,
|
|
22
19
|
}));
|
|
@@ -33,9 +30,9 @@ async function loadFiles(dir) {
|
|
|
33
30
|
});
|
|
34
31
|
await Promise.all(filesToUpload.map(async (asset) => {
|
|
35
32
|
const fileName = asset.filename_disk;
|
|
36
|
-
const assetPath =
|
|
37
|
-
const fileStream = new Blob([
|
|
38
|
-
const form = new
|
|
33
|
+
const assetPath = path.resolve(dir, 'assets', fileName);
|
|
34
|
+
const fileStream = new Blob([readFileSync(assetPath)], { type: asset.type });
|
|
35
|
+
const form = new FormData();
|
|
39
36
|
form.append('id', asset.id);
|
|
40
37
|
if (asset.title)
|
|
41
38
|
form.append('title', asset.title);
|
|
@@ -45,17 +42,16 @@ async function loadFiles(dir) {
|
|
|
45
42
|
form.append('folder', asset.folder);
|
|
46
43
|
form.append('file', fileStream, fileName);
|
|
47
44
|
try {
|
|
48
|
-
await
|
|
45
|
+
await api.client.request(uploadFiles(form));
|
|
49
46
|
}
|
|
50
47
|
catch (error) {
|
|
51
|
-
(
|
|
48
|
+
catchError(error);
|
|
52
49
|
}
|
|
53
50
|
}));
|
|
54
51
|
}
|
|
55
52
|
catch (error) {
|
|
56
|
-
(
|
|
53
|
+
catchError(error);
|
|
57
54
|
}
|
|
58
55
|
}
|
|
59
|
-
|
|
56
|
+
ux.action.stop();
|
|
60
57
|
}
|
|
61
|
-
exports.default = loadFiles;
|