Skip to content

feat: add notification history center#53

Merged
flyingrobots merged 4 commits intomainfrom
feat/post-v3-1-notification-center
Mar 19, 2026
Merged

feat: add notification history center#53
flyingrobots merged 4 commits intomainfrom
feat/post-v3-1-notification-center

Conversation

@flyingrobots
Copy link
Copy Markdown
Owner

@flyingrobots flyingrobots commented Mar 19, 2026

Summary

  • add a reusable notification history renderer plus a history-center modal in the notifications demo
  • expose the history view through the command palette with scroll/filter controls for archived notifications
  • upgrade GitHub workflow action majors to the Node 24-compatible runtime and refresh roadmap/changelog notes

Verification

  • npm run build
  • npm run typecheck:test
  • npx vitest run --config vitest.config.ts packages/bijou-tui/src/notification.test.ts
  • npx vitest run --config vitest.config.ts packages/bijou-tui/src/app-frame.test.ts
  • npm run workflow:shell:preflight
  • CI=1 node --import tsx examples/notifications/main.ts
  • npm run smoke:examples:all
  • npm test

Summary by CodeRabbit

  • New Features

    • Notification history modal: browse archived notifications, cycle filters (All/Actionable/by type), scroll navigation, and open via command palette/shortcut.
  • Documentation

    • Example and changelog updated to document the new notification history APIs and usage.
  • Chores

    • CI and publish workflows updated to newer GitHub Actions versions.
  • Tests

    • Added tests for history rendering, filtering, scrolling, and demo interactions.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 19, 2026

📝 Walkthrough

Walkthrough

Adds a notification history feature (counting, filtering, scrollable modal, command integration), exports new history APIs, updates example/demo to use the history UI, adds tests, and bumps several GitHub Actions to newer major versions across workflows.

Changes

Cohort / File(s) Summary
GitHub Actions Workflows
​.github/workflows/ci.yml, ​.github/workflows/publish.yml, ​.github/workflows/release-dry-run.yml
Bumped third‑party action major versions: actions/checkout@v4@v6, actions/setup-node@v4@v6, and actions/upload-artifact@v4@v7 (no other workflow logic changed).
Changelog & Examples Docs
docs/CHANGELOG.md, examples/README.md
Documented the notification history feature and updated examples README to list renderNotificationHistory() in the notifications example API.
Example Notification App
examples/notifications/main.ts
Added history modal state and controls (historyOpen, historyScroll, historyFilterIndex, HISTORY_FILTERS), command palette entry, navigation/quit handling, exported demo app/context, and conditional entry-run logic.
Core Notification API & Exports
packages/bijou-tui/src/notification.ts, packages/bijou-tui/src/index.ts
Introduced NotificationHistoryFilter and RenderNotificationHistoryOptions types; added countNotificationHistory() and renderNotificationHistory() implementations and exported them from package entry.
Tests — Notification History & Modal Key Handling
packages/bijou-tui/src/notification.test.ts, packages/bijou-tui/src/app-frame.test.ts, scripts/notifications-demo.test.ts
Added tests covering history counting/filtering/scrolling, modal key exclusivity (modalKeyMap behavior), and end-to-end demo flows including compact-terminal rendering and history shortcut behavior.
App Frame API
packages/bijou-tui/src/app-frame.ts
Added optional `modalKeyMap?: (model) => KeyMap

Sequence Diagram

sequenceDiagram
    actor User
    participant App as Notification App
    participant History as History Module
    participant Render as Render Engine

    User->>App: Trigger history (Shift+H / command)
    App->>App: Set historyOpen = true
    App->>History: countNotificationHistory(state, filter)
    History-->>App: totalCount
    App->>App: compute max visible / clamp scroll
    App->>History: renderNotificationHistory(state, {width,height,scroll,filter})
    History-->>App: formatted modal content
    App->>Render: overlay modal with content
    Render-->>User: display modal

    loop Navigation
        User->>App: Arrow / PgUp / PgDn
        App->>App: update historyScroll
        App->>History: renderNotificationHistory(...)
        History-->>App: updated content
        App->>Render: redraw modal
        Render-->>User: updated view
    end

    User->>App: Press Escape / quit
    App->>App: close modal (historyOpen = false)
    App->>Render: render main app
    Render-->>User: main view
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐇 Hop-hop, I scrolled the past tonight,

Archived bells kept neat and bright,
Filters spin and pages glide,
Modal opens — history’s pride,
V6 actions hum while rabbits write.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly and accurately summarizes the main feature being added—a notification history center—which aligns with the primary changes across the codebase.

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

✨ 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/post-v3-1-notification-center
📝 Coding Plan
  • Generate coding plan for human review comments

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

@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.

🧹 Nitpick comments (2)
.github/workflows/release-dry-run.yml (1)

126-129: actions/upload-artifact remains at v4 while other actions were bumped to v6.

This may be intentional if upload-artifact doesn't have a v6 release, but verify consistency if a newer version is available that addresses the Node 20 deprecation warning mentioned in the changelog.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/release-dry-run.yml around lines 126 - 129, The workflow
is pinning actions/upload-artifact@v4 while other actions were bumped to v6;
verify whether a v6 (or newer) release of actions/upload-artifact exists and, if
it does, update the usage string "actions/upload-artifact@v4" to the newer tag
(e.g., `@v6`) in the release-dry-run.yml, or add a comment explaining why v4 must
remain if no compatible v6 exists, so the workflow is consistent and avoids Node
20 deprecation warnings.
packages/bijou-tui/src/notification.ts (1)

147-152: Avoid intermediate allocation in countNotificationHistory.

filter(...).length allocates an array each call; a loop keeps it allocation-free.

♻️ Proposed change
 export function countNotificationHistory<Msg>(
   state: NotificationState<Msg>,
   filter: NotificationHistoryFilter = 'ALL',
 ): number {
-  return state.history.filter((item) => matchesHistoryFilter(item, filter)).length;
+  let count = 0;
+  for (const item of state.history) {
+    if (matchesHistoryFilter(item, filter)) count++;
+  }
+  return count;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/bijou-tui/src/notification.ts` around lines 147 - 152,
countNotificationHistory currently uses state.history.filter(...).length which
allocates an intermediate array; replace that with an allocation-free counting
loop that iterates over state.history and increments a counter when
matchesHistoryFilter(item, filter) is true, then return the counter. Locate the
function countNotificationHistory and the use of matchesHistoryFilter, iterate
over the NotificationState<Msg>.history array directly (for/for-of) to avoid
creating the filtered array; keep the same signature and behavior for
NotificationHistoryFilter.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In @.github/workflows/release-dry-run.yml:
- Around line 126-129: The workflow is pinning actions/upload-artifact@v4 while
other actions were bumped to v6; verify whether a v6 (or newer) release of
actions/upload-artifact exists and, if it does, update the usage string
"actions/upload-artifact@v4" to the newer tag (e.g., `@v6`) in the
release-dry-run.yml, or add a comment explaining why v4 must remain if no
compatible v6 exists, so the workflow is consistent and avoids Node 20
deprecation warnings.

In `@packages/bijou-tui/src/notification.ts`:
- Around line 147-152: countNotificationHistory currently uses
state.history.filter(...).length which allocates an intermediate array; replace
that with an allocation-free counting loop that iterates over state.history and
increments a counter when matchesHistoryFilter(item, filter) is true, then
return the counter. Locate the function countNotificationHistory and the use of
matchesHistoryFilter, iterate over the NotificationState<Msg>.history array
directly (for/for-of) to avoid creating the filtered array; keep the same
signature and behavior for NotificationHistoryFilter.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 657cc72d-bb44-4cc2-8964-11779a512277

📥 Commits

Reviewing files that changed from the base of the PR and between e066eb5 and 81f9c0c.

⛔ Files ignored due to path filters (1)
  • docs/ROADMAP.md is excluded by !docs/ROADMAP.md
📒 Files selected for processing (9)
  • .github/workflows/ci.yml
  • .github/workflows/publish.yml
  • .github/workflows/release-dry-run.yml
  • docs/CHANGELOG.md
  • examples/README.md
  • examples/notifications/main.ts
  • packages/bijou-tui/src/index.ts
  • packages/bijou-tui/src/notification.test.ts
  • packages/bijou-tui/src/notification.ts

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 81f9c0c0f0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/bijou-tui/src/notification.ts Outdated
Comment thread examples/notifications/main.ts Outdated
Comment thread examples/notifications/main.ts Outdated
@flyingrobots
Copy link
Copy Markdown
Owner Author

Addressed the remaining non-threaded review notes in ca36814 and 94e4e03:

  • countNotificationHistory() now uses an allocation-free counting loop
  • .github/workflows/release-dry-run.yml now uses actions/upload-artifact@v7 after verifying the current upstream release
  • the changelog records the notification-history and workflow follow-up fixes

Copy link
Copy Markdown

@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.

🧹 Nitpick comments (1)
scripts/notifications-demo.test.ts (1)

31-48: Consider resetting context after compact terminal test.

The test sets compactCtx as the default context but doesn't restore the original testCtx afterward. While afterAll calls _resetDefaultContextForTesting, this could cause issues if additional tests are added to this suite that expect the 80x24 terminal size.

🧹 Suggested improvement
   it('clamps the history center to compact terminals', async () => {
     const compactCtx = createTestContext({
       noColor: true,
       runtime: { columns: 40, rows: 12 },
     });
     setDefaultContext(compactCtx);
 
     const app = createNotificationDemoApp(compactCtx, { autoDemo: false });
     const result = await runScript(app, [{ key: 'H' }], {
       ctx: compactCtx,
       pulseFps: false,
     });
 
     const rendered = surfaceToString(result.frames.at(-1)!, compactCtx.style);
     expect(rendered).toContain('History');
     expect(rendered).toContain('PgUp/PgDn');
     expect(rendered).toContain('No archived notifications');
+
+    // Restore original context for subsequent tests
+    setDefaultContext(testCtx);
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/notifications-demo.test.ts` around lines 31 - 48, This test sets a
custom default context (compactCtx) via setDefaultContext but never restores the
original context; wrap the test body or add a finally/afterEach to call
_resetDefaultContextForTesting() (or explicitly restore the prior context) so
subsequent tests expecting the default 80x24 terminal aren't affected; locate
the compactCtx creation and setDefaultContext call in this test (and references
to createNotificationDemoApp/runScript) and ensure the default is reset at the
end of the test.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@scripts/notifications-demo.test.ts`:
- Around line 31-48: This test sets a custom default context (compactCtx) via
setDefaultContext but never restores the original context; wrap the test body or
add a finally/afterEach to call _resetDefaultContextForTesting() (or explicitly
restore the prior context) so subsequent tests expecting the default 80x24
terminal aren't affected; locate the compactCtx creation and setDefaultContext
call in this test (and references to createNotificationDemoApp/runScript) and
ensure the default is reset at the end of the test.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: deed6748-7b88-4956-af59-43b252aebe66

📥 Commits

Reviewing files that changed from the base of the PR and between 81f9c0c and 94e4e03.

📒 Files selected for processing (8)
  • .github/workflows/release-dry-run.yml
  • docs/CHANGELOG.md
  • examples/notifications/main.ts
  • packages/bijou-tui/src/app-frame.test.ts
  • packages/bijou-tui/src/app-frame.ts
  • packages/bijou-tui/src/notification.test.ts
  • packages/bijou-tui/src/notification.ts
  • scripts/notifications-demo.test.ts
✅ Files skipped from review due to trivial changes (2)
  • .github/workflows/release-dry-run.yml
  • docs/CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/bijou-tui/src/notification.test.ts

@flyingrobots flyingrobots merged commit a75e630 into main Mar 19, 2026
4 checks passed
@flyingrobots flyingrobots deleted the feat/post-v3-1-notification-center branch March 19, 2026 18:18
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