IntrospectionConfirmModal.tsx 3.4 KB

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