Skip to content

[Dashboard] Introduce changelog to stack-companion#1090

Merged
madster456 merged 27 commits intodevfrom
dashboard/changelog
Jan 29, 2026
Merged

[Dashboard] Introduce changelog to stack-companion#1090
madster456 merged 27 commits intodevfrom
dashboard/changelog

Conversation

@madster456
Copy link
Collaborator

@madster456 madster456 commented Jan 8, 2026

Summary by CodeRabbit

  • New Features

    • Changelog panel now fetches and displays recent releases with rich Markdown rendering, per-release cards, and change-type labels.
    • Visual cues (badge, glow, tooltip) indicate when unseen updates are available; last-seen state tracked for users.
  • Chores

    • Configured external changelog data source and added a backend endpoint to serve parsed changelog entries.

✏️ Tip: You can customize this high-level summary in your review settings.

@cmux-agent
Copy link

cmux-agent bot commented Jan 8, 2026

Older cmux preview screenshots (latest comment is below)

Preview Screenshots

Open Diff Heatmap

Preview screenshots are being captured...

Workspace and dev browser links will appear here once the preview environment is ready.


Generated by cmux preview system

@vercel
Copy link

vercel bot commented Jan 8, 2026

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

Project Deployment Review Updated (UTC)
stack-backend Ready Ready Preview, Comment Jan 29, 2026 6:29pm
stack-dashboard Ready Ready Preview, Comment Jan 29, 2026 6:29pm
stack-demo Ready Ready Preview, Comment Jan 29, 2026 6:29pm
stack-docs Ready Ready Preview, Comment Jan 29, 2026 6:29pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 8, 2026

📝 Walkthrough

Walkthrough

This PR adds a backend API that parses a remote Markdown CHANGELOG and serves structured changelog entries, introduces shared changelog types, and integrates an API-driven, markdown-rendered changelog UI in the dashboard with cookie-based "last seen" tracking and visual new-release indicators.

Changes

Cohort / File(s) Summary
Environment Configuration
apps/dashboard/.env, apps/backend/.env.development
Added STACK_CHANGELOG_URL env var pointing to the raw GitHub CHANGELOG.md.
Backend API - Changelog Parsing
apps/backend/src/app/api/latest/internal/changelog/route.tsx
New route: fetches markdown from STACK_CHANGELOG_URL, parses sections (including "Unreleased", semver/CalVer), extracts bullets/tags/dates, validates with Yup, returns up to 8 ChangelogEntry items, handles fetch errors and sets revalidate=3600.
Shared Changelog Types
apps/dashboard/src/lib/changelog.ts
Added public types: `ChangeType = 'major'
Frontend - StackCompanion Integration
apps/dashboard/src/components/stack-companion.tsx
Fetches changelog from new API on mount (via runAsynchronously), reads/writes stack-last-seen-changelog-version cookie, compares CalVer/semver with isNewerCalVer, computes hasNewVersions, shows glow/badge and updates tooltip, passes initialData to ChangelogWidget.
Frontend - Changelog Widget Refactor
apps/dashboard/src/components/stack-companion/changelog-widget.tsx
Refactored to accept initialData?: ApiChangelogEntry[]; implements fetch fallback, loading/error states, per-version card layout, expand/collapse, ReactMarkdown+remarkGfm rendering, formatting helpers, and persistence of latest-seen via cookie.

Sequence Diagram

sequenceDiagram
    participant Browser as Browser/Dashboard
    participant SC as StackCompanion
    participant API as Backend API
    participant Source as CHANGELOG.md
    participant Storage as Cookie Storage

    Browser->>SC: Initialize / render
    SC->>Storage: Read `stack-last-seen-changelog-version`
    SC->>API: GET /api/latest/internal/changelog
    API->>Source: Fetch from STACK_CHANGELOG_URL
    Source-->>API: Markdown content
    API->>API: Parse markdown → ChangelogEntry[]
    API-->>SC: JSON (ChangelogEntry[] up to 8)
    SC->>SC: Compare entries vs lastSeenVersion (isNewerCalVer)
    SC->>Browser: Render ChangelogWidget (initialData)
    Browser->>Browser: Show badge/glow if hasNewVersions

    Browser->>SC: User opens changelog panel
    SC->>Storage: Set latest released version as seen (cookie)
    SC->>SC: Update hasNewVersions = false
    Browser->>Browser: Hide badge/glow
    Browser->>SC: Display per-version cards (markdown-rendered)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • N2D4

Poem

🐰 I hopped through markdown, parsed each line,
Server fetched the changelog, made versions shine,
Cookies keep watch of what I've seen,
Badges blink green for updates keen,
A gentle glow — hooray, release time! ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description contains only a template reminder comment with no substantive content, implementation details, or usage information provided by the author. Provide a detailed description explaining the purpose of the changelog feature, how it works, what changes were made, and any relevant testing or migration notes.
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title '[Dashboard] Introduce changelog to stack-companion' directly and clearly summarizes the main change: adding a changelog feature to the stack-companion component in the dashboard.

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


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
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Greptile Overview

Greptile Summary

This PR introduces a changelog feature to the Stack Companion widget that fetches and displays release notes from a remote markdown file. The implementation includes a new API endpoint that caches changelog data, a parser for markdown changelog format, and a redesigned widget that replaces the previous Featurebase integration.

Key changes:

  • New /api/changelog API route that fetches from STACK_CHANGELOG_URL environment variable with 1-hour caching
  • Markdown changelog parser supporting both semver and CalVer version formats
  • Changelog widget with ReactMarkdown rendering, expandable entries, and custom components for notes/images
  • Notification badge on companion icon when new versions are detected (tracked via cookies)
  • Removed Featurebase SDK dependency in favor of self-hosted solution

Critical issues found:

  • Version comparison bug: Uses string comparison (entry.version > lastSeen) which fails for version numbers (e.g., "10.0.0" < "9.0.0" lexicographically). This will cause the notification badge to display incorrectly for many version releases.
  • Cookie injection risk: Version strings written to cookies aren't sanitized, allowing semicolons or other special characters to break cookie parsing or inject additional cookie values.

Confidence Score: 2/5

  • This PR has critical logic bugs that will cause incorrect behavior in production
  • The version comparison logic uses string comparison which fundamentally breaks the notification feature, and unsanitized cookie values create a potential injection vector. Both issues need fixes before merging.
  • Pay close attention to apps/dashboard/src/components/stack-companion.tsx and apps/dashboard/src/components/stack-companion/changelog-widget.tsx - both contain version comparison and cookie handling bugs

Important Files Changed

File Analysis

Filename Score Overview
apps/dashboard/src/app/api/changelog/route.ts 4/5 New API endpoint to fetch and parse changelog from remote URL with caching
apps/dashboard/src/components/stack-companion/changelog-widget.tsx 2/5 Redesigned changelog widget with markdown rendering - has cookie sanitization and version comparison bugs
apps/dashboard/src/components/stack-companion.tsx 2/5 Integrated changelog feature with notification badge - has version comparison logic error

Sequence Diagram

sequenceDiagram
    participant User
    participant StackCompanion
    participant ChangelogWidget
    participant API as /api/changelog
    participant GitHub as Remote Changelog

    User->>StackCompanion: Opens dashboard
    activate StackCompanion
    StackCompanion->>API: GET /api/changelog
    activate API
    API->>GitHub: fetch(STACK_CHANGELOG_URL)
    GitHub-->>API: changelog.md (markdown)
    API->>API: parseRootChangelog(content)
    API-->>StackCompanion: { entries: [...] }
    deactivate API
    StackCompanion->>StackCompanion: Check document.cookie for last seen version
    StackCompanion->>StackCompanion: Compare versions (string comparison)
    alt Has newer versions
        StackCompanion->>StackCompanion: Set hasNewVersions badge
    end
    deactivate StackCompanion
    
    User->>StackCompanion: Clicks changelog button
    activate StackCompanion
    StackCompanion->>ChangelogWidget: Pass initialData
    activate ChangelogWidget
    ChangelogWidget->>ChangelogWidget: Set changelog state
    ChangelogWidget->>ChangelogWidget: Set cookie with latest version
    ChangelogWidget-->>User: Display changelog entries (ReactMarkdown)
    deactivate ChangelogWidget
    deactivate StackCompanion
Loading

Copy link
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: 3

🤖 Fix all issues with AI agents
In @apps/dashboard/src/components/stack-companion.tsx:
- Around line 157-161: The current comparison uses string lexicographic order
(entry.version > lastSeen) which breaks for semantic versions; update the
hasNewer calculation to use a proper semver comparison (e.g., use semver.gt from
the semver package) or determine newer entries by array order: find the index of
the lastSeen version in entries and mark any entries with a lower index as
newer. Modify the block that computes hasNewer (references: entries,
ChangelogEntry, lastSeen, setHasNewVersions) to use one of these approaches and
ensure you handle missing lastSeen (treat as all entries new) and unreleased
entries as before.

In @apps/dashboard/src/components/stack-companion/changelog-widget.tsx:
- Around line 88-99: ChangelogImage spreads arbitrary props into Next.js Image
which can pass unsafe or conflicting attributes; change the component to stop
using ...props and instead accept and forward a whitelist of allowed props (for
example: priority, quality, sizes, placeholder, loading, className, style) and
explicitly merge className if provided; update the ChangelogImage signature to
destructure only those named props and pass them to Image so unknown props are
not forwarded.
- Around line 228-229: The variable `collapse` computed inside the changelog.map
(const collapse = shouldCollapseContent(entry.markdown)) is unused; either
remove that line entirely or actually apply it to the rendered entry by passing
it as a prop or state flag (e.g., collapsed/collapse) to the component or
element returned from the map so the result of
shouldCollapseContent(entry.markdown) controls rendering (use the symbol
collapse and shouldCollapseContent and the changelog.map/entry.markdown context
to locate where to apply it).
🧹 Nitpick comments (5)
apps/dashboard/src/components/stack-companion.tsx (2)

173-197: Consider extracting duplicate version-checking logic.

This effect duplicates the version comparison logic from lines 152-162. Extract a shared helper function to reduce duplication and ensure consistency when fixing the string comparison issue.

Suggested helper extraction
const checkForNewVersions = (entries: ChangelogEntry[], lastSeen: string): boolean => {
  if (entries.length === 0) return false;
  if (!lastSeen) return true;
  
  const lastSeenIndex = entries.findIndex(e => e.version === lastSeen);
  return lastSeenIndex === -1 || lastSeenIndex > 0;
};

90-90: Unused state variable.

lastSeenVersion is set at line 150 but never read. Consider removing it if not needed, or use it to avoid redundant cookie parsing in the re-check effect.

apps/dashboard/src/lib/changelog.ts (1)

62-70: Empty bullet lines may render oddly.

When a bullet contains only tags (e.g., - [internal]), the output becomes just "-" (line 66), which may render as a visually empty bullet point. Consider filtering out such entries or preserving a placeholder.

apps/dashboard/src/components/stack-companion/changelog-widget.tsx (2)

11-20: Type duplication with @/lib/changelog.ts.

ChangeType and the changelog entry structure are already defined in @/lib/changelog.ts. Consider importing them to maintain a single source of truth.

Suggested import
+'use client';
+
+import { ChangelogEntry, ChangeType } from '@/lib/changelog';
 import { Button } from '@/components/ui';
-
-type ChangeType = 'major' | 'minor' | 'patch';
-
-type ApiChangelogEntry = {
-  version: string,
-  type: ChangeType,
-  markdown: string,
-  bulletCount: number,
-  releasedAt?: string,
-  isUnreleased?: boolean,
-};
+
+type ApiChangelogEntry = ChangelogEntry;

67-78: Avoid any type for component props.

Per coding guidelines, any should be avoided. Use proper React types for the blockquote props.

Suggested typing
-const NoteBlockquote = ({ children, ...props }: any) => {
+const NoteBlockquote = ({ children }: React.ComponentPropsWithoutRef<'blockquote'>) => {
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 50ffd37 and 5aad4e6.

📒 Files selected for processing (5)
  • apps/dashboard/.env
  • apps/dashboard/src/app/api/changelog/route.ts
  • apps/dashboard/src/components/stack-companion.tsx
  • apps/dashboard/src/components/stack-companion/changelog-widget.tsx
  • apps/dashboard/src/lib/changelog.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{tsx,ts,jsx,js}

📄 CodeRabbit inference engine (AGENTS.md)

For blocking alerts and errors, never use toast; instead, use alerts as toasts are easily missed by the user

Files:

  • apps/dashboard/src/app/api/changelog/route.ts
  • apps/dashboard/src/lib/changelog.ts
  • apps/dashboard/src/components/stack-companion/changelog-widget.tsx
  • apps/dashboard/src/components/stack-companion.tsx
**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

NEVER use Next.js dynamic functions if avoidable; prefer using client components instead to keep pages static (e.g., use usePathname instead of await params)

Files:

  • apps/dashboard/src/app/api/changelog/route.ts
  • apps/dashboard/src/lib/changelog.ts
  • apps/dashboard/src/components/stack-companion/changelog-widget.tsx
  • apps/dashboard/src/components/stack-companion.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: NEVER try-catch-all, NEVER void a promise, and NEVER use .catch(console.error) or similar; use loading indicators instead; if asynchronous handling is necessary, use runAsynchronously or runAsynchronouslyWithAlert instead
Use ES6 maps instead of records wherever possible

Files:

  • apps/dashboard/src/app/api/changelog/route.ts
  • apps/dashboard/src/lib/changelog.ts
  • apps/dashboard/src/components/stack-companion/changelog-widget.tsx
  • apps/dashboard/src/components/stack-companion.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Code defensively; prefer ?? throwErr(...) over non-null assertions with good error messages explicitly stating violated assumptions
Avoid the any type; when necessary, leave a comment explaining why it's used, why the type system fails, and how errors would be caught at compile-, test-, or runtime

Files:

  • apps/dashboard/src/app/api/changelog/route.ts
  • apps/dashboard/src/lib/changelog.ts
  • apps/dashboard/src/components/stack-companion/changelog-widget.tsx
  • apps/dashboard/src/components/stack-companion.tsx
**/*.{tsx,css}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{tsx,css}: Keep hover/click animations snappy and fast; don't delay actions with pre-transitions (e.g., no fade-in on button hover) as it makes UI feel sluggish; instead apply transitions after the action like smooth fade-out when hover ends
When creating hover transitions, avoid hover-enter transitions and use only hover-exit transitions (e.g., transition-colors hover:transition-none)

Files:

  • apps/dashboard/src/components/stack-companion/changelog-widget.tsx
  • apps/dashboard/src/components/stack-companion.tsx
🧠 Learnings (5)
📚 Learning: 2026-01-07T00:55:19.856Z
Learnt from: CR
Repo: stack-auth/stack-auth PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-07T00:55:19.856Z
Learning: The project uses Next.js with App Router framework for the backend, dashboard, and dev-launchpad apps

Applied to files:

  • apps/dashboard/src/app/api/changelog/route.ts
📚 Learning: 2026-01-07T00:55:19.856Z
Learnt from: CR
Repo: stack-auth/stack-auth PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-07T00:55:19.856Z
Learning: Applies to **/apps-frontend.tsx,**/apps-config.ts : To update the list of available apps, edit `apps-frontend.tsx` and `apps-config.ts`

Applied to files:

  • apps/dashboard/src/app/api/changelog/route.ts
📚 Learning: 2026-01-07T00:55:19.856Z
Learnt from: CR
Repo: stack-auth/stack-auth PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-07T00:55:19.856Z
Learning: When making changes in the dashboard, provide users with a deep link; typically formatted as `http://localhost:<$NEXT_PUBLIC_STACK_PORT_PREFIX>01/projects/-selector-/...`; use a.localhost, b.localhost, c.localhost for port prefixes 91, 92, 93 respectively

Applied to files:

  • apps/dashboard/src/app/api/changelog/route.ts
  • apps/dashboard/.env
📚 Learning: 2026-01-07T00:55:19.856Z
Learnt from: CR
Repo: stack-auth/stack-auth PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-07T00:55:19.856Z
Learning: Applies to .env*,**/.env* : Any environment variables created should be prefixed with `STACK_` (or `NEXT_PUBLIC_STACK_` if public) to ensure Turborepo picks up changes and improves readability

Applied to files:

  • apps/dashboard/.env
📚 Learning: 2025-10-11T04:13:19.308Z
Learnt from: N2D4
Repo: stack-auth/stack-auth PR: 943
File: examples/convex/app/action/page.tsx:23-28
Timestamp: 2025-10-11T04:13:19.308Z
Learning: In the stack-auth codebase, use `runAsynchronouslyWithAlert` from `stackframe/stack-shared/dist/utils/promises` for async button click handlers and form submissions instead of manual try/catch blocks. This utility automatically handles errors and shows alerts to users.

Applied to files:

  • apps/dashboard/src/components/stack-companion.tsx
🧬 Code graph analysis (3)
apps/dashboard/src/app/api/changelog/route.ts (1)
apps/dashboard/src/lib/changelog.ts (1)
  • parseRootChangelog (33-87)
apps/dashboard/src/components/stack-companion/changelog-widget.tsx (2)
apps/dashboard/src/lib/changelog.ts (1)
  • ChangeType (1-1)
packages/stack-shared/src/utils/promises.tsx (1)
  • runAsynchronously (343-366)
apps/dashboard/src/components/stack-companion.tsx (3)
apps/dashboard/src/lib/changelog.ts (1)
  • ChangelogEntry (3-11)
packages/stack-shared/src/utils/promises.tsx (1)
  • runAsynchronously (343-366)
apps/dashboard/src/components/stack-companion/changelog-widget.tsx (1)
  • ChangelogWidget (101-273)
🪛 dotenv-linter (4.0.0)
apps/dashboard/.env

[warning] 19-19: [UnorderedKey] The STACK_CHANGELOG_URL key should go before the STACK_DEVELOPMENT_TRANSLATION_LOCALE key

(UnorderedKey)


[warning] 19-19: [ValueWithoutQuotes] This value needs to be surrounded in quotes

(ValueWithoutQuotes)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
  • GitHub Check: Vercel Agent Review
  • GitHub Check: E2E Tests (Node 22.x, Freestyle prod)
  • GitHub Check: docker
  • GitHub Check: E2E Tests (Node 22.x, Freestyle mock)
  • GitHub Check: check_prisma_migrations (22.x)
  • GitHub Check: all-good
  • GitHub Check: build (22.x)
  • GitHub Check: build (22.x)
  • GitHub Check: lint_and_build (latest)
  • GitHub Check: restart-dev-and-test
  • GitHub Check: restart-dev-and-test-with-custom-base-port
  • GitHub Check: setup-tests-with-custom-base-port
  • GitHub Check: setup-tests
🔇 Additional comments (5)
apps/dashboard/.env (1)

19-19: LGTM!

The environment variable follows the STACK_ prefix convention correctly. The static analysis hints about key ordering and quotes are minor style nits that can be optionally addressed.

apps/dashboard/src/app/api/changelog/route.ts (1)

6-41: LGTM!

The route handler is well-structured with appropriate error handling:

  • Graceful fallback when STACK_CHANGELOG_URL is not configured
  • Proper HTTP status codes (502 for upstream failures, 500 for internal errors)
  • ISR caching via next.revalidate
  • Reasonable entry limit (8 items)

The try-catch pattern is acceptable here since this is a route handler that needs to return HTTP responses for error conditions.

apps/dashboard/src/components/stack-companion.tsx (1)

413-428: Nice UI indicators for new changelog updates.

The visual feedback with the glow ring and pulsing badge provides clear visibility for users about new updates.

apps/dashboard/src/lib/changelog.ts (1)

33-87: Well-structured changelog parser.

The parsing logic handles multiple version formats (semver, calver, unreleased), extracts change types from headings, and processes tagged bullets cleanly. Good defensive handling of edge cases with empty sections and non-conforming headings.

apps/dashboard/src/components/stack-companion/changelog-widget.tsx (1)

101-171: Well-implemented data fetching with proper abort handling.

Good use of AbortSignal for cleanup, hasFetchedRef to prevent duplicate fetches, and runAsynchronously for async handling. The fallback pattern between initialData and fetching is clean.

@cmux-agent
Copy link

cmux-agent bot commented Jan 8, 2026

Older cmux preview screenshots (latest comment is below)

Preview Screenshots

Open Diff Heatmap

Preview screenshots are being captured...

Workspace and dev browser links will appear here once the preview environment is ready.


Generated by cmux preview system

@cmux-agent
Copy link

cmux-agent bot commented Jan 10, 2026

Preview Screenshots

Open Diff Heatmap

Preview screenshots are being captured...

Workspace and dev browser links will appear here once the preview environment is ready.


Generated by cmux preview system

Copy link
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

🤖 Fix all issues with AI agents
In `@apps/dashboard/src/components/stack-companion/changelog-widget.tsx`:
- Around line 135-160: The effect should create an AbortController, pass its
signal into fetchChangelog(signal) when calling runAsynchronously, and ensure
cleanup aborts the controller to prevent state updates on unmounted components;
update the useEffect to call runAsynchronously(() =>
fetchChangelog(controller.signal)) (or pass the signal into the existing call),
check the signal (or catch an AbortError) before calling
setChangelog/setLoading, and call controller.abort() in the effect cleanup to
cancel the fetch; reference the useEffect block, fetchChangelog(AbortSignal),
hasFetchedRef, setChangelog, and setLoading when making these changes.
🧹 Nitpick comments (1)
apps/dashboard/src/components/stack-companion/changelog-widget.tsx (1)

20-29: Consider importing ChangeType and ChangelogEntry from the shared lib.

ChangeType is already exported from apps/dashboard/src/lib/changelog.ts. The ApiChangelogEntry type here appears to mirror the structure from the same lib. Importing these types would reduce duplication and ensure consistency.

-type ChangeType = 'major' | 'minor' | 'patch';
-
-type ApiChangelogEntry = {
-  version: string,
-  type: ChangeType,
-  markdown: string,
-  bulletCount: number,
-  releasedAt?: string,
-  isUnreleased?: boolean,
-};
+import { ChangeType, ChangelogEntry } from '@/lib/changelog';
+
+type ApiChangelogEntry = ChangelogEntry;
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3971834 and 0a30feb.

📒 Files selected for processing (1)
  • apps/dashboard/src/components/stack-companion/changelog-widget.tsx
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: For blocking alerts and errors, never use toast, as they are easily missed by the user. Instead, use alerts
Keep hover/click transitions snappy and fast without pre-transition delays (e.g., no fade-in when hovering a button). Apply transitions after the action, like smooth fade-out when hover ends
NEVER try-catch-all, NEVER void a promise, and NEVER .catch(console.error). Use loading indicators for async operations. Use runAsynchronously or runAsynchronouslyWithAlert instead of general try-catch error handling
When creating hover transitions, avoid hover-enter transitions and use only hover-exit transitions (e.g., transition-colors hover:transition-none)
Don't use Date.now() for measuring elapsed (real) time; instead use performance.now()
Use ES6 maps instead of records wherever possible

Files:

  • apps/dashboard/src/components/stack-companion/changelog-widget.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: NEVER use Next.js dynamic functions if you can avoid them. Prefer using client components to keep pages static (e.g., use usePathname instead of await params)
Code defensively using ?? throwErr(...) instead of non-null assertions, with good error messages explicitly stating violated assumptions
Try to avoid the any type. When using any, leave a comment explaining why and how the type system fails or how errors would still be caught

Files:

  • apps/dashboard/src/components/stack-companion/changelog-widget.tsx
{.env*,**/*.{ts,tsx,js,jsx}}

📄 CodeRabbit inference engine (AGENTS.md)

All environment variables should be prefixed with STACK_ (or NEXT_PUBLIC_STACK_ if public) to ensure Turborepo picks up changes and improve readability

Files:

  • apps/dashboard/src/components/stack-companion/changelog-widget.tsx
🧬 Code graph analysis (1)
apps/dashboard/src/components/stack-companion/changelog-widget.tsx (2)
apps/dashboard/src/lib/changelog.ts (1)
  • ChangeType (1-1)
packages/stack-shared/src/utils/promises.tsx (1)
  • runAsynchronously (343-366)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
  • GitHub Check: E2E Tests (Node 22.x, Freestyle mock)
  • GitHub Check: E2E Tests (Node 22.x, Freestyle prod)
  • GitHub Check: build (22.x)
  • GitHub Check: build (22.x)
  • GitHub Check: restart-dev-and-test-with-custom-base-port
  • GitHub Check: lint_and_build (latest)
  • GitHub Check: setup-tests-with-custom-base-port
  • GitHub Check: setup-tests
  • GitHub Check: restart-dev-and-test
  • GitHub Check: all-good
  • GitHub Check: Vercel Agent Review
  • GitHub Check: check_prisma_migrations (22.x)
  • GitHub Check: docker
🔇 Additional comments (2)
apps/dashboard/src/components/stack-companion/changelog-widget.tsx (2)

192-257: LGTM!

The render logic is well-structured with proper handling of error states (inline display, not toast), empty states, and the expandable changelog entries. The ReactMarkdown integration with custom components (NoteBlockquote, ChangelogListItem, ChangelogImage) is clean. Previous review concerns about unused variables have been addressed.


74-88: Ensure external changelog images are from allowed domains or configure additional remote patterns.

The changelog API fetches markdown from a remote URL (via STACK_CHANGELOG_URL environment variable) and renders images from that markdown using the Next.js Image component. The next.config.mjs only allows images from *.featurebase-attachments.com. If the remote changelog contains images from other domains, they will fail at runtime. Either verify the remote changelog uses only whitelisted domains, or add additional remotePatterns to the Next.js image config to match the actual image sources.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Copy link
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

🤖 Fix all issues with AI agents
In `@apps/dashboard/src/components/stack-companion.tsx`:
- Around line 166-200: The fetch in the useEffect (fetch('/api/changelog'))
returns early when response.ok is false, causing silent failure and leaving
changelog state undefined; update the block inside runAsynchronously to throw or
propagate an Error when !response.ok (include response.status and
response.statusText or response.text() for details) so runAsynchronously' error
handling can catch and log it, and ensure setChangelogData and setHasNewVersions
are only run after a successful response; reference the fetch call, the
response.ok check, and state setters setChangelogData / setHasNewVersions when
making the change.
♻️ Duplicate comments (1)
apps/dashboard/src/components/stack-companion/changelog-widget.tsx (1)

41-46: Code duplication with parent component for cookie management.

This function duplicates the cookie-setting logic found in stack-companion.tsx (lines 206-209). When the changelog is opened, the parent already sets the cookie before passing initialData to this widget, causing redundant writes.

Consider extracting a shared utility or removing one of the duplicate calls.

🧹 Nitpick comments (2)
apps/dashboard/src/components/stack-companion/changelog-widget.tsx (1)

14-31: Consider using interface for object shape definitions.

Per coding guidelines, prefer interface over type for defining object shapes in TypeScript.

Suggested refactor
-type ApiChangelogEntry = {
+interface ApiChangelogEntry {
   version: string,
   type: ChangeType,
   markdown: string,
   bulletCount: number,
   releasedAt?: string,
   isUnreleased?: boolean,
-};
+}

-type ChangelogItem = ApiChangelogEntry & {
+interface ChangelogItem extends ApiChangelogEntry {
   id: string,
   expanded: boolean,
-};
+}

-type ChangelogWidgetProps = {
+interface ChangelogWidgetProps {
   isActive: boolean,
   initialData?: ApiChangelogEntry[],
-};
+}
apps/dashboard/src/components/stack-companion.tsx (1)

179-182: Duplicate cookie reading logic within the same file.

The cookie parsing logic for stack-last-seen-changelog-version is duplicated at lines 179-182 and 215-218. Consider extracting to a helper function:

Suggested refactor
+function getLastSeenVersion(): string {
+  const lastSeenRaw = document.cookie
+    .split('; ')
+    .find(row => row.startsWith('stack-last-seen-changelog-version='))
+    ?.split('=')[1] || '';
+  return lastSeenRaw ? decodeURIComponent(lastSeenRaw) : '';
+}

 // Then use in both effects:
-      const lastSeenRaw = document.cookie
-        .split('; ')
-        .find(row => row.startsWith('stack-last-seen-changelog-version='))
-        ?.split('=')[1] || '';
-
-      const lastSeen = lastSeenRaw ? decodeURIComponent(lastSeenRaw) : '';
+      const lastSeen = getLastSeenVersion();

Also applies to: 215-218

@madster456 madster456 merged commit b32eb9e into dev Jan 29, 2026
10 of 11 checks passed
@madster456 madster456 deleted the dashboard/changelog branch January 29, 2026 18:22
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