mirror of
https://github.com/yangcht/obsidian-things-toolkit.git
synced 2026-07-22 07:45:44 +00:00
Afix lints
This commit is contained in:
parent
90e1ff3c03
commit
2f9845e940
15 changed files with 1441 additions and 2611 deletions
32
.eslintrc.json
Normal file
32
.eslintrc.json
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": ["@typescript-eslint"],
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true,
|
||||
"es2020": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"sourceType": "module",
|
||||
"ecmaVersion": 2020,
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"ignorePatterns": [
|
||||
"main.js",
|
||||
"node_modules/",
|
||||
"dist/"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/no-floating-promises": "warn",
|
||||
"@typescript-eslint/no-explicit-any": "warn",
|
||||
"@typescript-eslint/no-unsafe-assignment": "warn",
|
||||
"@typescript-eslint/no-unsafe-call": "warn",
|
||||
"@typescript-eslint/no-unsafe-member-access": "warn",
|
||||
"@typescript-eslint/no-unsafe-return": "warn"
|
||||
}
|
||||
}
|
||||
0
eslint
Normal file
0
eslint
Normal file
38
eslint.config.mjs
Normal file
38
eslint.config.mjs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import js from "@eslint/js";
|
||||
import tseslint from "typescript-eslint";
|
||||
|
||||
export default tseslint.config(
|
||||
{
|
||||
ignores: [
|
||||
"eslint.config.mjs",
|
||||
"main.js",
|
||||
"rollup.config.js",
|
||||
"node_modules/**",
|
||||
"dist/**"
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
files: ["src/**/*.ts"],
|
||||
extends: [
|
||||
js.configs.recommended,
|
||||
...tseslint.configs.recommendedTypeChecked,
|
||||
],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
projectService: true,
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
"@typescript-eslint/no-explicit-any": "warn",
|
||||
"@typescript-eslint/no-unsafe-assignment": "warn",
|
||||
"@typescript-eslint/no-unsafe-call": "warn",
|
||||
"@typescript-eslint/no-unsafe-member-access": "warn",
|
||||
"@typescript-eslint/no-unsafe-return": "warn",
|
||||
"@typescript-eslint/no-unsafe-argument": "warn",
|
||||
"@typescript-eslint/no-floating-promises": "warn",
|
||||
"@typescript-eslint/unbound-method": "warn"
|
||||
},
|
||||
}
|
||||
);
|
||||
|
|
@ -2,9 +2,9 @@
|
|||
"id": "things-toolkit",
|
||||
"name": "Things Toolkit",
|
||||
"description": "Sync Things3 completions into daily notes with review stats and privacy-aware macOS access.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"author": "yangcht",
|
||||
"authorUrl": "https://github.com/yangcht",
|
||||
"isDesktopOnly": true,
|
||||
"minAppVersion": "1.0.0"
|
||||
"minAppVersion": "1.0.1"
|
||||
}
|
||||
|
|
|
|||
0
obsidian-things-toolkit-plugin@1.0.0
Normal file
0
obsidian-things-toolkit-plugin@1.0.0
Normal file
2338
package-lock.json
generated
2338
package-lock.json
generated
File diff suppressed because it is too large
Load diff
21
package.json
21
package.json
|
|
@ -6,28 +6,25 @@
|
|||
"main": "main.js",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"lint": "eslint . --ext .ts",
|
||||
"lint": "eslint src/**/*.ts",
|
||||
"build": "npm run lint && rollup -c",
|
||||
"build:nolint": "rollup -c",
|
||||
"test:watch": "yarn test -- --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"obsidian": "obsidianmd/obsidian-api#master",
|
||||
"obsidian-daily-notes-interface": "0.9.2",
|
||||
"papaparse": "5.3.1",
|
||||
"tslib": "2.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-commonjs": "17.1.0",
|
||||
"@rollup/plugin-json": "4.1.0",
|
||||
"@rollup/plugin-node-resolve": "11.2.0",
|
||||
"@rollup/plugin-replace": "2.4.1",
|
||||
"@rollup/plugin-typescript": "8.2.0",
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@types/node": "latest",
|
||||
"@types/papaparse": "5.3.1",
|
||||
"@typescript-eslint/eslint-plugin": "4.17.0",
|
||||
"@typescript-eslint/parser": "4.17.0",
|
||||
"eslint": "7.22.0",
|
||||
"rollup": "^2.80.0",
|
||||
"typescript": "4.2.3"
|
||||
"@typescript-eslint/eslint-plugin": "latest",
|
||||
"@typescript-eslint/parser": "latest",
|
||||
"eslint": "latest",
|
||||
"obsidian": "latest",
|
||||
"typescript": "latest",
|
||||
"typescript-eslint": "^8.61.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,18 @@
|
|||
import { Editor } from "codemirror";
|
||||
import { App, MarkdownView, TFile, WorkspaceLeaf } from "obsidian";
|
||||
import { App, Editor, MarkdownView, TFile, WorkspaceLeaf } from "obsidian";
|
||||
|
||||
export function getEditorForFile(app: App, file: TFile): Editor | null {
|
||||
let editor: Editor | null = null;
|
||||
|
||||
app.workspace.iterateAllLeaves((leaf: WorkspaceLeaf) => {
|
||||
const view = leaf.view;
|
||||
|
||||
if (view instanceof MarkdownView && view.file === file) {
|
||||
editor = view.editor;
|
||||
}
|
||||
});
|
||||
|
||||
return editor;
|
||||
}
|
||||
|
||||
type MarkdownEditor = Editor & {
|
||||
replaceRange: Editor["replaceRange"];
|
||||
|
|
|
|||
161
src/index.ts
161
src/index.ts
|
|
@ -37,22 +37,6 @@ import {
|
|||
updateSection,
|
||||
} from "./textUtils";
|
||||
|
||||
type ReviewLeaf = WorkspaceLeaf & {
|
||||
setViewState(state: { type: string; active: boolean }): Promise<void>;
|
||||
openFile(file: TFile): Promise<void>;
|
||||
};
|
||||
|
||||
type WorkspaceWithHelpers = typeof app.workspace & {
|
||||
getLeavesOfType(type: string): WorkspaceLeaf[];
|
||||
getRightLeaf(split: boolean): WorkspaceLeaf | null;
|
||||
revealLeaf(leaf: WorkspaceLeaf): Promise<void>;
|
||||
getLeaf(newLeaf?: boolean): WorkspaceLeaf;
|
||||
};
|
||||
|
||||
function getWorkspace(plugin: Plugin): WorkspaceWithHelpers {
|
||||
return plugin.app.workspace as WorkspaceWithHelpers;
|
||||
}
|
||||
|
||||
function isTFile(file: unknown): file is TFile {
|
||||
return file instanceof TFile;
|
||||
}
|
||||
|
|
@ -72,13 +56,16 @@ export default class ThingsToolkitPlugin extends Plugin {
|
|||
isSyncing: false,
|
||||
message: "",
|
||||
};
|
||||
|
||||
private syncTimeoutId?: number;
|
||||
private settingsTab?: ThingsToolkitSettingsTab;
|
||||
private statusBarEl?: HTMLElement;
|
||||
|
||||
async onload(): Promise<void> {
|
||||
if (!Platform.isDesktopApp || !isMacOS()) {
|
||||
console.info("Failed to load Things Toolkit plugin. Platform not supported");
|
||||
console.info(
|
||||
"Failed to load Things Toolkit plugin. Platform not supported"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -95,10 +82,13 @@ export default class ThingsToolkitPlugin extends Plugin {
|
|||
this.addCommand({
|
||||
id: "sync",
|
||||
name: "Sync",
|
||||
callback: () => window.setTimeout(() => {
|
||||
void this.tryToSyncLogbook();
|
||||
}, 20),
|
||||
callback: () => {
|
||||
window.setTimeout(() => {
|
||||
void this.tryToSyncLogbook();
|
||||
}, 20);
|
||||
},
|
||||
});
|
||||
|
||||
this.addCommand({
|
||||
id: "open-review",
|
||||
name: "Open review",
|
||||
|
|
@ -112,13 +102,16 @@ export default class ThingsToolkitPlugin extends Plugin {
|
|||
});
|
||||
|
||||
await this.loadOptions();
|
||||
|
||||
this.statusBarEl = this.addStatusBarItem();
|
||||
this.statusBarEl.addClass("things-toolkit-status");
|
||||
this.statusBarEl.addEventListener("click", () => {
|
||||
void this.activateReviewView();
|
||||
});
|
||||
|
||||
this.updateStatusBar();
|
||||
getWorkspace(this).onLayoutReady(() => {
|
||||
|
||||
this.app.workspace.onLayoutReady(() => {
|
||||
void this.refreshRecentDailyStats().then(() => {
|
||||
this.updateStatusBar();
|
||||
this.refreshReviewViews();
|
||||
|
|
@ -129,11 +122,11 @@ export default class ThingsToolkitPlugin extends Plugin {
|
|||
this.addSettingTab(this.settingsTab);
|
||||
|
||||
if (this.options.hasAcceptedDisclaimer && this.options.isSyncEnabled) {
|
||||
if (getWorkspace(this).layoutReady) {
|
||||
if (this.app.workspace.layoutReady) {
|
||||
this.scheduleNextSync();
|
||||
} else {
|
||||
this.registerEvent(
|
||||
getWorkspace(this).on("layout-ready", () => {
|
||||
this.app.workspace.on("layout-ready", () => {
|
||||
this.scheduleNextSync();
|
||||
})
|
||||
);
|
||||
|
|
@ -142,19 +135,24 @@ export default class ThingsToolkitPlugin extends Plugin {
|
|||
}
|
||||
|
||||
async activateReviewView(): Promise<void> {
|
||||
const workspace = getWorkspace(this);
|
||||
let leaf = workspace.getLeavesOfType(VIEW_TYPE_THINGS_TOOLKIT_REVIEW)[0] as ReviewLeaf | undefined;
|
||||
let leaf = this.app.workspace.getLeavesOfType(
|
||||
VIEW_TYPE_THINGS_TOOLKIT_REVIEW
|
||||
)[0];
|
||||
|
||||
if (!leaf) {
|
||||
leaf = workspace.getRightLeaf(false) as ReviewLeaf | null;
|
||||
leaf = this.app.workspace.getRightLeaf(false);
|
||||
|
||||
if (!leaf) {
|
||||
return;
|
||||
}
|
||||
|
||||
await leaf.setViewState({
|
||||
type: VIEW_TYPE_THINGS_TOOLKIT_REVIEW,
|
||||
active: true,
|
||||
});
|
||||
}
|
||||
await workspace.revealLeaf(leaf);
|
||||
|
||||
await this.app.workspace.revealLeaf(leaf);
|
||||
}
|
||||
|
||||
async tryToSyncLogbook(): Promise<void> {
|
||||
|
|
@ -175,7 +173,7 @@ export default class ThingsToolkitPlugin extends Plugin {
|
|||
}).open();
|
||||
}
|
||||
|
||||
async tryToScheduleSync(): Promise<void> {
|
||||
tryToScheduleSync(): void {
|
||||
if (this.options.hasAcceptedDisclaimer) {
|
||||
this.scheduleNextSync();
|
||||
return;
|
||||
|
|
@ -200,6 +198,7 @@ export default class ThingsToolkitPlugin extends Plugin {
|
|||
|
||||
async syncLogbook(): Promise<void> {
|
||||
const moment = getMoment();
|
||||
|
||||
if (this.syncStatus.isSyncing) {
|
||||
new Notice("Things Toolkit sync already running");
|
||||
return;
|
||||
|
|
@ -214,9 +213,6 @@ export default class ThingsToolkitPlugin extends Plugin {
|
|||
const logbookRenderer = new ToolkitRenderer(this.app, this.options);
|
||||
const dailyNotes = getAllDailyNotes();
|
||||
const latestSyncTime = this.options.latestSyncTime || 0;
|
||||
let taskCount = 0;
|
||||
let dayCount = 0;
|
||||
let changedDayCount = 0;
|
||||
|
||||
try {
|
||||
const fetchResult = await fetchThingsToolkit(
|
||||
|
|
@ -230,16 +226,19 @@ export default class ThingsToolkitPlugin extends Plugin {
|
|||
fetchResult.taskRecords,
|
||||
fetchResult.checklistRecords
|
||||
);
|
||||
taskCount = tasks.length;
|
||||
const taskCount = tasks.length;
|
||||
|
||||
const daysToTasks: Record<string, ITask[]> = groupBy(
|
||||
tasks.filter((task) => task.stopDate),
|
||||
(task) => moment.unix(task.stopDate).startOf("day").format()
|
||||
);
|
||||
|
||||
const dayEntries = Object.entries(daysToTasks).sort(([a], [b]) =>
|
||||
moment(a).diff(moment(b))
|
||||
);
|
||||
dayCount = dayEntries.length;
|
||||
const dayCount = dayEntries.length;
|
||||
let changedDayCount = 0;
|
||||
|
||||
const dailyStats = this.buildDailyStats(
|
||||
dayEntries,
|
||||
fetchResult.source,
|
||||
|
|
@ -249,6 +248,7 @@ export default class ThingsToolkitPlugin extends Plugin {
|
|||
for (const [dateStr, groupedTasks] of dayEntries) {
|
||||
const date = moment(dateStr);
|
||||
let dailyNote = getDailyNote(date, dailyNotes);
|
||||
|
||||
if (!dailyNote) {
|
||||
dailyNote = await createDailyNote(date);
|
||||
}
|
||||
|
|
@ -263,6 +263,7 @@ export default class ThingsToolkitPlugin extends Plugin {
|
|||
this.options.sectionHeading,
|
||||
logbookRenderer.render(groupedTasks)
|
||||
);
|
||||
|
||||
if (didChange) {
|
||||
changedDayCount++;
|
||||
}
|
||||
|
|
@ -274,24 +275,34 @@ export default class ThingsToolkitPlugin extends Plugin {
|
|||
thingsAccessStatus: fetchResult.accessStatus,
|
||||
});
|
||||
|
||||
const repairLookbackDays =
|
||||
fetchResult.repairLookbackDays ||
|
||||
(fetchResult.source === "applescript"
|
||||
? this.options.appleScriptFallbackLookbackDays
|
||||
: this.getReviewWindowDayCount());
|
||||
|
||||
const sourceLabel =
|
||||
fetchResult.source === "applescript"
|
||||
? `Things AppleScript, repairing last ${fetchResult.repairLookbackDays || this.options.appleScriptFallbackLookbackDays} days`
|
||||
: `Things SQLite, repairing last ${fetchResult.repairLookbackDays || this.getReviewWindowDayCount()} days`;
|
||||
? `Things AppleScript, repairing last ${repairLookbackDays} days`
|
||||
: `Things SQLite, repairing last ${repairLookbackDays} days`;
|
||||
|
||||
this.syncStatus = {
|
||||
isSyncing: false,
|
||||
message: `Last result: ${taskCount} tasks, ${changedDayCount}/${dayCount} notes updated via ${sourceLabel}. ${fetchResult.accessStatus.message}`,
|
||||
};
|
||||
|
||||
new Notice(
|
||||
`Things Toolkit sync complete (${taskCount} tasks, ${changedDayCount} notes updated)`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error("[Things Toolkit] Sync failed", err);
|
||||
|
||||
const errorMessage = err instanceof Error ? err.message : String(err);
|
||||
this.syncStatus = {
|
||||
isSyncing: false,
|
||||
message: `Last result: sync failed. ${errorMessage}`,
|
||||
};
|
||||
|
||||
new Notice("Things Toolkit sync failed");
|
||||
} finally {
|
||||
await this.refreshRecentDailyStats();
|
||||
|
|
@ -308,15 +319,20 @@ export default class ThingsToolkitPlugin extends Plugin {
|
|||
syncedAt: number
|
||||
): Record<string, IDailyLogbookStat> {
|
||||
const moment = getMoment();
|
||||
const dailyStats = { ...(this.options.dailyStats || {}) };
|
||||
const dailyStats: Record<string, IDailyLogbookStat> = {
|
||||
...(this.options.dailyStats || {}),
|
||||
};
|
||||
|
||||
dayEntries.forEach(([dateStr, tasks]) => {
|
||||
const dateKey = moment(dateStr).format("YYYY-MM-DD");
|
||||
|
||||
dailyStats[dateKey] = {
|
||||
taskCount: tasks.length,
|
||||
source,
|
||||
syncedAt,
|
||||
};
|
||||
});
|
||||
|
||||
return dailyStats;
|
||||
}
|
||||
|
||||
|
|
@ -328,17 +344,26 @@ export default class ThingsToolkitPlugin extends Plugin {
|
|||
return Math.max(7, Math.floor(Number(this.options.reviewWindowDays) || 365));
|
||||
}
|
||||
|
||||
async refreshRecentDailyStats(dayCount = this.getReviewWindowDayCount()): Promise<void> {
|
||||
async refreshRecentDailyStats(
|
||||
dayCount = this.getReviewWindowDayCount()
|
||||
): Promise<void> {
|
||||
const moment = getMoment();
|
||||
const dailyStats = { ...(this.options.dailyStats || {}) };
|
||||
const dailyStats: Record<string, IDailyLogbookStat> = {
|
||||
...(this.options.dailyStats || {}),
|
||||
};
|
||||
const dailyNotes = getAllDailyNotes();
|
||||
const syncedAt = moment().unix();
|
||||
const end = moment().startOf("day");
|
||||
const start = end.clone().subtract(dayCount - 1, "days");
|
||||
|
||||
for (let date = start.clone(); date.isSameOrBefore(end); date.add(1, "day")) {
|
||||
for (
|
||||
let date = start.clone();
|
||||
date.isSameOrBefore(end);
|
||||
date.add(1, "day")
|
||||
) {
|
||||
const dateKey = getDateKey(date);
|
||||
const dailyNote = getDailyNote(date, dailyNotes);
|
||||
|
||||
if (!isTFile(dailyNote)) {
|
||||
dailyStats[dateKey] = {
|
||||
taskCount: 0,
|
||||
|
|
@ -350,7 +375,10 @@ export default class ThingsToolkitPlugin extends Plugin {
|
|||
|
||||
const fileContents = await this.app.vault.read(dailyNote);
|
||||
dailyStats[dateKey] = {
|
||||
taskCount: countThingsTasksInSection(fileContents, this.options.sectionHeading),
|
||||
taskCount: countThingsTasksInSection(
|
||||
fileContents,
|
||||
this.options.sectionHeading
|
||||
),
|
||||
source: "daily-note",
|
||||
syncedAt,
|
||||
};
|
||||
|
|
@ -362,6 +390,7 @@ export default class ThingsToolkitPlugin extends Plugin {
|
|||
getCurrentCompletionStreak(): number {
|
||||
const moment = getMoment();
|
||||
let streak = 0;
|
||||
|
||||
for (
|
||||
let date = moment().startOf("day");
|
||||
this.getTaskCountForDay(getDateKey(date)) > 0;
|
||||
|
|
@ -369,6 +398,7 @@ export default class ThingsToolkitPlugin extends Plugin {
|
|||
) {
|
||||
streak++;
|
||||
}
|
||||
|
||||
return streak;
|
||||
}
|
||||
|
||||
|
|
@ -377,17 +407,22 @@ export default class ThingsToolkitPlugin extends Plugin {
|
|||
diff: Partial<IDailyLogbookReview>
|
||||
): Promise<void> {
|
||||
const moment = getMoment();
|
||||
const dailyReviews = { ...(this.options.dailyReviews || {}) };
|
||||
const nextReview = {
|
||||
const dailyReviews: Record<string, IDailyLogbookReview> = {
|
||||
...(this.options.dailyReviews || {}),
|
||||
};
|
||||
|
||||
const nextReview: IDailyLogbookReview = {
|
||||
...(dailyReviews[dateKey] || {}),
|
||||
...diff,
|
||||
updatedAt: moment().unix(),
|
||||
};
|
||||
|
||||
if (!nextReview.rating && !nextReview.reflection) {
|
||||
delete dailyReviews[dateKey];
|
||||
} else {
|
||||
dailyReviews[dateKey] = nextReview;
|
||||
}
|
||||
|
||||
await this.writeOptions({ dailyReviews });
|
||||
this.refreshReviewViews();
|
||||
}
|
||||
|
|
@ -397,27 +432,35 @@ export default class ThingsToolkitPlugin extends Plugin {
|
|||
const date = moment(dateKey, "YYYY-MM-DD");
|
||||
const dailyNotes = getAllDailyNotes();
|
||||
let dailyNote = getDailyNote(date, dailyNotes);
|
||||
|
||||
if (!dailyNote) {
|
||||
dailyNote = await createDailyNote(date);
|
||||
}
|
||||
|
||||
if (!isTFile(dailyNote)) {
|
||||
throw new Error("Daily note could not be opened as a file");
|
||||
}
|
||||
await (getWorkspace(this).getLeaf(false) as ReviewLeaf).openFile(dailyNote);
|
||||
|
||||
await this.app.workspace.getLeaf(false).openFile(dailyNote);
|
||||
}
|
||||
|
||||
refreshReviewViews(): void {
|
||||
getWorkspace(this)
|
||||
.getLeavesOfType(VIEW_TYPE_THINGS_TOOLKIT_REVIEW)
|
||||
.forEach((leaf) => {
|
||||
if (leaf.view instanceof ThingsToolkitReviewView) {
|
||||
leaf.view.display();
|
||||
}
|
||||
});
|
||||
const leaves: WorkspaceLeaf[] = this.app.workspace.getLeavesOfType(
|
||||
VIEW_TYPE_THINGS_TOOLKIT_REVIEW
|
||||
);
|
||||
|
||||
leaves.forEach((leaf: WorkspaceLeaf) => {
|
||||
const view = leaf.view;
|
||||
|
||||
if (view instanceof ThingsToolkitReviewView) {
|
||||
view.display();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updateStatusBar(): void {
|
||||
const moment = getMoment();
|
||||
|
||||
if (!this.statusBarEl) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -425,6 +468,7 @@ export default class ThingsToolkitPlugin extends Plugin {
|
|||
const todayKey = moment().format("YYYY-MM-DD");
|
||||
const todayCount = this.getTaskCountForDay(todayKey);
|
||||
const streak = this.getCurrentCompletionStreak();
|
||||
|
||||
this.statusBarEl.setText(`Things: ${todayCount} today | ${streak}d streak`);
|
||||
this.statusBarEl.setAttribute("aria-label", "Open Things toolkit review");
|
||||
}
|
||||
|
|
@ -432,6 +476,7 @@ export default class ThingsToolkitPlugin extends Plugin {
|
|||
cancelScheduledSync(): void {
|
||||
if (this.syncTimeoutId !== undefined) {
|
||||
window.clearTimeout(this.syncTimeoutId);
|
||||
this.syncTimeoutId = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -440,6 +485,7 @@ export default class ThingsToolkitPlugin extends Plugin {
|
|||
const now = moment().unix();
|
||||
|
||||
this.cancelScheduledSync();
|
||||
|
||||
if (!this.options.isSyncEnabled || !this.options.syncInterval) {
|
||||
console.debug("[Things Toolkit] scheduling skipped, no syncInterval set");
|
||||
return;
|
||||
|
|
@ -450,13 +496,20 @@ export default class ThingsToolkitPlugin extends Plugin {
|
|||
const nextSync = Math.max(secondsUntilNextSync * 1000, 20);
|
||||
|
||||
console.debug(`[Things Toolkit] next sync scheduled in ${nextSync}ms`);
|
||||
|
||||
this.syncTimeoutId = window.setTimeout(() => {
|
||||
void this.syncLogbook();
|
||||
}, nextSync);
|
||||
}
|
||||
|
||||
async loadOptions(): Promise<void> {
|
||||
this.options = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()) as ISettings;
|
||||
const loadedData = (await this.loadData()) as Partial<ISettings> | null;
|
||||
|
||||
this.options = {
|
||||
...DEFAULT_SETTINGS,
|
||||
...(loadedData ?? {}),
|
||||
};
|
||||
|
||||
if (!this.options.hasAcceptedDisclaimer) {
|
||||
this.options.isSyncEnabled = false;
|
||||
}
|
||||
|
|
@ -467,14 +520,14 @@ export default class ThingsToolkitPlugin extends Plugin {
|
|||
|
||||
if (diff.isSyncEnabled !== undefined) {
|
||||
if (diff.isSyncEnabled) {
|
||||
await this.tryToScheduleSync();
|
||||
this.tryToScheduleSync();
|
||||
} else {
|
||||
this.cancelScheduledSync();
|
||||
}
|
||||
} else if (diff.syncInterval !== undefined && this.options.isSyncEnabled) {
|
||||
await this.tryToScheduleSync();
|
||||
this.tryToScheduleSync();
|
||||
}
|
||||
|
||||
await this.saveData(this.options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -75,7 +75,7 @@ export class ToolkitRenderer {
|
|||
toHeading(heading, headingLevel + 1, doesAddNewlineBeforeHeadings)
|
||||
);
|
||||
}
|
||||
output.push(...groupedTasks.map(this.renderTask));
|
||||
output.push(...groupedTasks.map((task) => this.renderTask(task)));
|
||||
});
|
||||
|
||||
return output.join("\n");
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { ItemView, Notice, WorkspaceLeaf, moment } from "obsidian";
|
||||
import { ItemView, Notice, WorkspaceLeaf } from "obsidian";
|
||||
|
||||
import type ThingsToolkitPlugin from "./index";
|
||||
import { getMoment, type MomentLike } from "./moment";
|
||||
import { DayReviewRating } from "./settings";
|
||||
|
||||
export const VIEW_TYPE_THINGS_TOOLKIT_REVIEW = "things-toolkit-review";
|
||||
|
|
@ -14,11 +15,12 @@ const RATING_LABELS: Record<DayReviewRating, string> = {
|
|||
export class ThingsToolkitReviewView extends ItemView {
|
||||
private plugin: ThingsToolkitPlugin;
|
||||
private selectedDate: string;
|
||||
private readonly moment = getMoment();
|
||||
|
||||
constructor(leaf: WorkspaceLeaf, plugin: ThingsToolkitPlugin) {
|
||||
super(leaf);
|
||||
this.plugin = plugin;
|
||||
this.selectedDate = moment().format("YYYY-MM-DD");
|
||||
this.selectedDate = this.moment().format("YYYY-MM-DD");
|
||||
}
|
||||
|
||||
getViewType(): string {
|
||||
|
|
@ -49,7 +51,7 @@ export class ThingsToolkitReviewView extends ItemView {
|
|||
}
|
||||
|
||||
private renderSummary(containerEl: HTMLElement): void {
|
||||
const today = moment().format("YYYY-MM-DD");
|
||||
const today = this.moment().format("YYYY-MM-DD");
|
||||
const todayCount = this.plugin.getTaskCountForDay(today);
|
||||
const weeklyCount = this.getRecentTaskTotal(7);
|
||||
const streak = this.plugin.getCurrentCompletionStreak();
|
||||
|
|
@ -98,7 +100,7 @@ export class ThingsToolkitReviewView extends ItemView {
|
|||
|
||||
private renderSelectedDay(containerEl: HTMLElement): void {
|
||||
const dateKey = this.selectedDate;
|
||||
const date = moment(dateKey, "YYYY-MM-DD");
|
||||
const date = this.moment(dateKey, "YYYY-MM-DD");
|
||||
const review = this.plugin.options.dailyReviews[dateKey] || {};
|
||||
const stat = this.plugin.options.dailyStats[dateKey];
|
||||
const detailEl = containerEl.createDiv("things-toolkit-review-detail");
|
||||
|
|
@ -136,9 +138,10 @@ export class ThingsToolkitReviewView extends ItemView {
|
|||
if (review.rating === rating) {
|
||||
buttonEl.addClass("is-active");
|
||||
}
|
||||
buttonEl.addEventListener("click", async () => {
|
||||
await this.plugin.writeDayReview(dateKey, { rating });
|
||||
this.display();
|
||||
buttonEl.addEventListener("click", () => {
|
||||
void this.plugin.writeDayReview(dateKey, { rating }).then(() => {
|
||||
this.display();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -153,26 +156,27 @@ export class ThingsToolkitReviewView extends ItemView {
|
|||
const actionsEl = detailEl.createDiv("things-toolkit-review-actions");
|
||||
actionsEl
|
||||
.createEl("button", { text: "Save reflection" })
|
||||
.addEventListener("click", async () => {
|
||||
await this.plugin.writeDayReview(dateKey, {
|
||||
.addEventListener("click", () => {
|
||||
void this.plugin.writeDayReview(dateKey, {
|
||||
reflection: textareaEl.value.trim(),
|
||||
}).then(() => {
|
||||
new Notice("Things review saved");
|
||||
this.display();
|
||||
});
|
||||
new Notice("Things review saved");
|
||||
this.display();
|
||||
});
|
||||
|
||||
actionsEl
|
||||
.createEl("button", { text: "Open daily note" })
|
||||
.addEventListener("click", async () => {
|
||||
await this.plugin.openDailyNote(dateKey);
|
||||
.addEventListener("click", () => {
|
||||
void this.plugin.openDailyNote(dateKey);
|
||||
});
|
||||
}
|
||||
|
||||
private renderMonth(
|
||||
containerEl: HTMLElement,
|
||||
month: moment.Moment,
|
||||
startDate: moment.Moment,
|
||||
endDate: moment.Moment
|
||||
month: MomentLike,
|
||||
startDate: MomentLike,
|
||||
endDate: MomentLike
|
||||
): void {
|
||||
const monthEl = containerEl.createDiv("things-toolkit-review-month");
|
||||
const summary = this.getMonthSummary(month);
|
||||
|
|
@ -221,7 +225,7 @@ export class ThingsToolkitReviewView extends ItemView {
|
|||
}
|
||||
}
|
||||
|
||||
private renderCalendarDay(containerEl: HTMLElement, date: moment.Moment): void {
|
||||
private renderCalendarDay(containerEl: HTMLElement, date: MomentLike): void {
|
||||
const dateKey = date.format("YYYY-MM-DD");
|
||||
const count = this.plugin.getTaskCountForDay(dateKey);
|
||||
const review = this.plugin.options.dailyReviews[dateKey];
|
||||
|
|
@ -252,10 +256,10 @@ export class ThingsToolkitReviewView extends ItemView {
|
|||
text: String(count),
|
||||
});
|
||||
|
||||
buttonEl.addEventListener("click", async () => {
|
||||
buttonEl.addEventListener("click", () => {
|
||||
this.selectedDate = dateKey;
|
||||
this.display();
|
||||
await this.plugin.openDailyNote(dateKey);
|
||||
void this.plugin.openDailyNote(dateKey);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -275,10 +279,10 @@ export class ThingsToolkitReviewView extends ItemView {
|
|||
});
|
||||
}
|
||||
|
||||
private getRecentDates(dayCount: number): moment.Moment[] {
|
||||
const end = moment().startOf("day");
|
||||
private getRecentDates(dayCount: number): MomentLike[] {
|
||||
const end = this.moment().startOf("day");
|
||||
const start = end.clone().subtract(dayCount - 1, "days");
|
||||
const dates: moment.Moment[] = [];
|
||||
const dates: MomentLike[] = [];
|
||||
for (let date = start; date.isSameOrBefore(end); date.add(1, "day")) {
|
||||
dates.push(date.clone());
|
||||
}
|
||||
|
|
@ -292,21 +296,21 @@ export class ThingsToolkitReviewView extends ItemView {
|
|||
);
|
||||
}
|
||||
|
||||
private getWeekTotal(date: moment.Moment): number {
|
||||
private getWeekTotal(date: MomentLike): number {
|
||||
return this.sumDateRange(
|
||||
date.clone().startOf("isoWeek"),
|
||||
date.clone().endOf("isoWeek")
|
||||
);
|
||||
}
|
||||
|
||||
private getMonthTotal(date: moment.Moment): number {
|
||||
private getMonthTotal(date: MomentLike): number {
|
||||
return this.sumDateRange(
|
||||
date.clone().startOf("month"),
|
||||
date.clone().endOf("month")
|
||||
);
|
||||
}
|
||||
|
||||
private getMonthActiveDays(date: moment.Moment): number {
|
||||
private getMonthActiveDays(date: MomentLike): number {
|
||||
const end = date.clone().endOf("month");
|
||||
let activeDays = 0;
|
||||
for (
|
||||
|
|
@ -321,7 +325,7 @@ export class ThingsToolkitReviewView extends ItemView {
|
|||
return activeDays;
|
||||
}
|
||||
|
||||
private getMonthSummary(month: moment.Moment): {
|
||||
private getMonthSummary(month: MomentLike): {
|
||||
activeDays: number;
|
||||
bestDay: string;
|
||||
total: number;
|
||||
|
|
@ -351,7 +355,7 @@ export class ThingsToolkitReviewView extends ItemView {
|
|||
return { activeDays, bestDay, total };
|
||||
}
|
||||
|
||||
private sumDateRange(start: moment.Moment, end: moment.Moment): number {
|
||||
private sumDateRange(start: MomentLike, end: MomentLike): number {
|
||||
let total = 0;
|
||||
for (
|
||||
let date = start.clone().startOf("day");
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ export const DEFAULT_SETTINGS = Object.freeze({
|
|||
hasAcceptedDisclaimer: false,
|
||||
latestSyncTime: 0,
|
||||
appleScriptFallbackLookbackDays: DEFAULT_APPLESCRIPT_FALLBACK_LOOKBACK_DAYS,
|
||||
thingsAccessMode: "auto" as ThingsAccessMode,
|
||||
thingsAccessMode: "auto",
|
||||
thingsAccessStatus: undefined,
|
||||
reviewWindowDays: DEFAULT_REVIEW_WINDOW_DAYS,
|
||||
dailyStats: {},
|
||||
|
|
@ -113,9 +113,9 @@ export class ThingsToolkitSettingsTab extends PluginSettingTab {
|
|||
)
|
||||
.addText((textfield) => {
|
||||
textfield.setValue(this.plugin.options.sectionHeading);
|
||||
textfield.onChange(async (rawSectionHeading) => {
|
||||
textfield.onChange((rawSectionHeading) => {
|
||||
const sectionHeading = this.normalizeSectionHeading(rawSectionHeading);
|
||||
this.plugin.writeOptions({ sectionHeading });
|
||||
void this.plugin.writeOptions({ sectionHeading });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -130,12 +130,16 @@ export class ThingsToolkitSettingsTab extends PluginSettingTab {
|
|||
textfield.setValue(String(this.plugin.options.reviewWindowDays));
|
||||
textfield.inputEl.type = "number";
|
||||
textfield.inputEl.onblur = (e: FocusEvent) => {
|
||||
const target = e.target;
|
||||
if (!(target instanceof HTMLInputElement)) {
|
||||
return;
|
||||
}
|
||||
const reviewWindowDays = Math.max(
|
||||
30,
|
||||
Math.floor(Number((<HTMLInputElement>e.target).value) || DEFAULT_REVIEW_WINDOW_DAYS)
|
||||
Math.floor(Number(target.value) || DEFAULT_REVIEW_WINDOW_DAYS)
|
||||
);
|
||||
textfield.setValue(String(reviewWindowDays));
|
||||
this.plugin.writeOptions({ reviewWindowDays });
|
||||
void this.plugin.writeOptions({ reviewWindowDays });
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
@ -156,8 +160,8 @@ export class ThingsToolkitSettingsTab extends PluginSettingTab {
|
|||
.setName("Enable periodic syncing")
|
||||
.addToggle((toggle) => {
|
||||
toggle.setValue(this.plugin.options.isSyncEnabled);
|
||||
toggle.onChange(async (isSyncEnabled) => {
|
||||
this.plugin.writeOptions({ isSyncEnabled });
|
||||
toggle.onChange((isSyncEnabled) => {
|
||||
void this.plugin.writeOptions({ isSyncEnabled });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -218,8 +222,8 @@ export class ThingsToolkitSettingsTab extends PluginSettingTab {
|
|||
.setDesc('Includes MD notes of a task into the synced Obsidian document')
|
||||
.addToggle((toggle) => {
|
||||
toggle.setValue(this.plugin.options.doesSyncNoteBody);
|
||||
toggle.onChange(async (doesSyncNoteBody) => {
|
||||
this.plugin.writeOptions({ doesSyncNoteBody })
|
||||
toggle.onChange((doesSyncNoteBody) => {
|
||||
void this.plugin.writeOptions({ doesSyncNoteBody });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -230,8 +234,8 @@ export class ThingsToolkitSettingsTab extends PluginSettingTab {
|
|||
.setDesc("If the Things task belongs to a project, use project name as header instead of area")
|
||||
.addToggle((toggle) => {
|
||||
toggle.setValue(this.plugin.options.doesSyncProject);
|
||||
toggle.onChange(async (doesSyncProject) => {
|
||||
this.plugin.writeOptions({ doesSyncProject })
|
||||
toggle.onChange((doesSyncProject) => {
|
||||
void this.plugin.writeOptions({ doesSyncProject });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -244,12 +248,16 @@ export class ThingsToolkitSettingsTab extends PluginSettingTab {
|
|||
textfield.setValue(String(this.plugin.options.syncInterval));
|
||||
textfield.inputEl.type = "number";
|
||||
textfield.inputEl.onblur = (e: FocusEvent) => {
|
||||
const target = e.target;
|
||||
if (!(target instanceof HTMLInputElement)) {
|
||||
return;
|
||||
}
|
||||
const syncInterval = Math.max(
|
||||
60,
|
||||
Math.floor(Number((<HTMLInputElement>e.target).value) || DEFAULT_SYNC_FREQUENCY_SECONDS)
|
||||
Math.floor(Number(target.value) || DEFAULT_SYNC_FREQUENCY_SECONDS)
|
||||
);
|
||||
textfield.setValue(String(syncInterval));
|
||||
this.plugin.writeOptions({ syncInterval });
|
||||
void this.plugin.writeOptions({ syncInterval });
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
@ -264,12 +272,16 @@ export class ThingsToolkitSettingsTab extends PluginSettingTab {
|
|||
textfield.setValue(String(this.plugin.options.appleScriptFallbackLookbackDays));
|
||||
textfield.inputEl.type = "number";
|
||||
textfield.inputEl.onblur = (e: FocusEvent) => {
|
||||
const target = e.target;
|
||||
if (!(target instanceof HTMLInputElement)) {
|
||||
return;
|
||||
}
|
||||
const appleScriptFallbackLookbackDays = Math.max(
|
||||
1,
|
||||
Math.floor(Number((<HTMLInputElement>e.target).value) || DEFAULT_APPLESCRIPT_FALLBACK_LOOKBACK_DAYS)
|
||||
Math.floor(Number(target.value) || DEFAULT_APPLESCRIPT_FALLBACK_LOOKBACK_DAYS)
|
||||
);
|
||||
textfield.setValue(String(appleScriptFallbackLookbackDays));
|
||||
this.plugin.writeOptions({ appleScriptFallbackLookbackDays });
|
||||
void this.plugin.writeOptions({ appleScriptFallbackLookbackDays });
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
@ -282,8 +294,8 @@ export class ThingsToolkitSettingsTab extends PluginSettingTab {
|
|||
)
|
||||
.addText((textfield) => {
|
||||
textfield.setValue(this.plugin.options.tagPrefix);
|
||||
textfield.onChange(async (tagPrefix) => {
|
||||
this.plugin.writeOptions({ tagPrefix });
|
||||
textfield.onChange((tagPrefix) => {
|
||||
void this.plugin.writeOptions({ tagPrefix });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -296,8 +308,8 @@ export class ThingsToolkitSettingsTab extends PluginSettingTab {
|
|||
)
|
||||
.addText((textfield) => {
|
||||
textfield.setValue(this.plugin.options.canceledMark);
|
||||
textfield.onChange(async (canceledMark) => {
|
||||
this.plugin.writeOptions({ canceledMark });
|
||||
textfield.onChange((canceledMark) => {
|
||||
void this.plugin.writeOptions({ canceledMark });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -308,8 +320,8 @@ export class ThingsToolkitSettingsTab extends PluginSettingTab {
|
|||
.setDesc("When grouping tasks with headings by area or project, add an empty line before that heading")
|
||||
.addToggle((toggle) => {
|
||||
toggle.setValue(this.plugin.options.doesAddNewlineBeforeHeadings);
|
||||
toggle.onChange(async (doesAddNewlineBeforeHeadings) => {
|
||||
this.plugin.writeOptions({ doesAddNewlineBeforeHeadings });
|
||||
toggle.onChange((doesAddNewlineBeforeHeadings) => {
|
||||
void this.plugin.writeOptions({ doesAddNewlineBeforeHeadings });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -344,8 +356,8 @@ export class ThingsToolkitSettingsTab extends PluginSettingTab {
|
|||
button.setButtonText('Reset sync history');
|
||||
button.setClass('mod-danger');
|
||||
button.setDisabled(syncStatus.isSyncing);
|
||||
button.onClick(async () => {
|
||||
await this.plugin.writeOptions({ latestSyncTime: 0 });
|
||||
button.onClick(() => {
|
||||
void this.plugin.writeOptions({ latestSyncTime: 0 });
|
||||
this.display();
|
||||
});
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ import * as os from "os";
|
|||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import { spawn } from "child_process";
|
||||
import type moment from "moment";
|
||||
|
||||
import { getMoment, type MomentLike } from "./moment";
|
||||
|
||||
import { THINGS_DB_PATH_START, THINGS_DB_PATH_END } from "./constants";
|
||||
import { querySqliteDB } from "./sqlite";
|
||||
|
|
@ -142,16 +143,17 @@ function buildAccessStatus(
|
|||
message,
|
||||
source,
|
||||
sqliteBlocked,
|
||||
updatedAt: window.moment().unix(),
|
||||
updatedAt: getMoment()().unix(),
|
||||
};
|
||||
}
|
||||
|
||||
function getRepairCutoff(
|
||||
latestSyncTime: number,
|
||||
repairLookbackDays: number
|
||||
): moment.Moment {
|
||||
const incrementalCutoff = window.moment.unix(latestSyncTime).startOf("day");
|
||||
const repairCutoff = window.moment()
|
||||
): MomentLike {
|
||||
const moment = getMoment();
|
||||
const incrementalCutoff = moment.unix(latestSyncTime).startOf("day");
|
||||
const repairCutoff = moment()
|
||||
.subtract(Math.max(1, Number(repairLookbackDays) || 1), "days")
|
||||
.startOf("day");
|
||||
|
||||
|
|
@ -205,7 +207,8 @@ function getAppleScriptCutoff(
|
|||
latestSyncTime: number,
|
||||
fallbackLookbackDays: number,
|
||||
repairLookbackDays: number
|
||||
): moment.Moment {
|
||||
): MomentLike {
|
||||
const moment = getMoment();
|
||||
const configuredLookbackDays = Math.max(
|
||||
1,
|
||||
Number(fallbackLookbackDays) || DEFAULT_APPLESCRIPT_FALLBACK_LOOKBACK_DAYS
|
||||
|
|
@ -218,7 +221,7 @@ function getAppleScriptCutoff(
|
|||
const lookbackCutoff = getRepairCutoff(latestSyncTime, lookbackDays);
|
||||
|
||||
if (latestSyncTime > 0) {
|
||||
const incrementalCutoff = window.moment.unix(latestSyncTime).startOf("day");
|
||||
const incrementalCutoff = moment.unix(latestSyncTime).startOf("day");
|
||||
if (lookbackCutoff.isBefore(incrementalCutoff)) {
|
||||
console.debug(
|
||||
`[Things Toolkit] repairing the last ${lookbackDays} days from Things AppleScript.`
|
||||
|
|
@ -234,7 +237,7 @@ function getAppleScriptCutoff(
|
|||
return lookbackCutoff;
|
||||
}
|
||||
|
||||
function buildThingsToolkitAppleScript(cutoff: moment.Moment): string {
|
||||
function buildThingsToolkitAppleScript(cutoff: MomentLike): string {
|
||||
return `
|
||||
set cutoff to current date
|
||||
set year of cutoff to ${cutoff.year()}
|
||||
|
|
@ -302,6 +305,7 @@ async function getTasksFromThingsAppleScript(
|
|||
repairLookbackDays: number,
|
||||
accessStatus: IThingsAccessStatus
|
||||
): Promise<IThingsToolkitFetchResult> {
|
||||
const moment = getMoment();
|
||||
const cutoff = getAppleScriptCutoff(
|
||||
latestSyncTime,
|
||||
fallbackLookbackDays,
|
||||
|
|
@ -329,7 +333,7 @@ async function getTasksFromThingsAppleScript(
|
|||
source: "applescript",
|
||||
cutoffTime: cutoff.unix(),
|
||||
isLimited: latestSyncTime === 0,
|
||||
repairLookbackDays: window.moment().startOf("day").diff(cutoff, "days"),
|
||||
repairLookbackDays: moment().startOf("day").diff(cutoff, "days"),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -448,9 +452,10 @@ async function getChecklistItemsThingsDb(
|
|||
async function getTasksFromThingsSqlite(
|
||||
latestSyncTime: number
|
||||
): Promise<ITaskRecord[]> {
|
||||
const moment = getMoment();
|
||||
const taskRecords: ITaskRecord[] = [];
|
||||
let isSyncCompleted = false;
|
||||
let stopTime = window.moment.unix(latestSyncTime).startOf("day").unix();
|
||||
let stopTime = moment.unix(latestSyncTime).startOf("day").unix();
|
||||
|
||||
while (!isSyncCompleted) {
|
||||
console.debug("[Things Toolkit] fetching tasks from sqlite db...");
|
||||
|
|
@ -507,6 +512,7 @@ export async function fetchThingsToolkit(
|
|||
accessMode: ThingsAccessMode,
|
||||
repairLookbackDays: number
|
||||
): Promise<IThingsToolkitFetchResult> {
|
||||
const moment = getMoment();
|
||||
const cutoff = getRepairCutoff(latestSyncTime, repairLookbackDays);
|
||||
const cutoffTime = cutoff.unix();
|
||||
|
||||
|
|
@ -538,11 +544,13 @@ export async function fetchThingsToolkit(
|
|||
source: "sqlite",
|
||||
cutoffTime,
|
||||
isLimited: false,
|
||||
repairLookbackDays: window.moment().startOf("day").diff(cutoff, "days"),
|
||||
repairLookbackDays: moment().startOf("day").diff(cutoff, "days"),
|
||||
};
|
||||
} catch (err) {
|
||||
if (accessMode === "sqlite") {
|
||||
throw new Error(`Things SQLite access failed: ${getErrorMessage(err)}`);
|
||||
throw new Error(`Things SQLite access failed: ${getErrorMessage(err)}`, {
|
||||
cause: err,
|
||||
});
|
||||
}
|
||||
|
||||
const sqliteBlocked =
|
||||
|
|
@ -568,7 +576,8 @@ export async function fetchThingsToolkit(
|
|||
);
|
||||
} catch (appleScriptErr) {
|
||||
throw new Error(
|
||||
`Things AppleScript access failed after SQLite was unavailable: ${getErrorMessage(appleScriptErr)}`
|
||||
`Things AppleScript access failed after SQLite was unavailable: ${getErrorMessage(appleScriptErr)}`,
|
||||
{ cause: appleScriptErr }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,12 +5,15 @@
|
|||
"inlineSourceMap": true,
|
||||
"inlineSources": true,
|
||||
"module": "ESNext",
|
||||
"target": "esnext",
|
||||
"allowJs": true,
|
||||
"noImplicitAny": true,
|
||||
"target": "ES2020",
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"lib": ["dom", "esnext"]
|
||||
"strict": true,
|
||||
"noImplicitAny": true,
|
||||
"types": ["node"],
|
||||
"lib": ["DOM", "ES2020"],
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["**/*.ts"]
|
||||
}
|
||||
"include": ["src/**/*.ts"],
|
||||
"exclude": ["node_modules", "main.js"]
|
||||
}
|
||||
Loading…
Reference in a new issue