max / makenotwork
- Co-Authored-By
- Claude Opus 5 (1M context) <noreply@anthropic.com>
5 files changed,
+28 insertions,
-62 deletions
| @@ -246,18 +246,23 @@ | |||
| 246 | 246 | } | |
| 247 | 247 | ||
| 248 | 248 | #[test] | |
| 249 | - | fn the_four_routes_that_are_not_tabs_stay_out() { | |
| 250 | - | // Subscriptions, promotions and members are the monetization composite's | |
| 251 | - | // own self-refresh routes, and blog is reached from the content panel. | |
| 252 | - | // A button for any of them is a tab the page never had. | |
| 249 | + | fn the_two_routes_that_are_not_tabs_stay_out() { | |
| 250 | + | // Subscriptions and members are the monetization composite's own | |
| 251 | + | // self-refresh routes: each partial names its own address in a | |
| 252 | + | // `data-after="refresh"`. A button for either is a tab the page never | |
| 253 | + | // had. | |
| 254 | + | // | |
| 255 | + | // This list was four until 2026-08-26, and the comment vouched for all | |
| 256 | + | // of them. Two were not what it said. `/tabs/blog` was a route nothing | |
| 257 | + | // reached and is deleted (`6077d0d9`); `/tabs/promotions` was the same | |
| 258 | + | // and is deleted too (`f698064d`) -- its partial is live but the | |
| 259 | + | // monetization composite carries the data, so the route rendering that | |
| 260 | + | // partial alone had no caller. Only these two were ever self-refresh | |
| 261 | + | // targets, and the way to tell is to grep the partial for its own | |
| 262 | + | // address rather than to trust this comment. | |
| 253 | 263 | let html = strip(true, true); | |
| 254 | 264 | ||
| 255 | - | for route in [ | |
| 256 | - | "/tabs/subscriptions", | |
| 257 | - | "/tabs/promotions", | |
| 258 | - | "/tabs/members", | |
| 259 | - | "/tabs/blog", | |
| 260 | - | ] { | |
| 265 | + | for route in ["/tabs/subscriptions", "/tabs/members"] { | |
| 261 | 266 | assert!(!html.contains(route), "{route} is not a tab:\n{html}"); | |
| 262 | 267 | } | |
| 263 | 268 | } |
| @@ -249,7 +249,6 @@ | |||
| 249 | 249 | ItemLicenseKeysTemplate, | |
| 250 | 250 | // Promo codes | |
| 251 | 251 | PromoCodesListTemplate, | |
| 252 | - | ProjectPromotionsTabTemplate, | |
| 253 | 252 | // Sessions | |
| 254 | 253 | UserSessionsPartialTemplate, | |
| 255 | 254 | // SyncKit |
| @@ -782,15 +782,12 @@ | |||
| 782 | 782 | pub promo_codes: Vec<crate::types::PromoCodeRow>, | |
| 783 | 783 | } | |
| 784 | 784 | ||
| 785 | - | /// Promotions tab content for the project dashboard. | |
| 786 | - | #[derive(Template)] | |
| 787 | - | #[template(path = "partials/tabs/project_promotions.html")] | |
| 788 | - | pub struct ProjectPromotionsTabTemplate { | |
| 789 | - | pub project_id: String, | |
| 790 | - | pub project_slug: String, | |
| 791 | - | pub promo_codes: Vec<crate::types::PromoCodeRow>, | |
| 792 | - | pub items: Vec<ContentItem>, | |
| 793 | - | } | |
| 785 | + | // `ProjectPromotionsTabTemplate` was here until 2026-08-26. It rendered | |
| 786 | + | // `partials/tabs/project_promotions.html` for a route nothing reached. The | |
| 787 | + | // template itself is still live and is NOT deleted: `project_monetization.html` | |
| 788 | + | // includes it, and `ProjectMonetizationTabTemplate` carries the `promo_codes` | |
| 789 | + | // and `items` it needs. So the composite was always the only caller, and this | |
| 790 | + | // struct was the second way to render a partial that only ever had one. | |
| 794 | 791 | ||
| 795 | 792 | // License Key Partials | |
| 796 | 793 |
| @@ -142,10 +142,11 @@ | |||
| 142 | 142 | "/dashboard/project/{slug}/tabs/monetization", | |
| 143 | 143 | get(project_tabs::project_tab_monetization), | |
| 144 | 144 | ) | |
| 145 | - | .route_get( | |
| 146 | - | "/dashboard/project/{slug}/tabs/promotions", | |
| 147 | - | get(project_tabs::project_tab_promotions), | |
| 148 | - | ) | |
| 145 | + | // `/tabs/promotions` was registered here until 2026-08-26 and reached by | |
| 146 | + | // nothing. Its partial is live -- `project_monetization.html` includes | |
| 147 | + | // it -- but the composite carries the promo data itself, so the route | |
| 148 | + | // that rendered the partial alone had no caller. Its two neighbours | |
| 149 | + | // below are NOT the same case: both are real self-refresh targets. | |
| 149 | 150 | .route_get( | |
| 150 | 151 | "/dashboard/project/{slug}/tabs/subscriptions", | |
| 151 | 152 | get(project_tabs::project_tab_subscriptions), |
| @@ -16,8 +16,8 @@ | |||
| 16 | 16 | templates::{ | |
| 17 | 17 | LinkedRepoView, ProjectAnalyticsTabTemplate, ProjectCodeTabTemplate, | |
| 18 | 18 | ProjectContentTabTemplate, ProjectMembersTabTemplate, ProjectMonetizationTabTemplate, | |
| 19 | - | ProjectOverviewTabTemplate, ProjectPromotionsTabTemplate, ProjectSettingsTabTemplate, | |
| 20 | - | ProjectSubscriptionsTabTemplate, ProjectSyncKitTabTemplate, RepoCollaboratorView, | |
| 19 | + | ProjectOverviewTabTemplate, ProjectSettingsTabTemplate, ProjectSubscriptionsTabTemplate, | |
| 20 | + | ProjectSyncKitTabTemplate, RepoCollaboratorView, | |
| 21 | 21 | }, | |
| 22 | 22 | types::{ | |
| 23 | 23 | BlogPostDashboardRow, ContentItem, Project, ProjectMemberRow, PromoCodeRow, StatCard, | |
| @@ -487,42 +487,6 @@ | |||
| 487 | 487 | )) | |
| 488 | 488 | } | |
| 489 | 489 | ||
| 490 | - | /// Render the HTMX partial for the project promotions tab (promo codes). | |
| 491 | - | #[tracing::instrument(skip_all, name = "project_tabs::project_tab_promotions")] | |
| 492 | - | pub(super) async fn project_tab_promotions( | |
| 493 | - | State(db): State<PgPool>, | |
| 494 | - | AuthUser(session_user): AuthUser, | |
| 495 | - | headers: HeaderMap, | |
| 496 | - | Path(slug): Path<String>, | |
| 497 | - | ) -> Result<axum::response::Response> { | |
| 498 | - | let (db_project, generation) = | |
| 499 | - | match resolve_project_etag(&db, session_user.id, &slug, &headers).await? { | |
| 500 | - | Ok(pair) => pair, | |
| 501 | - | Err(not_modified) => return Ok(not_modified), | |
| 502 | - | }; | |
| 503 | - | ||
| 504 | - | let codes = db::promo_codes::get_promo_codes_by_project(&db, db_project.id).await?; | |
| 505 | - | let db_items = db::items::get_items_by_project(&db, db_project.id).await?; | |
| 506 | - | ||
| 507 | - | let items: Vec<ContentItem> = db_items | |
| 508 | - | .iter() | |
| 509 | - | .enumerate() | |
| 510 | - | .map(|(i, item)| { | |
| 511 | - | ContentItem::from_db(item, (i + 1) as u32, session_user.settlement_currency) | |
| 512 | - | }) | |
| 513 | - | .collect(); | |
| 514 | - | ||
| 515 | - | Ok(helpers::with_etag( | |
| 516 | - | generation, | |
| 517 | - | ProjectPromotionsTabTemplate { | |
| 518 | - | project_id: db_project.id.to_string(), | |
| 519 | - | project_slug: db_project.slug.to_string(), | |
| 520 | - | promo_codes: codes.into_iter().map(PromoCodeRow::from).collect(), | |
| 521 | - | items, | |
| 522 | - | }, | |
| 523 | - | )) | |
| 524 | - | } | |
| 525 | - | ||
| 526 | 490 | /// Render the HTMX partial for the project code tab (git repos). | |
| 527 | 491 | #[tracing::instrument(skip_all, name = "project_tabs::project_tab_code")] | |
| 528 | 492 | pub(super) async fn project_tab_code( |