From e3da0a4507585e24f74bb8a25278d969d0ef528e Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Tue, 18 Jun 2024 17:30:28 +0000 Subject: [PATCH 01/14] something --- .../DeploySettingsLayout.tsx | 18 +++- .../ManagementSettingsLayout.tsx} | 32 +++++-- .../OrganizationSettingsPage.tsx | 71 ++++++++++++++ .../OrganizationSettingsPageView.tsx} | 62 +++++------- .../OrganizationSettingsPlaceholder.tsx | 2 +- .../Sidebar.tsx | 94 ++++++++++++++++--- site/src/router.tsx | 8 +- 7 files changed, 217 insertions(+), 70 deletions(-) rename site/src/pages/{OrganizationSettingsPage/OrganizationSettingsLayout.tsx => ManagementSettingsPage/ManagementSettingsLayout.tsx} (69%) create mode 100644 site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.tsx rename site/src/pages/{OrganizationSettingsPage/OrganizationSettingsPage.tsx => ManagementSettingsPage/OrganizationSettingsPageView.tsx} (75%) rename site/src/pages/{OrganizationSettingsPage => ManagementSettingsPage}/OrganizationSettingsPlaceholder.tsx (93%) rename site/src/pages/{OrganizationSettingsPage => ManagementSettingsPage}/Sidebar.tsx (61%) diff --git a/site/src/pages/DeploySettingsPage/DeploySettingsLayout.tsx b/site/src/pages/DeploySettingsPage/DeploySettingsLayout.tsx index a100d5a99abcb..30653ba0dacd7 100644 --- a/site/src/pages/DeploySettingsPage/DeploySettingsLayout.tsx +++ b/site/src/pages/DeploySettingsPage/DeploySettingsLayout.tsx @@ -8,13 +8,15 @@ import { Margins } from "components/Margins/Margins"; import { Stack } from "components/Stack/Stack"; import { useAuthenticated } from "contexts/auth/RequireAuth"; import { RequirePermission } from "contexts/auth/RequirePermission"; -import { Sidebar } from "./Sidebar"; +import { Sidebar } from "../ManagementSettingsPage/Sidebar"; +import { useDashboard } from "modules/dashboard/useDashboard"; +import { ManagementSettingsLayout } from "pages/ManagementSettingsPage/ManagementSettingsLayout"; type DeploySettingsContextValue = { deploymentValues: DeploymentConfig; }; -const DeploySettingsContext = createContext< +export const DeploySettingsContext = createContext< DeploySettingsContextValue | undefined >(undefined); @@ -29,6 +31,18 @@ export const useDeploySettings = (): DeploySettingsContextValue => { }; export const DeploySettingsLayout: FC = () => { + const { experiments } = useDashboard(); + + const multiOrgExperimentEnabled = experiments.includes("multi-organization"); + + return multiOrgExperimentEnabled ? ( + + ) : ( + + ); +}; + +const DeploySettingsLayoutInner: FC = () => { const deploymentConfigQuery = useQuery(deploymentConfig()); const { permissions } = useAuthenticated(); diff --git a/site/src/pages/OrganizationSettingsPage/OrganizationSettingsLayout.tsx b/site/src/pages/ManagementSettingsPage/ManagementSettingsLayout.tsx similarity index 69% rename from site/src/pages/OrganizationSettingsPage/OrganizationSettingsLayout.tsx rename to site/src/pages/ManagementSettingsPage/ManagementSettingsLayout.tsx index ae278b053428a..f089acf361f4f 100644 --- a/site/src/pages/OrganizationSettingsPage/OrganizationSettingsLayout.tsx +++ b/site/src/pages/ManagementSettingsPage/ManagementSettingsLayout.tsx @@ -11,9 +11,11 @@ import { RequirePermission } from "contexts/auth/RequirePermission"; import { useDashboard } from "modules/dashboard/useDashboard"; import NotFoundPage from "pages/404Page/404Page"; import { Sidebar } from "./Sidebar"; +import { deploymentConfig } from "api/queries/deployment"; +import { DeploySettingsContext } from "../DeploySettingsPage/DeploySettingsLayout"; type OrganizationSettingsContextValue = { - currentOrganizationId: string; + currentOrganizationId?: string; organizations: Organization[]; }; @@ -31,10 +33,11 @@ export const useOrganizationSettings = (): OrganizationSettingsContextValue => { return context; }; -export const OrganizationSettingsLayout: FC = () => { +export const ManagementSettingsLayout: FC = () => { const { permissions, organizationIds } = useAuthenticated(); const { experiments } = useDashboard(); const { organization } = useParams() as { organization: string }; + const deploymentConfigQuery = useQuery(deploymentConfig()); const organizationsQuery = useQuery(myOrganizations()); const multiOrgExperimentEnabled = experiments.includes("multi-organization"); @@ -50,18 +53,29 @@ export const OrganizationSettingsLayout: FC = () => { {organizationsQuery.data ? ( org.name === organization, - )?.id ?? organizationIds[0], + currentOrganizationId: !organization + ? organizationIds[0] + : organizationsQuery.data.find( + (org) => org.name === organization, + )?.id, organizations: organizationsQuery.data, }} >
- }> - - + {deploymentConfigQuery.data ? ( + + }> + + + + ) : ( + + )}
) : ( diff --git a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.tsx b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.tsx new file mode 100644 index 0000000000000..99e67c8559203 --- /dev/null +++ b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.tsx @@ -0,0 +1,71 @@ +import { type FC } from "react"; +import { useMutation, useQueryClient } from "react-query"; +import { useNavigate } from "react-router-dom"; +import { + createOrganization, + updateOrganization, + deleteOrganization, +} from "api/queries/organizations"; +import { ErrorAlert } from "components/Alert/ErrorAlert"; +import { displaySuccess } from "components/GlobalSnackbar/utils"; +import { Stack } from "components/Stack/Stack"; +import { useOrganizationSettings } from "./ManagementSettingsLayout"; +import { OrganizationSettingsPageView } from "./OrganizationSettingsPageView"; + +const OrganizationSettingsPage: FC = () => { + const navigate = useNavigate(); + + const queryClient = useQueryClient(); + const addOrganizationMutation = useMutation(createOrganization(queryClient)); + const updateOrganizationMutation = useMutation( + updateOrganization(queryClient), + ); + const deleteOrganizationMutation = useMutation( + deleteOrganization(queryClient), + ); + + const { currentOrganizationId, organizations } = useOrganizationSettings(); + + const org = organizations.find((org) => org.id === currentOrganizationId); + + const error = + updateOrganizationMutation.error ?? + addOrganizationMutation.error ?? + deleteOrganizationMutation.error; + + if (!currentOrganizationId) { + return null; + } + + if (!org) { + return null; + } + + return ( + + {Boolean(error) && } + + { + await updateOrganizationMutation.mutateAsync({ + orgId: org.id, + req: values, + }); + displaySuccess("Organization settings updated."); + }} + onCreateOrg={(name) => { + addOrganizationMutation.mutate({ name }); + navigate(`/organizations/${name}`); + }} + onDeleteOrg={() => { + deleteOrganizationMutation.mutate(org.id); + navigate("/organizations"); + }} + /> + + ); +}; + +export default OrganizationSettingsPage; diff --git a/site/src/pages/OrganizationSettingsPage/OrganizationSettingsPage.tsx b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx similarity index 75% rename from site/src/pages/OrganizationSettingsPage/OrganizationSettingsPage.tsx rename to site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx index bc278b79c7e42..05a124f8afa65 100644 --- a/site/src/pages/OrganizationSettingsPage/OrganizationSettingsPage.tsx +++ b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx @@ -10,7 +10,10 @@ import { updateOrganization, deleteOrganization, } from "api/queries/organizations"; -import type { UpdateOrganizationRequest } from "api/typesGenerated"; +import type { + Organization, + UpdateOrganizationRequest, +} from "api/typesGenerated"; import { ErrorAlert } from "components/Alert/ErrorAlert"; import { FormFields, @@ -29,12 +32,12 @@ import { displayNameValidator, onChangeTrimmed, } from "utils/formUtils"; -import { useOrganizationSettings } from "./OrganizationSettingsLayout"; +import { useOrganizationSettings } from "./ManagementSettingsLayout"; const MAX_DESCRIPTION_CHAR_LIMIT = 128; const MAX_DESCRIPTION_MESSAGE = `Please enter a description that is no longer than ${MAX_DESCRIPTION_CHAR_LIMIT} characters.`; -export const validationSchema = Yup.object({ +const validationSchema = Yup.object({ name: nameValidator("Name"), display_name: displayNameValidator("Display name"), description: Yup.string().max( @@ -43,25 +46,18 @@ export const validationSchema = Yup.object({ ), }); -const OrganizationSettingsPage: FC = () => { - const queryClient = useQueryClient(); - const addOrganizationMutation = useMutation(createOrganization(queryClient)); - const updateOrganizationMutation = useMutation( - updateOrganization(queryClient), - ); - const deleteOrganizationMutation = useMutation( - deleteOrganization(queryClient), - ); - - const { currentOrganizationId, organizations } = useOrganizationSettings(); +interface OrganizationSettingsPageViewProps { + org: Organization; + error: unknown; + onSubmit: (values: UpdateOrganizationRequest) => Promise; - const org = organizations.find((org) => org.id === currentOrganizationId)!; - - const error = - updateOrganizationMutation.error ?? - addOrganizationMutation.error ?? - deleteOrganizationMutation.error; + onCreateOrg: (name: string) => void; + onDeleteOrg: () => void; +} +export const OrganizationSettingsPageView: FC< + OrganizationSettingsPageViewProps +> = ({ org, error, onSubmit, onCreateOrg, onDeleteOrg }) => { const form = useFormik({ initialValues: { name: org.name, @@ -70,13 +66,7 @@ const OrganizationSettingsPage: FC = () => { icon: org.icon, }, validationSchema, - onSubmit: async (values) => { - await updateOrganizationMutation.mutateAsync({ - orgId: org.id, - req: values, - }); - displaySuccess("Organization settings updated."); - }, + onSubmit, enableReinitialize: true, }); const getFieldHelpers = getFormHelpers(form, error); @@ -84,10 +74,8 @@ const OrganizationSettingsPage: FC = () => { const [newOrgName, setNewOrgName] = useState(""); return ( - - {Boolean(error) && } - - +
+ Organization settings @@ -139,9 +127,7 @@ const OrganizationSettingsPage: FC = () => { @@ -152,18 +138,14 @@ const OrganizationSettingsPage: FC = () => { label="New organization name" onChange={(event) => setNewOrgName(event.target.value)} /> - - +
); }; -export default OrganizationSettingsPage; - const styles = { dangerButton: (theme) => ({ "&.MuiButton-contained": { diff --git a/site/src/pages/OrganizationSettingsPage/OrganizationSettingsPlaceholder.tsx b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPlaceholder.tsx similarity index 93% rename from site/src/pages/OrganizationSettingsPage/OrganizationSettingsPlaceholder.tsx rename to site/src/pages/ManagementSettingsPage/OrganizationSettingsPlaceholder.tsx index d0b3d95bc894c..a1526ed53c102 100644 --- a/site/src/pages/OrganizationSettingsPage/OrganizationSettingsPlaceholder.tsx +++ b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPlaceholder.tsx @@ -6,7 +6,7 @@ import { } from "api/queries/organizations"; import { ErrorAlert } from "components/Alert/ErrorAlert"; import { Margins } from "components/Margins/Margins"; -import { useOrganizationSettings } from "./OrganizationSettingsLayout"; +import { useOrganizationSettings } from "./ManagementSettingsLayout"; const OrganizationSettingsPage: FC = () => { const queryClient = useQueryClient(); diff --git a/site/src/pages/OrganizationSettingsPage/Sidebar.tsx b/site/src/pages/ManagementSettingsPage/Sidebar.tsx similarity index 61% rename from site/src/pages/OrganizationSettingsPage/Sidebar.tsx rename to site/src/pages/ManagementSettingsPage/Sidebar.tsx index 20b45d44de344..b119202643143 100644 --- a/site/src/pages/OrganizationSettingsPage/Sidebar.tsx +++ b/site/src/pages/ManagementSettingsPage/Sidebar.tsx @@ -1,12 +1,14 @@ import { cx } from "@emotion/css"; import type { FC, ReactNode } from "react"; -import { Link, NavLink } from "react-router-dom"; +import { Link, NavLink, useLocation } from "react-router-dom"; import type { Organization } from "api/typesGenerated"; import { Sidebar as BaseSidebar } from "components/Sidebar/Sidebar"; import { Stack } from "components/Stack/Stack"; import { UserAvatar } from "components/UserAvatar/UserAvatar"; import { type ClassName, useClassName } from "hooks/useClassName"; -import { useOrganizationSettings } from "./OrganizationSettingsLayout"; +import { useOrganizationSettings } from "./ManagementSettingsLayout"; +import SettingsIcon from "@mui/icons-material/Settings"; +import AddIcon from "@mui/icons-material/Add"; export const Sidebar: FC = () => { const { currentOrganizationId, organizations } = useOrganizationSettings(); @@ -15,6 +17,21 @@ export const Sidebar: FC = () => { return ( + +
+ Organizations +
+ }> + New organization + {organizations.map((organization) => ( { ); }; -interface BloobProps { - organization: Organization; - active: boolean; -} +interface DeploymentSettingsNavigationProps {} + +const DeploymentSettingsNavigation: FC< + DeploymentSettingsNavigationProps +> = ({}) => { + const location = useLocation(); + const active = location.pathname.startsWith("/deployment"); + + return ( +
+ } + > + Deployment + + {active && ( + + General + Licenses + Appearance + + User Authentication + + + External Authentication + + {/* Not exposing this yet since token exchange is not finished yet. + Network + + Workspace Proxies + + Security + + Observability + + Users + Groups + + )} +
+ ); +}; function urlForSubpage(organizationName: string, subpage: string = ""): string { return `/organizations/${organizationName}/${subpage}`; } -export const OrganizationSettingsNavigation: FC = ({ - organization, - active, -}) => { +interface OrganizationSettingsNavigationProps { + organization: Organization; + active: boolean; +} + +export const OrganizationSettingsNavigation: FC< + OrganizationSettingsNavigationProps +> = ({ organization, active }) => { return ( <> = ({ }; interface SidebarNavItemProps { - active?: boolean; + active?: boolean | "auto"; children?: ReactNode; - icon: ReactNode; + icon?: ReactNode; href: string; } @@ -101,13 +165,15 @@ export const SidebarNavItem: FC = ({ const link = useClassName(classNames.link, []); const activeLink = useClassName(classNames.activeLink, []); + const LinkC = active === "auto" ? NavLink : Link; + return ( - + {icon} {children} - + ); }; diff --git a/site/src/router.tsx b/site/src/router.tsx index e2685c29f69c8..37bb258c8199f 100644 --- a/site/src/router.tsx +++ b/site/src/router.tsx @@ -13,7 +13,7 @@ import AuditPage from "./pages/AuditPage/AuditPage"; import { DeploySettingsLayout } from "./pages/DeploySettingsPage/DeploySettingsLayout"; import { HealthLayout } from "./pages/HealthPage/HealthLayout"; import LoginPage from "./pages/LoginPage/LoginPage"; -import { OrganizationSettingsLayout } from "./pages/OrganizationSettingsPage/OrganizationSettingsLayout"; +import { ManagementSettingsLayout } from "./pages/ManagementSettingsPage/ManagementSettingsLayout"; import { SetupPage } from "./pages/SetupPage/SetupPage"; import { TemplateLayout } from "./pages/TemplatePage/TemplateLayout"; import { TemplateSettingsLayout } from "./pages/TemplateSettingsPage/TemplateSettingsLayout"; @@ -222,11 +222,11 @@ const AddNewLicensePage = lazy( import("./pages/DeploySettingsPage/LicensesSettingsPage/AddNewLicensePage"), ); const OrganizationSettingsPage = lazy( - () => import("./pages/OrganizationSettingsPage/OrganizationSettingsPage"), + () => import("./pages/ManagementSettingsPage/OrganizationSettingsPage"), ); const OrganizationSettingsPlaceholder = lazy( () => - import("./pages/OrganizationSettingsPage/OrganizationSettingsPlaceholder"), + import("./pages/ManagementSettingsPage/OrganizationSettingsPlaceholder"), ); const TemplateEmbedPage = lazy( () => import("./pages/TemplatePage/TemplateEmbedPage/TemplateEmbedPage"), @@ -335,7 +335,7 @@ export const router = createBrowserRouter( } + element={} > } /> Date: Tue, 18 Jun 2024 20:11:17 +0000 Subject: [PATCH 02/14] yes --- .../CreateOrganizationPage.tsx | 41 +++++ .../CreateOrganizationPageView.tsx | 147 ++++++++++++++++++ .../ManagementSettingsLayout.tsx | 21 ++- .../OrganizationSettingsPageView.tsx | 2 +- .../pages/ManagementSettingsPage/Sidebar.tsx | 33 +++- site/src/router.tsx | 55 ++++--- 6 files changed, 260 insertions(+), 39 deletions(-) create mode 100644 site/src/pages/ManagementSettingsPage/CreateOrganizationPage.tsx create mode 100644 site/src/pages/ManagementSettingsPage/CreateOrganizationPageView.tsx diff --git a/site/src/pages/ManagementSettingsPage/CreateOrganizationPage.tsx b/site/src/pages/ManagementSettingsPage/CreateOrganizationPage.tsx new file mode 100644 index 0000000000000..f500305718f7a --- /dev/null +++ b/site/src/pages/ManagementSettingsPage/CreateOrganizationPage.tsx @@ -0,0 +1,41 @@ +import { type FC } from "react"; +import { useMutation, useQueryClient } from "react-query"; +import { useNavigate } from "react-router-dom"; +import { + createOrganization, + updateOrganization, + deleteOrganization, +} from "api/queries/organizations"; +import { ErrorAlert } from "components/Alert/ErrorAlert"; +import { displaySuccess } from "components/GlobalSnackbar/utils"; +import { Stack } from "components/Stack/Stack"; +import { useOrganizationSettings } from "./ManagementSettingsLayout"; +import { CreateOrganizationPageView } from "./CreateOrganizationPageView"; + +const CreateOrganizationPage: FC = () => { + const navigate = useNavigate(); + + const queryClient = useQueryClient(); + const createOrganizationMutation = useMutation( + createOrganization(queryClient), + ); + + const error = createOrganizationMutation.error; + + return ( + + {Boolean(error) && } + + { + await createOrganizationMutation.mutateAsync(values); + displaySuccess("Organization settings updated."); + navigate(`/organizations/${values.name}`); + }} + /> + + ); +}; + +export default CreateOrganizationPage; diff --git a/site/src/pages/ManagementSettingsPage/CreateOrganizationPageView.tsx b/site/src/pages/ManagementSettingsPage/CreateOrganizationPageView.tsx new file mode 100644 index 0000000000000..4f96fe4d727c5 --- /dev/null +++ b/site/src/pages/ManagementSettingsPage/CreateOrganizationPageView.tsx @@ -0,0 +1,147 @@ +import type { Interpolation, Theme } from "@emotion/react"; +import Button from "@mui/material/Button"; +import TextField from "@mui/material/TextField"; +import { useFormik } from "formik"; +import { type FC, useState } from "react"; +import { useMutation, useQueryClient } from "react-query"; +import * as Yup from "yup"; +import { + createOrganization, + updateOrganization, + deleteOrganization, +} from "api/queries/organizations"; +import type { + CreateOrganizationRequest, + Organization, +} from "api/typesGenerated"; +import { ErrorAlert } from "components/Alert/ErrorAlert"; +import { + FormFields, + FormSection, + HorizontalForm, + FormFooter, +} from "components/Form/Form"; +import { displaySuccess } from "components/GlobalSnackbar/utils"; +import { IconField } from "components/IconField/IconField"; +import { Margins } from "components/Margins/Margins"; +import { PageHeader, PageHeaderTitle } from "components/PageHeader/PageHeader"; +import { Stack } from "components/Stack/Stack"; +import { + getFormHelpers, + nameValidator, + displayNameValidator, + onChangeTrimmed, +} from "utils/formUtils"; +import { useOrganizationSettings } from "./ManagementSettingsLayout"; + +const MAX_DESCRIPTION_CHAR_LIMIT = 128; +const MAX_DESCRIPTION_MESSAGE = `Please enter a description that is no longer than ${MAX_DESCRIPTION_CHAR_LIMIT} characters.`; + +const validationSchema = Yup.object({ + name: nameValidator("Name"), + display_name: displayNameValidator("Display name"), + description: Yup.string().max( + MAX_DESCRIPTION_CHAR_LIMIT, + MAX_DESCRIPTION_MESSAGE, + ), +}); + +interface CreateOrganizationPageViewProps { + error: unknown; + onSubmit: (values: CreateOrganizationRequest) => Promise; +} + +export const CreateOrganizationPageView: FC< + CreateOrganizationPageViewProps +> = ({ error, onSubmit }) => { + const form = useFormik({ + initialValues: { + name: "", + display_name: "", + description: "", + icon: "", + }, + validationSchema, + onSubmit, + }); + const getFieldHelpers = getFormHelpers(form, error); + + return ( +
+ + Organization settings + + + + +
+ + + + + form.setFieldValue("icon", value)} + /> + +
+
+ +
+
+ ); +}; + +const styles = { + dangerButton: (theme) => ({ + "&.MuiButton-contained": { + backgroundColor: theme.roles.danger.fill.solid, + borderColor: theme.roles.danger.fill.outline, + + "&:not(.MuiLoadingButton-loading)": { + color: theme.roles.danger.fill.text, + }, + + "&:hover:not(:disabled)": { + backgroundColor: theme.roles.danger.hover.fill.solid, + borderColor: theme.roles.danger.hover.fill.outline, + }, + + "&.Mui-disabled": { + backgroundColor: theme.roles.danger.disabled.background, + borderColor: theme.roles.danger.disabled.outline, + + "&:not(.MuiLoadingButton-loading)": { + color: theme.roles.danger.disabled.fill.text, + }, + }, + }, + }), +} satisfies Record>; diff --git a/site/src/pages/ManagementSettingsPage/ManagementSettingsLayout.tsx b/site/src/pages/ManagementSettingsPage/ManagementSettingsLayout.tsx index f089acf361f4f..0a597b8425f87 100644 --- a/site/src/pages/ManagementSettingsPage/ManagementSettingsLayout.tsx +++ b/site/src/pages/ManagementSettingsPage/ManagementSettingsLayout.tsx @@ -1,6 +1,6 @@ import { createContext, type FC, Suspense, useContext } from "react"; import { useQuery } from "react-query"; -import { Outlet, useParams } from "react-router-dom"; +import { Outlet, useLocation, useParams } from "react-router-dom"; import { myOrganizations } from "api/queries/users"; import type { Organization } from "api/typesGenerated"; import { Loader } from "components/Loader/Loader"; @@ -34,6 +34,7 @@ export const useOrganizationSettings = (): OrganizationSettingsContextValue => { }; export const ManagementSettingsLayout: FC = () => { + const location = useLocation(); const { permissions, organizationIds } = useAuthenticated(); const { experiments } = useDashboard(); const { organization } = useParams() as { organization: string }; @@ -42,6 +43,12 @@ export const ManagementSettingsLayout: FC = () => { const multiOrgExperimentEnabled = experiments.includes("multi-organization"); + console.log("oh jeez", organization); + + const inOrganizationSettings = + location.pathname.startsWith("/organizations") && + location.pathname !== "/organizations/new"; + if (!multiOrgExperimentEnabled) { return ; } @@ -53,11 +60,13 @@ export const ManagementSettingsLayout: FC = () => { {organizationsQuery.data ? ( org.name === organization, - )?.id, + currentOrganizationId: !inOrganizationSettings + ? undefined + : !organization + ? organizationIds[0] + : organizationsQuery.data.find( + (org) => org.name === organization, + )?.id, organizations: organizationsQuery.data, }} > diff --git a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx index 05a124f8afa65..d3f0e988b217d 100644 --- a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx +++ b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx @@ -81,7 +81,7 @@ export const OrganizationSettingsPageView: FC< { > Organizations - }> + } + > New organization {organizations.map((organization) => ( @@ -165,15 +169,28 @@ export const SidebarNavItem: FC = ({ const link = useClassName(classNames.link, []); const activeLink = useClassName(classNames.activeLink, []); - const LinkC = active === "auto" ? NavLink : Link; + const content = ( + + {icon} + {children} + + ); + + if (active === "auto") { + return ( + cx([link, isActive && activeLink])} + > + {content} + + ); + } return ( - - - {icon} - {children} - - + + {content} + ); }; diff --git a/site/src/router.tsx b/site/src/router.tsx index 37bb258c8199f..e57176af28a84 100644 --- a/site/src/router.tsx +++ b/site/src/router.tsx @@ -221,6 +221,9 @@ const AddNewLicensePage = lazy( () => import("./pages/DeploySettingsPage/LicensesSettingsPage/AddNewLicensePage"), ); +const CreateOrganizationPage = lazy( + () => import("./pages/ManagementSettingsPage/CreateOrganizationPage"), +); const OrganizationSettingsPage = lazy( () => import("./pages/ManagementSettingsPage/OrganizationSettingsPage"), ); @@ -333,31 +336,35 @@ export const router = createBrowserRouter( } /> - } - > + }> + } /> + + {/* General settings for the default org can omit the organization name */} } /> - } - /> - } - /> - } - /> - } - /> - } - /> + + + } /> + } + /> + } + /> + } + /> + } + /> + } + /> + }> From 6443abca640f61826e47c7352228ee33c4e02f20 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Tue, 18 Jun 2024 21:59:53 +0000 Subject: [PATCH 03/14] =?UTF-8?q?=F0=9F=A7=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DeploySettingsLayout.tsx | 2 +- .../CreateOrganizationPage.tsx | 9 +--- .../CreateOrganizationPageView.tsx | 47 +------------------ .../ManagementSettingsLayout.tsx | 6 +-- .../OrganizationSettingsPage.tsx | 12 +---- .../OrganizationSettingsPageView.tsx | 28 +---------- .../pages/ManagementSettingsPage/Sidebar.tsx | 10 ++-- 7 files changed, 14 insertions(+), 100 deletions(-) diff --git a/site/src/pages/DeploySettingsPage/DeploySettingsLayout.tsx b/site/src/pages/DeploySettingsPage/DeploySettingsLayout.tsx index 30653ba0dacd7..338494237d5aa 100644 --- a/site/src/pages/DeploySettingsPage/DeploySettingsLayout.tsx +++ b/site/src/pages/DeploySettingsPage/DeploySettingsLayout.tsx @@ -8,9 +8,9 @@ import { Margins } from "components/Margins/Margins"; import { Stack } from "components/Stack/Stack"; import { useAuthenticated } from "contexts/auth/RequireAuth"; import { RequirePermission } from "contexts/auth/RequirePermission"; -import { Sidebar } from "../ManagementSettingsPage/Sidebar"; import { useDashboard } from "modules/dashboard/useDashboard"; import { ManagementSettingsLayout } from "pages/ManagementSettingsPage/ManagementSettingsLayout"; +import { Sidebar } from "../ManagementSettingsPage/Sidebar"; type DeploySettingsContextValue = { deploymentValues: DeploymentConfig; diff --git a/site/src/pages/ManagementSettingsPage/CreateOrganizationPage.tsx b/site/src/pages/ManagementSettingsPage/CreateOrganizationPage.tsx index f500305718f7a..7f27c15568607 100644 --- a/site/src/pages/ManagementSettingsPage/CreateOrganizationPage.tsx +++ b/site/src/pages/ManagementSettingsPage/CreateOrganizationPage.tsx @@ -1,15 +1,10 @@ -import { type FC } from "react"; +import type { FC } from "react"; import { useMutation, useQueryClient } from "react-query"; import { useNavigate } from "react-router-dom"; -import { - createOrganization, - updateOrganization, - deleteOrganization, -} from "api/queries/organizations"; +import { createOrganization } from "api/queries/organizations"; import { ErrorAlert } from "components/Alert/ErrorAlert"; import { displaySuccess } from "components/GlobalSnackbar/utils"; import { Stack } from "components/Stack/Stack"; -import { useOrganizationSettings } from "./ManagementSettingsLayout"; import { CreateOrganizationPageView } from "./CreateOrganizationPageView"; const CreateOrganizationPage: FC = () => { diff --git a/site/src/pages/ManagementSettingsPage/CreateOrganizationPageView.tsx b/site/src/pages/ManagementSettingsPage/CreateOrganizationPageView.tsx index 4f96fe4d727c5..f2b6a9e1b173d 100644 --- a/site/src/pages/ManagementSettingsPage/CreateOrganizationPageView.tsx +++ b/site/src/pages/ManagementSettingsPage/CreateOrganizationPageView.tsx @@ -1,38 +1,22 @@ -import type { Interpolation, Theme } from "@emotion/react"; -import Button from "@mui/material/Button"; import TextField from "@mui/material/TextField"; import { useFormik } from "formik"; -import { type FC, useState } from "react"; -import { useMutation, useQueryClient } from "react-query"; +import type { FC } from "react"; import * as Yup from "yup"; -import { - createOrganization, - updateOrganization, - deleteOrganization, -} from "api/queries/organizations"; -import type { - CreateOrganizationRequest, - Organization, -} from "api/typesGenerated"; -import { ErrorAlert } from "components/Alert/ErrorAlert"; +import type { CreateOrganizationRequest } from "api/typesGenerated"; import { FormFields, FormSection, HorizontalForm, FormFooter, } from "components/Form/Form"; -import { displaySuccess } from "components/GlobalSnackbar/utils"; import { IconField } from "components/IconField/IconField"; -import { Margins } from "components/Margins/Margins"; import { PageHeader, PageHeaderTitle } from "components/PageHeader/PageHeader"; -import { Stack } from "components/Stack/Stack"; import { getFormHelpers, nameValidator, displayNameValidator, onChangeTrimmed, } from "utils/formUtils"; -import { useOrganizationSettings } from "./ManagementSettingsLayout"; const MAX_DESCRIPTION_CHAR_LIMIT = 128; const MAX_DESCRIPTION_MESSAGE = `Please enter a description that is no longer than ${MAX_DESCRIPTION_CHAR_LIMIT} characters.`; @@ -118,30 +102,3 @@ export const CreateOrganizationPageView: FC< ); }; - -const styles = { - dangerButton: (theme) => ({ - "&.MuiButton-contained": { - backgroundColor: theme.roles.danger.fill.solid, - borderColor: theme.roles.danger.fill.outline, - - "&:not(.MuiLoadingButton-loading)": { - color: theme.roles.danger.fill.text, - }, - - "&:hover:not(:disabled)": { - backgroundColor: theme.roles.danger.hover.fill.solid, - borderColor: theme.roles.danger.hover.fill.outline, - }, - - "&.Mui-disabled": { - backgroundColor: theme.roles.danger.disabled.background, - borderColor: theme.roles.danger.disabled.outline, - - "&:not(.MuiLoadingButton-loading)": { - color: theme.roles.danger.disabled.fill.text, - }, - }, - }, - }), -} satisfies Record>; diff --git a/site/src/pages/ManagementSettingsPage/ManagementSettingsLayout.tsx b/site/src/pages/ManagementSettingsPage/ManagementSettingsLayout.tsx index 0a597b8425f87..84d16e93b7323 100644 --- a/site/src/pages/ManagementSettingsPage/ManagementSettingsLayout.tsx +++ b/site/src/pages/ManagementSettingsPage/ManagementSettingsLayout.tsx @@ -1,6 +1,7 @@ import { createContext, type FC, Suspense, useContext } from "react"; import { useQuery } from "react-query"; import { Outlet, useLocation, useParams } from "react-router-dom"; +import { deploymentConfig } from "api/queries/deployment"; import { myOrganizations } from "api/queries/users"; import type { Organization } from "api/typesGenerated"; import { Loader } from "components/Loader/Loader"; @@ -10,9 +11,8 @@ import { useAuthenticated } from "contexts/auth/RequireAuth"; import { RequirePermission } from "contexts/auth/RequirePermission"; import { useDashboard } from "modules/dashboard/useDashboard"; import NotFoundPage from "pages/404Page/404Page"; -import { Sidebar } from "./Sidebar"; -import { deploymentConfig } from "api/queries/deployment"; import { DeploySettingsContext } from "../DeploySettingsPage/DeploySettingsLayout"; +import { Sidebar } from "./Sidebar"; type OrganizationSettingsContextValue = { currentOrganizationId?: string; @@ -43,8 +43,6 @@ export const ManagementSettingsLayout: FC = () => { const multiOrgExperimentEnabled = experiments.includes("multi-organization"); - console.log("oh jeez", organization); - const inOrganizationSettings = location.pathname.startsWith("/organizations") && location.pathname !== "/organizations/new"; diff --git a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.tsx b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.tsx index 99e67c8559203..c5385e74eb5dd 100644 --- a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.tsx +++ b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.tsx @@ -1,8 +1,7 @@ -import { type FC } from "react"; +import type { FC } from "react"; import { useMutation, useQueryClient } from "react-query"; import { useNavigate } from "react-router-dom"; import { - createOrganization, updateOrganization, deleteOrganization, } from "api/queries/organizations"; @@ -16,7 +15,6 @@ const OrganizationSettingsPage: FC = () => { const navigate = useNavigate(); const queryClient = useQueryClient(); - const addOrganizationMutation = useMutation(createOrganization(queryClient)); const updateOrganizationMutation = useMutation( updateOrganization(queryClient), ); @@ -29,9 +27,7 @@ const OrganizationSettingsPage: FC = () => { const org = organizations.find((org) => org.id === currentOrganizationId); const error = - updateOrganizationMutation.error ?? - addOrganizationMutation.error ?? - deleteOrganizationMutation.error; + updateOrganizationMutation.error ?? deleteOrganizationMutation.error; if (!currentOrganizationId) { return null; @@ -55,10 +51,6 @@ const OrganizationSettingsPage: FC = () => { }); displaySuccess("Organization settings updated."); }} - onCreateOrg={(name) => { - addOrganizationMutation.mutate({ name }); - navigate(`/organizations/${name}`); - }} onDeleteOrg={() => { deleteOrganizationMutation.mutate(org.id); navigate("/organizations"); diff --git a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx index d3f0e988b217d..25bb756e41aab 100644 --- a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx +++ b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx @@ -2,37 +2,26 @@ import type { Interpolation, Theme } from "@emotion/react"; import Button from "@mui/material/Button"; import TextField from "@mui/material/TextField"; import { useFormik } from "formik"; -import { type FC, useState } from "react"; -import { useMutation, useQueryClient } from "react-query"; +import type { FC } from "react"; import * as Yup from "yup"; -import { - createOrganization, - updateOrganization, - deleteOrganization, -} from "api/queries/organizations"; import type { Organization, UpdateOrganizationRequest, } from "api/typesGenerated"; -import { ErrorAlert } from "components/Alert/ErrorAlert"; import { FormFields, FormSection, HorizontalForm, FormFooter, } from "components/Form/Form"; -import { displaySuccess } from "components/GlobalSnackbar/utils"; import { IconField } from "components/IconField/IconField"; -import { Margins } from "components/Margins/Margins"; import { PageHeader, PageHeaderTitle } from "components/PageHeader/PageHeader"; -import { Stack } from "components/Stack/Stack"; import { getFormHelpers, nameValidator, displayNameValidator, onChangeTrimmed, } from "utils/formUtils"; -import { useOrganizationSettings } from "./ManagementSettingsLayout"; const MAX_DESCRIPTION_CHAR_LIMIT = 128; const MAX_DESCRIPTION_MESSAGE = `Please enter a description that is no longer than ${MAX_DESCRIPTION_CHAR_LIMIT} characters.`; @@ -51,13 +40,12 @@ interface OrganizationSettingsPageViewProps { error: unknown; onSubmit: (values: UpdateOrganizationRequest) => Promise; - onCreateOrg: (name: string) => void; onDeleteOrg: () => void; } export const OrganizationSettingsPageView: FC< OrganizationSettingsPageViewProps -> = ({ org, error, onSubmit, onCreateOrg, onDeleteOrg }) => { +> = ({ org, error, onSubmit, onDeleteOrg }) => { const form = useFormik({ initialValues: { name: org.name, @@ -71,8 +59,6 @@ export const OrganizationSettingsPageView: FC< }); const getFieldHelpers = getFormHelpers(form, error); - const [newOrgName, setNewOrgName] = useState(""); - return (
@@ -132,16 +118,6 @@ export const OrganizationSettingsPageView: FC< Delete this organization )} - - - setNewOrgName(event.target.value)} - /> - -
); }; diff --git a/site/src/pages/ManagementSettingsPage/Sidebar.tsx b/site/src/pages/ManagementSettingsPage/Sidebar.tsx index 26653315635d5..0d6a1cfe81b23 100644 --- a/site/src/pages/ManagementSettingsPage/Sidebar.tsx +++ b/site/src/pages/ManagementSettingsPage/Sidebar.tsx @@ -1,4 +1,6 @@ import { cx } from "@emotion/css"; +import AddIcon from "@mui/icons-material/Add"; +import SettingsIcon from "@mui/icons-material/Settings"; import type { FC, ReactNode } from "react"; import { Link, NavLink, useLocation } from "react-router-dom"; import type { Organization } from "api/typesGenerated"; @@ -7,8 +9,6 @@ import { Stack } from "components/Stack/Stack"; import { UserAvatar } from "components/UserAvatar/UserAvatar"; import { type ClassName, useClassName } from "hooks/useClassName"; import { useOrganizationSettings } from "./ManagementSettingsLayout"; -import SettingsIcon from "@mui/icons-material/Settings"; -import AddIcon from "@mui/icons-material/Add"; export const Sidebar: FC = () => { const { currentOrganizationId, organizations } = useOrganizationSettings(); @@ -47,11 +47,7 @@ export const Sidebar: FC = () => { ); }; -interface DeploymentSettingsNavigationProps {} - -const DeploymentSettingsNavigation: FC< - DeploymentSettingsNavigationProps -> = ({}) => { +const DeploymentSettingsNavigation: FC = () => { const location = useLocation(); const active = location.pathname.startsWith("/deployment"); From d532a2b5d21cafa9ead145381b5c90b125317b1c Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 20 Jun 2024 17:07:34 +0000 Subject: [PATCH 04/14] yay --- .../CreateOrganizationPageView.stories.tsx | 12 +++ .../ManagementSettingsPage/Horizontal.tsx | 88 +++++++++++++++++++ .../OrganizationSettingsPageView.stories.tsx | 16 ++++ .../OrganizationSettingsPageView.tsx | 67 ++++++++++++-- site/src/testHelpers/entities.ts | 13 ++- 5 files changed, 183 insertions(+), 13 deletions(-) create mode 100644 site/src/pages/ManagementSettingsPage/CreateOrganizationPageView.stories.tsx create mode 100644 site/src/pages/ManagementSettingsPage/Horizontal.tsx create mode 100644 site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.stories.tsx diff --git a/site/src/pages/ManagementSettingsPage/CreateOrganizationPageView.stories.tsx b/site/src/pages/ManagementSettingsPage/CreateOrganizationPageView.stories.tsx new file mode 100644 index 0000000000000..fbc339da8b5fe --- /dev/null +++ b/site/src/pages/ManagementSettingsPage/CreateOrganizationPageView.stories.tsx @@ -0,0 +1,12 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { CreateOrganizationPageView } from "./CreateOrganizationPageView"; + +const meta: Meta = { + title: "pages/CreateOrganizationPageView", + component: CreateOrganizationPageView, +}; + +export default meta; +type Story = StoryObj; + +export const Example: Story = {}; diff --git a/site/src/pages/ManagementSettingsPage/Horizontal.tsx b/site/src/pages/ManagementSettingsPage/Horizontal.tsx new file mode 100644 index 0000000000000..79cd76c3ca808 --- /dev/null +++ b/site/src/pages/ManagementSettingsPage/Horizontal.tsx @@ -0,0 +1,88 @@ +import { type Interpolation, type Theme } from "@emotion/react"; +import { type FC, type HTMLAttributes, type ReactNode } from "react"; + +export const HorizontalContainer: FC> = ({ + ...attrs +}) => { + return
; +}; + +interface HorizontalSectionProps + extends Omit, "title"> { + title: ReactNode; + description: ReactNode; + children?: ReactNode; +} + +export const HorizontalSection: FC = ({ + children, + title, + description, + ...attrs +}) => { + return ( +
+
+

{title}

+
{description}
+
+ + {children} +
+ ); +}; + +const styles = { + horizontalContainer: (theme) => ({ + display: "flex", + flexDirection: "column", + gap: 80, + + [theme.breakpoints.down("md")]: { + gap: 64, + }, + }), + + formSection: (theme) => ({ + display: "flex", + flexDirection: "row", + gap: 120, + + [theme.breakpoints.down("lg")]: { + flexDirection: "column", + gap: 16, + }, + }), + + formSectionInfo: (theme) => ({ + width: "100%", + flexShrink: 0, + top: 24, + maxWidth: 312, + position: "sticky", + + [theme.breakpoints.down("md")]: { + width: "100%", + position: "initial" as const, + }, + }), + + formSectionInfoTitle: (theme) => ({ + fontSize: 20, + color: theme.palette.text.primary, + fontWeight: 400, + margin: 0, + marginBottom: 8, + display: "flex", + flexDirection: "row", + alignItems: "center", + gap: 12, + }), + + formSectionInfoDescription: (theme) => ({ + fontSize: 14, + color: theme.palette.text.secondary, + lineHeight: "160%", + margin: 0, + }), +} satisfies Record>; diff --git a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.stories.tsx b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.stories.tsx new file mode 100644 index 0000000000000..bdbd7749b3ef7 --- /dev/null +++ b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { OrganizationSettingsPageView } from "./OrganizationSettingsPageView"; +import { MockOrganization } from "testHelpers/entities"; + +const meta: Meta = { + title: "pages/OrganizationSettingsPageView", + component: OrganizationSettingsPageView, + args: { + org: MockOrganization, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Example: Story = {}; diff --git a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx index 25bb756e41aab..31e7c46dc0d70 100644 --- a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx +++ b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx @@ -2,7 +2,7 @@ import type { Interpolation, Theme } from "@emotion/react"; import Button from "@mui/material/Button"; import TextField from "@mui/material/TextField"; import { useFormik } from "formik"; -import type { FC } from "react"; +import { type FC, useState } from "react"; import * as Yup from "yup"; import type { Organization, @@ -22,6 +22,8 @@ import { displayNameValidator, onChangeTrimmed, } from "utils/formUtils"; +import { HorizontalContainer, HorizontalSection } from "./Horizontal"; +import { DeleteDialog } from "components/Dialogs/DeleteDialog/DeleteDialog"; const MAX_DESCRIPTION_CHAR_LIMIT = 128; const MAX_DESCRIPTION_MESSAGE = `Please enter a description that is no longer than ${MAX_DESCRIPTION_CHAR_LIMIT} characters.`; @@ -59,6 +61,8 @@ export const OrganizationSettingsPageView: FC< }); const getFieldHelpers = getFormHelpers(form, error); + const [isDeleting, setIsDeleting] = useState(false); + return (
@@ -70,7 +74,7 @@ export const OrganizationSettingsPageView: FC< aria-label="Organization settings form" >
{!org.is_default && ( - + + +
({ + display: "flex", + backgroundColor: theme.roles.danger.background, + alignItems: "center", + justifyContent: "space-between", + border: `1px solid ${theme.roles.danger.outline}`, + borderRadius: 8, + padding: 12, + paddingLeft: 18, + gap: 8, + lineHeight: "18px", + flexGrow: 1, + + "& .option": { + color: theme.roles.danger.fill.solid, + "&.Mui-checked": { + color: theme.roles.danger.fill.solid, + }, + }, + + "& .info": { + fontSize: 14, + fontWeight: 600, + color: theme.roles.danger.text, + }, + })} + > + Deleting an organization is irreversible. + +
+
+
)} + + setIsDeleting(false)} + entity="organization" + name={org.name} + />
); }; diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index 055093570c7ab..8928954b7931e 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -13,12 +13,17 @@ import type { TemplateVersionFiles } from "utils/templateVersion"; export const MockOrganization: TypesGen.Organization = { id: "fc0774ce-cc9e-48d4-80ae-88f7a4d4a8b0", - name: "test-organization", - display_name: "Test Organization", - description: "", - icon: "", + name: "my-organization", + display_name: "My Organization", + description: "An organization that gets used for stuff.", + icon: "/emojis/1f957.png", created_at: "", updated_at: "", + is_default: false, +}; + +export const MockDefaultOrganization: TypesGen.Organization = { + ...MockOrganization, is_default: true, }; From 73773bf266f1b4ea5112ae8f3bbb603d94eceb5a Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 20 Jun 2024 20:09:04 +0000 Subject: [PATCH 05/14] =?UTF-8?q?=F0=9F=A7=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ManagementSettingsPage/Horizontal.tsx | 4 +- .../OrganizationSettingsPage.tsx | 4 +- .../OrganizationSettingsPageView.stories.tsx | 13 ++++- .../OrganizationSettingsPageView.tsx | 56 ++++++++----------- 4 files changed, 39 insertions(+), 38 deletions(-) diff --git a/site/src/pages/ManagementSettingsPage/Horizontal.tsx b/site/src/pages/ManagementSettingsPage/Horizontal.tsx index 79cd76c3ca808..1b30933de3e37 100644 --- a/site/src/pages/ManagementSettingsPage/Horizontal.tsx +++ b/site/src/pages/ManagementSettingsPage/Horizontal.tsx @@ -1,5 +1,5 @@ -import { type Interpolation, type Theme } from "@emotion/react"; -import { type FC, type HTMLAttributes, type ReactNode } from "react"; +import type { Interpolation, Theme } from "@emotion/react"; +import type { FC, HTMLAttributes, ReactNode } from "react"; export const HorizontalContainer: FC> = ({ ...attrs diff --git a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.tsx b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.tsx index c5385e74eb5dd..2069729c8f19f 100644 --- a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.tsx +++ b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.tsx @@ -42,7 +42,7 @@ const OrganizationSettingsPage: FC = () => { {Boolean(error) && } { await updateOrganizationMutation.mutateAsync({ @@ -51,7 +51,7 @@ const OrganizationSettingsPage: FC = () => { }); displaySuccess("Organization settings updated."); }} - onDeleteOrg={() => { + onDeleteOrganization={() => { deleteOrganizationMutation.mutate(org.id); navigate("/organizations"); }} diff --git a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.stories.tsx b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.stories.tsx index bdbd7749b3ef7..37ce1185d7dba 100644 --- a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.stories.tsx +++ b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.stories.tsx @@ -1,12 +1,15 @@ import type { Meta, StoryObj } from "@storybook/react"; +import { + MockDefaultOrganization, + MockOrganization, +} from "testHelpers/entities"; import { OrganizationSettingsPageView } from "./OrganizationSettingsPageView"; -import { MockOrganization } from "testHelpers/entities"; const meta: Meta = { title: "pages/OrganizationSettingsPageView", component: OrganizationSettingsPageView, args: { - org: MockOrganization, + organization: MockOrganization, }, }; @@ -14,3 +17,9 @@ export default meta; type Story = StoryObj; export const Example: Story = {}; + +export const DefaultOrg: Story = { + args: { + organization: MockDefaultOrganization, + }, +}; diff --git a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx index 31e7c46dc0d70..47e7d6a59c6cb 100644 --- a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx +++ b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx @@ -8,6 +8,7 @@ import type { Organization, UpdateOrganizationRequest, } from "api/typesGenerated"; +import { DeleteDialog } from "components/Dialogs/DeleteDialog/DeleteDialog"; import { FormFields, FormSection, @@ -23,7 +24,6 @@ import { onChangeTrimmed, } from "utils/formUtils"; import { HorizontalContainer, HorizontalSection } from "./Horizontal"; -import { DeleteDialog } from "components/Dialogs/DeleteDialog/DeleteDialog"; const MAX_DESCRIPTION_CHAR_LIMIT = 128; const MAX_DESCRIPTION_MESSAGE = `Please enter a description that is no longer than ${MAX_DESCRIPTION_CHAR_LIMIT} characters.`; @@ -38,22 +38,21 @@ const validationSchema = Yup.object({ }); interface OrganizationSettingsPageViewProps { - org: Organization; + organization: Organization; error: unknown; onSubmit: (values: UpdateOrganizationRequest) => Promise; - - onDeleteOrg: () => void; + onDeleteOrganization: () => void; } export const OrganizationSettingsPageView: FC< OrganizationSettingsPageViewProps -> = ({ org, error, onSubmit, onDeleteOrg }) => { +> = ({ organization, error, onSubmit, onDeleteOrganization }) => { const form = useFormik({ initialValues: { - name: org.name, - display_name: org.display_name, - description: org.description, - icon: org.icon, + name: organization.name, + display_name: organization.display_name, + description: organization.description, + icon: organization.icon, }, validationSchema, onSubmit, @@ -113,7 +112,7 @@ export const OrganizationSettingsPageView: FC< - {!org.is_default && ( + {!organization.is_default && ( Deleting an organization is irreversible.
); @@ -173,27 +175,17 @@ export const OrganizationSettingsPageView: FC< const styles = { dangerButton: (theme) => ({ - "&.MuiButton-contained": { - backgroundColor: theme.roles.danger.fill.solid, - borderColor: theme.roles.danger.fill.outline, + // backgroundColor: theme.roles.danger.fill.solid, + borderColor: theme.roles.danger.outline, + color: theme.roles.danger.text, - "&:not(.MuiLoadingButton-loading)": { - color: theme.roles.danger.fill.text, - }, - - "&:hover:not(:disabled)": { - backgroundColor: theme.roles.danger.hover.fill.solid, - borderColor: theme.roles.danger.hover.fill.outline, - }, - - "&.Mui-disabled": { - backgroundColor: theme.roles.danger.disabled.background, - borderColor: theme.roles.danger.disabled.outline, + "&:not(.MuiLoadingButton-loading)": { + color: theme.roles.danger.fill.text, + }, - "&:not(.MuiLoadingButton-loading)": { - color: theme.roles.danger.disabled.fill.text, - }, - }, + "&:hover:not(:disabled)": { + backgroundColor: theme.roles.danger.hover.background, + borderColor: theme.roles.danger.hover.fill.outline, }, }), } satisfies Record>; From 32cbc68ddf44ea6dfec92dbb1daf7c4ebc380ff7 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 20 Jun 2024 20:48:53 +0000 Subject: [PATCH 06/14] =?UTF-8?q?=F0=9F=A7=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ManagementSettingsPage/Horizontal.tsx | 2 +- .../OrganizationSettingsPageView.tsx | 59 +++++++++---------- 2 files changed, 28 insertions(+), 33 deletions(-) diff --git a/site/src/pages/ManagementSettingsPage/Horizontal.tsx b/site/src/pages/ManagementSettingsPage/Horizontal.tsx index 1b30933de3e37..ff6ddba89f0eb 100644 --- a/site/src/pages/ManagementSettingsPage/Horizontal.tsx +++ b/site/src/pages/ManagementSettingsPage/Horizontal.tsx @@ -63,7 +63,7 @@ const styles = { [theme.breakpoints.down("md")]: { width: "100%", - position: "initial" as const, + position: "initial", }, }), diff --git a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx index 47e7d6a59c6cb..b32a92c92c844 100644 --- a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx +++ b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx @@ -118,41 +118,11 @@ export const OrganizationSettingsPageView: FC< title="Settings" description="Change or delete your organization." > -
({ - display: "flex", - backgroundColor: theme.roles.danger.background, - alignItems: "center", - justifyContent: "space-between", - border: `1px solid ${theme.roles.danger.outline}`, - borderRadius: 8, - padding: 12, - paddingLeft: 18, - gap: 8, - lineHeight: "18px", - flexGrow: 1, - - "& .option": { - color: theme.roles.danger.fill.solid, - "&.Mui-checked": { - color: theme.roles.danger.fill.solid, - }, - }, - - "& .info": { - fontSize: 14, - fontWeight: 600, - color: theme.roles.danger.text, - }, - })} - > +
Deleting an organization is irreversible.