diff --git a/web/src/app/app/chats/_ChatsListContainer/ChatItemsContainer.tsx b/web/src/app/app/chats/_ChatsListContainer/ChatItemsContainer.tsx index f768a6121..644e7adb5 100644 --- a/web/src/app/app/chats/_ChatsListContainer/ChatItemsContainer.tsx +++ b/web/src/app/app/chats/_ChatsListContainer/ChatItemsContainer.tsx @@ -178,9 +178,9 @@ const TitleCell = React.memo<{ title: string; status: VerificationStatus; chatId ); TitleCell.displayName = 'TitleCell'; -const OwnerCell = memo<{ name: string; image: string | null | undefined }>(({ name, image }) => ( +const OwnerCell = memo<{ name: string; image: string | undefined }>(({ name, image }) => (
- +
)); OwnerCell.displayName = 'OwnerCell'; diff --git a/web/src/components/ui/buttons/Button.tsx b/web/src/components/ui/buttons/Button.tsx index 952eadfe9..fff141dcc 100644 --- a/web/src/components/ui/buttons/Button.tsx +++ b/web/src/components/ui/buttons/Button.tsx @@ -30,9 +30,9 @@ const roundingVariants = { }; const sizeVariants = { - default: 'h-7', - tall: 'h-8', - small: 'h-6' + default: 'h-6', + tall: 'h-7', + small: 'h-5' }; export const buttonVariants = cva( diff --git a/web/src/components/ui/card/CardBase.tsx b/web/src/components/ui/card/CardBase.tsx index 56f27ec83..e857306ab 100644 --- a/web/src/components/ui/card/CardBase.tsx +++ b/web/src/components/ui/card/CardBase.tsx @@ -20,7 +20,7 @@ const Card = React.forwardRef = { + title: 'Base/Cards/CodeCard', + component: CodeCard, + parameters: { + layout: 'centered' + }, + tags: ['autodocs'], + decorators: [ + (Story) => ( +
+ +
+ ) + ] +}; + +export default meta; +type Story = StoryObj; + +const sampleCode = `function helloWorld() { + console.log('Hello, World!'); +}`; + +const longCode = `import React from 'react'; +import { Button } from 'antd'; + +export const MyComponent = () => { + const handleClick = () => { + console.log('Button clicked!'); + }; + + return ( +
+

Hello World

+ +
+ ); +};`; + +export const Default: Story = { + args: { + code: sampleCode, + language: 'javascript', + fileName: 'example.js', + className: 'w-[500px] h-[300px]' + } +}; + +export const ReadOnly: Story = { + args: { + code: sampleCode, + language: 'javascript', + fileName: 'readonly.js', + readOnly: true, + className: 'w-[500px] h-[300px]' + } +}; + +export const LargerEditor: Story = { + args: { + code: longCode, + language: 'typescript', + fileName: 'MyComponent.tsx', + className: 'w-[600px] h-[400px]' + } +}; + +export const NoButtons: Story = { + args: { + code: sampleCode, + language: 'javascript', + fileName: 'no-buttons.js', + buttons: false, + className: 'w-[500px] h-[300px]' + } +}; + +export const CustomButtons: Story = { + args: { + code: sampleCode, + language: 'javascript', + fileName: 'custom-buttons.js', + buttons:
Custom Buttons
, + className: 'w-[500px] h-[300px]' + } +}; diff --git a/web/src/components/ui/card/CodeCard.tsx b/web/src/components/ui/card/CodeCard.tsx index 62db18684..73d6d1754 100644 --- a/web/src/components/ui/card/CodeCard.tsx +++ b/web/src/components/ui/card/CodeCard.tsx @@ -50,6 +50,7 @@ export const CodeCard: React.FC<{ readOnly={readOnly} height="100%" onMetaEnter={onMetaEnter} + className="border-none" /> diff --git a/web/src/components/ui/charts/BusterChartLegend/LegendItem.tsx b/web/src/components/ui/charts/BusterChartLegend/LegendItem.tsx index 30d89cc18..570ebd3ea 100644 --- a/web/src/components/ui/charts/BusterChartLegend/LegendItem.tsx +++ b/web/src/components/ui/charts/BusterChartLegend/LegendItem.tsx @@ -105,7 +105,7 @@ const LegendItemStandard = React.memo( onMouseEnter={onMouseEnterHandler} onMouseLeave={onMouseLeaveHandler} className={cn( - 'flex flex-col justify-center space-y-0', + 'flex flex-col justify-center space-y-1', 'h-[24px] rounded-sm px-2.5', clickable && 'transition-background hover:bg-item-hover cursor-pointer duration-100' )}> diff --git a/web/src/components/ui/charts/BusterChartLegend/hooks/useMeasureElement.ts b/web/src/components/ui/charts/BusterChartLegend/hooks/useMeasureElement.ts deleted file mode 100644 index 99dcfbeaf..000000000 --- a/web/src/components/ui/charts/BusterChartLegend/hooks/useMeasureElement.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { useCallback, useEffect, useRef, useState } from 'react'; - -export const useMeasureElement = (useMeasure?: boolean) => { - const elementRef = useRef(null); - const [dimensions, setDimensions] = useState({ fullWidth: 0, fullHeight: 0 }); - - const updateDimensions = useCallback(() => { - if (elementRef.current) { - const rect = elementRef.current.getBoundingClientRect(); - - setDimensions({ - fullWidth: rect.width, - fullHeight: rect.height - }); - } - }, []); - - useEffect(() => { - if (!elementRef.current || !useMeasure) return; - - const resizeObserver = new ResizeObserver(updateDimensions); - resizeObserver.observe(elementRef.current); - - return () => { - resizeObserver.disconnect(); - }; - }, [updateDimensions, useMeasure]); - - return { - elementRef, - ...dimensions - }; -}; diff --git a/web/src/components/ui/charts/BusterChartLegend/stories/BusterChartLegend.stories.tsx b/web/src/components/ui/charts/BusterChartLegend/stories/BusterChartLegend.stories.tsx new file mode 100644 index 000000000..eee322857 --- /dev/null +++ b/web/src/components/ui/charts/BusterChartLegend/stories/BusterChartLegend.stories.tsx @@ -0,0 +1,146 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { BusterChartLegend } from '../BusterChartLegend'; +import { ChartType } from '../../interfaces'; + +const meta: Meta = { + title: 'Base/Charts/BusterChartLegend', + component: BusterChartLegend, + parameters: { + layout: 'centered' + }, + tags: ['autodocs'], + argTypes: { + onClickItem: { action: 'clicked' }, + onFocusItem: { action: 'focused' }, + showLegendHeadline: { + control: 'select', + description: + 'Show the legend headline will only work if a headline is provided (see example)', + options: [false, 'total', 'average', 'min', 'max', 'current', 'median'] + } + } +}; + +export default meta; +type Story = StoryObj; + +const defaultLegendItems = [ + { + color: '#1677FF', + inactive: false, + type: ChartType.Line, + formattedName: 'Revenue', + id: 'revenue', + serieName: 'revenue' + }, + { + color: '#52C41A', + inactive: false, + type: ChartType.Line, + formattedName: 'Profit', + id: 'profit', + serieName: 'profit' + }, + { + color: '#F5222D', + inactive: false, + type: ChartType.Bar, + formattedName: 'Orders', + id: 'orders', + serieName: 'orders' + } +]; + +export const Default: Story = { + args: { + legendItems: defaultLegendItems, + show: true, + animateLegend: true, + containerWidth: 600, + showLegendHeadline: false, + onClickItem: () => {}, + onFocusItem: () => {} + } +}; + +export const WithHeadline: Story = { + args: { + legendItems: [ + { + ...defaultLegendItems[0], + headline: { + type: 'total', + titleAmount: '$1,234,567' + } + }, + { + ...defaultLegendItems[1], + headline: { + type: 'total', + titleAmount: '$567,890' + } + }, + { + ...defaultLegendItems[2], + headline: { + type: 'total', + titleAmount: '$98,765' + } + } + ], + show: true, + animateLegend: true, + containerWidth: 600, + showLegendHeadline: 'total' + } +}; + +export const WithOverflow: Story = { + args: { + legendItems: [ + ...defaultLegendItems, + { + color: '#722ED1', + inactive: false, + type: ChartType.Line, + formattedName: 'Customers', + id: 'customers', + serieName: 'customers' + }, + { + color: '#13C2C2', + inactive: false, + type: ChartType.Line, + formattedName: 'Average Order Value', + id: 'aov', + serieName: 'aov' + }, + { + color: '#FA8C16', + inactive: false, + type: ChartType.Bar, + formattedName: 'Returns', + id: 'returns', + serieName: 'returns' + } + ], + show: true, + animateLegend: true, + containerWidth: 400, + showLegendHeadline: undefined, + onClickItem: () => {}, + onFocusItem: () => {} + } +}; + +export const Hidden: Story = { + args: { + legendItems: defaultLegendItems, + show: false, + animateLegend: true, + containerWidth: 600, + showLegendHeadline: undefined, + onClickItem: () => {}, + onFocusItem: () => {} + } +}; diff --git a/web/src/components/ui/charts/BusterChartLegend/OverflowButton.stories.tsx b/web/src/components/ui/charts/BusterChartLegend/stories/OverflowButton.stories.tsx similarity index 93% rename from web/src/components/ui/charts/BusterChartLegend/OverflowButton.stories.tsx rename to web/src/components/ui/charts/BusterChartLegend/stories/OverflowButton.stories.tsx index 6a24b2b08..03a8807b9 100644 --- a/web/src/components/ui/charts/BusterChartLegend/OverflowButton.stories.tsx +++ b/web/src/components/ui/charts/BusterChartLegend/stories/OverflowButton.stories.tsx @@ -1,6 +1,6 @@ import type { Meta, StoryObj } from '@storybook/react'; -import { OverflowButton } from './OverflowContainer'; -import { ChartType } from '../interfaces'; +import { OverflowButton } from '../OverflowContainer'; +import { ChartType } from '../../interfaces'; const meta = { title: 'Base/Charts/OverflowButton', diff --git a/web/src/components/ui/charts/LoadingComponents/ChartLoadingComponents.tsx b/web/src/components/ui/charts/LoadingComponents/ChartLoadingComponents.tsx index c42cfb424..390986739 100644 --- a/web/src/components/ui/charts/LoadingComponents/ChartLoadingComponents.tsx +++ b/web/src/components/ui/charts/LoadingComponents/ChartLoadingComponents.tsx @@ -1,7 +1,8 @@ 'use client'; -import { ShimmerText, Text } from '@/components/ui'; +import { ShimmerText } from '@/components/ui/text/ShimmerText'; import React from 'react'; +import { cn } from '@/lib/utils'; export const PreparingYourRequestLoader: React.FC<{ className?: string; @@ -12,10 +13,7 @@ export const PreparingYourRequestLoader: React.FC<{ return (
{error || useShimmer === false ? ( - - {/* {!!error && } */} - {error || text} - + {error || text} ) : ( )} @@ -29,9 +27,7 @@ export const NoChartData: React.FC<{ }> = ({ className = '', noDataText = 'The query ran successfully but didn’t return any data' }) => { return (
- - {noDataText} - + {noDataText}
); }; diff --git a/web/src/components/ui/charts/LoadingComponents/NoValidAxis.tsx b/web/src/components/ui/charts/LoadingComponents/NoValidAxis.tsx index d156b17f9..fd9af5759 100644 --- a/web/src/components/ui/charts/LoadingComponents/NoValidAxis.tsx +++ b/web/src/components/ui/charts/LoadingComponents/NoValidAxis.tsx @@ -1,8 +1,6 @@ import React, { useMemo } from 'react'; - -import { Text } from '@/components/ui'; import { useMount } from 'ahooks'; -import { BusterChartProps, ChartType } from '../interfaces'; +import { type BusterChartProps, ChartType } from '../interfaces'; export const NoValidAxis: React.FC<{ type: ChartType; @@ -20,7 +18,7 @@ export const NoValidAxis: React.FC<{ return (
- {inValidChartText} + {inValidChartText}
); }; diff --git a/web/src/components/ui/charts/MetricChart/BusterMetricChart.tsx b/web/src/components/ui/charts/MetricChart/BusterMetricChart.tsx index 100de7608..281269a1e 100644 --- a/web/src/components/ui/charts/MetricChart/BusterMetricChart.tsx +++ b/web/src/components/ui/charts/MetricChart/BusterMetricChart.tsx @@ -16,7 +16,6 @@ export const BusterMetricChart: React.FC = React.memo( metricSubHeader, metricValueAggregate, data, - isDarkMode, animate, columnLabelFormats, metricValueLabel, diff --git a/web/src/components/ui/dropdown/AppDropdownSelect.tsx b/web/src/components/ui/dropdown/AppDropdownSelect.tsx deleted file mode 100644 index cc78c2d06..000000000 --- a/web/src/components/ui/dropdown/AppDropdownSelect.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import { AppPopoverMenu, AppPopoverMenuProps } from '../tooltip'; - -export interface AppDropdownSelectProps extends AppPopoverMenuProps { - items: { - label: React.ReactNode; - key?: string; - index?: number; - onClick?: () => void; - icon?: React.ReactNode; - disabled?: boolean; - link?: string; - }[]; -} - -export const AppDropdownSelect: React.FC = React.memo((props) => { - return ; -}); - -AppDropdownSelect.displayName = 'AppDropdownSelect'; diff --git a/web/src/components/ui/error/GlobalErrorComponent.stories.tsx b/web/src/components/ui/error/GlobalErrorComponent.stories.tsx new file mode 100644 index 000000000..1f17b50bf --- /dev/null +++ b/web/src/components/ui/error/GlobalErrorComponent.stories.tsx @@ -0,0 +1,42 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { GlobalErrorComponent } from './GlobalErrorComponent'; + +const meta: Meta = { + title: 'Base/GlobalErrorComponent', + component: GlobalErrorComponent, + parameters: { + layout: 'fullscreen' + }, + tags: ['autodocs'] +}; + +export default meta; +type Story = StoryObj; + +// Normal state with content +export const Default: Story = { + args: { + children:
Normal application content
+ } +}; + +// Error state +export const WithError: Story = { + args: { + children:
This content won't be visible due to error
+ }, + parameters: { + error: new Error('Simulated error for story') + }, + render: (args) => { + const ErrorTrigger = () => { + throw new Error('Simulated error for story'); + }; + + return ( + + + + ); + } +}; diff --git a/web/src/components/ui/error/GlobalErrorComponent.tsx b/web/src/components/ui/error/GlobalErrorComponent.tsx index 13c6cc240..05edac97a 100644 --- a/web/src/components/ui/error/GlobalErrorComponent.tsx +++ b/web/src/components/ui/error/GlobalErrorComponent.tsx @@ -1,9 +1,15 @@ 'use client'; -import { Button } from 'antd'; import { Component, ErrorInfo, ReactNode } from 'react'; -import { Title } from '@/components/ui'; - +import { Button } from '../buttons/Button'; +import { + Card, + CardContent, + CardHeader, + CardTitle, + CardDescription, + CardFooter +} from '../card/CardBase'; interface Props { children: ReactNode; } @@ -31,26 +37,30 @@ export class GlobalErrorComponent extends Component {
-
-
- - Looks like we hit an error! 😅 - + + +
+

+ Looks like we hit an error! 😅 +

- - Don't worry, it's not you - it's us! - - - If this error persists, please contact Buster support! - -
+
+ Don't worry, it's not you - it's us! +
+
+ If this error persists, please contact Buster support! +
+
+ - - - -
+ + + + + +
); } diff --git a/web/src/components/ui/loaders/CircleSpinnerLoaderContainer.tsx b/web/src/components/ui/loaders/CircleSpinnerLoaderContainer.tsx index a5014e781..c3f7da520 100644 --- a/web/src/components/ui/loaders/CircleSpinnerLoaderContainer.tsx +++ b/web/src/components/ui/loaders/CircleSpinnerLoaderContainer.tsx @@ -1,6 +1,5 @@ import React from 'react'; import CircleSpinnerLoader from './CircleSpinnerLoader'; -import { Text } from '@/components/ui'; export const CircleSpinnerLoaderContainer: React.FC<{ text?: string; @@ -9,7 +8,7 @@ export const CircleSpinnerLoaderContainer: React.FC<{ return (
- {text && {text}} + {text && {text}}
); }; diff --git a/web/src/components/ui/toaster/Toaster.tsx b/web/src/components/ui/toaster/Toaster.tsx index 7974d333d..2d390ef48 100644 --- a/web/src/components/ui/toaster/Toaster.tsx +++ b/web/src/components/ui/toaster/Toaster.tsx @@ -3,7 +3,7 @@ import React from 'react'; import { useTheme } from 'next-themes'; import { Toaster as ToasterSonner } from 'sonner'; -import { CircleCheck } from '@/components/ui/icons'; +import { CircleCheck, CircleXmark, CircleWarning } from '@/components/ui/icons'; type ToasterProps = React.ComponentProps; @@ -16,7 +16,9 @@ const Toaster = ({ ...props }: ToasterProps) => { expand={true} visibleToasts={5} icons={{ - success: + success: , + error: , + warning: }} swipeDirections={['right']} theme={theme as ToasterProps['theme']} @@ -24,7 +26,7 @@ const Toaster = ({ ...props }: ToasterProps) => { toastOptions={{ classNames: { toast: - 'group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg', + 'group toast group-[.toaster]:bg-background! border !p-3 group-[.toaster]:text-foreground! group-[.toaster]:border-border! group-[.toaster]:shadow-hard!', description: 'group-[.toast]:text-muted-foreground', actionButton: 'group-[.toast]:bg-primary group-[.toast]:text-primary-foreground', cancelButton: 'group-[.toast]:bg-border group-[.toast]:text-foreground' diff --git a/web/src/controllers/MetricListContainer/MetricItemsContainer.tsx b/web/src/controllers/MetricListContainer/MetricItemsContainer.tsx index 3345ff90f..b485183e5 100644 --- a/web/src/controllers/MetricListContainer/MetricItemsContainer.tsx +++ b/web/src/controllers/MetricListContainer/MetricItemsContainer.tsx @@ -194,9 +194,9 @@ const TitleCell = React.memo<{ title: string; status: VerificationStatus; metric ); TitleCell.displayName = 'TitleCell'; -const OwnerCell = memo<{ name: string; image: string | null | undefined }>(({ name, image }) => ( +const OwnerCell = memo<{ name: string; image: string | undefined }>(({ name, image }) => (
- +
)); OwnerCell.displayName = 'OwnerCell';