directus-template-cli 0.2.0 → 0.3.0-beta.2
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 +27 -3
- package/dist/commands/apply.d.ts +1 -1
- package/dist/commands/apply.js +55 -46
- package/dist/commands/extract.d.ts +7 -0
- package/dist/commands/extract.js +54 -0
- package/dist/lib/extract/extract-assets.d.ts +3 -0
- package/dist/lib/extract/extract-assets.js +49 -0
- package/dist/lib/extract/extract-content.d.ts +3 -0
- package/dist/lib/extract/extract-content.js +33 -0
- package/dist/lib/extract/extract-files.d.ts +4 -0
- package/dist/lib/extract/extract-files.js +48 -0
- package/dist/lib/extract/extract-folders.d.ts +4 -0
- package/dist/lib/extract/extract-folders.js +26 -0
- package/dist/lib/extract/extract-from-endpoint.d.ts +4 -0
- package/dist/lib/extract/extract-from-endpoint.js +23 -0
- package/dist/lib/extract/extract-roles.d.ts +4 -0
- package/dist/lib/extract/extract-roles.js +36 -0
- package/dist/lib/extract/extract-schema.d.ts +1 -0
- package/dist/lib/extract/extract-schema.js +29 -0
- package/dist/lib/extract/extract-users.d.ts +4 -0
- package/dist/lib/extract/extract-users.js +49 -0
- package/dist/lib/extract/index.d.ts +1 -0
- package/dist/lib/extract/index.js +55 -0
- package/dist/lib/extract/public-permissions.d.ts +1 -0
- package/dist/lib/extract/public-permissions.js +21 -0
- package/dist/lib/load/index.js +31 -28
- package/dist/lib/load/load-folders.js +12 -4
- package/dist/lib/load/load-presets.js +19 -8
- package/dist/lib/load/load-public-permissions.d.ts +2 -1
- package/dist/lib/load/load-public-permissions.js +11 -5
- package/dist/lib/utils/auth.d.ts +2 -0
- package/dist/lib/utils/auth.js +34 -0
- package/dist/lib/utils/filter-fields.d.ts +1 -0
- package/dist/lib/utils/filter-fields.js +22 -0
- package/dist/lib/utils/read-templates.d.ts +2 -1
- package/dist/lib/utils/read-templates.js +25 -20
- package/dist/lib/utils/template-defaults.d.ts +2 -0
- package/dist/lib/utils/template-defaults.js +37 -0
- package/dist/lib/utils/write-to-file.d.ts +1 -1
- package/dist/lib/utils/write-to-file.js +13 -9
- package/oclif.manifest.json +15 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,19 +1,43 @@
|
|
|
1
1
|
# Directus Template CLI
|
|
2
2
|
|
|
3
|
-
A CLI tool to
|
|
3
|
+
A CLI tool to make applying or extracting Directus "templates" a little easier...well a lot easier.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**Notes:**
|
|
6
|
+
|
|
7
|
+
- This is a pre-release. It is recommended for use on POC or demo projects only.
|
|
8
|
+
- ⚠️ Known issues with using MySQL currently, please use ONLY PostgreSQL or SQLite for your database provider.
|
|
9
|
+
- Templates are applied / extracted on an all or nothing basis – meaning that all the schema, content, and system settings are extracted or applied. We'd love to support more granular operations in the future. (PRs welcome 🙏)
|
|
6
10
|
|
|
7
11
|
## Usage
|
|
8
12
|
|
|
13
|
+
### Applying a Template
|
|
14
|
+
|
|
15
|
+
**To avoid potential conflicts and bad outcomes, templates can only be applied to a blank instance currently.**
|
|
16
|
+
|
|
9
17
|
1. Create a Directus instance on [Directus Cloud](https://directus.cloud) or using self-hosted version.
|
|
10
18
|
2. Login and create a Static Access Token for the admin user.
|
|
11
19
|
3. Copy the static token and your Directus URL.
|
|
12
20
|
4. Run the following command on the terminal and follow the prompts.
|
|
21
|
+
|
|
13
22
|
```
|
|
14
23
|
$ npx directus-template-cli apply
|
|
15
24
|
```
|
|
16
25
|
|
|
26
|
+
You can choose from our templates bundled with the CLI or you can also choose a template from a local directory.
|
|
27
|
+
|
|
28
|
+
### Extracting a Template
|
|
29
|
+
|
|
30
|
+
The CLI can also extract a template from a Directus instance so that it can be applied to other instances.
|
|
31
|
+
|
|
32
|
+
1. Make sure you remove any sensitive data from the Directus instance you don't want to include in the template.
|
|
33
|
+
2. Login and create a Static Access Token for the admin user.
|
|
34
|
+
3. Copy the static token and your Directus URL.
|
|
35
|
+
4. Run the following command on the terminal and follow the prompts.
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
$ npx directus-template-cli extract
|
|
39
|
+
```
|
|
40
|
+
|
|
17
41
|
## License
|
|
18
42
|
|
|
19
|
-
This
|
|
43
|
+
This tool is licensed under the [MIT License](https://opensource.org/licenses/MIT).
|
package/dist/commands/apply.d.ts
CHANGED
package/dist/commands/apply.js
CHANGED
|
@@ -4,50 +4,61 @@ const tslib_1 = require("tslib");
|
|
|
4
4
|
const core_1 = require("@oclif/core");
|
|
5
5
|
const core_2 = require("@oclif/core");
|
|
6
6
|
const inquirer = tslib_1.__importStar(require("inquirer"));
|
|
7
|
-
const
|
|
8
|
-
const validate_url_1 = tslib_1.__importDefault(require("../lib/utils/validate-url"));
|
|
7
|
+
const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
|
|
9
8
|
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
9
|
+
const read_templates_1 = require("../lib/utils/read-templates");
|
|
10
10
|
const api_1 = require("../lib/api");
|
|
11
11
|
const load_1 = tslib_1.__importDefault(require("../lib/load/"));
|
|
12
|
-
const
|
|
12
|
+
const auth_1 = require("../lib/utils/auth");
|
|
13
|
+
const separator = "------------------";
|
|
13
14
|
async function getTemplate() {
|
|
14
|
-
const TEMPLATE_DIR = node_path_1.default.join(__dirname,
|
|
15
|
-
const templates = await (0, read_templates_1.
|
|
16
|
-
const
|
|
15
|
+
const TEMPLATE_DIR = node_path_1.default.join(__dirname, "..", "..", "templates");
|
|
16
|
+
const templates = await (0, read_templates_1.readAllTemplates)(TEMPLATE_DIR);
|
|
17
|
+
const officialTemplateChoices = templates.map((template) => {
|
|
17
18
|
return { name: template.templateName, value: template };
|
|
18
19
|
});
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
20
|
+
const templateType = await inquirer.prompt([
|
|
21
|
+
{
|
|
22
|
+
name: "templateType",
|
|
23
|
+
message: "What type of template would you like to apply?",
|
|
24
|
+
type: "list",
|
|
25
|
+
choices: [
|
|
26
|
+
{
|
|
27
|
+
name: "Official templates",
|
|
28
|
+
value: "official",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: "From a local directory",
|
|
32
|
+
value: "local",
|
|
33
|
+
},
|
|
34
|
+
// {
|
|
35
|
+
// name: "From a git repository",
|
|
36
|
+
// value: "git",
|
|
37
|
+
// },
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
]);
|
|
41
|
+
let template;
|
|
42
|
+
if (templateType.templateType === "official") {
|
|
43
|
+
template = await inquirer.prompt([
|
|
44
|
+
{
|
|
45
|
+
name: "template",
|
|
46
|
+
message: "Select a template.",
|
|
47
|
+
type: "list",
|
|
48
|
+
choices: officialTemplateChoices,
|
|
43
49
|
},
|
|
44
|
-
|
|
45
|
-
return directusToken;
|
|
50
|
+
]);
|
|
46
51
|
}
|
|
47
|
-
|
|
48
|
-
core_2.ux.
|
|
49
|
-
|
|
52
|
+
if (templateType.templateType === "local") {
|
|
53
|
+
const localTemplateDir = await core_2.ux.prompt("What is the local template directory?");
|
|
54
|
+
if (!node_fs_1.default.existsSync(localTemplateDir)) {
|
|
55
|
+
core_2.ux.error("Directory does not exist.");
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
template = { template: await (0, read_templates_1.readTemplate)(localTemplateDir) };
|
|
59
|
+
}
|
|
50
60
|
}
|
|
61
|
+
return template;
|
|
51
62
|
}
|
|
52
63
|
class ApplyCommand extends core_1.Command {
|
|
53
64
|
async run() {
|
|
@@ -55,32 +66,30 @@ class ApplyCommand extends core_1.Command {
|
|
|
55
66
|
const chosenTemplate = await getTemplate();
|
|
56
67
|
this.log(`You selected ${chosenTemplate.template.templateName}`);
|
|
57
68
|
this.log(separator);
|
|
58
|
-
const directusUrl = await getDirectusUrl();
|
|
69
|
+
const directusUrl = await (0, auth_1.getDirectusUrl)();
|
|
59
70
|
api_1.api.setBaseUrl(directusUrl);
|
|
60
|
-
const directusToken = await getDirectusToken(directusUrl);
|
|
71
|
+
const directusToken = await (0, auth_1.getDirectusToken)(directusUrl);
|
|
61
72
|
api_1.api.setAuthToken(directusToken);
|
|
62
73
|
this.log(separator);
|
|
63
74
|
// Check if Directus instance is empty, if not, throw error
|
|
64
|
-
const { data } = await api_1.api.get(
|
|
75
|
+
const { data } = await api_1.api.get("/collections");
|
|
65
76
|
// Look for collections that don't start with directus_
|
|
66
77
|
const collections = data.data.filter((collection) => {
|
|
67
|
-
return !collection.collection.startsWith(
|
|
78
|
+
return !collection.collection.startsWith("directus_");
|
|
68
79
|
});
|
|
69
80
|
if (collections.length > 0) {
|
|
70
|
-
core_2.ux.error(
|
|
81
|
+
core_2.ux.error("Directus instance is not empty. Please use a blank instance. Copying a template into an existing instance is not supported at this time.");
|
|
71
82
|
}
|
|
72
83
|
// Run load script
|
|
73
84
|
core_2.ux.action.start(`Applying template - ${chosenTemplate.template.templateName}`);
|
|
74
85
|
await (0, load_1.default)(chosenTemplate.template.directoryPath, this);
|
|
75
86
|
core_2.ux.action.stop();
|
|
76
87
|
this.log(separator);
|
|
77
|
-
this.log(
|
|
78
|
-
this.exit;
|
|
88
|
+
this.log("Template applied successfully.");
|
|
89
|
+
this.exit(0);
|
|
79
90
|
}
|
|
80
91
|
}
|
|
81
92
|
exports.default = ApplyCommand;
|
|
82
|
-
ApplyCommand.description =
|
|
83
|
-
ApplyCommand.examples = [
|
|
84
|
-
'$ directus-template-cli apply',
|
|
85
|
-
];
|
|
93
|
+
ApplyCommand.description = "Apply a template to a blank Directus instance.";
|
|
94
|
+
ApplyCommand.examples = ["$ directus-template-cli apply"];
|
|
86
95
|
ApplyCommand.flags = {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const core_1 = require("@oclif/core");
|
|
5
|
+
const core_2 = require("@oclif/core");
|
|
6
|
+
const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
|
|
7
|
+
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
8
|
+
const api_1 = require("../lib/api");
|
|
9
|
+
const extract_1 = tslib_1.__importDefault(require("../lib/extract/"));
|
|
10
|
+
const auth_1 = require("../lib/utils/auth");
|
|
11
|
+
const template_defaults_1 = require("../lib/utils/template-defaults");
|
|
12
|
+
const separator = "------------------";
|
|
13
|
+
class ExtractCommand extends core_1.Command {
|
|
14
|
+
async run() {
|
|
15
|
+
const { flags } = await this.parse(ExtractCommand);
|
|
16
|
+
const templateName = await core_2.ux.prompt("What is the name of the template?.");
|
|
17
|
+
const directory = await core_2.ux.prompt("What directory would you like to extract the template to? If it doesn't exist, it will be created.");
|
|
18
|
+
this.log(`You selected ${directory}`);
|
|
19
|
+
try {
|
|
20
|
+
// Check if directory exists, if not, then create it.
|
|
21
|
+
if (!node_fs_1.default.existsSync(directory)) {
|
|
22
|
+
node_fs_1.default.mkdirSync(directory, { recursive: true });
|
|
23
|
+
}
|
|
24
|
+
// Create package.json and README.md
|
|
25
|
+
const packageJSONContent = (0, template_defaults_1.generatePackageJsonContent)(templateName);
|
|
26
|
+
const readmeContent = (0, template_defaults_1.generateReadmeContent)(templateName);
|
|
27
|
+
// Write the content to the specified directory
|
|
28
|
+
const packageJSONPath = node_path_1.default.join(directory, "package.json");
|
|
29
|
+
const readmePath = node_path_1.default.join(directory, "README.md");
|
|
30
|
+
node_fs_1.default.writeFileSync(packageJSONPath, packageJSONContent);
|
|
31
|
+
node_fs_1.default.writeFileSync(readmePath, readmeContent);
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
console.error(`Failed to create directory or write files: ${error.message}`);
|
|
35
|
+
}
|
|
36
|
+
this.log(separator);
|
|
37
|
+
const directusUrl = await (0, auth_1.getDirectusUrl)();
|
|
38
|
+
api_1.api.setBaseUrl(directusUrl);
|
|
39
|
+
const directusToken = await (0, auth_1.getDirectusToken)(directusUrl);
|
|
40
|
+
api_1.api.setAuthToken(directusToken);
|
|
41
|
+
this.log(separator);
|
|
42
|
+
// Run the extract script
|
|
43
|
+
core_2.ux.action.start(`Extracting template - from ${directusUrl} to ${directory}`);
|
|
44
|
+
await (0, extract_1.default)(directory, this);
|
|
45
|
+
core_2.ux.action.stop();
|
|
46
|
+
this.log(separator);
|
|
47
|
+
this.log("Template extracted successfully.");
|
|
48
|
+
this.exit(0);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.default = ExtractCommand;
|
|
52
|
+
ExtractCommand.description = "Extract a template from a Directus instance.";
|
|
53
|
+
ExtractCommand.examples = ["$ directus-template-cli extract"];
|
|
54
|
+
ExtractCommand.flags = {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.downloadAllFiles = exports.downloadFile = exports.getAssetList = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
|
|
6
|
+
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
7
|
+
const api_1 = require("../api");
|
|
8
|
+
async function getAssetList() {
|
|
9
|
+
const { data } = await api_1.api.get("/files", {
|
|
10
|
+
params: {
|
|
11
|
+
limit: "-1",
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
return data.data;
|
|
15
|
+
}
|
|
16
|
+
exports.getAssetList = getAssetList;
|
|
17
|
+
async function downloadFile(file, dir) {
|
|
18
|
+
const response = await api_1.api.get(`assets/${file.id}`, {
|
|
19
|
+
responseType: "stream",
|
|
20
|
+
});
|
|
21
|
+
// Create assets folder if it doesn't exist
|
|
22
|
+
const fullPath = node_path_1.default.join(dir, "assets");
|
|
23
|
+
if (node_path_1.default && !node_fs_1.default.existsSync(fullPath)) {
|
|
24
|
+
node_fs_1.default.mkdirSync(fullPath, { recursive: true });
|
|
25
|
+
}
|
|
26
|
+
const writePath = node_path_1.default.resolve(dir, "assets", file.filename_disk);
|
|
27
|
+
const writer = node_fs_1.default.createWriteStream(writePath);
|
|
28
|
+
response.data.pipe(writer);
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
writer.on("finish", () => {
|
|
31
|
+
// console.log(`Wrote ${file.filename_disk}`);
|
|
32
|
+
resolve(null);
|
|
33
|
+
});
|
|
34
|
+
writer.on("error", reject);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
exports.downloadFile = downloadFile;
|
|
38
|
+
async function downloadAllFiles(dir) {
|
|
39
|
+
const fileList = await getAssetList();
|
|
40
|
+
for (const file of fileList) {
|
|
41
|
+
try {
|
|
42
|
+
await downloadFile(file, dir);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
console.log(`Error downloading ${file.filename_disk}`, error);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.downloadAllFiles = downloadAllFiles;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractContent = exports.getDataFromCollection = exports.getCollections = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const api_1 = require("../api");
|
|
6
|
+
const write_to_file_1 = tslib_1.__importDefault(require("../utils/write-to-file"));
|
|
7
|
+
async function getCollections() {
|
|
8
|
+
const { data } = await api_1.api.get("/collections");
|
|
9
|
+
const collections = data.data
|
|
10
|
+
.filter((item) => !item.collection.startsWith("directus_", 0))
|
|
11
|
+
.filter((item) => item.schema != null)
|
|
12
|
+
.map((i) => i.collection);
|
|
13
|
+
return collections;
|
|
14
|
+
}
|
|
15
|
+
exports.getCollections = getCollections;
|
|
16
|
+
async function getDataFromCollection(collection, dir) {
|
|
17
|
+
try {
|
|
18
|
+
const { data } = await api_1.api.get(`items/${collection}`); // ADD limit = -1
|
|
19
|
+
(0, write_to_file_1.default)(`${collection}`, data.data, `${dir}/content/`);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
console.log(`error getting items from ${collection}`);
|
|
23
|
+
// Errors are thrown for 'folder' collections
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.getDataFromCollection = getDataFromCollection;
|
|
27
|
+
async function extractContent(dir) {
|
|
28
|
+
const collections = await getCollections();
|
|
29
|
+
for (const collection of collections) {
|
|
30
|
+
await getDataFromCollection(collection, dir);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.extractContent = extractContent;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const api_1 = require("../api");
|
|
5
|
+
const write_to_file_1 = tslib_1.__importDefault(require("../utils/write-to-file"));
|
|
6
|
+
const filter_fields_1 = tslib_1.__importDefault(require("../utils/filter-fields"));
|
|
7
|
+
const systemFields = [
|
|
8
|
+
"id",
|
|
9
|
+
"storage",
|
|
10
|
+
"filename_disk",
|
|
11
|
+
"filename_download",
|
|
12
|
+
"title",
|
|
13
|
+
"type",
|
|
14
|
+
"folder",
|
|
15
|
+
"uploaded_by",
|
|
16
|
+
"uploaded_on",
|
|
17
|
+
"modified_by",
|
|
18
|
+
"modified_on",
|
|
19
|
+
"charset",
|
|
20
|
+
"filesize",
|
|
21
|
+
"width",
|
|
22
|
+
"height",
|
|
23
|
+
"duration",
|
|
24
|
+
"embed",
|
|
25
|
+
"description",
|
|
26
|
+
"location",
|
|
27
|
+
"tags",
|
|
28
|
+
"metadata",
|
|
29
|
+
];
|
|
30
|
+
/**
|
|
31
|
+
* Extract files from the API
|
|
32
|
+
*/
|
|
33
|
+
async function extractFiles(dir) {
|
|
34
|
+
try {
|
|
35
|
+
const { data } = await api_1.api.get("/files", {
|
|
36
|
+
params: {
|
|
37
|
+
limit: "-1",
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
const filteredData = (0, filter_fields_1.default)(data.data, systemFields);
|
|
41
|
+
// Use the dynamic dir parameter
|
|
42
|
+
await (0, write_to_file_1.default)("files", filteredData, dir);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
console.log("Error extracting Files:", error.response.data.errors);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.default = extractFiles;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const api_1 = require("../api");
|
|
5
|
+
const write_to_file_1 = tslib_1.__importDefault(require("../utils/write-to-file"));
|
|
6
|
+
const filter_fields_1 = tslib_1.__importDefault(require("../utils/filter-fields"));
|
|
7
|
+
const systemFields = ["id", "name", "parent"];
|
|
8
|
+
/**
|
|
9
|
+
* Extract folders from the API
|
|
10
|
+
*/
|
|
11
|
+
async function extractFolders(dir) {
|
|
12
|
+
try {
|
|
13
|
+
const { data } = await api_1.api.get("/folders", {
|
|
14
|
+
params: {
|
|
15
|
+
limit: "-1",
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
const filteredData = (0, filter_fields_1.default)(data.data, systemFields);
|
|
19
|
+
// Use the dynamic dir parameter
|
|
20
|
+
await (0, write_to_file_1.default)("folders", filteredData, dir);
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
console.log("Error extracting Folders:", error.response.data.errors);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.default = extractFolders;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const api_1 = require("../api");
|
|
5
|
+
const write_to_file_1 = tslib_1.__importDefault(require("../utils/write-to-file"));
|
|
6
|
+
/**
|
|
7
|
+
* [default query an endpoint and write the result to file]
|
|
8
|
+
*/
|
|
9
|
+
async function extractFromEndpoint(path, dir) {
|
|
10
|
+
try {
|
|
11
|
+
const { data } = await api_1.api.get(`/${path}`, {
|
|
12
|
+
params: {
|
|
13
|
+
limit: "-1",
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
// Use the dynamic dir parameter
|
|
17
|
+
await (0, write_to_file_1.default)(`${path}`, data.data, dir);
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
console.log(`Error querying endpoint ${path}:`, error.response.data.errors);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.default = extractFromEndpoint;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const api_1 = require("../api");
|
|
5
|
+
const write_to_file_1 = tslib_1.__importDefault(require("../utils/write-to-file"));
|
|
6
|
+
const filter_fields_1 = tslib_1.__importDefault(require("../utils/filter-fields"));
|
|
7
|
+
const systemFields = [
|
|
8
|
+
"id",
|
|
9
|
+
"name",
|
|
10
|
+
"description",
|
|
11
|
+
"icon",
|
|
12
|
+
"enforce_tfa",
|
|
13
|
+
"external_id",
|
|
14
|
+
"ip_whitelist",
|
|
15
|
+
"app_access",
|
|
16
|
+
"admin_access",
|
|
17
|
+
];
|
|
18
|
+
/**
|
|
19
|
+
* Extract roles from the API
|
|
20
|
+
*/
|
|
21
|
+
async function extractRoles(dir) {
|
|
22
|
+
try {
|
|
23
|
+
const { data } = await api_1.api.get("/roles", {
|
|
24
|
+
params: {
|
|
25
|
+
limit: "-1",
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
const filteredData = (0, filter_fields_1.default)(data.data, systemFields);
|
|
29
|
+
// Use the dynamic dir parameter
|
|
30
|
+
await (0, write_to_file_1.default)("roles", filteredData, dir);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
console.log("Error extracting Roles:", error.response.data.errors);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.default = extractRoles;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function extractSchema(dir: string): Promise<void>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
|
|
5
|
+
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
6
|
+
const api_1 = require("../api");
|
|
7
|
+
const write_to_file_1 = tslib_1.__importDefault(require("../utils/write-to-file"));
|
|
8
|
+
async function extractSchema(dir) {
|
|
9
|
+
const schemaDir = node_path_1.default.join(dir, "schema");
|
|
10
|
+
// Check if directory for schema exists, if not, then create it.
|
|
11
|
+
if (!node_fs_1.default.existsSync(schemaDir)) {
|
|
12
|
+
console.log(`Attempting to create directory at: ${schemaDir}`);
|
|
13
|
+
node_fs_1.default.mkdirSync(schemaDir, { recursive: true });
|
|
14
|
+
}
|
|
15
|
+
// Get the schema
|
|
16
|
+
try {
|
|
17
|
+
const { data } = await api_1.api.get("/schema/snapshot", {
|
|
18
|
+
params: {
|
|
19
|
+
limit: "-1",
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
// Write the schema to the specified directory
|
|
23
|
+
await (0, write_to_file_1.default)("schema/snapshot", data.data, dir);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
console.log("Error fetching schema snapshot:", error);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.default = extractSchema;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const api_1 = require("../api");
|
|
5
|
+
const write_to_file_1 = tslib_1.__importDefault(require("../utils/write-to-file"));
|
|
6
|
+
const filter_fields_1 = tslib_1.__importDefault(require("../utils/filter-fields"));
|
|
7
|
+
const systemFields = [
|
|
8
|
+
"id",
|
|
9
|
+
"status",
|
|
10
|
+
"first_name",
|
|
11
|
+
"last_name",
|
|
12
|
+
"email",
|
|
13
|
+
"password",
|
|
14
|
+
"token",
|
|
15
|
+
"last_access",
|
|
16
|
+
"last_page",
|
|
17
|
+
"external_identifier",
|
|
18
|
+
"tfa_secret",
|
|
19
|
+
"auth_data",
|
|
20
|
+
"provider",
|
|
21
|
+
"theme",
|
|
22
|
+
"role",
|
|
23
|
+
"language",
|
|
24
|
+
"avatar",
|
|
25
|
+
"title",
|
|
26
|
+
"description",
|
|
27
|
+
"location",
|
|
28
|
+
"tags",
|
|
29
|
+
"email_notifications",
|
|
30
|
+
];
|
|
31
|
+
/**
|
|
32
|
+
* Extract users from the API
|
|
33
|
+
*/
|
|
34
|
+
async function extractUsers(dir) {
|
|
35
|
+
try {
|
|
36
|
+
const { data } = await api_1.api.get("/users", {
|
|
37
|
+
params: {
|
|
38
|
+
limit: "-1",
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
const filteredData = (0, filter_fields_1.default)(data.data, systemFields);
|
|
42
|
+
// Use the dynamic dir parameter
|
|
43
|
+
await (0, write_to_file_1.default)("users", filteredData, dir);
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
console.log("Error extracting Users:", error.response.data.errors);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.default = extractUsers;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function extract(dir: string, cli: any): Promise<{}>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
|
|
5
|
+
const extract_assets_1 = require("./extract-assets");
|
|
6
|
+
const extract_schema_1 = tslib_1.__importDefault(require("./extract-schema"));
|
|
7
|
+
const extract_from_endpoint_1 = tslib_1.__importDefault(require("./extract-from-endpoint"));
|
|
8
|
+
const public_permissions_1 = tslib_1.__importDefault(require("./public-permissions"));
|
|
9
|
+
const extract_content_1 = require("./extract-content");
|
|
10
|
+
const extract_folders_1 = tslib_1.__importDefault(require("./extract-folders"));
|
|
11
|
+
const extract_users_1 = tslib_1.__importDefault(require("./extract-users"));
|
|
12
|
+
const extract_roles_1 = tslib_1.__importDefault(require("./extract-roles"));
|
|
13
|
+
const extract_files_1 = tslib_1.__importDefault(require("./extract-files"));
|
|
14
|
+
const endpoints = [
|
|
15
|
+
// "folders",
|
|
16
|
+
// "fields",
|
|
17
|
+
// "users",
|
|
18
|
+
// "roles",
|
|
19
|
+
// "files",
|
|
20
|
+
"operations",
|
|
21
|
+
"permissions",
|
|
22
|
+
"collections",
|
|
23
|
+
"flows",
|
|
24
|
+
"dashboards",
|
|
25
|
+
"panels",
|
|
26
|
+
"presets",
|
|
27
|
+
"settings",
|
|
28
|
+
];
|
|
29
|
+
async function extract(dir, cli) {
|
|
30
|
+
// Get the destination directory for the actual files
|
|
31
|
+
const destination = dir + "/src";
|
|
32
|
+
// Check if directory exists, if not, then create it.
|
|
33
|
+
if (!node_fs_1.default.existsSync(destination)) {
|
|
34
|
+
console.log(`Attempting to create directory at: ${destination}`);
|
|
35
|
+
node_fs_1.default.mkdirSync(destination, { recursive: true });
|
|
36
|
+
}
|
|
37
|
+
// Extract the schema
|
|
38
|
+
await (0, extract_schema_1.default)(destination);
|
|
39
|
+
await (0, extract_folders_1.default)(destination);
|
|
40
|
+
await (0, extract_users_1.default)(destination);
|
|
41
|
+
await (0, extract_roles_1.default)(destination);
|
|
42
|
+
await (0, extract_files_1.default)(destination);
|
|
43
|
+
// Iterate through the endpoints
|
|
44
|
+
for (const endpoint of endpoints) {
|
|
45
|
+
await (0, extract_from_endpoint_1.default)(endpoint, destination);
|
|
46
|
+
}
|
|
47
|
+
// Extract public permissions
|
|
48
|
+
await (0, public_permissions_1.default)(destination);
|
|
49
|
+
// Extract content
|
|
50
|
+
await (0, extract_content_1.extractContent)(destination);
|
|
51
|
+
// Extract assets
|
|
52
|
+
await (0, extract_assets_1.downloadAllFiles)(destination);
|
|
53
|
+
return {};
|
|
54
|
+
}
|
|
55
|
+
exports.default = extract;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function extractPublicPermissions(dir: string): Promise<void>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const api_1 = require("../api");
|
|
5
|
+
const write_to_file_1 = tslib_1.__importDefault(require("../utils/write-to-file"));
|
|
6
|
+
async function extractPublicPermissions(dir) {
|
|
7
|
+
try {
|
|
8
|
+
const { data } = await api_1.api.get("permissions", {
|
|
9
|
+
params: {
|
|
10
|
+
limit: "-1",
|
|
11
|
+
"filter[role][_null]": true,
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
// Write the public permissions to the specified directory
|
|
15
|
+
await (0, write_to_file_1.default)("public-permissions", data.data, dir);
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
console.log("Error fetching public permissions:", error);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.default = extractPublicPermissions;
|
package/dist/lib/load/index.js
CHANGED
|
@@ -7,43 +7,46 @@ const load_schema_1 = tslib_1.__importDefault(require("./load-schema"));
|
|
|
7
7
|
const load_roles_1 = tslib_1.__importDefault(require("./load-roles"));
|
|
8
8
|
const load_dashboards_1 = tslib_1.__importDefault(require("./load-dashboards"));
|
|
9
9
|
const load_files_1 = tslib_1.__importDefault(require("./load-files"));
|
|
10
|
+
const load_folders_1 = tslib_1.__importDefault(require("./load-folders"));
|
|
10
11
|
const load_users_1 = tslib_1.__importDefault(require("./load-users"));
|
|
11
12
|
const load_flows_1 = tslib_1.__importDefault(require("./load-flows"));
|
|
12
13
|
const load_operations_1 = tslib_1.__importDefault(require("./load-operations"));
|
|
13
14
|
const load_data_1 = tslib_1.__importDefault(require("./load-data"));
|
|
14
15
|
const load_presets_1 = tslib_1.__importDefault(require("./load-presets"));
|
|
15
16
|
const load_settings_1 = tslib_1.__importDefault(require("./load-settings"));
|
|
16
|
-
const load_public_permissions_1 =
|
|
17
|
+
const load_public_permissions_1 = require("./load-public-permissions");
|
|
17
18
|
async function apply(dir, cli) {
|
|
18
19
|
// Get the source directory for the actual files
|
|
19
|
-
const source = dir +
|
|
20
|
+
const source = dir + "/src";
|
|
20
21
|
// Load the template files into the destination
|
|
21
|
-
await (0, load_schema_1.default)(source +
|
|
22
|
-
cli.log(
|
|
23
|
-
await (0, load_roles_1.default)((0, read_file_1.default)(
|
|
24
|
-
cli.log(
|
|
25
|
-
await (0,
|
|
26
|
-
cli.log(
|
|
27
|
-
await (0,
|
|
28
|
-
cli.log(
|
|
29
|
-
await (0,
|
|
30
|
-
cli.log(
|
|
31
|
-
await (0,
|
|
32
|
-
cli.log(
|
|
33
|
-
await (0,
|
|
34
|
-
cli.log(
|
|
35
|
-
await (0, load_flows_1.default)((0, read_file_1.default)(
|
|
36
|
-
cli.log(
|
|
37
|
-
await (0, load_operations_1.default)((0, read_file_1.default)(
|
|
38
|
-
cli.log(
|
|
39
|
-
await (0, load_data_1.default)((0, read_file_1.default)(
|
|
40
|
-
cli.log(
|
|
41
|
-
await (0, load_presets_1.default)((0, read_file_1.default)(
|
|
42
|
-
cli.log(
|
|
43
|
-
await (0, load_settings_1.default)((0, read_file_1.default)(
|
|
44
|
-
cli.log(
|
|
45
|
-
await (0, load_public_permissions_1.
|
|
46
|
-
cli.log(
|
|
22
|
+
await (0, load_schema_1.default)(source + "/schema");
|
|
23
|
+
cli.log("Loaded Schema");
|
|
24
|
+
await (0, load_roles_1.default)((0, read_file_1.default)("roles", source));
|
|
25
|
+
cli.log("Loaded Roles");
|
|
26
|
+
await (0, load_files_1.default)((0, read_file_1.default)("files", source), source); // Comes after folders
|
|
27
|
+
cli.log("Loaded Files");
|
|
28
|
+
await (0, load_users_1.default)((0, read_file_1.default)("users", source)); // Comes after roles, files
|
|
29
|
+
cli.log("Loaded Users");
|
|
30
|
+
await (0, load_folders_1.default)(source);
|
|
31
|
+
cli.log("Loaded Folders");
|
|
32
|
+
await (0, load_dashboards_1.default)((0, read_file_1.default)("dashboards", source));
|
|
33
|
+
cli.log("Loaded Dashboards");
|
|
34
|
+
await (0, load_to_destination_1.default)("panels", (0, read_file_1.default)("panels", source)); // Comes after dashboards
|
|
35
|
+
cli.log("Loaded Panels");
|
|
36
|
+
await (0, load_flows_1.default)((0, read_file_1.default)("flows", source));
|
|
37
|
+
cli.log("Loaded Flows");
|
|
38
|
+
await (0, load_operations_1.default)((0, read_file_1.default)("operations", source)); // Comes after flows
|
|
39
|
+
cli.log("Loaded Operations");
|
|
40
|
+
await (0, load_data_1.default)((0, read_file_1.default)("collections", source), source);
|
|
41
|
+
cli.log("Loaded Data");
|
|
42
|
+
await (0, load_presets_1.default)((0, read_file_1.default)("presets", source));
|
|
43
|
+
cli.log("Loaded Presets");
|
|
44
|
+
await (0, load_settings_1.default)((0, read_file_1.default)("settings", source));
|
|
45
|
+
cli.log("Loaded Settings");
|
|
46
|
+
await (0, load_public_permissions_1.loadPublicPermissions)((0, read_file_1.default)("public-permissions", source));
|
|
47
|
+
cli.log("Loaded Public Permissions");
|
|
48
|
+
await (0, load_public_permissions_1.loadPermissions)((0, read_file_1.default)("permissions", source));
|
|
49
|
+
cli.log("Loaded Permissions");
|
|
47
50
|
return {};
|
|
48
51
|
}
|
|
49
52
|
exports.default = apply;
|
|
@@ -5,12 +5,20 @@ const api_1 = require("../api");
|
|
|
5
5
|
const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
6
6
|
async function loadFolders(dir) {
|
|
7
7
|
try {
|
|
8
|
-
const folders = await (0, read_file_1.default)(
|
|
9
|
-
const
|
|
10
|
-
|
|
8
|
+
const folders = await (0, read_file_1.default)("folders", dir);
|
|
9
|
+
const folderSkeleton = folders.map((folder) => {
|
|
10
|
+
return { id: folder.id, name: folder.name };
|
|
11
|
+
});
|
|
12
|
+
// Create the folders
|
|
13
|
+
const { data } = await api_1.api.post("/folders", folderSkeleton);
|
|
14
|
+
// Loop through the folders and update them with relationships
|
|
15
|
+
folders.forEach(async (folder) => {
|
|
16
|
+
const { id, ...rest } = folder;
|
|
17
|
+
await api_1.api.patch(`/folders/${id}`, rest);
|
|
18
|
+
});
|
|
11
19
|
}
|
|
12
20
|
catch (error) {
|
|
13
|
-
console.log(
|
|
21
|
+
console.log("Error loading Folders", error.response.data.errors);
|
|
14
22
|
}
|
|
15
23
|
}
|
|
16
24
|
exports.default = loadFolders;
|
|
@@ -2,16 +2,27 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const api_1 = require("../api");
|
|
4
4
|
exports.default = async (presets) => {
|
|
5
|
-
|
|
5
|
+
await deleteAllPresets();
|
|
6
|
+
const cleanPresets = presets.map((preset) => {
|
|
6
7
|
preset.user = null;
|
|
7
8
|
return preset;
|
|
8
9
|
});
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
try {
|
|
11
|
+
await api_1.api.post("presets", cleanPresets);
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
console.log("Error uploading preset", error.response.data.errors);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
const deleteAllPresets = async () => {
|
|
18
|
+
try {
|
|
19
|
+
const { data: presets } = await api_1.api.get("presets");
|
|
20
|
+
const ids = presets.data.map((preset) => preset.id);
|
|
21
|
+
await api_1.api.delete("presets", {
|
|
22
|
+
data: ids,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
console.log("Error removing existing presets", error.response.data.errors);
|
|
16
27
|
}
|
|
17
28
|
};
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export
|
|
1
|
+
export declare function loadPublicPermissions(roles: any): Promise<void>;
|
|
2
|
+
export declare function loadPermissions(roles: any): Promise<void>;
|
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadPermissions = exports.loadPublicPermissions = void 0;
|
|
3
4
|
const tslib_1 = require("tslib");
|
|
4
5
|
const api_1 = require("../api");
|
|
5
6
|
const load_to_destination_1 = tslib_1.__importDefault(require("../utils/load-to-destination"));
|
|
6
7
|
async function removeallPublicPermissions() {
|
|
7
|
-
const { data } = await api_1.api.get(
|
|
8
|
-
|
|
8
|
+
const { data } = await api_1.api.get("permissions?filter[role][_null]=true&limit=-1");
|
|
9
|
+
console.log("Removing all public permissions", data.data);
|
|
10
|
+
const ids = data.data.map((i) => i.id);
|
|
9
11
|
if (!ids)
|
|
10
12
|
return;
|
|
11
|
-
await api_1.api.delete(
|
|
13
|
+
await api_1.api.delete("permissions", {
|
|
12
14
|
data: ids,
|
|
13
15
|
});
|
|
14
16
|
}
|
|
15
17
|
async function loadPublicPermissions(roles) {
|
|
16
18
|
await removeallPublicPermissions();
|
|
17
|
-
await (0, load_to_destination_1.default)(
|
|
19
|
+
await (0, load_to_destination_1.default)("permissions", roles);
|
|
18
20
|
}
|
|
19
|
-
exports.
|
|
21
|
+
exports.loadPublicPermissions = loadPublicPermissions;
|
|
22
|
+
async function loadPermissions(roles) {
|
|
23
|
+
await (0, load_to_destination_1.default)("permissions", roles);
|
|
24
|
+
}
|
|
25
|
+
exports.loadPermissions = loadPermissions;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getDirectusToken = exports.getDirectusUrl = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const core_1 = require("@oclif/core");
|
|
6
|
+
const api_1 = require("../api");
|
|
7
|
+
const validate_url_1 = tslib_1.__importDefault(require("./validate-url"));
|
|
8
|
+
async function getDirectusUrl() {
|
|
9
|
+
const directusUrl = await core_1.ux.prompt("What is your Directus URL?");
|
|
10
|
+
// Validate URL
|
|
11
|
+
if (!(0, validate_url_1.default)(directusUrl)) {
|
|
12
|
+
core_1.ux.warn("Invalid URL");
|
|
13
|
+
return getDirectusUrl();
|
|
14
|
+
}
|
|
15
|
+
return directusUrl;
|
|
16
|
+
}
|
|
17
|
+
exports.getDirectusUrl = getDirectusUrl;
|
|
18
|
+
async function getDirectusToken(directusUrl) {
|
|
19
|
+
const directusToken = await core_1.ux.prompt("What is your Directus Admin Token?");
|
|
20
|
+
// Validate token
|
|
21
|
+
try {
|
|
22
|
+
await api_1.api.get("/users/me", {
|
|
23
|
+
headers: {
|
|
24
|
+
Authorization: `Bearer ${directusToken}`,
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
return directusToken;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
core_1.ux.warn("Invalid token");
|
|
31
|
+
return getDirectusToken(directusUrl);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.getDirectusToken = getDirectusToken;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function filterFields(dataArray: any, systemFields: any): any;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
// Utility function to filter out non-system fields
|
|
4
|
+
function filterFields(dataArray, systemFields) {
|
|
5
|
+
return dataArray.map((item) => {
|
|
6
|
+
for (const key of Object.keys(item)) {
|
|
7
|
+
if (!systemFields.includes(key)) {
|
|
8
|
+
const value = item[key];
|
|
9
|
+
if (Array.isArray(value)) {
|
|
10
|
+
const isArrayOfIntegers = value.every((v) => Number.isInteger(v));
|
|
11
|
+
const isArrayOfUUIDs = value.every((v) => typeof v === "string" &&
|
|
12
|
+
/[\dA-Fa-f]{8}(?:-[\dA-Fa-f]{4}){3}-[\dA-Fa-f]{12}/.test(v));
|
|
13
|
+
if (isArrayOfIntegers || isArrayOfUUIDs) {
|
|
14
|
+
item[key] = null; // or item[key] = [];
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return item;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
exports.default = filterFields;
|
|
@@ -2,5 +2,6 @@ interface Template {
|
|
|
2
2
|
directoryPath: string;
|
|
3
3
|
templateName: string;
|
|
4
4
|
}
|
|
5
|
-
export
|
|
5
|
+
export declare function readTemplate(directoryPath: string): Promise<Template | null>;
|
|
6
|
+
export declare function readAllTemplates(directoryPath: string): Promise<Template[]>;
|
|
6
7
|
export {};
|
|
@@ -1,36 +1,41 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readAllTemplates = exports.readTemplate = void 0;
|
|
3
4
|
const tslib_1 = require("tslib");
|
|
4
5
|
const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
|
|
5
6
|
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
6
|
-
async function
|
|
7
|
+
async function readTemplate(directoryPath) {
|
|
8
|
+
const packageFilePath = node_path_1.default.join(directoryPath, "package.json");
|
|
9
|
+
try {
|
|
10
|
+
const packageData = await node_fs_1.default.promises.readFile(packageFilePath, "utf-8");
|
|
11
|
+
const packageJson = JSON.parse(packageData);
|
|
12
|
+
if (packageJson.templateName) {
|
|
13
|
+
return {
|
|
14
|
+
directoryPath,
|
|
15
|
+
templateName: packageJson.templateName,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
console.error(`Failed to read package.json file in directory ${directoryPath}: ${error}`);
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.readTemplate = readTemplate;
|
|
26
|
+
async function readAllTemplates(directoryPath) {
|
|
7
27
|
const templates = [];
|
|
8
|
-
// Read the contents of the directory
|
|
9
28
|
const files = await node_fs_1.default.promises.readdir(directoryPath);
|
|
10
|
-
// Loop through each file in the directory
|
|
11
29
|
for (const file of files) {
|
|
12
|
-
// Check if the file is a directory
|
|
13
30
|
const filePath = node_path_1.default.join(directoryPath, file);
|
|
14
31
|
const stats = await node_fs_1.default.promises.stat(filePath);
|
|
15
32
|
if (stats.isDirectory()) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const packageData = await node_fs_1.default.promises.readFile(packageFilePath, 'utf-8');
|
|
20
|
-
const packageJson = JSON.parse(packageData);
|
|
21
|
-
if (packageJson.templateName) {
|
|
22
|
-
const template = {
|
|
23
|
-
directoryPath: filePath,
|
|
24
|
-
templateName: packageJson.templateName,
|
|
25
|
-
};
|
|
26
|
-
templates.push(template);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
catch (error) {
|
|
30
|
-
console.error(`Failed to read package.json file in directory ${filePath}: ${error}`);
|
|
33
|
+
const template = await readTemplate(filePath);
|
|
34
|
+
if (template) {
|
|
35
|
+
templates.push(template);
|
|
31
36
|
}
|
|
32
37
|
}
|
|
33
38
|
}
|
|
34
39
|
return templates;
|
|
35
40
|
}
|
|
36
|
-
exports.
|
|
41
|
+
exports.readAllTemplates = readAllTemplates;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateReadmeContent = exports.generatePackageJsonContent = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const slugify_1 = tslib_1.__importDefault(require("slugify"));
|
|
6
|
+
const generatePackageJsonContent = (templateName) => {
|
|
7
|
+
const slugifiedName = (0, slugify_1.default)(templateName, {
|
|
8
|
+
lower: true,
|
|
9
|
+
strict: true, // Remove special characters
|
|
10
|
+
});
|
|
11
|
+
const packageName = `directus-template-${slugifiedName}`;
|
|
12
|
+
return JSON.stringify({
|
|
13
|
+
name: packageName,
|
|
14
|
+
templateName: templateName,
|
|
15
|
+
version: "1.0.0",
|
|
16
|
+
description: "",
|
|
17
|
+
author: "",
|
|
18
|
+
license: "MIT",
|
|
19
|
+
files: ["src"],
|
|
20
|
+
}, null, 2);
|
|
21
|
+
};
|
|
22
|
+
exports.generatePackageJsonContent = generatePackageJsonContent;
|
|
23
|
+
const generateReadmeContent = (templateName) => {
|
|
24
|
+
return `# ${templateName} Template
|
|
25
|
+
|
|
26
|
+
This is a template for [Directus](https://directus.io/) - an open-source headless CMS and API. Use the template-cli to load / apply this template to a blank instance.
|
|
27
|
+
|
|
28
|
+
## Why
|
|
29
|
+
|
|
30
|
+
## What
|
|
31
|
+
|
|
32
|
+
## License
|
|
33
|
+
|
|
34
|
+
This template is licensed under the [MIT License](https://opensource.org/licenses/MIT).
|
|
35
|
+
`;
|
|
36
|
+
};
|
|
37
|
+
exports.generateReadmeContent = generateReadmeContent;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: (fileName: string, data: any) => Promise<void>;
|
|
1
|
+
declare const _default: (fileName: string, data: any, dir: string) => Promise<void>;
|
|
2
2
|
export default _default;
|
|
@@ -3,20 +3,24 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
5
5
|
const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const folders = fileName.split('/');
|
|
6
|
+
exports.default = async (fileName, data, dir) => {
|
|
7
|
+
const folders = fileName.split("/");
|
|
9
8
|
const endFileName = folders.pop();
|
|
10
|
-
const folderPath = folders.join(
|
|
9
|
+
const folderPath = folders.join("/");
|
|
10
|
+
// Generate the full path where you want to write the file
|
|
11
11
|
const fullPath = node_path_1.default.join(dir, folderPath);
|
|
12
|
-
if
|
|
13
|
-
|
|
12
|
+
// Check if the directory exists. Create if it doesn't.
|
|
13
|
+
if (!node_fs_1.default.existsSync(fullPath)) {
|
|
14
|
+
node_fs_1.default.mkdirSync(fullPath, { recursive: true });
|
|
14
15
|
}
|
|
16
|
+
// Construct the full file path
|
|
17
|
+
const fullFilePath = node_path_1.default.join(fullPath, `${endFileName}.json`);
|
|
15
18
|
try {
|
|
16
|
-
|
|
17
|
-
|
|
19
|
+
// Write the file
|
|
20
|
+
await node_fs_1.default.promises.writeFile(fullFilePath, JSON.stringify(data, null, 2));
|
|
21
|
+
// console.log(`Wrote ${fullFilePath}`);
|
|
18
22
|
}
|
|
19
23
|
catch (error) {
|
|
20
|
-
console.log(
|
|
24
|
+
console.log("Error writing to file", error.data.errors);
|
|
21
25
|
}
|
|
22
26
|
};
|
package/oclif.manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
2
|
+
"version": "0.3.0-beta.2",
|
|
3
3
|
"commands": {
|
|
4
4
|
"apply": {
|
|
5
5
|
"id": "apply",
|
|
@@ -14,6 +14,20 @@
|
|
|
14
14
|
],
|
|
15
15
|
"flags": {},
|
|
16
16
|
"args": {}
|
|
17
|
+
},
|
|
18
|
+
"extract": {
|
|
19
|
+
"id": "extract",
|
|
20
|
+
"description": "Extract a template from a Directus instance.",
|
|
21
|
+
"strict": true,
|
|
22
|
+
"pluginName": "directus-template-cli",
|
|
23
|
+
"pluginAlias": "directus-template-cli",
|
|
24
|
+
"pluginType": "core",
|
|
25
|
+
"aliases": [],
|
|
26
|
+
"examples": [
|
|
27
|
+
"$ directus-template-cli extract"
|
|
28
|
+
],
|
|
29
|
+
"flags": {},
|
|
30
|
+
"args": {}
|
|
17
31
|
}
|
|
18
32
|
}
|
|
19
33
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "directus-template-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0-beta.2",
|
|
4
4
|
"description": "CLI Utility for applying templates to a Directus instance.",
|
|
5
5
|
"author": "bryantgillespie @bryantgillespie",
|
|
6
6
|
"bin": {
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
"dotenv": "^16.0.3",
|
|
27
27
|
"formdata-node": "^5.0.0",
|
|
28
28
|
"generate-password": "^1.7.0",
|
|
29
|
-
"inquirer": "^8.2.5"
|
|
29
|
+
"inquirer": "^8.2.5",
|
|
30
|
+
"slugify": "^1.6.6"
|
|
30
31
|
},
|
|
31
32
|
"devDependencies": {
|
|
32
33
|
"@oclif/test": "^2.3.16",
|