Skip to content

Commit

Permalink
Refresh time full response (#25)
Browse files Browse the repository at this point in the history
* Added settings for group level, and project level. Added option for purgingIssues everytime, or not. Fix gitlab PAT reloading plugin. Fix gitlab icon.

* Options for Refresh Time, and onStartup Pull, refactors to not show groupid and project id in on personal, also updates issues to include entire response from gitlab api.

* Fixes linter Issues

* added a few tests

---------

Co-authored-by: Jonathan Deates <[email protected]>
  • Loading branch information
JonnyDeates and Jonathan Deates authored May 30, 2024
1 parent af0600a commit 98dbfbc
Show file tree
Hide file tree
Showing 8 changed files with 324 additions and 70 deletions.
12 changes: 6 additions & 6 deletions src/filesystem.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Issue } from "./issue";
import {Vault, TFile, TAbstractFile, TFolder} from "obsidian";
import { GitlabIssuesSettings } from "./settings";
import log from "./logger";
import { compile } from 'handlebars';
import defaultTemplate from './default-template';
import {ObsidianIssue} from "./types";

export default class Filesystem {

Expand Down Expand Up @@ -39,30 +39,30 @@ export default class Filesystem {
}
}

public processIssues(issues: Array<Issue>)
public processIssues(issues: Array<ObsidianIssue>)
{
this.vault.adapter.read(this.settings.templateFile)
.then((rawTemplate: string) => {
issues.map(
(issue: Issue) => this.writeFile(issue, compile(rawTemplate))
(issue: ObsidianIssue) => this.writeFile(issue, compile(rawTemplate))
);
})
.catch((error) => {
issues.map(
(issue: Issue) => this.writeFile(issue, compile(defaultTemplate.toString()))
(issue: ObsidianIssue) => this.writeFile(issue, compile(defaultTemplate.toString()))
);
})
;
}

private writeFile(issue: Issue, template: HandlebarsTemplateDelegate)
private writeFile(issue: ObsidianIssue, template: HandlebarsTemplateDelegate)
{
this.vault.create(this.buildFileName(issue), template(issue))
.catch((error) => log(error.message))
;
}

private buildFileName(issue: Issue): string
private buildFileName(issue: ObsidianIssue): string
{
return this.settings.outputDir + '/' + issue.filename + '.md';
}
Expand Down
4 changes: 2 additions & 2 deletions src/gitlab-loader.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import GitlabApi from "./gitlab-api";
import {GitlabIssue, Issue} from "./issue";
import {GitlabIssue} from "./issue";
import {App} from "obsidian";
import {GitlabIssuesSettings} from "./settings";
import Filesystem from "./filesystem";
import {Issue} from "./types";

export default class GitlabLoader {

Expand Down Expand Up @@ -34,7 +35,6 @@ export default class GitlabLoader {
if(this.settings.purgeIssues) {
this.fs.purgeExistingIssues();
}

this.fs.processIssues(gitlabIssues);
})
.catch(error => {
Expand Down
57 changes: 38 additions & 19 deletions src/issue.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,53 @@
import { sanitizeFileName } from './util';
import {sanitizeFileName} from './util';
import {Assignee, Epic, Issue, ObsidianIssue, References, ShortIssue, TimeStats} from "./types";

export interface Issue {
readonly id: number;
readonly title: string;
readonly description: string;
readonly due_date: string;
readonly web_url: string;
readonly references: string;
readonly filename: string;
}

export class GitlabIssue implements Issue {
export class GitlabIssue implements ObsidianIssue {

id: number;
title: string;
description: string;
due_date: string;
web_url: string;
references: string;
references: string | References;

get filename() {
return sanitizeFileName(this.title);
}

constructor(issue: Issue) {
this.id = issue.id;
this.title = issue.title;
this.description = issue.description;
this.due_date = issue.due_date;
this.web_url = issue.web_url;
this.references = issue.references;
Object.assign(this, issue);
}

_links: {
self: string;
notes: string;
award_emoji: string;
project: string;
closed_as_duplicate_of: string
};
assignees: Assignee[];
author: Assignee;
closed_by: Assignee;
confidential: boolean;
created_at: string;
discussion_locked: boolean;
downvotes: number;
epic: Epic;
has_tasks: boolean;
iid: number;
imported: boolean;
imported_from: string;
issue_type: string;
labels: string[];
merge_requests_count: number;
milestone: ShortIssue;
project_id: number;
severity: string;
state: string;
task_completion_status: { count: number; completed_count: number };
task_status: string;
time_stats: TimeStats;
updated_at: string;
upvotes: number;
user_notes_count: number;
}
67 changes: 36 additions & 31 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Notice, Plugin, addIcon} from 'obsidian';
import {addIcon, Notice, Plugin} from 'obsidian';
import {DEFAULT_SETTINGS, GitlabIssuesSettings, GitlabIssuesSettingTab} from './settings';
import log from "./logger";
import Filesystem from "./filesystem";
Expand All @@ -7,8 +7,8 @@ import gitlabIcon from './assets/gitlab-icon.svg';

export default class GitlabIssuesPlugin extends Plugin {
settings: GitlabIssuesSettings;
startupTimeout: number|null = null;
automaticRefresh: number|null = null;
startupTimeout: number | null = null;
automaticRefresh: number | null = null;
iconAdded = false;

async onload() {
Expand All @@ -17,6 +17,7 @@ export default class GitlabIssuesPlugin extends Plugin {
await this.loadSettings();
this.addSettingTab(new GitlabIssuesSettingTab(this.app, this));


if (this.settings.gitlabToken) {
this.createOutputFolder();
this.addIconToLeftRibbon();
Expand All @@ -26,12 +27,35 @@ export default class GitlabIssuesPlugin extends Plugin {
}
}

scheduleAutomaticRefresh() {
if (this.automaticRefresh) {
window.clearInterval(this.automaticRefresh);
}
if (this.settings.intervalOfRefresh !== "off") {
const intervalMinutes = parseInt(this.settings.intervalOfRefresh);

this.automaticRefresh = this.registerInterval(window.setInterval(() => {
this.fetchFromGitlab();
}, intervalMinutes * 60 * 1000)); // every settings interval in minutes
}
}

onunload() {

}

async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
}

async saveSettings() {
await this.saveData(this.settings);
}

private addIconToLeftRibbon() {
if (this.settings.showIcon)
{
if (this.settings.showIcon) {
// Ensure we did not already add an icon
if (!this.iconAdded)
{
if (!this.iconAdded) {
addIcon("gitlab", gitlabIcon);
this.addRibbonIcon('gitlab', 'Gitlab Issues', (evt: MouseEvent) => {
this.fetchFromGitlab();
Expand All @@ -56,40 +80,21 @@ export default class GitlabIssuesPlugin extends Plugin {
if (this.startupTimeout) {
window.clearTimeout(this.startupTimeout);
}
this.startupTimeout = this.registerInterval(window.setTimeout(() => {
this.fetchFromGitlab();
}, 30 * 1000)); // after 30 seconds
}

private scheduleAutomaticRefresh() {
if (this.automaticRefresh) {
window.clearInterval(this.automaticRefresh);
if(this.settings.refreshOnStartup) {
this.startupTimeout = this.registerInterval(window.setTimeout(() => {
this.fetchFromGitlab();
}, 30 * 1000)); // after 30 seconds
}
this.automaticRefresh = this.registerInterval(window.setInterval(() => {
this.fetchFromGitlab();
}, 15 * 60 * 1000)); // every 15 minutes
}

private createOutputFolder() {
const fs = new Filesystem(app.vault, this.settings);
fs.createOutputDirectory();
}

private fetchFromGitlab () {
private fetchFromGitlab() {
new Notice('Updating issues from Gitlab');
const loader = new GitlabLoader(this.app, this.settings);
loader.loadIssues();
}

onunload() {

}

async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
}

async saveSettings() {
await this.saveData(this.settings);
}
}
64 changes: 52 additions & 12 deletions src/settings.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import {App, normalizePath, PluginSettingTab, Setting} from "obsidian";
import GitlabIssuesPlugin from "./main";

type GitlabIssuesLevel = 'personal' | 'project' | 'group'

type GitlabIssuesLevel = 'personal' | 'project' | 'group';
type GitlabRefreshInterval = "15" | "30" | "45" |"60" | "120" | "off";

export interface GitlabIssuesSettings {
gitlabUrl: string;
Expand All @@ -13,6 +15,8 @@ export interface GitlabIssuesSettings {
filter: string;
showIcon: boolean;
purgeIssues: boolean;
refreshOnStartup: boolean;
intervalOfRefresh: GitlabRefreshInterval;
gitlabApiUrl(): string;
}

Expand All @@ -26,6 +30,8 @@ export const DEFAULT_SETTINGS: GitlabIssuesSettings = {
filter: 'due_date=month',
showIcon: false,
purgeIssues: true,
refreshOnStartup: true,
intervalOfRefresh: "15",
gitlabApiUrl(): string {
return `${this.gitlabUrl}/api/v4`;
}
Expand Down Expand Up @@ -102,6 +108,19 @@ export class GitlabIssuesSettingTab extends PluginSettingTab {
}));


new Setting(containerEl)

.setName('Refresh Rate')
.setDesc("That rate at which gitlab issues will be pulled.")
.addDropdown(value => value
.addOptions({off: "off", "15": "15", "30": "30", "45": "45", "60": "60", "120": "120"})
.setValue(this.plugin.settings.intervalOfRefresh)
.onChange(async (value: GitlabRefreshInterval) => {
this.plugin.settings.intervalOfRefresh = value;
this.plugin.scheduleAutomaticRefresh();
await this.plugin.saveSettings();
}));

new Setting(containerEl)
.setName('GitLab Level')
.addDropdown(value => value
Expand All @@ -110,18 +129,32 @@ export class GitlabIssuesSettingTab extends PluginSettingTab {
.onChange(async (value: GitlabIssuesLevel) => {
this.plugin.settings.gitlabIssuesLevel = value;
await this.plugin.saveSettings();
this.display();
}));

new Setting(containerEl)
.setName('Set Gitlab Project/Group Id')
.setDesc('If Group or Project is set, add the corresponding ID.')
.addText(value => value
.setValue(this.plugin.settings.gitlabAppId)
.onChange(async (value: string) => {
this.plugin.settings.gitlabAppId = value;
await this.plugin.saveSettings();
}));

if(this.plugin.settings.gitlabIssuesLevel !== "personal") {
const gitlabIssuesLevelIdObject = this.plugin.settings.gitlabIssuesLevel === 'group'
? {text: "Group", url: "https://docs.gitlab.com/ee/user/group/#get-the-group-id"}
: {text: "Project", url: "https://docs.gitlab.com/ee/user/project/working_with_projects.html#access-the-project-overview-page-by-using-the-project-id"};

const descriptionDocumentFragment = document.createDocumentFragment();
const descriptionLinkElement = descriptionDocumentFragment.createEl('a', {
href: gitlabIssuesLevelIdObject.url,
text: `Find your ${gitlabIssuesLevelIdObject.text} Id.`,
title: `Goto ${gitlabIssuesLevelIdObject.url}`
});
descriptionDocumentFragment.appendChild(descriptionLinkElement);

new Setting(containerEl)
.setName(`Set Gitlab ${gitlabIssuesLevelIdObject.text} Id`)
.setDesc(descriptionDocumentFragment)
.addText(value => value
.setValue(this.plugin.settings.gitlabAppId)
.onChange(async (value: string) => {
this.plugin.settings.gitlabAppId = value;
await this.plugin.saveSettings();
}));
}
new Setting(containerEl)
.setName('Purge issues that are no longer in Gitlab?')
.addToggle(value => value
Expand All @@ -139,7 +172,14 @@ export class GitlabIssuesSettingTab extends PluginSettingTab {
this.plugin.settings.showIcon = value;
await this.plugin.saveSettings();
}));

new Setting(containerEl)
.setName('Should refresh Gitlab issues on Startup?')
.addToggle(value => value
.setValue(this.plugin.settings.refreshOnStartup)
.onChange(async (value) => {
this.plugin.settings.refreshOnStartup = value;
await this.plugin.saveSettings();
}));
containerEl.createEl('h3', {text: 'More Information'});
containerEl.createEl('a', {
text: 'View the Gitlab documentation',
Expand Down
Loading

0 comments on commit 98dbfbc

Please sign in to comment.