From 92bcdcd953ccd285548196ddef49a106678e6942 Mon Sep 17 00:00:00 2001 From: Danny White <3104761+dnywh@users.noreply.github.com> Date: Wed, 11 Feb 2026 16:40:33 +1100 Subject: [PATCH] Update delete-organization dialog to TextConfirmModal (#42670) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What kind of change does this PR introduce? - ~Feat~ Chore - Resolves DEPR-33 ## What is the current behavior? The dialog used to delete an organization uses a ”type this org’s name in before you can press this button” interaction but: - A) Enables the button the whole time - B) We already have this componentized in TextConfirmModal ## What is the new behavior? - Refactored this dialog to use `TextConfirmModal` instead - Updated design docs to make this prop clearer | Before | After | | --- | --- | | Supabase | Supabase | ## Summary by CodeRabbit * **Documentation** * Updated Text Confirm Dialog documentation with clarifications: the confirm action remains disabled until input exactly matches the required string, and leading/trailing whitespace is trimmed from the input. * **Refactor** * Streamlined the organization deletion confirmation workflow for improved user experience. --- .../docs/fragments/text-confirm-dialog.mdx | 2 +- .../content/docs/ui-patterns/modality.mdx | 2 +- .../DeleteOrganizationButton.tsx | 98 +++++-------------- 3 files changed, 26 insertions(+), 76 deletions(-) diff --git a/apps/design-system/content/docs/fragments/text-confirm-dialog.mdx b/apps/design-system/content/docs/fragments/text-confirm-dialog.mdx index 4b812ead978..12f90b69c7a 100644 --- a/apps/design-system/content/docs/fragments/text-confirm-dialog.mdx +++ b/apps/design-system/content/docs/fragments/text-confirm-dialog.mdx @@ -53,7 +53,7 @@ export default function TextConfirmDialogDemo() { ## Props -- `confirmString`: The exact string the user must type to enable the confirm action +- `confirmString`: The exact string the user must type to enable the confirm action (leading/trailing whitespace is trimmed) - `confirmPlaceholder`: Placeholder text shown in the confirmation input - `variant`: Visual intent of the dialog (`default`, `destructive`, or `warning`) - Other standard modal props inherited from the underlying [Dialog](../components/dialog) component diff --git a/apps/design-system/content/docs/ui-patterns/modality.mdx b/apps/design-system/content/docs/ui-patterns/modality.mdx index 3da04913adf..3f593a0eb8e 100644 --- a/apps/design-system/content/docs/ui-patterns/modality.mdx +++ b/apps/design-system/content/docs/ui-patterns/modality.mdx @@ -43,7 +43,7 @@ There are quite a few dialog components, each suited to a different task or cont #### Text Confirm Dialog -[Text Confirm Dialog](../fragments/text-confirm-dialog) adds a deliberate speed bump for highly destructive actions by requiring the user to type an exact confirmation string before proceeding. +[Text Confirm Dialog](../fragments/text-confirm-dialog) adds a deliberate speed bump for highly destructive actions by requiring the user to type an exact confirmation string before proceeding. The confirm action remains disabled until the input matches. diff --git a/apps/studio/components/interfaces/Organization/GeneralSettings/DeleteOrganizationButton.tsx b/apps/studio/components/interfaces/Organization/GeneralSettings/DeleteOrganizationButton.tsx index 8f183a61719..759774d3269 100644 --- a/apps/studio/components/interfaces/Organization/GeneralSettings/DeleteOrganizationButton.tsx +++ b/apps/studio/components/interfaces/Organization/GeneralSettings/DeleteOrganizationButton.tsx @@ -9,7 +9,7 @@ import { useOrganizationDeleteMutation } from 'data/organizations/organization-d import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions' import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage' import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization' -import { Button, Form, Input, Modal } from 'ui' +import { TextConfirmModal } from 'components/ui/TextConfirmModalWrapper' export const DeleteOrganizationButton = () => { const router = useRouter() @@ -17,7 +17,6 @@ export const DeleteOrganizationButton = () => { const { slug: orgSlug, name: orgName } = selectedOrganization ?? {} const [isOpen, setIsOpen] = useState(false) - const [value, setValue] = useState('') const [_, setLastVisitedOrganization] = useLocalStorageQuery( LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION, @@ -37,23 +36,15 @@ export const DeleteOrganizationButton = () => { }, }) - const onValidate = (values: any) => { - const errors: any = {} - if (!values.orgName) { - errors.orgName = 'Enter the name of the organization.' - } - if (values.orgName.trim() !== orgSlug?.trim()) { - errors.orgName = 'Value entered does not match the value above.' - } - return errors - } - - const onConfirmDelete = async (values: any) => { + const onConfirmDelete = () => { if (!canDeleteOrganization) { - return toast.error('You do not have the required permissions to delete this organization') + toast.error('You do not have permission to delete this organization') + return + } + if (!orgSlug) { + console.error('Org slug is required') + return } - if (!orgSlug) return console.error('Org slug is required') - deleteOrganization({ slug: orgSlug }) } @@ -62,7 +53,7 @@ export const DeleteOrganizationButton = () => {
setIsOpen(true)} tooltip={{ @@ -77,65 +68,24 @@ export const DeleteOrganizationButton = () => { Delete organization
- setIsOpen(false)} - header={ -
- Delete organization - Are you sure? -
- } > -
- {() => ( - <> - -

- This action cannot be undone. This will - permanently delete the {orgName}{' '} - organization and remove all of its projects. -

-
- - - - Please type {orgSlug} to confirm - - } - onChange={(e) => setValue(e.target.value)} - value={value} - placeholder="Enter the string above" - className="w-full" - /> - - - - - - - )} - -
+

+ This action cannot be undone. This will + permanently delete the {orgName} organization and + remove all of its projects. +

+ ) }