Skip to content

Commit 99b0b71

Browse files
committed
Backend iteration
Tool: gitpod/catfood.gitpod.cloud
1 parent 3c62068 commit 99b0b71

File tree

9 files changed

+2526
-704
lines changed

9 files changed

+2526
-704
lines changed

components/dashboard/src/teams/TeamOnboarding.tsx

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import { OrganizationSettings } from "@gitpod/public-api/lib/gitpod/v1/organization_pb";
88
import { FormEvent, useCallback, useEffect, useState } from "react";
99
import { Heading2, Heading3, Subheading } from "../components/typography/headings";
10-
import { useIsOwner } from "../data/organizations/members-query";
10+
import { useIsOwner, useListOrganizationMembers } from "../data/organizations/members-query";
1111
import { useOrgSettingsQuery } from "../data/organizations/org-settings-query";
1212
import { useCurrentOrg } from "../data/organizations/orgs-query";
1313
import { useUpdateOrgSettingsMutation } from "../data/organizations/update-org-settings-mutation";
@@ -24,6 +24,7 @@ import { Textarea } from "@podkit/forms/TextArea";
2424
import Modal, { ModalFooter, ModalBody, ModalHeader } from "../components/Modal";
2525
import { Button } from "@podkit/buttons/Button";
2626
import { SwitchInputField } from "@podkit/switch/Switch";
27+
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@podkit/select/Select";
2728

2829
const sampleMarkdown = `“With Gitpod, you'll boost your productivity and streamline your workflow, giving you the freedom to work how you want while helping our team meet its efficiency goals.”
2930
@@ -43,6 +44,7 @@ export default function TeamOnboardingPage() {
4344
const [welcomeMessage, setWelcomeMessage] = useState<string>(sampleMarkdown);
4445
const [showWelcomeMessage, setShowWelcomeMessage] = useState<boolean>(true);
4546
const [welcomeMessageEditorOpen, setWelcomeMessageEditorOpen] = useState<boolean>(false);
47+
const [avatarURL, setAvatarURL] = useState<string | undefined>(undefined);
4648
const handleUpdateTeamSettings = useCallback(
4749
async (newSettings: Partial<PlainMessage<OrganizationSettings>>, options?: { throwMutateError?: boolean }) => {
4850
if (!org?.id) {
@@ -125,6 +127,7 @@ export default function TeamOnboardingPage() {
125127
<WelcomeMessagePreview
126128
welcomeMessage={welcomeMessage}
127129
setWelcomeMessageEditorOpen={setWelcomeMessageEditorOpen}
130+
avatarURL={avatarURL}
128131
/>
129132

130133
<Modal onClose={() => setWelcomeMessageEditorOpen(false)} visible={welcomeMessageEditorOpen}>
@@ -143,6 +146,12 @@ export default function TeamOnboardingPage() {
143146
label=""
144147
/>
145148
</InputField>
149+
150+
<OrgMemberSelect
151+
avatarURL={avatarURL}
152+
setAvatarURL={setAvatarURL}
153+
disabled={!showWelcomeMessage}
154+
/>
146155
<WelcomeMessageEditor
147156
welcomeMessage={welcomeMessage}
148157
setWelcomeMessage={setWelcomeMessage}
@@ -166,9 +175,14 @@ export default function TeamOnboardingPage() {
166175

167176
type WelcomeMessagePreviewProps = {
168177
welcomeMessage: string;
178+
avatarURL: string | undefined;
169179
setWelcomeMessageEditorOpen: (open: boolean) => void;
170180
};
171-
const WelcomeMessagePreview = ({ welcomeMessage, setWelcomeMessageEditorOpen }: WelcomeMessagePreviewProps) => {
181+
const WelcomeMessagePreview = ({
182+
welcomeMessage,
183+
avatarURL,
184+
setWelcomeMessageEditorOpen,
185+
}: WelcomeMessagePreviewProps) => {
172186
return (
173187
<div className="max-w-2xl mx-auto">
174188
<div className="flex justify-between gap-2 items-center">
@@ -182,10 +196,13 @@ const WelcomeMessagePreview = ({ welcomeMessage, setWelcomeMessageEditorOpen }:
182196
worrying about vulnerabilities impacting their local machines.
183197
</Subheading>
184198
{/* todo: sanitize md */}
185-
<MDEditor.Markdown
186-
source={welcomeMessage}
187-
className="md-preview space-y-4 p-8 my-4 bg-pk-surface-secondary text-pk-content-primary rounded-xl text-center"
188-
/>
199+
<div className="p-8 my-4 bg-pk-surface-secondary text-pk-content-primary rounded-xl flex flex-col gap-5 items-center justify-center">
200+
<img src={avatarURL} alt="" className="w-12 h-12 rounded-full" />
201+
<MDEditor.Markdown
202+
source={welcomeMessage}
203+
className="md-preview space-y-4 text-center bg-pk-surface-secondary"
204+
/>
205+
</div>
189206
</div>
190207
);
191208
};
@@ -208,3 +225,41 @@ const WelcomeMessageEditor = ({ welcomeMessage, setWelcomeMessage, disabled }: W
208225
</InputField>
209226
);
210227
};
228+
229+
type OrgMemberSelectProps = {
230+
avatarURL: string | undefined;
231+
setAvatarURL: (avatarURL: string | undefined) => void;
232+
disabled?: boolean;
233+
};
234+
const OrgMemberSelect = ({ avatarURL, setAvatarURL, disabled }: OrgMemberSelectProps) => {
235+
const { data: members } = useListOrganizationMembers();
236+
237+
return (
238+
<InputField label="Show an avatar on the welcome message" error={undefined} className="mb-4">
239+
<Select value={avatarURL} onValueChange={setAvatarURL} disabled={disabled}>
240+
<SelectTrigger>
241+
<SelectValue placeholder="No member" />
242+
</SelectTrigger>
243+
<SelectContent>
244+
<SelectGroup>
245+
<SelectItem value="disabled">No member</SelectItem>
246+
</SelectGroup>
247+
<SelectGroup>
248+
{members?.map((member) => (
249+
<SelectItem key={member.userId} value={member.avatarUrl || member.userId}>
250+
<div className="flex items-center gap-2">
251+
<img
252+
src={member.avatarUrl}
253+
className="w-4 h-4 rounded-full"
254+
alt={member.fullName}
255+
/>
256+
{member.fullName}
257+
</div>
258+
</SelectItem>
259+
))}
260+
</SelectGroup>
261+
</SelectContent>
262+
</Select>
263+
</InputField>
264+
);
265+
};

components/gitpod-protocol/src/teams-projects-protocol.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,15 @@ export interface OnboardingSettings {
271271
* the link to an internal onboarding page for the organization, possibly featuring a custom onboarding guide and other resources
272272
*/
273273
internalLink?: string;
274+
275+
/**
276+
* the welcome message for new members of the organization
277+
*/
278+
welcomeMessage?: {
279+
featuredMemberId?: string;
280+
message: string;
281+
footer?: string;
282+
};
274283
}
275284

276285
export type TeamMemberInfo = OrgMemberInfo;

components/public-api/gitpod/v1/organization.proto

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,28 @@ message RoleRestrictionEntry {
4949
}
5050

5151
message OnboardingSettings {
52+
message WelcomeMessage {
53+
// enabled specifies whether the welcome message is enabled
54+
bool enabled = 1;
55+
56+
// message is the welcome message for the organization
57+
string message = 2;
58+
59+
// footer is the footer message for the welcome message
60+
string footer = 3;
61+
62+
// featured_member_id is the ID of the member to show in the welcome message
63+
string featured_member_id = 4;
64+
65+
// featured_member_resolved_avatar_url is the avatar URL that is resolved from the featured_member_id by the server. Do not set this field manually.
66+
string featured_member_resolved_avatar_url = 5;
67+
}
68+
5269
// internal_link is the link to an internal onboarding page for the organization, possibly featuring a custom onboarding guide and other resources
5370
optional string internal_link = 1;
71+
72+
// welcome_message is the welcome message for the organization
73+
optional WelcomeMessage welcome_message = 3;
5474
}
5575

5676
message OrganizationSettings {

0 commit comments

Comments
 (0)