Skip to content

Commit 4341403

Browse files
chore: simplify workspaces data fetching (#17703)
We've been using an abstraction that was not necessary to fetch workspaces data. I also took sometime to use the new useWorkspaceUpdate hook in the update workspace tooltip that was missing some important steps like confirmation.
1 parent 2695f4e commit 4341403

File tree

9 files changed

+103
-229
lines changed

9 files changed

+103
-229
lines changed

site/src/components/Badge/Badge.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const badgeVariants = cva(
1919
warning:
2020
"border border-solid border-border-warning bg-surface-orange text-content-warning shadow",
2121
destructive:
22-
"border border-solid border-border-destructive bg-surface-red text-content-highlight-red shadow",
22+
"border border-solid border-border-destructive bg-surface-red text-highlight-red shadow",
2323
},
2424
size: {
2525
xs: "text-2xs font-regular h-5 [&_svg]:hidden rounded px-1.5",

site/src/hooks/usePagination.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const usePagination = ({
99
const [searchParams, setSearchParams] = searchParamsResult;
1010
const page = searchParams.get("page") ? Number(searchParams.get("page")) : 1;
1111
const limit = DEFAULT_RECORDS_PER_PAGE;
12-
const offset = calcOffset(page, limit);
12+
const offset = page <= 0 ? 0 : (page - 1) * limit;
1313

1414
const goToPage = (page: number) => {
1515
searchParams.set("page", page.toString());
@@ -23,7 +23,3 @@ export const usePagination = ({
2323
offset,
2424
};
2525
};
26-
27-
export const calcOffset = (page: number, limit: number) => {
28-
return page <= 0 ? 0 : (page - 1) * limit;
29-
};

site/src/modules/workspaces/WorkspaceOutdatedTooltip/WorkspaceOutdatedTooltip.stories.tsx

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
import { action } from "@storybook/addon-actions";
21
import type { Meta, StoryObj } from "@storybook/react";
32
import { expect, userEvent, waitFor, within } from "@storybook/test";
4-
import { MockTemplate, MockTemplateVersion } from "testHelpers/entities";
3+
import {
4+
MockTemplate,
5+
MockTemplateVersion,
6+
MockWorkspace,
7+
} from "testHelpers/entities";
58
import { withDashboardProvider } from "testHelpers/storybook";
69
import { WorkspaceOutdatedTooltip } from "./WorkspaceOutdatedTooltip";
710

@@ -18,9 +21,11 @@ const meta: Meta<typeof WorkspaceOutdatedTooltip> = {
1821
],
1922
},
2023
args: {
21-
onUpdateVersion: action("onUpdateVersion"),
22-
templateName: MockTemplate.display_name,
23-
latestVersionId: MockTemplateVersion.id,
24+
workspace: {
25+
...MockWorkspace,
26+
template_name: MockTemplate.display_name,
27+
template_active_version_id: MockTemplateVersion.id,
28+
},
2429
},
2530
};
2631

@@ -29,14 +34,12 @@ type Story = StoryObj<typeof WorkspaceOutdatedTooltip>;
2934

3035
const Example: Story = {
3136
play: async ({ canvasElement, step }) => {
32-
const screen = within(canvasElement);
37+
const body = within(canvasElement.ownerDocument.body);
3338

3439
await step("activate hover trigger", async () => {
35-
await userEvent.hover(screen.getByRole("button"));
40+
await userEvent.hover(body.getByRole("button"));
3641
await waitFor(() =>
37-
expect(
38-
screen.getByText(MockTemplateVersion.message),
39-
).toBeInTheDocument(),
42+
expect(body.getByText(MockTemplateVersion.message)).toBeInTheDocument(),
4043
);
4144
});
4245
},

site/src/modules/workspaces/WorkspaceOutdatedTooltip/WorkspaceOutdatedTooltip.tsx

Lines changed: 65 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ import InfoIcon from "@mui/icons-material/InfoOutlined";
33
import RefreshIcon from "@mui/icons-material/Refresh";
44
import Link from "@mui/material/Link";
55
import Skeleton from "@mui/material/Skeleton";
6+
import { getErrorDetail, getErrorMessage } from "api/errors";
67
import { templateVersion } from "api/queries/templates";
8+
import type { Workspace } from "api/typesGenerated";
9+
import { displayError } from "components/GlobalSnackbar/utils";
710
import {
811
HelpTooltip,
912
HelpTooltipAction,
@@ -17,102 +20,99 @@ import { usePopover } from "components/deprecated/Popover/Popover";
1720
import { linkToTemplate, useLinks } from "modules/navigation";
1821
import type { FC } from "react";
1922
import { useQuery } from "react-query";
20-
21-
const Language = {
22-
outdatedLabel: "Outdated",
23-
versionTooltipText:
24-
"This workspace version is outdated and a newer version is available.",
25-
updateVersionLabel: "Update",
26-
};
23+
import {
24+
WorkspaceUpdateDialogs,
25+
useWorkspaceUpdate,
26+
} from "../WorkspaceUpdateDialogs";
2727

2828
interface TooltipProps {
29-
organizationName: string;
30-
templateName: string;
31-
latestVersionId: string;
32-
onUpdateVersion: () => void;
33-
ariaLabel?: string;
29+
workspace: Workspace;
3430
}
3531

3632
export const WorkspaceOutdatedTooltip: FC<TooltipProps> = (props) => {
3733
return (
3834
<HelpTooltip>
39-
<HelpTooltipTrigger
40-
size="small"
41-
aria-label="More info"
42-
hoverEffect={false}
43-
>
35+
<HelpTooltipTrigger size="small" hoverEffect={false}>
4436
<InfoIcon css={styles.icon} />
37+
<span className="sr-only">Outdated info</span>
4538
</HelpTooltipTrigger>
46-
4739
<WorkspaceOutdatedTooltipContent {...props} />
4840
</HelpTooltip>
4941
);
5042
};
5143

52-
const WorkspaceOutdatedTooltipContent: FC<TooltipProps> = ({
53-
organizationName,
54-
templateName,
55-
latestVersionId,
56-
onUpdateVersion,
57-
ariaLabel,
58-
}) => {
44+
const WorkspaceOutdatedTooltipContent: FC<TooltipProps> = ({ workspace }) => {
5945
const getLink = useLinks();
6046
const theme = useTheme();
6147
const popover = usePopover();
6248
const { data: activeVersion } = useQuery({
63-
...templateVersion(latestVersionId),
49+
...templateVersion(workspace.template_active_version_id),
6450
enabled: popover.open,
6551
});
52+
const updateWorkspace = useWorkspaceUpdate({
53+
workspace,
54+
latestVersion: activeVersion,
55+
onError: (error) => {
56+
displayError(
57+
getErrorMessage(error, "Error updating workspace"),
58+
getErrorDetail(error),
59+
);
60+
},
61+
});
6662

6763
const versionLink = `${getLink(
68-
linkToTemplate(organizationName, templateName),
64+
linkToTemplate(workspace.organization_name, workspace.template_name),
6965
)}`;
7066

7167
return (
72-
<HelpTooltipContent>
73-
<HelpTooltipTitle>{Language.outdatedLabel}</HelpTooltipTitle>
74-
<HelpTooltipText>{Language.versionTooltipText}</HelpTooltipText>
68+
<>
69+
<HelpTooltipContent disablePortal={false}>
70+
<HelpTooltipTitle>Outdated</HelpTooltipTitle>
71+
<HelpTooltipText>
72+
This workspace version is outdated and a newer version is available.
73+
</HelpTooltipText>
7574

76-
<div css={styles.container}>
77-
<div css={{ lineHeight: "1.6" }}>
78-
<div css={styles.bold}>New version</div>
79-
<div>
80-
{activeVersion ? (
81-
<Link
82-
href={`${versionLink}/versions/${activeVersion.name}`}
83-
target="_blank"
84-
css={{ color: theme.palette.primary.light }}
85-
>
86-
{activeVersion.name}
87-
</Link>
88-
) : (
89-
<Skeleton variant="text" height={20} width={100} />
90-
)}
75+
<div css={styles.container}>
76+
<div css={{ lineHeight: "1.6" }}>
77+
<div css={styles.bold}>New version</div>
78+
<div>
79+
{activeVersion ? (
80+
<Link
81+
href={`${versionLink}/versions/${activeVersion.name}`}
82+
target="_blank"
83+
css={{ color: theme.palette.primary.light }}
84+
>
85+
{activeVersion.name}
86+
</Link>
87+
) : (
88+
<Skeleton variant="text" height={20} width={100} />
89+
)}
90+
</div>
9191
</div>
92-
</div>
9392

94-
<div css={{ lineHeight: "1.6" }}>
95-
<div css={styles.bold}>Message</div>
96-
<div>
97-
{activeVersion ? (
98-
activeVersion.message || "No message"
99-
) : (
100-
<Skeleton variant="text" height={20} width={150} />
101-
)}
93+
<div css={{ lineHeight: "1.6" }}>
94+
<div css={styles.bold}>Message</div>
95+
<div>
96+
{activeVersion ? (
97+
activeVersion.message || "No message"
98+
) : (
99+
<Skeleton variant="text" height={20} width={150} />
100+
)}
101+
</div>
102102
</div>
103103
</div>
104-
</div>
105104

106-
<HelpTooltipLinksGroup>
107-
<HelpTooltipAction
108-
icon={RefreshIcon}
109-
onClick={onUpdateVersion}
110-
ariaLabel={ariaLabel}
111-
>
112-
{Language.updateVersionLabel}
113-
</HelpTooltipAction>
114-
</HelpTooltipLinksGroup>
115-
</HelpTooltipContent>
105+
<HelpTooltipLinksGroup>
106+
<HelpTooltipAction
107+
icon={RefreshIcon}
108+
onClick={updateWorkspace.update}
109+
>
110+
Update
111+
</HelpTooltipAction>
112+
</HelpTooltipLinksGroup>
113+
</HelpTooltipContent>
114+
<WorkspaceUpdateDialogs {...updateWorkspace.dialogs} />
115+
</>
116116
);
117117
};
118118

site/src/pages/TemplateSettingsPage/TemplateSchedulePage/useWorkspacesToBeDeleted.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1+
import { workspaces } from "api/queries/workspaces";
12
import type { Template, Workspace } from "api/typesGenerated";
23
import { compareAsc } from "date-fns";
3-
import { calcOffset } from "hooks/usePagination";
4-
import { useWorkspacesData } from "pages/WorkspacesPage/data";
4+
import { useQuery } from "react-query";
55
import type { TemplateScheduleFormValues } from "./formHelpers";
66

77
export const useWorkspacesToGoDormant = (
88
template: Template,
99
formValues: TemplateScheduleFormValues,
1010
fromDate: Date,
1111
) => {
12-
const { data } = useWorkspacesData({
13-
offset: calcOffset(0, 0),
14-
limit: 0,
15-
q: `template:${template.name}`,
16-
});
12+
const { data } = useQuery(
13+
workspaces({
14+
q: `template:${template.name}`,
15+
}),
16+
);
1717

1818
return data?.workspaces?.filter((workspace: Workspace) => {
1919
if (!formValues.time_til_dormant_ms) {
@@ -40,11 +40,12 @@ export const useWorkspacesToBeDeleted = (
4040
formValues: TemplateScheduleFormValues,
4141
fromDate: Date,
4242
) => {
43-
const { data } = useWorkspacesData({
44-
offset: calcOffset(0, 0),
45-
limit: 0,
46-
q: `template:${template.name} dormant:true`,
47-
});
43+
const { data } = useQuery(
44+
workspaces({
45+
q: `template:${template.name} dormant:true`,
46+
}),
47+
);
48+
4849
return data?.workspaces?.filter((workspace: Workspace) => {
4950
if (!workspace.dormant_at || !formValues.time_til_dormant_autodelete_ms) {
5051
return false;

site/src/pages/WorkspacesPage/WorkspacesPage.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { getErrorDetail, getErrorMessage } from "api/errors";
22
import { workspacePermissionsByOrganization } from "api/queries/organizations";
33
import { templates } from "api/queries/templates";
4+
import { workspaces } from "api/queries/workspaces";
45
import type { Workspace } from "api/typesGenerated";
56
import { useFilter } from "components/Filter/Filter";
67
import { useUserFilterMenu } from "components/Filter/UserFilter";
@@ -19,7 +20,6 @@ import { BatchDeleteConfirmation } from "./BatchDeleteConfirmation";
1920
import { BatchUpdateConfirmation } from "./BatchUpdateConfirmation";
2021
import { WorkspacesPageView } from "./WorkspacesPageView";
2122
import { useBatchActions } from "./batchActions";
22-
import { useWorkspaceUpdate, useWorkspacesData } from "./data";
2323
import { useStatusFilterMenu, useTemplateFilterMenu } from "./filter/menus";
2424

2525
function useSafeSearchParams() {
@@ -45,9 +45,7 @@ const WorkspacesPage: FC = () => {
4545
const pagination = usePagination({ searchParamsResult });
4646
const { permissions, user: me } = useAuthenticated();
4747
const { entitlements } = useDashboard();
48-
4948
const templatesQuery = useQuery(templates());
50-
5149
const workspacePermissionsQuery = useQuery(
5250
workspacePermissionsByOrganization(
5351
templatesQuery.data?.map((template) => template.organization_id),
@@ -73,12 +71,17 @@ const WorkspacesPage: FC = () => {
7371
onFilterChange: () => pagination.goToPage(1),
7472
});
7573

76-
const { data, error, queryKey, refetch } = useWorkspacesData({
74+
const workspacesQueryOptions = workspaces({
7775
...pagination,
7876
q: filterProps.filter.query,
7977
});
78+
const { data, error, refetch } = useQuery({
79+
...workspacesQueryOptions,
80+
refetchInterval: (_, query) => {
81+
return query.state.error ? false : 5_000;
82+
},
83+
});
8084

81-
const updateWorkspace = useWorkspaceUpdate(queryKey);
8285
const [checkedWorkspaces, setCheckedWorkspaces] = useState<
8386
readonly Workspace[]
8487
>([]);
@@ -123,17 +126,14 @@ const WorkspacesPage: FC = () => {
123126
limit={pagination.limit}
124127
onPageChange={pagination.goToPage}
125128
filterProps={filterProps}
126-
onUpdateWorkspace={(workspace) => {
127-
updateWorkspace.mutate(workspace);
128-
}}
129129
isRunningBatchAction={batchActions.isLoading}
130130
onDeleteAll={() => setConfirmingBatchAction("delete")}
131131
onUpdateAll={() => setConfirmingBatchAction("update")}
132132
onStartAll={() => batchActions.startAll(checkedWorkspaces)}
133133
onStopAll={() => batchActions.stopAll(checkedWorkspaces)}
134134
onActionSuccess={async () => {
135135
await queryClient.invalidateQueries({
136-
queryKey,
136+
queryKey: workspacesQueryOptions.queryKey,
137137
});
138138
}}
139139
onActionError={(error) => {

site/src/pages/WorkspacesPage/WorkspacesPageView.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ export interface WorkspacesPageViewProps {
5353
page: number;
5454
limit: number;
5555
onPageChange: (page: number) => void;
56-
onUpdateWorkspace: (workspace: Workspace) => void;
5756
onCheckChange: (checkedWorkspaces: readonly Workspace[]) => void;
5857
isRunningBatchAction: boolean;
5958
onDeleteAll: () => void;
@@ -76,7 +75,6 @@ export const WorkspacesPageView: FC<WorkspacesPageViewProps> = ({
7675
count,
7776
filterProps,
7877
onPageChange,
79-
onUpdateWorkspace,
8078
page,
8179
checkedWorkspaces,
8280
onCheckChange,
@@ -223,7 +221,6 @@ export const WorkspacesPageView: FC<WorkspacesPageViewProps> = ({
223221
canCreateTemplate={canCreateTemplate}
224222
workspaces={workspaces}
225223
isUsingFilter={filterProps.filter.used}
226-
onUpdateWorkspace={onUpdateWorkspace}
227224
checkedWorkspaces={checkedWorkspaces}
228225
onCheckChange={onCheckChange}
229226
canCheckWorkspaces={canCheckWorkspaces}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy