소스 검색

Adds workaround to get team/org workspaces

main
Ramin Tadayon 1 년 전
부모
커밋
e0cdfe3cf1
No known key found for this signature in database GPG 키 ID: 79D60DDE3DFB95F5
3개의 변경된 파일130개의 추가작업 그리고 105개의 파일을 삭제
  1. +4
    -1
      src/plus/workspaces/models.ts
  2. +114
    -98
      src/plus/workspaces/workspacesApi.ts
  3. +12
    -6
      src/plus/workspaces/workspacesService.ts

+ 4
- 1
src/plus/workspaces/models.ts 파일 보기

@ -400,7 +400,7 @@ export interface CloudWorkspaceIssue {
repository: CloudWorkspaceRepositoryData;
}
interface CloudWorkspaceConnection<i> {
export interface CloudWorkspaceConnection<i> {
total_count: number;
page_info: {
start_cursor: string;
@ -477,6 +477,7 @@ export interface DeleteWorkspaceResponse {
data: {
delete_project: CloudWorkspaceData | null;
};
errors?: { code: number; message: string }[];
}
export type AddRepositoriesToWorkspaceResponse = {
@ -488,6 +489,7 @@ export type AddRepositoriesToWorkspaceResponse = {
};
} | null;
};
errors?: { code: number; message: string }[];
};
export interface RemoveRepositoriesFromWorkspaceResponse {
@ -496,6 +498,7 @@ export interface RemoveRepositoriesFromWorkspaceResponse {
id: string;
} | null;
};
errors?: { code: number; message: string }[];
}
export interface AddWorkspaceRepoDescriptor {

+ 114
- 98
src/plus/workspaces/workspacesApi.ts 파일 보기

@ -4,6 +4,8 @@ import type { ServerConnection } from '../subscription/serverConnection';
import type {
AddRepositoriesToWorkspaceResponse,
AddWorkspaceRepoDescriptor,
CloudWorkspaceConnection,
CloudWorkspaceData,
CreateWorkspaceResponse,
DeleteWorkspaceResponse,
RemoveRepositoriesFromWorkspaceResponse,
@ -27,11 +29,11 @@ export class WorkspacesApi {
return session.accessToken;
}
// TODO@ramint: We have a pagedresponse model available in case it helps here. Takes care of cursor internally
// Make the data return a promise for the repos. Should be async so we're set up for dynamic processing.
async getWorkspacesWithRepos(options?: {
async getWorkspaces(options?: {
count?: number;
cursor?: string;
includeOrganizations?: boolean;
includeRepositories?: boolean;
page?: number;
repoCount?: number;
repoPage?: number;
@ -41,6 +43,53 @@ export class WorkspacesApi {
return;
}
let repoQuery: string | undefined;
if (options?.includeRepositories) {
let repoQueryParams = `(first: ${options?.repoCount ?? defaultWorkspaceRepoCount}`;
if (options?.repoPage) {
repoQueryParams += `, page: ${options.repoPage}`;
}
repoQueryParams += ')';
repoQuery = `
provider_data {
repositories ${repoQueryParams} {
total_count
page_info {
end_cursor
has_next_page
}
nodes {
id
name
repository_id
provider
provider_organization_id
provider_organization_name
url
}
}
}
`;
}
const queryData = `
total_count
page_info {
end_cursor
has_next_page
}
nodes {
id
description
name
organization {
id
}
provider
${repoQuery ?? ''}
}
`;
let queryParams = `(first: ${options?.count ?? defaultWorkspaceCount}`;
if (options?.cursor) {
queryParams += `, after: "${options.cursor}"`;
@ -49,52 +98,29 @@ export class WorkspacesApi {
}
queryParams += ')';
let repoQueryParams = `(first: ${options?.repoCount ?? defaultWorkspaceRepoCount}`;
if (options?.repoPage) {
repoQueryParams += `, page: ${options.repoPage}`;
let query = 'query getWorkpacesWithRepos {';
query += `memberProjects: projects ${queryParams} { ${queryData} }`;
// TODO@axosoft-ramint This is a temporary and hacky workaround until projects api returns all projects the
// user belongs to in one query. Update once that is available.
if (options?.cursor == null && options?.includeOrganizations) {
const organizationIds =
(await this.container.subscription.getSubscription())?.account?.organizationIds ?? [];
for (const organizationId of organizationIds) {
let orgQueryParams = `(first: ${options?.count ?? defaultWorkspaceCount}`;
if (options?.page) {
orgQueryParams += `, page: ${options.page}`;
}
orgQueryParams += `, organization_id: "${organizationId}")`;
query += `organizationProjects_${organizationId}: projects ${orgQueryParams} { ${queryData} }`;
}
}
repoQueryParams += ')';
query += '}';
const rsp = await this.server.fetchGraphql(
{
query: `
query getWorkspacesWithRepos {
projects ${queryParams} {
total_count
page_info {
end_cursor
has_next_page
}
nodes {
id
description
name
organization {
id
}
provider
provider_data {
repositories ${repoQueryParams} {
total_count
page_info {
end_cursor
has_next_page
}
nodes {
id
name
repository_id
provider
provider_organization_id
provider_organization_name
url
}
}
}
}
}
}
`,
query: query,
},
accessToken,
);
@ -104,63 +130,32 @@ export class WorkspacesApi {
throw new Error(rsp.statusText);
}
const json: WorkspacesResponse | undefined = (await rsp.json()) as WorkspacesResponse | undefined;
return json;
}
async getWorkspaces(options?: {
count?: number;
cursor?: string;
page?: number;
}): Promise<WorkspacesResponse | undefined> {
const accessToken = await this.getAccessToken();
if (accessToken == null) {
return;
}
let queryparams = `(first: ${options?.count ?? defaultWorkspaceCount}`;
if (options?.cursor) {
queryparams += `, after: "${options.cursor}"`;
} else if (options?.page) {
queryparams += `, page: ${options.page}`;
const addedWorkspaceIds = new Set<string>();
const json: { data: { [queryKey: string]: CloudWorkspaceConnection<CloudWorkspaceData> | null } } | undefined =
await rsp.json();
if (json?.data == null) return undefined;
let outputData: WorkspacesResponse | undefined;
for (const workspaceData of Object.values(json.data)) {
if (workspaceData == null) continue;
if (outputData == null) {
outputData = { data: { projects: workspaceData } };
for (const node of workspaceData.nodes) {
addedWorkspaceIds.add(node.id);
}
} else {
for (const node of workspaceData.nodes) {
if (addedWorkspaceIds.has(node.id)) continue;
addedWorkspaceIds.add(node.id);
outputData.data.projects.nodes.push(node);
}
}
}
queryparams += ')';
const rsp = await this.server.fetchGraphql(
{
query: `
query getWorkspaces {
projects ${queryparams} {
total_count
page_info {
end_cursor
has_next_page
}
nodes {
id
description
name
organization {
id
}
provider
}
}
}
`,
},
accessToken,
);
if (!rsp.ok) {
Logger.error(undefined, `Getting workspaces failed: (${rsp.status}) ${rsp.statusText}`);
throw new Error(rsp.statusText);
if (outputData != null) {
outputData.data.projects.total_count = addedWorkspaceIds.size;
}
const json: WorkspacesResponse | undefined = (await rsp.json()) as WorkspacesResponse | undefined;
return json;
return outputData;
}
async getWorkspaceRepositories(
@ -326,6 +321,13 @@ export class WorkspacesApi {
const json: DeleteWorkspaceResponse | undefined = (await rsp.json()) as DeleteWorkspaceResponse | undefined;
if (json?.errors?.some(error => error.message.includes('permission'))) {
const errorMessage =
'Adding repositories to workspace failed: you do not have permission to delete this workspace';
Logger.error(undefined, errorMessage);
throw new Error(errorMessage);
}
return json;
}
@ -391,6 +393,13 @@ export class WorkspacesApi {
| AddRepositoriesToWorkspaceResponse
| undefined;
if (json?.errors?.some(error => error.message.includes('permission'))) {
const errorMessage =
'Adding repositories to workspace failed: you do not have permission to add repositories to this workspace';
Logger.error(undefined, errorMessage);
throw new Error(errorMessage);
}
return json;
}
@ -438,6 +447,13 @@ export class WorkspacesApi {
| RemoveRepositoriesFromWorkspaceResponse
| undefined;
if (json?.errors?.some(error => error.message.includes('permission'))) {
const errorMessage =
'Adding repositories to workspace failed: you do not have permission to remove repositories from this workspace';
Logger.error(undefined, errorMessage);
throw new Error(errorMessage);
}
return json;
}
}

+ 12
- 6
src/plus/workspaces/workspacesService.ts 파일 보기

@ -87,9 +87,10 @@ export class WorkspacesService implements Disposable {
const cloudWorkspaces: CloudWorkspace[] = [];
let workspaces: CloudWorkspaceData[] | undefined;
try {
const workspaceResponse: WorkspacesResponse | undefined = excludeRepositories
? await this._workspacesApi.getWorkspaces()
: await this._workspacesApi.getWorkspacesWithRepos();
const workspaceResponse: WorkspacesResponse | undefined = await this._workspacesApi.getWorkspaces({
includeRepositories: !excludeRepositories,
includeOrganizations: true,
});
workspaces = workspaceResponse?.data?.projects?.nodes;
} catch {
return {
@ -653,7 +654,9 @@ export class WorkspacesService implements Disposable {
// Remove the workspace from the local workspace list.
this._cloudWorkspaces = this._cloudWorkspaces?.filter(w => w.id !== workspaceId);
}
} catch {}
} catch (error) {
void window.showErrorMessage(error.message);
}
}
private async filterReposForProvider(
@ -806,7 +809,8 @@ export class WorkspacesService implements Disposable {
newRepoDescriptors = Object.values(response.data.add_repositories_to_project.provider_data).map(
descriptor => ({ ...descriptor, workspaceId: workspaceId }),
) as CloudWorkspaceRepositoryDescriptor[];
} catch {
} catch (error) {
void window.showErrorMessage(error.message);
return;
}
@ -839,7 +843,9 @@ export class WorkspacesService implements Disposable {
if (response?.data.remove_repositories_from_project == null) return;
workspace.removeRepositories([descriptor.name]);
} catch {}
} catch (error) {
void window.showErrorMessage(error.message);
}
}
async resolveWorkspaceRepositoriesByName(

불러오는 중...
취소
저장