@shoper/cli 0.1.0-25 → 0.1.0-26

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.
@@ -0,0 +1,7 @@
1
+ import { Error } from '../../ui/message_box/error.js';
2
+ import { Text } from '../../ui/text.js';
3
+ import React from 'react';
4
+ export const ErrorItem = ({ error, title }) => {
5
+ return (React.createElement(Error, { header: title },
6
+ React.createElement(Text, null, error)));
7
+ };
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import { ErrorItem } from './error_item.js';
3
+ import { Error } from '../../ui/message_box/error.js';
4
+ import { Text } from '../../ui/text.js';
5
+ import { Box } from '../../ui/box.js';
6
+ export const ErrorsList = ({ errors }) => {
7
+ if (typeof errors === 'string') {
8
+ return React.createElement(ErrorItem, { error: errors });
9
+ }
10
+ if (Array.isArray(errors)) {
11
+ return errors.map((error, index) => (React.createElement(ErrorItem, { key: index, error: error })));
12
+ }
13
+ return (React.createElement(React.Fragment, null, Object.entries(errors).map(([title, errorMessages], index) => (React.createElement(Error, { key: index, header: title },
14
+ React.createElement(Box, { flexDirection: "column" }, errorMessages.map((message, index) => (React.createElement(Text, { key: index }, message)))))))));
15
+ };
@@ -12,9 +12,9 @@ import { UnpermittedCommandError } from '../ui/unpermitted_command_error.js';
12
12
  import { MissingCredentialsError } from '../../../cli/commands/auth/ui/missing_credentials_error.js';
13
13
  import { ThemeCreatedSuccess } from './ui/theme_created_success.js';
14
14
  import { Text } from '../../../ui/text.js';
15
- import { Error } from '../../../ui/message_box/error.js';
16
15
  import { MissingThemeIdError } from '../ui/missing_theme_id_error.js';
17
16
  import { Box } from '../../../ui/box.js';
17
+ import { ErrorsList } from '../../../cli/ui/errors_list.js';
18
18
  export class ThemeInitCommand extends BaseThemeCommand {
19
19
  static summary = 'Creates a copy of an existing theme by duplicating it.';
20
20
  static description = 'The new theme will be named after the source theme with a "Copy" suffix and an incremental number.\n\nYou must run this command from the root directory (not inside any theme folder) and provide the ID of the theme you want to duplicate.';
@@ -73,6 +73,8 @@ export class ThemeInitCommand extends BaseThemeCommand {
73
73
  catch (err) {
74
74
  spinner?.stop();
75
75
  this._handleError(err, themeId);
76
+ //TODO analyze why on nodejs v22 this command does not exit properly, even all promises are resolved
77
+ this.exit();
76
78
  }
77
79
  }
78
80
  _handleError(err, themeId) {
@@ -81,8 +83,7 @@ export class ThemeInitCommand extends BaseThemeCommand {
81
83
  return;
82
84
  }
83
85
  if (err?.message) {
84
- renderOnce(React.createElement(Error, null,
85
- React.createElement(Text, null, err.message)));
86
+ renderOnce(React.createElement(ErrorsList, { errors: err.message }));
86
87
  return;
87
88
  }
88
89
  this.error(String(err));
@@ -2,7 +2,7 @@ import { BaseThemeCommand } from '../../class/base_theme_command.js';
2
2
  import { CLI_AUTH_API_NAME } from '../../../cli/auth/cli_auth_constants.js';
3
3
  import { EXECUTION_CONTEXT_API_NAME, EXECUTION_CONTEXTS } from '../../../cli/features/execution_context/execution_context_constants.js';
4
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 { THEME_ARCHIVE_UPLOAD_ERROR, THEME_PUSH_API_NAME } from '../../features/theme/push/theme_push_constants.js';
5
+ import { THEME_ARCHIVE_UPLOAD_ERROR, THEME_FILES_UPLOAD_ERROR, THEME_PUSH_API_NAME } from '../../features/theme/push/theme_push_constants.js';
6
6
  import { ThemeMetaDataUtils } from '../../features/theme/utils/meta_data/theme_meta_data_utils.js';
7
7
  import { mapChecksumToTree } from '../../../utils/checksums/checksums_utils.js';
8
8
  import { mapToPermissionsTree } from '../../utils/directory_validator/directory_validator_utils.js';
@@ -26,6 +26,7 @@ import { ThemeWorkUrlMismatch } from '../ui/theme_work_url_mismatch.js';
26
26
  import { THEME_WORK_URL_MISMATCH_ERROR } from '../../features/theme/utils/meta_data/theme_meta_data_constants.js';
27
27
  import { ThemeFilesStructureUtils } from '../../features/theme/utils/files_structure/theme_files_structure_utils.js';
28
28
  import { ThemeInfoUtils } from '../../features/theme/info/theme_info_utils.js';
29
+ import { ErrorsList } from '../../../cli/ui/errors_list.js';
29
30
  export class ThemePushCommand extends BaseThemeCommand {
30
31
  static summary = 'Uploads your local theme files to the store and overwrites the current version of the theme in your store.';
31
32
  static description = 'Check your local changes before pushing.\n\nYou must run this command from a specific theme directory (ID not needed).';
@@ -110,16 +111,20 @@ export class ThemePushCommand extends BaseThemeCommand {
110
111
  return;
111
112
  }
112
113
  if (err?.code === THEME_ARCHIVE_UPLOAD_ERROR) {
113
- // renderOnce(<ThemeValidationErrors errors={err?.details} />);
114
+ renderOnce(React.createElement(ErrorsList, { errors: err?.details }));
114
115
  return;
115
116
  }
116
117
  if (err?.code === THEME_WORK_URL_MISMATCH_ERROR) {
117
118
  this._renderUrlMismatchError();
118
119
  return;
119
120
  }
121
+ if (err?.code === THEME_FILES_UPLOAD_ERROR) {
122
+ return renderOnce(React.createElement(Error, { header: "Uploading theme files to the shop failed.\n" },
123
+ React.createElement(Text, null, "The rejected files have been removed locally. Please ensure that the files are not corrupted and that the file extensions are supported.")));
124
+ }
120
125
  if (err?.message) {
121
- renderOnce(React.createElement(Error, null,
122
- React.createElement(Text, null, err.message)));
126
+ console.log('error message', err.message);
127
+ renderOnce(React.createElement(ErrorsList, { errors: err.message }));
123
128
  return;
124
129
  }
125
130
  this.error(String(err));
@@ -105,18 +105,24 @@ export class ThemePushService {
105
105
  }
106
106
  async _uploadThemeFiles({ filesToUpload, themeRootDir, localFiles, credentials }) {
107
107
  try {
108
- const uploadedImageData = await this._uploadFiles(filesToUpload, credentials);
108
+ const { uploadedImageData, rejectedImageData } = await this._uploadFiles(filesToUpload, credentials);
109
109
  const newFilesList = ThemeImagesUtils.updateOriginalFilenameToUploadedFilename(localFiles, uploadedImageData);
110
110
  if (uploadedImageData.length)
111
111
  await ThemeImagesUtils.removeUploadedOriginalFiles(themeRootDir, uploadedImageData);
112
+ if (rejectedImageData.length)
113
+ await this._removeUploadedThemeFiles(rejectedImageData, themeRootDir);
112
114
  await this._createAFilesListFile(themeRootDir, newFilesList);
113
115
  }
114
116
  catch (err) {
115
117
  throw ThemePushErrorsFactory.createErrorWhileUploadingThemeFiles(credentials.shopUrl, err);
116
118
  }
117
119
  }
120
+ async _removeUploadedThemeFiles(uploadedImageData, themeRootDir) {
121
+ await Promise.all(uploadedImageData.map(({ location, originalFilename }) => removeFile(join(themeRootDir, location, originalFilename))));
122
+ }
118
123
  async _uploadFiles(uploadData, credentials) {
119
124
  const uploadedImageData = [];
125
+ const rejectedImageData = [];
120
126
  await Promise.all(uploadData.map(({ actionData, path }) => this.#themePushHttpApi
121
127
  .pushThemeData({
122
128
  actionData,
@@ -124,15 +130,22 @@ export class ThemePushService {
124
130
  shopUrl: credentials.shopUrl
125
131
  })
126
132
  .response.then((response) => {
127
- if (response.status !== 200 || !response.data.isSuccess)
128
- throw ThemePushErrorsFactory.createErrorWhileUploadingThemeFiles(credentials.shopUrl, response.data?.messages ?? []);
129
133
  uploadedImageData.push({
130
134
  location: dirname(path),
131
135
  originalFilename: basename(path),
132
136
  uploadedFilename: response.data.imageId
133
137
  });
138
+ })
139
+ .catch(() => {
140
+ rejectedImageData.push({
141
+ location: dirname(path),
142
+ originalFilename: basename(path)
143
+ });
134
144
  })));
135
- return uploadedImageData;
145
+ return {
146
+ uploadedImageData,
147
+ rejectedImageData
148
+ };
136
149
  }
137
150
  async _getActionDataForFilesToUpload({ pushAction, filesStructure, executionContext }) {
138
151
  const uploadData = [];
@@ -3,3 +3,4 @@ export const THEME_PUSH_API_NAME = 'ThemePushApi';
3
3
  export const THEME_FILES_LIST_FILE_NAME = 'filesList.json';
4
4
  export const THEME_MODULE_SETTINGS_FILE_NAME = 'settings.json';
5
5
  export const THEME_ARCHIVE_UPLOAD_ERROR = 'theme.push.error_uploading_theme_archive';
6
+ export const THEME_FILES_UPLOAD_ERROR = 'theme.push.error_uploading_theme_files';
@@ -1,12 +1,14 @@
1
1
  import { AppError } from '../../../../cli/class/errors/app/app_error.js';
2
- import { THEME_ARCHIVE_UPLOAD_ERROR } from './theme_push_constants.js';
2
+ import { THEME_ARCHIVE_UPLOAD_ERROR, THEME_FILES_UPLOAD_ERROR } from './theme_push_constants.js';
3
3
  export class ThemePushErrorsFactory {
4
4
  static createErrorWhileUploadingThemeFiles(shopUrl, messages) {
5
5
  return new AppError({
6
- code: 'theme.push.error_uploading_theme_files',
6
+ code: THEME_FILES_UPLOAD_ERROR,
7
7
  message: `Error while uploading theme files to shop "${shopUrl}"`,
8
8
  level: 'error',
9
- details: messages
9
+ details: {
10
+ messages
11
+ }
10
12
  });
11
13
  }
12
14
  static createErrorWhileCreatingThemeArchive(shopUrl, error) {
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@shoper/cli",
3
3
  "packageManager": "yarn@3.2.0",
4
4
  "sideEffects": false,
5
- "version": "0.1.0-25",
5
+ "version": "0.1.0-26",
6
6
  "description": "CLI tool for Shoper",
7
7
  "author": "Joanna Firek",
8
8
  "license": "MIT",