From 7cf84c194aa391c590df4152aa8a6e707e487112 Mon Sep 17 00:00:00 2001 From: syshinnn Date: Thu, 12 Sep 2024 18:42:48 -0500 Subject: [PATCH 1/2] add plugin-copy-column --- plugins/copy-column/src/copy-column.ts | 175 +++++++++++++++++++++++++ plugins/copy-column/src/index.ts | 1 + 2 files changed, 176 insertions(+) create mode 100644 plugins/copy-column/src/copy-column.ts create mode 100644 plugins/copy-column/src/index.ts diff --git a/plugins/copy-column/src/copy-column.ts b/plugins/copy-column/src/copy-column.ts new file mode 100644 index 000000000..772ebf5bf --- /dev/null +++ b/plugins/copy-column/src/copy-column.ts @@ -0,0 +1,175 @@ +import api, { Flatfile } from "@flatfile/api" +import type { FlatfileEvent, FlatfileListener } from '@flatfile/listener' + +export type Primitive = string | number | null | boolean +export type SimpleRecord = Record + +export function copyColumn() { + return (listener: FlatfileListener) => { + listener.on('workbook:created', async ({ context: { fileId, workbookId } }: FlatfileEvent) => { + const { data: sheets } = await api.sheets.list({ workbookId }) + + sheets.forEach(async (sheet) => { + const loadAllFields = await getAllFields(sheets, sheet.slug); + setSheetActions(sheet, [ + copyColumnValuesBlueprint(loadAllFields), + ...(sheet.config.actions?.filter( + (a) => + a.operation !== 'copy-column' + ) || []), + ]); + }) + }) + + listener.on("job:ready", { job: "sheet:copy-column" }, async (e) => { + const { records } = await e.data({ pageLength: 10_000 }) + const { data: job } = await api.jobs.get(e.context.jobId) + const { key_copy_from, key_paste_to } = job.input + const patch = records.map(copyColumnValues(key_copy_from, key_paste_to)) + + await updateRecords(e.context.sheetId, patch) + + await api.jobs.complete(e.context.jobId, { + outcome: { + message: `Data was successfully copied from ${key_copy_from} to ${key_paste_to}.`, + }, + }); + }) + } +} + +function copyColumnValues(from_key: string, to_key: string) { + return (record: Flatfile.Record_) => { + const obj = toSimpleRecord(record) + return { + id: record.id, + values: { + [to_key]: { value: obj[from_key] }, + }, + } + } +} + +/** + * Updates records in a sheet. Bypasses API SDK in order to suppress hooks + */ + async function updateRecords(sheetId: string, records: any): Promise { + const httpResponse = await fetch( + `${process.env.FLATFILE_API_URL || process.env.AGENT_INTERNAL_URL}/v1/sheets/${sheetId}/records`, + { + method: "PUT", + headers: { + Authorization: `Bearer ${process.env.FLATFILE_BEARER_TOKEN}`, + "Content-Type": "application/json", + "x-force-hooks": "true", + }, + body: JSON.stringify(records), + } + ) + + if (httpResponse.status === 304) { + return "not-modified" + } + if (!httpResponse.ok) { + console.log(await httpResponse?.text()) + throw new Error(`Updating records failed.`) + } + + const res = await httpResponse.json() + return res.data.commitId +} + +function toSimpleRecord(r: Flatfile.Record_): SimpleRecord { + const obj = Object.fromEntries(Object.entries(r.values).map(([key, value]) => [key, value.value] as [string, any])) + obj.id = r.id + return obj as SimpleRecord +} + +/** + * Set sheet actions + * + * @param sheet + * @param actions + */ + async function setSheetActions(sheet: any, actions: Flatfile.Action[]) { + try { + const { constraints } = sheet.config; + await api.workbooks.update(sheet.workbookId, { + sheets: [ + { + name: sheet.name, + slug: sheet.config.slug, + actions, + }, + ], + }); + + if (constraints?.length > 0) { + await api.workbooks.update(sheet.workbookId, { + sheets: [ + { + ...sheet, + config: { + ...sheet.config, + actions, + constraints, + }, + }, + ], + }); + } + } catch (e) { + console.log({ e }); + } + } + + export const getAllFields = (sheets, sheetSlug) => { + const _fields = sheets.reduce((acc, sheet) => { + console.log("in getallfields, sheet.config.fields here: ") + console.log(sheet.config) + if (sheet.config.slug == sheetSlug) { + acc.push( + ...sheet.config.fields + .map((f) => { + return { ...f, appearance: { size: "s" } } as const + }) + ) + } + return acc + }, [] as Flatfile.Property[]) + + return _fields + } + +export const copyColumnValuesBlueprint = (columns: Flatfile.Property[]): Flatfile.Action => ({ + label: "Copy Column", + primary: false, + operation: "copy-column", + inputForm: { + type: "simple", + fields: [ + { + key: "key_copy_from", + type: "enum", + label: "Copy data from column", + config: { + options: columns + .map((f) => ({ label: f.label, value: f.key })) + .sort((a, b) => a.label.localeCompare(b.label)), + }, + constraints: [{ type: "required" }], + }, + { + key: "key_paste_to", + type: "enum", + label: "Paste data to column", + config: { + options: columns + .map((f) => ({ label: f.label, value: f.key })) + .sort((a, b) => a.label.localeCompare(b.label)), + }, + constraints: [{ type: "required" }], + }, + ], + }, +}) \ No newline at end of file diff --git a/plugins/copy-column/src/index.ts b/plugins/copy-column/src/index.ts new file mode 100644 index 000000000..cc382a731 --- /dev/null +++ b/plugins/copy-column/src/index.ts @@ -0,0 +1 @@ +export * from './copy-column' \ No newline at end of file From e36a41b8000f4ffd55a45168c4a6cbe45fd64460 Mon Sep 17 00:00:00 2001 From: syshinnn Date: Wed, 16 Oct 2024 11:48:40 -0500 Subject: [PATCH 2/2] add suggestions from carl --- plugins/copy-column/src/copy-column.ts | 38 ++------------------------ 1 file changed, 2 insertions(+), 36 deletions(-) diff --git a/plugins/copy-column/src/copy-column.ts b/plugins/copy-column/src/copy-column.ts index 772ebf5bf..632580610 100644 --- a/plugins/copy-column/src/copy-column.ts +++ b/plugins/copy-column/src/copy-column.ts @@ -1,5 +1,6 @@ import api, { Flatfile } from "@flatfile/api" import type { FlatfileEvent, FlatfileListener } from '@flatfile/listener' +import { updateRecords, Simplified } from "../../../utils/common/src" export type Primitive = string | number | null | boolean export type SimpleRecord = Record @@ -40,7 +41,7 @@ export function copyColumn() { function copyColumnValues(from_key: string, to_key: string) { return (record: Flatfile.Record_) => { - const obj = toSimpleRecord(record) + const obj = Simplified.toSimpleRecord(record) return { id: record.id, values: { @@ -50,41 +51,6 @@ function copyColumnValues(from_key: string, to_key: string) { } } -/** - * Updates records in a sheet. Bypasses API SDK in order to suppress hooks - */ - async function updateRecords(sheetId: string, records: any): Promise { - const httpResponse = await fetch( - `${process.env.FLATFILE_API_URL || process.env.AGENT_INTERNAL_URL}/v1/sheets/${sheetId}/records`, - { - method: "PUT", - headers: { - Authorization: `Bearer ${process.env.FLATFILE_BEARER_TOKEN}`, - "Content-Type": "application/json", - "x-force-hooks": "true", - }, - body: JSON.stringify(records), - } - ) - - if (httpResponse.status === 304) { - return "not-modified" - } - if (!httpResponse.ok) { - console.log(await httpResponse?.text()) - throw new Error(`Updating records failed.`) - } - - const res = await httpResponse.json() - return res.data.commitId -} - -function toSimpleRecord(r: Flatfile.Record_): SimpleRecord { - const obj = Object.fromEntries(Object.entries(r.values).map(([key, value]) => [key, value.value] as [string, any])) - obj.id = r.id - return obj as SimpleRecord -} - /** * Set sheet actions *