Erster Commit
This commit is contained in:
718
main.js
Normal file
718
main.js
Normal file
@@ -0,0 +1,718 @@
|
||||
/**
|
||||
* Electron Main Process
|
||||
* - Window management
|
||||
* - Folder watcher via chokidar
|
||||
* - IPC handlers for renderer communication
|
||||
* - Archive functionality: moves processed files to inputDir/archiv
|
||||
*/
|
||||
const { app, BrowserWindow, ipcMain, dialog, Menu } = require('electron');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const chokidar = require('chokidar');
|
||||
const ConversionDB = require('./js/db');
|
||||
const edifactValidator = require('./js/edifact-validator');
|
||||
|
||||
let mainWindow = null;
|
||||
let watcher = null;
|
||||
let watcherPaused = false;
|
||||
let watcherConfig = { inputDir: '', outputDir: '', mode: 'auto' };
|
||||
|
||||
let outboundWatcher = null;
|
||||
let outboundWatcherPaused = false;
|
||||
let outboundWatcherConfig = { inputDir: '', outputDir: '', mode: 'auto' };
|
||||
|
||||
let werksWatcher = null;
|
||||
let werksWatcherPaused = false;
|
||||
let werksWatcherConfig = { inputDir: '', outputDir: '' };
|
||||
|
||||
// ─── Database & Storage ─────────────────────────────────────────────
|
||||
const dataDir = path.join(__dirname, 'db');
|
||||
if (!fs.existsSync(dataDir)) {
|
||||
fs.mkdirSync(dataDir, { recursive: true });
|
||||
}
|
||||
|
||||
let conversionDB = null;
|
||||
|
||||
// ─── Window ──────────────────────────────────────────────────────────
|
||||
function createWindow() {
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 1400,
|
||||
height: 900,
|
||||
minWidth: 900,
|
||||
minHeight: 600,
|
||||
title: 'ERP EDI Bridge',
|
||||
icon: path.join(__dirname, 'src', 'assets', 'icon.png'),
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js'),
|
||||
contextIsolation: true,
|
||||
nodeIntegration: false,
|
||||
}
|
||||
});
|
||||
|
||||
mainWindow.loadFile('index.html');
|
||||
|
||||
// Create Application Menu to handle shortcuts (including Zoom Fix)
|
||||
const template = [
|
||||
{
|
||||
label: 'Datei',
|
||||
submenu: [
|
||||
{ label: 'Beenden', role: 'quit' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Ansicht',
|
||||
submenu: [
|
||||
{ label: 'Neu laden', role: 'reload' },
|
||||
{ label: 'Entwicklertools', role: 'toggleDevTools' },
|
||||
{ type: 'separator' },
|
||||
{ label: 'Vergrößern', accelerator: 'CmdOrCtrl+Plus', role: 'zoomIn' },
|
||||
{ label: 'Vergrößern (Alternativ)', accelerator: 'CmdOrCtrl+=', role: 'zoomIn', visible: false },
|
||||
{ label: 'Verkleinern', accelerator: 'CmdOrCtrl+-', role: 'zoomOut' },
|
||||
{ label: 'Zoom zurücksetzen', accelerator: 'CmdOrCtrl+0', role: 'resetZoom' },
|
||||
{ type: 'separator' },
|
||||
{ label: 'Vollbild', role: 'togglefullscreen' }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
const menu = Menu.buildFromTemplate(template);
|
||||
Menu.setApplicationMenu(menu);
|
||||
}
|
||||
|
||||
app.whenReady().then(async () => {
|
||||
// Initialize conversion history database using async sqlite3 (local directory)
|
||||
const dbPath = path.join(dataDir, 'conversions.sqlite3');
|
||||
conversionDB = new ConversionDB(dbPath);
|
||||
try {
|
||||
await conversionDB.init();
|
||||
console.log(`[DB] Initialized at: ${dbPath}`);
|
||||
} catch (e) {
|
||||
console.error('[DB] Initialization error:', e);
|
||||
}
|
||||
|
||||
createWindow();
|
||||
});
|
||||
app.on('window-all-closed', () => {
|
||||
if (conversionDB) conversionDB.close();
|
||||
app.quit();
|
||||
});
|
||||
|
||||
// ─── IPC: Folder dialog ─────────────────────────────────────────────
|
||||
ipcMain.handle('select-folder', async () => {
|
||||
const result = await dialog.showOpenDialog(mainWindow, {
|
||||
properties: ['openDirectory']
|
||||
});
|
||||
if (result.canceled || result.filePaths.length === 0) return null;
|
||||
return result.filePaths[0];
|
||||
});
|
||||
|
||||
// ─── IPC: Settings persistence ──────────────────────────────────────
|
||||
const settingsPath = path.join(dataDir, 'watcher-settings.json');
|
||||
|
||||
function loadSettings() {
|
||||
try {
|
||||
if (fs.existsSync(settingsPath)) {
|
||||
return JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
||||
}
|
||||
} catch (e) { console.error('Settings load error:', e); }
|
||||
return {
|
||||
inputDir: '', outputDir: '', mode: 'auto',
|
||||
outboundInputDir: '', outboundOutputDir: '', mode: 'auto',
|
||||
werksInputDir: '', werksOutputDir: ''
|
||||
};
|
||||
}
|
||||
|
||||
function saveSettings(settings) {
|
||||
try {
|
||||
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8');
|
||||
} catch (e) { console.error('Settings save error:', e); }
|
||||
}
|
||||
|
||||
ipcMain.handle('load-settings', () => loadSettings());
|
||||
ipcMain.handle('save-settings', (_, settings) => {
|
||||
// Preserve existing settings and merge new ones
|
||||
const current = loadSettings();
|
||||
const updated = { ...current, ...settings };
|
||||
|
||||
// Update active configs if they are loaded
|
||||
watcherConfig = { ...watcherConfig, ...updated };
|
||||
outboundWatcherConfig = {
|
||||
inputDir: updated.outboundInputDir || outboundWatcherConfig.inputDir,
|
||||
outputDir: updated.outboundOutputDir || outboundWatcherConfig.outputDir
|
||||
};
|
||||
werksWatcherConfig = {
|
||||
inputDir: updated.werksInputDir || werksWatcherConfig.inputDir,
|
||||
outputDir: updated.werksOutputDir || werksWatcherConfig.werksOutputDir
|
||||
};
|
||||
|
||||
saveSettings(updated);
|
||||
return true;
|
||||
});
|
||||
|
||||
// ─── IPC: Read file content ─────────────────────────────────────────
|
||||
ipcMain.handle('read-file', async (_, filePath) => {
|
||||
try {
|
||||
return fs.readFileSync(filePath, 'utf8');
|
||||
} catch (e) {
|
||||
return { error: e.message };
|
||||
}
|
||||
});
|
||||
|
||||
// ─── IPC: Write file content ────────────────────────────────────────
|
||||
ipcMain.handle('write-file', async (_, filePath, content) => {
|
||||
try {
|
||||
// Ensure output directory exists
|
||||
const dir = path.dirname(filePath);
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
fs.writeFileSync(filePath, content, 'utf8');
|
||||
return { success: true };
|
||||
} catch (e) {
|
||||
return { error: e.message };
|
||||
}
|
||||
});
|
||||
|
||||
// ─── IPC: Move file to archive ──────────────────────────────────────
|
||||
ipcMain.handle('move-to-archive', async (_, filePath) => {
|
||||
try {
|
||||
const dir = path.dirname(filePath);
|
||||
const archiveDir = path.join(dir, 'archiv');
|
||||
const fileName = path.basename(filePath);
|
||||
|
||||
// Create archiv subfolder if needed
|
||||
if (!fs.existsSync(archiveDir)) {
|
||||
fs.mkdirSync(archiveDir, { recursive: true });
|
||||
}
|
||||
|
||||
// If a file with the same name exists in archive, add timestamp
|
||||
let destPath = path.join(archiveDir, fileName);
|
||||
if (fs.existsSync(destPath)) {
|
||||
const baseName = fileName.replace(/(\.[^.]+)$/, '');
|
||||
const ext = path.extname(fileName);
|
||||
const ts = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
||||
destPath = path.join(archiveDir, `${baseName}_${ts}${ext}`);
|
||||
}
|
||||
|
||||
fs.renameSync(filePath, destPath);
|
||||
return { success: true, archivePath: destPath };
|
||||
} catch (e) {
|
||||
return { error: e.message };
|
||||
}
|
||||
});
|
||||
|
||||
// ─── Folder Watcher ─────────────────────────────────────────────────
|
||||
function sendToRenderer(channel, data) {
|
||||
if (mainWindow && !mainWindow.isDestroyed()) {
|
||||
mainWindow.webContents.send(channel, data);
|
||||
}
|
||||
}
|
||||
|
||||
ipcMain.handle('start-watcher', (_, config) => {
|
||||
if (watcher) {
|
||||
watcher.close();
|
||||
watcher = null;
|
||||
}
|
||||
|
||||
watcherConfig = { ...watcherConfig, ...config };
|
||||
saveSettings(watcherConfig);
|
||||
|
||||
const inputDir = watcherConfig.inputDir;
|
||||
const outputDir = watcherConfig.outputDir;
|
||||
|
||||
if (!inputDir || !outputDir) {
|
||||
return { error: 'Input- und Output-Ordner müssen angegeben werden.' };
|
||||
}
|
||||
|
||||
if (!fs.existsSync(inputDir)) {
|
||||
return { error: `Input-Ordner existiert nicht: ${inputDir}` };
|
||||
}
|
||||
|
||||
if (!fs.existsSync(outputDir)) {
|
||||
try { fs.mkdirSync(outputDir, { recursive: true }); }
|
||||
catch (e) { return { error: `Output-Ordner konnte nicht erstellt werden: ${e.message}` }; }
|
||||
}
|
||||
|
||||
watcherPaused = false;
|
||||
|
||||
// Watch only the input directory itself, not subdirectories (depth: 0)
|
||||
// This avoids triggering on files moved to the archiv subfolder
|
||||
watcher = chokidar.watch(inputDir, {
|
||||
ignored: [
|
||||
/(^|[\/\\])\../, // dotfiles
|
||||
path.join(inputDir, 'archiv', '**'), // ignore archiv subfolder
|
||||
path.join(inputDir, 'archiv'),
|
||||
],
|
||||
persistent: true,
|
||||
ignoreInitial: true,
|
||||
depth: 0,
|
||||
usePolling: true,
|
||||
interval: 1000, // slightly more frequent polling
|
||||
binaryInterval: 1000,
|
||||
awaitWriteFinish: {
|
||||
stabilityThreshold: 1000, // wait 1s after last write before firing
|
||||
pollInterval: 100
|
||||
}
|
||||
});
|
||||
|
||||
// Diagnostic logging for all events
|
||||
watcher.on('all', (event, path) => {
|
||||
console.log(`[Watcher Debug] Event: ${event} on ${path}`);
|
||||
});
|
||||
|
||||
watcher.on('add', (filePath) => {
|
||||
if (watcherPaused) {
|
||||
console.log(`[Watcher] Paused. Ignoring: ${filePath}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const ext = path.extname(filePath).toLowerCase();
|
||||
const fileName = path.basename(filePath);
|
||||
|
||||
// Skip files in archiv directory (double safety)
|
||||
if (filePath.includes(path.sep + 'archiv' + path.sep)) {
|
||||
console.log(`[Watcher] Ignoring file in archive: ${fileName}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Expanded EDI file extensions, case-insensitive check
|
||||
const allowedExts = ['.txt', '.vda', '.edi', '.dat', '.seq', '.tmp', '.idoc', ''];
|
||||
if (!allowedExts.includes(ext)) {
|
||||
console.log(`[Watcher] Ignoring file with extension "${ext}": ${fileName}`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[Watcher] File detected and accepted: ${filePath}`);
|
||||
|
||||
// Small delay to ensure file is fully written and closed
|
||||
setTimeout(() => {
|
||||
try {
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
|
||||
sendToRenderer('watcher-file-detected', {
|
||||
filePath,
|
||||
fileName,
|
||||
content,
|
||||
outputDir
|
||||
});
|
||||
|
||||
console.log(`[Watcher] Sent to renderer: ${fileName} (${content.length} bytes)`);
|
||||
} catch (e) {
|
||||
console.error(`[Watcher] Read error: ${e.message}`);
|
||||
sendToRenderer('watcher-error', {
|
||||
filePath: fileName,
|
||||
error: `Datei konnte nicht gelesen werden: ${e.message}`
|
||||
});
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
|
||||
watcher.on('error', (err) => {
|
||||
console.error(`[Watcher] Error: ${err.message}`);
|
||||
sendToRenderer('watcher-error', {
|
||||
error: `Watcher-Fehler: ${err.message}`
|
||||
});
|
||||
});
|
||||
|
||||
watcher.on('ready', () => {
|
||||
console.log(`[Watcher] Ready. Watching: ${inputDir}`);
|
||||
sendToRenderer('watcher-ready', { inputDir });
|
||||
});
|
||||
|
||||
return { success: true, status: 'running' };
|
||||
});
|
||||
|
||||
ipcMain.handle('stop-watcher', () => {
|
||||
if (watcher) {
|
||||
watcher.close();
|
||||
watcher = null;
|
||||
console.log('[Watcher] Stopped.');
|
||||
}
|
||||
watcherPaused = false;
|
||||
return { success: true, status: 'stopped' };
|
||||
});
|
||||
|
||||
ipcMain.handle('pause-watcher', () => {
|
||||
watcherPaused = true;
|
||||
console.log('[Watcher] Paused.');
|
||||
return { success: true, status: 'paused' };
|
||||
});
|
||||
|
||||
ipcMain.handle('resume-watcher', () => {
|
||||
if (!watcher) {
|
||||
return { error: 'Kein Watcher aktiv. Bitte zuerst starten.' };
|
||||
}
|
||||
watcherPaused = false;
|
||||
console.log('[Watcher] Resumed.');
|
||||
return { success: true, status: 'running' };
|
||||
});
|
||||
|
||||
ipcMain.handle('get-watcher-status', () => {
|
||||
if (!watcher) return { status: 'stopped' };
|
||||
if (watcherPaused) return { status: 'paused' };
|
||||
return { status: 'running' };
|
||||
});
|
||||
|
||||
// ─── Outbound Folder Watcher ────────────────────────────────────────
|
||||
|
||||
ipcMain.handle('start-outbound-watcher', (_, config) => {
|
||||
if (outboundWatcher) {
|
||||
outboundWatcher.close();
|
||||
outboundWatcher = null;
|
||||
}
|
||||
|
||||
outboundWatcherConfig = { ...outboundWatcherConfig, ...config };
|
||||
|
||||
// Save to global settings
|
||||
const current = loadSettings();
|
||||
saveSettings({
|
||||
...current,
|
||||
outboundInputDir: outboundWatcherConfig.inputDir,
|
||||
outboundOutputDir: outboundWatcherConfig.outputDir
|
||||
});
|
||||
|
||||
const inputDir = outboundWatcherConfig.inputDir;
|
||||
const outputDir = outboundWatcherConfig.outputDir;
|
||||
|
||||
if (!inputDir || !outputDir) {
|
||||
return { error: 'Input- und Output-Ordner müssen angegeben werden.' };
|
||||
}
|
||||
|
||||
if (!fs.existsSync(inputDir)) {
|
||||
return { error: `Input-Ordner existiert nicht: ${inputDir}` };
|
||||
}
|
||||
|
||||
if (!fs.existsSync(outputDir)) {
|
||||
try { fs.mkdirSync(outputDir, { recursive: true }); }
|
||||
catch (e) { return { error: `Output-Ordner konnte nicht erstellt werden: ${e.message}` }; }
|
||||
}
|
||||
|
||||
outboundWatcherPaused = false;
|
||||
|
||||
outboundWatcher = chokidar.watch(inputDir, {
|
||||
ignored: [
|
||||
/(^|[\/\\])\../,
|
||||
path.join(inputDir, 'archiv', '**'),
|
||||
path.join(inputDir, 'archiv'),
|
||||
],
|
||||
persistent: true,
|
||||
ignoreInitial: true,
|
||||
depth: 0,
|
||||
usePolling: true,
|
||||
interval: 1000,
|
||||
binaryInterval: 1000,
|
||||
awaitWriteFinish: {
|
||||
stabilityThreshold: 1000,
|
||||
pollInterval: 100
|
||||
}
|
||||
});
|
||||
|
||||
outboundWatcher.on('all', (event, path) => {
|
||||
console.log(`[OutboundWatcher Debug] Event: ${event} on ${path}`);
|
||||
});
|
||||
|
||||
outboundWatcher.on('add', (filePath) => {
|
||||
if (outboundWatcherPaused) {
|
||||
console.log(`[OutboundWatcher] Paused. Ignoring: ${filePath}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const ext = path.extname(filePath).toLowerCase();
|
||||
const fileName = path.basename(filePath);
|
||||
|
||||
if (filePath.includes(path.sep + 'archiv' + path.sep)) {
|
||||
console.log(`[OutboundWatcher] Ignoring file in archive: ${fileName}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const allowedExts = ['.txt', '.vda', '.edi', '.dat', '.seq', '.tmp', '.idoc', ''];
|
||||
if (!allowedExts.includes(ext)) {
|
||||
console.log(`[OutboundWatcher] Ignoring file with extension "${ext}": ${fileName}`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[OutboundWatcher] File detected and accepted: ${filePath}`);
|
||||
|
||||
setTimeout(() => {
|
||||
try {
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
|
||||
sendToRenderer('outbound-watcher-file-detected', {
|
||||
filePath,
|
||||
fileName,
|
||||
content,
|
||||
outputDir
|
||||
});
|
||||
|
||||
console.log(`[OutboundWatcher] Sent to renderer: ${fileName} (${content.length} bytes)`);
|
||||
} catch (e) {
|
||||
console.error(`[OutboundWatcher] Read error: ${e.message}`);
|
||||
sendToRenderer('outbound-watcher-error', {
|
||||
filePath: fileName,
|
||||
error: `Datei konnte nicht gelesen werden: ${e.message}`
|
||||
});
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
|
||||
outboundWatcher.on('error', (err) => {
|
||||
console.error(`[OutboundWatcher] Error: ${err.message}`);
|
||||
sendToRenderer('outbound-watcher-error', {
|
||||
error: `Watcher-Fehler: ${err.message}`
|
||||
});
|
||||
});
|
||||
|
||||
outboundWatcher.on('ready', () => {
|
||||
console.log(`[OutboundWatcher] Ready. Watching: ${inputDir}`);
|
||||
sendToRenderer('outbound-watcher-ready', { inputDir });
|
||||
});
|
||||
|
||||
return { success: true, status: 'running' };
|
||||
});
|
||||
|
||||
ipcMain.handle('stop-outbound-watcher', () => {
|
||||
if (outboundWatcher) {
|
||||
outboundWatcher.close();
|
||||
outboundWatcher = null;
|
||||
console.log('[OutboundWatcher] Stopped.');
|
||||
}
|
||||
outboundWatcherPaused = false;
|
||||
return { success: true, status: 'stopped' };
|
||||
});
|
||||
|
||||
ipcMain.handle('pause-outbound-watcher', () => {
|
||||
outboundWatcherPaused = true;
|
||||
console.log('[OutboundWatcher] Paused.');
|
||||
return { success: true, status: 'paused' };
|
||||
});
|
||||
|
||||
ipcMain.handle('resume-outbound-watcher', () => {
|
||||
if (!outboundWatcher) {
|
||||
return { error: 'Kein Watcher aktiv. Bitte zuerst starten.' };
|
||||
}
|
||||
outboundWatcherPaused = false;
|
||||
console.log('[OutboundWatcher] Resumed.');
|
||||
return { success: true, status: 'running' };
|
||||
});
|
||||
|
||||
ipcMain.handle('get-outbound-watcher-status', () => {
|
||||
if (!outboundWatcher) return { status: 'stopped' };
|
||||
if (outboundWatcherPaused) return { status: 'paused' };
|
||||
return { status: 'running' };
|
||||
});
|
||||
|
||||
// ─── Werksnummer Watcher ───────────────────────────────────────────
|
||||
|
||||
ipcMain.handle('start-werks-watcher', (_, config) => {
|
||||
if (werksWatcher) {
|
||||
werksWatcher.close();
|
||||
werksWatcher = null;
|
||||
}
|
||||
|
||||
werksWatcherConfig = { ...werksWatcherConfig, ...config };
|
||||
|
||||
// Save to global settings
|
||||
const current = loadSettings();
|
||||
saveSettings({
|
||||
...current,
|
||||
werksInputDir: werksWatcherConfig.inputDir,
|
||||
werksOutputDir: werksWatcherConfig.outputDir
|
||||
});
|
||||
|
||||
const { inputDir, outputDir } = werksWatcherConfig;
|
||||
|
||||
if (!inputDir || !outputDir) {
|
||||
return { error: 'Input- und Output-Ordner müssen angegeben werden.' };
|
||||
}
|
||||
|
||||
if (!fs.existsSync(inputDir)) {
|
||||
return { error: `Input-Ordner existiert nicht: ${inputDir}` };
|
||||
}
|
||||
|
||||
if (!fs.existsSync(outputDir)) {
|
||||
try { fs.mkdirSync(outputDir, { recursive: true }); }
|
||||
catch (e) { return { error: `Output-Ordner konnte nicht erstellt werden: ${e.message}` }; }
|
||||
}
|
||||
|
||||
werksWatcherPaused = false;
|
||||
|
||||
werksWatcher = chokidar.watch(inputDir, {
|
||||
ignored: [/(^|[\/\\])\../, path.join(inputDir, 'archiv', '**')],
|
||||
persistent: true,
|
||||
ignoreInitial: true,
|
||||
depth: 0,
|
||||
usePolling: true,
|
||||
interval: 1000,
|
||||
awaitWriteFinish: { stabilityThreshold: 1000, pollInterval: 100 }
|
||||
});
|
||||
|
||||
werksWatcher.on('add', (filePath) => {
|
||||
if (werksWatcherPaused) return;
|
||||
|
||||
const fileName = path.basename(filePath);
|
||||
if (!fileName.startsWith('RA_VDA')) return;
|
||||
|
||||
console.log(`[WerksWatcher] Testing file: ${fileName}`);
|
||||
|
||||
setTimeout(() => {
|
||||
try {
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
const lines = content.split(/\r?\n/);
|
||||
let plant = null;
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.startsWith('512') && line.length >= 8) {
|
||||
const extracted = line.substring(5, 8).trim();
|
||||
if (extracted === '100' || extracted === '280') {
|
||||
plant = extracted;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!plant) {
|
||||
console.log(`[WerksWatcher] No relevant plant (100/280) found in ${fileName}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const prefix = plant === '100' ? 'RA_LEIFERS.' : 'RA_PITESTI.';
|
||||
const newName = fileName.replace('RA_VDA', prefix);
|
||||
const outPath = path.join(outputDir, newName);
|
||||
|
||||
fs.copyFileSync(filePath, outPath);
|
||||
console.log(`[WerksWatcher] Processed: ${fileName} -> ${newName}`);
|
||||
|
||||
sendToRenderer('werks-watcher-success', {
|
||||
fileName,
|
||||
newName,
|
||||
plant: plant === '100' ? 'Leifers (100)' : 'Pitesti (280)'
|
||||
});
|
||||
|
||||
// Delete original file
|
||||
fs.unlinkSync(filePath);
|
||||
|
||||
} catch (e) {
|
||||
console.error(`[WerksWatcher] Error processing ${fileName}:`, e);
|
||||
sendToRenderer('werks-watcher-error', { fileName, error: e.message });
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
|
||||
werksWatcher.on('ready', () => {
|
||||
sendToRenderer('werks-watcher-ready', { inputDir });
|
||||
});
|
||||
|
||||
return { success: true, status: 'running' };
|
||||
});
|
||||
|
||||
ipcMain.handle('stop-werks-watcher', () => {
|
||||
if (werksWatcher) {
|
||||
werksWatcher.close();
|
||||
werksWatcher = null;
|
||||
}
|
||||
werksWatcherPaused = false;
|
||||
return { success: true, status: 'stopped' };
|
||||
});
|
||||
|
||||
ipcMain.handle('pause-werks-watcher', () => {
|
||||
werksWatcherPaused = true;
|
||||
return { success: true, status: 'paused' };
|
||||
});
|
||||
|
||||
ipcMain.handle('resume-werks-watcher', () => {
|
||||
if (!werksWatcher) return { error: 'Nicht aktiv.' };
|
||||
werksWatcherPaused = false;
|
||||
return { success: true, status: 'running' };
|
||||
});
|
||||
|
||||
ipcMain.handle('get-werks-watcher-status', () => {
|
||||
if (!werksWatcher) return { status: 'stopped' };
|
||||
if (werksWatcherPaused) return { status: 'paused' };
|
||||
return { status: 'running' };
|
||||
});
|
||||
|
||||
// ─── IPC: Conversion History DB ─────────────────────────────────────
|
||||
ipcMain.handle('db-insert', async (_, record) => {
|
||||
try {
|
||||
return await conversionDB.insert(record);
|
||||
} catch (e) {
|
||||
console.error('[DB] Insert error:', e);
|
||||
return { error: e.message };
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('db-get-all', async (_, params) => {
|
||||
try {
|
||||
const { limit, offset, statusFilter, search, dateFilter } = params || {};
|
||||
console.log(`[DB] db-get-all called with params:`, { limit, offset, statusFilter, search, dateFilter });
|
||||
const result = await conversionDB.getAll(limit || 50, offset || 0, statusFilter || 'ALL', search || '', dateFilter || 'ALL');
|
||||
console.log(`[DB] db-get-all returned: ${result.rows.length} rows, Total: ${result.total}`);
|
||||
return result;
|
||||
} catch (e) {
|
||||
console.error('[DB] db-get-all error:', e);
|
||||
return { rows: [], total: 0, error: e.message };
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('db-get-by-id', async (_, id) => {
|
||||
try {
|
||||
return await conversionDB.getById(id);
|
||||
} catch (e) {
|
||||
console.error('[DB] GetById error:', e);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('db-delete', async (_, id) => {
|
||||
try {
|
||||
return { success: await conversionDB.deleteById(id) };
|
||||
} catch (e) {
|
||||
console.error('[DB] Delete error:', e);
|
||||
return { error: e.message };
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('db-get-stats', async () => {
|
||||
try {
|
||||
return await conversionDB.getStats();
|
||||
} catch (e) {
|
||||
console.error('[DB] Stats error:', e);
|
||||
return { total: 0, success: 0, error: 0, today: 0 };
|
||||
}
|
||||
});
|
||||
|
||||
// ─── IPC: Config DB ─────────────────────────────────────────────────
|
||||
ipcMain.handle('db-insert-config', async (_, configData) => {
|
||||
try {
|
||||
return await conversionDB.insertConfig(configData);
|
||||
} catch (e) {
|
||||
console.error('[DB] Insert config error:', e);
|
||||
return { error: e.message };
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('db-get-config', async () => {
|
||||
try {
|
||||
return await conversionDB.getConfig();
|
||||
} catch (e) {
|
||||
console.error('[DB] Get config error:', e);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
// ─── IPC: EDIFACT Validation (ts-edifact library) ────────────────────
|
||||
ipcMain.handle('validate-edifact', (_, content) => {
|
||||
try {
|
||||
return edifactValidator.validateEdifact(content);
|
||||
} catch (e) {
|
||||
return { valid: false, errors: [e.message], warnings: [], stats: {} };
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('parse-edifact-lib', (_, content) => {
|
||||
try {
|
||||
return edifactValidator.parseWithLib(content);
|
||||
} catch (e) {
|
||||
return { segments: [], segmentCount: 0, error: e.message };
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user