display multiple issues in overlay (vercel/turbo#2803)
This commit is contained in:
parent
b680327280
commit
65016c65e3
9 changed files with 210 additions and 140 deletions
|
@ -17,7 +17,7 @@ import {
|
|||
onBeforeRefresh,
|
||||
onBuildOk,
|
||||
onRefresh,
|
||||
onTurbopackError,
|
||||
onTurbopackIssues,
|
||||
} from "../overlay/client";
|
||||
import { addEventListener, sendMessage } from "./websocket";
|
||||
import { ModuleId } from "@vercel/turbopack-runtime/types";
|
||||
|
@ -95,18 +95,18 @@ type AggregatedUpdates = {
|
|||
};
|
||||
|
||||
// we aggregate all updates until the issues are resolved
|
||||
const chunksWithErrors: Map<ChunkPath, AggregatedUpdates> = new Map();
|
||||
const chunksWithUpdates: Map<ChunkPath, AggregatedUpdates> = new Map();
|
||||
|
||||
function aggregateUpdates(
|
||||
msg: ServerMessage,
|
||||
hasErrors: boolean
|
||||
hasIssues: boolean
|
||||
): ServerMessage {
|
||||
const key = resourceKey(msg.resource);
|
||||
const aggregated = chunksWithErrors.get(key);
|
||||
const aggregated = chunksWithUpdates.get(key);
|
||||
|
||||
if (msg.type === "issues" && aggregated != null) {
|
||||
if (!hasErrors) {
|
||||
chunksWithErrors.delete(key);
|
||||
if (!hasIssues) {
|
||||
chunksWithUpdates.delete(key);
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -124,8 +124,8 @@ function aggregateUpdates(
|
|||
if (msg.type !== "partial") return msg;
|
||||
|
||||
if (aggregated == null) {
|
||||
if (hasErrors) {
|
||||
chunksWithErrors.set(key, {
|
||||
if (hasIssues) {
|
||||
chunksWithUpdates.set(key, {
|
||||
added: msg.instruction.added,
|
||||
modified: msg.instruction.modified,
|
||||
deleted: new Set(msg.instruction.deleted),
|
||||
|
@ -172,10 +172,10 @@ function aggregateUpdates(
|
|||
aggregated.deleted.add(moduleId);
|
||||
}
|
||||
|
||||
if (!hasErrors) {
|
||||
chunksWithErrors.delete(key);
|
||||
if (!hasIssues) {
|
||||
chunksWithUpdates.delete(key);
|
||||
} else {
|
||||
chunksWithErrors.set(key, aggregated);
|
||||
chunksWithUpdates.set(key, aggregated);
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -198,21 +198,20 @@ function compareByList(list: any[], a: any, b: any) {
|
|||
}
|
||||
|
||||
function handleIssues(msg: ServerMessage): boolean {
|
||||
let issueToReport = null;
|
||||
let hasCriticalIssues = false;
|
||||
|
||||
for (const issue of msg.issues) {
|
||||
if (CRITICAL.includes(issue.severity)) {
|
||||
issueToReport = issue;
|
||||
break;
|
||||
console.error(stripAnsi(issue.formatted));
|
||||
hasCriticalIssues = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (issueToReport) {
|
||||
console.error(stripAnsi(issueToReport.formatted));
|
||||
onTurbopackError(issueToReport);
|
||||
if (msg.issues.length > 0) {
|
||||
onTurbopackIssues(msg.issues);
|
||||
}
|
||||
|
||||
return issueToReport != null;
|
||||
return hasCriticalIssues;
|
||||
}
|
||||
|
||||
const SEVERITY_ORDER = ["bug", "fatal", "error", "warning", "info", "log"];
|
||||
|
@ -232,20 +231,20 @@ function handleSocketMessage(msg: ServerMessage) {
|
|||
return compareByList(CATEGORY_ORDER, a.category, b.category);
|
||||
});
|
||||
|
||||
const hasErrors = handleIssues(msg);
|
||||
const aggregatedMsg = aggregateUpdates(msg, hasErrors);
|
||||
const hasIssues = handleIssues(msg);
|
||||
const aggregatedMsg = aggregateUpdates(msg, hasIssues);
|
||||
|
||||
if (hasErrors) return;
|
||||
if (hasIssues) return;
|
||||
|
||||
if (aggregatedMsg.type !== "issues") {
|
||||
onBeforeRefresh();
|
||||
triggerUpdate(aggregatedMsg);
|
||||
if (chunksWithErrors.size === 0) {
|
||||
if (chunksWithUpdates.size === 0) {
|
||||
onRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
if (chunksWithErrors.size === 0) {
|
||||
if (chunksWithUpdates.size === 0) {
|
||||
onBuildOk();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,8 +85,8 @@ function onBuildOk() {
|
|||
Bus.emit({ type: Bus.TYPE_BUILD_OK });
|
||||
}
|
||||
|
||||
function onTurbopackError(issue: Issue) {
|
||||
Bus.emit({ type: Bus.TYPE_TURBOPACK_ERROR, issue });
|
||||
function onTurbopackIssues(issues: Issue[]) {
|
||||
Bus.emit({ type: Bus.TYPE_TURBOPACK_ISSUES, issues });
|
||||
}
|
||||
|
||||
function onBeforeRefresh() {
|
||||
|
@ -102,7 +102,7 @@ export { getServerError } from "./internal/helpers/nodeStackFrames";
|
|||
export { default as ReactDevOverlay } from "./internal/ReactDevOverlay";
|
||||
export {
|
||||
onBuildOk,
|
||||
onTurbopackError,
|
||||
onTurbopackIssues,
|
||||
register,
|
||||
unregister,
|
||||
onBeforeRefresh,
|
||||
|
|
|
@ -4,7 +4,6 @@ import type { Issue } from "@vercel/turbopack-runtime/types/protocol";
|
|||
|
||||
import * as Bus from "./bus";
|
||||
import { ShadowPortal } from "./components/ShadowPortal";
|
||||
import { BuildError } from "./container/BuildError";
|
||||
import { Errors, SupportedErrorEvent } from "./container/Errors";
|
||||
import { ErrorBoundary } from "./ErrorBoundary";
|
||||
import { Base } from "./styles/Base";
|
||||
|
@ -25,7 +24,11 @@ type RefreshState =
|
|||
|
||||
type OverlayState = {
|
||||
nextId: number;
|
||||
issue: Issue | null;
|
||||
|
||||
// issues are from turbopack
|
||||
issues: Issue[];
|
||||
|
||||
// errors are client side
|
||||
errors: SupportedErrorEvent[];
|
||||
|
||||
refreshState: RefreshState;
|
||||
|
@ -47,10 +50,10 @@ function pushErrorFilterDuplicates(
|
|||
function reducer(state: OverlayState, ev: Bus.BusEvent): OverlayState {
|
||||
switch (ev.type) {
|
||||
case Bus.TYPE_BUILD_OK: {
|
||||
return { ...state, issue: null };
|
||||
return { ...state, issues: [] };
|
||||
}
|
||||
case Bus.TYPE_TURBOPACK_ERROR: {
|
||||
return { ...state, issue: ev.issue };
|
||||
case Bus.TYPE_TURBOPACK_ISSUES: {
|
||||
return { ...state, issues: ev.issues };
|
||||
}
|
||||
case Bus.TYPE_BEFORE_REFRESH: {
|
||||
return { ...state, refreshState: { type: "pending", errors: [] } };
|
||||
|
@ -58,7 +61,7 @@ function reducer(state: OverlayState, ev: Bus.BusEvent): OverlayState {
|
|||
case Bus.TYPE_REFRESH: {
|
||||
return {
|
||||
...state,
|
||||
issue: null,
|
||||
issues: [],
|
||||
errors:
|
||||
// Errors can come in during updates. In this case, UNHANDLED_ERROR
|
||||
// and UNHANDLED_REJECTION events might be dispatched between the
|
||||
|
@ -135,7 +138,7 @@ export default function ReactDevOverlay({
|
|||
React.Reducer<OverlayState, Bus.BusEvent>
|
||||
>(reducer, {
|
||||
nextId: 1,
|
||||
issue: null,
|
||||
issues: [],
|
||||
errors: [],
|
||||
refreshState: {
|
||||
type: "idle",
|
||||
|
@ -156,8 +159,8 @@ export default function ReactDevOverlay({
|
|||
[]
|
||||
);
|
||||
|
||||
const hasBuildError = state.issue != null;
|
||||
const hasRuntimeErrors = Boolean(state.errors.length);
|
||||
const hasBuildError = state.issues.length > 0;
|
||||
const hasRuntimeErrors = state.errors.length > 0;
|
||||
|
||||
const errorType = hasBuildError
|
||||
? "build"
|
||||
|
@ -182,14 +185,9 @@ export default function ReactDevOverlay({
|
|||
<Base />
|
||||
<ComponentStyles />
|
||||
|
||||
{shouldPreventDisplay(
|
||||
errorType,
|
||||
preventDisplay
|
||||
) ? null : hasBuildError ? (
|
||||
<BuildError issue={state.issue!} />
|
||||
) : hasRuntimeErrors ? (
|
||||
<Errors errors={state.errors} />
|
||||
) : null}
|
||||
{shouldPreventDisplay(errorType, preventDisplay) ? null : (
|
||||
<Errors issues={state.issues} errors={state.errors} />
|
||||
)}
|
||||
</ShadowPortal>
|
||||
) : null}
|
||||
</React.Fragment>
|
||||
|
|
|
@ -3,16 +3,16 @@ import { StackFrame } from "stacktrace-parser";
|
|||
import type { Issue } from "@vercel/turbopack-runtime/types/protocol";
|
||||
|
||||
export const TYPE_BUILD_OK = "build-ok";
|
||||
export const TYPE_TURBOPACK_ERROR = "turbopack-error";
|
||||
export const TYPE_TURBOPACK_ISSUES = "turbopack-error";
|
||||
export const TYPE_BEFORE_REFRESH = "before-fast-refresh";
|
||||
export const TYPE_REFRESH = "fast-refresh";
|
||||
export const TYPE_UNHANDLED_ERROR = "unhandled-error";
|
||||
export const TYPE_UNHANDLED_REJECTION = "unhandled-rejection";
|
||||
|
||||
export type BuildOk = { type: typeof TYPE_BUILD_OK };
|
||||
export type TurbopackError = {
|
||||
type: typeof TYPE_TURBOPACK_ERROR;
|
||||
issue: Issue;
|
||||
export type TurbopackIssues = {
|
||||
type: typeof TYPE_TURBOPACK_ISSUES;
|
||||
issues: Issue[];
|
||||
};
|
||||
export type BeforeFastRefresh = { type: typeof TYPE_BEFORE_REFRESH };
|
||||
export type FastRefresh = { type: typeof TYPE_REFRESH };
|
||||
|
@ -28,7 +28,7 @@ export type UnhandledRejection = {
|
|||
};
|
||||
export type BusEvent =
|
||||
| BuildOk
|
||||
| TurbopackError
|
||||
| TurbopackIssues
|
||||
| BeforeFastRefresh
|
||||
| FastRefresh
|
||||
| UnhandledError
|
||||
|
|
|
@ -19,7 +19,6 @@ type TabRefs = Record<string, HTMLElement | undefined>;
|
|||
|
||||
type TabsContextType = {
|
||||
selectedId: string;
|
||||
tabRefs: Readonly<TabRefs>;
|
||||
registerTabRef: (id: string, el: HTMLElement | null) => void;
|
||||
onSelectTab: (id: string) => void;
|
||||
};
|
||||
|
@ -69,6 +68,8 @@ export function Tabs({
|
|||
setTimeout(() => {
|
||||
tab.focus();
|
||||
}, 0);
|
||||
|
||||
onSelectTabUnchecked(id);
|
||||
},
|
||||
[selectedId, onSelectTabUnchecked]
|
||||
);
|
||||
|
@ -108,7 +109,6 @@ export function Tabs({
|
|||
return (
|
||||
<TabsProvider
|
||||
selectedId={selectedId}
|
||||
tabRefs={tabRefs.current}
|
||||
registerTabRef={registerTabRef}
|
||||
onSelectTab={onSelectTab}
|
||||
>
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
import * as React from "react";
|
||||
import type { Issue } from "@vercel/turbopack-runtime/types/protocol";
|
||||
|
||||
import {
|
||||
Dialog,
|
||||
DialogBody,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
} from "../components/Dialog";
|
||||
import { Overlay } from "../components/Overlay";
|
||||
import { Terminal } from "../components/Terminal";
|
||||
import { noop as css } from "../helpers/noop-template";
|
||||
|
||||
export type BuildErrorProps = { issue: Issue };
|
||||
|
||||
export function BuildError({ issue }: BuildErrorProps) {
|
||||
const noop = React.useCallback(() => {}, []);
|
||||
return (
|
||||
<Overlay fixed>
|
||||
<Dialog
|
||||
aria-labelledby="nextjs__container_build_error_label"
|
||||
aria-describedby="nextjs__container_build_error_desc"
|
||||
onClose={noop}
|
||||
>
|
||||
<DialogContent>
|
||||
<DialogHeader className="nextjs-container-build-error-header">
|
||||
<h4 id="nextjs__container_build_error_label">
|
||||
Turbopack failed to compile
|
||||
</h4>
|
||||
</DialogHeader>
|
||||
<DialogBody className="nextjs-container-build-error-body">
|
||||
<Terminal content={issue.formatted} />
|
||||
<footer>
|
||||
<p id="nextjs__container_build_error_desc">
|
||||
<small>
|
||||
This error occurred during the build process and can only be
|
||||
dismissed by fixing the error.
|
||||
</small>
|
||||
</p>
|
||||
</footer>
|
||||
</DialogBody>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Overlay>
|
||||
);
|
||||
}
|
||||
|
||||
export const styles = css`
|
||||
.nextjs-container-build-error-header > h4 {
|
||||
line-height: 1.5;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.nextjs-container-build-error-body footer {
|
||||
margin-top: var(--size-gap);
|
||||
}
|
||||
.nextjs-container-build-error-body footer p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.nextjs-container-build-error-body small {
|
||||
color: #757575;
|
||||
}
|
||||
`;
|
|
@ -1,5 +1,7 @@
|
|||
import * as React from "react";
|
||||
|
||||
import { Issue } from "@vercel/turbopack-runtime/types/protocol";
|
||||
|
||||
import {
|
||||
TYPE_UNHANDLED_ERROR,
|
||||
TYPE_UNHANDLED_REJECTION,
|
||||
|
@ -18,8 +20,9 @@ import { Tab, TabPanel, Tabs } from "../components/Tabs";
|
|||
import { getErrorByType, ReadyRuntimeError } from "../helpers/getErrorByType";
|
||||
import { getErrorSource } from "../helpers/nodeStackFrames";
|
||||
import { noop as css } from "../helpers/noop-template";
|
||||
import { AlertOctagon } from "../icons";
|
||||
import { AlertOctagon, PackageX } from "../icons";
|
||||
import { RuntimeErrorsDialogBody } from "./RuntimeError";
|
||||
import { TurbopackIssuesDialogBody } from "../container/TurbopackIssue";
|
||||
import { ErrorsToast } from "../container/ErrorsToast";
|
||||
|
||||
export type SupportedErrorEvent = {
|
||||
|
@ -27,6 +30,7 @@ export type SupportedErrorEvent = {
|
|||
event: UnhandledError | UnhandledRejection;
|
||||
};
|
||||
export type ErrorsProps = {
|
||||
issues: Issue[];
|
||||
errors: SupportedErrorEvent[];
|
||||
};
|
||||
|
||||
|
@ -82,9 +86,7 @@ function useResolvedErrors(
|
|||
return [ready, next];
|
||||
}, [errors, lookups]);
|
||||
|
||||
const isLoading = React.useMemo<boolean>(() => {
|
||||
return readyErrors.length < 1 && errors.length > 1;
|
||||
}, [errors.length, readyErrors.length]);
|
||||
const isLoading = readyErrors.length === 0 && errors.length > 1;
|
||||
|
||||
React.useEffect(() => {
|
||||
if (nextError == null) {
|
||||
|
@ -114,7 +116,7 @@ function useResolvedErrors(
|
|||
// Reset component state when there are no errors to be displayed.
|
||||
// This should never happen, but let's handle it.
|
||||
React.useEffect(() => {
|
||||
if (errors.length < 1) {
|
||||
if (errors.length === 0) {
|
||||
setLookups({});
|
||||
}
|
||||
}, [errors.length]);
|
||||
|
@ -123,24 +125,18 @@ function useResolvedErrors(
|
|||
}
|
||||
|
||||
const enum TabId {
|
||||
TurbopackIssues = "turbopack-issues",
|
||||
RuntimeErrors = "runtime-errors",
|
||||
}
|
||||
|
||||
export function Errors({ errors }: ErrorsProps) {
|
||||
const [displayState, setDisplayState] = React.useState<
|
||||
export function Errors({ issues, errors }: ErrorsProps) {
|
||||
// eslint-disable-next-line prefer-const
|
||||
let [displayState, setDisplayState] = React.useState<
|
||||
"minimized" | "fullscreen" | "hidden"
|
||||
>("fullscreen");
|
||||
|
||||
const [readyErrors, isLoading] = useResolvedErrors(errors);
|
||||
|
||||
// Reset component state when there are no errors to be displayed.
|
||||
// This should never happen, but let's handle it.
|
||||
React.useEffect(() => {
|
||||
if (errors.length < 1) {
|
||||
setDisplayState("hidden");
|
||||
}
|
||||
}, [errors.length]);
|
||||
|
||||
const minimize = React.useCallback((e?: MouseEvent | TouchEvent) => {
|
||||
e?.preventDefault();
|
||||
setDisplayState("minimized");
|
||||
|
@ -157,18 +153,37 @@ export function Errors({ errors }: ErrorsProps) {
|
|||
[]
|
||||
);
|
||||
|
||||
const hasErrors = errors.length > 0;
|
||||
const hasIssues = issues.length !== 0;
|
||||
const hasIssueWithError = issues.some((issue) =>
|
||||
["bug", "fatal", "error"].includes(issue.severity)
|
||||
);
|
||||
|
||||
const hasErrors = errors.length !== 0;
|
||||
const hasServerError = readyErrors.some((err) =>
|
||||
["server", "edge-server"].includes(getErrorSource(err.error) || "")
|
||||
);
|
||||
const isClosable = !isLoading && !hasServerError;
|
||||
const isClosable = !isLoading && !hasIssueWithError && !hasServerError;
|
||||
|
||||
const defaultTab =
|
||||
hasIssueWithError || !hasErrors
|
||||
? TabId.TurbopackIssues
|
||||
: TabId.RuntimeErrors;
|
||||
|
||||
const defaultTab = TabId.RuntimeErrors;
|
||||
const [selectedTab, setSelectedTab] = React.useState<string>(defaultTab);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (defaultTab === TabId.TurbopackIssues) {
|
||||
setSelectedTab(TabId.TurbopackIssues);
|
||||
}
|
||||
}, [defaultTab]);
|
||||
|
||||
if (!isClosable) {
|
||||
displayState = "fullscreen";
|
||||
}
|
||||
|
||||
// This component shouldn't be rendered with no errors, but if it is, let's
|
||||
// handle it gracefully by rendering nothing.
|
||||
if (errors.length < 1) {
|
||||
if (!hasErrors && !hasIssues) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -179,7 +194,7 @@ export function Errors({ errors }: ErrorsProps) {
|
|||
if (displayState === "minimized") {
|
||||
return (
|
||||
<ErrorsToast
|
||||
errorCount={readyErrors.length}
|
||||
errorCount={readyErrors.length + issues.length}
|
||||
onClick={fullscreen}
|
||||
onClose={hide}
|
||||
/>
|
||||
|
@ -202,15 +217,40 @@ export function Errors({ errors }: ErrorsProps) {
|
|||
close={isClosable ? minimize : undefined}
|
||||
>
|
||||
<DialogHeaderTabList>
|
||||
{hasIssues && (
|
||||
<Tab
|
||||
id={TabId.TurbopackIssues}
|
||||
next={hasErrors ? TabId.RuntimeErrors : undefined}
|
||||
data-severity={hasIssueWithError ? "error" : "warning"}
|
||||
>
|
||||
<PackageX />
|
||||
{issues.length} Turbopack Issue{issues.length > 1 ? "s" : ""}
|
||||
</Tab>
|
||||
)}
|
||||
{hasErrors && (
|
||||
<Tab id={TabId.RuntimeErrors} data-severity="error">
|
||||
<Tab
|
||||
id={TabId.RuntimeErrors}
|
||||
prev={hasIssues ? TabId.TurbopackIssues : undefined}
|
||||
data-severity="error"
|
||||
>
|
||||
<AlertOctagon />
|
||||
{isLoading ? "Loading" : readyErrors.length} Runtime Errors
|
||||
{isLoading ? "..." : null}
|
||||
{isLoading
|
||||
? "Loading Runtime Errors ..."
|
||||
: `${readyErrors.length} Runtime Error${
|
||||
readyErrors.length > 1 ? "s" : ""
|
||||
}`}
|
||||
</Tab>
|
||||
)}
|
||||
</DialogHeaderTabList>
|
||||
</DialogHeader>
|
||||
{hasIssues && (
|
||||
<TabPanel
|
||||
as={TurbopackIssuesDialogBody}
|
||||
id={TabId.TurbopackIssues}
|
||||
issues={issues}
|
||||
className="errors-body"
|
||||
/>
|
||||
)}
|
||||
{hasErrors && (
|
||||
<TabPanel
|
||||
as={RuntimeErrorsDialogBody}
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
import { Issue } from "@vercel/turbopack-runtime/types/protocol";
|
||||
|
||||
import { LeftRightDialogHeader } from "../components/LeftRightDialogHeader";
|
||||
import { DialogBody, DialogBodyProps } from "../components/Dialog";
|
||||
import { Terminal } from "../components/Terminal";
|
||||
import { noop as css } from "../helpers/noop-template";
|
||||
import { clsx } from "../helpers/clsx";
|
||||
import { usePagination } from "../hooks/usePagination";
|
||||
|
||||
type TurbopackIssuesDialogBodyProps = {
|
||||
issues: Issue[];
|
||||
"data-hidden"?: boolean;
|
||||
};
|
||||
|
||||
export function TurbopackIssuesDialogBody({
|
||||
issues,
|
||||
"data-hidden": hidden = false,
|
||||
className,
|
||||
...rest
|
||||
}: TurbopackIssuesDialogBodyProps & Omit<DialogBodyProps, "children">) {
|
||||
const [activeIssue, { previous, next }, activeIdx] = usePagination(issues);
|
||||
|
||||
const hasIssues = issues.length > 0;
|
||||
const hasIssueWithError = issues.some((issue) =>
|
||||
["bug", "fatal", "error"].includes(issue.severity)
|
||||
);
|
||||
|
||||
if (!hasIssues || !activeIssue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const activeIssueIsError = ["bug", "fatal", "error"].includes(
|
||||
activeIssue.severity
|
||||
);
|
||||
|
||||
return (
|
||||
<DialogBody
|
||||
{...rest}
|
||||
data-hidden={hidden}
|
||||
className={clsx("issues-body", className)}
|
||||
>
|
||||
<div className="title-pagination">
|
||||
<h1 id="errors_label">
|
||||
{hasIssueWithError
|
||||
? "Turbopack failed to compile"
|
||||
: "Turbopack compiled with warnings"}
|
||||
</h1>
|
||||
<LeftRightDialogHeader
|
||||
hidden={hidden}
|
||||
previous={activeIdx > 0 ? previous : null}
|
||||
next={activeIdx < issues.length - 1 ? next : null}
|
||||
severity={activeIssueIsError ? "error" : "warning"}
|
||||
>
|
||||
<small>
|
||||
<span>{activeIdx + 1}</span> of <span>{issues.length}</span>
|
||||
</small>
|
||||
</LeftRightDialogHeader>
|
||||
</div>
|
||||
|
||||
<h2
|
||||
id="errors_desc"
|
||||
data-severity={activeIssueIsError ? "error" : "warning"}
|
||||
>
|
||||
{activeIssue.title}
|
||||
</h2>
|
||||
|
||||
<Terminal content={activeIssue.formatted} />
|
||||
{activeIssueIsError && (
|
||||
<footer>
|
||||
<p>
|
||||
<small>
|
||||
This error occurred during the build process and can only be
|
||||
dismissed by fixing the error.
|
||||
</small>
|
||||
</p>
|
||||
</footer>
|
||||
)}
|
||||
</DialogBody>
|
||||
);
|
||||
}
|
||||
|
||||
export const styles = css`
|
||||
.issues-body > .terminal {
|
||||
margin-top: var(--size-gap-double);
|
||||
}
|
||||
|
||||
.issues-body > footer {
|
||||
margin-top: var(--size-gap);
|
||||
}
|
||||
|
||||
.issues-body > footer > p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.issues-body > footer > small {
|
||||
color: #757575;
|
||||
}
|
||||
`;
|
|
@ -7,10 +7,10 @@ import { styles as overlay } from "../components/Overlay";
|
|||
import { styles as tabs } from "../components/Tabs";
|
||||
import { styles as terminal } from "../components/Terminal";
|
||||
import { styles as toast } from "../components/Toast";
|
||||
import { styles as buildErrorStyles } from "../container/BuildError";
|
||||
import { styles as containerErrorStyles } from "../container/Errors";
|
||||
import { styles as containerErrorToastStyles } from "../container/ErrorsToast";
|
||||
import { styles as containerRuntimeErrorStyles } from "../container/RuntimeError";
|
||||
import { styles as containerTurbopackIssueStyles } from "../container/TurbopackIssue";
|
||||
import { noop as css } from "../helpers/noop-template";
|
||||
|
||||
export function ComponentStyles() {
|
||||
|
@ -25,10 +25,10 @@ export function ComponentStyles() {
|
|||
${terminal}
|
||||
${tabs}
|
||||
|
||||
${buildErrorStyles}
|
||||
${containerErrorStyles}
|
||||
${containerErrorToastStyles}
|
||||
${containerRuntimeErrorStyles}
|
||||
${containerTurbopackIssueStyles}
|
||||
`}
|
||||
</style>
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue