Skip to content

Commit 6af5924

Browse files
committed
[public-api] align with API guidelines
1 parent 2e3429a commit 6af5924

31 files changed

+937
-764
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-mutation.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
* See License.AGPL.txt in the project root for license information.
55
*/
66

7-
import { Organization } from "@gitpod/gitpod-protocol";
87
import { useMutation } from "@tanstack/react-query";
9-
import { getGitpodService } from "../../service/service";
108
import { useCurrentOrg, useOrganizationsInvalidator } from "./orgs-query";
9+
import { organizationClient } from "../../service/public-api";
10+
import { Organization } from "@gitpod/public-api/lib/gitpod/v1/organization_pb";
1111

1212
type UpdateOrgArgs = Pick<Organization, "name">;
1313

@@ -21,7 +21,11 @@ export const useUpdateOrgMutation = () => {
2121
throw new Error("No current organization selected");
2222
}
2323

24-
return await getGitpodService().server.updateTeam(org.id, { name });
24+
const response = await organizationClient.updateOrganization({
25+
organizationId: org.id,
26+
name,
27+
});
28+
return response.organization!;
2529
},
2630
onSuccess(updatedOrg) {
2731
// TODO: Update query cache with new org prior to invalidation so it's reflected immediately

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,10 @@ export const useUpdateOrgSettingsMutation = () => {
2323
mutationFn: async ({ workspaceSharingDisabled, defaultWorkspaceImage }) => {
2424
const settings = await organizationClient.updateOrganizationSettings({
2525
organizationId: teamId,
26-
settings: {
27-
workspaceSharingDisabled: workspaceSharingDisabled || false,
28-
defaultWorkspaceImage,
29-
},
26+
workspaceSharingDisabled: workspaceSharingDisabled || false,
27+
defaultWorkspaceImage,
3028
});
31-
return settings.settings || new OrganizationSettings();
29+
return settings.settings!;
3230
},
3331
onSuccess: invalidator,
3432
});

components/dashboard/src/data/setup.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import * as ConfigurationClasses from "@gitpod/public-api/lib/gitpod/v1/configur
2525
// This is used to version the cache
2626
// If data we cache changes in a non-backwards compatible way, increment this version
2727
// That will bust any previous cache versions a client may have stored
28-
const CACHE_VERSION = "2";
28+
const CACHE_VERSION = "3";
2929

3030
export function noPersistence(queryKey: QueryKey): QueryKey {
3131
return [...queryKey, "no-persistence"];

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

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
7171
options?: CallOptions | undefined,
7272
): Promise<UpdateOrganizationResponse> {
7373
if (!request.organizationId) {
74-
throw new ConnectError("id is required", Code.InvalidArgument);
74+
throw new ConnectError("organizationId is required", Code.InvalidArgument);
7575
}
7676
if (!request.name) {
7777
throw new ConnectError("name is required", Code.InvalidArgument);
@@ -97,7 +97,7 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
9797
options?: CallOptions | undefined,
9898
): Promise<DeleteOrganizationResponse> {
9999
if (!request.organizationId) {
100-
throw new ConnectError("id is required", Code.InvalidArgument);
100+
throw new ConnectError("organizationId is required", Code.InvalidArgument);
101101
}
102102
await getGitpodService().server.deleteTeam(request.organizationId);
103103
return new DeleteOrganizationResponse();
@@ -108,7 +108,7 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
108108
options?: CallOptions | undefined,
109109
): Promise<GetOrganizationInvitationResponse> {
110110
if (!request.organizationId) {
111-
throw new ConnectError("id is required", Code.InvalidArgument);
111+
throw new ConnectError("organizationId is required", Code.InvalidArgument);
112112
}
113113
const result = await getGitpodService().server.getGenericInvite(request.organizationId);
114114
return new GetOrganizationInvitationResponse({
@@ -134,7 +134,7 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
134134
options?: CallOptions | undefined,
135135
): Promise<ResetOrganizationInvitationResponse> {
136136
if (!request.organizationId) {
137-
throw new ConnectError("id is required", Code.InvalidArgument);
137+
throw new ConnectError("organizationId is required", Code.InvalidArgument);
138138
}
139139
const newInvite = await getGitpodService().server.resetGenericInvite(request.organizationId);
140140
return new ResetOrganizationInvitationResponse({
@@ -147,7 +147,7 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
147147
options?: CallOptions | undefined,
148148
): Promise<ListOrganizationMembersResponse> {
149149
if (!request.organizationId) {
150-
throw new ConnectError("id is required", Code.InvalidArgument);
150+
throw new ConnectError("organizationId is required", Code.InvalidArgument);
151151
}
152152
const result = await getGitpodService().server.getTeamMembers(request.organizationId);
153153
return new ListOrganizationMembersResponse({
@@ -160,7 +160,7 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
160160
options?: CallOptions | undefined,
161161
): Promise<UpdateOrganizationMemberResponse> {
162162
if (!request.organizationId) {
163-
throw new ConnectError("id is required", Code.InvalidArgument);
163+
throw new ConnectError("organizationId is required", Code.InvalidArgument);
164164
}
165165
if (!request.userId) {
166166
throw new ConnectError("userId is required", Code.InvalidArgument);
@@ -181,7 +181,7 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
181181
options?: CallOptions | undefined,
182182
): Promise<DeleteOrganizationMemberResponse> {
183183
if (!request.organizationId) {
184-
throw new ConnectError("id is required", Code.InvalidArgument);
184+
throw new ConnectError("organizationId is required", Code.InvalidArgument);
185185
}
186186
if (!request.userId) {
187187
throw new ConnectError("userId is required", Code.InvalidArgument);
@@ -195,7 +195,7 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
195195
options?: CallOptions | undefined,
196196
): Promise<GetOrganizationSettingsResponse> {
197197
if (!request.organizationId) {
198-
throw new ConnectError("id is required", Code.InvalidArgument);
198+
throw new ConnectError("organizationId is required", Code.InvalidArgument);
199199
}
200200
const result = await getGitpodService().server.getOrgSettings(request.organizationId);
201201
return new GetOrganizationSettingsResponse({
@@ -208,11 +208,11 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
208208
options?: CallOptions | undefined,
209209
): Promise<UpdateOrganizationSettingsResponse> {
210210
if (!request.organizationId) {
211-
throw new ConnectError("id is required", Code.InvalidArgument);
211+
throw new ConnectError("organizationId is required", Code.InvalidArgument);
212212
}
213213
await getGitpodService().server.updateOrgSettings(request.organizationId, {
214-
workspaceSharingDisabled: request.settings?.workspaceSharingDisabled,
215-
defaultWorkspaceImage: request.settings?.defaultWorkspaceImage,
214+
workspaceSharingDisabled: request?.workspaceSharingDisabled,
215+
defaultWorkspaceImage: request?.defaultWorkspaceImage,
216216
});
217217
return new UpdateOrganizationSettingsResponse();
218218
}

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

Lines changed: 8 additions & 8 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) {
24-
throw new ConnectError("id is required", Code.InvalidArgument);
23+
if (!request.workspaceId) {
24+
throw new ConnectError("workspaceId 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/dashboard/src/teams/TeamSettings.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { organizationClient } from "../service/public-api";
2727
import { gitpodHostUrl } from "../service/service";
2828
import { useCurrentUser } from "../user-context";
2929
import { OrgSettingsPage } from "./OrgSettingsPage";
30+
import { ErrorCode } from "@gitpod/gitpod-protocol/lib/messaging/error";
3031

3132
export default function TeamSettingsPage() {
3233
const user = useCurrentUser();
@@ -204,7 +205,6 @@ function OrgSettingsForm(props: { org?: Organization; isOwner: boolean }) {
204205
<form
205206
onSubmit={(e) => {
206207
e.preventDefault();
207-
// handleUpdateTeamSettings({ defaultWorkspaceImage });
208208
}}
209209
>
210210
{props.org && (
@@ -282,7 +282,7 @@ function WorkspaceImageButton(props: {
282282
};
283283
}
284284

285-
const image = props.settings?.defaultWorkspaceImage ?? props.defaultWorkspaceImage ?? "";
285+
const image = props.settings?.defaultWorkspaceImage || props.defaultWorkspaceImage || "";
286286

287287
const descList = useMemo(() => {
288288
const arr: ReactNode[] = [<span>Default image</span>];
@@ -348,7 +348,7 @@ interface OrgDefaultWorkspaceImageModalProps {
348348

349349
function OrgDefaultWorkspaceImageModal(props: OrgDefaultWorkspaceImageModalProps) {
350350
const [errorMsg, setErrorMsg] = useState("");
351-
const [defaultWorkspaceImage, setDefaultWorkspaceImage] = useState(props.settings?.defaultWorkspaceImage ?? "");
351+
const [defaultWorkspaceImage, setDefaultWorkspaceImage] = useState(props.settings?.defaultWorkspaceImage || "");
352352
const updateTeamSettings = useUpdateOrgSettingsMutation();
353353

354354
const handleUpdateTeamSettings = useCallback(
@@ -360,7 +360,9 @@ function OrgDefaultWorkspaceImageModal(props: OrgDefaultWorkspaceImageModalProps
360360
});
361361
props.onClose();
362362
} catch (error) {
363-
console.error(error);
363+
if (!ErrorCode.isUserError(error["code"])) {
364+
console.error(error);
365+
}
364366
setErrorMsg(error.message);
365367
}
366368
},

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/messaging/error.ts

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
*/
66

77
import { scrubber } from "../util/scrubbing";
8-
import { Status } from "nice-grpc-common";
98

109
export class ApplicationError extends Error {
1110
constructor(public readonly code: ErrorCode, message: string, public readonly data?: any) {
@@ -24,7 +23,7 @@ export class ApplicationError extends Error {
2423

2524
export namespace ApplicationError {
2625
export function hasErrorCode(e: any): e is Error & { code: ErrorCode; data?: any } {
27-
return e && e.code !== undefined;
26+
return ErrorCode.is(e["code"]);
2827
}
2928

3029
export async function notFoundToUndefined<T>(p: Promise<T>): Promise<T | undefined> {
@@ -37,41 +36,18 @@ export namespace ApplicationError {
3736
throw e;
3837
}
3938
}
40-
41-
export function fromGRPCError(e: any, data?: any): ApplicationError {
42-
// Argument e should be ServerErrorResponse
43-
// But to reduce dependency requirement, we use Error here
44-
45-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
46-
return new ApplicationError(categorizeRPCError(e.code), e.message, data);
47-
}
48-
49-
export function categorizeRPCError(code?: Status): ErrorCode {
50-
// Mostly align to https://github.com/gitpod-io/gitpod/blob/ef95e6f3ca0bf314c40da1b83251423c2208d175/components/public-api-server/pkg/proxy/errors.go#L25
51-
switch (code) {
52-
case Status.INVALID_ARGUMENT:
53-
return ErrorCodes.BAD_REQUEST;
54-
case Status.UNAUTHENTICATED:
55-
return ErrorCodes.NOT_AUTHENTICATED;
56-
case Status.PERMISSION_DENIED:
57-
return ErrorCodes.PERMISSION_DENIED; // or UserBlocked
58-
case Status.NOT_FOUND:
59-
return ErrorCodes.NOT_FOUND;
60-
case Status.ALREADY_EXISTS:
61-
return ErrorCodes.CONFLICT;
62-
case Status.FAILED_PRECONDITION:
63-
return ErrorCodes.PRECONDITION_FAILED;
64-
case Status.RESOURCE_EXHAUSTED:
65-
return ErrorCodes.TOO_MANY_REQUESTS;
66-
}
67-
return ErrorCodes.INTERNAL_SERVER_ERROR;
68-
}
6939
}
7040

7141
export namespace ErrorCode {
7242
export function isUserError(code: number | ErrorCode) {
7343
return code >= 400 && code < 500;
7444
}
45+
export function is(code: any): code is ErrorCode {
46+
if (typeof code !== "number") {
47+
return false;
48+
}
49+
return Object.values(ErrorCodes).includes(code as ErrorCode);
50+
}
7551
}
7652

7753
export type ErrorCode = typeof ErrorCodes[keyof typeof ErrorCodes];

0 commit comments

Comments
 (0)