-
{generateCascadeActionDescription(
'update',
@@ -533,45 +524,60 @@ export const ForeignKeySelector = ({
)}
}
- onChange={(value: string) => updateCascadeAction('updateAction', value)}
+ className="gap-[2px]"
+ size="tiny"
>
- {FOREIGN_KEY_CASCADE_OPTIONS.filter((option) =>
- ['no-action', 'cascade', 'restrict'].includes(option.key)
- ).map((option) => (
-
- {option.label}
-
- ))}
-
-
-
updateCascadeAction('updateAction', value)}
+ >
+
+
+
+
+ {FOREIGN_KEY_CASCADE_OPTIONS.filter((option) =>
+ ['no-action', 'cascade', 'restrict'].includes(option.key)
+ ).map((option) => (
+
+ {option.label}
+
+ ))}
+
+
+
+
+ description={
+
+ {generateCascadeActionDescription(
+ 'delete',
+ fk.deletionAction,
+ `${fk.schema}.${fk.table}`
+ )}
+
}
- descriptionText={
- <>
-
- {generateCascadeActionDescription(
- 'delete',
- fk.deletionAction,
- `${fk.schema}.${fk.table}`
- )}
-
- >
- }
- onChange={(value: string) => updateCascadeAction('deletionAction', value)}
+ className="gap-[2px]"
+ size="tiny"
>
- {FOREIGN_KEY_CASCADE_OPTIONS.map((option) => (
-
- {option.label}
-
- ))}
-
+
updateCascadeAction('deletionAction', value)}
+ >
+
+
+
+
+ {FOREIGN_KEY_CASCADE_OPTIONS.map((option) => (
+
+ {option.label}
+
+ ))}
+
+
+
>
)}
>
diff --git a/apps/studio/pages/integrations/vercel/[slug]/deploy-button/new-project.tsx b/apps/studio/pages/integrations/vercel/[slug]/deploy-button/new-project.tsx
index 9fafeb0d27c..f24bbb298e1 100644
--- a/apps/studio/pages/integrations/vercel/[slug]/deploy-button/new-project.tsx
+++ b/apps/studio/pages/integrations/vercel/[slug]/deploy-button/new-project.tsx
@@ -3,7 +3,18 @@ import { useParams } from 'common'
import { ChangeEvent, useEffect, useState } from 'react'
import { AWS_REGIONS } from 'shared-data'
import { toast } from 'sonner'
-import { Alert, Button, Checkbox, Input, Listbox } from 'ui'
+import {
+ Alert,
+ Button,
+ Checkbox,
+ Input,
+ Select_Shadcn_,
+ SelectContent_Shadcn_,
+ SelectItem_Shadcn_,
+ SelectTrigger_Shadcn_,
+ SelectValue_Shadcn_,
+} from 'ui'
+import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
import { isVercelUrl } from '@/components/interfaces/Integrations/Vercel/VercelIntegration.utils'
import { Markdown } from '@/components/interfaces/Markdown'
@@ -65,7 +76,7 @@ const CreateProject = () => {
const [passwordStrengthMessage, setPasswordStrengthMessage] = useState('')
const [passwordStrengthScore, setPasswordStrengthScore] = useState(-1)
const [shouldRunMigrations, setShouldRunMigrations] = useState(true)
- const [dbRegion, setDbRegion] = useState(PROVIDERS.AWS.default_region.displayName)
+ const [dbRegion, setDbRegion] = useState
(PROVIDERS.AWS.default_region.displayName)
const track = useTrack()
const snapshot = useIntegrationInstallationSnapshot()
@@ -276,33 +287,38 @@ const CreateProject = () => {
diff --git a/e2e/studio/features/table-editor.spec.ts b/e2e/studio/features/table-editor.spec.ts
index e85d9f46ac4..1fc0bc481f3 100644
--- a/e2e/studio/features/table-editor.spec.ts
+++ b/e2e/studio/features/table-editor.spec.ts
@@ -1076,19 +1076,19 @@ testRunner('table editor', () => {
.click()
await page.getByRole('menuitem', { name: 'Edit table' }).click()
- // Open foreign key selector
- await page.getByRole('button', { name: 'Add foreign key relation' }).click()
-
- // Select schema (should default to public)
- await expect(page.getByRole('button', { name: 'Select a schema' })).toContainText('public')
-
// Select target table
const tableQueryPromise = waitForApiResponseWithTimeout(page, (response) =>
response.url().includes(`table-public-${targetTableName}`)
)
- await page.getByRole('button', { name: 'Select a table to reference to' }).click()
- await page.getByRole('menuitem', { name: `public ${targetTableName}` }).click()
+ // Open foreign key selector
+ await page.getByRole('button', { name: 'Add foreign key relation' }).click()
+
+ // Select schema (should default to public)
+ await expect(page.getByRole('combobox', { name: 'Select a schema' })).toContainText('public')
+
+ await page.getByRole('combobox', { name: 'Select a table to reference to' }).click()
+ await page.getByRole('option', { name: `public ${targetTableName}` }).click()
// Wait for table columns to load
await tableQueryPromise
@@ -1099,15 +1099,12 @@ testRunner('table editor', () => {
).toBeVisible()
// Select source column (id from source table)
- await page.getByRole('button', { name: '---' }).first().click()
- await page.getByRole('menuitem', { name: 'id int8' }).click()
-
- // Wait for the first dropdown to update - there should only be one '---' button left now
- await expect(page.getByRole('button', { name: '---' })).toHaveCount(1)
+ await page.getByRole('combobox', { name: 'Column from public.pw_table_fk_source' }).click()
+ await page.getByRole('option', { name: 'id int8' }).click()
// Select target column (id from target table)
- await page.getByRole('button', { name: '---' }).first().click()
- await page.getByRole('menuitem', { name: 'id int8' }).click()
+ await page.getByRole('combobox', { name: 'Column from public.pw_table_fk_target' }).click()
+ await page.getByRole('option', { name: 'id int8' }).click()
// Verify cascade action options are visible
await expect(page.getByText('Action if referenced row is updated')).toBeVisible()
diff --git a/packages/ui/index.tsx b/packages/ui/index.tsx
index 5fa82d80ca5..0c0058cc0f3 100644
--- a/packages/ui/index.tsx
+++ b/packages/ui/index.tsx
@@ -36,7 +36,6 @@ export * from './src/lib/utils'
// DATA ENTRY
-export * from './src/components/Listbox'
export * from './src/components/Input'
export * from './src/components/Toggle'
export * from './src/components/ExpandingTextArea'
diff --git a/packages/ui/src/components/Listbox/Listbox2.tsx b/packages/ui/src/components/Listbox/Listbox2.tsx
deleted file mode 100644
index 74122084c94..00000000000
--- a/packages/ui/src/components/Listbox/Listbox2.tsx
+++ /dev/null
@@ -1,288 +0,0 @@
-'use client'
-
-import { flatten } from 'lodash'
-import { Check } from 'lucide-react'
-import { DropdownMenu as DropdownMenuPrimitive } from 'radix-ui'
-import React, { useEffect, useRef, useState } from 'react'
-
-import { FormLayout } from '../../lib/Layout/FormLayout/FormLayout'
-import InputErrorIcon from '../../lib/Layout/InputErrorIcon'
-import InputIconContainer from '../../lib/Layout/InputIconContainer'
-import styleHandler from '../../lib/theme/styleHandler'
-import { cn } from '../../lib/utils/cn'
-import { SelectContext } from './SelectContext'
-
-export interface Props extends Omit
, 'size'> {
- className?: string
- buttonClassName?: string
- children: React.ReactNode
- descriptionText?: string | React.ReactNode
- error?: string
- icon?: any
- id?: string
- label?: string | React.ReactNode
- labelOptional?: string
- layout?: 'horizontal' | 'vertical'
- style?: React.CSSProperties
- value?: any
- reveal?: boolean
- actions?: React.ReactNode
- size?: 'tiny' | 'small' | 'medium' | 'large' | 'xlarge'
- defaultValue?: any
- validation?: (x: any) => void
- optionsWidth?: number
- // override the button prop for onchange we only return a single value
- // rather than a ChangeEvent
- onChange?: (x: any) => void
-}
-
-/**
- * @deprecated Use `import { Select_shadcn_ } from "ui"` or follow ComboBox convention or use ./ui-patterns/multi-select
- */
-function Listbox({
- children,
- className,
- buttonClassName,
- descriptionText,
- error,
- icon,
- id = '',
- name = '',
- label,
- labelOptional,
- layout,
- value = undefined,
- onChange,
- onFocus,
- onBlur,
- style,
- size = 'medium',
- defaultValue,
- disabled,
- optionsWidth,
-}: Props) {
- const [selected, setSelected] = useState(undefined)
- const [selectedNode, setSelectedNode] = useState({})
-
- const __styles = styleHandler('listbox')
-
- const triggerRef = useRef(null)
-
- useEffect(() => {
- if (value !== undefined) {
- setSelected(value)
- }
- }, [value])
-
- useEffect(() => {
- // handle listbox options width size
-
- function handleResize() {
- // Set window width/height to state
-
- // [Joshen] Note this causes some style conflicts if there are multiple listboxes
- // rendered on the same page. All listbox option widths will be that of the latest
- // listbox component that got rendered, rather than following its parent
- document.documentElement.style.setProperty(
- '--width-listbox',
- `${optionsWidth ? optionsWidth : triggerRef.current?.offsetWidth}px`
- )
- }
-
- // Add event listener
- window.addEventListener('resize', handleResize)
-
- // Call handler right away so state gets updated with initial window size
- handleResize()
-
- // Remove event listener on cleanup
- return () => window.removeEventListener('resize', handleResize)
- }, [])
-
- useEffect(() => {
- const data: any = children
- const content: any = flatten(data)
-
- function findNode(_value: any) {
- return content.find((node: any) => node.props.value === _value)
- }
-
- /*
- * value prop overrides everything
- */
- if (value) {
- setSelected(value)
- const node: any = findNode(value)
- setSelectedNode(node?.props ? node.props : undefined)
- return
- }
-
- /*
- * if no value prop, then use selected state
- */
- if (selected) {
- const node: any = findNode(selected)
- setSelectedNode(node?.props ? node.props : undefined)
- return
- } else if (defaultValue) {
- setSelected(defaultValue)
- const node: any = findNode(defaultValue)
- setSelectedNode(node?.props ? node.props : undefined)
- return
- } else {
- /*
- * if no selected value (including a `defaultvalue`), then use first child
- */
- setSelectedNode(content[0]?.props)
- return
- }
- }, [selected])
-
- function handleOnChange(value: any) {
- if (onChange) onChange(value)
- setSelected(value)
- }
-
- let selectClasses = [__styles.container, __styles.base, buttonClassName]
- let addonBeforeClasses = [__styles.addOnBefore]
-
- if (error) selectClasses.push(__styles.variants.error)
- if (!error) selectClasses.push(__styles.variants.standard)
- // if (icon) selectClasses.push(SelectStyles['sbui-listbox--with-icon'])
- if (icon) addonBeforeClasses.push(__styles.with_icon[size])
- // if (size) selectClasses.push(SelectStyles[`sbui-listbox--${size}`])
- if (size) selectClasses.push(__styles.size[size])
- // if (borderless) selectClasses.push(SelectStyles['sbui-listbox--borderless'])
- if (disabled) selectClasses.push(__styles.disabled)
-
- return (
-
-
-
-
-
-
-
-
- {children}
-
-
-
-
-
- )
-}
-
-interface OptionProps {
- id?: string
- value: any
- label: string
- disabled?: boolean
- children?: React.ReactNode | (({ active, selected }: any) => React.ReactNode)
- className?: string
- addOnBefore?: ({ active, selected }: any) => React.ReactNode
-}
-
-/**
- * @deprecated Use ./Select_shadcn_ or follow ComboBox convention or use ./ui-patterns/multi-select
- */
-function SelectOption({
- id,
- value,
- disabled = false,
- children,
- className = '',
- addOnBefore,
-}: OptionProps) {
- const __styles = styleHandler('listbox')
-
- return (
-
- {({ onChange, selected }) => {
- const active = selected === value ? true : false
-
- return (
- (!disabled ? onChange(value) : {})}
- >
-
- {addOnBefore && addOnBefore({ active, selected })}
-
- {typeof children === 'function' ? children({ active, selected }) : children}
-
-
-
- {active ? (
-
-
-
- ) : null}
-
- )
- }}
-
- )
-}
-
-Listbox.Option = SelectOption
-
-export default Listbox
diff --git a/packages/ui/src/components/Listbox/SelectContext.tsx b/packages/ui/src/components/Listbox/SelectContext.tsx
deleted file mode 100644
index 754cbddf4f6..00000000000
--- a/packages/ui/src/components/Listbox/SelectContext.tsx
+++ /dev/null
@@ -1,8 +0,0 @@
-import { createContext } from 'react'
-
-// Make sure the shape of the default value passed to
-// createContext matches the shape that the consumers expect!
-export const SelectContext = createContext({
- onChange: (_e: any) => {},
- selected: undefined,
-})
diff --git a/packages/ui/src/components/Listbox/SelectStyled.module.css b/packages/ui/src/components/Listbox/SelectStyled.module.css
deleted file mode 100644
index aa9941d73a9..00000000000
--- a/packages/ui/src/components/Listbox/SelectStyled.module.css
+++ /dev/null
@@ -1,145 +0,0 @@
-/* .sbui-listbox-container {
- @apply relative;
-} */
-
-/* .sbui-listbox {
- @apply block w-full bg-white pl-3 pr-10 py-2 text-sm rounded-md transition-all;
- @apply text-gray-700 border border-solid border-gray-300;
- @apply cursor-default focus:outline-none focus:ring-1 focus:ring-brand-600 focus:border-brand-600;
- @apply dark:bg-transparent dark:text-white dark:border-gray-500;
- @apply dark:focus:border-brand-300;
- -webkit-appearance: none;
- -moz-appearance: none;
- text-indent: 1px;
- text-overflow: '';
- box-shadow: 0 0 0 2px rgba(255, 255, 255, 0);
- transition: box-shadow 0.3s ease-in-out; */
-
-/* // temporary fix
- //
- // temporary fix for supabase apps
- // tailwind @base styles adds a dropdown chevron
- // using background image as default
- // */
-/* background-image: none;
-} */
-
-.sbui-listbox:focus {
- box-shadow: 0 0 0 2px rgba(62, 207, 142, 0.1);
-}
-
-.sbui-listbox--error {
- @apply border-red-500;
-}
-
-.sbui-listbox--borderless {
- @apply border-transparent shadow-none;
-}
-
-/*
- Select sizes
-*/
-
-/* .sbui-listbox--tiny {
- @apply px-2.5 py-1.5 text-xs;
-}
-.sbui-listbox--small {
- @apply px-3 py-2 text-sm leading-4;
-}
-.sbui-listbox--medium {
- @apply px-4 py-2 text-sm;
-}
-.sbui-listbox--large {
- @apply px-4 py-2 text-base;
-}
-.sbui-listbox--xlarge {
- @apply px-6 py-3 text-base;
-} */
-
-/* .sbui-listbox-actions-container {
- @apply absolute inset-y-0 right-0 pl-3 pr-1 mr-5 flex items-center;
-} */
-
-/*
- Select icon
-*/
-
-/* .sbui-listbox--with-icon {
- @apply pl-7;
-} */
-
-/*
- Add on before
-*/
-
-/* .sbui-listbox-addonbefore {
- @apply w-full flex flex-row items-center space-x-3;
-} */
-
-.sbui-listbox-label {
- @apply truncate;
-}
-
-/*
- Select Chevron
-*/
-
-.sbui-listbox-chevron-container {
- @apply absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none;
-}
-
-.sbui-listbox-chevron {
- @apply h-5 w-5 text-gray-400;
-}
-
-/*
- Option
-*/
-
-/* .sbui-listbox-option-container {
- @apply list-none p-0 absolute mt-1 w-full bg-white dark:bg-gray-800 shadow-lg border border-solid border-control max-h-60 rounded-md py-1 text-base ring-1 ring-black/5 overflow-auto focus:outline-none sm:text-sm z-10;
-} */
-
-/* .sbui-listbox-option {
- @apply cursor-pointer select-none relative py-2 pl-3 pr-9 text-gray-900 dark:text-white;
-} */
-
-/* .sbui-listbox-option--active {
- @apply text-brand-600 dark:text-brand-600 bg-brand-600/20;
-}
-
-.sbui-listbox-option--disabled {
- @apply cursor-not-allowed opacity-50;
-} */
-
-/* .sbui-listbox-option__inner {
- @apply flex items-center space-x-3;
-} */
-
-/* .sbui-listbox-option__check {
- @apply absolute inset-y-0 right-0 flex items-center pr-3;
-}
-
-.sbui-listbox-option__check--active {
- @apply text-brand-600;
-} */
-
-.sbui-listbox-option__check__icon {
- @apply h-5 w-5;
-}
-
-/*
- Transition
-*/
-
-.sbui-listbox-transition--leave {
- @apply transition ease-in duration-100;
-}
-
-.sbui-listbox-transition--leave-from {
- @apply opacity-100;
-}
-
-.sbui-listbox-transition--leave-to {
- @apply opacity-0;
-}
diff --git a/packages/ui/src/components/Listbox/SelectStyled.test.jsx b/packages/ui/src/components/Listbox/SelectStyled.test.jsx
deleted file mode 100644
index cdd90f083c6..00000000000
--- a/packages/ui/src/components/Listbox/SelectStyled.test.jsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import { render, screen } from '@testing-library/react'
-import React from 'react'
-import { describe, expect, it } from 'vitest'
-
-import Select from './index'
-
-describe('#Select', () => {
- it.skip('should render select correctly', async () => {
- render(
-
- )
- expect(screen.queryByTestId('form-select')).toBeInTheDocument()
- })
-
- it.skip('should have "form-select--error" class', () => {
- render(
-
- )
- expect(screen.queryByTestId('form-select')).toHaveClass(
- 'form-select border-solid form-select--error'
- )
- })
-})
diff --git a/packages/ui/src/components/Listbox/index.tsx b/packages/ui/src/components/Listbox/index.tsx
deleted file mode 100644
index 5bbc0008547..00000000000
--- a/packages/ui/src/components/Listbox/index.tsx
+++ /dev/null
@@ -1,4 +0,0 @@
-import Listbox from './Listbox2'
-
-export default Listbox
-export { default as Listbox } from './Listbox2'