V 2.0.1 - Regeln-Filter nach Ordner + Markierung ohne Zuordnung
Neue Features: - Filter-Dropdown für Regeln nach Ordner - Option "Ohne Zuordnung" zeigt nur Regeln ohne Ordner - Regeln ohne Ordner-Zuweisung werden mit orangem Rand und Badge markiert - Zugeordnete Ordner werden unter jeder Regel angezeigt - Filter-Einstellung wird in localStorage gespeichert Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
c5ee82e1c2
commit
a9a5482c94
5 changed files with 118 additions and 8 deletions
BIN
Docker - Image/V 2.0/V 2.0.tar
Executable file
BIN
Docker - Image/V 2.0/V 2.0.tar
Executable file
Binary file not shown.
BIN
Docker - Image/V 2.1/V 2.1.tar
Executable file
BIN
Docker - Image/V 2.1/V 2.1.tar
Executable file
Binary file not shown.
|
|
@ -142,6 +142,7 @@ class RegelResponse(BaseModel):
|
||||||
freie_ordner: Optional[List[str]] = []
|
freie_ordner: Optional[List[str]] = []
|
||||||
ziel_ordner: Optional[str] = None
|
ziel_ordner: Optional[str] = None
|
||||||
nur_umbenennen: bool = False
|
nur_umbenennen: bool = False
|
||||||
|
ordner_ids: List[int] = [] # IDs der zugeordneten Ordner
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
from_attributes = True
|
from_attributes = True
|
||||||
|
|
@ -959,9 +960,40 @@ def verarbeite_ordner(id: int, db: Session = Depends(get_db)):
|
||||||
|
|
||||||
# ============ Regeln ============
|
# ============ Regeln ============
|
||||||
|
|
||||||
@router.get("/regeln", response_model=List[RegelResponse])
|
@router.get("/regeln")
|
||||||
def liste_regeln(db: Session = Depends(get_db)):
|
def liste_regeln(db: Session = Depends(get_db)):
|
||||||
return db.query(SortierRegel).order_by(SortierRegel.prioritaet).all()
|
"""Gibt alle Regeln mit ihren zugeordneten Ordner-IDs zurück"""
|
||||||
|
regeln = db.query(SortierRegel).order_by(SortierRegel.prioritaet).all()
|
||||||
|
|
||||||
|
# Alle Ordner-Zuweisungen auf einmal laden
|
||||||
|
alle_zuweisungen = db.query(OrdnerRegel).all()
|
||||||
|
regel_ordner_map = {}
|
||||||
|
for z in alle_zuweisungen:
|
||||||
|
if z.regel_id not in regel_ordner_map:
|
||||||
|
regel_ordner_map[z.regel_id] = []
|
||||||
|
regel_ordner_map[z.regel_id].append(z.ordner_id)
|
||||||
|
|
||||||
|
# Regeln mit Ordner-IDs anreichern
|
||||||
|
result = []
|
||||||
|
for r in regeln:
|
||||||
|
regel_dict = {
|
||||||
|
"id": r.id,
|
||||||
|
"name": r.name,
|
||||||
|
"prioritaet": r.prioritaet,
|
||||||
|
"aktiv": r.aktiv,
|
||||||
|
"muster": r.muster or {},
|
||||||
|
"extraktion": r.extraktion or {},
|
||||||
|
"ist_fallback": r.ist_fallback,
|
||||||
|
"schema": r.schema,
|
||||||
|
"unterordner": r.unterordner,
|
||||||
|
"freie_ordner": r.freie_ordner or [],
|
||||||
|
"ziel_ordner": r.ziel_ordner,
|
||||||
|
"nur_umbenennen": r.nur_umbenennen,
|
||||||
|
"ordner_ids": regel_ordner_map.get(r.id, [])
|
||||||
|
}
|
||||||
|
result.append(regel_dict)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
@router.post("/regeln", response_model=RegelResponse)
|
@router.post("/regeln", response_model=RegelResponse)
|
||||||
|
|
|
||||||
|
|
@ -1034,10 +1034,68 @@ function natuerlicheSortierung(a, b) {
|
||||||
return a.localeCompare(b, 'de', { numeric: true, sensitivity: 'base' });
|
return a.localeCompare(b, 'de', { numeric: true, sensitivity: 'base' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cache für Ordner (für Filter-Dropdown)
|
||||||
|
let ordnerCache = [];
|
||||||
|
|
||||||
|
async function ladeOrdnerFuerFilter() {
|
||||||
|
try {
|
||||||
|
const ordner = await api('/ordner');
|
||||||
|
ordnerCache = ordner;
|
||||||
|
|
||||||
|
const filterSelect = document.getElementById('regeln-ordner-filter');
|
||||||
|
if (!filterSelect) return;
|
||||||
|
|
||||||
|
// Gespeicherten Filter wiederherstellen
|
||||||
|
const gespeichert = localStorage.getItem('regeln-ordner-filter');
|
||||||
|
|
||||||
|
// Bestehende Optionen nach "Ohne Zuordnung" entfernen
|
||||||
|
while (filterSelect.options.length > 2) {
|
||||||
|
filterSelect.remove(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ordner hinzufügen
|
||||||
|
ordner.forEach(o => {
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.value = o.id;
|
||||||
|
option.textContent = o.name;
|
||||||
|
filterSelect.appendChild(option);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Gespeicherten Wert setzen
|
||||||
|
if (gespeichert) {
|
||||||
|
filterSelect.value = gespeichert;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Fehler beim Laden der Ordner für Filter:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function ladeRegeln() {
|
async function ladeRegeln() {
|
||||||
try {
|
try {
|
||||||
const regeln = await api('/regeln');
|
const regeln = await api('/regeln');
|
||||||
|
|
||||||
|
// Ordner-Filter Dropdown beim ersten Mal befüllen
|
||||||
|
const filterSelect = document.getElementById('regeln-ordner-filter');
|
||||||
|
if (filterSelect && filterSelect.options.length <= 2) {
|
||||||
|
await ladeOrdnerFuerFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter anwenden
|
||||||
|
if (filterSelect) {
|
||||||
|
localStorage.setItem('regeln-ordner-filter', filterSelect.value);
|
||||||
|
}
|
||||||
|
const filter = filterSelect?.value || 'alle';
|
||||||
|
|
||||||
|
let gefilterteRegeln = regeln;
|
||||||
|
if (filter === 'ohne') {
|
||||||
|
// Nur Regeln ohne Ordner-Zuweisung
|
||||||
|
gefilterteRegeln = regeln.filter(r => !r.ordner_ids || r.ordner_ids.length === 0);
|
||||||
|
} else if (filter !== 'alle') {
|
||||||
|
// Nach spezifischem Ordner filtern
|
||||||
|
const ordnerId = parseInt(filter);
|
||||||
|
gefilterteRegeln = regeln.filter(r => r.ordner_ids && r.ordner_ids.includes(ordnerId));
|
||||||
|
}
|
||||||
|
|
||||||
// Sortierung anwenden (und in localStorage speichern)
|
// Sortierung anwenden (und in localStorage speichern)
|
||||||
const sortSelect = document.getElementById('regeln-sortierung');
|
const sortSelect = document.getElementById('regeln-sortierung');
|
||||||
if (sortSelect) {
|
if (sortSelect) {
|
||||||
|
|
@ -1051,7 +1109,7 @@ async function ladeRegeln() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const sortierung = sortSelect?.value || 'name_asc';
|
const sortierung = sortSelect?.value || 'name_asc';
|
||||||
regeln.sort((a, b) => {
|
gefilterteRegeln.sort((a, b) => {
|
||||||
switch (sortierung) {
|
switch (sortierung) {
|
||||||
case 'name_asc':
|
case 'name_asc':
|
||||||
return natuerlicheSortierung(a.name || '', b.name || '');
|
return natuerlicheSortierung(a.name || '', b.name || '');
|
||||||
|
|
@ -1066,7 +1124,7 @@ async function ladeRegeln() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
renderRegeln(regeln);
|
renderRegeln(gefilterteRegeln);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Fehler:', error);
|
console.error('Fehler:', error);
|
||||||
}
|
}
|
||||||
|
|
@ -1083,11 +1141,26 @@ function renderRegeln(regeln) {
|
||||||
container.innerHTML = regeln.map(r => {
|
container.innerHTML = regeln.map(r => {
|
||||||
const aktivClass = r.aktiv ? '' : 'opacity: 0.5;';
|
const aktivClass = r.aktiv ? '' : 'opacity: 0.5;';
|
||||||
const aktivBadge = r.aktiv ? '<span class="badge badge-success">Aktiv</span>' : '<span class="badge badge-danger">Inaktiv</span>';
|
const aktivBadge = r.aktiv ? '<span class="badge badge-success">Aktiv</span>' : '<span class="badge badge-danger">Inaktiv</span>';
|
||||||
|
|
||||||
|
// Warnung wenn keine Ordner zugeordnet
|
||||||
|
const ohneOrdner = !r.ordner_ids || r.ordner_ids.length === 0;
|
||||||
|
const ohneOrdnerBadge = ohneOrdner ? '<span class="badge badge-warning" title="Keinem Ordner zugeordnet">⚠ Ohne Ordner</span>' : '';
|
||||||
|
const ohneOrdnerStyle = ohneOrdner ? 'border-left: 3px solid var(--warning);' : '';
|
||||||
|
|
||||||
|
// Ordner-Namen anzeigen
|
||||||
|
let ordnerInfo = '';
|
||||||
|
if (r.ordner_ids && r.ordner_ids.length > 0 && ordnerCache.length > 0) {
|
||||||
|
const ordnerNamen = r.ordner_ids
|
||||||
|
.map(id => ordnerCache.find(o => o.id === id)?.name || `ID ${id}`)
|
||||||
|
.join(', ');
|
||||||
|
ordnerInfo = `<br><small style="color: var(--text-secondary);">📁 ${escapeHtml(ordnerNamen)}</small>`;
|
||||||
|
}
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="config-item" style="${aktivClass}">
|
<div class="config-item" style="${aktivClass}${ohneOrdnerStyle}">
|
||||||
<div class="config-item-info">
|
<div class="config-item-info">
|
||||||
<h4>${escapeHtml(r.name)} ${aktivBadge} <span class="badge badge-info">Prio ${r.prioritaet}</span></h4>
|
<h4>${escapeHtml(r.name)} ${aktivBadge} ${ohneOrdnerBadge} <span class="badge badge-info">Prio ${r.prioritaet}</span></h4>
|
||||||
<small>${escapeHtml(r.schema)}</small>
|
<small>${escapeHtml(r.schema)}</small>${ordnerInfo}
|
||||||
</div>
|
</div>
|
||||||
<div class="config-item-actions">
|
<div class="config-item-actions">
|
||||||
<button class="btn btn-sm" onclick="bearbeiteRegel(${r.id})" title="Bearbeiten">✎</button>
|
<button class="btn btn-sm" onclick="bearbeiteRegel(${r.id})" title="Bearbeiten">✎</button>
|
||||||
|
|
|
||||||
|
|
@ -199,7 +199,12 @@
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h3>📑 Sortier-Regeln</h3>
|
<h3>📑 Sortier-Regeln</h3>
|
||||||
<div style="display: flex; gap: 0.5rem; align-items: center;">
|
<div style="display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap;">
|
||||||
|
<select id="regeln-ordner-filter" onchange="ladeRegeln()" title="Nach Ordner filtern" style="padding: 0.25rem 0.5rem; font-size: 0.85rem; max-width: 150px;">
|
||||||
|
<option value="alle">Alle Ordner</option>
|
||||||
|
<option value="ohne">⚠ Ohne Zuordnung</option>
|
||||||
|
<!-- Ordner werden dynamisch geladen -->
|
||||||
|
</select>
|
||||||
<select id="regeln-sortierung" onchange="ladeRegeln()" title="Sortierung" style="padding: 0.25rem 0.5rem; font-size: 0.85rem;">
|
<select id="regeln-sortierung" onchange="ladeRegeln()" title="Sortierung" style="padding: 0.25rem 0.5rem; font-size: 0.85rem;">
|
||||||
<option value="name_asc">Name A-Z</option>
|
<option value="name_asc">Name A-Z</option>
|
||||||
<option value="name_desc">Name Z-A</option>
|
<option value="name_desc">Name Z-A</option>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue