@shoper/cli 0.1.0-26 → 0.1.0-28

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,19 @@
1
+ import { Text } from '../../../ui/text.js';
2
+ import { List } from '../../../ui/list/list.js';
3
+ import { ValidationErrorsUtils } from './validation_errors_utils.js';
4
+ import React from 'react';
5
+ export const ValidationErrorContent = ({ errors }) => {
6
+ if (typeof errors === 'string') {
7
+ return React.createElement(Text, null, errors);
8
+ }
9
+ if (Array.isArray(errors)) {
10
+ return (React.createElement(List, { items: errors.map((error) => ({
11
+ content: error
12
+ })) }));
13
+ }
14
+ return (React.createElement(List, { items: Object.entries(errors).map(([title, errorMessages]) => {
15
+ return {
16
+ content: `${title} - ${ValidationErrorsUtils.getErrorContent(errorMessages)}`
17
+ };
18
+ }) }));
19
+ };
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import { Error } from '../../../ui/message_box/error.js';
3
+ import { Text } from '../../../ui/text.js';
4
+ import { List } from '../../../ui/list/list.js';
5
+ import { ValidationErrorContent } from './validation_error_content.js';
6
+ export const ValidationErrors = ({ errors }) => {
7
+ if (typeof errors === 'string') {
8
+ return (React.createElement(Error, null,
9
+ React.createElement(Text, null, errors)));
10
+ }
11
+ if (Array.isArray(errors)) {
12
+ return (React.createElement(Error, null,
13
+ React.createElement(List, { items: errors.map((error) => ({
14
+ content: error
15
+ })) })));
16
+ }
17
+ return (React.createElement(React.Fragment, null, Object.entries(errors).map(([title, errorMessages], index) => {
18
+ return (React.createElement(Error, { key: index, header: title },
19
+ React.createElement(ValidationErrorContent, { errors: errorMessages })));
20
+ })));
21
+ };
@@ -0,0 +1,17 @@
1
+ export class ValidationErrorsUtils {
2
+ static getErrorContent(errors) {
3
+ if (typeof errors === 'string') {
4
+ return errors;
5
+ }
6
+ if (Array.isArray(errors)) {
7
+ return errors.join(', ');
8
+ }
9
+ if (errors?.errors && Array.isArray(errors?.errors)) {
10
+ return errors.errors.join(', ');
11
+ }
12
+ if (typeof errors === 'object') {
13
+ return Object.values(errors).join(', ');
14
+ }
15
+ throw new Error('Not supported validation errors', errors);
16
+ }
17
+ }
package/build/index.js CHANGED
@@ -47,7 +47,3 @@ export const COMMANDS = {
47
47
  ...THEME_COMMANDS
48
48
  };
49
49
  export { runCLI } from './cli/index.js';
50
- /**
51
- * TODO:
52
- * Windows - zwłąszcza w kejsie z git grzie push i pull jest na dwóch platformach
53
- */
@@ -2,7 +2,7 @@ import { Args } from '@oclif/core';
2
2
  import { BaseThemeCommand } from '../../class/base_theme_command.js';
3
3
  import { CLI_AUTH_API_NAME } from '../../../cli/auth/cli_auth_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 { EXECUTION_CONTEXT_API_NAME } from '../../../cli/features/execution_context/execution_context_constants.js';
5
+ import { EXECUTION_CONTEXT_API_NAME, EXECUTION_CONTEXTS } from '../../../cli/features/execution_context/execution_context_constants.js';
6
6
  import { renderOnce } from '../../../ui/ui_utils.js';
7
7
  import { MissingCredentialsError } from '../../../cli/commands/auth/ui/missing_credentials_error.js';
8
8
  import React from 'react';
@@ -10,9 +10,12 @@ import { THEME_DELETE_API_NAME } from '../../features/theme/delete/theme_delete_
10
10
  import { UnpermittedCommandError } from '../ui/unpermitted_command_error.js';
11
11
  import { Error } from '../../../ui/message_box/error.js';
12
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
13
  import { Info } from '../../../ui/message_box/info.js';
14
+ import { MissingThemeIdError } from '../ui/missing_theme_id_error.js';
15
+ import { Box } from '../../../ui/box.js';
16
+ import { ThemeDeletedSuccessfully } from './ui/theme_deleted_successfully.js';
17
+ import { ThemeDeletionWarning } from './ui/theme_deletion_warning.js';
18
+ import { promptConfirmation } from '../../../ui/prompts/prompt_confirmation.js';
16
19
  export class ThemeDeleteCommand extends BaseThemeCommand {
17
20
  static summary = 'Permanently deletes the specified theme from your store.';
18
21
  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).';
@@ -42,43 +45,51 @@ export class ThemeDeleteCommand extends BaseThemeCommand {
42
45
  renderOnce(React.createElement(MissingCredentialsError, null));
43
46
  return;
44
47
  }
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);
48
+ const executionContext = await executionContextApi.getExecutionContext();
77
49
  try {
78
- await themeDeleteApi.deleteTheme({
50
+ let _themeId = themeId;
51
+ if (executionContext.type !== EXECUTION_CONTEXTS.theme && !_themeId) {
52
+ renderOnce(React.createElement(MissingThemeIdError, null,
53
+ React.createElement(Box, { flexDirection: "column", gap: 1 },
54
+ React.createElement(Text, null, "Usage: shoper theme delete [ID]"),
55
+ React.createElement(Text, null, "Please run this command inside a theme directory or provide a theme ID."))));
56
+ return;
57
+ }
58
+ if (executionContext.type === EXECUTION_CONTEXTS.theme)
59
+ _themeId = _themeId ?? executionContext.themeId;
60
+ if (!_themeId) {
61
+ renderOnce(React.createElement(MissingThemeIdError, null));
62
+ return;
63
+ }
64
+ const themeActionsApi = this.getApi(THEME_ACTIONS_API_NAME);
65
+ const deleteAction = themeActionsApi.getThemeAction({
66
+ actionType: THEME_ACTIONS_TYPES.delete,
67
+ themeId: _themeId,
68
+ credentials
69
+ });
70
+ if (!deleteAction) {
71
+ renderOnce(React.createElement(UnpermittedCommandError, { themeId: _themeId, commandName: "delete" }));
72
+ return;
73
+ }
74
+ renderOnce(React.createElement(ThemeDeletionWarning, { themeId: _themeId }));
75
+ const { proceed } = await promptConfirmation('Proceed?');
76
+ if (!proceed) {
77
+ renderOnce(React.createElement(Info, { header: "Theme deletion was cancelled." }));
78
+ return;
79
+ }
80
+ const themeDeleteApi = this.getApi(THEME_DELETE_API_NAME);
81
+ const { isSuccess } = await themeDeleteApi.deleteTheme({
79
82
  actionData: deleteAction.data,
80
83
  credentials
81
84
  });
85
+ themeActionsApi.removeThemeActions({
86
+ themeId: _themeId,
87
+ credentials
88
+ });
89
+ if (!isSuccess)
90
+ return;
91
+ renderOnce(React.createElement(ThemeDeletedSuccessfully, null));
92
+ return;
82
93
  }
83
94
  catch (err) {
84
95
  this._handleError(err, themeId);
@@ -87,7 +98,8 @@ export class ThemeDeleteCommand extends BaseThemeCommand {
87
98
  }
88
99
  _handleError(err, themeId) {
89
100
  if (err?.code === THEME_ACTION_NOT_FOUND_ERROR_CODE && themeId) {
90
- renderOnce(React.createElement(UnpermittedCommandError, { themeId: themeId, commandName: "init" }));
101
+ renderOnce(React.createElement(UnpermittedCommandError, { themeId: themeId, commandName: "delete" }));
102
+ return;
91
103
  }
92
104
  if (err?.message) {
93
105
  renderOnce(React.createElement(Error, null,
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import { Text } from '../../../../ui/text.js';
3
+ import { List } from '../../../../ui/list/list.js';
4
+ import { Tip } from '../../../../ui/tip.js';
5
+ import { Success } from '../../../../ui/message_box/success.js';
6
+ export const ThemeDeletedSuccessfully = () => {
7
+ return (React.createElement(Success, { header: "Success: Theme was deleted from the store." },
8
+ React.createElement(Text, null, "The theme is no longer available in your store panel, but its files remain locally."),
9
+ React.createElement(Tip, null, "If you want to reuse this theme:"),
10
+ React.createElement(List, { items: [
11
+ 'create a new theme using shoper theme init [id]',
12
+ 'copy the local files into the new theme folder',
13
+ 'and push it using shoper theme push'
14
+ ] })));
15
+ };
@@ -0,0 +1,10 @@
1
+ import { Warning } from '../../../../ui/message_box/warning.js';
2
+ import { Text } from '../../../../ui/text.js';
3
+ import React from 'react';
4
+ export const ThemeDeletionWarning = ({ themeId }) => {
5
+ return (React.createElement(Warning, { header: `Warning: This will permanently delete the theme (ID: ${themeId}) from your store and cannot be undone.` },
6
+ React.createElement(Text, null,
7
+ "Your local files ",
8
+ React.createElement(Text, { bold: true }, "will not be removed"),
9
+ ". You\u2019ll still be able to access and modify them.")));
10
+ };
@@ -45,30 +45,27 @@ export class ThemeInfoCommand extends BaseThemeCommand {
45
45
  return;
46
46
  }
47
47
  const executionContext = await executionContextApi.getExecutionContext();
48
- let theme;
49
- let _themeId = themeId;
50
48
  try {
49
+ let _themeId = themeId;
50
+ if (executionContext.type !== EXECUTION_CONTEXTS.theme && !_themeId) {
51
+ renderOnce(React.createElement(MissingThemeIdError, null,
52
+ React.createElement(Box, { flexDirection: "column", gap: 1 },
53
+ React.createElement(Text, null, "Usage: shoper theme info [ID]"),
54
+ React.createElement(Text, null, "Please run this command inside a theme directory or provide a theme ID."))));
55
+ return;
56
+ }
51
57
  if (executionContext.type === EXECUTION_CONTEXTS.theme) {
52
58
  await ThemeMetaDataUtils.ensureThemeWorkUrlMatch(executionContext.themeRootDir, credentials.shopUrl);
53
59
  _themeId = themeId ?? executionContext.themeId;
54
- theme = await themesListApi.getTheme({
55
- themeId: _themeId,
56
- shopUrl: credentials.shopUrl
57
- });
58
60
  }
59
- if (executionContext.type !== EXECUTION_CONTEXTS.theme) {
60
- if (_themeId === undefined) {
61
- renderOnce(React.createElement(MissingThemeIdError, null,
62
- React.createElement(Box, { flexDirection: "column", gap: 1 },
63
- React.createElement(Text, null, "Usage: shoper theme info [ID]"),
64
- React.createElement(Text, null, "Please run this command inside a theme directory or provide a theme ID."))));
65
- return;
66
- }
67
- theme = await themesListApi.getTheme({
68
- themeId: _themeId,
69
- shopUrl: credentials.shopUrl
70
- });
61
+ if (!_themeId) {
62
+ renderOnce(React.createElement(MissingThemeIdError, null));
63
+ return;
71
64
  }
65
+ const theme = await themesListApi.getTheme({
66
+ themeId: _themeId,
67
+ shopUrl: credentials.shopUrl
68
+ });
72
69
  if (!theme) {
73
70
  renderOnce(_themeId ? React.createElement(InvalidThemeIdError, { themeId: _themeId }) : React.createElement(Error, { header: "Error: Theme information is not available." }));
74
71
  return;
@@ -30,7 +30,7 @@ export class ThemeInfoCommandUtils {
30
30
  [
31
31
  React.createElement(Text, null,
32
32
  React.createElement(Text, { bold: true }, "Status: "),
33
- ": $",
33
+ ": ",
34
34
  theme.isActive ? 'Active' : 'Inactive')
35
35
  ]
36
36
  ]
@@ -14,7 +14,7 @@ import { ThemeCreatedSuccess } from './ui/theme_created_success.js';
14
14
  import { Text } from '../../../ui/text.js';
15
15
  import { MissingThemeIdError } from '../ui/missing_theme_id_error.js';
16
16
  import { Box } from '../../../ui/box.js';
17
- import { ErrorsList } from '../../../cli/ui/errors_list.js';
17
+ import { ValidationErrors } from '../../../cli/ui/validation_errors/validation_errors.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.';
@@ -83,7 +83,7 @@ export class ThemeInitCommand extends BaseThemeCommand {
83
83
  return;
84
84
  }
85
85
  if (err?.message) {
86
- renderOnce(React.createElement(ErrorsList, { errors: err.message }));
86
+ renderOnce(React.createElement(ValidationErrors, { errors: err.message }));
87
87
  return;
88
88
  }
89
89
  this.error(String(err));
@@ -94,7 +94,6 @@ export class ThemePullCommand extends BaseThemeCommand {
94
94
  }
95
95
  catch (err) {
96
96
  this.#spinner?.stop();
97
- console.log('err', err);
98
97
  this._handleError(err, _themeId);
99
98
  }
100
99
  }
@@ -145,7 +144,7 @@ export class ThemePullCommand extends BaseThemeCommand {
145
144
  renderOnce(React.createElement(ThemePulledSuccess, null));
146
145
  }
147
146
  async _pullThemeIntoExistingOne({ themeId, themeFetchApi, themeActionsApi, fetchType, executionContext, credentials }) {
148
- //TODO move these logis somvewhere else?
147
+ //TODO move these logi somvewhere else?
149
148
  await ThemeMetaDataUtils.ensureThemeWorkUrlMatch(executionContext.themeRootDir, credentials.shopUrl);
150
149
  const pullAction = themeActionsApi.getThemeAction({
151
150
  actionType: THEME_ACTIONS_TYPES.pull,
@@ -26,7 +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
+ import { ValidationErrors } from '../../../cli/ui/validation_errors/validation_errors.js';
30
30
  export class ThemePushCommand extends BaseThemeCommand {
31
31
  static summary = 'Uploads your local theme files to the store and overwrites the current version of the theme in your store.';
32
32
  static description = 'Check your local changes before pushing.\n\nYou must run this command from a specific theme directory (ID not needed).';
@@ -111,7 +111,7 @@ export class ThemePushCommand extends BaseThemeCommand {
111
111
  return;
112
112
  }
113
113
  if (err?.code === THEME_ARCHIVE_UPLOAD_ERROR) {
114
- renderOnce(React.createElement(ErrorsList, { errors: err?.details }));
114
+ renderOnce(React.createElement(ValidationErrors, { errors: err?.details }));
115
115
  return;
116
116
  }
117
117
  if (err?.code === THEME_WORK_URL_MISMATCH_ERROR) {
@@ -123,8 +123,7 @@ export class ThemePushCommand extends BaseThemeCommand {
123
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
124
  }
125
125
  if (err?.message) {
126
- console.log('error message', err.message);
127
- renderOnce(React.createElement(ErrorsList, { errors: err.message }));
126
+ renderOnce(React.createElement(ValidationErrors, { errors: err.message }));
128
127
  return;
129
128
  }
130
129
  this.error(String(err));
@@ -16,4 +16,7 @@ export class ThemeActionsApi extends FeatureApi {
16
16
  clearThemesActions(props) {
17
17
  return this.#service.clearThemesActions(props);
18
18
  }
19
+ removeThemeActions(props) {
20
+ return this.#service.removeThemeActions(props);
21
+ }
19
22
  }
@@ -25,6 +25,17 @@ export class ThemeActionsService {
25
25
  });
26
26
  return actions[actionType];
27
27
  }
28
+ removeThemeActions({ themeId, credentials }) {
29
+ const storeActions = this.#themesActionsStore.get(this._getKey(credentials.shopUrl));
30
+ if (!storeActions || !storeActions.actions[themeId]) {
31
+ throw new AppError({
32
+ code: THEME_ACTION_NOTS_FOUND_ERROR_CODE,
33
+ message: `Theme actions for store ${credentials.shopUrl} not found.`
34
+ });
35
+ }
36
+ delete storeActions.actions[themeId];
37
+ this.#themesActionsStore.set(this._getKey(credentials.shopUrl), storeActions);
38
+ }
28
39
  async ensureThemesActions({ credentials, themeId }) {
29
40
  if (!themeId)
30
41
  return;
@@ -1,4 +1,3 @@
1
- import { STATUS_CODES } from '@dreamcommerce/star_core';
2
1
  import { HttpErrorsFactory } from '../../../../../cli/class/errors/http/http_errors_factory.js';
3
2
  import { DownloadFileErrorsFactory } from '../../../../../utils/download_file/download_file_errors_factory.js';
4
3
  export class ThemeDeleteService {
@@ -9,10 +8,7 @@ export class ThemeDeleteService {
9
8
  async deleteTheme({ actionData, credentials }) {
10
9
  try {
11
10
  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
11
+ const { data } = await response;
16
12
  return data;
17
13
  }
18
14
  catch (err) {
@@ -25,9 +21,7 @@ export class ThemeDeleteService {
25
21
  case 404:
26
22
  throw HttpErrorsFactory.createNotFoundError();
27
23
  default:
28
- if (err.response?.status !== 200) {
29
- throw DownloadFileErrorsFactory.downloadError(err.response.status);
30
- }
24
+ throw DownloadFileErrorsFactory.downloadError(err.response.status);
31
25
  }
32
26
  }
33
27
  }
@@ -16,10 +16,10 @@ export class ThemeMergeApi extends FeatureApi {
16
16
  applyChanges(fromTheme, toTheme, changes) {
17
17
  return this.#service.applyChanges(fromTheme, toTheme, changes);
18
18
  }
19
- hasFileBeenCreated(path, executionContext) {
20
- return this.#service.hasFileBeenCreated(path, executionContext);
19
+ hasFileBeenCreated(path, themeDir) {
20
+ return this.#service.hasFileBeenCreated(path, themeDir);
21
21
  }
22
- hasFileBeenModified(path, executionContext) {
23
- return this.#service.hasFileBeenModified(path, executionContext);
22
+ hasFileBeenModified(path, themeDir) {
23
+ return this.#service.hasFileBeenModified(path, themeDir);
24
24
  }
25
25
  }
@@ -1,10 +1,9 @@
1
1
  import FSTree from 'fs-tree-diff';
2
- import { join } from '../../../../../utils/path_utils.js';
3
- import { computeFileChecksum } from '../../../../../utils/checksums/checksums_utils.js';
4
2
  import { copyFileSync, fileExists, getAllDirectoriesNamesInside } from '../../../../../utils/fs/fs_utils.js';
5
3
  import { ThemeChecksumsUtils } from '../../utils/checksums/theme_checksums_utils.js';
6
4
  import walkSync from 'walk-sync';
7
5
  import { SHOPER_THEME_METADATA_DIR } from '../../../../constants/directory_contstants.js';
6
+ import { join } from '../../../../../utils/path_utils.js';
8
7
  export class ThemeMergeService {
9
8
  async applyChanges(fromTheme, toTheme, changes) {
10
9
  FSTree.applyPatch(fromTheme, toTheme, changes, {
@@ -46,13 +45,13 @@ export class ThemeMergeService {
46
45
  const currentChecksums = await ThemeChecksumsUtils.getThemeCurrentChecksumsVerification(themeRootDir);
47
46
  return initialChecksums !== currentChecksums;
48
47
  }
49
- async hasFileBeenCreated(path, executionContext) {
50
- const checksums = await ThemeChecksumsUtils.getThemeInitialChecksums(executionContext.themeRootDir);
51
- return checksums[path] === undefined && (await fileExists(join(executionContext.themeRootDir, path)));
48
+ async hasFileBeenCreated(path, themeDir) {
49
+ const initialChecksum = await ThemeChecksumsUtils.getInitialChecksumFromPath(path, themeDir);
50
+ return !initialChecksum && (await fileExists(join(themeDir, path)));
52
51
  }
53
- async hasFileBeenModified(path, executionContext) {
54
- const checksums = await ThemeChecksumsUtils.getThemeInitialChecksums(executionContext.themeRootDir);
55
- const currentChecksum = await computeFileChecksum(join(executionContext.themeRootDir, path));
56
- return !!checksums[path] && checksums[path] !== currentChecksum;
52
+ async hasFileBeenModified(path, themeDir) {
53
+ const currentChecksum = await ThemeChecksumsUtils.getCurrentChecksumFromPath(path, themeDir);
54
+ const initialChecksum = await ThemeChecksumsUtils.getInitialChecksumFromPath(path, themeDir);
55
+ return !!currentChecksum && !!initialChecksum && currentChecksum !== initialChecksum;
57
56
  }
58
57
  }
@@ -2,7 +2,7 @@ import tmp from 'tmp-promise';
2
2
  import { THEME_ACTION_DATA_TYPE, THEME_ACTIONS_TYPES } from '../../actions/theme_actions_constants.js';
3
3
  import { createZip } from '../../../../../utils/zip/create_zip_utils.js';
4
4
  import { basename, dirname, extname, join, looksLikeDirectory, toUnixPath } from '../../../../../utils/path_utils.js';
5
- import { createReadStream } from 'node:fs';
5
+ import fs, { createReadStream } from 'node:fs';
6
6
  import { v4 as uuid } from 'uuid';
7
7
  import globs from 'fast-glob';
8
8
  import { THEME_WILDCARD_ACTION_NAME } from '../../actions/service/theme_actions_service_constants.js';
@@ -27,13 +27,14 @@ export class ThemePushService {
27
27
  }
28
28
  async push({ pushAction, filesStructure, credentials, executionContext }) {
29
29
  const { path: tmpDir } = await tmp.dir({ unsafeCleanup: true });
30
- if (await this.#themeMergeApi.hasFileBeenCreated(ThemePublishUtils.getSkinStoreSettingsFilePath(executionContext.themeRootDir), executionContext))
30
+ if (await this.#themeMergeApi.hasFileBeenCreated(ThemePublishUtils.getSkinStoreSettingsFilePath(executionContext.themeRootDir), executionContext.themeRootDir))
31
31
  throw ThemePushErrorsFactory.createErrorWhilePushingUnpublishedThemeWithSkinstoreData(credentials.shopUrl);
32
32
  const { uploadData, localFiles } = await this._getActionDataForFilesToUpload({
33
33
  pushAction,
34
34
  filesStructure,
35
35
  executionContext
36
36
  });
37
+ console.log('uploadData', uploadData);
37
38
  if (uploadData.length) {
38
39
  await this._uploadThemeFiles({
39
40
  filesToUpload: uploadData,
@@ -123,25 +124,30 @@ export class ThemePushService {
123
124
  async _uploadFiles(uploadData, credentials) {
124
125
  const uploadedImageData = [];
125
126
  const rejectedImageData = [];
126
- await Promise.all(uploadData.map(({ actionData, path }) => this.#themePushHttpApi
127
- .pushThemeData({
128
- actionData,
129
- stream: createReadStream(path),
130
- shopUrl: credentials.shopUrl
131
- })
132
- .response.then((response) => {
133
- uploadedImageData.push({
134
- location: dirname(path),
135
- originalFilename: basename(path),
136
- uploadedFilename: response.data.imageId
137
- });
138
- })
139
- .catch(() => {
140
- rejectedImageData.push({
141
- location: dirname(path),
142
- originalFilename: basename(path)
127
+ console.log('uploadData', uploadData);
128
+ await Promise.all(uploadData.map(({ actionData, path }) => {
129
+ const fstat = fs.lstatSync(path);
130
+ console.log('fstat', fstat);
131
+ return this.#themePushHttpApi
132
+ .pushThemeData({
133
+ actionData,
134
+ stream: createReadStream(path),
135
+ shopUrl: credentials.shopUrl
136
+ })
137
+ .response.then((response) => {
138
+ uploadedImageData.push({
139
+ location: dirname(path),
140
+ originalFilename: basename(path),
141
+ uploadedFilename: response.data.imageId
142
+ });
143
+ })
144
+ .catch(() => {
145
+ rejectedImageData.push({
146
+ location: dirname(path),
147
+ originalFilename: basename(path)
148
+ });
143
149
  });
144
- })));
150
+ }));
145
151
  return {
146
152
  uploadedImageData,
147
153
  rejectedImageData
@@ -169,8 +175,8 @@ export class ThemePushService {
169
175
  localFiles[fileGlob] = files.length ? basename(files[0]) : null;
170
176
  }
171
177
  for (const filePath of files) {
172
- if ((await this.#themeMergeApi.hasFileBeenCreated(filePath, executionContext)) ||
173
- (await this.#themeMergeApi.hasFileBeenModified(filePath, executionContext))) {
178
+ if ((await this.#themeMergeApi.hasFileBeenCreated(filePath, executionContext.themeRootDir)) ||
179
+ (await this.#themeMergeApi.hasFileBeenModified(filePath, executionContext.themeRootDir))) {
174
180
  uploadData.push({
175
181
  actionData,
176
182
  actionKey,
@@ -1,4 +1,4 @@
1
- import { join, mapKeysPathsToWindowPlatform } from '../../../../../utils/path_utils.js';
1
+ import { join, mapKeysPathsToWindowPlatform, toUnixPath, toWinowsPath } from '../../../../../utils/path_utils.js';
2
2
  import { THEME_CURRENT_CHECKSUMS_FILE_NAME, THEME_CURRENT_CHECKSUMS_VERITY_FILE_NAME, THEME_INITIAL_CHECKSUMS_FILE_NAME, THEME_INITIAL_CHECKSUMS_VERITY_FILE_NAME } from '../../theme_constants.js';
3
3
  import { createWriteStream } from 'fs';
4
4
  import { copyFile, readJSONFile, removeFile } from '../../../../../utils/fs/fs_utils.js';
@@ -126,4 +126,12 @@ export class ThemeChecksumsUtils {
126
126
  const directoriesChecksums = computeDirectoriesChecksums(filesChecksumsInDirectories);
127
127
  return { ...filesChecksums, ...directoriesChecksums };
128
128
  }
129
+ static async getCurrentChecksumFromPath(path, themeDir) {
130
+ const checksums = await this.getThemeCurrentChecksums(themeDir);
131
+ return checksums[isWindowsOs() ? toWinowsPath(path) : toUnixPath(path)];
132
+ }
133
+ static async getInitialChecksumFromPath(path, themeDir) {
134
+ const checksums = await this.getThemeInitialChecksums(themeDir);
135
+ return checksums[isWindowsOs() ? toWinowsPath(path) : toUnixPath(path)];
136
+ }
129
137
  }
@@ -3,5 +3,8 @@ import { Box } from '../box.js';
3
3
  import React from 'react';
4
4
  import { ListItem } from './list_item.js';
5
5
  export const List = ({ type = LIST_TYPES.unordered, items }) => {
6
- return (React.createElement(Box, { flexDirection: "column", gap: 1, width: "100%", marginLeft: 2 }, items.map(({ content }, index) => (React.createElement(ListItem, { key: index, index: index, type: type }, content)))));
6
+ return (React.createElement(Box, { flexDirection: "column", gap: 1, width: "100%", marginLeft: 2 }, items.map((item, index) => {
7
+ const itemContent = typeof item === 'string' ? item : item.content;
8
+ return (React.createElement(ListItem, { key: index, index: index, type: type }, itemContent));
9
+ })));
7
10
  };
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-26",
5
+ "version": "0.1.0-28",
6
6
  "description": "CLI tool for Shoper",
7
7
  "author": "Joanna Firek",
8
8
  "license": "MIT",
@@ -1,7 +0,0 @@
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
- };
@@ -1,15 +0,0 @@
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
- };