diff --git a/package-lock.json b/package-lock.json index 0e55479..1dd2a26 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,8 @@ "@octokit/core": "^5.1.0", "@octokit/openapi-types": "^19.1.0", "@octokit/plugin-rest-endpoint-methods": "^10.3.0", - "@octokit/request": "^8.2.0" + "@octokit/request": "^8.2.0", + "queue": "^7.0.0" }, "devDependencies": { "@codemirror/view": "^6.23.0", @@ -28,7 +29,6 @@ "obsidian": "latest", "octokit": "^3.1.2", "prettier": "^3.2.5", - "queue": "^7.0.0", "tslib": "2.6.2", "typescript": "5.3.3" } @@ -2484,8 +2484,7 @@ "node_modules/queue": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/queue/-/queue-7.0.0.tgz", - "integrity": "sha512-sphwS7HdfQnvrJAXUNAUgpf9H/546IE3p/5Lf2jr71O4udEYlqAhkevykumas2FYuMkX/29JMOgrRdRoYZ/X9w==", - "dev": true + "integrity": "sha512-sphwS7HdfQnvrJAXUNAUgpf9H/546IE3p/5Lf2jr71O4udEYlqAhkevykumas2FYuMkX/29JMOgrRdRoYZ/X9w==" }, "node_modules/queue-microtask": { "version": "1.2.3", diff --git a/package.json b/package.json index 2a4bc76..f1c7a17 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,6 @@ "obsidian": "latest", "octokit": "^3.1.2", "prettier": "^3.2.5", - "queue": "^7.0.0", "tslib": "2.6.2", "typescript": "5.3.3" }, @@ -37,6 +36,7 @@ "@octokit/core": "^5.1.0", "@octokit/openapi-types": "^19.1.0", "@octokit/plugin-rest-endpoint-methods": "^10.3.0", - "@octokit/request": "^8.2.0" + "@octokit/request": "^8.2.0", + "queue": "^7.0.0" } } \ No newline at end of file diff --git a/src/github/api.ts b/src/github/api.ts index 461dc45..c8f3074 100644 --- a/src/github/api.ts +++ b/src/github/api.ts @@ -25,17 +25,21 @@ export class GitHubApi { private static rateLimitReset: Date | null = null; private static q = new Queue({ autostart: true, concurrency: 1 }); - public async queueRequest(config: RequestUrlParam, token?: string): Promise { + public queueRequest(config: RequestUrlParam, token?: string): Promise { // Responses we (probably) have cached will skip the queue if (getCache().get(config)) { return this.githubRequest(config, token); } - const { resolve, promise } = promiseWithResolvers(); + const { resolve, reject, promise } = promiseWithResolvers(); GitHubApi.q.push(() => { - return this.githubRequest(config, token).then((result) => { - resolve(result); - }); + return this.githubRequest(config, token) + .then((result) => { + resolve(result); + }) + .catch((err) => { + reject(err); + }); }); return promise; } @@ -175,7 +179,8 @@ export class GitHubApi { return response; } catch (err) { - throw new RequestError(err as Error); + logger.debug(err); + return Promise.reject(new RequestError(err as Error)); } } diff --git a/src/inline/inline.ts b/src/inline/inline.ts index 01540f8..adef149 100644 --- a/src/inline/inline.ts +++ b/src/inline/inline.ts @@ -7,6 +7,7 @@ import { parseUrl } from "../github/url-parse"; import { setIcon } from "obsidian"; import { setIssueIcon, setPRIcon, setPRMergeableIcon } from "src/icon"; import { PluginSettings } from "src/plugin"; +import { RequestError } from "src/util"; interface TagConfig { icon: HTMLSpanElement; @@ -34,7 +35,7 @@ export function createTag(href: string): HTMLAnchorElement { } if (parsedUrl.issue !== undefined) { - createIssueSection(config, parsedUrl); + createIssueSection(config, parsedUrl, container); } else if (parsedUrl.pr !== undefined) { createPullRequestSection(config, parsedUrl, container); } @@ -84,7 +85,7 @@ function createRepoSection(config: TagConfig, parsedUrl: ParsedUrl) { } } -function createIssueSection(config: TagConfig, parsedUrl: ParsedUrl) { +function createIssueSection(config: TagConfig, parsedUrl: ParsedUrl, container: HTMLAnchorElement) { if (parsedUrl.issue === undefined) { return; } @@ -95,17 +96,21 @@ function createIssueSection(config: TagConfig, parsedUrl: ParsedUrl) { }); config.sections.push(issueContainer); if (parsedUrl.org && parsedUrl.repo) { - getIssue(parsedUrl.org, parsedUrl.repo, parsedUrl.issue).then((issue) => { - if (issue.title) { - const status = getIssueStatus(issue); - setIssueIcon(config.icon, status); - issueContainer.setText(issue.title); - } - }); + getIssue(parsedUrl.org, parsedUrl.repo, parsedUrl.issue) + .then((issue) => { + if (issue.title) { + const status = getIssueStatus(issue); + setIssueIcon(config.icon, status); + issueContainer.setText(issue.title); + } + }) + .catch((err) => { + createErrorSection(config, container, err); + }); } } -function createPullRequestSection(config: TagConfig, parsedUrl: ParsedUrl, tag: HTMLElement) { +function createPullRequestSection(config: TagConfig, parsedUrl: ParsedUrl, container: HTMLAnchorElement) { if (parsedUrl.pr === undefined) { return; } @@ -116,28 +121,44 @@ function createPullRequestSection(config: TagConfig, parsedUrl: ParsedUrl, tag: }); config.sections.push(prContainer); if (parsedUrl.org && parsedUrl.repo) { - getPullRequest(parsedUrl.org, parsedUrl.repo, parsedUrl.pr).then((pr) => { - if (pr.title) { - const status = getPRStatus(pr); - setPRIcon(config.icon, status); - prContainer.setText(pr.title); - } - createPullRequestMergeableSection(config, pr, tag); - }); + getPullRequest(parsedUrl.org, parsedUrl.repo, parsedUrl.pr) + .then((pr) => { + if (pr.title) { + const status = getPRStatus(pr); + setPRIcon(config.icon, status); + prContainer.setText(pr.title); + } + createPullRequestMergeableSection(config, pr, container); + }) + .catch((err) => { + createErrorSection(config, container, err); + }); } } /** * Note that this function is called AFTER the tag has been built, so it adds itself to the dom. */ -function createPullRequestMergeableSection(config: TagConfig, pullRequest: PullResponse, tag: HTMLElement): void { +function createPullRequestMergeableSection(config: TagConfig, pullRequest: PullResponse, container: HTMLElement): void { if (!PluginSettings.tagShowPRMergeable || pullRequest.mergeable === null) { return; } const mergeableIcon = createSpan({ cls: ["github-link-inline-pr-mergeable-icon", "github-link-inline-icon"] }); setPRMergeableIcon(mergeableIcon, pullRequest.mergeable); config.sections.push(mergeableIcon); - tag.appendChild(createTagSection(mergeableIcon)); + container.appendChild(createTagSection(mergeableIcon)); +} + +function createErrorSection(config: TagConfig, container: HTMLAnchorElement, error: unknown) { + const errorIcon = createSpan({ + cls: ["github-link-inline-error-icon", "github-link-inline-icon"], + }); + setIcon(errorIcon, "lucide-alert-triangle"); + if (error instanceof RequestError) { + errorIcon.ariaLabel = error.message; + } + config.sections.push(errorIcon); + container.appendChild(createTagSection(errorIcon)); } export async function InlineRenderer(el: HTMLElement) { diff --git a/styles.css b/styles.css index a1b36bb..cbc7ba8 100644 --- a/styles.css +++ b/styles.css @@ -245,6 +245,11 @@ body.theme-dark { background-color: var(--gh-color-danger-subtle); border-color: var(--gh-color-danger-emphasis); } +.github-link-inline-section:has(> .github-link-inline-error-icon) { + color: var(--gh-color-closed-fg); + background-color: var(--gh-color-danger-subtle); + border-color: var(--gh-color-danger-emphasis); +} .github-link-inline-section:has(> .github-link-inline-repo) { background-color: var(--gh-color-accent-subtle);