test
This commit is contained in:
249
main.js
249
main.js
@@ -47,6 +47,7 @@ function createWindow() {
|
|||||||
return win;
|
return win;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Settings-Fenster
|
// Settings-Fenster
|
||||||
let settingsWin;
|
let settingsWin;
|
||||||
function openSettings(win) {
|
function openSettings(win) {
|
||||||
@@ -101,6 +102,87 @@ async function initGitRepo(folder) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Map für Monitoring-Watcher (nicht repoWatchers!)
|
||||||
|
const monitoringWatchers = new Map();
|
||||||
|
|
||||||
|
function startMonitoringWatcher(folderPath, win) {
|
||||||
|
// Nicht mehrfach starten
|
||||||
|
if (monitoringWatchers.has(folderPath)) return;
|
||||||
|
const watcher = chokidar.watch(folderPath, {
|
||||||
|
ignored: /(^|[\/\\])\..|node_modules|\.git/, // ignoriert .git und .dot-Dateien + node_modules
|
||||||
|
ignoreInitial: true,
|
||||||
|
persistent: true,
|
||||||
|
depth: 99, // Rekursiv
|
||||||
|
awaitWriteFinish: {
|
||||||
|
stabilityThreshold: 300,
|
||||||
|
pollInterval: 100
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: Optionale .gitignore Logik nachrüsten
|
||||||
|
|
||||||
|
watcher.on('all', async (event, changedPath) => {
|
||||||
|
debug(`[MONITOR] ${event} in ${changedPath}`);
|
||||||
|
// Hier einfach auto-commit Funktion rufen:
|
||||||
|
await autoCommit(folderPath, `[auto] ${event} ${path.relative(folderPath, changedPath)}`);
|
||||||
|
// Repo-UI aktualisieren:
|
||||||
|
win.webContents.send('repo-updated', folderPath);
|
||||||
|
});
|
||||||
|
|
||||||
|
monitoringWatchers.set(folderPath, watcher);
|
||||||
|
debug(`[MONITOR] Watcher aktiv für ${folderPath}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopMonitoringWatcher(folderPath) {
|
||||||
|
const watcher = monitoringWatchers.get(folderPath);
|
||||||
|
if (watcher) {
|
||||||
|
watcher.close();
|
||||||
|
monitoringWatchers.delete(folderPath);
|
||||||
|
debug(`[MONITOR] Watcher gestoppt für ${folderPath}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function autoCommit(folder, message) {
|
||||||
|
const git = simpleGit(folder);
|
||||||
|
const status = await git.status();
|
||||||
|
if (
|
||||||
|
status.not_added.length === 0 &&
|
||||||
|
status.created.length === 0 &&
|
||||||
|
status.deleted.length === 0 &&
|
||||||
|
status.modified.length === 0 &&
|
||||||
|
status.renamed.length === 0
|
||||||
|
) {
|
||||||
|
debug('Auto-Commit: Keine Änderungen zum committen.');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Der Rest wie in commit-current-folder
|
||||||
|
let currentBranch = null;
|
||||||
|
try {
|
||||||
|
currentBranch = (await git.revparse(['--abbrev-ref', 'HEAD'])).trim();
|
||||||
|
debug(`[autoCommit] Aktueller Branch: ${currentBranch}`);
|
||||||
|
} catch {
|
||||||
|
debug('[autoCommit] HEAD ist detached.');
|
||||||
|
}
|
||||||
|
if (!currentBranch || currentBranch === 'HEAD') {
|
||||||
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
||||||
|
const backupBranch = `backup-master-${timestamp}`;
|
||||||
|
const branches = await git.branchLocal();
|
||||||
|
if (branches.all.includes('master')) {
|
||||||
|
await git.branch(['-m', 'master', backupBranch]);
|
||||||
|
debug(`[autoCommit] Alter master in ${backupBranch} umbenannt.`);
|
||||||
|
}
|
||||||
|
await git.checkout(['-b', 'master']);
|
||||||
|
debug('[autoCommit] Neuer master-Branch erstellt und ausgecheckt.');
|
||||||
|
}
|
||||||
|
await git.add(['-A']);
|
||||||
|
debug('[autoCommit] Alle Änderungen gestaged.');
|
||||||
|
await git.commit(message || '[auto]');
|
||||||
|
debug('[autoCommit] Commit erfolgreich erstellt.');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
app.whenReady().then(() => {
|
app.whenReady().then(() => {
|
||||||
const win = createWindow();
|
const win = createWindow();
|
||||||
|
|
||||||
@@ -118,22 +200,39 @@ app.whenReady().then(() => {
|
|||||||
]);
|
]);
|
||||||
Menu.setApplicationMenu(menu);
|
Menu.setApplicationMenu(menu);
|
||||||
|
|
||||||
// 1) Beim Start bereits gespeicherte Ordner überwachen
|
// 1) Beim Start bereits gespeicherte Ordner überwachen und monitoren
|
||||||
const folders = store.get('folders');
|
const folders = store.get('folders') || [];
|
||||||
folders.forEach(folder => {
|
folders.forEach(folderObj => {
|
||||||
// nur watchen, wenn .git existiert
|
if (fs.existsSync(path.join(folderObj.path, '.git', 'refs', 'heads', 'master'))) {
|
||||||
if (fs.existsSync(path.join(folder, '.git', 'refs', 'heads', 'master'))) {
|
watchRepo(folderObj.path, win);
|
||||||
watchRepo(folder, win);
|
}
|
||||||
|
if (folderObj.monitoring) {
|
||||||
|
startMonitoringWatcher(folderObj.path, win);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 2) IPC-Handler
|
// 2) IPC-Handler
|
||||||
|
ipcMain.handle('get-selected', () => {
|
||||||
|
const folders = store.get('folders') || [];
|
||||||
|
const selectedPath = store.get('selected');
|
||||||
|
return folders.find(f => f.path === selectedPath) || null;
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('set-selected', (_e, folderObjOrPath) => {
|
||||||
|
// Akzeptiert sowohl String (legacy) als auch Objekt:
|
||||||
|
const folderPath = typeof folderObjOrPath === 'string'
|
||||||
|
? folderObjOrPath
|
||||||
|
: folderObjOrPath.path;
|
||||||
|
store.set('selected', folderPath);
|
||||||
|
const folders = store.get('folders') || [];
|
||||||
|
return folders.find(f => f.path === folderPath) || null;
|
||||||
|
});
|
||||||
|
|
||||||
// Liste aller Folders
|
// Liste aller Folders
|
||||||
ipcMain.handle('get-folders', () => store.get('folders'));
|
ipcMain.handle('get-folders', () => store.get('folders'));
|
||||||
|
|
||||||
// Ordner hinzufügen: Open-Dialog, init, Store-Update, watchen
|
|
||||||
|
// Ordner hinzufügen: Open-Dialog, init, Store-Update, watchen, monitoren
|
||||||
ipcMain.handle('add-folder', async () => {
|
ipcMain.handle('add-folder', async () => {
|
||||||
const { canceled, filePaths } = await dialog.showOpenDialog({
|
const { canceled, filePaths } = await dialog.showOpenDialog({
|
||||||
properties: ['openDirectory']
|
properties: ['openDirectory']
|
||||||
@@ -142,6 +241,24 @@ app.whenReady().then(() => {
|
|||||||
return store.get('folders');
|
return store.get('folders');
|
||||||
}
|
}
|
||||||
const newFolder = filePaths[0];
|
const newFolder = filePaths[0];
|
||||||
|
await initGitRepo(newFolder);
|
||||||
|
let folders = store.get('folders') || [];
|
||||||
|
let folderObj = folders.find(f => f.path === newFolder);
|
||||||
|
if (!folderObj) {
|
||||||
|
folderObj = { path: newFolder, monitoring: true };
|
||||||
|
folders.push(folderObj);
|
||||||
|
store.set('folders', folders);
|
||||||
|
}
|
||||||
|
store.set('selected', newFolder);
|
||||||
|
watchRepo(newFolder, win);
|
||||||
|
startMonitoringWatcher(newFolder, win);
|
||||||
|
return store.get('folders');
|
||||||
|
});
|
||||||
|
/*
|
||||||
|
ipcMain.handle('add-folder', async () => {
|
||||||
|
const { canceled, filePaths } = await dialog.showOpenDialog({ properties: ['openDirectory'] });
|
||||||
|
if (canceled || !filePaths[0]) return store.get('folders');
|
||||||
|
const newFolder = filePaths[0];
|
||||||
|
|
||||||
// Repo initialisieren
|
// Repo initialisieren
|
||||||
await initGitRepo(newFolder);
|
await initGitRepo(newFolder);
|
||||||
@@ -158,8 +275,27 @@ app.whenReady().then(() => {
|
|||||||
|
|
||||||
return store.get('folders');
|
return store.get('folders');
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
// Ordner entfernen: Watcher schließen, Store-Update
|
// Ordner entfernen: Watcher schließen, Store-Update
|
||||||
|
ipcMain.handle('remove-folder', (_e, folderObj) => {
|
||||||
|
const folders = store.get('folders') || [];
|
||||||
|
const updated = folders.filter(f => f.path !== folderObj.path);
|
||||||
|
store.set('folders', updated);
|
||||||
|
if (store.get('selected') === folderObj.path) store.set('selected', null);
|
||||||
|
stopMonitoringWatcher(folderObj.path);
|
||||||
|
const watcher = repoWatchers.get(folderObj.path);
|
||||||
|
if (watcher) watcher.close(), repoWatchers.delete(folderObj.path);
|
||||||
|
return updated;
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
ipcMain.handle('get-selected', () => store.get('selected'));
|
||||||
|
ipcMain.handle('set-selected', (_e, folderPath) => {
|
||||||
|
store.set('selected', folderPath);
|
||||||
|
return folderPath;
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
/*
|
||||||
ipcMain.handle('remove-folder', (_e, folder) => {
|
ipcMain.handle('remove-folder', (_e, folder) => {
|
||||||
const watcher = repoWatchers.get(folder);
|
const watcher = repoWatchers.get(folder);
|
||||||
if (watcher) {
|
if (watcher) {
|
||||||
@@ -173,41 +309,45 @@ app.whenReady().then(() => {
|
|||||||
}
|
}
|
||||||
return updated;
|
return updated;
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
// Zähle Commits
|
// Zähle Commits
|
||||||
ipcMain.handle('get-commit-count', async (_e, folder) => {
|
ipcMain.handle('get-commit-count', async (_e, folderObj) => {
|
||||||
const git = simpleGit(folder);
|
const git = simpleGit(folderObj.path);
|
||||||
const log = await git.log();
|
const log = await git.log();
|
||||||
return log.total; // Anzahl der Commits
|
return log.total; // Anzahl der Commits
|
||||||
});
|
});
|
||||||
|
|
||||||
// Prüfe, ob es ungestagte Änderungen gibt
|
// Prüfe, ob es ungestagte Änderungen gibt
|
||||||
ipcMain.handle('has-diffs', async (_e, folder) => {
|
ipcMain.handle('has-diffs', async (_e, folderObj) => {
|
||||||
const git = simpleGit(folder);
|
const git = simpleGit(folderObj.path);
|
||||||
const status = await git.status();
|
const status = await git.status();
|
||||||
// modified, not_added, deleted, etc.
|
// modified, not_added, deleted, etc.
|
||||||
return status.files.length > 0;
|
return status.files.length > 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Entferne das .git-Verzeichnis
|
// Entferne das .git-Verzeichnis
|
||||||
ipcMain.handle('remove-git-folder', async (_e, folder) => {
|
ipcMain.handle('remove-git-folder', async (_e, folderObj) => {
|
||||||
const gitDir = path.join(folder, '.git');
|
const gitDir = path.join(folderObj.path, '.git');
|
||||||
if (fs.existsSync(gitDir)) {
|
if (fs.existsSync(gitDir)) {
|
||||||
await fs.promises.rm(gitDir, { recursive: true, force: true });
|
await fs.promises.rm(gitDir, { recursive: true, force: true });
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
// Selected
|
// Selected
|
||||||
ipcMain.handle('get-selected', () => store.get('selected'));
|
ipcMain.handle('get-selected', () => store.get('selected'));
|
||||||
ipcMain.handle('set-selected', (_e, folder) => {
|
ipcMain.handle('set-selected', (_e, folder) => {
|
||||||
store.set('selected', folder);
|
store.set('selected', folder);
|
||||||
return folder;
|
return folder;
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
// Commits holen
|
// Commits holen
|
||||||
ipcMain.handle('get-commits', async (_e, folder) => {
|
ipcMain.handle('get-commits', async (_e, folderObj) => {
|
||||||
const git = simpleGit(folder);
|
const git = simpleGit(folderObj.path);
|
||||||
// alle Commits holen
|
// alle Commits holen
|
||||||
const log = await git.log(['--all']);
|
const log = await git.log(['--all']);
|
||||||
// aktuellen HEAD‐Hash ermitteln
|
// aktuellen HEAD‐Hash ermitteln
|
||||||
@@ -224,40 +364,40 @@ app.whenReady().then(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Diff
|
// Diff
|
||||||
ipcMain.handle('diff-commit', async (_e, folder, hash) => {
|
ipcMain.handle('diff-commit', async (_e, folderObj, hash) => {
|
||||||
const git = simpleGit(folder);
|
const git = simpleGit(folderObj.path);
|
||||||
return git.diff([`${hash}^!`]);
|
return git.diff([`${hash}^!`]);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Revert
|
// Revert
|
||||||
ipcMain.handle('revert-commit', async (_e, folder, hash) => {
|
ipcMain.handle('revert-commit', async (_e, folderObj, hash) => {
|
||||||
const git = simpleGit(folder);
|
const git = simpleGit(folderObj.path);
|
||||||
await git.revert(hash, ['--no-edit']);
|
await git.revert(hash, ['--no-edit']);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checkt das Arbeitsverzeichnis auf exakt den Zustand von `hash` aus.
|
* Checkt das Arbeitsverzeichnis auf exakt den Zustand von `hash` aus.
|
||||||
*/
|
*/
|
||||||
ipcMain.handle('checkout-commit', async (_e, folder, hash) => {
|
ipcMain.handle('checkout-commit', async (_e, folderObj, hash) => {
|
||||||
const git = simpleGit(folder);
|
const git = simpleGit(folderObj.path);
|
||||||
// clean mode: alle lokalen Veränderungen verwerfen
|
// clean mode: alle lokalen Veränderungen verwerfen
|
||||||
await git.checkout([hash, '--force']);
|
await git.checkout([hash, '--force']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Snapshot
|
// Snapshot
|
||||||
ipcMain.handle('snapshot-commit', async (_e, folder, hash) => {
|
ipcMain.handle('snapshot-commit', async (_e, folderObj, hash) => {
|
||||||
const { canceled, filePaths } = await dialog.showOpenDialog({
|
const { canceled, filePaths } = await dialog.showOpenDialog({
|
||||||
title: 'Ordner auswählen zum Speichern des Snapshots',
|
title: 'Ordner auswählen zum Speichern des Snapshots',
|
||||||
properties: ['openDirectory']
|
properties: ['openDirectory']
|
||||||
});
|
});
|
||||||
if (canceled || !filePaths[0]) return;
|
if (canceled || !filePaths[0]) return;
|
||||||
const outDir = filePaths[0];
|
const outDir = filePaths[0];
|
||||||
const baseName = path.basename(folder);
|
const baseName = path.basename(folderObj.path);
|
||||||
const filePath = path.join(outDir, `${baseName}-${hash}.zip`);
|
const filePath = path.join(outDir, `${baseName}-${hash}.zip`);
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
exec(
|
exec(
|
||||||
`git -C "${folder}" archive --format zip --output "${filePath}" ${hash}`,
|
`git -C "${folderObj.path}" archive --format zip --output "${filePath}" ${hash}`,
|
||||||
err => err ? reject(err) : resolve(filePath)
|
err => err ? reject(err) : resolve(filePath)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -277,38 +417,58 @@ app.whenReady().then(() => {
|
|||||||
ipcMain.handle('set-skip-git-prompt', (_e,val) => store.set('skipGitPrompt', val));
|
ipcMain.handle('set-skip-git-prompt', (_e,val) => store.set('skipGitPrompt', val));
|
||||||
|
|
||||||
|
|
||||||
ipcMain.handle('commit-current-folder', async (_e, folder, message) => {
|
|
||||||
|
|
||||||
|
|
||||||
|
ipcMain.handle('commit-current-folder', async (_e, folderObj, message) => {
|
||||||
|
folder = folderObj.path;
|
||||||
try {
|
try {
|
||||||
debug(`Commit-Vorgang für ${folder} gestartet…`);
|
debug(`Commit-Vorgang für ${folder} gestartet…`);
|
||||||
const git = simpleGit(folder);
|
const git = simpleGit(folder);
|
||||||
|
|
||||||
// 1) Branch‐Status prüfen
|
// Prüfe: Gibt es was zu committen?
|
||||||
|
const status = await git.status();
|
||||||
|
if (
|
||||||
|
status.not_added.length === 0 &&
|
||||||
|
status.created.length === 0 &&
|
||||||
|
status.deleted.length === 0 &&
|
||||||
|
status.modified.length === 0 &&
|
||||||
|
status.renamed.length === 0
|
||||||
|
) {
|
||||||
|
debug('Nichts zu committen.');
|
||||||
|
return { success: false, error: 'Nichts zu committen.' };
|
||||||
|
}
|
||||||
|
|
||||||
|
// HEAD-Status prüfen
|
||||||
let currentBranch = null;
|
let currentBranch = null;
|
||||||
try {
|
try {
|
||||||
currentBranch = (await git.revparse(['--abbrev-ref', 'HEAD'])).trim();
|
currentBranch = (await git.revparse(['--abbrev-ref', 'HEAD'])).trim();
|
||||||
debug(`Aktueller Branch: ${currentBranch}`);
|
debug(`Aktueller Branch: ${currentBranch}`);
|
||||||
} catch {
|
} catch (err) {
|
||||||
debug('HEAD ist detached.');
|
debug('HEAD ist detached.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) Falls detached, alten master sichern und neuen anlegen
|
// Falls detached, **jetzt erst** alten Branch umbenennen und neuen master erzeugen
|
||||||
if (!currentBranch || currentBranch === 'HEAD') {
|
if (!currentBranch || currentBranch === 'HEAD') {
|
||||||
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
||||||
const backupBranch = `backup-master-${timestamp}`;
|
const backupBranch = `backup-master-${timestamp}`;
|
||||||
const branches = await git.branchLocal();
|
|
||||||
|
|
||||||
|
// Alten master umbenennen (nur falls vorhanden!)
|
||||||
|
const branches = await git.branchLocal();
|
||||||
if (branches.all.includes('master')) {
|
if (branches.all.includes('master')) {
|
||||||
await git.branch(['-m', 'master', backupBranch]);
|
await git.branch(['-m', 'master', backupBranch]);
|
||||||
debug(`Alter master → ${backupBranch}`);
|
debug(`Alter master-Branch wurde in ${backupBranch} umbenannt.`);
|
||||||
}
|
}
|
||||||
|
// Neuer master-Branch
|
||||||
await git.checkout(['-b', 'master']);
|
await git.checkout(['-b', 'master']);
|
||||||
debug('Neuer master-Branch erstellt.');
|
debug('Neuer master-Branch erstellt und ausgecheckt.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3) Commit & Push
|
await git.add(['-A']);
|
||||||
await git.add(['-A']); debug('git add -A');
|
debug('Alle Änderungen gestaged.');
|
||||||
await git.commit(message || 'test'); debug('git commit');
|
await git.commit(message || 'test');
|
||||||
await git.push(['-u','origin','master']); debug('git push');
|
debug('Commit erfolgreich erstellt.');
|
||||||
|
// Push hier ggf. noch auskommentiert lassen
|
||||||
|
|
||||||
return { success: true };
|
return { success: true };
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -317,8 +477,21 @@ app.whenReady().then(() => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('set-monitoring', async (_e, folderPath, monitoring) => {
|
||||||
|
let folders = store.get('folders') || [];
|
||||||
|
folders = folders.map(f =>
|
||||||
|
f.path === folderPath ? { ...f, monitoring } : f
|
||||||
|
);
|
||||||
|
store.set('folders', folders);
|
||||||
|
debug(`[STORE] Monitoring für ${folderPath}: ${monitoring}`);
|
||||||
|
// Monitoring-Watcher starten/stoppen → gleich mehr dazu
|
||||||
|
if (monitoring) {
|
||||||
|
startMonitoringWatcher(folderPath, win);
|
||||||
|
} else {
|
||||||
|
stopMonitoringWatcher(folderPath);
|
||||||
|
}
|
||||||
|
return monitoring;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// … Ende der IPC-Handler …
|
// … Ende der IPC-Handler …
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chokidar": "^4.0.3",
|
"chokidar": "^4.0.3",
|
||||||
"electron-store": "^8.2.0",
|
"electron-store": "^8.2.0",
|
||||||
|
"ignore": "^7.0.4",
|
||||||
"simple-git": "^3.20.0",
|
"simple-git": "^3.20.0",
|
||||||
"suncalc": "^1.9.0"
|
"suncalc": "^1.9.0"
|
||||||
},
|
},
|
||||||
|
|||||||
27
preload.js
27
preload.js
@@ -10,23 +10,20 @@ contextBridge.exposeInMainWorld('settingsAPI', {
|
|||||||
contextBridge.exposeInMainWorld('electronAPI', {
|
contextBridge.exposeInMainWorld('electronAPI', {
|
||||||
getFolders: () => ipcRenderer.invoke('get-folders'),
|
getFolders: () => ipcRenderer.invoke('get-folders'),
|
||||||
addFolder: () => ipcRenderer.invoke('add-folder'),
|
addFolder: () => ipcRenderer.invoke('add-folder'),
|
||||||
removeFolder: folder => ipcRenderer.invoke('remove-folder', folder),
|
removeFolder: folderObj=> ipcRenderer.invoke('remove-folder', folderObj),
|
||||||
getSelected: () => ipcRenderer.invoke('get-selected'),
|
getSelected: () => ipcRenderer.invoke('get-selected'),
|
||||||
setSelected: folder => ipcRenderer.invoke('set-selected', folder),
|
setSelected: folderObj=> ipcRenderer.invoke('set-selected', folderObj),
|
||||||
listFolder: folder => ipcRenderer.invoke('list-folder', folder),
|
getCommits: folderObj=> ipcRenderer.invoke('get-commits', folderObj),
|
||||||
getCommits: folder => ipcRenderer.invoke('get-commits', folder),
|
diffCommit: (folderObj, hash) => ipcRenderer.invoke('diff-commit', folderObj, hash),
|
||||||
diffCommit: (folder, hash) => ipcRenderer.invoke('diff-commit', folder, hash),
|
revertCommit: (folderObj, hash) => ipcRenderer.invoke('revert-commit', folderObj, hash),
|
||||||
revertCommit: (folder, hash) => ipcRenderer.invoke('revert-commit', folder, hash),
|
snapshotCommit: (folderObj, hash) => ipcRenderer.invoke('snapshot-commit', folderObj, hash),
|
||||||
snapshotCommit: (folder, hash) => ipcRenderer.invoke('snapshot-commit', folder, hash),
|
checkoutCommit: (folderObj, hash) => ipcRenderer.invoke('checkout-commit', folderObj, hash),
|
||||||
checkoutCommit: (folder, hash) => ipcRenderer.invoke('checkout-commit', folder, hash),
|
getCommitCount: folderObj=> ipcRenderer.invoke('get-commit-count', folderObj),
|
||||||
getCommitCount: folder => ipcRenderer.invoke('get-commit-count', folder),
|
hasDiffs: folderObj=> ipcRenderer.invoke('has-diffs', folderObj),
|
||||||
hasDiffs: folder => ipcRenderer.invoke('has-diffs', folder),
|
removeGitFolder:folderObj=> ipcRenderer.invoke('remove-git-folder', folderObj),
|
||||||
removeGitFolder: folder => ipcRenderer.invoke('remove-git-folder', folder),
|
commitCurrentFolder: (folderObj, message) => ipcRenderer.invoke('commit-current-folder', folderObj, message),
|
||||||
getSkipPrompt: () => ipcRenderer.invoke('get-skip-git-prompt'),
|
|
||||||
setSkipPrompt: val => ipcRenderer.invoke('set-skip-git-prompt', val),
|
|
||||||
showFolderContextMenu: folderPath => ipcRenderer.send('show-folder-context-menu', folderPath),
|
|
||||||
commitCurrentFolder: (folder, message) => ipcRenderer.invoke('commit-current-folder', folder, message),
|
|
||||||
showFolderContextMenu: folderPath => ipcRenderer.send('show-folder-context-menu', folderPath),
|
showFolderContextMenu: folderPath => ipcRenderer.send('show-folder-context-menu', folderPath),
|
||||||
|
setMonitoring: (folderObj, monitoring) => ipcRenderer.invoke('set-monitoring', folderObj.path, monitoring),
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcRenderer.on('repo-updated', (_e, folder) => {
|
ipcRenderer.on('repo-updated', (_e, folder) => {
|
||||||
|
|||||||
155
renderer.js
155
renderer.js
@@ -8,18 +8,13 @@ window.addEventListener('DOMContentLoaded', async () => {
|
|||||||
const contentList = document.getElementById('contentList');
|
const contentList = document.getElementById('contentList');
|
||||||
const panel = document.querySelector('.flex-1.p-4.overflow-y-auto');
|
const panel = document.querySelector('.flex-1.p-4.overflow-y-auto');
|
||||||
|
|
||||||
|
// Farben für Sky-Mode
|
||||||
|
|
||||||
// 1) Baby-Blau und Nacht-Blau als RGB-Arrays
|
|
||||||
const DAY_COLOR = [173, 216, 230];
|
const DAY_COLOR = [173, 216, 230];
|
||||||
const NIGHT_COLOR = [0, 0, 50];
|
const NIGHT_COLOR = [0, 0, 50];
|
||||||
|
|
||||||
// 2) Linearer Interpolator
|
|
||||||
function lerpColor(c1, c2, t) {
|
function lerpColor(c1, c2, t) {
|
||||||
return c1.map((v, i) => Math.round(v + t * (c2[i] - v)));
|
return c1.map((v, i) => Math.round(v + t * (c2[i] - v)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3) Entscheider für den Zeit-Factor
|
|
||||||
function getTimeFactor() {
|
function getTimeFactor() {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const md = now.getHours() * 60 + now.getMinutes();
|
const md = now.getHours() * 60 + now.getMinutes();
|
||||||
@@ -29,29 +24,20 @@ window.addEventListener('DOMContentLoaded', async () => {
|
|||||||
if (md < 20 * 60) return 1 - ((md - 16*60) / (4*60));
|
if (md < 20 * 60) return 1 - ((md - 16*60) / (4*60));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4) setzt die Hintergrundfarbe
|
|
||||||
function updateBackground() {
|
function updateBackground() {
|
||||||
const factor = getTimeFactor();
|
const factor = getTimeFactor();
|
||||||
const [r,g,b] = lerpColor(NIGHT_COLOR, DAY_COLOR, factor);
|
const [r,g,b] = lerpColor(NIGHT_COLOR, DAY_COLOR, factor);
|
||||||
panel.style.backgroundColor = `rgb(${r}, ${g}, ${b})`;
|
panel.style.backgroundColor = `rgb(${r}, ${g}, ${b})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5) applySkyMode-Funktion
|
|
||||||
let skyIntervalId, titleIntervalId;
|
let skyIntervalId, titleIntervalId;
|
||||||
function applySkyMode(enabled) {
|
function applySkyMode(enabled) {
|
||||||
document.body.classList.toggle('sky-mode', enabled);
|
document.body.classList.toggle('sky-mode', enabled);
|
||||||
|
|
||||||
// alte Intervalle löschen
|
|
||||||
clearInterval(skyIntervalId);
|
clearInterval(skyIntervalId);
|
||||||
clearInterval(titleIntervalId);
|
clearInterval(titleIntervalId);
|
||||||
|
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
// Hintergrund updaten
|
|
||||||
updateBackground();
|
updateBackground();
|
||||||
skyIntervalId = setInterval(updateBackground, 60_000);
|
skyIntervalId = setInterval(updateBackground, 60_000);
|
||||||
|
|
||||||
// Titel-Farbe je nach Uhrzeit
|
|
||||||
function updateTitleColor() {
|
function updateTitleColor() {
|
||||||
const hour = new Date().getHours();
|
const hour = new Date().getHours();
|
||||||
if (hour >= 18 || hour < 6) {
|
if (hour >= 18 || hour < 6) {
|
||||||
@@ -63,36 +49,38 @@ window.addEventListener('DOMContentLoaded', async () => {
|
|||||||
updateTitleColor();
|
updateTitleColor();
|
||||||
titleIntervalId = setInterval(updateTitleColor, 60_000);
|
titleIntervalId = setInterval(updateTitleColor, 60_000);
|
||||||
} else {
|
} else {
|
||||||
// Sky-Mode aus → zurücksetzen
|
|
||||||
panel.style.backgroundColor = '';
|
panel.style.backgroundColor = '';
|
||||||
titleEl.style.color = '';
|
titleEl.style.color = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6) initial anwenden und auf Event lauschen
|
|
||||||
const initialSky = await window.settingsAPI.getSkyMode();
|
const initialSky = await window.settingsAPI.getSkyMode();
|
||||||
applySkyMode(initialSky);
|
applySkyMode(initialSky);
|
||||||
window.addEventListener('skymode-changed', e => applySkyMode(e.detail));
|
window.addEventListener('skymode-changed', e => applySkyMode(e.detail));
|
||||||
|
|
||||||
// … restliches Rendering wie gehabt …
|
|
||||||
function basename(fullPath) {
|
function basename(fullPath) {
|
||||||
return fullPath.replace(/.*[\\/]/, '');
|
return fullPath.replace(/.*[\\/]/, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Utility für FolderObj-Suche per Path
|
||||||
|
async function getFolderObjByPath(path) {
|
||||||
|
const folders = await window.electronAPI.getFolders();
|
||||||
|
return folders.find(f => f.path === path) || null;
|
||||||
|
}
|
||||||
|
|
||||||
async function renderSidebar() {
|
async function renderSidebar() {
|
||||||
const folders = await window.electronAPI.getFolders();
|
const folders = await window.electronAPI.getFolders();
|
||||||
const selected = await window.electronAPI.getSelected();
|
const selected = await window.electronAPI.getSelected();
|
||||||
folderList.innerHTML = '';
|
folderList.innerHTML = '';
|
||||||
|
|
||||||
folders.forEach(folder => {
|
folders.forEach(folderObj => {
|
||||||
// 1) li anlegen, selected-Klasse statt bg-[#fecdd3]
|
const folder = folderObj.path;
|
||||||
|
const isMonitoring = folderObj.monitoring;
|
||||||
const li = document.createElement('li');
|
const li = document.createElement('li');
|
||||||
li.className = [
|
li.className = [
|
||||||
'flex items-center justify-between px-3 py-2 rounded cursor-pointer',
|
'flex items-center justify-between px-3 py-2 rounded cursor-pointer',
|
||||||
folder === selected ? 'selected' : ''
|
selected && folder === selected.path ? 'selected' : ''
|
||||||
].join(' ');
|
].join(' ');
|
||||||
|
|
||||||
// 2) inneres Markup, ohne Hard-Coded-Farben
|
|
||||||
li.innerHTML = `
|
li.innerHTML = `
|
||||||
<div class="flex items-center space-x-2 overflow-hidden">
|
<div class="flex items-center space-x-2 overflow-hidden">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg"
|
<svg xmlns="http://www.w3.org/2000/svg"
|
||||||
@@ -113,57 +101,61 @@ async function renderSidebar() {
|
|||||||
</button>
|
</button>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// rechter Mausklick in der Sidebar
|
// play/pause Button korrekt initialisieren
|
||||||
|
const pausePlayBtn = document.createElement('button');
|
||||||
|
pausePlayBtn.className = 'pause-play-btn ml-2';
|
||||||
|
pausePlayBtn.innerHTML = isMonitoring ? '⏸️' : '▶️';
|
||||||
|
pausePlayBtn.title = isMonitoring ? 'Monitoring pausieren' : 'Monitoring starten';
|
||||||
|
pausePlayBtn.addEventListener('click', async e => {
|
||||||
|
e.stopPropagation();
|
||||||
|
await window.electronAPI.setMonitoring(folderObj, !isMonitoring);
|
||||||
|
await renderSidebar();
|
||||||
|
});
|
||||||
|
li.appendChild(pausePlayBtn);
|
||||||
|
|
||||||
li.addEventListener('contextmenu', e => {
|
li.addEventListener('contextmenu', e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
window.electronAPI.showFolderContextMenu(folder);
|
window.electronAPI.showFolderContextMenu(folderObj.path);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3) Klick auf li (Select)
|
|
||||||
li.addEventListener('click', async e => {
|
li.addEventListener('click', async e => {
|
||||||
if (e.target.closest('.remove-btn')) return;
|
if (e.target.closest('.remove-btn')) return;
|
||||||
await window.electronAPI.setSelected(folder);
|
await window.electronAPI.setSelected(folderObj);
|
||||||
await renderSidebar();
|
await renderSidebar();
|
||||||
await renderContent(folder);
|
await renderContent(folderObj);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 4) Remove-Button
|
|
||||||
li.querySelector('.remove-btn').addEventListener('click', async e => {
|
li.querySelector('.remove-btn').addEventListener('click', async e => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
const count = await window.electronAPI.getCommitCount(folderObj);
|
||||||
// Commit-Count / Diffs / SkipPrompt-Logik wie gehabt
|
const hasUnstaged= await window.electronAPI.hasDiffs(folderObj);
|
||||||
const count = await window.electronAPI.getCommitCount(folder);
|
|
||||||
const hasUnstaged= await window.electronAPI.hasDiffs(folder);
|
|
||||||
const skipPrompt = await window.settingsAPI.getSkipPrompt();
|
const skipPrompt = await window.settingsAPI.getSkipPrompt();
|
||||||
|
|
||||||
if (count === 1 && !hasUnstaged) {
|
if (count === 1 && !hasUnstaged) {
|
||||||
if (skipPrompt) {
|
if (skipPrompt) {
|
||||||
await window.electronAPI.removeGitFolder(folder);
|
await window.electronAPI.removeGitFolder(folderObj);
|
||||||
} else {
|
} else {
|
||||||
const ok = confirm(
|
const ok = confirm(
|
||||||
'Dieser Ordner hat nur einen Initial-Commit und keine Änderungen.\n' +
|
'Dieser Ordner hat nur einen Initial-Commit und keine Änderungen.\n' +
|
||||||
'Möchtest du das gesamte Git-Repository (den .git-Ordner) löschen?'
|
'Möchtest du das gesamte Git-Repository (den .git-Ordner) löschen?'
|
||||||
);
|
);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
await window.electronAPI.removeGitFolder(folder);
|
await window.electronAPI.removeGitFolder(folderObj);
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5) aus Sidebar/Store entfernen
|
await window.electronAPI.removeFolder(folderObj);
|
||||||
await window.electronAPI.removeFolder(folder);
|
|
||||||
await renderSidebar();
|
await renderSidebar();
|
||||||
|
|
||||||
// 6) neue Selektion
|
|
||||||
const all = await window.electronAPI.getFolders();
|
const all = await window.electronAPI.getFolders();
|
||||||
if (all.length === 0) {
|
if (all.length === 0) {
|
||||||
titleEl.textContent = 'No folder selected';
|
titleEl.textContent = 'No folder selected';
|
||||||
contentList.innerHTML = '';
|
contentList.innerHTML = '';
|
||||||
} else {
|
} else {
|
||||||
// entfernten Index vorher merken, dann neuen auswählen
|
const idxOld = folders.findIndex(f => f.path === folderObj.path);
|
||||||
const idxOld = folders.indexOf(folder);
|
|
||||||
let idxNew = Math.max(0, idxOld - 1);
|
let idxNew = Math.max(0, idxOld - 1);
|
||||||
const pick = all[idxNew];
|
const pick = all[idxNew];
|
||||||
await window.electronAPI.setSelected(pick);
|
await window.electronAPI.setSelected(pick);
|
||||||
@@ -176,11 +168,10 @@ async function renderSidebar() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function renderContent(folder) {
|
async function renderContent(folderObj) {
|
||||||
const currentFolder = folder;
|
const folder = folderObj.path;
|
||||||
titleEl.textContent = folder;
|
titleEl.textContent = folder;
|
||||||
const { head, commits } = await window.electronAPI.getCommits(folder);
|
const { head, commits } = await window.electronAPI.getCommits(folderObj);
|
||||||
|
|
||||||
|
|
||||||
contentList.innerHTML = commits.map(c => `
|
contentList.innerHTML = commits.map(c => `
|
||||||
<li class="w-full p-3 mb-2 bg-white border border-gray-200 rounded shadow-sm
|
<li class="w-full p-3 mb-2 bg-white border border-gray-200 rounded shadow-sm
|
||||||
@@ -220,21 +211,10 @@ async function renderSidebar() {
|
|||||||
</svg>
|
</svg>
|
||||||
Jump Here
|
Jump Here
|
||||||
</button>
|
</button>
|
||||||
<!-- Revert-Button -->
|
|
||||||
<!--<button class="revert-btn flex items-center px-2 py-1 text-xs border rounded hover:bg-gray-100" data-hash="${c.hash}">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none"
|
|
||||||
viewBox="0 0 24 24" stroke="currentColor">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
||||||
d="M15 12H3m12 0l-4-4m4 4l-4 4"/>
|
|
||||||
</svg>
|
|
||||||
Revert
|
|
||||||
</button>-->
|
|
||||||
</div>
|
</div>
|
||||||
<div class="diff-container relative">
|
<div class="diff-container relative">
|
||||||
<!-- copy-Button oben rechts -->
|
|
||||||
<button class="copy-diff-btn absolute top-1 right-1 p-1 border rounded hover:bg-gray-100 flex items-center justify-center">
|
<button class="copy-diff-btn absolute top-1 right-1 p-1 border rounded hover:bg-gray-100 flex items-center justify-center">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
<!-- Copy-Icon: -->
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h6a2 2 0 012 2v2m0 4h2a2 2 0 002-2v-6a2 2 0 00-2-2h-6a2 2 0 00-2 2v2" />
|
d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h6a2 2 0 012 2v2m0 4h2a2 2 0 002-2v-6a2 2 0 00-2-2h-6a2 2 0 00-2 2v2" />
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
@@ -246,10 +226,10 @@ async function renderSidebar() {
|
|||||||
</li>
|
</li>
|
||||||
`).join('');
|
`).join('');
|
||||||
|
|
||||||
// Erst mal alle Diff-Buttons prüfen und ggf. deaktivieren
|
// Diff-Buttons prüfen und ggf. deaktivieren
|
||||||
contentList.querySelectorAll('.diff-btn').forEach(async btn => {
|
contentList.querySelectorAll('.diff-btn').forEach(async btn => {
|
||||||
const hash = btn.dataset.hash;
|
const hash = btn.dataset.hash;
|
||||||
const diffText = await window.electronAPI.diffCommit(folder, hash);
|
const diffText = await window.electronAPI.diffCommit(folderObj, hash);
|
||||||
if (!diffText.trim()) {
|
if (!diffText.trim()) {
|
||||||
btn.disabled = true;
|
btn.disabled = true;
|
||||||
btn.classList.add('disabled');
|
btn.classList.add('disabled');
|
||||||
@@ -267,7 +247,7 @@ async function renderSidebar() {
|
|||||||
|
|
||||||
if (!pre.innerHTML.trim()) {
|
if (!pre.innerHTML.trim()) {
|
||||||
// fetch und HTML-Snippet bauen
|
// fetch und HTML-Snippet bauen
|
||||||
const diff = await window.electronAPI.diffCommit(folder, hash);
|
const diff = await window.electronAPI.diffCommit(folderObj, hash);
|
||||||
const escaped = diff
|
const escaped = diff
|
||||||
.replace(/&/g, '&')
|
.replace(/&/g, '&')
|
||||||
.replace(/</g, '<')
|
.replace(/</g, '<')
|
||||||
@@ -300,8 +280,7 @@ async function renderSidebar() {
|
|||||||
btn.addEventListener('click', async () => {
|
btn.addEventListener('click', async () => {
|
||||||
const hash = btn.dataset.hash;
|
const hash = btn.dataset.hash;
|
||||||
try {
|
try {
|
||||||
// verwende jetzt currentFolder statt einer undefinierten Variable
|
const savedPath = await window.electronAPI.snapshotCommit(folderObj, hash);
|
||||||
const savedPath = await window.electronAPI.snapshotCommit(currentFolder, hash);
|
|
||||||
if (savedPath) {
|
if (savedPath) {
|
||||||
alert(`Snapshot gespeichert unter:\n${savedPath}`);
|
alert(`Snapshot gespeichert unter:\n${savedPath}`);
|
||||||
}
|
}
|
||||||
@@ -312,37 +291,20 @@ async function renderSidebar() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Revert-Button
|
|
||||||
contentList.querySelectorAll('.revert-btn').forEach(btn => {
|
|
||||||
btn.addEventListener('click', async () => {
|
|
||||||
const hash = btn.dataset.hash;
|
|
||||||
if (confirm(`Commit ${hash} wirklich revertieren?`)) {
|
|
||||||
await window.electronAPI.revertCommit(folder, hash);
|
|
||||||
await renderContent(folder);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Checkout-Button
|
// Checkout-Button
|
||||||
contentList.querySelectorAll('.checkout-btn').forEach(btn => {
|
contentList.querySelectorAll('.checkout-btn').forEach(btn => {
|
||||||
btn.addEventListener('click', async () => {
|
btn.addEventListener('click', async () => {
|
||||||
const hash = btn.dataset.hash;
|
const hash = btn.dataset.hash;
|
||||||
//if (!confirm(`Jump here? Ungestagte Änderungen werden verworfen.`)) return;
|
await window.electronAPI.checkoutCommit(folderObj, hash);
|
||||||
// currentFolder hast du oben in renderContent gespeichert
|
await renderContent(folderObj);
|
||||||
await window.electronAPI.checkoutCommit(currentFolder, hash);
|
|
||||||
await renderContent(currentFolder);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
const currentEl = contentList.querySelector('li.current-commit');
|
|
||||||
|
|
||||||
// Copy-Diff-Button
|
// Copy-Diff-Button
|
||||||
contentList.querySelectorAll('.diff-container').forEach(container => {
|
contentList.querySelectorAll('.diff-container').forEach(container => {
|
||||||
const btn = container.querySelector('.copy-diff-btn');
|
const btn = container.querySelector('.copy-diff-btn');
|
||||||
const pre = container.querySelector('pre');
|
const pre = container.querySelector('pre');
|
||||||
|
|
||||||
// speicher die ursprüngliche SVG
|
|
||||||
const originalSVG = btn.innerHTML;
|
const originalSVG = btn.innerHTML;
|
||||||
// erstelle die Checkmark-SVG
|
|
||||||
const checkSVG = `
|
const checkSVG = `
|
||||||
<svg xmlns="http://www.w3.org/2000/svg"
|
<svg xmlns="http://www.w3.org/2000/svg"
|
||||||
class="h-4 w-4 text-green-600"
|
class="h-4 w-4 text-green-600"
|
||||||
@@ -351,13 +313,10 @@ async function renderSidebar() {
|
|||||||
d="M5 13l4 4L19 7"/>
|
d="M5 13l4 4L19 7"/>
|
||||||
</svg>
|
</svg>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
btn.addEventListener('click', () => {
|
btn.addEventListener('click', () => {
|
||||||
navigator.clipboard.writeText(pre.textContent)
|
navigator.clipboard.writeText(pre.textContent)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// Icon tauschen
|
|
||||||
btn.innerHTML = checkSVG;
|
btn.innerHTML = checkSVG;
|
||||||
// nach 1s wieder zurück
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
btn.innerHTML = originalSVG;
|
btn.innerHTML = originalSVG;
|
||||||
}, 1000);
|
}, 1000);
|
||||||
@@ -368,8 +327,8 @@ async function renderSidebar() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const currentEl = contentList.querySelector('li.current-commit');
|
||||||
if (currentEl) {
|
if (currentEl) {
|
||||||
// weich scrollen und zentriert in den Viewport bringen
|
|
||||||
currentEl.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
currentEl.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -378,7 +337,6 @@ async function renderSidebar() {
|
|||||||
const initial = await window.electronAPI.getSelected();
|
const initial = await window.electronAPI.getSelected();
|
||||||
if (initial) await renderContent(initial);
|
if (initial) await renderContent(initial);
|
||||||
|
|
||||||
// Add-Folder
|
|
||||||
addBtn.addEventListener('click', async () => {
|
addBtn.addEventListener('click', async () => {
|
||||||
await window.electronAPI.addFolder();
|
await window.electronAPI.addFolder();
|
||||||
await renderSidebar();
|
await renderSidebar();
|
||||||
@@ -386,10 +344,12 @@ async function renderSidebar() {
|
|||||||
if (sel) await renderContent(sel);
|
if (sel) await renderContent(sel);
|
||||||
});
|
});
|
||||||
|
|
||||||
// repo-updated, contextmenus usw.
|
// Repo-Update Handling jetzt mit Lookup für folderObj
|
||||||
window.addEventListener('repo-updated', e => {
|
window.addEventListener('repo-updated', async e => {
|
||||||
if (titleEl.textContent === e.detail) renderContent(e.detail);
|
const obj = await getFolderObjByPath(e.detail);
|
||||||
|
if (obj) renderContent(obj);
|
||||||
});
|
});
|
||||||
|
|
||||||
titleEl.addEventListener('contextmenu', e => {
|
titleEl.addEventListener('contextmenu', e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (titleEl.textContent !== 'No folder selected') {
|
if (titleEl.textContent !== 'No folder selected') {
|
||||||
@@ -397,40 +357,27 @@ async function renderSidebar() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const commitBtn = document.getElementById('commitBtn');
|
const commitBtn = document.getElementById('commitBtn');
|
||||||
commitBtn.addEventListener('click', async () => {
|
commitBtn.addEventListener('click', async () => {
|
||||||
// 1) Welcher Ordner ist gerade ausgewählt?
|
const folderObj = await window.electronAPI.getSelected();
|
||||||
const folder = await window.electronAPI.getSelected();
|
if (!folderObj || !folderObj.path) {
|
||||||
if (!folder) {
|
|
||||||
alert('Kein Ordner ausgewählt!');
|
alert('Kein Ordner ausgewählt!');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 2) Nachricht abfragen
|
|
||||||
const message = 'test'
|
const message = 'test'
|
||||||
alert('Commit-Button geklickt!');
|
|
||||||
// 3) UI blockieren
|
|
||||||
commitBtn.disabled = true;
|
commitBtn.disabled = true;
|
||||||
commitBtn.textContent = 'Committing…';
|
commitBtn.textContent = 'Committing…';
|
||||||
|
|
||||||
// 4) IPC‐Aufruf
|
const result = await window.electronAPI.commitCurrentFolder(folderObj, message);
|
||||||
const result = await window.electronAPI.commitCurrentFolder(folder, message);
|
|
||||||
console.log('[renderer] commit result:', result);
|
|
||||||
|
|
||||||
// 5) Ergebnis anzeigen und Liste neu laden
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
alert('Commit erfolgreich!');
|
alert('Commit erfolgreich!');
|
||||||
await renderContent(folder);
|
await renderContent(folderObj);
|
||||||
} else {
|
} else {
|
||||||
alert('Commit fehlgeschlagen:\n' + result.error);
|
alert('Commit fehlgeschlagen:\n' + result.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6) UI wieder freigeben
|
|
||||||
commitBtn.disabled = false;
|
commitBtn.disabled = false;
|
||||||
commitBtn.textContent = 'Commit';
|
commitBtn.textContent = 'Commit';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
Reference in New Issue
Block a user