Stage 06.1 - journal management UI, export and system menu redesign

This commit is contained in:
2026-04-27 15:02:56 +03:00
parent 1fb72ced58
commit f6fc300e84
19 changed files with 1935 additions and 421 deletions

View File

@@ -1,3 +1,5 @@
# app/src/storage/repositories/journal.py
from __future__ import annotations
import json
@@ -20,10 +22,10 @@ class JournalRepository:
with get_connection() as connection:
with connection.cursor() as cursor:
cursor.execute(
'''
"""
INSERT INTO journal_events (level, event_type, message, payload_json)
VALUES (%s, %s, %s, %s::jsonb)
''',
""",
(
level.upper().strip(),
event_type.strip(),
@@ -32,32 +34,69 @@ class JournalRepository:
),
)
def list_recent_events(self, limit: int = 10) -> list[dict[str, str]]:
def _parse_payload(self, raw_payload: Any) -> dict[str, Any] | None:
if raw_payload is None:
return None
if isinstance(raw_payload, dict):
return raw_payload
if isinstance(raw_payload, str):
try:
parsed = json.loads(raw_payload)
return parsed if isinstance(parsed, dict) else None
except json.JSONDecodeError:
return None
return None
def list_recent_events(self, limit: int = 10) -> list[dict[str, Any]]:
with get_connection() as connection:
with connection.cursor() as cursor:
cursor.execute(
'''
SELECT id, created_at, level, event_type, message
"""
SELECT id, created_at, level, event_type, message, payload_json
FROM journal_events
ORDER BY created_at DESC, id DESC
LIMIT %s
''',
""",
(limit,),
)
rows = cursor.fetchall()
items: list[dict[str, str]] = []
for row in rows:
items.append(
{
"id": str(row[0]),
"created_at": str(row[1]),
"level": str(row[2]),
"event_type": str(row[3]),
"message": str(row[4]),
}
)
return items
return [self._row_to_dict(row) for row in rows]
def list_recent_with_offset(self, limit: int, offset: int) -> list[dict[str, Any]]:
with get_connection() as connection:
with connection.cursor() as cursor:
cursor.execute(
"""
SELECT id, created_at, level, event_type, message, payload_json
FROM journal_events
ORDER BY created_at DESC, id DESC
LIMIT %s OFFSET %s
""",
(limit, offset),
)
rows = cursor.fetchall()
return [self._row_to_dict(row) for row in rows]
def list_export_rows(self, limit: int = 5000) -> list[dict[str, Any]]:
with get_connection() as connection:
with connection.cursor() as cursor:
cursor.execute(
"""
SELECT id, created_at, level, event_type, message, payload_json
FROM journal_events
ORDER BY created_at DESC, id DESC
LIMIT %s
""",
(limit,),
)
rows = cursor.fetchall()
return [self._row_to_dict(row) for row in rows]
def count_events(self) -> int:
with get_connection() as connection:
@@ -67,26 +106,35 @@ class JournalRepository:
return int(row[0]) if row else 0
def list_recent_with_offset(self, limit: int, offset: int):
def delete_all(self) -> int:
with get_connection() as connection:
with connection.cursor() as cursor:
cursor.execute("DELETE FROM journal_events")
deleted_count = cursor.rowcount
return int(deleted_count or 0)
def _row_to_dict(self, row: tuple[Any, ...]) -> dict[str, Any]:
return {
"id": str(row[0]),
"created_at": str(row[1]),
"level": str(row[2]),
"event_type": str(row[3]),
"message": str(row[4]),
"payload": self._parse_payload(row[5]),
}
def delete_older_than_days(self, days: int) -> int:
with get_connection() as connection:
with connection.cursor() as cursor:
cursor.execute(
"""
SELECT created_at, level, event_type, message
FROM journal_events
ORDER BY created_at DESC
LIMIT %s OFFSET %s
DELETE FROM journal_events
WHERE created_at < NOW() - (%s * INTERVAL '1 day')
""",
(limit, offset),
(days,),
)
rows = cursor.fetchall()
deleted_count = cursor.rowcount
return [
{
"created_at": str(r[0]),
"level": r[1],
"event_type": r[2],
"message": r[3],
}
for r in rows
]
return deleted_count