Skip to content

Commit 365bc1d

Browse files
committed
feat: show summary if unable to edit org
This can happen if you can edit the members, for example, but not the organization settings. In this case you will see a new summary page instead of the edit form.
1 parent 83bf388 commit 365bc1d

6 files changed

+105
-13
lines changed

site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.test.tsx

+20
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,24 @@ describe("OrganizationSettingsPage", () => {
122122
await renderPage("the-endless-void");
123123
await screen.findByText("Organization not found");
124124
});
125+
126+
it("cannot edit organization", async () => {
127+
server.use(
128+
http.get("/api/v2/organizations", () => {
129+
return HttpResponse.json([MockDefaultOrganization]);
130+
}),
131+
http.post("/api/v2/authcheck", async () => {
132+
return HttpResponse.json({
133+
viewDeploymentValues: true,
134+
});
135+
}),
136+
);
137+
// No form since they cannot edit, instead sees the summary view.
138+
await renderPage(MockDefaultOrganization.name);
139+
expect(screen.queryByTestId("org-settings-form")).not.toBeInTheDocument();
140+
await screen.findByRole("heading", {
141+
level: 1,
142+
name: MockDefaultOrganization.display_name,
143+
});
144+
});
125145
});

site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.tsx

+8-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
useOrganizationSettings,
1616
} from "./ManagementSettingsLayout";
1717
import { OrganizationSettingsPageView } from "./OrganizationSettingsPageView";
18+
import { OrganizationSummaryPageView } from "./OrganizationSummaryPageView";
1819

1920
const OrganizationSettingsPage: FC = () => {
2021
const { organization: organizationName } = useParams() as {
@@ -66,12 +67,18 @@ const OrganizationSettingsPage: FC = () => {
6667
return <EmptyState message="Organization not found" />;
6768
}
6869

70+
// The user may not be able to edit this org but they can still see it because
71+
// they can edit members, etc. In this case they will be shown a read-only
72+
// summary page instead of the settings form.
73+
if (!permissions[organization.id]?.editOrganization) {
74+
return <OrganizationSummaryPageView organization={organization} />;
75+
}
76+
6977
const error =
7078
updateOrganizationMutation.error ?? deleteOrganizationMutation.error;
7179

7280
return (
7381
<OrganizationSettingsPageView
74-
canEdit={permissions[organization.id]?.editOrganization ?? false}
7582
organization={organization}
7683
error={error}
7784
onSubmit={async (values) => {

site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.stories.tsx

-7
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ const meta: Meta<typeof OrganizationSettingsPageView> = {
1010
component: OrganizationSettingsPageView,
1111
args: {
1212
organization: MockOrganization,
13-
canEdit: true,
1413
},
1514
};
1615

@@ -24,9 +23,3 @@ export const DefaultOrg: Story = {
2423
organization: MockDefaultOrganization,
2524
},
2625
};
27-
28-
export const CannotEdit: Story = {
29-
args: {
30-
canEdit: false,
31-
},
32-
};

site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx

+4-5
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,11 @@ interface OrganizationSettingsPageViewProps {
4444
error: unknown;
4545
onSubmit: (values: UpdateOrganizationRequest) => Promise<void>;
4646
onDeleteOrganization: () => void;
47-
canEdit: boolean;
4847
}
4948

5049
export const OrganizationSettingsPageView: FC<
5150
OrganizationSettingsPageViewProps
52-
> = ({ organization, error, onSubmit, onDeleteOrganization, canEdit }) => {
51+
> = ({ organization, error, onSubmit, onDeleteOrganization }) => {
5352
const form = useFormik<UpdateOrganizationRequest>({
5453
initialValues: {
5554
name: organization.name,
@@ -87,7 +86,7 @@ export const OrganizationSettingsPageView: FC<
8786
description="The name and description of the organization."
8887
>
8988
<fieldset
90-
disabled={form.isSubmitting || !canEdit}
89+
disabled={form.isSubmitting}
9190
css={{ border: "unset", padding: 0, margin: 0, width: "100%" }}
9291
>
9392
<FormFields>
@@ -119,10 +118,10 @@ export const OrganizationSettingsPageView: FC<
119118
</FormFields>
120119
</fieldset>
121120
</FormSection>
122-
{canEdit && <FormFooter isLoading={form.isSubmitting} />}
121+
<FormFooter isLoading={form.isSubmitting} />
123122
</HorizontalForm>
124123

125-
{canEdit && !organization.is_default && (
124+
{!organization.is_default && (
126125
<HorizontalContainer css={{ marginTop: 48 }}>
127126
<HorizontalSection
128127
title="Settings"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import type { Meta, StoryObj } from "@storybook/react";
2+
import {
3+
MockDefaultOrganization,
4+
MockOrganization,
5+
} from "testHelpers/entities";
6+
import { OrganizationSummaryPageView } from "./OrganizationSummaryPageView";
7+
8+
const meta: Meta<typeof OrganizationSummaryPageView> = {
9+
title: "pages/OrganizationSummaryPageView",
10+
component: OrganizationSummaryPageView,
11+
args: {
12+
organization: MockOrganization,
13+
},
14+
};
15+
16+
export default meta;
17+
type Story = StoryObj<typeof OrganizationSummaryPageView>;
18+
19+
export const DefaultOrg: Story = {
20+
args: {
21+
organization: MockDefaultOrganization,
22+
},
23+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import type { FC } from "react";
2+
import type { Organization } from "api/typesGenerated";
3+
import {
4+
PageHeader,
5+
PageHeaderTitle,
6+
PageHeaderSubtitle,
7+
} from "components/PageHeader/PageHeader";
8+
import { Stack } from "components/Stack/Stack";
9+
import { UserAvatar } from "components/UserAvatar/UserAvatar";
10+
11+
interface OrganizationSummaryPageViewProps {
12+
organization: Organization;
13+
}
14+
15+
export const OrganizationSummaryPageView: FC<
16+
OrganizationSummaryPageViewProps
17+
> = (props) => {
18+
return (
19+
<div>
20+
<PageHeader
21+
css={{
22+
// The deployment settings layout already has padding.
23+
paddingTop: 0,
24+
}}
25+
>
26+
<Stack direction="row" spacing={3} alignItems="center">
27+
<UserAvatar
28+
key={props.organization.id}
29+
size="xl"
30+
username={
31+
props.organization.display_name || props.organization.name
32+
}
33+
avatarURL={props.organization.icon}
34+
/>
35+
<div>
36+
<PageHeaderTitle>
37+
{props.organization.display_name || props.organization.name}
38+
</PageHeaderTitle>
39+
{props.organization.description && (
40+
<PageHeaderSubtitle>
41+
{props.organization.description}
42+
</PageHeaderSubtitle>
43+
)}
44+
</div>
45+
</Stack>
46+
</PageHeader>
47+
You are a member of this organization.
48+
</div>
49+
);
50+
};

0 commit comments

Comments
 (0)