Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/components/dashboard/src/teams/policies/OrgWorkspaceClassesOptions.tsx
2501 views
1
/**
2
* Copyright (c) 2025 Gitpod GmbH. All rights reserved.
3
* Licensed under the GNU Affero General Public License (AGPL).
4
* See License.AGPL.txt in the project root for license information.
5
*/
6
7
import { OrganizationSettings } from "@gitpod/public-api/lib/gitpod/v1/organization_pb";
8
import { Button } from "@podkit/buttons/Button";
9
import { useMutation } from "@tanstack/react-query";
10
import { useState, useMemo } from "react";
11
import { Heading3, Subheading } from "../../components/typography/headings";
12
import {
13
WorkspaceClassesModifyModalProps,
14
WorkspaceClassesOptions,
15
WorkspaceClassesModifyModal,
16
} from "../../components/WorkspaceClassesOptions";
17
import { useAllowedWorkspaceClassesMemo } from "../../data/workspaces/workspace-classes-query";
18
import { ConfigurationSettingsField } from "../../repositories/detail/ConfigurationSettingsField";
19
20
interface OrgWorkspaceClassesOptionsProps {
21
isOwner: boolean;
22
settings?: OrganizationSettings;
23
handleUpdateTeamSettings: (
24
newSettings: Partial<OrganizationSettings>,
25
options?: { throwMutateError?: boolean },
26
) => Promise<void>;
27
}
28
export const OrgWorkspaceClassesOptions = ({
29
isOwner,
30
settings,
31
handleUpdateTeamSettings,
32
}: OrgWorkspaceClassesOptionsProps) => {
33
const [showModal, setShowModal] = useState(false);
34
const { data: allowedClassesInOrganization, isLoading: isLoadingClsInOrg } = useAllowedWorkspaceClassesMemo(
35
undefined,
36
{
37
filterOutDisabled: true,
38
ignoreScope: ["configuration"],
39
},
40
);
41
const { data: allowedClassesInInstallation, isLoading: isLoadingClsInInstall } = useAllowedWorkspaceClassesMemo(
42
undefined,
43
{
44
filterOutDisabled: true,
45
ignoreScope: ["organization", "configuration"],
46
},
47
);
48
49
const restrictedWorkspaceClasses = useMemo(() => {
50
const allowedList = settings?.allowedWorkspaceClasses ?? [];
51
if (allowedList.length === 0) {
52
return [];
53
}
54
return allowedClassesInInstallation.filter((cls) => !allowedList.includes(cls.id)).map((cls) => cls.id);
55
}, [settings?.allowedWorkspaceClasses, allowedClassesInInstallation]);
56
57
const updateMutation: WorkspaceClassesModifyModalProps["updateMutation"] = useMutation({
58
mutationFn: async ({ restrictedWorkspaceClasses }) => {
59
let allowedWorkspaceClasses = allowedClassesInInstallation.map((e) => e.id);
60
if (restrictedWorkspaceClasses.length > 0) {
61
allowedWorkspaceClasses = allowedWorkspaceClasses.filter(
62
(e) => !restrictedWorkspaceClasses.includes(e),
63
);
64
}
65
const allAllowed = allowedClassesInInstallation.every((e) => allowedWorkspaceClasses.includes(e.id));
66
if (allAllowed) {
67
// empty means allow all classes
68
allowedWorkspaceClasses = [];
69
}
70
await handleUpdateTeamSettings({ allowedWorkspaceClasses }, { throwMutateError: true });
71
},
72
});
73
74
return (
75
<ConfigurationSettingsField>
76
<Heading3>Available workspace classes</Heading3>
77
<Subheading>
78
Limit the available workspace classes in your organization. Requires{" "}
79
<span className="font-medium">Owner</span> permissions to change.
80
</Subheading>
81
82
<WorkspaceClassesOptions
83
isLoading={isLoadingClsInOrg}
84
className="mt-4"
85
classes={allowedClassesInOrganization}
86
/>
87
88
{isOwner && (
89
<Button className="mt-6" onClick={() => setShowModal(true)}>
90
Manage Classes
91
</Button>
92
)}
93
94
{showModal && (
95
<WorkspaceClassesModifyModal
96
isLoading={isLoadingClsInInstall}
97
showSetDefaultButton={false}
98
showSwitchTitle={false}
99
restrictedWorkspaceClasses={restrictedWorkspaceClasses}
100
allowedClasses={allowedClassesInInstallation}
101
updateMutation={updateMutation}
102
onClose={() => setShowModal(false)}
103
/>
104
)}
105
</ConfigurationSettingsField>
106
);
107
};
108
109