Skip to content

Commit

Permalink
fix: Correct typo in containerClassName and remove unused RouteErrorB…
Browse files Browse the repository at this point in the history
…oundary component
  • Loading branch information
berry-13 committed Jan 22, 2025
1 parent c8ef5a0 commit a406830
Show file tree
Hide file tree
Showing 3 changed files with 218 additions and 95 deletions.
2 changes: 1 addition & 1 deletion client/src/components/Chat/Landing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export default function Landing({ Header }: { Header?: ReactNode }) {
assistantMap={assistantMap}
conversation={conversation}
endpointsConfig={endpointsConfig}
containerClassName={containerClassName}
containerClassName={containerClassNam2e}
context="landing"
className="h-2/3 w-2/3"
size={41}
Expand Down
216 changes: 216 additions & 0 deletions client/src/routes/RouteErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
import { useRouteError } from 'react-router-dom';
import { Button } from '~/components/ui';

interface UserAgentData {
getHighEntropyValues(hints: string[]): Promise<{ platform: string; platformVersion: string }>;
}

type PlatformInfo = {
os: string;
version?: string;
};

const formatStackTrace = (stack: string) => {
return stack
.split('\n')
.map((line) => line.trim())
.filter(Boolean)
.map((line, i) => ({
number: i + 1,
content: line,
}));
};

const getPlatformInfo = async (): Promise<PlatformInfo> => {
if ('userAgentData' in navigator) {
try {
const ua = navigator.userAgentData as UserAgentData;
const highEntropyValues = await ua.getHighEntropyValues(['platform', 'platformVersion']);
return {
os: highEntropyValues.platform,
version: highEntropyValues.platformVersion,
};
} catch (e) {
console.warn('Failed to get high entropy values:', e);
}
}

const userAgent = navigator.userAgent.toLowerCase();

if (userAgent.includes('mac')) {
return { os: 'macOS' };
}
if (userAgent.includes('win')) {
return { os: 'Windows' };
}
if (userAgent.includes('linux')) {
return { os: 'Linux' };
}
if (userAgent.includes('android')) {
return { os: 'Android' };
}
if (userAgent.includes('ios') || userAgent.includes('iphone') || userAgent.includes('ipad')) {
return { os: 'iOS' };
}

return { os: 'Unknown' };
};

const getBrowserInfo = async () => {
const platformInfo = await getPlatformInfo();
return {
userAgent: navigator.userAgent,
platform: platformInfo.os,
platformVersion: platformInfo.version,
language: navigator.language,
windowSize: `${window.innerWidth}x${window.innerHeight}`,
};
};

export default function RouteErrorBoundary() {
const typedError = useRouteError() as {
message?: string;
stack?: string;
status?: number;
statusText?: string;
data?: unknown;
};

const errorDetails = {
message: typedError.message ?? 'An unexpected error occurred',
stack: typedError.stack,
status: typedError.status,
statusText: typedError.statusText,
data: typedError.data,
};

const handleDownloadLogs = async () => {
const browser = await getBrowserInfo();
const errorLog = {
timestamp: new Date().toISOString(),
browser,
error: {
...errorDetails,
stack:
errorDetails.stack != null && errorDetails.stack.trim() !== ''
? formatStackTrace(errorDetails.stack)
: undefined,
},
};

const blob = new Blob([JSON.stringify(errorLog, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `error-log-${new Date().toISOString()}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
};

const handleCopyStack = async () => {
if (errorDetails.stack != null && errorDetails.stack !== '') {
await navigator.clipboard.writeText(errorDetails.stack);
}
};

return (
<div
role="alert"
className="flex min-h-screen flex-col items-center justify-center bg-surface-primary bg-gradient-to-br"
>
<div className="bg-surface-primary/60 mx-4 w-11/12 max-w-4xl rounded-2xl border border-border-light p-8 shadow-2xl backdrop-blur-xl">
<h2 className="mb-6 text-center text-3xl font-medium tracking-tight text-text-primary">
Oops! Something Unexpected Occurred
</h2>

{/* Error Message */}
<div className="mb-4 rounded-xl border border-red-500/20 bg-red-500/5 p-4 text-sm text-gray-600 dark:text-gray-200">
<h3 className="mb-2 font-medium">Error Message:</h3>
<pre className="whitespace-pre-wrap text-sm font-light leading-relaxed text-text-primary">
{errorDetails.message}
</pre>
</div>

{/* Status Information */}
{(typeof errorDetails.status === 'number' ||
typeof errorDetails.statusText === 'string') && (
<div className="mb-4 rounded-xl border border-yellow-500/20 bg-yellow-500/5 p-4 text-sm text-text-primary">
<h3 className="mb-2 font-medium">Status:</h3>
<p className="text-text-primary">
{typeof errorDetails.status === 'number' && `${errorDetails.status} `}
{typeof errorDetails.statusText === 'string' && errorDetails.statusText}
</p>
</div>
)}

{/* Stack Trace - Collapsible */}
{errorDetails.stack != null && errorDetails.stack.trim() !== '' && (
<details className="group mb-4 rounded-xl border border-border-light p-4">
<summary className="mb-2 flex cursor-pointer items-center justify-between text-sm font-medium text-text-primary">
<span>Stack Trace</span>
<div className="flex items-center">
<Button
variant="outline"
size="sm"
onClick={handleCopyStack}
className="ml-2 px-2 py-1 text-xs"
>
Copy
</Button>
</div>
</summary>
<div className="overflow-x-auto rounded-lg bg-black/5 p-4 dark:bg-white/5">
{formatStackTrace(errorDetails.stack).map(({ number, content }) => (
<div key={number} className="flex">
<span className="select-none pr-4 font-mono text-xs text-text-secondary">
{String(number).padStart(3, '0')}
</span>
<pre className="flex-1 font-mono text-xs leading-relaxed text-text-primary">
{content}
</pre>
</div>
))}
</div>
</details>
)}

{/* Additional Error Data */}
{errorDetails.data != null && (
<details className="group mb-4 rounded-xl border border-border-light p-4">
<summary className="mb-2 flex cursor-pointer items-center justify-between text-sm font-medium text-text-primary">
<span>Additional Details</span>
<span className="transition-transform group-open:rotate-90">{'>'}</span>
</summary>
<pre className="whitespace-pre-wrap text-xs font-light leading-relaxed text-text-primary">
{JSON.stringify(errorDetails.data, null, 2)}
</pre>
</details>
)}

<div className="mt-6 flex flex-col gap-4">
<p className="text-sm font-light text-text-secondary">Please try one of the following:</p>
<ul className="list-inside list-disc text-sm text-text-secondary">
<li>Refresh the page</li>
<li>Clear your browser cache</li>
<li>Check your internet connection</li>
<li>Contact the Admin if the issue persists</li>
</ul>
<div className="mt-4 flex flex-col items-center gap-4 sm:flex-row sm:justify-center">
<Button
variant="submit"
onClick={() => window.location.reload()}
className="w-full sm:w-auto"
>
Refresh Page
</Button>
<Button variant="outline" onClick={handleDownloadLogs} className="w-full sm:w-auto">
Download Error Logs
</Button>
</div>
</div>
</div>
</div>
);
}
95 changes: 1 addition & 94 deletions client/src/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import {
ApiErrorWatcher,
} from '~/components/Auth';
import { AuthContextProvider } from '~/hooks/AuthContext';
import RouteErrorBoundary from './RouteErrorBoundary';
import StartupLayout from './Layouts/Startup';
import LoginLayout from './Layouts/Login';
import dashboardRoutes from './Dashboard';
import ShareRoute from './ShareRoute';
import ChatRoute from './ChatRoute';
import Search from './Search';
import Root from './Root';
import { useRouteError } from 'react-router-dom';

const AuthLayout = () => (
<AuthContextProvider>
Expand All @@ -24,99 +24,6 @@ const AuthLayout = () => (
</AuthContextProvider>
);

function RouteErrorBoundary() {
const typedError = useRouteError() as {
message?: string;
stack?: string;
status?: number;
statusText?: string;
data?: unknown;
};

const errorDetails = {
message: typedError.message ?? 'An unexpected error occurred',
stack: typedError.stack,
status: typedError.status,
statusText: typedError.statusText,
data: typedError.data,
};

return (
<div
role="alert"
className="flex min-h-screen flex-col items-center justify-center bg-surface-primary bg-gradient-to-br"
>
<div className="bg-surface-primary/60 mx-4 w-full max-w-4xl rounded-2xl border border-border-light p-8 shadow-2xl backdrop-blur-xl">
<h2 className="mb-6 text-center text-3xl font-medium tracking-tight text-text-primary">
Oops! Something went wrong
</h2>

{/* Error Message */}
<div className="mb-4 rounded-xl border border-red-500/20 bg-red-500/5 p-4 text-sm text-gray-600 dark:text-gray-200">
<h3 className="mb-2 font-medium">Error Message:</h3>
<pre className="whitespace-pre-wrap text-sm font-light leading-relaxed text-text-primary">
{errorDetails.message}
</pre>
</div>

{/* Status Information */}
{(typeof errorDetails.status === 'number' ||
typeof errorDetails.statusText === 'string') && (
<div className="mb-4 rounded-xl border border-yellow-500/20 bg-yellow-500/5 p-4 text-sm text-text-primary">
<h3 className="mb-2 font-medium">Status:</h3>
<p className="text-text-primary">
{typeof errorDetails.status === 'number' && `${errorDetails.status} `}
{typeof errorDetails.statusText === 'string' && errorDetails.statusText}
</p>
</div>
)}

{/* Stack Trace - Collapsible */}
{errorDetails.stack && (
<details className="mb-4 rounded-xl border border-border-light p-4">
<summary className="mb-2 cursor-pointer text-sm font-medium text-text-primary">
Stack Trace
</summary>
<pre className="overflow-x-auto whitespace-pre-wrap text-xs font-light leading-relaxed text-text-primary">
{errorDetails.stack}
</pre>
</details>
)}

{/* Additional Error Data */}
{errorDetails.data && (
<details className="mb-4 rounded-xl border border-border-light p-4">
<summary className="mb-2 cursor-pointer text-sm font-medium text-text-primary">
Additional Details
</summary>
<pre className="whitespace-pre-wrap text-xs font-light leading-relaxed text-text-primary">
{JSON.stringify(errorDetails.data, null, 2)}
</pre>
</details>
)}

<div className="mt-6 flex flex-col gap-4">
<p className="text-sm font-light text-text-secondary">Please try one of the following:</p>
<ul className="list-inside list-disc text-sm text-text-secondary">
<li>Refresh the page</li>
<li>Clear your browser cache</li>
<li>Check your internet connection</li>
<li>Contact the Admin if the issue persists</li>
</ul>
<div className="mt-4 flex justify-center gap-4">
<button
onClick={() => window.location.reload()}
className="rounded-lg bg-surface-submit px-4 py-2 text-white transition-colors hover:bg-surface-submit-hover"
>
Refresh Page
</button>
</div>
</div>
</div>
</div>
);
}

export const router = createBrowserRouter([
{
path: 'share/:shareId',
Expand Down

0 comments on commit a406830

Please sign in to comment.