mirror of
https://github.com/nwbort/obsidian-harvest.git
synced 2026-07-22 06:43:24 +00:00
Remove compiled files from repo
This commit is contained in:
parent
a3602ed818
commit
66ac00f68f
2 changed files with 3 additions and 534 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -7,4 +7,6 @@ npm-debug.log*
|
|||
|
||||
node_modules/
|
||||
|
||||
*.tsbuildinfo
|
||||
*.tsbuildinfo
|
||||
|
||||
main.js
|
||||
|
|
|
|||
533
main.js
533
main.js
|
|
@ -1,533 +0,0 @@
|
|||
/*
|
||||
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
||||
if you want to view the source, please visit the github repository of this plugin
|
||||
*/
|
||||
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// main.ts
|
||||
var main_exports = {};
|
||||
__export(main_exports, {
|
||||
default: () => HarvestPlugin
|
||||
});
|
||||
module.exports = __toCommonJS(main_exports);
|
||||
var import_obsidian = require("obsidian");
|
||||
function parseQuery(source) {
|
||||
const tokens = source.trim().split(/\s+/).map((t) => t.toUpperCase());
|
||||
if (tokens.length < 2)
|
||||
throw new Error("Query is too short.");
|
||||
const type = tokens[0];
|
||||
if (type !== "LIST" /* LIST */ && type !== "SUMMARY" /* SUMMARY */) {
|
||||
throw new Error(`Invalid query type: ${type}. Must be LIST or SUMMARY.`);
|
||||
}
|
||||
const { from, to } = parseTimeRange(tokens.slice(1));
|
||||
return { type, from, to };
|
||||
}
|
||||
function parseTimeRange(tokens) {
|
||||
const today = new Date();
|
||||
const formatDate = (date) => {
|
||||
const year = date.getFullYear();
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, "0");
|
||||
const day = date.getDate().toString().padStart(2, "0");
|
||||
return `${year}-${month}-${day}`;
|
||||
};
|
||||
let from;
|
||||
let to;
|
||||
switch (tokens[0]) {
|
||||
case "TODAY":
|
||||
from = today;
|
||||
to = today;
|
||||
break;
|
||||
case "WEEK": {
|
||||
const dayOfWeek = today.getDay();
|
||||
const firstDayOfWeek = new Date(today.setDate(today.getDate() - dayOfWeek + (dayOfWeek === 0 ? -6 : 1)));
|
||||
from = firstDayOfWeek;
|
||||
to = new Date(new Date(firstDayOfWeek).setDate(firstDayOfWeek.getDate() + 6));
|
||||
break;
|
||||
}
|
||||
case "MONTH":
|
||||
from = new Date(today.getFullYear(), today.getMonth(), 1);
|
||||
to = new Date(today.getFullYear(), today.getMonth() + 1, 0);
|
||||
break;
|
||||
case "PAST": {
|
||||
const count = parseInt(tokens[1]);
|
||||
if (isNaN(count) || tokens[2] !== "DAYS")
|
||||
throw new Error("Invalid PAST format. Use 'PAST <number> DAYS'.");
|
||||
to = today;
|
||||
from = new Date(new Date().setDate(today.getDate() - (count - 1)));
|
||||
break;
|
||||
}
|
||||
case "FROM": {
|
||||
if (tokens.length < 4 || tokens[2] !== "TO")
|
||||
throw new Error("Invalid FROM...TO format.");
|
||||
from = new Date(tokens[1]);
|
||||
to = new Date(tokens[3]);
|
||||
if (isNaN(from.getTime()) || isNaN(to.getTime()))
|
||||
throw new Error("Invalid date format in FROM...TO. Use YYYY-MM-DD.");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error(`Unknown time range specifier: ${tokens[0]}`);
|
||||
}
|
||||
return { from: formatDate(from), to: formatDate(to) };
|
||||
}
|
||||
function renderReport(container, entries, query) {
|
||||
container.empty();
|
||||
const wrapper = container.createDiv({ cls: "harvest-report" });
|
||||
if (entries.length === 0) {
|
||||
wrapper.createEl("p", { text: "No time entries found for the selected period." });
|
||||
return;
|
||||
}
|
||||
if (query.type === "LIST" /* LIST */) {
|
||||
renderList(wrapper, entries);
|
||||
} else if (query.type === "SUMMARY" /* SUMMARY */) {
|
||||
renderSummary(wrapper, entries);
|
||||
}
|
||||
}
|
||||
function renderList(container, entries) {
|
||||
const table = container.createEl("table", { cls: "harvest-table" });
|
||||
const thead = table.createTHead();
|
||||
const headerRow = thead.insertRow();
|
||||
headerRow.createEl("th", { text: "Project" });
|
||||
headerRow.createEl("th", { text: "Task" });
|
||||
headerRow.createEl("th", { text: "Date" });
|
||||
headerRow.createEl("th", { text: "Hours" });
|
||||
const tbody = table.createTBody();
|
||||
for (const entry of entries) {
|
||||
const row = tbody.insertRow();
|
||||
row.createEl("td", { text: entry.project.name });
|
||||
row.createEl("td", { text: entry.task.name });
|
||||
row.createEl("td", { text: entry.spent_date });
|
||||
row.createEl("td", { text: entry.hours.toFixed(2), cls: "harvest-hours" });
|
||||
}
|
||||
}
|
||||
function renderSummary(container, entries) {
|
||||
let totalHours = 0;
|
||||
const projectTotals = {};
|
||||
for (const entry of entries) {
|
||||
totalHours += entry.hours;
|
||||
const projectName = entry.project.name;
|
||||
if (!projectTotals[projectName]) {
|
||||
projectTotals[projectName] = 0;
|
||||
}
|
||||
projectTotals[projectName] += entry.hours;
|
||||
}
|
||||
container.createEl("h3", { text: "Time summary" });
|
||||
const summaryDiv = container.createDiv({ cls: "harvest-summary" });
|
||||
summaryDiv.createEl("p").createEl("strong", { text: `Total hours: ${totalHours.toFixed(2)}` });
|
||||
const barChartContainer = summaryDiv.createDiv({ cls: "harvest-barchart-container" });
|
||||
const colors = ["#84b65a", "#c25956", "#59a7c2", "#c29b59", "#8e59c2", "#c2598e", "#5ac28a"];
|
||||
let colorIndex = 0;
|
||||
const sortedProjects = Object.keys(projectTotals).sort((a, b) => projectTotals[b] - projectTotals[a]);
|
||||
for (const projectName of sortedProjects) {
|
||||
const projectHours = projectTotals[projectName];
|
||||
const percentage = totalHours > 0 ? projectHours / totalHours * 100 : 0;
|
||||
const color = colors[colorIndex % colors.length];
|
||||
const bar = barChartContainer.createDiv({ cls: "harvest-barchart-bar" });
|
||||
bar.style.setProperty("--bar-width", `${percentage}%`);
|
||||
bar.style.setProperty("--bar-color", color);
|
||||
bar.title = `${projectName}: ${projectHours.toFixed(2)} hours`;
|
||||
colorIndex++;
|
||||
}
|
||||
const legendContainer = summaryDiv.createDiv({ cls: "harvest-barchart-legend" });
|
||||
colorIndex = 0;
|
||||
for (const projectName of sortedProjects) {
|
||||
const projectHours = projectTotals[projectName];
|
||||
const color = colors[colorIndex % colors.length];
|
||||
const legendItem = legendContainer.createDiv({ cls: "harvest-legend-item" });
|
||||
const colorSwatch = legendItem.createDiv({ cls: "harvest-legend-swatch" });
|
||||
colorSwatch.style.backgroundColor = color;
|
||||
legendItem.createSpan({ text: `${projectName}: ${projectHours.toFixed(2)} hours` });
|
||||
colorIndex++;
|
||||
}
|
||||
}
|
||||
var hqlProcessor = (plugin) => async (source, el, ctx) => {
|
||||
try {
|
||||
const query = parseQuery(source);
|
||||
if (!query)
|
||||
return;
|
||||
el.setText("Loading Harvest report...");
|
||||
const entries = await plugin.getTimeEntries(query);
|
||||
if (entries) {
|
||||
renderReport(el, entries, query);
|
||||
} else {
|
||||
el.setText("Failed to fetch Harvest report.");
|
||||
}
|
||||
} catch (e) {
|
||||
el.setText(`Error processing Harvest query: ${e.message}`);
|
||||
}
|
||||
};
|
||||
var DEFAULT_SETTINGS = {
|
||||
personalAccessToken: "",
|
||||
accountId: "",
|
||||
pollingInterval: 5,
|
||||
// Default to 5 minutes
|
||||
folderProjectCache: {}
|
||||
};
|
||||
var HarvestPlugin = class extends import_obsidian.Plugin {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.runningTimer = null;
|
||||
this.projectCache = [];
|
||||
// Cache for the combined project list
|
||||
this.userId = null;
|
||||
}
|
||||
async onload() {
|
||||
await this.loadSettings();
|
||||
this.statusBarItemEl = this.addStatusBarItem();
|
||||
this.statusBarItemEl.setText("Harvest");
|
||||
this.statusBarItemEl.addClass("mod-clickable");
|
||||
this.statusBarItemEl.addEventListener("click", () => void this.toggleTimer());
|
||||
this.addSettingTab(new HarvestSettingTab(this.app, this));
|
||||
if (this.settings.personalAccessToken && this.settings.accountId) {
|
||||
await this.fetchCurrentUserId();
|
||||
}
|
||||
void this.fetchAllTrackableProjects();
|
||||
this.addCommand({
|
||||
id: "start-timer",
|
||||
name: "Start timer",
|
||||
callback: () => {
|
||||
void new ProjectSuggestModal(this.app, this, this.app.workspace.getActiveFile()).open();
|
||||
}
|
||||
});
|
||||
this.addCommand({
|
||||
id: "stop-timer",
|
||||
name: "Stop timer",
|
||||
callback: async () => {
|
||||
if (this.runningTimer) {
|
||||
await this.stopTimer(this.runningTimer.id);
|
||||
} else {
|
||||
new import_obsidian.Notice("No timer is currently running.");
|
||||
}
|
||||
}
|
||||
});
|
||||
this.addCommand({
|
||||
id: "toggle-timer",
|
||||
name: "Toggle timer",
|
||||
callback: async () => {
|
||||
await this.toggleTimer();
|
||||
}
|
||||
});
|
||||
this.addCommand({
|
||||
id: "refresh-projects",
|
||||
name: "Refresh projects",
|
||||
callback: async () => {
|
||||
new import_obsidian.Notice("Refreshing project list from Harvest...");
|
||||
await this.fetchAllTrackableProjects(true);
|
||||
new import_obsidian.Notice("Project list has been updated.");
|
||||
}
|
||||
});
|
||||
this.registerMarkdownCodeBlockProcessor("harvest", hqlProcessor(this));
|
||||
const pollingMinutes = this.settings.pollingInterval > 0 ? this.settings.pollingInterval : 5;
|
||||
this.timerInterval = window.setInterval(() => void this.updateRunningTimer(), pollingMinutes * 60 * 1e3);
|
||||
void this.updateRunningTimer();
|
||||
}
|
||||
onunload() {
|
||||
if (this.timerInterval) {
|
||||
clearInterval(this.timerInterval);
|
||||
}
|
||||
}
|
||||
async loadSettings() {
|
||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||
}
|
||||
async saveSettings() {
|
||||
await this.saveData(this.settings);
|
||||
}
|
||||
async request(endpoint, method = "GET", body = null) {
|
||||
if (!this.settings.personalAccessToken || !this.settings.accountId) {
|
||||
new import_obsidian.Notice("Harvest API credentials are not set.");
|
||||
return null;
|
||||
}
|
||||
const headers = {
|
||||
"Authorization": `Bearer ${this.settings.personalAccessToken}`,
|
||||
"Harvest-Account-Id": this.settings.accountId,
|
||||
"User-Agent": "Obsidian Harvest Integration",
|
||||
"Content-Type": "application/json"
|
||||
};
|
||||
try {
|
||||
const response = await (0, import_obsidian.requestUrl)({
|
||||
url: `https://api.harvestapp.com/v2${endpoint}`,
|
||||
method,
|
||||
headers,
|
||||
body: body ? JSON.stringify(body) : void 0
|
||||
});
|
||||
if (response.status >= 400) {
|
||||
new import_obsidian.Notice(`Harvest API error: ${response.json.message || response.status}`);
|
||||
return null;
|
||||
}
|
||||
return response.json;
|
||||
} catch (error) {
|
||||
new import_obsidian.Notice("Failed to connect to Harvest API.");
|
||||
console.error("Harvest API request error:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
async fetchCurrentUserId() {
|
||||
const me = await this.request("/users/me");
|
||||
if (me && me.id) {
|
||||
this.userId = me.id;
|
||||
} else {
|
||||
this.userId = null;
|
||||
new import_obsidian.Notice("Could not retrieve Harvest user ID.");
|
||||
console.error("Failed to fetch Harvest user ID.");
|
||||
}
|
||||
}
|
||||
async getTimeEntries(query) {
|
||||
if (!this.userId) {
|
||||
new import_obsidian.Notice("Harvest user ID not found. Cannot fetch your time entries.");
|
||||
return [];
|
||||
}
|
||||
const endpoint = `/time_entries?from=${query.from}&to=${query.to}&user_id=${this.userId}`;
|
||||
const data = await this.request(endpoint);
|
||||
if (data && data.time_entries) {
|
||||
return data.time_entries;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
async fetchAllTrackableProjects(forceRefresh = false) {
|
||||
if (this.projectCache.length > 0 && !forceRefresh) {
|
||||
return this.projectCache;
|
||||
}
|
||||
const managedProjects = await this.getManagedProjects();
|
||||
const recentProjects = await this.getRecentProjectsFromTimeEntries();
|
||||
const combinedProjectMap = /* @__PURE__ */ new Map();
|
||||
managedProjects.forEach((proj) => combinedProjectMap.set(proj.id, proj));
|
||||
recentProjects.forEach((proj) => {
|
||||
if (!combinedProjectMap.has(proj.id)) {
|
||||
combinedProjectMap.set(proj.id, proj);
|
||||
}
|
||||
});
|
||||
const sortedProjects = Array.from(combinedProjectMap.values()).sort((a, b) => a.name.localeCompare(b.name));
|
||||
this.projectCache = sortedProjects;
|
||||
return this.projectCache;
|
||||
}
|
||||
async getManagedProjects() {
|
||||
let allProjects = [];
|
||||
let page = 1;
|
||||
let totalPages = 1;
|
||||
do {
|
||||
const data = await this.request(`/projects?is_active=true&page=${page}`);
|
||||
if (data && data.projects) {
|
||||
allProjects = allProjects.concat(data.projects);
|
||||
totalPages = data.total_pages;
|
||||
page++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while (page <= totalPages);
|
||||
return allProjects;
|
||||
}
|
||||
async getRecentProjectsFromTimeEntries() {
|
||||
if (!this.userId)
|
||||
return [];
|
||||
const thirtyDaysAgo = new Date();
|
||||
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
|
||||
const fromDate = thirtyDaysAgo.toISOString().split("T")[0];
|
||||
const data = await this.request(`/time_entries?from=${fromDate}&user_id=${this.userId}`);
|
||||
if (!data || !data.time_entries)
|
||||
return [];
|
||||
const recentProjectsMap = /* @__PURE__ */ new Map();
|
||||
data.time_entries.forEach((entry) => {
|
||||
if (entry.project && !recentProjectsMap.has(entry.project.id)) {
|
||||
recentProjectsMap.set(entry.project.id, entry.project);
|
||||
}
|
||||
});
|
||||
return Array.from(recentProjectsMap.values());
|
||||
}
|
||||
async startTimer(projectId, taskId, activeFile) {
|
||||
if (activeFile && activeFile.parent) {
|
||||
const folderPath = activeFile.parent.path;
|
||||
this.settings.folderProjectCache[folderPath] = { projectId, taskId };
|
||||
await this.saveSettings();
|
||||
}
|
||||
const today = new Date();
|
||||
const year = today.getFullYear();
|
||||
const month = (today.getMonth() + 1).toString().padStart(2, "0");
|
||||
const day = today.getDate().toString().padStart(2, "0");
|
||||
const spentDate = `${year}-${month}-${day}`;
|
||||
if (this.userId) {
|
||||
const data = await this.request(`/time_entries?from=${spentDate}&to=${spentDate}&user_id=${this.userId}`);
|
||||
if (data && data.time_entries) {
|
||||
const existingEntry = data.time_entries.find(
|
||||
(entry) => entry.project.id === projectId && entry.task.id === taskId
|
||||
);
|
||||
if (existingEntry) {
|
||||
const result2 = await this.request(`/time_entries/${existingEntry.id}/restart`, "PATCH");
|
||||
if (result2) {
|
||||
new import_obsidian.Notice("Timer restarted!");
|
||||
void this.updateRunningTimer();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
const body = {
|
||||
project_id: projectId,
|
||||
task_id: taskId,
|
||||
spent_date: spentDate
|
||||
};
|
||||
const result = await this.request("/time_entries", "POST", body);
|
||||
if (result) {
|
||||
new import_obsidian.Notice("Timer started!");
|
||||
void this.updateRunningTimer();
|
||||
}
|
||||
}
|
||||
async updateRunningTimer() {
|
||||
if (!this.userId)
|
||||
return;
|
||||
const data = await this.request(`/time_entries?is_running=true&user_id=${this.userId}`);
|
||||
if (data && data.time_entries && data.time_entries.length > 0) {
|
||||
this.runningTimer = data.time_entries[0];
|
||||
const { project, task, hours } = this.runningTimer;
|
||||
this.statusBarItemEl.setText(`Harvest: ${project.name} - ${task.name} (${hours.toFixed(2)}h)`);
|
||||
} else {
|
||||
this.runningTimer = null;
|
||||
this.statusBarItemEl.setText("Harvest: no timer running");
|
||||
}
|
||||
}
|
||||
async stopTimer(timerId) {
|
||||
const result = await this.request(`/time_entries/${timerId}/stop`, "PATCH");
|
||||
if (result) {
|
||||
new import_obsidian.Notice("Timer stopped.");
|
||||
void this.updateRunningTimer();
|
||||
}
|
||||
}
|
||||
async toggleTimer() {
|
||||
await this.updateRunningTimer();
|
||||
if (this.runningTimer) {
|
||||
new import_obsidian.Notice("Stopping timer...");
|
||||
await this.stopTimer(this.runningTimer.id);
|
||||
} else {
|
||||
new import_obsidian.Notice("No timer running. Starting a new one...");
|
||||
new ProjectSuggestModal(this.app, this, this.app.workspace.getActiveFile()).open();
|
||||
}
|
||||
}
|
||||
};
|
||||
var ProjectSuggestModal = class extends import_obsidian.FuzzySuggestModal {
|
||||
constructor(app, plugin, activeFile) {
|
||||
super(app);
|
||||
this.plugin = plugin;
|
||||
this.activeFile = activeFile;
|
||||
}
|
||||
getItems() {
|
||||
let projects = [...this.plugin.projectCache];
|
||||
if (this.activeFile && this.activeFile.parent) {
|
||||
const folderPath = this.activeFile.parent.path;
|
||||
const cachedInfo = this.plugin.settings.folderProjectCache[folderPath];
|
||||
if (cachedInfo) {
|
||||
const cachedProjectIndex = projects.findIndex((p) => p.id === cachedInfo.projectId);
|
||||
if (cachedProjectIndex > -1) {
|
||||
const cachedProject = projects.splice(cachedProjectIndex, 1)[0];
|
||||
projects.unshift(cachedProject);
|
||||
}
|
||||
}
|
||||
}
|
||||
return projects;
|
||||
}
|
||||
getItemText(project) {
|
||||
return project.name;
|
||||
}
|
||||
renderSuggestion(match, el) {
|
||||
var _a;
|
||||
const project = match.item;
|
||||
el.createEl("div", { text: project.name });
|
||||
el.createEl("small", { text: ((_a = project.client) == null ? void 0 : _a.name) || "No client" });
|
||||
}
|
||||
onChooseItem(project) {
|
||||
void this.handleProjectChoice(project);
|
||||
}
|
||||
async handleProjectChoice(project) {
|
||||
let tasks = project.task_assignments;
|
||||
if (!tasks) {
|
||||
const data = await this.plugin.request(`/projects/${project.id}/task_assignments`);
|
||||
tasks = data == null ? void 0 : data.task_assignments;
|
||||
}
|
||||
if (tasks && tasks.length > 0) {
|
||||
new TaskSuggestModal(this.app, this.plugin, project, tasks, this.activeFile).open();
|
||||
} else {
|
||||
new import_obsidian.Notice("No tasks found for this project.");
|
||||
}
|
||||
}
|
||||
};
|
||||
var TaskSuggestModal = class extends import_obsidian.FuzzySuggestModal {
|
||||
constructor(app, plugin, project, tasks, activeFile) {
|
||||
super(app);
|
||||
this.plugin = plugin;
|
||||
this.project = project;
|
||||
this.tasks = tasks;
|
||||
this.activeFile = activeFile;
|
||||
}
|
||||
getItems() {
|
||||
let tasks = [...this.tasks];
|
||||
if (this.activeFile && this.activeFile.parent) {
|
||||
const folderPath = this.activeFile.parent.path;
|
||||
const cachedInfo = this.plugin.settings.folderProjectCache[folderPath];
|
||||
if (cachedInfo && cachedInfo.projectId === this.project.id) {
|
||||
const cachedTaskIndex = tasks.findIndex((t) => t.task.id === cachedInfo.taskId);
|
||||
if (cachedTaskIndex > -1) {
|
||||
const cachedTask = tasks.splice(cachedTaskIndex, 1)[0];
|
||||
tasks.unshift(cachedTask);
|
||||
}
|
||||
}
|
||||
}
|
||||
return tasks;
|
||||
}
|
||||
getItemText(taskAssignment) {
|
||||
return taskAssignment.task.name;
|
||||
}
|
||||
renderSuggestion(match, el) {
|
||||
el.createEl("div", { text: match.item.task.name });
|
||||
}
|
||||
onChooseItem(taskAssignment) {
|
||||
void this.plugin.startTimer(this.project.id, taskAssignment.task.id, this.activeFile);
|
||||
}
|
||||
};
|
||||
var HarvestSettingTab = class extends import_obsidian.PluginSettingTab {
|
||||
constructor(app, plugin) {
|
||||
super(app, plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
display() {
|
||||
const { containerEl } = this;
|
||||
containerEl.empty();
|
||||
new import_obsidian.Setting(containerEl).setName("Credentials").setHeading();
|
||||
new import_obsidian.Setting(containerEl).setName("Personal access token").setDesc("Get this from the developers section of your Harvest ID.").addText((text) => text.setPlaceholder("Enter your token").setValue(this.plugin.settings.personalAccessToken).onChange(async (value) => {
|
||||
this.plugin.settings.personalAccessToken = value;
|
||||
await this.plugin.saveSettings();
|
||||
if (this.plugin.settings.accountId) {
|
||||
await this.plugin.fetchCurrentUserId();
|
||||
}
|
||||
}));
|
||||
new import_obsidian.Setting(containerEl).setName("Account ID").setDesc("You can also find this on the same page as your token.").addText((text) => text.setPlaceholder("Enter your account ID").setValue(this.plugin.settings.accountId).onChange(async (value) => {
|
||||
this.plugin.settings.accountId = value;
|
||||
await this.plugin.saveSettings();
|
||||
if (this.plugin.settings.personalAccessToken) {
|
||||
await this.plugin.fetchCurrentUserId();
|
||||
}
|
||||
}));
|
||||
new import_obsidian.Setting(containerEl).setName("Configuration").setHeading();
|
||||
new import_obsidian.Setting(containerEl).setName("Polling interval").setDesc("How often to check for a running timer, in minutes. Requires a reload to take effect.").addText((text) => text.setPlaceholder("Default: 5").setValue(String(this.plugin.settings.pollingInterval)).onChange(async (value) => {
|
||||
const interval = parseInt(value);
|
||||
if (!isNaN(interval) && interval > 0) {
|
||||
this.plugin.settings.pollingInterval = interval;
|
||||
await this.plugin.saveSettings();
|
||||
}
|
||||
}));
|
||||
}
|
||||
};
|
||||
Loading…
Reference in a new issue