firstsun-dev_git-files-sync/src/settings.ts
2026-06-28 04:50:34 +00:00

291 lines
9.1 KiB
TypeScript

import {App, PluginSettingTab, Setting, Notice} from 'obsidian';
import GitLabFilesPush from "./main";
export interface SyncMetadata {
lastSyncedSha: string;
lastSyncedAt: number;
lastKnownPath?: string;
}
export type GitServiceType = 'gitlab' | 'github' | 'gitea';
/**
* How symbolic links (Git blobs with mode 120000) are synced:
* - 'real': recreate a real OS symlink on desktop; on mobile (no symlink API)
* fall back to syncing the link target's content as a normal file.
* - 'follow': always sync the target file's content as a normal file.
* - 'skip': ignore symlinks entirely.
*/
export type SymlinkHandling = 'real' | 'follow' | 'skip';
export interface GitLabFilesPushSettings {
serviceType: GitServiceType;
gitlabToken: string;
gitlabBaseUrl: string;
projectId: string;
githubToken: string;
githubOwner: string;
githubRepo: string;
giteaToken: string;
giteaBaseUrl: string;
giteaOwner: string;
giteaRepo: string;
branch: string;
syncMetadata: Record<string, SyncMetadata>;
rootPath: string;
vaultFolder: string;
symlinkHandling: SymlinkHandling;
}
export function getServiceName(settings: GitLabFilesPushSettings): string {
if (settings.serviceType === 'gitlab') return 'GitLab';
if (settings.serviceType === 'gitea') return 'Gitea';
return 'GitHub';
}
export const DEFAULT_SETTINGS: GitLabFilesPushSettings = {
serviceType: 'gitlab',
gitlabToken: '',
gitlabBaseUrl: 'https://gitlab.com',
projectId: '',
githubToken: '',
githubOwner: '',
githubRepo: '',
giteaToken: '',
giteaBaseUrl: '',
giteaOwner: '',
giteaRepo: '',
rootPath: "",
branch: 'main',
syncMetadata: {},
vaultFolder: '',
symlinkHandling: 'real'
}
export class GitLabSyncSettingTab extends PluginSettingTab {
plugin: GitLabFilesPush;
constructor(app: App, plugin: GitLabFilesPush) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
const {containerEl} = this;
containerEl.empty();
new Setting(containerEl)
.setName('Git service')
.setDesc('Choose your Git hosting service')
.addDropdown(dropdown => dropdown
.addOption('gitlab', 'GitLab')
.addOption('github', 'GitHub')
.addOption('gitea', 'Gitea')
.setValue(this.plugin.settings.serviceType)
.onChange((value: string) => {
this.plugin.settings.serviceType = value as GitServiceType;
void this.plugin.saveSettings();
this.plugin.initializeGitService();
this.display();
}));
new Setting(containerEl).setName('').setHeading();
if (this.plugin.settings.serviceType === 'gitlab') {
this.displayGitLabSettings(containerEl);
} else if (this.plugin.settings.serviceType === 'gitea') {
this.displayGiteaSettings(containerEl);
} else {
this.displayGitHubSettings(containerEl);
}
new Setting(containerEl)
.setName('Branch')
.setDesc('Branch to push or pull from')
.addText(text => text
.setPlaceholder('Main')
.setValue(this.plugin.settings.branch)
.onChange((value) => {
this.plugin.settings.branch = value || 'main';
void this.plugin.saveSettings();
}));
new Setting(containerEl)
.setName('Root path')
.setDesc('Optional: subfolder in repository (e.g. "notes")')
.addText(text => text
.setPlaceholder('Enter subfolder path')
.setValue(this.plugin.settings.rootPath)
.onChange((value) => {
this.plugin.settings.rootPath = value.replace(/^\/|\/$/g, '');
void this.plugin.saveSettings();
this.plugin.initializeGitService();
}));
new Setting(containerEl)
.setName('Vault folder')
.setDesc('Optional: only sync files in this vault folder (e.g. "sync" to only sync files in the sync folder)')
.addText(text => text
.setPlaceholder('Leave empty to sync all files')
.setValue(this.plugin.settings.vaultFolder)
.onChange((value) => {
this.plugin.settings.vaultFolder = value.replace(/^\/|\/$/g, '');
void this.plugin.saveSettings();
}));
new Setting(containerEl)
.setName('Symbolic links')
.setDesc('How to sync symlinks: "real" recreates the link on desktop and falls back to the target content on mobile, "follow" always syncs the target content, and "skip" ignores symlinks.')
.addDropdown(dropdown => dropdown
.addOption('real', 'Real symlink (recommended)')
.addOption('follow', 'Follow (sync target content)')
.addOption('skip', 'Skip')
.setValue(this.plugin.settings.symlinkHandling)
.onChange((value: string) => {
this.plugin.settings.symlinkHandling = value as SymlinkHandling;
void this.plugin.saveSettings();
}));
new Setting(containerEl)
.setName('Test connection')
.setDesc(`Verify your ${getServiceName(this.plugin.settings)} settings`)
.addButton(button => button
.setButtonText('Test connection')
.onClick(async () => {
try {
await this.plugin.gitService.testConnection();
new Notice(`${getServiceName(this.plugin.settings)} connection successful!`);
} catch (e: unknown) {
const message = e instanceof Error ? e.message : String(e);
new Notice(`Connection failed: ${message}`);
}
}));
}
private displayGitLabSettings(containerEl: HTMLElement): void {
new Setting(containerEl)
.setName('GitLab personal access token')
.setDesc('Create a token in GitLab user settings > access tokens with "API" scope')
.addText(text => text
.setPlaceholder('Enter your token')
.setValue(this.plugin.settings.gitlabToken)
.onChange((value) => {
this.plugin.settings.gitlabToken = value;
void this.plugin.saveSettings();
this.plugin.initializeGitService();
}));
new Setting(containerEl)
.setName('GitLab base URL')
.setDesc('Defaults to https://gitlab.com')
.addText(text => text
.setPlaceholder('https://gitlab.com')
.setValue(this.plugin.settings.gitlabBaseUrl)
.onChange((value) => {
this.plugin.settings.gitlabBaseUrl = value || 'https://gitlab.com';
void this.plugin.saveSettings();
this.plugin.initializeGitService();
}));
new Setting(containerEl)
.setName('Project ID')
.setDesc('Found in GitLab project overview')
.addText(text => text
.setPlaceholder('Enter numeric project ID')
.setValue(this.plugin.settings.projectId)
.onChange((value) => {
this.plugin.settings.projectId = value;
void this.plugin.saveSettings();
this.plugin.initializeGitService();
}));
}
private displayGiteaSettings(containerEl: HTMLElement): void {
new Setting(containerEl)
.setName('Gitea personal access token')
.setDesc('Create a token in user settings > applications > access tokens')
.addText(text => text
.setPlaceholder('Enter your token')
.setValue(this.plugin.settings.giteaToken)
.onChange((value) => {
this.plugin.settings.giteaToken = value;
void this.plugin.saveSettings();
this.plugin.initializeGitService();
}));
new Setting(containerEl)
.setName('Gitea base URL')
.setDesc('URL of your Gitea instance (e.g. https://gitea.example.com)')
.addText(text => text
.setPlaceholder('https://gitea.example.com')
.setValue(this.plugin.settings.giteaBaseUrl)
.onChange((value) => {
this.plugin.settings.giteaBaseUrl = value;
void this.plugin.saveSettings();
this.plugin.initializeGitService();
}));
new Setting(containerEl)
.setName('Repository owner')
.setDesc('Gitea username or organization name')
.addText(text => text
.setPlaceholder('Username')
.setValue(this.plugin.settings.giteaOwner)
.onChange((value) => {
this.plugin.settings.giteaOwner = value;
void this.plugin.saveSettings();
this.plugin.initializeGitService();
}));
new Setting(containerEl)
.setName('Repository name')
.setDesc('Name of the repository')
.addText(text => text
.setPlaceholder('My notes')
.setValue(this.plugin.settings.giteaRepo)
.onChange((value) => {
this.plugin.settings.giteaRepo = value;
void this.plugin.saveSettings();
this.plugin.initializeGitService();
}));
}
private displayGitHubSettings(containerEl: HTMLElement): void {
new Setting(containerEl)
.setName('GitHub personal access token')
.setDesc('Create a token in GitHub settings > developer settings > personal access tokens with "repo" scope')
.addText(text => text
.setPlaceholder('Enter your token')
.setValue(this.plugin.settings.githubToken)
.onChange((value) => {
this.plugin.settings.githubToken = value;
void this.plugin.saveSettings();
this.plugin.initializeGitService();
}));
new Setting(containerEl)
.setName('Repository owner')
.setDesc('GitHub username or organization name')
.addText(text => text
.setPlaceholder('Username')
.setValue(this.plugin.settings.githubOwner)
.onChange((value) => {
this.plugin.settings.githubOwner = value;
void this.plugin.saveSettings();
this.plugin.initializeGitService();
}));
new Setting(containerEl)
.setName('Repository name')
.setDesc('Name of the GitHub repository')
.addText(text => text
.setPlaceholder('My notes')
.setValue(this.plugin.settings.githubRepo)
.onChange((value) => {
this.plugin.settings.githubRepo = value;
void this.plugin.saveSettings();
this.plugin.initializeGitService();
}));
}
}