Skip to content

Commit 59bfc3e

Browse files
committed
Add permission check for Insights page and don't show it in the menu for non-owners
Tool: gitpod/catfood.gitpod.cloud
1 parent 10c49da commit 59bfc3e

File tree

2 files changed

+24
-13
lines changed

2 files changed

+24
-13
lines changed

components/dashboard/src/Insights.tsx

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { DownloadIcon } from "lucide-react";
2727
import { Button } from "@podkit/buttons/Button";
2828
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from "@podkit/dropdown/DropDown";
2929
import { useInstallationConfiguration } from "./data/installation/installation-config-query";
30+
import { ApplicationError, ErrorCodes } from "@gitpod/gitpod-protocol/lib/messaging/error";
3031

3132
export const Insights = () => {
3233
const toDate = useMemo(() => Timestamp.fromDate(new Date()), []);
@@ -49,6 +50,9 @@ export const Insights = () => {
4950
const grouped = Object.groupBy(sessions, (ws) => ws.workspace?.id ?? "unknown");
5051
const [page, setPage] = useState(0);
5152

53+
const isLackingPermissions =
54+
errorMessage instanceof ApplicationError && errorMessage.code === ErrorCodes.PERMISSION_DENIED;
55+
5256
return (
5357
<>
5458
<Header title="Insights" subtitle="Insights into workspace sessions in your organization" />
@@ -59,7 +63,7 @@ export const Insights = () => {
5963
"md:flex-row md:items-center md:space-x-4 md:space-y-0",
6064
)}
6165
>
62-
<DownloadUsage to={toDate} />
66+
<DownloadUsage to={toDate} disabled={isLackingPermissions} />
6367
</div>
6468

6569
<div
@@ -71,7 +75,11 @@ export const Insights = () => {
7175

7276
{errorMessage && (
7377
<Alert type="error" className="mt-4">
74-
{errorMessage instanceof Error ? errorMessage.message : "An error occurred."}
78+
{isLackingPermissions
79+
? "You don't have permission to access this organization's insights."
80+
: errorMessage instanceof Error
81+
? errorMessage.message
82+
: "An error occurred."}
7583
</Alert>
7684
)}
7785

@@ -151,8 +159,9 @@ export const Insights = () => {
151159

152160
type DownloadUsageProps = {
153161
to: Timestamp;
162+
disabled?: boolean;
154163
};
155-
export const DownloadUsage = ({ to }: DownloadUsageProps) => {
164+
export const DownloadUsage = ({ to, disabled }: DownloadUsageProps) => {
156165
const { data: org } = useCurrentOrg();
157166
const { toast } = useToast();
158167
// When we start the download, we disable the button for a short time
@@ -184,7 +193,7 @@ export const DownloadUsage = ({ to }: DownloadUsageProps) => {
184193
return (
185194
<DropdownMenu>
186195
<DropdownMenuTrigger asChild>
187-
<Button variant="secondary" className="gap-1" disabled={downloadDisabled}>
196+
<Button variant="secondary" className="gap-1" disabled={disabled ?? downloadDisabled}>
188197
<DownloadIcon strokeWidth={3} className="w-4" />
189198
<span>Export as CSV</span>
190199
</Button>

components/dashboard/src/menu/OrganizationSelector.tsx

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export default function OrganizationSelector() {
2323
const orgs = useOrganizations();
2424
const currentOrg = useCurrentOrg();
2525
const members = useListOrganizationMembers().data ?? [];
26-
const owner = useIsOwner();
26+
const isOwner = useIsOwner();
2727
const hasMemberPermission = useHasRolePermission(OrganizationRole.MEMBER);
2828
const { data: billingMode } = useOrgBillingMode();
2929
const getOrgURL = useGetOrgURL();
@@ -78,13 +78,15 @@ export default function OrganizationSelector() {
7878
link: "/members",
7979
});
8080
if (isDedicated) {
81-
linkEntries.push({
82-
title: "Insights",
83-
customContent: <LinkEntry>Insights</LinkEntry>,
84-
active: false,
85-
separator: false,
86-
link: "/insights",
87-
});
81+
if (isOwner) {
82+
linkEntries.push({
83+
title: "Insights",
84+
customContent: <LinkEntry>Insights</LinkEntry>,
85+
active: false,
86+
separator: false,
87+
link: "/insights",
88+
});
89+
}
8890
} else {
8991
linkEntries.push({
9092
title: "Usage",
@@ -95,7 +97,7 @@ export default function OrganizationSelector() {
9597
});
9698
}
9799
// Show billing if user is an owner of current org
98-
if (owner) {
100+
if (isOwner) {
99101
if (billingMode?.mode === "usage-based") {
100102
linkEntries.push({
101103
title: "Billing",

0 commit comments

Comments
 (0)