Better error toast when previewing bot

Closes #475
This commit is contained in:
Baptiste Arnaud
2023-04-27 11:21:32 +02:00
parent 3c6a666d9b
commit d448e64dc9
7 changed files with 235 additions and 40 deletions

View File

@@ -0,0 +1,139 @@
import { Flex, HStack, IconButton, Stack, Text } from '@chakra-ui/react'
import { AlertIcon, CloseIcon, InfoIcon, SmileIcon } from './icons'
import { CodeEditor } from './inputs/CodeEditor'
import { LanguageName } from '@uiw/codemirror-extensions-langs'
export type ToastProps = {
title?: string
description?: string
details?: {
content: string
lang: LanguageName
}
status?: 'info' | 'error' | 'success'
icon?: React.ReactNode
primaryButton?: React.ReactNode
secondaryButton?: React.ReactNode
onClose: () => void
}
export const Toast = ({
status = 'error',
title,
description,
details,
icon,
primaryButton,
secondaryButton,
onClose,
}: ToastProps) => {
return (
<Flex
p={3}
rounded="md"
bgColor="white"
borderWidth="1px"
shadow="sm"
fontSize="sm"
pos="relative"
maxW="450px"
>
<HStack alignItems="flex-start" pr="7" spacing="3" w="full">
<Icon customIcon={icon} status={status} />{' '}
<Stack spacing={3} flex="1">
<Stack spacing={1}>
{title && <Text fontWeight="semibold">{title}</Text>}
{description && <Text>{description}</Text>}
</Stack>
{details && (
<CodeEditor
isReadOnly
value={details.content}
lang={details.lang}
maxHeight="200px"
maxWidth="calc(450px - 100px)"
/>
)}
{(secondaryButton || primaryButton) && (
<HStack>
{secondaryButton}
{primaryButton}
</HStack>
)}
</Stack>
</HStack>
<IconButton
aria-label="Close"
icon={<CloseIcon />}
size="sm"
onClick={onClose}
variant="ghost"
pos="absolute"
top={1}
right={1}
/>
</Flex>
)
}
const Icon = ({
customIcon,
status,
}: {
customIcon?: React.ReactNode
status: ToastProps['status']
}) => {
const color = parseColor(status)
const icon = parseIcon(status, customIcon)
return (
<Flex
bgColor={`${color}.50`}
boxSize="40px"
justifyContent="center"
alignItems="center"
rounded="full"
flexShrink={0}
>
<Flex
bgColor={`${color}.100`}
boxSize="30px"
justifyContent="center"
alignItems="center"
rounded="full"
fontSize="18px"
color={`${color}.600`}
>
{icon}
</Flex>
</Flex>
)
}
const parseColor = (status: ToastProps['status']) => {
if (!status) return 'red'
switch (status) {
case 'error':
return 'red'
case 'success':
return 'green'
case 'info':
return 'blue'
}
}
const parseIcon = (
status: ToastProps['status'],
customIcon?: React.ReactNode
) => {
if (customIcon) return customIcon
switch (status) {
case 'error':
return <AlertIcon />
case 'success':
return <SmileIcon />
case 'info':
return <InfoIcon />
}
}

View File

@@ -604,3 +604,20 @@ export const ShuffleIcon = (props: IconProps) => (
<line x1="4" y1="4" x2="9" y2="9"></line>
</Icon>
)
export const InfoIcon = (props: IconProps) => (
<Icon viewBox="0 0 24 24" {...featherIconsBaseProps} {...props}>
<circle cx="12" cy="12" r="10"></circle>
<line x1="12" y1="16" x2="12" y2="12"></line>
<line x1="12" y1="8" x2="12.01" y2="8"></line>
</Icon>
)
export const SmileIcon = (props: IconProps) => (
<Icon viewBox="0 0 24 24" {...featherIconsBaseProps} {...props}>
<circle cx="12" cy="12" r="10"></circle>
<path d="M8 14s1.5 2 4 2 4-2 4-2"></path>
<line x1="9" y1="9" x2="9.01" y2="9"></line>
<line x1="15" y1="9" x2="15.01" y2="9"></line>
</Icon>
)

View File

@@ -25,6 +25,7 @@ type Props = {
debounceTimeout?: number
withVariableButton?: boolean
height?: string
maxHeight?: string
onChange?: (value: string) => void
}
export const CodeEditor = ({
@@ -32,6 +33,7 @@ export const CodeEditor = ({
lang,
onChange,
height = '250px',
maxHeight = '70vh',
withVariableButton = true,
isReadOnly = false,
debounceTimeout = 1000,
@@ -93,9 +95,10 @@ export const CodeEditor = ({
pos="relative"
onMouseEnter={onOpen}
onMouseLeave={onClose}
maxWidth={props.maxWidth}
sx={{
'& .cm-editor': {
maxH: '70vh',
maxH: maxHeight,
outline: '0px solid transparent !important',
rounded: 'md',
},