[Dashboard] Introduce changelog to stack-companion#1090
Conversation
Older cmux preview screenshots (latest comment is below)Preview Screenshots⏳ Preview screenshots are being captured... Workspace and dev browser links will appear here once the preview environment is ready. Generated by cmux preview system |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughThis 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
Sequence DiagramsequenceDiagram
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)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✏️ 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. Comment |
There was a problem hiding this comment.
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/changelogAPI route that fetches fromSTACK_CHANGELOG_URLenvironment 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.tsxandapps/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
apps/dashboard/src/components/stack-companion/changelog-widget.tsx
Outdated
Show resolved
Hide resolved
apps/dashboard/src/components/stack-companion/changelog-widget.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
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.
lastSeenVersionis 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.
ChangeTypeand 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: Avoidanytype for component props.Per coding guidelines,
anyshould 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
📒 Files selected for processing (5)
apps/dashboard/.envapps/dashboard/src/app/api/changelog/route.tsapps/dashboard/src/components/stack-companion.tsxapps/dashboard/src/components/stack-companion/changelog-widget.tsxapps/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.tsapps/dashboard/src/lib/changelog.tsapps/dashboard/src/components/stack-companion/changelog-widget.tsxapps/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
usePathnameinstead ofawait params)
Files:
apps/dashboard/src/app/api/changelog/route.tsapps/dashboard/src/lib/changelog.tsapps/dashboard/src/components/stack-companion/changelog-widget.tsxapps/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, userunAsynchronouslyorrunAsynchronouslyWithAlertinstead
Use ES6 maps instead of records wherever possible
Files:
apps/dashboard/src/app/api/changelog/route.tsapps/dashboard/src/lib/changelog.tsapps/dashboard/src/components/stack-companion/changelog-widget.tsxapps/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 theanytype; 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.tsapps/dashboard/src/lib/changelog.tsapps/dashboard/src/components/stack-companion/changelog-widget.tsxapps/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.tsxapps/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.tsapps/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_URLis 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
AbortSignalfor cleanup,hasFetchedRefto prevent duplicate fetches, andrunAsynchronouslyfor async handling. The fallback pattern betweeninitialDataand fetching is clean.
apps/dashboard/src/components/stack-companion/changelog-widget.tsx
Outdated
Show resolved
Hide resolved
apps/dashboard/src/components/stack-companion/changelog-widget.tsx
Outdated
Show resolved
Hide resolved
Older cmux preview screenshots (latest comment is below)Preview Screenshots⏳ Preview screenshots are being captured... Workspace and dev browser links will appear here once the preview environment is ready. Generated by cmux preview system |
Preview Screenshots⏳ Preview screenshots are being captured... Workspace and dev browser links will appear here once the preview environment is ready. Generated by cmux preview system |
There was a problem hiding this comment.
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 importingChangeTypeandChangelogEntryfrom the shared lib.
ChangeTypeis already exported fromapps/dashboard/src/lib/changelog.ts. TheApiChangelogEntrytype 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
📒 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 usetoast, 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. UserunAsynchronouslyorrunAsynchronouslyWithAlertinstead 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 useDate.now()for measuring elapsed (real) time; instead useperformance.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., useusePathnameinstead ofawait params)
Code defensively using?? throwErr(...)instead of non-null assertions, with good error messages explicitly stating violated assumptions
Try to avoid theanytype. When usingany, 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_(orNEXT_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_URLenvironment variable) and renders images from that markdown using the Next.jsImagecomponent. Thenext.config.mjsonly 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 additionalremotePatternsto 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.
apps/dashboard/src/components/stack-companion/changelog-widget.tsx
Outdated
Show resolved
Hide resolved
apps/dashboard/src/components/stack-companion/changelog-widget.tsx
Outdated
Show resolved
Hide resolved
apps/dashboard/src/components/stack-companion/changelog-widget.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
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 passinginitialDatato 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 usinginterfacefor object shape definitions.Per coding guidelines, prefer
interfaceovertypefor 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-versionis 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
Summary by CodeRabbit
New Features
Chores
✏️ Tip: You can customize this high-level summary in your review settings.