mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-09-07 08:26:15 +00:00
sync mode dropdown — entire vault or selected folders
This commit is contained in:
parent
d5aa92167d
commit
b6a09f8f88
4 changed files with 85 additions and 6 deletions
|
|
@ -12,6 +12,8 @@ const DEFAULT_SETTINGS: SupermemorySettings = {
|
|||
connectionId: "",
|
||||
syncOnSave: true,
|
||||
syncOnStartup: true,
|
||||
syncMode: "all",
|
||||
includedFolders: "",
|
||||
}
|
||||
|
||||
export default class SupermemoryPlugin extends Plugin {
|
||||
|
|
@ -101,7 +103,9 @@ export default class SupermemoryPlugin extends Plugin {
|
|||
if (!connectionId) return
|
||||
|
||||
if (!this.syncEngine) {
|
||||
this.syncEngine = new SyncEngine(this.app, connectionId)
|
||||
this.syncEngine = new SyncEngine(this.app, connectionId, this.settings)
|
||||
} else {
|
||||
this.syncEngine.updateSettings(this.settings)
|
||||
}
|
||||
|
||||
await this.syncEngine.fullSync()
|
||||
|
|
@ -118,5 +122,6 @@ export default class SupermemoryPlugin extends Plugin {
|
|||
async saveSettings() {
|
||||
await this.saveData(this.settings)
|
||||
configure(this.settings)
|
||||
this.syncEngine?.updateSettings(this.settings)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { App, PluginSettingTab, Setting } from "obsidian"
|
||||
import type SupermemoryPlugin from "./main"
|
||||
import type { SyncMode } from "./types"
|
||||
|
||||
export class SupermemorySettingTab extends PluginSettingTab {
|
||||
plugin: SupermemoryPlugin
|
||||
|
|
@ -39,5 +40,37 @@ export class SupermemorySettingTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings()
|
||||
}),
|
||||
)
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Sync mode")
|
||||
.setDesc("Which notes in your vault to sync to Supermemory.")
|
||||
.addDropdown((dropdown) =>
|
||||
dropdown
|
||||
.addOption("all", "Entire vault")
|
||||
.addOption("folders", "Only selected folders")
|
||||
.setValue(this.plugin.settings.syncMode)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.syncMode = value as SyncMode
|
||||
await this.plugin.saveSettings()
|
||||
this.display()
|
||||
}),
|
||||
)
|
||||
|
||||
if (this.plugin.settings.syncMode === "folders") {
|
||||
new Setting(containerEl)
|
||||
.setName("Folders to sync")
|
||||
.setDesc(
|
||||
"Comma-separated folder paths (e.g. Projects, Daily). Subfolders are included.",
|
||||
)
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("Projects, Daily")
|
||||
.setValue(this.plugin.settings.includedFolders)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.includedFolders = value
|
||||
await this.plugin.saveSettings()
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { type App, Notice, TFile, parseFrontMatterEntry, parseFrontMatterTags } from "obsidian"
|
||||
import { type App, Notice, TFile, parseFrontMatterTags } from "obsidian"
|
||||
import { pushDeletions, pushNotes, type NotePayload } from "./api"
|
||||
import type { SupermemorySettings } from "./types"
|
||||
|
||||
const BATCH_SIZE = 50
|
||||
const DEBOUNCE_MS = 3000
|
||||
|
|
@ -12,13 +13,41 @@ interface SyncState {
|
|||
export class SyncEngine {
|
||||
private app: App
|
||||
private connectionId: string
|
||||
private settings: SupermemorySettings
|
||||
private state: SyncState = { syncing: false, lastFullSync: 0 }
|
||||
private pendingChanges: Map<string, "upsert" | "delete"> = new Map()
|
||||
private debounceTimer: ReturnType<typeof setTimeout> | null = null
|
||||
|
||||
constructor(app: App, connectionId: string) {
|
||||
constructor(app: App, connectionId: string, settings: SupermemorySettings) {
|
||||
this.app = app
|
||||
this.connectionId = connectionId
|
||||
this.settings = settings
|
||||
}
|
||||
|
||||
updateSettings(settings: SupermemorySettings) {
|
||||
this.settings = settings
|
||||
}
|
||||
|
||||
private shouldSync(file: TFile): boolean {
|
||||
if (file.extension !== "md") return false
|
||||
|
||||
const mode = this.settings.syncMode
|
||||
if (mode === "all") return true
|
||||
|
||||
if (mode === "folders") {
|
||||
const folders = this.settings.includedFolders
|
||||
.split(",")
|
||||
.map((f) => f.trim().replace(/^\/+|\/+$/g, ""))
|
||||
.filter((f) => f.length > 0)
|
||||
if (folders.length === 0) return false
|
||||
return folders.some(
|
||||
(folder) =>
|
||||
file.path === `${folder}.md` ||
|
||||
file.path.startsWith(`${folder}/`),
|
||||
)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
async fullSync(): Promise<{ queued: number; failed: number }> {
|
||||
|
|
@ -32,7 +61,9 @@ export class SyncEngine {
|
|||
let totalFailed = 0
|
||||
|
||||
try {
|
||||
const files = this.app.vault.getMarkdownFiles()
|
||||
const files = this.app.vault
|
||||
.getMarkdownFiles()
|
||||
.filter((f) => this.shouldSync(f))
|
||||
const batches = this.chunk(files, BATCH_SIZE)
|
||||
|
||||
for (const batch of batches) {
|
||||
|
|
@ -60,13 +91,16 @@ export class SyncEngine {
|
|||
}
|
||||
|
||||
onFileChange(file: TFile) {
|
||||
if (!(file instanceof TFile) || file.extension !== "md") return
|
||||
if (!(file instanceof TFile) || !this.shouldSync(file)) return
|
||||
this.pendingChanges.set(file.path, "upsert")
|
||||
this.schedulePush()
|
||||
}
|
||||
|
||||
onFileDelete(file: TFile) {
|
||||
if (!(file instanceof TFile) || file.extension !== "md") return
|
||||
// Always allow deletes through (file may have been previously synced
|
||||
// before its folder was excluded). The server safely no-ops on unknown
|
||||
// customIds.
|
||||
this.pendingChanges.set(file.path, "delete")
|
||||
this.schedulePush()
|
||||
}
|
||||
|
|
@ -74,7 +108,9 @@ export class SyncEngine {
|
|||
onFileRename(file: TFile, oldPath: string) {
|
||||
if (!(file instanceof TFile) || file.extension !== "md") return
|
||||
this.pendingChanges.set(oldPath, "delete")
|
||||
this.pendingChanges.set(file.path, "upsert")
|
||||
if (this.shouldSync(file)) {
|
||||
this.pendingChanges.set(file.path, "upsert")
|
||||
}
|
||||
this.schedulePush()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
export type SyncMode = "all" | "folders"
|
||||
|
||||
export interface SupermemorySettings {
|
||||
apiKey: string
|
||||
apiBaseUrl: string
|
||||
|
|
@ -6,4 +8,7 @@ export interface SupermemorySettings {
|
|||
connectionId: string
|
||||
syncOnSave: boolean
|
||||
syncOnStartup: boolean
|
||||
syncMode: SyncMode
|
||||
/** Comma-separated folder paths; only used when syncMode === "folders" */
|
||||
includedFolders: string
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue