feat: Enhance Admin Activity Attribute Profiles UI and styling
- Introduced a new layout for the Admin Activity Attribute Profiles page, improving the user interface with a dedicated class for styling. - Added new CSS styles for input fields, labels, and layout structures to enhance the visual presentation and usability of the attribute profiles. - Updated the form structure to include clearer labels and organization for input fields, ensuring better accessibility and user experience. - Improved responsiveness of the layout for mobile devices, ensuring a consistent experience across different screen sizes.
This commit is contained in:
parent
bc8e9fb7fa
commit
92e334dcd2
|
|
@ -440,6 +440,141 @@ a.analysis-split__nav-item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Admin: Session-Metriken / Attributprofile — volle Breite, linksbündig (nicht globale 90px-Zahlfelder) */
|
||||||
|
.activity-attribute-profiles .aaf-stack {
|
||||||
|
max-width: 42rem;
|
||||||
|
}
|
||||||
|
.activity-attribute-profiles .aaf-field {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
.activity-attribute-profiles .aaf-label {
|
||||||
|
display: block;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text1);
|
||||||
|
text-align: left;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
line-height: 1.35;
|
||||||
|
}
|
||||||
|
.activity-attribute-profiles .aaf-sublabel {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text2);
|
||||||
|
text-align: left;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
.activity-attribute-profiles .aaf-hint {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text3);
|
||||||
|
text-align: left;
|
||||||
|
margin: 6px 0 0;
|
||||||
|
line-height: 1.45;
|
||||||
|
}
|
||||||
|
.activity-attribute-profiles .aaf-input,
|
||||||
|
.activity-attribute-profiles textarea.aaf-input {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 10px 12px;
|
||||||
|
text-align: left;
|
||||||
|
font-family: var(--font);
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--text1);
|
||||||
|
background: var(--surface2);
|
||||||
|
border: 1.5px solid var(--border2);
|
||||||
|
border-radius: 8px;
|
||||||
|
transition: border-color 0.15s;
|
||||||
|
}
|
||||||
|
.activity-attribute-profiles textarea.aaf-input {
|
||||||
|
resize: vertical;
|
||||||
|
min-height: 4.5rem;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
.activity-attribute-profiles .aaf-input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--accent);
|
||||||
|
}
|
||||||
|
.activity-attribute-profiles .aaf-split {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
@media (max-width: 560px) {
|
||||||
|
.activity-attribute-profiles .aaf-split {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.activity-attribute-profiles .aaf-field-select {
|
||||||
|
padding: 12px 0;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
.activity-attribute-profiles .aaf-field-select:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
.activity-attribute-profiles .aaf-field-select .form-label {
|
||||||
|
display: block;
|
||||||
|
text-align: left;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
font-weight: 600;
|
||||||
|
flex: unset;
|
||||||
|
}
|
||||||
|
.activity-attribute-profiles .aaf-field-select .form-input,
|
||||||
|
.activity-attribute-profiles .aaf-field-select select.form-input {
|
||||||
|
width: 100%;
|
||||||
|
max-width: none;
|
||||||
|
min-width: 0;
|
||||||
|
text-align: left;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 10px 12px;
|
||||||
|
}
|
||||||
|
.activity-attribute-profiles .aaf-toolbar {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: flex-end;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 12px 0;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
.activity-attribute-profiles .aaf-toolbar .form-label {
|
||||||
|
display: block;
|
||||||
|
text-align: left;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
font-weight: 600;
|
||||||
|
flex: unset;
|
||||||
|
}
|
||||||
|
.activity-attribute-profiles .aaf-toolbar__grow {
|
||||||
|
flex: 1 1 240px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.activity-attribute-profiles .aaf-toolbar .form-input,
|
||||||
|
.activity-attribute-profiles .aaf-toolbar select.form-input {
|
||||||
|
width: 100%;
|
||||||
|
min-width: 140px;
|
||||||
|
max-width: none;
|
||||||
|
text-align: left;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 10px 12px;
|
||||||
|
}
|
||||||
|
.activity-attribute-profiles .aaf-toolbar__compact {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
.activity-attribute-profiles .aaf-toolbar__compact .form-input,
|
||||||
|
.activity-attribute-profiles .aaf-toolbar__compact select.form-input {
|
||||||
|
width: 100%;
|
||||||
|
min-width: 5rem;
|
||||||
|
}
|
||||||
|
.activity-attribute-profiles .aaf-inline-edit .form-input,
|
||||||
|
.activity-attribute-profiles .aaf-inline-edit select.form-input {
|
||||||
|
text-align: left;
|
||||||
|
min-width: 4.5rem;
|
||||||
|
width: auto;
|
||||||
|
max-width: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 8px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Erfassung: Sub-Navigation (Mobil = Chips, Desktop = linke Spalte) */
|
/* Erfassung: Sub-Navigation (Mobil = Chips, Desktop = linke Spalte) */
|
||||||
.capture-shell {
|
.capture-shell {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
||||||
|
|
@ -279,7 +279,7 @@ export default function AdminActivityAttributeProfilesPage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="capture-page">
|
<div className="capture-page activity-attribute-profiles">
|
||||||
<div style={{ marginBottom: 12 }}>
|
<div style={{ marginBottom: 12 }}>
|
||||||
<Link to="/admin/g/training" className="text-link" style={{ fontSize: 13 }}>
|
<Link to="/admin/g/training" className="text-link" style={{ fontSize: 13 }}>
|
||||||
← Training (Hub)
|
← Training (Hub)
|
||||||
|
|
@ -378,87 +378,151 @@ export default function AdminActivityAttributeProfilesPage() {
|
||||||
style={{
|
style={{
|
||||||
border: '1px solid var(--border)',
|
border: '1px solid var(--border)',
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
padding: 12,
|
padding: 16,
|
||||||
marginBottom: 12,
|
marginBottom: 12,
|
||||||
background: 'var(--surface2)',
|
background: 'var(--surface2)',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="form-row">
|
<div className="aaf-stack">
|
||||||
<label className="form-label">key</label>
|
<div className="aaf-field">
|
||||||
<input
|
<label className="aaf-label" htmlFor="aaf-new-key">
|
||||||
className="form-input"
|
Technischer Schlüssel (key)
|
||||||
placeholder="z. B. avg_power"
|
</label>
|
||||||
value={paramForm.key}
|
<input
|
||||||
onChange={(e) => setParamForm((f) => ({ ...f, key: e.target.value }))}
|
id="aaf-new-key"
|
||||||
/>
|
className="aaf-input"
|
||||||
</div>
|
placeholder="z. B. avg_power"
|
||||||
<div className="form-row">
|
value={paramForm.key}
|
||||||
<label className="form-label">name_de / name_en</label>
|
onChange={(e) => setParamForm((f) => ({ ...f, key: e.target.value }))}
|
||||||
<input
|
/>
|
||||||
className="form-input"
|
</div>
|
||||||
value={paramForm.name_de}
|
<div className="aaf-field">
|
||||||
onChange={(e) => setParamForm((f) => ({ ...f, name_de: e.target.value }))}
|
<span className="aaf-label">Bezeichnung</span>
|
||||||
/>
|
<div className="aaf-split">
|
||||||
<input
|
<div>
|
||||||
className="form-input"
|
<label className="aaf-sublabel" htmlFor="aaf-new-name-de">
|
||||||
value={paramForm.name_en}
|
Deutsch
|
||||||
onChange={(e) => setParamForm((f) => ({ ...f, name_en: e.target.value }))}
|
</label>
|
||||||
/>
|
<input
|
||||||
</div>
|
id="aaf-new-name-de"
|
||||||
<div className="form-row">
|
className="aaf-input"
|
||||||
<label className="form-label">Beschreibung DE / EN (optional, für KI)</label>
|
value={paramForm.name_de}
|
||||||
<textarea
|
onChange={(e) => setParamForm((f) => ({ ...f, name_de: e.target.value }))}
|
||||||
className="form-input"
|
/>
|
||||||
rows={2}
|
</div>
|
||||||
placeholder="Was bedeutet der Wert? Einheit/Skala?"
|
<div>
|
||||||
value={paramForm.description_de}
|
<label className="aaf-sublabel" htmlFor="aaf-new-name-en">
|
||||||
onChange={(e) => setParamForm((f) => ({ ...f, description_de: e.target.value }))}
|
English
|
||||||
/>
|
</label>
|
||||||
<textarea
|
<input
|
||||||
className="form-input"
|
id="aaf-new-name-en"
|
||||||
rows={2}
|
className="aaf-input"
|
||||||
placeholder="Short meaning for prompts / EN users"
|
value={paramForm.name_en}
|
||||||
value={paramForm.description_en}
|
onChange={(e) => setParamForm((f) => ({ ...f, name_en: e.target.value }))}
|
||||||
onChange={(e) => setParamForm((f) => ({ ...f, description_en: e.target.value }))}
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="form-row">
|
</div>
|
||||||
<label className="form-label">Gruppe / Datentyp</label>
|
<div className="aaf-field">
|
||||||
<select
|
<span className="aaf-label">Beschreibung (optional, für KI / Export)</span>
|
||||||
className="form-input"
|
<div className="aaf-split">
|
||||||
value={paramForm.category}
|
<div>
|
||||||
onChange={(e) => setParamForm((f) => ({ ...f, category: e.target.value }))}
|
<label className="aaf-sublabel" htmlFor="aaf-new-desc-de">
|
||||||
>
|
Deutsch
|
||||||
{PARAM_GROUP.map((c) => (
|
</label>
|
||||||
<option key={c} value={c}>
|
<textarea
|
||||||
{c}
|
id="aaf-new-desc-de"
|
||||||
</option>
|
className="aaf-input"
|
||||||
))}
|
rows={3}
|
||||||
</select>
|
placeholder="Was bedeutet der Wert? Einheit, Skala, Herkunft …"
|
||||||
<select
|
value={paramForm.description_de}
|
||||||
className="form-input"
|
onChange={(e) => setParamForm((f) => ({ ...f, description_de: e.target.value }))}
|
||||||
value={paramForm.data_type}
|
/>
|
||||||
onChange={(e) => setParamForm((f) => ({ ...f, data_type: e.target.value }))}
|
</div>
|
||||||
>
|
<div>
|
||||||
{DATA_TYPES.map((c) => (
|
<label className="aaf-sublabel" htmlFor="aaf-new-desc-en">
|
||||||
<option key={c} value={c}>
|
English
|
||||||
{c}
|
</label>
|
||||||
</option>
|
<textarea
|
||||||
))}
|
id="aaf-new-desc-en"
|
||||||
</select>
|
className="aaf-input"
|
||||||
</div>
|
rows={3}
|
||||||
<div className="form-row">
|
placeholder="Short meaning for prompts and EN contexts"
|
||||||
<label className="form-label">Einheit / source_field</label>
|
value={paramForm.description_en}
|
||||||
<input
|
onChange={(e) => setParamForm((f) => ({ ...f, description_en: e.target.value }))}
|
||||||
className="form-input"
|
/>
|
||||||
value={paramForm.unit}
|
</div>
|
||||||
onChange={(e) => setParamForm((f) => ({ ...f, unit: e.target.value }))}
|
</div>
|
||||||
/>
|
</div>
|
||||||
<input
|
<div className="aaf-field">
|
||||||
className="form-input"
|
<span className="aaf-label">Gruppe und Datentyp</span>
|
||||||
value={paramForm.source_field}
|
<div className="aaf-split">
|
||||||
onChange={(e) => setParamForm((f) => ({ ...f, source_field: e.target.value }))}
|
<div>
|
||||||
/>
|
<label className="aaf-sublabel" htmlFor="aaf-new-cat">
|
||||||
|
Parameter-Gruppe
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
id="aaf-new-cat"
|
||||||
|
className="aaf-input"
|
||||||
|
value={paramForm.category}
|
||||||
|
onChange={(e) => setParamForm((f) => ({ ...f, category: e.target.value }))}
|
||||||
|
>
|
||||||
|
{PARAM_GROUP.map((c) => (
|
||||||
|
<option key={c} value={c}>
|
||||||
|
{c}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="aaf-sublabel" htmlFor="aaf-new-dtype">
|
||||||
|
Datentyp
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
id="aaf-new-dtype"
|
||||||
|
className="aaf-input"
|
||||||
|
value={paramForm.data_type}
|
||||||
|
onChange={(e) => setParamForm((f) => ({ ...f, data_type: e.target.value }))}
|
||||||
|
>
|
||||||
|
{DATA_TYPES.map((c) => (
|
||||||
|
<option key={c} value={c}>
|
||||||
|
{c}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="aaf-field">
|
||||||
|
<label className="aaf-label" htmlFor="aaf-new-unit">
|
||||||
|
Einheit (optional)
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="aaf-new-unit"
|
||||||
|
className="aaf-input"
|
||||||
|
placeholder="z. B. W, bpm, min"
|
||||||
|
value={paramForm.unit}
|
||||||
|
onChange={(e) => setParamForm((f) => ({ ...f, unit: e.target.value }))}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="aaf-field">
|
||||||
|
<label className="aaf-label" htmlFor="aaf-new-source-field">
|
||||||
|
Quell-Spalte in activity_log (source_field, optional)
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="aaf-new-source-field"
|
||||||
|
className="aaf-input"
|
||||||
|
placeholder="z. B. hr_avg — Spaltenname der Trainingseinheit"
|
||||||
|
autoComplete="off"
|
||||||
|
value={paramForm.source_field}
|
||||||
|
onChange={(e) => setParamForm((f) => ({ ...f, source_field: e.target.value }))}
|
||||||
|
/>
|
||||||
|
<p className="aaf-hint">
|
||||||
|
Wenn gesetzt, wird der Messwert beim Anzeigen und Zusammenführen mit EAV primär aus dieser
|
||||||
|
Spalte der Einheit gelesen (nicht aus der EAV-Tabelle). Leer lassen, wenn der Wert nur über
|
||||||
|
EAV oder Standard-Spalten kommt.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: 'flex', gap: 8, marginTop: 8 }}>
|
<div style={{ display: 'flex', gap: 8, marginTop: 8 }}>
|
||||||
<button type="button" className="btn btn-primary" onClick={saveNewParameter}>
|
<button type="button" className="btn btn-primary" onClick={saveNewParameter}>
|
||||||
|
|
@ -476,78 +540,138 @@ export default function AdminActivityAttributeProfilesPage() {
|
||||||
style={{
|
style={{
|
||||||
border: '1px solid var(--accent)',
|
border: '1px solid var(--accent)',
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
padding: 12,
|
padding: 16,
|
||||||
marginBottom: 12,
|
marginBottom: 12,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="card-title" style={{ fontSize: 14 }}>
|
<div className="card-title" style={{ fontSize: 14 }}>
|
||||||
Bearbeiten: <code>{editParam.key}</code>
|
Bearbeiten: <code>{editParam.key}</code>
|
||||||
</div>
|
</div>
|
||||||
<div className="form-row">
|
<div className="aaf-stack">
|
||||||
<label className="form-label">name_de / name_en</label>
|
<div className="aaf-field">
|
||||||
<input
|
<span className="aaf-label">Bezeichnung</span>
|
||||||
className="form-input"
|
<div className="aaf-split">
|
||||||
value={editParam.name_de || ''}
|
<div>
|
||||||
onChange={(e) => setEditParam((p) => ({ ...p, name_de: e.target.value }))}
|
<label className="aaf-sublabel" htmlFor="aaf-edit-name-de">
|
||||||
/>
|
Deutsch
|
||||||
<input
|
</label>
|
||||||
className="form-input"
|
<input
|
||||||
value={editParam.name_en || ''}
|
id="aaf-edit-name-de"
|
||||||
onChange={(e) => setEditParam((p) => ({ ...p, name_en: e.target.value }))}
|
className="aaf-input"
|
||||||
/>
|
value={editParam.name_de || ''}
|
||||||
</div>
|
onChange={(e) => setEditParam((p) => ({ ...p, name_de: e.target.value }))}
|
||||||
<div className="form-row">
|
/>
|
||||||
<label className="form-label">Beschreibung DE / EN (optional, für KI)</label>
|
</div>
|
||||||
<textarea
|
<div>
|
||||||
className="form-input"
|
<label className="aaf-sublabel" htmlFor="aaf-edit-name-en">
|
||||||
rows={2}
|
English
|
||||||
value={editParam.description_de || ''}
|
</label>
|
||||||
onChange={(e) => setEditParam((p) => ({ ...p, description_de: e.target.value }))}
|
<input
|
||||||
/>
|
id="aaf-edit-name-en"
|
||||||
<textarea
|
className="aaf-input"
|
||||||
className="form-input"
|
value={editParam.name_en || ''}
|
||||||
rows={2}
|
onChange={(e) => setEditParam((p) => ({ ...p, name_en: e.target.value }))}
|
||||||
value={editParam.description_en || ''}
|
/>
|
||||||
onChange={(e) => setEditParam((p) => ({ ...p, description_en: e.target.value }))}
|
</div>
|
||||||
/>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="form-row">
|
<div className="aaf-field">
|
||||||
<label className="form-label">Gruppe / Typ</label>
|
<span className="aaf-label">Beschreibung (optional, für KI / Export)</span>
|
||||||
<select
|
<div className="aaf-split">
|
||||||
className="form-input"
|
<div>
|
||||||
value={editParam.category}
|
<label className="aaf-sublabel" htmlFor="aaf-edit-desc-de">
|
||||||
onChange={(e) => setEditParam((p) => ({ ...p, category: e.target.value }))}
|
Deutsch
|
||||||
>
|
</label>
|
||||||
{PARAM_GROUP.map((c) => (
|
<textarea
|
||||||
<option key={c} value={c}>
|
id="aaf-edit-desc-de"
|
||||||
{c}
|
className="aaf-input"
|
||||||
</option>
|
rows={3}
|
||||||
))}
|
value={editParam.description_de || ''}
|
||||||
</select>
|
onChange={(e) => setEditParam((p) => ({ ...p, description_de: e.target.value }))}
|
||||||
<select
|
/>
|
||||||
className="form-input"
|
</div>
|
||||||
value={editParam.data_type}
|
<div>
|
||||||
onChange={(e) => setEditParam((p) => ({ ...p, data_type: e.target.value }))}
|
<label className="aaf-sublabel" htmlFor="aaf-edit-desc-en">
|
||||||
>
|
English
|
||||||
{DATA_TYPES.map((c) => (
|
</label>
|
||||||
<option key={c} value={c}>
|
<textarea
|
||||||
{c}
|
id="aaf-edit-desc-en"
|
||||||
</option>
|
className="aaf-input"
|
||||||
))}
|
rows={3}
|
||||||
</select>
|
value={editParam.description_en || ''}
|
||||||
</div>
|
onChange={(e) => setEditParam((p) => ({ ...p, description_en: e.target.value }))}
|
||||||
<div className="form-row">
|
/>
|
||||||
<label className="form-label">Einheit / source_field</label>
|
</div>
|
||||||
<input
|
</div>
|
||||||
className="form-input"
|
</div>
|
||||||
value={editParam.unit || ''}
|
<div className="aaf-field">
|
||||||
onChange={(e) => setEditParam((p) => ({ ...p, unit: e.target.value }))}
|
<span className="aaf-label">Gruppe und Datentyp</span>
|
||||||
/>
|
<div className="aaf-split">
|
||||||
<input
|
<div>
|
||||||
className="form-input"
|
<label className="aaf-sublabel" htmlFor="aaf-edit-cat">
|
||||||
value={editParam.source_field || ''}
|
Parameter-Gruppe
|
||||||
onChange={(e) => setEditParam((p) => ({ ...p, source_field: e.target.value }))}
|
</label>
|
||||||
/>
|
<select
|
||||||
|
id="aaf-edit-cat"
|
||||||
|
className="aaf-input"
|
||||||
|
value={editParam.category}
|
||||||
|
onChange={(e) => setEditParam((p) => ({ ...p, category: e.target.value }))}
|
||||||
|
>
|
||||||
|
{PARAM_GROUP.map((c) => (
|
||||||
|
<option key={c} value={c}>
|
||||||
|
{c}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="aaf-sublabel" htmlFor="aaf-edit-dtype">
|
||||||
|
Datentyp
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
id="aaf-edit-dtype"
|
||||||
|
className="aaf-input"
|
||||||
|
value={editParam.data_type}
|
||||||
|
onChange={(e) => setEditParam((p) => ({ ...p, data_type: e.target.value }))}
|
||||||
|
>
|
||||||
|
{DATA_TYPES.map((c) => (
|
||||||
|
<option key={c} value={c}>
|
||||||
|
{c}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="aaf-field">
|
||||||
|
<label className="aaf-label" htmlFor="aaf-edit-unit">
|
||||||
|
Einheit (optional)
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="aaf-edit-unit"
|
||||||
|
className="aaf-input"
|
||||||
|
placeholder="z. B. W, bpm, min"
|
||||||
|
value={editParam.unit || ''}
|
||||||
|
onChange={(e) => setEditParam((p) => ({ ...p, unit: e.target.value }))}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="aaf-field">
|
||||||
|
<label className="aaf-label" htmlFor="aaf-edit-source-field">
|
||||||
|
Quell-Spalte in activity_log (source_field, optional)
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="aaf-edit-source-field"
|
||||||
|
className="aaf-input"
|
||||||
|
placeholder="z. B. hr_avg"
|
||||||
|
autoComplete="off"
|
||||||
|
value={editParam.source_field || ''}
|
||||||
|
onChange={(e) => setEditParam((p) => ({ ...p, source_field: e.target.value }))}
|
||||||
|
/>
|
||||||
|
<p className="aaf-hint">
|
||||||
|
Optional: Name der <code>activity_log</code>-Spalte, aus der dieser Parameter beim Lesen zuerst
|
||||||
|
befüllt wird (kanonisch vor EAV). Leer, wenn nur EAV oder implizites Spalten-Mapping.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<label style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13, marginBottom: 8 }}>
|
<label style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13, marginBottom: 8 }}>
|
||||||
<input
|
<input
|
||||||
|
|
@ -625,13 +749,15 @@ export default function AdminActivityAttributeProfilesPage() {
|
||||||
{tab === 'category' && (
|
{tab === 'category' && (
|
||||||
<div className="card section-gap">
|
<div className="card section-gap">
|
||||||
<div className="card-title">Zuordnung: Trainings-Kategorie</div>
|
<div className="card-title">Zuordnung: Trainings-Kategorie</div>
|
||||||
<div className="form-row">
|
<div className="aaf-field-select">
|
||||||
<label className="form-label">Kategorie</label>
|
<label className="form-label" htmlFor="aaf-cat-pick">
|
||||||
|
Kategorie
|
||||||
|
</label>
|
||||||
<select
|
<select
|
||||||
|
id="aaf-cat-pick"
|
||||||
className="form-input"
|
className="form-input"
|
||||||
value={selCategory}
|
value={selCategory}
|
||||||
onChange={(e) => setSelCategory(e.target.value)}
|
onChange={(e) => setSelCategory(e.target.value)}
|
||||||
style={{ maxWidth: 280 }}
|
|
||||||
>
|
>
|
||||||
{categoryKeys.map((k) => (
|
{categoryKeys.map((k) => (
|
||||||
<option key={k} value={k}>
|
<option key={k} value={k}>
|
||||||
|
|
@ -640,10 +766,13 @@ export default function AdminActivityAttributeProfilesPage() {
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div className="form-row" style={{ alignItems: 'flex-end', flexWrap: 'wrap', gap: 8 }}>
|
<div className="aaf-toolbar">
|
||||||
<div style={{ flex: 1, minWidth: 200 }}>
|
<div className="aaf-toolbar__grow">
|
||||||
<label className="form-label">Parameter</label>
|
<label className="form-label" htmlFor="aaf-cat-param">
|
||||||
|
Parameter
|
||||||
|
</label>
|
||||||
<select
|
<select
|
||||||
|
id="aaf-cat-param"
|
||||||
className="form-input"
|
className="form-input"
|
||||||
value={catAdd.training_parameter_id}
|
value={catAdd.training_parameter_id}
|
||||||
onChange={(e) => setCatAdd((a) => ({ ...a, training_parameter_id: e.target.value }))}
|
onChange={(e) => setCatAdd((a) => ({ ...a, training_parameter_id: e.target.value }))}
|
||||||
|
|
@ -656,17 +785,22 @@ export default function AdminActivityAttributeProfilesPage() {
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="aaf-toolbar__compact">
|
||||||
<label className="form-label">sort</label>
|
<label className="form-label" htmlFor="aaf-cat-sort">
|
||||||
|
Sortierung
|
||||||
|
</label>
|
||||||
<input
|
<input
|
||||||
|
id="aaf-cat-sort"
|
||||||
type="number"
|
type="number"
|
||||||
className="form-input"
|
className="form-input"
|
||||||
style={{ width: 80 }}
|
|
||||||
value={catAdd.sort_order}
|
value={catAdd.sort_order}
|
||||||
onChange={(e) => setCatAdd((a) => ({ ...a, sort_order: e.target.value }))}
|
onChange={(e) => setCatAdd((a) => ({ ...a, sort_order: e.target.value }))}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<label style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 13 }}>
|
<label
|
||||||
|
className="aaf-toolbar__compact"
|
||||||
|
style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 14, paddingBottom: 4 }}
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={catAdd.required}
|
checked={catAdd.required}
|
||||||
|
|
@ -674,11 +808,14 @@ export default function AdminActivityAttributeProfilesPage() {
|
||||||
/>
|
/>
|
||||||
Pflicht
|
Pflicht
|
||||||
</label>
|
</label>
|
||||||
<div>
|
<div className="aaf-toolbar__compact">
|
||||||
<label className="form-label">ui_group</label>
|
<label className="form-label" htmlFor="aaf-cat-uigroup">
|
||||||
|
ui_group
|
||||||
|
</label>
|
||||||
<input
|
<input
|
||||||
|
id="aaf-cat-uigroup"
|
||||||
className="form-input"
|
className="form-input"
|
||||||
style={{ width: 120 }}
|
placeholder="optional"
|
||||||
value={catAdd.ui_group}
|
value={catAdd.ui_group}
|
||||||
onChange={(e) => setCatAdd((a) => ({ ...a, ui_group: e.target.value }))}
|
onChange={(e) => setCatAdd((a) => ({ ...a, ui_group: e.target.value }))}
|
||||||
/>
|
/>
|
||||||
|
|
@ -698,21 +835,20 @@ export default function AdminActivityAttributeProfilesPage() {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{editingCatId === l.id ? (
|
{editingCatId === l.id ? (
|
||||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 8, alignItems: 'flex-end' }}>
|
<div className="aaf-inline-edit" style={{ display: 'flex', flexWrap: 'wrap', gap: 10, alignItems: 'flex-end' }}>
|
||||||
<span style={{ flex: '1 1 200px' }}>
|
<span style={{ flex: '1 1 200px' }}>
|
||||||
<strong>{l.parameter_key}</strong> · {l.parameter_name_de}
|
<strong>{l.parameter_key}</strong> · {l.parameter_name_de}
|
||||||
</span>
|
</span>
|
||||||
<div>
|
<div>
|
||||||
<label className="form-label">sort</label>
|
<label className="form-label">Sortierung</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
className="form-input"
|
className="form-input"
|
||||||
style={{ width: 72 }}
|
|
||||||
value={catDraft.sort_order}
|
value={catDraft.sort_order}
|
||||||
onChange={(e) => setCatDraft((d) => ({ ...d, sort_order: e.target.value }))}
|
onChange={(e) => setCatDraft((d) => ({ ...d, sort_order: e.target.value }))}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<label style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
<label style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 14, paddingBottom: 4 }}>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={!!catDraft.required}
|
checked={!!catDraft.required}
|
||||||
|
|
@ -722,7 +858,6 @@ export default function AdminActivityAttributeProfilesPage() {
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
className="form-input"
|
className="form-input"
|
||||||
style={{ width: 100 }}
|
|
||||||
placeholder="ui_group"
|
placeholder="ui_group"
|
||||||
value={catDraft.ui_group}
|
value={catDraft.ui_group}
|
||||||
onChange={(e) => setCatDraft((d) => ({ ...d, ui_group: e.target.value }))}
|
onChange={(e) => setCatDraft((d) => ({ ...d, ui_group: e.target.value }))}
|
||||||
|
|
@ -782,13 +917,15 @@ export default function AdminActivityAttributeProfilesPage() {
|
||||||
{tab === 'type' && (
|
{tab === 'type' && (
|
||||||
<div className="card section-gap">
|
<div className="card section-gap">
|
||||||
<div className="card-title">Zuordnung: Trainingstyp (Zusatz / Override)</div>
|
<div className="card-title">Zuordnung: Trainingstyp (Zusatz / Override)</div>
|
||||||
<div className="form-row">
|
<div className="aaf-field-select">
|
||||||
<label className="form-label">Trainingstyp</label>
|
<label className="form-label" htmlFor="aaf-type-pick">
|
||||||
|
Trainingstyp
|
||||||
|
</label>
|
||||||
<select
|
<select
|
||||||
|
id="aaf-type-pick"
|
||||||
className="form-input"
|
className="form-input"
|
||||||
value={selTypeId}
|
value={selTypeId}
|
||||||
onChange={(e) => setSelTypeId(e.target.value)}
|
onChange={(e) => setSelTypeId(e.target.value)}
|
||||||
style={{ maxWidth: 420 }}
|
|
||||||
>
|
>
|
||||||
{flatTypes.map((t) => (
|
{flatTypes.map((t) => (
|
||||||
<option key={t.id} value={t.id}>
|
<option key={t.id} value={t.id}>
|
||||||
|
|
@ -797,10 +934,13 @@ export default function AdminActivityAttributeProfilesPage() {
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div className="form-row" style={{ alignItems: 'flex-end', flexWrap: 'wrap', gap: 8 }}>
|
<div className="aaf-toolbar">
|
||||||
<div style={{ flex: 1, minWidth: 200 }}>
|
<div className="aaf-toolbar__grow">
|
||||||
<label className="form-label">Parameter</label>
|
<label className="form-label" htmlFor="aaf-type-param">
|
||||||
|
Parameter
|
||||||
|
</label>
|
||||||
<select
|
<select
|
||||||
|
id="aaf-type-param"
|
||||||
className="form-input"
|
className="form-input"
|
||||||
value={typeAdd.training_parameter_id}
|
value={typeAdd.training_parameter_id}
|
||||||
onChange={(e) => setTypeAdd((a) => ({ ...a, training_parameter_id: e.target.value }))}
|
onChange={(e) => setTypeAdd((a) => ({ ...a, training_parameter_id: e.target.value }))}
|
||||||
|
|
@ -813,21 +953,25 @@ export default function AdminActivityAttributeProfilesPage() {
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="aaf-toolbar__compact">
|
||||||
<label className="form-label">sort (leer=Erben)</label>
|
<label className="form-label" htmlFor="aaf-type-sort">
|
||||||
|
Sortierung (leer = erben)
|
||||||
|
</label>
|
||||||
<input
|
<input
|
||||||
|
id="aaf-type-sort"
|
||||||
type="number"
|
type="number"
|
||||||
className="form-input"
|
className="form-input"
|
||||||
style={{ width: 80 }}
|
|
||||||
value={typeAdd.sort_order}
|
value={typeAdd.sort_order}
|
||||||
onChange={(e) => setTypeAdd((a) => ({ ...a, sort_order: e.target.value }))}
|
onChange={(e) => setTypeAdd((a) => ({ ...a, sort_order: e.target.value }))}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="aaf-toolbar__compact">
|
||||||
<label className="form-label">Pflicht (leer=Erben)</label>
|
<label className="form-label" htmlFor="aaf-type-req">
|
||||||
|
Pflicht (leer = erben)
|
||||||
|
</label>
|
||||||
<select
|
<select
|
||||||
|
id="aaf-type-req"
|
||||||
className="form-input"
|
className="form-input"
|
||||||
style={{ width: 100 }}
|
|
||||||
value={typeAdd.required}
|
value={typeAdd.required}
|
||||||
onChange={(e) => setTypeAdd((a) => ({ ...a, required: e.target.value }))}
|
onChange={(e) => setTypeAdd((a) => ({ ...a, required: e.target.value }))}
|
||||||
>
|
>
|
||||||
|
|
@ -836,11 +980,14 @@ export default function AdminActivityAttributeProfilesPage() {
|
||||||
<option value="false">nein</option>
|
<option value="false">nein</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="aaf-toolbar__compact">
|
||||||
<label className="form-label">ui_group</label>
|
<label className="form-label" htmlFor="aaf-type-uigroup">
|
||||||
|
ui_group
|
||||||
|
</label>
|
||||||
<input
|
<input
|
||||||
|
id="aaf-type-uigroup"
|
||||||
className="form-input"
|
className="form-input"
|
||||||
style={{ width: 120 }}
|
placeholder="optional"
|
||||||
value={typeAdd.ui_group}
|
value={typeAdd.ui_group}
|
||||||
onChange={(e) => setTypeAdd((a) => ({ ...a, ui_group: e.target.value }))}
|
onChange={(e) => setTypeAdd((a) => ({ ...a, ui_group: e.target.value }))}
|
||||||
/>
|
/>
|
||||||
|
|
@ -860,23 +1007,21 @@ export default function AdminActivityAttributeProfilesPage() {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{editingTypeId === l.id ? (
|
{editingTypeId === l.id ? (
|
||||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 8, alignItems: 'flex-end' }}>
|
<div className="aaf-inline-edit" style={{ display: 'flex', flexWrap: 'wrap', gap: 10, alignItems: 'flex-end' }}>
|
||||||
<span style={{ flex: '1 1 200px' }}>
|
<span style={{ flex: '1 1 200px' }}>
|
||||||
<strong>{l.parameter_key}</strong>
|
<strong>{l.parameter_key}</strong>
|
||||||
</span>
|
</span>
|
||||||
<div>
|
<div>
|
||||||
<label className="form-label">sort</label>
|
<label className="form-label">Sortierung</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
className="form-input"
|
className="form-input"
|
||||||
style={{ width: 72 }}
|
|
||||||
value={typeDraft.sort_order}
|
value={typeDraft.sort_order}
|
||||||
onChange={(e) => setTypeDraft((d) => ({ ...d, sort_order: e.target.value }))}
|
onChange={(e) => setTypeDraft((d) => ({ ...d, sort_order: e.target.value }))}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<select
|
<select
|
||||||
className="form-input"
|
className="form-input"
|
||||||
style={{ width: 100 }}
|
|
||||||
value={typeDraft.required}
|
value={typeDraft.required}
|
||||||
onChange={(e) => setTypeDraft((d) => ({ ...d, required: e.target.value }))}
|
onChange={(e) => setTypeDraft((d) => ({ ...d, required: e.target.value }))}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user