719 lines
24 KiB
JavaScript
719 lines
24 KiB
JavaScript
/**
|
|
* 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 };
|
|
}
|
|
});
|