From ee5013f912340d13061d5f399766bf393fcd94c9 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 7 Mar 2025 17:06:26 +0000 Subject: [PATCH 1/4] can't disappoint the fans :) --- enterprise/coderd/groups.go | 2 - site/e2e/constants.ts | 8 ++-- site/e2e/helpers.ts | 2 +- site/e2e/setup/addUsersAndLicense.spec.ts | 6 +-- site/e2e/tests/auditLogs.spec.ts | 40 ++++++++++--------- site/e2e/tests/deployment/general.spec.ts | 2 +- site/e2e/tests/roles.spec.ts | 4 +- site/src/@types/storybook.d.ts | 2 +- site/src/api/queries/organizations.ts | 2 +- site/src/contexts/auth/AuthProvider.tsx | 2 +- .../src/modules/dashboard/DashboardLayout.tsx | 4 +- .../modules/dashboard/DashboardProvider.tsx | 2 +- .../DeploymentBanner/DeploymentBanner.tsx | 4 +- site/src/modules/dashboard/Navbar/Navbar.tsx | 2 +- .../dashboard/Navbar/ProxyMenu.stories.tsx | 2 +- ...vider.tsx => DeploymentConfigProvider.tsx} | 20 +++++----- .../management/DeploymentSettingsLayout.tsx | 8 ++-- .../DeploymentSidebarView.stories.tsx | 4 +- .../management/DeploymentSidebarView.tsx | 33 +++++++-------- .../management/OrganizationSettingsLayout.tsx | 10 ++--- .../management/OrganizationSidebarView.tsx | 4 +- .../permissions}/RequirePermission.tsx | 0 .../permissions/index.ts} | 21 +++------- .../organizations.ts} | 0 .../ExternalAuthSettingsPage.tsx | 4 +- .../LicenseSeatConsumptionChart.tsx | 2 +- .../NetworkSettingsPage.tsx | 4 +- .../NotificationsPage/NotificationsPage.tsx | 4 +- .../NotificationsPage/storybookUtils.ts | 2 +- .../ObservabilitySettingsPage.tsx | 4 +- .../ChartSection.tsx | 0 .../OverviewPage.tsx} | 4 +- .../OverviewPageView.stories.tsx} | 0 .../OverviewPageView.tsx} | 0 .../UserEngagementChart.stories.tsx | 0 .../UserEngagementChart.tsx | 0 .../SecuritySettingsPage.tsx | 4 +- .../UserAuthSettingsPage.tsx | 4 +- .../ExternalAuthPage/ExternalAuthPage.tsx | 2 +- .../CreateOrganizationPage.tsx | 2 +- .../CustomRolesPage/CreateEditRolePage.tsx | 2 +- .../CustomRolesPage/CustomRolesPage.tsx | 2 +- .../OrganizationRedirect.tsx | 18 ++++++--- .../TerminalPage/TerminalPage.stories.tsx | 2 +- .../NotificationsPage.stories.tsx | 4 +- .../NotificationsPage/NotificationsPage.tsx | 2 +- .../src/pages/UsersPage/UsersPage.stories.tsx | 2 +- site/src/pages/UsersPage/UsersPage.tsx | 6 +-- .../pages/WorkspacePage/Workspace.stories.tsx | 2 +- .../WorkspaceNotifications.stories.tsx | 2 +- .../WorkspacePage/WorkspaceReadyPage.tsx | 2 +- site/src/pages/WorkspacePage/permissions.ts | 2 +- .../pages/WorkspacesPage/WorkspacesPage.tsx | 2 +- site/src/router.tsx | 12 +++--- site/src/testHelpers/entities.ts | 16 +++----- site/src/testHelpers/handlers.ts | 2 +- site/src/testHelpers/storybook.tsx | 8 ++-- 57 files changed, 147 insertions(+), 159 deletions(-) rename site/src/modules/management/{DeploymentSettingsProvider.tsx => DeploymentConfigProvider.tsx} (60%) rename site/src/{contexts/auth => modules/permissions}/RequirePermission.tsx (100%) rename site/src/{contexts/auth/permissions.tsx => modules/permissions/index.ts} (91%) rename site/src/modules/{management/organizationPermissions.tsx => permissions/organizations.ts} (100%) rename site/src/pages/DeploymentSettingsPage/{GeneralSettingsPage => OverviewPage}/ChartSection.tsx (100%) rename site/src/pages/DeploymentSettingsPage/{GeneralSettingsPage/GeneralSettingsPage.tsx => OverviewPage/OverviewPage.tsx} (89%) rename site/src/pages/DeploymentSettingsPage/{GeneralSettingsPage/GeneralSettingsPageView.stories.tsx => OverviewPage/OverviewPageView.stories.tsx} (100%) rename site/src/pages/DeploymentSettingsPage/{GeneralSettingsPage/GeneralSettingsPageView.tsx => OverviewPage/OverviewPageView.tsx} (100%) rename site/src/pages/DeploymentSettingsPage/{GeneralSettingsPage => OverviewPage}/UserEngagementChart.stories.tsx (100%) rename site/src/pages/DeploymentSettingsPage/{GeneralSettingsPage => OverviewPage}/UserEngagementChart.tsx (100%) diff --git a/enterprise/coderd/groups.go b/enterprise/coderd/groups.go index 9771dd9800bb0..6b94adb2c5b78 100644 --- a/enterprise/coderd/groups.go +++ b/enterprise/coderd/groups.go @@ -167,8 +167,6 @@ func (api *API) patchGroup(rw http.ResponseWriter, r *http.Request) { }) return } - // TODO: It would be nice to enforce this at the schema level - // but unfortunately our org_members table does not have an ID. _, err := database.ExpectOne(api.Database.OrganizationMembers(ctx, database.OrganizationMembersParams{ OrganizationID: group.OrganizationID, UserID: uuid.MustParse(id), diff --git a/site/e2e/constants.ts b/site/e2e/constants.ts index 4d2d9099692d5..98757064c6f3f 100644 --- a/site/e2e/constants.ts +++ b/site/e2e/constants.ts @@ -20,10 +20,10 @@ export const defaultPassword = "SomeSecurePassword!"; // Credentials for users export const users = { - admin: { - username: "admin", + owner: { + username: "owner", password: defaultPassword, - email: "admin@coder.com", + email: "owner@coder.com", }, templateAdmin: { username: "template-admin", @@ -41,7 +41,7 @@ export const users = { username: "auditor", password: defaultPassword, email: "auditor@coder.com", - roles: ["Template Admin", "Auditor"], + roles: ["Auditor"], }, member: { username: "member", diff --git a/site/e2e/helpers.ts b/site/e2e/helpers.ts index 0dc2642ab4634..3a3355d18e222 100644 --- a/site/e2e/helpers.ts +++ b/site/e2e/helpers.ts @@ -67,7 +67,7 @@ export type LoginOptions = { password: string; }; -export async function login(page: Page, options: LoginOptions = users.admin) { +export async function login(page: Page, options: LoginOptions = users.owner) { const ctx = page.context(); // biome-ignore lint/suspicious/noExplicitAny: reset the current user (ctx as any)[Symbol.for("currentUser")] = undefined; diff --git a/site/e2e/setup/addUsersAndLicense.spec.ts b/site/e2e/setup/addUsersAndLicense.spec.ts index 784db4812aaa1..1e227438c2843 100644 --- a/site/e2e/setup/addUsersAndLicense.spec.ts +++ b/site/e2e/setup/addUsersAndLicense.spec.ts @@ -16,8 +16,8 @@ test("setup deployment", async ({ page }) => { } // Setup first user - await page.getByLabel(Language.emailLabel).fill(users.admin.email); - await page.getByLabel(Language.passwordLabel).fill(users.admin.password); + await page.getByLabel(Language.emailLabel).fill(users.owner.email); + await page.getByLabel(Language.passwordLabel).fill(users.owner.password); await page.getByTestId("create").click(); await expectUrl(page).toHavePathName("/workspaces"); @@ -25,7 +25,7 @@ test("setup deployment", async ({ page }) => { for (const user of Object.values(users)) { // Already created as first user - if (user.username === "admin") { + if (user.username === "owner") { continue; } diff --git a/site/e2e/tests/auditLogs.spec.ts b/site/e2e/tests/auditLogs.spec.ts index cd12f7507c1ac..8afb2e714c695 100644 --- a/site/e2e/tests/auditLogs.spec.ts +++ b/site/e2e/tests/auditLogs.spec.ts @@ -13,19 +13,17 @@ test.describe.configure({ mode: "parallel" }); test.beforeEach(async ({ page }) => { beforeCoderTest(page); - await login(page, users.auditor); }); -async function resetSearch(page: Page) { +async function resetSearch(page: Page, username: string) { const clearButton = page.getByLabel("Clear search"); if (await clearButton.isVisible()) { await clearButton.click(); } // Filter by the auditor test user to prevent race conditions - const user = currentUser(page); await expect(page.getByText("All users")).toBeVisible(); - await page.getByPlaceholder("Search...").fill(`username:${user.username}`); + await page.getByPlaceholder("Search...").fill(`username:${username}`); await expect(page.getByText("All users")).not.toBeVisible(); } @@ -33,12 +31,14 @@ test("logins are logged", async ({ page }) => { requiresLicense(); // Go to the audit history + await login(page, users.auditor); await page.goto("/audit"); + const username = users.auditor.username; const user = currentUser(page); - const loginMessage = `${user.username} logged in`; + const loginMessage = `${username} logged in`; // Make sure those things we did all actually show up - await resetSearch(page); + await resetSearch(page, username); await expect(page.getByText(loginMessage).first()).toBeVisible(); }); @@ -46,29 +46,30 @@ test("creating templates and workspaces is logged", async ({ page }) => { requiresLicense(); // Do some stuff that should show up in the audit logs + await login(page, users.templateAdmin); + const username = users.templateAdmin.username; const templateName = await createTemplate(page); const workspaceName = await createWorkspace(page, templateName); // Go to the audit history + await login(page, users.auditor); await page.goto("/audit"); - const user = currentUser(page); - // Make sure those things we did all actually show up - await resetSearch(page); + await resetSearch(page, username); await expect( - page.getByText(`${user.username} created template ${templateName}`), + page.getByText(`${username} created template ${templateName}`), ).toBeVisible(); await expect( - page.getByText(`${user.username} created workspace ${workspaceName}`), + page.getByText(`${username} created workspace ${workspaceName}`), ).toBeVisible(); await expect( - page.getByText(`${user.username} started workspace ${workspaceName}`), + page.getByText(`${username} started workspace ${workspaceName}`), ).toBeVisible(); // Make sure we can inspect the details of the log item const createdWorkspace = page.locator(".MuiTableRow-root", { - hasText: `${user.username} created workspace ${workspaceName}`, + hasText: `${username} created workspace ${workspaceName}`, }); await createdWorkspace.getByLabel("open-dropdown").click(); await expect( @@ -83,18 +84,19 @@ test("inspecting and filtering audit logs", async ({ page }) => { requiresLicense(); // Do some stuff that should show up in the audit logs + await login(page, users.templateAdmin); + const username = users.templateAdmin.username; const templateName = await createTemplate(page); const workspaceName = await createWorkspace(page, templateName); // Go to the audit history + await login(page, users.auditor); await page.goto("/audit"); - - const user = currentUser(page); - const loginMessage = `${user.username} logged in`; - const startedWorkspaceMessage = `${user.username} started workspace ${workspaceName}`; + const loginMessage = `${username} logged in`; + const startedWorkspaceMessage = `${username} started workspace ${workspaceName}`; // Filter by resource type - await resetSearch(page); + await resetSearch(page, username); await page.getByText("All resource types").click(); const workspaceBuildsOption = page.getByText("Workspace Build"); await workspaceBuildsOption.scrollIntoViewIfNeeded({ timeout: 5000 }); @@ -107,7 +109,7 @@ test("inspecting and filtering audit logs", async ({ page }) => { await expect(page.getByText("All resource types")).toBeVisible(); // Filter by action type - await resetSearch(page); + await resetSearch(page, username); await page.getByText("All actions").click(); await page.getByText("Login", { exact: true }).click(); // Logins should be visible diff --git a/site/e2e/tests/deployment/general.spec.ts b/site/e2e/tests/deployment/general.spec.ts index 260a094bcfc93..40c8342e89929 100644 --- a/site/e2e/tests/deployment/general.spec.ts +++ b/site/e2e/tests/deployment/general.spec.ts @@ -16,7 +16,7 @@ test("experiments", async ({ page }) => { const availableExperiments = await API.getAvailableExperiments(); // Verify if the site lists the same experiments - await page.goto("/deployment/general", { waitUntil: "networkidle" }); + await page.goto("/deployment/overview", { waitUntil: "domcontentloaded" }); const experimentsLocator = page.locator( "div.options-table tr.option-experiments ul.option-array", diff --git a/site/e2e/tests/roles.spec.ts b/site/e2e/tests/roles.spec.ts index 482436c9c9b2d..484e6294de7a1 100644 --- a/site/e2e/tests/roles.spec.ts +++ b/site/e2e/tests/roles.spec.ts @@ -82,8 +82,8 @@ test.describe("roles admin settings access", () => { ]); }); - test("admin can see admin settings", async ({ page }) => { - await login(page, users.admin); + test("owner can see admin settings", async ({ page }) => { + await login(page, users.owner); await page.goto("/", { waitUntil: "domcontentloaded" }); await hasAccessToAdminSettings(page, [ diff --git a/site/src/@types/storybook.d.ts b/site/src/@types/storybook.d.ts index 31a96dd5c6ab4..836728d170b9f 100644 --- a/site/src/@types/storybook.d.ts +++ b/site/src/@types/storybook.d.ts @@ -6,7 +6,7 @@ import type { SerpentOption, User, } from "api/typesGenerated"; -import type { Permissions } from "contexts/auth/permissions"; +import type { Permissions } from "modules/permissions"; import type { QueryKey } from "react-query"; declare module "@storybook/react" { diff --git a/site/src/api/queries/organizations.ts b/site/src/api/queries/organizations.ts index 374f9e7eacf4e..bca0bc6a72fff 100644 --- a/site/src/api/queries/organizations.ts +++ b/site/src/api/queries/organizations.ts @@ -9,7 +9,7 @@ import { type OrganizationPermissionName, type OrganizationPermissions, organizationPermissionChecks, -} from "modules/management/organizationPermissions"; +} from "modules/permissions/organizations"; import type { QueryClient } from "react-query"; import { meKey } from "./users"; diff --git a/site/src/contexts/auth/AuthProvider.tsx b/site/src/contexts/auth/AuthProvider.tsx index 7418691a291e5..d47a3f71459f0 100644 --- a/site/src/contexts/auth/AuthProvider.tsx +++ b/site/src/contexts/auth/AuthProvider.tsx @@ -10,6 +10,7 @@ import { import type { UpdateUserProfileRequest, User } from "api/typesGenerated"; import { displaySuccess } from "components/GlobalSnackbar/utils"; import { useEmbeddedMetadata } from "hooks/useEmbeddedMetadata"; +import { type Permissions, permissionChecks } from "modules/permissions"; import { type FC, type PropsWithChildren, @@ -18,7 +19,6 @@ import { useContext, } from "react"; import { useMutation, useQuery, useQueryClient } from "react-query"; -import { type Permissions, permissionChecks } from "./permissions"; export type AuthContextValue = { isLoading: boolean; diff --git a/site/src/modules/dashboard/DashboardLayout.tsx b/site/src/modules/dashboard/DashboardLayout.tsx index 5fd5e67a0c3d2..b4ca5a7ae98d6 100644 --- a/site/src/modules/dashboard/DashboardLayout.tsx +++ b/site/src/modules/dashboard/DashboardLayout.tsx @@ -16,8 +16,8 @@ import { useUpdateCheck } from "./useUpdateCheck"; export const DashboardLayout: FC = () => { const { permissions } = useAuthenticated(); - const updateCheck = useUpdateCheck(permissions.viewUpdateCheck); - const canViewDeployment = Boolean(permissions.viewDeploymentValues); + const updateCheck = useUpdateCheck(permissions.viewDeploymentConfig); + const canViewDeployment = Boolean(permissions.viewDeploymentConfig); return ( <> diff --git a/site/src/modules/dashboard/DashboardProvider.tsx b/site/src/modules/dashboard/DashboardProvider.tsx index bb5987d6546be..c7f7733f153a7 100644 --- a/site/src/modules/dashboard/DashboardProvider.tsx +++ b/site/src/modules/dashboard/DashboardProvider.tsx @@ -11,8 +11,8 @@ import type { import { ErrorAlert } from "components/Alert/ErrorAlert"; import { Loader } from "components/Loader/Loader"; import { useAuthenticated } from "contexts/auth/RequireAuth"; -import { canViewAnyOrganization } from "contexts/auth/permissions"; import { useEmbeddedMetadata } from "hooks/useEmbeddedMetadata"; +import { canViewAnyOrganization } from "modules/permissions"; import { type FC, type PropsWithChildren, createContext } from "react"; import { useQuery } from "react-query"; import { selectFeatureVisibility } from "./entitlements"; diff --git a/site/src/modules/dashboard/DeploymentBanner/DeploymentBanner.tsx b/site/src/modules/dashboard/DeploymentBanner/DeploymentBanner.tsx index 03d664c6f68e5..182682399250f 100644 --- a/site/src/modules/dashboard/DeploymentBanner/DeploymentBanner.tsx +++ b/site/src/modules/dashboard/DeploymentBanner/DeploymentBanner.tsx @@ -10,10 +10,10 @@ export const DeploymentBanner: FC = () => { const deploymentStatsQuery = useQuery(deploymentStats()); const healthQuery = useQuery({ ...health(), - enabled: permissions.viewDeploymentValues, + enabled: permissions.viewDeploymentConfig, }); - if (!permissions.viewDeploymentValues || !deploymentStatsQuery.data) { + if (!permissions.viewDeploymentConfig || !deploymentStatsQuery.data) { return null; } diff --git a/site/src/modules/dashboard/Navbar/Navbar.tsx b/site/src/modules/dashboard/Navbar/Navbar.tsx index 7dc96c791e7ca..0b7d64de5e290 100644 --- a/site/src/modules/dashboard/Navbar/Navbar.tsx +++ b/site/src/modules/dashboard/Navbar/Navbar.tsx @@ -1,9 +1,9 @@ import { buildInfo } from "api/queries/buildInfo"; import { useProxy } from "contexts/ProxyContext"; import { useAuthenticated } from "contexts/auth/RequireAuth"; -import { canViewDeploymentSettings } from "contexts/auth/permissions"; import { useEmbeddedMetadata } from "hooks/useEmbeddedMetadata"; import { useDashboard } from "modules/dashboard/useDashboard"; +import { canViewDeploymentSettings } from "modules/permissions"; import type { FC } from "react"; import { useQuery } from "react-query"; import { useFeatureVisibility } from "../useFeatureVisibility"; diff --git a/site/src/modules/dashboard/Navbar/ProxyMenu.stories.tsx b/site/src/modules/dashboard/Navbar/ProxyMenu.stories.tsx index 8e8cf7fcb8951..95a5e441f561f 100644 --- a/site/src/modules/dashboard/Navbar/ProxyMenu.stories.tsx +++ b/site/src/modules/dashboard/Navbar/ProxyMenu.stories.tsx @@ -3,7 +3,7 @@ import { fn, userEvent, within } from "@storybook/test"; import { getAuthorizationKey } from "api/queries/authCheck"; import { getPreferredProxy } from "contexts/ProxyContext"; import { AuthProvider } from "contexts/auth/AuthProvider"; -import { permissionChecks } from "contexts/auth/permissions"; +import { permissionChecks } from "modules/permissions"; import { MockAuthMethodsAll, MockPermissions, diff --git a/site/src/modules/management/DeploymentSettingsProvider.tsx b/site/src/modules/management/DeploymentConfigProvider.tsx similarity index 60% rename from site/src/modules/management/DeploymentSettingsProvider.tsx rename to site/src/modules/management/DeploymentConfigProvider.tsx index 766d75aacd216..a6de49974d86e 100644 --- a/site/src/modules/management/DeploymentSettingsProvider.tsx +++ b/site/src/modules/management/DeploymentConfigProvider.tsx @@ -6,26 +6,26 @@ import { type FC, createContext, useContext } from "react"; import { useQuery } from "react-query"; import { Outlet } from "react-router-dom"; -export const DeploymentSettingsContext = createContext< - DeploymentSettingsValue | undefined +export const DeploymentConfigContext = createContext< + DeploymentConfigValue | undefined >(undefined); -type DeploymentSettingsValue = Readonly<{ +type DeploymentConfigValue = Readonly<{ deploymentConfig: DeploymentConfig; }>; -export const useDeploymentSettings = (): DeploymentSettingsValue => { - const context = useContext(DeploymentSettingsContext); +export const useDeploymentConfig = (): DeploymentConfigValue => { + const context = useContext(DeploymentConfigContext); if (!context) { throw new Error( - `${useDeploymentSettings.name} should be used inside of ${DeploymentSettingsProvider.name}`, + `${useDeploymentConfig.name} should be used inside of ${DeploymentConfigProvider.name}`, ); } return context; }; -const DeploymentSettingsProvider: FC = () => { +const DeploymentConfigProvider: FC = () => { const deploymentConfigQuery = useQuery(deploymentConfig()); if (deploymentConfigQuery.error) { @@ -37,12 +37,12 @@ const DeploymentSettingsProvider: FC = () => { } return ( - - + ); }; -export default DeploymentSettingsProvider; +export default DeploymentConfigProvider; diff --git a/site/src/modules/management/DeploymentSettingsLayout.tsx b/site/src/modules/management/DeploymentSettingsLayout.tsx index c40b6440a81c3..42e695c80654e 100644 --- a/site/src/modules/management/DeploymentSettingsLayout.tsx +++ b/site/src/modules/management/DeploymentSettingsLayout.tsx @@ -7,8 +7,8 @@ import { } from "components/Breadcrumb/Breadcrumb"; import { Loader } from "components/Loader/Loader"; import { useAuthenticated } from "contexts/auth/RequireAuth"; -import { RequirePermission } from "contexts/auth/RequirePermission"; -import { canViewDeploymentSettings } from "contexts/auth/permissions"; +import { canViewDeploymentSettings } from "modules/permissions"; +import { RequirePermission } from "modules/permissions/RequirePermission"; import { type FC, Suspense } from "react"; import { Navigate, Outlet, useLocation } from "react-router-dom"; import { DeploymentSidebar } from "./DeploymentSidebar"; @@ -21,8 +21,8 @@ const DeploymentSettingsLayout: FC = () => { return ( = ({ permissions, @@ -30,32 +27,32 @@ export const DeploymentSidebarView: FC = ({ return (
- {permissions.viewDeploymentValues && ( - General + {permissions.viewDeploymentConfig && ( + Overview )} {permissions.viewAllLicenses && ( Licenses )} - {permissions.editDeploymentValues && ( + {permissions.editDeploymentConfig && ( Appearance )} - {permissions.viewDeploymentValues && ( + {permissions.viewDeploymentConfig && ( User Authentication )} - {permissions.viewDeploymentValues && ( + {permissions.viewDeploymentConfig && ( External Authentication )} {/* Not exposing this yet since token exchange is not finished yet. - + OAuth2 Applications */} - {permissions.viewDeploymentValues && ( + {permissions.viewDeploymentConfig && ( Network )} {permissions.readWorkspaceProxies && ( @@ -63,10 +60,10 @@ export const DeploymentSidebarView: FC = ({ Workspace Proxies )} - {permissions.viewDeploymentValues && ( + {permissions.viewDeploymentConfig && ( Security )} - {permissions.viewDeploymentValues && ( + {permissions.viewDeploymentConfig && ( Observability @@ -81,6 +78,11 @@ export const DeploymentSidebarView: FC = ({ )} + {permissions.viewOrganizationIDPSyncSettings && ( + + IdP Organization Sync + + )} {permissions.viewNotificationTemplate && (
@@ -89,11 +91,6 @@ export const DeploymentSidebarView: FC = ({
)} - {permissions.viewOrganizationIDPSyncSettings && ( - - IdP Organization Sync - - )} {!hasPremiumLicense && ( Premium )} diff --git a/site/src/modules/management/OrganizationSettingsLayout.tsx b/site/src/modules/management/OrganizationSettingsLayout.tsx index ae1ce597641ae..00a435b82cd41 100644 --- a/site/src/modules/management/OrganizationSettingsLayout.tsx +++ b/site/src/modules/management/OrganizationSettingsLayout.tsx @@ -11,14 +11,14 @@ import { } from "components/Breadcrumb/Breadcrumb"; import { Loader } from "components/Loader/Loader"; import { useDashboard } from "modules/dashboard/useDashboard"; +import { + type OrganizationPermissions, + canViewOrganization, +} from "modules/permissions/organizations"; import NotFoundPage from "pages/404Page/404Page"; import { type FC, Suspense, createContext, useContext } from "react"; import { useQuery } from "react-query"; import { Outlet, useParams } from "react-router-dom"; -import { - type OrganizationPermissions, - canViewOrganization, -} from "./organizationPermissions"; export const OrganizationSettingsContext = createContext< OrganizationSettingsValue | undefined @@ -46,7 +46,7 @@ export const useOrganizationSettings = (): OrganizationSettingsValue => { }; const OrganizationSettingsLayout: FC = () => { - const { organizations, showOrganizations } = useDashboard(); + const { organizations } = useDashboard(); const { organization: orgName } = useParams() as { organization?: string; }; diff --git a/site/src/modules/management/OrganizationSidebarView.tsx b/site/src/modules/management/OrganizationSidebarView.tsx index 71a37659ab14d..ff5617eaa495d 100644 --- a/site/src/modules/management/OrganizationSidebarView.tsx +++ b/site/src/modules/management/OrganizationSidebarView.tsx @@ -16,11 +16,11 @@ import { PopoverTrigger, } from "components/Popover/Popover"; import { SettingsSidebarNavItem } from "components/Sidebar/Sidebar"; -import type { Permissions } from "contexts/auth/permissions"; import { Check, ChevronDown, Plus } from "lucide-react"; +import type { Permissions } from "modules/permissions"; +import type { OrganizationPermissions } from "modules/permissions/organizations"; import { type FC, useState } from "react"; import { useNavigate } from "react-router-dom"; -import type { OrganizationPermissions } from "./organizationPermissions"; interface OrganizationsSettingsNavigationProps { /** The organization selected from the dropdown */ diff --git a/site/src/contexts/auth/RequirePermission.tsx b/site/src/modules/permissions/RequirePermission.tsx similarity index 100% rename from site/src/contexts/auth/RequirePermission.tsx rename to site/src/modules/permissions/RequirePermission.tsx diff --git a/site/src/contexts/auth/permissions.tsx b/site/src/modules/permissions/index.ts similarity index 91% rename from site/src/contexts/auth/permissions.tsx rename to site/src/modules/permissions/index.ts index 0d8957627c36d..ea34cd6d97377 100644 --- a/site/src/contexts/auth/permissions.tsx +++ b/site/src/modules/permissions/index.ts @@ -30,7 +30,7 @@ export const permissionChecks = { resource_type: "template", any_org: true, }, - action: "update", + action: "create", }, updateTemplates: { object: { @@ -44,30 +44,18 @@ export const permissionChecks = { }, action: "delete", }, - viewDeploymentValues: { + viewDeploymentConfig: { object: { resource_type: "deployment_config", }, action: "read", }, - editDeploymentValues: { + editDeploymentConfig: { object: { resource_type: "deployment_config", }, action: "update", }, - viewUpdateCheck: { - object: { - resource_type: "deployment_config", - }, - action: "read", - }, - viewExternalAuthConfig: { - object: { - resource_type: "deployment_config", - }, - action: "read", - }, viewDeploymentStats: { object: { resource_type: "deployment_stats", @@ -178,8 +166,9 @@ export const canViewDeploymentSettings = ( ): permissions is Permissions => { return ( permissions !== undefined && - (permissions.viewDeploymentValues || + (permissions.viewDeploymentConfig || permissions.viewAllLicenses || + permissions.viewDeploymentConfig || permissions.viewAllUsers || permissions.viewAnyGroup || permissions.viewNotificationTemplate || diff --git a/site/src/modules/management/organizationPermissions.tsx b/site/src/modules/permissions/organizations.ts similarity index 100% rename from site/src/modules/management/organizationPermissions.tsx rename to site/src/modules/permissions/organizations.ts diff --git a/site/src/pages/DeploymentSettingsPage/ExternalAuthSettingsPage/ExternalAuthSettingsPage.tsx b/site/src/pages/DeploymentSettingsPage/ExternalAuthSettingsPage/ExternalAuthSettingsPage.tsx index 03908da7e3a78..88b90f7f8c1d0 100644 --- a/site/src/pages/DeploymentSettingsPage/ExternalAuthSettingsPage/ExternalAuthSettingsPage.tsx +++ b/site/src/pages/DeploymentSettingsPage/ExternalAuthSettingsPage/ExternalAuthSettingsPage.tsx @@ -1,11 +1,11 @@ -import { useDeploymentSettings } from "modules/management/DeploymentSettingsProvider"; +import { useDeploymentConfig } from "modules/management/DeploymentConfigProvider"; import type { FC } from "react"; import { Helmet } from "react-helmet-async"; import { pageTitle } from "utils/page"; import { ExternalAuthSettingsPageView } from "./ExternalAuthSettingsPageView"; const ExternalAuthSettingsPage: FC = () => { - const { deploymentConfig } = useDeploymentSettings(); + const { deploymentConfig } = useDeploymentConfig(); return ( <> diff --git a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicenseSeatConsumptionChart.tsx b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicenseSeatConsumptionChart.tsx index 78f6a08087d74..3a3d191e030be 100644 --- a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicenseSeatConsumptionChart.tsx +++ b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicenseSeatConsumptionChart.tsx @@ -108,7 +108,7 @@ export const LicenseSeatConsumptionChart: FC<
  • - + Daily user activity diff --git a/site/src/pages/DeploymentSettingsPage/NetworkSettingsPage/NetworkSettingsPage.tsx b/site/src/pages/DeploymentSettingsPage/NetworkSettingsPage/NetworkSettingsPage.tsx index cdbc3fb142ff1..7118560dca1bf 100644 --- a/site/src/pages/DeploymentSettingsPage/NetworkSettingsPage/NetworkSettingsPage.tsx +++ b/site/src/pages/DeploymentSettingsPage/NetworkSettingsPage/NetworkSettingsPage.tsx @@ -1,11 +1,11 @@ -import { useDeploymentSettings } from "modules/management/DeploymentSettingsProvider"; +import { useDeploymentConfig } from "modules/management/DeploymentConfigProvider"; import type { FC } from "react"; import { Helmet } from "react-helmet-async"; import { pageTitle } from "utils/page"; import { NetworkSettingsPageView } from "./NetworkSettingsPageView"; const NetworkSettingsPage: FC = () => { - const { deploymentConfig } = useDeploymentSettings(); + const { deploymentConfig } = useDeploymentConfig(); return ( <> diff --git a/site/src/pages/DeploymentSettingsPage/NotificationsPage/NotificationsPage.tsx b/site/src/pages/DeploymentSettingsPage/NotificationsPage/NotificationsPage.tsx index 2e73e4c6a2b9b..1a38cd1de9c84 100644 --- a/site/src/pages/DeploymentSettingsPage/NotificationsPage/NotificationsPage.tsx +++ b/site/src/pages/DeploymentSettingsPage/NotificationsPage/NotificationsPage.tsx @@ -9,7 +9,7 @@ import { Loader } from "components/Loader/Loader"; import { SettingsHeader } from "components/SettingsHeader/SettingsHeader"; import { TabLink, Tabs, TabsList } from "components/Tabs/Tabs"; import { useSearchParamsKey } from "hooks/useSearchParamsKey"; -import { useDeploymentSettings } from "modules/management/DeploymentSettingsProvider"; +import { useDeploymentConfig } from "modules/management/DeploymentConfigProvider"; import { castNotificationMethod } from "modules/notifications/utils"; import type { FC } from "react"; import { Helmet } from "react-helmet-async"; @@ -22,7 +22,7 @@ import { NotificationEvents } from "./NotificationEvents"; import { Troubleshooting } from "./Troubleshooting"; export const NotificationsPage: FC = () => { - const { deploymentConfig } = useDeploymentSettings(); + const { deploymentConfig } = useDeploymentConfig(); const [templatesByGroup, dispatchMethods] = useQueries({ queries: [ { diff --git a/site/src/pages/DeploymentSettingsPage/NotificationsPage/storybookUtils.ts b/site/src/pages/DeploymentSettingsPage/NotificationsPage/storybookUtils.ts index fc500efd847d6..0ceac24520e1a 100644 --- a/site/src/pages/DeploymentSettingsPage/NotificationsPage/storybookUtils.ts +++ b/site/src/pages/DeploymentSettingsPage/NotificationsPage/storybookUtils.ts @@ -194,7 +194,7 @@ export const baseMeta = { }, ], user: MockUser, - permissions: { viewDeploymentValues: true }, + permissions: { viewDeploymentConfig: true }, deploymentOptions: mockNotificationsDeploymentOptions, deploymentValues: { notifications: { diff --git a/site/src/pages/DeploymentSettingsPage/ObservabilitySettingsPage/ObservabilitySettingsPage.tsx b/site/src/pages/DeploymentSettingsPage/ObservabilitySettingsPage/ObservabilitySettingsPage.tsx index 12b574c177384..bce0a0d544709 100644 --- a/site/src/pages/DeploymentSettingsPage/ObservabilitySettingsPage/ObservabilitySettingsPage.tsx +++ b/site/src/pages/DeploymentSettingsPage/ObservabilitySettingsPage/ObservabilitySettingsPage.tsx @@ -1,13 +1,13 @@ import { useDashboard } from "modules/dashboard/useDashboard"; import { useFeatureVisibility } from "modules/dashboard/useFeatureVisibility"; -import { useDeploymentSettings } from "modules/management/DeploymentSettingsProvider"; +import { useDeploymentConfig } from "modules/management/DeploymentConfigProvider"; import type { FC } from "react"; import { Helmet } from "react-helmet-async"; import { pageTitle } from "utils/page"; import { ObservabilitySettingsPageView } from "./ObservabilitySettingsPageView"; const ObservabilitySettingsPage: FC = () => { - const { deploymentConfig } = useDeploymentSettings(); + const { deploymentConfig } = useDeploymentConfig(); const { entitlements } = useDashboard(); const { multiple_organizations: hasPremiumLicense } = useFeatureVisibility(); diff --git a/site/src/pages/DeploymentSettingsPage/GeneralSettingsPage/ChartSection.tsx b/site/src/pages/DeploymentSettingsPage/OverviewPage/ChartSection.tsx similarity index 100% rename from site/src/pages/DeploymentSettingsPage/GeneralSettingsPage/ChartSection.tsx rename to site/src/pages/DeploymentSettingsPage/OverviewPage/ChartSection.tsx diff --git a/site/src/pages/DeploymentSettingsPage/GeneralSettingsPage/GeneralSettingsPage.tsx b/site/src/pages/DeploymentSettingsPage/OverviewPage/OverviewPage.tsx similarity index 89% rename from site/src/pages/DeploymentSettingsPage/GeneralSettingsPage/GeneralSettingsPage.tsx rename to site/src/pages/DeploymentSettingsPage/OverviewPage/OverviewPage.tsx index 32a9c3c971d78..63563503de362 100644 --- a/site/src/pages/DeploymentSettingsPage/GeneralSettingsPage/GeneralSettingsPage.tsx +++ b/site/src/pages/DeploymentSettingsPage/OverviewPage/OverviewPage.tsx @@ -1,7 +1,7 @@ import { deploymentDAUs } from "api/queries/deployment"; import { availableExperiments, experiments } from "api/queries/experiments"; import { useEmbeddedMetadata } from "hooks/useEmbeddedMetadata"; -import { useDeploymentSettings } from "modules/management/DeploymentSettingsProvider"; +import { useDeploymentConfig } from "modules/management/DeploymentConfigProvider"; import type { FC } from "react"; import { Helmet } from "react-helmet-async"; import { useQuery } from "react-query"; @@ -9,7 +9,7 @@ import { pageTitle } from "utils/page"; import { GeneralSettingsPageView } from "./GeneralSettingsPageView"; const GeneralSettingsPage: FC = () => { - const { deploymentConfig } = useDeploymentSettings(); + const { deploymentConfig } = useDeploymentConfig(); const safeExperimentsQuery = useQuery(availableExperiments()); const { metadata } = useEmbeddedMetadata(); diff --git a/site/src/pages/DeploymentSettingsPage/GeneralSettingsPage/GeneralSettingsPageView.stories.tsx b/site/src/pages/DeploymentSettingsPage/OverviewPage/OverviewPageView.stories.tsx similarity index 100% rename from site/src/pages/DeploymentSettingsPage/GeneralSettingsPage/GeneralSettingsPageView.stories.tsx rename to site/src/pages/DeploymentSettingsPage/OverviewPage/OverviewPageView.stories.tsx diff --git a/site/src/pages/DeploymentSettingsPage/GeneralSettingsPage/GeneralSettingsPageView.tsx b/site/src/pages/DeploymentSettingsPage/OverviewPage/OverviewPageView.tsx similarity index 100% rename from site/src/pages/DeploymentSettingsPage/GeneralSettingsPage/GeneralSettingsPageView.tsx rename to site/src/pages/DeploymentSettingsPage/OverviewPage/OverviewPageView.tsx diff --git a/site/src/pages/DeploymentSettingsPage/GeneralSettingsPage/UserEngagementChart.stories.tsx b/site/src/pages/DeploymentSettingsPage/OverviewPage/UserEngagementChart.stories.tsx similarity index 100% rename from site/src/pages/DeploymentSettingsPage/GeneralSettingsPage/UserEngagementChart.stories.tsx rename to site/src/pages/DeploymentSettingsPage/OverviewPage/UserEngagementChart.stories.tsx diff --git a/site/src/pages/DeploymentSettingsPage/GeneralSettingsPage/UserEngagementChart.tsx b/site/src/pages/DeploymentSettingsPage/OverviewPage/UserEngagementChart.tsx similarity index 100% rename from site/src/pages/DeploymentSettingsPage/GeneralSettingsPage/UserEngagementChart.tsx rename to site/src/pages/DeploymentSettingsPage/OverviewPage/UserEngagementChart.tsx diff --git a/site/src/pages/DeploymentSettingsPage/SecuritySettingsPage/SecuritySettingsPage.tsx b/site/src/pages/DeploymentSettingsPage/SecuritySettingsPage/SecuritySettingsPage.tsx index 1ac3fb00c7569..981f35d34704a 100644 --- a/site/src/pages/DeploymentSettingsPage/SecuritySettingsPage/SecuritySettingsPage.tsx +++ b/site/src/pages/DeploymentSettingsPage/SecuritySettingsPage/SecuritySettingsPage.tsx @@ -1,12 +1,12 @@ import { useDashboard } from "modules/dashboard/useDashboard"; -import { useDeploymentSettings } from "modules/management/DeploymentSettingsProvider"; +import { useDeploymentConfig } from "modules/management/DeploymentConfigProvider"; import type { FC } from "react"; import { Helmet } from "react-helmet-async"; import { pageTitle } from "utils/page"; import { SecuritySettingsPageView } from "./SecuritySettingsPageView"; const SecuritySettingsPage: FC = () => { - const { deploymentConfig } = useDeploymentSettings(); + const { deploymentConfig } = useDeploymentConfig(); const { entitlements } = useDashboard(); return ( diff --git a/site/src/pages/DeploymentSettingsPage/UserAuthSettingsPage/UserAuthSettingsPage.tsx b/site/src/pages/DeploymentSettingsPage/UserAuthSettingsPage/UserAuthSettingsPage.tsx index 1502fe0eab366..0f5d0269c8849 100644 --- a/site/src/pages/DeploymentSettingsPage/UserAuthSettingsPage/UserAuthSettingsPage.tsx +++ b/site/src/pages/DeploymentSettingsPage/UserAuthSettingsPage/UserAuthSettingsPage.tsx @@ -1,11 +1,11 @@ -import { useDeploymentSettings } from "modules/management/DeploymentSettingsProvider"; +import { useDeploymentConfig } from "modules/management/DeploymentConfigProvider"; import type { FC } from "react"; import { Helmet } from "react-helmet-async"; import { pageTitle } from "utils/page"; import { UserAuthSettingsPageView } from "./UserAuthSettingsPageView"; const UserAuthSettingsPage: FC = () => { - const { deploymentConfig } = useDeploymentSettings(); + const { deploymentConfig } = useDeploymentConfig(); return ( <> diff --git a/site/src/pages/ExternalAuthPage/ExternalAuthPage.tsx b/site/src/pages/ExternalAuthPage/ExternalAuthPage.tsx index 7cef9e8774b4c..a7f97cefa92f4 100644 --- a/site/src/pages/ExternalAuthPage/ExternalAuthPage.tsx +++ b/site/src/pages/ExternalAuthPage/ExternalAuthPage.tsx @@ -104,7 +104,7 @@ const ExternalAuthPage: FC = () => { authenticated: false, }); }} - viewExternalAuthConfig={permissions.viewExternalAuthConfig} + viewExternalAuthConfig={permissions.viewDeploymentConfig} deviceExchangeError={deviceExchangeError} externalAuthDevice={externalAuthDeviceQuery.data} /> diff --git a/site/src/pages/OrganizationSettingsPage/CreateOrganizationPage.tsx b/site/src/pages/OrganizationSettingsPage/CreateOrganizationPage.tsx index cecfae677f4b9..3258461ea79bb 100644 --- a/site/src/pages/OrganizationSettingsPage/CreateOrganizationPage.tsx +++ b/site/src/pages/OrganizationSettingsPage/CreateOrganizationPage.tsx @@ -1,8 +1,8 @@ import { createOrganization } from "api/queries/organizations"; import { displaySuccess } from "components/GlobalSnackbar/utils"; import { useAuthenticated } from "contexts/auth/RequireAuth"; -import { RequirePermission } from "contexts/auth/RequirePermission"; import { useFeatureVisibility } from "modules/dashboard/useFeatureVisibility"; +import { RequirePermission } from "modules/permissions/RequirePermission"; import type { FC } from "react"; import { useMutation, useQueryClient } from "react-query"; import { useNavigate } from "react-router-dom"; diff --git a/site/src/pages/OrganizationSettingsPage/CustomRolesPage/CreateEditRolePage.tsx b/site/src/pages/OrganizationSettingsPage/CustomRolesPage/CreateEditRolePage.tsx index 43ae73598059e..0d702b400e69d 100644 --- a/site/src/pages/OrganizationSettingsPage/CustomRolesPage/CreateEditRolePage.tsx +++ b/site/src/pages/OrganizationSettingsPage/CustomRolesPage/CreateEditRolePage.tsx @@ -8,8 +8,8 @@ import type { CustomRoleRequest } from "api/typesGenerated"; import { ErrorAlert } from "components/Alert/ErrorAlert"; import { displayError } from "components/GlobalSnackbar/utils"; import { Loader } from "components/Loader/Loader"; -import { RequirePermission } from "contexts/auth/RequirePermission"; import { useOrganizationSettings } from "modules/management/OrganizationSettingsLayout"; +import { RequirePermission } from "modules/permissions/RequirePermission"; import type { FC } from "react"; import { Helmet } from "react-helmet-async"; import { useMutation, useQuery, useQueryClient } from "react-query"; diff --git a/site/src/pages/OrganizationSettingsPage/CustomRolesPage/CustomRolesPage.tsx b/site/src/pages/OrganizationSettingsPage/CustomRolesPage/CustomRolesPage.tsx index 4e7b8c386120a..ca567fdce7836 100644 --- a/site/src/pages/OrganizationSettingsPage/CustomRolesPage/CustomRolesPage.tsx +++ b/site/src/pages/OrganizationSettingsPage/CustomRolesPage/CustomRolesPage.tsx @@ -6,9 +6,9 @@ import { displayError, displaySuccess } from "components/GlobalSnackbar/utils"; import { Loader } from "components/Loader/Loader"; import { SettingsHeader } from "components/SettingsHeader/SettingsHeader"; import { Stack } from "components/Stack/Stack"; -import { RequirePermission } from "contexts/auth/RequirePermission"; import { useFeatureVisibility } from "modules/dashboard/useFeatureVisibility"; import { useOrganizationSettings } from "modules/management/OrganizationSettingsLayout"; +import { RequirePermission } from "modules/permissions/RequirePermission"; import { type FC, useEffect, useState } from "react"; import { Helmet } from "react-helmet-async"; import { useMutation, useQuery, useQueryClient } from "react-query"; diff --git a/site/src/pages/OrganizationSettingsPage/OrganizationRedirect.tsx b/site/src/pages/OrganizationSettingsPage/OrganizationRedirect.tsx index b862ad41dc883..d01c9d1cda29f 100644 --- a/site/src/pages/OrganizationSettingsPage/OrganizationRedirect.tsx +++ b/site/src/pages/OrganizationSettingsPage/OrganizationRedirect.tsx @@ -1,6 +1,6 @@ import { EmptyState } from "components/EmptyState/EmptyState"; import { useOrganizationSettings } from "modules/management/OrganizationSettingsLayout"; -import { canEditOrganization } from "modules/management/organizationPermissions"; +import { canEditOrganization } from "modules/permissions/organizations"; import type { FC } from "react"; import { Navigate } from "react-router-dom"; @@ -10,19 +10,25 @@ const OrganizationRedirect: FC = () => { organizationPermissionsByOrganizationId: organizationPermissions, } = useOrganizationSettings(); + const sortedOrganizations = [...organizations].sort( + (a, b) => (b.is_default ? 1 : 0) - (a.is_default ? 1 : 0), + ); + // Redirect /organizations => /organizations/some-organization-name // If they can edit the default org, we should redirect to the default. // If they cannot edit the default, we should redirect to the first org that // they can edit. - const editableOrg = [...organizations] - .sort((a, b) => (b.is_default ? 1 : 0) - (a.is_default ? 1 : 0)) - .find((org) => canEditOrganization(organizationPermissions[org.id])); + const editableOrg = sortedOrganizations.find((org) => + canEditOrganization(organizationPermissions[org.id]), + ); if (editableOrg) { return ; } // If they cannot edit any org, just redirect to an org they can read. - if (organizations.length > 0) { - return ; + if (sortedOrganizations.length > 0) { + return ( + + ); } return ; }; diff --git a/site/src/pages/TerminalPage/TerminalPage.stories.tsx b/site/src/pages/TerminalPage/TerminalPage.stories.tsx index f50b75bac4a26..4cf052668bb06 100644 --- a/site/src/pages/TerminalPage/TerminalPage.stories.tsx +++ b/site/src/pages/TerminalPage/TerminalPage.stories.tsx @@ -4,7 +4,7 @@ import { workspaceByOwnerAndNameKey } from "api/queries/workspaces"; import type { Workspace, WorkspaceAgentLifecycle } from "api/typesGenerated"; import { AuthProvider } from "contexts/auth/AuthProvider"; import { RequireAuth } from "contexts/auth/RequireAuth"; -import { permissionChecks } from "contexts/auth/permissions"; +import { permissionChecks } from "modules/permissions"; import { reactRouterOutlet, reactRouterParameters, diff --git a/site/src/pages/UserSettingsPage/NotificationsPage/NotificationsPage.stories.tsx b/site/src/pages/UserSettingsPage/NotificationsPage/NotificationsPage.stories.tsx index 2d7509ac7d171..433045c625b17 100644 --- a/site/src/pages/UserSettingsPage/NotificationsPage/NotificationsPage.stories.tsx +++ b/site/src/pages/UserSettingsPage/NotificationsPage/NotificationsPage.stories.tsx @@ -40,7 +40,7 @@ const meta = { }, ], user: MockUser, - permissions: { viewDeploymentValues: true }, + permissions: { viewDeploymentConfig: true }, }, decorators: [withGlobalSnackbar, withAuthProvider, withDashboardProvider], } satisfies Meta; @@ -74,7 +74,7 @@ export const ToggleNotification: Story = { export const NonAdmin: Story = { parameters: { - permissions: { viewDeploymentValues: false }, + permissions: { viewDeploymentConfig: false }, }, }; diff --git a/site/src/pages/UserSettingsPage/NotificationsPage/NotificationsPage.tsx b/site/src/pages/UserSettingsPage/NotificationsPage/NotificationsPage.tsx index d10a5c853e56a..6e7b9ac8ab8e0 100644 --- a/site/src/pages/UserSettingsPage/NotificationsPage/NotificationsPage.tsx +++ b/site/src/pages/UserSettingsPage/NotificationsPage/NotificationsPage.tsx @@ -48,7 +48,7 @@ export const NotificationsPage: FC = () => { ...systemNotificationTemplates(), select: (data: NotificationTemplate[]) => { const groups = selectTemplatesByGroup(data); - return permissions.viewDeploymentValues + return permissions.viewDeploymentConfig ? groups : { // Members only have access to the "Workspace Notifications" group diff --git a/site/src/pages/UsersPage/UsersPage.stories.tsx b/site/src/pages/UsersPage/UsersPage.stories.tsx index cd4a1cfc7e113..8a3c9bea5d013 100644 --- a/site/src/pages/UsersPage/UsersPage.stories.tsx +++ b/site/src/pages/UsersPage/UsersPage.stories.tsx @@ -63,7 +63,7 @@ const parameters = { permissions: { createUser: true, updateUsers: true, - viewDeploymentValues: true, + viewDeploymentConfig: true, }, }; diff --git a/site/src/pages/UsersPage/UsersPage.tsx b/site/src/pages/UsersPage/UsersPage.tsx index 81b7dfcb5ca71..9d2aaadefc96d 100644 --- a/site/src/pages/UsersPage/UsersPage.tsx +++ b/site/src/pages/UsersPage/UsersPage.tsx @@ -51,12 +51,12 @@ const UsersPage: FC = ({ defaultNewPassword }) => { const { createUser: canCreateUser, updateUsers: canEditUsers, - viewDeploymentValues, + viewDeploymentConfig, } = permissions; const rolesQuery = useQuery(roles()); const { data: deploymentValues } = useQuery({ ...deploymentConfig(), - enabled: viewDeploymentValues, + enabled: viewDeploymentConfig, }); const usersQuery = usePaginatedQuery(paginatedUsers(searchParamsResult[0])); @@ -94,7 +94,7 @@ const UsersPage: FC = ({ defaultNewPassword }) => { // Indicates if oidc roles are synced from the oidc idp. // Assign 'false' if unknown. const oidcRoleSyncEnabled = - viewDeploymentValues && + viewDeploymentConfig && deploymentValues?.config.oidc?.user_role_field !== ""; const isLoading = diff --git a/site/src/pages/WorkspacePage/Workspace.stories.tsx b/site/src/pages/WorkspacePage/Workspace.stories.tsx index 9ff40eccaf12c..52d68d1dd0fd8 100644 --- a/site/src/pages/WorkspacePage/Workspace.stories.tsx +++ b/site/src/pages/WorkspacePage/Workspace.stories.tsx @@ -11,7 +11,7 @@ const permissions: WorkspacePermissions = { readWorkspace: true, updateWorkspace: true, updateTemplate: true, - viewDeploymentValues: true, + viewDeploymentConfig: true, }; const meta: Meta = { diff --git a/site/src/pages/WorkspacePage/WorkspaceNotifications/WorkspaceNotifications.stories.tsx b/site/src/pages/WorkspacePage/WorkspaceNotifications/WorkspaceNotifications.stories.tsx index 055c07a248f2c..6f02d925f6485 100644 --- a/site/src/pages/WorkspacePage/WorkspaceNotifications/WorkspaceNotifications.stories.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceNotifications/WorkspaceNotifications.stories.tsx @@ -15,7 +15,7 @@ const defaultPermissions = { readWorkspace: true, updateTemplate: true, updateWorkspace: true, - viewDeploymentValues: true, + viewDeploymentConfig: true, }; const meta: Meta = { diff --git a/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx b/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx index b3f4a76cd4b3d..e4329ecad78aa 100644 --- a/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx @@ -66,7 +66,7 @@ export const WorkspaceReadyPage: FC = ({ // Debug mode const { data: deploymentValues } = useQuery({ ...deploymentConfig(), - enabled: permissions.viewDeploymentValues, + enabled: permissions.viewDeploymentConfig, }); // Build logs diff --git a/site/src/pages/WorkspacePage/permissions.ts b/site/src/pages/WorkspacePage/permissions.ts index dece7d03b3921..3ac1df5a3a7fd 100644 --- a/site/src/pages/WorkspacePage/permissions.ts +++ b/site/src/pages/WorkspacePage/permissions.ts @@ -25,7 +25,7 @@ export const workspaceChecks = (workspace: Workspace, template: Template) => }, action: "update", }, - viewDeploymentValues: { + viewDeploymentConfig: { object: { resource_type: "deployment_config", }, diff --git a/site/src/pages/WorkspacesPage/WorkspacesPage.tsx b/site/src/pages/WorkspacesPage/WorkspacesPage.tsx index abade141d5183..e94ccbbd86605 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesPage.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesPage.tsx @@ -156,7 +156,7 @@ const useWorkspacesFilter = ({ }); const { permissions } = useAuthenticated(); - const canFilterByUser = permissions.viewDeploymentValues; + const canFilterByUser = permissions.viewDeploymentConfig; const userMenu = useUserFilterMenu({ value: filter.values.owner, onChange: (option) => diff --git a/site/src/router.tsx b/site/src/router.tsx index ebb9e6763d058..6eaae4922f5c0 100644 --- a/site/src/router.tsx +++ b/site/src/router.tsx @@ -31,8 +31,8 @@ const NotFoundPage = lazy(() => import("./pages/404Page/404Page")); const DeploymentSettingsLayout = lazy( () => import("./modules/management/DeploymentSettingsLayout"), ); -const DeploymentSettingsProvider = lazy( - () => import("./modules/management/DeploymentSettingsProvider"), +const DeploymentConfigProvider = lazy( + () => import("./modules/management/DeploymentConfigProvider"), ); const OrganizationSidebarLayout = lazy( () => import("./modules/management/OrganizationSidebarLayout"), @@ -98,10 +98,10 @@ const TemplateSummaryPage = lazy( const CreateWorkspacePage = lazy( () => import("./pages/CreateWorkspacePage/CreateWorkspacePage"), ); -const GeneralSettingsPage = lazy( +const OverviewPage = lazy( () => import( - "./pages/DeploymentSettingsPage/GeneralSettingsPage/GeneralSettingsPage" + "./pages/DeploymentSettingsPage/OverviewPage/OverviewPage" ), ); const SecuritySettingsPage = lazy( @@ -435,8 +435,8 @@ export const router = createBrowserRouter( }> - }> - } /> + }> + } /> } /> { organizationPermissions: MockOrganizationPermissions, }} > - - + ); }; From 2413f9645fbb790ff94e6d5c241e1a1ec6081801 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 7 Mar 2025 17:07:25 +0000 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=99=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- site/src/router.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/site/src/router.tsx b/site/src/router.tsx index 6eaae4922f5c0..06e3c0d6cf892 100644 --- a/site/src/router.tsx +++ b/site/src/router.tsx @@ -99,10 +99,7 @@ const CreateWorkspacePage = lazy( () => import("./pages/CreateWorkspacePage/CreateWorkspacePage"), ); const OverviewPage = lazy( - () => - import( - "./pages/DeploymentSettingsPage/OverviewPage/OverviewPage" - ), + () => import("./pages/DeploymentSettingsPage/OverviewPage/OverviewPage"), ); const SecuritySettingsPage = lazy( () => From 18eb42e0891e47c620f69c05d6553426a901f6e3 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 7 Mar 2025 17:09:52 +0000 Subject: [PATCH 3/4] :| --- site/src/modules/permissions/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/site/src/modules/permissions/index.ts b/site/src/modules/permissions/index.ts index ea34cd6d97377..300edec9e52db 100644 --- a/site/src/modules/permissions/index.ts +++ b/site/src/modules/permissions/index.ts @@ -168,7 +168,6 @@ export const canViewDeploymentSettings = ( permissions !== undefined && (permissions.viewDeploymentConfig || permissions.viewAllLicenses || - permissions.viewDeploymentConfig || permissions.viewAllUsers || permissions.viewAnyGroup || permissions.viewNotificationTemplate || From 58e1653ea3e2084a1f7624bf131691078c5a6a5f Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 7 Mar 2025 17:20:45 +0000 Subject: [PATCH 4/4] :^| --- .../OverviewPage/OverviewPage.tsx | 10 +++++----- .../OverviewPage/OverviewPageView.stories.tsx | 10 +++++----- .../OverviewPage/OverviewPageView.tsx | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/site/src/pages/DeploymentSettingsPage/OverviewPage/OverviewPage.tsx b/site/src/pages/DeploymentSettingsPage/OverviewPage/OverviewPage.tsx index 63563503de362..fc15eca1ec4f1 100644 --- a/site/src/pages/DeploymentSettingsPage/OverviewPage/OverviewPage.tsx +++ b/site/src/pages/DeploymentSettingsPage/OverviewPage/OverviewPage.tsx @@ -6,9 +6,9 @@ import type { FC } from "react"; import { Helmet } from "react-helmet-async"; import { useQuery } from "react-query"; import { pageTitle } from "utils/page"; -import { GeneralSettingsPageView } from "./GeneralSettingsPageView"; +import { OverviewPageView } from "./OverviewPageView"; -const GeneralSettingsPage: FC = () => { +const OverviewPage: FC = () => { const { deploymentConfig } = useDeploymentConfig(); const safeExperimentsQuery = useQuery(availableExperiments()); @@ -26,9 +26,9 @@ const GeneralSettingsPage: FC = () => { return ( <> - {pageTitle("General Settings")} + {pageTitle("Overview", "Deployment")} - { ); }; -export default GeneralSettingsPage; +export default OverviewPage; diff --git a/site/src/pages/DeploymentSettingsPage/OverviewPage/OverviewPageView.stories.tsx b/site/src/pages/DeploymentSettingsPage/OverviewPage/OverviewPageView.stories.tsx index 50b04bb64228e..b3398f8b1f204 100644 --- a/site/src/pages/DeploymentSettingsPage/OverviewPage/OverviewPageView.stories.tsx +++ b/site/src/pages/DeploymentSettingsPage/OverviewPage/OverviewPageView.stories.tsx @@ -1,10 +1,10 @@ import type { Meta, StoryObj } from "@storybook/react"; import { MockDeploymentDAUResponse } from "testHelpers/entities"; -import { GeneralSettingsPageView } from "./GeneralSettingsPageView"; +import { OverviewPageView } from "./OverviewPageView"; -const meta: Meta = { - title: "pages/DeploymentSettingsPage/GeneralSettingsPageView", - component: GeneralSettingsPageView, +const meta: Meta = { + title: "pages/DeploymentSettingsPage/OverviewPageView", + component: OverviewPageView, args: { deploymentOptions: [ { @@ -42,7 +42,7 @@ const meta: Meta = { }; export default meta; -type Story = StoryObj; +type Story = StoryObj; export const Page: Story = {}; diff --git a/site/src/pages/DeploymentSettingsPage/OverviewPage/OverviewPageView.tsx b/site/src/pages/DeploymentSettingsPage/OverviewPage/OverviewPageView.tsx index 57bb213457e9f..b3a72a7623082 100644 --- a/site/src/pages/DeploymentSettingsPage/OverviewPage/OverviewPageView.tsx +++ b/site/src/pages/DeploymentSettingsPage/OverviewPage/OverviewPageView.tsx @@ -14,14 +14,14 @@ import { Alert } from "../../../components/Alert/Alert"; import OptionsTable from "../OptionsTable"; import { UserEngagementChart } from "./UserEngagementChart"; -export type GeneralSettingsPageViewProps = { +export type OverviewPageViewProps = { deploymentOptions: SerpentOption[]; dailyActiveUsers: DAUsResponse | undefined; readonly invalidExperiments: Experiments | string[]; readonly safeExperiments: Experiments | string[]; }; -export const GeneralSettingsPageView: FC = ({ +export const OverviewPageView: FC = ({ deploymentOptions, dailyActiveUsers, safeExperiments,