@shoper/cli 0.1.0-24 → 0.1.0-25
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/build/cli/core/cli_setup.js +3 -1
- package/build/theme/commands/delete/theme_delete_command.js +99 -0
- package/build/theme/commands/init/theme_init_command.js +1 -0
- package/build/theme/commands/push/theme_push_command.js +1 -2
- package/build/theme/commands/theme_commands_constants.js +2 -1
- package/build/theme/features/theme/actions/theme_actions_constants.js +1 -2
- package/build/theme/features/theme/delete/api/theme_delete_api.js +13 -0
- package/build/theme/features/theme/delete/http/theme_delete_http_api.js +17 -0
- package/build/theme/features/theme/delete/service/theme_delete_service.js +34 -0
- package/build/theme/features/theme/delete/theme_delete_constants.js +2 -0
- package/build/theme/features/theme/delete/theme_delete_initalizer.js +20 -0
- package/build/theme/features/theme/merge/service/theme_merge_service.js +2 -2
- package/build/theme/features/theme/push/service/theme_push_service.js +1 -1
- package/build/theme/features/theme/utils/checksums/theme_checksums_utils.js +0 -2
- package/build/theme/features/theme/utils/meta_data/theme_meta_data_utils.js +1 -1
- package/build/theme/index.js +3 -1
- package/build/utils/download_file/download_file_utils.js +1 -1
- package/package.json +1 -1
- package/build/theme/commands/push/ui/theme_validation_error.js +0 -6
- package/build/theme/commands/push/ui/theme_validation_errors.js +0 -5
|
@@ -14,6 +14,7 @@ import { ThemeFetchInitializer } from '../../theme/features/theme/fetch/theme_fe
|
|
|
14
14
|
import { ThemeMergeInitializer } from '../../theme/features/theme/merge/theme_merge_initializer.js';
|
|
15
15
|
import { ThemeActionsInitializer } from '../../theme/features/theme/actions/theme_actions_initializer.js';
|
|
16
16
|
import { ThemePushInitializer } from '../../theme/features/theme/push/theme_push_initializer.js';
|
|
17
|
+
import { ThemeDeleteInitializer } from '../../theme/features/theme/delete/theme_delete_initalizer.js';
|
|
17
18
|
tmp.setGracefulCleanup();
|
|
18
19
|
export const cliSetup = async () => {
|
|
19
20
|
//TODO jakis ładny komuniakt błedu
|
|
@@ -34,7 +35,8 @@ export const cliSetup = async () => {
|
|
|
34
35
|
ThemeInitInitializer,
|
|
35
36
|
ThemeMergeInitializer,
|
|
36
37
|
ThemeFetchInitializer,
|
|
37
|
-
ThemePushInitializer
|
|
38
|
+
ThemePushInitializer,
|
|
39
|
+
ThemeDeleteInitializer
|
|
38
40
|
],
|
|
39
41
|
options: {
|
|
40
42
|
featuresTracking: false,
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Args } from '@oclif/core';
|
|
2
|
+
import { BaseThemeCommand } from '../../class/base_theme_command.js';
|
|
3
|
+
import { CLI_AUTH_API_NAME } from '../../../cli/auth/cli_auth_constants.js';
|
|
4
|
+
import { THEME_ACTION_NOT_FOUND_ERROR_CODE, THEME_ACTIONS_API_NAME, THEME_ACTIONS_TYPES } from '../../features/theme/actions/theme_actions_constants.js';
|
|
5
|
+
import { EXECUTION_CONTEXT_API_NAME } from '../../../cli/features/execution_context/execution_context_constants.js';
|
|
6
|
+
import { renderOnce } from '../../../ui/ui_utils.js';
|
|
7
|
+
import { MissingCredentialsError } from '../../../cli/commands/auth/ui/missing_credentials_error.js';
|
|
8
|
+
import React from 'react';
|
|
9
|
+
import { THEME_DELETE_API_NAME } from '../../features/theme/delete/theme_delete_constants.js';
|
|
10
|
+
import { UnpermittedCommandError } from '../ui/unpermitted_command_error.js';
|
|
11
|
+
import { Error } from '../../../ui/message_box/error.js';
|
|
12
|
+
import { Text } from '../../../ui/text.js';
|
|
13
|
+
import { promptInput } from '../../../ui/prompts/prompt_input.js';
|
|
14
|
+
import { Warning } from '../../../ui/message_box/warning.js';
|
|
15
|
+
import { Info } from '../../../ui/message_box/info.js';
|
|
16
|
+
export class ThemeDeleteCommand extends BaseThemeCommand {
|
|
17
|
+
static summary = 'Permanently deletes the specified theme from your store.';
|
|
18
|
+
static description = 'This action cannot be undone, so make sure you really want to remove this theme.\n\nYou can run this command from a specific theme directory (ID not needed) or outside any theme directory (theme ID required).';
|
|
19
|
+
static examples = [
|
|
20
|
+
{
|
|
21
|
+
description: 'This will delete the theme with ID 123 permanently from your store. Make sure you have a backup if needed.',
|
|
22
|
+
command: '<%= config.bin %> <%= command.id %> 123'
|
|
23
|
+
}
|
|
24
|
+
];
|
|
25
|
+
static hidden = true;
|
|
26
|
+
static args = {
|
|
27
|
+
id: Args.string({
|
|
28
|
+
description: 'Theme id',
|
|
29
|
+
name: 'id',
|
|
30
|
+
required: false,
|
|
31
|
+
type: 'string'
|
|
32
|
+
})
|
|
33
|
+
};
|
|
34
|
+
async run() {
|
|
35
|
+
const data = await this.parse(ThemeDeleteCommand);
|
|
36
|
+
const { args } = data;
|
|
37
|
+
const themeId = args.id;
|
|
38
|
+
const cliAuthApi = this.getApi(CLI_AUTH_API_NAME);
|
|
39
|
+
const executionContextApi = this.getApi(EXECUTION_CONTEXT_API_NAME);
|
|
40
|
+
const credentials = cliAuthApi.getCredentials();
|
|
41
|
+
if (!credentials) {
|
|
42
|
+
renderOnce(React.createElement(MissingCredentialsError, null));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
//
|
|
46
|
+
// if (!themeId) {
|
|
47
|
+
// renderOnce(<MissingThemeIdError />);
|
|
48
|
+
//
|
|
49
|
+
// return;
|
|
50
|
+
// }
|
|
51
|
+
// const executionContext = await executionContextApi.getExecutionContext();
|
|
52
|
+
//
|
|
53
|
+
// if (executionContext.type === EXECUTION_CONTEXTS.theme) {
|
|
54
|
+
// renderOnce(<ThemeDirectoryContextError />);
|
|
55
|
+
//
|
|
56
|
+
// return;
|
|
57
|
+
// }
|
|
58
|
+
renderOnce(React.createElement(Warning, { header: `Warning: This will permanently delete the theme {Theme_name} (ID: {theme_ID}) and cannot be undone.` }));
|
|
59
|
+
const { input: procced } = await promptInput('Proceed?');
|
|
60
|
+
if (!procced) {
|
|
61
|
+
renderOnce(React.createElement(Info, { header: "Theme deletion was cancelled." }));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (!themeId)
|
|
65
|
+
return;
|
|
66
|
+
const themeActionsApi = this.getApi(THEME_ACTIONS_API_NAME);
|
|
67
|
+
const deleteAction = themeActionsApi.getThemeAction({
|
|
68
|
+
actionType: THEME_ACTIONS_TYPES.delete,
|
|
69
|
+
themeId,
|
|
70
|
+
credentials
|
|
71
|
+
});
|
|
72
|
+
if (!deleteAction) {
|
|
73
|
+
renderOnce(React.createElement(UnpermittedCommandError, { themeId: themeId, commandName: "delete" }));
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const themeDeleteApi = this.getApi(THEME_DELETE_API_NAME);
|
|
77
|
+
try {
|
|
78
|
+
await themeDeleteApi.deleteTheme({
|
|
79
|
+
actionData: deleteAction.data,
|
|
80
|
+
credentials
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
this._handleError(err, themeId);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
_handleError(err, themeId) {
|
|
89
|
+
if (err?.code === THEME_ACTION_NOT_FOUND_ERROR_CODE && themeId) {
|
|
90
|
+
renderOnce(React.createElement(UnpermittedCommandError, { themeId: themeId, commandName: "init" }));
|
|
91
|
+
}
|
|
92
|
+
if (err?.message) {
|
|
93
|
+
renderOnce(React.createElement(Error, null,
|
|
94
|
+
React.createElement(Text, null, err.message)));
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
this.error(String(err));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -78,6 +78,7 @@ export class ThemeInitCommand extends BaseThemeCommand {
|
|
|
78
78
|
_handleError(err, themeId) {
|
|
79
79
|
if (err?.code === THEME_ACTION_NOT_FOUND_ERROR_CODE && themeId) {
|
|
80
80
|
renderOnce(React.createElement(UnpermittedCommandError, { themeId: themeId, commandName: "init" }));
|
|
81
|
+
return;
|
|
81
82
|
}
|
|
82
83
|
if (err?.message) {
|
|
83
84
|
renderOnce(React.createElement(Error, null,
|
|
@@ -20,7 +20,6 @@ import { THEME_FILES_STRUCTURE_FILE_NAME } from '../../features/theme/theme_cons
|
|
|
20
20
|
import { THEME_MERGE_API_NAME } from '../../features/theme/merge/theme_merge_constants.js';
|
|
21
21
|
import { ThemePushSkipInfo } from './ui/theme_push_skip_into.js';
|
|
22
22
|
import { ThemeUnpermittedActionsError } from './ui/theme_unpermitted_actions_error.js';
|
|
23
|
-
import { ThemeValidationErrors } from './ui/theme_validation_errors.js';
|
|
24
23
|
import { Error } from '../../../ui/message_box/error.js';
|
|
25
24
|
import { Text } from '../../../ui/text.js';
|
|
26
25
|
import { ThemeWorkUrlMismatch } from '../ui/theme_work_url_mismatch.js';
|
|
@@ -111,7 +110,7 @@ export class ThemePushCommand extends BaseThemeCommand {
|
|
|
111
110
|
return;
|
|
112
111
|
}
|
|
113
112
|
if (err?.code === THEME_ARCHIVE_UPLOAD_ERROR) {
|
|
114
|
-
renderOnce(
|
|
113
|
+
// renderOnce(<ThemeValidationErrors errors={err?.details} />);
|
|
115
114
|
return;
|
|
116
115
|
}
|
|
117
116
|
if (err?.code === THEME_WORK_URL_MISMATCH_ERROR) {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { FeatureApi } from '@dreamcommerce/star_core';
|
|
2
|
+
import { THEME_DELETE_API_NAME } from '../theme_delete_constants.js';
|
|
3
|
+
export class ThemeDeleteApi extends FeatureApi {
|
|
4
|
+
moduleName = THEME_DELETE_API_NAME;
|
|
5
|
+
#service;
|
|
6
|
+
constructor(service) {
|
|
7
|
+
super();
|
|
8
|
+
this.#service = service;
|
|
9
|
+
}
|
|
10
|
+
async deleteTheme(props) {
|
|
11
|
+
return this.#service.deleteTheme(props);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export class ThemeDeleteHttpApi {
|
|
2
|
+
#httpApi;
|
|
3
|
+
constructor(httpApi) {
|
|
4
|
+
this.#httpApi = httpApi;
|
|
5
|
+
}
|
|
6
|
+
deleteTheme({ shopUrl, actionData }) {
|
|
7
|
+
const { method, url } = actionData;
|
|
8
|
+
return this.#httpApi.fetch({
|
|
9
|
+
url: `${shopUrl}${url}`,
|
|
10
|
+
method,
|
|
11
|
+
sanitizeOptions: {
|
|
12
|
+
disable: true
|
|
13
|
+
},
|
|
14
|
+
isPrivate: true
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { STATUS_CODES } from '@dreamcommerce/star_core';
|
|
2
|
+
import { HttpErrorsFactory } from '../../../../../cli/class/errors/http/http_errors_factory.js';
|
|
3
|
+
import { DownloadFileErrorsFactory } from '../../../../../utils/download_file/download_file_errors_factory.js';
|
|
4
|
+
export class ThemeDeleteService {
|
|
5
|
+
#httpApi;
|
|
6
|
+
constructor(httpApi) {
|
|
7
|
+
this.#httpApi = httpApi;
|
|
8
|
+
}
|
|
9
|
+
async deleteTheme({ actionData, credentials }) {
|
|
10
|
+
try {
|
|
11
|
+
const { response } = this.#httpApi.deleteTheme({ actionData, shopUrl: credentials.shopUrl });
|
|
12
|
+
const { data, status } = await response;
|
|
13
|
+
if (status !== STATUS_CODES.ok)
|
|
14
|
+
return;
|
|
15
|
+
//TODO if is success remove theme directory
|
|
16
|
+
return data;
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
//TODO to basic class
|
|
20
|
+
switch (err.response?.status) {
|
|
21
|
+
case 403:
|
|
22
|
+
throw HttpErrorsFactory.createForbiddenError();
|
|
23
|
+
case 401:
|
|
24
|
+
throw HttpErrorsFactory.createUnauthorizedError();
|
|
25
|
+
case 404:
|
|
26
|
+
throw HttpErrorsFactory.createNotFoundError();
|
|
27
|
+
default:
|
|
28
|
+
if (err.response?.status !== 200) {
|
|
29
|
+
throw DownloadFileErrorsFactory.downloadError(err.response.status);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { FEATURE_CORES_TYPES, HTTP_REQUESTER_API_NAME, SyncFeatureInitializer } from '@dreamcommerce/star_core';
|
|
2
|
+
import { ThemeDeleteApi } from './api/theme_delete_api.js';
|
|
3
|
+
import { ThemeDeleteService } from './service/theme_delete_service.js';
|
|
4
|
+
import { ThemeDeleteHttpApi } from './http/theme_delete_http_api.js';
|
|
5
|
+
import { THEME_DELETE_FEATURE_NAME } from './theme_delete_constants.js';
|
|
6
|
+
export class ThemeDeleteInitializer extends SyncFeatureInitializer {
|
|
7
|
+
static featureName = THEME_DELETE_FEATURE_NAME;
|
|
8
|
+
init() {
|
|
9
|
+
const httpApi = this.getApiSync(HTTP_REQUESTER_API_NAME);
|
|
10
|
+
const service = new ThemeDeleteService(new ThemeDeleteHttpApi(httpApi));
|
|
11
|
+
return {
|
|
12
|
+
cores: [
|
|
13
|
+
{
|
|
14
|
+
type: FEATURE_CORES_TYPES.api,
|
|
15
|
+
instance: new ThemeDeleteApi(service)
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import FSTree from 'fs-tree-diff';
|
|
2
2
|
import { join } from '../../../../../utils/path_utils.js';
|
|
3
3
|
import { computeFileChecksum } from '../../../../../utils/checksums/checksums_utils.js';
|
|
4
|
-
import {
|
|
4
|
+
import { copyFileSync, fileExists, getAllDirectoriesNamesInside } from '../../../../../utils/fs/fs_utils.js';
|
|
5
5
|
import { ThemeChecksumsUtils } from '../../utils/checksums/theme_checksums_utils.js';
|
|
6
6
|
import walkSync from 'walk-sync';
|
|
7
7
|
import { SHOPER_THEME_METADATA_DIR } from '../../../../constants/directory_contstants.js';
|
|
@@ -9,7 +9,7 @@ export class ThemeMergeService {
|
|
|
9
9
|
async applyChanges(fromTheme, toTheme, changes) {
|
|
10
10
|
FSTree.applyPatch(fromTheme, toTheme, changes, {
|
|
11
11
|
create(inputPath, outputPath) {
|
|
12
|
-
|
|
12
|
+
copyFileSync(inputPath, outputPath);
|
|
13
13
|
},
|
|
14
14
|
change(inputPath, outputPath) {
|
|
15
15
|
copyFileSync(inputPath, outputPath);
|
|
@@ -183,7 +183,7 @@ export class ThemePushService {
|
|
|
183
183
|
return;
|
|
184
184
|
const toUnixStyleFilesList = Object.entries(filesList).reduce((acc, [filePath, value]) => {
|
|
185
185
|
const unixPath = toUnixPath(filePath);
|
|
186
|
-
const finalPath = looksLikeDirectory(unixPath) ?
|
|
186
|
+
const finalPath = looksLikeDirectory(unixPath) ? `${unixPath}${path.posix.sep}` : unixPath;
|
|
187
187
|
return {
|
|
188
188
|
...acc,
|
|
189
189
|
[finalPath]: value
|
|
@@ -25,7 +25,6 @@ export class ThemeChecksumsUtils {
|
|
|
25
25
|
}
|
|
26
26
|
static async createThemeChecksumsFiles(themeDir, checksums) {
|
|
27
27
|
return new Promise((resolve, reject) => {
|
|
28
|
-
// const sortedChecksums = _.pick(checksums, Object.keys(checksums).sort());
|
|
29
28
|
const currentChecksumFilePath = this.getCurrentThemeChecksumsFilePath(themeDir);
|
|
30
29
|
const initialChecksumFilePath = this.getInitialThemeChecksumsFilePath(themeDir);
|
|
31
30
|
const checksumStream = createWriteStream(initialChecksumFilePath);
|
|
@@ -48,7 +47,6 @@ export class ThemeChecksumsUtils {
|
|
|
48
47
|
}
|
|
49
48
|
static async createThemeCurrentChecksumsFile(themeDir, checksums) {
|
|
50
49
|
return new Promise((resolve, reject) => {
|
|
51
|
-
// const sortedChecksums = _.pick(checksums, Object.keys(checksums).sort());
|
|
52
50
|
const currentChecksumFilePath = this.getCurrentThemeChecksumsFilePath(themeDir);
|
|
53
51
|
const checksumStream = createWriteStream(currentChecksumFilePath);
|
|
54
52
|
checksumStream.write(JSON.stringify(checksums, null, JSON_FILE_INDENT));
|
package/build/theme/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { ThemePushCommand } from './commands/push/theme_push_command.js';
|
|
|
6
6
|
import { ThemeShowChangesCommand } from './commands/theme_show_changes_command.js';
|
|
7
7
|
import { ThemeVerifyCommand } from './commands/theme_verify_command.js';
|
|
8
8
|
import { ThemeInfoCommand } from './commands/info/theme_info_command.js';
|
|
9
|
+
import { ThemeDeleteCommand } from './commands/delete/theme_delete_command.js';
|
|
9
10
|
export const COMMANDS = {
|
|
10
11
|
[THEME_COMMANDS_NAME.list]: ThemeListCommand,
|
|
11
12
|
[THEME_COMMANDS_NAME.pull]: ThemePullCommand,
|
|
@@ -13,5 +14,6 @@ export const COMMANDS = {
|
|
|
13
14
|
[THEME_COMMANDS_NAME.push]: ThemePushCommand,
|
|
14
15
|
[THEME_COMMANDS_NAME.showChanges]: ThemeShowChangesCommand,
|
|
15
16
|
[THEME_COMMANDS_NAME.verify]: ThemeVerifyCommand,
|
|
16
|
-
[THEME_COMMANDS_NAME.info]: ThemeInfoCommand
|
|
17
|
+
[THEME_COMMANDS_NAME.info]: ThemeInfoCommand,
|
|
18
|
+
[THEME_COMMANDS_NAME.delete]: ThemeDeleteCommand
|
|
17
19
|
};
|
|
@@ -41,6 +41,6 @@ export const downloadFile = async ({ dist, request }) => {
|
|
|
41
41
|
throw DownloadFileErrorsFactory.downloadError(err.response.status);
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
+
throw DownloadFileErrorsFactory.downloadError('Unknown error');
|
|
44
45
|
}
|
|
45
|
-
throw DownloadFileErrorsFactory.downloadError('Unknown error');
|
|
46
46
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Error } from '../../../../ui/message_box/error.js';
|
|
3
|
-
import { Text } from '../../../../ui/text.js';
|
|
4
|
-
export const ThemeValidationError = ({ messages, name }) => {
|
|
5
|
-
return (React.createElement(Error, { header: name }, messages.map((message, index) => (React.createElement(Text, { key: index }, message)))));
|
|
6
|
-
};
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { ThemeValidationError } from './theme_validation_error.js';
|
|
3
|
-
export const ThemeValidationErrors = ({ errors }) => {
|
|
4
|
-
return (React.createElement(React.Fragment, null, Object.entries(errors).map(([name, messages]) => (React.createElement(ThemeValidationError, { key: name, name: name, messages: messages })))));
|
|
5
|
-
};
|