chore: remove `Maybe` (#9880)

This commit is contained in:
Kayla Washburn 2023-09-27 10:45:12 -06:00 committed by GitHub
parent 72e8f88af3
commit 066b25f710
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 202 additions and 259 deletions

View File

@ -1,25 +0,0 @@
import { StoryObj, Meta } from "@storybook/react";
import { Maybe } from "./Maybe";
const meta: Meta<typeof Maybe> = {
title: "components/Conditionals/Maybe",
component: Maybe,
args: {
children: "Now you see me",
},
};
export default meta;
type Story = StoryObj<typeof Maybe>;
export const ConditionIsTrue: Story = {
args: {
condition: true,
},
};
export const ConditionIsFalse: Story = {
args: {
condition: false,
},
};

View File

@ -1,17 +0,0 @@
import { PropsWithChildren } from "react";
export interface MaybeProps {
condition: boolean;
}
/**
* Wrapper component for conditionally rendering a child component without using "curly brace mode."
* @param condition boolean expression that determines whether the child will be rendered
* @returns the child or null
*/
export const Maybe = ({
children,
condition,
}: PropsWithChildren<MaybeProps>): JSX.Element | null => {
return condition ? <>{children}</> : null;
};

View File

@ -1,6 +1,5 @@
import makeStyles from "@mui/styles/makeStyles";
import TextField from "@mui/material/TextField";
import { Maybe } from "components/Conditionals/Maybe";
import { ChangeEvent, useState, PropsWithChildren, FC } from "react";
import { ConfirmDialog } from "../ConfirmDialog/ConfirmDialog";
@ -34,9 +33,7 @@ export const DeleteDialog: FC<PropsWithChildren<DeleteDialogProps>> = ({
const content = (
<>
<p>Deleting this {entity} is irreversible!</p>
<Maybe condition={info !== undefined}>
<p className={styles.warning}>{info}</p>
</Maybe>
{Boolean(info) && <p className={styles.warning}>{info}</p>}
<p>Are you sure you want to proceed?</p>
<p>Type {name} below to confirm.</p>

View File

@ -1,10 +1,10 @@
import { makeStyles } from "@mui/styles";
import { PropsWithChildren, FC } from "react";
import { combineClasses } from "../../utils/combineClasses";
import { type FC, type PropsWithChildren, type ReactNode } from "react";
import { combineClasses } from "utils/combineClasses";
import { Stack } from "../Stack/Stack";
export interface PageHeaderProps {
actions?: JSX.Element;
actions?: ReactNode;
className?: string;
}

View File

@ -5,7 +5,6 @@ import KeyboardArrowLeft from "@mui/icons-material/KeyboardArrowLeft";
import KeyboardArrowRight from "@mui/icons-material/KeyboardArrowRight";
import { useActor } from "@xstate/react";
import { ChooseOne, Cond } from "components/Conditionals/ChooseOne";
import { Maybe } from "components/Conditionals/Maybe";
import { CSSProperties } from "react";
import { PaginationMachineRef } from "xServices/pagination/paginationXService";
import { PageButton } from "./PageButton";
@ -40,57 +39,59 @@ export const PaginationWidget = ({
// if beyond page 1, show pagination widget even if there's only one true page, so user can navigate back
const showWidget = numPages > 1 || currentPage > 1;
if (!showWidget) {
return null;
}
return (
<Maybe condition={showWidget}>
<div style={containerStyle} className={styles.defaultContainerStyles}>
<Button
className={styles.prevLabelStyles}
aria-label="Previous page"
disabled={firstPageActive}
onClick={() => send({ type: "PREVIOUS_PAGE" })}
>
<KeyboardArrowLeft />
<div>{prevLabel}</div>
</Button>
<ChooseOne>
<Cond condition={isMobile}>
<PageButton
activePage={currentPage}
page={currentPage}
numPages={numPages}
/>
</Cond>
<Cond>
{buildPagedList(numPages, currentPage).map((page) =>
typeof page !== "number" ? (
<PageButton
key={`Page${page}`}
activePage={currentPage}
placeholder="..."
disabled
/>
) : (
<PageButton
key={`Page${page}`}
activePage={currentPage}
page={page}
numPages={numPages}
onPageClick={() => send({ type: "GO_TO_PAGE", page })}
/>
),
)}
</Cond>
</ChooseOne>
<Button
aria-label="Next page"
disabled={lastPageActive}
onClick={() => send({ type: "NEXT_PAGE" })}
>
<div>{nextLabel}</div>
<KeyboardArrowRight />
</Button>
</div>
</Maybe>
<div style={containerStyle} className={styles.defaultContainerStyles}>
<Button
className={styles.prevLabelStyles}
aria-label="Previous page"
disabled={firstPageActive}
onClick={() => send({ type: "PREVIOUS_PAGE" })}
>
<KeyboardArrowLeft />
<div>{prevLabel}</div>
</Button>
<ChooseOne>
<Cond condition={isMobile}>
<PageButton
activePage={currentPage}
page={currentPage}
numPages={numPages}
/>
</Cond>
<Cond>
{buildPagedList(numPages, currentPage).map((page) =>
typeof page !== "number" ? (
<PageButton
key={`Page${page}`}
activePage={currentPage}
placeholder="..."
disabled
/>
) : (
<PageButton
key={`Page${page}`}
activePage={currentPage}
page={page}
numPages={numPages}
onPageClick={() => send({ type: "GO_TO_PAGE", page })}
/>
),
)}
</Cond>
</ChooseOne>
<Button
aria-label="Next page"
disabled={lastPageActive}
onClick={() => send({ type: "NEXT_PAGE" })}
>
<div>{nextLabel}</div>
<KeyboardArrowRight />
</Button>
</div>
);
};

View File

@ -1,9 +1,8 @@
import { makeStyles } from "@mui/styles";
import { AppPreviewLink } from "components/Resources/AppLink/AppPreviewLink";
import { Maybe } from "components/Conditionals/Maybe";
import { FC } from "react";
import { combineClasses } from "utils/combineClasses";
import { WorkspaceAgent } from "../../api/typesGenerated";
import { WorkspaceAgent } from "api/typesGenerated";
import { Stack } from "../Stack/Stack";
interface AgentRowPreviewStyles {
@ -90,9 +89,9 @@ export const AgentRowPreview: FC<AgentRowPreviewProps> = ({
{agent.apps.map((app) => (
<AppPreviewLink key={app.slug} app={app} />
))}
<Maybe condition={agent.apps.length === 0}>
{agent.apps.length === 0 && (
<span className={styles.agentDataValue}>None</span>
</Maybe>
)}
</Stack>
</Stack>
</Stack>

View File

@ -1,7 +1,6 @@
import { FC } from "react";
import * as TypesGen from "api/typesGenerated";
import { Alert } from "components/Alert/Alert";
import { Maybe } from "components/Conditionals/Maybe";
export interface TemplateVersionWarningsProps {
warnings?: TypesGen.TemplateVersionWarning[];
@ -9,19 +8,19 @@ export interface TemplateVersionWarningsProps {
export const TemplateVersionWarnings: FC<
React.PropsWithChildren<TemplateVersionWarningsProps>
> = ({ warnings }) => {
if (!warnings) {
return <></>;
> = (props) => {
const { warnings = [] } = props;
if (!warnings.includes("UNSUPPORTED_WORKSPACES")) {
return null;
}
return (
<Maybe condition={Boolean(warnings.includes("UNSUPPORTED_WORKSPACES"))}>
<div data-testid="error-unsupported-workspaces">
<Alert severity="error">
This template uses legacy parameters which are not supported anymore.
Contact your administrator for assistance.
</Alert>
</div>
</Maybe>
<div data-testid="error-unsupported-workspaces">
<Alert severity="error">
This template uses legacy parameters which are not supported anymore.
Contact your administrator for assistance.
</Alert>
</div>
);
};

View File

@ -1,4 +1,3 @@
import { Maybe } from "components/Conditionals/Maybe";
import { StatsItem } from "components/Stats/Stats";
import Link from "@mui/material/Link";
import { Link as RouterLink } from "react-router-dom";
@ -6,12 +5,15 @@ import styled from "@emotion/styled";
import { Workspace } from "api/typesGenerated";
import { displayDormantDeletion } from "./utils";
import { useDashboard } from "components/Dashboard/DashboardProvider";
import { type FC } from "react";
export const DormantDeletionStat = ({
workspace,
}: {
interface DormantDeletionStatProps {
workspace: Workspace;
}): JSX.Element => {
}
export const DormantDeletionStat: FC<DormantDeletionStatProps> = ({
workspace,
}) => {
const { entitlements, experiments } = useDashboard();
const allowAdvancedScheduling =
entitlements.features["advanced_template_scheduling"].enabled;
@ -19,29 +21,31 @@ export const DormantDeletionStat = ({
// is merged up
const allowWorkspaceActions = experiments.includes("workspace_actions");
if (
!displayDormantDeletion(
workspace,
allowAdvancedScheduling,
allowWorkspaceActions,
)
) {
return null;
}
return (
<Maybe
condition={displayDormantDeletion(
workspace,
allowAdvancedScheduling,
allowWorkspaceActions,
)}
>
<StyledStatsItem
label="Deletion on"
className="containerClass"
value={
<Link
component={RouterLink}
to={`/templates/${workspace.template_name}/settings/schedule`}
title="Schedule settings"
>
{/* We check for string existence in the conditional */}
{new Date(workspace.deleting_at as string).toLocaleString()}
</Link>
}
/>
</Maybe>
<StyledStatsItem
label="Deletion on"
className="containerClass"
value={
<Link
component={RouterLink}
to={`/templates/${workspace.template_name}/settings/schedule`}
title="Schedule settings"
>
{/* We check for string existence in the conditional */}
{new Date(workspace.deleting_at!).toLocaleString()}
</Link>
}
/>
);
};

View File

@ -1,6 +1,5 @@
import { useMachine } from "@xstate/react";
import { isApiValidationError } from "api/errors";
import { Maybe } from "components/Conditionals/Maybe";
import { useDashboard } from "components/Dashboard/DashboardProvider";
import { FullPageHorizontalForm } from "components/FullPageForm/FullPageHorizontalForm";
import { Loader } from "components/Loader/Loader";
@ -55,14 +54,12 @@ const CreateTemplatePage: FC = () => {
</Helmet>
<FullPageHorizontalForm title="Create Template" onCancel={onCancel}>
<Maybe condition={state.hasTag("loading")}>
<Loader />
</Maybe>
{state.hasTag("loading") && <Loader />}
<Stack spacing={6}>
<Maybe condition={Boolean(error && !isApiValidationError(error))}>
{Boolean(error) && !isApiValidationError(error) && (
<ErrorAlert error={error} />
</Maybe>
)}
{shouldDisplayForm && (
<CreateTemplateForm

View File

@ -24,11 +24,10 @@ import {
import { Stack } from "components/Stack/Stack";
import { TableRowMenu } from "components/TableRowMenu/TableRowMenu";
import { UserAutocomplete } from "components/UserAutocomplete/UserAutocomplete";
import { useState } from "react";
import { type FC, useState } from "react";
import { Helmet } from "react-helmet-async";
import { Link as RouterLink, useNavigate, useParams } from "react-router-dom";
import { pageTitle } from "utils/page";
import { Maybe } from "components/Conditionals/Maybe";
import { makeStyles } from "@mui/styles";
import {
PaginationStatus,
@ -47,7 +46,7 @@ import {
import { displayError, displaySuccess } from "components/GlobalSnackbar/utils";
import { getErrorMessage } from "api/errors";
export const GroupPage: React.FC = () => {
export const GroupPage: FC = () => {
const { groupId } = useParams() as { groupId: string };
const queryClient = useQueryClient();
const navigate = useNavigate();
@ -79,25 +78,27 @@ export const GroupPage: React.FC = () => {
<Margins>
<PageHeader
actions={
<Maybe condition={canUpdateGroup}>
<Button
startIcon={<SettingsOutlined />}
to="settings"
component={RouterLink}
>
Settings
</Button>
<Button
disabled={groupData?.id === groupData?.organization_id}
onClick={() => {
setIsDeletingGroup(true);
}}
startIcon={<DeleteOutline />}
className={styles.removeButton}
>
Delete&hellip;
</Button>
</Maybe>
canUpdateGroup && (
<>
<Button
startIcon={<SettingsOutlined />}
to="settings"
component={RouterLink}
>
Settings
</Button>
<Button
disabled={groupData?.id === groupData?.organization_id}
onClick={() => {
setIsDeletingGroup(true);
}}
startIcon={<DeleteOutline />}
className={styles.removeButton}
>
Delete&hellip;
</Button>
</>
)
}
>
<PageHeaderTitle>
@ -113,13 +114,7 @@ export const GroupPage: React.FC = () => {
</PageHeader>
<Stack spacing={1}>
<Maybe
condition={
canUpdateGroup &&
groupData !== undefined &&
!isEveryoneGroup(groupData)
}
>
{canUpdateGroup && groupData && !isEveryoneGroup(groupData) && (
<AddGroupMember
isLoading={addMemberMutation.isLoading}
onSubmit={async (user, reset) => {
@ -136,7 +131,7 @@ export const GroupPage: React.FC = () => {
}
}}
/>
</Maybe>
)}
<TableToolbar>
<PaginationStatus
isLoading={Boolean(isLoading)}
@ -279,7 +274,7 @@ const GroupMemberRow = (props: {
/>
</TableCell>
<TableCell width="1%">
<Maybe condition={canUpdate}>
{canUpdate && (
<TableRowMenu
data={member}
menuItems={[
@ -302,7 +297,7 @@ const GroupMemberRow = (props: {
},
]}
/>
</Maybe>
)}
</TableCell>
</TableRow>
);

View File

@ -2,7 +2,6 @@ import { makeStyles } from "@mui/styles";
import { FormikTouched } from "formik";
import { FC, useState } from "react";
import { AuthMethods } from "api/typesGenerated";
import { Maybe } from "components/Conditionals/Maybe";
import { PasswordSignInForm } from "./PasswordSignInForm";
import { OAuthSignInForm } from "./OAuthSignInForm";
import { BuiltInAuthFormValues } from "./SignInForm.types";
@ -97,58 +96,65 @@ export const SignInForm: FC<React.PropsWithChildren<SignInFormProps>> = ({
<h1 className={styles.title}>
Sign in to <strong>Coder</strong>
</h1>
<Maybe condition={error !== undefined}>
{Boolean(error) && (
<div className={styles.alert}>
<ErrorAlert error={error} />
</div>
</Maybe>
<Maybe condition={Boolean(info) && info !== "" && error === undefined}>
)}
{Boolean(info) && Boolean(error) && (
<div className={styles.alert}>
<Alert severity="info">{info}</Alert>
</div>
</Maybe>
<Maybe condition={passwordEnabled && showPasswordAuth}>
)}
{passwordEnabled && showPasswordAuth && (
<PasswordSignInForm
onSubmit={onSubmit}
initialTouched={initialTouched}
isSigningIn={isSigningIn}
/>
</Maybe>
<Maybe condition={passwordEnabled && showPasswordAuth && oAuthEnabled}>
)}
{passwordEnabled && showPasswordAuth && oAuthEnabled && (
<div className={styles.divider}>
<div className={styles.dividerLine} />
<div className={styles.dividerLabel}>Or</div>
<div className={styles.dividerLine} />
</div>
</Maybe>
<Maybe condition={oAuthEnabled}>
)}
{oAuthEnabled && (
<OAuthSignInForm
isSigningIn={isSigningIn}
redirectTo={redirectTo}
authMethods={authMethods}
/>
</Maybe>
)}
<Maybe condition={!passwordEnabled && !oAuthEnabled}>
{!passwordEnabled && !oAuthEnabled && (
<Alert severity="error">No authentication methods configured!</Alert>
</Maybe>
)}
<Maybe condition={passwordEnabled && !showPasswordAuth}>
<div className={styles.divider}>
<div className={styles.dividerLine} />
<div className={styles.dividerLabel}>Or</div>
<div className={styles.dividerLine} />
</div>
{passwordEnabled && !showPasswordAuth && (
<>
<div className={styles.divider}>
<div className={styles.dividerLine} />
<div className={styles.dividerLabel}>Or</div>
<div className={styles.dividerLine} />
</div>
<Button
fullWidth
size="large"
onClick={() => setShowPasswordAuth(true)}
startIcon={<EmailIcon className={styles.icon} />}
>
Email and password
</Button>
</Maybe>
<Button
fullWidth
size="large"
onClick={() => setShowPasswordAuth(true)}
startIcon={<EmailIcon className={styles.icon} />}
>
Email and password
</Button>
</>
)}
</div>
);
};

View File

@ -1,6 +1,5 @@
import { makeStyles } from "@mui/styles";
import { ErrorAlert } from "components/Alert/ErrorAlert";
import { Maybe } from "components/Conditionals/Maybe";
import { Loader } from "components/Loader/Loader";
import { Margins } from "components/Margins/Margins";
import {
@ -59,13 +58,9 @@ export const StarterTemplatesPageView: FC<StarterTemplatesPageViewProps> = ({
</PageHeaderSubtitle>
</PageHeader>
<Maybe condition={Boolean(error)}>
<ErrorAlert error={error} />
</Maybe>
{Boolean(error) && <ErrorAlert error={error} />}
<Maybe condition={Boolean(!starterTemplatesByTag)}>
<Loader />
</Maybe>
{Boolean(!starterTemplatesByTag) && <Loader />}
<Stack direction="row" spacing={4}>
{starterTemplatesByTag && tags && (

View File

@ -6,7 +6,6 @@ import {
TemplateVersion,
} from "api/typesGenerated";
import { Avatar } from "components/Avatar/Avatar";
import { Maybe } from "components/Conditionals/Maybe";
import { DeleteDialog } from "components/Dialogs/DeleteDialog/DeleteDialog";
import {
PageHeader,
@ -132,13 +131,13 @@ export const TemplatePageHeader: FC<TemplatePageHeaderProps> = ({
actions={
<>
<CreateWorkspaceButton templateName={template.name} />
<Maybe condition={permissions.canUpdateTemplate}>
{permissions.canUpdateTemplate && (
<TemplateMenu
templateVersion={activeVersion.name}
templateName={template.name}
onDelete={deleteTemplate.openDeleteConfirmation}
/>
</Maybe>
)}
</>
}
>

View File

@ -27,7 +27,6 @@ import {
UserOrGroupAutocompleteValue,
} from "components/UserOrGroupAutocomplete/UserOrGroupAutocomplete";
import { FC, useState } from "react";
import { Maybe } from "components/Conditionals/Maybe";
import { GroupAvatar } from "components/GroupAvatar/GroupAvatar";
import { getGroupSubtitle } from "utils/groups";
import { PageHeader, PageHeaderTitle } from "components/PageHeader/PageHeader";
@ -213,7 +212,7 @@ export const TemplatePermissionsPageView: FC<
</PageHeader>
<Stack spacing={2.5}>
<Maybe condition={canUpdatePermissions}>
{canUpdatePermissions && (
<AddTemplateUserOrGroup
templateACL={templateACL}
templateID={templateID}
@ -225,7 +224,7 @@ export const TemplatePermissionsPageView: FC<
: onAddUser(value, role, resetAutocomplete)
}
/>
</Maybe>
)}
<TableContainer>
<Table>
<TableHead>
@ -288,7 +287,7 @@ export const TemplatePermissionsPageView: FC<
</TableCell>
<TableCell>
<Maybe condition={canUpdatePermissions}>
{canUpdatePermissions && (
<TableRowMenu
data={group}
menuItems={[
@ -299,7 +298,7 @@ export const TemplatePermissionsPageView: FC<
},
]}
/>
</Maybe>
)}
</TableCell>
</TableRow>
))}
@ -336,7 +335,7 @@ export const TemplatePermissionsPageView: FC<
</TableCell>
<TableCell>
<Maybe condition={canUpdatePermissions}>
{canUpdatePermissions && (
<TableRowMenu
data={user}
menuItems={[
@ -347,7 +346,7 @@ export const TemplatePermissionsPageView: FC<
},
]}
/>
</Maybe>
)}
</TableCell>
</TableRow>
))}

View File

@ -8,7 +8,6 @@ import TableHead from "@mui/material/TableHead";
import TableRow from "@mui/material/TableRow";
import AddIcon from "@mui/icons-material/AddOutlined";
import { ChooseOne, Cond } from "components/Conditionals/ChooseOne";
import { Maybe } from "components/Conditionals/Maybe";
import { FC } from "react";
import { useNavigate, Link as RouterLink } from "react-router-dom";
import { createDayString } from "utils/createDayString";
@ -158,19 +157,21 @@ export const TemplatesPageView: FC<TemplatesPageViewProps> = ({
<Margins>
<PageHeader
actions={
<Maybe condition={canCreateTemplates}>
<Button component={RouterLink} to="/starter-templates">
Starter Templates
</Button>
<Button
startIcon={<AddIcon />}
component={RouterLink}
to="new"
variant="contained"
>
Create Template
</Button>
</Maybe>
canCreateTemplates && (
<>
<Button component={RouterLink} to="/starter-templates">
Starter Templates
</Button>
<Button
startIcon={<AddIcon />}
component={RouterLink}
to="new"
variant="contained"
>
Create Template
</Button>
</>
)
}
>
<PageHeaderTitle>
@ -179,11 +180,11 @@ export const TemplatesPageView: FC<TemplatesPageViewProps> = ({
<TemplateHelpTooltip />
</Stack>
</PageHeaderTitle>
<Maybe condition={Boolean(templates && templates.length > 0)}>
{templates && templates.length > 0 && (
<PageHeaderSubtitle>
Select a template to create a workspace.
</PageHeaderSubtitle>
</Maybe>
)}
</PageHeader>
<ChooseOne>
@ -204,9 +205,7 @@ export const TemplatesPageView: FC<TemplatesPageViewProps> = ({
</TableRow>
</TableHead>
<TableBody>
<Maybe condition={isLoading}>
<TableLoader />
</Maybe>
{isLoading && <TableLoader />}
<ChooseOne>
<Cond condition={isEmpty}>

View File

@ -12,7 +12,6 @@ import {
} from "components/DeploySettingsLayout/Badges";
import { ProxyLatencyReport } from "contexts/useProxyLatency";
import { getLatencyColor } from "utils/latency";
import { Maybe } from "components/Conditionals/Maybe";
import Box from "@mui/material/Box";
export const ProxyRow: FC<{
@ -72,7 +71,7 @@ export const ProxyRow: FC<{
{latency ? `${latency.latencyMS.toFixed(0)} ms` : "Not available"}
</TableCell>
</TableRow>
<Maybe condition={shouldShowMessages}>
{shouldShowMessages && (
<TableRow>
<TableCell
colSpan={4}
@ -81,7 +80,7 @@ export const ProxyRow: FC<{
<ProxyMessagesRow proxy={proxy as WorkspaceProxy} />
</TableCell>
</TableRow>
</Maybe>
)}
</>
);
};

View File

@ -12,7 +12,6 @@ import {
HelpTooltipText,
HelpTooltipTitle,
} from "components/HelpTooltip/HelpTooltip";
import { Maybe } from "components/Conditionals/Maybe";
const roleDescriptions: Record<string, string> = {
owner:
@ -94,7 +93,7 @@ export const EditRolesButton: FC<EditRolesButtonProps> = ({
return (
<>
<Maybe condition={canSetRoles}>
{canSetRoles ? (
<IconButton
ref={anchorRef}
size="small"
@ -104,15 +103,14 @@ export const EditRolesButton: FC<EditRolesButtonProps> = ({
>
<EditSquare />
</IconButton>
</Maybe>
<Maybe condition={!canSetRoles}>
) : (
<HelpTooltip size="small">
<HelpTooltipTitle>Externally controlled</HelpTooltipTitle>
<HelpTooltipText>
Roles for this user are controlled by the OIDC identity provider.
</HelpTooltipText>
</HelpTooltip>
</Maybe>
)}
<Popover
id={id}

View File

@ -29,7 +29,6 @@ import { DormantWorkspaceBanner } from "components/WorkspaceDeletion";
import { useLocalStorage } from "hooks";
import { ChooseOne, Cond } from "components/Conditionals/ChooseOne";
import AlertTitle from "@mui/material/AlertTitle";
import { Maybe } from "components/Conditionals/Maybe";
import dayjs from "dayjs";
export enum WorkspaceErrors {
@ -278,7 +277,7 @@ export const Workspace: FC<React.PropsWithChildren<WorkspaceProps>> = ({
<TemplateVersionWarnings warnings={templateWarnings} />
<Maybe condition={showAlertPendingInQueue}>
{showAlertPendingInQueue && (
<Alert severity="info">
<AlertTitle>Workspace build is pending</AlertTitle>
<AlertDetail>
@ -294,7 +293,7 @@ export const Workspace: FC<React.PropsWithChildren<WorkspaceProps>> = ({
</div>
</AlertDetail>
</Alert>
</Maybe>
)}
{workspace.latest_build.job.error && (
<Alert

View File

@ -1,6 +1,5 @@
import Link from "@mui/material/Link";
import { Workspace } from "api/typesGenerated";
import { Maybe } from "components/Conditionals/Maybe";
import { PaginationWidgetBase } from "components/PaginationWidget/PaginationWidgetBase";
import { ComponentProps, FC } from "react";
import { Link as RouterLink } from "react-router-dom";
@ -97,9 +96,9 @@ export const WorkspacesPageView: FC<
</PageHeader>
<Stack>
<Maybe condition={hasError(error) && !isApiValidationError(error)}>
{hasError(error) && !isApiValidationError(error) && (
<ErrorAlert error={error} />
</Maybe>
)}
{/* <DormantWorkspaceBanner/> determines its own visibility */}
<DormantWorkspaceBanner
workspaces={dormantWorkspaces}