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);
}