feat: implement rootPath setting and Test connection button

- Added rootPath to GitLabFilesPushSettings and DEFAULT_SETTINGS
- Implemented testConnection in GitLabService to verify credentials
- Added rootPath support to GitLabService API URL generation
- Added UI fields for rootPath and Test connection button in settings tab
- Updated tests to include rootPath in mock settings and services

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
tianyao 2026-04-01 17:13:12 +00:00
parent b472594d31
commit cccf096103
6 changed files with 58 additions and 7 deletions

4
package-lock.json generated
View file

@ -1,11 +1,11 @@
{
"name": "obsidian-sample-plugin",
"name": "gitlab-files-push",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "obsidian-sample-plugin",
"name": "gitlab-files-push",
"version": "1.0.0",
"license": "0-BSD",
"dependencies": {

View file

@ -15,7 +15,8 @@ export default class GitLabFilesPush extends Plugin {
this.gitlab = new GitLabService(
this.settings.gitlabBaseUrl,
this.settings.gitlabToken,
this.settings.projectId
this.settings.projectId,
this.settings.rootPath
);
this.sync = new SyncManager(this.app, this.gitlab, this.settings);

View file

@ -10,15 +10,18 @@ export class GitLabService {
private baseUrl: string;
private token: string;
private projectId: string;
private rootPath: string;
constructor(baseUrl: string, token: string, projectId: string) {
constructor(baseUrl: string, token: string, projectId: string, rootPath: string = '') {
this.baseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
this.token = token;
this.projectId = projectId;
this.rootPath = rootPath.replace(/^\/|\/$/g, '');
}
private getApiUrl(path: string): string {
const encodedPath = encodeURIComponent(path);
const fullPath = this.rootPath ? `${this.rootPath}/${path}` : path;
const encodedPath = encodeURIComponent(fullPath);
return `${this.baseUrl}/api/v4/projects/${this.projectId}/repository/files/${encodedPath}`;
}
@ -87,4 +90,22 @@ export class GitLabService {
return ((response.json as unknown) as GitLabFileResponse).file_path;
}
async testConnection(): Promise<void> {
if (!this.token) throw new Error('Token is missing');
if (!this.projectId) throw new Error('Project ID is missing');
const url = `${this.baseUrl}/api/v4/projects/${this.projectId}`;
const response = await requestUrl({
url,
method: 'GET',
headers: {
'PRIVATE-TOKEN': this.token
}
});
if (response.status !== 200) {
throw new Error(`Failed to connect: ${response.status}`);
}
}
}

View file

@ -1,4 +1,4 @@
import {App, PluginSettingTab, Setting} from 'obsidian';
import {App, PluginSettingTab, Setting, Notice} from 'obsidian';
import GitLabFilesPush from "./main";
export interface SyncMetadata {
@ -12,12 +12,14 @@ export interface GitLabFilesPushSettings {
projectId: string;
branch: string;
syncMetadata: Record<string, SyncMetadata>;
rootPath: string;
}
export const DEFAULT_SETTINGS: GitLabFilesPushSettings = {
gitlabToken: '',
gitlabBaseUrl: 'https://gitlab.com',
projectId: '',
rootPath: "",
branch: 'main',
syncMetadata: {}
}
@ -78,5 +80,31 @@ export class GitLabSyncSettingTab extends PluginSettingTab {
this.plugin.settings.branch = value || 'main';
await 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(async (value) => {
this.plugin.settings.rootPath = value.replace(/^\/|\/$/g, '');
await this.plugin.saveSettings();
}));
new Setting(containerEl)
.setName('Test connection')
.setDesc('Verify your GitLab settings')
.addButton(button => button
.setButtonText('Test connection')
.onClick(async () => {
try {
await this.plugin.gitlab.testConnection();
new Notice('GitLab connection successful!');
} catch (e: unknown) {
const message = e instanceof Error ? e.message : String(e);
new Notice(`GitLab connection failed: ${message}`);
}
}));
}
}

View file

@ -27,6 +27,7 @@ const mockSettings: GitLabFilesPushSettings = {
gitlabBaseUrl: 'https://gitlab.com',
projectId: '123',
branch: 'main',
rootPath: '',
syncMetadata: {}
};

View file

@ -15,7 +15,7 @@ describe('GitLabService', () => {
beforeEach(() => {
vi.clearAllMocks();
service = new GitLabService(baseUrl, token, projectId);
service = new GitLabService(baseUrl, token, projectId, '');
});
describe('getFile', () => {