From 497b527f59a3e117142c531312cc1fa1edcf8c14 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Mon, 30 Dec 2024 17:49:08 +0000 Subject: [PATCH 01/17] Refactor new workspace and templates button --- site/src/components/Button/Button.tsx | 2 +- .../pages/TemplatesPage/TemplatesPageView.tsx | 24 +++++++++---------- .../pages/WorkspacesPage/WorkspacesButton.tsx | 7 +++--- .../WorkspacesPage/WorkspacesPageView.tsx | 3 +-- 4 files changed, 17 insertions(+), 19 deletions(-) diff --git a/site/src/components/Button/Button.tsx b/site/src/components/Button/Button.tsx index 4eeada4696b5a..3d08e3f8b8e92 100644 --- a/site/src/components/Button/Button.tsx +++ b/site/src/components/Button/Button.tsx @@ -10,7 +10,7 @@ import { cn } from "utils/cn"; export const buttonVariants = cva( `inline-flex items-center justify-center gap-2 whitespace-nowrap border-solid rounded-md transition-colors - text-sm font-semibold font-medium cursor-pointer + text-sm font-semibold font-medium cursor-pointer no-underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-content-link disabled:pointer-events-none disabled:text-content-disabled [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 diff --git a/site/src/pages/TemplatesPage/TemplatesPageView.tsx b/site/src/pages/TemplatesPage/TemplatesPageView.tsx index d936abb781b90..a01a97ede0ed7 100644 --- a/site/src/pages/TemplatesPage/TemplatesPageView.tsx +++ b/site/src/pages/TemplatesPage/TemplatesPageView.tsx @@ -1,7 +1,6 @@ import type { Interpolation, Theme } from "@emotion/react"; -import AddIcon from "@mui/icons-material/AddOutlined"; import ArrowForwardOutlined from "@mui/icons-material/ArrowForwardOutlined"; -import Button from "@mui/material/Button"; +import MuiButton from "@mui/material/Button"; import Skeleton from "@mui/material/Skeleton"; import Table from "@mui/material/Table"; import TableBody from "@mui/material/TableBody"; @@ -40,7 +39,7 @@ import { import { useClickableTableRow } from "hooks/useClickableTableRow"; import { linkToTemplate, useLinks } from "modules/navigation"; import type { FC } from "react"; -import { useNavigate } from "react-router-dom"; +import { Link, useNavigate } from "react-router-dom"; import { createDayString } from "utils/createDayString"; import { docs } from "utils/docs"; import { @@ -50,6 +49,8 @@ import { import { CreateTemplateButton } from "./CreateTemplateButton"; import { EmptyTemplates } from "./EmptyTemplates"; import { TemplatesFilter } from "./TemplatesFilter"; +import { Button } from "components/Button/Button"; +import { PlusIcon } from "lucide-react"; export const Language = { developerCount: (activeCount: number): string => { @@ -154,7 +155,7 @@ const TemplateRow: FC = ({ showOrganizations, template }) => { {template.deprecated ? ( ) : ( - + )} @@ -195,14 +196,11 @@ export const TemplatesPageView: FC = ({ const navigate = useNavigate(); const createTemplateAction = showOrganizations ? ( - ) : ( diff --git a/site/src/pages/WorkspacesPage/WorkspacesButton.tsx b/site/src/pages/WorkspacesPage/WorkspacesButton.tsx index 504a8e156ce5f..973c4d9b13e05 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesButton.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesButton.tsx @@ -1,9 +1,8 @@ -import AddIcon from "@mui/icons-material/AddOutlined"; import OpenIcon from "@mui/icons-material/OpenInNewOutlined"; -import Button from "@mui/material/Button"; import Link from "@mui/material/Link"; import type { Template } from "api/typesGenerated"; import { Avatar } from "components/Avatar/Avatar"; +import { Button } from "components/Button/Button"; import { Loader } from "components/Loader/Loader"; import { MenuSearch } from "components/Menu/MenuSearch"; import { OverflowY } from "components/OverflowY/OverflowY"; @@ -13,6 +12,7 @@ import { PopoverContent, PopoverTrigger, } from "components/deprecated/Popover/Popover"; +import { ChevronDownIcon } from "lucide-react"; import { linkToTemplate, useLinks } from "modules/navigation"; import { type FC, type ReactNode, useState } from "react"; import type { UseQueryResult } from "react-query"; @@ -56,8 +56,9 @@ export const WorkspacesButton: FC = ({ return ( - Create Workspace…, seeAllTemplates: "See all templates", template: "Template", }; @@ -103,7 +102,7 @@ export const WorkspacesPageView: FC = ({ templates={templates} templatesFetchStatus={templatesFetchStatus} > - {Language.createWorkspace} + New workspace } > From c228f1042c15a436d0e2579a15c0b447216145c5 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Mon, 30 Dec 2024 18:05:08 +0000 Subject: [PATCH 02/17] Remove ghost variant and fix icon sizes to match the design --- site/src/components/Button/Button.tsx | 15 +++++---------- site/src/modules/dashboard/Navbar/MobileMenu.tsx | 12 ++++-------- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/site/src/components/Button/Button.tsx b/site/src/components/Button/Button.tsx index 3d08e3f8b8e92..c67ffa5817e2f 100644 --- a/site/src/components/Button/Button.tsx +++ b/site/src/components/Button/Button.tsx @@ -8,13 +8,12 @@ import { forwardRef } from "react"; import { cn } from "utils/cn"; export const buttonVariants = cva( - `inline-flex items-center justify-center gap-2 whitespace-nowrap + `inline-flex items-center justify-center gap-1 whitespace-nowrap border-solid rounded-md transition-colors text-sm font-semibold font-medium cursor-pointer no-underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-content-link disabled:pointer-events-none disabled:text-content-disabled - [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 - px-3 py-2`, + [&_svg]:pointer-events-none [&_svg]:shrink-0`, { variants: { variant: { @@ -26,20 +25,16 @@ export const buttonVariants = cva( "border-none bg-transparent text-content-secondary hover:text-content-primary", warning: "border border-border-error text-content-primary bg-surface-error hover:bg-transparent", - ghost: - "text-content-primary bg-transparent border-0 hover:bg-surface-secondary", }, size: { - lg: "h-10", - default: "h-9", - sm: "h-8 px-2 py-1.5 text-xs", - icon: "h-10 w-10", + lg: "h-10 px-3 py-2 [&_svg]:size-icon-lg", + sm: "h-[30px] px-2 py-1.5 text-xs font-semibold [&_svg]:size-icon-sm", }, }, defaultVariants: { variant: "default", - size: "default", + size: "lg", }, }, ); diff --git a/site/src/modules/dashboard/Navbar/MobileMenu.tsx b/site/src/modules/dashboard/Navbar/MobileMenu.tsx index e04bb7328d78c..c4983846b34ee 100644 --- a/site/src/modules/dashboard/Navbar/MobileMenu.tsx +++ b/site/src/modules/dashboard/Navbar/MobileMenu.tsx @@ -70,15 +70,11 @@ export const MobileMenu: FC = ({ Date: Fri, 3 Jan 2025 13:23:54 +0000 Subject: [PATCH 03/17] Run make fmt --- site/src/pages/TemplatesPage/TemplatesPageView.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/src/pages/TemplatesPage/TemplatesPageView.tsx b/site/src/pages/TemplatesPage/TemplatesPageView.tsx index a01a97ede0ed7..6d85aa293b16d 100644 --- a/site/src/pages/TemplatesPage/TemplatesPageView.tsx +++ b/site/src/pages/TemplatesPage/TemplatesPageView.tsx @@ -15,6 +15,7 @@ import { Avatar } from "components/Avatar/Avatar"; import { AvatarData } from "components/Avatar/AvatarData"; import { AvatarDataSkeleton } from "components/Avatar/AvatarDataSkeleton"; import { DeprecatedBadge } from "components/Badges/Badges"; +import { Button } from "components/Button/Button"; import type { useFilter } from "components/Filter/Filter"; import { HelpTooltip, @@ -37,6 +38,7 @@ import { TableRowSkeleton, } from "components/TableLoader/TableLoader"; import { useClickableTableRow } from "hooks/useClickableTableRow"; +import { PlusIcon } from "lucide-react"; import { linkToTemplate, useLinks } from "modules/navigation"; import type { FC } from "react"; import { Link, useNavigate } from "react-router-dom"; @@ -49,8 +51,6 @@ import { import { CreateTemplateButton } from "./CreateTemplateButton"; import { EmptyTemplates } from "./EmptyTemplates"; import { TemplatesFilter } from "./TemplatesFilter"; -import { Button } from "components/Button/Button"; -import { PlusIcon } from "lucide-react"; export const Language = { developerCount: (activeCount: number): string => { From 1b2017d0a38549176f8e29b35e76c1dc95035e56 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Fri, 3 Jan 2025 18:39:45 +0000 Subject: [PATCH 04/17] Refactor form buttons --- site/e2e/helpers.ts | 14 ++-- site/e2e/tests/deployment/appearance.spec.ts | 2 +- site/e2e/tests/groups/createGroup.spec.ts | 2 +- site/e2e/tests/organizationGroups.spec.ts | 4 +- site/e2e/tests/organizations.spec.ts | 4 +- .../templates/updateTemplateSchedule.spec.ts | 2 +- site/e2e/tests/updateTemplate.spec.ts | 2 +- site/src/components/Form/Form.tsx | 39 +++------- .../FormFooter/FormFooter.stories.tsx | 37 --------- site/src/components/FormFooter/FormFooter.tsx | 78 ------------------- .../FullPageForm/FullPageForm.stories.tsx | 11 ++- .../CreateTemplatePage/CreateTemplateForm.tsx | 62 ++++++++------- .../pages/CreateTokenPage/CreateTokenForm.tsx | 21 +++-- .../pages/CreateUserPage/CreateUserForm.tsx | 21 +++-- .../CreateWorkspacePage.test.tsx | 4 +- .../CreateWorkspacePageView.tsx | 29 ++++--- .../AppearanceSettingsPageView.tsx | 2 +- .../pages/DeploymentSettingsPage/Fieldset.tsx | 2 +- .../pages/GroupsPage/CreateGroupPageView.tsx | 16 +++- .../GroupsPage/SettingsGroupPageView.tsx | 15 +++- .../CreateOrganizationPageView.tsx | 10 ++- .../CreateEditRolePageView.tsx | 25 +++--- .../GroupsPage/CreateGroupPageView.tsx | 14 +++- .../GroupsPage/GroupSettingsPageView.tsx | 13 +++- .../IdpSyncPage/ExportPolicyButton.tsx | 6 +- .../OrganizationSettingsPageView.tsx | 9 ++- .../TemplateSettingsForm.tsx | 13 +++- .../TemplateSettingsPage.test.tsx | 9 +-- .../TemplateScheduleForm.tsx | 20 +++-- .../TemplateSchedulePage.test.tsx | 3 +- .../TemplateVariablesForm.tsx | 13 +++- .../TemplateVariablesPage.test.tsx | 5 +- .../UpdateBuildParametersDialog.tsx | 10 +-- .../WorkspacePage/WorkspacePage.test.tsx | 4 +- .../WorkspaceParametersForm.tsx | 21 +++-- .../WorkspaceScheduleForm.test.tsx | 8 +- .../WorkspaceScheduleForm.tsx | 28 ++++--- .../WorkspaceSchedulePage.test.tsx | 4 +- .../WorkspaceSettingsForm.tsx | 13 +++- .../WorkspaceSettingsPage.test.tsx | 4 +- 40 files changed, 310 insertions(+), 289 deletions(-) delete mode 100644 site/src/components/FormFooter/FormFooter.stories.tsx delete mode 100644 site/src/components/FormFooter/FormFooter.tsx diff --git a/site/e2e/helpers.ts b/site/e2e/helpers.ts index 38a00134800f4..144ba31f5a65d 100644 --- a/site/e2e/helpers.ts +++ b/site/e2e/helpers.ts @@ -147,7 +147,7 @@ export const createWorkspace = async ( await popup.waitForSelector("text=You are now authenticated."); } - await page.getByTestId("form-submit").click(); + await page.getByRole("button", { name: /create workspace/i }).click(); const user = currentUser(page); @@ -276,7 +276,7 @@ export const createTemplate = async ( const name = randomName(); await page.getByLabel("Name *").fill(name); - await page.getByTestId("form-submit").click(); + await page.getByRole("button", { name: /create template/i }).click(); await expectUrl(page).toHavePathName( organizationsEnabled ? `/templates/${orgName}/${name}/files` @@ -298,7 +298,7 @@ export const createGroup = async (page: Page): Promise => { const name = randomName(); await page.getByLabel("Name", { exact: true }).fill(name); - await page.getByTestId("form-submit").click(); + await page.getByRole("button", { name: /create group/i }).click(); await expectUrl(page).toHavePathName(`/groups/${name}`); return name; }; @@ -982,7 +982,7 @@ export const updateTemplateSettings = async ( await page.getByLabel(labelText, { exact: true }).fill(value); } - await page.getByTestId("form-submit").click(); + await page.getByRole("button", { name: /save settings/i }).click(); const name = templateSettingValues.name ?? templateName; await expectUrl(page).toHavePathNameEndingWith(`/${name}`); @@ -1003,7 +1003,7 @@ export const updateWorkspace = async ( await page.getByTestId("confirm-button").click(); await fillParameters(page, richParameters, buildParameters); - await page.getByTestId("form-submit").click(); + await page.getByRole("button", { name: /update parameters/i }).click(); await page.waitForSelector("*[data-testid='build-status'] >> text=Running", { state: "visible", @@ -1024,7 +1024,7 @@ export const updateWorkspaceParameters = async ( ); await fillParameters(page, richParameters, buildParameters); - await page.getByTestId("form-submit").click(); + await page.getByRole("button", { name: /submit and restart/i }).click(); await page.waitForSelector("*[data-testid='build-status'] >> text=Running", { state: "visible", @@ -1123,7 +1123,7 @@ export async function createOrganization(page: Page): Promise<{ const description = `Org description ${name}`; await page.getByLabel("Description").fill(description); await page.getByLabel("Icon", { exact: true }).fill("/emojis/1f957.png"); - await page.getByRole("button", { name: "Submit" }).click(); + await page.getByRole("button", { name: "Create organization" }).click(); await expectUrl(page).toHavePathName(`/organizations/${name}`); await expect(page.getByText("Organization created.")).toBeVisible(); diff --git a/site/e2e/tests/deployment/appearance.spec.ts b/site/e2e/tests/deployment/appearance.spec.ts index c2b129c632cb3..744cf90580b7b 100644 --- a/site/e2e/tests/deployment/appearance.spec.ts +++ b/site/e2e/tests/deployment/appearance.spec.ts @@ -20,7 +20,7 @@ test("set application name", async ({ page }) => { await form .getByLabel("Application name", { exact: true }) .fill(applicationName); - await form.getByRole("button", { name: "Submit" }).click(); + await form.getByRole("button", { name: /save settings/i }).click(); // Open a new session without cookies to see the login page const browser = await chromium.launch(); diff --git a/site/e2e/tests/groups/createGroup.spec.ts b/site/e2e/tests/groups/createGroup.spec.ts index fbfb775c5b950..cfffe94d81a05 100644 --- a/site/e2e/tests/groups/createGroup.spec.ts +++ b/site/e2e/tests/groups/createGroup.spec.ts @@ -27,7 +27,7 @@ test("create group", async ({ page, baseURL }) => { await page.getByLabel("Name", { exact: true }).fill(groupValues.name); await page.getByLabel("Display Name").fill(groupValues.displayName); await page.getByLabel("Avatar URL").fill(groupValues.avatarURL); - await page.getByRole("button", { name: "Submit" }).click(); + await page.getByRole("button", { name: "Create group" }).click(); await expect(page).toHaveTitle(`${groupValues.displayName} - Coder`); await expect(page.getByText(groupValues.displayName)).toBeVisible(); diff --git a/site/e2e/tests/organizationGroups.spec.ts b/site/e2e/tests/organizationGroups.spec.ts index 2f419dd7ee4ac..754cf0a6a2711 100644 --- a/site/e2e/tests/organizationGroups.spec.ts +++ b/site/e2e/tests/organizationGroups.spec.ts @@ -34,7 +34,7 @@ test("create group", async ({ page }) => { const displayName = `Group ${name}`; await page.getByLabel("Display Name").fill(displayName); await page.getByLabel("Avatar URL").fill("/emojis/1f60d.png"); - await page.getByRole("button", { name: "Submit" }).click(); + await page.getByRole("button", { name: "Create group" }).click(); await expectUrl(page).toHavePathName( `/organizations/${org.name}/groups/${name}`, @@ -91,7 +91,7 @@ test("change quota settings", async ({ page }) => { // Update Quota await page.getByLabel("Quota Allowance").fill("100"); - await page.getByRole("button", { name: "Submit" }).click(); + await page.getByRole("button", { name: "Create group" }).click(); // We should get sent back to the group page afterwards expectUrl(page).toHavePathName( diff --git a/site/e2e/tests/organizations.spec.ts b/site/e2e/tests/organizations.spec.ts index c7ea60e64eb14..fe6a77a4d29f4 100644 --- a/site/e2e/tests/organizations.spec.ts +++ b/site/e2e/tests/organizations.spec.ts @@ -23,7 +23,7 @@ test("create and delete organization", async ({ page }) => { await page.getByLabel("Display name").fill(`Org ${name}`); await page.getByLabel("Description").fill(`Org description ${name}`); await page.getByLabel("Icon", { exact: true }).fill("/emojis/1f957.png"); - await page.getByRole("button", { name: "Submit" }).click(); + await page.getByRole("button", { name: "Create organization" }).click(); // Expect to be redirected to the new organization await expectUrl(page).toHavePathName(`/organizations/${name}`); @@ -32,7 +32,7 @@ test("create and delete organization", async ({ page }) => { const newName = randomName(); await page.getByLabel("Slug").fill(newName); await page.getByLabel("Description").fill(`Org description ${newName}`); - await page.getByRole("button", { name: "Submit" }).click(); + await page.getByRole("button", { name: "Create organization" }).click(); // Expect to be redirected when renaming the organization await expectUrl(page).toHavePathName(`/organizations/${newName}`); diff --git a/site/e2e/tests/templates/updateTemplateSchedule.spec.ts b/site/e2e/tests/templates/updateTemplateSchedule.spec.ts index 3c4d7e2341611..1af5eacda3a72 100644 --- a/site/e2e/tests/templates/updateTemplateSchedule.spec.ts +++ b/site/e2e/tests/templates/updateTemplateSchedule.spec.ts @@ -36,7 +36,7 @@ test("update template schedule settings without override other settings", async waitUntil: "domcontentloaded", }); await page.getByLabel("Default autostop (hours)").fill("48"); - await page.getByRole("button", { name: "Submit" }).click(); + await page.getByRole("button", { name: /save settings/i }).click(); await expect(page.getByText("Template updated successfully")).toBeVisible(); const updatedTemplate = await API.getTemplate(template.id); diff --git a/site/e2e/tests/updateTemplate.spec.ts b/site/e2e/tests/updateTemplate.spec.ts index 87fc7e5a104cf..43c8fee695d87 100644 --- a/site/e2e/tests/updateTemplate.spec.ts +++ b/site/e2e/tests/updateTemplate.spec.ts @@ -67,7 +67,7 @@ test("require latest version", async ({ page }) => { await expectUrl(page).toHavePathName(`/templates/${templateName}/settings`); let checkbox = await page.waitForSelector("#require_active_version"); await checkbox.click(); - await page.getByTestId("form-submit").click(); + await page.getByRole("button", { name: /save settings/i }).click(); await page.goto(`/templates/${templateName}/settings`, { waitUntil: "domcontentloaded", diff --git a/site/src/components/Form/Form.tsx b/site/src/components/Form/Form.tsx index 7286e0df1e700..faf900fb4f344 100644 --- a/site/src/components/Form/Form.tsx +++ b/site/src/components/Form/Form.tsx @@ -10,11 +10,7 @@ import { forwardRef, useContext, } from "react"; -import { - FormFooter as BaseFormFooter, - type FormFooterProps, - type FormFooterStyles, -} from "../FormFooter/FormFooter"; +import { cn } from "utils/cn"; type FormContextValue = { direction?: "horizontal" | "vertical" }; @@ -191,29 +187,12 @@ const styles = { }, } satisfies Record>; -export const FormFooter: FC> = (props) => ( - +export const FormFooter: FC> = ({ + className, + ...props +}) => ( +