Skip to content

Commit

Permalink
[public-api] align with API guidelines
Browse files Browse the repository at this point in the history
  • Loading branch information
akosyakov committed Nov 10, 2023
1 parent 2e3429a commit 95065d2
Show file tree
Hide file tree
Showing 31 changed files with 935 additions and 762 deletions.
1 change: 1 addition & 0 deletions components/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"version": "0.0.0",
"private": true,
"dependencies": {
"@bufbuild/protobuf": "^1.3.3",
"@connectrpc/connect": "1.1.2",
"@connectrpc/connect-web": "1.1.2",
"@gitpod/gitpod-protocol": "0.1.5",
Expand Down
6 changes: 3 additions & 3 deletions components/dashboard/src/components/PrebuildLogs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,11 @@ export default function PrebuildLogs(props: PrebuildLogsProps) {
// Try get hold of a recent WorkspaceInfo
try {
const request = new GetWorkspaceRequest();
request.id = props.workspaceId;
request.workspaceId = props.workspaceId;
const response = await workspaceClient.getWorkspace(request);
setWorkspace({
instanceId: response.item?.status?.instanceId,
phase: response.item?.status?.phase?.name,
instanceId: response.workspace?.status?.instanceId,
phase: response.workspace?.status?.phase?.name,
});
} catch (err) {
console.error(err);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
* See License.AGPL.txt in the project root for license information.
*/

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

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

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

return await getGitpodService().server.updateTeam(org.id, { name });
const response = await organizationClient.updateOrganization({
organizationId: org.id,
name,
});
return response.organization!;
},
onSuccess(updatedOrg) {
// TODO: Update query cache with new org prior to invalidation so it's reflected immediately
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,10 @@ export const useUpdateOrgSettingsMutation = () => {
mutationFn: async ({ workspaceSharingDisabled, defaultWorkspaceImage }) => {
const settings = await organizationClient.updateOrganizationSettings({
organizationId: teamId,
settings: {
workspaceSharingDisabled: workspaceSharingDisabled || false,
defaultWorkspaceImage,
},
workspaceSharingDisabled: workspaceSharingDisabled || false,
defaultWorkspaceImage,
});
return settings.settings || new OrganizationSettings();
return settings.settings!;
},
onSuccess: invalidator,
});
Expand Down
2 changes: 1 addition & 1 deletion components/dashboard/src/data/setup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import * as ConfigurationClasses from "@gitpod/public-api/lib/gitpod/v1/configur
// This is used to version the cache
// If data we cache changes in a non-backwards compatible way, increment this version
// That will bust any previous cache versions a client may have stored
const CACHE_VERSION = "2";
const CACHE_VERSION = "3";

export function noPersistence(queryKey: QueryKey): QueryKey {
return [...queryKey, "no-persistence"];
Expand Down
22 changes: 11 additions & 11 deletions components/dashboard/src/service/json-rpc-organization-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
options?: CallOptions | undefined,
): Promise<UpdateOrganizationResponse> {
if (!request.organizationId) {
throw new ConnectError("id is required", Code.InvalidArgument);
throw new ConnectError("organizationId is required", Code.InvalidArgument);
}
if (!request.name) {
throw new ConnectError("name is required", Code.InvalidArgument);
Expand All @@ -97,7 +97,7 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
options?: CallOptions | undefined,
): Promise<DeleteOrganizationResponse> {
if (!request.organizationId) {
throw new ConnectError("id is required", Code.InvalidArgument);
throw new ConnectError("organizationId is required", Code.InvalidArgument);
}
await getGitpodService().server.deleteTeam(request.organizationId);
return new DeleteOrganizationResponse();
Expand All @@ -108,7 +108,7 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
options?: CallOptions | undefined,
): Promise<GetOrganizationInvitationResponse> {
if (!request.organizationId) {
throw new ConnectError("id is required", Code.InvalidArgument);
throw new ConnectError("organizationId is required", Code.InvalidArgument);
}
const result = await getGitpodService().server.getGenericInvite(request.organizationId);
return new GetOrganizationInvitationResponse({
Expand All @@ -134,7 +134,7 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
options?: CallOptions | undefined,
): Promise<ResetOrganizationInvitationResponse> {
if (!request.organizationId) {
throw new ConnectError("id is required", Code.InvalidArgument);
throw new ConnectError("organizationId is required", Code.InvalidArgument);
}
const newInvite = await getGitpodService().server.resetGenericInvite(request.organizationId);
return new ResetOrganizationInvitationResponse({
Expand All @@ -147,7 +147,7 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
options?: CallOptions | undefined,
): Promise<ListOrganizationMembersResponse> {
if (!request.organizationId) {
throw new ConnectError("id is required", Code.InvalidArgument);
throw new ConnectError("organizationId is required", Code.InvalidArgument);
}
const result = await getGitpodService().server.getTeamMembers(request.organizationId);
return new ListOrganizationMembersResponse({
Expand All @@ -160,7 +160,7 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
options?: CallOptions | undefined,
): Promise<UpdateOrganizationMemberResponse> {
if (!request.organizationId) {
throw new ConnectError("id is required", Code.InvalidArgument);
throw new ConnectError("organizationId is required", Code.InvalidArgument);
}
if (!request.userId) {
throw new ConnectError("userId is required", Code.InvalidArgument);
Expand All @@ -181,7 +181,7 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
options?: CallOptions | undefined,
): Promise<DeleteOrganizationMemberResponse> {
if (!request.organizationId) {
throw new ConnectError("id is required", Code.InvalidArgument);
throw new ConnectError("organizationId is required", Code.InvalidArgument);
}
if (!request.userId) {
throw new ConnectError("userId is required", Code.InvalidArgument);
Expand All @@ -195,7 +195,7 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
options?: CallOptions | undefined,
): Promise<GetOrganizationSettingsResponse> {
if (!request.organizationId) {
throw new ConnectError("id is required", Code.InvalidArgument);
throw new ConnectError("organizationId is required", Code.InvalidArgument);
}
const result = await getGitpodService().server.getOrgSettings(request.organizationId);
return new GetOrganizationSettingsResponse({
Expand All @@ -208,11 +208,11 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
options?: CallOptions | undefined,
): Promise<UpdateOrganizationSettingsResponse> {
if (!request.organizationId) {
throw new ConnectError("id is required", Code.InvalidArgument);
throw new ConnectError("organizationId is required", Code.InvalidArgument);
}
await getGitpodService().server.updateOrgSettings(request.organizationId, {
workspaceSharingDisabled: request.settings?.workspaceSharingDisabled,
defaultWorkspaceImage: request.settings?.defaultWorkspaceImage,
workspaceSharingDisabled: request?.workspaceSharingDisabled,
defaultWorkspaceImage: request?.defaultWorkspaceImage,
});
return new UpdateOrganizationSettingsResponse();
}
Expand Down
16 changes: 8 additions & 8 deletions components/dashboard/src/service/json-rpc-workspace-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ import { WorkspaceInstance } from "@gitpod/gitpod-protocol";

export class JsonRpcWorkspaceClient implements PromiseClient<typeof WorkspaceService> {
async getWorkspace(request: PartialMessage<GetWorkspaceRequest>): Promise<GetWorkspaceResponse> {
if (!request.id) {
throw new ConnectError("id is required", Code.InvalidArgument);
if (!request.workspaceId) {
throw new ConnectError("workspaceId is required", Code.InvalidArgument);
}
const info = await getGitpodService().server.getWorkspace(request.id);
const info = await getGitpodService().server.getWorkspace(request.workspaceId);
const workspace = converter.toWorkspace(info);
const result = new GetWorkspaceResponse();
result.item = workspace;
result.workspace = workspace;
return result;
}

Expand All @@ -38,11 +38,11 @@ export class JsonRpcWorkspaceClient implements PromiseClient<typeof WorkspaceSer
throw new ConnectError("signal is required", Code.InvalidArgument);
}
if (request.workspaceId) {
const resp = await this.getWorkspace({ id: request.workspaceId });
if (resp.item?.status) {
const resp = await this.getWorkspace({ workspaceId: request.workspaceId });
if (resp.workspace?.status) {
const response = new WatchWorkspaceStatusResponse();
response.workspaceId = resp.item.id;
response.status = resp.item.status;
response.workspaceId = resp.workspace.id;
response.status = resp.workspace.status;
yield response;
}
}
Expand Down
10 changes: 5 additions & 5 deletions components/dashboard/src/start/StartWorkspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -272,14 +272,14 @@ export default class StartWorkspace extends React.Component<StartWorkspaceProps,
const { workspaceId } = this.props;
try {
const request = new GetWorkspaceRequest();
request.id = workspaceId;
request.workspaceId = workspaceId;
const response = await workspaceClient.getWorkspace(request);
if (response.item?.status?.instanceId) {
if (response.workspace?.status?.instanceId) {
this.setState((s) => ({
workspace: response.item,
startedInstanceId: s.startedInstanceId || response.item?.status?.instanceId, // note: here's a potential mismatch between startedInstanceId and instance.id. TODO(gpl) How to handle this?
workspace: response.workspace,
startedInstanceId: s.startedInstanceId || response.workspace?.status?.instanceId, // note: here's a potential mismatch between startedInstanceId and instance.id. TODO(gpl) How to handle this?
}));
this.onWorkspaceUpdate(response.item);
this.onWorkspaceUpdate(response.workspace);
}
} catch (error) {
console.error(error);
Expand Down
6 changes: 4 additions & 2 deletions components/dashboard/src/teams/TeamSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { organizationClient } from "../service/public-api";
import { gitpodHostUrl } from "../service/service";
import { useCurrentUser } from "../user-context";
import { OrgSettingsPage } from "./OrgSettingsPage";
import { ErrorCode } from "@gitpod/gitpod-protocol/lib/messaging/error";

export default function TeamSettingsPage() {
const user = useCurrentUser();
Expand Down Expand Up @@ -204,7 +205,6 @@ function OrgSettingsForm(props: { org?: Organization; isOwner: boolean }) {
<form
onSubmit={(e) => {
e.preventDefault();
// handleUpdateTeamSettings({ defaultWorkspaceImage });
}}
>
{props.org && (
Expand Down Expand Up @@ -360,7 +360,9 @@ function OrgDefaultWorkspaceImageModal(props: OrgDefaultWorkspaceImageModalProps
});
props.onClose();
} catch (error) {
console.error(error);
if (!ErrorCode.isUserError(error["code"])) {
console.error(error);
}
setErrorMsg(error.message);
}
},
Expand Down
2 changes: 1 addition & 1 deletion components/gitpod-db/src/team-db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export interface TeamDB extends TransactionalDB<TeamDB> {
deleteTeam(teamId: string): Promise<void>;

findOrgSettings(teamId: string): Promise<OrganizationSettings | undefined>;
setOrgSettings(teamId: string, settings: Partial<OrganizationSettings>): Promise<void>;
setOrgSettings(teamId: string, settings: Partial<OrganizationSettings>): Promise<OrganizationSettings>;

hasActiveSSO(organizationId: string): Promise<boolean>;
}
23 changes: 7 additions & 16 deletions components/gitpod-db/src/typeorm/team-db-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,28 +366,19 @@ export class TeamDBImpl extends TransactionalDBImpl<TeamDB> implements TeamDB {
});
}

public async setOrgSettings(orgId: string, settings: Partial<OrganizationSettings>): Promise<void> {
public async setOrgSettings(orgId: string, settings: Partial<OrganizationSettings>): Promise<OrganizationSettings> {
const repo = await this.getOrgSettingsRepo();
const team = await repo.findOne({ where: { orgId, deleted: false } });
const update: Partial<OrganizationSettings> = {
defaultWorkspaceImage: settings.defaultWorkspaceImage,
workspaceSharingDisabled: settings.workspaceSharingDisabled,
};
// Set to null if defaultWorkspaceImage is empty string, so that it can fallback to default image
if (update.defaultWorkspaceImage?.trim() === "") {
update.defaultWorkspaceImage = null;
}
if (!team) {
await repo.insert({
...update,
return await repo.save({
...settings,
orgId,
});
} else {
await repo.save({
...team,
...update,
});
}
return await repo.save({
...team,
...settings,
});
}

public async hasActiveSSO(organizationId: string): Promise<boolean> {
Expand Down
38 changes: 7 additions & 31 deletions components/gitpod-protocol/src/messaging/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
*/

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

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

export namespace ApplicationError {
export function hasErrorCode(e: any): e is Error & { code: ErrorCode; data?: any } {
return e && e.code !== undefined;
return ErrorCode.is(e["code"]);
}

export async function notFoundToUndefined<T>(p: Promise<T>): Promise<T | undefined> {
Expand All @@ -37,41 +36,18 @@ export namespace ApplicationError {
throw e;
}
}

export function fromGRPCError(e: any, data?: any): ApplicationError {
// Argument e should be ServerErrorResponse
// But to reduce dependency requirement, we use Error here

// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
return new ApplicationError(categorizeRPCError(e.code), e.message, data);
}

export function categorizeRPCError(code?: Status): ErrorCode {
// Mostly align to https://github.com/gitpod-io/gitpod/blob/ef95e6f3ca0bf314c40da1b83251423c2208d175/components/public-api-server/pkg/proxy/errors.go#L25
switch (code) {
case Status.INVALID_ARGUMENT:
return ErrorCodes.BAD_REQUEST;
case Status.UNAUTHENTICATED:
return ErrorCodes.NOT_AUTHENTICATED;
case Status.PERMISSION_DENIED:
return ErrorCodes.PERMISSION_DENIED; // or UserBlocked
case Status.NOT_FOUND:
return ErrorCodes.NOT_FOUND;
case Status.ALREADY_EXISTS:
return ErrorCodes.CONFLICT;
case Status.FAILED_PRECONDITION:
return ErrorCodes.PRECONDITION_FAILED;
case Status.RESOURCE_EXHAUSTED:
return ErrorCodes.TOO_MANY_REQUESTS;
}
return ErrorCodes.INTERNAL_SERVER_ERROR;
}
}

export namespace ErrorCode {
export function isUserError(code: number | ErrorCode) {
return code >= 400 && code < 500;
}
export function is(code: any): code is ErrorCode {
if (typeof code !== "number") {
return false;
}
return Object.values(ErrorCodes).includes(code as ErrorCode);
}
}

export type ErrorCode = typeof ErrorCodes[keyof typeof ErrorCodes];
Expand Down
4 changes: 4 additions & 0 deletions components/gitpod-protocol/src/public-api-converter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ describe("PublicAPIConverter", () => {
},
additionalEnvironmentVariables: [],
region: "dev",
prebuildId: "",
workspaceClass: "g1-standard",
editor: {
name: "code",
Expand Down Expand Up @@ -362,6 +363,7 @@ describe("PublicAPIConverter", () => {
},
additionalEnvironmentVariables: [],
region: "dev",
prebuildId: "",
workspaceClass: "g1-standard",
editor: {
name: "code",
Expand Down Expand Up @@ -502,6 +504,7 @@ describe("PublicAPIConverter", () => {
},
additionalEnvironmentVariables: [],
region: "dev",
prebuildId: "",
workspaceClass: "g1-standard",
editor: {
name: "code",
Expand Down Expand Up @@ -617,6 +620,7 @@ describe("PublicAPIConverter", () => {
},
additionalEnvironmentVariables: [],
region: "dev",
prebuildId: "",
workspaceClass: "g1-standard",
editor: {
name: "code",
Expand Down
Loading

0 comments on commit 95065d2

Please sign in to comment.