import dayjs from 'dayjs' import Link from 'next/link' import { useRouter } from 'next/router' import { FC, useState, useEffect } from 'react' import * as Tooltip from '@radix-ui/react-tooltip' import { PermissionAction } from '@supabase/shared-types/out/constants' import { Alert, IconTerminal, IconMinimize2, IconMaximize2, Button, Modal, Form, Toggle, Input, IconExternalLink, } from 'ui' import { useStore, checkPermissions } from 'hooks' import { useParams } from 'common/hooks' import Panel from 'components/ui/Panel' import CommandRender from '../CommandRender' import { generateCLICommands } from './EdgeFunctionDetails.utils' import { useProjectApiQuery } from 'data/config/project-api-query' import { useEdgeFunctionUpdateMutation } from 'data/edge-functions/edge-functions-update-mutation' import { useEdgeFunctionDeleteMutation } from 'data/edge-functions/edge-functions-delete-mutation' import { FormHeader, FormPanel, FormActions, FormSection, FormSectionLabel, FormSectionContent, } from 'components/ui/Forms' import { useEdgeFunctionQuery } from 'data/edge-functions/edge-function-query' import clsx from 'clsx' interface Props {} const EdgeFunctionDetails: FC = () => { const router = useRouter() const { ui } = useStore() const { ref: projectRef, functionSlug } = useParams() const [showDeleteModal, setShowDeleteModal] = useState(false) const [showInstructions, setShowInstructions] = useState(false) const { data: settings } = useProjectApiQuery({ projectRef }) const { data: selectedFunction } = useEdgeFunctionQuery({ projectRef, slug: functionSlug }) const { mutateAsync: updateEdgeFunction } = useEdgeFunctionUpdateMutation() const { mutateAsync: deleteEdgeFunction, isLoading: isDeleting } = useEdgeFunctionDeleteMutation() const formId = 'edge-function-update-form' const canUpdateEdgeFunction = checkPermissions(PermissionAction.FUNCTIONS_WRITE, '*') // Get the API service const apiService = settings?.autoApiService const anonKey = apiService?.service_api_keys.find((x) => x.name === 'anon key') ? apiService.defaultApiKey : '[YOUR ANON KEY]' const endpoint = apiService?.app_config.endpoint ?? '' const endpointSections = endpoint.split('.') const functionsEndpoint = [ ...endpointSections.slice(0, 1), 'functions', ...endpointSections.slice(1), ].join('.') const functionUrl = `${apiService?.protocol}://${functionsEndpoint}/${selectedFunction?.slug}` const { managementCommands, secretCommands, invokeCommands } = generateCLICommands( selectedFunction, functionUrl, anonKey ) const onUpdateFunction = async (values: any, { setSubmitting, resetForm }: any) => { if (!projectRef) return console.error('Project ref is required') if (selectedFunction === undefined) return console.error('No edge function selected') setSubmitting(true) try { await updateEdgeFunction({ projectRef, slug: selectedFunction.slug, payload: values, }) resetForm({ values, initialValues: values }) ui.setNotification({ category: 'success', message: `Successfully updated edge function` }) } catch (error: any) { ui.setNotification({ category: 'error', message: `Failed to update edge function: ${error.message}`, }) } finally { setSubmitting(false) } } const onConfirmDelete = async () => { if (!projectRef) return console.error('Project ref is required') if (selectedFunction === undefined) return console.error('No edge function selected') try { await deleteEdgeFunction({ projectRef, slug: selectedFunction.slug }) ui.setNotification({ category: 'success', message: `Successfully deleted "${selectedFunction.name}"`, }) router.push(`/project/${projectRef}/functions`) } catch (error: any) { ui.setNotification({ category: 'error', message: `Failed to delete function: ${error.message}`, }) } } return ( <>
{({ isSubmitting, handleReset, values, initialValues, resetForm }: any) => { const hasChanges = JSON.stringify(values) !== JSON.stringify(initialValues) // [Alaister] although this "technically" is breaking the rules of React hooks // it won't error because the hooks are always rendered in the same order // eslint-disable-next-line react-hooks/rules-of-hooks useEffect(() => { if (selectedFunction !== undefined) { const formValues = { name: selectedFunction?.name, verify_jwt: selectedFunction?.verify_jwt, } resetForm({ values: formValues, initialValues: formValues }) } }, [selectedFunction]) return ( <>
} > Function Details}> Function Configuration}>

Import maps are{' '} {selectedFunction?.import_map ? 'allowed' : 'disallowed'} {' '} for this function

Import maps allow the use of bare specifiers without having to install the Node.js package locally

) }}

Command line access

setShowInstructions(!showInstructions)}> {showInstructions ? ( ) : ( )}
Deployment management
Invoke
Secrets management

Make sure you have made a backup if you want to restore your edge function

{!canUpdateEdgeFunction && (
You need additional permissions to delete an edge function
)}
Confirm to delete {selectedFunction?.name}} visible={showDeleteModal} loading={isDeleting} onCancel={() => setShowDeleteModal(false)} onConfirm={onConfirmDelete} >
Ensure that you have made a backup if you want to restore your edge function
) } export default EdgeFunctionDetails