Skip to content

feat(web-ui): heatmap, recycle bin auto-purge, and config improvements#122

Merged
ymkiux merged 9 commits intoSakuraByteCore:mainfrom
SurviveM:fix/claude-config-flicker-and-xiaomi-presets
May 5, 2026
Merged

feat(web-ui): heatmap, recycle bin auto-purge, and config improvements#122
ymkiux merged 9 commits intoSakuraByteCore:mainfrom
SurviveM:fix/claude-config-flicker-and-xiaomi-presets

Conversation

@SurviveM
Copy link
Copy Markdown
Collaborator

@SurviveM SurviveM commented May 5, 2026

Summary

  • fix: persist currentClaudeConfig to localStorage, eliminating refresh flicker
  • feat: add Xiaomi MiMo and Xiaomi Token Plan provider presets
  • feat: 7x24 hourly heatmap in Usage page, colors aligned to theme brand coral
  • feat: session trash auto-purge with configurable retention days (1-365)
  • fix: persist sessionsUsageTimeRange and remove day detail select placeholder
  • fix: safer localStorage I/O, locale-independent heatmap weekday keys, max=0 guard

Tests

  • 521 unit tests passed, 0 fail
  • E2e skipped (Termux env timeout, unaffected on CI)

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 5, 2026

📝 Walkthrough

Walkthrough

This PR introduces an hourly activity heatmap visualization for session usage, adds configurable session-trash retention settings with auto-purge behavior, and improves Claude config persistence by saving and restoring the current config selection from localStorage.

Changes

Hourly Usage Heatmap

Layer / File(s) Summary
Core Calculation
web-ui/logic.sessions.mjs
Adds buildUsageHourlyHeatmap() that aggregates sessions into a normalized 7×24 grid indexed by UTC weekday and hour, with optional date-range filtering (7d/30d/all), computing per-cell session/message counts and token totals, returning { range, grid, maxSessionCount, weekdayKeys, hourLabels }.
Computed Property & Data Binding
web-ui/modules/app.computed.session.mjs
Introduces sessionUsageHourlyHeatmap() computed method that calls buildUsageHourlyHeatmap, normalizes cell intensity levels (0–4) relative to maxSessionCount, formats hour labels (0023), and generates localized/fallback tooltips.
UI Rendering
web-ui/partials/index/panel-usage.html
Renders hourly heatmap card with hour headers, weekday rows, colored cells with intensity levels and tooltips, and a legend with less/more labels. Also fixes day-detail select to auto-populate from session data.
Styling
web-ui/styles/sessions-usage.css
Adds CSS layout and theming for heatmap container, header, cells (1:1 aspect ratio with rounded corners), intensity levels (level-0 through level-4 with CSS variable colors), and legend.
i18n & Utilities
web-ui/modules/i18n.dict.mjs, web-ui/modules/app.methods.session-browser.mjs
Adds Chinese/English i18n keys for heatmap title, subtitle, tooltip template, and legend. Wraps localStorage.setItem in try/catch for time-range persistence and initializes selected day on usage load.
Tests & Parity
tests/unit/session-usage.test.mjs, tests/unit/web-ui-behavior-parity.test.mjs
Adds unit tests for buildUsageHourlyHeatmap (grid dimensions, cell aggregation, range filtering, empty inputs). Extends parity allowlist to include sessionUsageHourlyHeatmap computed key.

Session Trash Retention Settings

Layer / File(s) Summary
Backend Purge Logic
cli.js
Adds DEFAULT_SESSION_TRASH_RETENTION_DAYS constant and purgeExpiredSessionTrashEntries(retentionDays) function that deletes trash files and index entries older than the retention cutoff. Updates listSessionTrashItems() to auto-purge expired entries (unless autoPurge: false) before returning trash list.
Frontend State & Methods
web-ui/modules/app.methods.session-trash.mjs
Adds normalizeSessionTrashRetentionDays() (clamps 1–365 range, defaults 30) and setSessionTrashRetentionDays() (updates state and persists to localStorage under codexmateSessionTrashRetentionDays). Extends list-session-trash API call to include retentionDays parameter.
App Initialization
web-ui/app.js
Adds reactive sessionTrashRetentionDays field (default 30) and initializes it from localStorage via normalizeSessionTrashRetentionDays() in mounted().
UI Form & Styling
web-ui/partials/index/panel-settings.html, web-ui/styles/settings-panel.css
Adds number input (1–365 range) in trash settings card bound to sessionTrashRetentionDays with setSessionTrashRetentionDays() change handler. Introduces .settings-retention-row and .settings-retention-input CSS classes for layout and styling.
i18n Dictionary
web-ui/modules/i18n.dict.mjs
Adds Chinese/English i18n keys for trash retention title, explanation, label, and hint text describing the 1–365 day range and auto-cleanup behavior.
Tests & E2E
tests/unit/session-trash-state.test.mjs, tests/unit/web-ui-behavior-parity.test.mjs, tests/e2e/test-sessions.js
Extends trash context fixtures to include sessionTrashRetentionDays: 30. Adds unit tests for purge logic, retention normalization/persistence, and auto-purge behavior. Updates parity allowlist to include new methods/data keys. E2E tests now pass autoPurge: false to list-session-trash calls to isolate test assertions from auto-purge side effects.

Claude Config Persistence

Layer / File(s) Summary
Data Shape & Initialization
web-ui/app.js
In mounted(), restores currentClaudeConfig from localStorage key currentClaudeConfig (when it exists in claudeConfigs), then falls back to existing logic that selects the first available config and derives currentClaudeModel.
Persistence Methods
web-ui/modules/app.methods.claude-config.mjs
switchClaudeConfig(), saveClaudeConfigs(), and applyClaudeConfig() now persist currentClaudeConfig to localStorage (with silent try/catch error handling) in addition to existing config updates.
Test Initialization
tests/unit/web-ui-startup-init.test.mjs
Test contexts now include normalizeSessionTrashRetentionDays() stub to match updated app initialization expectations (no functional change to Claude config test logic).

Sequence Diagram

sequenceDiagram
    actor User
    participant UI as Panel (Usage Card)
    participant Computed as sessionUsageHourlyHeatmap()
    participant Logic as buildUsageHourlyHeatmap()
    participant Data as Sessions Data
    
    User->>UI: View hourly heatmap
    UI->>Computed: Render with computed property
    Computed->>Logic: Call with filtered sessions & range
    Logic->>Data: Iterate sessions
    Data-->>Logic: Return UTC weekday/hour + metrics
    Logic->>Logic: Aggregate into 7×24 grid cells
    Logic-->>Computed: Return grid + maxSessionCount
    Computed->>Computed: Normalize intensity levels (0–4)
    Computed-->>UI: Return rows with tooltips & labels
    UI->>UI: Render cells with level-* classes
    UI-->>User: Display color-coded heatmap + legend
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • SakuraByteCore/codexmate#46: Modifies Claude config handling (switch/apply/save logic) and localStorage persistence, directly related to the currentClaudeConfig persistence improvements in this PR.
  • SakuraByteCore/codexmate#82: Modifies buildUsageChartGroups in logic.sessions.mjs with hour/weekday time calculations; this PR adds buildUsageHourlyHeatmap to the same module with related UTC weekday/hour logic.
  • SakuraByteCore/codexmate#80: Introduces session-usage state and list-sessions-usage API; this PR builds on that by adding the sessionUsageHourlyHeatmap computed property and related usage visualization logic.

Suggested reviewers

  • ymkiux
  • awsl233777

🐰 A heatmap blooms in seven-by-twenty-four,
Each hour glows with sessions' warming store,
Trash retention locked in localStorage's chest,
And Claude configs now persist their best!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the three main features added: heatmap visualization, recycle bin auto-purge, and config improvements (localStorage persistence).

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web-ui/modules/app.methods.claude-config.mjs`:
- Around line 39-43: The call to localStorage.setItem for claudeConfigs in
saveClaudeConfigs can throw like the currentClaudeConfig write does, so wrap the
first setItem (for this.claudeConfigs) in a try/catch for consistent fault
tolerance; specifically update the saveClaudeConfigs() method to catch errors
from localStorage.setItem('claudeConfigs', JSON.stringify(this.claudeConfigs))
and swallow or log the error similarly to how the currentClaudeConfig write is
handled (preserving the existing try/catch pattern around localStorage.setItem
for currentClaudeConfig).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 892acb54-2c62-4e42-83a9-7dddeaddd212

📥 Commits

Reviewing files that changed from the base of the PR and between 156f119 and 21fc5ae.

📒 Files selected for processing (4)
  • web-ui/app.js
  • web-ui/modules/app.methods.claude-config.mjs
  • web-ui/modules/app.methods.startup-claude.mjs
  • web-ui/partials/index/panel-config-claude.html
📜 Review details
🔇 Additional comments (4)
web-ui/partials/index/panel-config-claude.html (1)

67-68: Looks good — Xiaomi presets follow existing preset flow.

Line 67 and Line 68 correctly initialize newClaudeConfig fields and open the modal consistently with other provider presets.

web-ui/modules/app.methods.claude-config.mjs (1)

7-7: Good hardening on selection persistence writes.

Line 7 and Line 150 now safely degrade on storage failures without disrupting config switching/apply flows.

Also applies to: 150-150

web-ui/modules/app.methods.startup-claude.mjs (1)

315-351: Startup reconciliation persistence update is solid.

The guarded localStorage.currentClaudeConfig writes in match/import/fallback/clear paths are consistent and help prevent refresh-state drift.

web-ui/app.js (1)

501-516: Nice startup restoration flow.

Line 501-Line 516 cleanly restores the selected Claude config from storage and only backfills model when needed, which should reduce refresh flicker.

Comment thread web-ui/modules/app.methods.claude-config.mjs
@SurviveM SurviveM force-pushed the fix/claude-config-flicker-and-xiaomi-presets branch from 21fc5ae to 0552a27 Compare May 5, 2026 08:11
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web-ui/logic.sessions.mjs`:
- Around line 355-356: The logic function buildUsageHourlyHeatmap is emitting
hardcoded Chinese weekdayLabels; change it to return locale-neutral weekday
identifiers (e.g., ISO names like ['Mon','Tue',...'Sun'] or keys like
['weekday_1'..'weekday_7'] or numeric indices) instead of ['周一'...'周日'] so the
presentation layer can localize via i18n; update the weekdayLabels value in
buildUsageHourlyHeatmap to use neutral keys and add a brief comment that the
UI/computed layer must map those keys to localized strings.

In `@web-ui/modules/app.computed.session.mjs`:
- Line 612: The fallback tooltip string is using raw `${cell.tokenTotal}` and
can render "null"/"undefined tokens"; update the fallback branch so it
normalizes tokenTotal the same way the other branch does—replace the raw
interpolation with the guarded, localized value `(cell.tokenTotal ||
0).toLocaleString('en-US')` when constructing the string that combines
weekdayLabels[dayIndex], hourLabel, cell.sessionCount, cell.messageCount, and
the token text.
- Around line 594-602: The code uses const max = result.maxSessionCount and then
divides by max when computing ratio in the grid mapping (cells => { const ratio
= cell.sessionCount > 0 ? (cell.sessionCount / max) : 0 }), which can yield
Infinity if max is 0; update the code to guard max by replacing max with
Math.max(1, max) (e.g., compute max = Math.max(1, result.maxSessionCount) before
the grid/rows mapping) so the ratio calculation and level assignment behave like
the sibling sessionUsageHeatmap pattern; ensure you reference and update the
same max variable used in the cells mapping.
- Around line 591-597: The code reads result.weekdayLabels unguarded when lang
!== 'en', which can be undefined or shorter than grid and cause a TypeError in
rows mapping; fix by normalizing/guarding weekdayLabels before use: compute a
safe array (e.g., const weekdayLabels = lang === 'en' ? ['Mon',...,'Sun'] :
(Array.isArray(result.weekdayLabels) ? result.weekdayLabels : [])) and then when
building rows (the rows = grid.map(...) block) use a fallback for missing
entries (weekdayLabels[dayIndex] ?? '') so accessing weekdayLabels[dayIndex]
cannot throw; update the use-sites weekdayLabels, result.weekdayLabels, lang,
grid and rows accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d1e07c03-10bf-41d5-9075-8aa35a3eb62b

📥 Commits

Reviewing files that changed from the base of the PR and between 21fc5ae and 112f4a2.

📒 Files selected for processing (12)
  • tests/unit/session-usage.test.mjs
  • tests/unit/web-ui-behavior-parity.test.mjs
  • web-ui/app.js
  • web-ui/logic.sessions.mjs
  • web-ui/modules/app.computed.session.mjs
  • web-ui/modules/app.methods.claude-config.mjs
  • web-ui/modules/app.methods.session-browser.mjs
  • web-ui/modules/app.methods.startup-claude.mjs
  • web-ui/modules/i18n.dict.mjs
  • web-ui/partials/index/panel-config-claude.html
  • web-ui/partials/index/panel-usage.html
  • web-ui/styles/sessions-usage.css
✅ Files skipped from review due to trivial changes (2)
  • web-ui/partials/index/panel-config-claude.html
  • web-ui/styles/sessions-usage.css
🚧 Files skipped from review as they are similar to previous changes (3)
  • web-ui/modules/app.methods.claude-config.mjs
  • web-ui/modules/app.methods.startup-claude.mjs
  • web-ui/app.js
📜 Review details
🔇 Additional comments (5)
web-ui/modules/i18n.dict.mjs (1)

625-629: Hourly heatmap i18n coverage looks complete.

Both locales include matching keys and placeholder shapes for title/subtitle/tooltip/legend, which keeps rendering and interpolation stable.

Also applies to: 1684-1688

web-ui/modules/app.methods.session-browser.mjs (1)

777-785: Good persistence fix for usage range selection.

Persisting the normalized range before reload (with storage failure isolation) is a solid fix for refresh-state flicker.

tests/unit/web-ui-behavior-parity.test.mjs (1)

595-619: Parity allowlist update is appropriate.

Including sessionUsageHourlyHeatmap keeps computed-key parity tests aligned with the new usage feature surface.

web-ui/partials/index/panel-usage.html (1)

291-319: Hourly heatmap rendering block is well wired.

The grid/legend bindings and tooltip wiring are consistent with the new computed data contract.

tests/unit/session-usage.test.mjs (1)

8-8: Hourly heatmap unit coverage is solid.

These tests cover the important paths (shape, aggregation correctness, range filtering, empty-state defaults) for the new helper.

Also applies to: 111-153

Comment thread web-ui/logic.sessions.mjs Outdated
Comment thread web-ui/modules/app.computed.session.mjs Outdated
Comment thread web-ui/modules/app.computed.session.mjs Outdated
Comment thread web-ui/modules/app.computed.session.mjs Outdated
@SurviveM SurviveM force-pushed the fix/claude-config-flicker-and-xiaomi-presets branch 2 times, most recently from e812d46 to b6074bb Compare May 5, 2026 11:30
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
web-ui/app.js (1)

114-115: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove the duplicate agentsPath key.

agentsPath is declared twice in the data() object. JavaScript silently uses the last definition in sloppy mode; strict-mode engines and linters (no-dupe-keys) treat it as an error.

🐛 Proposed fix
-                agentsPath: '',
                 agentsPath: '',
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web-ui/app.js` around lines 114 - 115, Duplicate agentsPath entries in the
data() object cause a dupe-key error; remove the redundant agentsPath key so
only one agentsPath property remains in the data() return value (keep the
intended value from whichever entry is correct), e.g., edit the data() function
to have a single agentsPath property and ensure surrounding syntax
(commas/braces) remains valid.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@web-ui/app.js`:
- Around line 114-115: Duplicate agentsPath entries in the data() object cause a
dupe-key error; remove the redundant agentsPath key so only one agentsPath
property remains in the data() return value (keep the intended value from
whichever entry is correct), e.g., edit the data() function to have a single
agentsPath property and ensure surrounding syntax (commas/braces) remains valid.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f5972123-d426-4a00-a297-608c9e6a69be

📥 Commits

Reviewing files that changed from the base of the PR and between 112f4a2 and b6074bb.

📒 Files selected for processing (9)
  • tests/unit/session-usage.test.mjs
  • tests/unit/web-ui-behavior-parity.test.mjs
  • web-ui/app.js
  • web-ui/logic.sessions.mjs
  • web-ui/modules/app.computed.session.mjs
  • web-ui/modules/app.methods.session-browser.mjs
  • web-ui/modules/i18n.dict.mjs
  • web-ui/partials/index/panel-usage.html
  • web-ui/styles/sessions-usage.css
✅ Files skipped from review due to trivial changes (5)
  • web-ui/modules/i18n.dict.mjs
  • web-ui/modules/app.methods.session-browser.mjs
  • tests/unit/web-ui-behavior-parity.test.mjs
  • web-ui/styles/sessions-usage.css
  • tests/unit/session-usage.test.mjs
🚧 Files skipped from review as they are similar to previous changes (2)
  • web-ui/partials/index/panel-usage.html
  • web-ui/modules/app.computed.session.mjs
📜 Review details
🔇 Additional comments (3)
web-ui/logic.sessions.mjs (2)

355-355: Hardcoded Chinese weekday labels in logic layer — already flagged.

This was raised in a previous review: buildUsageHourlyHeatmap should return locale-neutral identifiers (e.g. ['mon','tue','wed','thu','fri','sat','sun']) and let the UI/computed layer localize them via i18n.


304-354: LGTM — buildUsageHourlyHeatmap logic is correct.

  • Source filter, Date.parse + Number.isFinite guard, and range-window clamp are consistent with buildUsageHeatmap.
  • The weekday formula (getUTCDay() + 6) % 7 correctly maps Mon→0 … Sun→6 in UTC, matching the grid row order.
  • Math.max(1, maxSessionCount) correctly prevents division-by-zero in the downstream level computation.

Also applies to: 356-358

web-ui/app.js (1)

161-161: LGTM — localStorage init is well-guarded.

The IIFE validates against the same three accepted values as normalizeUsageRange, and the try/catch covers SecurityError from restricted storage contexts. The '7d' fallback is consistent with the rest of the codebase.

@SurviveM SurviveM force-pushed the fix/claude-config-flicker-and-xiaomi-presets branch from b6074bb to e0a40fd Compare May 5, 2026 12:39
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
web-ui/modules/app.methods.claude-config.mjs (1)

93-97: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Persist selection in saveAndApplyConfig success path too.

On Line 93, this.currentClaudeConfig is updated, but this path does not write currentClaudeConfig to localStorage. If the user refreshes before another save/switch, persisted selection can still be stale.

Suggested patch
                 } else {
                     this.currentClaudeConfig = name;
+                    try { localStorage.setItem('currentClaudeConfig', name || ''); } catch (_) {}
                     const targetTip = res.targetPath ? `(${res.targetPath})` : '';
                     this.showMessage(`已保存并应用到 Claude 配置${targetTip}`, 'success');
                     this.closeEditConfigModal();
                     this.refreshClaudeModelContext();
                 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web-ui/modules/app.methods.claude-config.mjs` around lines 93 - 97, In the
saveAndApplyConfig success path (inside saveAndApplyConfig) you set
this.currentClaudeConfig = name but don't persist it; after updating
this.currentClaudeConfig add a localStorage write using the same storage key the
app uses for Claude selection (e.g. localStorage.setItem('currentClaudeConfig',
name)) so the choice survives a page refresh, then continue to call
this.showMessage, this.closeEditConfigModal, and this.refreshClaudeModelContext
as before.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@web-ui/modules/app.methods.claude-config.mjs`:
- Around line 93-97: In the saveAndApplyConfig success path (inside
saveAndApplyConfig) you set this.currentClaudeConfig = name but don't persist
it; after updating this.currentClaudeConfig add a localStorage write using the
same storage key the app uses for Claude selection (e.g.
localStorage.setItem('currentClaudeConfig', name)) so the choice survives a page
refresh, then continue to call this.showMessage, this.closeEditConfigModal, and
this.refreshClaudeModelContext as before.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 60861557-4282-45bb-9fb2-482d2992b157

📥 Commits

Reviewing files that changed from the base of the PR and between b6074bb and e0a40fd.

📒 Files selected for processing (12)
  • tests/unit/session-usage.test.mjs
  • tests/unit/web-ui-behavior-parity.test.mjs
  • web-ui/app.js
  • web-ui/logic.sessions.mjs
  • web-ui/modules/app.computed.session.mjs
  • web-ui/modules/app.methods.claude-config.mjs
  • web-ui/modules/app.methods.session-browser.mjs
  • web-ui/modules/app.methods.startup-claude.mjs
  • web-ui/modules/i18n.dict.mjs
  • web-ui/partials/index/panel-config-claude.html
  • web-ui/partials/index/panel-usage.html
  • web-ui/styles/sessions-usage.css
✅ Files skipped from review due to trivial changes (2)
  • web-ui/modules/i18n.dict.mjs
  • tests/unit/web-ui-behavior-parity.test.mjs
🚧 Files skipped from review as they are similar to previous changes (5)
  • web-ui/app.js
  • web-ui/modules/app.methods.session-browser.mjs
  • web-ui/partials/index/panel-usage.html
  • tests/unit/session-usage.test.mjs
  • web-ui/styles/sessions-usage.css
📜 Review details
🔇 Additional comments (5)
web-ui/partials/index/panel-config-claude.html (1)

67-68: Xiaomi presets are wired consistently with existing provider presets.

The new buttons on Line 67 and Line 68 correctly prefill newClaudeConfig and open the modal in the same pattern as the other presets.

web-ui/modules/app.methods.claude-config.mjs (1)

40-43: Good hardening for storage failures in config persistence.

Guarding both claudeConfigs and currentClaudeConfig writes with try/catch on Line 40–43 makes save flow resilient in restricted/private storage environments.

web-ui/modules/app.methods.startup-claude.mjs (1)

318-350: Startup selection persistence looks correct and robust.

Writing/clearing currentClaudeConfig on the match/import/fallback branches (Line 318, 327, 343, 350) closes refresh-state gaps while safely tolerating localStorage errors.

web-ui/logic.sessions.mjs (1)

304-358: LGTM — buildUsageHourlyHeatmap is correct and the past locale-neutrality concern is resolved.

The 7×24 grid initialization, UTC-based weekday/hour bucketing, range boundaries, and maxSessionCount clamping are all correct and consistent with the sibling buildUsageHeatmap. Returning numeric weekdayKeys instead of hardcoded Chinese labels (as flagged in the previous review) cleanly separates logic from presentation.

web-ui/modules/app.computed.session.mjs (1)

584-630: LGTM — all three previously flagged issues are resolved; sessionUsageHourlyHeatmap is correct.

  • Past issue 1 (unguarded result.weekdayLabels): weekdayLabels is now constructed locally (lines 591–593) and never sourced from result, so result.weekdayLabels can never be undefined here. ✅
  • Past issue 2 (Math.max(1, max) guard): Line 594 correctly clamps max to at least 1. ✅
  • Past issue 3 (raw cell.tokenTotal in fallback tooltip): Line 612 uses (cell.tokenTotal || 0).toLocaleString('en-US'). ✅

SurviveM added 4 commits May 5, 2026 20:48
Add weekday-by-hour heatmap grid (7 rows x 24 columns) to the usage
page, showing session distribution across weekdays and hours with
color-coded intensity levels.
Save usage time range to localStorage on change and restore on init,
preventing reset to default '7d' after page refresh.
Remove the "选择日期" placeholder from the day detail dropdown and
auto-select the first available day when usage data loads.
- remove duplicate agentsPath key in app.js data()
- wrap localStorage.setItem for claudeConfigs in try/catch
- use locale-neutral weekdayKeys in logic layer, localize in computed
- guard weekdayLabels fallback and max division-by-zero
- normalize fallback tooltip tokenTotal to prevent null render
@SurviveM SurviveM force-pushed the fix/claude-config-flicker-and-xiaomi-presets branch from e0a40fd to af68afb Compare May 5, 2026 12:50
Add auto-purge for session trash entries older than a configurable
retention period (default 30 days). Purge runs automatically on each
trash list load. Retention days (1-365) is persisted in localStorage
and configurable from the settings panel.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/unit/session-trash-state.test.mjs`:
- Around line 2476-2483: The test title is misleading: it claims keys exist "in
both locales" but only checks template usage (indexHtmlSource) and backend
symbols (cliSource, DEFAULT_SESSION_TRASH_RETENTION_DAYS,
purgeExpiredSessionTrashEntries); either rename the test to something like
"references retention i18n key and backend symbols" or add explicit assertions
that the locale dictionaries contain the 'settings.trash.retention' key for both
language objects (e.g., assert(localesEn.includes('settings.trash.retention'))
and assert(localesZh.includes('settings.trash.retention'))), keeping the
existing checks for indexHtmlSource and cliSource intact.

In `@web-ui/partials/index/panel-usage.html`:
- Around line 99-102: The select forces a fallback to
sessionUsageDailyTableRows[0].key so clearing via clearSessionsUsageDay can't be
represented; change the binding to use only sessionsUsageSelectedDayKey
(defaulting to '' when undefined) and add a dedicated empty option (e.g.,
<option :key="'day-select-empty'" value="">) so the UI can show a cleared state,
and ensure select handler selectSessionsUsageDay continues to accept and handle
'' (empty string) as the cleared value.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3a33808f-4aac-4b84-9225-284de182e232

📥 Commits

Reviewing files that changed from the base of the PR and between e0a40fd and 8b838c9.

📒 Files selected for processing (16)
  • cli.js
  • tests/unit/session-trash-state.test.mjs
  • tests/unit/session-usage.test.mjs
  • tests/unit/web-ui-behavior-parity.test.mjs
  • tests/unit/web-ui-startup-init.test.mjs
  • web-ui/app.js
  • web-ui/logic.sessions.mjs
  • web-ui/modules/app.computed.session.mjs
  • web-ui/modules/app.methods.claude-config.mjs
  • web-ui/modules/app.methods.session-browser.mjs
  • web-ui/modules/app.methods.session-trash.mjs
  • web-ui/modules/i18n.dict.mjs
  • web-ui/partials/index/panel-settings.html
  • web-ui/partials/index/panel-usage.html
  • web-ui/styles/sessions-usage.css
  • web-ui/styles/settings-panel.css
✅ Files skipped from review due to trivial changes (3)
  • web-ui/styles/sessions-usage.css
  • web-ui/styles/settings-panel.css
  • web-ui/modules/i18n.dict.mjs
🚧 Files skipped from review as they are similar to previous changes (5)
  • web-ui/modules/app.methods.claude-config.mjs
  • web-ui/modules/app.computed.session.mjs
  • web-ui/modules/app.methods.session-browser.mjs
  • tests/unit/session-usage.test.mjs
  • web-ui/logic.sessions.mjs
📜 Review details
🔇 Additional comments (10)
cli.js (3)

225-225: Default retention constant addition looks good.

This introduces a clear single-source default for trash retention and keeps behavior predictable.


5605-5632: Purge implementation is solid and consistent with the retention objective.

The fallback handling, cutoff computation, file deletion, and index rewrite flow all look correct.


5845-5847: Auto-purge integration before listing is correctly wired.

This cleanly enables retention-based cleanup while preserving explicit opt-out via autoPurge: false.

web-ui/partials/index/panel-settings.html (1)

144-158: Looks good — retention UI wiring is consistent.

The new retention card, numeric constraints, and setSessionTrashRetentionDays(...) binding align cleanly with the state/persistence flow.

tests/unit/web-ui-startup-init.test.mjs (1)

34-38: Good parity setup for mounted startup tests.

Adding normalizeSessionTrashRetentionDays to both contexts keeps these startup tests aligned with the new initialization path.

Also applies to: 140-144

web-ui/partials/index/panel-usage.html (1)

290-318: Hourly heatmap template structure is clean.

Row/column iteration, level classes, and tooltip/aria-label bindings are all implemented clearly.

web-ui/app.js (1)

160-160: Good state restoration flow.

The retained usage range, trash retention restore, and currentClaudeConfig restore-before-fallback sequence are well ordered and should stabilize startup behavior.

Also applies to: 365-365, 482-517

tests/unit/web-ui-behavior-parity.test.mjs (1)

333-347: Parity updates are coherent with intended feature drift.

Allowlist additions and retentionDays normalization keep parity checks stable while still validating core behavior.

Also applies to: 512-514, 623-624, 892-901, 943-952

web-ui/modules/app.methods.session-trash.mjs (1)

273-285: Retention methods and request wiring look solid.

Normalization, persistence, and forwarding retentionDays in loadSessionTrash are implemented cleanly.

Also applies to: 309-313

tests/unit/session-trash-state.test.mjs (1)

2277-2490: Great retention coverage expansion.

The new tests cover retention purge behavior, bounds normalization, persistence, and request propagation comprehensively.

Comment on lines +2476 to +2483
test('retention days i18n keys exist in both locales', () => {
const zhRetention = indexHtmlSource.includes("t('settings.trash.retention')") ||
indexHtmlSource.includes('t(\'settings.trash.retention\')');
assert(zhRetention, 'retention section should reference i18n key');

assert(cliSource.includes('DEFAULT_SESSION_TRASH_RETENTION_DAYS'), 'backend should define default retention constant');
assert(cliSource.includes('purgeExpiredSessionTrashEntries'), 'backend should define auto-purge function');
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Test title overstates what is actually verified.

The test says “exist in both locales” but only checks template key usage and backend symbols, not locale dictionaries. Rename the test or add explicit locale assertions.

✏️ Minimal corrective diff
-test('retention days i18n keys exist in both locales', () => {
+test('retention settings wiring references i18n usage and backend retention hooks', () => {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/session-trash-state.test.mjs` around lines 2476 - 2483, The test
title is misleading: it claims keys exist "in both locales" but only checks
template usage (indexHtmlSource) and backend symbols (cliSource,
DEFAULT_SESSION_TRASH_RETENTION_DAYS, purgeExpiredSessionTrashEntries); either
rename the test to something like "references retention i18n key and backend
symbols" or add explicit assertions that the locale dictionaries contain the
'settings.trash.retention' key for both language objects (e.g.,
assert(localesEn.includes('settings.trash.retention')) and
assert(localesZh.includes('settings.trash.retention'))), keeping the existing
checks for indexHtmlSource and cliSource intact.

Comment on lines +99 to 102
:value="sessionsUsageSelectedDayKey || (sessionUsageDailyTableRows[0] && sessionUsageDailyTableRows[0].key) || ''"
@change="selectSessionsUsageDay(($event.target && $event.target.value) ? String($event.target.value) : '')">
<option value="">{{ t('usage.dayDetail.pick') }}</option>
<option v-for="day in sessionUsageDailyTableRows" :key="'day-select-' + day.key" :value="day.key">{{ day.key }}</option>
</select>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Day selector clear-state is no longer representable.

On Line 99, forcing :value to the first row key when sessionsUsageSelectedDayKey is empty makes clearSessionsUsageDay visually ambiguous and can desync the select UI from cleared detail state.

💡 Proposed fix
-:value="sessionsUsageSelectedDayKey || (sessionUsageDailyTableRows[0] && sessionUsageDailyTableRows[0].key) || ''"
+:value="sessionsUsageSelectedDayKey || ''"
 `@change`="selectSessionsUsageDay(($event.target && $event.target.value) ? String($event.target.value) : '')">
+    <option value="">{{ t('usage.dayDetail.pick') }}</option>
     <option v-for="day in sessionUsageDailyTableRows" :key="'day-select-' + day.key" :value="day.key">{{ day.key }}</option>
 </select>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
:value="sessionsUsageSelectedDayKey || (sessionUsageDailyTableRows[0] && sessionUsageDailyTableRows[0].key) || ''"
@change="selectSessionsUsageDay(($event.target && $event.target.value) ? String($event.target.value) : '')">
<option value="">{{ t('usage.dayDetail.pick') }}</option>
<option v-for="day in sessionUsageDailyTableRows" :key="'day-select-' + day.key" :value="day.key">{{ day.key }}</option>
</select>
:value="sessionsUsageSelectedDayKey || ''"
`@change`="selectSessionsUsageDay(($event.target && $event.target.value) ? String($event.target.value) : '')">
<option value="">{{ t('usage.dayDetail.pick') }}</option>
<option v-for="day in sessionUsageDailyTableRows" :key="'day-select-' + day.key" :value="day.key">{{ day.key }}</option>
</select>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web-ui/partials/index/panel-usage.html` around lines 99 - 102, The select
forces a fallback to sessionUsageDailyTableRows[0].key so clearing via
clearSessionsUsageDay can't be represented; change the binding to use only
sessionsUsageSelectedDayKey (defaulting to '' when undefined) and add a
dedicated empty option (e.g., <option :key="'day-select-empty'" value="">) so
the UI can show a cleared state, and ensure select handler
selectSessionsUsageDay continues to accept and handle '' (empty string) as the
cleared value.

SurviveM added 2 commits May 5, 2026 23:23
- Resolve merge conflict in claude-config.mjs (keep try/catch fix)
- Normalize retentionDays in parity test HEAD baseline calls
- Add autoPurge: false to e2e stale trash test API calls
@SurviveM SurviveM changed the title fix(web-ui): persist claude config selection and add Xiaomi presets feat(web-ui): heatmap, recycle bin auto-purge, and config improvements May 5, 2026
@ymkiux ymkiux merged commit adca196 into SakuraByteCore:main May 5, 2026
4 checks passed
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.

2 participants