diff --git a/packages/backend/src/apps/airtable/actions/find-record/index.js b/packages/backend/src/apps/airtable/actions/find-record/index.js new file mode 100644 index 00000000..47243dc3 --- /dev/null +++ b/packages/backend/src/apps/airtable/actions/find-record/index.js @@ -0,0 +1,174 @@ +import defineAction from '../../../../helpers/define-action.js'; +import { URLSearchParams } from 'url'; + +export default defineAction({ + name: 'Find record', + key: 'findRecord', + description: + "Finds a record using simple field search or use Airtable's formula syntax to find a matching record.", + 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}', + }, + ], + }, + }, + { + label: 'Search by field', + key: 'tableField', + type: 'dropdown', + required: false, + dependsOn: ['parameters.baseId', 'parameters.tableId'], + description: '', + variables: true, + source: { + type: 'query', + name: 'getDynamicData', + arguments: [ + { + name: 'key', + value: 'listTableFields', + }, + { + name: 'parameters.baseId', + value: '{parameters.baseId}', + }, + { + name: 'parameters.tableId', + value: '{parameters.tableId}', + }, + ], + }, + }, + { + label: 'Search Value', + key: 'searchValue', + type: 'string', + required: false, + variables: true, + description: + 'The value of unique identifier for the record. For date values, please use the ISO format (e.g., "YYYY-MM-DD").', + }, + { + label: 'Search for exact match?', + key: 'exactMatch', + type: 'dropdown', + required: true, + description: '', + variables: true, + options: [ + { label: 'Yes', value: 'true' }, + { label: 'No', value: 'false' }, + ], + }, + { + label: 'Search Formula', + key: 'searchFormula', + type: 'string', + required: false, + variables: true, + description: + 'Instead, you have the option to use an Airtable search formula for locating records according to sophisticated criteria and across various fields.', + }, + { + label: 'Limit to View', + key: 'limitToView', + type: 'dropdown', + required: true, + dependsOn: ['parameters.baseId', 'parameters.tableId'], + description: + 'You have the choice to restrict the search to a particular view ID if desired.', + variables: true, + source: { + type: 'query', + name: 'getDynamicData', + arguments: [ + { + name: 'key', + value: 'listTableViews', + }, + { + name: 'parameters.baseId', + value: '{parameters.baseId}', + }, + { + name: 'parameters.tableId', + value: '{parameters.tableId}', + }, + ], + }, + }, + ], + + async run($) { + const { + baseId, + tableId, + tableField, + searchValue, + exactMatch, + searchFormula, + limitToView, + } = $.step.parameters; + + let filterByFormula; + + if (tableField && searchValue) { + filterByFormula = + exactMatch === 'true' + ? `{${tableField}} = '${searchValue}'` + : `LOWER({${tableField}}) = LOWER('${searchValue}')`; + } else { + filterByFormula = searchFormula; + } + + const body = new URLSearchParams({ + filterByFormula, + view: limitToView, + }); + + const { data } = await $.http.post( + `/v0/${baseId}/${tableId}/listRecords`, + body + ); + + $.setActionItem({ + raw: data, + }); + }, +}); diff --git a/packages/backend/src/apps/airtable/actions/index.js b/packages/backend/src/apps/airtable/actions/index.js index abe026dd..bb3c63ce 100644 --- a/packages/backend/src/apps/airtable/actions/index.js +++ b/packages/backend/src/apps/airtable/actions/index.js @@ -1,3 +1,4 @@ import createRecord from './create-record/index.js'; +import findRecord from './find-record/index.js'; -export default [createRecord]; +export default [createRecord, findRecord]; diff --git a/packages/backend/src/apps/airtable/dynamic-data/index.js b/packages/backend/src/apps/airtable/dynamic-data/index.js index 344ff5d1..c12f341f 100644 --- a/packages/backend/src/apps/airtable/dynamic-data/index.js +++ b/packages/backend/src/apps/airtable/dynamic-data/index.js @@ -1,4 +1,6 @@ import listBases from './list-bases/index.js'; +import listTableFields from './list-table-fields/index.js'; +import listTableViews from './list-table-views/index.js'; import listTables from './list-tables/index.js'; -export default [listBases, listTables]; +export default [listBases, listTableFields, listTableViews, listTables]; diff --git a/packages/backend/src/apps/airtable/dynamic-data/list-table-fields/index.js b/packages/backend/src/apps/airtable/dynamic-data/list-table-fields/index.js new file mode 100644 index 00000000..3f96d127 --- /dev/null +++ b/packages/backend/src/apps/airtable/dynamic-data/list-table-fields/index.js @@ -0,0 +1,39 @@ +export default { + name: 'List table fields', + key: 'listTableFields', + + async run($) { + const tableFields = { + data: [], + }; + const { baseId, tableId } = $.step.parameters; + + if (!baseId) { + return tableFields; + } + + 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) { + if (table.id === tableId) { + table.fields.forEach((field) => { + tableFields.data.push({ + value: field.name, + name: field.name, + }); + }); + } + } + } + } while (params.offset); + + return tableFields; + }, +}; diff --git a/packages/backend/src/apps/airtable/dynamic-data/list-table-views/index.js b/packages/backend/src/apps/airtable/dynamic-data/list-table-views/index.js new file mode 100644 index 00000000..d2ec9127 --- /dev/null +++ b/packages/backend/src/apps/airtable/dynamic-data/list-table-views/index.js @@ -0,0 +1,39 @@ +export default { + name: 'List table views', + key: 'listTableViews', + + async run($) { + const tableViews = { + data: [], + }; + const { baseId, tableId } = $.step.parameters; + + if (!baseId) { + return tableViews; + } + + 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) { + if (table.id === tableId) { + table.views.forEach((view) => { + tableViews.data.push({ + value: view.id, + name: view.name, + }); + }); + } + } + } + } while (params.offset); + + return tableViews; + }, +}; diff --git a/packages/docs/pages/apps/airtable/actions.md b/packages/docs/pages/apps/airtable/actions.md index e496a373..432e0d46 100644 --- a/packages/docs/pages/apps/airtable/actions.md +++ b/packages/docs/pages/apps/airtable/actions.md @@ -3,6 +3,8 @@ favicon: /favicons/airtable.svg items: - name: Create record desc: Creates a new record with fields that automatically populate. + - name: Find record + desc: Finds a record using simple field search or use Airtable's formula syntax to find a matching record. ---