diff --git a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.stories.tsx b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.stories.tsx index 1d4658e2661c6..7aab615ebbc7a 100644 --- a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.stories.tsx +++ b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.stories.tsx @@ -10,6 +10,7 @@ const meta: Meta = { decorators: [withAuthProvider, withDashboardProvider], parameters: { user: MockUser, + features: ["multiple_organizations"], permissions: { viewDeploymentValues: true }, queries: [ { @@ -61,3 +62,23 @@ export const CanEditOrganization: Story = { ], }, }; + +export const CanEditOrganizationNotEntitled: Story = { + parameters: { + reactRouter: reactRouterParameters({ + location: { pathParams: { organization: MockDefaultOrganization.name } }, + routing: { path: "/organizations/:organization" }, + }), + features: [], + queries: [ + { + key: ["organizations", [MockDefaultOrganization.id], "permissions"], + data: { + [MockDefaultOrganization.id]: { + editOrganization: true, + }, + }, + }, + ], + }, +}; diff --git a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.test.tsx b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.test.tsx index 23e3fb97f0ecd..418ac2e8f7f9e 100644 --- a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.test.tsx +++ b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.test.tsx @@ -2,6 +2,7 @@ import { screen, within } from "@testing-library/react"; import { http, HttpResponse } from "msw"; import { MockDefaultOrganization, + MockEntitlementsWithMultiOrg, MockOrganization2, } from "testHelpers/entities"; import { @@ -24,6 +25,9 @@ const renderPage = async () => { describe("OrganizationSettingsPage", () => { it("has no editable organizations", async () => { server.use( + http.get("/api/v2/entitlements", () => { + return HttpResponse.json(MockEntitlementsWithMultiOrg); + }), http.get("/api/v2/organizations", () => { return HttpResponse.json([MockDefaultOrganization, MockOrganization2]); }), @@ -39,6 +43,9 @@ describe("OrganizationSettingsPage", () => { it("redirects to default organization", async () => { server.use( + http.get("/api/v2/entitlements", () => { + return HttpResponse.json(MockEntitlementsWithMultiOrg); + }), http.get("/api/v2/organizations", () => { // Default always preferred regardless of order. return HttpResponse.json([MockOrganization2, MockDefaultOrganization]); @@ -60,6 +67,9 @@ describe("OrganizationSettingsPage", () => { it("redirects to non-default organization", async () => { server.use( + http.get("/api/v2/entitlements", () => { + return HttpResponse.json(MockEntitlementsWithMultiOrg); + }), http.get("/api/v2/organizations", () => { return HttpResponse.json([MockDefaultOrganization, MockOrganization2]); }), diff --git a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.tsx b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.tsx index 6873561985b73..bce41745a2d7d 100644 --- a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.tsx +++ b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.tsx @@ -7,6 +7,7 @@ import type { Organization } from "api/typesGenerated"; import { EmptyState } from "components/EmptyState/EmptyState"; import { displaySuccess } from "components/GlobalSnackbar/utils"; import { Loader } from "components/Loader/Loader"; +import { useFeatureVisibility } from "modules/dashboard/useFeatureVisibility"; import type { FC } from "react"; import { useMutation, useQuery, useQueryClient } from "react-query"; import { Navigate, useNavigate, useParams } from "react-router-dom"; @@ -22,6 +23,7 @@ const OrganizationSettingsPage: FC = () => { organization?: string; }; const { organizations } = useOrganizationSettings(); + const feats = useFeatureVisibility(); const navigate = useNavigate(); const queryClient = useQueryClient(); @@ -69,7 +71,12 @@ const OrganizationSettingsPage: FC = () => { // The user may not be able to edit this org but they can still see it because // they can edit members, etc. In this case they will be shown a read-only // summary page instead of the settings form. - if (!permissions[organization.id]?.editOrganization) { + // Similarly, if the feature is not entitled then the user will not be able to + // edit the organization. + if ( + !permissions[organization.id]?.editOrganization || + !feats.multiple_organizations + ) { return ; } diff --git a/site/src/testHelpers/storybook.tsx b/site/src/testHelpers/storybook.tsx index 8f32e6ec6ab07..decfd3eb94dc2 100644 --- a/site/src/testHelpers/storybook.tsx +++ b/site/src/testHelpers/storybook.tsx @@ -24,6 +24,7 @@ export const withDashboardProvider = ( const entitlements: Entitlements = { ...MockEntitlements, + has_license: features.length > 0, features: withDefaultFeatures( Object.fromEntries( features.map((feature) => [