diff --git a/src/cli.ts b/src/cli.ts index 9173fe8..b7a5350 100755 --- a/src/cli.ts +++ b/src/cli.ts @@ -142,11 +142,12 @@ program .option("--sf, --separate-files [value]", "Argument to create a single file for each component") .option("-p, --path ", "Path to save the component files") .option("-f, --file-name ", "custom name to be used in file(s) name instead of space id") + .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 } = options; + const { separateFiles, path, resolveDatasources } = options; if (!space) { console.log(chalk.red("X") + " Please provide the space as argument --space YOUR_SPACE_ID."); process.exit(0); @@ -160,7 +161,7 @@ program } api.setSpaceId(space); - await tasks.pullComponents(api, { fileName, separateFiles, path }); + await tasks.pullComponents(api, { fileName, separateFiles, path, resolveDatasources }); } catch (e) { errorHandler(e, COMMANDS.PULL_COMPONENTS); } diff --git a/src/tasks/pull-components.js b/src/tasks/pull-components.js index d0b9744..07fd19c 100644 --- a/src/tasks/pull-components.js +++ b/src/tasks/pull-components.js @@ -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} */ const pullComponents = async (api, options) => { - const { fileName, separateFiles, path } = options + const { fileName, separateFiles, path, 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) { diff --git a/src/utils/api.js b/src/utils/api.js index 46bf674..86c7d64 100644 --- a/src/utils/api.js +++ b/src/utils/api.js @@ -248,6 +248,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() diff --git a/tests/constants.js b/tests/constants.js index 398104e..0bddd32 100644 --- a/tests/constants.js +++ b/tests/constants.js @@ -135,6 +135,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: "" } ] diff --git a/tests/units/pull-components.spec.js b/tests/units/pull-components.spec.js index 5ee3ea2..8c1b178 100644 --- a/tests/units/pull-components.spec.js +++ b/tests/units/pull-components.spec.js @@ -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, 'writeFile').mockImplementation(jest.fn((key, data, _) => { @@ -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) {