Skip to content

feat: save recent generations in local history - #224

Merged
naheel0 merged 5 commits into
mainfrom
feat/162-recent-generations-history
Aug 8, 2026
Merged

feat: save recent generations in local history#224
naheel0 merged 5 commits into
mainfrom
feat/162-recent-generations-history

Conversation

@naheel0

@naheel0 naheel0 commented Aug 8, 2026

Copy link
Copy Markdown
Member

Closes #162

Persists recent generated repositories in the browser (localStorage) and adds a history panel to the generate page.

Changes

  • New \src/lib/generationHistory.ts\ — SSR-safe storage layer with max 10 entries, markdown cap (~120KB), URL+language dedupe, oldest-eviction, quota-exceeded retry, and corrupt-data tolerance.
  • New \src/components/Generator/GenerationHistory.tsx\ — collapsible panel showing recent generations with relative timestamps and language badges; clicking an item restores the saved output and pre-fills the form; clear-all with inline confirm; note that data stays on-device.
  • \GeneratePageClient.tsx\ — history state, cross-tab sync via the \storage\ event, persistence on successful generation, restore and clear handlers.
  • \SearchInput.tsx\ — optional \initialLanguage\ prop so a restored entry pre-fills both URL and language.
  • Unit tests: \src/tmp/generationHistory.test.ts\ (append/dedupe/eviction/truncation, corrupt-data tolerance, quota fallback, round-trip, remove/clear).

Acceptances

  • Recent generations survive refresh (localStorage-backed). ✔
  • Last few repos reopen via the panel (restores output + form, no regeneration). ✔
  • History can be cleared from the UI. ✔

Validation


  • px vitest run\ — 17/17 passing

  • pm run lint,
    px tsc --noEmit,
    pm run build\ — clean

@naheel0
naheel0 requested a review from adithyanmkd as a code owner August 8, 2026 18:05
@vercel

vercel Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
readme-gen-ai Ready Ready Preview Aug 8, 2026 6:29pm

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 7414fe9a-9b41-4946-aa01-cd2f89713a41

📥 Commits

Reviewing files that changed from the base of the PR and between 9685bb2 and c9c5880.

📒 Files selected for processing (1)
  • src/app/generate/GeneratePageClient.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app/generate/GeneratePageClient.tsx

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added browser-saved generation history for previously created content.
    • View, expand, and restore saved entries, including repository URL, language, generated content, and preview position.
    • Restored entries preserve their original language selection.
    • Clear all saved history with confirmation.
    • History stays synchronized across browser tabs.
  • Bug Fixes

    • Improved handling of invalid, duplicate, oversized, or storage-limited history data.

Walkthrough

The PR adds bounded browser storage for generated markdown, a history panel, cross-tab synchronization, restoration of repository and language values, and clearing controls. Tests cover normalization, limits, invalid data, persistence, quota recovery, removal, and clearing.

Changes

Generation history

Layer / File(s) Summary
History storage and validation
src/lib/generationHistory.ts, src/__tmp__/generationHistory.test.ts
Adds normalized, validated, size-limited history storage with resilient persistence, removal, clearing, and comprehensive tests.
Generate page integration
src/app/generate/GeneratePageClient.tsx, src/components/Generator/SearchInput.tsx
Persists successful generations, synchronizes storage events, restores form and preview state, and supports initial language values.
History panel behavior
src/components/Generator/GenerationHistory.tsx
Adds expandable history entries, active-entry highlighting, restore actions, relative timestamps, and two-step clearing.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GeneratePageClient
  participant generationHistory
  participant localStorage
  participant GenerationHistory
  GeneratePageClient->>generationHistory: append generated markdown
  generationHistory->>localStorage: save bounded history
  localStorage-->>GeneratePageClient: storage event
  GeneratePageClient->>GenerationHistory: render synchronized entries
  GenerationHistory->>GeneratePageClient: restore selected entry
  GeneratePageClient->>GeneratePageClient: restore form and preview
Loading

Possibly related PRs

Suggested labels: area: frontend

Suggested reviewers: adithyanmkd

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: saving recent generations in local history.
Description check ✅ Passed The description directly explains local persistence, the history panel, restoration, clearing, and validation for the changeset.
Linked Issues check ✅ Passed The implementation satisfies issue #162 by persisting generations, providing a history panel, restoring entries, and clearing history.
Out of Scope Changes check ✅ Passed The changes remain within issue #162 scope and include supporting tests for the new history functionality.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/162-recent-generations-history

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 `@src/app/generate/GeneratePageClient.tsx`:
- Around line 114-123: Update the history handling around appendGeneration so
next is computed from the current history outside the setHistory functional
updater, then pass next to saveHistory and setHistory separately. Remove the
persistence side effect from the setHistory callback while preserving the
existing appendGeneration inputs and update order.

In `@src/components/Generator/GenerationHistory.tsx`:
- Line 49: Update GenerationHistory to receive the active history entry id from
GeneratePageClient and determine the active row by comparing entry.id with that
id, removing the URL-only activeUrl comparison. Ensure GeneratePageClient passes
the restored or currently selected entry id through the component props.

In `@src/lib/generationHistory.ts`:
- Around line 17-20: Update getStorage so the globalThis.localStorage property
access is wrapped in try/catch; return the retrieved storage on success and null
when accessing it throws, while preserving the existing undefined-global and
missing-storage behavior.
- Around line 113-126: Update saveHistory to return the pool that was
successfully persisted, while distinguishing the no-storage or completely
failed-write case. Update GeneratePageClient’s history state flow to consume
that result and replace its in-memory entries with the persisted subset after
quota eviction, preserving consistent behavior across refreshes and tabs.
🪄 Autofix

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 Plus

Run ID: ed69b1ac-4a60-4c2f-858a-eb7cec0b41c4

📥 Commits

Reviewing files that changed from the base of the PR and between c70640f and 477da2f.

📒 Files selected for processing (5)
  • src/__tmp__/generationHistory.test.ts
  • src/app/generate/GeneratePageClient.tsx
  • src/components/Generator/GenerationHistory.tsx
  • src/components/Generator/SearchInput.tsx
  • src/lib/generationHistory.ts

Comment thread src/app/generate/GeneratePageClient.tsx Outdated
Comment thread src/components/Generator/GenerationHistory.tsx Outdated
Comment thread src/lib/generationHistory.ts Outdated
Comment on lines +113 to +126
export function saveHistory(
entries: GenerationHistoryEntry[],
storage: StorageLike | null = getStorage(),
): void {
if (!storage) return;
let pool = entries;
for (;;) {
try {
storage.setItem(GENERATION_HISTORY_KEY, JSON.stringify(pool));
return;
} catch {
if (pool.length <= 1) return;
pool = pool.slice(0, Math.ceil(pool.length / 2));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Keep in-memory history equal to the persisted history after quota eviction.

When setItem rejects a large payload, this function writes a smaller pool but does not return it. GeneratePageClient retains the original list, so entries can remain visible until refresh and then disappear. Other tabs also load a different list.

Return the successfully saved pool, or a result that distinguishes a failed write. Update GeneratePageClient to use the returned entries as its state.

🤖 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 `@src/lib/generationHistory.ts` around lines 113 - 126, Update saveHistory to
return the pool that was successfully persisted, while distinguishing the
no-storage or completely failed-write case. Update GeneratePageClient’s history
state flow to consume that result and replace its in-memory entries with the
persisted subset after quota eviction, preserving consistent behavior across
refreshes and tabs.

@naheel0

naheel0 commented Aug 8, 2026

Copy link
Copy Markdown
Member Author

Addressed all 4 CodeRabbit comments:

  1. No side effects in setHistory updater
    ext is now computed from current history, saveHistory(next) runs first, then setHistory(next).
  2. Active entry by id — GenerationHistory now takes �ctiveEntryId and compares entry.id, not URL.
  3. getStorage try/catch — globalThis.localStorage access is guarded so blocked storage returns null instead of breaking mount.
  4. saveHistory returns persisted pool — returns the successfully written subset (or
    ull when nothing persisted); GeneratePageClient sets state from the returned value so memory stays in sync after quota eviction.

Re-verified: vitest 18/18, lint, tsc, build.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 `@src/components/Generator/GenerationHistory.tsx`:
- Around line 99-100: Update the generation flow around handleGenerate to
synchronize activeHistoryEntryId with the newly persisted generation entry,
replacing the restored ID or clearing it before generation starts. Ensure
GenerationHistory receives the current displayed generation ID so isActive
highlights entry B rather than a previously restored entry A.
🪄 Autofix

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 Plus

Run ID: 4a247af2-caa7-4590-b2cf-96ec9d4c6b4d

📥 Commits

Reviewing files that changed from the base of the PR and between 477da2f and 9685bb2.

📒 Files selected for processing (4)
  • src/__tmp__/generationHistory.test.ts
  • src/app/generate/GeneratePageClient.tsx
  • src/components/Generator/GenerationHistory.tsx
  • src/lib/generationHistory.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/lib/generationHistory.ts
  • src/tmp/generationHistory.test.ts
  • src/app/generate/GeneratePageClient.tsx

Comment on lines +99 to +100
const isActive = entry.id === activeEntryId;
return (

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Synchronize activeEntryId with the displayed generation.

GeneratePageClient.handleRestoreGeneration sets activeHistoryEntryId, but handleGenerate does not clear or replace it. If a user restores entry A and then generates entry B, this component still highlights A while displaying B. Update the parent state from the newly persisted entry ID, or clear it before starting a new generation.

🤖 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 `@src/components/Generator/GenerationHistory.tsx` around lines 99 - 100, Update
the generation flow around handleGenerate to synchronize activeHistoryEntryId
with the newly persisted generation entry, replacing the restored ID or clearing
it before generation starts. Ensure GenerationHistory receives the current
displayed generation ID so isActive highlights entry B rather than a previously
restored entry A.

@naheel0

naheel0 commented Aug 8, 2026

Copy link
Copy Markdown
Member Author

Fixed the remaining CodeRabbit comment: after a successful generation, \GeneratePageClient\ now sets \�ctiveHistoryEntryId\ to the newly persisted entry (index 0), so the history panel highlights the current displayed generation instead of a previously restored one. Verified: lint, tsc, vitest 18/18, build.

@naheel0
naheel0 merged commit daa286b into main Aug 8, 2026
7 checks passed
@naheel0
naheel0 deleted the feat/162-recent-generations-history branch August 8, 2026 18:33
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.

Save recent generations in local history

1 participant