Upload main.js via GUI
This commit is contained in:
509
main.js
509
main.js
@@ -14,7 +14,20 @@ const {
|
||||
listGiteaRepos,
|
||||
getGiteaRepoContents,
|
||||
getGiteaFileContent,
|
||||
uploadGiteaFile
|
||||
uploadGiteaFile,
|
||||
getGiteaCommits,
|
||||
getGiteaCommit,
|
||||
getGiteaCommitDiff,
|
||||
getGiteaCommitFiles,
|
||||
searchGiteaCommits,
|
||||
getGiteaBranches,
|
||||
listGiteaReleases,
|
||||
getGiteaRelease,
|
||||
createGiteaRelease,
|
||||
editGiteaRelease,
|
||||
deleteGiteaRelease,
|
||||
uploadReleaseAsset,
|
||||
deleteReleaseAsset
|
||||
} = require('./src/git/apiHandler.js');
|
||||
|
||||
const { initRepo, commitAndPush, getBranches, getCommitLogs } = require('./src/git/gitHandler.js');
|
||||
@@ -329,6 +342,52 @@ ipcMain.handle('getCommitLogs', async (event, data) => {
|
||||
}
|
||||
});
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
Neue/kompatible Handler: 'get-commits' (Renderer verwendet ggf. diesen)
|
||||
- Unterstützt:
|
||||
1) Lokale Git-Logs via data.folder -> getCommitLogs
|
||||
2) Gitea Commits via owner+repo -> getGiteaCommits
|
||||
---------------------------------------------------------------- */
|
||||
ipcMain.handle('get-commits', async (event, data) => {
|
||||
try {
|
||||
// 1) Lokale Git-Logs (folder vorhanden)
|
||||
if (data && data.folder) {
|
||||
const logs = await getCommitLogs(data.folder, data.count || 50);
|
||||
return { ok: true, logs };
|
||||
}
|
||||
|
||||
// 2) Gitea-Commits (owner/repo vorhanden)
|
||||
if (data && data.owner && data.repo) {
|
||||
const credentials = readCredentials();
|
||||
const token = (data && data.token) || (credentials && credentials.giteaToken);
|
||||
const url = (data && data.url) || (credentials && credentials.giteaURL);
|
||||
if (!token || !url) return { ok: false, error: 'missing-token-or-url' };
|
||||
|
||||
// map optional params
|
||||
const page = data.page || 1;
|
||||
const limit = data.limit || 50;
|
||||
const sha = data.sha; // optional branch/sha filter
|
||||
|
||||
const commits = await getGiteaCommits({
|
||||
token,
|
||||
url,
|
||||
owner: data.owner,
|
||||
repo: data.repo,
|
||||
page,
|
||||
limit,
|
||||
sha
|
||||
});
|
||||
|
||||
return { ok: true, commits };
|
||||
}
|
||||
|
||||
return { ok: false, error: 'invalid-parameters-for-get-commits' };
|
||||
} catch (e) {
|
||||
console.error('get-commits error', e);
|
||||
return { ok: false, error: String(e) };
|
||||
}
|
||||
});
|
||||
|
||||
/* -----------------------------
|
||||
Local file tree functions
|
||||
----------------------------- */
|
||||
@@ -387,6 +446,21 @@ ipcMain.handle('readFile', async (event, data) => {
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('writeFile', async (event, data) => {
|
||||
try {
|
||||
if (!data || !data.path) return { ok: false, error: 'invalid-path' };
|
||||
const dir = ppath.dirname(data.path);
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
fs.writeFileSync(data.path, data.content || '', 'utf8');
|
||||
return { ok: true };
|
||||
} catch (e) {
|
||||
console.error('writeFile error', e);
|
||||
return { ok: false, error: String(e) };
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('deleteFile', async (event, data) => {
|
||||
try {
|
||||
if (!data || !data.path || !fs.existsSync(data.path)) return { ok: false, error: 'file-not-found' };
|
||||
@@ -458,6 +532,83 @@ ipcMain.handle('get-gitea-file-content', async (event, data) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Alias für Editor: read-gitea-file (für Text und Bilder)
|
||||
ipcMain.handle('read-gitea-file', async (event, data) => {
|
||||
try {
|
||||
const credentials = readCredentials();
|
||||
const token = (data && data.token) || (credentials && credentials.giteaToken);
|
||||
const url = (data && data.url) || (credentials && credentials.giteaURL);
|
||||
if (!token || !url) {
|
||||
console.error('Missing token or URL');
|
||||
return { ok: false, error: 'missing-token-or-url' };
|
||||
}
|
||||
|
||||
const owner = data.owner;
|
||||
const repo = data.repo;
|
||||
const p = data.path;
|
||||
const ref = data.ref || 'main';
|
||||
|
||||
console.log(`read-gitea-file: ${owner}/${repo}/${p} (ref: ${ref})`);
|
||||
|
||||
// Prüfe ob es eine Bilddatei ist
|
||||
const isImage = /\.(png|jpg|jpeg|gif|webp|svg)$/i.test(p);
|
||||
|
||||
if (isImage) {
|
||||
// Für Bilder: Lade als Base64
|
||||
console.log('Loading as image (Base64)');
|
||||
const apiUrl = `${url}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/raw/${encodeURIComponent(p)}?ref=${ref}`;
|
||||
console.log('Image URL:', apiUrl);
|
||||
|
||||
return new Promise((resolve) => {
|
||||
try {
|
||||
const protocol = url.startsWith('https') ? https : http;
|
||||
protocol.get(apiUrl, {
|
||||
headers: {
|
||||
'Authorization': `token ${token}`,
|
||||
'User-Agent': 'Git-Manager-GUI'
|
||||
}
|
||||
}, (res) => {
|
||||
console.log(`Image response status: ${res.statusCode}`);
|
||||
if (res.statusCode !== 200) {
|
||||
resolve({ ok: false, error: `HTTP ${res.statusCode}` });
|
||||
return;
|
||||
}
|
||||
|
||||
const chunks = [];
|
||||
res.on('data', chunk => chunks.push(chunk));
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const buffer = Buffer.concat(chunks);
|
||||
const base64 = buffer.toString('base64');
|
||||
console.log(`Image loaded: ${base64.length} bytes`);
|
||||
resolve({ ok: true, content: base64 });
|
||||
} catch (e) {
|
||||
console.error('Base64 conversion error:', e.message);
|
||||
resolve({ ok: false, error: String(e) });
|
||||
}
|
||||
});
|
||||
}).on('error', (e) => {
|
||||
console.error('Image HTTP error:', e.message);
|
||||
resolve({ ok: false, error: String(e) });
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('Image load try error:', e.message);
|
||||
resolve({ ok: false, error: String(e) });
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Für Text: Nutze normale Funktion
|
||||
console.log('Loading as text file');
|
||||
const content = await getGiteaFileContent({ token, url, owner, repo, path: p, ref });
|
||||
console.log(`Text file loaded: ${content.length} chars`);
|
||||
return { ok: true, content };
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('read-gitea-file error:', e.message, e.stack);
|
||||
return { ok: false, error: String(e) };
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('upload-gitea-file', async (event, data) => {
|
||||
try {
|
||||
const credentials = readCredentials();
|
||||
@@ -515,6 +666,41 @@ ipcMain.handle('upload-gitea-file', async (event, data) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Alias für Editor: write-gitea-file
|
||||
ipcMain.handle('write-gitea-file', async (event, data) => {
|
||||
try {
|
||||
const credentials = readCredentials();
|
||||
const token = (data && data.token) || (credentials && credentials.giteaToken);
|
||||
const url = (data && data.url) || (credentials && credentials.giteaURL);
|
||||
if (!token || !url) return { ok: false, error: 'missing-token-or-url' };
|
||||
|
||||
const owner = data.owner;
|
||||
const repo = data.repo;
|
||||
const path = data.path;
|
||||
const content = data.content || '';
|
||||
const ref = data.ref || 'main';
|
||||
|
||||
// Konvertiere Content zu Base64
|
||||
const base64 = Buffer.from(content, 'utf8').toString('base64');
|
||||
|
||||
const uploaded = await uploadGiteaFile({
|
||||
token,
|
||||
url,
|
||||
owner,
|
||||
repo,
|
||||
path,
|
||||
contentBase64: base64,
|
||||
message: `Edit ${path} via Git Manager GUI`,
|
||||
branch: ref
|
||||
});
|
||||
|
||||
return { ok: true, uploaded };
|
||||
} catch (e) {
|
||||
console.error('write-gitea-file error', e);
|
||||
return { ok: false, error: String(e) };
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('upload-local-folder-to-gitea', async (event, data) => {
|
||||
try {
|
||||
const credentials = readCredentials();
|
||||
@@ -780,6 +966,7 @@ ipcMain.on('ondragstart', async (event, filePath) => {
|
||||
// Prefer folder icon when dragging a directory
|
||||
let icon = nativeImage.createEmpty();
|
||||
try {
|
||||
// ask platform for file icon; large size for clearer drag icon
|
||||
icon = await app.getFileIcon(filePath, { size: 'large' });
|
||||
} catch (e) {
|
||||
// ignore, keep empty icon
|
||||
@@ -798,15 +985,6 @@ ipcMain.on('ondragstart', async (event, filePath) => {
|
||||
});
|
||||
|
||||
|
||||
ipcMain.on('ondragstart', async (event, filePath) => {
|
||||
try {
|
||||
if (!filePath || !fs.existsSync(filePath)) return;
|
||||
let icon = nativeImage.createEmpty();
|
||||
try { icon = await app.getFileIcon(filePath); } catch (e) {}
|
||||
try { event.sender.startDrag({ file: filePath, icon: icon }); } catch (e) { console.error('startDrag failed', e); }
|
||||
} catch (e) { console.error('ondragstart error', e); }
|
||||
});
|
||||
|
||||
ipcMain.handle('delete-gitea-repo', async (event, data) => {
|
||||
try {
|
||||
const credentials = readCredentials();
|
||||
@@ -1097,3 +1275,314 @@ ipcMain.handle('upload-and-push', async (event, data) => {
|
||||
return { ok: false, error: String(e) };
|
||||
}
|
||||
});
|
||||
/* ================================
|
||||
RELEASE MANAGEMENT IPC HANDLERS
|
||||
================================ */
|
||||
|
||||
// List all releases for a repository
|
||||
ipcMain.handle('list-releases', async (event, data) => {
|
||||
try {
|
||||
const credentials = readCredentials();
|
||||
if (!credentials) return { ok: false, error: 'no-credentials' };
|
||||
|
||||
const releases = await listGiteaReleases({
|
||||
token: credentials.giteaToken,
|
||||
url: credentials.giteaURL,
|
||||
owner: data.owner,
|
||||
repo: data.repo
|
||||
});
|
||||
|
||||
return { ok: true, releases };
|
||||
} catch (error) {
|
||||
console.error('list-releases error:', error);
|
||||
return { ok: false, error: String(error) };
|
||||
}
|
||||
});
|
||||
|
||||
// Get a specific release by tag
|
||||
ipcMain.handle('get-release', async (event, data) => {
|
||||
try {
|
||||
const credentials = readCredentials();
|
||||
if (!credentials) return { ok: false, error: 'no-credentials' };
|
||||
|
||||
const release = await getGiteaRelease({
|
||||
token: credentials.giteaToken,
|
||||
url: credentials.giteaURL,
|
||||
owner: data.owner,
|
||||
repo: data.repo,
|
||||
tag: data.tag
|
||||
});
|
||||
|
||||
return { ok: true, release };
|
||||
} catch (error) {
|
||||
console.error('get-release error:', error);
|
||||
return { ok: false, error: String(error) };
|
||||
}
|
||||
});
|
||||
|
||||
// Create a new release
|
||||
ipcMain.handle('create-release', async (event, data) => {
|
||||
try {
|
||||
const credentials = readCredentials();
|
||||
if (!credentials) return { ok: false, error: 'no-credentials' };
|
||||
|
||||
const releaseData = {
|
||||
tag_name: data.tag_name,
|
||||
name: data.name,
|
||||
body: data.body,
|
||||
draft: data.draft,
|
||||
prerelease: data.prerelease,
|
||||
target_commitish: data.target_commitish
|
||||
};
|
||||
|
||||
const release = await createGiteaRelease({
|
||||
token: credentials.giteaToken,
|
||||
url: credentials.giteaURL,
|
||||
owner: data.owner,
|
||||
repo: data.repo,
|
||||
data: releaseData
|
||||
});
|
||||
|
||||
return { ok: true, release };
|
||||
} catch (error) {
|
||||
console.error('create-release error:', error);
|
||||
return { ok: false, error: String(error) };
|
||||
}
|
||||
});
|
||||
|
||||
// Edit/update a release
|
||||
ipcMain.handle('edit-release', async (event, data) => {
|
||||
try {
|
||||
const credentials = readCredentials();
|
||||
if (!credentials) return { ok: false, error: 'no-credentials' };
|
||||
|
||||
const updateData = {};
|
||||
if (data.name !== undefined) updateData.name = data.name;
|
||||
if (data.body !== undefined) updateData.body = data.body;
|
||||
if (data.draft !== undefined) updateData.draft = data.draft;
|
||||
if (data.prerelease !== undefined) updateData.prerelease = data.prerelease;
|
||||
|
||||
const release = await editGiteaRelease({
|
||||
token: credentials.giteaToken,
|
||||
url: credentials.giteaURL,
|
||||
owner: data.owner,
|
||||
repo: data.repo,
|
||||
releaseId: data.releaseId,
|
||||
data: updateData
|
||||
});
|
||||
|
||||
return { ok: true, release };
|
||||
} catch (error) {
|
||||
console.error('edit-release error:', error);
|
||||
return { ok: false, error: String(error) };
|
||||
}
|
||||
});
|
||||
|
||||
// Delete a release
|
||||
ipcMain.handle('delete-release', async (event, data) => {
|
||||
try {
|
||||
const credentials = readCredentials();
|
||||
if (!credentials) return { ok: false, error: 'no-credentials' };
|
||||
|
||||
await deleteGiteaRelease({
|
||||
token: credentials.giteaToken,
|
||||
url: credentials.giteaURL,
|
||||
owner: data.owner,
|
||||
repo: data.repo,
|
||||
releaseId: data.releaseId
|
||||
});
|
||||
|
||||
return { ok: true };
|
||||
} catch (error) {
|
||||
console.error('delete-release error:', error);
|
||||
return { ok: false, error: String(error) };
|
||||
}
|
||||
});
|
||||
|
||||
// Upload a release asset
|
||||
ipcMain.handle('upload-release-asset', async (event, data) => {
|
||||
try {
|
||||
const credentials = readCredentials();
|
||||
if (!credentials) return { ok: false, error: 'no-credentials' };
|
||||
|
||||
const asset = await uploadReleaseAsset({
|
||||
token: credentials.giteaToken,
|
||||
url: credentials.giteaURL,
|
||||
owner: data.owner,
|
||||
repo: data.repo,
|
||||
releaseId: data.releaseId,
|
||||
filePath: data.filePath,
|
||||
fileName: data.fileName
|
||||
});
|
||||
|
||||
return { ok: true, asset };
|
||||
} catch (error) {
|
||||
console.error('upload-release-asset error:', error);
|
||||
return { ok: false, error: String(error) };
|
||||
}
|
||||
});
|
||||
|
||||
// Delete a release asset
|
||||
ipcMain.handle('delete-release-asset', async (event, data) => {
|
||||
try {
|
||||
const credentials = readCredentials();
|
||||
if (!credentials) return { ok: false, error: 'no-credentials' };
|
||||
|
||||
await deleteReleaseAsset({
|
||||
token: credentials.giteaToken,
|
||||
url: credentials.giteaURL,
|
||||
owner: data.owner,
|
||||
repo: data.repo,
|
||||
assetId: data.assetId
|
||||
});
|
||||
|
||||
return { ok: true };
|
||||
} catch (error) {
|
||||
console.error('delete-release-asset error:', error);
|
||||
return { ok: false, error: String(error) };
|
||||
}
|
||||
});
|
||||
|
||||
// Download release archive (ZIP/TAR)
|
||||
ipcMain.handle('download-release-archive', async (event, data) => {
|
||||
try {
|
||||
const credentials = readCredentials();
|
||||
if (!credentials) return { ok: false, error: 'no-credentials' };
|
||||
|
||||
const base = credentials.giteaURL.replace(/\/$/, '');
|
||||
const archiveUrl = `${base}/${data.owner}/${data.repo}/archive/${data.tag}.zip`;
|
||||
|
||||
// Ask user where to save
|
||||
const result = await dialog.showSaveDialog({
|
||||
defaultPath: `${data.repo}-${data.tag}.zip`,
|
||||
filters: [{ name: 'ZIP Archive', extensions: ['zip'] }]
|
||||
});
|
||||
|
||||
if (result.canceled) return { ok: false, canceled: true };
|
||||
|
||||
const savePath = result.filePath;
|
||||
|
||||
// Download archive
|
||||
const axios = require('axios');
|
||||
const fs = require('fs');
|
||||
const writer = fs.createWriteStream(savePath);
|
||||
|
||||
const response = await axios({
|
||||
url: archiveUrl,
|
||||
method: 'GET',
|
||||
responseType: 'stream',
|
||||
headers: { Authorization: `token ${credentials.giteaToken}` }
|
||||
});
|
||||
|
||||
response.data.pipe(writer);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
writer.on('finish', () => resolve({ ok: true, savedTo: savePath }));
|
||||
writer.on('error', (err) => reject(err));
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('download-release-archive error:', error);
|
||||
return { ok: false, error: String(error) };
|
||||
}
|
||||
});
|
||||
|
||||
/* ========================
|
||||
LOCAL COMMIT HANDLERS
|
||||
======================== */
|
||||
ipcMain.handle('get-local-commits', async (event, data) => {
|
||||
try {
|
||||
const { getCommitLogs } = require('./src/git/gitHandler.js');
|
||||
const commits = await getCommitLogs(data.folderPath, data.branch || 'HEAD');
|
||||
return { ok: true, commits };
|
||||
} catch (error) {
|
||||
console.error('get-local-commits error:', error);
|
||||
return { ok: false, error: String(error) };
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('get-local-commit-details', async (event, data) => {
|
||||
try {
|
||||
const { getCommitDetails } = require('./src/git/gitHandler.js');
|
||||
const details = await getCommitDetails(data.folderPath, data.sha);
|
||||
return { ok: true, ...details };
|
||||
} catch (error) {
|
||||
console.error('get-local-commit-details error:', error);
|
||||
return { ok: false, error: String(error) };
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('get-local-commit-diff', async (event, data) => {
|
||||
try {
|
||||
const { getCommitDiff } = require('./src/git/gitHandler.js');
|
||||
const diff = await getCommitDiff(data.folderPath, data.sha);
|
||||
return { ok: true, diff };
|
||||
} catch (error) {
|
||||
console.error('get-local-commit-diff error:', error);
|
||||
return { ok: false, error: String(error) };
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('get-local-commit-files', async (event, data) => {
|
||||
try {
|
||||
const { getCommitDetails } = require('./src/git/gitHandler.js');
|
||||
const details = await getCommitDetails(data.folderPath, data.sha);
|
||||
return { ok: true, files: details.files || [], stats: { additions: 0, deletions: 0 } };
|
||||
} catch (error) {
|
||||
console.error('get-local-commit-files error:', error);
|
||||
return { ok: false, error: String(error) };
|
||||
}
|
||||
});
|
||||
|
||||
/* ========================
|
||||
GITEA COMMIT HANDLERS
|
||||
======================== */
|
||||
ipcMain.handle('get-commit-diff', async (event, data) => {
|
||||
try {
|
||||
const credentials = readCredentials();
|
||||
const token = (data && data.token) || (credentials && credentials.giteaToken);
|
||||
const url = (data && data.url) || (credentials && credentials.giteaURL);
|
||||
|
||||
if (!token || !url) {
|
||||
return { ok: false, error: 'missing-token-or-url' };
|
||||
}
|
||||
|
||||
const diff = await getGiteaCommitDiff({
|
||||
token,
|
||||
url,
|
||||
owner: data.owner,
|
||||
repo: data.repo,
|
||||
sha: data.sha
|
||||
});
|
||||
|
||||
return { ok: true, diff };
|
||||
} catch (error) {
|
||||
console.error('get-commit-diff error:', error);
|
||||
return { ok: false, error: String(error) };
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('get-commit-files', async (event, data) => {
|
||||
try {
|
||||
const credentials = readCredentials();
|
||||
const token = (data && data.token) || (credentials && credentials.giteaToken);
|
||||
const url = (data && data.url) || (credentials && credentials.giteaURL);
|
||||
|
||||
if (!token || !url) {
|
||||
return { ok: false, error: 'missing-token-or-url' };
|
||||
}
|
||||
|
||||
const result = await getGiteaCommitFiles({
|
||||
token,
|
||||
url,
|
||||
owner: data.owner,
|
||||
repo: data.repo,
|
||||
sha: data.sha
|
||||
});
|
||||
|
||||
return { ok: true, files: result.files, stats: result.stats };
|
||||
} catch (error) {
|
||||
console.error('get-commit-files error:', error);
|
||||
return { ok: false, error: String(error) };
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user