feat(csv-import): Add custom row aggregation options in AdminCsvTemplateEditorPage
- Introduced a new section for row aggregation settings, allowing users to customize aggregation functions for imported CSV data. - Implemented functionality for users to save custom aggregation configurations and select key fields for aggregation. - Enhanced user interface with detailed instructions and options for managing row aggregation, improving overall usability in template management.
This commit is contained in:
parent
a51ee1d304
commit
ad7aa2d255
|
|
@ -965,6 +965,191 @@ export default function AdminCsvTemplateEditorPage() {
|
|||
)}
|
||||
</div>
|
||||
|
||||
{!aggregateSleepImport && (
|
||||
<div className="card" style={{ padding: 16, marginBottom: 16 }}>
|
||||
<div className="form-label">3a. Zeilenaggregation</div>
|
||||
{!modMeta?.fields || Object.keys(modMeta.fields).length === 0 ? (
|
||||
<p style={{ fontSize: 14, color: 'var(--text2)', marginTop: 8 }}>
|
||||
Modul-Metadaten laden … bitte Seite kurz offen lassen oder neu laden.
|
||||
</p>
|
||||
) : (
|
||||
<>
|
||||
<p style={{ fontSize: 13, color: 'var(--text2)', marginTop: 8, lineHeight: 1.55 }}>
|
||||
Mehrere CSV-Zeilen mit denselben Werten in den gewählten <strong>Schlüsselfeldern</strong> werden zu einer
|
||||
importierten Zeile zusammengefasst. Für alle übrigen zugewiesenen Zielfelder gilt{' '}
|
||||
<strong>eine gemeinsame</strong> Funktion. Textfelder werden bei Summe/Mittelwert usw. automatisch
|
||||
ausgelassen; mit „Erster/Letzter Wert“ sind sie enthalten.
|
||||
</p>
|
||||
<label
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'flex-start',
|
||||
gap: 10,
|
||||
marginTop: 14,
|
||||
cursor: 'pointer',
|
||||
fontSize: 14,
|
||||
color: 'var(--text1)',
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={rowAggUseCustom}
|
||||
onChange={(e) => {
|
||||
const on = e.target.checked
|
||||
setRowAggUseCustom(on)
|
||||
if (!on) {
|
||||
setRowAggIrregular(false)
|
||||
setRowAggGroupBy([])
|
||||
setRowAggMode('')
|
||||
setRowAggJsonText('{}')
|
||||
}
|
||||
}}
|
||||
style={{ marginTop: 3 }}
|
||||
/>
|
||||
<span>
|
||||
<strong>Eigene Aggregation in dieser Vorlage speichern.</strong> Wenn deaktiviert, gilt der{' '}
|
||||
<strong>Modul-Standard</strong> (siehe unten) bzw. kein Aggregat, wenn das Modul keinen definiert.
|
||||
</span>
|
||||
</label>
|
||||
{modMeta.import_row_processing_default && (
|
||||
<details style={{ marginTop: 12, fontSize: 13, color: 'var(--text2)' }}>
|
||||
<summary style={{ cursor: 'pointer' }}>Modul-Standard (Referenz, wenn Haken oben aus ist)</summary>
|
||||
<pre
|
||||
style={{
|
||||
marginTop: 8,
|
||||
padding: 12,
|
||||
background: 'var(--surface2)',
|
||||
borderRadius: 8,
|
||||
overflow: 'auto',
|
||||
fontSize: 12,
|
||||
textAlign: 'left',
|
||||
}}
|
||||
>
|
||||
{JSON.stringify(modMeta.import_row_processing_default, null, 2)}
|
||||
</pre>
|
||||
</details>
|
||||
)}
|
||||
{rowAggUseCustom && (
|
||||
<>
|
||||
{modMeta.import_row_processing_default && (
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-secondary"
|
||||
style={{ marginTop: 12 }}
|
||||
onClick={() => {
|
||||
const d = modMeta.import_row_processing_default
|
||||
const p = parseStoredImportRowProcessing(d)
|
||||
setRowAggIrregular(p.irregular)
|
||||
setRowAggGroupBy(p.groupBy)
|
||||
setRowAggMode(p.mode)
|
||||
setRowAggJsonText(JSON.stringify(d, null, 2))
|
||||
}}
|
||||
>
|
||||
Modul-Vorgabe übernehmen
|
||||
</button>
|
||||
)}
|
||||
{rowAggIrregular ? (
|
||||
<>
|
||||
<p style={{ fontSize: 13, color: 'var(--text2)', marginTop: 14, lineHeight: 1.55 }}>
|
||||
Diese Vorlage nutzt <strong>unterschiedliche</strong> Aggregations-Funktionen pro Feld. JSON
|
||||
anpassen oder vereinheitlichen (pro-Feld-Auswahl folgt in einer späteren Ausbaustufe).
|
||||
</p>
|
||||
<textarea
|
||||
className="form-input"
|
||||
style={{
|
||||
width: '100%',
|
||||
minHeight: 160,
|
||||
marginTop: 8,
|
||||
fontFamily: 'monospace',
|
||||
fontSize: 12,
|
||||
textAlign: 'left',
|
||||
}}
|
||||
value={rowAggJsonText}
|
||||
onChange={(e) => setRowAggJsonText(e.target.value)}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="form-label" style={{ marginTop: 16 }}>
|
||||
Schlüsselfelder (Mehrfachauswahl)
|
||||
</div>
|
||||
<p style={{ fontSize: 12, color: 'var(--text3)', marginTop: 6 }}>
|
||||
Nur bereits zugewiesene Zielfelder (Abschnitt 3).
|
||||
</p>
|
||||
{rowAggGroupCandidates.length === 0 ? (
|
||||
<p style={{ fontSize: 13, color: 'var(--text2)', marginTop: 8 }}>
|
||||
Noch keine Zielfelder zugewiesen — nach Zuweisung erscheinen die Schlüssel hier.
|
||||
</p>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
marginTop: 10,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 8,
|
||||
alignItems: 'flex-start',
|
||||
}}
|
||||
>
|
||||
{rowAggGroupCandidates.map((key) => (
|
||||
<label
|
||||
key={key}
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 8,
|
||||
cursor: 'pointer',
|
||||
fontSize: 14,
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={rowAggGroupBy.includes(key)}
|
||||
onChange={() => {
|
||||
setRowAggIrregular(false)
|
||||
setRowAggGroupBy((prev) =>
|
||||
prev.includes(key) ? prev.filter((x) => x !== key) : [...prev, key],
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<code>{key}</code>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<label className="form-label" style={{ marginTop: 16, display: 'block' }}>
|
||||
Funktion für alle übrigen Zielfelder
|
||||
</label>
|
||||
<select
|
||||
className="form-input"
|
||||
style={{
|
||||
width: '100%',
|
||||
maxWidth: 420,
|
||||
marginTop: 8,
|
||||
textAlign: 'left',
|
||||
minHeight: 46,
|
||||
}}
|
||||
value={rowAggMode}
|
||||
onChange={(e) => {
|
||||
setRowAggIrregular(false)
|
||||
setRowAggMode(e.target.value)
|
||||
}}
|
||||
>
|
||||
<option value="">— wählen —</option>
|
||||
{ROW_AGG_OPS.map((o) => (
|
||||
<option key={o.value} value={o.value}>
|
||||
{o.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{unitTargets.length > 0 && (
|
||||
<div className="card" style={{ padding: 16, marginBottom: 16 }}>
|
||||
<div className="form-label">3b. Quelleinheit (optional)</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user