From 442ace2c42b35e5210a4e75bc07fa0500e1cfff2 Mon Sep 17 00:00:00 2001 From: Danny White <3104761+dnywh@users.noreply.github.com> Date: Mon, 31 Aug 2026 16:53:47 +1000 Subject: [PATCH] trim redundant wizard foundations --- .../content/docs/copywriting.mdx | 2 +- .../example/form-patterns-pagelayout.tsx | 2 +- .../example/form-patterns-sidepanel.tsx | 2 +- .../DestinationFormFieldCopy.ts | 4 +- .../DestinationForm/PublicationSelect.tsx | 167 ------------------ .../DestinationForm/PublicationSelection.tsx | 9 +- .../DestinationForm/PublicationsComboBox.tsx | 167 ++++++++++++++++++ 7 files changed, 176 insertions(+), 177 deletions(-) delete mode 100644 apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationForm/PublicationSelect.tsx create mode 100644 apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationForm/PublicationsComboBox.tsx diff --git a/apps/design-system/content/docs/copywriting.mdx b/apps/design-system/content/docs/copywriting.mdx index b986af5d58a..4709faa48fe 100644 --- a/apps/design-system/content/docs/copywriting.mdx +++ b/apps/design-system/content/docs/copywriting.mdx @@ -127,7 +127,7 @@ Supabase UI copy is: ### Use title case for page titles and global navigation -Use title case for page names in the main nav and document titles (e.g. "Database Settings", "Project Settings"). This includes browser tab titles set via the `browserTitle` prop on layout components (e.g. "New Pipeline", not "New pipeline"). +Use title case for page names in the main nav and document titles (e.g. "Database Settings", "Project Settings"). This distinguishes the page as a destination from section labels and in-page headings, which use sentence case. ### Use declarative page descriptions diff --git a/apps/design-system/registry/default/example/form-patterns-pagelayout.tsx b/apps/design-system/registry/default/example/form-patterns-pagelayout.tsx index 270c6320bd5..42deb0f33d0 100644 --- a/apps/design-system/registry/default/example/form-patterns-pagelayout.tsx +++ b/apps/design-system/registry/default/example/form-patterns-pagelayout.tsx @@ -252,7 +252,7 @@ export default function FormPatternsPageLayout() { - milliseconds + ms diff --git a/apps/design-system/registry/default/example/form-patterns-sidepanel.tsx b/apps/design-system/registry/default/example/form-patterns-sidepanel.tsx index e8e6af1d1a9..1b3a146e357 100644 --- a/apps/design-system/registry/default/example/form-patterns-sidepanel.tsx +++ b/apps/design-system/registry/default/example/form-patterns-sidepanel.tsx @@ -265,7 +265,7 @@ export default function FormPatternsSidePanel() { - milliseconds + ms diff --git a/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationForm/DestinationFormFieldCopy.ts b/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationForm/DestinationFormFieldCopy.ts index 220541d9270..fd69f9b8d5c 100644 --- a/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationForm/DestinationFormFieldCopy.ts +++ b/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationForm/DestinationFormFieldCopy.ts @@ -40,12 +40,12 @@ export const getDestinationTypeCreateDescription = (type: DestinationType) => { export const BIGQUERY_PROJECT_ID_FIELD_COPY = { label: 'Project ID', - description: 'Google Cloud project ID where data will be sent.', + description: 'The Google Cloud project ID where data will be sent', } as const export const BIGQUERY_DATASET_ID_FIELD_COPY = { label: 'Dataset ID', - description: 'BigQuery dataset where replicated tables will be created.', + description: 'The BigQuery dataset where replicated tables will be created', } as const export const ANALYTICS_BUCKET_BUCKET_FIELD_COPY = { diff --git a/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationForm/PublicationSelect.tsx b/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationForm/PublicationSelect.tsx deleted file mode 100644 index a55089f0d58..00000000000 --- a/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationForm/PublicationSelect.tsx +++ /dev/null @@ -1,167 +0,0 @@ -import { useParams } from 'common' -import { Check, Loader2, Plus } from 'lucide-react' -import { useId, useState } from 'react' -import { ControllerRenderProps } from 'react-hook-form' -import { - cn, - ComboboxTrigger, - Command, - CommandEmpty, - CommandGroup, - CommandInput, - CommandItem, - CommandList, - CommandSeparator, - Popover, - PopoverContent, - PopoverTrigger, - ScrollArea, -} from 'ui' -import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader' - -import type { DestinationPanelSchemaType } from './DestinationForm.schema' -import { useReplicationPublicationsQuery } from '@/data/replication/publications-query' - -interface PublicationSelectProps { - sourceId?: number - field: ControllerRenderProps - onNewPublicationClick: () => void -} - -export const PublicationSelect = ({ - sourceId, - field, - onNewPublicationClick, -}: PublicationSelectProps) => { - const { ref: projectRef } = useParams() - const listboxId = useId() - const [open, setOpen] = useState(false) - const selectedPublication = field.value ?? '' - - const { - data: publications = [], - isPending, - isFetching, - refetch: refetchPublications, - } = useReplicationPublicationsQuery({ projectRef, sourceId }) - const isLoadingPublications = isPending || isFetching - const showLoadingState = isLoadingPublications && publications.length === 0 - - const handlePublicationSelect = (publicationName: string) => { - setOpen(false) - field.onChange(publicationName) - } - - return ( - { - setOpen(nextOpen) - if (nextOpen) { - if (typeof projectRef !== 'undefined' && typeof sourceId !== 'undefined') { - refetchPublications() - } - } - - if (!nextOpen) { - field.onBlur() - } - }} - > - - - ) : undefined - } - > - {showLoadingState - ? 'Loading publications...' - : selectedPublication || 'Select publication'} - - - - - - - No publications found - - {showLoadingState ? ( - - - - ) : ( - <> - {publications.length === 0 ? ( - - No publications available - Publications with no tables are hidden - - ) : ( - - 7 ? 'h-[210px]' : ''} - onWheel={(event) => event.stopPropagation()} - > - {publications.map((pub) => ( - { - handlePublicationSelect(pub.name) - }} - > - - - {pub.name} - - {pub.tables.length} {pub.tables.length === 1 ? 'table' : 'tables'} - - - - - - ))} - - - )} - - - - - { - setOpen(false) - onNewPublicationClick() - }} - > - - New publication - - - > - )} - - - - - ) -} diff --git a/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationForm/PublicationSelection.tsx b/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationForm/PublicationSelection.tsx index 9eaebb92380..e0ac6818d71 100644 --- a/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationForm/PublicationSelection.tsx +++ b/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationForm/PublicationSelection.tsx @@ -6,8 +6,7 @@ import { Admonition } from 'ui-patterns/Admonition' import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' import type { DestinationPanelSchemaType } from './DestinationForm.schema' -import { PUBLICATION_FIELD_COPY } from './DestinationFormFieldCopy' -import { PublicationSelect } from './PublicationSelect' +import { PublicationsComboBox } from './PublicationsComboBox' import { useReplicationPublicationsQuery } from '@/data/replication/publications-query' import { useReplicationSourceId } from '@/data/replication/sources-query' @@ -41,11 +40,11 @@ export const PublicationSelection = ({ render={({ field }) => ( - { diff --git a/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationForm/PublicationsComboBox.tsx b/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationForm/PublicationsComboBox.tsx new file mode 100644 index 00000000000..2e6e8f70144 --- /dev/null +++ b/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationForm/PublicationsComboBox.tsx @@ -0,0 +1,167 @@ +import { useParams } from 'common' +import { Check, ChevronsUpDown, Loader2, Plus } from 'lucide-react' +import { useEffect, useState } from 'react' +import { ControllerRenderProps } from 'react-hook-form' +import { + Badge, + Button, + cn, + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, + CommandSeparator, + Popover, + PopoverContent, + PopoverTrigger, + ScrollArea, +} from 'ui' +import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader' + +import type { DestinationPanelSchemaType } from './DestinationForm.schema' +import { useReplicationPublicationsQuery } from '@/data/replication/publications-query' + +interface PublicationsComboBoxProps { + sourceId?: number + field: ControllerRenderProps + onNewPublicationClick: () => void +} + +export const PublicationsComboBox = ({ + sourceId, + field, + onNewPublicationClick, +}: PublicationsComboBoxProps) => { + const { ref: projectRef } = useParams() + + const [searchTerm, setSearchTerm] = useState('') + const [dropdownOpen, setDropdownOpen] = useState(false) + const [selectedPublication, setSelectedPublication] = useState(field?.value || '') + + const { + data: publications = [], + isPending, + isFetching, + refetch: refetchPublications, + } = useReplicationPublicationsQuery({ projectRef, sourceId }) + const isLoadingPublications = isPending || isFetching + const showLoadingState = isLoadingPublications && publications.length === 0 + + function handlePublicationSelect(pub: string) { + setSelectedPublication(pub) + setDropdownOpen(false) + field.onChange(pub) + } + + useEffect(() => { + setSelectedPublication(field?.value || '') + }, [field?.value]) + + return ( + { + setDropdownOpen(open) + if (open) { + if (typeof projectRef !== 'undefined' && typeof sourceId !== 'undefined') { + refetchPublications() + } + } + + if (!open && field?.onBlur) { + field.onBlur() + } + }} + > + + span]:w-full text-left', + !selectedPublication && 'text-foreground-muted' + )} + iconRight={showLoadingState ? : } + name={field.name} + onBlur={field.onBlur} + > + {selectedPublication || 'Select publication'} + + + + + + + No publications found + + {showLoadingState && ( + + + + )} + + + {publications.length === 0 && !showLoadingState && ( + + No publications available + Publications with no tables are hidden + + )} + 7 ? 'h-[210px]' : ''} + onWheel={(e) => e.stopPropagation()} + > + {publications.map((pub) => ( + { + handlePublicationSelect(pub.name) + }} + onClick={() => { + handlePublicationSelect(pub.name) + }} + > + {pub.name} + + + {pub.tables.length} {pub.tables.length === 1 ? 'table' : 'tables'} + + {selectedPublication === pub.name && ( + + )} + + + ))} + + + + + + + + + New publication + + + + + + + ) +}
No publications available
Publications with no tables are hidden
{pub.name}
- {pub.tables.length} {pub.tables.length === 1 ? 'table' : 'tables'} -
New publication