Skip to content

feat(ui): add the "new this month" card to the sharing page - #175

Merged
argszero merged 1 commit into
mainfrom
feat/sharing-new-this-month-card
Sep 12, 2026
Merged

argszero merged 1 commit into
mainfrom
feat/sharing-new-this-month-card

Conversation

@argszero

Copy link
Copy Markdown
Owner

Summary

The sharing page's stat row showed three cards where the prototype shows four — the fourth, 「本月新增」(new this month), was missing. The reason was on the backend: GET /api/sharings never returned a row's listing time, so the client had nothing to count. This PR exposes that field and renders the card.

keys.created_at has existed since the schema's first commit, so no migration is involved; only the SELECT and the response were missing it.

Related Issue

Changes

  • sharing_row() (src/routes/sharing.rs) now returns created_at, serialized with the existing dao::utc_iso — same convention as api_keys.created_at. ⚠️ sharing_row() reads its columns positionally (r.get(0..12)), so its two call sites — the list SELECT and the single-row PATCH SELECT — both gain the column in this one commit, appended at the end. A one-sided change would silently shift every field without erroring.
  • renderSharing() (ui/js/app.js) renders the fourth stat card, counting rows whose listing time falls in the current month.
  • The month key is derived from the UTC timestamp (utcMonth → YYYY-MM), matching the SQL-side strftime('%Y-%m', …) that every other aggregate in this repo uses (ops.rs, wallet.rs, admin.rs, org.rs). Using the local month would disagree with the rest of the page for the first eight hours of each month in UTC+8. Rows without a created_at are not counted — under-report rather than mis-report.
  • The card's subtitle deliberately does not copy the prototype, which hardcodes the model name deepseek-v4-flash on a card that may aggregate several models (the prototype's own table renders multiple rows). A single listing shows its model name, several show a generic label, none shows an empty-state label.
  • New bilingual keys share.stats.newthis{,.sub,.none}; the i18n_pack gate's maintained counts move 783 → 786 keys and 531 → 535 call sites (426 → 429 distinct).
  • ui/README.md documents the convention, and corrects a stale line that claimed the sharing list has a 上架时间 column — it never had one (neither the prototype nor the implementation), and no column is added here, so the table's 8-column colspan stays consistent.
  • No config/config.example.toml change — this touches no configuration or data structure. keys.created_at existed already.

Tests

  • cargo test 全部通过 — 164 passed / 0 failed (163 before; +1 new).
  • cargo fmt --check 通过
  • cargo clippy --all-targets -- -D warnings 通过
  • 新增/更新了单元测试(如适用)

New test sharing::tests::created_at_is_exposed_and_utc_serialized asserts:

  1. both SELECTs carry the column — the GET /api/sharings list and the PATCH /api/sharings/:id response are both asserted (they read from two separate column lists, which is the shape that fails silently);
  2. the pre-existing fields do not shift (a regression guard for positional reads);
  3. the serialization is UTC — the test sets the timestamp to 2026-08-31 17:30:00, which is August in UTC but already September in UTC+8, so a local-time regression is distinguishable rather than self-confirming.

Both assertions were proven to have teeth before landing, by injecting the defect and watching them fail (then restoring the file and verifying its md5):

  • dropping created_at from only the PATCH SELECT → Invalid column index: 12 on the PATCH path, while the GET path still passed (exactly the one-sided-drift failure mode);
  • serializing the raw SQLite string instead of utc_iso → left: "2026-08-31 17:30:00" vs right: "2026-08-31T17:30:00Z".

An A/B run of the real renderSharing() against the real language packs (before tree from git show HEAD:ui/js/app.js, same generator and same stub data for both legs) went 15/15: BEFORE 3 cards and no 「本月新增」 label → AFTER 4 cards; count 3 个 for 3 in-month rows out of 4; subtitle 多个模型; single in-month row → subtitle = that row's model (glm-5.2); zero in-month rows → 0 个 + 「本月还没有上架」; a 2026-09-30T23:30:00Z row still counts in September. It also asserts the prototype's hardcoded literals (1, deepseek-v4-flash) never appear.

Checklist

  • 分支命名符合约定(feat/ /fix/ /docs/ …)
  • Commit message 使用 Conventional Commits 格式
  • 单一职责,改动最小化

The sharing page's stat row had three cards where the prototype has four:
the fourth ("本月新增") was missing because GET /api/sharings never returned
a row's listing time, so the client had nothing to count.

- sharing_row() now returns `created_at` (UTC ISO via dao::utc_iso, the same
  convention as api_keys.created_at). sharing_row() reads its columns
  POSITIONALLY, so both of its call sites (the list SELECT and the
  single-row PATCH SELECT) gain the column in this one commit, appended at
  the end; a one-sided change would silently shift every field.
- renderSharing() renders the fourth card. The month key is derived from the
  UTC timestamp (utcMonth -> YYYY-MM), matching the SQL-side
  strftime('%Y-%m', ...) every other aggregate in this repo uses; using the
  local month would disagree with the rest of the page for the first eight
  hours of each month in UTC+8. Rows without a created_at are not counted
  (under-report rather than mis-report).
- The subtitle deliberately does not copy the prototype, which hardcodes the
  model name "deepseek-v4-flash" on a card that may aggregate several models
  (the prototype's own table renders multiple rows): a single listing shows
  its model, several show a generic label, none shows an empty-state label.
- New bilingual keys share.stats.newthis{,.sub,.none}; the i18n_pack gate's
  maintained counts move 783 -> 786 keys and 531 -> 535 call sites
  (426 -> 429 distinct).
- ui/README.md documents the convention, and corrects a stale line claiming
  the sharing list has a 上架时间 column (it never had one; no column added
  here either, so the table's 8-column colspan stays consistent).

Tests: sharing::tests::created_at_is_exposed_and_utc_serialized asserts both
SELECTs and the UTC serialization using a `2026-08-31 17:30:00` timestamp,
which is August in UTC but September locally (UTC+8) - so a local-time
regression is distinguishable rather than self-confirming.

Co-authored-by: argszero <argszero@argszerodeMac-mini.local>
@argszero
argszero merged commit 940850e into main Sep 12, 2026
1 check passed
@argszero
argszero deleted the feat/sharing-new-this-month-card branch September 12, 2026 02:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant