diff --git a/web/src/components/features/errors/GlobalErrorComponent.tsx b/web/src/components/features/errors/GlobalErrorComponent.tsx
index fe54b9d89..d5de986d0 100644
--- a/web/src/components/features/errors/GlobalErrorComponent.tsx
+++ b/web/src/components/features/errors/GlobalErrorComponent.tsx
@@ -1,64 +1,47 @@
'use client';
-import { Component, ErrorInfo, ReactNode } from 'react';
+import React, { ReactNode } from 'react';
import { Button } from '@/components/ui/buttons/Button';
import { Card, CardContent, CardFooter } from '@/components/ui/card/CardBase';
+import { ErrorBoundary } from '@/components/ui/error';
interface Props {
children: ReactNode;
}
-interface State {
- hasError: boolean;
-}
+const ErrorCard = () => {
+ return (
+
+
+
+
+
+ Looks like we hit an error! 😅
+
-export class GlobalErrorComponent extends Component
{
- state = {
- hasError: false
- };
+
+ Don't worry, it's not you - it's us!
+
+
+ If this error persists, please contact Buster support!
+
+
+
- static getDerivedStateFromError(_: Error): State {
- return { hasError: true };
- }
+
+
+
+
+
+
+
+ );
+};
- componentDidCatch(error: Error, errorInfo: ErrorInfo) {
- console.error('Global error:', error, errorInfo);
- }
-
- render() {
- if (this.state.hasError) {
- return (
-
-
-
-
-
- Looks like we hit an error! 😅
-
-
-
- Don't worry, it's not you - it's us!
-
-
- If this error persists, please contact Buster support!
-
-
-
-
-
-
-
-
-
-
-
- );
- }
-
- return this.props.children;
- }
-}
+export const GlobalErrorComponent = ({ children }: Props) => {
+ return }>{children};
+};
diff --git a/web/src/components/features/sidebars/SidebarUserFooter/SidebarUserFooter.stories.tsx b/web/src/components/features/sidebars/SidebarUserFooter/SidebarUserFooter.stories.tsx
index c9faed0fe..1a4f7fd34 100644
--- a/web/src/components/features/sidebars/SidebarUserFooter/SidebarUserFooter.stories.tsx
+++ b/web/src/components/features/sidebars/SidebarUserFooter/SidebarUserFooter.stories.tsx
@@ -23,20 +23,15 @@ type Story = StoryObj;
export const Default: Story = {
args: {
name: 'John Doe',
- email: 'john.doe@example.com'
- }
-};
-
-export const WithoutAvatar: Story = {
- args: {
- name: 'Jane Smith',
- email: 'jane.smith@example.com'
+ email: 'john.doe@example.com',
+ signOut: () => Promise.resolve({ error: '' })
}
};
export const LongName: Story = {
args: {
name: 'Alexander Bartholomew Christopherson III',
- email: 'alexander@example.com'
+ email: 'alexander@example.com',
+ signOut: () => Promise.resolve({ error: '' })
}
};
diff --git a/web/src/components/ui/card/CodeCard.stories.tsx b/web/src/components/ui/card/CodeCard.stories.tsx
index c850c17af..bf8ffd4c1 100644
--- a/web/src/components/ui/card/CodeCard.stories.tsx
+++ b/web/src/components/ui/card/CodeCard.stories.tsx
@@ -25,7 +25,7 @@ const sampleCode = `function helloWorld() {
}`;
const longCode = `import React from 'react';
-import { Button } from 'antd';
+import { Button } from '../buttons';
export const MyComponent = () => {
const handleClick = () => {
diff --git a/web/src/components/ui/charts/BusterChartErrorWrapper.tsx b/web/src/components/ui/charts/BusterChartErrorWrapper.tsx
index 257d0c4e9..4c94b6c86 100644
--- a/web/src/components/ui/charts/BusterChartErrorWrapper.tsx
+++ b/web/src/components/ui/charts/BusterChartErrorWrapper.tsx
@@ -1,40 +1,17 @@
-import { Alert } from 'antd';
-import { Component, ErrorInfo, ReactNode } from 'react';
+import { ErrorCard } from '@/components/ui/error/ErrorCard';
+import { ReactNode } from 'react';
+import { ErrorBoundary } from '../error/ErrorBoundary';
interface Props {
children: ReactNode;
}
-interface State {
- hasError: boolean;
-}
+const ErrorCardComponent: React.FC = () => {
+ return (
+
+ );
+};
-export class BusterChartErrorWrapper extends Component {
- state = {
- hasError: false
- };
-
- static getDerivedStateFromError(_: Error): State {
- return { hasError: true };
- }
-
- componentDidCatch(error: Error, errorInfo: ErrorInfo) {
- console.error('Chart Error:', error, errorInfo);
- }
-
- render() {
- if (this.state.hasError) {
- return (
-
- );
- }
-
- return this.props.children;
- }
-}
+export const BusterChartErrorWrapper: React.FC = ({ children }) => {
+ return }>{children};
+};
diff --git a/web/src/components/ui/error/ErrorBoundary.tsx b/web/src/components/ui/error/ErrorBoundary.tsx
index 03b5a63d7..6bf09d306 100644
--- a/web/src/components/ui/error/ErrorBoundary.tsx
+++ b/web/src/components/ui/error/ErrorBoundary.tsx
@@ -2,6 +2,7 @@ import React, { Component, ErrorInfo, ReactNode } from 'react';
interface Props {
children: ReactNode;
+ errorComponent?: ReactNode;
onError?: () => void;
}
@@ -24,7 +25,7 @@ export class ErrorBoundary extends Component {
render() {
if (this.state.hasError) {
- return Error boundary...;
+ return this.props.errorComponent;
}
return this.props.children;
diff --git a/web/src/components/ui/error/ErrorCard.stories.tsx b/web/src/components/ui/error/ErrorCard.stories.tsx
new file mode 100644
index 000000000..a5efa29ca
--- /dev/null
+++ b/web/src/components/ui/error/ErrorCard.stories.tsx
@@ -0,0 +1,58 @@
+import type { Meta, StoryObj } from '@storybook/react';
+import { ErrorCard } from './ErrorCard';
+
+const meta: Meta = {
+ title: 'UI/Error/ErrorCard',
+ component: ErrorCard,
+ tags: ['autodocs'],
+ argTypes: {
+ error: {
+ control: 'text',
+ description: 'The error message to display'
+ },
+ title: {
+ control: 'text',
+ description: 'Optional title for the error alert'
+ },
+ variant: {
+ control: { type: 'select' },
+ options: ['danger', 'default'],
+ description: 'The visual style of the error alert'
+ }
+ }
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ error: 'Something went wrong. Please try again later.',
+ title: 'Error',
+ variant: 'default'
+ }
+};
+
+export const Danger: Story = {
+ args: {
+ error: 'Failed to save changes. Please check your connection and try again.',
+ title: 'Connection Error',
+ variant: 'danger'
+ }
+};
+
+export const WithoutTitle: Story = {
+ args: {
+ error: 'This is an error message without a title.',
+ variant: 'default'
+ }
+};
+
+export const LongErrorMessage: Story = {
+ args: {
+ error:
+ 'This is a very long error message that might wrap to multiple lines. It contains detailed information about what went wrong and possibly some suggestions on how to fix the issue.',
+ title: 'Detailed Error',
+ variant: 'danger'
+ }
+};
diff --git a/web/src/components/ui/error/ErrorCard.tsx b/web/src/components/ui/error/ErrorCard.tsx
new file mode 100644
index 000000000..29168e134
--- /dev/null
+++ b/web/src/components/ui/error/ErrorCard.tsx
@@ -0,0 +1,42 @@
+import { cva, VariantProps } from 'class-variance-authority';
+import React from 'react';
+import { cn } from '@/lib/classMerge';
+import { Text } from '../typography';
+import { Xmark } from '../icons';
+
+const errorVariants = cva('shadow p-3 rounded', {
+ variants: {
+ variant: {
+ danger: 'bg-danger-foreground text-white',
+ default: 'bg-background text-foreground'
+ }
+ }
+});
+
+export const ErrorCard: React.FC<
+ {
+ error: string;
+ title?: string;
+ className?: string;
+ onClose?: () => void;
+ } & VariantProps
+> = ({ error, title, variant, className, onClose }) => {
+ return (
+
+ {title &&
{title}}
+
+ {error}
+
+ {onClose && (
+
+
+
+ )}
+
+ );
+};