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 +2 -1
- package/src/tasks/sync-commands/datasources.js +145 -13
- package/src/tasks/sync.js +8 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "storyblok",
|
|
3
|
-
"version": "3.
|
|
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
|
|
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 =
|
|
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 (
|
|
91
|
+
async syncDatasourceEntries (datasourceId, targetId) {
|
|
92
92
|
try {
|
|
93
|
-
const sourceEntries = await this.getDatasourceEntries(this.sourceSpaceId,
|
|
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
|
-
|
|
136
|
-
|
|
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
|
-
|
|
163
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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 ? {
|
|
90
|
+
...(sourceStory.published ? { publish: 1 } : {})
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
let createdStory = null
|