Skip to content

fix: handle workspace errors #3341

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Aug 5, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
fix: handle workspace errors
  • Loading branch information
AbhineetJain committed Aug 1, 2022
commit 12cdd47a8534ecff3746f4eb86e192bdd1688d1b
3 changes: 3 additions & 0 deletions site/src/api/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,6 @@ export const getValidationErrorMessage = (error: Error | ApiError | unknown): st

export const getErrorDetail = (error: Error | ApiError | unknown): string | undefined | null =>
isApiError(error) ? error.response.data.detail : error instanceof Error ? error.stack : null

export const getErrorIfErrorType = (error: Error | unknown): Error | undefined =>
error instanceof Error ? error : undefined
3 changes: 2 additions & 1 deletion site/src/components/Resources/Resources.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import TableContainer from "@material-ui/core/TableContainer"
import TableHead from "@material-ui/core/TableHead"
import TableRow from "@material-ui/core/TableRow"
import useTheme from "@material-ui/styles/useTheme"
import { ErrorSummary } from "components/ErrorSummary/ErrorSummary"
import { FC } from "react"
import { Workspace, WorkspaceResource } from "../../api/typesGenerated"
import { AvatarData } from "../../components/AvatarData/AvatarData"
Expand Down Expand Up @@ -45,7 +46,7 @@ export const Resources: FC<ResourcesProps> = ({
return (
<div aria-label={Language.resources} className={styles.wrapper}>
{getResourcesError ? (
{ getResourcesError }
<ErrorSummary error={getResourcesError} />
) : (
<TableContainer className={styles.tableContainer}>
<Table>
Expand Down
28 changes: 24 additions & 4 deletions site/src/components/Workspace/Workspace.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { makeStyles } from "@material-ui/core/styles"
import { ErrorSummary } from "components/ErrorSummary/ErrorSummary"
import { WorkspaceStatusBadge } from "components/WorkspaceStatusBadge/WorkspaceStatusBadge"
import { FC } from "react"
import { useNavigate } from "react-router-dom"
Expand All @@ -15,6 +16,13 @@ import { WorkspaceScheduleButton } from "../WorkspaceScheduleButton/WorkspaceSch
import { WorkspaceSection } from "../WorkspaceSection/WorkspaceSection"
import { WorkspaceStats } from "../WorkspaceStats/WorkspaceStats"

export enum WorkspaceErrors {
GET_RESOURCES_ERROR = "getResourcesError",
GET_BUILDS_ERROR = "getBuildsError",
BUILD_ERROR = "buildError",
CANCELLATION_MESSAGE = "cancellationMessage",
}

export interface WorkspaceProps {
bannerProps: {
isLoading?: boolean
Expand All @@ -31,9 +39,9 @@ export interface WorkspaceProps {
handleCancel: () => void
workspace: TypesGen.Workspace
resources?: TypesGen.WorkspaceResource[]
getResourcesError?: Error
builds?: TypesGen.WorkspaceBuild[]
canUpdateWorkspace: boolean
workspaceErrors: Partial<Record<WorkspaceErrors, Error>>
}

/**
Expand All @@ -49,15 +57,23 @@ export const Workspace: FC<WorkspaceProps> = ({
handleCancel,
workspace,
resources,
getResourcesError,
builds,
canUpdateWorkspace,
workspaceErrors,
}) => {
const styles = useStyles()
const navigate = useNavigate()

return (
<Margins>
<Stack spacing={1}>
{workspaceErrors[WorkspaceErrors.BUILD_ERROR] && (
<ErrorSummary error={workspaceErrors[WorkspaceErrors.BUILD_ERROR]} dismissible />
)}
{workspaceErrors[WorkspaceErrors.CANCELLATION_MESSAGE] && (
<ErrorSummary error={workspaceErrors[WorkspaceErrors.CANCELLATION_MESSAGE]} dismissible />
)}
</Stack>
<PageHeader
actions={
<Stack direction="row" spacing={1} className={styles.actions}>
Expand Down Expand Up @@ -101,14 +117,18 @@ export const Workspace: FC<WorkspaceProps> = ({
{!!resources && !!resources.length && (
<Resources
resources={resources}
getResourcesError={getResourcesError}
getResourcesError={workspaceErrors[WorkspaceErrors.GET_RESOURCES_ERROR]}
workspace={workspace}
canUpdateWorkspace={canUpdateWorkspace}
/>
)}

<WorkspaceSection title="Logs" contentsProps={{ className: styles.timelineContents }}>
<BuildsTable builds={builds} className={styles.timelineTable} />
{workspaceErrors[WorkspaceErrors.GET_BUILDS_ERROR] ? (
<ErrorSummary error={workspaceErrors[WorkspaceErrors.GET_BUILDS_ERROR]} />
) : (
<BuildsTable builds={builds} className={styles.timelineTable} />
)}
</WorkspaceSection>
</Stack>
</Stack>
Expand Down
41 changes: 36 additions & 5 deletions site/src/pages/WorkspacePage/WorkspacePage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { makeStyles } from "@material-ui/core/styles"
import { useMachine, useSelector } from "@xstate/react"
import { getErrorIfErrorType } from "api/errors"
import dayjs from "dayjs"
import minMax from "dayjs/plugin/minMax"
import React, { useContext, useEffect } from "react"
Expand All @@ -7,7 +9,7 @@ import { useParams } from "react-router-dom"
import { DeleteWorkspaceDialog } from "../../components/DeleteWorkspaceDialog/DeleteWorkspaceDialog"
import { ErrorSummary } from "../../components/ErrorSummary/ErrorSummary"
import { FullScreenLoader } from "../../components/Loader/FullScreenLoader"
import { Workspace } from "../../components/Workspace/Workspace"
import { Workspace, WorkspaceErrors } from "../../components/Workspace/Workspace"
import { firstOrItem } from "../../util/array"
import { pageTitle } from "../../util/page"
import { getFaviconByStatus } from "../../util/workspace"
Expand All @@ -31,13 +33,26 @@ export const WorkspacePage: React.FC = () => {
userId: me?.id,
},
})
const { workspace, resources, getWorkspaceError, getResourcesError, builds, permissions } =
workspaceState.context
const {
workspace,
getWorkspaceError,
resources,
getResourcesError,
builds,
getBuildsError,
permissions,
checkPermissionsError,
buildError,
cancellationMessage,
} = workspaceState.context

console.log(cancellationMessage)
const canUpdateWorkspace = !!permissions?.updateWorkspace

const [bannerState, bannerSend] = useMachine(workspaceScheduleBannerMachine)

const styles = useStyles()

/**
* Get workspace, template, and organization on mount and whenever workspaceId changes.
* workspaceSend should not change.
Expand All @@ -47,7 +62,12 @@ export const WorkspacePage: React.FC = () => {
}, [username, workspaceName, workspaceSend])

if (workspaceState.matches("error")) {
return <ErrorSummary error={getWorkspaceError} />
return (
<div className={styles.error}>
{getWorkspaceError && <ErrorSummary error={getWorkspaceError} />}
{checkPermissionsError && <ErrorSummary error={checkPermissionsError} />}
</div>
)
} else if (!workspace) {
return <FullScreenLoader />
} else {
Expand Down Expand Up @@ -100,9 +120,14 @@ export const WorkspacePage: React.FC = () => {
handleUpdate={() => workspaceSend("UPDATE")}
handleCancel={() => workspaceSend("CANCEL")}
resources={resources}
getResourcesError={getResourcesError instanceof Error ? getResourcesError : undefined}
builds={builds}
canUpdateWorkspace={canUpdateWorkspace}
workspaceErrors={{
[WorkspaceErrors.GET_RESOURCES_ERROR]: getErrorIfErrorType(getResourcesError),
[WorkspaceErrors.GET_BUILDS_ERROR]: getErrorIfErrorType(getBuildsError),
[WorkspaceErrors.BUILD_ERROR]: getErrorIfErrorType(buildError),
[WorkspaceErrors.CANCELLATION_MESSAGE]: getErrorIfErrorType(cancellationMessage),
}}
/>
<DeleteWorkspaceDialog
isOpen={workspaceState.matches({ ready: { build: "askingDelete" } })}
Expand All @@ -121,3 +146,9 @@ export const boundedDeadline = (newDeadline: dayjs.Dayjs, now: dayjs.Dayjs): day
const maxDeadline = now.add(24, "hours")
return dayjs.min(dayjs.max(minDeadline, newDeadline), maxDeadline)
}

const useStyles = makeStyles((theme) => ({
error: {
margin: theme.spacing(2),
},
}))
16 changes: 5 additions & 11 deletions site/src/xServices/workspace/workspaceXService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export interface WorkspaceContext {
builds?: TypesGen.WorkspaceBuild[]
getBuildsError?: Error | unknown
loadMoreBuildsError?: Error | unknown
cancellationMessage: string
cancellationMessage: Types.Message
// permissions
permissions?: Permissions
checkPermissionsError?: Error | unknown
Expand Down Expand Up @@ -213,7 +213,7 @@ export const workspaceMachine = createMachine(
},
onError: {
target: "idle",
actions: ["assignBuildError", "displayBuildError"],
actions: ["assignBuildError"],
},
},
},
Expand All @@ -228,7 +228,7 @@ export const workspaceMachine = createMachine(
},
onError: {
target: "idle",
actions: ["assignBuildError", "displayBuildError"],
actions: ["assignBuildError"],
},
},
},
Expand All @@ -243,7 +243,7 @@ export const workspaceMachine = createMachine(
},
onError: {
target: "idle",
actions: ["assignBuildError", "displayBuildError"],
actions: ["assignBuildError"],
},
},
},
Expand All @@ -258,7 +258,7 @@ export const workspaceMachine = createMachine(
},
onError: {
target: "idle",
actions: ["assignCancellationMessage", "displayCancellationError"],
actions: ["assignCancellationMessage"],
},
},
},
Expand Down Expand Up @@ -395,9 +395,6 @@ export const workspaceMachine = createMachine(
assign({
buildError: event.data,
}),
displayBuildError: () => {
displayError(Language.buildError)
},
clearBuildError: (_) =>
assign({
buildError: undefined,
Expand All @@ -410,9 +407,6 @@ export const workspaceMachine = createMachine(
assign({
cancellationMessage: undefined,
}),
displayCancellationError: (context) => {
displayError(context.cancellationMessage)
},
assignRefreshWorkspaceError: (_, event) =>
assign({
refreshWorkspaceError: event.data,
Expand Down