-
-
Notifications
You must be signed in to change notification settings - Fork 92
Expand file tree
/
Copy pathindex.ts
More file actions
118 lines (97 loc) · 3.47 KB
/
index.ts
File metadata and controls
118 lines (97 loc) · 3.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import { setLanguage, t } from "@/i18n";
import "@/styles/main.scss";
import type { PluginManifest } from "obsidian";
import { type App, Notice, Plugin } from "obsidian";
import { TodoistApiClient } from "@/api";
import { ObsidianFetcher } from "@/api/fetcher";
import { registerCommands } from "@/commands";
import { secondsToMillis } from "@/infra/time";
import { QueryInjector } from "@/query/injector";
import { makeServices, type Services } from "@/services";
import { type Settings, useSettingsStore } from "@/settings";
import { SettingsTab } from "@/ui/settings";
// biome-ignore lint/style/noMagicNumbers: 600 seconds is easily recognizable as 10 minutes
const metadataSyncIntervalMs = secondsToMillis(600);
// biome-ignore lint/style/noDefaultExport: We must use default export for Obsidian plugins
export default class TodoistPlugin extends Plugin {
public readonly services: Services;
constructor(app: App, pluginManifest: PluginManifest) {
super(app, pluginManifest);
this.services = makeServices(this);
}
async onload() {
const queryInjector = new QueryInjector(this);
this.registerMarkdownCodeBlockProcessor(
"todoist",
queryInjector.onNewBlock.bind(queryInjector),
);
this.addSettingTab(new SettingsTab(this.app, this));
registerCommands(this);
setLanguage(document.documentElement.lang);
await this.loadOptions();
this.app.workspace.onLayoutReady(async () => {
try {
await this.applyMigrations();
} catch (error: unknown) {
console.error("Failed to apply migrations:", error);
new Notice(t().notices.migrationFailed);
}
await this.loadApiClient();
});
this.registerInterval(
window.setInterval(async () => {
await this.services.todoist.sync();
}, metadataSyncIntervalMs),
);
}
private async loadApiClient(): Promise<void> {
const accessor = this.services.token;
const token = await accessor.read();
if (token !== null) {
await this.services.todoist.initialize(new TodoistApiClient(token, new ObsidianFetcher()));
return;
}
this.services.modals.onboarding({
onTokenSubmit: async (token) => {
await accessor.write(token);
await this.services.todoist.initialize(new TodoistApiClient(token, new ObsidianFetcher()));
},
});
}
async loadOptions(): Promise<void> {
const options = await this.loadData();
useSettingsStore.setState((old) => {
return {
...old,
...options,
};
}, true);
await this.saveData(useSettingsStore.getState());
}
async writeOptions(update: Partial<Settings>): Promise<void> {
useSettingsStore.setState(update);
await this.saveData(useSettingsStore.getState());
}
private static readonly settingsVersion = 1;
private async applyMigrations(): Promise<void> {
const migrations: Record<number, () => Promise<void>> = {
1: async () => {
// Migration from 0 -> 1: migrate token to secrets
await this.services.token.migrateStorage("file", "secrets");
},
};
for (
let version = useSettingsStore.getState().version;
version < TodoistPlugin.settingsVersion;
version++
) {
const nextVersion = version + 1;
const migration = migrations[nextVersion];
if (!migration) {
throw new Error(`No migration defined for version ${version} -> ${nextVersion}`);
}
await migration();
await this.writeOptions({ version: nextVersion });
}
}
}