From 3bbcd1c12df7825da8df3d46713581b45b731db9 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Mon, 16 Oct 2023 18:11:07 +0000 Subject: [PATCH] refactor(site): refactor create workspace button --- .../pages/WorkspacesPage/WorkspacesButton.tsx | 351 ++++++++++-------- 1 file changed, 186 insertions(+), 165 deletions(-) diff --git a/site/src/pages/WorkspacesPage/WorkspacesButton.tsx b/site/src/pages/WorkspacesPage/WorkspacesButton.tsx index c6c238e5dff9a..dfb6e05be35b0 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesButton.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesButton.tsx @@ -1,121 +1,30 @@ -import { type PropsWithChildren, type ReactNode, useState } from "react"; -import { useTheme } from "@emotion/react"; -import { Language } from "./WorkspacesPageView"; - +import { + type PropsWithChildren, + type ReactNode, + useState, + useRef, +} from "react"; import { type Template } from "api/typesGenerated"; import { type UseQueryResult } from "react-query"; - -import { Link as RouterLink } from "react-router-dom"; +import { + Link as RouterLink, + LinkProps as RouterLinkProps, +} from "react-router-dom"; import Box from "@mui/system/Box"; import Button from "@mui/material/Button"; import Link from "@mui/material/Link"; import AddIcon from "@mui/icons-material/AddOutlined"; import OpenIcon from "@mui/icons-material/OpenInNewOutlined"; -import Typography from "@mui/material/Typography"; - import { Loader } from "components/Loader/Loader"; import { OverflowY } from "components/OverflowY/OverflowY"; import { EmptyState } from "components/EmptyState/EmptyState"; import { Avatar } from "components/Avatar/Avatar"; import { SearchBox } from "./WorkspacesSearchBox"; -import { - PopoverContainer, - PopoverLink, -} from "components/PopoverContainer/PopoverContainer"; +import Popover from "@mui/material/Popover"; const ICON_SIZE = 18; const COLUMN_GAP = 1.5; -function sortTemplatesByUsersDesc( - templates: readonly Template[], - searchTerm: string, -) { - const allWhitespace = /^\s+$/.test(searchTerm); - if (allWhitespace) { - return templates; - } - - const termMatcher = new RegExp(searchTerm.replaceAll(/[^\w]/g, "."), "i"); - return templates - .filter( - (template) => - termMatcher.test(template.display_name) || - termMatcher.test(template.name), - ) - .sort((t1, t2) => t2.active_user_count - t1.active_user_count) - .slice(0, 10); -} - -function WorkspaceResultsRow({ template }: { template: Template }) { - const theme = useTheme(); - - return ( - - - - {template.display_name || "-"} - - - - - {template.display_name || template.name || "[Unnamed]"} - - - - {/* - * There are some templates that have -1 as their user count – - * basically functioning like a null value in JS. Can safely just - * treat them as if they were 0. - */} - {template.active_user_count <= 0 - ? "No" - : template.active_user_count}{" "} - developer - {template.active_user_count === 1 ? "" : "s"} - - - - - ); -} - type TemplatesQuery = UseQueryResult; type WorkspacesButtonProps = PropsWithChildren<{ @@ -128,13 +37,14 @@ export function WorkspacesButton({ templatesFetchStatus, templates, }: WorkspacesButtonProps) { - const theme = useTheme(); - // Dataset should always be small enough that client-side filtering should be // good enough. Can swap out down the line if it becomes an issue const [searchTerm, setSearchTerm] = useState(""); const processed = sortTemplatesByUsersDesc(templates ?? [], searchTerm); + const anchorRef = useRef(null); + const [isOpen, setIsOpen] = useState(false); + let emptyState: ReactNode = undefined; if (templates?.length === 0) { emptyState = ( @@ -152,75 +62,186 @@ export function WorkspacesButton({ } return ( - } variant="contained"> - {children} - - } - > - setSearchTerm(newValue)} - placeholder="Type/select a workspace template" - label="Template select for workspace" - sx={{ flexShrink: 0, columnGap: COLUMN_GAP }} - /> - - +