From 1f5d34362ed16bcabede7af55cda6b5b8e7578e9 Mon Sep 17 00:00:00 2001 From: Alex Freska Date: Tue, 2 Apr 2024 12:04:45 -0400 Subject: [PATCH] feat: toasts dismissible --- .changeset/cuddly-tomatoes-move.md | 8 + .changeset/famous-donkeys-flash.md | 5 + .../components/Faucet/FaucetFundForm.tsx | 4 +- apps/explorer/components/Layout/Search.tsx | 6 +- .../components/Config/AnnounceButton.tsx | 6 +- .../Contracts/ContractContextMenu.tsx | 28 ++-- .../DirectorySelectCmd/DirectoryCreate.tsx | 5 +- .../components/Volumes/VolumeContextMenu.tsx | 36 ++--- apps/hostd/contexts/config/index.tsx | 2 +- apps/hostd/contexts/config/useOnValid.tsx | 18 ++- apps/hostd/dialogs/AlertsDialog.tsx | 28 ++-- apps/hostd/dialogs/VolumeCreateDialog.tsx | 7 +- apps/hostd/dialogs/VolumeDeleteDialog.tsx | 7 +- apps/hostd/dialogs/VolumeResizeDialog.tsx | 7 +- .../Contracts/useContractConfirmDelete.tsx | 7 +- .../Files/FileContextMenu/index.tsx | 32 ++-- .../components/Files/useDirectoryDelete.tsx | 7 +- .../components/Files/useFileDelete.tsx | 7 +- .../components/Keys/KeyContextMenu.tsx | 4 +- .../components/Keys/KeysCreateDialog.tsx | 4 +- apps/renterd/contexts/alerts/index.tsx | 14 +- apps/renterd/contexts/config/index.tsx | 2 +- apps/renterd/contexts/config/useOnValid.tsx | 7 +- .../contexts/config/useSyncContractSet.tsx | 21 ++- apps/renterd/contexts/filesDirectory/move.tsx | 2 +- .../contexts/filesManager/downloads.tsx | 10 +- .../renterd/contexts/filesManager/uploads.tsx | 12 +- apps/renterd/contexts/hosts/index.tsx | 7 +- apps/renterd/dialogs/FileRenameDialog.tsx | 15 +- .../dialogs/FilesBucketCreateDialog.tsx | 7 +- .../dialogs/FilesBucketDeleteDialog.tsx | 7 +- .../dialogs/FilesBucketPolicyDialog.tsx | 7 +- .../dialogs/FilesCreateDirectoryDialog.tsx | 9 +- apps/renterd/hooks/useAllowlistUpdate.tsx | 25 +-- apps/renterd/hooks/useBlocklistUpdate.tsx | 23 ++- apps/renterd/lib/multipartUpload.ts | 2 +- .../WalletAddresses/AddressContextMenu.tsx | 16 +- apps/walletd/dialogs/AddressRemoveDialog.tsx | 7 +- .../dialogs/AddressUpdateDialog/index.tsx | 5 +- .../dialogs/WalletAddLedgerDialog/index.tsx | 7 +- .../dialogs/WalletAddNewDialog/index.tsx | 5 +- .../dialogs/WalletAddRecoverDialog/index.tsx | 5 +- .../dialogs/WalletAddWatchDialog/index.tsx | 5 +- .../dialogs/WalletAddressesAddDialog.tsx | 23 +-- .../LedgerAddress/index.tsx | 5 +- .../index.tsx | 22 +-- .../index.tsx | 35 ++-- apps/walletd/dialogs/WalletRemoveDialog.tsx | 7 +- .../WalletSendLedgerDialog/useSendForm.tsx | 6 +- .../WalletSendSeedDialog/useSendForm.tsx | 2 +- .../dialogs/WalletUpdateDialog/index.tsx | 5 +- .../dialogs/_sharedWalletSend/useCancel.tsx | 5 +- .../src/app/SyncerConnectPeerDialog.tsx | 4 +- .../src/form/configurationFields.ts | 9 +- .../src/lib/{clipboard.ts => clipboard.tsx} | 25 ++- libs/design-system/src/lib/toast.tsx | 149 ++++++++++++------ 56 files changed, 478 insertions(+), 267 deletions(-) create mode 100644 .changeset/cuddly-tomatoes-move.md create mode 100644 .changeset/famous-donkeys-flash.md rename libs/design-system/src/lib/{clipboard.ts => clipboard.tsx} (53%) diff --git a/.changeset/cuddly-tomatoes-move.md b/.changeset/cuddly-tomatoes-move.md new file mode 100644 index 000000000..67222d206 --- /dev/null +++ b/.changeset/cuddly-tomatoes-move.md @@ -0,0 +1,8 @@ +--- +'explorer': minor +'hostd': minor +'renterd': minor +'walletd': minor +--- + +Toast notifications can now be dismissed. Closes https://github.com/SiaFoundation/web/issues/542 diff --git a/.changeset/famous-donkeys-flash.md b/.changeset/famous-donkeys-flash.md new file mode 100644 index 000000000..468a0f9d7 --- /dev/null +++ b/.changeset/famous-donkeys-flash.md @@ -0,0 +1,5 @@ +--- +'@siafoundation/design-system': minor +--- + +Toasts can not be dismissed and now use separate title and body props. diff --git a/apps/explorer/components/Faucet/FaucetFundForm.tsx b/apps/explorer/components/Faucet/FaucetFundForm.tsx index 8802970c2..57cfefa5a 100644 --- a/apps/explorer/components/Faucet/FaucetFundForm.tsx +++ b/apps/explorer/components/Faucet/FaucetFundForm.tsx @@ -2,7 +2,7 @@ import { FormFieldFormik, FormSubmitButtonFormik, Paragraph, - triggerToast, + triggerSuccessToast, } from '@siafoundation/design-system' import { toHastings } from '@siafoundation/units' import BigNumber from 'bignumber.js' @@ -50,7 +50,7 @@ export function FaucetFundForm({ onDone }: Props) { if (response.error) { actions.setStatus({ error: response.error }) } else { - triggerToast('Address has been funded.') + triggerSuccessToast({ title: 'Address has been funded' }) if (response.data) { onDone(response.data.id) } diff --git a/apps/explorer/components/Layout/Search.tsx b/apps/explorer/components/Layout/Search.tsx index 10b2edc18..d35dd5591 100644 --- a/apps/explorer/components/Layout/Search.tsx +++ b/apps/explorer/components/Layout/Search.tsx @@ -5,7 +5,7 @@ import { ConfigFields, ControlGroup, FieldText, - triggerToast, + triggerErrorToast, } from '@siafoundation/design-system' import { Search16 } from '@siafoundation/react-icons' import React, { useCallback } from 'react' @@ -51,7 +51,7 @@ export function Search() { if (!response.data) { form.setError('query', { message: 'Error connecting to server.' }) - triggerToast('Error connecting to server.') + triggerErrorToast({ title: 'Error connecting to server' }) return } @@ -91,7 +91,7 @@ export function Search() { form.reset() } else { form.setError('query', { message: 'No results match query.' }) - triggerToast('No results match query.') + triggerErrorToast({ title: 'No results match query' }) } }, [form, router, search] diff --git a/apps/hostd/components/Config/AnnounceButton.tsx b/apps/hostd/components/Config/AnnounceButton.tsx index 47144a089..0658aab32 100644 --- a/apps/hostd/components/Config/AnnounceButton.tsx +++ b/apps/hostd/components/Config/AnnounceButton.tsx @@ -61,10 +61,12 @@ export function AnnounceButton() { const response = await settingsAnnounce.post({}) if (response.error) { - triggerErrorToast('Error announcing host.') + triggerErrorToast({ title: 'Error announcing host' }) return } - triggerSuccessToast('Successfully broadcast host announcement.') + triggerSuccessToast({ + title: 'Successfully broadcast host announcement', + }) }, }), [openConfirmDialog, settingsAnnounce, txpoolFee] diff --git a/apps/hostd/components/Contracts/ContractContextMenu.tsx b/apps/hostd/components/Contracts/ContractContextMenu.tsx index 5b3f52986..473cca2ce 100644 --- a/apps/hostd/components/Contracts/ContractContextMenu.tsx +++ b/apps/hostd/components/Contracts/ContractContextMenu.tsx @@ -41,19 +41,25 @@ export function ContractContextMenu({ }, }) if (response.error) { - triggerErrorToast(response.error) + triggerErrorToast({ + title: 'Error starting integrity check', + body: response.error, + }) } else { - triggerSuccessToast( - <> - Integrity check successfully started, depending on contract data size - this operation can take a while. Check hostd{' '} - openDialog('alerts')}>alerts for status - updates. - , - { + triggerSuccessToast({ + title: 'Integrity check started', + body: ( + <> + Depending on contract data size this operation can take a while. + Check hostd{' '} + openDialog('alerts')}>alerts for status + updates. + + ), + options: { duration: 12_000, - } - ) + }, + }) } }, [id, integrityCheck, openDialog]) diff --git a/apps/hostd/components/DirectorySelectMenu/DirectorySelectCmd/DirectoryCreate.tsx b/apps/hostd/components/DirectorySelectMenu/DirectorySelectCmd/DirectoryCreate.tsx index aa75359b7..7dd651fdb 100644 --- a/apps/hostd/components/DirectorySelectMenu/DirectorySelectCmd/DirectoryCreate.tsx +++ b/apps/hostd/components/DirectorySelectMenu/DirectorySelectCmd/DirectoryCreate.tsx @@ -30,7 +30,10 @@ export function DirectoryCreate({ }, }) if (response.error) { - triggerErrorToast(`Error creating directory: ${response.error}`) + triggerErrorToast({ + title: 'Error creating directory', + body: response.error, + }) } else { onCreate(newDirName) setNewDirName('') diff --git a/apps/hostd/components/Volumes/VolumeContextMenu.tsx b/apps/hostd/components/Volumes/VolumeContextMenu.tsx index 1b84b2ac8..bccb3cce9 100644 --- a/apps/hostd/components/Volumes/VolumeContextMenu.tsx +++ b/apps/hostd/components/Volumes/VolumeContextMenu.tsx @@ -68,15 +68,15 @@ export function VolumeContextMenu({ id, contentProps, buttonProps }: Props) { }, }) if (response.error) { - triggerErrorToast( - `Error canceling volume ${getActiveOperationLabel(status)}.` - ) - } else { - triggerSuccessToast( - `Successfully canceled volume ${getActiveOperationLabel( + triggerErrorToast({ + title: `Error canceling volume ${getActiveOperationLabel( status - )}.` - ) + )}`, + }) + } else { + triggerSuccessToast({ + title: `Canceled volume ${getActiveOperationLabel(status)}`, + }) } }} > @@ -100,17 +100,17 @@ export function VolumeContextMenu({ id, contentProps, buttonProps }: Props) { }, }) if (response.error) { - triggerErrorToast( - nextReadOnly - ? 'Error setting volume to read-only.' - : 'Error setting volume to read/write.' - ) + triggerErrorToast({ + title: nextReadOnly + ? 'Error setting volume to read-only' + : 'Error setting volume to read/write', + }) } else { - triggerSuccessToast( - nextReadOnly - ? 'Volume set to read-only.' - : 'Volume set to read/write.' - ) + triggerSuccessToast({ + title: nextReadOnly + ? 'Volume set to read-only' + : 'Volume set to read/write', + }) } }} > diff --git a/apps/hostd/contexts/config/index.tsx b/apps/hostd/contexts/config/index.tsx index 6facdd427..717573b09 100644 --- a/apps/hostd/contexts/config/index.tsx +++ b/apps/hostd/contexts/config/index.tsx @@ -50,7 +50,7 @@ export function useConfigMain() { const revalidateAndResetForm = useCallback(async () => { const _settings = await settings.mutate() if (!_settings) { - triggerErrorToast('Error fetching settings.') + triggerErrorToast({ title: 'Error fetching settings' }) } else { // also recheck dynamic dns await dynDNSCheck.mutate() diff --git a/apps/hostd/contexts/config/useOnValid.tsx b/apps/hostd/contexts/config/useOnValid.tsx index 912cd89c7..b3ce7135e 100644 --- a/apps/hostd/contexts/config/useOnValid.tsx +++ b/apps/hostd/contexts/config/useOnValid.tsx @@ -54,18 +54,22 @@ export function useOnValid({ const needsToAnnounce = host.data?.lastAnnouncement?.address !== values.netAddress if (needsToAnnounce) { - triggerSuccessToast( - 'Settings have been saved. Address has changed, make sure to re-announce the host.', - { + triggerSuccessToast({ + title: 'Settings have been saved', + body: 'Address has changed, make sure to re-announce the host.', + options: { duration: 20_000, - } - ) + }, + }) } else { - triggerSuccessToast('Settings have been saved.') + triggerSuccessToast({ title: 'Settings have been saved' }) } await revalidateAndResetForm() } catch (e) { - triggerErrorToast((e as Error).message) + triggerErrorToast({ + title: 'Error updating settings', + body: (e as Error).message, + }) console.log(e) } }, diff --git a/apps/hostd/dialogs/AlertsDialog.tsx b/apps/hostd/dialogs/AlertsDialog.tsx index ae8ea407b..adf75132f 100644 --- a/apps/hostd/dialogs/AlertsDialog.tsx +++ b/apps/hostd/dialogs/AlertsDialog.tsx @@ -35,9 +35,12 @@ export function AlertsDialog({ open, onOpenChange }: Props) { payload: [id], }) if (response.error) { - triggerErrorToast('Error dismissing alert.') + triggerErrorToast({ + title: 'Error dismissing alert', + body: response.error, + }) } else { - triggerSuccessToast('Alert has been dismissed.') + triggerSuccessToast({ title: 'Alert has been dismissed' }) } }, [dismiss] @@ -52,17 +55,18 @@ export function AlertsDialog({ open, onOpenChange }: Props) { payload: ids, }) if (response.error) { - triggerErrorToast( - filter - ? `Error dismissing all ${filter} alerts.` - : 'Error dismissing all alerts.' - ) + triggerErrorToast({ + title: filter + ? `Error dismissing all ${filter} alerts` + : 'Error dismissing all alerts', + body: response.error, + }) } else { - triggerSuccessToast( - filter - ? `All ${filter} alerts have been dismissed.` - : 'All alerts have been dismissed.' - ) + triggerSuccessToast({ + title: filter + ? `All ${filter} alerts have been dismissed` + : 'All alerts have been dismissed', + }) } }, [dismiss, alerts] diff --git a/apps/hostd/dialogs/VolumeCreateDialog.tsx b/apps/hostd/dialogs/VolumeCreateDialog.tsx index 40be940d1..c8efdadca 100644 --- a/apps/hostd/dialogs/VolumeCreateDialog.tsx +++ b/apps/hostd/dialogs/VolumeCreateDialog.tsx @@ -136,9 +136,12 @@ export function VolumeCreateDialog({ trigger, open, onOpenChange }: Props) { }, }) if (response.error) { - triggerErrorToast(response.error) + triggerErrorToast({ + title: 'Error creating volume', + body: response.error, + }) } else { - triggerSuccessToast('New volume created.') + triggerSuccessToast({ title: 'New volume created' }) form.reset(defaultValues) closeDialog() } diff --git a/apps/hostd/dialogs/VolumeDeleteDialog.tsx b/apps/hostd/dialogs/VolumeDeleteDialog.tsx index bc8ae4fe7..699d8c3c5 100644 --- a/apps/hostd/dialogs/VolumeDeleteDialog.tsx +++ b/apps/hostd/dialogs/VolumeDeleteDialog.tsx @@ -79,9 +79,12 @@ export function VolumeDeleteDialog({ trigger, open, onOpenChange }: Props) { }, }) if (response.error) { - triggerErrorToast(response.error) + triggerErrorToast({ + title: 'Error deleting volume', + body: response.error, + }) } else { - triggerSuccessToast('Volume permanently deleted.') + triggerSuccessToast({ title: 'Volume permanently deleted' }) form.reset() closeDialog() } diff --git a/apps/hostd/dialogs/VolumeResizeDialog.tsx b/apps/hostd/dialogs/VolumeResizeDialog.tsx index 4684b46c6..36c813168 100644 --- a/apps/hostd/dialogs/VolumeResizeDialog.tsx +++ b/apps/hostd/dialogs/VolumeResizeDialog.tsx @@ -102,9 +102,12 @@ export function VolumeResizeDialog({ trigger, open, onOpenChange }: Props) { }, }) if (response.error) { - triggerErrorToast(response.error) + triggerErrorToast({ + title: 'Error resizing volume', + body: response.error, + }) } else { - triggerSuccessToast('Volume resizing initiated.') + triggerSuccessToast({ title: 'Volume resizing initiated' }) form.reset(defaultValues) closeDialog() } diff --git a/apps/renterd/components/Contracts/useContractConfirmDelete.tsx b/apps/renterd/components/Contracts/useContractConfirmDelete.tsx index 2f3206c00..606cdbb90 100644 --- a/apps/renterd/components/Contracts/useContractConfirmDelete.tsx +++ b/apps/renterd/components/Contracts/useContractConfirmDelete.tsx @@ -39,9 +39,12 @@ export function useContractConfirmDelete() { }) if (response.error) { - triggerErrorToast('Error deleting contract.') + triggerErrorToast({ + title: 'Error deleting contract', + body: response.error, + }) } - triggerSuccessToast('Successfully deleted contract.') + triggerSuccessToast({ title: 'Deleted contract' }) }, }), [openConfirmDialog, deleteContract] diff --git a/apps/renterd/components/Files/FileContextMenu/index.tsx b/apps/renterd/components/Files/FileContextMenu/index.tsx index 82f09dda7..b1bb6b0fa 100644 --- a/apps/renterd/components/Files/FileContextMenu/index.tsx +++ b/apps/renterd/components/Files/FileContextMenu/index.tsx @@ -6,7 +6,6 @@ import { DropdownMenuLeftSlot, DropdownMenuLabel, copyToClipboardCustom, - Text, Code, } from '@siafoundation/design-system' import { @@ -14,9 +13,9 @@ import { Copy16, Delete16, Document16, - Warning16, Filter16, Edit16, + Warning24, } from '@siafoundation/react-icons' import { useFileDelete } from '../useFileDelete' import { CopyMetadataMenuItem } from './CopyMetadataMenuItem' @@ -110,25 +109,20 @@ export function FileContextMenu({ path }: Props) { { - copyToClipboardCustom( - getFileUrl(path, true), -
- Copied authenticated file URL to clipboard. - + copyToClipboardCustom({ + text: getFileUrl(path, true), + title: 'Copied authenticated file URL to clipboard', + body: ( + <> The authenticated URL contains the renterd{' '} password, be careful when pasting or sharing the URL. - -
, - { - icon: ( -
- -
- ), - duration: 10_000, - className: '!max-w-[1200px]', - } - ) + + ), + icon: , + options: { + duration: 100_000, + }, + }) }} > diff --git a/apps/renterd/components/Files/useDirectoryDelete.tsx b/apps/renterd/components/Files/useDirectoryDelete.tsx index c3d233c76..e5ccb3f20 100644 --- a/apps/renterd/components/Files/useDirectoryDelete.tsx +++ b/apps/renterd/components/Files/useDirectoryDelete.tsx @@ -42,9 +42,12 @@ export function useDirectoryDelete() { }) if (response.error) { - triggerErrorToast('Error deleting directory.') + triggerErrorToast({ + title: 'Error deleting directory', + body: response.error, + }) } - triggerSuccessToast('Successfully deleted directory.') + triggerSuccessToast({ title: 'Deleted directory' }) }, }), [openConfirmDialog, deleteObject] diff --git a/apps/renterd/components/Files/useFileDelete.tsx b/apps/renterd/components/Files/useFileDelete.tsx index 51ad0e360..7905b53a0 100644 --- a/apps/renterd/components/Files/useFileDelete.tsx +++ b/apps/renterd/components/Files/useFileDelete.tsx @@ -40,9 +40,12 @@ export function useFileDelete() { }) if (response.error) { - triggerErrorToast('Error deleting file.') + triggerErrorToast({ + title: 'Error deleting file', + body: response.error, + }) } - triggerSuccessToast('Successfully deleted file.') + triggerSuccessToast({ title: 'Deleted file' }) }, }), [openConfirmDialog, deleteObject] diff --git a/apps/renterd/components/Keys/KeyContextMenu.tsx b/apps/renterd/components/Keys/KeyContextMenu.tsx index db87f6c8e..ff2f8a52a 100644 --- a/apps/renterd/components/Keys/KeyContextMenu.tsx +++ b/apps/renterd/components/Keys/KeyContextMenu.tsx @@ -38,9 +38,9 @@ export function KeyContextMenu({ s3Key, contentProps, buttonProps }: Props) { }, }) if (response.error) { - triggerErrorToast(`Failed to delete key: ${response.error}`) + triggerErrorToast({ title: 'Error deleting key', body: response.error }) } else { - triggerSuccessToast(`Key ${s3Key} removed.`) + triggerSuccessToast({ title: `Key ${s3Key} removed` }) } }, [s3AuthenticationSettings.data, s3Key, update]) diff --git a/apps/renterd/components/Keys/KeysCreateDialog.tsx b/apps/renterd/components/Keys/KeysCreateDialog.tsx index 5d7bea5d2..2d268b98b 100644 --- a/apps/renterd/components/Keys/KeysCreateDialog.tsx +++ b/apps/renterd/components/Keys/KeysCreateDialog.tsx @@ -121,9 +121,9 @@ export function KeysCreateDialog({ trigger, open, onOpenChange }: Props) { }, }) if (response.error) { - triggerErrorToast(response.error) + triggerErrorToast({ title: 'Error creating key', body: response.error }) } else { - triggerSuccessToast('New key created.') + triggerSuccessToast({ title: 'New key created' }) form.reset(getDefaultValues()) closeDialog() } diff --git a/apps/renterd/contexts/alerts/index.tsx b/apps/renterd/contexts/alerts/index.tsx index f162c8fd5..5c35f5eb3 100644 --- a/apps/renterd/contexts/alerts/index.tsx +++ b/apps/renterd/contexts/alerts/index.tsx @@ -79,9 +79,12 @@ function useAlertsMain() { payload: [id], }) if (response.error) { - triggerErrorToast('Error dismissing alert.') + triggerErrorToast({ + title: 'Error dismissing alert', + body: response.error, + }) } else { - triggerSuccessToast('Alert has been dismissed.') + triggerSuccessToast({ title: 'Alert has been dismissed.' }) } }, [dismiss] @@ -93,9 +96,12 @@ function useAlertsMain() { payload: ids, }) if (response.error) { - triggerErrorToast('Error dismissing alerts.') + triggerErrorToast({ + title: 'Error dismissing alerts', + body: response.error, + }) } else { - triggerSuccessToast('Selected alerts have been dismissed.') + triggerSuccessToast({ title: 'Selected alerts have been dismissed' }) } }, [dismiss] diff --git a/apps/renterd/contexts/config/index.tsx b/apps/renterd/contexts/config/index.tsx index 791f19ef2..a0e59c87c 100644 --- a/apps/renterd/contexts/config/index.tsx +++ b/apps/renterd/contexts/config/index.tsx @@ -133,7 +133,7 @@ export function useConfigMain() { const _redundancy = await redundancy.mutate() const _uploadPacking = await uploadPacking.mutate() if (!gouging || !redundancy) { - triggerErrorToast('Error fetching settings.') + triggerErrorToast({ title: 'Error fetching settings' }) return null } form.reset( diff --git a/apps/renterd/contexts/config/useOnValid.tsx b/apps/renterd/contexts/config/useOnValid.tsx index 3f4d5b450..0ce7a9a61 100644 --- a/apps/renterd/contexts/config/useOnValid.tsx +++ b/apps/renterd/contexts/config/useOnValid.tsx @@ -148,7 +148,7 @@ export function useOnValid({ }) } - triggerSuccessToast('Configuration has been saved.') + triggerSuccessToast({ title: 'Configuration has been saved' }) // If autopilot is being configured for the first time, // revalidate the empty hosts list. @@ -164,7 +164,10 @@ export function useOnValid({ await revalidateAndResetForm() } catch (e) { - triggerErrorToast((e as Error).message) + triggerErrorToast({ + title: 'Error updating configuration', + body: (e as Error).message, + }) console.log(e) } }, diff --git a/apps/renterd/contexts/config/useSyncContractSet.tsx b/apps/renterd/contexts/config/useSyncContractSet.tsx index fad4a909c..ecd52b9fd 100644 --- a/apps/renterd/contexts/config/useSyncContractSet.tsx +++ b/apps/renterd/contexts/config/useSyncContractSet.tsx @@ -1,6 +1,5 @@ import { Code, - Text, triggerErrorToast, triggerSuccessToast, } from '@siafoundation/design-system' @@ -44,15 +43,21 @@ export function useSyncContractSet() { ), }) contractSet.mutate() - triggerSuccessToast( - - Default contract set has been updated to:{' '} - {autopilotContractSet}. - - ) + triggerSuccessToast({ + title: 'Default contract set updated', + body: ( + <> + Default contract set has been updated to:{' '} + {autopilotContractSet}. + + ), + }) } } catch (e) { - triggerErrorToast((e as Error).message) + triggerErrorToast({ + title: 'Error updating default contract set', + body: (e as Error).message, + }) console.log(e) } }, diff --git a/apps/renterd/contexts/filesDirectory/move.tsx b/apps/renterd/contexts/filesDirectory/move.tsx index e12cbb825..100dbe4c4 100644 --- a/apps/renterd/contexts/filesDirectory/move.tsx +++ b/apps/renterd/contexts/filesDirectory/move.tsx @@ -53,7 +53,7 @@ export function useMove({ }) refresh() if (response.error) { - triggerErrorToast(response.error) + triggerErrorToast({ title: 'Error moving files', body: response.error }) } }, [refresh, rename, activeDirectory] diff --git a/apps/renterd/contexts/filesManager/downloads.tsx b/apps/renterd/contexts/filesManager/downloads.tsx index e8f6f2a42..f6457a7c9 100644 --- a/apps/renterd/contexts/filesManager/downloads.tsx +++ b/apps/renterd/contexts/filesManager/downloads.tsx @@ -88,7 +88,7 @@ export function useDownloads() { const name = getFilename(path) if (downloadsMap[path]) { - triggerErrorToast(`Already downloading file: ${path}`) + triggerErrorToast({ title: 'Already downloading file', body: path }) return } @@ -123,14 +123,16 @@ export function useDownloads() { isDone = true if (response.error) { if (response.error === 'canceled') { - triggerToast('File download canceled.') + triggerToast({ title: 'File download canceled' }) } else { - triggerErrorToast(response.error) + triggerErrorToast({ + title: 'Error downloading file', + body: response.error, + }) } removeDownload(path) } else { removeDownload(path) - // triggerToast(`Download complete: ${name}`) } }) } diff --git a/apps/renterd/contexts/filesManager/uploads.tsx b/apps/renterd/contexts/filesManager/uploads.tsx index 644060c4e..d15dbb30f 100644 --- a/apps/renterd/contexts/filesManager/uploads.tsx +++ b/apps/renterd/contexts/filesManager/uploads.tsx @@ -120,7 +120,10 @@ export function useUploads({ activeDirectoryPath }: Props) { const uploadId = await multipartUpload.create() multipartUpload.setOnError((error) => { - triggerErrorToast(error.message) + triggerErrorToast({ + title: 'Error uploading file', + body: error.message, + }) ref.current.removeUpload(uploadId) }) multipartUpload.setOnProgress( @@ -234,9 +237,10 @@ export function useUploads({ activeDirectoryPath }: Props) { const bucketName = getBucketFromPath(path) const bucket = buckets.data?.find((b) => b.name === bucketName) if (uploadsMap[path]) { - triggerErrorToast( - `Already uploading file: ${path}, aborting previous upload.` - ) + triggerErrorToast({ + title: `Already uploading file, aborting previous upload.`, + body: path, + }) uploadsMap[path].uploadAbort?.() } addUploadToQueue({ diff --git a/apps/renterd/contexts/hosts/index.tsx b/apps/renterd/contexts/hosts/index.tsx index 0f76ee081..e42e913c3 100644 --- a/apps/renterd/contexts/hosts/index.tsx +++ b/apps/renterd/contexts/hosts/index.tsx @@ -179,9 +179,10 @@ function useHostsMain() { if (location) { cmdRef.current.moveToLocation(location) } else { - triggerErrorToast( - `Geographic location is unknown for host ${truncate(publicKey, 20)}` - ) + triggerErrorToast({ + title: 'Geographic location is unknown for host', + body: truncate(publicKey, 20), + }) } scrollToHost(publicKey) }, diff --git a/apps/renterd/dialogs/FileRenameDialog.tsx b/apps/renterd/dialogs/FileRenameDialog.tsx index 5a8680c8e..9d55c33d4 100644 --- a/apps/renterd/dialogs/FileRenameDialog.tsx +++ b/apps/renterd/dialogs/FileRenameDialog.tsx @@ -97,15 +97,22 @@ export function FileRenameDialog({ }, }) if (response.error) { - triggerErrorToast(response.error) + triggerErrorToast({ + title: isDirectory(originalPath) + ? 'Error renaming directory' + : 'Error renaming file', + body: response.error, + }) } else { refreshDirectory() refreshFlat() form.reset() closeDialog() - triggerSuccessToast( - isDirectory(originalPath) ? 'Directory renamed.' : 'File renamed.' - ) + triggerSuccessToast({ + title: isDirectory(originalPath) + ? 'Directory renamed' + : 'File renamed', + }) } }, [ diff --git a/apps/renterd/dialogs/FilesBucketCreateDialog.tsx b/apps/renterd/dialogs/FilesBucketCreateDialog.tsx index 64e386674..cede1f2a4 100644 --- a/apps/renterd/dialogs/FilesBucketCreateDialog.tsx +++ b/apps/renterd/dialogs/FilesBucketCreateDialog.tsx @@ -57,9 +57,12 @@ export function FilesBucketCreateDialog({ }, }) if (response.error) { - triggerErrorToast(response.error) + triggerErrorToast({ + title: 'Error creating bucket', + body: response.error, + }) } else { - triggerSuccessToast('Bucket created.') + triggerSuccessToast({ title: 'Bucket created' }) form.reset() closeDialog() } diff --git a/apps/renterd/dialogs/FilesBucketDeleteDialog.tsx b/apps/renterd/dialogs/FilesBucketDeleteDialog.tsx index 9ef02be42..4831f732a 100644 --- a/apps/renterd/dialogs/FilesBucketDeleteDialog.tsx +++ b/apps/renterd/dialogs/FilesBucketDeleteDialog.tsx @@ -63,9 +63,12 @@ export function FilesBucketDeleteDialog({ }, }) if (response.error) { - triggerErrorToast(response.error) + triggerErrorToast({ + title: 'Error deleting bucket', + body: response.error, + }) } else { - triggerSuccessToast('Bucket permanently deleted.') + triggerSuccessToast({ title: 'Bucket permanently deleted' }) form.reset() closeDialog() } diff --git a/apps/renterd/dialogs/FilesBucketPolicyDialog.tsx b/apps/renterd/dialogs/FilesBucketPolicyDialog.tsx index 3e7d76529..77c993b52 100644 --- a/apps/renterd/dialogs/FilesBucketPolicyDialog.tsx +++ b/apps/renterd/dialogs/FilesBucketPolicyDialog.tsx @@ -89,9 +89,12 @@ export function FilesBucketPolicyDialog({ }, }) if (response.error) { - triggerErrorToast(response.error) + triggerErrorToast({ + title: 'Error updating bucket policy', + body: response.error, + }) } else { - triggerSuccessToast('Bucket policy has been updated.') + triggerSuccessToast({ title: 'Bucket policy has been updated' }) form.reset() closeDialog() } diff --git a/apps/renterd/dialogs/FilesCreateDirectoryDialog.tsx b/apps/renterd/dialogs/FilesCreateDirectoryDialog.tsx index 76d6b7952..0b554bc22 100644 --- a/apps/renterd/dialogs/FilesCreateDirectoryDialog.tsx +++ b/apps/renterd/dialogs/FilesCreateDirectoryDialog.tsx @@ -3,7 +3,7 @@ import { FormFieldFormik, FormSubmitButtonFormik, triggerErrorToast, - triggerToast, + triggerSuccessToast, } from '@siafoundation/design-system' import { useObjectUpload } from '@siafoundation/react-renterd' import { useFilesManager } from '../contexts/filesManager' @@ -44,9 +44,12 @@ export function FilesCreateDirectoryDialog({ payload: null, }) if (response.error) { - triggerErrorToast(response.error) + triggerErrorToast({ + title: 'Error creating directory', + body: response.error, + }) } else { - triggerToast('Directory created.') + triggerSuccessToast({ title: 'Directory created' }) actions.resetForm() onOpenChange(false) } diff --git a/apps/renterd/hooks/useAllowlistUpdate.tsx b/apps/renterd/hooks/useAllowlistUpdate.tsx index fd48f53e4..86e1fd85f 100644 --- a/apps/renterd/hooks/useAllowlistUpdate.tsx +++ b/apps/renterd/hooks/useAllowlistUpdate.tsx @@ -1,6 +1,6 @@ import { triggerErrorToast, - triggerToast, + triggerSuccessToast, truncate, } from '@siafoundation/design-system' import { useHostsAllowlistUpdate } from '@siafoundation/react-renterd' @@ -19,20 +19,27 @@ export function useAllowlistUpdate() { }, }) if (response.error) { - triggerErrorToast(response.error) + triggerErrorToast({ + title: 'Error updating allowlist', + body: response.error, + }) return false } else { if (add.length) { - triggerToast( - `${add.map((i) => truncate(i, 20)).join(', ')} added to allowlist` - ) + triggerSuccessToast({ + title: 'Allowlist updated', + body: `${add + .map((i) => truncate(i, 20)) + .join(', ')} added to allowlist.`, + }) } if (remove.length) { - triggerToast( - `${remove + triggerSuccessToast({ + title: 'Allowlist updated', + body: `${remove .map((i) => truncate(i, 20)) - .join(', ')} removed from allowlist` - ) + .join(', ')} removed from allowlist.`, + }) } return true } diff --git a/apps/renterd/hooks/useBlocklistUpdate.tsx b/apps/renterd/hooks/useBlocklistUpdate.tsx index 00afd01b8..4c3802081 100644 --- a/apps/renterd/hooks/useBlocklistUpdate.tsx +++ b/apps/renterd/hooks/useBlocklistUpdate.tsx @@ -19,20 +19,27 @@ export function useBlocklistUpdate() { }, }) if (response.error) { - triggerErrorToast(response.error) + triggerErrorToast({ + title: 'Error updating blocklist', + body: response.error, + }) return false } else { if (add.length) { - triggerToast( - `${add.map((i) => truncate(i, 20)).join(', ')} added to blocklist` - ) + triggerToast({ + title: 'Blocklist updated', + body: `${add + .map((i) => truncate(i, 20)) + .join(', ')} added to blocklist.`, + }) } if (remove.length) { - triggerToast( - `${remove + triggerToast({ + title: 'Blocklist updated', + body: `${remove .map((i) => truncate(i, 20)) - .join(', ')} removed from blocklist` - ) + .join(', ')} removed from blocklist.`, + }) } return true } diff --git a/apps/renterd/lib/multipartUpload.ts b/apps/renterd/lib/multipartUpload.ts index 84f63cf02..424d9e9d7 100644 --- a/apps/renterd/lib/multipartUpload.ts +++ b/apps/renterd/lib/multipartUpload.ts @@ -138,7 +138,7 @@ export class MultipartUpload { }, }) } catch (e) { - triggerErrorToast(e.message) + triggerErrorToast({ title: 'Error aborting upload', body: e.message }) } this.#resolve?.() } diff --git a/apps/walletd/components/WalletAddresses/AddressContextMenu.tsx b/apps/walletd/components/WalletAddresses/AddressContextMenu.tsx index ae6715515..3c5e2a943 100644 --- a/apps/walletd/components/WalletAddresses/AddressContextMenu.tsx +++ b/apps/walletd/components/WalletAddresses/AddressContextMenu.tsx @@ -54,13 +54,17 @@ export function AddressContextMenu({ }, }) if (response.error) { - triggerErrorToast(`Failed to delete address: ${response.error}`) + triggerErrorToast({ + title: 'Error deleting address', + body: response.error, + }) } else { - triggerSuccessToast( - metadata.index !== undefined - ? `Address ${metadata.index} removed.` - : 'Address removed.' - ) + triggerSuccessToast({ + title: + metadata.index !== undefined + ? `Address ${metadata.index} removed` + : 'Address removed', + }) } }, }) diff --git a/apps/walletd/dialogs/AddressRemoveDialog.tsx b/apps/walletd/dialogs/AddressRemoveDialog.tsx index de7a94c91..247215848 100644 --- a/apps/walletd/dialogs/AddressRemoveDialog.tsx +++ b/apps/walletd/dialogs/AddressRemoveDialog.tsx @@ -72,9 +72,12 @@ export function AddressRemoveDialog({ }, }) if (response.error) { - triggerErrorToast(response.error) + triggerErrorToast({ + title: 'Error removing address', + body: response.error, + }) } else { - triggerSuccessToast('Address permanently removed.') + triggerSuccessToast({ title: 'Address permanently removed' }) form.reset() closeDialog() } diff --git a/apps/walletd/dialogs/AddressUpdateDialog/index.tsx b/apps/walletd/dialogs/AddressUpdateDialog/index.tsx index 4d7eca919..23ee47069 100644 --- a/apps/walletd/dialogs/AddressUpdateDialog/index.tsx +++ b/apps/walletd/dialogs/AddressUpdateDialog/index.tsx @@ -85,7 +85,10 @@ export function AddressUpdateDialog({ }, }) if (response.error) { - triggerErrorToast(response.error) + triggerErrorToast({ + title: 'Error updating address', + body: response.error, + }) } else { closeDialog() form.reset(defaultValues) diff --git a/apps/walletd/dialogs/WalletAddLedgerDialog/index.tsx b/apps/walletd/dialogs/WalletAddLedgerDialog/index.tsx index 693642b8c..ed405ead4 100644 --- a/apps/walletd/dialogs/WalletAddLedgerDialog/index.tsx +++ b/apps/walletd/dialogs/WalletAddLedgerDialog/index.tsx @@ -152,7 +152,7 @@ export function WalletAddLedgerDialog({ trigger, open, onOpenChange }: Props) { }, }) if (response.error) { - triggerErrorToast('Error saving address.') + triggerErrorToast({ title: 'Error saving address' }) return } }, @@ -180,7 +180,10 @@ export function WalletAddLedgerDialog({ trigger, open, onOpenChange }: Props) { }, }) if (response.error) { - triggerErrorToast(response.error) + triggerErrorToast({ + title: 'Error saving wallet', + body: response.error, + }) } else { const uc = getSDK().wallet.standardUnlockConditions(device.publicKey0) if (!uc.error) { diff --git a/apps/walletd/dialogs/WalletAddNewDialog/index.tsx b/apps/walletd/dialogs/WalletAddNewDialog/index.tsx index 3e19b9e1c..6933607c2 100644 --- a/apps/walletd/dialogs/WalletAddNewDialog/index.tsx +++ b/apps/walletd/dialogs/WalletAddNewDialog/index.tsx @@ -151,7 +151,10 @@ export function WalletAddNewDialog({ trigger, open, onOpenChange }: Props) { }, }) if (response.error) { - triggerErrorToast(response.error) + triggerErrorToast({ + title: 'Error creating wallet', + body: response.error, + }) } else { openDialog('walletAddressesGenerate', { walletId: response.data.id, diff --git a/apps/walletd/dialogs/WalletAddRecoverDialog/index.tsx b/apps/walletd/dialogs/WalletAddRecoverDialog/index.tsx index dc1172e8f..bd590b573 100644 --- a/apps/walletd/dialogs/WalletAddRecoverDialog/index.tsx +++ b/apps/walletd/dialogs/WalletAddRecoverDialog/index.tsx @@ -108,7 +108,10 @@ export function WalletAddRecoverDialog({ trigger, open, onOpenChange }: Props) { }, }) if (response.error) { - triggerErrorToast(response.error) + triggerErrorToast({ + title: 'Error adding wallet', + body: response.error, + }) } else { openDialog('walletAddressesGenerate', { walletId: response.data.id, diff --git a/apps/walletd/dialogs/WalletAddWatchDialog/index.tsx b/apps/walletd/dialogs/WalletAddWatchDialog/index.tsx index 7c5033663..3d98a6c1a 100644 --- a/apps/walletd/dialogs/WalletAddWatchDialog/index.tsx +++ b/apps/walletd/dialogs/WalletAddWatchDialog/index.tsx @@ -88,7 +88,10 @@ export function WalletAddWatchDialog({ trigger, open, onOpenChange }: Props) { }, }) if (response.error) { - triggerErrorToast(response.error) + triggerErrorToast({ + title: 'Error adding wallet', + body: response.error, + }) } else { openDialog('walletAddressesAdd', { walletId: response.data.id, diff --git a/apps/walletd/dialogs/WalletAddressesAddDialog.tsx b/apps/walletd/dialogs/WalletAddressesAddDialog.tsx index d334f3266..e4a487e79 100644 --- a/apps/walletd/dialogs/WalletAddressesAddDialog.tsx +++ b/apps/walletd/dialogs/WalletAddressesAddDialog.tsx @@ -156,24 +156,27 @@ export function WalletAddressesAddDialog({ const result = await addAllAddresses(values.addresses) if (result.error) { if (result.total === 1) { - triggerErrorToast('Error saving address.') + triggerErrorToast({ + title: 'Error saving address', + body: result.error, + }) } else { - triggerErrorToast( - `Error saving addresses. ${ + triggerErrorToast({ + title: 'Error saving addresses', + body: result.successful > 0 ? `${result.successful} of ${result.total} addresses were saved.` - : '' - }` - ) + : '', + }) } return } if (result.total === 1) { - triggerSuccessToast('Successfully added 1 address.') + triggerSuccessToast({ title: 'Added 1 address' }) } else { - triggerSuccessToast( - `Successfully added ${result.successful} addresses.` - ) + triggerSuccessToast({ + title: `Added ${result.successful} addresses`, + }) } if (values.shouldResubscribe) { resubscribe.post({ diff --git a/apps/walletd/dialogs/WalletAddressesGenerateLedgerDialog/LedgerAddress/index.tsx b/apps/walletd/dialogs/WalletAddressesGenerateLedgerDialog/LedgerAddress/index.tsx index a6cddc2db..a1866c283 100644 --- a/apps/walletd/dialogs/WalletAddressesGenerateLedgerDialog/LedgerAddress/index.tsx +++ b/apps/walletd/dialogs/WalletAddressesGenerateLedgerDialog/LedgerAddress/index.tsx @@ -34,7 +34,10 @@ export function LedgerAddress({ return } if (error) { - triggerErrorToast(error.message) + triggerErrorToast({ + title: 'Error connecting to Ledger', + body: error.message, + }) return } try { diff --git a/apps/walletd/dialogs/WalletAddressesGenerateLedgerDialog/index.tsx b/apps/walletd/dialogs/WalletAddressesGenerateLedgerDialog/index.tsx index 877f658c7..6cc833890 100644 --- a/apps/walletd/dialogs/WalletAddressesGenerateLedgerDialog/index.tsx +++ b/apps/walletd/dialogs/WalletAddressesGenerateLedgerDialog/index.tsx @@ -245,13 +245,12 @@ export function WalletAddressesGenerateLedgerDialog({ const count = newGeneratedAddresses.length function toastBatchError(count: number, i: number) { if (count === 1) { - triggerErrorToast('Error saving address.') + triggerErrorToast({ title: 'Error saving address' }) } else { - triggerErrorToast( - `Error saving addresses. ${ - i > 0 ? 'Not all addresses were saved.' : '' - }` - ) + triggerErrorToast({ + title: 'Error saving addresses', + body: i > 0 ? 'Not all addresses were saved.' : '', + }) } } for (const [ @@ -284,9 +283,9 @@ export function WalletAddressesGenerateLedgerDialog({ } } if (count === 1) { - triggerSuccessToast('Successfully added 1 address.') + triggerSuccessToast({ title: 'Added 1 address' }) } else { - triggerSuccessToast(`Successfully added ${count} addresses.`) + triggerSuccessToast({ title: `Added ${count} addresses` }) } return }, [addressAdd, walletId, newGeneratedAddresses]) @@ -302,9 +301,10 @@ export function WalletAddressesGenerateLedgerDialog({ const onSubmit = useCallback(async () => { if (newGeneratedAddresses.length === 0) { - triggerErrorToast( - 'Add and generate addresses with your Ledger device to continue.' - ) + triggerErrorToast({ + title: 'Generate an address', + body: 'Add and generate addresses with your Ledger device to continue.', + }) return } await saveAddresses() diff --git a/apps/walletd/dialogs/WalletAddressesGenerateSeedDialog/index.tsx b/apps/walletd/dialogs/WalletAddressesGenerateSeedDialog/index.tsx index 8a0ee81ef..1960a7f0d 100644 --- a/apps/walletd/dialogs/WalletAddressesGenerateSeedDialog/index.tsx +++ b/apps/walletd/dialogs/WalletAddressesGenerateSeedDialog/index.tsx @@ -126,17 +126,26 @@ export function WalletAddressesGenerateSeedDialog({ for (let i = index; i < index + count; i++) { const kp = getSDK().wallet.keyPairFromSeedPhrase(mnemonic, i) if (kp.error) { - triggerErrorToast('Error generating addresses.') + triggerErrorToast({ + title: 'Error generating addresses', + body: kp.error, + }) return } const suh = getSDK().wallet.standardUnlockHash(kp.publicKey) if (suh.error) { - triggerErrorToast('Error generating unlock hash.') + triggerErrorToast({ + title: 'Error generating unlock hash', + body: suh.error, + }) return } const uc = getSDK().wallet.standardUnlockConditions(kp.publicKey) if (uc.error) { - triggerErrorToast('Error generating unlock conditions.') + triggerErrorToast({ + title: 'Error generating unlock conditions', + body: uc.error, + }) return } const metadata: WalletAddressMetadata = { @@ -156,21 +165,25 @@ export function WalletAddressesGenerateSeedDialog({ }) if (response.error) { if (count === 1) { - triggerErrorToast('Error saving address.') + triggerErrorToast({ + title: 'Error saving address', + body: response.error, + }) } else { - triggerErrorToast( - `Error saving addresses. ${ - i > 0 ? 'Not all addresses were saved.' : '' - }` - ) + triggerErrorToast({ + title: 'Error saving addresses', + body: i > 0 ? 'Not all addresses were saved.' : '', + }) } return } } if (count === 1) { - triggerSuccessToast('Successfully generated 1 address.') + triggerSuccessToast({ title: 'Generated 1 address' }) } else { - triggerSuccessToast(`Successfully generated ${count} addresses.`) + triggerSuccessToast({ + title: `Generated ${count} addresses`, + }) } // if successfully generated an address, cache the seed diff --git a/apps/walletd/dialogs/WalletRemoveDialog.tsx b/apps/walletd/dialogs/WalletRemoveDialog.tsx index 8df362d9d..7e66455f5 100644 --- a/apps/walletd/dialogs/WalletRemoveDialog.tsx +++ b/apps/walletd/dialogs/WalletRemoveDialog.tsx @@ -74,9 +74,12 @@ export function WalletRemoveDialog({ }, }) if (response.error) { - triggerErrorToast(response.error) + triggerErrorToast({ + title: 'Error removing wallet', + body: response.error, + }) } else { - triggerSuccessToast('Wallet permanently removed.') + triggerSuccessToast({ title: 'Wallet permanently removed' }) form.reset() closeDialog() router.push(routes.home) diff --git a/apps/walletd/dialogs/WalletSendLedgerDialog/useSendForm.tsx b/apps/walletd/dialogs/WalletSendLedgerDialog/useSendForm.tsx index d50386859..24c375351 100644 --- a/apps/walletd/dialogs/WalletSendLedgerDialog/useSendForm.tsx +++ b/apps/walletd/dialogs/WalletSendLedgerDialog/useSendForm.tsx @@ -114,7 +114,9 @@ export function useSendForm({ params, step, onConfirm }: Props) { }) if (error) { - triggerErrorToast(error) + triggerErrorToast({ + title: error, + }) return } @@ -136,7 +138,7 @@ export function useSendForm({ params, step, onConfirm }: Props) { setWaitingForUser(true) const { signedTransaction, error } = await fundAndSign(params) if (error) { - triggerErrorToast(error) + triggerErrorToast({ title: error }) } else { setTxn(signedTransaction) form.setValue('isSigned', true) diff --git a/apps/walletd/dialogs/WalletSendSeedDialog/useSendForm.tsx b/apps/walletd/dialogs/WalletSendSeedDialog/useSendForm.tsx index 5b4064524..7c3409df3 100644 --- a/apps/walletd/dialogs/WalletSendSeedDialog/useSendForm.tsx +++ b/apps/walletd/dialogs/WalletSendSeedDialog/useSendForm.tsx @@ -84,7 +84,7 @@ export function useSendForm({ walletId, params, onConfirm }: Props) { }) if (error) { - triggerErrorToast(error) + triggerErrorToast({ title: error }) return } diff --git a/apps/walletd/dialogs/WalletUpdateDialog/index.tsx b/apps/walletd/dialogs/WalletUpdateDialog/index.tsx index 871c8df62..41f8cfdf2 100644 --- a/apps/walletd/dialogs/WalletUpdateDialog/index.tsx +++ b/apps/walletd/dialogs/WalletUpdateDialog/index.tsx @@ -117,7 +117,10 @@ export function WalletUpdateDialog({ }, }) if (response.error) { - triggerErrorToast(response.error) + triggerErrorToast({ + title: 'Error updating wallet', + body: response.error, + }) } else { closeAndReset() } diff --git a/apps/walletd/dialogs/_sharedWalletSend/useCancel.tsx b/apps/walletd/dialogs/_sharedWalletSend/useCancel.tsx index 1d018a6ae..29e5c4f7e 100644 --- a/apps/walletd/dialogs/_sharedWalletSend/useCancel.tsx +++ b/apps/walletd/dialogs/_sharedWalletSend/useCancel.tsx @@ -25,7 +25,10 @@ export function useCancel() { }, }) if (response.error) { - triggerErrorToast(response.error) + triggerErrorToast({ + title: 'Error canceling transaction', + body: response.error, + }) } }, [walletId, walletRelease] diff --git a/libs/design-system/src/app/SyncerConnectPeerDialog.tsx b/libs/design-system/src/app/SyncerConnectPeerDialog.tsx index ad194dcd8..c1369fd3a 100644 --- a/libs/design-system/src/app/SyncerConnectPeerDialog.tsx +++ b/libs/design-system/src/app/SyncerConnectPeerDialog.tsx @@ -1,7 +1,7 @@ 'use client' import { Paragraph } from '../core/Paragraph' -import { triggerToast } from '../lib/toast' +import { triggerSuccessToast } from '../lib/toast' import { FormFieldFormik, FormSubmitButtonFormik, @@ -58,7 +58,7 @@ export function SyncerConnectPeerDialog({ ) actions.setStatus({ error: formattedError }) } else { - triggerToast('Connected to peer') + triggerSuccessToast({ title: 'Connected to peer' }) actions.resetForm() onOpenChange(false) } diff --git a/libs/design-system/src/form/configurationFields.ts b/libs/design-system/src/form/configurationFields.ts index bf7db5d8a..d95b87cfc 100644 --- a/libs/design-system/src/form/configurationFields.ts +++ b/libs/design-system/src/form/configurationFields.ts @@ -128,11 +128,12 @@ export function useOnInvalid< >(fields: ConfigFields) { return useCallback( (errors: FieldErrors) => { - triggerErrorToast( - entries(errors) + triggerErrorToast({ + title: 'Error', + body: entries(errors) .map(([key, e]) => `${fields[key].title || key}: ${e?.message}`) - .join(', ') - ) + .join(', '), + }) }, [fields] ) diff --git a/libs/design-system/src/lib/clipboard.ts b/libs/design-system/src/lib/clipboard.tsx similarity index 53% rename from libs/design-system/src/lib/clipboard.ts rename to libs/design-system/src/lib/clipboard.tsx index e088403cc..d4d65f6d0 100644 --- a/libs/design-system/src/lib/clipboard.ts +++ b/libs/design-system/src/lib/clipboard.tsx @@ -1,12 +1,13 @@ import React from 'react' import { writeText, write } from 'clipboard-polyfill' -import { ToastOptions, triggerToast, triggerToastNode } from './toast' +import { ToastOptions, triggerToast } from './toast' +import { Copy24 } from '@siafoundation/react-icons' export const copyToClipboard = (text: string, entity?: string) => { const message = entity ? `Copied ${entity} to clipboard` : 'Copied to clipboard' - triggerToast(message) + triggerToast({ title: message, icon: }) writeText(text) } @@ -18,15 +19,23 @@ export const copyImageToClipboard = ( const message = entity ? `Copied ${entity} to clipboard` : 'Copied to clipboard' - triggerToast(message) + triggerToast({ title: message, icon: }) write([new ClipboardItem({ [type]: image })]) } -export const copyToClipboardCustom = ( - text: string, - message: React.ReactNode, +export const copyToClipboardCustom = ({ + text, + title, + body, + icon, + options, +}: { + text: string + title: React.ReactNode + body: React.ReactNode + icon?: React.ReactNode options?: ToastOptions -) => { - triggerToastNode(message, options) +}) => { + triggerToast({ title, body, icon: icon || , options }) writeText(text) } diff --git a/libs/design-system/src/lib/toast.tsx b/libs/design-system/src/lib/toast.tsx index 2846d550e..deb24fc46 100644 --- a/libs/design-system/src/lib/toast.tsx +++ b/libs/design-system/src/lib/toast.tsx @@ -1,65 +1,109 @@ 'use client' -import { CheckmarkOutline16, CloseOutline16 } from '@siafoundation/react-icons' -import toast, { - Renderable, - Toaster as RToaster, - ToastOptions, -} from 'react-hot-toast' +import { + CheckmarkOutline16, + CheckmarkOutline24, + Close16, + CloseOutline16, + CloseOutline24, +} from '@siafoundation/react-icons' +import toast, { Toaster as RToaster, ToastOptions } from 'react-hot-toast' import { cx } from 'class-variance-authority' import { panelStyles } from '../core/Panel' import React from 'react' import { Text } from '../core/Text' +import { Button } from '../core/Button' +import { Tooltip } from '../core/Tooltip' +import { ScrollArea } from '../core/ScrollArea' export type { ToastOptions } -export const triggerToast = ( - text: React.ReactNode, - options: ToastOptions = {} -) => { - toast( - - {typeof text === 'string' && text.length > 200 - ? `${text.slice(0, 200)}` - : text} - , - buildToastOptions(options) +function ToastLayout({ + icon, + title, + body, + toastId, +}: { + icon?: React.ReactNode + title: React.ReactNode + body: React.ReactNode + toastId: string +}) { + return ( +
+
+ {icon && ( + + {icon} + + )} + + + {title} + + +
+ +
+
+ {body && ( +
+ +
+ + {body} + +
+
+
+ )} +
) } -export const triggerToastNode = ( - text: React.ReactNode, - options: ToastOptions = {} -) => { - toast(text as Renderable, buildToastOptions(options)) +type ToastParams = { + title: React.ReactNode + body?: React.ReactNode + icon?: React.ReactNode + options?: ToastOptions } -export const triggerSuccessToast = ( - text: React.ReactNode, - options: ToastOptions = {} -) => { - toast.success( - - {typeof text === 'string' && text.length > 200 - ? `${text.slice(0, 200)}...` - : text} - , +export const triggerToast = ({ + title, + body, + icon, + options = {}, +}: ToastParams) => { + toast( + (t) => , buildToastOptions(options) ) } -export const triggerErrorToast = ( - text: React.ReactNode, - options: ToastOptions = {} -) => { - toast.error( - - {typeof text === 'string' && text.length > 200 - ? `${text.slice(0, 200)}...` - : text} - , - buildToastOptions(options) - ) +export function triggerSuccessToast({ title, body, options }: ToastParams) { + triggerToast({ + title, + body, + icon: , + options, + }) +} + +export function triggerErrorToast({ title, body, options }: ToastParams) { + triggerToast({ + title, + body, + icon: , + options, + }) } export function buildToastOptions({ @@ -71,11 +115,11 @@ export function buildToastOptions({ duration: 6_000, className: cx( panelStyles(), - 'font-sans font-normal', - 'text-gray-1100 dark:text-white', - 'max-w-[800px] overflow-hidden text-ellipsis', + 'overflow-hidden', + '!max-w-[800px]', '[&>div]:overflow-hidden', - '[&>div]:flex-1', + '!p-0', + 'z-50', className ), success: { @@ -97,5 +141,12 @@ export function buildToastOptions({ } export function Toaster() { - return + return ( + + ) }