mirror of https://github.com/coder/coder.git
feat(site): Show update confirmation dialog (#7420)
This commit is contained in:
parent
6d24f7c894
commit
164146c462
|
@ -65,6 +65,7 @@ export const DialogActionButtons: React.FC<DialogActionButtonsProps> = ({
|
|||
{onConfirm && (
|
||||
<LoadingButton
|
||||
fullWidth
|
||||
data-testid="confirm-button"
|
||||
variant="contained"
|
||||
onClick={onConfirm}
|
||||
color={typeToColor(type)}
|
||||
|
|
|
@ -114,10 +114,10 @@ export const AgentRow: FC<AgentRowProps> = ({
|
|||
useEffect(() => {
|
||||
// We only want to fetch logs when they are actually shown,
|
||||
// otherwise we can make a lot of requests that aren't necessary.
|
||||
if (showStartupLogs) {
|
||||
if (showStartupLogs && logsMachine.can("FETCH_STARTUP_LOGS")) {
|
||||
sendLogsEvent("FETCH_STARTUP_LOGS")
|
||||
}
|
||||
}, [sendLogsEvent, showStartupLogs])
|
||||
}, [logsMachine, sendLogsEvent, showStartupLogs])
|
||||
const logListRef = useRef<List>(null)
|
||||
const logListDivRef = useRef<HTMLDivElement>(null)
|
||||
const startupLogs = useMemo(() => {
|
||||
|
|
|
@ -21,6 +21,7 @@ export const UpdateButton: FC<PropsWithChildren<WorkspaceAction>> = ({
|
|||
|
||||
return (
|
||||
<Button
|
||||
data-testid="workspace-update-button"
|
||||
variant="outlined"
|
||||
startIcon={<CloudQueueIcon />}
|
||||
onClick={handleAction}
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
import { screen } from "@testing-library/react"
|
||||
import WS from "jest-websocket-mock"
|
||||
import {
|
||||
MockWorkspace,
|
||||
MockWorkspaceBuild,
|
||||
renderWithAuth,
|
||||
} from "../../testHelpers/renderHelpers"
|
||||
import { renderWithAuth } from "../../testHelpers/renderHelpers"
|
||||
import { WorkspaceBuildPage } from "./WorkspaceBuildPage"
|
||||
import { MockWorkspace, MockWorkspaceBuild } from "testHelpers/entities"
|
||||
|
||||
describe("WorkspaceBuildPage", () => {
|
||||
test("the mock server seamlessly handles JSON protocols", async () => {
|
||||
|
|
|
@ -35,6 +35,10 @@ const { t } = i18next
|
|||
const renderWorkspacePage = async () => {
|
||||
jest.spyOn(api, "getTemplate").mockResolvedValueOnce(MockTemplate)
|
||||
jest.spyOn(api, "getTemplateVersionRichParameters").mockResolvedValueOnce([])
|
||||
jest.spyOn(api, "watchStartupLogs").mockImplementation((_, options) => {
|
||||
options.onDone()
|
||||
return new WebSocket("")
|
||||
})
|
||||
renderWithAuth(<WorkspacePage />, {
|
||||
route: `/@${MockWorkspace.owner_name}/${MockWorkspace.name}`,
|
||||
path: "/@:username/:workspace",
|
||||
|
@ -188,22 +192,32 @@ describe("WorkspacePage", () => {
|
|||
})
|
||||
|
||||
it("requests an update when the user presses Update", async () => {
|
||||
// Mocks
|
||||
jest
|
||||
.spyOn(api, "getWorkspaceByOwnerAndName")
|
||||
.mockResolvedValueOnce(MockOutdatedWorkspace)
|
||||
|
||||
const updateWorkspaceMock = jest
|
||||
.spyOn(api, "updateWorkspace")
|
||||
.mockResolvedValueOnce(MockWorkspaceBuild)
|
||||
|
||||
await testButton(
|
||||
t("actionButton.update", { ns: "workspacePage" }),
|
||||
updateWorkspaceMock,
|
||||
)
|
||||
// Render
|
||||
await renderWorkspacePage()
|
||||
|
||||
// Actions
|
||||
const user = userEvent.setup()
|
||||
await user.click(screen.getByTestId("workspace-update-button"))
|
||||
const confirmButton = await screen.findByTestId("confirm-button")
|
||||
await user.click(confirmButton)
|
||||
|
||||
// Assertions
|
||||
await waitFor(() => {
|
||||
expect(updateWorkspaceMock).toBeCalled()
|
||||
})
|
||||
})
|
||||
|
||||
it("updates the parameters when they are missing during update", async () => {
|
||||
// Setup mocks
|
||||
const user = userEvent.setup()
|
||||
// Mocks
|
||||
jest
|
||||
.spyOn(api, "getWorkspaceByOwnerAndName")
|
||||
.mockResolvedValueOnce(MockOutdatedWorkspace)
|
||||
|
@ -215,23 +229,24 @@ describe("WorkspacePage", () => {
|
|||
MockTemplateVersionParameter2,
|
||||
]),
|
||||
)
|
||||
// Render page and wait for it to be loaded
|
||||
renderWithAuth(<WorkspacePage />, {
|
||||
route: `/@${MockWorkspace.owner_name}/${MockWorkspace.name}`,
|
||||
path: "/@:username/:workspace",
|
||||
})
|
||||
await waitForLoaderToBeRemoved()
|
||||
// Click on the update button
|
||||
const workspaceActions = screen.getByTestId("workspace-actions")
|
||||
await user.click(
|
||||
within(workspaceActions).getByRole("button", { name: "Update" }),
|
||||
)
|
||||
|
||||
// Render
|
||||
await renderWorkspacePage()
|
||||
|
||||
// Actions
|
||||
const user = userEvent.setup()
|
||||
await user.click(screen.getByTestId("workspace-update-button"))
|
||||
const confirmButton = await screen.findByTestId("confirm-button")
|
||||
await user.click(confirmButton)
|
||||
|
||||
// The update was called
|
||||
await waitFor(() => {
|
||||
expect(api.updateWorkspace).toBeCalled()
|
||||
// We want to clear this mock to use it later
|
||||
updateWorkspaceSpy.mockClear()
|
||||
})
|
||||
// Fill the parameters and send the form
|
||||
|
||||
// After trying to update, a new dialog asking for missed parameters should
|
||||
// be displayed and filled
|
||||
const dialog = await screen.findByTestId("dialog")
|
||||
const firstParameterInput = within(dialog).getByLabelText(
|
||||
MockTemplateVersionParameter1.name,
|
||||
|
@ -246,6 +261,7 @@ describe("WorkspacePage", () => {
|
|||
await user.clear(secondParameterInput)
|
||||
await user.type(secondParameterInput, "2")
|
||||
await user.click(within(dialog).getByRole("button", { name: "Update" }))
|
||||
|
||||
// Check if the update was called using the values from the form
|
||||
await waitFor(() => {
|
||||
expect(api.updateWorkspace).toBeCalledWith(MockOutdatedWorkspace, [
|
||||
|
|
|
@ -31,6 +31,7 @@ import { ChangeVersionDialog } from "./ChangeVersionDialog"
|
|||
import { useQuery } from "@tanstack/react-query"
|
||||
import { getTemplateVersions } from "api/api"
|
||||
import { useRestartWorkspace } from "./hooks"
|
||||
import { ConfirmDialog } from "components/Dialogs/ConfirmDialog/ConfirmDialog"
|
||||
|
||||
interface WorkspaceReadyPageProps {
|
||||
workspaceState: StateFrom<typeof workspaceMachine>
|
||||
|
@ -76,6 +77,7 @@ export const WorkspaceReadyPage = ({
|
|||
queryFn: () => getTemplateVersions(workspace.template_id),
|
||||
enabled: changeVersionDialogOpen,
|
||||
})
|
||||
const [isConfirmingUpdate, setIsConfirmingUpdate] = useState(false)
|
||||
|
||||
const {
|
||||
mutate: restartWorkspace,
|
||||
|
@ -132,7 +134,7 @@ export const WorkspaceReadyPage = ({
|
|||
handleStop={() => workspaceSend({ type: "STOP" })}
|
||||
handleRestart={() => restartWorkspace(workspace)}
|
||||
handleDelete={() => workspaceSend({ type: "ASK_DELETE" })}
|
||||
handleUpdate={() => workspaceSend({ type: "UPDATE" })}
|
||||
handleUpdate={() => setIsConfirmingUpdate(true)}
|
||||
handleCancel={() => workspaceSend({ type: "CANCEL" })}
|
||||
handleSettings={() => navigate("settings")}
|
||||
handleBuildRetry={() => workspaceSend({ type: "RETRY_BUILD" })}
|
||||
|
@ -198,6 +200,19 @@ export const WorkspaceReadyPage = ({
|
|||
})
|
||||
}}
|
||||
/>
|
||||
<ConfirmDialog
|
||||
type="info"
|
||||
hideCancel={false}
|
||||
open={isConfirmingUpdate}
|
||||
onConfirm={() => {
|
||||
workspaceSend({ type: "UPDATE" })
|
||||
setIsConfirmingUpdate(false)
|
||||
}}
|
||||
onClose={() => setIsConfirmingUpdate(false)}
|
||||
title="Confirm update"
|
||||
confirmText="Update"
|
||||
description="Are you sure you want to update your workspace? Updating your workspace will stop all running processes and delete non-persistent data."
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1639,3 +1639,36 @@ export const MockDeploymentStats: TypesGen.DeploymentStats = {
|
|||
tx_bytes: 36113513253,
|
||||
},
|
||||
}
|
||||
|
||||
export const MockDeploymentSSH: TypesGen.SSHConfigResponse = {
|
||||
hostname_prefix: " coder.",
|
||||
ssh_config_options: {},
|
||||
}
|
||||
|
||||
export const MockStartupLogs: TypesGen.WorkspaceAgentStartupLog[] = [
|
||||
{
|
||||
id: 166663,
|
||||
created_at: "2023-05-04T11:30:41.402072Z",
|
||||
output: "+ curl -fsSL https://code-server.dev/install.sh",
|
||||
level: "info",
|
||||
},
|
||||
{
|
||||
id: 166664,
|
||||
created_at: "2023-05-04T11:30:41.40228Z",
|
||||
output:
|
||||
"+ sh -s -- --method=standalone --prefix=/tmp/code-server --version 4.8.3",
|
||||
level: "info",
|
||||
},
|
||||
{
|
||||
id: 166665,
|
||||
created_at: "2023-05-04T11:30:42.590731Z",
|
||||
output: "Ubuntu 22.04.2 LTS",
|
||||
level: "info",
|
||||
},
|
||||
{
|
||||
id: 166666,
|
||||
created_at: "2023-05-04T11:30:42.593686Z",
|
||||
output: "Installing v4.8.3 of the amd64 release from GitHub.",
|
||||
level: "info",
|
||||
},
|
||||
]
|
||||
|
|
|
@ -385,4 +385,12 @@ export const handlers = [
|
|||
)
|
||||
},
|
||||
),
|
||||
|
||||
rest.get("/api/v2/deployment/ssh", (_, res, ctx) => {
|
||||
return res(ctx.status(200), ctx.json(M.MockDeploymentSSH))
|
||||
}),
|
||||
|
||||
rest.get("/api/v2/workspaceagents/:agent/startup-logs", (_, res, ctx) => {
|
||||
return res(ctx.status(200), ctx.json(M.MockStartupLogs))
|
||||
}),
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue