@kontent-ai/migration-toolkit 1.3.0 → 1.5.0

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.
Files changed (88) hide show
  1. package/README.md +79 -67
  2. package/dist/es2022/core/helpers/workflow-helper.d.ts +1 -0
  3. package/dist/es2022/core/helpers/workflow-helper.js +6 -4
  4. package/dist/es2022/core/helpers/workflow-helper.js.map +1 -1
  5. package/dist/es2022/core/logs/loggers.js +13 -22
  6. package/dist/es2022/core/logs/loggers.js.map +1 -1
  7. package/dist/es2022/core/models/core.models.d.ts +16 -6
  8. package/dist/es2022/core/models/migration.models.d.ts +9 -9
  9. package/dist/es2022/core/models/migration.schema.d.ts +247 -0
  10. package/dist/es2022/core/models/migration.schema.js +12 -2
  11. package/dist/es2022/core/models/migration.schema.js.map +1 -1
  12. package/dist/es2022/core/utils/array.utils.js.map +1 -1
  13. package/dist/es2022/core/utils/binary-data.utils.js +2 -6
  14. package/dist/es2022/core/utils/binary-data.utils.js.map +1 -1
  15. package/dist/es2022/core/utils/confirm.utils.js +10 -14
  16. package/dist/es2022/core/utils/confirm.utils.js.map +1 -1
  17. package/dist/es2022/core/utils/error.utils.js +35 -27
  18. package/dist/es2022/core/utils/error.utils.js.map +1 -1
  19. package/dist/es2022/core/utils/http.utils.js +7 -11
  20. package/dist/es2022/core/utils/http.utils.js.map +1 -1
  21. package/dist/es2022/core/utils/management-client-utils.d.ts +2 -1
  22. package/dist/es2022/core/utils/management-client-utils.js +12 -2
  23. package/dist/es2022/core/utils/management-client-utils.js.map +1 -1
  24. package/dist/es2022/core/utils/run.utils.js +12 -10
  25. package/dist/es2022/core/utils/run.utils.js.map +1 -1
  26. package/dist/es2022/export/context/export-context-fetcher.js +2 -1
  27. package/dist/es2022/export/context/export-context-fetcher.js.map +1 -1
  28. package/dist/es2022/export/export-manager.js +8 -0
  29. package/dist/es2022/export/export-manager.js.map +1 -1
  30. package/dist/es2022/export/export.models.d.ts +2 -1
  31. package/dist/es2022/import/comparers/asset-comparer.d.ts +2 -1
  32. package/dist/es2022/import/comparers/asset-comparer.js +9 -17
  33. package/dist/es2022/import/comparers/asset-comparer.js.map +1 -1
  34. package/dist/es2022/import/context/import-context-fetcher.js +120 -40
  35. package/dist/es2022/import/context/import-context-fetcher.js.map +1 -1
  36. package/dist/es2022/import/import.models.d.ts +2 -1
  37. package/dist/es2022/import/importers/assets-importer.js +12 -2
  38. package/dist/es2022/import/importers/assets-importer.js.map +1 -1
  39. package/dist/es2022/import/importers/language-variant-importer.js +95 -83
  40. package/dist/es2022/import/importers/language-variant-importer.js.map +1 -1
  41. package/dist/es2022/import/importers/workflow-importer.d.ts +41 -4
  42. package/dist/es2022/import/importers/workflow-importer.js +158 -17
  43. package/dist/es2022/import/importers/workflow-importer.js.map +1 -1
  44. package/dist/es2022/metadata.js +2 -2
  45. package/dist/es2022/node/cli/app.js +8 -12
  46. package/dist/es2022/node/cli/app.js.map +1 -1
  47. package/dist/es2022/node/cli/args/args-fetcher.js +9 -10
  48. package/dist/es2022/node/cli/args/args-fetcher.js.map +1 -1
  49. package/dist/es2022/toolkit/migrate.d.ts +1 -3
  50. package/dist/es2022/toolkit/migrate.js.map +1 -1
  51. package/dist/es2022/translation/extraction/items-extraction.processor.js +17 -17
  52. package/dist/es2022/translation/extraction/items-extraction.processor.js.map +1 -1
  53. package/dist/es2022/translation/transforms/export-transforms.js +1 -1
  54. package/dist/es2022/translation/transforms/export-transforms.js.map +1 -1
  55. package/dist/es2022/zip/zip-packager.js +13 -18
  56. package/dist/es2022/zip/zip-packager.js.map +1 -1
  57. package/dist/es2022/zip/zip-transformer.js +3 -1
  58. package/dist/es2022/zip/zip-transformer.js.map +1 -1
  59. package/lib/core/helpers/workflow-helper.ts +8 -8
  60. package/lib/core/logs/loggers.ts +14 -22
  61. package/lib/core/models/core.models.ts +23 -4
  62. package/lib/core/models/migration.models.ts +13 -12
  63. package/lib/core/models/migration.schema.ts +189 -178
  64. package/lib/core/utils/array.utils.ts +2 -10
  65. package/lib/core/utils/binary-data.utils.ts +2 -7
  66. package/lib/core/utils/confirm.utils.ts +18 -24
  67. package/lib/core/utils/error.utils.ts +50 -30
  68. package/lib/core/utils/http.utils.ts +14 -15
  69. package/lib/core/utils/management-client-utils.ts +188 -182
  70. package/lib/core/utils/run.utils.ts +27 -18
  71. package/lib/export/context/export-context-fetcher.ts +2 -1
  72. package/lib/export/export-manager.ts +14 -3
  73. package/lib/export/export.models.ts +3 -1
  74. package/lib/import/comparers/asset-comparer.ts +16 -24
  75. package/lib/import/context/import-context-fetcher.ts +179 -85
  76. package/lib/import/import.models.ts +2 -0
  77. package/lib/import/importers/assets-importer.ts +19 -12
  78. package/lib/import/importers/language-variant-importer.ts +125 -129
  79. package/lib/import/importers/workflow-importer.ts +228 -20
  80. package/lib/metadata.ts +2 -2
  81. package/lib/node/cli/app.ts +11 -12
  82. package/lib/node/cli/args/args-fetcher.ts +12 -14
  83. package/lib/toolkit/migrate.ts +1 -3
  84. package/lib/translation/extraction/items-extraction.processor.ts +93 -93
  85. package/lib/translation/transforms/export-transforms.ts +1 -1
  86. package/lib/zip/zip-packager.ts +26 -28
  87. package/lib/zip/zip-transformer.ts +3 -1
  88. package/package.json +14 -13
@@ -2,27 +2,30 @@ import { AssetModels, ContentItemModels, LanguageVariantModels } from '@kontent-
2
2
  import {
3
3
  AssetStateInTargetEnvironmentByCodename,
4
4
  ItemStateInTargetEnvironmentByCodename,
5
+ LanguageVariantSchedulesStateValues,
6
+ LanguageVariantStateData,
5
7
  LanguageVariantStateInTargetEnvironmentByCodename,
8
+ LanguageVariantWorkflowState,
9
+ LanguageVariantWorkflowStateValues,
10
+ LogSpinnerData,
6
11
  MigrationItem,
12
+ WorkflowStep,
7
13
  findRequired,
8
14
  is404Error,
9
15
  isNotUndefined,
10
16
  managementClientUtils,
11
17
  processItemsAsync,
12
18
  runMapiRequestAsync,
13
- workflowHelper
19
+ workflowHelper as workflowHelperInit
14
20
  } from '../../core/index.js';
15
- import {
16
- GetFlattenedElementByCodenames,
17
- ImportContext,
18
- ImportContextConfig,
19
- ImportContextEnvironmentData
20
- } from '../import.models.js';
21
+ import { GetFlattenedElementByCodenames, ImportContext, ImportContextConfig, ImportContextEnvironmentData } from '../import.models.js';
21
22
  import { ExtractItemByCodename, itemsExtractionProcessor } from '../../translation/index.js';
22
23
  import chalk from 'chalk';
24
+ import { match } from 'ts-pattern';
23
25
 
24
26
  interface LanguageVariantWrapper {
25
- readonly languageVariant: Readonly<LanguageVariantModels.ContentItemLanguageVariant>;
27
+ readonly draftLanguageVariant: Readonly<LanguageVariantModels.ContentItemLanguageVariant> | undefined;
28
+ readonly publishedLanguageVariant: Readonly<LanguageVariantModels.ContentItemLanguageVariant> | undefined;
26
29
  readonly migrationItem: MigrationItem;
27
30
  }
28
31
 
@@ -37,7 +40,8 @@ export async function importContextFetcherAsync(config: ImportContextConfig) {
37
40
  collections: await mapiUtils.getAllCollectionsAsync(spinnerData),
38
41
  languages: await mapiUtils.getAllLanguagesAsync(spinnerData),
39
42
  workflows: await mapiUtils.getAllWorkflowsAsync(spinnerData),
40
- types: await mapiUtils.getFlattenedContentTypesAsync(spinnerData)
43
+ types: await mapiUtils.getFlattenedContentTypesAsync(spinnerData),
44
+ assetFolders: await mapiUtils.getAllAssetFoldersAsync(spinnerData)
41
45
  };
42
46
 
43
47
  spinnerData({ type: 'info', message: `Environmental data loaded` });
@@ -47,13 +51,10 @@ export async function importContextFetcherAsync(config: ImportContextConfig) {
47
51
  };
48
52
 
49
53
  const environmentData = await getEnvironmentDataAsync();
54
+ const workflowHelper = workflowHelperInit(environmentData.workflows);
50
55
 
51
56
  const getElement = () => {
52
- const getFlattenedElement: GetFlattenedElementByCodenames = (
53
- contentTypeCodename,
54
- elementCodename,
55
- sourceType
56
- ) => {
57
+ const getFlattenedElement: GetFlattenedElementByCodenames = (contentTypeCodename, elementCodename, sourceType) => {
57
58
  const contentType = findRequired(
58
59
  environmentData.types,
59
60
  (type) => type.contentTypeCodename === contentTypeCodename,
@@ -65,9 +66,7 @@ export async function importContextFetcherAsync(config: ImportContextConfig) {
65
66
  (element) => element.codename === elementCodename,
66
67
  `Element type with codename '${chalk.red(elementCodename)}' was not found in content type '${chalk.red(
67
68
  contentTypeCodename
68
- )}'. Available elements are '${contentType.elements
69
- .map((element) => chalk.yellow(element.codename))
70
- .join(', ')}'`
69
+ )}'. Available elements are '${contentType.elements.map((element) => chalk.yellow(element.codename)).join(', ')}'`
71
70
  );
72
71
 
73
72
  if (sourceType !== element.type) {
@@ -84,7 +83,70 @@ export async function importContextFetcherAsync(config: ImportContextConfig) {
84
83
  return getFlattenedElement;
85
84
  };
86
85
 
87
- const getLanguageVariantsAsync = async (
86
+ const getLatestLanguageVariantAsync = async (
87
+ logSpinner: LogSpinnerData,
88
+ migrationItem: MigrationItem
89
+ ): Promise<Readonly<LanguageVariantModels.ContentItemLanguageVariant> | undefined> => {
90
+ try {
91
+ const latestLanguageVariant = await runMapiRequestAsync({
92
+ logger: config.logger,
93
+ func: async () =>
94
+ (
95
+ await config.managementClient
96
+ .viewLanguageVariant()
97
+ .byItemCodename(migrationItem.system.codename)
98
+ .byLanguageCodename(migrationItem.system.language.codename)
99
+ .toPromise()
100
+ ).data,
101
+ action: 'view',
102
+ type: 'languageVariant',
103
+ logSpinner: logSpinner,
104
+ itemName: `latest -> codename -> ${migrationItem.system.codename} (${migrationItem.system.language.codename})`
105
+ });
106
+
107
+ return latestLanguageVariant;
108
+ } catch (error) {
109
+ if (!is404Error(error)) {
110
+ throw error;
111
+ }
112
+
113
+ return undefined;
114
+ }
115
+ };
116
+
117
+ const getPublishedLanguageVariantAsync = async (
118
+ logSpinner: LogSpinnerData,
119
+ migrationItem: MigrationItem
120
+ ): Promise<Readonly<LanguageVariantModels.ContentItemLanguageVariant> | undefined> => {
121
+ try {
122
+ const draftLanguageVariant = await runMapiRequestAsync({
123
+ logger: config.logger,
124
+ func: async () =>
125
+ (
126
+ await config.managementClient
127
+ .viewLanguageVariant()
128
+ .byItemCodename(migrationItem.system.codename)
129
+ .byLanguageCodename(migrationItem.system.language.codename)
130
+ .published()
131
+ .toPromise()
132
+ ).data,
133
+ action: 'view',
134
+ type: 'languageVariant',
135
+ logSpinner: logSpinner,
136
+ itemName: `published -> codename -> ${migrationItem.system.codename} (${migrationItem.system.language.codename})`
137
+ });
138
+
139
+ return draftLanguageVariant;
140
+ } catch (error) {
141
+ if (!is404Error(error)) {
142
+ throw error;
143
+ }
144
+
145
+ return undefined;
146
+ }
147
+ };
148
+
149
+ const getLanguageVariantWrappersAsync = async (
88
150
  migrationItems: readonly MigrationItem[]
89
151
  ): Promise<readonly LanguageVariantWrapper[]> => {
90
152
  return (
@@ -100,34 +162,28 @@ export async function importContextFetcherAsync(config: ImportContextConfig) {
100
162
  };
101
163
  },
102
164
  processAsync: async (item, logSpinner) => {
103
- try {
104
- const languageVariant = await runMapiRequestAsync({
105
- logger: config.logger,
106
- func: async () =>
107
- (
108
- await config.managementClient
109
- .viewLanguageVariant()
110
- .byItemCodename(item.system.codename)
111
- .byLanguageCodename(item.system.language.codename)
112
- .toPromise()
113
- ).data,
114
- action: 'view',
115
- type: 'languageVariant',
116
- logSpinner: logSpinner,
117
- itemName: `codename -> ${item.system.codename} (${item.system.language.codename})`
118
- });
165
+ const latestLanguageVariant = await getLatestLanguageVariantAsync(logSpinner, item);
119
166
 
167
+ if (!latestLanguageVariant) {
168
+ // there is neither published or draft version as latest version does not exist at all
169
+ return undefined;
170
+ }
171
+
172
+ if (workflowHelper.isPublishedStepById(latestLanguageVariant.workflow.stepIdentifier.id ?? '')) {
173
+ // if latest version is published, it means that there is no draft, but there is published version
120
174
  return {
121
- languageVariant: languageVariant,
122
- migrationItem: item
175
+ migrationItem: item,
176
+ draftLanguageVariant: undefined,
177
+ publishedLanguageVariant: latestLanguageVariant
123
178
  };
124
- } catch (error) {
125
- if (!is404Error(error)) {
126
- throw error;
127
- }
128
-
129
- return undefined;
130
179
  }
180
+
181
+ // if latest version is a draft version, check if there is published version as well
182
+ return {
183
+ migrationItem: item,
184
+ draftLanguageVariant: latestLanguageVariant,
185
+ publishedLanguageVariant: await getPublishedLanguageVariantAsync(logSpinner, item)
186
+ };
131
187
  }
132
188
  })
133
189
  ).filter(isNotUndefined);
@@ -152,10 +208,7 @@ export async function importContextFetcherAsync(config: ImportContextConfig) {
152
208
  try {
153
209
  return await runMapiRequestAsync({
154
210
  logger: config.logger,
155
- func: async () =>
156
- (
157
- await config.managementClient.viewContentItem().byItemCodename(codename).toPromise()
158
- ).data,
211
+ func: async () => (await config.managementClient.viewContentItem().byItemCodename(codename).toPromise()).data,
159
212
  action: 'view',
160
213
  type: 'contentItem',
161
214
  logSpinner: logSpinner,
@@ -173,9 +226,7 @@ export async function importContextFetcherAsync(config: ImportContextConfig) {
173
226
  ).filter(isNotUndefined);
174
227
  };
175
228
 
176
- const getAssetsByCodenamesAsync = async (
177
- assetCodenames: ReadonlySet<string>
178
- ): Promise<readonly AssetModels.Asset[]> => {
229
+ const getAssetsByCodenamesAsync = async (assetCodenames: ReadonlySet<string>): Promise<readonly AssetModels.Asset[]> => {
179
230
  return (
180
231
  await processItemsAsync<string, Readonly<AssetModels.Asset> | undefined>({
181
232
  action: 'Fetching assets',
@@ -192,10 +243,7 @@ export async function importContextFetcherAsync(config: ImportContextConfig) {
192
243
  try {
193
244
  return await runMapiRequestAsync({
194
245
  logger: config.logger,
195
- func: async () =>
196
- (
197
- await config.managementClient.viewAsset().byAssetCodename(codename).toPromise()
198
- ).data,
246
+ func: async () => (await config.managementClient.viewAsset().byAssetCodename(codename).toPromise()).data,
199
247
  action: 'view',
200
248
  type: 'asset',
201
249
  logSpinner: logSpinner,
@@ -213,44 +261,98 @@ export async function importContextFetcherAsync(config: ImportContextConfig) {
213
261
  ).filter(isNotUndefined);
214
262
  };
215
263
 
264
+ const getVariantState = (languageVariant: Readonly<LanguageVariantModels.ContentItemLanguageVariant>): LanguageVariantStateData => {
265
+ const variantWorkflowId = languageVariant.workflow.workflowIdentifier.id;
266
+ const variantStepId = languageVariant.workflow.stepIdentifier.id;
267
+ const { workflow, step } = workflowHelper.getWorkflowAndStep({
268
+ workflowMatcher: {
269
+ errorMessage: `Could not workflow with id '${chalk.red(variantWorkflowId)}' in target project`,
270
+ match: (workflow) => workflow.id == variantWorkflowId
271
+ },
272
+ stepMatcher: {
273
+ errorMessage: `Could not workflow step with id '${chalk.red(variantStepId)}' in workflow '${chalk.yellow(
274
+ variantWorkflowId
275
+ )}'`,
276
+ match: (step) => step.id == variantStepId
277
+ }
278
+ });
279
+
280
+ return {
281
+ languageVariant: languageVariant,
282
+ workflow: workflow,
283
+ workflowState: getWorkflowState(step, languageVariant)
284
+ };
285
+ };
286
+
216
287
  const getVariantStatesAsync = async (
217
288
  migrationItems: readonly MigrationItem[]
218
289
  ): Promise<readonly LanguageVariantStateInTargetEnvironmentByCodename[]> => {
219
- const variants = await getLanguageVariantsAsync(migrationItems);
290
+ const variantWrappers = await getLanguageVariantWrappersAsync(migrationItems);
220
291
 
221
292
  return migrationItems.map<LanguageVariantStateInTargetEnvironmentByCodename>((migrationItem) => {
222
- const variant = variants.find(
293
+ const variantWrapper = variantWrappers.find(
223
294
  (m) =>
224
295
  m.migrationItem.system.codename === migrationItem.system.codename &&
225
296
  m.migrationItem.system.language === migrationItem.system.language
226
297
  );
227
298
 
228
- const variantWorkflowId = variant?.languageVariant?.workflow?.workflowIdentifier?.id;
229
- const variantStepId = variant?.languageVariant?.workflow?.stepIdentifier?.id;
230
-
231
- const workflow = environmentData.workflows.find((workflow) => workflow.id === variantWorkflowId);
232
-
233
299
  return {
234
300
  itemCodename: migrationItem.system.codename,
235
301
  languageCodename: migrationItem.system.language.codename,
236
- languageVariant: variant?.languageVariant,
237
- workflow: workflow,
238
- step: workflow
239
- ? workflowHelper(environmentData.workflows).getWorkflowStep(workflow, {
240
- errorMessage: `Could not workflow step with id '${chalk.red(
241
- variantStepId
242
- )}' in workflow '${chalk.yellow(workflow.codename)}'`,
243
- match: (step) => step.id == variantStepId
244
- })
302
+ draftLanguageVariant: variantWrapper?.draftLanguageVariant
303
+ ? getVariantState(variantWrapper.draftLanguageVariant)
245
304
  : undefined,
246
- state: variant ? 'exists' : 'doesNotExists'
305
+ publishedLanguageVariant: variantWrapper?.publishedLanguageVariant
306
+ ? getVariantState(variantWrapper.publishedLanguageVariant)
307
+ : undefined,
308
+ state: variantWrapper ? 'exists' : 'doesNotExists'
247
309
  };
248
310
  });
249
311
  };
250
312
 
251
- const getItemStatesAsync = async (
252
- itemCodenames: ReadonlySet<string>
253
- ): Promise<readonly ItemStateInTargetEnvironmentByCodename[]> => {
313
+ const getWorkflowState = (
314
+ step: Readonly<WorkflowStep>,
315
+ variant: Readonly<LanguageVariantModels.ContentItemLanguageVariant> | undefined
316
+ ): LanguageVariantWorkflowState => {
317
+ if (!variant) {
318
+ return undefined;
319
+ }
320
+
321
+ const getScheduledState = (): LanguageVariantSchedulesStateValues => {
322
+ return match(variant.schedule)
323
+ .returnType<LanguageVariantSchedulesStateValues>()
324
+ .when(
325
+ (schedule) => schedule.publishTime && schedule.publishDisplayTimezone,
326
+ () => 'scheduledPublish'
327
+ )
328
+ .when(
329
+ (schedule) => schedule.unpublishTime && schedule.unpublishDisplayTimezone,
330
+ () => 'scheduledUnpublish'
331
+ )
332
+ .otherwise(() => 'n/a');
333
+ };
334
+
335
+ const getWorkflowState = (): LanguageVariantWorkflowStateValues => {
336
+ return match(step.codename)
337
+ .returnType<LanguageVariantWorkflowStateValues>()
338
+ .when(
339
+ (stepCodename) => workflowHelper.isPublishedStepByCodename(stepCodename),
340
+ () => 'published'
341
+ )
342
+ .when(
343
+ (stepCodename) => workflowHelper.isArchivedStepByCodename(stepCodename),
344
+ () => 'archived'
345
+ )
346
+ .otherwise(() => 'draft');
347
+ };
348
+
349
+ return {
350
+ workflowState: getWorkflowState(),
351
+ scheduledState: getScheduledState()
352
+ };
353
+ };
354
+
355
+ const getItemStatesAsync = async (itemCodenames: ReadonlySet<string>): Promise<readonly ItemStateInTargetEnvironmentByCodename[]> => {
254
356
  const items = await getContentItemsByCodenamesAsync(itemCodenames);
255
357
 
256
358
  return Array.from(itemCodenames).map<ItemStateInTargetEnvironmentByCodename>((codename) => {
@@ -311,17 +413,13 @@ export async function importContextFetcherAsync(config: ImportContextConfig) {
311
413
  ]);
312
414
 
313
415
  // prepare state of objects in target environment
314
- const itemStates: readonly ItemStateInTargetEnvironmentByCodename[] = await getItemStatesAsync(
315
- itemCodenamesToCheckInTargetEnv
316
- );
416
+ const itemStates: readonly ItemStateInTargetEnvironmentByCodename[] = await getItemStatesAsync(itemCodenamesToCheckInTargetEnv);
317
417
 
318
418
  const variantStates: readonly LanguageVariantStateInTargetEnvironmentByCodename[] = await getVariantStatesAsync(
319
419
  config.migrationData.items
320
420
  );
321
421
 
322
- const assetStates: readonly AssetStateInTargetEnvironmentByCodename[] = await getAssetStatesAsync(
323
- assetCodenamesToCheckInTargetEnv
324
- );
422
+ const assetStates: readonly AssetStateInTargetEnvironmentByCodename[] = await getAssetStatesAsync(assetCodenamesToCheckInTargetEnv);
325
423
 
326
424
  return {
327
425
  environmentData,
@@ -334,9 +432,7 @@ export async function importContextFetcherAsync(config: ImportContextConfig) {
334
432
  return findRequired(
335
433
  itemStates,
336
434
  (state) => state.itemCodename === itemCodename,
337
- `Invalid state for item '${chalk.red(
338
- itemCodename
339
- )}'. It is expected that all item states will be initialized`
435
+ `Invalid state for item '${chalk.red(itemCodename)}'. It is expected that all item states will be initialized`
340
436
  );
341
437
  },
342
438
  getLanguageVariantStateInTargetEnvironment: (itemCodename, languageCodename) => {
@@ -352,9 +448,7 @@ export async function importContextFetcherAsync(config: ImportContextConfig) {
352
448
  return findRequired(
353
449
  assetStates,
354
450
  (state) => state.assetCodename === assetCodename,
355
- `Invalid state for asset '${chalk.red(
356
- assetCodename
357
- )}'. It is expected that all asset states will be initialized`
451
+ `Invalid state for asset '${chalk.red(assetCodename)}'. It is expected that all asset states will be initialized`
358
452
  );
359
453
  },
360
454
  getElement: getElementByCodenames
@@ -15,6 +15,7 @@ import {
15
15
  FlattenedContentType
16
16
  } from '../core/index.js';
17
17
  import {
18
+ AssetFolderModels,
18
19
  AssetModels,
19
20
  CollectionModels,
20
21
  ContentItemModels,
@@ -34,6 +35,7 @@ export interface ImportContextConfig {
34
35
 
35
36
  export interface ImportContextEnvironmentData {
36
37
  readonly languages: readonly Readonly<LanguageModels.LanguageModel>[];
38
+ readonly assetFolders: readonly Readonly<AssetFolderModels.AssetFolder>[];
37
39
  readonly collections: readonly Readonly<CollectionModels.Collection>[];
38
40
  readonly workflows: readonly Readonly<WorkflowModels.Workflow>[];
39
41
  readonly types: readonly Readonly<FlattenedContentType>[];
@@ -1,4 +1,4 @@
1
- import { AssetModels, ManagementClient } from '@kontent-ai/management-sdk';
1
+ import { AssetModels, ManagementClient, SharedContracts } from '@kontent-ai/management-sdk';
2
2
  import {
3
3
  MigrationAsset,
4
4
  Logger,
@@ -45,6 +45,7 @@ export function assetsImporter(data: {
45
45
  !shouldUpdateAsset({
46
46
  collections: data.importContext.environmentData.collections,
47
47
  languages: data.importContext.environmentData.languages,
48
+ assetFolders: data.importContext.environmentData.assetFolders,
48
49
  migrationAsset: migrationAsset,
49
50
  targetAsset: assetState.asset
50
51
  })
@@ -64,9 +65,7 @@ export function assetsImporter(data: {
64
65
  .filter(isNotUndefined);
65
66
  };
66
67
 
67
- const editAssets = async (
68
- assetsToEdit: readonly AssetToEdit[]
69
- ): Promise<readonly Readonly<AssetModels.Asset>[]> => {
68
+ const editAssets = async (assetsToEdit: readonly AssetToEdit[]): Promise<readonly Readonly<AssetModels.Asset>[]> => {
70
69
  data.logger.log({
71
70
  type: 'upsert',
72
71
  message: `Upserting '${chalk.yellow(assetsToEdit.length.toString())}' assets`
@@ -100,11 +99,10 @@ export function assetsImporter(data: {
100
99
  .withData(() => {
101
100
  return {
102
101
  title: assetEditRequest.migrationAsset.title,
103
- descriptions: mapAssetDescriptions(
104
- assetEditRequest.migrationAsset.descriptions
105
- ),
102
+ descriptions: mapAssetDescriptions(assetEditRequest.migrationAsset.descriptions),
106
103
  collection: mapAssetCollection(assetEditRequest.migrationAsset.collection),
107
- file_reference: uploadedBinaryFile ?? undefined
104
+ file_reference: uploadedBinaryFile ?? undefined,
105
+ folder: mapAssetFolder(assetEditRequest.migrationAsset.folder)
108
106
  };
109
107
  })
110
108
  .toPromise()
@@ -131,6 +129,16 @@ export function assetsImporter(data: {
131
129
  : undefined;
132
130
  };
133
131
 
132
+ const mapAssetFolder = (
133
+ migrationFolder: MigrationReference | undefined
134
+ ): Readonly<SharedContracts.IReferenceObjectContract> | undefined => {
135
+ return migrationFolder
136
+ ? {
137
+ codename: migrationFolder.codename
138
+ }
139
+ : undefined;
140
+ };
141
+
134
142
  const mapAssetDescriptions = (
135
143
  migrationDescription: readonly MigrationAssetDescription[] | undefined
136
144
  ): Readonly<AssetModels.IAssetFileDescription>[] => {
@@ -172,9 +180,7 @@ export function assetsImporter(data: {
172
180
  });
173
181
  };
174
182
 
175
- const uploadAssetsAsync = async (
176
- assetsToUpload: readonly MigrationAsset[]
177
- ): Promise<readonly Readonly<AssetModels.Asset>[]> => {
183
+ const uploadAssetsAsync = async (assetsToUpload: readonly MigrationAsset[]): Promise<readonly Readonly<AssetModels.Asset>[]> => {
178
184
  data.logger.log({
179
185
  type: 'upload',
180
186
  message: `Uploading '${chalk.yellow(assetsToUpload.length.toString())}' assets`
@@ -211,7 +217,8 @@ export function assetsImporter(data: {
211
217
  title: migrationAsset.title,
212
218
  external_id: assetStateInTargetEnv.externalIdToUse,
213
219
  collection: mapAssetCollection(migrationAsset.collection),
214
- descriptions: mapAssetDescriptions(migrationAsset.descriptions)
220
+ descriptions: mapAssetDescriptions(migrationAsset.descriptions),
221
+ folder: mapAssetFolder(migrationAsset.folder)
215
222
  };
216
223
  return assetRequestData;
217
224
  })