diff --git a/apps/studio/components/interfaces/Integrations/Wrappers/WrapperRow.tsx b/apps/studio/components/interfaces/Integrations/Wrappers/WrapperRow.tsx index 7e583499894..bfdd02cf96d 100644 --- a/apps/studio/components/interfaces/Integrations/Wrappers/WrapperRow.tsx +++ b/apps/studio/components/interfaces/Integrations/Wrappers/WrapperRow.tsx @@ -23,7 +23,7 @@ const WrapperRow = ({ wrapper }: WrapperRowProps) => { const canManageWrappers = useCheckPermissions(PermissionAction.TENANT_SQL_ADMIN_WRITE, 'wrappers') const [editWrapperShown, setEditWrapperShown] = useState(false) - const [isClosingEditWrapper, setisClosingEditWrapper] = useState(false) + const [isClosingEditWrapper, setIsClosingEditWrapper] = useState(false) const [deleteWrapperShown, setDeleteWrapperShown] = useState(false) const integration = INTEGRATIONS.find((i) => i.id === id) @@ -45,7 +45,7 @@ const WrapperRow = ({ wrapper }: WrapperRowProps) => { return ( <> - + {wrapper.name} {visibleMetadata.map((metadata) => ( @@ -53,8 +53,10 @@ const WrapperRow = ({ wrapper }: WrapperRowProps) => { key={metadata.name} className="flex items-center space-x-2 text-sm text-foreground-light" > - {metadata.label}: - {serverOptions[metadata.name]} + {metadata.label}: + + {serverOptions[metadata.name]} + ))} @@ -99,7 +101,7 @@ const WrapperRow = ({ wrapper }: WrapperRowProps) => { ))} - + { /> - setisClosingEditWrapper(true)}> + setIsClosingEditWrapper(true)}> { setEditWrapperShown(false) - setisClosingEditWrapper(false) + setIsClosingEditWrapper(false) }} isClosing={isClosingEditWrapper} - setIsClosing={setisClosingEditWrapper} + setIsClosing={setIsClosingEditWrapper} /> diff --git a/apps/studio/components/interfaces/Integrations/Wrappers/Wrappers.constants.ts b/apps/studio/components/interfaces/Integrations/Wrappers/Wrappers.constants.ts index a6b2bb40718..bae71c82a7e 100644 --- a/apps/studio/components/interfaces/Integrations/Wrappers/Wrappers.constants.ts +++ b/apps/studio/components/interfaces/Integrations/Wrappers/Wrappers.constants.ts @@ -20,6 +20,7 @@ export const WRAPPER_HANDLERS = { CLERK: 'wasm_fdw_handler', NOTION: 'wasm_fdw_handler', SLACK: 'wasm_fdw_handler', + CLOUDFLARE_D1: 'wasm_fdw_handler', } export const WRAPPERS: WrapperMeta[] = [ @@ -3316,4 +3317,140 @@ export const WRAPPERS: WrapperMeta[] = [ }, ], }, + { + name: 'cfd1_wrapper', + description: 'Read and write data from Cloudflare D1 databases using the Wasm FDW.', + handlerName: WRAPPER_HANDLERS.CLOUDFLARE_D1, + validatorName: 'wasm_fdw_validator', + icon: `${BASE_PATH}/img/icons/cloudflare-icon.svg`, + extensionName: 'Cfd1Fdw', + label: 'Cloudflare D1', + docsUrl: 'https://fdw.dev/catalog/cfd1/', + minimumExtensionVersion: '0.4.0', + server: { + options: [ + { + name: 'fdw_package_url', + label: 'FDW Package URL', + required: true, + encrypted: false, + secureEntry: false, + defaultValue: + 'https://github.com/supabase/wrappers/releases/download/wasm_cfd1_fdw_v0.1.0/cfd1_fdw.wasm', + hidden: true, + }, + { + name: 'fdw_package_name', + label: 'FDW Package Name', + required: true, + encrypted: false, + secureEntry: false, + defaultValue: 'supabase:cfd1-fdw', + hidden: true, + }, + { + name: 'fdw_package_version', + label: 'FDW Package Version', + required: true, + encrypted: false, + secureEntry: false, + defaultValue: '0.1.0', + hidden: true, + }, + { + name: 'fdw_package_checksum', + label: 'FDW Package Checksum', + required: true, + encrypted: false, + secureEntry: false, + defaultValue: '783232834bb29dbd3ee6b09618c16f8a847286e63d05c54397d56c3e703fad31', + hidden: true, + }, + { + name: 'api_url', + label: 'API URL', + required: false, + encrypted: false, + secureEntry: false, + defaultValue: 'https://api.cloudflare.com/client/v4/accounts//d1/database', + }, + { + name: 'account_id', + label: 'Account ID', + required: true, + encrypted: false, + secureEntry: false, + }, + { + name: 'database_id', + label: 'Database ID', + required: true, + encrypted: false, + secureEntry: false, + }, + { + name: 'api_token_id', + label: 'Cloudflare D1 API Token', + required: true, + encrypted: true, + secureEntry: true, + urlHelper: 'https://dash.cloudflare.com/profile/api-tokens', + }, + ], + }, + tables: [ + { + label: 'D1 Databases', + description: 'D1 databases in your Cloudflare account', + availableColumns: [ + { name: 'uuid', type: 'text' }, + { name: 'name', type: 'text' }, + { name: 'version', type: 'text' }, + { name: 'num_tables', type: 'bigint' }, + { name: 'file_size', type: 'bigint' }, + { name: 'created_at', type: 'text' }, + { name: '_attrs', type: 'jsonb' }, + ], + options: [ + { + name: 'table', + defaultValue: '_meta_databases', + editable: false, + required: true, + type: 'text', + }, + ], + }, + { + label: 'D1 Table', + description: 'A table in your D1 database (define columns to match your D1 schema)', + availableColumns: [ + { name: 'id', type: 'bigint' }, + { name: 'name', type: 'text' }, + { name: 'amount', type: 'double precision' }, + { name: 'metadata', type: 'text' }, + { name: '_attrs', type: 'jsonb' }, + ], + options: [ + { + label: 'Table', + name: 'table', + placeholder: 'mytable', + editable: true, + required: true, + type: 'text', + }, + { + label: 'Row ID Column', + name: 'rowid_column', + placeholder: 'id', + defaultValue: 'id', + editable: true, + required: false, + type: 'text', + }, + ], + }, + ], + }, ] diff --git a/apps/studio/public/img/icons/cloudflare-icon.svg b/apps/studio/public/img/icons/cloudflare-icon.svg new file mode 100644 index 00000000000..739274a993c --- /dev/null +++ b/apps/studio/public/img/icons/cloudflare-icon.svg @@ -0,0 +1,7 @@ + + \ No newline at end of file diff --git a/apps/studio/static-data/integrations/cfd1_wrapper/overview.md b/apps/studio/static-data/integrations/cfd1_wrapper/overview.md new file mode 100644 index 00000000000..424a5977bba --- /dev/null +++ b/apps/studio/static-data/integrations/cfd1_wrapper/overview.md @@ -0,0 +1,10 @@ +Cloudflare D1 is Cloudflare's managed, serverless database with SQLite's SQL semantics, built-in disaster recovery, and Worker and HTTP API access. + +The Cloudflare D1 Wrapper is a WebAssembly (Wasm) foreign data wrapper that allows you to read and write data from Cloudflare D1 databases within your Postgres database. + +**Features** + +- Query D1 databases directly from Postgres using SQL. +- Read and write support for D1 tables. +- Secure credential storage via Supabase Vault. +- Supports query pushdown (where, order by, limit).