Skip to content

Commit f3e41f8

Browse files
committed
[public-api] only allow optional in update
1 parent 2e3429a commit f3e41f8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+887
-607
lines changed

components/dashboard/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"version": "0.0.0",
55
"private": true,
66
"dependencies": {
7+
"@bufbuild/protobuf": "^1.3.3",
78
"@connectrpc/connect": "1.1.2",
89
"@connectrpc/connect-web": "1.1.2",
910
"@gitpod/gitpod-protocol": "0.1.5",

components/dashboard/src/components/PrebuildLogs.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,11 @@ export default function PrebuildLogs(props: PrebuildLogsProps) {
6767
// Try get hold of a recent WorkspaceInfo
6868
try {
6969
const request = new GetWorkspaceRequest();
70-
request.id = props.workspaceId;
70+
request.workspaceId = props.workspaceId;
7171
const response = await workspaceClient.getWorkspace(request);
7272
setWorkspace({
73-
instanceId: response.item?.status?.instanceId,
74-
phase: response.item?.status?.phase?.name,
73+
instanceId: response.workspace?.status?.instanceId,
74+
phase: response.workspace?.status?.phase?.name,
7575
});
7676
} catch (err) {
7777
console.error(err);

components/dashboard/src/data/organizations/update-org-settings-mutation.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ import { useMutation } from "@tanstack/react-query";
88
import { useOrgSettingsQueryInvalidator } from "./org-settings-query";
99
import { useCurrentOrg } from "./orgs-query";
1010
import { organizationClient } from "../../service/public-api";
11-
import { OrganizationSettings } from "@gitpod/public-api/lib/gitpod/v1/organization_pb";
11+
import {
12+
OrganizationSettings,
13+
UpdateOrganizationSettingsRequest,
14+
} from "@gitpod/public-api/lib/gitpod/v1/organization_pb";
15+
import { FieldMask } from "@bufbuild/protobuf";
1216

1317
type UpdateOrganizationSettingsArgs = Partial<
1418
Pick<OrganizationSettings, "workspaceSharingDisabled" | "defaultWorkspaceImage">
@@ -17,17 +21,23 @@ type UpdateOrganizationSettingsArgs = Partial<
1721
export const useUpdateOrgSettingsMutation = () => {
1822
const org = useCurrentOrg().data;
1923
const invalidator = useOrgSettingsQueryInvalidator();
20-
const teamId = org?.id || "";
24+
const organizationId = org?.id || "";
2125

2226
return useMutation<OrganizationSettings, Error, UpdateOrganizationSettingsArgs>({
2327
mutationFn: async ({ workspaceSharingDisabled, defaultWorkspaceImage }) => {
24-
const settings = await organizationClient.updateOrganizationSettings({
25-
organizationId: teamId,
26-
settings: {
27-
workspaceSharingDisabled: workspaceSharingDisabled || false,
28-
defaultWorkspaceImage,
29-
},
28+
const request = new UpdateOrganizationSettingsRequest({
29+
organizationId,
30+
workspaceSharingDisabled,
3031
});
32+
defaultWorkspaceImage = defaultWorkspaceImage?.trim();
33+
if (defaultWorkspaceImage) {
34+
request.defaultWorkspaceImage = defaultWorkspaceImage;
35+
} else if (defaultWorkspaceImage === "") {
36+
request.resetMask = new FieldMask({
37+
paths: ["defaultWorkspaceImage"],
38+
});
39+
}
40+
const settings = await organizationClient.updateOrganizationSettings(request);
3141
return settings.settings || new OrganizationSettings();
3242
},
3343
onSuccess: invalidator,

components/dashboard/src/service/json-rpc-organization-client.ts

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import {
3737
} from "@gitpod/public-api/lib/gitpod/v1/organization_pb";
3838
import { getGitpodService } from "./service";
3939
import { converter } from "./public-api";
40+
import { OrganizationSettings } from "@gitpod/gitpod-protocol";
4041

4142
export class JsonRpcOrganizationClient implements PromiseClient<typeof OrganizationService> {
4243
async createOrganization(
@@ -71,7 +72,7 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
7172
options?: CallOptions | undefined,
7273
): Promise<UpdateOrganizationResponse> {
7374
if (!request.organizationId) {
74-
throw new ConnectError("id is required", Code.InvalidArgument);
75+
throw new ConnectError("organizationId is required", Code.InvalidArgument);
7576
}
7677
if (!request.name) {
7778
throw new ConnectError("name is required", Code.InvalidArgument);
@@ -97,7 +98,7 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
9798
options?: CallOptions | undefined,
9899
): Promise<DeleteOrganizationResponse> {
99100
if (!request.organizationId) {
100-
throw new ConnectError("id is required", Code.InvalidArgument);
101+
throw new ConnectError("organizationId is required", Code.InvalidArgument);
101102
}
102103
await getGitpodService().server.deleteTeam(request.organizationId);
103104
return new DeleteOrganizationResponse();
@@ -108,7 +109,7 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
108109
options?: CallOptions | undefined,
109110
): Promise<GetOrganizationInvitationResponse> {
110111
if (!request.organizationId) {
111-
throw new ConnectError("id is required", Code.InvalidArgument);
112+
throw new ConnectError("organizationId is required", Code.InvalidArgument);
112113
}
113114
const result = await getGitpodService().server.getGenericInvite(request.organizationId);
114115
return new GetOrganizationInvitationResponse({
@@ -134,7 +135,7 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
134135
options?: CallOptions | undefined,
135136
): Promise<ResetOrganizationInvitationResponse> {
136137
if (!request.organizationId) {
137-
throw new ConnectError("id is required", Code.InvalidArgument);
138+
throw new ConnectError("organizationId is required", Code.InvalidArgument);
138139
}
139140
const newInvite = await getGitpodService().server.resetGenericInvite(request.organizationId);
140141
return new ResetOrganizationInvitationResponse({
@@ -147,7 +148,7 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
147148
options?: CallOptions | undefined,
148149
): Promise<ListOrganizationMembersResponse> {
149150
if (!request.organizationId) {
150-
throw new ConnectError("id is required", Code.InvalidArgument);
151+
throw new ConnectError("organizationId is required", Code.InvalidArgument);
151152
}
152153
const result = await getGitpodService().server.getTeamMembers(request.organizationId);
153154
return new ListOrganizationMembersResponse({
@@ -160,7 +161,7 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
160161
options?: CallOptions | undefined,
161162
): Promise<UpdateOrganizationMemberResponse> {
162163
if (!request.organizationId) {
163-
throw new ConnectError("id is required", Code.InvalidArgument);
164+
throw new ConnectError("organizationId is required", Code.InvalidArgument);
164165
}
165166
if (!request.userId) {
166167
throw new ConnectError("userId is required", Code.InvalidArgument);
@@ -181,7 +182,7 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
181182
options?: CallOptions | undefined,
182183
): Promise<DeleteOrganizationMemberResponse> {
183184
if (!request.organizationId) {
184-
throw new ConnectError("id is required", Code.InvalidArgument);
185+
throw new ConnectError("organizationId is required", Code.InvalidArgument);
185186
}
186187
if (!request.userId) {
187188
throw new ConnectError("userId is required", Code.InvalidArgument);
@@ -195,7 +196,7 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
195196
options?: CallOptions | undefined,
196197
): Promise<GetOrganizationSettingsResponse> {
197198
if (!request.organizationId) {
198-
throw new ConnectError("id is required", Code.InvalidArgument);
199+
throw new ConnectError("organizationId is required", Code.InvalidArgument);
199200
}
200201
const result = await getGitpodService().server.getOrgSettings(request.organizationId);
201202
return new GetOrganizationSettingsResponse({
@@ -208,12 +209,18 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
208209
options?: CallOptions | undefined,
209210
): Promise<UpdateOrganizationSettingsResponse> {
210211
if (!request.organizationId) {
211-
throw new ConnectError("id is required", Code.InvalidArgument);
212-
}
213-
await getGitpodService().server.updateOrgSettings(request.organizationId, {
214-
workspaceSharingDisabled: request.settings?.workspaceSharingDisabled,
215-
defaultWorkspaceImage: request.settings?.defaultWorkspaceImage,
216-
});
212+
throw new ConnectError("organizationId is required", Code.InvalidArgument);
213+
}
214+
const update: Partial<OrganizationSettings> = {
215+
workspaceSharingDisabled: request?.workspaceSharingDisabled,
216+
};
217+
const resetDefaultWorkspaceImage = request.resetMask?.paths?.includes("defaultWorkspaceImage");
218+
if (resetDefaultWorkspaceImage) {
219+
update.defaultWorkspaceImage = null;
220+
} else if (typeof request?.defaultWorkspaceImage === "string") {
221+
update.defaultWorkspaceImage = request.defaultWorkspaceImage;
222+
}
223+
await getGitpodService().server.updateOrgSettings(request.organizationId, update);
217224
return new UpdateOrganizationSettingsResponse();
218225
}
219226
}

components/dashboard/src/service/json-rpc-workspace-client.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ import { WorkspaceInstance } from "@gitpod/gitpod-protocol";
2020

2121
export class JsonRpcWorkspaceClient implements PromiseClient<typeof WorkspaceService> {
2222
async getWorkspace(request: PartialMessage<GetWorkspaceRequest>): Promise<GetWorkspaceResponse> {
23-
if (!request.id) {
23+
if (!request.workspaceId) {
2424
throw new ConnectError("id is required", Code.InvalidArgument);
2525
}
26-
const info = await getGitpodService().server.getWorkspace(request.id);
26+
const info = await getGitpodService().server.getWorkspace(request.workspaceId);
2727
const workspace = converter.toWorkspace(info);
2828
const result = new GetWorkspaceResponse();
29-
result.item = workspace;
29+
result.workspace = workspace;
3030
return result;
3131
}
3232

@@ -38,11 +38,11 @@ export class JsonRpcWorkspaceClient implements PromiseClient<typeof WorkspaceSer
3838
throw new ConnectError("signal is required", Code.InvalidArgument);
3939
}
4040
if (request.workspaceId) {
41-
const resp = await this.getWorkspace({ id: request.workspaceId });
42-
if (resp.item?.status) {
41+
const resp = await this.getWorkspace({ workspaceId: request.workspaceId });
42+
if (resp.workspace?.status) {
4343
const response = new WatchWorkspaceStatusResponse();
44-
response.workspaceId = resp.item.id;
45-
response.status = resp.item.status;
44+
response.workspaceId = resp.workspace.id;
45+
response.status = resp.workspace.status;
4646
yield response;
4747
}
4848
}

components/dashboard/src/start/StartWorkspace.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -272,14 +272,14 @@ export default class StartWorkspace extends React.Component<StartWorkspaceProps,
272272
const { workspaceId } = this.props;
273273
try {
274274
const request = new GetWorkspaceRequest();
275-
request.id = workspaceId;
275+
request.workspaceId = workspaceId;
276276
const response = await workspaceClient.getWorkspace(request);
277-
if (response.item?.status?.instanceId) {
277+
if (response.workspace?.status?.instanceId) {
278278
this.setState((s) => ({
279-
workspace: response.item,
280-
startedInstanceId: s.startedInstanceId || response.item?.status?.instanceId, // note: here's a potential mismatch between startedInstanceId and instance.id. TODO(gpl) How to handle this?
279+
workspace: response.workspace,
280+
startedInstanceId: s.startedInstanceId || response.workspace?.status?.instanceId, // note: here's a potential mismatch between startedInstanceId and instance.id. TODO(gpl) How to handle this?
281281
}));
282-
this.onWorkspaceUpdate(response.item);
282+
this.onWorkspaceUpdate(response.workspace);
283283
}
284284
} catch (error) {
285285
console.error(error);

components/gitpod-db/src/team-db.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export interface TeamDB extends TransactionalDB<TeamDB> {
4040
deleteTeam(teamId: string): Promise<void>;
4141

4242
findOrgSettings(teamId: string): Promise<OrganizationSettings | undefined>;
43-
setOrgSettings(teamId: string, settings: Partial<OrganizationSettings>): Promise<void>;
43+
setOrgSettings(teamId: string, settings: Partial<OrganizationSettings>): Promise<OrganizationSettings>;
4444

4545
hasActiveSSO(organizationId: string): Promise<boolean>;
4646
}

components/gitpod-db/src/typeorm/team-db-impl.ts

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -366,28 +366,19 @@ export class TeamDBImpl extends TransactionalDBImpl<TeamDB> implements TeamDB {
366366
});
367367
}
368368

369-
public async setOrgSettings(orgId: string, settings: Partial<OrganizationSettings>): Promise<void> {
369+
public async setOrgSettings(orgId: string, settings: Partial<OrganizationSettings>): Promise<OrganizationSettings> {
370370
const repo = await this.getOrgSettingsRepo();
371371
const team = await repo.findOne({ where: { orgId, deleted: false } });
372-
const update: Partial<OrganizationSettings> = {
373-
defaultWorkspaceImage: settings.defaultWorkspaceImage,
374-
workspaceSharingDisabled: settings.workspaceSharingDisabled,
375-
};
376-
// Set to null if defaultWorkspaceImage is empty string, so that it can fallback to default image
377-
if (update.defaultWorkspaceImage?.trim() === "") {
378-
update.defaultWorkspaceImage = null;
379-
}
380372
if (!team) {
381-
await repo.insert({
382-
...update,
373+
return await repo.save({
374+
...settings,
383375
orgId,
384376
});
385-
} else {
386-
await repo.save({
387-
...team,
388-
...update,
389-
});
390377
}
378+
return await repo.save({
379+
...team,
380+
...settings,
381+
});
391382
}
392383

393384
public async hasActiveSSO(organizationId: string): Promise<boolean> {

components/gitpod-protocol/src/public-api-converter.spec.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ describe("PublicAPIConverter", () => {
233233
},
234234
additionalEnvironmentVariables: [],
235235
region: "dev",
236+
prebuildId: "",
236237
workspaceClass: "g1-standard",
237238
editor: {
238239
name: "code",
@@ -362,6 +363,7 @@ describe("PublicAPIConverter", () => {
362363
},
363364
additionalEnvironmentVariables: [],
364365
region: "dev",
366+
prebuildId: "",
365367
workspaceClass: "g1-standard",
366368
editor: {
367369
name: "code",
@@ -502,6 +504,7 @@ describe("PublicAPIConverter", () => {
502504
},
503505
additionalEnvironmentVariables: [],
504506
region: "dev",
507+
prebuildId: "",
505508
workspaceClass: "g1-standard",
506509
editor: {
507510
name: "code",
@@ -617,6 +620,7 @@ describe("PublicAPIConverter", () => {
617620
},
618621
additionalEnvironmentVariables: [],
619622
region: "dev",
623+
prebuildId: "",
620624
workspaceClass: "g1-standard",
621625
editor: {
622626
name: "code",

components/gitpod-protocol/src/public-api-converter.ts

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -129,23 +129,27 @@ export class PublicAPIConverter {
129129
phase.lastTransitionTime = Timestamp.fromDate(new Date(lastTransitionTime));
130130

131131
status.instanceId = arg.id;
132-
status.message = arg.status.message;
132+
if (arg.status.message) {
133+
status.message = arg.status.message;
134+
}
133135
status.workspaceUrl = arg.ideUrl;
134136
status.ports = this.toPorts(arg.status.exposedPorts);
135137
status.conditions = this.toWorkspaceConditions(arg.status.conditions);
136138
status.gitStatus = this.toGitStatus(arg, status.gitStatus);
137139
workspace.region = arg.region;
138-
workspace.workspaceClass = arg.workspaceClass;
140+
if (arg.workspaceClass) {
141+
workspace.workspaceClass = arg.workspaceClass;
142+
}
139143
workspace.editor = this.toEditor(arg.configuration.ideConfig);
140144

141145
return workspace;
142146
}
143147

144148
toWorkspaceConditions(conditions: WorkspaceInstanceConditions): WorkspaceConditions {
145-
const result = new WorkspaceConditions();
146-
result.failed = conditions.failed;
147-
result.timeout = conditions.timeout;
148-
return result;
149+
return new WorkspaceConditions({
150+
failed: conditions.failed,
151+
timeout: conditions.timeout,
152+
});
149153
}
150154

151155
toEditor(ideConfig: ConfigurationIdeConfig | undefined): EditorReference | undefined {
@@ -345,15 +349,15 @@ export class PublicAPIConverter {
345349
}
346350

347351
toOrganizationMember(member: OrgMemberInfo): OrganizationMember {
348-
const result = new OrganizationMember();
349-
result.userId = member.userId;
350-
result.fullName = member.fullName;
351-
result.email = member.primaryEmail;
352-
result.avatarUrl = member.avatarUrl;
353-
result.role = this.toOrgMemberRole(member.role);
354-
result.memberSince = Timestamp.fromDate(new Date(member.memberSince));
355-
result.ownedByOrganization = member.ownedByOrganization;
356-
return result;
352+
return new OrganizationMember({
353+
userId: member.userId,
354+
fullName: member.fullName,
355+
email: member.primaryEmail,
356+
avatarUrl: member.avatarUrl,
357+
role: this.toOrgMemberRole(member.role),
358+
memberSince: Timestamp.fromDate(new Date(member.memberSince)),
359+
ownedByOrganization: member.ownedByOrganization,
360+
});
357361
}
358362

359363
toOrgMemberRole(role: OrgMemberRole): OrganizationRole {
@@ -379,10 +383,10 @@ export class PublicAPIConverter {
379383
}
380384

381385
toOrganizationSettings(settings: OrganizationSettingsProtocol): OrganizationSettings {
382-
const result = new OrganizationSettings();
383-
result.workspaceSharingDisabled = !!settings.workspaceSharingDisabled;
384-
result.defaultWorkspaceImage = settings.defaultWorkspaceImage || undefined;
385-
return result;
386+
return new OrganizationSettings({
387+
workspaceSharingDisabled: !!settings.workspaceSharingDisabled,
388+
defaultWorkspaceImage: settings.defaultWorkspaceImage || undefined,
389+
});
386390
}
387391

388392
toConfiguration(project: Project): Configuration {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ export interface Organization {
195195

196196
export interface OrganizationSettings {
197197
workspaceSharingDisabled?: boolean;
198+
// null to reset to default
198199
defaultWorkspaceImage?: string | null;
199200
}
200201

components/public-api/buf.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ breaking:
55
ignore:
66
# Do not enforce breaking change detection for the experimental package
77
- gitpod/experimental
8+
# TODO enable again after landing style changes
9+
- gitpod/v1
810
lint:
911
use:
1012
- DEFAULT

0 commit comments

Comments
 (0)