From d36c9d43f614247b2bd0d758b8f5359a627b7e99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C4=B1dvan=20Akca?= Date: Tue, 23 Jan 2024 16:26:38 +0300 Subject: [PATCH] feat(airtable): add create record action --- .../airtable/actions/create-record/index.js | 92 +++++++++++++++++++ .../src/apps/airtable/actions/index.js | 3 + .../src/apps/airtable/dynamic-data/index.js | 4 + .../airtable/dynamic-data/list-bases/index.js | 28 ++++++ .../dynamic-data/list-tables/index.js | 35 +++++++ .../src/apps/airtable/dynamic-fields/index.js | 3 + .../dynamic-fields/list-fields/index.js | 86 +++++++++++++++++ packages/backend/src/apps/airtable/index.js | 6 ++ packages/docs/pages/.vitepress/config.js | 5 +- packages/docs/pages/apps/airtable/actions.md | 12 +++ packages/docs/pages/guide/available-apps.md | 1 + 11 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 packages/backend/src/apps/airtable/actions/create-record/index.js create mode 100644 packages/backend/src/apps/airtable/actions/index.js create mode 100644 packages/backend/src/apps/airtable/dynamic-data/index.js create mode 100644 packages/backend/src/apps/airtable/dynamic-data/list-bases/index.js create mode 100644 packages/backend/src/apps/airtable/dynamic-data/list-tables/index.js create mode 100644 packages/backend/src/apps/airtable/dynamic-fields/index.js create mode 100644 packages/backend/src/apps/airtable/dynamic-fields/list-fields/index.js create mode 100644 packages/docs/pages/apps/airtable/actions.md diff --git a/packages/backend/src/apps/airtable/actions/create-record/index.js b/packages/backend/src/apps/airtable/actions/create-record/index.js new file mode 100644 index 00000000..554015be --- /dev/null +++ b/packages/backend/src/apps/airtable/actions/create-record/index.js @@ -0,0 +1,92 @@ +import defineAction from '../../../../helpers/define-action.js'; + +export default defineAction({ + name: 'Create record', + key: 'createRecord', + description: 'Creates a new record with fields that automatically populate.', + arguments: [ + { + label: 'Base', + key: 'baseId', + type: 'dropdown', + required: true, + description: 'Base in which to create the record.', + variables: true, + source: { + type: 'query', + name: 'getDynamicData', + arguments: [ + { + name: 'key', + value: 'listBases', + }, + ], + }, + }, + { + label: 'Table', + key: 'tableId', + type: 'dropdown', + required: true, + dependsOn: ['parameters.baseId'], + description: '', + variables: true, + source: { + type: 'query', + name: 'getDynamicData', + arguments: [ + { + name: 'key', + value: 'listTables', + }, + { + name: 'parameters.baseId', + value: '{parameters.baseId}', + }, + ], + }, + additionalFields: { + type: 'query', + name: 'getDynamicFields', + arguments: [ + { + name: 'key', + value: 'listFields', + }, + { + name: 'parameters.baseId', + value: '{parameters.baseId}', + }, + { + name: 'parameters.tableId', + value: '{parameters.tableId}', + }, + ], + }, + }, + ], + + async run($) { + const { baseId, tableId, ...rest } = $.step.parameters; + + const fields = Object.entries(rest).reduce((result, [key, value]) => { + if (Array.isArray(value)) { + result[key] = value.map((item) => item.value); + } else if (value !== '') { + result[key] = value; + } + return result; + }, {}); + + const body = { + typecast: true, + fields, + }; + + const { data } = await $.http.post(`/v0/${baseId}/${tableId}`, body); + + $.setActionItem({ + raw: data, + }); + }, +}); diff --git a/packages/backend/src/apps/airtable/actions/index.js b/packages/backend/src/apps/airtable/actions/index.js new file mode 100644 index 00000000..abe026dd --- /dev/null +++ b/packages/backend/src/apps/airtable/actions/index.js @@ -0,0 +1,3 @@ +import createRecord from './create-record/index.js'; + +export default [createRecord]; diff --git a/packages/backend/src/apps/airtable/dynamic-data/index.js b/packages/backend/src/apps/airtable/dynamic-data/index.js new file mode 100644 index 00000000..344ff5d1 --- /dev/null +++ b/packages/backend/src/apps/airtable/dynamic-data/index.js @@ -0,0 +1,4 @@ +import listBases from './list-bases/index.js'; +import listTables from './list-tables/index.js'; + +export default [listBases, listTables]; diff --git a/packages/backend/src/apps/airtable/dynamic-data/list-bases/index.js b/packages/backend/src/apps/airtable/dynamic-data/list-bases/index.js new file mode 100644 index 00000000..2f075694 --- /dev/null +++ b/packages/backend/src/apps/airtable/dynamic-data/list-bases/index.js @@ -0,0 +1,28 @@ +export default { + name: 'List bases', + key: 'listBases', + + async run($) { + const bases = { + data: [], + }; + + const params = {}; + + do { + const { data } = await $.http.get('/v0/meta/bases', { params }); + params.offset = data.offset; + + if (data?.bases) { + for (const base of data.bases) { + bases.data.push({ + value: base.id, + name: base.name, + }); + } + } + } while (params.offset); + + return bases; + }, +}; diff --git a/packages/backend/src/apps/airtable/dynamic-data/list-tables/index.js b/packages/backend/src/apps/airtable/dynamic-data/list-tables/index.js new file mode 100644 index 00000000..90d6b4c0 --- /dev/null +++ b/packages/backend/src/apps/airtable/dynamic-data/list-tables/index.js @@ -0,0 +1,35 @@ +export default { + name: 'List tables', + key: 'listTables', + + async run($) { + const tables = { + data: [], + }; + const baseId = $.step.parameters.baseId; + + if (!baseId) { + return tables; + } + + const params = {}; + + do { + const { data } = await $.http.get(`/v0/meta/bases/${baseId}/tables`, { + params, + }); + params.offset = data.offset; + + if (data?.tables) { + for (const table of data.tables) { + tables.data.push({ + value: table.id, + name: table.name, + }); + } + } + } while (params.offset); + + return tables; + }, +}; diff --git a/packages/backend/src/apps/airtable/dynamic-fields/index.js b/packages/backend/src/apps/airtable/dynamic-fields/index.js new file mode 100644 index 00000000..5d97313e --- /dev/null +++ b/packages/backend/src/apps/airtable/dynamic-fields/index.js @@ -0,0 +1,3 @@ +import listFields from './list-fields/index.js'; + +export default [listFields]; diff --git a/packages/backend/src/apps/airtable/dynamic-fields/list-fields/index.js b/packages/backend/src/apps/airtable/dynamic-fields/list-fields/index.js new file mode 100644 index 00000000..704d1940 --- /dev/null +++ b/packages/backend/src/apps/airtable/dynamic-fields/list-fields/index.js @@ -0,0 +1,86 @@ +const hasValue = (value) => value !== null && value !== undefined; + +export default { + name: 'List fields', + key: 'listFields', + + async run($) { + const options = []; + const { baseId, tableId } = $.step.parameters; + + if (!hasValue(baseId) || !hasValue(tableId)) { + return; + } + + const { data } = await $.http.get(`/v0/meta/bases/${baseId}/tables`); + + const selectedTable = data.tables.find((table) => table.id === tableId); + + if (!selectedTable) return; + + selectedTable.fields.forEach((field) => { + if (field.type === 'singleSelect') { + options.push({ + label: field.name, + key: field.name, + type: 'dropdown', + required: false, + variables: true, + options: field.options.choices.map((choice) => ({ + label: choice.name, + value: choice.id, + })), + }); + } else if (field.type === 'multipleSelects') { + options.push({ + label: field.name, + key: field.name, + type: 'dynamic', + required: false, + variables: true, + fields: [ + { + label: 'Value', + key: 'value', + type: 'dropdown', + required: false, + variables: true, + options: field.options.choices.map((choice) => ({ + label: choice.name, + value: choice.id, + })), + }, + ], + }); + } else if (field.type === 'checkbox') { + options.push({ + label: field.name, + key: field.name, + type: 'dropdown', + required: false, + variables: true, + options: [ + { + label: 'Yes', + value: 'true', + }, + { + label: 'No', + value: 'false', + }, + ], + }); + } else { + options.push({ + label: field.name, + key: field.name, + type: 'string', + required: false, + variables: true, + }); + } + }); + + return options; + }, +}; diff --git a/packages/backend/src/apps/airtable/index.js b/packages/backend/src/apps/airtable/index.js index c658c6ab..b2bb56a0 100644 --- a/packages/backend/src/apps/airtable/index.js +++ b/packages/backend/src/apps/airtable/index.js @@ -1,6 +1,9 @@ import defineApp from '../../helpers/define-app.js'; import addAuthHeader from './common/add-auth-header.js'; import auth from './auth/index.js'; +import actions from './actions/index.js'; +import dynamicData from './dynamic-data/index.js'; +import dynamicFields from './dynamic-fields/index.js'; export default defineApp({ name: 'Airtable', @@ -13,4 +16,7 @@ export default defineApp({ supportsConnections: true, beforeRequest: [addAuthHeader], auth, + actions, + dynamicData, + dynamicFields, }); diff --git a/packages/docs/pages/.vitepress/config.js b/packages/docs/pages/.vitepress/config.js index d5fee6f8..86d71774 100644 --- a/packages/docs/pages/.vitepress/config.js +++ b/packages/docs/pages/.vitepress/config.js @@ -36,7 +36,10 @@ export default defineConfig({ text: 'Airtable', collapsible: true, collapsed: true, - items: [{ text: 'Connection', link: '/apps/airtable/connection' }], + items: [ + { text: 'Actions', link: '/apps/airtable/actions' }, + { text: 'Connection', link: '/apps/airtable/connection' }, + ], }, { text: 'Carbone', diff --git a/packages/docs/pages/apps/airtable/actions.md b/packages/docs/pages/apps/airtable/actions.md new file mode 100644 index 00000000..e496a373 --- /dev/null +++ b/packages/docs/pages/apps/airtable/actions.md @@ -0,0 +1,12 @@ +--- +favicon: /favicons/airtable.svg +items: + - name: Create record + desc: Creates a new record with fields that automatically populate. +--- + + + + diff --git a/packages/docs/pages/guide/available-apps.md b/packages/docs/pages/guide/available-apps.md index 90f8ba0a..49242ef3 100644 --- a/packages/docs/pages/guide/available-apps.md +++ b/packages/docs/pages/guide/available-apps.md @@ -2,6 +2,7 @@ The following integrations are currently supported by Automatisch. +- [Airtable](/apps/airtable/actions) - [Carbone](/apps/carbone/actions) - [DeepL](/apps/deepl/actions) - [Delay](/apps/delay/actions)