feat: redesign settings page with sidebar navigation and improved layout

This commit is contained in:
zed
2026-03-13 15:32:29 +01:00
parent 67bd64b688
commit bffe69abaf
4 changed files with 507 additions and 318 deletions

View File

@@ -276,340 +276,336 @@
<!-- ═══════════════════════════════════════════════════════════ -->
<!-- PAGE: SETTINGS -->
<!-- ═══════════════════════════════════════════════════════════ -->
<!-- ═══════════════════════════════════════════════════════════ -->
<!-- PAGE: SETTINGS -->
<!-- ═══════════════════════════════════════════════════════════ -->
<main class="main-card page-content" id="pageSettings" style="display:none">
<h2 class="settings-title">
<i data-lucide="folder-search"></i>
Ankommende Dateien (Folder Watch)
</h2>
<p class="subtitle" style="margin-bottom: 30px;">Überwacht einen Netzwerkordner auf neue Dateien,
konvertiert sie automatisch und schreibt die Ergebnisse in den Output-Ordner.</p>
<!-- General Settings & ID Mapping -->
<div class="log-section" style="margin-top: 40px;">
<h2 class="settings-title">
<i data-lucide="user-check"></i>
VDA 711 ID-Umschlüsselung
</h2>
<p class="subtitle" style="margin-bottom: 20px;">
Weisen Sie extrahierten IDs (Datenempfänger) eine eigene Kundennummer für den VDA 711 Header zu.
</p>
<!-- Settings Layout: Sidebar + Content -->
<div class="settings-layout">
<div class="mapping-editor">
<div class="folder-input-row" style="margin-bottom: 20px;">
<input type="text" id="newIdMapOriginal" class="folder-path-input"
placeholder="Alt (z.B. 8810)" style="max-width: 200px;">
<input type="text" id="newIdMapTarget" class="folder-path-input"
placeholder="Neu (z.B. 10305)" style="max-width: 200px;">
<button class="btn-primary" onclick="app.addIdMapping711()">
<i data-lucide="plus"></i>
Hinzufügen
</button>
<!-- ── Left Sidebar ── -->
<nav class="settings-sidebar">
<div class="settings-sidebar-header">
<i data-lucide="settings-2"></i>
<span>Einstellungen</span>
</div>
<div class="table-container">
<table id="idMapping711Table">
<thead>
<tr>
<th>Extrahierte ID (Alt)</th>
<th>Eigene ID (Neu)</th>
<th style="width: 100px;">Aktion</th>
</tr>
</thead>
<tbody>
<!-- Populated by JS -->
</tbody>
</table>
</div>
</div>
</div>
<!-- Electron notice -->
<div id="electronNotice" class="electron-notice" style="display:none">
<i data-lucide="alert-triangle"></i>
<span>Ordnerüberwachung ist nur in der Electron-App verfügbar. Bitte starten Sie die App mit
<code>npm start</code>.</span>
</div>
<!-- Folder Config -->
<div class="settings-grid">
<div class="settings-card">
<div class="settings-card-header">
<i data-lucide="folder-input"></i>
<span>Input-Ordner</span>
</div>
<div class="folder-input-row">
<input type="text" id="inputDirPath" class="folder-path-input"
placeholder="z.B. \\server\edi\input" readonly>
<button class="btn-secondary" id="btnSelectInput" onclick="app.selectInputFolder()">
<i data-lucide="folder-open"></i>
Wählen
</button>
</div>
</div>
<div class="settings-card">
<div class="settings-card-header">
<i data-lucide="folder-output"></i>
<span>Output-Ordner</span>
</div>
<div class="folder-input-row">
<input type="text" id="outputDirPath" class="folder-path-input"
placeholder="z.B. \\server\edi\output" readonly>
<button class="btn-secondary" id="btnSelectOutput" onclick="app.selectOutputFolder()">
<i data-lucide="folder-open"></i>
Wählen
</button>
</div>
</div>
<div class="settings-card">
<div class="settings-card-header">
<i data-lucide="folder-output"></i>
<span>Output-Ordner (INVRPT → VDA 4913)</span>
</div>
<div class="folder-input-row">
<input type="text" id="invrptOutputPath" class="folder-path-input"
placeholder="Leer = gleicher Output-Ordner" readonly>
<button class="btn-secondary" id="btnSelectInvrptOutput" onclick="app.selectInvrptOutputFolder()">
<i data-lucide="folder-open"></i>
Wählen
</button>
</div>
</div>
</div>
<!-- Watcher Controls -->
<div class="watcher-controls">
<div class="watcher-status-display">
<span class="watcher-status-dot" id="watcherDot"></span>
<span id="watcherStatusText">Gestoppt</span>
</div>
<div class="watcher-buttons">
<button class="btn-primary btn-start" id="btnStartWatcher" onclick="app.startWatcher()">
<i data-lucide="play"></i>
Starten
<button class="settings-nav-btn active" data-section="inbound" onclick="app.switchSettingsSection('inbound')">
<i data-lucide="arrow-down-to-line"></i>
<span>Eingehend</span>
</button>
<button class="btn-secondary btn-pause" id="btnPauseWatcher" onclick="app.pauseWatcher()" disabled>
<i data-lucide="pause"></i>
Pausieren
<button class="settings-nav-btn" data-section="outbound" onclick="app.switchSettingsSection('outbound')">
<i data-lucide="arrow-up-from-line"></i>
<span>Ausgehend</span>
</button>
<button class="btn-secondary btn-resume" id="btnResumeWatcher" onclick="app.resumeWatcher()"
style="display:none">
<i data-lucide="play"></i>
Fortsetzen
<button class="settings-nav-btn" data-section="werks" onclick="app.switchSettingsSection('werks')">
<i data-lucide="file-symlink"></i>
<span>Werksnummer</span>
</button>
<button class="btn-secondary btn-stop" id="btnStopWatcher" onclick="app.stopWatcher()" disabled>
<i data-lucide="square"></i>
Stoppen
<button class="settings-nav-btn" data-section="mapping" onclick="app.switchSettingsSection('mapping')">
<i data-lucide="git-merge"></i>
<span>Mapping</span>
</button>
</div>
</div>
<button class="settings-nav-btn" data-section="log" onclick="app.switchSettingsSection('log')">
<i data-lucide="scroll-text"></i>
<span>Log</span>
</button>
</nav>
<!-- Outbound Folder Config -->
<div class="log-section" style="margin-top: 40px;">
<h2 class="settings-title">
<i data-lucide="folder-search"></i>
Ausgehende Dateien (Folder Watch)
</h2>
<p class="subtitle" style="margin-bottom: 20px;">
Überwacht einen Netzwerkordner auf ausgehende Dateien, konvertiert sie automatisch und schreibt die Ergebnisse in den Output-Ordner.
</p>
<!-- ── Right Content Area ── -->
<div class="settings-content">
<div class="settings-grid">
<div class="settings-card">
<div class="settings-card-header">
<i data-lucide="folder-input"></i>
<span>Input-Ordner (Ausgehend)</span>
<!-- ─── SECTION: Eingehend ─────────────────────────── -->
<div class="settings-section" id="settingsSection-inbound">
<div class="settings-section-header">
<div>
<h2>Eingehende Dateien <span class="settings-section-sub">(Folder Watch)</span></h2>
<p class="subtitle">Überwacht einen Netzwerkordner auf neue Dateien, konvertiert sie automatisch und schreibt die Ergebnisse in den Output-Ordner.</p>
</div>
</div>
<div class="folder-input-row">
<input type="text" id="outboundInputPath" class="folder-path-input"
placeholder="z.B. \\server\edi\outbound_in" readonly>
<button class="btn-secondary" onclick="app.selectOutboundInput()">
<i data-lucide="folder-open"></i>
Wählen
<!-- Electron notice -->
<div id="electronNotice" class="electron-notice" style="display:none">
<i data-lucide="alert-triangle"></i>
<span>Ordnerüberwachung ist nur in der Electron-App verfügbar. Bitte starten Sie die App mit <code>npm start</code>.</span>
</div>
<!-- Watcher Status Banner -->
<div class="watcher-banner" id="watcherBanner">
<div class="watcher-banner-left">
<span class="watcher-status-dot" id="watcherDot"></span>
<span id="watcherStatusText">Gestoppt</span>
</div>
<div class="watcher-buttons">
<button class="btn-primary btn-start" id="btnStartWatcher" onclick="app.startWatcher()">
<i data-lucide="play"></i> Starten
</button>
<button class="btn-secondary btn-pause" id="btnPauseWatcher" onclick="app.pauseWatcher()" disabled>
<i data-lucide="pause"></i> Pausieren
</button>
<button class="btn-secondary btn-resume" id="btnResumeWatcher" onclick="app.resumeWatcher()" style="display:none">
<i data-lucide="play"></i> Fortsetzen
</button>
<button class="btn-secondary btn-stop" id="btnStopWatcher" onclick="app.stopWatcher()" disabled>
<i data-lucide="square"></i> Stoppen
</button>
</div>
</div>
<!-- Folder Cards: 3-column -->
<div class="settings-grid-3">
<div class="settings-card">
<div class="settings-card-header">
<i data-lucide="folder-input"></i>
<span>Input-Ordner</span>
</div>
<div class="folder-input-row">
<input type="text" id="inputDirPath" class="folder-path-input" placeholder="z.B. \\server\edi\input" readonly>
<button class="btn-secondary" id="btnSelectInput" onclick="app.selectInputFolder()">
<i data-lucide="folder-open"></i>
</button>
</div>
</div>
<div class="settings-card">
<div class="settings-card-header">
<i data-lucide="folder-output"></i>
<span>Output-Ordner</span>
</div>
<div class="folder-input-row">
<input type="text" id="outputDirPath" class="folder-path-input" placeholder="z.B. \\server\edi\output" readonly>
<button class="btn-secondary" id="btnSelectOutput" onclick="app.selectOutputFolder()">
<i data-lucide="folder-open"></i>
</button>
</div>
</div>
<div class="settings-card">
<div class="settings-card-header">
<i data-lucide="folder-output"></i>
<span>Output (INVRPT → VDA 4913)</span>
</div>
<div class="folder-input-row">
<input type="text" id="invrptOutputPath" class="folder-path-input" placeholder="Leer = gleicher Output-Ordner" readonly>
<button class="btn-secondary" id="btnSelectInvrptOutput" onclick="app.selectInvrptOutputFolder()">
<i data-lucide="folder-open"></i>
</button>
</div>
</div>
</div>
<!-- VDA 711 ID-Umschlüsselung -->
<div class="section-panel" style="margin-top: 24px;">
<div class="section-panel-header">
<i data-lucide="user-check"></i>
<div>
<h3>VDA 711 ID-Umschlüsselung</h3>
<p class="subtitle">Extrahierten IDs (Datenempfänger) eine eigene Kundennummer zuweisen.</p>
</div>
</div>
<div class="folder-input-row" style="margin-bottom: 16px; margin-top: 16px;">
<input type="text" id="newIdMapOriginal" class="folder-path-input" placeholder="Alt (z.B. 8810)" style="max-width: 180px;">
<input type="text" id="newIdMapTarget" class="folder-path-input" placeholder="Neu (z.B. 10305)" style="max-width: 180px;">
<button class="btn-primary" onclick="app.addIdMapping711()">
<i data-lucide="plus"></i> Hinzufügen
</button>
</div>
<div class="table-container">
<table id="idMapping711Table">
<thead>
<tr>
<th>Extrahierte ID (Alt)</th>
<th>Eigene ID (Neu)</th>
<th style="width: 100px;">Aktion</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
</div>
<!-- ─── SECTION: Ausgehend ─────────────────────────── -->
<div class="settings-section" id="settingsSection-outbound" style="display:none">
<div class="settings-section-header">
<div>
<h2>Ausgehende Dateien <span class="settings-section-sub">(Folder Watch)</span></h2>
<p class="subtitle">Überwacht einen Netzwerkordner auf ausgehende Dateien, konvertiert sie automatisch und schreibt die Ergebnisse in den Output-Ordner.</p>
</div>
</div>
<!-- Watcher Status Banner -->
<div class="watcher-banner" id="outboundWatcherBanner">
<div class="watcher-banner-left">
<span class="watcher-status-dot" id="outboundWatcherDot"></span>
<span id="outboundWatcherStatusText">Gestoppt</span>
</div>
<div class="watcher-buttons">
<button class="btn-primary btn-start" id="btnStartOutboundWatcher" onclick="app.startOutboundWatcher()">
<i data-lucide="play"></i> Starten
</button>
<button class="btn-secondary btn-pause" id="btnPauseOutboundWatcher" onclick="app.pauseOutboundWatcher()" disabled>
<i data-lucide="pause"></i> Pausieren
</button>
<button class="btn-secondary btn-resume" id="btnResumeOutboundWatcher" onclick="app.resumeOutboundWatcher()" style="display:none">
<i data-lucide="play"></i> Fortsetzen
</button>
<button class="btn-secondary btn-stop" id="btnStopOutboundWatcher" onclick="app.stopOutboundWatcher()" disabled>
<i data-lucide="square"></i> Stoppen
</button>
</div>
</div>
<!-- Folder Cards: 2-column -->
<div class="settings-grid">
<div class="settings-card">
<div class="settings-card-header">
<i data-lucide="folder-input"></i>
<span>Input-Ordner (Ausgehend)</span>
</div>
<div class="folder-input-row">
<input type="text" id="outboundInputPath" class="folder-path-input" placeholder="z.B. \\server\edi\outbound_in" readonly>
<button class="btn-secondary" onclick="app.selectOutboundInput()">
<i data-lucide="folder-open"></i>
</button>
</div>
</div>
<div class="settings-card">
<div class="settings-card-header">
<i data-lucide="folder-output"></i>
<span>Output-Ordner (Ausgehend)</span>
</div>
<div class="folder-input-row">
<input type="text" id="outboundOutputPath" class="folder-path-input" placeholder="z.B. \\server\edi\outbound_out" readonly>
<button class="btn-secondary" onclick="app.selectOutboundOutput()">
<i data-lucide="folder-open"></i>
</button>
</div>
</div>
</div>
</div>
<!-- ─── SECTION: Werksnummer ───────────────────────── -->
<div class="settings-section" id="settingsSection-werks" style="display:none">
<div class="settings-section-header">
<div>
<h2>Werksnummer Umbenennung</h2>
<p class="subtitle">Überwacht VDA-Dateien (RA_VDA*) und benennt sie basierend auf der Werksnummer in Satzart 512 um (100 → LEIFERS, 280 → PITESTI).</p>
</div>
</div>
<!-- Watcher Status Banner -->
<div class="watcher-banner" id="werksWatcherBanner">
<div class="watcher-banner-left">
<span class="watcher-status-dot" id="werksWatcherDot"></span>
<span id="werksWatcherStatusText">Gestoppt</span>
</div>
<div class="watcher-buttons">
<button class="btn-primary btn-start" id="btnStartWerksWatcher" onclick="app.startWerksWatcher()">
<i data-lucide="play"></i> Starten
</button>
<button class="btn-secondary btn-pause" id="btnPauseWerksWatcher" onclick="app.pauseWerksWatcher()" disabled>
<i data-lucide="pause"></i> Pausieren
</button>
<button class="btn-secondary btn-resume" id="btnResumeWerksWatcher" onclick="app.resumeWerksWatcher()" style="display:none">
<i data-lucide="play"></i> Fortsetzen
</button>
<button class="btn-secondary btn-stop" id="btnStopWerksWatcher" onclick="app.stopWerksWatcher()" disabled>
<i data-lucide="square"></i> Stoppen
</button>
</div>
</div>
<!-- Folder Cards: 2-column -->
<div class="settings-grid">
<div class="settings-card">
<div class="settings-card-header">
<i data-lucide="folder-input"></i>
<span>Input-Ordner (Werksnummer)</span>
</div>
<div class="folder-input-row">
<input type="text" id="werksInputPath" class="folder-path-input" placeholder="Input für Umbenennung" readonly>
<button class="btn-secondary" onclick="app.selectWerksInput()">
<i data-lucide="folder-open"></i>
</button>
</div>
</div>
<div class="settings-card">
<div class="settings-card-header">
<i data-lucide="folder-output"></i>
<span>Output-Ordner (Werksnummer)</span>
</div>
<div class="folder-input-row">
<input type="text" id="werksOutputPath" class="folder-path-input" placeholder="Output für Umbenennung" readonly>
<button class="btn-secondary" onclick="app.selectWerksOutput()">
<i data-lucide="folder-open"></i>
</button>
</div>
</div>
</div>
</div>
<!-- ─── SECTION: Mapping ───────────────────────────── -->
<div class="settings-section" id="settingsSection-mapping" style="display:none">
<div class="settings-section-header">
<div>
<h2>Kundennummern-Zuordnung</h2>
<p class="subtitle">Weisen Sie Kundennummern automatisch einer Konvertierung zu.</p>
</div>
</div>
<div class="section-panel">
<div class="folder-input-row" style="margin-bottom: 16px;">
<input type="text" id="newMappingId" class="folder-path-input" placeholder="Kundennummer (z.B. 5060)" style="max-width: 200px;">
<select id="newMappingMode" class="folder-path-input" style="max-width: 260px;">
<option value="outbound-bosch">VDA 4913 → Bosch DESADV</option>
<option value="outbound-zf">VDA 4913 → ZF DESADV</option>
<option value="outbound-ifm">VDA 4913 → IFM DELVRY03</option>
<option value="inbound-bosch">DELFOR → VDA 4905</option>
<option value="inbound-ifm">IFM DELFOR → VDA 4905</option>
<option value="inbound-invrpt">INVRPT → VDA 4913</option>
<option value="validate-edifact">EDIFACT Validieren</option>
</select>
<button class="btn-primary" onclick="app.addMapping()">
<i data-lucide="plus"></i> Hinzufügen
</button>
</div>
<div class="table-container">
<table id="mappingTable">
<thead>
<tr>
<th>Kundennummer</th>
<th>Konvertierungs-Modus</th>
<th style="width: 100px;">Aktion</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
</div>
<!-- ─── SECTION: Log ───────────────────────────────── -->
<div class="settings-section" id="settingsSection-log" style="display:none">
<div class="settings-section-header">
<div>
<h2>Konvertierungs-Log</h2>
<p class="subtitle">Echtzeit-Protokoll aller automatisierten Konvertierungen.</p>
</div>
<button class="btn-secondary" onclick="app.clearLog()">
<i data-lucide="trash-2"></i> Leeren
</button>
</div>
</div>
<div class="settings-card">
<div class="settings-card-header">
<i data-lucide="folder-output"></i>
<span>Output-Ordner (Ausgehend)</span>
</div>
<div class="folder-input-row">
<input type="text" id="outboundOutputPath" class="folder-path-input"
placeholder="z.B. \\server\edi\outbound_out" readonly>
<button class="btn-secondary" onclick="app.selectOutboundOutput()">
<i data-lucide="folder-open"></i>
Wählen
</button>
<div class="log-container" id="logContainer">
<div class="log-empty">Noch keine Aktivitäten.</div>
</div>
</div>
</div>
<div class="watcher-controls">
<div class="watcher-status-display">
<span class="watcher-status-dot" id="outboundWatcherDot"></span>
<span id="outboundWatcherStatusText">Gestoppt</span>
</div>
<div class="watcher-buttons">
<button class="btn-primary btn-start" id="btnStartOutboundWatcher"
onclick="app.startOutboundWatcher()">
<i data-lucide="play"></i>
Starten
</button>
<button class="btn-secondary btn-pause" id="btnPauseOutboundWatcher"
onclick="app.pauseOutboundWatcher()" disabled>
<i data-lucide="pause"></i>
Pausieren
</button>
<button class="btn-secondary btn-resume" id="btnResumeOutboundWatcher"
onclick="app.resumeOutboundWatcher()" style="display:none">
<i data-lucide="play"></i>
Fortsetzen
</button>
<button class="btn-secondary btn-stop" id="btnStopOutboundWatcher" onclick="app.stopOutboundWatcher()"
disabled>
<i data-lucide="square"></i>
Stoppen
</button>
</div>
</div>
</div>
<!-- Werksnummer Watcher Controls (New Section) -->
<div class="log-section" style="margin-top: 40px;">
<h2 class="settings-title">
<i data-lucide="file-text"></i>
Werksnummer Umbenennung
</h2>
<p class="subtitle" style="margin-bottom: 20px;">
Überwacht VDA-Dateien (RA_VDA*) und benennt sie basierend auf der Werksnummer in Satzart 512 um
(100 → LEIFERS, 280 → PITESTI).
</p>
<div class="settings-grid">
<div class="settings-card">
<div class="settings-card-header">
<i data-lucide="folder-input"></i>
<span>Input-Ordner (Werksnummer)</span>
</div>
<div class="folder-input-row">
<input type="text" id="werksInputPath" class="folder-path-input"
placeholder="Input für Umbenennung" readonly>
<button class="btn-secondary" onclick="app.selectWerksInput()">
<i data-lucide="folder-open"></i>
Wählen
</button>
</div>
</div>
<div class="settings-card">
<div class="settings-card-header">
<i data-lucide="folder-output"></i>
<span>Output-Ordner (Werksnummer)</span>
</div>
<div class="folder-input-row">
<input type="text" id="werksOutputPath" class="folder-path-input"
placeholder="Output für Umbenennung" readonly>
<button class="btn-secondary" onclick="app.selectWerksOutput()">
<i data-lucide="folder-open"></i>
Wählen
</button>
</div>
</div>
</div>
<div class="watcher-controls">
<div class="watcher-status-display">
<span class="watcher-status-dot" id="werksWatcherDot"></span>
<span id="werksWatcherStatusText">Gestoppt</span>
</div>
<div class="watcher-buttons">
<button class="btn-primary btn-start" id="btnStartWerksWatcher"
onclick="app.startWerksWatcher()">
<i data-lucide="play"></i>
Starten
</button>
<button class="btn-secondary btn-pause" id="btnPauseWerksWatcher"
onclick="app.pauseWerksWatcher()" disabled>
<i data-lucide="pause"></i>
Pausieren
</button>
<button class="btn-secondary btn-resume" id="btnResumeWerksWatcher"
onclick="app.resumeWerksWatcher()" style="display:none">
<i data-lucide="play"></i>
Fortsetzen
</button>
<button class="btn-secondary btn-stop" id="btnStopWerksWatcher" onclick="app.stopWerksWatcher()"
disabled>
<i data-lucide="square"></i>
Stoppen
</button>
</div>
</div>
</div>
<!-- Customer Mappings -->
<div class="log-section" style="margin-top: 40px;">
<div class="preview-header">
<h2>
<i data-lucide="map"></i>
Kundennummern-Zuordnung
</h2>
</div>
<p class="subtitle" style="margin-bottom: 20px;">Weisen Sie Kundennummern automatisch einer
Konvertierung zu.</p>
<div class="mapping-editor">
<div class="folder-input-row" style="margin-bottom: 20px;">
<input type="text" id="newMappingId" class="folder-path-input"
placeholder="Kundennummer (z.B. 5060)" style="max-width: 200px;">
<select id="newMappingMode" class="folder-path-input" style="max-width: 250px;">
<option value="outbound-bosch">VDA 4913 → Bosch DESADV</option>
<option value="outbound-zf">VDA 4913 → ZF DESADV</option>
<option value="outbound-ifm">VDA 4913 → IFM DELVRY03</option>
<option value="inbound-bosch">DELFOR → VDA 4905</option>
<option value="inbound-ifm">IFM DELFOR → VDA 4905</option>
<option value="inbound-invrpt">INVRPT → VDA 4913</option>
<option value="validate-edifact">EDIFACT Validieren</option>
</select>
<button class="btn-primary" onclick="app.addMapping()">
<i data-lucide="plus"></i>
Hinzufügen
</button>
</div>
<div class="table-container">
<table id="mappingTable">
<thead>
<tr>
<th>Kundennummer</th>
<th>Konvertierungs-Modus</th>
<th style="width: 100px;">Aktion</th>
</tr>
</thead>
<tbody>
<!-- Will be populated by JS -->
</tbody>
</table>
</div>
</div>
</div>
<!-- Conversion Log -->
<div class="log-section">
<div class="preview-header">
<h2>Konvertierungs-Log</h2>
<button class="btn-secondary" onclick="app.clearLog()">
<i data-lucide="trash-2"></i>
Leeren
</button>
</div>
<div class="log-container" id="logContainer">
<div class="log-empty">Noch keine Aktivitäten.</div>
</div>
</div>
</div><!-- /settings-content -->
</div><!-- /settings-layout -->
</main>
<!-- ═══════════════════════════════════════════════════════════ -->
<!-- PAGE: VIEWER -->
<!-- ═══════════════════════════════════════════════════════════ -->