Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/components/dashboard/src/teams/TeamOnboarding.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 { FormEvent, useCallback, useEffect, useState } from "react";
8
import { Heading2, Heading3, Subheading } from "../components/typography/headings";
9
import { useIsOwner } from "../data/organizations/members-query";
10
import { useOrgSettingsQuery } from "../data/organizations/org-settings-query";
11
import { useCurrentOrg } from "../data/organizations/orgs-query";
12
import {
13
UpdateOrganizationSettingsArgs,
14
useUpdateOrgSettingsMutation,
15
} from "../data/organizations/update-org-settings-mutation";
16
import { OrgSettingsPage } from "./OrgSettingsPage";
17
import { ConfigurationSettingsField } from "../repositories/detail/ConfigurationSettingsField";
18
import { useDocumentTitle } from "../hooks/use-document-title";
19
import { useToast } from "../components/toasts/Toasts";
20
import { InputField } from "../components/forms/InputField";
21
import { TextInput } from "../components/forms/TextInputField";
22
import { LoadingButton } from "@podkit/buttons/LoadingButton";
23
import { Link } from "react-router-dom";
24
import { useOrgSuggestedRepos } from "../data/organizations/suggested-repositories-query";
25
import { RepositoryListItem } from "../repositories/list/RepoListItem";
26
import { LoadingState } from "@podkit/loading/LoadingState";
27
import { Table, TableHeader, TableRow, TableHead, TableBody } from "@podkit/tables/Table";
28
import { WelcomeMessageConfigurationField } from "./onboarding/WelcomeMessageConfigurationField";
29
30
export type UpdateTeamSettingsOptions = {
31
throwMutateError?: boolean;
32
};
33
34
export default function TeamOnboardingPage() {
35
useDocumentTitle("Organization Settings - Onboarding");
36
const { toast } = useToast();
37
const { data: org } = useCurrentOrg();
38
const isOwner = useIsOwner();
39
40
const { data: settings } = useOrgSettingsQuery();
41
const updateTeamSettings = useUpdateOrgSettingsMutation();
42
43
const { data: suggestedRepos, isLoading: isLoadingSuggestedRepos } = useOrgSuggestedRepos();
44
45
const [internalLink, setInternalLink] = useState<string | undefined>(undefined);
46
47
const handleUpdateTeamSettings = useCallback(
48
async (newSettings: UpdateOrganizationSettingsArgs, options?: UpdateTeamSettingsOptions) => {
49
if (!org?.id) {
50
throw new Error("no organization selected");
51
}
52
if (!isOwner) {
53
throw new Error("no organization settings change permission");
54
}
55
try {
56
await updateTeamSettings.mutateAsync(newSettings);
57
toast("Organization settings updated");
58
} catch (error) {
59
if (options?.throwMutateError) {
60
throw error;
61
}
62
toast(`Failed to update organization settings: ${error.message}`);
63
console.error(error);
64
}
65
},
66
[updateTeamSettings, org?.id, isOwner, toast],
67
);
68
69
const handleUpdateInternalLink = useCallback(
70
async (e: FormEvent) => {
71
e.preventDefault();
72
73
await handleUpdateTeamSettings({
74
onboardingSettings: {
75
internalLink,
76
},
77
});
78
},
79
[handleUpdateTeamSettings, internalLink],
80
);
81
82
useEffect(() => {
83
if (settings) {
84
setInternalLink(settings.onboardingSettings?.internalLink);
85
}
86
}, [settings]);
87
88
return (
89
<OrgSettingsPage>
90
<div className="space-y-8">
91
<div>
92
<Heading2>Onboarding</Heading2>
93
<Subheading>Customize the onboarding experience for your organization members.</Subheading>
94
</div>
95
<ConfigurationSettingsField>
96
<Heading3>Internal landing page</Heading3>
97
<Subheading>
98
The link to your internal landing page. This link will be shown to your organization members
99
during the onboarding process. You can disable showing a link by leaving this field empty.
100
</Subheading>
101
<form onSubmit={handleUpdateInternalLink}>
102
<InputField label="Internal landing page link" error={undefined} className="mb-4">
103
<TextInput
104
value={internalLink}
105
type="url"
106
placeholder="https://en.wikipedia.org/wiki/Heisenbug"
107
onChange={setInternalLink}
108
disabled={updateTeamSettings.isLoading || !isOwner}
109
/>
110
</InputField>
111
<LoadingButton type="submit" loading={updateTeamSettings.isLoading} disabled={!isOwner}>
112
Save
113
</LoadingButton>
114
</form>
115
</ConfigurationSettingsField>
116
117
<ConfigurationSettingsField>
118
<Heading3>Suggested repositories</Heading3>
119
<Subheading>
120
A list of repositories suggested to new organization members. You can toggle a repository's
121
visibility in the onboarding process by visiting the{" "}
122
<Link to="/repositories" className="gp-link">
123
Repository settings
124
</Link>{" "}
125
page and toggling the "Mark this repository as Suggested" setting under the details of the
126
repository.
127
</Subheading>
128
{(suggestedRepos ?? []).length > 0 && (
129
<Table className="mt-4">
130
<TableHeader>
131
<TableRow>
132
<TableHead className="w-52">Name</TableHead>
133
<TableHead hideOnSmallScreen>Repository</TableHead>
134
<TableHead className="w-32" hideOnSmallScreen>
135
Created
136
</TableHead>
137
<TableHead className="w-24" hideOnSmallScreen>
138
Prebuilds
139
</TableHead>
140
{/* Action column, loading status in header */}
141
<TableHead className="w-24 text-right">
142
{isLoadingSuggestedRepos && (
143
<div className="flex flex-right justify-end items-center">
144
<LoadingState delay={false} size={16} />
145
</div>
146
)}
147
</TableHead>
148
</TableRow>
149
</TableHeader>
150
<TableBody>
151
{suggestedRepos?.map((repo) => (
152
<RepositoryListItem
153
key={repo.configurationId}
154
configuration={repo.configuration}
155
isSuggested={true}
156
/>
157
))}
158
</TableBody>
159
</Table>
160
)}
161
</ConfigurationSettingsField>
162
163
<WelcomeMessageConfigurationField handleUpdateTeamSettings={handleUpdateTeamSettings} />
164
</div>
165
</OrgSettingsPage>
166
);
167
}
168
169