Skip to content

[dashboard] List projects using Public API #14938

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions components/dashboard/src/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { inResource, isGitpodIo } from "./utils";
import { BillingMode } from "@gitpod/gitpod-protocol/lib/billing-mode";
import { FeatureFlagContext } from "./contexts/FeatureFlagContext";
import { publicApiTeamMembersToProtocol, teamsService } from "./service/public-api";
import { listAllProjects } from "./service/public-api";

interface Entry {
title: string;
Expand All @@ -37,7 +38,7 @@ interface Entry {

export default function Menu() {
const { user } = useContext(UserContext);
const { showUsageView, usePublicApiTeamsService } = useContext(FeatureFlagContext);
const { showUsageView, usePublicApiTeamsService, usePublicApiProjectsService } = useContext(FeatureFlagContext);
const { teams } = useContext(TeamsContext);
const location = useLocation();
const team = getCurrentTeam(location, teams);
Expand Down Expand Up @@ -154,9 +155,16 @@ export default function Menu() {
return;
}
(async () => {
const projects = !!team
? await getGitpodService().server.getTeamProjects(team.id)
: await getGitpodService().server.getUserProjects();
let projects: Project[];
if (!!team) {
projects = usePublicApiProjectsService
? await listAllProjects({ teamId: team.id })
: await getGitpodService().server.getTeamProjects(team.id);
} else {
projects = usePublicApiProjectsService
? await listAllProjects({ userId: user?.id })
: await getGitpodService().server.getUserProjects();
}

// Find project matching with slug, otherwise with name
const project =
Expand Down
5 changes: 5 additions & 0 deletions components/dashboard/src/contexts/FeatureFlagContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ const FeatureFlagContext = createContext<{
isUsageBasedBillingEnabled: boolean;
showUseLastSuccessfulPrebuild: boolean;
usePublicApiTeamsService: boolean;
usePublicApiProjectsService: boolean;
enablePersonalAccessTokens: boolean;
}>({
showUsageView: false,
isUsageBasedBillingEnabled: false,
showUseLastSuccessfulPrebuild: false,
usePublicApiTeamsService: false,
usePublicApiProjectsService: false,
enablePersonalAccessTokens: false,
});

Expand All @@ -39,6 +41,7 @@ const FeatureFlagContextProvider: React.FC = ({ children }) => {
const [isUsageBasedBillingEnabled, setIsUsageBasedBillingEnabled] = useState<boolean>(false);
const [showUseLastSuccessfulPrebuild, setShowUseLastSuccessfulPrebuild] = useState<boolean>(false);
const [usePublicApiTeamsService, setUsePublicApiTeamsService] = useState<boolean>(false);
const [usePublicApiProjectsService, setUsePublicApiProjectsService] = useState<boolean>(false);
const [enablePersonalAccessTokens, setPersonalAccessTokensEnabled] = useState<boolean>(false);

useEffect(() => {
Expand All @@ -49,6 +52,7 @@ const FeatureFlagContextProvider: React.FC = ({ children }) => {
isUsageBasedBillingEnabled: { defaultValue: false, setter: setIsUsageBasedBillingEnabled },
showUseLastSuccessfulPrebuild: { defaultValue: false, setter: setShowUseLastSuccessfulPrebuild },
publicApiExperimentalTeamsService: { defaultValue: false, setter: setUsePublicApiTeamsService },
publicApiExperimentalProjectsService: { defaultValue: false, setter: setUsePublicApiProjectsService },
personalAccessTokensEnabled: { defaultValue: false, setter: setPersonalAccessTokensEnabled },
};

Expand Down Expand Up @@ -94,6 +98,7 @@ const FeatureFlagContextProvider: React.FC = ({ children }) => {
showUseLastSuccessfulPrebuild,
usePublicApiTeamsService,
enablePersonalAccessTokens,
usePublicApiProjectsService,
}}
>
{children}
Expand Down
18 changes: 15 additions & 3 deletions components/dashboard/src/projects/Events.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,16 @@ import Spinner from "../icons/Spinner.svg";
import NoAccess from "../icons/NoAccess.svg";
import { ErrorCodes } from "@gitpod/gitpod-protocol/lib/messaging/error";
import { openAuthorizeWindow } from "../provider-utils";
import { UserContext } from "../user-context";
import { FeatureFlagContext } from "../contexts/FeatureFlagContext";
import { listAllProjects } from "../service/public-api";

export default function () {
const location = useLocation();

const { teams } = useContext(TeamsContext);
const { user } = useContext(UserContext);
const { usePublicApiProjectsService } = useContext(FeatureFlagContext);
const team = getCurrentTeam(location, teams);

const match = useRouteMatch<{ team: string; resource: string }>("/(t/)?:team/:resource");
Expand Down Expand Up @@ -61,9 +66,16 @@ export default function () {
if (!teams || !projectSlug) {
return;
}
const projects = !!team
? await getGitpodService().server.getTeamProjects(team.id)
: await getGitpodService().server.getUserProjects();
let projects: Project[];
if (!!team) {
projects = usePublicApiProjectsService
? await listAllProjects({ teamId: team.id })
: await getGitpodService().server.getTeamProjects(team.id);
} else {
projects = usePublicApiProjectsService
? await listAllProjects({ userId: user?.id })
: await getGitpodService().server.getUserProjects();
}

// Find project matching with slug, otherwise with name
const project = projectSlug && projects.find((p) => (p.slug ? p.slug === projectSlug : p.name === projectSlug));
Expand Down
20 changes: 16 additions & 4 deletions components/dashboard/src/projects/Prebuild.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

import dayjs from "dayjs";
import { PrebuildWithStatus } from "@gitpod/gitpod-protocol";
import { PrebuildWithStatus, Project } from "@gitpod/gitpod-protocol";
import { useContext, useEffect, useState } from "react";
import { useHistory, useLocation, useRouteMatch } from "react-router";
import Header from "../components/Header";
Expand All @@ -14,12 +14,17 @@ import Spinner from "../icons/Spinner.svg";
import { getGitpodService, gitpodHostUrl } from "../service/service";
import { TeamsContext, getCurrentTeam } from "../teams/teams-context";
import { shortCommitMessage } from "./render-utils";
import { listAllProjects } from "../service/public-api";
import { UserContext } from "../user-context";
import { FeatureFlagContext } from "../contexts/FeatureFlagContext";

export default function () {
const history = useHistory();
const location = useLocation();

const { teams } = useContext(TeamsContext);
const { user } = useContext(UserContext);
const { usePublicApiProjectsService } = useContext(FeatureFlagContext);
const team = getCurrentTeam(location, teams);

const match = useRouteMatch<{ team: string; project: string; prebuildId: string }>(
Expand All @@ -37,9 +42,16 @@ export default function () {
return;
}
(async () => {
const projects = !!team
? await getGitpodService().server.getTeamProjects(team.id)
: await getGitpodService().server.getUserProjects();
let projects: Project[];
if (!!team) {
projects = usePublicApiProjectsService
? await listAllProjects({ teamId: team.id })
: await getGitpodService().server.getTeamProjects(team.id);
} else {
projects = usePublicApiProjectsService
? await listAllProjects({ userId: user?.id })
: await getGitpodService().server.getUserProjects();
}

const project =
projectSlug && projects.find((p) => (!!p.slug ? p.slug === projectSlug : p.name === projectSlug));
Expand Down
19 changes: 15 additions & 4 deletions components/dashboard/src/projects/Prebuilds.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,16 @@ import { TeamsContext, getCurrentTeam } from "../teams/teams-context";
import { shortCommitMessage } from "./render-utils";
import { Link } from "react-router-dom";
import { Disposable } from "vscode-jsonrpc";
import { UserContext } from "../user-context";
import { FeatureFlagContext } from "../contexts/FeatureFlagContext";
import { listAllProjects } from "../service/public-api";

export default function (props: { project?: Project; isAdminDashboard?: boolean }) {
const location = useLocation();

const { teams } = useContext(TeamsContext);
const { user } = useContext(UserContext);
const { usePublicApiProjectsService } = useContext(FeatureFlagContext);
const team = getCurrentTeam(location, teams);

const match = useRouteMatch<{ team: string; resource: string }>("/(t/)?:team/:resource");
Expand Down Expand Up @@ -85,10 +90,16 @@ export default function (props: { project?: Project; isAdminDashboard?: boolean
return;
}
(async () => {
const projects = !!team
? await getGitpodService().server.getTeamProjects(team.id)
: await getGitpodService().server.getUserProjects();

let projects: Project[];
if (!!team) {
projects = usePublicApiProjectsService
? await listAllProjects({ teamId: team.id })
: await getGitpodService().server.getTeamProjects(team.id);
} else {
projects = usePublicApiProjectsService
? await listAllProjects({ userId: user?.id })
: await getGitpodService().server.getUserProjects();
}
const newProject =
projectSlug && projects.find((p) => (p.slug ? p.slug === projectSlug : p.name === projectSlug));

Expand Down
19 changes: 15 additions & 4 deletions components/dashboard/src/projects/Project.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,17 @@ import NoAccess from "../icons/NoAccess.svg";
import { ErrorCodes } from "@gitpod/gitpod-protocol/lib/messaging/error";
import { openAuthorizeWindow } from "../provider-utils";
import Alert from "../components/Alert";
import { FeatureFlagContext } from "../contexts/FeatureFlagContext";
import { listAllProjects } from "../service/public-api";
import { UserContext } from "../user-context";

export default function () {
const location = useLocation();
const history = useHistory();

const { teams } = useContext(TeamsContext);
const { user } = useContext(UserContext);
const { usePublicApiProjectsService } = useContext(FeatureFlagContext);
const team = getCurrentTeam(location, teams);

const match = useRouteMatch<{ team: string; resource: string }>("/(t/)?:team/:resource");
Expand Down Expand Up @@ -69,10 +74,16 @@ export default function () {
if (!teams || !projectSlug) {
return;
}
const projects = !!team
? await getGitpodService().server.getTeamProjects(team.id)
: await getGitpodService().server.getUserProjects();

let projects: Project[];
if (!!team) {
projects = usePublicApiProjectsService
? await listAllProjects({ teamId: team.id })
: await getGitpodService().server.getTeamProjects(team.id);
} else {
projects = usePublicApiProjectsService
? await listAllProjects({ userId: user?.id })
: await getGitpodService().server.getUserProjects();
}
// Find project matching with slug, otherwise with name
const project = projectSlug && projects.find((p) => (p.slug ? p.slug === projectSlug : p.name === projectSlug));

Expand Down
19 changes: 16 additions & 3 deletions components/dashboard/src/projects/Projects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,17 @@ import ContextMenu from "../components/ContextMenu";
import ConfirmationModal from "../components/ConfirmationModal";
import { prebuildStatusIcon } from "./Prebuilds";
import Alert from "../components/Alert";
import { FeatureFlagContext } from "../contexts/FeatureFlagContext";
import { listAllProjects } from "../service/public-api";
import { UserContext } from "../user-context";

export default function () {
const location = useLocation();
const history = useHistory();

const { teams } = useContext(TeamsContext);
const { user } = useContext(UserContext);
const { usePublicApiProjectsService } = useContext(FeatureFlagContext);
const team = getCurrentTeam(location, teams);
const [projects, setProjects] = useState<Project[]>([]);
const [lastPrebuilds, setLastPrebuilds] = useState<Map<string, PrebuildWithStatus>>(new Map());
Expand All @@ -42,9 +47,17 @@ export default function () {
if (!teams) {
return;
}
const infos = !!team
? await getGitpodService().server.getTeamProjects(team.id)
: await getGitpodService().server.getUserProjects();

let infos: Project[];
if (!!team) {
infos = usePublicApiProjectsService
? await listAllProjects({ teamId: team.id })
: await getGitpodService().server.getTeamProjects(team.id);
} else {
infos = usePublicApiProjectsService
? await listAllProjects({ userId: user?.id })
: await getGitpodService().server.getUserProjects();
}
setProjects(infos);

const map = new Map();
Expand Down
57 changes: 56 additions & 1 deletion components/dashboard/src/service/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
*/

import { createConnectTransport, createPromiseClient } from "@bufbuild/connect-web";
import { Team as ProtocolTeam } from "@gitpod/gitpod-protocol/lib/teams-projects-protocol";
import { Project as ProtocolProject, Team as ProtocolTeam } from "@gitpod/gitpod-protocol/lib/teams-projects-protocol";
import { TeamsService } from "@gitpod/public-api/lib/gitpod/experimental/v1/teams_connectweb";
import { TokensService } from "@gitpod/public-api/lib/gitpod/experimental/v1/tokens_connectweb";
import { ProjectsService } from "@gitpod/public-api/lib/gitpod/experimental/v1/projects_connectweb";
import { Team } from "@gitpod/public-api/lib/gitpod/experimental/v1/teams_pb";
import { TeamMemberInfo, TeamMemberRole } from "@gitpod/gitpod-protocol";
import { TeamMember, TeamRole } from "@gitpod/public-api/lib/gitpod/experimental/v1/teams_pb";
import { Project } from "@gitpod/public-api/lib/gitpod/experimental/v1/projects_pb";

const transport = createConnectTransport({
baseUrl: `${window.location.protocol}//api.${window.location.host}`,
Expand All @@ -19,6 +21,7 @@ const transport = createConnectTransport({

export const teamsService = createPromiseClient(TeamsService, transport);
export const personalAccessTokensService = createPromiseClient(TokensService, transport);
export const projectsService = createPromiseClient(ProjectsService, transport);

export function publicApiTeamToProtocol(team: Team): ProtocolTeam {
return {
Expand Down Expand Up @@ -58,3 +61,55 @@ export function publicApiTeamRoleToProtocol(role: TeamRole): TeamMemberRole {
return "member";
}
}

export async function listAllProjects(opts: { userId?: string; teamId?: string }): Promise<ProtocolProject[]> {
let pagination = {
page: 1,
pageSize: 100,
};

const response = await projectsService.listProjects({
teamId: opts.teamId,
userId: opts.userId,
pagination,
});
const results = response.projects;

while (results.length < response.totalResults) {
pagination = {
pageSize: 100,
page: 1 + pagination.page,
};
const response = await projectsService.listProjects({
teamId: opts.teamId,
userId: opts.userId,
pagination,
});
results.push(...response.projects);
}

return results.map(projectToProtocol);
}

export function projectToProtocol(project: Project): ProtocolProject {
return {
id: project.id,
name: project.name,
cloneUrl: project.cloneUrl,
creationTime: project.creationTime?.toDate().toISOString() || "",
slug: project.slug,
teamId: project.teamId,
userId: project.userId,
appInstallationId: "undefined",
settings: {
allowUsingPreviousPrebuilds: project.settings?.prebuild?.usePreviousPrebuilds,
keepOutdatedPrebuildsRunning: project.settings?.prebuild?.keepOutdatedPrebuildsRunning,
prebuildEveryNthCommit: project.settings?.prebuild?.prebuildEveryNth,
useIncrementalPrebuilds: project.settings?.prebuild?.enableIncrementalPrebuilds,
workspaceClasses: {
prebuild: project.settings?.workspace?.workspaceClass?.prebuild || "",
regular: project.settings?.workspace?.workspaceClass?.regular || "",
},
},
};
}
6 changes: 3 additions & 3 deletions components/gitpod-protocol/go/gitpod-service.go
Original file line number Diff line number Diff line change
Expand Up @@ -1540,7 +1540,7 @@ func (gp *APIoverJSONRPC) CreateProject(ctx context.Context, options *CreateProj
return
}
_params := []interface{}{options}
err = gp.C.Call(ctx, string(FunctionCreateProject), _params, nil)
err = gp.C.Call(ctx, string(FunctionCreateProject), _params, &res)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We forgot to include these originally, which resulted in the API call always returning nil

return
}

Expand All @@ -1560,7 +1560,7 @@ func (gp *APIoverJSONRPC) GetUserProjects(ctx context.Context) (res []*Project,
return
}
_params := []interface{}{}
err = gp.C.Call(ctx, string(FunctionGetUserProjects), _params, nil)
err = gp.C.Call(ctx, string(FunctionGetUserProjects), _params, &res)
return
}

Expand All @@ -1570,7 +1570,7 @@ func (gp *APIoverJSONRPC) GetTeamProjects(ctx context.Context, teamID string) (r
return
}
_params := []interface{}{teamID}
err = gp.C.Call(ctx, string(FunctionGetTeamProjects), _params, nil)
err = gp.C.Call(ctx, string(FunctionGetTeamProjects), _params, &res)
return
}

Expand Down