Skip to content

Commit

Permalink
feat(pull-components): add option to resolve datasource for single/mu…
Browse files Browse the repository at this point in the history
…ltiple option field
  • Loading branch information
RKcode committed Sep 3, 2024
1 parent 3016650 commit e8c9322
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 13 deletions.
19 changes: 10 additions & 9 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,12 @@ program
.option("-p, --path <path>", "Path to save the component files")
.option("-f, --file-name <fileName>", "custom name to be used in file(s) name instead of space id")
.option("-ppn, --prefix-presets-names", "Prefixes the names of presets with the name of the components")
.option("--rd, --resolve-datasources", "Fill options for single/multiple option field with the linked datasource")
.description("Download your space's components schema as json")
.action(async (options) => {
console.log(`${chalk.blue("-")} Executing pull-components task`);
const space = program.space;
const { separateFiles, path, prefixPresetsNames } = options;
const { separateFiles, path, prefixPresetsNames, resolveDatasources } = options;
if (!space) {
console.log(chalk.red("X") + " Please provide the space as argument --space YOUR_SPACE_ID.");
process.exit(0);
Expand All @@ -161,7 +162,7 @@ program
}

api.setSpaceId(space);
await tasks.pullComponents(api, { fileName, separateFiles, path, prefixPresetsNames });
await tasks.pullComponents(api, { fileName, separateFiles, path, prefixPresetsNames, resolveDatasources });
} catch (e) {
errorHandler(e, COMMANDS.PULL_COMPONENTS);
}
Expand Down Expand Up @@ -299,11 +300,11 @@ program
)
.requiredOption("--source <SPACE_ID>", "Source space id")
.requiredOption("--target <SPACE_ID>", "Target space id")
.option('--starts-with <STARTS_WITH>', 'Sync only stories that starts with the given string')
.option('--filter', 'Enable filter options to sync only stories that match the given filter. Required options: --keys; --operations; --values')
.option('--keys <KEYS>', 'Field names in your story object which should be used for filtering. Multiple keys should separated by comma.')
.option('--operations <OPERATIONS>', 'Operations to be used for filtering. Can be: is, in, not_in, like, not_like, any_in_array, all_in_array, gt_date, lt_date, gt_int, lt_int, gt_float, lt_float. Multiple operations should be separated by comma.')
.option('--values <VALUES>', 'Values to be used for filtering. Any string or number. If you want to use multiple values, separate them with a comma. Multiple values should be separated by comma.')
.option("--starts-with <STARTS_WITH>", "Sync only stories that starts with the given string")
.option("--filter", "Enable filter options to sync only stories that match the given filter. Required options: --keys; --operations; --values")
.option("--keys <KEYS>", "Field names in your story object which should be used for filtering. Multiple keys should separated by comma.")
.option("--operations <OPERATIONS>", "Operations to be used for filtering. Can be: is, in, not_in, like, not_like, any_in_array, all_in_array, gt_date, lt_date, gt_int, lt_int, gt_float, lt_float. Multiple operations should be separated by comma.")
.option("--values <VALUES>", "Values to be used for filtering. Any string or number. If you want to use multiple values, separate them with a comma. Multiple values should be separated by comma.")
.option("--components-groups <UUIDs>", "Synchronize components based on their group UUIDs separated by commas")
.option("--components-full-sync", "Synchronize components by overriding any property from source to target")
.action(async (options) => {
Expand All @@ -317,7 +318,7 @@ program
const {
type,
target,
source,
source,
startsWith,
filter,
keys,
Expand All @@ -329,7 +330,7 @@ program

const _componentsGroups = componentsGroups ? componentsGroups.split(",") : null;
const _componentsFullSync = !!componentsFullSync;
const filterQuery = filter ? buildFilterQuery(keys, operations, values) : undefined
const filterQuery = filter ? buildFilterQuery(keys, operations, values) : undefined;
const token = creds.get().token || null;

const _types = type.split(",") || [];
Expand Down
35 changes: 32 additions & 3 deletions src/tasks/pull-components.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,51 @@ const getNameFromComponentGroups = (groups, uuid) => {
return ''
}

const resolveDatasourceOptions = async (api, components) => {
const datasources = await api.getDatasources()

for (const datasource of datasources) {
const datasourceEntries = await api.getDatasourceEntries(datasource.id)
datasource.entries = datasourceEntries
}

return components.map(component => {
const schema = component.schema

for (const field in schema) {
if (schema[field].source === 'internal' && schema[field].datasource_slug) {
const datasource = datasources.find(ds => ds.slug === schema[field].datasource_slug)

if (datasource) {
schema[field].options = datasource.entries.map(entry => ({ value: entry.value, name: entry.name }))
}
}
}

return component
})
}

/**
* @method pullComponents
* @param {Object} api
* @param {Object} options { fileName: string, separateFiles: Boolean, path: String }
* @param {Object} options { fileName: string, separateFiles: Boolean, path: String, resolveDatasources: Boolean }
* @return {Promise<Object>}
*/
const pullComponents = async (api, options) => {
const { fileName, separateFiles, path, prefixPresetsNames } = options
const { fileName, separateFiles, path, prefixPresetsNames, resolveDatasources } = options

try {
const componentGroups = await api.getComponentGroups()

const components = await api.getComponents()
let components = await api.getComponents()

const presets = await api.getPresets()

if (resolveDatasources) {
components = await resolveDatasourceOptions(api, components)
}

components.forEach(component => {
const groupUuid = component.component_group_uuid
if (groupUuid) {
Expand Down
9 changes: 9 additions & 0 deletions src/utils/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,15 @@ export default {
.catch(err => Promise.reject(err))
},

getDatasourceEntries (id) {
const client = this.getClient()

return client
.get(this.getPath(`datasource_entries?datasource_id=${id}`))
.then(data => data.data.datasource_entries || [])
.catch(err => Promise.reject(err))
},

deleteDatasource (id) {
const client = this.getClient()

Expand Down
49 changes: 49 additions & 0 deletions tests/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,55 @@ export const FAKE_COMPONENTS = () => [
preset_id: null,
real_name: 'hero',
component_group_uuid: null
},
{
name: 'meta',
display_name: null,
created_at: '2019-11-06T17:07:04.196Z',
updated_at: '2019-11-06T18:12:29.136Z',
id: 4,
schema: {
robot: {
type: "option",
source: "internal",
datasource_slug: "robots",
}
},
image: null,
preview_field: null,
is_root: false,
preview_tmpl: null,
is_nestable: true,
all_presets: [],
preset_id: null,
real_name: 'meta',
component_group_uuid: null
},
]

export const FAKE_DATASOURCES = () => [
{
id: 1,
name: "Robots",
slug: "robots",
dimensions: [],
created_at: "2019-10-15T17:00:32.212Z",
updated_at: "2019-11-15T17:00:32.212Z",
},
]

export const FAKE_DATASOURCE_ENTRIES = () => [
{
id: 1,
name: "No index",
value: "noindex",
dimension_value: ""
},
{
id: 2,
name: "No follow",
value: "nofollow",
dimension_value: ""
}
]

Expand Down
50 changes: 49 additions & 1 deletion tests/units/pull-components.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import fs from 'fs'
import pullComponents from '../../src/tasks/pull-components'
import { FAKE_PRESET, FAKE_COMPONENTS } from '../constants'
import { FAKE_PRESET, FAKE_COMPONENTS, FAKE_DATASOURCES, FAKE_DATASOURCE_ENTRIES } from '../constants'
import { jest } from '@jest/globals'

jest.spyOn(fs, 'writeFileSync').mockImplementation(jest.fn((key, data, _) => {
Expand Down Expand Up @@ -126,6 +126,54 @@ describe('testing pullComponents', () => {
}
})

it('pull components should be call fs.writeFile correctly and return filled options from datasource entries', async () => {
const SPACE = 12345

const api = {
getComponents () {
return Promise.resolve([FAKE_COMPONENTS()[5]])
},
getComponentGroups () {
return Promise.resolve([])
},
getDatasources () {
return Promise.resolve(FAKE_DATASOURCES())
},
getDatasourceEntries () {
return Promise.resolve(FAKE_DATASOURCE_ENTRIES())
},
getPresets () {
return Promise.resolve([])
}
}

const options = {
fileName: SPACE,
resolveDatasources: true
}

const expectFileName = `components.${SPACE}.json`

await pullComponents(api, options)
const [path, data] = fs.writeFile.mock.calls[0]

expect(fs.writeFile.mock.calls.length).toBe(1)
expect(path).toBe(`./${expectFileName}`)
expect(JSON.parse(data)).toEqual({
components: [{
...FAKE_COMPONENTS()[5],
schema: {
robot: {
type: "option",
source: "internal",
datasource_slug: "robots",
options: FAKE_DATASOURCE_ENTRIES().map(entry => ({ value: entry.value, name: entry.name }))
}
}
}]
})
})

it('api.getComponents() when a error ocurred, catch the body response', async () => {
const _api = {
getComponents (_, fn) {
Expand Down

0 comments on commit e8c9322

Please sign in to comment.