IntrospectionConfirmModal.tsx119 lines · main
| 1 | import { type SafeSqlFragment } from '@supabase/pg-meta' |
| 2 | import type { ReactNode } from 'react' |
| 3 | import { CodeBlock } from 'ui-patterns/CodeBlock' |
| 4 | import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' |
| 5 | |
| 6 | type IntrospectionMode = 'enable' | 'disable' |
| 7 | |
| 8 | interface ModeCopy { |
| 9 | title: string |
| 10 | confirmLabel: string |
| 11 | confirmLabelLoading: string |
| 12 | persistenceBullet: (schema: string) => ReactNode |
| 13 | securityBullet: ReactNode |
| 14 | } |
| 15 | |
| 16 | const COPY: Record<IntrospectionMode, ModeCopy> = { |
| 17 | enable: { |
| 18 | title: 'Enable GraphQL introspection?', |
| 19 | confirmLabel: 'Enable introspection', |
| 20 | confirmLabelLoading: 'Enabling...', |
| 21 | persistenceBullet: (_schema) => <>This setting persists until explicitly disabled.</>, |
| 22 | securityBullet: ( |
| 23 | <> |
| 24 | External actors will be able to introspect your schema using the <code>anon</code> key. |
| 25 | </> |
| 26 | ), |
| 27 | }, |
| 28 | disable: { |
| 29 | title: 'Disable GraphQL introspection?', |
| 30 | confirmLabel: 'Disable introspection', |
| 31 | confirmLabelLoading: 'Disabling...', |
| 32 | persistenceBullet: (_schema) => <>This setting persists until explicitly re-enabled.</>, |
| 33 | securityBullet: ( |
| 34 | <> |
| 35 | External actors will no longer be able to introspect your schema via the <code>anon</code>{' '} |
| 36 | key. GraphiQL's docs explorer and autocomplete will stop working until introspection is |
| 37 | re-enabled. |
| 38 | </> |
| 39 | ), |
| 40 | }, |
| 41 | } |
| 42 | |
| 43 | interface IntrospectionConfirmModalProps { |
| 44 | mode: IntrospectionMode |
| 45 | visible: boolean |
| 46 | schema: string |
| 47 | sql: SafeSqlFragment |
| 48 | otherExistingKeys: string[] |
| 49 | existingDirectiveIsMalformed: boolean |
| 50 | isPending: boolean |
| 51 | onCancel: () => void |
| 52 | onConfirm: () => void |
| 53 | } |
| 54 | |
| 55 | export const IntrospectionConfirmModal = ({ |
| 56 | mode, |
| 57 | visible, |
| 58 | schema, |
| 59 | sql, |
| 60 | otherExistingKeys, |
| 61 | existingDirectiveIsMalformed, |
| 62 | isPending, |
| 63 | onCancel, |
| 64 | onConfirm, |
| 65 | }: IntrospectionConfirmModalProps) => { |
| 66 | const copy = COPY[mode] |
| 67 | const hasPreservedOptions = otherExistingKeys.length > 0 |
| 68 | |
| 69 | return ( |
| 70 | <ConfirmationModal |
| 71 | visible={visible} |
| 72 | size="large" |
| 73 | title={copy.title} |
| 74 | confirmLabel={copy.confirmLabel} |
| 75 | confirmLabelLoading={copy.confirmLabelLoading} |
| 76 | cancelLabel="Cancel" |
| 77 | loading={isPending} |
| 78 | onCancel={onCancel} |
| 79 | onConfirm={onConfirm} |
| 80 | > |
| 81 | <div className="space-y-4 text-sm"> |
| 82 | <ul className="list-disc space-y-1 pl-5 text-foreground-light"> |
| 83 | <li>{copy.persistenceBullet(schema)}</li> |
| 84 | <li>{copy.securityBullet}</li> |
| 85 | {hasPreservedOptions && ( |
| 86 | <li> |
| 87 | Existing <code>@graphql(...)</code> options on this schema will be preserved:{' '} |
| 88 | <PreservedOptionKeys keys={otherExistingKeys} />. |
| 89 | </li> |
| 90 | )} |
| 91 | {existingDirectiveIsMalformed && ( |
| 92 | <li className="text-warning"> |
| 93 | The existing <code>@graphql(...)</code> directive on this schema could not be parsed |
| 94 | and will be replaced by the statement below. |
| 95 | </li> |
| 96 | )} |
| 97 | </ul> |
| 98 | |
| 99 | <div> |
| 100 | <p className="text-foreground-light mb-2">The following statement will be executed:</p> |
| 101 | <CodeBlock language="sql" className="text-xs" hideLineNumbers> |
| 102 | {sql} |
| 103 | </CodeBlock> |
| 104 | </div> |
| 105 | </div> |
| 106 | </ConfirmationModal> |
| 107 | ) |
| 108 | } |
| 109 | |
| 110 | const PreservedOptionKeys = ({ keys }: { keys: string[] }) => ( |
| 111 | <> |
| 112 | {keys.map((k, i) => ( |
| 113 | <span key={k}> |
| 114 | {i > 0 && ', '} |
| 115 | <code>{k}</code> |
| 116 | </span> |
| 117 | ))} |
| 118 | </> |
| 119 | ) |