fix(P-13): leserliche Journals, readOnly-Felder, Meldungs-Badge auf Medienkacheln
Some checks failed
Deploy Development / deploy (push) Successful in 37s
Test Suite / pytest-backend (push) Failing after 36s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 10s
Test Suite / playwright-tests (push) Successful in 56s
Some checks failed
Deploy Development / deploy (push) Successful in 37s
Test Suite / pytest-backend (push) Failing after 36s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 10s
Test Suite / playwright-tests (push) Successful in 56s
- ReportContentModal: Name/E-Mail readOnly fuer eingeloggte Nutzer - MediaLibraryPage: content_report_filed im Journal leserlich (Meldegrund, Prioritaet, Status DE) - MediaLibraryPage: Badge auf Medienkacheln zeigt offene Meldungsanzahl (nur Admins) - media_assets.py: open_report_count Subquery fuer Admin-Sicht in Listendaten - Inbox-500-Fix: ma.media_kind -> ma.mime_type (alle 3 Stellen) - PATCH content_reports: Statuswechsel wird in Audit-Log protokolliert - E-Mails: Dateiname statt Medium-ID, lesbarer Inhalt version: 0.8.91 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
8dd748e7d9
commit
bb4d927090
|
|
@ -341,32 +341,33 @@ def _notify_report_submitted(
|
||||||
priority: str,
|
priority: str,
|
||||||
target_type: str,
|
target_type: str,
|
||||||
target_id: int,
|
target_id: int,
|
||||||
|
target_label: str,
|
||||||
admin_emails: list[str],
|
admin_emails: list[str],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Sendet Bestaetigungs-Mail an Melder + Benachrichtigung an alle Plattform-Admins (best-effort)."""
|
"""Sendet Bestaetigungs-Mail an Melder + Benachrichtigung an alle Plattform-Admins (best-effort)."""
|
||||||
app_url = (os.getenv("APP_URL") or "https://shinkan.jinkendo.de").rstrip("/")
|
app_url = (os.getenv("APP_URL") or "https://shinkan.jinkendo.de").rstrip("/")
|
||||||
reason_label = REASON_LABELS_DE.get(reason, reason)
|
reason_label = REASON_LABELS_DE.get(reason, reason)
|
||||||
target_label = ("Medium" if target_type == "media_asset" else "Übung") + f" #{target_id}"
|
prio_label = "DRINGEND" if priority == "high" else "normal"
|
||||||
|
|
||||||
# Bestaetigungs-Mail an Melder
|
# Bestaetigungs-Mail an Melder
|
||||||
confirmation_body = (
|
confirmation_body = (
|
||||||
f"Hallo {reporter_name},\n\n"
|
f"Hallo {reporter_name},\n\n"
|
||||||
f"Ihre Meldung (#{report_id}) wurde entgegengenommen.\n\n"
|
f"Ihre Meldung (#{report_id}) wurde entgegengenommen.\n\n"
|
||||||
f"Meldegrund: {reason_label}\n"
|
f"Meldegrund: {reason_label}\n"
|
||||||
f"Gemeldeter Inhalt: {target_label}\n\n"
|
f"Gemeldeter Inhalt: {target_label}\n\n"
|
||||||
f"Ein Administrator wird Ihre Meldung zeitnah prüfen.\n\n"
|
f"Ein Administrator wird Ihre Meldung zeitnah prüfen. Sie müssen nichts weiter tun.\n\n"
|
||||||
f"Shinkan Jinkendo"
|
f"Shinkan Jinkendo\n"
|
||||||
|
f"{app_url}"
|
||||||
)
|
)
|
||||||
_send_email(reporter_email, f"Meldung #{report_id} eingegangen – Shinkan Jinkendo", confirmation_body)
|
_send_email(reporter_email, f"Meldung #{report_id} eingegangen – Shinkan Jinkendo", confirmation_body)
|
||||||
|
|
||||||
# Admin-Benachrichtigung
|
# Admin-Benachrichtigung
|
||||||
prio_label = "DRINGEND" if priority == "high" else "normal"
|
|
||||||
admin_body = (
|
admin_body = (
|
||||||
f"Neue Inhaltsmeldung #{report_id} [{prio_label}]\n\n"
|
f"Neue Inhaltsmeldung #{report_id} [{prio_label}]\n\n"
|
||||||
f"Meldegrund: {reason_label}\n"
|
f"Meldegrund: {reason_label}\n"
|
||||||
f"Ziel: {target_label}\n"
|
f"Gemeldeter Inhalt: {target_label}\n"
|
||||||
f"Gemeldet von: {reporter_name} <{reporter_email}>\n\n"
|
f"Gemeldet von: {reporter_name} <{reporter_email}>\n\n"
|
||||||
f"Zur Inbox: {app_url}/inbox\n"
|
f"Posteingang öffnen: {app_url}/inbox\n"
|
||||||
)
|
)
|
||||||
subject = f"Inhaltsmeldung #{report_id} [{prio_label}] – Shinkan Jinkendo"
|
subject = f"Inhaltsmeldung #{report_id} [{prio_label}] – Shinkan Jinkendo"
|
||||||
for email in admin_emails:
|
for email in admin_emails:
|
||||||
|
|
@ -456,6 +457,24 @@ def submit_content_report(
|
||||||
result = r2d(row)
|
result = r2d(row)
|
||||||
report_id = int(result["id"])
|
report_id = int(result["id"])
|
||||||
|
|
||||||
|
# Dateinamen / Zielbezeichnung fuer E-Mail abfragen
|
||||||
|
target_label_for_email = f"{'Medium' if body.target_type == 'media_asset' else 'Übung'} #{body.target_id}"
|
||||||
|
if body.target_type == "media_asset":
|
||||||
|
cur.execute("SELECT original_filename FROM media_assets WHERE id = %s", (body.target_id,))
|
||||||
|
fn_row = cur.fetchone()
|
||||||
|
if fn_row:
|
||||||
|
fn = r2d(fn_row).get("original_filename") or ""
|
||||||
|
if fn:
|
||||||
|
target_label_for_email = f"{fn} (Medium #{body.target_id})"
|
||||||
|
|
||||||
|
elif body.target_type == "exercise":
|
||||||
|
cur.execute("SELECT name FROM exercises WHERE id = %s", (body.target_id,))
|
||||||
|
ex_row = cur.fetchone()
|
||||||
|
if ex_row:
|
||||||
|
ex_name = r2d(ex_row).get("name") or ""
|
||||||
|
if ex_name:
|
||||||
|
target_label_for_email = f"{ex_name} (Übung #{body.target_id})"
|
||||||
|
|
||||||
# Audit-Log-Eintrag (nur fuer media_asset-Meldungen)
|
# Audit-Log-Eintrag (nur fuer media_asset-Meldungen)
|
||||||
if body.target_type == "media_asset":
|
if body.target_type == "media_asset":
|
||||||
write_audit_log_entry(
|
write_audit_log_entry(
|
||||||
|
|
@ -466,9 +485,8 @@ def submit_content_report(
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
"content_report_id": report_id,
|
"content_report_id": report_id,
|
||||||
"report_reason": body.report_reason,
|
"report_reason": REASON_LABELS_DE.get(body.report_reason, body.report_reason),
|
||||||
"priority": priority,
|
"priority": "hoch" if priority == "high" else "normal",
|
||||||
"reporter_email": body.reporter_email,
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -486,6 +504,7 @@ def submit_content_report(
|
||||||
priority=priority,
|
priority=priority,
|
||||||
target_type=body.target_type,
|
target_type=body.target_type,
|
||||||
target_id=body.target_id,
|
target_id=body.target_id,
|
||||||
|
target_label=target_label_for_email,
|
||||||
admin_emails=admin_emails,
|
admin_emails=admin_emails,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -539,7 +558,7 @@ def list_inbox_content_reports(
|
||||||
cr.updated_at,
|
cr.updated_at,
|
||||||
ma.original_filename AS target_filename,
|
ma.original_filename AS target_filename,
|
||||||
ma.visibility AS target_visibility,
|
ma.visibility AS target_visibility,
|
||||||
ma.media_kind AS target_media_kind,
|
ma.mime_type AS target_mime_type,
|
||||||
ma.legal_hold_active AS target_legal_hold_active,
|
ma.legal_hold_active AS target_legal_hold_active,
|
||||||
ex.name AS target_exercise_name,
|
ex.name AS target_exercise_name,
|
||||||
rev.name AS reviewed_by_name,
|
rev.name AS reviewed_by_name,
|
||||||
|
|
@ -596,7 +615,7 @@ def list_inbox_content_reports(
|
||||||
cr.updated_at,
|
cr.updated_at,
|
||||||
ma.original_filename AS target_filename,
|
ma.original_filename AS target_filename,
|
||||||
ma.visibility AS target_visibility,
|
ma.visibility AS target_visibility,
|
||||||
ma.media_kind AS target_media_kind,
|
ma.mime_type AS target_mime_type,
|
||||||
ma.legal_hold_active AS target_legal_hold_active,
|
ma.legal_hold_active AS target_legal_hold_active,
|
||||||
ex.name AS target_exercise_name,
|
ex.name AS target_exercise_name,
|
||||||
rev.name AS reviewed_by_name,
|
rev.name AS reviewed_by_name,
|
||||||
|
|
@ -643,7 +662,7 @@ def get_content_report(
|
||||||
cr.*,
|
cr.*,
|
||||||
ma.original_filename AS target_filename,
|
ma.original_filename AS target_filename,
|
||||||
ma.visibility AS target_visibility,
|
ma.visibility AS target_visibility,
|
||||||
ma.media_kind AS target_media_kind,
|
ma.mime_type AS target_mime_type,
|
||||||
ma.legal_hold_active AS target_legal_hold_active,
|
ma.legal_hold_active AS target_legal_hold_active,
|
||||||
ma.legal_hold_reason_code AS target_legal_hold_reason_code,
|
ma.legal_hold_reason_code AS target_legal_hold_reason_code,
|
||||||
ex.name AS target_exercise_name,
|
ex.name AS target_exercise_name,
|
||||||
|
|
@ -686,12 +705,25 @@ def patch_content_report(
|
||||||
detail="Bei Abschluss ohne Massnahme ist eine Begründung (resolution_note) Pflicht.",
|
detail="Bei Abschluss ohne Massnahme ist eine Begründung (resolution_note) Pflicht.",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
STATUS_LABELS_DE = {
|
||||||
|
"submitted": "Eingegangen",
|
||||||
|
"under_review": "In Bearbeitung",
|
||||||
|
"resolved_no_action": "Abgeschlossen (kein Handlungsbedarf)",
|
||||||
|
"resolved_legal_hold": "Abgeschlossen (Legal Hold)",
|
||||||
|
"rejected_invalid": "Abgewiesen (ungültig)",
|
||||||
|
}
|
||||||
|
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
cur = get_cursor(conn)
|
cur = get_cursor(conn)
|
||||||
cur.execute("SELECT id, status FROM content_reports WHERE id = %s", (report_id,))
|
cur.execute(
|
||||||
|
"SELECT id, status, target_type, target_id FROM content_reports WHERE id = %s",
|
||||||
|
(report_id,),
|
||||||
|
)
|
||||||
row = cur.fetchone()
|
row = cur.fetchone()
|
||||||
if not row:
|
if not row:
|
||||||
raise HTTPException(status_code=404, detail="Meldung nicht gefunden")
|
raise HTTPException(status_code=404, detail="Meldung nicht gefunden")
|
||||||
|
old_report = r2d(row)
|
||||||
|
old_status = old_report["status"]
|
||||||
|
|
||||||
updates = ["updated_at = NOW()"]
|
updates = ["updated_at = NOW()"]
|
||||||
params = []
|
params = []
|
||||||
|
|
@ -721,6 +753,24 @@ def patch_content_report(
|
||||||
params,
|
params,
|
||||||
)
|
)
|
||||||
updated = r2d(cur.fetchone())
|
updated = r2d(cur.fetchone())
|
||||||
|
new_status = updated["status"]
|
||||||
|
|
||||||
|
# Audit-Log-Eintrag bei Status-Aenderung auf media_asset-Meldungen
|
||||||
|
if body.status is not None and old_status != new_status and old_report["target_type"] == "media_asset":
|
||||||
|
resolution = (body.resolution_note or "").strip() or None
|
||||||
|
write_audit_log_entry(
|
||||||
|
cur,
|
||||||
|
int(old_report["target_id"]),
|
||||||
|
pid,
|
||||||
|
"content_report_filed",
|
||||||
|
{"status": STATUS_LABELS_DE.get(old_status, old_status)},
|
||||||
|
{
|
||||||
|
"content_report_id": report_id,
|
||||||
|
"status": STATUS_LABELS_DE.get(new_status, new_status),
|
||||||
|
**({"begründung": resolution} if resolution else {}),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
return {"ok": True, "id": updated["id"], "status": updated["status"]}
|
return {"ok": True, "id": updated["id"], "status": updated["status"]}
|
||||||
|
|
|
||||||
|
|
@ -1168,10 +1168,26 @@ def list_media_assets(
|
||||||
show_club = sup or is_adm or bool(admin_club_ids)
|
show_club = sup or is_adm or bool(admin_club_ids)
|
||||||
asset_ids = [int(r["id"]) for r in rows]
|
asset_ids = [int(r["id"]) for r in rows]
|
||||||
usage_map = _usage_for_media_assets(cur, asset_ids)
|
usage_map = _usage_for_media_assets(cur, asset_ids)
|
||||||
|
# open_report_count: nur für Admins relevant; immer befüllen (0 für normale Nutzer ok)
|
||||||
|
report_count_map: dict[int, int] = {}
|
||||||
|
if asset_ids and (is_adm or bool(admin_club_ids)):
|
||||||
|
cur.execute(
|
||||||
|
"""SELECT target_id, COUNT(*) AS cnt
|
||||||
|
FROM content_reports
|
||||||
|
WHERE target_type = 'media_asset'
|
||||||
|
AND target_id = ANY(%s)
|
||||||
|
AND status IN ('submitted', 'under_review')
|
||||||
|
GROUP BY target_id""",
|
||||||
|
(asset_ids,),
|
||||||
|
)
|
||||||
|
for row in cur.fetchall():
|
||||||
|
rd = r2d(row)
|
||||||
|
report_count_map[int(rd["target_id"])] = int(rd["cnt"])
|
||||||
for r in rows:
|
for r in rows:
|
||||||
r["permissions"] = _item_permissions(r, tenant, admin_club_ids)
|
r["permissions"] = _item_permissions(r, tenant, admin_club_ids)
|
||||||
tid = int(r["id"])
|
tid = int(r["id"])
|
||||||
r["usage"] = usage_map.get(tid, {"exercises": [], "training_units": []})
|
r["usage"] = usage_map.get(tid, {"exercises": [], "training_units": []})
|
||||||
|
r["open_report_count"] = report_count_map.get(tid, 0)
|
||||||
tags_val = r.get("tags")
|
tags_val = r.get("tags")
|
||||||
if tags_val is None:
|
if tags_val is None:
|
||||||
r["tags"] = []
|
r["tags"] = []
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Shinkan Jinkendo Version Information
|
# Shinkan Jinkendo Version Information
|
||||||
|
|
||||||
APP_VERSION = "0.8.90"
|
APP_VERSION = "0.8.91"
|
||||||
BUILD_DATE = "2026-05-11"
|
BUILD_DATE = "2026-05-11"
|
||||||
DB_SCHEMA_VERSION = "20260511053"
|
DB_SCHEMA_VERSION = "20260511053"
|
||||||
|
|
||||||
|
|
@ -15,7 +15,7 @@ MODULE_VERSIONS = {
|
||||||
"admin_users": "1.0.0", # GET /api/admin/users
|
"admin_users": "1.0.0", # GET /api/admin/users
|
||||||
"platform_media_storage": "1.0.0", # GET/PUT /api/admin/platform-media-storage (Superadmin-Pfad unter MEDIA_ROOT)
|
"platform_media_storage": "1.0.0", # GET/PUT /api/admin/platform-media-storage (Superadmin-Pfad unter MEDIA_ROOT)
|
||||||
"media_rights": "1.3.1", # acting_profile_id in write_audit_log_entry auf Optional[int] (P-13 anonyme Meldungen)
|
"media_rights": "1.3.1", # acting_profile_id in write_audit_log_entry auf Optional[int] (P-13 anonyme Meldungen)
|
||||||
"media_assets": "1.18.0", # P-11: Legal-Hold nur fuer Superadmin sichtbar (nicht fuer alle Plattform-Admins)
|
"media_assets": "1.18.1", # P-13: open_report_count in Listendaten (fuer Admins)
|
||||||
"media_legal_hold": "1.0.0", # P-11: Sofortsperre-Services (set_legal_hold, release_legal_hold)
|
"media_legal_hold": "1.0.0", # P-11: Sofortsperre-Services (set_legal_hold, release_legal_hold)
|
||||||
"media_lifecycle": "1.1.0", # P-11: Retention-Job ueberspringt Legal-Hold-Assets
|
"media_lifecycle": "1.1.0", # P-11: Retention-Job ueberspringt Legal-Hold-Assets
|
||||||
"groups": "0.1.0",
|
"groups": "0.1.0",
|
||||||
|
|
@ -34,6 +34,16 @@ MODULE_VERSIONS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
CHANGELOG = [
|
CHANGELOG = [
|
||||||
|
{
|
||||||
|
"version": "0.8.91",
|
||||||
|
"date": "2026-05-11",
|
||||||
|
"changes": [
|
||||||
|
"Fix P-13: Name- und E-Mail-Felder im Melde-Dialog fuer eingeloggte Nutzer nicht mehr bearbeitbar (readOnly).",
|
||||||
|
"Fix P-13: Journaleintraege fuer content_report_filed leserlich (Meldegrund, Prioritaet, Status auf Deutsch).",
|
||||||
|
"Fix P-13: Badge auf Medienkacheln zeigt Anzahl offener Meldungen (nur fuer Admins).",
|
||||||
|
"Fix P-13: Statuswechsel an Meldungen werden im Journal des Mediums protokolliert.",
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "0.8.90",
|
"version": "0.8.90",
|
||||||
"date": "2026-05-11",
|
"date": "2026-05-11",
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,9 @@ export default function ReportContentModal({ targetType, targetId, targetLabel,
|
||||||
type="text"
|
type="text"
|
||||||
className="form-input"
|
className="form-input"
|
||||||
value={name}
|
value={name}
|
||||||
onChange={(e) => setName(e.target.value)}
|
onChange={user?.name ? undefined : (e) => setName(e.target.value)}
|
||||||
|
readOnly={!!user?.name}
|
||||||
|
style={user?.name ? { background: 'var(--surface2)', color: 'var(--text2)' } : undefined}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -154,7 +156,9 @@ export default function ReportContentModal({ targetType, targetId, targetLabel,
|
||||||
type="email"
|
type="email"
|
||||||
className="form-input"
|
className="form-input"
|
||||||
value={email}
|
value={email}
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
onChange={user?.email ? undefined : (e) => setEmail(e.target.value)}
|
||||||
|
readOnly={!!user?.email}
|
||||||
|
style={user?.email ? { background: 'var(--surface2)', color: 'var(--text2)' } : undefined}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -254,6 +254,7 @@ function eventTypeLabel(et) {
|
||||||
lifecycle_change: 'Lifecycle geändert',
|
lifecycle_change: 'Lifecycle geändert',
|
||||||
legal_hold_set: 'Sofortsperre gesetzt',
|
legal_hold_set: 'Sofortsperre gesetzt',
|
||||||
legal_hold_released: 'Sofortsperre aufgehoben',
|
legal_hold_released: 'Sofortsperre aufgehoben',
|
||||||
|
content_report_filed: 'Inhaltsmeldung',
|
||||||
}
|
}
|
||||||
return MAP[et] || et
|
return MAP[et] || et
|
||||||
}
|
}
|
||||||
|
|
@ -978,6 +979,20 @@ export default function MediaLibraryPage() {
|
||||||
title="Altbestand – Rechtserklärung nach neuem Standard (P-06) noch nicht erfasst"
|
title="Altbestand – Rechtserklärung nach neuem Standard (P-06) noch nicht erfasst"
|
||||||
>Altbestand ⚠</span>
|
>Altbestand ⚠</span>
|
||||||
)}
|
)}
|
||||||
|
{it.open_report_count > 0 && (
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
fontSize: '0.7rem',
|
||||||
|
background: 'var(--danger)',
|
||||||
|
color: '#fff',
|
||||||
|
borderRadius: '10px',
|
||||||
|
padding: '1px 6px',
|
||||||
|
marginLeft: 4,
|
||||||
|
fontWeight: 600,
|
||||||
|
}}
|
||||||
|
title={`${it.open_report_count} offene Inhaltsmeldung${it.open_report_count > 1 ? 'en' : ''}`}
|
||||||
|
>{it.open_report_count} Meldung{it.open_report_count > 1 ? 'en' : ''}</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{(it.tags || []).length ? (
|
{(it.tags || []).length ? (
|
||||||
<div className="media-library__tag-chips">
|
<div className="media-library__tag-chips">
|
||||||
|
|
@ -1598,6 +1613,39 @@ export default function MediaLibraryPage() {
|
||||||
<span>{nw.rights_status || '—'}</span>
|
<span>{nw.rights_status || '—'}</span>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
) : evt.event_type === 'content_report_filed' ? (
|
||||||
|
<>
|
||||||
|
{nw.content_report_id ? (
|
||||||
|
<div className="media-library__journal-audit-row">
|
||||||
|
<span className="media-library__journal-audit-label">Meldungs-ID:</span>
|
||||||
|
<span>#{nw.content_report_id}</span>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
{nw.report_reason ? (
|
||||||
|
<div className="media-library__journal-audit-row">
|
||||||
|
<span className="media-library__journal-audit-label">Meldegrund:</span>
|
||||||
|
<span>{nw.report_reason}</span>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
{nw.priority ? (
|
||||||
|
<div className="media-library__journal-audit-row">
|
||||||
|
<span className="media-library__journal-audit-label">Priorität:</span>
|
||||||
|
<span>{nw.priority}</span>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
{nw.status ? (
|
||||||
|
<div className="media-library__journal-audit-row">
|
||||||
|
<span className="media-library__journal-audit-label">Status:</span>
|
||||||
|
<span>{old.status ? `${old.status} → ` : ''}{nw.status}</span>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
{nw.begründung ? (
|
||||||
|
<div className="media-library__journal-audit-row">
|
||||||
|
<span className="media-library__journal-audit-label">Begründung:</span>
|
||||||
|
<span>{nw.begründung}</span>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
) : (
|
) : (
|
||||||
Object.keys(nw).map((k) => (
|
Object.keys(nw).map((k) => (
|
||||||
<div key={k} className="media-library__journal-audit-row">
|
<div key={k} className="media-library__journal-audit-row">
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Shinkan Jinkendo Frontend Version
|
// Shinkan Jinkendo Frontend Version
|
||||||
|
|
||||||
export const APP_VERSION = "0.8.90"
|
export const APP_VERSION = "0.8.91"
|
||||||
export const BUILD_DATE = "2026-05-11"
|
export const BUILD_DATE = "2026-05-11"
|
||||||
|
|
||||||
export const PAGE_VERSIONS = {
|
export const PAGE_VERSIONS = {
|
||||||
|
|
@ -20,7 +20,7 @@ export const PAGE_VERSIONS = {
|
||||||
TrainingCoachPage: "1.0.0",
|
TrainingCoachPage: "1.0.0",
|
||||||
AdminCatalogsPage: "2.2.0",
|
AdminCatalogsPage: "2.2.0",
|
||||||
TrainerContextsPage: "1.0.0",
|
TrainerContextsPage: "1.0.0",
|
||||||
MediaLibraryPage: "1.8.0", // P-13: MediaPreviewModal (geteilt) + Melde-Button in Viewer
|
MediaLibraryPage: "1.9.0", // P-13: open_report_count Badge + Journal content_report_filed
|
||||||
ExerciseFormPage: "1.1.0", // P-13: MediaPreviewModal (geteilt) + Melden im Viewer
|
ExerciseFormPage: "1.1.0", // P-13: MediaPreviewModal (geteilt) + Melden im Viewer
|
||||||
ExerciseInlineFileMediaModal: "1.1.0", // P-06: RightsDeclarationDialog vor Upload
|
ExerciseInlineFileMediaModal: "1.1.0", // P-06: RightsDeclarationDialog vor Upload
|
||||||
ExerciseInlineEmbedModal: "1.1.0", // P-06: RightsDeclarationDialog vor Embed-Upload
|
ExerciseInlineEmbedModal: "1.1.0", // P-06: RightsDeclarationDialog vor Embed-Upload
|
||||||
|
|
@ -30,5 +30,5 @@ export const PAGE_VERSIONS = {
|
||||||
InboxPage: "2.1.0", // P-13: target_filename/target_exercise_name fix; Club-Admin-Sicht
|
InboxPage: "2.1.0", // P-13: target_filename/target_exercise_name fix; Club-Admin-Sicht
|
||||||
OrgInboxContext: "1.1.0", // P-13: canSeeContentReports schliesst Club-Admins ein
|
OrgInboxContext: "1.1.0", // P-13: canSeeContentReports schliesst Club-Admins ein
|
||||||
MediaPreviewModal: "1.0.0", // P-13: geteilter Medienvorschau-Dialog (Melden + Bearbeiten optional)
|
MediaPreviewModal: "1.0.0", // P-13: geteilter Medienvorschau-Dialog (Melden + Bearbeiten optional)
|
||||||
ReportContentModal: "1.0.0", // P-13: Melde-Formular (Grund, Beschreibung, Name, E-Mail)
|
ReportContentModal: "1.1.0", // P-13: Name/E-Mail readOnly fuer eingeloggte Nutzer
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user