From a3bd2a0c4f2875997afb76b73fcb7cf6a06db4fe Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Tue, 15 Apr 2025 14:37:09 +0000 Subject: [PATCH 1/3] refactor: update the workspace table design --- site/src/hooks/useClickableTableRow.ts | 22 +- .../pages/TemplatesPage/TemplatesPageView.tsx | 4 +- site/src/pages/WorkspacesPage/LastUsed.tsx | 7 +- .../WorkspacesPage/WorkspacesPageView.tsx | 2 +- .../pages/WorkspacesPage/WorkspacesTable.tsx | 403 ++++++++---------- 5 files changed, 194 insertions(+), 244 deletions(-) diff --git a/site/src/hooks/useClickableTableRow.ts b/site/src/hooks/useClickableTableRow.ts index 1967762aa24dc..9c30ecd7cafe8 100644 --- a/site/src/hooks/useClickableTableRow.ts +++ b/site/src/hooks/useClickableTableRow.ts @@ -13,7 +13,6 @@ * It might not make sense to test this hook until the underlying design * problems are fixed. */ -import { type CSSObject, useTheme } from "@emotion/react"; import type { TableRowProps } from "@mui/material/TableRow"; import type { MouseEventHandler } from "react"; import { @@ -21,12 +20,13 @@ import { type UseClickableResult, useClickable, } from "./useClickable"; +import { cn } from "utils/cn"; type UseClickableTableRowResult< TRole extends ClickableAriaRole = ClickableAriaRole, > = UseClickableResult & TableRowProps & { - css: CSSObject; + className: string; hover: true; onAuxClick: MouseEventHandler; }; @@ -54,23 +54,13 @@ export const useClickableTableRow = < onAuxClick: externalOnAuxClick, }: UseClickableTableRowConfig): UseClickableTableRowResult => { const clickableProps = useClickable(onClick, (role ?? "button") as TRole); - const theme = useTheme(); return { ...clickableProps, - css: { - cursor: "pointer", - - "&:focus": { - outline: `1px solid ${theme.palette.primary.main}`, - outlineOffset: -1, - }, - - "&:last-of-type": { - borderBottomLeftRadius: 8, - borderBottomRightRadius: 8, - }, - }, + className: cn([ + "cursor-pointer hover:outline focus:outline -outline-offset-1 outline-border-hover", + "first:rounded-t-md last:rounded-b-md", + ]), hover: true, onDoubleClick, onAuxClick: (event) => { diff --git a/site/src/pages/TemplatesPage/TemplatesPageView.tsx b/site/src/pages/TemplatesPage/TemplatesPageView.tsx index 3a4e5a7812f09..30b1cd5093185 100644 --- a/site/src/pages/TemplatesPage/TemplatesPageView.tsx +++ b/site/src/pages/TemplatesPage/TemplatesPageView.tsx @@ -102,7 +102,7 @@ const TemplateRow: FC = ({ ); const navigate = useNavigate(); - const { css: clickableCss, ...clickableRow } = useClickableTableRow({ + const clickableRow = useClickableTableRow({ onClick: () => navigate(templatePageLink), }); @@ -111,7 +111,7 @@ const TemplateRow: FC = ({ key={template.id} data-testid={`template-${template.id}`} {...clickableRow} - css={[clickableCss, styles.tableRow]} + css={styles.tableRow} > = ({ lastUsedAt }) => { - const theme = useTheme(); - const [circle, message] = useTime(() => { const t = dayjs(lastUsedAt); const now = dayjs(); @@ -40,7 +37,7 @@ export const LastUsed: FC = ({ lastUsedAt }) => { return ( = ({ lastUsedAt }) => { {message} ); -}; +}; \ No newline at end of file diff --git a/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx b/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx index b6a474f57b220..2c501b0670808 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx @@ -239,4 +239,4 @@ export const WorkspacesPageView: FC = ({ )} ); -}; +}; \ No newline at end of file diff --git a/site/src/pages/WorkspacesPage/WorkspacesTable.tsx b/site/src/pages/WorkspacesPage/WorkspacesTable.tsx index 5f6d32614abf1..0717b71cd0ad2 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesTable.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesTable.tsx @@ -1,15 +1,7 @@ -import { useTheme } from "@emotion/react"; import KeyboardArrowRight from "@mui/icons-material/KeyboardArrowRight"; import Star from "@mui/icons-material/Star"; import Checkbox from "@mui/material/Checkbox"; import Skeleton from "@mui/material/Skeleton"; -import Table from "@mui/material/Table"; -import TableBody from "@mui/material/TableBody"; -import TableCell from "@mui/material/TableCell"; -import TableContainer from "@mui/material/TableContainer"; -import TableHead from "@mui/material/TableHead"; -import TableRow from "@mui/material/TableRow"; -import { visuallyHidden } from "@mui/utils"; import type { Template, Workspace, @@ -21,6 +13,14 @@ import { AvatarData } from "components/Avatar/AvatarData"; import { AvatarDataSkeleton } from "components/Avatar/AvatarDataSkeleton"; import { InfoTooltip } from "components/InfoTooltip/InfoTooltip"; import { Stack } from "components/Stack/Stack"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "components/Table/Table"; import { TableLoaderSkeleton, TableRowSkeleton, @@ -36,6 +36,7 @@ import { type FC, type ReactNode, useMemo } from "react"; import { useNavigate } from "react-router-dom"; import { getDisplayWorkspaceTemplateName } from "utils/workspace"; import { WorkspacesEmpty } from "./WorkspacesEmpty"; +import { cn } from "utils/cn"; export interface WorkspacesTableProps { workspaces?: readonly Workspace[]; @@ -59,7 +60,6 @@ export const WorkspacesTable: FC = ({ templates, canCreateTemplate, }) => { - const theme = useTheme(); const dashboard = useDashboard(); const workspaceIDToAppByStatus = useMemo(() => { return ( @@ -96,213 +96,185 @@ export const WorkspacesTable: FC = ({ ); return ( - - - - - -
- {canCheckWorkspaces && ( - { - if (!workspaces) { - return; - } +
+ + + +
+ {canCheckWorkspaces && ( + { + if (!workspaces) { + return; + } - if (!checked) { - onCheckChange([]); - } else { - onCheckChange(workspaces); - } - }} - /> - )} - Name -
+ if (!checked) { + onCheckChange([]); + } else { + onCheckChange(workspaces); + } + }} + /> + )} + Name + +
+ {hasAppStatus && Activity} + Template + Last used + Status + +
+
+ + {!workspaces && } + {workspaces && workspaces.length === 0 && ( + + + - {hasAppStatus && Activity} - Template - Last used - Status - - - - {!workspaces && ( - - )} - {workspaces && workspaces.length === 0 && ( - - )} - {workspaces?.map((workspace) => { - const checked = checkedWorkspaces.some( - (w) => w.id === workspace.id, - ); - const activeOrg = dashboard.organizations.find( - (o) => o.id === workspace.organization_id, - ); + )} + {workspaces?.map((workspace) => { + const checked = checkedWorkspaces.some((w) => w.id === workspace.id); + const activeOrg = dashboard.organizations.find( + (o) => o.id === workspace.organization_id, + ); - return ( - - -
- {canCheckWorkspaces && ( - { - e.stopPropagation(); - }} - onChange={(e) => { - if (e.currentTarget.checked) { - onCheckChange([...checkedWorkspaces, workspace]); - } else { - onCheckChange( - checkedWorkspaces.filter( - (w) => w.id !== workspace.id, - ), - ); - } - }} - /> - )} - - {workspace.name} - {workspace.favorite && ( - - )} - {workspace.outdated && ( - { - onUpdateWorkspace(workspace); - }} - /> - )} - - } - subtitle={ -
- Owner: - {workspace.owner_name} -
- } - avatar={ - - } - /> -
-
- - {hasAppStatus && ( - - - - )} - - -
{getDisplayWorkspaceTemplateName(workspace)}
- - {dashboard.showOrganizations && ( -
+ +
+ {canCheckWorkspaces && ( + { + e.stopPropagation(); + }} + onChange={(e) => { + if (e.currentTarget.checked) { + onCheckChange([...checkedWorkspaces, workspace]); + } else { + onCheckChange( + checkedWorkspaces.filter( + (w) => w.id !== workspace.id, + ), + ); + } }} - > - Organization: - {activeOrg?.display_name || workspace.organization_name} -
+ /> )} -
+ + {workspace.name} + {workspace.favorite && } + {workspace.outdated && ( + { + onUpdateWorkspace(workspace); + }} + /> + )} + + } + subtitle={ +
+ Owner: + {workspace.owner_name} +
+ } + avatar={ + + } + /> +
+
+ {hasAppStatus && ( - + + )} - -
- - {workspace.latest_build.status === "running" && - !workspace.health.healthy && ( - - )} - {workspace.dormant_at && ( - + + + } + /> + + + + + + + +
+ + {workspace.latest_build.status === "running" && + !workspace.health.healthy && ( + )} -
-
+ {workspace.dormant_at && ( + + )} +
+
- -
- -
-
-
- ); - })} -
-
-
+ +
+ +
+
+ + ); + })} + + ); }; @@ -318,7 +290,6 @@ const WorkspacesRow: FC = ({ checked, }) => { const navigate = useNavigate(); - const theme = useTheme(); const workspacePageLink = `/@${workspace.owner_name}/${workspace.name}`; const openLinkInNewTab = () => window.open(workspacePageLink, "_blank"); @@ -339,20 +310,14 @@ const WorkspacesRow: FC = ({ }, }); - const bgColor = checked ? theme.palette.action.hover : undefined; - return ( {children} @@ -367,11 +332,9 @@ const TableLoader: FC = ({ canCheckWorkspaces }) => { return ( - -
- {canCheckWorkspaces && ( - - )} + +
+ {canCheckWorkspaces && }
From 62a89d85fa053e1fb16a2cae147af1b451ccca6d Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Tue, 15 Apr 2025 14:38:54 +0000 Subject: [PATCH 2/3] FMT --- site/src/hooks/useClickableTableRow.ts | 2 +- site/src/pages/WorkspacesPage/LastUsed.tsx | 2 +- site/src/pages/WorkspacesPage/WorkspacesPageView.tsx | 2 +- site/src/pages/WorkspacesPage/WorkspacesTable.tsx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/site/src/hooks/useClickableTableRow.ts b/site/src/hooks/useClickableTableRow.ts index 9c30ecd7cafe8..21e42d236e4a8 100644 --- a/site/src/hooks/useClickableTableRow.ts +++ b/site/src/hooks/useClickableTableRow.ts @@ -15,12 +15,12 @@ */ import type { TableRowProps } from "@mui/material/TableRow"; import type { MouseEventHandler } from "react"; +import { cn } from "utils/cn"; import { type ClickableAriaRole, type UseClickableResult, useClickable, } from "./useClickable"; -import { cn } from "utils/cn"; type UseClickableTableRowResult< TRole extends ClickableAriaRole = ClickableAriaRole, diff --git a/site/src/pages/WorkspacesPage/LastUsed.tsx b/site/src/pages/WorkspacesPage/LastUsed.tsx index e4a80fe51ba6f..b0ca728468c51 100644 --- a/site/src/pages/WorkspacesPage/LastUsed.tsx +++ b/site/src/pages/WorkspacesPage/LastUsed.tsx @@ -46,4 +46,4 @@ export const LastUsed: FC = ({ lastUsedAt }) => { {message} ); -}; \ No newline at end of file +}; diff --git a/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx b/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx index 2c501b0670808..b6a474f57b220 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx @@ -239,4 +239,4 @@ export const WorkspacesPageView: FC = ({ )} ); -}; \ No newline at end of file +}; diff --git a/site/src/pages/WorkspacesPage/WorkspacesTable.tsx b/site/src/pages/WorkspacesPage/WorkspacesTable.tsx index 0717b71cd0ad2..e22715fb06b03 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesTable.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesTable.tsx @@ -34,9 +34,9 @@ import { WorkspaceStatusBadge } from "modules/workspaces/WorkspaceStatusBadge/Wo import { LastUsed } from "pages/WorkspacesPage/LastUsed"; import { type FC, type ReactNode, useMemo } from "react"; import { useNavigate } from "react-router-dom"; +import { cn } from "utils/cn"; import { getDisplayWorkspaceTemplateName } from "utils/workspace"; import { WorkspacesEmpty } from "./WorkspacesEmpty"; -import { cn } from "utils/cn"; export interface WorkspacesTableProps { workspaces?: readonly Workspace[]; From 244d1cfcd5284c0cbe82b99cc1dfbbe9c3afed09 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Tue, 15 Apr 2025 16:44:20 +0000 Subject: [PATCH 3/3] Fixes --- site/src/hooks/useClickableTableRow.ts | 2 +- .../pages/WorkspacesPage/WorkspacesTable.tsx | 40 ++++++++++--------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/site/src/hooks/useClickableTableRow.ts b/site/src/hooks/useClickableTableRow.ts index 21e42d236e4a8..5f10c637b8de3 100644 --- a/site/src/hooks/useClickableTableRow.ts +++ b/site/src/hooks/useClickableTableRow.ts @@ -58,7 +58,7 @@ export const useClickableTableRow = < return { ...clickableProps, className: cn([ - "cursor-pointer hover:outline focus:outline -outline-offset-1 outline-border-hover", + "cursor-pointer hover:outline focus:outline outline-1 -outline-offset-1 outline-border-hover", "first:rounded-t-md last:rounded-b-md", ]), hover: true, diff --git a/site/src/pages/WorkspacesPage/WorkspacesTable.tsx b/site/src/pages/WorkspacesPage/WorkspacesTable.tsx index e22715fb06b03..9fe72c23910e5 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesTable.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesTable.tsx @@ -99,7 +99,7 @@ export const WorkspacesTable: FC = ({ - +
{canCheckWorkspaces && ( = ({ Name
- {hasAppStatus && Activity} - Template - Last used - Status - + {hasAppStatus && Activity} + Template + Last used + Status +
- + {!workspaces && } {workspaces && workspaces.length === 0 && ( @@ -230,8 +230,12 @@ export const WorkspacesTable: FC = ({ + Organization:{" "} + {activeOrg?.display_name || workspace.organization_name} + + ) } avatar={ = ({ canCheckWorkspaces }) => { return ( - +
{canCheckWorkspaces && }
- - + + - - + + - - + + - - + +