Initial commit: Plane
Some checks failed
Branch Build CE / Build Setup (push) Has been cancelled
Branch Build CE / Build-Push Admin Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Web Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Space Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Live Collaboration Docker Image (push) Has been cancelled
Branch Build CE / Build-Push API Server Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Proxy Docker Image (push) Has been cancelled
Branch Build CE / Build-Push AIO Docker Image (push) Has been cancelled
Branch Build CE / Upload Build Assets (push) Has been cancelled
Branch Build CE / Build Release (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Codespell / Check for spelling errors (push) Has been cancelled
Sync Repositories / sync_changes (push) Has been cancelled
Some checks failed
Branch Build CE / Build Setup (push) Has been cancelled
Branch Build CE / Build-Push Admin Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Web Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Space Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Live Collaboration Docker Image (push) Has been cancelled
Branch Build CE / Build-Push API Server Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Proxy Docker Image (push) Has been cancelled
Branch Build CE / Build-Push AIO Docker Image (push) Has been cancelled
Branch Build CE / Upload Build Assets (push) Has been cancelled
Branch Build CE / Build Release (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Codespell / Check for spelling errors (push) Has been cancelled
Sync Repositories / sync_changes (push) Has been cancelled
Synced from upstream: 8853637e981ed7d8a6cff32bd98e7afe20f54362
This commit is contained in:
155
apps/web/app/error/dev.tsx
Normal file
155
apps/web/app/error/dev.tsx
Normal file
@@ -0,0 +1,155 @@
|
||||
"use client";
|
||||
|
||||
// plane imports
|
||||
import { isRouteErrorResponse } from "react-router";
|
||||
import { Banner } from "@plane/propel/banner";
|
||||
import { Button } from "@plane/propel/button";
|
||||
import { Card, ECardVariant } from "@plane/propel/card";
|
||||
import { InfoFillIcon } from "@plane/propel/icons";
|
||||
|
||||
interface ErrorActionsProps {
|
||||
onGoHome: () => void;
|
||||
onReload?: () => void;
|
||||
}
|
||||
|
||||
const ErrorActions: React.FC<ErrorActionsProps> = ({ onGoHome, onReload }) => (
|
||||
<div className="flex gap-3 pt-2">
|
||||
<Button variant="primary" size="md" onClick={onGoHome}>
|
||||
Go to home
|
||||
</Button>
|
||||
{onReload && (
|
||||
<Button variant="outline-primary" size="md" onClick={onReload}>
|
||||
Reload page
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
interface DevErrorComponentProps {
|
||||
error: unknown;
|
||||
onGoHome: () => void;
|
||||
onReload: () => void;
|
||||
}
|
||||
|
||||
export const DevErrorComponent: React.FC<DevErrorComponentProps> = ({ error, onGoHome, onReload }) => {
|
||||
if (isRouteErrorResponse(error)) {
|
||||
return (
|
||||
<div className="min-h-screen bg-custom-background-90 p-6 flex items-start justify-center transition-none">
|
||||
<div className="w-full max-w-4xl mt-12 space-y-4 transition-none">
|
||||
<Banner
|
||||
variant="error"
|
||||
icon={<InfoFillIcon className="size-5" />}
|
||||
title="Route Error Response"
|
||||
animationDuration={0}
|
||||
/>
|
||||
|
||||
<Card variant={ECardVariant.WITH_SHADOW} className="!p-6 transition-none">
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h2 className="text-2xl font-semibold text-red-500 mb-2">
|
||||
{error.status} {error.statusText}
|
||||
</h2>
|
||||
<div className="h-px w-full bg-custom-border-200" />
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<h3 className="text-sm font-medium text-custom-text-300 uppercase tracking-wide">Error Data</h3>
|
||||
<div className="bg-custom-background-80 rounded-md p-4">
|
||||
<p className="text-sm text-custom-text-200 font-mono">{error.data}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ErrorActions onGoHome={onGoHome} onReload={onReload} />
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (error instanceof Error) {
|
||||
return (
|
||||
<div className="min-h-screen bg-custom-background-90 p-6 flex items-start justify-center transition-none">
|
||||
<div className="w-full max-w-4xl mt-12 space-y-4 transition-none">
|
||||
<Banner
|
||||
variant="error"
|
||||
icon={<InfoFillIcon className="size-5" />}
|
||||
title="Runtime Error"
|
||||
animationDuration={0}
|
||||
/>
|
||||
<Card variant={ECardVariant.WITH_SHADOW} className="!p-6 transition-none">
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h2 className="text-2xl font-semibold text-red-500 mb-2">Error</h2>
|
||||
<div className="h-px w-full bg-custom-border-200" />
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<h3 className="text-sm font-medium text-custom-text-300 uppercase tracking-wide">Message</h3>
|
||||
<div className="bg-custom-background-80 rounded-md p-4">
|
||||
<p className="text-sm text-custom-text-100 font-medium">{error.message}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{error.stack && (
|
||||
<div className="space-y-2">
|
||||
<h3 className="text-sm font-medium text-custom-text-300 uppercase tracking-wide">Stack Trace</h3>
|
||||
<div className="bg-custom-background-80 rounded-md border border-custom-border-200 max-h-96 overflow-auto">
|
||||
<pre className="p-4 text-xs text-custom-text-200 font-mono whitespace-pre-wrap break-words">
|
||||
{error.stack}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<ErrorActions onGoHome={onGoHome} onReload={onReload} />
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<Card variant={ECardVariant.WITHOUT_SHADOW} className="!p-4 bg-custom-background-80 transition-none">
|
||||
<div className="flex items-start gap-3">
|
||||
<InfoFillIcon className="size-5 text-custom-text-300 flex-shrink-0 mt-0.5" />
|
||||
<div className="space-y-1">
|
||||
<p className="text-sm font-medium text-custom-text-200">Development Mode</p>
|
||||
<p className="text-xs text-custom-text-300">
|
||||
This detailed error view is only visible in development. In production, users will see a friendly
|
||||
error page.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-custom-background-90 p-6 flex items-start justify-center transition-none">
|
||||
<div className="w-full max-w-4xl mt-12 space-y-4 transition-none">
|
||||
<Banner
|
||||
variant="error"
|
||||
icon={<InfoFillIcon className="size-5" />}
|
||||
title="Unknown Error"
|
||||
animationDuration={0}
|
||||
/>
|
||||
|
||||
<Card variant={ECardVariant.WITH_SHADOW} className="!p-6">
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h2 className="text-2xl font-semibold text-custom-text-100 mb-2">Unknown Error</h2>
|
||||
<div className="h-px w-full bg-custom-border-200" />
|
||||
</div>
|
||||
|
||||
<div className="bg-custom-background-80 rounded-md p-4">
|
||||
<p className="text-sm text-custom-text-200">
|
||||
An unknown error occurred. Please try refreshing the page or contact support if the problem persists.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<ErrorActions onGoHome={onGoHome} onReload={onReload} />
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
21
apps/web/app/error/index.tsx
Normal file
21
apps/web/app/error/index.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
"use client";
|
||||
|
||||
// hooks
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
// layouts
|
||||
import { DevErrorComponent } from "./dev";
|
||||
import { ProdErrorComponent } from "./prod";
|
||||
|
||||
export const CustomErrorComponent: React.FC<{ error: unknown }> = ({ error }) => {
|
||||
// router
|
||||
const router = useAppRouter();
|
||||
|
||||
const handleGoHome = () => router.push("/");
|
||||
const handleReload = () => window.location.reload();
|
||||
|
||||
if (import.meta.env.DEV) {
|
||||
return <DevErrorComponent error={error} onGoHome={handleGoHome} onReload={handleReload} />;
|
||||
}
|
||||
|
||||
return <ProdErrorComponent onGoHome={handleGoHome} />;
|
||||
};
|
||||
89
apps/web/app/error/prod.tsx
Normal file
89
apps/web/app/error/prod.tsx
Normal file
@@ -0,0 +1,89 @@
|
||||
"use client";
|
||||
|
||||
import { useTheme } from "next-themes";
|
||||
// plane imports
|
||||
import { Button } from "@plane/propel/button";
|
||||
// assets
|
||||
import maintenanceModeDarkModeImage from "@/app/assets/instance/maintenance-mode-dark.svg?url";
|
||||
import maintenanceModeLightModeImage from "@/app/assets/instance/maintenance-mode-light.svg?url";
|
||||
// layouts
|
||||
import DefaultLayout from "@/layouts/default-layout";
|
||||
|
||||
const linkMap = [
|
||||
{
|
||||
key: "mail_to",
|
||||
label: "Contact Support",
|
||||
value: "mailto:support@plane.so",
|
||||
},
|
||||
{
|
||||
key: "status",
|
||||
label: "Status Page",
|
||||
value: "https://status.plane.so/",
|
||||
},
|
||||
{
|
||||
key: "twitter_handle",
|
||||
label: "@planepowers",
|
||||
value: "https://x.com/planepowers",
|
||||
},
|
||||
];
|
||||
|
||||
// Production Error Component
|
||||
interface ProdErrorComponentProps {
|
||||
onGoHome: () => void;
|
||||
}
|
||||
|
||||
export const ProdErrorComponent: React.FC<ProdErrorComponentProps> = ({ onGoHome }) => {
|
||||
// hooks
|
||||
const { resolvedTheme } = useTheme();
|
||||
|
||||
// derived values
|
||||
const maintenanceModeImage = resolvedTheme === "dark" ? maintenanceModeDarkModeImage : maintenanceModeLightModeImage;
|
||||
|
||||
return (
|
||||
<DefaultLayout>
|
||||
<div className="relative container mx-auto h-full w-full max-w-xl flex flex-col gap-2 items-center justify-center gap-y-6 bg-custom-background-100 text-center px-6">
|
||||
<div className="relative w-full">
|
||||
<img
|
||||
src={maintenanceModeImage}
|
||||
height="176"
|
||||
width="288"
|
||||
alt="ProjectSettingImg"
|
||||
className="w-full h-full object-fill object-center"
|
||||
/>
|
||||
</div>
|
||||
<div className="w-full relative flex flex-col gap-4 mt-4">
|
||||
<div className="flex flex-col gap-2.5">
|
||||
<h1 className="text-xl font-semibold text-custom-text-100 text-left">
|
||||
🚧 Looks like something went wrong!
|
||||
</h1>
|
||||
<span className="text-base font-medium text-custom-text-200 text-left">
|
||||
We track these errors automatically and working on getting things back up and running. If the problem
|
||||
persists feel free to contact us. In the meantime, try refreshing.
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-start gap-6 mt-1">
|
||||
{linkMap.map((link) => (
|
||||
<div key={link.key}>
|
||||
<a
|
||||
href={link.value}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-custom-primary-100 hover:underline text-sm"
|
||||
>
|
||||
{link.label}
|
||||
</a>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-start gap-6">
|
||||
<Button variant="primary" size="md" onClick={onGoHome}>
|
||||
Go to home
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DefaultLayout>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user