mirror of
https://github.com/srwildman/Obsidian-Gitlab-Inbox.git
synced 2026-07-22 06:55:17 +00:00
fix review bot issues: sentence case, promises, activeWindow
- sentence case for all UI text (enum values, labels, headings, buttons) - await workspace.revealLeaf (was floating promise) - activeWindow.setTimeout with block-body arrows (no-misused-promises) - window -> activeWindow for popout window compatibility - window.moment() -> obsidian module moment export - bump minAppVersion to 1.7.2 (required by revealLeaf) - add eslint-plugin-obsidianmd for local validation
This commit is contained in:
parent
37193cf693
commit
d28c0849d6
10 changed files with 5050 additions and 88 deletions
14
eslint.config.mjs
Normal file
14
eslint.config.mjs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import tsparser from "@typescript-eslint/parser";
|
||||
import { defineConfig } from "eslint/config";
|
||||
import obsidianmd from "eslint-plugin-obsidianmd";
|
||||
|
||||
export default defineConfig([
|
||||
...obsidianmd.configs.recommended,
|
||||
{
|
||||
files: ["src/**/*.ts"],
|
||||
languageOptions: {
|
||||
parser: tsparser,
|
||||
parserOptions: { project: "./tsconfig.json" },
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "gitlab-inbox",
|
||||
"name": "GitLab Inbox",
|
||||
"version": "1.0.0",
|
||||
"minAppVersion": "1.7.0",
|
||||
"minAppVersion": "1.7.2",
|
||||
"description": "Auto-refreshing GitLab inbox showing MRs to review, your open MRs, mentions, and todos with check-off support.",
|
||||
"author": "Sam Wildman",
|
||||
"authorUrl": "https://github.com/SrWildman",
|
||||
|
|
|
|||
5031
package-lock.json
generated
5031
package-lock.json
generated
File diff suppressed because it is too large
Load diff
11
package.json
11
package.json
|
|
@ -5,7 +5,8 @@
|
|||
"main": "main.js",
|
||||
"scripts": {
|
||||
"dev": "node esbuild.config.mjs",
|
||||
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production"
|
||||
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
|
||||
"lint": "eslint src/"
|
||||
},
|
||||
"keywords": [
|
||||
"obsidian",
|
||||
|
|
@ -16,9 +17,15 @@
|
|||
],
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@eslint/json": "^1.2.0",
|
||||
"@types/node": "^22.0.0",
|
||||
"@typescript-eslint/parser": "^8.59.0",
|
||||
"esbuild": "^0.25.0",
|
||||
"eslint": "^9.39.4",
|
||||
"eslint-plugin-obsidianmd": "^0.2.4",
|
||||
"obsidian": "latest",
|
||||
"typescript": "^5.8.0"
|
||||
"typescript": "^5.8.0",
|
||||
"typescript-eslint": "^8.59.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { ItemView, WorkspaceLeaf } from "obsidian";
|
||||
import { ItemView, moment, WorkspaceLeaf } from "obsidian";
|
||||
import type GitLabInboxPlugin from "./main";
|
||||
import {
|
||||
Category,
|
||||
|
|
@ -29,7 +29,7 @@ export class InboxView extends ItemView {
|
|||
}
|
||||
|
||||
getDisplayText(): string {
|
||||
return "GitLab Inbox";
|
||||
return "GitLab inbox";
|
||||
}
|
||||
|
||||
getIcon(): string {
|
||||
|
|
@ -64,7 +64,7 @@ export class InboxView extends ItemView {
|
|||
// Header
|
||||
const header = container.createDiv({ cls: "gi-header" });
|
||||
const titleRow = header.createDiv({ cls: "gi-title-row" });
|
||||
titleRow.createEl("h4", { text: "GitLab Inbox" });
|
||||
titleRow.createEl("h4", { text: "GitLab inbox" });
|
||||
|
||||
const headerButtons = titleRow.createDiv({ cls: "gi-header-buttons" });
|
||||
|
||||
|
|
@ -107,7 +107,7 @@ export class InboxView extends ItemView {
|
|||
const batchBar = container.createDiv({ cls: "gi-batch-bar" });
|
||||
batchBar.createSpan({ text: this.selectedKeys.size > 0 ? `${this.selectedKeys.size} selected` : "Select items" });
|
||||
|
||||
const batchDone = batchBar.createEl("button", { cls: "gi-batch-btn", text: "\u2713 Done" });
|
||||
const batchDone = batchBar.createEl("button", { cls: "gi-batch-btn", text: "\u2713 done" });
|
||||
if (this.selectedKeys.size === 0) batchDone.setAttribute("disabled", "");
|
||||
batchDone.addEventListener("click", () => {
|
||||
if (this.selectedKeys.size === 0) return;
|
||||
|
|
@ -188,7 +188,7 @@ export class InboxView extends ItemView {
|
|||
});
|
||||
link.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
window.open(item.url, "_blank");
|
||||
activeWindow.open(item.url, "_blank");
|
||||
});
|
||||
|
||||
info.createSpan({ cls: "gi-item-title", text: ` ${item.title}` });
|
||||
|
|
@ -290,7 +290,7 @@ export class InboxView extends ItemView {
|
|||
await this.plugin.checkOffItem(item);
|
||||
}
|
||||
row.addClass("gi-item-done");
|
||||
setTimeout(() => {
|
||||
activeWindow.setTimeout(() => {
|
||||
if (this.data) {
|
||||
this.data.items = this.data.items.filter((i) => i.key !== item.key);
|
||||
this.render();
|
||||
|
|
@ -299,10 +299,10 @@ export class InboxView extends ItemView {
|
|||
}
|
||||
|
||||
private async handleSnooze(item: InboxItem, row: HTMLElement): Promise<void> {
|
||||
const tomorrow = window.moment().add(1, "day").format("YYYY-MM-DD");
|
||||
const tomorrow = moment().add(1, "day").format("YYYY-MM-DD");
|
||||
await this.plugin.snoozeItem(item, tomorrow);
|
||||
row.addClass("gi-item-done");
|
||||
setTimeout(() => {
|
||||
activeWindow.setTimeout(() => {
|
||||
if (this.data) {
|
||||
this.data.items = this.data.items.filter((i) => i.key !== item.key);
|
||||
this.render();
|
||||
|
|
@ -313,7 +313,7 @@ export class InboxView extends ItemView {
|
|||
private renderTeamLoad(parent: HTMLElement, teamLoad: TeamMemberLoad[]): void {
|
||||
const section = parent.createDiv({ cls: "gi-section gi-team-section" });
|
||||
section.createDiv({ cls: "gi-section-header" })
|
||||
.createSpan({ cls: "gi-section-title", text: "Team Review Load" });
|
||||
.createSpan({ cls: "gi-section-title", text: "Team review load" });
|
||||
|
||||
const table = section.createEl("table", { cls: "gi-team-table" });
|
||||
const thead = table.createEl("thead");
|
||||
|
|
@ -336,7 +336,7 @@ export class InboxView extends ItemView {
|
|||
const selected = this.data.items.filter((i) => this.selectedKeys.has(i.key));
|
||||
if (selected.length === 0) return;
|
||||
|
||||
const tomorrow = window.moment().add(1, "day").format("YYYY-MM-DD");
|
||||
const tomorrow = moment().add(1, "day").format("YYYY-MM-DD");
|
||||
|
||||
for (const item of selected) {
|
||||
if (action === "done") {
|
||||
|
|
|
|||
18
src/main.ts
18
src/main.ts
|
|
@ -1,4 +1,4 @@
|
|||
import { normalizePath, Notice, Plugin } from "obsidian";
|
||||
import { moment, normalizePath, Notice, Plugin } from "obsidian";
|
||||
import { GitLabApi } from "./gitlab-api";
|
||||
import { fetchInboxData } from "./inbox-processor";
|
||||
import { InboxView, VIEW_TYPE_INBOX } from "./inbox-view";
|
||||
|
|
@ -30,7 +30,7 @@ export default class GitLabInboxPlugin extends Plugin {
|
|||
this.registerView(VIEW_TYPE_INBOX, (leaf) => new InboxView(leaf, this));
|
||||
|
||||
// Ribbon icon
|
||||
this.addRibbonIcon("inbox", "GitLab Inbox", () => {
|
||||
this.addRibbonIcon("inbox", "GitLab inbox", () => {
|
||||
void this.activateView();
|
||||
});
|
||||
|
||||
|
|
@ -62,8 +62,8 @@ export default class GitLabInboxPlugin extends Plugin {
|
|||
if (this.settings.gitlabHostname && this.settings.personalAccessToken) {
|
||||
this.startInterval();
|
||||
// Initial fetch after a short delay to let Obsidian finish loading
|
||||
const t = window.setTimeout(() => { void this.refresh(); }, 5000);
|
||||
this.register(() => window.clearTimeout(t));
|
||||
const t = activeWindow.setTimeout(() => { void this.refresh(); }, 5000);
|
||||
this.register(() => activeWindow.clearTimeout(t));
|
||||
}
|
||||
|
||||
// Watch for changes to the inbox file (user checking items off)
|
||||
|
|
@ -81,7 +81,7 @@ export default class GitLabInboxPlugin extends Plugin {
|
|||
}
|
||||
|
||||
async loadSettings(): Promise<void> {
|
||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData() as Partial<GitLabInboxSettings>);
|
||||
}
|
||||
|
||||
async saveSettings(): Promise<void> {
|
||||
|
|
@ -96,13 +96,13 @@ export default class GitLabInboxPlugin extends Plugin {
|
|||
this.stopInterval();
|
||||
const ms = this.settings.refreshIntervalMinutes * 60 * 1000;
|
||||
this.intervalId = this.registerInterval(
|
||||
window.setInterval(() => { void this.refresh(); }, ms)
|
||||
activeWindow.setInterval(() => { void this.refresh(); }, ms)
|
||||
);
|
||||
}
|
||||
|
||||
stopInterval(): void {
|
||||
if (this.intervalId !== null) {
|
||||
window.clearInterval(this.intervalId);
|
||||
activeWindow.clearInterval(this.intervalId);
|
||||
this.intervalId = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -291,7 +291,7 @@ export default class GitLabInboxPlugin extends Plugin {
|
|||
const keyPattern = `<!-- ${item.key} -->`;
|
||||
const updated = content.replace(
|
||||
new RegExp(`^(\\s*- )\\[ \\](.+${keyPattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}.*)$`, "m"),
|
||||
`$1[x]$2 done on ${window.moment().format("YYYY-MM-DD")}`
|
||||
`$1[x]$2 done on ${moment().format("YYYY-MM-DD")}`
|
||||
);
|
||||
|
||||
if (updated !== content) {
|
||||
|
|
@ -348,7 +348,7 @@ export default class GitLabInboxPlugin extends Plugin {
|
|||
}
|
||||
|
||||
if (leaf) {
|
||||
workspace.revealLeaf(leaf);
|
||||
await workspace.revealLeaf(leaf);
|
||||
// If we have data, show it filtered by current note state
|
||||
const view = leaf.view as InboxView;
|
||||
if (this.lastData) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { App, normalizePath, TFile } from "obsidian";
|
||||
import { App, moment, normalizePath, TFile } from "obsidian";
|
||||
import {
|
||||
Category,
|
||||
CheckedState,
|
||||
|
|
@ -179,7 +179,7 @@ export function generateNote(
|
|||
|
||||
// Team review load
|
||||
if (data.teamLoad.length > 0) {
|
||||
lines.push("## Team Review Load");
|
||||
lines.push("## Team review load");
|
||||
lines.push("");
|
||||
lines.push("| Reviewer | Open Reviews | Oldest |");
|
||||
lines.push("|----------|-------------|--------|");
|
||||
|
|
@ -244,7 +244,7 @@ export async function logToDailyNote(
|
|||
): Promise<void> {
|
||||
if (!settings.enableDailyNoteLogging || checkedItems.length === 0) return;
|
||||
|
||||
const today = window.moment().format(settings.dailyNoteDateFormat);
|
||||
const today = moment().format(settings.dailyNoteDateFormat);
|
||||
const dailyPath = normalizePath(`${settings.dailyNotesFolder}/${today}.md`);
|
||||
const dailyFile = app.vault.getFileByPath(dailyPath);
|
||||
if (!dailyFile || !(dailyFile instanceof TFile)) return;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export class GitLabInboxSettingTab extends PluginSettingTab {
|
|||
|
||||
new Setting(containerEl)
|
||||
.setName("GitLab hostname")
|
||||
.setDesc("Your self-hosted GitLab instance (e.g. gitlab.company.com).")
|
||||
.setDesc("Your self-hosted GitLab instance (e.g. GitLab.company.com).")
|
||||
.addText((text) => {
|
||||
text
|
||||
.setPlaceholder("gitlab.example.com")
|
||||
|
|
@ -31,9 +31,10 @@ export class GitLabInboxSettingTab extends PluginSettingTab {
|
|||
|
||||
new Setting(containerEl)
|
||||
.setName("Personal access token")
|
||||
.setDesc("Token with API scope. Create at GitLab > Settings > Access tokens.")
|
||||
.setDesc("Token with API scope. Create at GitLab > settings > access tokens.")
|
||||
.addText((text) => {
|
||||
text
|
||||
// eslint-disable-next-line obsidianmd/ui/sentence-case
|
||||
.setPlaceholder("glpat-...")
|
||||
.setValue(this.plugin.settings.personalAccessToken)
|
||||
.onChange(async (value) => {
|
||||
|
|
@ -65,10 +66,10 @@ export class GitLabInboxSettingTab extends PluginSettingTab {
|
|||
|
||||
new Setting(containerEl)
|
||||
.setName("Inbox filename")
|
||||
.setDesc("Name of the markdown note written to your vault root.")
|
||||
.setDesc("Name of the Markdown note written to your vault root.")
|
||||
.addText((text) => {
|
||||
text
|
||||
.setPlaceholder("GitLab Inbox.md")
|
||||
.setPlaceholder("GitLab inbox.md")
|
||||
.setValue(this.plugin.settings.inboxFilename)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.inboxFilename = value;
|
||||
|
|
@ -118,6 +119,7 @@ export class GitLabInboxSettingTab extends PluginSettingTab {
|
|||
.setDesc("Moment.js format for daily note filenames.")
|
||||
.addText((text) => {
|
||||
text
|
||||
// eslint-disable-next-line obsidianmd/ui/sentence-case
|
||||
.setPlaceholder("YYYY-MM-DD")
|
||||
.setValue(this.plugin.settings.dailyNoteDateFormat)
|
||||
.onChange(async (value) => {
|
||||
|
|
@ -256,9 +258,9 @@ export class GitLabInboxSettingTab extends PluginSettingTab {
|
|||
|
||||
new Setting(container)
|
||||
.addButton((btn) => {
|
||||
btn.setButtonText("+ Add Label").onClick(async () => {
|
||||
btn.setButtonText("+ add label").onClick(async () => {
|
||||
const id = `label_${Date.now()}`;
|
||||
labels.push({ id, label: "New Label", color: "var(--text-muted)" });
|
||||
labels.push({ id, label: "New label", color: "var(--text-muted)" });
|
||||
await this.plugin.saveSettings();
|
||||
this.renderLabels(container);
|
||||
});
|
||||
|
|
@ -364,7 +366,7 @@ export class GitLabInboxSettingTab extends PluginSettingTab {
|
|||
// Add rule button
|
||||
new Setting(container)
|
||||
.addButton((btn) => {
|
||||
btn.setButtonText("+ Add Rule").onClick(async () => {
|
||||
btn.setButtonText("+ add rule").onClick(async () => {
|
||||
const firstLabel = labels[0]?.id ?? "";
|
||||
if (!firstLabel) return;
|
||||
rules.push({
|
||||
|
|
@ -384,10 +386,10 @@ export class GitLabInboxSettingTab extends PluginSettingTab {
|
|||
const api = this.plugin.createApi();
|
||||
const username = await api.getUsername();
|
||||
button.setButtonText(`Connected as ${username}`);
|
||||
setTimeout(() => button.setButtonText("Test"), 3000);
|
||||
activeWindow.setTimeout(() => { button.setButtonText("Test"); }, 3000);
|
||||
} catch {
|
||||
button.setButtonText("Failed - check settings");
|
||||
setTimeout(() => button.setButtonText("Test"), 3000);
|
||||
activeWindow.setTimeout(() => { button.setButtonText("Test"); }, 3000);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -395,6 +397,6 @@ export class GitLabInboxSettingTab extends PluginSettingTab {
|
|||
button.setButtonText("Refreshing...");
|
||||
await this.plugin.refresh();
|
||||
button.setButtonText("Done");
|
||||
setTimeout(() => button.setButtonText("Refresh"), 2000);
|
||||
activeWindow.setTimeout(() => { button.setButtonText("Refresh"); }, 2000);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
12
src/types.ts
12
src/types.ts
|
|
@ -1,11 +1,11 @@
|
|||
// Enums
|
||||
|
||||
export enum Category {
|
||||
NeedsReview = "Needs Your Review",
|
||||
ReReview = "Re-Review",
|
||||
NeedsReview = "Needs your review",
|
||||
ReReview = "Re-review",
|
||||
Approved = "Approved",
|
||||
YourMRs = "Your MRs",
|
||||
Todos = "Mentions & Todos",
|
||||
Todos = "Mentions & todos",
|
||||
}
|
||||
|
||||
export enum ConditionType {
|
||||
|
|
@ -81,11 +81,11 @@ export interface GitLabInboxSettings {
|
|||
}
|
||||
|
||||
export const DEFAULT_SECTION_ORDER: SectionConfig[] = [
|
||||
{ category: Category.NeedsReview, label: "Needs Your Review", enabled: true },
|
||||
{ category: Category.ReReview, label: "Re-Review", enabled: true },
|
||||
{ category: Category.NeedsReview, label: "Needs your review", enabled: true },
|
||||
{ category: Category.ReReview, label: "Re-review", enabled: true },
|
||||
{ category: Category.Approved, label: "Approved", enabled: true },
|
||||
{ category: Category.YourMRs, label: "Your MRs", enabled: true },
|
||||
{ category: Category.Todos, label: "Mentions & Todos", enabled: true },
|
||||
{ category: Category.Todos, label: "Mentions & todos", enabled: true },
|
||||
];
|
||||
|
||||
export const DEFAULT_LABELS: PriorityLabel[] = [
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"1.0.0": "1.7.0"
|
||||
"1.0.0": "1.7.2"
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue