diff --git a/src/data_providers/items/mr_item_model.ts b/src/data_providers/items/mr_item_model.ts index ed272c7d23fc202098de344db9d58135fd1ff345..80eb6413b7b4a09a025a9e9891539d558f7404f7 100644 --- a/src/data_providers/items/mr_item_model.ts +++ b/src/data_providers/items/mr_item_model.ts @@ -32,7 +32,9 @@ export class MrItemModel extends ItemModel { `!${iid} ยท ${title}`, vscode.TreeItemCollapsibleState.Collapsed, ); - item.iconPath = vscode.Uri.parse(author.avatar_url); + if (author.avatar_url) { + item.iconPath = vscode.Uri.parse(author.avatar_url); + } return item; } @@ -91,7 +93,7 @@ export class MrItemModel extends ItemModel { mode: vscode.CommentMode.Preview, author: { name: author.name, - iconPath: vscode.Uri.parse(author.avatarUrl), + iconPath: author.avatarUrl !== null ? vscode.Uri.parse(author.avatarUrl) : undefined, }, })); const position = notes.nodes[0]?.position as GqlPosition; // we filtered out all discussions without position diff --git a/src/gitlab/gitlab_new_service.ts b/src/gitlab/gitlab_new_service.ts index 126069bbfc201c380cd6ff002d55ccbb17359d61..6a30c07e9f1b567b2a639819d3c99dd2cb023c18 100644 --- a/src/gitlab/gitlab_new_service.ts +++ b/src/gitlab/gitlab_new_service.ts @@ -8,7 +8,7 @@ import * as assert from 'assert'; import { tokenService } from '../services/token_service'; import { FetchError } from '../errors/fetch_error'; import { getUserAgentHeader } from '../utils/get_user_agent_header'; -import { getAvatarUrl } from '../utils/get_avatar_url'; +import { ensureAbsoluteAvatarUrl } from '../utils/ensure_absolute_avatar_url'; import { getHttpAgentOptions } from '../utils/get_http_agent_options'; import { GitLabProject, GqlProject } from './gitlab_project'; import { getRestIdFromGraphQLId } from '../utils/get_rest_id_from_graphql_id'; @@ -43,15 +43,15 @@ export interface GqlBlob { path: string; } -interface GqlNoteAuthor { - avatarUrl: string; +interface GqlUser { + avatarUrl: string | null; name: string; username: string; webUrl: string; } interface GqlNote { id: string; - author: GqlNoteAuthor; + author: GqlUser; createdAt: string; system: boolean; body: string; // TODO: remove this once the SystemNote.vue doesn't require plain text body @@ -335,7 +335,8 @@ export class GitLabNewService { bodyHtml: note.bodyHtml.replace(/href="\//, `href="${this.instanceUrl}/`), author: { ...note.author, - avatarUrl: getAvatarUrl(this.instanceUrl, note.author.avatarUrl), + avatarUrl: + note.author.avatarUrl && ensureAbsoluteAvatarUrl(this.instanceUrl, note.author.avatarUrl), }, }); return { diff --git a/src/gitlab_service.ts b/src/gitlab_service.ts index c1ad4596a10ae22b92513aae89f5ab03dc6cbff0..7a0e66d200fbbc5ee53c0af61361282ff6994376 100644 --- a/src/gitlab_service.ts +++ b/src/gitlab_service.ts @@ -12,7 +12,7 @@ import { handleError, logError } from './log'; import { getUserAgentHeader } from './utils/get_user_agent_header'; import { CustomQueryType } from './gitlab/custom_query_type'; import { CustomQuery } from './gitlab/custom_query'; -import { getAvatarUrl } from './utils/get_avatar_url'; +import { ensureAbsoluteAvatarUrl } from './utils/ensure_absolute_avatar_url'; import { getHttpAgentOptions } from './utils/get_http_agent_options'; import { getInstanceUrl as getInstanceUrlUtil } from './utils/get_instance_url'; import { GitLabProject } from './gitlab/gitlab_project'; @@ -27,13 +27,19 @@ interface GitLabJob { created_at: string; } -const normalizeAvatarUrl = (instanceUrl: string) => (issuable: RestIssuable): RestIssuable => ({ - ...issuable, - author: { - ...issuable.author, - avatar_url: getAvatarUrl(instanceUrl, issuable.author.avatar_url), - }, -}); +const normalizeAvatarUrl = (instanceUrl: string) => (issuable: RestIssuable): RestIssuable => { + const { author } = issuable; + if (!author.avatar_url) { + return issuable; + } + return { + ...issuable, + author: { + ...author, + avatar_url: ensureAbsoluteAvatarUrl(instanceUrl, author.avatar_url), + }, + }; +}; const projectCache: Record = {}; let versionCache: string | null = null; diff --git a/src/types.d.ts b/src/types.d.ts index 8ee42097a4f0a5c6b4f64360de118f23b54dab5f..9f5e19d177cef087e20cdc71bf2e5cc6b0ebc5c3 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -13,7 +13,7 @@ interface RestIssuable { title: string; project_id: number; web_url: string; - author: { name: string; avatar_url: string }; + author: { name: string; avatar_url: string | null }; sha?: string; // only present in MR, legacy logic uses the presence to decide issuable type references: { full: string; // e.g. "gitlab-org/gitlab#219925" diff --git a/src/utils/get_avatar_url.ts b/src/utils/ensure_absolute_avatar_url.ts similarity index 66% rename from src/utils/get_avatar_url.ts rename to src/utils/ensure_absolute_avatar_url.ts index f55835f33aa7ee808ad9085fd02af135bf6e66c4..414aa51e96643377f220de083bb3dc9c56437c93 100644 --- a/src/utils/get_avatar_url.ts +++ b/src/utils/ensure_absolute_avatar_url.ts @@ -1,6 +1,6 @@ import * as vscode from 'vscode'; -export const getAvatarUrl = (instanceUrl: string, avatarUrl: string): string => { +export const ensureAbsoluteAvatarUrl = (instanceUrl: string, avatarUrl: string): string => { if (!avatarUrl.startsWith('/')) { return avatarUrl; }