From 9b1ae14359af88190488c414d135d0483e12eb39 Mon Sep 17 00:00:00 2001 From: Parkreiner Date: Mon, 9 Oct 2023 13:37:09 +0000 Subject: [PATCH 01/10] refactor: clean up TemplatePageHeader --- .../pages/TemplatePage/TemplatePageHeader.tsx | 73 ++++++++++--------- 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/site/src/pages/TemplatePage/TemplatePageHeader.tsx b/site/src/pages/TemplatePage/TemplatePageHeader.tsx index 3985306a97548..57ed553875a5d 100644 --- a/site/src/pages/TemplatePage/TemplatePageHeader.tsx +++ b/site/src/pages/TemplatePage/TemplatePageHeader.tsx @@ -1,36 +1,46 @@ -import Button from "@mui/material/Button"; -import AddIcon from "@mui/icons-material/AddOutlined"; +import { type FC, useRef, useState } from "react"; +import { Link as RouterLink, useNavigate } from "react-router-dom"; +import { useDeleteTemplate } from "./deleteTemplate"; + import { AuthorizationResponse, Template, TemplateVersion, } from "api/typesGenerated"; + import { Avatar } from "components/Avatar/Avatar"; import { DeleteDialog } from "components/Dialogs/DeleteDialog/DeleteDialog"; +import { Stack } from "components/Stack/Stack"; +import { Margins } from "components/Margins/Margins"; import { PageHeader, PageHeaderTitle, PageHeaderSubtitle, } from "components/PageHeader/PageHeader"; -import { Stack } from "components/Stack/Stack"; -import { FC, useRef, useState } from "react"; -import { Link as RouterLink, useNavigate } from "react-router-dom"; -import { useDeleteTemplate } from "./deleteTemplate"; -import { Margins } from "components/Margins/Margins"; + +import Button from "@mui/material/Button"; import MoreVertOutlined from "@mui/icons-material/MoreVertOutlined"; import Menu from "@mui/material/Menu"; import MenuItem from "@mui/material/MenuItem"; -import SettingsOutlined from "@mui/icons-material/SettingsOutlined"; -import DeleteOutlined from "@mui/icons-material/DeleteOutlined"; -import EditOutlined from "@mui/icons-material/EditOutlined"; -import FileCopyOutlined from "@mui/icons-material/FileCopyOutlined"; import IconButton from "@mui/material/IconButton"; +import AddIcon from "@mui/icons-material/AddOutlined"; +import SettingsIcon from "@mui/icons-material/SettingsOutlined"; +import DeleteIcon from "@mui/icons-material/DeleteOutlined"; +import EditIcon from "@mui/icons-material/EditOutlined"; +import CopyIcon from "@mui/icons-material/FileCopyOutlined"; -const TemplateMenu: FC<{ +type TemplateMenuProps = { templateName: string; templateVersion: string; onDelete: () => void; -}> = ({ templateName, templateVersion, onDelete }) => { + onMenuOpen?: () => void; +}; + +const TemplateMenu: FC = ({ + templateName, + templateVersion, + onDelete, +}) => { const menuTriggerRef = useRef(null); const [isMenuOpen, setIsMenuOpen] = useState(false); const navigate = useNavigate(); @@ -38,7 +48,6 @@ const TemplateMenu: FC<{ // Returns a function that will execute the action and close the menu const onMenuItemClick = (actionFn: () => void) => () => { setIsMenuOpen(false); - actionFn(); }; @@ -65,9 +74,10 @@ const TemplateMenu: FC<{ navigate(`/templates/${templateName}/settings`), )} > - + Settings + navigate( @@ -75,19 +85,21 @@ const TemplateMenu: FC<{ ), )} > - + Edit files + navigate(`/templates/new?fromTemplate=${templateName}`), )} > - + Duplicate… + - + Delete… @@ -95,20 +107,6 @@ const TemplateMenu: FC<{ ); }; -const CreateWorkspaceButton: FC<{ - templateName: string; - className?: string; -}> = ({ templateName }) => ( - -); - export type TemplatePageHeaderProps = { template: Template; activeVersion: TemplateVersion; @@ -130,7 +128,15 @@ export const TemplatePageHeader: FC = ({ - + + {permissions.canUpdateTemplate && ( = ({ ? template.display_name : template.name} + {template.description !== "" && ( {template.description} From 3349176457d5fa98d0a355ccd0a7babb5b4f9b89 Mon Sep 17 00:00:00 2001 From: Parkreiner Date: Mon, 9 Oct 2023 16:20:44 +0000 Subject: [PATCH 02/10] chore: add react query configs for workspace lists --- site/src/api/queries/workspaces.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 site/src/api/queries/workspaces.ts diff --git a/site/src/api/queries/workspaces.ts b/site/src/api/queries/workspaces.ts new file mode 100644 index 0000000000000..d8d22831ceeaa --- /dev/null +++ b/site/src/api/queries/workspaces.ts @@ -0,0 +1,14 @@ +import * as API from "api/api"; +import { type WorkspacesResponse } from "api/typesGenerated"; +import { type QueryOptions } from "react-query"; + +export function workspacesByQueryKey(query: string) { + return ["workspaces", query] as const; +} + +export function workspacesByQuery(query: string) { + return { + queryKey: workspacesByQueryKey(query), + queryFn: () => API.getWorkspaces({ q: query }), + } as const satisfies QueryOptions; +} From 5604a0de4eca6d0a51968bbd519952f0c4a19546 Mon Sep 17 00:00:00 2001 From: Parkreiner Date: Mon, 9 Oct 2023 16:21:14 +0000 Subject: [PATCH 03/10] feat: add delete-intercept functionality --- .../pages/TemplatePage/TemplatePageHeader.tsx | 72 ++++++++++++++++--- 1 file changed, 61 insertions(+), 11 deletions(-) diff --git a/site/src/pages/TemplatePage/TemplatePageHeader.tsx b/site/src/pages/TemplatePage/TemplatePageHeader.tsx index 57ed553875a5d..79493b589a003 100644 --- a/site/src/pages/TemplatePage/TemplatePageHeader.tsx +++ b/site/src/pages/TemplatePage/TemplatePageHeader.tsx @@ -2,6 +2,9 @@ import { type FC, useRef, useState } from "react"; import { Link as RouterLink, useNavigate } from "react-router-dom"; import { useDeleteTemplate } from "./deleteTemplate"; +import { useQuery } from "react-query"; +import { workspacesByQuery } from "api/queries/workspaces"; +import { ConfirmDialog } from "components/Dialogs/ConfirmDialog/ConfirmDialog"; import { AuthorizationResponse, Template, @@ -33,7 +36,6 @@ type TemplateMenuProps = { templateName: string; templateVersion: string; onDelete: () => void; - onMenuOpen?: () => void; }; const TemplateMenu: FC = ({ @@ -120,8 +122,16 @@ export const TemplatePageHeader: FC = ({ permissions, onDeleteTemplate, }) => { + const navigate = useNavigate(); + const deletionState = useDeleteTemplate(template, onDeleteTemplate); + + const queryText = `template:${template.name}`; + const workspaceCountQuery = useQuery({ + ...workspacesByQuery(queryText), + select: (res) => res.count, + }); + const hasIcon = template.icon && template.icon !== ""; - const deleteTemplate = useDeleteTemplate(template, onDeleteTemplate); return ( @@ -141,7 +151,7 @@ export const TemplatePageHeader: FC = ({ )} @@ -170,14 +180,54 @@ export const TemplatePageHeader: FC = ({ - + {workspaceCountQuery.status === "success" && + workspaceCountQuery.data === 0 ? ( + + ) : ( + { + navigate({ + pathname: "/workspaces", + search: new URLSearchParams({ filter: queryText }).toString(), + }); + }} + description={ + <> + {workspaceCountQuery.isSuccess && ( + <> + This template is used by{" "} + + {workspaceCountQuery.data} workspace + {workspaceCountQuery.data === 1 ? "" : "s"} + + . Please delete all related workspaces before deleting this + template. + + )} + + {workspaceCountQuery.isLoading && ( + <>Loading information about workspaces used by this template. + )} + + {workspaceCountQuery.isError && ( + <>Unable to determine workspaces used by this template. + )} + + } + /> + )} ); }; From 8f50beb7dbef76f906f924f0580c52df40798704 Mon Sep 17 00:00:00 2001 From: Parkreiner Date: Mon, 9 Oct 2023 16:27:06 +0000 Subject: [PATCH 04/10] refactor: improve readability --- site/src/pages/TemplatePage/TemplatePageHeader.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/site/src/pages/TemplatePage/TemplatePageHeader.tsx b/site/src/pages/TemplatePage/TemplatePageHeader.tsx index 79493b589a003..ef1382f9f7a8a 100644 --- a/site/src/pages/TemplatePage/TemplatePageHeader.tsx +++ b/site/src/pages/TemplatePage/TemplatePageHeader.tsx @@ -132,6 +132,8 @@ export const TemplatePageHeader: FC = ({ }); const hasIcon = template.icon && template.icon !== ""; + const safeToDeleteTemplate = + workspaceCountQuery.status === "success" && workspaceCountQuery.data === 0; return ( @@ -180,8 +182,7 @@ export const TemplatePageHeader: FC = ({ - {workspaceCountQuery.status === "success" && - workspaceCountQuery.data === 0 ? ( + {safeToDeleteTemplate ? ( = ({ open={deletionState.isDeleteDialogOpen} onClose={deletionState.cancelDeleteConfirmation} confirmText="See workspaces" + confirmLoading={workspaceCountQuery.status !== "success"} onConfirm={() => { navigate({ pathname: "/workspaces", From eac4164cf8c3122e9e23dbf69c34a79766d07b31 Mon Sep 17 00:00:00 2001 From: Parkreiner Date: Mon, 9 Oct 2023 17:55:48 +0000 Subject: [PATCH 05/10] refactor: rename entities for readability/accuracy --- .../pages/TemplatePage/TemplatePageHeader.tsx | 16 ++++++++-------- ...e.test.ts => useDeletionPopoverState.test.ts} | 8 ++++---- ...eteTemplate.ts => useDeletionPopoverState.ts} | 5 ++++- 3 files changed, 16 insertions(+), 13 deletions(-) rename site/src/pages/TemplatePage/{deleteTemplate.test.ts => useDeletionPopoverState.test.ts} (83%) rename site/src/pages/TemplatePage/{deleteTemplate.ts => useDeletionPopoverState.ts} (92%) diff --git a/site/src/pages/TemplatePage/TemplatePageHeader.tsx b/site/src/pages/TemplatePage/TemplatePageHeader.tsx index ef1382f9f7a8a..abc20e5cd11c7 100644 --- a/site/src/pages/TemplatePage/TemplatePageHeader.tsx +++ b/site/src/pages/TemplatePage/TemplatePageHeader.tsx @@ -1,6 +1,6 @@ import { type FC, useRef, useState } from "react"; import { Link as RouterLink, useNavigate } from "react-router-dom"; -import { useDeleteTemplate } from "./deleteTemplate"; +import { useDeletionPopoverState } from "./useDeletionPopoverState"; import { useQuery } from "react-query"; import { workspacesByQuery } from "api/queries/workspaces"; @@ -123,7 +123,7 @@ export const TemplatePageHeader: FC = ({ onDeleteTemplate, }) => { const navigate = useNavigate(); - const deletionState = useDeleteTemplate(template, onDeleteTemplate); + const popoverState = useDeletionPopoverState(template, onDeleteTemplate); const queryText = `template:${template.name}`; const workspaceCountQuery = useQuery({ @@ -153,7 +153,7 @@ export const TemplatePageHeader: FC = ({ )} @@ -184,9 +184,9 @@ export const TemplatePageHeader: FC = ({ {safeToDeleteTemplate ? ( @@ -195,8 +195,8 @@ export const TemplatePageHeader: FC = ({ type="info" title="Unable to delete" hideCancel={false} - open={deletionState.isDeleteDialogOpen} - onClose={deletionState.cancelDeleteConfirmation} + open={popoverState.isDeleteDialogOpen} + onClose={popoverState.cancelDeleteConfirmation} confirmText="See workspaces" confirmLoading={workspaceCountQuery.status !== "success"} onConfirm={() => { diff --git a/site/src/pages/TemplatePage/deleteTemplate.test.ts b/site/src/pages/TemplatePage/useDeletionPopoverState.test.ts similarity index 83% rename from site/src/pages/TemplatePage/deleteTemplate.test.ts rename to site/src/pages/TemplatePage/useDeletionPopoverState.test.ts index fc4a4076d2852..20240f85901f9 100644 --- a/site/src/pages/TemplatePage/deleteTemplate.test.ts +++ b/site/src/pages/TemplatePage/useDeletionPopoverState.test.ts @@ -1,11 +1,11 @@ import { act, renderHook, waitFor } from "@testing-library/react"; import { MockTemplate } from "testHelpers/entities"; -import { useDeleteTemplate } from "./deleteTemplate"; +import { useDeletionPopoverState } from "./useDeletionPopoverState"; import * as API from "api/api"; test("delete dialog starts closed", () => { const { result } = renderHook(() => - useDeleteTemplate(MockTemplate, jest.fn()), + useDeletionPopoverState(MockTemplate, jest.fn()), ); expect(result.current.isDeleteDialogOpen).toBeFalsy(); }); @@ -13,7 +13,7 @@ test("delete dialog starts closed", () => { test("confirm template deletion", async () => { const onDeleteTemplate = jest.fn(); const { result } = renderHook(() => - useDeleteTemplate(MockTemplate, onDeleteTemplate), + useDeletionPopoverState(MockTemplate, onDeleteTemplate), ); //Open delete confirmation @@ -31,7 +31,7 @@ test("confirm template deletion", async () => { test("cancel template deletion", () => { const { result } = renderHook(() => - useDeleteTemplate(MockTemplate, jest.fn()), + useDeletionPopoverState(MockTemplate, jest.fn()), ); //Open delete confirmation diff --git a/site/src/pages/TemplatePage/deleteTemplate.ts b/site/src/pages/TemplatePage/useDeletionPopoverState.ts similarity index 92% rename from site/src/pages/TemplatePage/deleteTemplate.ts rename to site/src/pages/TemplatePage/useDeletionPopoverState.ts index e8a4f1e44b153..4354e58b11c57 100644 --- a/site/src/pages/TemplatePage/deleteTemplate.ts +++ b/site/src/pages/TemplatePage/useDeletionPopoverState.ts @@ -9,7 +9,10 @@ type DeleteTemplateState = | { status: "confirming" } | { status: "deleting" }; -export const useDeleteTemplate = (template: Template, onDelete: () => void) => { +export const useDeletionPopoverState = ( + template: Template, + onDelete: () => void, +) => { const [state, setState] = useState({ status: "idle" }); const isDeleteDialogOpen = state.status === "confirming" || state.status === "deleting"; From 1cc293519aee552b99863da473adca55ad58b792 Mon Sep 17 00:00:00 2001 From: Parkreiner Date: Mon, 9 Oct 2023 18:28:32 +0000 Subject: [PATCH 06/10] refactor: clean up variable names again --- .../pages/TemplatePage/TemplatePageHeader.tsx | 16 ++++++++-------- ...te.test.ts => useDeletionDialogState.test.ts} | 8 ++++---- ...PopoverState.ts => useDeletionDialogState.ts} | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) rename site/src/pages/TemplatePage/{useDeletionPopoverState.test.ts => useDeletionDialogState.test.ts} (83%) rename site/src/pages/TemplatePage/{useDeletionPopoverState.ts => useDeletionDialogState.ts} (96%) diff --git a/site/src/pages/TemplatePage/TemplatePageHeader.tsx b/site/src/pages/TemplatePage/TemplatePageHeader.tsx index abc20e5cd11c7..2d442bd1f3445 100644 --- a/site/src/pages/TemplatePage/TemplatePageHeader.tsx +++ b/site/src/pages/TemplatePage/TemplatePageHeader.tsx @@ -1,6 +1,6 @@ import { type FC, useRef, useState } from "react"; import { Link as RouterLink, useNavigate } from "react-router-dom"; -import { useDeletionPopoverState } from "./useDeletionPopoverState"; +import { useDeletionDialogState } from "./useDeletionDialogState"; import { useQuery } from "react-query"; import { workspacesByQuery } from "api/queries/workspaces"; @@ -123,7 +123,7 @@ export const TemplatePageHeader: FC = ({ onDeleteTemplate, }) => { const navigate = useNavigate(); - const popoverState = useDeletionPopoverState(template, onDeleteTemplate); + const dialogState = useDeletionDialogState(template, onDeleteTemplate); const queryText = `template:${template.name}`; const workspaceCountQuery = useQuery({ @@ -153,7 +153,7 @@ export const TemplatePageHeader: FC = ({ )} @@ -184,9 +184,9 @@ export const TemplatePageHeader: FC = ({ {safeToDeleteTemplate ? ( @@ -195,8 +195,8 @@ export const TemplatePageHeader: FC = ({ type="info" title="Unable to delete" hideCancel={false} - open={popoverState.isDeleteDialogOpen} - onClose={popoverState.cancelDeleteConfirmation} + open={dialogState.isDeleteDialogOpen} + onClose={dialogState.cancelDeleteConfirmation} confirmText="See workspaces" confirmLoading={workspaceCountQuery.status !== "success"} onConfirm={() => { diff --git a/site/src/pages/TemplatePage/useDeletionPopoverState.test.ts b/site/src/pages/TemplatePage/useDeletionDialogState.test.ts similarity index 83% rename from site/src/pages/TemplatePage/useDeletionPopoverState.test.ts rename to site/src/pages/TemplatePage/useDeletionDialogState.test.ts index 20240f85901f9..c0214dd5a8a23 100644 --- a/site/src/pages/TemplatePage/useDeletionPopoverState.test.ts +++ b/site/src/pages/TemplatePage/useDeletionDialogState.test.ts @@ -1,11 +1,11 @@ import { act, renderHook, waitFor } from "@testing-library/react"; import { MockTemplate } from "testHelpers/entities"; -import { useDeletionPopoverState } from "./useDeletionPopoverState"; +import { useDeletionDialogState } from "./useDeletionDialogState"; import * as API from "api/api"; test("delete dialog starts closed", () => { const { result } = renderHook(() => - useDeletionPopoverState(MockTemplate, jest.fn()), + useDeletionDialogState(MockTemplate, jest.fn()), ); expect(result.current.isDeleteDialogOpen).toBeFalsy(); }); @@ -13,7 +13,7 @@ test("delete dialog starts closed", () => { test("confirm template deletion", async () => { const onDeleteTemplate = jest.fn(); const { result } = renderHook(() => - useDeletionPopoverState(MockTemplate, onDeleteTemplate), + useDeletionDialogState(MockTemplate, onDeleteTemplate), ); //Open delete confirmation @@ -31,7 +31,7 @@ test("confirm template deletion", async () => { test("cancel template deletion", () => { const { result } = renderHook(() => - useDeletionPopoverState(MockTemplate, jest.fn()), + useDeletionDialogState(MockTemplate, jest.fn()), ); //Open delete confirmation diff --git a/site/src/pages/TemplatePage/useDeletionPopoverState.ts b/site/src/pages/TemplatePage/useDeletionDialogState.ts similarity index 96% rename from site/src/pages/TemplatePage/useDeletionPopoverState.ts rename to site/src/pages/TemplatePage/useDeletionDialogState.ts index 4354e58b11c57..dd4c7ebe711f1 100644 --- a/site/src/pages/TemplatePage/useDeletionPopoverState.ts +++ b/site/src/pages/TemplatePage/useDeletionDialogState.ts @@ -9,7 +9,7 @@ type DeleteTemplateState = | { status: "confirming" } | { status: "deleting" }; -export const useDeletionPopoverState = ( +export const useDeletionDialogState = ( template: Template, onDelete: () => void, ) => { From 8b6653de9b9c886e2006ac3ee000231b0414cec0 Mon Sep 17 00:00:00 2001 From: Parkreiner Date: Mon, 9 Oct 2023 18:41:52 +0000 Subject: [PATCH 07/10] refactor: remove redudant function calls --- .../pages/TemplatePage/TemplatePageHeader.tsx | 226 +++++++++--------- .../useDeletionDialogState.test.ts | 6 +- .../TemplatePage/useDeletionDialogState.ts | 7 +- 3 files changed, 122 insertions(+), 117 deletions(-) diff --git a/site/src/pages/TemplatePage/TemplatePageHeader.tsx b/site/src/pages/TemplatePage/TemplatePageHeader.tsx index 2d442bd1f3445..1add917502cc0 100644 --- a/site/src/pages/TemplatePage/TemplatePageHeader.tsx +++ b/site/src/pages/TemplatePage/TemplatePageHeader.tsx @@ -35,77 +35,142 @@ import CopyIcon from "@mui/icons-material/FileCopyOutlined"; type TemplateMenuProps = { templateName: string; templateVersion: string; + templateId: string; onDelete: () => void; }; const TemplateMenu: FC = ({ templateName, templateVersion, + templateId, onDelete, }) => { + const dialogState = useDeletionDialogState(templateId, onDelete); const menuTriggerRef = useRef(null); const [isMenuOpen, setIsMenuOpen] = useState(false); const navigate = useNavigate(); + const queryText = `template:${templateName}`; + const workspaceCountQuery = useQuery({ + ...workspacesByQuery(queryText), + select: (res) => res.count, + }); + // Returns a function that will execute the action and close the menu const onMenuItemClick = (actionFn: () => void) => () => { setIsMenuOpen(false); actionFn(); }; + const safeToDeleteTemplate = + workspaceCountQuery.status === "success" && workspaceCountQuery.data === 0; + return ( -
- setIsMenuOpen(true)} - ref={menuTriggerRef} - arial-label="More options" - > - - - - setIsMenuOpen(false)} - > - - navigate(`/templates/${templateName}/settings`), - )} + <> +
+ setIsMenuOpen(true)} + ref={menuTriggerRef} + arial-label="More options" > - - Settings - - - - navigate( - `/templates/${templateName}/versions/${templateVersion}/edit`, - ), - )} + + + + setIsMenuOpen(false)} > - - Edit files - + + navigate(`/templates/${templateName}/settings`), + )} + > + + Settings + + + + navigate( + `/templates/${templateName}/versions/${templateVersion}/edit`, + ), + )} + > + + Edit files + + + + navigate(`/templates/new?fromTemplate=${templateName}`), + )} + > + + Duplicate… + + + + + Delete… + + +
- - navigate(`/templates/new?fromTemplate=${templateName}`), - )} - > - - Duplicate… - - - - - Delete… - -
-
+ {safeToDeleteTemplate ? ( + + ) : ( + { + navigate({ + pathname: "/workspaces", + search: new URLSearchParams({ filter: queryText }).toString(), + }); + }} + description={ + <> + {workspaceCountQuery.isSuccess && ( + <> + This template is used by{" "} + + {workspaceCountQuery.data} workspace + {workspaceCountQuery.data === 1 ? "" : "s"} + + . Please delete all related workspaces before deleting this + template. + + )} + + {workspaceCountQuery.isLoading && ( + <>Loading information about workspaces used by this template. + )} + + {workspaceCountQuery.isError && ( + <>Unable to determine workspaces used by this template. + )} + + } + /> + )} + ); }; @@ -122,18 +187,7 @@ export const TemplatePageHeader: FC = ({ permissions, onDeleteTemplate, }) => { - const navigate = useNavigate(); - const dialogState = useDeletionDialogState(template, onDeleteTemplate); - - const queryText = `template:${template.name}`; - const workspaceCountQuery = useQuery({ - ...workspacesByQuery(queryText), - select: (res) => res.count, - }); - const hasIcon = template.icon && template.icon !== ""; - const safeToDeleteTemplate = - workspaceCountQuery.status === "success" && workspaceCountQuery.data === 0; return ( @@ -153,7 +207,8 @@ export const TemplatePageHeader: FC = ({ )} @@ -181,55 +236,6 @@ export const TemplatePageHeader: FC = ({ - - {safeToDeleteTemplate ? ( - - ) : ( - { - navigate({ - pathname: "/workspaces", - search: new URLSearchParams({ filter: queryText }).toString(), - }); - }} - description={ - <> - {workspaceCountQuery.isSuccess && ( - <> - This template is used by{" "} - - {workspaceCountQuery.data} workspace - {workspaceCountQuery.data === 1 ? "" : "s"} - - . Please delete all related workspaces before deleting this - template. - - )} - - {workspaceCountQuery.isLoading && ( - <>Loading information about workspaces used by this template. - )} - - {workspaceCountQuery.isError && ( - <>Unable to determine workspaces used by this template. - )} - - } - /> - )} ); }; diff --git a/site/src/pages/TemplatePage/useDeletionDialogState.test.ts b/site/src/pages/TemplatePage/useDeletionDialogState.test.ts index c0214dd5a8a23..1858520bff06f 100644 --- a/site/src/pages/TemplatePage/useDeletionDialogState.test.ts +++ b/site/src/pages/TemplatePage/useDeletionDialogState.test.ts @@ -5,7 +5,7 @@ import * as API from "api/api"; test("delete dialog starts closed", () => { const { result } = renderHook(() => - useDeletionDialogState(MockTemplate, jest.fn()), + useDeletionDialogState(MockTemplate.id, jest.fn()), ); expect(result.current.isDeleteDialogOpen).toBeFalsy(); }); @@ -13,7 +13,7 @@ test("delete dialog starts closed", () => { test("confirm template deletion", async () => { const onDeleteTemplate = jest.fn(); const { result } = renderHook(() => - useDeletionDialogState(MockTemplate, onDeleteTemplate), + useDeletionDialogState(MockTemplate.id, onDeleteTemplate), ); //Open delete confirmation @@ -31,7 +31,7 @@ test("confirm template deletion", async () => { test("cancel template deletion", () => { const { result } = renderHook(() => - useDeletionDialogState(MockTemplate, jest.fn()), + useDeletionDialogState(MockTemplate.id, jest.fn()), ); //Open delete confirmation diff --git a/site/src/pages/TemplatePage/useDeletionDialogState.ts b/site/src/pages/TemplatePage/useDeletionDialogState.ts index dd4c7ebe711f1..7b3b7bbfcac63 100644 --- a/site/src/pages/TemplatePage/useDeletionDialogState.ts +++ b/site/src/pages/TemplatePage/useDeletionDialogState.ts @@ -1,8 +1,7 @@ +import { useState } from "react"; import { deleteTemplate } from "api/api"; import { getErrorMessage } from "api/errors"; -import { Template } from "api/typesGenerated"; import { displayError } from "components/GlobalSnackbar/utils"; -import { useState } from "react"; type DeleteTemplateState = | { status: "idle" } @@ -10,7 +9,7 @@ type DeleteTemplateState = | { status: "deleting" }; export const useDeletionDialogState = ( - template: Template, + templateId: string, onDelete: () => void, ) => { const [state, setState] = useState({ status: "idle" }); @@ -28,7 +27,7 @@ export const useDeletionDialogState = ( const confirmDelete = async () => { try { setState({ status: "deleting" }); - await deleteTemplate(template.id); + await deleteTemplate(templateId); onDelete(); } catch (e) { setState({ status: "confirming" }); From 164227e3d9177c88c84b369e5484ee9c24efa0e1 Mon Sep 17 00:00:00 2001 From: Parkreiner Date: Mon, 9 Oct 2023 18:52:17 +0000 Subject: [PATCH 08/10] fix: update logic check for safe deletions --- site/src/pages/TemplatePage/TemplatePageHeader.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/site/src/pages/TemplatePage/TemplatePageHeader.tsx b/site/src/pages/TemplatePage/TemplatePageHeader.tsx index 1add917502cc0..cdb4b41e983a8 100644 --- a/site/src/pages/TemplatePage/TemplatePageHeader.tsx +++ b/site/src/pages/TemplatePage/TemplatePageHeader.tsx @@ -62,8 +62,7 @@ const TemplateMenu: FC = ({ actionFn(); }; - const safeToDeleteTemplate = - workspaceCountQuery.status === "success" && workspaceCountQuery.data === 0; + const safeToDeleteTemplate = workspaceCountQuery.data === 0; return ( <> From bf2394ed22f1512b9083ffef351a204b159ec890 Mon Sep 17 00:00:00 2001 From: Parkreiner Date: Mon, 9 Oct 2023 22:04:54 +0000 Subject: [PATCH 09/10] fix: update workspaces query logic --- site/src/api/queries/workspaces.ts | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/site/src/api/queries/workspaces.ts b/site/src/api/queries/workspaces.ts index d8d22831ceeaa..8e11409b49d62 100644 --- a/site/src/api/queries/workspaces.ts +++ b/site/src/api/queries/workspaces.ts @@ -1,14 +1,22 @@ import * as API from "api/api"; -import { type WorkspacesResponse } from "api/typesGenerated"; import { type QueryOptions } from "react-query"; +import { + type WorkspacesResponse, + type WorkspacesRequest, +} from "api/typesGenerated"; -export function workspacesByQueryKey(query: string) { - return ["workspaces", query] as const; +export function workspacesKey(config: WorkspacesRequest = {}) { + const { q, limit } = config; + return ["workspaces", { q, limit }] as const; } -export function workspacesByQuery(query: string) { +export function workspaces(config: WorkspacesRequest = {}) { + // Duplicates some of the work from workspacesKey, but that felt better than + // letting invisible properties sneak into the query logic + const { q, limit } = config; + return { - queryKey: workspacesByQueryKey(query), - queryFn: () => API.getWorkspaces({ q: query }), + queryKey: workspacesKey(config), + queryFn: () => API.getWorkspaces({ q, limit }), } as const satisfies QueryOptions; } From fd220d980654b33caec26fc35b3ad142d30ed1ef Mon Sep 17 00:00:00 2001 From: Parkreiner Date: Mon, 9 Oct 2023 22:06:20 +0000 Subject: [PATCH 10/10] fix: update call site for workspaces key --- site/src/pages/TemplatePage/TemplatePageHeader.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/src/pages/TemplatePage/TemplatePageHeader.tsx b/site/src/pages/TemplatePage/TemplatePageHeader.tsx index cdb4b41e983a8..ec2bae83bd852 100644 --- a/site/src/pages/TemplatePage/TemplatePageHeader.tsx +++ b/site/src/pages/TemplatePage/TemplatePageHeader.tsx @@ -3,7 +3,7 @@ import { Link as RouterLink, useNavigate } from "react-router-dom"; import { useDeletionDialogState } from "./useDeletionDialogState"; import { useQuery } from "react-query"; -import { workspacesByQuery } from "api/queries/workspaces"; +import { workspaces } from "api/queries/workspaces"; import { ConfirmDialog } from "components/Dialogs/ConfirmDialog/ConfirmDialog"; import { AuthorizationResponse, @@ -52,7 +52,7 @@ const TemplateMenu: FC = ({ const queryText = `template:${templateName}`; const workspaceCountQuery = useQuery({ - ...workspacesByQuery(queryText), + ...workspaces({ q: queryText }), select: (res) => res.count, });