Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
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
5 changes: 3 additions & 2 deletions 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 All @@ -28,7 +29,7 @@ const Language = {

interface ResourcesProps {
resources?: WorkspaceResource[]
getResourcesError?: Error
getResourcesError?: Error | unknown
workspace: Workspace
canUpdateWorkspace: boolean
}
Expand All @@ -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
32 changes: 31 additions & 1 deletion site/src/components/Workspace/Workspace.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { action } from "@storybook/addon-actions"
import { Story } from "@storybook/react"
import * as Mocks from "../../testHelpers/entities"
import { Workspace, WorkspaceProps } from "./Workspace"
import { Workspace, WorkspaceErrors, WorkspaceProps } from "./Workspace"

export default {
title: "components/Workspace",
Expand Down Expand Up @@ -71,6 +71,11 @@ Error.args = {
transition: "start",
},
},
workspaceErrors: {
[WorkspaceErrors.BUILD_ERROR]: Mocks.makeMockApiError({
message: "A workspace build is already active.",
}),
},
}

export const Deleting = Template.bind({})
Expand All @@ -95,10 +100,35 @@ export const Canceled = Template.bind({})
Canceled.args = {
...Started.args,
workspace: Mocks.MockCanceledWorkspace,
workspaceErrors: {
[WorkspaceErrors.CANCELLATION_MESSAGE]: Mocks.makeMockApiError({
message: "Job has been marked as canceled...",
}),
},
}

export const Outdated = Template.bind({})
Outdated.args = {
...Started.args,
workspace: Mocks.MockOutdatedWorkspace,
}

export const GetBuildsError = Template.bind({})
GetBuildsError.args = {
...Started.args,
workspaceErrors: {
[WorkspaceErrors.GET_BUILDS_ERROR]: Mocks.makeMockApiError({
message: "There is a problem fetching builds.",
}),
},
}

export const GetResourcesError = Template.bind({})
GetResourcesError.args = {
...Started.args,
workspaceErrors: {
[WorkspaceErrors.GET_RESOURCES_ERROR]: Mocks.makeMockApiError({
message: "There is a problem fetching workspace resources.",
}),
},
}
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 | unknown>>
}

/**
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
39 changes: 34 additions & 5 deletions site/src/pages/WorkspacePage/WorkspacePage.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { makeStyles } from "@material-ui/core/styles"
import { useMachine, useSelector } from "@xstate/react"
import dayjs from "dayjs"
import minMax from "dayjs/plugin/minMax"
Expand All @@ -7,7 +8,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 +32,25 @@ 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

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 +60,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 +118,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]: getResourcesError,
[WorkspaceErrors.GET_BUILDS_ERROR]: getBuildsError,
[WorkspaceErrors.BUILD_ERROR]: buildError,
[WorkspaceErrors.CANCELLATION_MESSAGE]: cancellationMessage,
}}
/>
<DeleteWorkspaceDialog
isOpen={workspaceState.matches({ ready: { build: "askingDelete" } })}
Expand All @@ -121,3 +144,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