Skip to main content

max / makenotwork

Retire the four standalone-tag suppliers onto the new members e2030032 answered (b), so a standalone tag is a member now and the suppliers that existed only because `token` is a setting come out. project_analytics and user_analytics drew the same range selector and duplicated five things between them: the Range struct, the RANGES const, range_heading, is_shown and a chip supplier each. The four shared ones are in quasi/mod.rs and the two chips are `chip <value> to <action>`. project's Subscribed badge and git_commit's diff-status badge are `badge` members too. MNW's remaining count falls 16 to 12, and all twelve are what progress.py --parked now reports. 2688 lib tests pass, clippy clean.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session
https://claude.ai/code/session_01MptwXZ8k65v19rFmdGAyki
Author: Max Johnson <me@maxj.phd> · 2026-09-04 16:15 UTC
Signed with PGP, not checked
Commit: fd90160f3da3b0b7a08531e63a9c075dc07f06f6
Parent: 56f1bf3
5 files changed, +81 insertions, -172 deletions
@@ -35,7 +35,7 @@
35 35
36 36 use makeover_layout as layout;
37 37 use quasi_declare::declare;
38 - use quasi_router::{Action, Document, Node, RegionKind};
38 + use quasi_router::{Action, Document, RegionKind};
39 39 use quasi_webview::Webview;
40 40
41 41 use crate::git::signing::SignatureStatus;
@@ -488,19 +488,6 @@
488 488 }
489 489 }
490 490
491 - /// The one-letter status, as the tag it always was.
492 - ///
493 - /// A supplier and not a member: `token` is a **setting** on a row and on a
494 - /// cell, so the name cannot also be a node member. The fourth instance of that
495 - /// forcing, and quasicoherent `e2030032` is where it is being decided.
496 - fn status_badge(file: &DiffFile) -> Node {
497 - Node::token(
498 - quasi_router::screen::Tag::badge(file.status.label())
499 - .tone(status_tone(file))
500 - .hinted(file.status.name()),
501 - )
502 - }
503 -
504 491 /// What the file is called, and what it was called before.
505 492 fn diff_label(file: &DiffFile) -> String {
506 493 match &file.old_path {
@@ -521,7 +508,10 @@
521 508 region "diff-{slug(&file.path)}" as Group {
522 509 region "diff-header-{slug(&file.path)}" as Group {
523 510 across Wrap {
524 - beside Essential include status_badge(file);
511 + beside Essential badge file.status.label() {
512 + tone status_tone(file);
513 + hinted file.status.name();
514 + }
525 515 beside Essential link diff_label(file)
526 516 to get "{view.base()}/tree/{view.current_ref}/{file.path}" navigating;
527 517 beside Secondary toned "+{file.additions}" layout::Tone::Success
@@ -451,6 +451,59 @@
451 451 forum_memberships::SETTINGS_SCREEN,
452 452 ];
453 453
454 + /// One window an analytics panel offers.
455 + ///
456 + /// Named members rather than a tuple, for `policy`'s reason: a description names
457 + /// what it draws, and `.1` is not a name.
458 + pub(super) struct Range {
459 + /// What the address carries.
460 + pub value: &'static str,
461 + /// What the heading calls it.
462 + pub label: &'static str,
463 + }
464 +
465 + /// The four windows, and what each is called.
466 + ///
467 + /// Shared by `project_analytics` and `user_analytics`, which draw the same
468 + /// selector against different addresses. It was duplicated between them, along
469 + /// with `Range`, `range_heading`, `is_shown` and a `chip` supplier each; the
470 + /// supplier went when `chip` became a node member (quasicoherent `e2030032`)
471 + /// and the rest is here.
472 + pub(super) const RANGES: &[Range] = &[
473 + Range {
474 + value: "7d",
475 + label: "Last 7 days",
476 + },
477 + Range {
478 + value: "30d",
479 + label: "Last 30 days",
480 + },
481 + Range {
482 + value: "90d",
483 + label: "Last 90 days",
484 + },
485 + Range {
486 + value: "all",
487 + label: "All time",
488 + },
489 + ];
490 +
491 + /// What the current range is called.
492 + pub(super) fn range_heading(range: &str) -> &'static str {
493 + RANGES
494 + .iter()
495 + .find(|window| window.value == range)
496 + .map_or("All time", |window| window.label)
497 + }
498 +
499 + /// Whether this window is the one being shown.
500 + ///
501 + /// A supplier because a comparison is an expression and the form admits none in
502 + /// an argument. It hands back a `bool`, which is the smallest type that works.
503 + pub(super) fn is_shown(window: &Range, range: &str) -> bool {
504 + window.value == range
505 + }
506 +
454 507 /// Every described screen, mounted.
455 508 ///
456 509 /// Unconditional since `64b33b26`. Each entry used to be gated on
@@ -65,7 +65,7 @@
65 65
66 66 use makeover_layout as layout;
67 67 use quasi_declare::declare;
68 - use quasi_router::{Action, Document, Feed, FeedKind, Node, RegionKind, Tag};
68 + use quasi_router::{Action, Document, Feed, FeedKind, RegionKind, Tag};
69 69 use quasi_webview::Webview;
70 70
71 71 use crate::templates::CarouselFrame;
@@ -329,16 +329,6 @@
329 329 }
330 330 }
331 331
332 - /// The badge a subscriber wears on a tier they already hold.
333 - ///
334 - /// A supplier and not a member: `token` is a **setting** on a row and on a
335 - /// cell, so the name cannot also be a node member. The third instance of that
336 - /// forcing after both analytics panels' `chip`, and quasicoherent `e2030032`
337 - /// is where it is being decided.
338 - fn subscribed_badge() -> Node {
339 - Node::token(Tag::badge("Subscribed"))
340 - }
341 -
342 332 declare! {
343 333 /// One membership tier, as a group.
344 334 shape tier_group(store: &Store<'_>, tier: &SubscriptionTier) -> Node;
@@ -348,7 +338,7 @@
348 338 text tier.price.clone();
349 339 text tier.description.clone() unless tier.description.is_empty();
350 340
351 - include subscribed_badge() when store.has_subscription;
341 + badge "Subscribed" when store.has_subscription;
352 342
353 343 // The hidden `_csrf` goes the way the tip form's did: this arrives as
354 344 // an htmx post and `frontend/src/core/htmx-glue.ts` attaches the token
@@ -43,8 +43,8 @@
43 43
44 44 use makeover_layout as layout;
45 45 use quasi_declare::declare;
46 - use quasi_router::screen::{Figure, Tag};
47 - use quasi_router::{Action, Node, RegionKind, Slot};
46 + use quasi_router::screen::Figure;
47 + use quasi_router::{Node, RegionKind, Slot};
48 48 use quasi_webview::Webview;
49 49
50 50 use crate::types::{ChartBar, ContentItem, StatCard};
@@ -54,36 +54,6 @@
54 54
55 55 /// The bespoke region the chart is drawn into.
56 56 const CHART_SLOT: &str = "project-revenue-chart";
57 -
58 - /// One window the panel offers.
59 - ///
60 - /// Named members rather than a tuple, for `policy`'s reason: a description names
61 - /// what it draws, and `.1` is not a name.
62 - struct Range {
63 - value: &'static str,
64 - label: &'static str,
65 - }
66 -
67 - /// The four windows the panel offers, and what each is called.
68 - const RANGES: &[Range] = &[
69 - Range {
70 - value: "7d",
71 - label: "Last 7 days",
72 - },
73 - Range {
74 - value: "30d",
75 - label: "Last 30 days",
76 - },
77 - Range {
78 - value: "90d",
79 - label: "Last 90 days",
80 - },
81 - Range {
82 - value: "all",
83 - label: "All time",
84 - },
85 - ];
86 -
87 57 /// The panel as the route answers it: the region, carrying its own id.
88 58 #[must_use]
89 59 pub fn fragment(
@@ -129,7 +99,7 @@
129 99
130 100 link "Docs: Analytics" to get "/docs/analytics" navigating;
131 101 link "Export data" to get "/dashboard/export" navigating;
132 - section heading(range);
102 + section super::range_heading(range);
133 103
134 104 for chip in range_chips(slug, range) {
135 105 include chip;
@@ -148,40 +118,6 @@
148 118 when items.is_empty();
149 119 include top_items(items) unless items.is_empty();
150 120 }
151 -
152 - /// What the window is called, as the heading says it.
153 - fn heading(range: &str) -> &'static str {
154 - RANGES
155 - .iter()
156 - .find(|window| window.value == range)
157 - .map_or("All time", |window| window.label)
158 - }
159 -
160 - /// Whether this window is the one being shown.
161 - ///
162 - /// A supplier because a comparison is an expression, and the form admits none
163 - /// in an argument. It hands back a `bool`, which is the smallest thing that
164 - /// works and keeps it out of the population.
165 - fn is_shown(window: &Range, range: &str) -> bool {
166 - window.value == range
167 - }
168 -
169 - /// One range control.
170 - ///
171 - /// A supplier and not a member: `token` is a **setting** on a row and on a cell,
172 - /// and a body's idents are told from settings by the member list alone, so the
173 - /// name cannot mean both. `quasi_declare`'s `NODE_MEMBERS` records the ruling.
174 - fn chip(window: &Range, slug: &str, range: &str) -> Node {
175 - Node::token(
176 - Tag::chip(
177 - window.value,
178 - Action::get(format!("/dashboard/project/{slug}/tabs/analytics"))
179 - .carrying("range", window.value),
180 - )
181 - .latched(is_shown(window, range)),
182 - )
183 - }
184 -
185 121 declare! {
186 122 /// The four range controls.
187 123 ///
@@ -191,8 +127,11 @@
191 127 /// the template composing a class name.
192 128 shape range_chips(slug: &str, range: &str) -> Vec<Node>;
193 129
194 - for window in RANGES {
195 - include chip(window, slug, range);
130 + for window in super::RANGES {
131 + chip window.value
132 + to get "/dashboard/project/{slug}/tabs/analytics" carrying "range" window.value {
133 + latched super::is_shown(window, range);
134 + }
196 135 }
197 136 }
198 137
@@ -301,10 +240,10 @@
301 240
302 241 #[test]
303 242 fn the_heading_names_the_window_and_falls_back_to_all_time() {
304 - assert_eq!(heading("7d"), "Last 7 days");
305 - assert_eq!(heading("90d"), "Last 90 days");
243 + assert_eq!(super::super::range_heading("7d"), "Last 7 days");
244 + assert_eq!(super::super::range_heading("90d"), "Last 90 days");
306 245 // What the template's `{% else %}` did for anything unrecognised.
307 - assert_eq!(heading("nonsense"), "All time");
246 + assert_eq!(super::super::range_heading("nonsense"), "All time");
308 247 }
309 248
310 249 #[test]
@@ -46,8 +46,8 @@
46 46
47 47 use makeover_layout as layout;
48 48 use quasi_declare::declare;
49 - use quasi_router::screen::{Figure, Tag};
50 - use quasi_router::{Action, Node, RegionKind, Request, Response, RouteError};
49 + use quasi_router::screen::Figure;
50 + use quasi_router::{RegionKind, Request, Response, RouteError};
51 51 use quasi_webview::Webview;
52 52
53 53 use super::Viewer;
@@ -73,38 +73,6 @@
73 73 /// The slot the chart's own markup mounts into.
74 74 const CHART_SLOT: &str = "analytics-chart";
75 75
76 - /// One window the selector offers.
77 - ///
78 - /// Named members rather than a tuple, for `policy`'s reason and
79 - /// `super::project_analytics`'s: a description names what it draws, and `.1` is
80 - /// not a name.
81 - struct Range {
82 - /// What the address carries.
83 - value: &'static str,
84 - /// What the heading calls it.
85 - label: &'static str,
86 - }
87 -
88 - /// The ranges offered, in the order the selector draws them.
89 - const RANGES: &[Range] = &[
90 - Range {
91 - value: "7d",
92 - label: "Last 7 days",
93 - },
94 - Range {
95 - value: "30d",
96 - label: "Last 30 days",
97 - },
98 - Range {
99 - value: "90d",
100 - label: "Last 90 days",
101 - },
102 - Range {
103 - value: "all",
104 - label: "All time",
105 - },
106 - ];
107 -
108 76 /// One stat card, as the screen needs it.
109 77 pub struct StatView {
110 78 label: String,
@@ -293,7 +261,7 @@
293 261 shape pane(analytics: &Analytics) -> Node;
294 262
295 263 region REGION as Pane {
296 - section range_heading(&analytics.range);
264 + section super::range_heading(&analytics.range);
297 265
298 266 for chip in range_chips(&analytics.range) {
299 267 include chip;
@@ -318,45 +286,14 @@
318 286 }
319 287 }
320 288
321 - /// What the current range is called.
322 - fn range_heading(range: &str) -> &'static str {
323 - RANGES
324 - .iter()
325 - .find(|window| window.value == range)
326 - .map_or("All time", |window| window.label)
327 - }
328 -
329 - /// Whether this window is the one being shown.
330 - ///
331 - /// A supplier because a comparison is an expression, and the form admits none
332 - /// in an argument. It hands back a `bool`, which is the smallest thing that
333 - /// works and keeps it out of the population.
334 - fn is_shown(window: &Range, range: &str) -> bool {
335 - window.value == range
336 - }
337 -
338 - /// One range control.
339 - ///
340 - /// A supplier and not a member: `token` is a **setting** on a row and on a
341 - /// cell, so the name cannot also be a node member. `quasi_declare`'s
342 - /// `NODE_MEMBERS` records the ruling and `super::project_analytics::chip` is
343 - /// the same supplier for the project-level panel.
344 - fn chip(window: &Range, range: &str) -> Node {
345 - Node::token(
346 - Tag::chip(
347 - window.value,
348 - Action::get(PATH).carrying("range", window.value),
349 - )
350 - .latched(is_shown(window, range)),
351 - )
352 - }
353 -
354 289 declare! {
355 290 /// The range selector: one chip per range, the current one held down.
356 291 shape range_chips(range: &str) -> Vec<Node>;
357 292
358 - for window in RANGES {
359 - include chip(window, range);
293 + for window in super::RANGES {
294 + chip window.value to get PATH carrying "range" window.value {
295 + latched super::is_shown(window, range);
296 + }
360 297 }
361 298 }
362 299
@@ -514,7 +451,7 @@
514 451 mod tests {
515 452 use super::*;
516 453 use quasi_axum::Serves;
517 - use quasi_router::Slot;
454 + use quasi_router::{Node, Slot};
518 455
519 456 fn analytics() -> Analytics {
520 457 Analytics {
@@ -591,8 +528,8 @@
591 528 }
592 529 // An unknown range falls back rather than leaving nothing selected, so
593 530 // the heading and the selector cannot disagree about where the reader is.
594 - assert_eq!(range_heading("nonsense"), "All time");
595 - assert_eq!(range_heading("7d"), "Last 7 days");
531 + assert_eq!(super::super::range_heading("nonsense"), "All time");
532 + assert_eq!(super::super::range_heading("7d"), "Last 7 days");
596 533 }
597 534
598 535 #[test]