Skip to content

Commit 41f8e39

Browse files
fix(web): compact Routes stats dash and chart 'Now' label
Replace arrow with dash in the matched/threshold/degraded stat (0/2→6 becomes 0/2-6) to save horizontal space and prevent the stats row from wrapping on mobile. Change the last history chart label from 'Last XXh' to 'Now' for clarity and brevity. Add 'now' key to en.json ('Now') and nl.json ('Nu'); remove the now-dead 'last_n_hours' key from both locale files. Add tests for the dash separator format and the 'Now' label.
1 parent fea1278 commit 41f8e39

4 files changed

Lines changed: 52 additions & 6 deletions

File tree

src/meshcore_hub/web/static/js/spa-react/pages/Routes.test.tsx

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,52 @@ describe("Routes", () => {
7474
).not.toBeNull();
7575
});
7676

77+
it("renders matched/threshold/degraded stat with dash separator", async () => {
78+
const data = {
79+
items: [
80+
{
81+
...ROUTES.items[0],
82+
route_result: {
83+
quality: "clear",
84+
state: "healthy",
85+
matched_count: 3,
86+
threshold: 5,
87+
effective_clear: 2,
88+
},
89+
},
90+
],
91+
};
92+
vi.spyOn(api, "apiGet").mockImplementation(async (path) => {
93+
if (path === "/api/v1/routes") return data;
94+
if (path.match(/\/api\/v1\/routes\/[^/]+$/)) return ROUTE_DETAIL;
95+
if (path.includes("/history")) return ROUTE_HISTORY;
96+
throw new Error(`Unexpected: ${path}`);
97+
});
98+
renderWithProviders(<Routes />);
99+
await waitFor(() => {
100+
expect(screen.getByText("3/5-2")).toBeInTheDocument();
101+
});
102+
});
103+
104+
it("shows Now label for the last history chart entry", async () => {
105+
const historyWithData = {
106+
data: [
107+
{ date: "2026-07-20", matched: 0, total: 0 },
108+
{ date: "2026-07-21", matched: 1, total: 1 },
109+
],
110+
};
111+
vi.spyOn(api, "apiGet").mockImplementation(async (path) => {
112+
if (path === "/api/v1/routes") return ROUTES;
113+
if (path.match(/\/api\/v1\/routes\/[^/]+$/)) return ROUTE_DETAIL;
114+
if (path.includes("/history")) return historyWithData;
115+
throw new Error(`Unexpected: ${path}`);
116+
});
117+
renderWithProviders(<Routes />);
118+
await waitFor(() => {
119+
expect(screen.getByText("common.now")).toBeInTheDocument();
120+
});
121+
});
122+
77123
it("shows an error on fetch failure", async () => {
78124
vi.spyOn(api, "apiGet").mockRejectedValue(new Error("routes error"));
79125
renderWithProviders(<Routes />);

src/meshcore_hub/web/static/js/spa-react/pages/Routes.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ function StatsRow({ route }: { route: RouteItem }) {
310310
<IconPackets className="h-3.5 w-3.5" />
311311
<span>
312312
{matched}/{threshold}
313-
{"\u2192"}
313+
{"-"}
314314
{degraded}
315315
</span>
316316
</span>
@@ -473,7 +473,7 @@ function DetailContent({
473473
{historyData.map((d, i) => (
474474
<span key={d.date} className="flex-1 text-center min-w-0 truncate">
475475
{i === historyData.length - 1
476-
? t("routes.last_n_hours", { n: route.window_hours })
476+
? t("common.now")
477477
: new Date(`${d.date}T00:00:00`).toLocaleDateString(
478478
undefined,
479479
{ day: "2-digit", month: "2-digit" },

src/meshcore_hub/web/static/locales/en.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@
117117
"unnamed_node": "Unnamed Node",
118118
"validation_invalid_number": "Value must be a valid number",
119119
"validation_invalid_boolean": "Value must be true, false, yes, no, 1, or 0",
120-
"sort_by": "Sort by"
120+
"sort_by": "Sort by",
121+
"now": "Now"
121122
},
122123
"links": {
123124
"website": "Website",
@@ -359,7 +360,6 @@
359360
"quality_no_coverage": "No Coverage",
360361
"quality_unknown": "Unknown",
361362
"recent_packets": "Recent Packets",
362-
"last_n_hours": "Last {{n}}h",
363363
"min_nodes_error": "At least 2 path nodes are required.",
364364
"other_routes": "Other routes",
365365
"filter_mine": "Show only my routes"

src/meshcore_hub/web/static/locales/nl.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@
108108
"filter_operator_label": "Operator",
109109
"filter_observer_label": "Waarnemer",
110110
"filter_observer_enable": "Klik om deze waarnemer te tonen",
111-
"filter_observer_disable": "Klik om deze waarnemer te verbergen"
111+
"filter_observer_disable": "Klik om deze waarnemer te verbergen",
112+
"now": "Nu"
112113
},
113114
"links": {
114115
"website": "Website",
@@ -282,7 +283,6 @@
282283
"quality_no_coverage": "Geen dekking",
283284
"quality_unknown": "Onbekend",
284285
"recent_packets": "Recente packets",
285-
"last_n_hours": "Laatste {{n}}u",
286286
"min_nodes_error": "Minimaal 2 padknooppunten zijn vereist.",
287287
"other_routes": "Overige routes",
288288
"filter_mine": "Toon alleen mijn routes"

0 commit comments

Comments
 (0)