From 0bfd6519437e45c043b8e94f7022dbbe59293e38 Mon Sep 17 00:00:00 2001
From: David Crespo
Date: Thu, 11 Apr 2024 14:28:27 -0500
Subject: [PATCH 1/2] clean up profile page visually. it doesn't need to be a
form
---
app/pages/settings/ProfilePage.tsx | 63 ++++++++++++------------------
app/ui/lib/CopyToClipboard.tsx | 18 ++++++---
test/e2e/profile.e2e.ts | 3 +-
3 files changed, 40 insertions(+), 44 deletions(-)
diff --git a/app/pages/settings/ProfilePage.tsx b/app/pages/settings/ProfilePage.tsx
index 8cfa3aa2f5..f2f046ba57 100644
--- a/app/pages/settings/ProfilePage.tsx
+++ b/app/pages/settings/ProfilePage.tsx
@@ -10,12 +10,13 @@ import { createColumnHelper, getCoreRowModel, useReactTable } from '@tanstack/re
import type { Group } from '@oxide/api'
import { Settings24Icon } from '@oxide/design-system/icons/react'
-import { TextField } from '~/components/form/fields/TextField'
-import { FullPageForm } from '~/components/form/FullPageForm'
-import { useForm } from '~/hooks'
import { useCurrentUser } from '~/layouts/AuthenticatedLayout'
import { getActionsCol } from '~/table/columns/action-col'
import { Table } from '~/table/Table'
+import { CopyToClipboard } from '~/ui/lib/CopyToClipboard'
+import { PageHeader, PageTitle } from '~/ui/lib/PageHeader'
+import { PropertiesTable } from '~/ui/lib/PropertiesTable'
+import { TableControls, TableTitle } from '~/ui/lib/Table'
const colHelper = createColumnHelper()
@@ -34,42 +35,30 @@ export function ProfilePage() {
getCoreRowModel: getCoreRowModel(),
})
- const form = useForm({
- defaultValues: {
- id: me.id,
- },
- })
-
return (
- }
- submitError={null}
- onSubmit={() => Promise.resolve()}
- >
-
- Groups
-
-
- Your user information is managed by your organization.
+ <>
+
+ }>Profile
+
+
+
+ {me.displayName}
+
+ {me.id}
+
+
+
+
+
+ Groups
+
+
+
+ Your user information is managed by your organization.{' '}
- To update, contact your{' '}
-
- IDP admin
-
- .
+ To update your information, contact your administrator.
-
-
+
+ >
)
}
diff --git a/app/ui/lib/CopyToClipboard.tsx b/app/ui/lib/CopyToClipboard.tsx
index cb411b2142..71a707de49 100644
--- a/app/ui/lib/CopyToClipboard.tsx
+++ b/app/ui/lib/CopyToClipboard.tsx
@@ -14,13 +14,17 @@ import { Copy12Icon, Success12Icon } from '@oxide/design-system/icons/react'
import { useTimeout } from './use-timeout'
-export const CopyToClipboard = ({
- ariaLabel = 'Click to copy this text',
- text,
-}: {
+type Props = {
ariaLabel?: string
text: string
-}) => {
+ className?: string
+}
+
+export const CopyToClipboard = ({
+ ariaLabel = 'Click to copy',
+ text,
+ className,
+}: Props) => {
const [hasCopied, setHasCopied] = useState(false)
useTimeout(() => setHasCopied(false), hasCopied ? 2000 : null)
@@ -46,7 +50,9 @@ export const CopyToClipboard = ({
'relative h-5 w-5 rounded',
hasCopied
? 'text-accent bg-accent-secondary'
- : 'text-quaternary hover:text-secondary hover:bg-hover'
+ : 'text-quaternary hover:text-secondary hover:bg-hover',
+
+ className
)}
onClick={handleCopy}
type="button"
diff --git a/test/e2e/profile.e2e.ts b/test/e2e/profile.e2e.ts
index e94ef6ad43..7dd4b517ed 100644
--- a/test/e2e/profile.e2e.ts
+++ b/test/e2e/profile.e2e.ts
@@ -11,6 +11,7 @@ import { expect, test } from './utils'
test('Profile page works', async ({ page }) => {
await page.goto('/settings/profile')
- await expect(page.getByRole('textbox', { name: 'User ID' })).toHaveValue(user1.id)
+ await expect(page.getByText('User ID')).toBeVisible()
+ await expect(page.getByText(user1.id)).toBeVisible()
await expect(page.getByRole('cell', { name: 'web-devs' })).toBeVisible()
})
From a4b048fcf193255772a9daca6c6aec99cf1a76ba Mon Sep 17 00:00:00 2001
From: David Crespo
Date: Thu, 11 Apr 2024 14:57:47 -0500
Subject: [PATCH 2/2] don't use toast. just add toast, remove toast. be toast
---
app/components/ToastStack.tsx | 5 ++---
app/forms/disk-create.tsx | 4 ++--
app/forms/floating-ip-create.tsx | 4 ++--
app/forms/floating-ip-edit.tsx | 4 ++--
app/forms/idp/create.tsx | 4 ++--
app/forms/instance-create.tsx | 4 ++--
app/forms/ip-pool-edit.tsx | 4 ++--
app/forms/project-edit.tsx | 4 ++--
app/forms/silo-create.tsx | 4 ++--
app/forms/snapshot-create.tsx | 4 ++--
app/forms/vpc-create.tsx | 4 ++--
app/forms/vpc-edit.tsx | 4 ++--
app/hooks/index.ts | 1 -
app/hooks/use-toast.ts | 10 ----------
app/pages/LoginPage.tsx | 6 +++---
app/pages/project/disks/DisksPage.tsx | 6 +++---
app/pages/project/images/ImagesPage.tsx | 6 +++---
app/pages/system/SiloImagesPage.tsx | 6 +++---
app/stores/toast.ts | 19 +++++--------------
19 files changed, 41 insertions(+), 62 deletions(-)
delete mode 100644 app/hooks/use-toast.ts
diff --git a/app/components/ToastStack.tsx b/app/components/ToastStack.tsx
index 7d87a0cbed..56d5c9a4b5 100644
--- a/app/components/ToastStack.tsx
+++ b/app/components/ToastStack.tsx
@@ -7,12 +7,11 @@
*/
import { animated, useTransition } from '@react-spring/web'
-import { useToastStore } from '~/stores/toast'
+import { removeToast, useToastStore } from '~/stores/toast'
import { Toast } from '~/ui/lib/Toast'
export function ToastStack() {
const toasts = useToastStore((state) => state.toasts)
- const remove = useToastStore((state) => state.remove)
const transition = useTransition(toasts, {
keys: (toast) => toast.id,
@@ -36,7 +35,7 @@ export function ToastStack() {
key={item.id}
{...item.options}
onClose={() => {
- remove(item.id)
+ removeToast(item.id)
item.options.onClose?.()
}}
/>
diff --git a/app/forms/disk-create.tsx b/app/forms/disk-create.tsx
index 590a027a37..d20c0f928d 100644
--- a/app/forms/disk-create.tsx
+++ b/app/forms/disk-create.tsx
@@ -29,7 +29,8 @@ import { ListboxField } from '~/components/form/fields/ListboxField'
import { NameField } from '~/components/form/fields/NameField'
import { RadioField } from '~/components/form/fields/RadioField'
import { SideModalForm } from '~/components/form/SideModalForm'
-import { useForm, useProjectSelector, useToast } from '~/hooks'
+import { useForm, useProjectSelector } from '~/hooks'
+import { addToast } from '~/stores/toast'
import { FormDivider } from '~/ui/lib/Divider'
import { FieldLabel } from '~/ui/lib/FieldLabel'
import { Radio } from '~/ui/lib/Radio'
@@ -69,7 +70,6 @@ export function CreateDiskSideModalForm({
onDismiss,
}: CreateSideModalFormProps) {
const queryClient = useApiQueryClient()
- const addToast = useToast()
const navigate = useNavigate()
const createDisk = useApiMutation('diskCreate', {
diff --git a/app/forms/floating-ip-create.tsx b/app/forms/floating-ip-create.tsx
index 3ef9869f2f..017c9ec096 100644
--- a/app/forms/floating-ip-create.tsx
+++ b/app/forms/floating-ip-create.tsx
@@ -24,7 +24,8 @@ import { ListboxField } from '~/components/form/fields/ListboxField'
import { NameField } from '~/components/form/fields/NameField'
import { TextField } from '~/components/form/fields/TextField'
import { SideModalForm } from '~/components/form/SideModalForm'
-import { useForm, useProjectSelector, useToast } from '~/hooks'
+import { useForm, useProjectSelector } from '~/hooks'
+import { addToast } from '~/stores/toast'
import { Badge } from '~/ui/lib/Badge'
import { Message } from '~/ui/lib/Message'
import { pb } from '~/util/path-builder'
@@ -65,7 +66,6 @@ export function CreateFloatingIpSideModalForm() {
const queryClient = useApiQueryClient()
const projectSelector = useProjectSelector()
- const addToast = useToast()
const navigate = useNavigate()
const createFloatingIp = useApiMutation('floatingIpCreate', {
diff --git a/app/forms/floating-ip-edit.tsx b/app/forms/floating-ip-edit.tsx
index 94b568adfa..d0120aa6a1 100644
--- a/app/forms/floating-ip-edit.tsx
+++ b/app/forms/floating-ip-edit.tsx
@@ -17,7 +17,8 @@ import {
import { DescriptionField } from '~/components/form/fields/DescriptionField'
import { NameField } from '~/components/form/fields/NameField'
import { SideModalForm } from '~/components/form/SideModalForm'
-import { getFloatingIpSelector, useFloatingIpSelector, useForm, useToast } from 'app/hooks'
+import { addToast } from '~/stores/toast'
+import { getFloatingIpSelector, useFloatingIpSelector, useForm } from 'app/hooks'
import { pb } from 'app/util/path-builder'
EditFloatingIpSideModalForm.loader = async ({ params }: LoaderFunctionArgs) => {
@@ -31,7 +32,6 @@ EditFloatingIpSideModalForm.loader = async ({ params }: LoaderFunctionArgs) => {
export function EditFloatingIpSideModalForm() {
const queryClient = useApiQueryClient()
- const addToast = useToast()
const navigate = useNavigate()
const floatingIpSelector = useFloatingIpSelector()
diff --git a/app/forms/idp/create.tsx b/app/forms/idp/create.tsx
index 8bed8ea2db..e32d24c6fa 100644
--- a/app/forms/idp/create.tsx
+++ b/app/forms/idp/create.tsx
@@ -14,7 +14,8 @@ import { FileField } from '~/components/form/fields/FileField'
import { NameField } from '~/components/form/fields/NameField'
import { TextField } from '~/components/form/fields/TextField'
import { SideModalForm } from '~/components/form/SideModalForm'
-import { useForm, useSiloSelector, useToast } from '~/hooks'
+import { useForm, useSiloSelector } from '~/hooks'
+import { addToast } from '~/stores/toast'
import { readBlobAsBase64 } from '~/util/file'
import { pb } from '~/util/path-builder'
@@ -43,7 +44,6 @@ const defaultValues: IdpCreateFormValues = {
export function CreateIdpSideModalForm() {
const navigate = useNavigate()
const queryClient = useApiQueryClient()
- const addToast = useToast()
const { silo } = useSiloSelector()
diff --git a/app/forms/instance-create.tsx b/app/forms/instance-create.tsx
index a86eaf4d64..6d53acc033 100644
--- a/app/forms/instance-create.tsx
+++ b/app/forms/instance-create.tsx
@@ -48,7 +48,8 @@ import { SshKeysField } from '~/components/form/fields/SshKeysField'
import { TextField } from '~/components/form/fields/TextField'
import { Form } from '~/components/form/Form'
import { FullPageForm } from '~/components/form/FullPageForm'
-import { getProjectSelector, useForm, useProjectSelector, useToast } from '~/hooks'
+import { getProjectSelector, useForm, useProjectSelector } from '~/hooks'
+import { addToast } from '~/stores/toast'
import { FormDivider } from '~/ui/lib/Divider'
import { EmptyMessage } from '~/ui/lib/EmptyMessage'
import { Message } from '~/ui/lib/Message'
@@ -150,7 +151,6 @@ CreateInstanceForm.loader = async ({ params }: LoaderFunctionArgs) => {
export function CreateInstanceForm() {
const [isSubmitting, setIsSubmitting] = useState(false)
const queryClient = useApiQueryClient()
- const addToast = useToast()
const { project } = useProjectSelector()
const navigate = useNavigate()
diff --git a/app/forms/ip-pool-edit.tsx b/app/forms/ip-pool-edit.tsx
index da2467ebf8..befe790dcf 100644
--- a/app/forms/ip-pool-edit.tsx
+++ b/app/forms/ip-pool-edit.tsx
@@ -17,7 +17,8 @@ import {
import { DescriptionField } from '~/components/form/fields/DescriptionField'
import { NameField } from '~/components/form/fields/NameField'
import { SideModalForm } from '~/components/form/SideModalForm'
-import { getIpPoolSelector, useForm, useIpPoolSelector, useToast } from '~/hooks'
+import { getIpPoolSelector, useForm, useIpPoolSelector } from '~/hooks'
+import { addToast } from '~/stores/toast'
import { pb } from '~/util/path-builder'
EditIpPoolSideModalForm.loader = async ({ params }: LoaderFunctionArgs) => {
@@ -28,7 +29,6 @@ EditIpPoolSideModalForm.loader = async ({ params }: LoaderFunctionArgs) => {
export function EditIpPoolSideModalForm() {
const queryClient = useApiQueryClient()
- const addToast = useToast()
const navigate = useNavigate()
const poolSelector = useIpPoolSelector()
diff --git a/app/forms/project-edit.tsx b/app/forms/project-edit.tsx
index 300df72b92..a610c95c0d 100644
--- a/app/forms/project-edit.tsx
+++ b/app/forms/project-edit.tsx
@@ -18,9 +18,10 @@ import { DescriptionField } from '~/components/form/fields/DescriptionField'
import { NameField } from '~/components/form/fields/NameField'
import { SideModalForm } from '~/components/form/SideModalForm'
import { useForm } from '~/hooks'
+import { addToast } from '~/stores/toast'
import { pb } from '~/util/path-builder'
-import { getProjectSelector, useProjectSelector, useToast } from '../hooks'
+import { getProjectSelector, useProjectSelector } from '../hooks'
EditProjectSideModalForm.loader = async ({ params }: LoaderFunctionArgs) => {
const { project } = getProjectSelector(params)
@@ -30,7 +31,6 @@ EditProjectSideModalForm.loader = async ({ params }: LoaderFunctionArgs) => {
export function EditProjectSideModalForm() {
const queryClient = useApiQueryClient()
- const addToast = useToast()
const navigate = useNavigate()
const projectSelector = useProjectSelector()
diff --git a/app/forms/silo-create.tsx b/app/forms/silo-create.tsx
index 782fd18dba..701c7a0a28 100644
--- a/app/forms/silo-create.tsx
+++ b/app/forms/silo-create.tsx
@@ -17,7 +17,8 @@ import { RadioField } from '~/components/form/fields/RadioField'
import { TextField } from '~/components/form/fields/TextField'
import { TlsCertsField } from '~/components/form/fields/TlsCertsField'
import { SideModalForm } from '~/components/form/SideModalForm'
-import { useForm, useToast } from '~/hooks'
+import { useForm } from '~/hooks'
+import { addToast } from '~/stores/toast'
import { FormDivider } from '~/ui/lib/Divider'
import { pb } from '~/util/path-builder'
import { GiB } from '~/util/units'
@@ -50,7 +51,6 @@ function validateQuota(value: number) {
export function CreateSiloSideModalForm() {
const navigate = useNavigate()
const queryClient = useApiQueryClient()
- const addToast = useToast()
const onDismiss = () => navigate(pb.silos())
diff --git a/app/forms/snapshot-create.tsx b/app/forms/snapshot-create.tsx
index 7a173a8c09..dfb9e111b7 100644
--- a/app/forms/snapshot-create.tsx
+++ b/app/forms/snapshot-create.tsx
@@ -20,7 +20,8 @@ import { DescriptionField } from '~/components/form/fields/DescriptionField'
import { ListboxField } from '~/components/form/fields/ListboxField'
import { NameField } from '~/components/form/fields/NameField'
import { SideModalForm } from '~/components/form/SideModalForm'
-import { useForm, useProjectSelector, useToast } from '~/hooks'
+import { useForm, useProjectSelector } from '~/hooks'
+import { addToast } from '~/stores/toast'
import { pb } from '~/util/path-builder'
const useSnapshotDiskItems = (projectSelector: PP.Project) => {
@@ -43,7 +44,6 @@ const defaultValues: SnapshotCreate = {
export function CreateSnapshotSideModalForm() {
const queryClient = useApiQueryClient()
const projectSelector = useProjectSelector()
- const addToast = useToast()
const navigate = useNavigate()
const diskItems = useSnapshotDiskItems(projectSelector)
diff --git a/app/forms/vpc-create.tsx b/app/forms/vpc-create.tsx
index e89683e40d..92bff170d6 100644
--- a/app/forms/vpc-create.tsx
+++ b/app/forms/vpc-create.tsx
@@ -13,7 +13,8 @@ import { DescriptionField } from '~/components/form/fields/DescriptionField'
import { NameField } from '~/components/form/fields/NameField'
import { TextField } from '~/components/form/fields/TextField'
import { SideModalForm } from '~/components/form/SideModalForm'
-import { useForm, useProjectSelector, useToast } from '~/hooks'
+import { useForm, useProjectSelector } from '~/hooks'
+import { addToast } from '~/stores/toast'
import { pb } from '~/util/path-builder'
const defaultValues: VpcCreate = {
@@ -25,7 +26,6 @@ const defaultValues: VpcCreate = {
export function CreateVpcSideModalForm() {
const projectSelector = useProjectSelector()
const queryClient = useApiQueryClient()
- const addToast = useToast()
const navigate = useNavigate()
const createVpc = useApiMutation('vpcCreate', {
diff --git a/app/forms/vpc-edit.tsx b/app/forms/vpc-edit.tsx
index 169098cd51..87859b5521 100644
--- a/app/forms/vpc-edit.tsx
+++ b/app/forms/vpc-edit.tsx
@@ -17,7 +17,8 @@ import {
import { DescriptionField } from '~/components/form/fields/DescriptionField'
import { NameField } from '~/components/form/fields/NameField'
import { SideModalForm } from '~/components/form/SideModalForm'
-import { getVpcSelector, useForm, useToast, useVpcSelector } from '~/hooks'
+import { getVpcSelector, useForm, useVpcSelector } from '~/hooks'
+import { addToast } from '~/stores/toast'
import { pb } from '~/util/path-builder'
EditVpcSideModalForm.loader = async ({ params }: LoaderFunctionArgs) => {
@@ -29,7 +30,6 @@ EditVpcSideModalForm.loader = async ({ params }: LoaderFunctionArgs) => {
export function EditVpcSideModalForm() {
const { vpc: vpcName, project } = useVpcSelector()
const queryClient = useApiQueryClient()
- const addToast = useToast()
const navigate = useNavigate()
const { data: vpc } = usePrefetchedApiQuery('vpcView', {
diff --git a/app/hooks/index.ts b/app/hooks/index.ts
index 1a4d9ce75f..3c2b3cb2bd 100644
--- a/app/hooks/index.ts
+++ b/app/hooks/index.ts
@@ -12,4 +12,3 @@ export * from './use-key'
export * from './use-params'
export * from './use-quick-actions'
export * from './use-reduce-motion'
-export * from './use-toast'
diff --git a/app/hooks/use-toast.ts b/app/hooks/use-toast.ts
deleted file mode 100644
index 37845c195c..0000000000
--- a/app/hooks/use-toast.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at https://mozilla.org/MPL/2.0/.
- *
- * Copyright Oxide Computer Company
- */
-import { useToastStore } from '~/stores/toast'
-
-export const useToast = () => useToastStore(({ add }) => add)
diff --git a/app/pages/LoginPage.tsx b/app/pages/LoginPage.tsx
index ed21d57337..dfa905db0f 100644
--- a/app/pages/LoginPage.tsx
+++ b/app/pages/LoginPage.tsx
@@ -12,11 +12,12 @@ import { useApiMutation, type UsernamePasswordCredentials } from '@oxide/api'
import { TextFieldInner } from '~/components/form/fields/TextField'
import { useForm } from '~/hooks'
+import { addToast } from '~/stores/toast'
import { Button } from '~/ui/lib/Button'
import { Identicon } from '~/ui/lib/Identicon'
import { pb } from '~/util/path-builder'
-import { useSiloSelector, useToast } from '../hooks'
+import { useSiloSelector } from '../hooks'
const defaultValues: UsernamePasswordCredentials = {
username: '',
@@ -27,7 +28,6 @@ const defaultValues: UsernamePasswordCredentials = {
export function LoginPage() {
const [searchParams] = useSearchParams()
const navigate = useNavigate()
- const addToast = useToast()
const { silo } = useSiloSelector()
const form = useForm({ defaultValues })
@@ -39,7 +39,7 @@ export function LoginPage() {
addToast({ title: 'Logged in' })
navigate(searchParams.get('redirect_uri') || pb.projects())
}
- }, [loginPost.isSuccess, navigate, searchParams, addToast])
+ }, [loginPost.isSuccess, navigate, searchParams])
return (
<>
diff --git a/app/pages/project/disks/DisksPage.tsx b/app/pages/project/disks/DisksPage.tsx
index 8342bfc589..2f0eb2a0f9 100644
--- a/app/pages/project/disks/DisksPage.tsx
+++ b/app/pages/project/disks/DisksPage.tsx
@@ -20,8 +20,9 @@ import {
import { Storage24Icon } from '@oxide/design-system/icons/react'
import { DiskStatusBadge } from '~/components/StatusBadge'
-import { getProjectSelector, useProjectSelector, useToast } from '~/hooks'
+import { getProjectSelector, useProjectSelector } from '~/hooks'
import { confirmDelete } from '~/stores/confirm-delete'
+import { addToast } from '~/stores/toast'
import { InstanceLinkCell } from '~/table/cells/InstanceLinkCell'
import { useColsWithActions, type MenuAction } from '~/table/columns/action-col'
import { Columns } from '~/table/columns/common'
@@ -94,7 +95,6 @@ export function DisksPage() {
const queryClient = useApiQueryClient()
const { project } = useProjectSelector()
const { Table } = useQueryTable('diskList', { query: { project } })
- const addToast = useToast()
const deleteDisk = useApiMutation('diskDelete', {
onSuccess() {
@@ -153,7 +153,7 @@ export function DisksPage() {
)),
},
],
- [addToast, createSnapshot, deleteDisk, project]
+ [createSnapshot, deleteDisk, project]
)
const columns = useColsWithActions(staticCols, makeActions)
diff --git a/app/pages/project/images/ImagesPage.tsx b/app/pages/project/images/ImagesPage.tsx
index f51172d0db..f984a63389 100644
--- a/app/pages/project/images/ImagesPage.tsx
+++ b/app/pages/project/images/ImagesPage.tsx
@@ -12,8 +12,9 @@ import { Link, Outlet, type LoaderFunctionArgs } from 'react-router-dom'
import { apiQueryClient, useApiMutation, useApiQueryClient, type Image } from '@oxide/api'
import { Images24Icon } from '@oxide/design-system/icons/react'
-import { getProjectSelector, useProjectSelector, useToast } from '~/hooks'
+import { getProjectSelector, useProjectSelector } from '~/hooks'
import { confirmDelete } from '~/stores/confirm-delete'
+import { addToast } from '~/stores/toast'
import { makeLinkCell } from '~/table/cells/LinkCell'
import { getActionsCol, type MenuAction } from '~/table/columns/action-col'
import { Columns } from '~/table/columns/common'
@@ -50,7 +51,6 @@ export function ImagesPage() {
const { project } = useProjectSelector()
const { Table } = useQueryTable('imageList', { query: { project } })
const queryClient = useApiQueryClient()
- const addToast = useToast()
const [promoteImageName, setPromoteImageName] = useState(null)
@@ -121,7 +121,7 @@ type PromoteModalProps = { onDismiss: () => void; imageName: string }
const PromoteImageModal = ({ onDismiss, imageName }: PromoteModalProps) => {
const { project } = useProjectSelector()
const queryClient = useApiQueryClient()
- const addToast = useToast()
+
const promoteImage = useApiMutation('imagePromote', {
onSuccess(data) {
addToast({
diff --git a/app/pages/system/SiloImagesPage.tsx b/app/pages/system/SiloImagesPage.tsx
index 17d4d0dfea..f67329fba4 100644
--- a/app/pages/system/SiloImagesPage.tsx
+++ b/app/pages/system/SiloImagesPage.tsx
@@ -21,7 +21,7 @@ import { Images24Icon } from '@oxide/design-system/icons/react'
import { toListboxItem } from '~/components/form/fields/ImageSelectField'
import { ListboxField } from '~/components/form/fields/ListboxField'
-import { useForm, useToast } from '~/hooks'
+import { useForm } from '~/hooks'
import { confirmDelete } from '~/stores/confirm-delete'
import { addToast } from '~/stores/toast'
import { makeLinkCell } from '~/table/cells/LinkCell'
@@ -119,7 +119,7 @@ const PromoteImageModal = ({ onDismiss }: { onDismiss: () => void }) => {
const { control, handleSubmit, watch, resetField } = useForm({ defaultValues })
const queryClient = useApiQueryClient()
- const addToast = useToast()
+
const promoteImage = useApiMutation('imagePromote', {
onSuccess(data) {
addToast({ content: `${data.name} has been promoted` })
@@ -208,7 +208,7 @@ const DemoteImageModal = ({
const selectedProject: string | undefined = watch('project')
const queryClient = useApiQueryClient()
- const addToast = useToast()
+
const demoteImage = useApiMutation('imageDemote', {
onSuccess(data) {
addToast({
diff --git a/app/stores/toast.ts b/app/stores/toast.ts
index 1168f2ec9f..ea06db7213 100644
--- a/app/stores/toast.ts
+++ b/app/stores/toast.ts
@@ -15,20 +15,11 @@ type Toast = {
options: Optional
}
-type ToastStore = {
- toasts: Toast[]
- add: (options: Toast['options']) => void
- remove: (id: Toast['id']) => void
-}
-
-export const useToastStore = create((set) => ({
- toasts: [],
- add: (options) => set(({ toasts }) => ({ toasts: [...toasts, { id: uuid(), options }] })),
- remove: (id) => set(({ toasts }) => ({ toasts: toasts.filter((t) => t.id !== id) })),
-}))
-
-// TODO: take add and remove out of the store once everthing is converted to this addToast
+export const useToastStore = create<{ toasts: Toast[] }>(() => ({ toasts: [] }))
export function addToast(options: Toast['options']) {
- useToastStore.getState().add(options)
+ useToastStore.setState(({ toasts }) => ({ toasts: [...toasts, { id: uuid(), options }] }))
+}
+export function removeToast(id: Toast['id']) {
+ useToastStore.setState(({ toasts }) => ({ toasts: toasts.filter((t) => t.id !== id) }))
}