storyblok 3.13.1 → 3.14.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "storyblok",
3
- "version": "3.13.1",
3
+ "version": "3.14.0",
4
4
  "description": "A simple CLI to start Storyblok from your command line.",
5
5
  "keywords": [
6
6
  "storyblok",
@@ -37,6 +37,7 @@
37
37
  "open": "^6.0.0",
38
38
  "p-series": "^2.1.0",
39
39
  "path": "^0.12.7",
40
+ "simple-uuid": "^0.0.1",
40
41
  "storyblok-js-client": "^4.5.6",
41
42
  "update-notifier": "^5.1.0",
42
43
  "xml-js": "^1.6.11"
@@ -1,5 +1,6 @@
1
1
  const chalk = require('chalk')
2
- const StoryblokClient = require('storyblok-js-client')
2
+ const UUID = require('simple-uuid')
3
+ const api = require('../../utils/api')
3
4
 
4
5
  class SyncDatasources {
5
6
  /**
@@ -11,9 +12,7 @@ class SyncDatasources {
11
12
  this.sourceSpaceId = options.sourceSpaceId
12
13
  this.targetSpaceId = options.targetSpaceId
13
14
  this.oauthToken = options.oauthToken
14
- this.client = new StoryblokClient({
15
- oauthToken: options.oauthToken
16
- })
15
+ this.client = api.getClient()
17
16
  }
18
17
 
19
18
  async sync () {
@@ -41,9 +40,10 @@ class SyncDatasources {
41
40
  await this.updateDatasources()
42
41
  }
43
42
 
44
- async getDatasourceEntries (spaceId, datasourceId) {
43
+ async getDatasourceEntries (spaceId, datasourceId, dimensionId = null) {
44
+ const dimensionQuery = dimensionId ? `&dimension=${dimensionId}` : ''
45
45
  try {
46
- const entriesFirstPage = await this.client.get(`spaces/${spaceId}/datasource_entries/?datasource_id=${datasourceId}`)
46
+ const entriesFirstPage = await this.client.get(`spaces/${spaceId}/datasource_entries/?datasource_id=${datasourceId}${dimensionQuery}`)
47
47
  const entriesRequets = []
48
48
  for (let i = 2; i <= Math.ceil(entriesFirstPage.total / 25); i++) {
49
49
  entriesRequets.push(this.client.get(`spaces/${spaceId}/datasource_entries/?datasource_id=${datasourceId}`, { page: i }))
@@ -88,9 +88,9 @@ class SyncDatasources {
88
88
  }
89
89
  }
90
90
 
91
- async syncDatasourceEntries (sourceId, targetId) {
91
+ async syncDatasourceEntries (datasourceId, targetId) {
92
92
  try {
93
- const sourceEntries = await this.getDatasourceEntries(this.sourceSpaceId, sourceId)
93
+ const sourceEntries = await this.getDatasourceEntries(this.sourceSpaceId, datasourceId)
94
94
  const targetEntries = await this.getDatasourceEntries(this.targetSpaceId, targetId)
95
95
  const updateEntries = targetEntries.filter(e => sourceEntries.map(se => se.name).includes(e.name))
96
96
  const addEntries = sourceEntries.filter(e => !targetEntries.map(te => te.name).includes(e.name))
@@ -126,17 +126,31 @@ class SyncDatasources {
126
126
 
127
127
  for (let i = 0; i < datasourcesToAdd.length; i++) {
128
128
  try {
129
+ console.log(` ${chalk.green('-')} Creating datasource ${datasourcesToAdd[i].name} (${datasourcesToAdd[i].slug})`)
129
130
  /* Create the datasource */
130
131
  const newDatasource = await this.client.post(`spaces/${this.targetSpaceId}/datasources`, {
131
132
  name: datasourcesToAdd[i].name,
132
133
  slug: datasourcesToAdd[i].slug
133
134
  })
134
135
 
135
- await this.syncDatasourceEntries(datasourcesToAdd[i].id, newDatasource.data.datasource.id)
136
- console.log(chalk.green('✓') + ' Created datasource ' + datasourcesToAdd[i].name)
136
+ if (datasourcesToAdd[i].dimensions.length) {
137
+ console.log(
138
+ ` ${chalk.blue('-')} Creating dimensions...`
139
+ )
140
+ const { data } = await this.createDatasourcesDimensions(datasourcesToAdd[i].dimensions, newDatasource.data.datasource)
141
+ await this.syncDatasourceEntries(datasourcesToAdd[i].id, newDatasource.data.datasource.id)
142
+ console.log(
143
+ ` ${chalk.blue('-')} Sync dimensions values...`
144
+ )
145
+ await this.syncDatasourceDimensionsValues(datasourcesToAdd[i], data.datasource)
146
+ console.log(` ${chalk.green('✓')} Created datasource ${datasourcesToAdd[i].name}`)
147
+ } else {
148
+ await this.syncDatasourceEntries(datasourcesToAdd[i].id, newDatasource.data.datasource.id)
149
+ console.log(` ${chalk.green('✓')} Created datasource ${datasourcesToAdd[i].name}`)
150
+ }
137
151
  } catch (err) {
138
152
  console.error(
139
- `${chalk.red('X')} Datasource ${datasourcesToAdd[i].name} creation failed: ${err.message}`
153
+ `${chalk.red('X')} Datasource ${datasourcesToAdd[i].name} creation failed: ${err.response.data.error || err.message}`
140
154
  )
141
155
  }
142
156
  }
@@ -154,13 +168,35 @@ class SyncDatasources {
154
168
  try {
155
169
  /* Update the datasource */
156
170
  const sourceDatasource = this.sourceDatasources.find(d => d.slug === datasourcesToUpdate[i].slug)
171
+
157
172
  await this.client.put(`spaces/${this.targetSpaceId}/datasources/${datasourcesToUpdate[i].id}`, {
158
173
  name: sourceDatasource.name,
159
174
  slug: sourceDatasource.slug
160
175
  })
161
176
 
162
- await this.syncDatasourceEntries(sourceDatasource.id, datasourcesToUpdate[i].id)
163
- console.log(chalk.green('') + ' Updated datasource ' + datasourcesToUpdate[i].name)
177
+ if (datasourcesToUpdate[i].dimensions.length) {
178
+ console.log(` ${chalk.blue('-')} Updating datasources dimensions ${datasourcesToUpdate[i].name}...`)
179
+ const sourceDimensionsNames = sourceDatasource.dimensions.map((dimension) => dimension.name)
180
+ const targetDimensionsNames = datasourcesToUpdate[i].dimensions.map((dimension) => dimension.name)
181
+ const intersection = sourceDimensionsNames.filter(item => !targetDimensionsNames.includes(item))
182
+ let datasourceToSyncDimensionsValues = datasourcesToUpdate[i]
183
+
184
+ if (intersection) {
185
+ const dimensionsToCreate = sourceDatasource.dimensions.filter((dimension) => {
186
+ if (intersection.includes(dimension.name)) return dimension
187
+ })
188
+ const { data } = await this.createDatasourcesDimensions(dimensionsToCreate, datasourcesToUpdate[i], true)
189
+ datasourceToSyncDimensionsValues = data.datasource
190
+ }
191
+
192
+ await this.syncDatasourceEntries(sourceDatasource.id, datasourcesToUpdate[i].id)
193
+
194
+ await this.syncDatasourceDimensionsValues(sourceDatasource, datasourceToSyncDimensionsValues)
195
+ console.log(`${chalk.green('✓')} Updated datasource ${datasourcesToUpdate[i].name}`)
196
+ } else {
197
+ await this.syncDatasourceEntries(sourceDatasource.id, datasourcesToUpdate[i].id)
198
+ console.log(`${chalk.green('✓')} Updated datasource ${datasourcesToUpdate[i].name}`)
199
+ }
164
200
  } catch (err) {
165
201
  console.error(
166
202
  `${chalk.red('X')} Datasource ${datasourcesToUpdate[i].name} update failed: ${err.message}`
@@ -168,6 +204,102 @@ class SyncDatasources {
168
204
  }
169
205
  }
170
206
  }
207
+
208
+ async createDatasourcesDimensions (dimensions, datasource, isToUpdate = false) {
209
+ const newDimensions = dimensions.map((dimension) => {
210
+ return {
211
+ name: dimension.name,
212
+ entry_value: dimension.entry_value,
213
+ datasource_id: datasource.id,
214
+ _uid: UUID()
215
+ }
216
+ })
217
+
218
+ let payload = null
219
+
220
+ if (isToUpdate) {
221
+ payload = {
222
+ dimensions: [...datasource.dimensions, ...newDimensions],
223
+ dimensions_attributes: [...datasource.dimensions, ...newDimensions]
224
+ }
225
+ } else {
226
+ payload = {
227
+ dimensions: newDimensions,
228
+ dimensions_attributes: newDimensions
229
+ }
230
+ }
231
+
232
+ try {
233
+ return await this.client.put(`spaces/${this.targetSpaceId}/datasources/${datasource.id}`, {
234
+ ...datasource,
235
+ ...payload
236
+ })
237
+ } catch (error) {
238
+ console.error(error)
239
+ }
240
+ }
241
+
242
+ async syncDatasourceDimensionsValues (sourceDatasource, targetDatasource) {
243
+ const sourceEntriesPromisses = []
244
+ const targetEmptyEntriesPromisses = []
245
+ try {
246
+ for (let index = 0; index < sourceDatasource.dimensions.length; index++) {
247
+ const targetDimensionId = targetDatasource.dimensions[index].id
248
+ sourceEntriesPromisses.push(...await this.getDatasourceEntries(this.sourceSpaceId, sourceDatasource.id, sourceDatasource.dimensions[index].id))
249
+ targetEmptyEntriesPromisses.push(
250
+ ...await this.getDatasourceEntries(this.targetSpaceId, targetDatasource.id, targetDimensionId).then((res) => {
251
+ return res.map((entry) => {
252
+ return {
253
+ ...entry,
254
+ target_dimension_id: targetDimensionId
255
+ }
256
+ })
257
+ })
258
+ )
259
+ }
260
+
261
+ await Promise.all(sourceEntriesPromisses)
262
+ await Promise.all(targetEmptyEntriesPromisses)
263
+
264
+ const targetEntriesPromisses = []
265
+
266
+ while (sourceEntriesPromisses.length !== 0) {
267
+ const currentSourceEntry = sourceEntriesPromisses[0]
268
+ const targetEntryIndex = targetEmptyEntriesPromisses.findIndex((tEntry) => tEntry.name === currentSourceEntry.name)
269
+ const currentTargetEntry = targetEmptyEntriesPromisses[targetEntryIndex]
270
+ const valuesAreEqual = currentTargetEntry.dimension_value === currentSourceEntry.dimension_value
271
+
272
+ if (valuesAreEqual) {
273
+ sourceEntriesPromisses.shift()
274
+ targetEmptyEntriesPromisses.splice(targetEntryIndex, 1)
275
+ } else {
276
+ const payload = {
277
+ ...currentTargetEntry,
278
+ dimension_value: currentSourceEntry.dimension_value
279
+ }
280
+
281
+ targetEntriesPromisses.push(await this.syncDimensionEntryValues(currentTargetEntry.target_dimension_id, currentTargetEntry.id, payload))
282
+ sourceEntriesPromisses.shift()
283
+ targetEmptyEntriesPromisses.splice(targetEntryIndex, 1)
284
+ }
285
+ }
286
+
287
+ await Promise.all(targetEntriesPromisses)
288
+ } catch (error) {
289
+ console.error(` ${chalk.red('X')} Sync dimensions values failed: ${error.response.data.error || error.message || error}`)
290
+ }
291
+ }
292
+
293
+ async syncDimensionEntryValues (dimensionId = null, datasourceEntryId = null, payload = null) {
294
+ try {
295
+ await this.client.put(`spaces/${this.targetSpaceId}/datasource_entries/${datasourceEntryId}`, {
296
+ datasource_entry: payload,
297
+ dimension_id: dimensionId
298
+ })
299
+ } catch (error) {
300
+ console.error(` ${chalk.red('X')} Sync entry error ${payload.name} sync failed: ${error.response.data.error || error.message}`)
301
+ }
302
+ }
171
303
  }
172
304
 
173
305
  module.exports = SyncDatasources
package/src/tasks/sync.js CHANGED
@@ -43,29 +43,29 @@ const SyncSpaces = {
43
43
 
44
44
  async syncStories () {
45
45
  console.log(chalk.green('✓') + ' Syncing stories...')
46
- var targetFolders = await this.client.getAll(`spaces/${this.targetSpaceId}/stories`, {
46
+ const targetFolders = await this.client.getAll(`spaces/${this.targetSpaceId}/stories`, {
47
47
  folder_only: 1,
48
48
  sort_by: 'slug:asc'
49
49
  })
50
50
 
51
- var folderMapping = {}
51
+ const folderMapping = {}
52
52
 
53
53
  for (let i = 0; i < targetFolders.length; i++) {
54
54
  var folder = targetFolders[i]
55
55
  folderMapping[folder.full_slug] = folder.id
56
56
  }
57
57
 
58
- var all = await this.client.getAll(`spaces/${this.sourceSpaceId}/stories`, {
58
+ const all = await this.client.getAll(`spaces/${this.sourceSpaceId}/stories`, {
59
59
  story_only: 1
60
60
  })
61
61
 
62
62
  for (let i = 0; i < all.length; i++) {
63
63
  console.log(chalk.green('✓') + ' Starting update ' + all[i].full_slug)
64
64
 
65
- var storyResult = await this.client.get('spaces/' + this.sourceSpaceId + '/stories/' + all[i].id)
66
- var sourceStory = storyResult.data.story
67
- var slugs = sourceStory.full_slug.split('/')
68
- var folderId = 0
65
+ const { data } = await this.client.get('spaces/' + this.sourceSpaceId + '/stories/' + all[i].id)
66
+ const sourceStory = data.story
67
+ const slugs = sourceStory.full_slug.split('/')
68
+ let folderId = 0
69
69
 
70
70
  if (slugs.length > 1) {
71
71
  slugs.pop()
@@ -87,7 +87,7 @@ const SyncSpaces = {
87
87
  const payload = {
88
88
  story: storyData,
89
89
  force_update: '1',
90
- ...(sourceStory.published ? { published: 1 } : {})
90
+ ...(sourceStory.published ? { publish: 1 } : {})
91
91
  }
92
92
 
93
93
  let createdStory = null