directus-template-cli 0.6.0-beta.2 → 0.7.0-beta.10
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 +0 -14
- 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 +166 -174
- package/dist/commands/base.d.ts +15 -0
- package/dist/commands/base.js +45 -0
- package/dist/commands/extract.d.ts +16 -9
- package/dist/commands/extract.js +81 -100
- package/dist/commands/init.d.ts +42 -0
- package/dist/commands/init.js +241 -0
- 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 +18 -0
- package/dist/lib/constants.js +25 -6
- 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.d.ts +1 -1
- package/dist/lib/extract/extract-content.js +17 -26
- 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 +12 -16
- 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.d.ts +1 -6
- package/dist/lib/extract/index.js +47 -58
- package/dist/lib/init/config.d.ts +3 -0
- package/dist/lib/init/config.js +12 -0
- package/dist/lib/init/index.d.ts +10 -0
- package/dist/lib/init/index.js +192 -0
- package/dist/lib/init/types.d.ts +30 -0
- package/dist/lib/init/types.js +1 -0
- 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.d.ts +2 -0
- package/dist/lib/load/load-collections.js +29 -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.d.ts +2 -0
- package/dist/lib/utils/animated-bunny.js +62 -0
- 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.d.ts +2 -0
- package/dist/lib/utils/ensure-dir.js +11 -0
- 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 -36
- 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 +19 -0
- package/dist/lib/utils/parse-github-url.js +89 -0
- 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.d.ts +7 -0
- package/dist/lib/utils/wait.js +9 -0
- package/dist/lib/utils/write-to-file.js +8 -11
- package/dist/services/docker.d.ts +23 -0
- package/dist/services/docker.js +187 -0
- package/dist/services/github.d.ts +18 -0
- package/dist/services/github.js +88 -0
- package/dist/services/posthog.d.ts +37 -0
- package/dist/services/posthog.js +104 -0
- package/oclif.manifest.json +102 -23
- package/package.json +46 -29
- package/bin/dev +0 -17
- package/bin/run +0 -5
package/README.md
CHANGED
|
@@ -181,18 +181,6 @@ Using email/password:
|
|
|
181
181
|
npx directus-template-cli@latest extract -p --templateName="My Template" --templateLocation="./my-template" --userEmail="admin@example.com" --userPassword="admin" --directusUrl="http://localhost:8055"
|
|
182
182
|
```
|
|
183
183
|
|
|
184
|
-
Skipping extracting content from sensitive or large collections:
|
|
185
|
-
|
|
186
|
-
```
|
|
187
|
-
npx directus-template-cli@latest extract -p --templateName="My Template" --templateLocation="./my-template" --directusToken="admin-token-here" --directusUrl="http://localhost:8055" --excludeCollections="posts,globals"
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
Skipping extracting files and assets:
|
|
191
|
-
|
|
192
|
-
```
|
|
193
|
-
npx directus-template-cli@latest extract -p --templateName="My Template" --templateLocation="./my-template" --directusToken="admin-token-here" --directusUrl="http://localhost:8055" --skipFiles
|
|
194
|
-
```
|
|
195
|
-
|
|
196
184
|
Available flags for programmatic mode:
|
|
197
185
|
|
|
198
186
|
- `--directusUrl`: URL of the Directus instance to extract the template from (required)
|
|
@@ -201,8 +189,6 @@ Available flags for programmatic mode:
|
|
|
201
189
|
- `--userPassword`: Password for Directus authentication (required if not using token)
|
|
202
190
|
- `--templateLocation`: Directory to extract the template to (required)
|
|
203
191
|
- `--templateName`: Name of the template (required)
|
|
204
|
-
- `--excludeCollections`: Comma-separated list of collection names to exclude from extraction
|
|
205
|
-
- `--skipFiles`: Skip extracting files and assets
|
|
206
192
|
|
|
207
193
|
#### Using Environment Variables
|
|
208
194
|
|
package/bin/dev.js
ADDED
package/bin/run.js
ADDED
package/dist/commands/apply.d.ts
CHANGED
|
@@ -3,23 +3,23 @@ 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/
|
|
7
|
-
dashboards: import("@oclif/core/
|
|
8
|
-
directusToken: import("@oclif/core/
|
|
9
|
-
directusUrl: import("@oclif/core/
|
|
10
|
-
extensions: import("@oclif/core/
|
|
11
|
-
files: import("@oclif/core/
|
|
12
|
-
flows: import("@oclif/core/
|
|
13
|
-
partial: import("@oclif/core/
|
|
14
|
-
permissions: import("@oclif/core/
|
|
15
|
-
programmatic: import("@oclif/core/
|
|
16
|
-
schema: import("@oclif/core/
|
|
17
|
-
settings: import("@oclif/core/
|
|
18
|
-
templateLocation: import("@oclif/core/
|
|
19
|
-
templateType: import("@oclif/core/
|
|
20
|
-
userEmail: import("@oclif/core/
|
|
21
|
-
userPassword: import("@oclif/core/
|
|
22
|
-
users: import("@oclif/core/
|
|
6
|
+
content: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
7
|
+
dashboards: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
directusToken: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
directusUrl: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
extensions: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
|
+
files: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
|
+
flows: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
partial: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
14
|
+
permissions: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
15
|
+
programmatic: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
16
|
+
schema: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
17
|
+
settings: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
18
|
+
templateLocation: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
|
+
templateType: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
|
+
userEmail: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
|
+
userPassword: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
22
|
+
users: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
23
23
|
};
|
|
24
24
|
/**
|
|
25
25
|
* MAIN
|
package/dist/commands/apply.js
CHANGED
|
@@ -1,19 +1,92 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class ApplyCommand extends
|
|
1
|
+
import { Command, Flags, ux } from '@oclif/core';
|
|
2
|
+
import { text, select, password, log, intro } from '@clack/prompts';
|
|
3
|
+
import * as path from 'pathe';
|
|
4
|
+
import { animatedBunny } from '../lib/utils/animated-bunny.js';
|
|
5
|
+
import { BSL_LICENSE_TEXT } from '../lib/constants.js';
|
|
6
|
+
import * as customFlags from '../flags/common.js';
|
|
7
|
+
import { DIRECTUS_PINK, DIRECTUS_PURPLE, SEPARATOR } from '../lib/constants.js';
|
|
8
|
+
import { validateInteractiveFlags, validateProgrammaticFlags } from '../lib/load/apply-flags.js';
|
|
9
|
+
import apply from '../lib/load/index.js';
|
|
10
|
+
import { getDirectusToken, getDirectusUrl, initializeDirectusApi } from '../lib/utils/auth.js';
|
|
11
|
+
import catchError from '../lib/utils/catch-error.js';
|
|
12
|
+
import { getCommunityTemplates, getGithubTemplate, getInteractiveLocalTemplate, getLocalTemplate } from '../lib/utils/get-template.js';
|
|
13
|
+
import { logger } from '../lib/utils/logger.js';
|
|
14
|
+
import openUrl from '../lib/utils/open-url.js';
|
|
15
|
+
import chalk from 'chalk';
|
|
16
|
+
export default class ApplyCommand extends Command {
|
|
17
|
+
static description = 'Apply a template to a blank Directus instance.';
|
|
18
|
+
static examples = [
|
|
19
|
+
'$ directus-template-cli apply',
|
|
20
|
+
'$ directus-template-cli apply -p --directusUrl="http://localhost:8055" --directusToken="admin-token-here" --templateLocation="./my-template" --templateType="local"',
|
|
21
|
+
'$ directus-template-cli@beta apply -p --directusUrl="http://localhost:8055" --directusToken="admin-token-here" --templateLocation="./my-template" --templateType="local" --partial --no-content --no-users',
|
|
22
|
+
];
|
|
23
|
+
static flags = {
|
|
24
|
+
content: Flags.boolean({
|
|
25
|
+
allowNo: true,
|
|
26
|
+
default: undefined,
|
|
27
|
+
description: 'Load Content (data)',
|
|
28
|
+
}),
|
|
29
|
+
dashboards: Flags.boolean({
|
|
30
|
+
allowNo: true,
|
|
31
|
+
default: undefined,
|
|
32
|
+
description: 'Load Dashboards (dashboards, panels)',
|
|
33
|
+
}),
|
|
34
|
+
directusToken: customFlags.directusToken,
|
|
35
|
+
directusUrl: customFlags.directusUrl,
|
|
36
|
+
extensions: Flags.boolean({
|
|
37
|
+
allowNo: true,
|
|
38
|
+
default: undefined,
|
|
39
|
+
description: 'Load Extensions',
|
|
40
|
+
}),
|
|
41
|
+
files: Flags.boolean({
|
|
42
|
+
allowNo: true,
|
|
43
|
+
default: undefined,
|
|
44
|
+
description: 'Load Files (files, folders)',
|
|
45
|
+
}),
|
|
46
|
+
flows: Flags.boolean({
|
|
47
|
+
allowNo: true,
|
|
48
|
+
default: undefined,
|
|
49
|
+
description: 'Load Flows (operations, flows)',
|
|
50
|
+
}),
|
|
51
|
+
partial: Flags.boolean({
|
|
52
|
+
dependsOn: ['programmatic'],
|
|
53
|
+
description: 'Enable partial template application (all components enabled by default)',
|
|
54
|
+
summary: 'Enable partial template application',
|
|
55
|
+
}),
|
|
56
|
+
permissions: Flags.boolean({
|
|
57
|
+
allowNo: true,
|
|
58
|
+
default: undefined,
|
|
59
|
+
description: 'Loads permissions data. Collections include: directus_roles, directus_policies, directus_access, directus_permissions.',
|
|
60
|
+
summary: 'Load permissions (roles, policies, access, permissions)',
|
|
61
|
+
}),
|
|
62
|
+
programmatic: customFlags.programmatic,
|
|
63
|
+
schema: Flags.boolean({
|
|
64
|
+
allowNo: true,
|
|
65
|
+
default: undefined,
|
|
66
|
+
description: 'Load schema (collections, relations)',
|
|
67
|
+
}),
|
|
68
|
+
settings: Flags.boolean({
|
|
69
|
+
allowNo: true,
|
|
70
|
+
default: undefined,
|
|
71
|
+
description: 'Load settings (project settings, translations, presets)',
|
|
72
|
+
}),
|
|
73
|
+
templateLocation: customFlags.templateLocation,
|
|
74
|
+
templateType: Flags.string({
|
|
75
|
+
default: 'local',
|
|
76
|
+
dependsOn: ['programmatic'],
|
|
77
|
+
description: 'Type of template to apply. You can apply templates from our community repo, local directories, or public repositories from Github. Defaults to local. ',
|
|
78
|
+
env: 'TEMPLATE_TYPE',
|
|
79
|
+
options: ['community', 'local', 'github'],
|
|
80
|
+
summary: 'Type of template to apply. Options: community, local, github.',
|
|
81
|
+
}),
|
|
82
|
+
userEmail: customFlags.userEmail,
|
|
83
|
+
userPassword: customFlags.userPassword,
|
|
84
|
+
users: Flags.boolean({
|
|
85
|
+
allowNo: true,
|
|
86
|
+
default: undefined,
|
|
87
|
+
description: 'Load users',
|
|
88
|
+
}),
|
|
89
|
+
};
|
|
17
90
|
/**
|
|
18
91
|
* MAIN
|
|
19
92
|
* Run the command
|
|
@@ -31,88 +104,85 @@ class ApplyCommand extends core_1.Command {
|
|
|
31
104
|
* @returns {Promise<void>} - Returns nothing
|
|
32
105
|
*/
|
|
33
106
|
async runInteractive(flags) {
|
|
34
|
-
const validatedFlags =
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
},
|
|
48
|
-
]);
|
|
107
|
+
const validatedFlags = validateInteractiveFlags(flags);
|
|
108
|
+
// Show animated intro
|
|
109
|
+
await animatedBunny('Let\'s apply a template!');
|
|
110
|
+
intro(`${chalk.bgHex(DIRECTUS_PURPLE).white.bold('Directus Template CLI')} - Apply Template`);
|
|
111
|
+
const templateType = await select({
|
|
112
|
+
options: [
|
|
113
|
+
{ label: 'Community templates', value: 'community' },
|
|
114
|
+
{ label: 'From a local directory', value: 'local' },
|
|
115
|
+
{ label: 'From a public GitHub repository', value: 'github' },
|
|
116
|
+
{ label: 'Get premium templates', value: 'directus-plus' },
|
|
117
|
+
],
|
|
118
|
+
message: 'What type of template would you like to apply?',
|
|
119
|
+
});
|
|
49
120
|
let template;
|
|
50
|
-
switch (templateType
|
|
121
|
+
switch (templateType) {
|
|
51
122
|
case 'community': {
|
|
52
|
-
const templates = await
|
|
53
|
-
const
|
|
54
|
-
{
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
name: 'selectedTemplate',
|
|
58
|
-
type: 'list',
|
|
59
|
-
},
|
|
60
|
-
]);
|
|
123
|
+
const templates = await getCommunityTemplates();
|
|
124
|
+
const selectedTemplate = await select({
|
|
125
|
+
options: templates.map(t => ({ label: t.templateName, value: t })),
|
|
126
|
+
message: 'Select a template.',
|
|
127
|
+
});
|
|
61
128
|
template = selectedTemplate;
|
|
62
129
|
break;
|
|
63
130
|
}
|
|
64
131
|
case 'local': {
|
|
65
|
-
const localTemplateDir = await
|
|
132
|
+
const localTemplateDir = await text({
|
|
133
|
+
message: 'What is the local template directory?',
|
|
134
|
+
});
|
|
66
135
|
template = await this.selectLocalTemplate(localTemplateDir);
|
|
67
136
|
break;
|
|
68
137
|
}
|
|
69
138
|
case 'github': {
|
|
70
|
-
const ghTemplateUrl = await
|
|
71
|
-
|
|
139
|
+
const ghTemplateUrl = await text({
|
|
140
|
+
message: 'What is the public GitHub repository URL?',
|
|
141
|
+
});
|
|
142
|
+
template = await getGithubTemplate(ghTemplateUrl);
|
|
72
143
|
break;
|
|
73
144
|
}
|
|
74
145
|
case 'directus-plus': {
|
|
75
|
-
(
|
|
76
|
-
|
|
77
|
-
|
|
146
|
+
openUrl('https://directus.io/plus?utm_source=directus-template-cli&utm_content=apply-command');
|
|
147
|
+
log.info('Redirecting to Directus website.');
|
|
148
|
+
ux.exit(0);
|
|
78
149
|
}
|
|
79
150
|
}
|
|
80
|
-
|
|
81
|
-
core_1.ux.log(constants_1.SEPARATOR);
|
|
151
|
+
log.info(`You selected ${ux.colorize(DIRECTUS_PINK, template.templateName)}`);
|
|
82
152
|
// Get Directus URL
|
|
83
|
-
const directusUrl = await
|
|
153
|
+
const directusUrl = await getDirectusUrl();
|
|
84
154
|
validatedFlags.directusUrl = directusUrl;
|
|
85
155
|
// Prompt for login method
|
|
86
|
-
const loginMethod = await
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
type: 'list',
|
|
96
|
-
},
|
|
97
|
-
]);
|
|
98
|
-
if (loginMethod.loginMethod === 'token') {
|
|
99
|
-
const directusToken = await (0, auth_1.getDirectusToken)(directusUrl);
|
|
156
|
+
const loginMethod = await select({
|
|
157
|
+
options: [
|
|
158
|
+
{ label: 'Directus Access Token', value: 'token' },
|
|
159
|
+
{ label: 'Email and Password', value: 'email' },
|
|
160
|
+
],
|
|
161
|
+
message: 'How do you want to log in?',
|
|
162
|
+
});
|
|
163
|
+
if (loginMethod === 'token') {
|
|
164
|
+
const directusToken = await getDirectusToken(directusUrl);
|
|
100
165
|
validatedFlags.directusToken = directusToken;
|
|
101
166
|
}
|
|
102
167
|
else {
|
|
103
|
-
const userEmail = await
|
|
168
|
+
const userEmail = await text({
|
|
169
|
+
message: 'What is your email?',
|
|
170
|
+
});
|
|
104
171
|
validatedFlags.userEmail = userEmail;
|
|
105
|
-
const userPassword = await
|
|
172
|
+
const userPassword = await password({
|
|
173
|
+
message: 'What is your password?',
|
|
174
|
+
});
|
|
106
175
|
validatedFlags.userPassword = userPassword;
|
|
107
176
|
}
|
|
108
|
-
await
|
|
177
|
+
await initializeDirectusApi(validatedFlags);
|
|
109
178
|
if (template) {
|
|
110
|
-
|
|
111
|
-
await (
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
179
|
+
// /* TODO: Replace with custom styledHeader function */ ux.styledHeader(ux.colorize(DIRECTUS_PURPLE, `Applying template - ${template.templateName} to ${directusUrl}`))
|
|
180
|
+
await apply(template.directoryPath, validatedFlags);
|
|
181
|
+
ux.action.stop();
|
|
182
|
+
ux.stdout(SEPARATOR);
|
|
183
|
+
log.warn(BSL_LICENSE_TEXT);
|
|
184
|
+
ux.stdout('Template applied successfully.');
|
|
185
|
+
ux.exit(0);
|
|
116
186
|
}
|
|
117
187
|
}
|
|
118
188
|
/**
|
|
@@ -122,37 +192,37 @@ class ApplyCommand extends core_1.Command {
|
|
|
122
192
|
* @returns {Promise<void>} - Returns nothing
|
|
123
193
|
*/
|
|
124
194
|
async runProgrammatic(flags) {
|
|
125
|
-
const validatedFlags =
|
|
195
|
+
const validatedFlags = validateProgrammaticFlags(flags);
|
|
126
196
|
let template;
|
|
127
197
|
switch (validatedFlags.templateType) {
|
|
128
198
|
case 'community': {
|
|
129
|
-
const templates = await
|
|
199
|
+
const templates = await getCommunityTemplates();
|
|
130
200
|
template = templates.find(t => t.templateName === validatedFlags.templateLocation) || templates[0];
|
|
131
201
|
break;
|
|
132
202
|
}
|
|
133
203
|
case 'local': {
|
|
134
|
-
template = await
|
|
204
|
+
template = await getLocalTemplate(validatedFlags.templateLocation);
|
|
135
205
|
break;
|
|
136
206
|
}
|
|
137
207
|
case 'github': {
|
|
138
|
-
template = await
|
|
208
|
+
template = await getGithubTemplate(validatedFlags.templateLocation);
|
|
139
209
|
break;
|
|
140
210
|
}
|
|
141
211
|
default: {
|
|
142
|
-
(
|
|
212
|
+
catchError('Invalid template type. Please check your template type.', {
|
|
143
213
|
fatal: true,
|
|
144
214
|
});
|
|
145
215
|
}
|
|
146
216
|
}
|
|
147
|
-
await
|
|
217
|
+
await initializeDirectusApi(validatedFlags);
|
|
148
218
|
const logMessage = `Applying template - ${template.templateName} to ${validatedFlags.directusUrl}`;
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
await (
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
219
|
+
// /* TODO: Replace with custom styledHeader function */ ux.styledHeader(logMessage)
|
|
220
|
+
logger.log('info', logMessage);
|
|
221
|
+
await apply(template.directoryPath, validatedFlags);
|
|
222
|
+
ux.action.stop();
|
|
223
|
+
ux.stdout(SEPARATOR);
|
|
224
|
+
ux.stdout('Template applied successfully.');
|
|
225
|
+
// ux.exit(0)
|
|
156
226
|
}
|
|
157
227
|
/**
|
|
158
228
|
* INTERACTIVE
|
|
@@ -162,104 +232,26 @@ class ApplyCommand extends core_1.Command {
|
|
|
162
232
|
*/
|
|
163
233
|
async selectLocalTemplate(localTemplateDir) {
|
|
164
234
|
try {
|
|
165
|
-
const templates = await
|
|
235
|
+
const templates = await getInteractiveLocalTemplate(localTemplateDir);
|
|
166
236
|
if (templates.length === 1) {
|
|
167
237
|
return templates[0];
|
|
168
238
|
}
|
|
169
|
-
const
|
|
170
|
-
{
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
name: 'selectedTemplate',
|
|
177
|
-
type: 'list',
|
|
178
|
-
},
|
|
179
|
-
]);
|
|
239
|
+
const selectedTemplate = await select({
|
|
240
|
+
options: templates.map(t => ({
|
|
241
|
+
label: `${t.templateName} (${path.basename(t.directoryPath)})`,
|
|
242
|
+
value: t,
|
|
243
|
+
})),
|
|
244
|
+
message: 'Multiple templates found. Please select one:',
|
|
245
|
+
});
|
|
180
246
|
return selectedTemplate;
|
|
181
247
|
}
|
|
182
248
|
catch (error) {
|
|
183
249
|
if (error instanceof Error) {
|
|
184
|
-
|
|
250
|
+
ux.error(error.message);
|
|
185
251
|
}
|
|
186
252
|
else {
|
|
187
|
-
|
|
253
|
+
ux.error('An unknown error occurred while getting the local template.');
|
|
188
254
|
}
|
|
189
255
|
}
|
|
190
256
|
}
|
|
191
257
|
}
|
|
192
|
-
ApplyCommand.description = 'Apply a template to a blank Directus instance.';
|
|
193
|
-
ApplyCommand.examples = [
|
|
194
|
-
'$ directus-template-cli apply',
|
|
195
|
-
'$ directus-template-cli apply -p --directusUrl="http://localhost:8055" --directusToken="admin-token-here" --templateLocation="./my-template" --templateType="local"',
|
|
196
|
-
'$ directus-template-cli@beta apply -p --directusUrl="http://localhost:8055" --directusToken="admin-token-here" --templateLocation="./my-template" --templateType="local" --partial --no-content --no-users',
|
|
197
|
-
];
|
|
198
|
-
ApplyCommand.flags = {
|
|
199
|
-
content: core_1.Flags.boolean({
|
|
200
|
-
allowNo: true,
|
|
201
|
-
default: undefined,
|
|
202
|
-
description: 'Load Content (data)',
|
|
203
|
-
}),
|
|
204
|
-
dashboards: core_1.Flags.boolean({
|
|
205
|
-
allowNo: true,
|
|
206
|
-
default: undefined,
|
|
207
|
-
description: 'Load Dashboards (dashboards, panels)',
|
|
208
|
-
}),
|
|
209
|
-
directusToken: customFlags.directusToken,
|
|
210
|
-
directusUrl: customFlags.directusUrl,
|
|
211
|
-
extensions: core_1.Flags.boolean({
|
|
212
|
-
allowNo: true,
|
|
213
|
-
default: undefined,
|
|
214
|
-
description: 'Load Extensions',
|
|
215
|
-
}),
|
|
216
|
-
files: core_1.Flags.boolean({
|
|
217
|
-
allowNo: true,
|
|
218
|
-
default: undefined,
|
|
219
|
-
description: 'Load Files (files, folders)',
|
|
220
|
-
}),
|
|
221
|
-
flows: core_1.Flags.boolean({
|
|
222
|
-
allowNo: true,
|
|
223
|
-
default: undefined,
|
|
224
|
-
description: 'Load Flows (operations, flows)',
|
|
225
|
-
}),
|
|
226
|
-
partial: core_1.Flags.boolean({
|
|
227
|
-
dependsOn: ['programmatic'],
|
|
228
|
-
description: 'Enable partial template application (all components enabled by default)',
|
|
229
|
-
summary: 'Enable partial template application',
|
|
230
|
-
}),
|
|
231
|
-
permissions: core_1.Flags.boolean({
|
|
232
|
-
allowNo: true,
|
|
233
|
-
default: undefined,
|
|
234
|
-
description: 'Loads permissions data. Collections include: directus_roles, directus_policies, directus_access, directus_permissions.',
|
|
235
|
-
summary: 'Load permissions (roles, policies, access, permissions)',
|
|
236
|
-
}),
|
|
237
|
-
programmatic: customFlags.programmatic,
|
|
238
|
-
schema: core_1.Flags.boolean({
|
|
239
|
-
allowNo: true,
|
|
240
|
-
default: undefined,
|
|
241
|
-
description: 'Load schema (collections, relations)',
|
|
242
|
-
}),
|
|
243
|
-
settings: core_1.Flags.boolean({
|
|
244
|
-
allowNo: true,
|
|
245
|
-
default: undefined,
|
|
246
|
-
description: 'Load settings (project settings, translations, presets)',
|
|
247
|
-
}),
|
|
248
|
-
templateLocation: customFlags.templateLocation,
|
|
249
|
-
templateType: core_1.Flags.string({
|
|
250
|
-
default: 'local',
|
|
251
|
-
dependsOn: ['programmatic'],
|
|
252
|
-
description: 'Type of template to apply. You can apply templates from our community repo, local directories, or public repositories from Github. Defaults to local. ',
|
|
253
|
-
env: 'TEMPLATE_TYPE',
|
|
254
|
-
options: ['community', 'local', 'github'],
|
|
255
|
-
summary: 'Type of template to apply. Options: community, local, github.',
|
|
256
|
-
}),
|
|
257
|
-
userEmail: customFlags.userEmail,
|
|
258
|
-
userPassword: customFlags.userPassword,
|
|
259
|
-
users: core_1.Flags.boolean({
|
|
260
|
-
allowNo: true,
|
|
261
|
-
default: undefined,
|
|
262
|
-
description: 'Load users',
|
|
263
|
-
}),
|
|
264
|
-
};
|
|
265
|
-
exports.default = ApplyCommand;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Command, type Config } from '@oclif/core';
|
|
2
|
+
interface UserConfig {
|
|
3
|
+
distinctId?: string | null;
|
|
4
|
+
}
|
|
5
|
+
export declare abstract class BaseCommand extends Command {
|
|
6
|
+
runId: string;
|
|
7
|
+
userConfig: UserConfig;
|
|
8
|
+
constructor(argv: string[], config: Config);
|
|
9
|
+
private loadUserConfig;
|
|
10
|
+
/**
|
|
11
|
+
* Save the current user configuration to disk
|
|
12
|
+
*/
|
|
13
|
+
protected saveUserConfig(): void;
|
|
14
|
+
}
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'pathe';
|
|
5
|
+
export class BaseCommand extends Command {
|
|
6
|
+
runId;
|
|
7
|
+
userConfig = {};
|
|
8
|
+
constructor(argv, config) {
|
|
9
|
+
super(argv, config);
|
|
10
|
+
this.runId = randomUUID();
|
|
11
|
+
this.loadUserConfig();
|
|
12
|
+
}
|
|
13
|
+
loadUserConfig() {
|
|
14
|
+
try {
|
|
15
|
+
const configPath = path.join(this.config.configDir, 'config.json');
|
|
16
|
+
if (fs.existsSync(configPath)) {
|
|
17
|
+
this.userConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
// Create default config if it doesn't exist
|
|
21
|
+
const defaultConfig = {
|
|
22
|
+
distinctId: randomUUID(),
|
|
23
|
+
};
|
|
24
|
+
fs.mkdirSync(this.config.configDir, { recursive: true });
|
|
25
|
+
fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2));
|
|
26
|
+
this.userConfig = defaultConfig;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
this.warn(`Failed to load user config: ${error}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Save the current user configuration to disk
|
|
35
|
+
*/
|
|
36
|
+
saveUserConfig() {
|
|
37
|
+
try {
|
|
38
|
+
const configPath = path.join(this.config.configDir, 'config.json');
|
|
39
|
+
fs.writeFileSync(configPath, JSON.stringify(this.userConfig, null, 2));
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
this.warn(`Failed to save user config: ${error}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
|
+
export interface ExtractFlags {
|
|
3
|
+
directusToken: string;
|
|
4
|
+
directusUrl: string;
|
|
5
|
+
programmatic: boolean;
|
|
6
|
+
templateLocation: string;
|
|
7
|
+
templateName: string;
|
|
8
|
+
userEmail: string;
|
|
9
|
+
userPassword: string;
|
|
10
|
+
}
|
|
2
11
|
export default class ExtractCommand extends Command {
|
|
3
12
|
static description: string;
|
|
4
13
|
static examples: string[];
|
|
5
14
|
static flags: {
|
|
6
|
-
directusToken: import("@oclif/core/
|
|
7
|
-
directusUrl: import("@oclif/core/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
userEmail: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
14
|
-
userPassword: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
15
|
+
directusToken: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
directusUrl: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
programmatic: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
18
|
+
templateLocation: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
|
+
templateName: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
|
+
userEmail: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
|
+
userPassword: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
22
|
};
|
|
16
23
|
/**
|
|
17
24
|
* Main run method for the ExtractCommand
|