feat(#537): analytics screen — usage + per-model stats (#558)

* feat(#537): analytics screen — usage + per-model stats from /api/analytics/*

* fix(#537): address PR review — cancel-in-flight loads, retain cache on refresh, drop redundant async

* fix(#537): surface real analytics failure, mirror backend shape (period_days/tools), round-trip test

* fix(#537): tolerate float last_used_at in analytics (backend emits epoch as number)

* fix(#537): type tools[] as AnalyticsToolUsage (tool/count/percentage), render Top tools section

* fix(analytics): fix crashes and refactor tab layout

* perf(analytics): cache responses and prefetch day windows

---------

Co-authored-by: M57 <m57@hermes-control.app>
This commit is contained in:
M57andM57 authored and GitHub committed 2026-07-12 00:04:56 +03:00
1 parent afa82ceec2
commit 9156064d2b
9 files changed
+1031 -1

No files matched your search

@@ -5,6 +5,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.Chat
import androidx.compose.material.icons.automirrored.filled.ListAlt
import androidx.compose.material.icons.filled.AccountCircle
import androidx.compose.material.icons.filled.BarChart
import androidx.compose.material.icons.filled.Bolt
import androidx.compose.material.icons.filled.Build
import androidx.compose.material.icons.filled.Code
@@ -24,6 +25,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.navigation3.runtime.NavKey
import com.m57.hermescontrol.ui.achievements.AchievementsScreen as AchievementsScreenContent
import com.m57.hermescontrol.ui.analytics.AnalyticsScreen as AnalyticsScreenContent
import com.m57.hermescontrol.ui.channels.ChannelsScreen as ChannelsScreenContent
import com.m57.hermescontrol.ui.chat.ChatScreen as ChatScreenContent
import com.m57.hermescontrol.ui.config.ConfigScreen as ConfigScreenContent
@@ -173,6 +175,12 @@ object ScreenRegistry {
Icons.Filled.Memory,
DrawerSection.INSPECT,
) { sessionId, openDrawer -> ProcessesScreenContent(onOpenDrawer = openDrawer) },
ScreenDefinition(
AnalyticsScreen,
R.string.screen_analytics,
Icons.Filled.BarChart,
DrawerSection.INSPECT,
) { sessionId, openDrawer -> AnalyticsScreenContent(onOpenDrawer = openDrawer) },
ScreenDefinition(
KanbanScreen,
R.string.screen_kanban,