diff --git a/components/dashboard/src/projects/NewProject.tsx b/components/dashboard/src/projects/NewProject.tsx index 47cce7c49d5822..74c532e4d07a35 100644 --- a/components/dashboard/src/projects/NewProject.tsx +++ b/components/dashboard/src/projects/NewProject.tsx @@ -315,15 +315,17 @@ export default function NewProject() {
-
{toSimpleName(r.name)}
+
{toSimpleName(r.name)}

Updated {moment(r.updatedAt).fromNow()}

-
+
{!r.inUse ? ( ) : ( -

already taken

+

+ @{r.inUse.userName} already
added this repo +

)}
diff --git a/components/gitpod-db/src/project-db.ts b/components/gitpod-db/src/project-db.ts index 35c7948b23e4f0..d18fab1b1d8d95 100644 --- a/components/gitpod-db/src/project-db.ts +++ b/components/gitpod-db/src/project-db.ts @@ -10,7 +10,7 @@ export const ProjectDB = Symbol('ProjectDB'); export interface ProjectDB { findProjectById(projectId: string): Promise; findProjectByCloneUrl(cloneUrl: string): Promise; - findProjectsByCloneUrls(cloneUrls: string[]): Promise; + findProjectsByCloneUrls(cloneUrls: string[]): Promise<(Project & { teamOwners?: string[] })[]>; findTeamProjects(teamId: string): Promise; findUserProjects(userId: string): Promise; storeProject(project: Project): Promise; diff --git a/components/gitpod-db/src/typeorm/project-db-impl.ts b/components/gitpod-db/src/typeorm/project-db-impl.ts index ea6abab77cf606..38e7bbe23b732e 100644 --- a/components/gitpod-db/src/typeorm/project-db-impl.ts +++ b/components/gitpod-db/src/typeorm/project-db-impl.ts @@ -33,7 +33,7 @@ export class ProjectDBImpl implements ProjectDB { return repo.findOne({ cloneUrl, markedDeleted: false }); } - public async findProjectsByCloneUrls(cloneUrls: string[]): Promise { + public async findProjectsByCloneUrls(cloneUrls: string[]): Promise<(Project & { teamOwners?: string[] })[]> { if (cloneUrls.length === 0) { return []; } @@ -41,7 +41,23 @@ export class ProjectDBImpl implements ProjectDB { const q = repo.createQueryBuilder("project") .where("project.markedDeleted = false") .andWhere(`project.cloneUrl in (${ cloneUrls.map(u => `'${u}'`).join(", ") })`) - const result = await q.getMany(); + const projects = await q.getMany(); + + const teamIds = Array.from(new Set(projects.map(p => p.teamId).filter(id => !!id))); + + const teamIdsAndOwners = teamIds.length === 0 ? [] : (await (await this.getEntityManager()).query(` + SELECT member.teamId AS teamId, user.name AS owner FROM d_b_user AS user + LEFT JOIN d_b_team_membership AS member ON (user.id = member.userId) + WHERE member.teamId IN (${teamIds.map(id => `'${id}'`).join(", ")}) + AND member.deleted = 0 + AND member.role = 'owner' + `)) as { teamId: string, owner: string }[]; + + const result: (Project & { teamOwners?: string[] })[] = []; + for (const project of projects) { + result.push({...project, teamOwners: teamIdsAndOwners.filter(i => i.teamId === project.teamId).map(i => i.owner)}); + } + return result; } diff --git a/components/gitpod-protocol/src/gitpod-service.ts b/components/gitpod-protocol/src/gitpod-service.ts index a0911270311551..a4ad550efb49a9 100644 --- a/components/gitpod-protocol/src/gitpod-service.ts +++ b/components/gitpod-protocol/src/gitpod-service.ts @@ -271,7 +271,7 @@ export interface ProviderRepository { installationId?: number; installationUpdatedAt?: string; - inUse?: boolean; + inUse?: { userName: string }; } export interface ClientHeaderFields { diff --git a/components/server/ee/src/workspace/gitpod-server-impl.ts b/components/server/ee/src/workspace/gitpod-server-impl.ts index e56ebee99cb8ce..5f164b98ca3c29 100644 --- a/components/server/ee/src/workspace/gitpod-server-impl.ts +++ b/components/server/ee/src/workspace/gitpod-server-impl.ts @@ -1440,8 +1440,25 @@ export class GitpodServerEEImpl extends GitpodServerImpl { } const projects = await this.projectsService.getProjectsByCloneUrls(repositories.map(r => r.cloneUrl)); - const cloneUrlsInUse = new Set(projects.map(p => p.cloneUrl)); - repositories.forEach(r => { r.inUse = cloneUrlsInUse.has(r.cloneUrl) }); + const cloneUrlToProject = new Map(projects.map(p => [p.cloneUrl, p])); + + for (const repo of repositories) { + const p = cloneUrlToProject.get(repo.cloneUrl); + if (p) { + if (p.userId) { + const owner = await this.userDB.findUserById(p.userId); + if (owner) { + repo.inUse = { + userName: owner?.name || owner?.fullName || 'somebody' + } + } + } else if (p.teamOwners && p.teamOwners[0]) { + repo.inUse = { + userName: p.teamOwners[0] || 'somebody' + } + } + } + } return repositories; } diff --git a/components/server/src/projects/projects-service.ts b/components/server/src/projects/projects-service.ts index 182f6861282578..7042371ec485f0 100644 --- a/components/server/src/projects/projects-service.ts +++ b/components/server/src/projects/projects-service.ts @@ -37,7 +37,7 @@ export class ProjectsService { return this.projectDB.findUserProjects(userId); } - async getProjectsByCloneUrls(cloneUrls: string[]): Promise { + async getProjectsByCloneUrls(cloneUrls: string[]): Promise<(Project & { teamOwners?: string[] })[]> { return this.projectDB.findProjectsByCloneUrls(cloneUrls); }