Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bdb5cb3

Browse files
committed
feat: give update button primary focus when applicable
resolves #3024
1 parent 62e6856 commit bdb5cb3

File tree

4 files changed

+44
-49
lines changed

4 files changed

+44
-49
lines changed

site/src/components/WorkspaceActions/ActionCtas.tsx

Lines changed: 10 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline"
66
import HighlightOffIcon from "@material-ui/icons/HighlightOff"
77
import PlayCircleOutlineIcon from "@material-ui/icons/PlayCircleOutline"
88
import { FC } from "react"
9-
import { Workspace } from "../../api/typesGenerated"
10-
import { WorkspaceStatus } from "../../util/workspace"
119
import { WorkspaceActionButton } from "../WorkspaceActionButton/WorkspaceActionButton"
1210

1311
export const Language = {
@@ -22,6 +20,16 @@ interface WorkspaceAction {
2220
handleAction: () => void
2321
}
2422

23+
export const UpdateButton: FC<WorkspaceAction> = ({ handleAction }) => {
24+
const styles = useStyles()
25+
26+
return (
27+
<Button className={styles.actionButton} startIcon={<CloudQueueIcon />} onClick={handleAction}>
28+
{Language.update}
29+
</Button>
30+
)
31+
}
32+
2533
export const StartButton: FC<WorkspaceAction> = ({ handleAction }) => {
2634
const styles = useStyles()
2735

@@ -61,36 +69,6 @@ export const DeleteButton: FC<WorkspaceAction> = ({ handleAction }) => {
6169
)
6270
}
6371

64-
type UpdateAction = WorkspaceAction & {
65-
workspace: Workspace
66-
workspaceStatus: WorkspaceStatus
67-
}
68-
69-
export const UpdateButton: FC<UpdateAction> = ({ handleAction, workspace, workspaceStatus }) => {
70-
const styles = useStyles()
71-
72-
/**
73-
* Jobs submitted while another job is in progress will be discarded,
74-
* so check whether workspace job status has reached completion (whether successful or not).
75-
*/
76-
const canAcceptJobs = (workspaceStatus: WorkspaceStatus) =>
77-
["started", "stopped", "deleted", "error", "canceled"].includes(workspaceStatus)
78-
79-
return (
80-
<>
81-
{workspace.outdated && canAcceptJobs(workspaceStatus) && (
82-
<Button
83-
className={styles.actionButton}
84-
startIcon={<CloudQueueIcon />}
85-
onClick={handleAction}
86-
>
87-
{Language.update}
88-
</Button>
89-
)}
90-
</>
91-
)
92-
}
93-
9472
export const CancelButton: FC<WorkspaceAction> = ({ handleAction }) => {
9573
const styles = useStyles()
9674

site/src/components/WorkspaceActions/WorkspaceActions.test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,11 @@ describe("WorkspaceActions", () => {
7979
})
8080
})
8181
describe("when the workspace is outdated", () => {
82-
it("primary is start; secondary are delete, update", async () => {
82+
it("primary is update; secondary are start, delete", async () => {
8383
await renderAndClick({ workspace: Mocks.MockOutdatedWorkspace })
84-
expect(screen.getByTestId("primary-cta")).toHaveTextContent(Language.start)
84+
expect(screen.getByTestId("primary-cta")).toHaveTextContent(Language.update)
85+
expect(screen.getByTestId("secondary-ctas")).toHaveTextContent(Language.start)
8586
expect(screen.getByTestId("secondary-ctas")).toHaveTextContent(Language.delete)
86-
expect(screen.getByTestId("secondary-ctas")).toHaveTextContent(Language.update)
8787
})
8888
})
8989
})

site/src/components/WorkspaceActions/WorkspaceActions.tsx

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
import Button from "@material-ui/core/Button"
22
import Popover from "@material-ui/core/Popover"
33
import { makeStyles } from "@material-ui/core/styles"
4-
import { FC, ReactNode, useEffect, useRef, useState } from "react"
4+
import { FC, ReactNode, useEffect, useMemo, useRef, useState } from "react"
55
import { Workspace } from "../../api/typesGenerated"
6-
import { getWorkspaceStatus } from "../../util/workspace"
6+
import { getWorkspaceStatus, WorkspaceStatus } from "../../util/workspace"
77
import { CloseDropdown, OpenDropdown } from "../DropdownArrows/DropdownArrows"
88
import { CancelButton, DeleteButton, StartButton, StopButton, UpdateButton } from "./ActionCtas"
99
import { ButtonTypesEnum, WorkspaceStateActions, WorkspaceStateEnum } from "./constants"
1010

11+
/**
12+
* Jobs submitted while another job is in progress will be discarded,
13+
* so check whether workspace job status has reached completion (whether successful or not).
14+
*/
15+
const canAcceptJobs = (workspaceStatus: WorkspaceStatus) =>
16+
["started", "stopped", "deleted", "error", "canceled"].includes(workspaceStatus)
17+
1118
export interface WorkspaceActionsProps {
1219
workspace: Workspace
1320
handleStart: () => void
@@ -34,7 +41,23 @@ export const WorkspaceActions: FC<WorkspaceActionsProps> = ({
3441
workspace.latest_build,
3542
)
3643
const workspaceState = WorkspaceStateEnum[workspaceStatus]
37-
const actions = WorkspaceStateActions[workspaceState]
44+
45+
const canUpdateWorkspace = workspace.outdated && canAcceptJobs(workspaceStatus)
46+
47+
// actions are the primary and secondary CTAs that appear in the workspace actions dropdown
48+
const actions = useMemo(() => {
49+
if (!canUpdateWorkspace) {
50+
return WorkspaceStateActions[workspaceState]
51+
}
52+
53+
// if an update is available, we make the update button the primary CTA
54+
// and move the former primary CTA to the secondary actions list
55+
const updatedActions = { ...WorkspaceStateActions[workspaceState] }
56+
updatedActions.secondary.unshift(updatedActions.primary)
57+
updatedActions.primary = ButtonTypesEnum.update
58+
59+
return updatedActions
60+
}, [canUpdateWorkspace, workspaceState])
3861

3962
/**
4063
* Ensures we close the popover before calling any action handler
@@ -58,16 +81,10 @@ export const WorkspaceActions: FC<WorkspaceActionsProps> = ({
5881

5982
// A mapping of button type to the corresponding React component
6083
const buttonMapping: ButtonMapping = {
84+
[ButtonTypesEnum.update]: <UpdateButton handleAction={handleUpdate} />,
6185
[ButtonTypesEnum.start]: <StartButton handleAction={handleStart} />,
6286
[ButtonTypesEnum.stop]: <StopButton handleAction={handleStop} />,
6387
[ButtonTypesEnum.delete]: <DeleteButton handleAction={handleDelete} />,
64-
[ButtonTypesEnum.update]: (
65-
<UpdateButton
66-
handleAction={handleUpdate}
67-
workspace={workspace}
68-
workspaceStatus={workspaceStatus}
69-
/>
70-
),
7188
[ButtonTypesEnum.cancel]: <CancelButton handleAction={handleCancel} />,
7289
[ButtonTypesEnum.canceling]: disabledButton,
7390
[ButtonTypesEnum.disabled]: disabledButton,

site/src/components/WorkspaceActions/constants.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,24 +45,24 @@ export const WorkspaceStateActions: StateActionsType = {
4545
},
4646
[WorkspaceStateEnum.started]: {
4747
primary: ButtonTypesEnum.stop,
48-
secondary: [ButtonTypesEnum.delete, ButtonTypesEnum.update],
48+
secondary: [ButtonTypesEnum.delete],
4949
},
5050
[WorkspaceStateEnum.stopping]: {
5151
primary: ButtonTypesEnum.cancel,
5252
secondary: [],
5353
},
5454
[WorkspaceStateEnum.stopped]: {
5555
primary: ButtonTypesEnum.start,
56-
secondary: [ButtonTypesEnum.delete, ButtonTypesEnum.update],
56+
secondary: [ButtonTypesEnum.delete],
5757
},
5858
[WorkspaceStateEnum.canceled]: {
5959
primary: ButtonTypesEnum.start,
60-
secondary: [ButtonTypesEnum.stop, ButtonTypesEnum.delete, ButtonTypesEnum.update],
60+
secondary: [ButtonTypesEnum.stop, ButtonTypesEnum.delete],
6161
},
6262
// in the case of an error
6363
[WorkspaceStateEnum.error]: {
6464
primary: ButtonTypesEnum.start, // give the user the ability to start a workspace again
65-
secondary: [ButtonTypesEnum.delete, ButtonTypesEnum.update], // allows the user to delete or update
65+
secondary: [ButtonTypesEnum.delete], // allows the user to delete
6666
},
6767
/**
6868
* disabled states

0 commit comments

Comments
 (0)