Updated to latest version of ESlint ghost plugin#25713
Conversation
|
Warning Rate limit exceeded@ibalosh has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 1 minutes and 7 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (55)
WalkthroughRemoved a local patch in apps/admin/eslint.config.js and changed its parserOptions from Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20–30 minutes
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
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.
Actionable comments posted: 0
🧹 Nitpick comments (5)
apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx (2)
33-41: Consider using an explicitifstatement to avoid the ESLint suppression.The logical AND pattern for conditional execution is valid but triggers the
no-unused-expressionsrule. Refactoring to an explicitifstatement would eliminate the need for the suppression comment and improve clarity.Apply this diff:
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions - !!item.errors.label && clearError?.('label'); + if (item.errors.label) { + clearError?.('label'); + }Note: The
!!double negation is also unnecessary since theifstatement coerces to boolean automatically.
60-69: Consider using an explicitifstatement to avoid the ESLint suppression.Same pattern as above—refactoring to an explicit
ifstatement would eliminate the suppression and improve code clarity.Apply this diff:
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions - !!item.errors.url && clearError?.('url'); + if (item.errors.url) { + clearError?.('url'); + }apps/posts/src/views/PostAnalytics/Growth/growth.tsx (1)
16-16: LGTM! Type alias aligns with ESLint standardization.The change is consistent with the ESLint-driven refactoring across PostAnalytics components. Note: This line includes a semicolon while the equivalent lines in
web.tsxandnewsletter.tsxdo not—consider standardizing for consistency, though this is a minor stylistic detail.apps/activitypub/src/views/profile/profile.tsx (1)
13-13: Tighten ProfileProps to reflect “no props” intentUsing
objecthere makesProfileaccept any non‑primitive props. If the component truly has no props, consider:-type ProfileProps = object +type ProfileProps = {}(or
Record<string, never>) for clearer intent and stricter typing.apps/activitypub/src/components/modals/new-note-modal.tsx (1)
75-104: Stale comment still refers to anerrorvariableThe switch to a bare
catchis fine behavior‑wise, but the commentedconsole.error('Failed to create post:', error);is now misleading because there’s noerrorbinding anymore. Consider removing that comment or rephrasing it so it doesn’t rely on an unavailable variable.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (53)
apps/activitypub/src/api/activitypub.ts(1 hunks)apps/activitypub/src/components/modals/new-note-modal.tsx(1 hunks)apps/activitypub/src/hooks/use-activity-pub-queries.ts(3 hunks)apps/activitypub/src/utils/get-username.ts(1 hunks)apps/activitypub/src/utils/image.ts(1 hunks)apps/activitypub/src/views/preferences/components/bluesky-sharing.tsx(1 hunks)apps/activitypub/src/views/preferences/components/profile.tsx(1 hunks)apps/activitypub/src/views/profile/profile.tsx(1 hunks)apps/admin-x-design-system/src/global/sortable-list.tsx(1 hunks)apps/admin-x-design-system/src/typings.d.ts(1 hunks)apps/admin-x-design-system/src/utils/format-url.ts(1 hunks)apps/admin-x-framework/src/api/config.ts(1 hunks)apps/admin-x-framework/src/api/recommendations.ts(1 hunks)apps/admin-x-framework/src/test/acceptance.ts(1 hunks)apps/admin-x-framework/src/test/test-utils.tsx(1 hunks)apps/admin-x-framework/test/unit/hooks/use-form.test.ts(2 hunks)apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/incoming-recommendation-list.tsx(1 hunks)apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx(2 hunks)apps/admin-x-settings/src/typings.d.ts(1 hunks)apps/admin-x-settings/src/utils/link-to-github-releases.ts(1 hunks)apps/admin-x-settings/src/utils/url.ts(1 hunks)apps/comments-ui/src/actions.ts(2 hunks)apps/comments-ui/src/app-context.ts(1 hunks)apps/comments-ui/src/components/content/forms/form.tsx(1 hunks)apps/comments-ui/src/components/popup-box.tsx(1 hunks)apps/comments-ui/src/typings.d.ts(1 hunks)apps/comments-ui/src/utils/admin-api.ts(1 hunks)apps/comments-ui/src/utils/api.ts(1 hunks)apps/posts/src/hooks/use-post-success-modal.ts(1 hunks)apps/posts/src/utils/link-helpers.ts(1 hunks)apps/posts/src/views/PostAnalytics/Growth/growth.tsx(1 hunks)apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx(1 hunks)apps/posts/src/views/PostAnalytics/Web/web.tsx(1 hunks)apps/shade/src/components/features/color-picker/color-picker.tsx(1 hunks)apps/shade/src/components/layout/header.tsx(6 hunks)apps/shade/src/components/layout/heading.tsx(1 hunks)apps/shade/src/components/layout/page.tsx(1 hunks)apps/shade/src/components/layout/view-header.tsx(2 hunks)apps/shade/src/components/ui/card.tsx(1 hunks)apps/shade/src/lib/utils.ts(1 hunks)apps/shade/src/typings.d.ts(1 hunks)apps/signup-form/src/components/pages/form-page.tsx(1 hunks)apps/signup-form/src/typings.d.ts(1 hunks)apps/stats/src/hooks/use-feature-flag.tsx(1 hunks)apps/stats/src/types/svg.d.ts(1 hunks)apps/stats/src/utils/url-helpers.ts(5 hunks)apps/stats/test/utils/tinybird-helpers.ts(1 hunks)ghost/core/core/server/services/recommendations/service/RecommendationMetadataService.ts(2 hunks)ghost/core/core/server/services/recommendations/service/UnsafeData.ts(1 hunks)
✅ Files skipped from review due to trivial changes (6)
- apps/shade/src/typings.d.ts
- apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx
- apps/admin-x-framework/src/test/test-utils.tsx
- apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx
- apps/comments-ui/src/components/popup-box.tsx
- apps/admin-x-settings/src/typings.d.ts
🧰 Additional context used
📓 Path-based instructions (7)
apps/shade/src/components/layout/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
Reusable layout containers (Page, Heading, Header, ViewHeader, ErrorPage) should be placed in
src/components/layout/*
Files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/view-header.tsxapps/shade/src/components/layout/page.tsx
apps/shade/src/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/src/components/**/*.{ts,tsx}: UsePascalCasefor component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Always forward and mergeclassNameprop withcn(...)utility function
Use CVA (Class Variance Authority) for component variants when useful instead of heavy prop configuration
Prefer compound subcomponents (e.g.,Header.Title,Header.Meta,Header.Actions) for multi-region components instead of many props
Use Tailwind CSS scoped via.shadeclass; dark mode uses.dark
Files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/components/ui/card.tsxapps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/view-header.tsxapps/shade/src/components/layout/page.tsx
apps/shade/src/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/src/**/*.{ts,tsx,js}: UsecamelCasefor function and variable names
Use the@alias for internal imports (e.g.,@/lib/utils)
Files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/lib/utils.tsapps/shade/src/components/ui/card.tsxapps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/view-header.tsxapps/shade/src/components/layout/page.tsx
apps/shade/{src,test}/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/{src,test}/**/*.{ts,tsx,js}: Runyarn lintafter making changes to fix any ESLint errors and warnings before committing
Follow ESLint andtailwindcss/*plugin rules when writing styles
Files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/lib/utils.tsapps/shade/src/components/ui/card.tsxapps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/view-header.tsxapps/shade/src/components/layout/page.tsx
apps/shade/src/lib/utils.ts
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
Shared utilities (class merging, formatting, chart helpers) should be centralized in
src/lib/utils.ts
Files:
apps/shade/src/lib/utils.ts
apps/shade/src/components/ui/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
Atomic UI components should be placed in
src/components/ui/*and each component must have a corresponding*.stories.tsxfile next to it for Storybook documentation
Files:
apps/shade/src/components/ui/card.tsx
apps/shade/src/components/features/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
Higher-level, opinionated components (e.g., PostShareModal, SourceTabs) should be placed in
src/components/features/*
Files:
apps/shade/src/components/features/color-picker/color-picker.tsx
🧠 Learnings (29)
📓 Common learnings
Learnt from: cmraible
Repo: TryGhost/Ghost PR: 24658
File: ghost/admin/package.json:3-3
Timestamp: 2025-08-12T18:33:15.524Z
Learning: In Ghost's admin package.json, third-party packages like ember-cli-postcss, ember-exam, and ember-power-select have their own independent versioning schemes that are unrelated to Ghost's version numbers. Version number coincidences between Ghost versions and these packages should not trigger update suggestions.
Learnt from: niranjan-uma-shankar
Repo: TryGhost/Ghost PR: 24557
File: apps/admin-x-settings/src/components/settings/general/TimeZone.tsx:7-7
Timestamp: 2025-08-01T12:44:07.467Z
Learning: In Ghost development, PRs may depend on unpublished changes from SDK packages. When this occurs, TypeScript compilation errors for missing exports are expected and documented in the PR description until the dependency packages are published and updated. This is normal workflow for cross-repository feature development.
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 24651
File: ghost/core/test/utils/urlUtils.js:53-57
Timestamp: 2025-08-11T19:39:00.428Z
Learning: In Ghost's test utilities, when fixing specific issues like async behavior, it's preferred to maintain existing error handling patterns (even if suboptimal) to keep PRs focused on their primary objective. Error handling improvements can be addressed in separate, dedicated PRs.
Learnt from: sagzy
Repo: TryGhost/Ghost PR: 24673
File: ghost/i18n/lib/i18n.js:34-35
Timestamp: 2025-11-24T11:12:15.712Z
Learning: In the Ghost i18n package (ghost/i18n/lib/i18n.js), changing existing locale codes requires backwards compatibility handling for users who have already configured those locales. Such changes should be done in a separate PR with migration logic rather than included in feature PRs.
Learnt from: sam-lord
Repo: TryGhost/Ghost PR: 25303
File: ghost/core/core/server/services/email-service/BatchSendingService.js:19-19
Timestamp: 2025-10-30T17:13:26.190Z
Learning: In ghost/core/core/server/services/email-service/BatchSendingService.js and similar files in the Ghost codebase, prefer using `{...options}` spread syntax without explicit guards like `...(options || {})` when spreading potentially undefined objects, as the maintainer prefers cleaner syntax over defensive patterns when the behavior is safe.
Learnt from: ErisDS
Repo: TryGhost/Ghost PR: 23644
File: ghost/admin/tests/unit/controllers/application-test.js:57-71
Timestamp: 2025-06-06T09:03:17.958Z
Learning: In Ghost admin, the hardcoded version filtering logic that checks for versions starting with "5." is acceptable for now. The team prefers to defer making this configurable until major updates become more frequent, at which point they'll create a better system.
Learnt from: troyciesco
Repo: TryGhost/Ghost PR: 24749
File: ghost/core/core/server/services/members/SingleUseTokenProvider.js:3-5
Timestamp: 2025-08-26T16:47:28.150Z
Learning: When checking for dependencies in Ghost project, ensure to look directly in the specific package.json files rather than relying only on automated searches, as otplib dependency exists at line 204 in ghost/core/package.json version "12.0.1"
📚 Learning: 2025-10-30T17:13:26.190Z
Learnt from: sam-lord
Repo: TryGhost/Ghost PR: 25303
File: ghost/core/core/server/services/email-service/BatchSendingService.js:19-19
Timestamp: 2025-10-30T17:13:26.190Z
Learning: In ghost/core/core/server/services/email-service/BatchSendingService.js and similar files in the Ghost codebase, prefer using `{...options}` spread syntax without explicit guards like `...(options || {})` when spreading potentially undefined objects, as the maintainer prefers cleaner syntax over defensive patterns when the behavior is safe.
Applied to files:
ghost/core/core/server/services/recommendations/service/RecommendationMetadataService.tsapps/comments-ui/src/utils/api.ts
📚 Learning: 2025-10-09T15:31:06.587Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 25118
File: apps/portal/src/actions.js:160-173
Timestamp: 2025-10-09T15:31:06.587Z
Learning: When reviewing PRs that introduce feature-flagged changes (e.g., `labs?.membersSigninOTCAlpha`), avoid suggesting modifications to non-flagged code paths unless they're directly related to the PR's objectives. Keep the scope focused on the feature-flag-specific changes only.
Applied to files:
apps/admin-x-framework/src/test/acceptance.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Always follow ADRs in `../adr/` folder (ADR-0001: AAA pattern, ADR-0002: Page Objects)
Applied to files:
apps/admin-x-framework/src/test/acceptance.tsapps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Use factory pattern for all test data creation instead of hard-coded data or direct database manipulation
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Test names should be lowercase and follow the format 'what is tested - expected outcome'
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Use `getByTestId()` only when semantic locators are unavailable, and suggest adding `data-testid` to Ghost codebase when needed
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-03-13T09:02:50.102Z
Learnt from: mike182uk
Repo: TryGhost/Ghost PR: 22471
File: apps/admin-x-activitypub/src/views/Feed/components/NewPostModal.tsx:29-34
Timestamp: 2025-03-13T09:02:50.102Z
Learning: In the Ghost ActivityPub module, error handling for mutations is handled at the hook level (in use-activity-pub-queries.ts) rather than in individual components. This allows for centralized error handling across the application.
Applied to files:
apps/activitypub/src/components/modals/new-note-modal.tsxapps/activitypub/src/hooks/use-activity-pub-queries.tsapps/comments-ui/src/actions.tsapps/activitypub/src/views/preferences/components/profile.tsxapps/posts/src/hooks/use-post-success-modal.tsapps/activitypub/src/api/activitypub.tsapps/comments-ui/src/utils/api.tsapps/activitypub/src/views/preferences/components/bluesky-sharing.tsx
📚 Learning: 2025-03-13T09:02:50.102Z
Learnt from: mike182uk
Repo: TryGhost/Ghost PR: 22471
File: apps/admin-x-activitypub/src/views/Feed/components/NewPostModal.tsx:29-34
Timestamp: 2025-03-13T09:02:50.102Z
Learning: In the ActivityPub module, error handling for mutations is handled at the hook level (in use-activity-pub-queries.ts) rather than in individual components. This allows for centralized error handling across the application.
Applied to files:
apps/activitypub/src/components/modals/new-note-modal.tsxapps/activitypub/src/hooks/use-activity-pub-queries.tsapps/comments-ui/src/actions.tsapps/posts/src/hooks/use-post-success-modal.tsapps/activitypub/src/api/activitypub.tsapps/activitypub/src/views/preferences/components/bluesky-sharing.tsx
📚 Learning: 2025-08-11T19:39:00.428Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 24651
File: ghost/core/test/utils/urlUtils.js:53-57
Timestamp: 2025-08-11T19:39:00.428Z
Learning: In Ghost's test utilities, when fixing specific issues like async behavior, it's preferred to maintain existing error handling patterns (even if suboptimal) to keep PRs focused on their primary objective. Error handling improvements can be addressed in separate, dedicated PRs.
Applied to files:
apps/comments-ui/src/actions.tsapps/stats/test/utils/tinybird-helpers.tsapps/comments-ui/src/utils/api.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Prefer compound subcomponents (e.g., `Header.Title`, `Header.Meta`, `Header.Actions`) for multi-region components instead of many props
Applied to files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/components/ui/card.tsxapps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/view-header.tsxapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use `PascalCase` for component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Applied to files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/components/ui/card.tsxapps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/view-header.tsxapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use CVA (Class Variance Authority) for component variants when useful instead of heavy prop configuration
Applied to files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/components/ui/card.tsxapps/comments-ui/src/app-context.tsapps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/view-header.tsxapps/shade/src/components/layout/page.tsxapps/activitypub/src/views/profile/profile.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/index.ts : Place new UI components under `src/components/ui` and export them from `src/index.ts`
Applied to files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/components/ui/card.tsxapps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/view-header.tsxapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/**/*.{ts,tsx,js} : Use the `@` alias for internal imports (e.g., `@/lib/utils`)
Applied to files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/components/ui/card.tsxapps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/view-header.tsxapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/layout/**/*.{ts,tsx} : Reusable layout containers (Page, Heading, Header, ViewHeader, ErrorPage) should be placed in `src/components/layout/*`
Applied to files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/view-header.tsxapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use Tailwind CSS scoped via `.shade` class; dark mode uses `.dark`
Applied to files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/view-header.tsxapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-25T11:58:51.652Z
Learnt from: ibalosh
Repo: TryGhost/Ghost PR: 25525
File: apps/shade/src/shade-app.tsx:4-4
Timestamp: 2025-11-25T11:58:51.652Z
Learning: In apps/shade, the app wrapper file should be named `src/shade-app.tsx` (kebab-case) while the component itself is exported as `ShadeApp` (PascalCase). Context providers should be placed in `src/providers/*` using kebab-case filenames.
Applied to files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/view-header.tsxapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/**/*.{ts,tsx,js} : Use `camelCase` for function and variable names
Applied to files:
apps/shade/src/components/layout/heading.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Always forward and merge `className` prop with `cn(...)` utility function
Applied to files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-12-09T12:37:23.267Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 25501
File: apps/shade/src/hooks/use-mobile.tsx:5-10
Timestamp: 2025-12-09T12:37:23.267Z
Learning: In the Ghost repository, this guideline applies to the shade admin app. For files under apps/shade that access browser globals (navigator, window, document) at module load time, SSR is not used, so typeof guards are not required. Reviewers should verify that such files remain client-side only and that no SSR context is introduced; apply this understanding to similarly structured files under apps/shade.
Applied to files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/components/ui/card.tsxapps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/view-header.tsxapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/lib/utils.ts : Shared utilities (class merging, formatting, chart helpers) should be centralized in `src/lib/utils.ts`
Applied to files:
apps/shade/src/lib/utils.tsapps/shade/src/components/features/color-picker/color-picker.tsx
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.{ts,tsx} : Prefer less comments and give things clear names
Applied to files:
apps/comments-ui/src/typings.d.tsapps/comments-ui/src/app-context.tsapps/signup-form/src/typings.d.ts
📚 Learning: 2025-09-10T07:05:34.606Z
Learnt from: jonatansberg
Repo: TryGhost/Ghost PR: 24838
File: apps/shade/src/components/features/color-picker/color-picker.tsx:0-0
Timestamp: 2025-09-10T07:05:34.606Z
Learning: The Color library used in the color picker component handles input validation and clamping automatically, so manual validation of HSL and RGB values is not necessary when using Color constructors.
Applied to files:
apps/shade/src/components/features/color-picker/color-picker.tsx
📚 Learning: 2025-04-23T15:44:52.549Z
Learnt from: 9larsons
Repo: TryGhost/Ghost PR: 21866
File: ghost/core/core/server/web/admin/middleware/serve-auth-frame-file.js:10-19
Timestamp: 2025-04-23T15:44:52.549Z
Learning: The existing implementation in `ghost/core/core/server/web/admin/middleware/serve-auth-frame-file.js` using `path.parse(req.url).base` is secure against path traversal attacks as it properly extracts only the filename component without any directory parts.
Applied to files:
apps/stats/src/utils/url-helpers.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/features/**/*.{ts,tsx} : Higher-level, opinionated components (e.g., PostShareModal, SourceTabs) should be placed in `src/components/features/*`
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/ui/**/*.{ts,tsx} : Atomic UI components should be placed in `src/components/ui/*` and each component must have a corresponding `*.stories.tsx` file next to it for Storybook documentation
Applied to files:
apps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/helpers/pages/**/*.ts : Expose locators as `public readonly` in Page Objects when used with assertions
Applied to files:
apps/shade/src/components/layout/page.tsx
📚 Learning: 2025-07-14T12:20:35.268Z
Learnt from: sagzy
Repo: TryGhost/Ghost PR: 24346
File: apps/admin-x-settings/src/components/settings/growth/Network.tsx:8-12
Timestamp: 2025-07-14T12:20:35.268Z
Learning: The Network component toggle in `apps/admin-x-settings/src/components/settings/growth/Network.tsx` is intentionally implemented as static UI with a no-op onChange handler, as part of a UI-first development approach before connecting actual ActivityPub functionality.
Applied to files:
apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx
⏰ 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: Acceptance tests (Node 22.18.0, mysql8)
- GitHub Check: Acceptance tests (Node 22.18.0, sqlite3)
- GitHub Check: Legacy tests (Node 22.18.0, mysql8)
- GitHub Check: Legacy tests (Node 22.18.0, sqlite3)
- GitHub Check: Comments-UI tests
- GitHub Check: ActivityPub tests
- GitHub Check: Ghost-CLI tests
- GitHub Check: Signup-form tests
- GitHub Check: Admin-X Settings tests
- GitHub Check: Admin tests - Chrome
- GitHub Check: Lint
- GitHub Check: Unit tests (Node 22.18.0)
- GitHub Check: Build & Push Docker Image
🔇 Additional comments (50)
apps/posts/src/utils/link-helpers.ts (1)
30-33: LGTM! Clean refactor removing unused error binding.The error parameter was never referenced in the catch block, so removing it aligns with best practices and the updated ESLint rules.
apps/stats/src/hooks/use-feature-flag.tsx (1)
20-25: LGTM!The bare
catchis appropriate since the error was never used. The fallback behavior (empty object on parse failure) is preserved.apps/comments-ui/src/app-context.ts (1)
118-118: LGTM: Consistent with ESLint plugin update.The change to a bare
catchclause is appropriate since the error was never referenced. This aligns with the optional catch binding feature (ES2019) and the updated eslint-plugin-ghost rules.apps/stats/src/utils/url-helpers.ts (2)
12-24: LGTM: Bare catch is appropriate here.The change from
catch (error)to barecatchis correct since the error was never used—the function simply returns an empty string on failure. This aligns with the ESLint plugin updates.
15-15: LGTM: Formatting improvements enhance readability.The blank line additions improve code organization by separating logical blocks within the functions.
Also applies to: 37-37, 53-53, 58-58, 106-106, 115-115
ghost/core/core/server/services/recommendations/service/UnsafeData.ts (1)
175-190: Barecatchchange is safe and keeps behavior identicalRemoving the unused error binding and using
catch { ... }keeps the same behavior: any failure innew URL(string)or the protocol check is still normalized to aValidationError. No functional or type-safety concerns here; this is a clean, lint-driven tidy‑up.apps/admin-x-settings/src/utils/link-to-github-releases.ts (1)
32-32: LGTM! Clean removal of unused error binding.The bare
catchsyntax is valid and improves code clarity since the error was never referenced. This aligns with the ESLint plugin update enforcing removal of unused error bindings across the codebase.apps/posts/src/views/PostAnalytics/Web/web.tsx (1)
26-26: LGTM! Type alias aligns with updated ESLint rules.The change from an empty interface to
type postAnalyticsProps = objectis semantically equivalent and appears to be driven by the ESLint plugin update to version 3.4.4. This provides consistent type definition style across the codebase.apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx (1)
17-17: LGTM! Consistent with ESLint-driven type definition standardization.The type alias change matches the pattern applied across other PostAnalytics components and maintains the same type semantics.
ghost/core/core/server/services/recommendations/service/RecommendationMetadataService.ts (2)
62-66: Barecatchpreserves existing error handling behaviorThe inner
JSON.parseand outer network-leveltryblocks now use barecatchclauses, but the caught error was not previously used and the failure paths still returnundefined. Behavior and control flow are unchanged and the lint-driven cleanup looks good.Also applies to: 68-70
77-81: URL parsingcatchchange is a no-op behaviorallySimilarly, switching to a bare
catchin#castUrlkeeps the same behavior of returningnullon invalid URLs while removing an unused error binding. No functional impact here.apps/comments-ui/src/typings.d.ts (1)
1-7: LGTM! Appropriate lint suppression for ambient module declaration.The ESLint disable directive is correctly applied to suppress the
@typescript-eslint/no-require-importsrule for the CommonJS-style import syntax, which is appropriate in ambient module declarations where this syntax is sometimes necessary for TypeScript.apps/admin-x-design-system/src/typings.d.ts (1)
1-7: LGTM! Consistent lint suppression applied.The lint directive is appropriately applied, consistent with the pattern established across other SVG type definition files in this PR.
apps/signup-form/src/typings.d.ts (1)
1-7: LGTM! Lint suppression applied consistently.The targeted
eslint-disable-next-linedirective appropriately handles the CommonJS import syntax required in this ambient module declaration.apps/stats/src/types/svg.d.ts (1)
1-7: LGTM! Completes the consistent lint suppression pattern.The lint directive is appropriately applied, maintaining consistency with the other SVG type definition files updated in this PR.
apps/comments-ui/src/actions.ts (2)
257-265: LGTM! Bare catch syntax correctly applied.The error object was not used in the original catch block, so removing the binding is appropriate. The optimistic update pattern remains intact.
267-276: LGTM! Bare catch syntax correctly applied.The error object was not used in the original catch block, so removing the binding is appropriate. The optimistic update pattern remains intact.
apps/admin-x-settings/src/components/settings/growth/recommendations/incoming-recommendation-list.tsx (1)
23-27: Bare catch on URL parsing is appropriate hereThe error value was never used; switching to
catch {}keeps behavior identical while satisfying lint rules and avoiding an unused binding.apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx (1)
103-117: onOk catch cleanup keeps behavior unchangedRemoving the unused error parameter in
onOk’stry/catchkeeps the same toast-based error handling and matches the lint-driven pattern used elsewhere in this PR.apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx (1)
83-93: Submission catch block correctly drops unused error bindingHere the error object wasn’t used; changing to a bare
catchkeeps the same user-facing toast while simplifying the handler and aligning with the updated lint rules.apps/shade/src/lib/utils.ts (1)
97-103: Bare catch keeps formatUrl behavior unchangedThe switch to a bare
catchhere is safe; the error value was not used, and the function still correctly falls back to{save: url, display: url}when URL construction fails.apps/posts/src/hooks/use-post-success-modal.ts (1)
154-169: LocalStorage error handling remains safeDropping the unused error parameter in the
catchkeeps the intended behavior of silently ignoring localStorage/JSON failures and falling back cleanly. No functional change.apps/admin-x-design-system/src/utils/format-url.ts (1)
44-50: Consistent bare catch in formatUrlThis matches the pattern used elsewhere: the unused error variable is removed while continuing to fall back to
{save: url, display: url}on URL parse failures.apps/activitypub/src/utils/image.ts (1)
10-28: imageUrlToDataUrl fallback behavior preservedSwitching to a bare
catchkeeps the same contract: on any fetch/parse error, the function returns the original URL as a safe fallback.apps/admin-x-settings/src/utils/url.ts (1)
24-32: arePathsEqual retains same invalid-URL behaviorThe bare
catchkeeps the logic of returningfalsewhen either URL string can’t be parsed, just without binding an unused error variable.apps/stats/test/utils/tinybird-helpers.ts (1)
81-91: Test helper still produces the same error messagesRemoving the unused error binding in the
catchkeeps the same behavior: on JSON parse failure, it falls back tobodyTextwhen constructing the thrownError.apps/signup-form/src/components/pages/form-page.tsx (1)
23-39: Submit error handling unchanged aside from lint cleanupThe bare
catchkeeps the same UX: on any failure, loading is cleared and a generic “Something went wrong” message is shown. Only the unused error parameter was removed.apps/activitypub/src/utils/get-username.ts (1)
5-9: Bare catch keeps username fallback behavior unchangedThe catch binding removal is safe here; the fallback
@unknown@unknownis preserved and no error object was previously used.apps/comments-ui/src/utils/api.ts (1)
312-319: Init labs error handling remains behavior‑preservingSwitching to a bare
catchkeeps the same behavior (resettinglabsto{}on any settings fetch/parse error) and removes an unused binding.apps/comments-ui/src/components/content/forms/form.tsx (1)
72-81: submitForm error state handling unchangedRemoving the error parameter from the catch block doesn’t alter behavior; the form still transitions to
'error'state on any failure.apps/comments-ui/src/utils/admin-api.ts (1)
15-20: Admin iframe message parsing: behavior unchanged with bare catchThe bare
catchkeeps the early‑return behavior on invalid JSON while dropping an unused error variable, which is appropriate for this handler.apps/activitypub/src/views/preferences/components/bluesky-sharing.tsx (1)
48-58: Bluesky enable error path remains intactChanging to a bare
catchhere keeps the same UX (clearingloadingand showing the generic error toast) while avoiding an unused error parameter.apps/activitypub/src/api/activitypub.ts (1)
252-260: getToken’s null‑on‑error contract preservedThe bare
catchkeepsgetToken’s existing behavior of returningnullon any failure, and call sites already tolerate a missing token, so this change is safe.apps/admin-x-framework/src/test/acceptance.ts (1)
127-133: Labs settings parse failure handling unchangedSwitching to a bare
catchhere keeps the same behavior (throwing'Failed to parse labs settings') while removing an unused error parameter in this test helper.apps/shade/src/components/features/color-picker/color-picker.tsx (1)
369-391: Barecatchis appropriate hereThe caught error wasn’t used, so switching to a bare
catchkeeps behavior identical while satisfying linting (no-unused-vars) and keeps the handler focused on just ignoring invalid input.apps/admin-x-framework/test/unit/hooks/use-form.test.ts (2)
202-208: Removing the error binding in the testcatchblock is safeThis test only asserts that an error is thrown and state/onSaveError behavior, not the error object itself, so using a bare
catchkeeps semantics intact while avoiding an unused variable.
229-235: Consistent barecatchusage in async error testSame here: the error instance isn’t inspected, so changing to
catch {}is a no-op behavior-wise and keeps the test aligned with the new lint rules.apps/activitypub/src/views/preferences/components/profile.tsx (1)
258-314: Barecatchblocks inhandleCopypreserve behaviorBoth inner and outer
catchblocks only emit a toast and (outer) resetisProcessing, never using the error value, so switching tocatch {}is behaviorally identical and matches the lint-driven style across the PR.apps/activitypub/src/hooks/use-activity-pub-queries.ts (3)
360-403: Notification liked-cache try/catch remains robustThe catch block only returns
currentand never referenced the error, so moving to a barecatchkeeps the safe fallback behavior unchanged while satisfying lint rules.
406-449: Notification repost-cache catch simplification is safeSame pattern here: the catch just returns
current; dropping the unused error parameter has no effect on cache semantics.
452-495: Notification reply-count cache catch simplification is safeAgain, the error value wasn’t used; retaining the
return currentfallback with a barecatchis functionally equivalent and keeps the code lint-clean.apps/shade/src/components/layout/view-header.tsx (2)
4-6: Prop typing change to alias looks fineSwitching
ViewHeaderActionsPropsfrom an interface totype ViewHeaderActionsProps = React.HTMLAttributes<HTMLElement>keeps the component’s public surface the same and doesn’t affect runtime behavior.
31-31: Named exports unchanged
ViewHeaderandViewHeaderActionsare still exported as before; no issues with the export shape from this module.apps/shade/src/components/ui/card.tsx (1)
219-223: EmptyCard props alias is equivalent and safeChanging
EmptyCardPropsfrom an interface toexport type EmptyCardProps = React.ComponentPropsWithoutRef<'div'>doesn’t alter the component’s external API or behavior and aligns with the broader type-alias pattern in this PR.apps/shade/src/components/layout/page.tsx (1)
4-16: PageProps interface→type refactor is non-breakingDefining
PagePropsas a type alias forReact.HTMLAttributes<HTMLDivElement>keeps the same prop surface while simplifying the typing style; the component implementation and usage remain unchanged.apps/admin-x-framework/src/api/config.ts (1)
3-6: No breaking change concern here.JSONArrayis only used internally withinconfig.tsto defineJSONValueand is not imported by any other files in the codebase. Making it a non-exported type alias has no impact on external code.Likely an incorrect or invalid review comment.
apps/shade/src/components/layout/heading.tsx (1)
4-4: HeadingProps interface→type alias change is safeUsing
type HeadingProps = React.HTMLAttributes<HTMLHeadingElement>is equivalent in shape to the previous extending interface and keeps the H1–H4 APIs unchanged, while matching the broader move to type aliases. As per coding guidelines, className merging viacnand layout placement remain correct.apps/admin-x-framework/src/api/recommendations.ts (1)
25-27: Confirm the stricterRecommendationDeleteResponseType = objectis intended
RecommendationEditResponseTypebeing an alias ofRecommendationResponseTypekeeps the previous interface extension behavior in practice, so that change is safe.For
RecommendationDeleteResponseType, changing from an empty interface toobjectmakes the type slightly stricter than{}(it excludes primitives). That’s probably fine for a DELETE response that’s ignored or returns an empty/JSON object, but it’s worth confirming that existing call sites don’t rely on assigning other shapes here.apps/shade/src/components/layout/header.tsx (1)
11-75: Header subcomponent prop interfaces→type aliases keep behavior unchangedAll
Header*Propsnow aliasPropsWithChildrenAndClassNameinstead of extending it as interfaces. That’s structurally equivalent, keepschildren/classNameexactly as before, and fits the broader shift toward type aliases without affecting the Header compound subcomponents or their usage. This remains aligned with the shade layout guidelines (compound subcomponents +cnfor className).apps/admin-x-design-system/src/global/sortable-list.tsx (1)
17-18: The ESLint rule name@typescript-eslint/no-unsafe-function-typeis correct and properly suppresses the warning about using the genericFunctiontype. The TODO comment on line 16 appropriately flags that a stricter type alternative should be defined in the future.
d75e2cb to
2500ab9
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/admin-x-design-system/src/global/sortable-list.tsx (1)
140-145: UpdateonMovetype signature to reflect thatoverIdcan beundefinedThe
onMoveprop is typed as(id: string, overId: string) => void, but when a drop occurs outside a valid target,event.over?.idisundefined, violating the type contract. The actual implementations (e.g.,moveIteminuseSortableIndexedList, the storybook example) already handle this by makingoverIdoptional, so the type signature should match reality:- onMove: (id: string, overId: string) => void; + onMove: (id: string, overId: string | undefined) => void;Alternatively, add a guard in the handler to skip the callback when there's no valid drop target:
onDragEnd={(event) => { + if (!event.over) { + setDraggingId(null); + return; + } - onMove(event.active.id as string, event.over?.id as string); + onMove(event.active.id as string, event.over.id as string); setDraggingId(null); }}
🧹 Nitpick comments (4)
apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx (1)
87-93: LGTM! Consistent error handling.The change to bare
catchis correct since the error object wasn't being used. The code maintains consistency: error bindings are retained where they're used (line 60 in the delete handler) and removed where they're not.Optional: Consider logging the error for debugging/monitoring purposes, even when showing a generic user message.
- } catch { + } catch (error) { + console.error('Failed to save recommendation:', error); showToast({ title: 'Something went wrong', type: 'error', message: 'Please try again later.' }); }apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx (1)
112-117: LGTM! Aligns with ESLint rule update.The bare
catchsyntax is appropriate here since the error binding was unused. This change is consistent with the ESLint plugin update mentioned in the PR title.Optional: Consider capturing the error for debugging/telemetry purposes.
- } catch { + } catch (error) { + console.error('Failed to add recommendation:', error); showToast({ type: 'error', title: 'Something went wrong when adding this recommendation, please try again.' }); }apps/activitypub/src/views/preferences/components/profile.tsx (1)
272-314: Catch parameter removal maintains existing error UX/stateDropping the error parameter from both inner and outer
catchblocks doesn’t change behavior: failures still trigger the same toast message andsetIsProcessing(false)paths, and the Clipboard API support check still flows into the outer catch as before. This aligns with the lint-driven cleanup without altering the image-copy UX.Based on learnings, if you later revisit this area, you could consider consolidating the duplicated “Failed to copy image” toast into a small helper, but that’s not necessary for this PR.
apps/admin-x-design-system/src/global/sortable-list.tsx (1)
16-18: ESLint rule update is correct; consider tighteningdragHandleListenerstype in a future refactorThe switch to
@typescript-eslint/no-unsafe-function-typeis the appropriate rule name for the current plugin version. TheRecord<string, Function>type itself is still loose—since these listeners come from the@dnd-kit/sortablehook and are spread directly onto DOM elements, they could be typed more precisely (for instance, as a mapped type of the actual dnd-kit event handler shapes orRecord<string, (...args: unknown[]) => void>). This doesn't need to block the current PR, but can be a follow-up improvement once you want to remove the ESLint suppression entirely.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (53)
apps/activitypub/src/api/activitypub.ts(1 hunks)apps/activitypub/src/components/modals/new-note-modal.tsx(1 hunks)apps/activitypub/src/hooks/use-activity-pub-queries.ts(3 hunks)apps/activitypub/src/utils/get-username.ts(1 hunks)apps/activitypub/src/utils/image.ts(1 hunks)apps/activitypub/src/views/preferences/components/bluesky-sharing.tsx(1 hunks)apps/activitypub/src/views/preferences/components/profile.tsx(1 hunks)apps/activitypub/src/views/profile/profile.tsx(1 hunks)apps/admin-x-design-system/src/global/sortable-list.tsx(1 hunks)apps/admin-x-design-system/src/typings.d.ts(1 hunks)apps/admin-x-design-system/src/utils/format-url.ts(1 hunks)apps/admin-x-framework/src/api/config.ts(1 hunks)apps/admin-x-framework/src/api/recommendations.ts(1 hunks)apps/admin-x-framework/src/test/acceptance.ts(1 hunks)apps/admin-x-framework/src/test/test-utils.tsx(1 hunks)apps/admin-x-framework/test/unit/hooks/use-form.test.ts(2 hunks)apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/incoming-recommendation-list.tsx(1 hunks)apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx(2 hunks)apps/admin-x-settings/src/typings.d.ts(1 hunks)apps/admin-x-settings/src/utils/link-to-github-releases.ts(1 hunks)apps/admin-x-settings/src/utils/url.ts(1 hunks)apps/comments-ui/src/actions.ts(2 hunks)apps/comments-ui/src/app-context.ts(1 hunks)apps/comments-ui/src/components/content/forms/form.tsx(1 hunks)apps/comments-ui/src/components/popup-box.tsx(1 hunks)apps/comments-ui/src/typings.d.ts(1 hunks)apps/comments-ui/src/utils/admin-api.ts(1 hunks)apps/comments-ui/src/utils/api.ts(1 hunks)apps/posts/src/hooks/use-post-success-modal.ts(1 hunks)apps/posts/src/utils/link-helpers.ts(1 hunks)apps/posts/src/views/PostAnalytics/Growth/growth.tsx(1 hunks)apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx(1 hunks)apps/posts/src/views/PostAnalytics/Web/web.tsx(1 hunks)apps/shade/src/components/features/color-picker/color-picker.tsx(1 hunks)apps/shade/src/components/layout/header.tsx(6 hunks)apps/shade/src/components/layout/heading.tsx(1 hunks)apps/shade/src/components/layout/page.tsx(1 hunks)apps/shade/src/components/layout/view-header.tsx(2 hunks)apps/shade/src/components/ui/card.tsx(1 hunks)apps/shade/src/lib/utils.ts(1 hunks)apps/shade/src/typings.d.ts(1 hunks)apps/signup-form/src/components/pages/form-page.tsx(1 hunks)apps/signup-form/src/typings.d.ts(1 hunks)apps/stats/src/hooks/use-feature-flag.tsx(1 hunks)apps/stats/src/types/svg.d.ts(1 hunks)apps/stats/src/utils/url-helpers.ts(5 hunks)apps/stats/test/utils/tinybird-helpers.ts(1 hunks)ghost/core/core/server/services/recommendations/service/RecommendationMetadataService.ts(2 hunks)ghost/core/core/server/services/recommendations/service/UnsafeData.ts(1 hunks)
✅ Files skipped from review due to trivial changes (2)
- apps/posts/src/hooks/use-post-success-modal.ts
- apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx
🚧 Files skipped from review as they are similar to previous changes (31)
- apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx
- apps/comments-ui/src/components/popup-box.tsx
- apps/posts/src/utils/link-helpers.ts
- apps/comments-ui/src/actions.ts
- apps/comments-ui/src/utils/api.ts
- apps/stats/test/utils/tinybird-helpers.ts
- apps/comments-ui/src/components/content/forms/form.tsx
- apps/stats/src/utils/url-helpers.ts
- apps/activitypub/src/hooks/use-activity-pub-queries.ts
- apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx
- apps/shade/src/lib/utils.ts
- apps/activitypub/src/views/preferences/components/bluesky-sharing.tsx
- apps/comments-ui/src/utils/admin-api.ts
- apps/shade/src/components/layout/view-header.tsx
- apps/comments-ui/src/app-context.ts
- apps/admin-x-framework/src/test/test-utils.tsx
- apps/shade/src/components/ui/card.tsx
- ghost/core/core/server/services/recommendations/service/UnsafeData.ts
- apps/shade/src/typings.d.ts
- apps/activitypub/src/api/activitypub.ts
- apps/admin-x-settings/src/components/settings/growth/recommendations/incoming-recommendation-list.tsx
- apps/admin-x-design-system/src/typings.d.ts
- apps/stats/src/hooks/use-feature-flag.tsx
- apps/activitypub/src/utils/get-username.ts
- apps/admin-x-design-system/src/utils/format-url.ts
- apps/signup-form/src/typings.d.ts
- apps/stats/src/types/svg.d.ts
- apps/admin-x-framework/src/api/recommendations.ts
- apps/comments-ui/src/typings.d.ts
- apps/admin-x-framework/test/unit/hooks/use-form.test.ts
- apps/shade/src/components/layout/header.tsx
🧰 Additional context used
📓 Path-based instructions (5)
apps/shade/src/components/features/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
Higher-level, opinionated components (e.g., PostShareModal, SourceTabs) should be placed in
src/components/features/*
Files:
apps/shade/src/components/features/color-picker/color-picker.tsx
apps/shade/src/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/src/components/**/*.{ts,tsx}: UsePascalCasefor component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Always forward and mergeclassNameprop withcn(...)utility function
Use CVA (Class Variance Authority) for component variants when useful instead of heavy prop configuration
Prefer compound subcomponents (e.g.,Header.Title,Header.Meta,Header.Actions) for multi-region components instead of many props
Use Tailwind CSS scoped via.shadeclass; dark mode uses.dark
Files:
apps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/page.tsx
apps/shade/src/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/src/**/*.{ts,tsx,js}: UsecamelCasefor function and variable names
Use the@alias for internal imports (e.g.,@/lib/utils)
Files:
apps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/page.tsx
apps/shade/{src,test}/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/{src,test}/**/*.{ts,tsx,js}: Runyarn lintafter making changes to fix any ESLint errors and warnings before committing
Follow ESLint andtailwindcss/*plugin rules when writing styles
Files:
apps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/page.tsx
apps/shade/src/components/layout/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
Reusable layout containers (Page, Heading, Header, ViewHeader, ErrorPage) should be placed in
src/components/layout/*
Files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/page.tsx
🧠 Learnings (21)
📓 Common learnings
Learnt from: cmraible
Repo: TryGhost/Ghost PR: 24658
File: ghost/admin/package.json:3-3
Timestamp: 2025-08-12T18:33:15.524Z
Learning: In Ghost's admin package.json, third-party packages like ember-cli-postcss, ember-exam, and ember-power-select have their own independent versioning schemes that are unrelated to Ghost's version numbers. Version number coincidences between Ghost versions and these packages should not trigger update suggestions.
Learnt from: sagzy
Repo: TryGhost/Ghost PR: 24673
File: ghost/i18n/lib/i18n.js:34-35
Timestamp: 2025-11-24T11:12:15.712Z
Learning: In the Ghost i18n package (ghost/i18n/lib/i18n.js), changing existing locale codes requires backwards compatibility handling for users who have already configured those locales. Such changes should be done in a separate PR with migration logic rather than included in feature PRs.
Learnt from: sam-lord
Repo: TryGhost/Ghost PR: 25303
File: ghost/core/core/server/services/email-service/BatchSendingService.js:19-19
Timestamp: 2025-10-30T17:13:26.190Z
Learning: In ghost/core/core/server/services/email-service/BatchSendingService.js and similar files in the Ghost codebase, prefer using `{...options}` spread syntax without explicit guards like `...(options || {})` when spreading potentially undefined objects, as the maintainer prefers cleaner syntax over defensive patterns when the behavior is safe.
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T14:28:50.351Z
Learning: Applies to ghost/i18n/locales/en/ghost.json : Add UI translations to `ghost/i18n/locales/en/ghost.json` for Admin UI features
Learnt from: niranjan-uma-shankar
Repo: TryGhost/Ghost PR: 24557
File: apps/admin-x-settings/src/components/settings/general/TimeZone.tsx:7-7
Timestamp: 2025-08-01T12:44:07.467Z
Learning: In Ghost development, PRs may depend on unpublished changes from SDK packages. When this occurs, TypeScript compilation errors for missing exports are expected and documented in the PR description until the dependency packages are published and updated. This is normal workflow for cross-repository feature development.
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T14:28:50.351Z
Learning: Admin-x React apps build to `apps/*/dist` using Vite, which are then copied by `ghost/admin/lib/asset-delivery` to `ghost/core/core/built/admin/assets/*`
Learnt from: ErisDS
Repo: TryGhost/Ghost PR: 23644
File: ghost/admin/tests/unit/controllers/application-test.js:57-71
Timestamp: 2025-06-06T09:03:17.958Z
Learning: In Ghost admin, the hardcoded version filtering logic that checks for versions starting with "5." is acceptable for now. The team prefers to defer making this configurable until major updates become more frequent, at which point they'll create a better system.
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 24651
File: ghost/core/test/utils/urlUtils.js:53-57
Timestamp: 2025-08-11T19:39:00.428Z
Learning: In Ghost's test utilities, when fixing specific issues like async behavior, it's preferred to maintain existing error handling patterns (even if suboptimal) to keep PRs focused on their primary objective. Error handling improvements can be addressed in separate, dedicated PRs.
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.{ts,tsx} : Prefer less comments and give things clear names
Applied to files:
apps/admin-x-settings/src/typings.d.ts
📚 Learning: 2025-08-11T19:39:00.428Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 24651
File: ghost/core/test/utils/urlUtils.js:53-57
Timestamp: 2025-08-11T19:39:00.428Z
Learning: In Ghost's test utilities, when fixing specific issues like async behavior, it's preferred to maintain existing error handling patterns (even if suboptimal) to keep PRs focused on their primary objective. Error handling improvements can be addressed in separate, dedicated PRs.
Applied to files:
apps/activitypub/src/views/preferences/components/profile.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use CVA (Class Variance Authority) for component variants when useful instead of heavy prop configuration
Applied to files:
apps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/heading.tsxapps/posts/src/views/PostAnalytics/Growth/growth.tsxapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/lib/utils.ts : Shared utilities (class merging, formatting, chart helpers) should be centralized in `src/lib/utils.ts`
Applied to files:
apps/shade/src/components/features/color-picker/color-picker.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use `PascalCase` for component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Applied to files:
apps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use Tailwind CSS scoped via `.shade` class; dark mode uses `.dark`
Applied to files:
apps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-09-10T07:05:34.606Z
Learnt from: jonatansberg
Repo: TryGhost/Ghost PR: 24838
File: apps/shade/src/components/features/color-picker/color-picker.tsx:0-0
Timestamp: 2025-09-10T07:05:34.606Z
Learning: The Color library used in the color picker component handles input validation and clamping automatically, so manual validation of HSL and RGB values is not necessary when using Color constructors.
Applied to files:
apps/shade/src/components/features/color-picker/color-picker.tsx
📚 Learning: 2025-12-09T12:37:23.267Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 25501
File: apps/shade/src/hooks/use-mobile.tsx:5-10
Timestamp: 2025-12-09T12:37:23.267Z
Learning: In the Ghost repository, this guideline applies to the shade admin app. For files under apps/shade that access browser globals (navigator, window, document) at module load time, SSR is not used, so typeof guards are not required. Reviewers should verify that such files remain client-side only and that no SSR context is introduced; apply this understanding to similarly structured files under apps/shade.
Applied to files:
apps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Prefer compound subcomponents (e.g., `Header.Title`, `Header.Meta`, `Header.Actions`) for multi-region components instead of many props
Applied to files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/index.ts : Place new UI components under `src/components/ui` and export them from `src/index.ts`
Applied to files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/**/*.{ts,tsx,js} : Use the `@` alias for internal imports (e.g., `@/lib/utils`)
Applied to files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/layout/**/*.{ts,tsx} : Reusable layout containers (Page, Heading, Header, ViewHeader, ErrorPage) should be placed in `src/components/layout/*`
Applied to files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-25T11:58:51.652Z
Learnt from: ibalosh
Repo: TryGhost/Ghost PR: 25525
File: apps/shade/src/shade-app.tsx:4-4
Timestamp: 2025-11-25T11:58:51.652Z
Learning: In apps/shade, the app wrapper file should be named `src/shade-app.tsx` (kebab-case) while the component itself is exported as `ShadeApp` (PascalCase). Context providers should be placed in `src/providers/*` using kebab-case filenames.
Applied to files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/**/*.{ts,tsx,js} : Use `camelCase` for function and variable names
Applied to files:
apps/shade/src/components/layout/heading.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/ui/**/*.{ts,tsx} : Atomic UI components should be placed in `src/components/ui/*` and each component must have a corresponding `*.stories.tsx` file next to it for Storybook documentation
Applied to files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Always forward and merge `className` prop with `cn(...)` utility function
Applied to files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-03-13T09:02:50.102Z
Learnt from: mike182uk
Repo: TryGhost/Ghost PR: 22471
File: apps/admin-x-activitypub/src/views/Feed/components/NewPostModal.tsx:29-34
Timestamp: 2025-03-13T09:02:50.102Z
Learning: In the Ghost ActivityPub module, error handling for mutations is handled at the hook level (in use-activity-pub-queries.ts) rather than in individual components. This allows for centralized error handling across the application.
Applied to files:
apps/activitypub/src/components/modals/new-note-modal.tsx
📚 Learning: 2025-03-13T09:02:50.102Z
Learnt from: mike182uk
Repo: TryGhost/Ghost PR: 22471
File: apps/admin-x-activitypub/src/views/Feed/components/NewPostModal.tsx:29-34
Timestamp: 2025-03-13T09:02:50.102Z
Learning: In the ActivityPub module, error handling for mutations is handled at the hook level (in use-activity-pub-queries.ts) rather than in individual components. This allows for centralized error handling across the application.
Applied to files:
apps/activitypub/src/components/modals/new-note-modal.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/features/**/*.{ts,tsx} : Higher-level, opinionated components (e.g., PostShareModal, SourceTabs) should be placed in `src/components/features/*`
Applied to files:
apps/shade/src/components/layout/page.tsx
📚 Learning: 2025-07-14T12:20:35.268Z
Learnt from: sagzy
Repo: TryGhost/Ghost PR: 24346
File: apps/admin-x-settings/src/components/settings/growth/Network.tsx:8-12
Timestamp: 2025-07-14T12:20:35.268Z
Learning: The Network component toggle in `apps/admin-x-settings/src/components/settings/growth/Network.tsx` is intentionally implemented as static UI with a no-op onChange handler, as part of a UI-first development approach before connecting actual ActivityPub functionality.
Applied to files:
apps/activitypub/src/views/profile/profile.tsx
🪛 Biome (2.1.2)
apps/activitypub/src/views/profile/profile.tsx
[error] 13-14: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
⏰ 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: Comments-UI tests
- GitHub Check: Ghost-CLI tests
- GitHub Check: ActivityPub tests
- GitHub Check: Signup-form tests
- GitHub Check: Acceptance tests (Node 22.18.0, mysql8)
- GitHub Check: Legacy tests (Node 22.18.0, mysql8)
- GitHub Check: Admin-X Settings tests
- GitHub Check: Unit tests (Node 22.18.0)
- GitHub Check: Admin tests - Chrome
- GitHub Check: Legacy tests (Node 22.18.0, sqlite3)
- GitHub Check: Acceptance tests (Node 22.18.0, sqlite3)
- GitHub Check: Lint
- GitHub Check: Build & Push Docker Image
🔇 Additional comments (17)
apps/activitypub/src/views/profile/profile.tsx (1)
13-14: ESLint disable comment is appropriate for the linting update scope.The
@typescript-eslint/no-empty-object-typerule suppression is a pragmatic choice for this linting-focused PR. SinceProfilePropsis legitimately empty (the component accepts no props), the disable comment keeps this PR focused on updating the ESLint version without requiring structural refactors.apps/admin-x-settings/src/utils/url.ts (1)
24-32: Barecatchhere is a clean, behavior‑preserving changeThe error object wasn’t used, so switching to a bare
catchkeeps the “return false on parse failure” behavior while satisfying the updated ESLint rule and slightly reducing noise.Please confirm your TS/JS target (and ESLint/parser config) is ES2019+ so optional catch binding is always supported across your runtimes.
ghost/core/core/server/services/recommendations/service/RecommendationMetadataService.ts (3)
62-66: LGTM: Unused error binding correctly removed.The error binding was never referenced in the catch block. Removing it aligns with the ESLint upgrade while preserving the existing behavior of returning
undefinedon JSON parse failures.
47-70: LGTM: Unused error binding correctly removed.The error binding was never referenced in the catch block. Removing it aligns with the ESLint upgrade while preserving the existing error handling strategy of returning
undefinedfor DNS and network errors.
77-81: LGTM: Unused error binding correctly removed.The error binding was never referenced in the catch block. Removing it aligns with the ESLint upgrade while preserving the existing behavior of returning
nullfor invalid URLs.apps/admin-x-settings/src/typings.d.ts (1)
4-9: Scoped lint-disable looks appropriate hereThe
@typescript-eslint/no-require-importssuppression is tightly scoped to the onerequire-style React import inside a.d.tsSVG module, which is a reasonable exception and has no runtime or typing impact. This matches the pattern used elsewhere in the repo for SVG typings and keeps the rule enabled everywhere else.apps/admin-x-settings/src/utils/link-to-github-releases.ts (1)
32-32: LGTM!The change from
catch (e)to barecatchis correct since the error variable was never used. This cleanup aligns with the ESLint plugin update objective.apps/activitypub/src/components/modals/new-note-modal.tsx (1)
96-104: LGTM! Bare catch aligns with linting requirements.The change from a named catch parameter to a bare
catchis appropriate since the error object wasn't being used (the console.error on line 101 is commented out). This aligns with the ESLint plugin update and maintains the existing error handling behavior—invokingonReplyErrorfor replies while relying on centralized error handling at the hook level.Based on learnings, error handling for ActivityPub mutations is already centralized at the hook level in use-activity-pub-queries.ts.
apps/shade/src/components/features/color-picker/color-picker.tsx (1)
369-390: Optional catch binding change looks correctSwitching from
catch (error)tocatch {is safe here because the error object was never used and the behavior (silently ignoring invalid color input) is unchanged. This is aligned with modern JS/TS and the updated ESLint rules.Please confirm that your TypeScript/ES target already supports optional catch bindings (it should in modern setups) and that
yarn lint/CI pass after this change.apps/activitypub/src/utils/image.ts (1)
19-28: Behavior-preserving catch simplification looks goodThe switch to a parameterless
catchkeeps the same fallback behavior (returning the original URL) while removing an unused error binding, which is appropriate here. No functional change introduced.apps/signup-form/src/components/pages/form-page.tsx (1)
36-36: LGTM! Bare catch is appropriate here.The error parameter was unused, so removing it aligns with ESLint best practices while preserving the exact same error handling behavior.
apps/admin-x-framework/src/test/acceptance.ts (1)
130-130: LGTM! Bare catch is appropriate here.The error parameter was not being used in the catch block, so removing it aligns with ESLint best practices without changing behavior.
apps/shade/src/components/layout/heading.tsx (1)
4-4: LGTM! Type alias is preferred for simple extensions.Converting from interface to type alias is appropriate when the type simply extends a single type without additional properties. This follows TypeScript best practices.
apps/shade/src/components/layout/page.tsx (1)
4-4: LGTM! Type alias is preferred for simple extensions.Converting from interface to type alias is appropriate when the type simply extends a single type without additional properties. This follows TypeScript best practices and aligns with the pattern used across other layout components in this PR.
apps/admin-x-framework/src/api/config.ts (1)
5-5: No breaking change from removing JSONArray export.
JSONArrayis not used anywhere outside this file and was only ever referenced internally within the definitions ofJSONValueandJSONObject. The change from an exported interface to a non-exported type alias is safe and represents internal refactoring only.apps/posts/src/views/PostAnalytics/Web/web.tsx (1)
26-26: Prop type alias update looks fineUsing a named
postAnalyticsPropstype alias here keeps the component signature consistent with the other PostAnalytics views and avoids empty-interface lint issues. No further changes needed in this file.apps/posts/src/views/PostAnalytics/Growth/growth.tsx (1)
16-16: Consistent prop typing with other analytics viewsDefining
postAnalyticsPropsas a type alias and using it inReact.FC<postAnalyticsProps>aligns Growth with the other PostAnalytics components and avoids empty-interface warnings. Looks good as-is.
apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx
Show resolved
Hide resolved
5895daa to
495218a
Compare
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (8)
apps/admin-x-design-system/src/typings.d.ts (1)
2-2: ESLint suppressions are consistent and appropriate.The addition of
@typescript-eslint/no-require-importssuppressions across all SVG typing files is consistent with the ESLint plugin update. The CommonJS-style import pattern is standard for ambient module declarations.If you prefer to avoid suppressions entirely, consider modernizing to ES6 imports:
- // eslint-disable-next-line @typescript-eslint/no-require-imports - import React = require('react'); + import type * as React from 'react';This change would be optional and could be applied across all four SVG typing files for consistency.
apps/posts/src/views/PostAnalytics/Web/web.tsx (1)
26-27: Consider using a type alias or removing the empty interface.The empty interface with an ESLint suppression is functionally equivalent to
{}. As Biome suggests, a type alias would be more appropriate, or you could remove it entirely if no props are needed.Option 1: Use a type alias (as Biome suggests)
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} +type postAnalyticsProps = Record<string, never>;Option 2: Remove the interface entirely
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} - -const Web: React.FC<postAnalyticsProps> = () => { +const Web: React.FC = () => {apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx (1)
17-18: Consider using a type alias or removing the empty interface.The empty interface with an ESLint suppression is functionally equivalent to
{}. As Biome suggests, a type alias would be more appropriate, or you could remove it entirely if no props are needed.Option 1: Use a type alias (as Biome suggests)
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} +type postAnalyticsProps = Record<string, never>;Option 2: Remove the interface entirely
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} - -const Newsletter: React.FC<postAnalyticsProps> = () => { +const Newsletter: React.FC = () => {apps/posts/src/views/PostAnalytics/Growth/growth.tsx (1)
16-17: Consider using a type alias or removing the empty interface.The empty interface with an ESLint suppression is functionally equivalent to
{}. As Biome suggests, a type alias would be more appropriate, or you could remove it entirely if no props are needed.Option 1: Use a type alias (as Biome suggests)
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} +type postAnalyticsProps = Record<string, never>;Option 2: Remove the interface entirely
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} - -const Growth: React.FC<postAnalyticsProps> = () => { +const Growth: React.FC = () => {apps/activitypub/src/views/profile/profile.tsx (1)
13-14: Avoid empty interface + lint disable by using a stricter props typeInstead of an empty interface plus an ESLint-disable, consider a concrete “no-props” type, e.g.:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface ProfileProps {} +type ProfileProps = Record<string, never>;This removes the need for the disable comment, satisfies Biome’s no-empty-interface rule, and clearly expresses that
Profileshould not receive any props.apps/admin-x-framework/src/api/config.ts (1)
6-7: ESLint suppression is valid; consider type alias as cleaner alternative.The eslint-disable comment correctly addresses the new
no-empty-object-typerule for this intentionally empty interface. However, sinceJSONArrayis simply extending an array type without adding properties, a type alias would be more idiomatic and eliminate the need for the lint suppression.Consider this refactor:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface JSONArray extends Array<string|number|boolean|Date|JSONObject|JSONValue> {} +type JSONArray = Array<string|number|boolean|Date|JSONObject|JSONValue>;apps/shade/src/components/layout/view-header.tsx (1)
32-32: ExportingViewHeaderActionssurfaces a props/runtime mismatch – consider forwarding attributes
ViewHeaderActionsPropsextendsReact.HTMLAttributes<HTMLElement>, butViewHeaderActionsonly destructureschildrenand doesn’t forwardclassNameor other attributes to the<div>. Now thatViewHeaderActionsis exported, callers can legally passclassName,aria-*, etc., but they’ll be dropped at runtime.Consider updating the component to forward
classNameviacn(...)and spread the remaining props onto the div:-const ViewHeaderActions:React.FC<ViewHeaderActionsProps> = ({children}) => { - return ( - <div className='flex items-center gap-2'> - {children} - </div> - ); -}; +const ViewHeaderActions:React.FC<ViewHeaderActionsProps> = ({ + children, + className, + ...props +}) => { + return ( + <div + {...props} + className={cn('flex items-center gap-2', className)} + > + {children} + </div> + ); +};This keeps the type contract honest and follows the
className+cn(...)forwarding guideline.As per coding guidelines, ...
apps/shade/src/components/layout/header.tsx (1)
103-104: Clarify whetherHeaderPropsshould be part of the public type surface
HeaderPropsis a nice centralisation of the Header’s prop type (PropsWithChildrenAndClassName+VariantProps<typeof headerVariants>), but it’s currently file-internal (noexport).If you intend consumers to use this type directly, consider exporting it, for example:
-interface HeaderProps extends PropsWithChildrenAndClassName, VariantProps<typeof headerVariants> {} +export interface HeaderProps extends PropsWithChildrenAndClassName, VariantProps<typeof headerVariants> {}or
export type HeaderProps = React.ComponentProps<typeof Header>;If it’s meant to stay internal, the current setup is fine as-is.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (53)
apps/activitypub/src/api/activitypub.ts(1 hunks)apps/activitypub/src/components/modals/new-note-modal.tsx(1 hunks)apps/activitypub/src/hooks/use-activity-pub-queries.ts(3 hunks)apps/activitypub/src/utils/get-username.ts(1 hunks)apps/activitypub/src/utils/image.ts(1 hunks)apps/activitypub/src/views/preferences/components/bluesky-sharing.tsx(1 hunks)apps/activitypub/src/views/preferences/components/profile.tsx(1 hunks)apps/activitypub/src/views/profile/profile.tsx(1 hunks)apps/admin-x-design-system/src/global/sortable-list.tsx(1 hunks)apps/admin-x-design-system/src/typings.d.ts(1 hunks)apps/admin-x-design-system/src/utils/format-url.ts(1 hunks)apps/admin-x-framework/src/api/config.ts(1 hunks)apps/admin-x-framework/src/api/recommendations.ts(1 hunks)apps/admin-x-framework/src/test/acceptance.ts(1 hunks)apps/admin-x-framework/src/test/test-utils.tsx(1 hunks)apps/admin-x-framework/test/unit/hooks/use-form.test.ts(2 hunks)apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/incoming-recommendation-list.tsx(1 hunks)apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx(2 hunks)apps/admin-x-settings/src/typings.d.ts(1 hunks)apps/admin-x-settings/src/utils/link-to-github-releases.ts(1 hunks)apps/admin-x-settings/src/utils/url.ts(1 hunks)apps/comments-ui/src/actions.ts(2 hunks)apps/comments-ui/src/app-context.ts(1 hunks)apps/comments-ui/src/components/content/forms/form.tsx(1 hunks)apps/comments-ui/src/components/popup-box.tsx(1 hunks)apps/comments-ui/src/typings.d.ts(1 hunks)apps/comments-ui/src/utils/admin-api.ts(1 hunks)apps/comments-ui/src/utils/api.ts(1 hunks)apps/posts/src/hooks/use-post-success-modal.ts(1 hunks)apps/posts/src/utils/link-helpers.ts(1 hunks)apps/posts/src/views/PostAnalytics/Growth/growth.tsx(1 hunks)apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx(1 hunks)apps/posts/src/views/PostAnalytics/Web/web.tsx(1 hunks)apps/shade/src/components/features/color-picker/color-picker.tsx(1 hunks)apps/shade/src/components/layout/header.tsx(7 hunks)apps/shade/src/components/layout/heading.tsx(1 hunks)apps/shade/src/components/layout/page.tsx(1 hunks)apps/shade/src/components/layout/view-header.tsx(2 hunks)apps/shade/src/components/ui/card.tsx(1 hunks)apps/shade/src/lib/utils.ts(1 hunks)apps/shade/src/typings.d.ts(1 hunks)apps/signup-form/src/components/pages/form-page.tsx(1 hunks)apps/signup-form/src/typings.d.ts(1 hunks)apps/stats/src/hooks/use-feature-flag.tsx(1 hunks)apps/stats/src/types/svg.d.ts(1 hunks)apps/stats/src/utils/url-helpers.ts(5 hunks)apps/stats/test/utils/tinybird-helpers.ts(1 hunks)ghost/core/core/server/services/recommendations/service/RecommendationMetadataService.ts(2 hunks)ghost/core/core/server/services/recommendations/service/UnsafeData.ts(1 hunks)
✅ Files skipped from review due to trivial changes (3)
- apps/shade/src/components/layout/page.tsx
- apps/shade/src/components/ui/card.tsx
- ghost/core/core/server/services/recommendations/service/RecommendationMetadataService.ts
🚧 Files skipped from review as they are similar to previous changes (27)
- ghost/core/core/server/services/recommendations/service/UnsafeData.ts
- apps/activitypub/src/api/activitypub.ts
- apps/shade/src/components/features/color-picker/color-picker.tsx
- apps/comments-ui/src/components/popup-box.tsx
- apps/activitypub/src/views/preferences/components/bluesky-sharing.tsx
- apps/admin-x-framework/src/test/test-utils.tsx
- apps/admin-x-settings/src/utils/url.ts
- apps/shade/src/lib/utils.ts
- apps/stats/src/utils/url-helpers.ts
- apps/admin-x-design-system/src/global/sortable-list.tsx
- apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx
- apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx
- apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx
- apps/stats/test/utils/tinybird-helpers.ts
- apps/posts/src/hooks/use-post-success-modal.ts
- apps/admin-x-framework/src/api/recommendations.ts
- apps/admin-x-settings/src/typings.d.ts
- apps/admin-x-design-system/src/utils/format-url.ts
- apps/shade/src/typings.d.ts
- apps/comments-ui/src/utils/api.ts
- apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx
- apps/shade/src/components/layout/heading.tsx
- apps/comments-ui/src/app-context.ts
- apps/activitypub/src/utils/get-username.ts
- apps/activitypub/src/utils/image.ts
- apps/admin-x-framework/src/test/acceptance.ts
- apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx
🧰 Additional context used
📓 Path-based instructions (4)
apps/shade/src/components/layout/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
Reusable layout containers (Page, Heading, Header, ViewHeader, ErrorPage) should be placed in
src/components/layout/*
Files:
apps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/view-header.tsx
apps/shade/src/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/src/components/**/*.{ts,tsx}: UsePascalCasefor component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Always forward and mergeclassNameprop withcn(...)utility function
Use CVA (Class Variance Authority) for component variants when useful instead of heavy prop configuration
Prefer compound subcomponents (e.g.,Header.Title,Header.Meta,Header.Actions) for multi-region components instead of many props
Use Tailwind CSS scoped via.shadeclass; dark mode uses.dark
Files:
apps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/view-header.tsx
apps/shade/src/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/src/**/*.{ts,tsx,js}: UsecamelCasefor function and variable names
Use the@alias for internal imports (e.g.,@/lib/utils)
Files:
apps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/view-header.tsx
apps/shade/{src,test}/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/{src,test}/**/*.{ts,tsx,js}: Runyarn lintafter making changes to fix any ESLint errors and warnings before committing
Follow ESLint andtailwindcss/*plugin rules when writing styles
Files:
apps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/view-header.tsx
🧠 Learnings (28)
📓 Common learnings
Learnt from: cmraible
Repo: TryGhost/Ghost PR: 24658
File: ghost/admin/package.json:3-3
Timestamp: 2025-08-12T18:33:15.524Z
Learning: In Ghost's admin package.json, third-party packages like ember-cli-postcss, ember-exam, and ember-power-select have their own independent versioning schemes that are unrelated to Ghost's version numbers. Version number coincidences between Ghost versions and these packages should not trigger update suggestions.
Learnt from: sagzy
Repo: TryGhost/Ghost PR: 24673
File: ghost/i18n/lib/i18n.js:34-35
Timestamp: 2025-11-24T11:12:15.712Z
Learning: In the Ghost i18n package (ghost/i18n/lib/i18n.js), changing existing locale codes requires backwards compatibility handling for users who have already configured those locales. Such changes should be done in a separate PR with migration logic rather than included in feature PRs.
Learnt from: sam-lord
Repo: TryGhost/Ghost PR: 25303
File: ghost/core/core/server/services/email-service/BatchSendingService.js:19-19
Timestamp: 2025-10-30T17:13:26.190Z
Learning: In ghost/core/core/server/services/email-service/BatchSendingService.js and similar files in the Ghost codebase, prefer using `{...options}` spread syntax without explicit guards like `...(options || {})` when spreading potentially undefined objects, as the maintainer prefers cleaner syntax over defensive patterns when the behavior is safe.
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T14:28:50.351Z
Learning: Admin-x React apps build to `apps/*/dist` using Vite, which are then copied by `ghost/admin/lib/asset-delivery` to `ghost/core/core/built/admin/assets/*`
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 24651
File: ghost/core/test/utils/urlUtils.js:53-57
Timestamp: 2025-08-11T19:39:00.428Z
Learning: In Ghost's test utilities, when fixing specific issues like async behavior, it's preferred to maintain existing error handling patterns (even if suboptimal) to keep PRs focused on their primary objective. Error handling improvements can be addressed in separate, dedicated PRs.
Learnt from: niranjan-uma-shankar
Repo: TryGhost/Ghost PR: 24557
File: apps/admin-x-settings/src/components/settings/general/TimeZone.tsx:7-7
Timestamp: 2025-08-01T12:44:07.467Z
Learning: In Ghost development, PRs may depend on unpublished changes from SDK packages. When this occurs, TypeScript compilation errors for missing exports are expected and documented in the PR description until the dependency packages are published and updated. This is normal workflow for cross-repository feature development.
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Use factory pattern for all test data creation instead of hard-coded data or direct database manipulation
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Test names should be lowercase and follow the format 'what is tested - expected outcome'
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Always follow ADRs in `../adr/` folder (ADR-0001: AAA pattern, ADR-0002: Page Objects)
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Follow the AAA (Arrange, Act, Assert) pattern in test structure
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Use `getByTestId()` only when semantic locators are unavailable, and suggest adding `data-testid` to Ghost codebase when needed
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Manual login should not be used - authentication is automatic via fixture
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-03-13T09:02:50.102Z
Learnt from: mike182uk
Repo: TryGhost/Ghost PR: 22471
File: apps/admin-x-activitypub/src/views/Feed/components/NewPostModal.tsx:29-34
Timestamp: 2025-03-13T09:02:50.102Z
Learning: In the Ghost ActivityPub module, error handling for mutations is handled at the hook level (in use-activity-pub-queries.ts) rather than in individual components. This allows for centralized error handling across the application.
Applied to files:
apps/activitypub/src/components/modals/new-note-modal.tsxapps/activitypub/src/hooks/use-activity-pub-queries.ts
📚 Learning: 2025-03-13T09:02:50.102Z
Learnt from: mike182uk
Repo: TryGhost/Ghost PR: 22471
File: apps/admin-x-activitypub/src/views/Feed/components/NewPostModal.tsx:29-34
Timestamp: 2025-03-13T09:02:50.102Z
Learning: In the ActivityPub module, error handling for mutations is handled at the hook level (in use-activity-pub-queries.ts) rather than in individual components. This allows for centralized error handling across the application.
Applied to files:
apps/activitypub/src/components/modals/new-note-modal.tsxapps/activitypub/src/hooks/use-activity-pub-queries.ts
📚 Learning: 2025-08-11T19:39:00.428Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 24651
File: ghost/core/test/utils/urlUtils.js:53-57
Timestamp: 2025-08-11T19:39:00.428Z
Learning: In Ghost's test utilities, when fixing specific issues like async behavior, it's preferred to maintain existing error handling patterns (even if suboptimal) to keep PRs focused on their primary objective. Error handling improvements can be addressed in separate, dedicated PRs.
Applied to files:
apps/activitypub/src/views/preferences/components/profile.tsx
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.{ts,tsx} : Prefer less comments and give things clear names
Applied to files:
apps/comments-ui/src/actions.tsapps/signup-form/src/typings.d.tsapps/activitypub/src/views/profile/profile.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Prefer compound subcomponents (e.g., `Header.Title`, `Header.Meta`, `Header.Actions`) for multi-region components instead of many props
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/layout/**/*.{ts,tsx} : Reusable layout containers (Page, Heading, Header, ViewHeader, ErrorPage) should be placed in `src/components/layout/*`
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use CVA (Class Variance Authority) for component variants when useful instead of heavy prop configuration
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/index.ts : Place new UI components under `src/components/ui` and export them from `src/index.ts`
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use `PascalCase` for component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use Tailwind CSS scoped via `.shade` class; dark mode uses `.dark`
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/features/**/*.{ts,tsx} : Higher-level, opinionated components (e.g., PostShareModal, SourceTabs) should be placed in `src/components/features/*`
Applied to files:
apps/shade/src/components/layout/header.tsx
📚 Learning: 2025-11-25T11:58:51.652Z
Learnt from: ibalosh
Repo: TryGhost/Ghost PR: 25525
File: apps/shade/src/shade-app.tsx:4-4
Timestamp: 2025-11-25T11:58:51.652Z
Learning: In apps/shade, the app wrapper file should be named `src/shade-app.tsx` (kebab-case) while the component itself is exported as `ShadeApp` (PascalCase). Context providers should be placed in `src/providers/*` using kebab-case filenames.
Applied to files:
apps/shade/src/components/layout/header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/ui/**/*.{ts,tsx} : Atomic UI components should be placed in `src/components/ui/*` and each component must have a corresponding `*.stories.tsx` file next to it for Storybook documentation
Applied to files:
apps/shade/src/components/layout/header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/lib/utils.ts : Shared utilities (class merging, formatting, chart helpers) should be centralized in `src/lib/utils.ts`
Applied to files:
apps/shade/src/components/layout/header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Always forward and merge `className` prop with `cn(...)` utility function
Applied to files:
apps/shade/src/components/layout/header.tsx
📚 Learning: 2025-12-09T12:37:23.267Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 25501
File: apps/shade/src/hooks/use-mobile.tsx:5-10
Timestamp: 2025-12-09T12:37:23.267Z
Learning: In the Ghost repository, this guideline applies to the shade admin app. For files under apps/shade that access browser globals (navigator, window, document) at module load time, SSR is not used, so typeof guards are not required. Reviewers should verify that such files remain client-side only and that no SSR context is introduced; apply this understanding to similarly structured files under apps/shade.
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-03-13T09:00:20.205Z
Learnt from: mike182uk
Repo: TryGhost/Ghost PR: 22471
File: apps/admin-x-activitypub/src/utils/pending-activity.ts:13-71
Timestamp: 2025-03-13T09:00:20.205Z
Learning: The pending activity utilities in Ghost's ActivityPub module are thoroughly tested in `apps/admin-x-activitypub/test/unit/utils/pending-activity.ts`, which covers `generatePendingActivityId`, `isPendingActivity`, and `generatePendingActivity` functions.
Applied to files:
apps/activitypub/src/hooks/use-activity-pub-queries.ts
📚 Learning: 2025-03-13T09:00:20.205Z
Learnt from: mike182uk
Repo: TryGhost/Ghost PR: 22471
File: apps/admin-x-activitypub/src/utils/pending-activity.ts:13-71
Timestamp: 2025-03-13T09:00:20.205Z
Learning: The pending activity utilities in the Ghost ActivityPub module are covered by tests in the file `apps/admin-x-activitypub/test/unit/utils/pending-activity.ts`.
Applied to files:
apps/activitypub/src/hooks/use-activity-pub-queries.ts
📚 Learning: 2025-11-05T16:49:21.124Z
Learnt from: rob-ghost
Repo: TryGhost/Ghost PR: 25356
File: apps/admin/src/hooks/user-preferences.ts:20-20
Timestamp: 2025-11-05T16:49:21.124Z
Learning: In apps/admin/src/hooks/user-preferences.ts, the query key for user preferences intentionally includes `user?.accessibility` (not just `user?.id`) so the cache automatically reacts to changes from any source (useEditUserPreferences, other editUser calls, external updates). Combined with `cacheTime: 0`, this design garbage-collects orphaned entries while keeping the active entry cached. This is a documented, intentional architectural decision.
Applied to files:
apps/activitypub/src/hooks/use-activity-pub-queries.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/**/*.{ts,tsx,js} : Use the `@` alias for internal imports (e.g., `@/lib/utils`)
Applied to files:
apps/admin-x-design-system/src/typings.d.ts
📚 Learning: 2025-07-14T12:20:35.268Z
Learnt from: sagzy
Repo: TryGhost/Ghost PR: 24346
File: apps/admin-x-settings/src/components/settings/growth/Network.tsx:8-12
Timestamp: 2025-07-14T12:20:35.268Z
Learning: The Network component toggle in `apps/admin-x-settings/src/components/settings/growth/Network.tsx` is intentionally implemented as static UI with a no-op onChange handler, as part of a UI-first development approach before connecting actual ActivityPub functionality.
Applied to files:
apps/activitypub/src/views/profile/profile.tsx
🪛 Biome (2.1.2)
apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx
[error] 17-18: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/posts/src/views/PostAnalytics/Web/web.tsx
[error] 26-27: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/activitypub/src/views/profile/profile.tsx
[error] 13-14: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/posts/src/views/PostAnalytics/Growth/growth.tsx
[error] 16-17: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
🔇 Additional comments (16)
apps/posts/src/utils/link-helpers.ts (1)
30-30: LGTM! Clean linting fix.The bare
catchsyntax correctly removes the unused error binding while preserving the fallback behavior.apps/admin-x-settings/src/components/settings/growth/recommendations/incoming-recommendation-list.tsx (1)
20-27: Barecatchis appropriate; behavior remains unchangedThe error value was unused and the intent is clearly to ignore invalid URLs, so switching to a bare
catchis idiomatic and keeps the existing control flow intact.apps/comments-ui/src/components/content/forms/form.tsx (1)
78-78: LGTM! Valid refactor aligning with ESLint rules.The change to a bare
catchblock is correct since the error variable wasn't being used. This is a clean refactor enforced by the updated ESLint plugin.apps/admin-x-settings/src/utils/link-to-github-releases.ts (1)
32-32: LGTM! Bare catch is appropriate here.The change to bare
catchsyntax is correct since the error parameter isn't used. This aligns with the updated ESLint rules and produces cleaner code.apps/comments-ui/src/utils/admin-api.ts (1)
15-20: Barecatchhere is safe and keeps behavior unchanged
catch {is equivalent to the previouscatch (err)because the error value wasn’t used. JSON parse failures still cause an early return, and there’s no change to control flow or observable behavior. This fits the lint-driven cleanup in this PR.apps/admin-x-framework/test/unit/hooks/use-form.test.ts (1)
186-212: Bare catch usage in tests keeps behavior unchangedBoth error-handling tests still behave the same; the caught error value was never used, so switching to
catch {}is fine and keeps intent clear.Also applies to: 214-238
apps/signup-form/src/components/pages/form-page.tsx (1)
23-39: Submit error handler change is a no-op behaviorallySwapping
catch (_: any)forcatch {}is safe here—the error value wasn’t used, and the user-facing error + loading reset logic is unchanged.apps/activitypub/src/hooks/use-activity-pub-queries.ts (3)
360-403: Notifications “liked” cache: bare catch preserves existing fallbackThe change to
catch {}simply drops an unused parameter; on any exception you still returncurrent, so runtime behavior is identical.
406-449: Notifications “repost” cache: no functional change from catch refactorSame pattern here—the error value wasn’t used, and you still fall back to
currenton any failure, so cache behavior is unchanged.
452-495: Notifications reply-count cache: behaviorally equivalent catchAgain, moving to
catch {}keeps the same “return current on error” behavior with no change to observable results.apps/activitypub/src/components/modals/new-note-modal.tsx (1)
68-105: handlePost catch cleanup is safeThe caught error was unused; switching to
catch {}keeps the same control flow (includingonReplyError?.()and thefinally-drivensetIsPosting(false)).apps/comments-ui/src/actions.ts (1)
257-276: like/unlike optimistic updates: catch refactor keeps rollback behaviorUsing
catch {}instead ofcatch (err)is fine here; errors are still swallowed and the optimisticupdateCommentLikeStateis reverted on failure as before.apps/stats/src/hooks/use-feature-flag.tsx (1)
17-25: Labs JSON parsing: bare catch is fineDropping the unused error parameter in the parse
try/catchhas no behavioral impact; you still safely fall back to an empty labs object on invalid JSON.apps/activitypub/src/views/preferences/components/profile.tsx (1)
258-315: Profile image copy: nested bare catches keep UX behaviorBoth inner and outer
catchblocks only showed a toast and resetisProcessing; removing the unused error binding doesn’t alter success/failure behavior or state cleanup.apps/shade/src/components/layout/view-header.tsx (1)
4-5: Localizedno-empty-object-typedisable for named props alias looks fineThis interface is acting as a named alias for
React.HTMLAttributes<HTMLElement>rather than introducing new fields, so the per-interface eslint-disable is a reasonable way to keep the public props name without fighting the rule. No changes needed here.apps/shade/src/components/layout/header.tsx (1)
11-12: Scopedno-empty-object-typedisables for Header subcomponent props are appropriateEach of these interfaces is a named wrapper around
PropsWithChildrenAndClassNameused for theHeader.*compound subcomponents, so they intentionally don’t add new fields. Using per-interface@typescript-eslint/no-empty-object-typedisables keeps the lint rule active for other types while preserving clear, named props for the publicHeader.*API.Based on learnings, this aligns with the preferred compound subcomponent pattern for
Header.*.Also applies to: 24-25, 40-41, 53-54, 66-67, 79-80
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (4)
apps/posts/src/views/PostAnalytics/Web/web.tsx (1)
26-27: Consider using a type alias instead of suppressing the lint rule.The empty interface could be replaced with a type alias to align with TypeScript best practices and avoid the need for the ESLint suppression.
Apply this diff:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} +type postAnalyticsProps = Record<string, never>;Alternatively, if props are planned for the future, consider adding a comment to document that intent.
apps/posts/src/views/PostAnalytics/Growth/growth.tsx (1)
16-17: Consider using a type alias instead of suppressing the lint rule.The empty interface could be replaced with a type alias to align with TypeScript best practices and avoid the need for the ESLint suppression.
Apply this diff:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} +type postAnalyticsProps = Record<string, never>;Alternatively, if props are planned for the future, consider adding a comment to document that intent.
apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx (1)
17-18: Consider using a type alias instead of suppressing the lint rule.The empty interface could be replaced with a type alias to align with TypeScript best practices and avoid the need for the ESLint suppression.
Apply this diff:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} +type postAnalyticsProps = Record<string, never>;Alternatively, if props are planned for the future, consider adding a comment to document that intent.
apps/activitypub/src/views/profile/profile.tsx (1)
13-14: Consider simplifying the empty interface.The ESLint disable comment works, but empty interfaces are often unnecessary. Since this interface has no properties, you could:
- Remove the interface entirely and use
React.FCwithout type parameters, or- Use
type ProfileProps = Record<string, never>for explicit empty typingHowever, if you're planning to add props in the near future, the current approach is acceptable.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (53)
apps/activitypub/src/api/activitypub.ts(1 hunks)apps/activitypub/src/components/modals/new-note-modal.tsx(1 hunks)apps/activitypub/src/hooks/use-activity-pub-queries.ts(3 hunks)apps/activitypub/src/utils/get-username.ts(1 hunks)apps/activitypub/src/utils/image.ts(1 hunks)apps/activitypub/src/views/preferences/components/bluesky-sharing.tsx(1 hunks)apps/activitypub/src/views/preferences/components/profile.tsx(1 hunks)apps/activitypub/src/views/profile/profile.tsx(1 hunks)apps/admin-x-design-system/src/global/sortable-list.tsx(1 hunks)apps/admin-x-design-system/src/typings.d.ts(1 hunks)apps/admin-x-design-system/src/utils/format-url.ts(1 hunks)apps/admin-x-framework/src/api/config.ts(1 hunks)apps/admin-x-framework/src/api/recommendations.ts(1 hunks)apps/admin-x-framework/src/test/acceptance.ts(1 hunks)apps/admin-x-framework/src/test/test-utils.tsx(1 hunks)apps/admin-x-framework/test/unit/hooks/use-form.test.ts(2 hunks)apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/incoming-recommendation-list.tsx(1 hunks)apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx(2 hunks)apps/admin-x-settings/src/typings.d.ts(1 hunks)apps/admin-x-settings/src/utils/link-to-github-releases.ts(1 hunks)apps/admin-x-settings/src/utils/url.ts(1 hunks)apps/comments-ui/src/actions.ts(2 hunks)apps/comments-ui/src/app-context.ts(1 hunks)apps/comments-ui/src/components/content/forms/form.tsx(1 hunks)apps/comments-ui/src/components/popup-box.tsx(1 hunks)apps/comments-ui/src/typings.d.ts(1 hunks)apps/comments-ui/src/utils/admin-api.ts(1 hunks)apps/comments-ui/src/utils/api.ts(1 hunks)apps/posts/src/hooks/use-post-success-modal.ts(1 hunks)apps/posts/src/utils/link-helpers.ts(1 hunks)apps/posts/src/views/PostAnalytics/Growth/growth.tsx(1 hunks)apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx(1 hunks)apps/posts/src/views/PostAnalytics/Web/web.tsx(1 hunks)apps/shade/src/components/features/color-picker/color-picker.tsx(1 hunks)apps/shade/src/components/layout/header.tsx(7 hunks)apps/shade/src/components/layout/heading.tsx(1 hunks)apps/shade/src/components/layout/page.tsx(1 hunks)apps/shade/src/components/layout/view-header.tsx(2 hunks)apps/shade/src/components/ui/card.tsx(1 hunks)apps/shade/src/lib/utils.ts(1 hunks)apps/shade/src/typings.d.ts(1 hunks)apps/signup-form/src/components/pages/form-page.tsx(1 hunks)apps/signup-form/src/typings.d.ts(1 hunks)apps/stats/src/hooks/use-feature-flag.tsx(1 hunks)apps/stats/src/types/svg.d.ts(1 hunks)apps/stats/src/utils/url-helpers.ts(5 hunks)apps/stats/test/utils/tinybird-helpers.ts(1 hunks)ghost/core/core/server/services/recommendations/service/RecommendationMetadataService.ts(2 hunks)ghost/core/core/server/services/recommendations/service/UnsafeData.ts(1 hunks)
✅ Files skipped from review due to trivial changes (3)
- apps/admin-x-settings/src/typings.d.ts
- apps/comments-ui/src/utils/api.ts
- apps/comments-ui/src/typings.d.ts
🚧 Files skipped from review as they are similar to previous changes (30)
- apps/stats/src/hooks/use-feature-flag.tsx
- ghost/core/core/server/services/recommendations/service/UnsafeData.ts
- apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx
- apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx
- apps/shade/src/components/ui/card.tsx
- apps/admin-x-settings/src/utils/link-to-github-releases.ts
- apps/posts/src/hooks/use-post-success-modal.ts
- apps/admin-x-framework/src/test/acceptance.ts
- apps/admin-x-design-system/src/global/sortable-list.tsx
- apps/signup-form/src/components/pages/form-page.tsx
- apps/activitypub/src/utils/get-username.ts
- apps/activitypub/src/hooks/use-activity-pub-queries.ts
- apps/admin-x-settings/src/components/settings/growth/recommendations/incoming-recommendation-list.tsx
- apps/stats/test/utils/tinybird-helpers.ts
- apps/admin-x-framework/src/api/config.ts
- apps/shade/src/components/layout/header.tsx
- apps/activitypub/src/views/preferences/components/bluesky-sharing.tsx
- apps/shade/src/components/layout/page.tsx
- apps/admin-x-design-system/src/utils/format-url.ts
- apps/comments-ui/src/actions.ts
- apps/shade/src/components/layout/heading.tsx
- apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx
- apps/stats/src/utils/url-helpers.ts
- apps/posts/src/utils/link-helpers.ts
- apps/comments-ui/src/utils/admin-api.ts
- apps/signup-form/src/typings.d.ts
- apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx
- apps/admin-x-framework/src/test/test-utils.tsx
- apps/activitypub/src/components/modals/new-note-modal.tsx
- ghost/core/core/server/services/recommendations/service/RecommendationMetadataService.ts
🧰 Additional context used
📓 Path-based instructions (6)
apps/shade/src/lib/utils.ts
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
Shared utilities (class merging, formatting, chart helpers) should be centralized in
src/lib/utils.ts
Files:
apps/shade/src/lib/utils.ts
apps/shade/src/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/src/**/*.{ts,tsx,js}: UsecamelCasefor function and variable names
Use the@alias for internal imports (e.g.,@/lib/utils)
Files:
apps/shade/src/lib/utils.tsapps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/view-header.tsxapps/shade/src/typings.d.ts
apps/shade/{src,test}/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/{src,test}/**/*.{ts,tsx,js}: Runyarn lintafter making changes to fix any ESLint errors and warnings before committing
Follow ESLint andtailwindcss/*plugin rules when writing styles
Files:
apps/shade/src/lib/utils.tsapps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/view-header.tsxapps/shade/src/typings.d.ts
apps/shade/src/components/features/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
Higher-level, opinionated components (e.g., PostShareModal, SourceTabs) should be placed in
src/components/features/*
Files:
apps/shade/src/components/features/color-picker/color-picker.tsx
apps/shade/src/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/src/components/**/*.{ts,tsx}: UsePascalCasefor component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Always forward and mergeclassNameprop withcn(...)utility function
Use CVA (Class Variance Authority) for component variants when useful instead of heavy prop configuration
Prefer compound subcomponents (e.g.,Header.Title,Header.Meta,Header.Actions) for multi-region components instead of many props
Use Tailwind CSS scoped via.shadeclass; dark mode uses.dark
Files:
apps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/view-header.tsx
apps/shade/src/components/layout/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
Reusable layout containers (Page, Heading, Header, ViewHeader, ErrorPage) should be placed in
src/components/layout/*
Files:
apps/shade/src/components/layout/view-header.tsx
🧠 Learnings (25)
📓 Common learnings
Learnt from: cmraible
Repo: TryGhost/Ghost PR: 24658
File: ghost/admin/package.json:3-3
Timestamp: 2025-08-12T18:33:15.524Z
Learning: In Ghost's admin package.json, third-party packages like ember-cli-postcss, ember-exam, and ember-power-select have their own independent versioning schemes that are unrelated to Ghost's version numbers. Version number coincidences between Ghost versions and these packages should not trigger update suggestions.
Learnt from: sam-lord
Repo: TryGhost/Ghost PR: 25303
File: ghost/core/core/server/services/email-service/BatchSendingService.js:19-19
Timestamp: 2025-10-30T17:13:26.190Z
Learning: In ghost/core/core/server/services/email-service/BatchSendingService.js and similar files in the Ghost codebase, prefer using `{...options}` spread syntax without explicit guards like `...(options || {})` when spreading potentially undefined objects, as the maintainer prefers cleaner syntax over defensive patterns when the behavior is safe.
Learnt from: sagzy
Repo: TryGhost/Ghost PR: 24673
File: ghost/i18n/lib/i18n.js:34-35
Timestamp: 2025-11-24T11:12:15.712Z
Learning: In the Ghost i18n package (ghost/i18n/lib/i18n.js), changing existing locale codes requires backwards compatibility handling for users who have already configured those locales. Such changes should be done in a separate PR with migration logic rather than included in feature PRs.
Learnt from: niranjan-uma-shankar
Repo: TryGhost/Ghost PR: 24557
File: apps/admin-x-settings/src/components/settings/general/TimeZone.tsx:7-7
Timestamp: 2025-08-01T12:44:07.467Z
Learning: In Ghost development, PRs may depend on unpublished changes from SDK packages. When this occurs, TypeScript compilation errors for missing exports are expected and documented in the PR description until the dependency packages are published and updated. This is normal workflow for cross-repository feature development.
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 24651
File: ghost/core/test/utils/urlUtils.js:53-57
Timestamp: 2025-08-11T19:39:00.428Z
Learning: In Ghost's test utilities, when fixing specific issues like async behavior, it's preferred to maintain existing error handling patterns (even if suboptimal) to keep PRs focused on their primary objective. Error handling improvements can be addressed in separate, dedicated PRs.
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T14:28:50.351Z
Learning: Admin-x React apps build to `apps/*/dist` using Vite, which are then copied by `ghost/admin/lib/asset-delivery` to `ghost/core/core/built/admin/assets/*`
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/lib/utils.ts : Shared utilities (class merging, formatting, chart helpers) should be centralized in `src/lib/utils.ts`
Applied to files:
apps/shade/src/lib/utils.tsapps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/typings.d.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Test names should be lowercase and follow the format 'what is tested - expected outcome'
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Use factory pattern for all test data creation instead of hard-coded data or direct database manipulation
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Follow the AAA (Arrange, Act, Assert) pattern in test structure
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Always follow ADRs in `../adr/` folder (ADR-0001: AAA pattern, ADR-0002: Page Objects)
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Manual login should not be used - authentication is automatic via fixture
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Use `getByTestId()` only when semantic locators are unavailable, and suggest adding `data-testid` to Ghost codebase when needed
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Prefer semantic locators (`getByRole`, `getByLabel`, `getByText`) over test IDs and never use CSS selectors, XPath, nth-child, or class names
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use CVA (Class Variance Authority) for component variants when useful instead of heavy prop configuration
Applied to files:
apps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/view-header.tsxapps/comments-ui/src/components/popup-box.tsxapps/comments-ui/src/app-context.tsapps/shade/src/typings.d.ts
📚 Learning: 2025-09-10T07:05:34.606Z
Learnt from: jonatansberg
Repo: TryGhost/Ghost PR: 24838
File: apps/shade/src/components/features/color-picker/color-picker.tsx:0-0
Timestamp: 2025-09-10T07:05:34.606Z
Learning: The Color library used in the color picker component handles input validation and clamping automatically, so manual validation of HSL and RGB values is not necessary when using Color constructors.
Applied to files:
apps/shade/src/components/features/color-picker/color-picker.tsx
📚 Learning: 2025-12-09T12:37:23.267Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 25501
File: apps/shade/src/hooks/use-mobile.tsx:5-10
Timestamp: 2025-12-09T12:37:23.267Z
Learning: In the Ghost repository, this guideline applies to the shade admin app. For files under apps/shade that access browser globals (navigator, window, document) at module load time, SSR is not used, so typeof guards are not required. Reviewers should verify that such files remain client-side only and that no SSR context is introduced; apply this understanding to similarly structured files under apps/shade.
Applied to files:
apps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Prefer compound subcomponents (e.g., `Header.Title`, `Header.Meta`, `Header.Actions`) for multi-region components instead of many props
Applied to files:
apps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/layout/**/*.{ts,tsx} : Reusable layout containers (Page, Heading, Header, ViewHeader, ErrorPage) should be placed in `src/components/layout/*`
Applied to files:
apps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.{ts,tsx} : Prefer less comments and give things clear names
Applied to files:
apps/shade/src/components/layout/view-header.tsxapps/comments-ui/src/app-context.tsapps/admin-x-framework/src/api/recommendations.tsapps/activitypub/src/views/profile/profile.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/index.ts : Place new UI components under `src/components/ui` and export them from `src/index.ts`
Applied to files:
apps/shade/src/components/layout/view-header.tsxapps/shade/src/typings.d.ts
📚 Learning: 2025-03-13T09:02:50.102Z
Learnt from: mike182uk
Repo: TryGhost/Ghost PR: 22471
File: apps/admin-x-activitypub/src/views/Feed/components/NewPostModal.tsx:29-34
Timestamp: 2025-03-13T09:02:50.102Z
Learning: In the Ghost ActivityPub module, error handling for mutations is handled at the hook level (in use-activity-pub-queries.ts) rather than in individual components. This allows for centralized error handling across the application.
Applied to files:
apps/activitypub/src/views/preferences/components/profile.tsxapps/activitypub/src/api/activitypub.ts
📚 Learning: 2025-03-13T09:02:50.102Z
Learnt from: mike182uk
Repo: TryGhost/Ghost PR: 22471
File: apps/admin-x-activitypub/src/views/Feed/components/NewPostModal.tsx:29-34
Timestamp: 2025-03-13T09:02:50.102Z
Learning: In the ActivityPub module, error handling for mutations is handled at the hook level (in use-activity-pub-queries.ts) rather than in individual components. This allows for centralized error handling across the application.
Applied to files:
apps/activitypub/src/views/preferences/components/profile.tsxapps/activitypub/src/api/activitypub.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/**/*.{ts,tsx,js} : Use the `@` alias for internal imports (e.g., `@/lib/utils`)
Applied to files:
apps/admin-x-design-system/src/typings.d.tsapps/shade/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use Tailwind CSS scoped via `.shade` class; dark mode uses `.dark`
Applied to files:
apps/shade/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use `PascalCase` for component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Applied to files:
apps/shade/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Follow ESLint and `tailwindcss/*` plugin rules when writing styles
Applied to files:
apps/shade/src/typings.d.ts
📚 Learning: 2025-11-25T11:58:51.652Z
Learnt from: ibalosh
Repo: TryGhost/Ghost PR: 25525
File: apps/shade/src/shade-app.tsx:4-4
Timestamp: 2025-11-25T11:58:51.652Z
Learning: In apps/shade, the app wrapper file should be named `src/shade-app.tsx` (kebab-case) while the component itself is exported as `ShadeApp` (PascalCase). Context providers should be placed in `src/providers/*` using kebab-case filenames.
Applied to files:
apps/shade/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Run `yarn lint` after making changes to fix any ESLint errors and warnings before committing
Applied to files:
apps/shade/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/ui/**/*.{ts,tsx} : Atomic UI components should be placed in `src/components/ui/*` and each component must have a corresponding `*.stories.tsx` file next to it for Storybook documentation
Applied to files:
apps/shade/src/typings.d.ts
🪛 Biome (2.1.2)
apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx
[error] 17-18: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/activitypub/src/views/profile/profile.tsx
[error] 13-14: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/posts/src/views/PostAnalytics/Growth/growth.tsx
[error] 16-17: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/posts/src/views/PostAnalytics/Web/web.tsx
[error] 26-27: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
🔇 Additional comments (18)
apps/admin-x-settings/src/utils/url.ts (1)
27-32: LGTM!Clean refactor removing the unused error parameter. The bare
catchsyntax is idiomatic when the error object isn't needed.apps/comments-ui/src/components/popup-box.tsx (1)
6-8: ESLint rule rename looks correctSwitching the disable to
@typescript-eslint/no-empty-object-typematches the newer rule name and keeps the existing emptyPropspattern intact; no behavior change here and it aligns with the rest of the PR.apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx (1)
19-31: BarecatchinvalidateUrlkeeps behavior unchanged and removes an unused bindingSwitching from
catch (e)to a barecatchis correct here: the error object wasn’t used, and all exceptions fromnew URL(url)are still handled by settingerrors.url. This aligns with linting expectations without altering validation behavior.apps/admin-x-design-system/src/typings.d.ts (1)
2-2: LGTM! Correct suppression for ambient module declaration.The
no-require-importsrule must be disabled here because TypeScript's ambient module declarations require theimport = require()syntax. This is the appropriate fix after updating the ESLint plugin.apps/stats/src/types/svg.d.ts (1)
2-2: LGTM! Consistent with other SVG module declarations.This matches the pattern applied across the codebase for handling the updated ESLint rules. The suppression is necessary for ambient module syntax.
apps/shade/src/typings.d.ts (1)
2-2: LGTM! Correct ESLint suppression.The lint suppression is properly applied. As per coding guidelines, ensure
yarn linthas been run to verify all ESLint rules are satisfied.apps/activitypub/src/views/preferences/components/profile.tsx (2)
62-79: LGTM: Unused error parameter removed.The removal of the unused error parameter from the catch block aligns with the ESLint plugin update. The error handling behavior (toast notification and state reset) remains unchanged.
258-315: LGTM: Unused error parameters removed from nested catch blocks.Both the inner (line 307) and outer (line 311) catch blocks have had their unused error parameters removed, consistent with the ESLint plugin update. The error handling logic (toast notifications and processing state management) is preserved.
apps/comments-ui/src/components/content/forms/form.tsx (1)
78-78: LGTM!The change from
catch (e)to barecatchis safe and follows modern JavaScript best practices. Since the error variable was unused, removing the binding is appropriate and aligns with the updated ESLint rules.apps/comments-ui/src/app-context.ts (1)
118-118: LGTM!The change to bare
catchis appropriate since the error is not used. The fallback behavior (returning an empty object) is preserved.apps/admin-x-framework/test/unit/hooks/use-form.test.ts (1)
206-208: LGTM!The bare
catch {}syntax correctly handles expected exceptions in these tests. The change removes unused error bindings while preserving test behavior.Also applies to: 233-235
apps/shade/src/lib/utils.ts (1)
101-101: LGTM!The bare
catchis appropriate here since the error is not used. The fallback behavior (returning the original URL when parsing fails) is preserved.apps/activitypub/src/api/activitypub.ts (1)
257-257: LGTM!The bare
catchis appropriate since the error is currently unused. The fallback behavior (returningnull) is preserved. Note that the TODO comment on line 258 suggests error tracking might be added in the future.apps/activitypub/src/utils/image.ts (1)
25-25: LGTM!The bare
catchis appropriate since the error is not used. The fallback behavior (returning the original URL when conversion fails) is preserved, which is a sensible approach for handling CORS or fetch failures gracefully.apps/shade/src/components/features/color-picker/color-picker.tsx (1)
388-388: LGTM!The bare
catchis appropriate here since invalid color inputs are intentionally ignored (as noted in the comment). The error binding was unnecessary for this use case.apps/shade/src/components/layout/view-header.tsx (2)
4-5: Lint suppression around empty props interface is appropriateDisabling
@typescript-eslint/no-empty-object-typehere keeps the existingViewHeaderActionsPropsshape without altering runtime behavior and is consistent with the pattern used across shade layout components.
32-32: Named export of ViewHeader components looks goodExporting
ViewHeaderandViewHeaderActionstogether matches the compound subcomponent pattern we use for layout pieces and keeps them discoverable from a single module. Based on learnings, this aligns with the shade layout guidelines.apps/admin-x-framework/src/api/recommendations.ts (1)
25-29: ESLint suppressions on empty response interfaces are fineThe targeted
@typescript-eslint/no-empty-object-typedisables preserve the existing public response types for edit/delete mutations without changing any runtime behavior, which is appropriate for this ESLint-focused PR.
c0f581d to
b48e7c2
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
apps/activitypub/src/views/profile/profile.tsx (1)
13-14: Consider removing the empty interface or using an explicit no-props type.The ESLint disable comment masks a valid warning. Since
Profilereceives no props, you have cleaner alternatives:Option 1 (recommended): Remove the interface entirely
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface ProfileProps {} - -const Profile: React.FC<ProfileProps> = ({}) => { +const Profile: React.FC = () => {Option 2: Use an explicit no-props type if you want to document the intent
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface ProfileProps {} +type ProfileProps = Record<string, never>;Based on learnings, run
yarn lintafter making changes to fix any ESLint errors and warnings before committing.apps/posts/src/views/PostAnalytics/Web/web.tsx (1)
26-27: EmptypostAnalyticsPropsinterface – consider a type alias to satisfy linters without disablesThis placeholder props type is fine functionally, but Biome flags the empty interface and you’re also having to suppress
@typescript-eslint/no-empty-object-type. To keep the named props type while avoiding both lint issues, you could switch to a non-empty alias and drop the disable:-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} +type postAnalyticsProps = Record<string, never>;This keeps
React.FC<postAnalyticsProps>intact, removes the need for the eslint-disable, and should make Biome happy as well.apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx (1)
17-18: AlignpostAnalyticsPropswith type-alias pattern to avoid empty-interface lint noiseSame as in
web.tsx: the empty interface is harmless but trips Biome and requires an ESLint suppression. If you want to clean this up and stay consistent across analytics views, you could switch to a non-empty alias:-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} +type postAnalyticsProps = Record<string, never>;This keeps the component signature (
React.FC<postAnalyticsProps>) while removing the eslint-disable and addressing Biome’s noEmptyInterface error.apps/posts/src/views/PostAnalytics/Growth/growth.tsx (1)
16-17: Optional: replace emptypostAnalyticsPropsinterface with an alias (and drop the disable)To keep the placeholder props type but avoid both the ESLint suppression and Biome’s noEmptyInterface error, you can mirror the pattern suggested for the other analytics views:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} +type postAnalyticsProps = Record<string, never>;Behavior stays the same, but linting becomes cleaner and consistent across Growth/Web/Newsletter.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (55)
apps/activitypub/src/api/activitypub.ts(1 hunks)apps/activitypub/src/components/modals/new-note-modal.tsx(1 hunks)apps/activitypub/src/hooks/use-activity-pub-queries.ts(3 hunks)apps/activitypub/src/utils/get-username.ts(1 hunks)apps/activitypub/src/utils/image.ts(1 hunks)apps/activitypub/src/views/preferences/components/bluesky-sharing.tsx(1 hunks)apps/activitypub/src/views/preferences/components/profile.tsx(1 hunks)apps/activitypub/src/views/profile/profile.tsx(1 hunks)apps/admin-x-design-system/src/global/sortable-list.tsx(1 hunks)apps/admin-x-design-system/src/typings.d.ts(1 hunks)apps/admin-x-design-system/src/utils/format-url.ts(1 hunks)apps/admin-x-framework/src/api/config.ts(1 hunks)apps/admin-x-framework/src/api/recommendations.ts(1 hunks)apps/admin-x-framework/src/test/acceptance.ts(1 hunks)apps/admin-x-framework/src/test/test-utils.tsx(1 hunks)apps/admin-x-framework/test/unit/hooks/use-form.test.ts(2 hunks)apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/incoming-recommendation-list.tsx(1 hunks)apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx(2 hunks)apps/admin-x-settings/src/typings.d.ts(1 hunks)apps/admin-x-settings/src/utils/link-to-github-releases.ts(2 hunks)apps/admin-x-settings/src/utils/url.ts(1 hunks)apps/admin/eslint.config.js(0 hunks)apps/comments-ui/src/actions.ts(2 hunks)apps/comments-ui/src/app-context.ts(1 hunks)apps/comments-ui/src/components/content/forms/form.tsx(1 hunks)apps/comments-ui/src/components/popup-box.tsx(1 hunks)apps/comments-ui/src/typings.d.ts(1 hunks)apps/comments-ui/src/utils/admin-api.ts(1 hunks)apps/comments-ui/src/utils/api.ts(1 hunks)apps/posts/src/hooks/use-post-success-modal.ts(1 hunks)apps/posts/src/utils/link-helpers.ts(1 hunks)apps/posts/src/views/PostAnalytics/Growth/growth.tsx(1 hunks)apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx(1 hunks)apps/posts/src/views/PostAnalytics/Web/web.tsx(1 hunks)apps/shade/src/components/features/color-picker/color-picker.tsx(1 hunks)apps/shade/src/components/layout/header.tsx(7 hunks)apps/shade/src/components/layout/heading.tsx(1 hunks)apps/shade/src/components/layout/page.tsx(1 hunks)apps/shade/src/components/layout/view-header.tsx(2 hunks)apps/shade/src/components/ui/card.tsx(1 hunks)apps/shade/src/lib/utils.ts(1 hunks)apps/shade/src/typings.d.ts(1 hunks)apps/signup-form/src/components/pages/form-page.tsx(1 hunks)apps/signup-form/src/typings.d.ts(1 hunks)apps/stats/src/hooks/use-feature-flag.tsx(1 hunks)apps/stats/src/types/svg.d.ts(1 hunks)apps/stats/src/utils/url-helpers.ts(5 hunks)apps/stats/test/utils/tinybird-helpers.ts(1 hunks)ghost/core/core/server/services/recommendations/service/RecommendationMetadataService.ts(2 hunks)ghost/core/core/server/services/recommendations/service/UnsafeData.ts(1 hunks)package.json(1 hunks)
💤 Files with no reviewable changes (1)
- apps/admin/eslint.config.js
✅ Files skipped from review due to trivial changes (1)
- apps/admin-x-design-system/src/global/sortable-list.tsx
🚧 Files skipped from review as they are similar to previous changes (30)
- apps/admin-x-settings/src/utils/link-to-github-releases.ts
- apps/activitypub/src/components/modals/new-note-modal.tsx
- apps/admin-x-design-system/src/utils/format-url.ts
- apps/activitypub/src/utils/image.ts
- apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx
- apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx
- apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx
- apps/admin-x-framework/src/test/acceptance.ts
- apps/activitypub/src/api/activitypub.ts
- apps/activitypub/src/utils/get-username.ts
- apps/signup-form/src/typings.d.ts
- apps/comments-ui/src/components/content/forms/form.tsx
- apps/stats/test/utils/tinybird-helpers.ts
- apps/shade/src/components/features/color-picker/color-picker.tsx
- apps/activitypub/src/hooks/use-activity-pub-queries.ts
- apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx
- apps/comments-ui/src/utils/api.ts
- apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx
- ghost/core/core/server/services/recommendations/service/RecommendationMetadataService.ts
- apps/shade/src/components/layout/view-header.tsx
- apps/shade/src/components/layout/heading.tsx
- apps/admin-x-framework/src/test/test-utils.tsx
- ghost/core/core/server/services/recommendations/service/UnsafeData.ts
- apps/comments-ui/src/actions.ts
- apps/admin-x-settings/src/typings.d.ts
- apps/stats/src/hooks/use-feature-flag.tsx
- apps/admin-x-framework/src/api/recommendations.ts
- apps/admin-x-design-system/src/typings.d.ts
- package.json
- apps/activitypub/src/views/preferences/components/bluesky-sharing.tsx
🧰 Additional context used
📓 Path-based instructions (6)
apps/shade/src/components/layout/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
Reusable layout containers (Page, Heading, Header, ViewHeader, ErrorPage) should be placed in
src/components/layout/*
Files:
apps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/page.tsx
apps/shade/src/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/src/components/**/*.{ts,tsx}: UsePascalCasefor component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Always forward and mergeclassNameprop withcn(...)utility function
Use CVA (Class Variance Authority) for component variants when useful instead of heavy prop configuration
Prefer compound subcomponents (e.g.,Header.Title,Header.Meta,Header.Actions) for multi-region components instead of many props
Use Tailwind CSS scoped via.shadeclass; dark mode uses.dark
Files:
apps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/page.tsxapps/shade/src/components/ui/card.tsx
apps/shade/src/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/src/**/*.{ts,tsx,js}: UsecamelCasefor function and variable names
Use the@alias for internal imports (e.g.,@/lib/utils)
Files:
apps/shade/src/components/layout/header.tsxapps/shade/src/typings.d.tsapps/shade/src/components/layout/page.tsxapps/shade/src/lib/utils.tsapps/shade/src/components/ui/card.tsx
apps/shade/{src,test}/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/{src,test}/**/*.{ts,tsx,js}: Runyarn lintafter making changes to fix any ESLint errors and warnings before committing
Follow ESLint andtailwindcss/*plugin rules when writing styles
Files:
apps/shade/src/components/layout/header.tsxapps/shade/src/typings.d.tsapps/shade/src/components/layout/page.tsxapps/shade/src/lib/utils.tsapps/shade/src/components/ui/card.tsx
apps/shade/src/lib/utils.ts
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
Shared utilities (class merging, formatting, chart helpers) should be centralized in
src/lib/utils.ts
Files:
apps/shade/src/lib/utils.ts
apps/shade/src/components/ui/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
Atomic UI components should be placed in
src/components/ui/*and each component must have a corresponding*.stories.tsxfile next to it for Storybook documentation
Files:
apps/shade/src/components/ui/card.tsx
🧠 Learnings (28)
📓 Common learnings
Learnt from: cmraible
Repo: TryGhost/Ghost PR: 24658
File: ghost/admin/package.json:3-3
Timestamp: 2025-08-12T18:33:15.524Z
Learning: In Ghost's admin package.json, third-party packages like ember-cli-postcss, ember-exam, and ember-power-select have their own independent versioning schemes that are unrelated to Ghost's version numbers. Version number coincidences between Ghost versions and these packages should not trigger update suggestions.
Learnt from: sam-lord
Repo: TryGhost/Ghost PR: 25303
File: ghost/core/core/server/services/email-service/BatchSendingService.js:19-19
Timestamp: 2025-10-30T17:13:26.190Z
Learning: In ghost/core/core/server/services/email-service/BatchSendingService.js and similar files in the Ghost codebase, prefer using `{...options}` spread syntax without explicit guards like `...(options || {})` when spreading potentially undefined objects, as the maintainer prefers cleaner syntax over defensive patterns when the behavior is safe.
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Run `yarn lint` after making changes to fix any ESLint errors and warnings before committing
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 24651
File: ghost/core/test/utils/urlUtils.js:53-57
Timestamp: 2025-08-11T19:39:00.428Z
Learning: In Ghost's test utilities, when fixing specific issues like async behavior, it's preferred to maintain existing error handling patterns (even if suboptimal) to keep PRs focused on their primary objective. Error handling improvements can be addressed in separate, dedicated PRs.
Learnt from: sagzy
Repo: TryGhost/Ghost PR: 24673
File: ghost/i18n/lib/i18n.js:34-35
Timestamp: 2025-11-24T11:12:15.712Z
Learning: In the Ghost i18n package (ghost/i18n/lib/i18n.js), changing existing locale codes requires backwards compatibility handling for users who have already configured those locales. Such changes should be done in a separate PR with migration logic rather than included in feature PRs.
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Follow ESLint and `tailwindcss/*` plugin rules when writing styles
Learnt from: niranjan-uma-shankar
Repo: TryGhost/Ghost PR: 24557
File: apps/admin-x-settings/src/components/settings/general/TimeZone.tsx:7-7
Timestamp: 2025-08-01T12:44:07.467Z
Learning: In Ghost development, PRs may depend on unpublished changes from SDK packages. When this occurs, TypeScript compilation errors for missing exports are expected and documented in the PR description until the dependency packages are published and updated. This is normal workflow for cross-repository feature development.
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T14:28:50.351Z
Learning: Applies to ghost/i18n/locales/en/ghost.json : Add UI translations to `ghost/i18n/locales/en/ghost.json` for Admin UI features
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Use factory pattern for all test data creation instead of hard-coded data or direct database manipulation
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Test names should be lowercase and follow the format 'what is tested - expected outcome'
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Follow the AAA (Arrange, Act, Assert) pattern in test structure
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Always follow ADRs in `../adr/` folder (ADR-0001: AAA pattern, ADR-0002: Page Objects)
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Use `getByTestId()` only when semantic locators are unavailable, and suggest adding `data-testid` to Ghost codebase when needed
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-03-13T09:02:50.102Z
Learnt from: mike182uk
Repo: TryGhost/Ghost PR: 22471
File: apps/admin-x-activitypub/src/views/Feed/components/NewPostModal.tsx:29-34
Timestamp: 2025-03-13T09:02:50.102Z
Learning: In the Ghost ActivityPub module, error handling for mutations is handled at the hook level (in use-activity-pub-queries.ts) rather than in individual components. This allows for centralized error handling across the application.
Applied to files:
apps/activitypub/src/views/preferences/components/profile.tsxapps/posts/src/hooks/use-post-success-modal.ts
📚 Learning: 2025-03-13T09:02:50.102Z
Learnt from: mike182uk
Repo: TryGhost/Ghost PR: 22471
File: apps/admin-x-activitypub/src/views/Feed/components/NewPostModal.tsx:29-34
Timestamp: 2025-03-13T09:02:50.102Z
Learning: In the ActivityPub module, error handling for mutations is handled at the hook level (in use-activity-pub-queries.ts) rather than in individual components. This allows for centralized error handling across the application.
Applied to files:
apps/activitypub/src/views/preferences/components/profile.tsxapps/posts/src/hooks/use-post-success-modal.ts
📚 Learning: 2025-08-11T19:39:00.428Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 24651
File: ghost/core/test/utils/urlUtils.js:53-57
Timestamp: 2025-08-11T19:39:00.428Z
Learning: In Ghost's test utilities, when fixing specific issues like async behavior, it's preferred to maintain existing error handling patterns (even if suboptimal) to keep PRs focused on their primary objective. Error handling improvements can be addressed in separate, dedicated PRs.
Applied to files:
apps/posts/src/utils/link-helpers.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.{ts,tsx} : Prefer less comments and give things clear names
Applied to files:
apps/comments-ui/src/app-context.tsapps/comments-ui/src/typings.d.tsapps/comments-ui/src/components/popup-box.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use CVA (Class Variance Authority) for component variants when useful instead of heavy prop configuration
Applied to files:
apps/comments-ui/src/app-context.tsapps/comments-ui/src/typings.d.tsapps/shade/src/components/layout/header.tsxapps/comments-ui/src/components/popup-box.tsxapps/shade/src/typings.d.tsapps/shade/src/components/layout/page.tsxapps/shade/src/components/ui/card.tsx
📚 Learning: 2025-04-23T15:44:52.549Z
Learnt from: 9larsons
Repo: TryGhost/Ghost PR: 21866
File: ghost/core/core/server/web/admin/middleware/serve-auth-frame-file.js:10-19
Timestamp: 2025-04-23T15:44:52.549Z
Learning: The existing implementation in `ghost/core/core/server/web/admin/middleware/serve-auth-frame-file.js` using `path.parse(req.url).base` is secure against path traversal attacks as it properly extracts only the filename component without any directory parts.
Applied to files:
apps/stats/src/utils/url-helpers.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/**/*.{ts,tsx,js} : Use the `@` alias for internal imports (e.g., `@/lib/utils`)
Applied to files:
apps/comments-ui/src/typings.d.tsapps/shade/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/index.ts : Place new UI components under `src/components/ui` and export them from `src/index.ts`
Applied to files:
apps/comments-ui/src/typings.d.tsapps/shade/src/components/layout/header.tsxapps/shade/src/typings.d.tsapps/shade/src/components/layout/page.tsxapps/shade/src/components/ui/card.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Follow ESLint and `tailwindcss/*` plugin rules when writing styles
Applied to files:
apps/comments-ui/src/typings.d.tsapps/shade/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Run `yarn lint` after making changes to fix any ESLint errors and warnings before committing
Applied to files:
apps/comments-ui/src/typings.d.tsapps/shade/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Prefer compound subcomponents (e.g., `Header.Title`, `Header.Meta`, `Header.Actions`) for multi-region components instead of many props
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/layout/**/*.{ts,tsx} : Reusable layout containers (Page, Heading, Header, ViewHeader, ErrorPage) should be placed in `src/components/layout/*`
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use Tailwind CSS scoped via `.shade` class; dark mode uses `.dark`
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/typings.d.tsapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use `PascalCase` for component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/typings.d.tsapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/features/**/*.{ts,tsx} : Higher-level, opinionated components (e.g., PostShareModal, SourceTabs) should be placed in `src/components/features/*`
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-25T11:58:51.652Z
Learnt from: ibalosh
Repo: TryGhost/Ghost PR: 25525
File: apps/shade/src/shade-app.tsx:4-4
Timestamp: 2025-11-25T11:58:51.652Z
Learning: In apps/shade, the app wrapper file should be named `src/shade-app.tsx` (kebab-case) while the component itself is exported as `ShadeApp` (PascalCase). Context providers should be placed in `src/providers/*` using kebab-case filenames.
Applied to files:
apps/shade/src/components/layout/header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/ui/**/*.{ts,tsx} : Atomic UI components should be placed in `src/components/ui/*` and each component must have a corresponding `*.stories.tsx` file next to it for Storybook documentation
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/lib/utils.ts : Shared utilities (class merging, formatting, chart helpers) should be centralized in `src/lib/utils.ts`
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/typings.d.tsapps/shade/src/lib/utils.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Always forward and merge `className` prop with `cn(...)` utility function
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/page.tsx
📚 Learning: 2025-12-09T12:37:23.267Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 25501
File: apps/shade/src/hooks/use-mobile.tsx:5-10
Timestamp: 2025-12-09T12:37:23.267Z
Learning: In the Ghost repository, this guideline applies to the shade admin app. For files under apps/shade that access browser globals (navigator, window, document) at module load time, SSR is not used, so typeof guards are not required. Reviewers should verify that such files remain client-side only and that no SSR context is introduced; apply this understanding to similarly structured files under apps/shade.
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/components/layout/page.tsxapps/shade/src/components/ui/card.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/hooks/**/*.{ts,tsx} : Custom React hooks should be placed in `src/hooks/*`
Applied to files:
apps/shade/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/**/*.{ts,tsx,js} : Use `camelCase` for function and variable names
Applied to files:
apps/shade/src/typings.d.ts
🪛 Biome (2.1.2)
apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx
[error] 17-18: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/activitypub/src/views/profile/profile.tsx
[error] 13-14: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/posts/src/views/PostAnalytics/Growth/growth.tsx
[error] 16-17: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/posts/src/views/PostAnalytics/Web/web.tsx
[error] 26-27: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
⏰ 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: ActivityPub tests
- GitHub Check: Unit tests (Node 22.18.0)
- GitHub Check: Legacy tests (Node 22.18.0, sqlite3)
- GitHub Check: Legacy tests (Node 22.18.0, mysql8)
- GitHub Check: Acceptance tests (Node 22.18.0, sqlite3)
- GitHub Check: Admin-X Settings tests
- GitHub Check: Ghost-CLI tests
- GitHub Check: Comments-UI tests
- GitHub Check: Admin tests - Chrome
- GitHub Check: Signup-form tests
- GitHub Check: Lint
- GitHub Check: Acceptance tests (Node 22.18.0, mysql8)
- GitHub Check: Build & Push Docker Image
🔇 Additional comments (25)
apps/comments-ui/src/components/popup-box.tsx (1)
6-8: LGTM!The ESLint directive update from
ban-typestono-empty-object-typeis the correct adaptation for newer@typescript-eslintversions, where the monolithicban-typesrule was split into more specific rules. This aligns with the ESLint plugin upgrade.apps/admin-x-settings/src/components/settings/growth/recommendations/incoming-recommendation-list.tsx (1)
23-27: Catch block change is behavior‑neutral and matches lint expectationsSwitching from
catch (_)to a barecatch {}keeps the same semantics (errors are ignored) while removing an unused variable, which aligns with the updated ESLint ghost plugin rules. No functional impact on URL handling or stats aggregation.Please run your usual lint task (e.g.
yarn lint) to confirm there are no remaining unused catch parameter warnings in this file after the plugin bump.apps/comments-ui/src/utils/admin-api.ts (1)
15-20: Bare catch around JSON.parse is fine hereThe error value was unused; switching to
catch {}keeps the same “ignore invalid messages and return early” behavior and satisfies lint rules.apps/posts/src/hooks/use-post-success-modal.ts (1)
155-168: Parameterless catch matches intentional “ignore localStorage errors” behaviorThe error value wasn’t used;
catch {}cleanly expresses the intent to ignore storage/parse failures without altering control flow.apps/admin-x-framework/test/unit/hooks/use-form.test.ts (1)
202-208: Tests now use bare catch where the error value is unusedBoth error-handling tests still exercise the rejection path and assert on side effects; dropping the unused catch parameter simply matches the intent and lint rules.
Also applies to: 229-235
apps/signup-form/src/components/pages/form-page.tsx (1)
23-39: Submit handler catch cleanup keeps behavior identicalThe catch block already ignored the specific error; using
catch {}keeps the same UX (reset loading + generic error) while avoiding an unused parameter.apps/shade/src/lib/utils.ts (1)
97-103: formatUrl’s parameterless catch preserves existing fallback behaviorURL-construction failures still fall back to
{save: url, display: url}; removing the unused error binding just satisfies eslint without changing semantics. Based on learnings, this remains correctly centralized insrc/lib/utils.ts.apps/admin-x-settings/src/utils/url.ts (1)
24-32: arePathsEqual keeps same semantics with bare catchReturning
falseon URL-construction failure is preserved; dropping the unused error parameter is a straightforward lint-driven cleanup.apps/comments-ui/src/app-context.ts (1)
114-120: useLabs now uses a parameterless catch while keeping its safe fallbackThe hook still returns an empty labs object when context lookup fails; switching to
catch {}simply removes an unused variable and aligns with the new eslint rules.apps/activitypub/src/views/preferences/components/profile.tsx (1)
272-314: handleCopy’s nested catches correctly drop unused error parametersBoth inner and outer catch blocks still surface a generic “Failed to copy image” toast and reset
isProcessing; usingcatch {}is a no-op behavior-wise and matches the linted style.apps/posts/src/utils/link-helpers.ts (1)
30-33: LGTM! Unused error parameter removed.The change from
catch (error)to barecatchcorrectly removes the unused error binding while preserving the fallback behavior. This aligns with the updated ESLint rules.apps/admin-x-framework/src/api/config.ts (1)
5-7: LGTM! Appropriate ESLint suppression for empty interface pattern.The
JSONArrayinterface correctly extendsArrayto create a recursive type definition used byJSONValue. Theeslint-disable-next-linecomment is appropriate since the empty interface body is intentional—theextendsclause provides the necessary type structure.apps/stats/src/utils/url-helpers.ts (2)
21-24: LGTM! Unused error parameter removed.The change from
catch (error)to barecatchis consistent with the ESLint update pattern, removing the unused error binding while maintaining the error-handling behavior.
15-20: LGTM! Formatting improvements from linter.The blank line adjustments improve code readability and align with the updated ESLint formatting rules.
Also applies to: 37-38, 53-58, 106-115
apps/shade/src/components/ui/card.tsx (1)
219-220: Scoped lint suppression forEmptyCardPropslooks goodThe no-empty-object-type disable is narrowly scoped to this intentional marker interface and doesn’t affect runtime behavior. Fits the pattern used elsewhere in shade for empty prop interfaces.
apps/shade/src/components/layout/page.tsx (1)
4-5: PageProps lint suppression is appropriate and non-invasiveDisabling no-empty-object-type for this simple wrapper interface keeps the public API clean without changing how
Pagebehaves.apps/shade/src/components/layout/header.tsx (7)
11-22: HeaderAbove props lint suppression is reasonableThe targeted no-empty-object-type disable on
HeaderAbovePropskeeps the lightweight props shape while avoiding unnecessary lint noise; implementation continues to forward className viacn(...)correctly.
24-38: HeaderTitle props suppression keeps API simpleUsing a scoped disable for the empty
HeaderTitlePropsinterface is consistent with the rest of the Header API and doesn’t affect rendering or styling.
40-51: HeaderMeta props interface + lint suppression are fineThe empty
HeaderMetaPropswrapper plus scoped eslint-disable cleanly convey intent without changing layout or behavior.
53-64: HeaderActionGroup props pattern matches the rest of HeaderThe empty props interface with a per-line suppression is consistent with other Header subcomponents and keeps types readable.
66-77: HeaderActions props suppression aligns with compound subcomponent patternSame scoped no-empty-object-type disable here maintains a simple, shared props shape for action areas; behavior is unchanged.
79-90: HeaderNav props interface and lint disable are consistentThe empty
HeaderNavPropsplus local suppression follow the same pattern as other Header regions and keep the compound API tidy.
103-115: HeaderProps typing and usage withheaderVariantslook correct
HeaderPropscleanly combines children/className with the header variant options, andHeadercontinues to mergeclassNamethroughcn(headerVariants({variant, className}))as per shade guidelines. No issues spotted.apps/shade/src/typings.d.ts (1)
2-2: LGTM – Consistent lint suppression.Identical to the change in apps/comments-ui/src/typings.d.ts. The suppression is appropriate for this declaration file context.
apps/stats/src/types/svg.d.ts (1)
2-2: LGTM – Consistent with PR-wide pattern.The lint suppression matches the approach used in other declaration files across this PR. No issues identified.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #25713 +/- ##
==========================================
+ Coverage 72.08% 72.10% +0.01%
==========================================
Files 1539 1539
Lines 117719 117730 +11
Branches 14102 14110 +8
==========================================
+ Hits 84856 84885 +29
+ Misses 31832 31831 -1
+ Partials 1031 1014 -17
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
b48e7c2 to
fff3de2
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/activitypub/src/hooks/use-activity-pub-queries.ts (1)
360-495: Guard notification like/repost counts against undefined valuesIn
updateNotificationsLikedCacheandupdateNotificationsRepostCachethe math assumesnotification.post.likeCount/notification.post.repostCountare always defined:likeCount: Math.max( liked ? notification.post.likeCount + 1 : notification.post.likeCount - 1, 0 ) repostCount: Math.max( reposted ? notification.post.repostCount + 1 : notification.post.repostCount - 1, 0 )If either count is ever
undefinedthese expressions produceNaN, andMath.max(NaN, 0)will stayNaN, corrupting the cached value. Note howupdateNotificationsReplyCountCachealready uses a?? 0fallback.Consider aligning these to the safer pattern:
- likeCount: Math.max(liked ? notification.post.likeCount + 1 : notification.post.likeCount - 1, 0) + likeCount: Math.max( + liked + ? (notification.post.likeCount ?? 0) + 1 + : (notification.post.likeCount ?? 0) - 1, + 0 + ) - repostCount: Math.max(reposted ? notification.post.repostCount + 1 : notification.post.repostCount - 1, 0) + repostCount: Math.max( + reposted + ? (notification.post.repostCount ?? 0) + 1 + : (notification.post.repostCount ?? 0) - 1, + 0 + )The new bare
catch {}blocks look fine and preserve the existing fallback-to-current behavior.
🧹 Nitpick comments (6)
apps/posts/src/views/PostAnalytics/Growth/growth.tsx (1)
16-17: Consider improving the interface naming and structure.The interface name
postAnalyticsPropsdoesn't follow the TypeScript convention of PascalCase for type names. Additionally, since this is an empty interface, it could be simplified to a type alias or removed entirely if no props are needed.Apply this diff to use PascalCase naming and convert to a type alias:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} +type PostAnalyticsProps = Record<string, never>; -const Growth: React.FC<postAnalyticsProps> = () => { +const Growth: React.FC<PostAnalyticsProps> = () => {Alternatively, if no props are expected, you can simplify to:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} - -const Growth: React.FC<postAnalyticsProps> = () => { +const Growth: React.FC = () => {apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx (1)
17-18: Consider improving the interface naming and structure.The interface name
postAnalyticsPropsdoesn't follow the TypeScript convention of PascalCase for type names. Additionally, since this is an empty interface, it could be simplified to a type alias or removed entirely if no props are needed.Apply this diff to use PascalCase naming and convert to a type alias:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} +type PostAnalyticsProps = Record<string, never>; -const Newsletter: React.FC<postAnalyticsProps> = () => { +const Newsletter: React.FC<PostAnalyticsProps> = () => {Alternatively, if no props are expected, you can simplify to:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} - -const Newsletter: React.FC<postAnalyticsProps> = () => { +const Newsletter: React.FC = () => {apps/posts/src/views/PostAnalytics/Web/web.tsx (1)
26-27: Consider improving the interface naming and structure.The interface name
postAnalyticsPropsdoesn't follow the TypeScript convention of PascalCase for type names. Additionally, since this is an empty interface, it could be simplified to a type alias or removed entirely if no props are needed.This same pattern appears in all three PostAnalytics views (Growth, Newsletter, Web). If all components share the same empty props interface, consider defining it once in a shared location like
../components/post-analytics-types.tsto reduce duplication.Apply this diff to use PascalCase naming and convert to a type alias:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} +type PostAnalyticsProps = Record<string, never>; -const Web: React.FC<postAnalyticsProps> = () => { +const Web: React.FC<PostAnalyticsProps> = () => {Alternatively, if no props are expected, you can simplify to:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} - -const Web: React.FC<postAnalyticsProps> = () => { +const Web: React.FC = () => {apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx (1)
39-41: Scoped ESLint disable is acceptable; consider small refactor to avoid itThe inline
eslint-disable-next-linecomments are tightly scoped to theclearErrorexpressions and introduce no runtime changes, which is appropriate for this ESLint-upgrade PR. If you’d like to avoid the suppression altogether, you could refactor both expressions toifstatements:- // eslint-disable-next-line @typescript-eslint/no-unused-expressions - !!item.errors.label && clearError?.('label'); + if (item.errors.label) { + clearError?.('label'); + }- // eslint-disable-next-line @typescript-eslint/no-unused-expressions - !!item.errors.url && clearError?.('url'); + if (item.errors.url) { + clearError?.('url'); + }This keeps the intent clear and satisfies the lint rule without needing disables, but treating it as optional here is reasonable given the PR’s scope.
Also applies to: 67-69
apps/activitypub/src/views/profile/profile.tsx (1)
13-14: EmptyProfileProps+ ESLint suppression is fine; optional simplificationThis is functionally harmless and matches the PR-wide lint pattern. If you don’t plan to add props soon, you could simplify and drop both the interface and the disable:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface ProfileProps {} - -const Profile: React.FC<ProfileProps> = ({}) => { +const Profile: React.FC = () => {That also sidesteps Biome’s
noEmptyInterfacewarning, but it’s purely optional.apps/comments-ui/src/actions.ts (1)
257-276: Like/unlike bare catches keep optimistic update behavior intactRemoving the unused error binding and using bare
catch {}keeps the existing pattern: optimistic toggle viaupdateCommentLikeStateand simple revert on failure. No behavioral change here.If you ever want more observability, a non-blocking enhancement would be to log or surface a toast in these branches, but that can be deferred.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (54)
apps/activitypub/src/api/activitypub.ts(1 hunks)apps/activitypub/src/components/modals/new-note-modal.tsx(1 hunks)apps/activitypub/src/hooks/use-activity-pub-queries.ts(3 hunks)apps/activitypub/src/utils/get-username.ts(1 hunks)apps/activitypub/src/utils/image.ts(1 hunks)apps/activitypub/src/views/preferences/components/bluesky-sharing.tsx(1 hunks)apps/activitypub/src/views/preferences/components/profile.tsx(1 hunks)apps/activitypub/src/views/profile/profile.tsx(1 hunks)apps/admin-x-design-system/src/global/sortable-list.tsx(1 hunks)apps/admin-x-design-system/src/typings.d.ts(1 hunks)apps/admin-x-design-system/src/utils/format-url.ts(1 hunks)apps/admin-x-framework/src/api/config.ts(1 hunks)apps/admin-x-framework/src/api/recommendations.ts(1 hunks)apps/admin-x-framework/src/test/acceptance.ts(1 hunks)apps/admin-x-framework/src/test/test-utils.tsx(1 hunks)apps/admin-x-framework/test/unit/hooks/use-form.test.ts(2 hunks)apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/incoming-recommendation-list.tsx(1 hunks)apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx(2 hunks)apps/admin-x-settings/src/typings.d.ts(1 hunks)apps/admin-x-settings/src/utils/link-to-github-releases.ts(2 hunks)apps/admin-x-settings/src/utils/url.ts(1 hunks)apps/comments-ui/src/actions.ts(2 hunks)apps/comments-ui/src/app-context.ts(1 hunks)apps/comments-ui/src/components/content/forms/form.tsx(1 hunks)apps/comments-ui/src/components/popup-box.tsx(1 hunks)apps/comments-ui/src/typings.d.ts(1 hunks)apps/comments-ui/src/utils/admin-api.ts(1 hunks)apps/comments-ui/src/utils/api.ts(1 hunks)apps/posts/src/hooks/use-post-success-modal.ts(1 hunks)apps/posts/src/utils/link-helpers.ts(1 hunks)apps/posts/src/views/PostAnalytics/Growth/growth.tsx(1 hunks)apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx(1 hunks)apps/posts/src/views/PostAnalytics/Web/web.tsx(1 hunks)apps/shade/src/components/features/color-picker/color-picker.tsx(1 hunks)apps/shade/src/components/layout/header.tsx(7 hunks)apps/shade/src/components/layout/heading.tsx(1 hunks)apps/shade/src/components/layout/page.tsx(1 hunks)apps/shade/src/components/layout/view-header.tsx(2 hunks)apps/shade/src/components/ui/card.tsx(1 hunks)apps/shade/src/lib/utils.ts(1 hunks)apps/shade/src/typings.d.ts(1 hunks)apps/signup-form/src/components/pages/form-page.tsx(1 hunks)apps/signup-form/src/typings.d.ts(1 hunks)apps/stats/src/hooks/use-feature-flag.tsx(1 hunks)apps/stats/src/types/svg.d.ts(1 hunks)apps/stats/src/utils/url-helpers.ts(5 hunks)apps/stats/test/utils/tinybird-helpers.ts(1 hunks)ghost/core/core/server/services/recommendations/service/RecommendationMetadataService.ts(2 hunks)ghost/core/core/server/services/recommendations/service/UnsafeData.ts(1 hunks)package.json(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (32)
- apps/activitypub/src/components/modals/new-note-modal.tsx
- apps/admin-x-settings/src/components/settings/growth/recommendations/incoming-recommendation-list.tsx
- apps/shade/src/lib/utils.ts
- apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx
- apps/stats/src/hooks/use-feature-flag.tsx
- apps/shade/src/components/layout/heading.tsx
- apps/comments-ui/src/utils/api.ts
- apps/admin-x-framework/src/test/test-utils.tsx
- apps/signup-form/src/components/pages/form-page.tsx
- apps/stats/test/utils/tinybird-helpers.ts
- apps/posts/src/utils/link-helpers.ts
- apps/stats/src/utils/url-helpers.ts
- apps/activitypub/src/views/preferences/components/profile.tsx
- apps/admin-x-settings/src/utils/url.ts
- apps/comments-ui/src/app-context.ts
- apps/activitypub/src/api/activitypub.ts
- apps/admin-x-settings/src/utils/link-to-github-releases.ts
- apps/posts/src/hooks/use-post-success-modal.ts
- apps/comments-ui/src/typings.d.ts
- apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx
- apps/admin-x-settings/src/typings.d.ts
- apps/shade/src/components/layout/page.tsx
- apps/admin-x-framework/src/api/recommendations.ts
- apps/signup-form/src/typings.d.ts
- package.json
- apps/admin-x-framework/test/unit/hooks/use-form.test.ts
- apps/shade/src/components/ui/card.tsx
- apps/comments-ui/src/components/popup-box.tsx
- apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx
- apps/shade/src/components/features/color-picker/color-picker.tsx
- apps/shade/src/components/layout/view-header.tsx
- apps/comments-ui/src/utils/admin-api.ts
🧰 Additional context used
📓 Path-based instructions (4)
apps/shade/src/components/layout/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
Reusable layout containers (Page, Heading, Header, ViewHeader, ErrorPage) should be placed in
src/components/layout/*
Files:
apps/shade/src/components/layout/header.tsx
apps/shade/src/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/src/components/**/*.{ts,tsx}: UsePascalCasefor component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Always forward and mergeclassNameprop withcn(...)utility function
Use CVA (Class Variance Authority) for component variants when useful instead of heavy prop configuration
Prefer compound subcomponents (e.g.,Header.Title,Header.Meta,Header.Actions) for multi-region components instead of many props
Use Tailwind CSS scoped via.shadeclass; dark mode uses.dark
Files:
apps/shade/src/components/layout/header.tsx
apps/shade/src/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/src/**/*.{ts,tsx,js}: UsecamelCasefor function and variable names
Use the@alias for internal imports (e.g.,@/lib/utils)
Files:
apps/shade/src/components/layout/header.tsxapps/shade/src/typings.d.ts
apps/shade/{src,test}/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/{src,test}/**/*.{ts,tsx,js}: Runyarn lintafter making changes to fix any ESLint errors and warnings before committing
Follow ESLint andtailwindcss/*plugin rules when writing styles
Files:
apps/shade/src/components/layout/header.tsxapps/shade/src/typings.d.ts
🧠 Learnings (21)
📓 Common learnings
Learnt from: sam-lord
Repo: TryGhost/Ghost PR: 25303
File: ghost/core/core/server/services/email-service/BatchSendingService.js:19-19
Timestamp: 2025-10-30T17:13:26.190Z
Learning: In ghost/core/core/server/services/email-service/BatchSendingService.js and similar files in the Ghost codebase, prefer using `{...options}` spread syntax without explicit guards like `...(options || {})` when spreading potentially undefined objects, as the maintainer prefers cleaner syntax over defensive patterns when the behavior is safe.
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 24651
File: ghost/core/test/utils/urlUtils.js:53-57
Timestamp: 2025-08-11T19:39:00.428Z
Learning: In Ghost's test utilities, when fixing specific issues like async behavior, it's preferred to maintain existing error handling patterns (even if suboptimal) to keep PRs focused on their primary objective. Error handling improvements can be addressed in separate, dedicated PRs.
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Run `yarn lint` after making changes to fix any ESLint errors and warnings before committing
Learnt from: sagzy
Repo: TryGhost/Ghost PR: 24673
File: ghost/i18n/lib/i18n.js:34-35
Timestamp: 2025-11-24T11:12:15.712Z
Learning: In the Ghost i18n package (ghost/i18n/lib/i18n.js), changing existing locale codes requires backwards compatibility handling for users who have already configured those locales. Such changes should be done in a separate PR with migration logic rather than included in feature PRs.
Learnt from: niranjan-uma-shankar
Repo: TryGhost/Ghost PR: 24557
File: apps/admin-x-settings/src/components/settings/general/TimeZone.tsx:7-7
Timestamp: 2025-08-01T12:44:07.467Z
Learning: In Ghost development, PRs may depend on unpublished changes from SDK packages. When this occurs, TypeScript compilation errors for missing exports are expected and documented in the PR description until the dependency packages are published and updated. This is normal workflow for cross-repository feature development.
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Follow ESLint and `tailwindcss/*` plugin rules when writing styles
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T14:28:50.351Z
Learning: Applies to ghost/i18n/locales/en/ghost.json : Add UI translations to `ghost/i18n/locales/en/ghost.json` for Admin UI features
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T14:28:50.351Z
Learning: Applies to ghost/i18n/locales/en/{portal,comments,signup-form,search}.json : Add UI translations to namespace-specific files in `ghost/i18n/locales/en/` for public UI apps (portal.json for Portal, comments.json for Comments UI, etc.)
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use `PascalCase` for component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Prefer compound subcomponents (e.g., `Header.Title`, `Header.Meta`, `Header.Actions`) for multi-region components instead of many props
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.{ts,tsx} : Prefer less comments and give things clear names
Applied to files:
apps/comments-ui/src/actions.ts
📚 Learning: 2025-03-13T09:02:50.102Z
Learnt from: mike182uk
Repo: TryGhost/Ghost PR: 22471
File: apps/admin-x-activitypub/src/views/Feed/components/NewPostModal.tsx:29-34
Timestamp: 2025-03-13T09:02:50.102Z
Learning: In the Ghost ActivityPub module, error handling for mutations is handled at the hook level (in use-activity-pub-queries.ts) rather than in individual components. This allows for centralized error handling across the application.
Applied to files:
apps/activitypub/src/hooks/use-activity-pub-queries.ts
📚 Learning: 2025-03-13T09:02:50.102Z
Learnt from: mike182uk
Repo: TryGhost/Ghost PR: 22471
File: apps/admin-x-activitypub/src/views/Feed/components/NewPostModal.tsx:29-34
Timestamp: 2025-03-13T09:02:50.102Z
Learning: In the ActivityPub module, error handling for mutations is handled at the hook level (in use-activity-pub-queries.ts) rather than in individual components. This allows for centralized error handling across the application.
Applied to files:
apps/activitypub/src/hooks/use-activity-pub-queries.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Prefer compound subcomponents (e.g., `Header.Title`, `Header.Meta`, `Header.Actions`) for multi-region components instead of many props
Applied to files:
apps/shade/src/components/layout/header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/layout/**/*.{ts,tsx} : Reusable layout containers (Page, Heading, Header, ViewHeader, ErrorPage) should be placed in `src/components/layout/*`
Applied to files:
apps/shade/src/components/layout/header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use CVA (Class Variance Authority) for component variants when useful instead of heavy prop configuration
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use Tailwind CSS scoped via `.shade` class; dark mode uses `.dark`
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use `PascalCase` for component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/index.ts : Place new UI components under `src/components/ui` and export them from `src/index.ts`
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/features/**/*.{ts,tsx} : Higher-level, opinionated components (e.g., PostShareModal, SourceTabs) should be placed in `src/components/features/*`
Applied to files:
apps/shade/src/components/layout/header.tsx
📚 Learning: 2025-11-25T11:58:51.652Z
Learnt from: ibalosh
Repo: TryGhost/Ghost PR: 25525
File: apps/shade/src/shade-app.tsx:4-4
Timestamp: 2025-11-25T11:58:51.652Z
Learning: In apps/shade, the app wrapper file should be named `src/shade-app.tsx` (kebab-case) while the component itself is exported as `ShadeApp` (PascalCase). Context providers should be placed in `src/providers/*` using kebab-case filenames.
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/typings.d.ts
📚 Learning: 2025-11-06T05:35:41.162Z
Learnt from: danielraffel
Repo: TryGhost/Ghost PR: 25366
File: apps/admin/src/layout/app-sidebar/NavHeader.tsx:13-23
Timestamp: 2025-11-06T05:35:41.162Z
Learning: In apps/admin/src/layout/app-sidebar/NavHeader.tsx, the React component dispatches a synthetic KeyboardEvent to trigger the Ember keymaster.js search modal shortcut. This approach is known to have cross-browser reliability issues but was deferred for architectural refactoring in a separate PR. The recommended fix is to expose a global function or custom DOM event from the Ember app instead of relying on synthetic keyboard events with keymaster.js.
Applied to files:
apps/shade/src/components/layout/header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/lib/utils.ts : Shared utilities (class merging, formatting, chart helpers) should be centralized in `src/lib/utils.ts`
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Always forward and merge `className` prop with `cn(...)` utility function
Applied to files:
apps/shade/src/components/layout/header.tsx
📚 Learning: 2025-12-09T12:37:23.267Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 25501
File: apps/shade/src/hooks/use-mobile.tsx:5-10
Timestamp: 2025-12-09T12:37:23.267Z
Learning: In the Ghost repository, this guideline applies to the shade admin app. For files under apps/shade that access browser globals (navigator, window, document) at module load time, SSR is not used, so typeof guards are not required. Reviewers should verify that such files remain client-side only and that no SSR context is introduced; apply this understanding to similarly structured files under apps/shade.
Applied to files:
apps/shade/src/components/layout/header.tsx
📚 Learning: 2025-10-09T15:31:06.587Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 25118
File: apps/portal/src/actions.js:160-173
Timestamp: 2025-10-09T15:31:06.587Z
Learning: When reviewing PRs that introduce feature-flagged changes (e.g., `labs?.membersSigninOTCAlpha`), avoid suggesting modifications to non-flagged code paths unless they're directly related to the PR's objectives. Keep the scope focused on the feature-flag-specific changes only.
Applied to files:
apps/admin-x-framework/src/test/acceptance.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/**/*.{ts,tsx,js} : Use the `@` alias for internal imports (e.g., `@/lib/utils`)
Applied to files:
apps/admin-x-design-system/src/typings.d.tsapps/shade/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Follow ESLint and `tailwindcss/*` plugin rules when writing styles
Applied to files:
apps/shade/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Run `yarn lint` after making changes to fix any ESLint errors and warnings before committing
Applied to files:
apps/shade/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/hooks/**/*.{ts,tsx} : Custom React hooks should be placed in `src/hooks/*`
Applied to files:
apps/shade/src/typings.d.ts
🪛 Biome (2.1.2)
apps/activitypub/src/views/profile/profile.tsx
[error] 13-14: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/posts/src/views/PostAnalytics/Growth/growth.tsx
[error] 16-17: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx
[error] 17-18: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/posts/src/views/PostAnalytics/Web/web.tsx
[error] 26-27: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
⏰ 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). (2)
- GitHub Check: Setup
- GitHub Check: Build & Push Docker Image
🔇 Additional comments (14)
apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx (1)
29-29: LGTM! Unused catch parameter removed.The error variable was never referenced in the catch block, so removing it is correct and improves code cleanliness. The behavior is preserved—the catch block still handles invalid URL errors properly.
apps/admin-x-framework/src/test/acceptance.ts (1)
127-132: Barecatchbinding change is safe and keeps behavior identicalThe error object was not used in this block, so moving to a parameterless
catchkeeps semantics the same while satisfying linting rules. No further changes needed here.apps/comments-ui/src/components/content/forms/form.tsx (1)
78-78: LGTM! Correctly removes unused error binding.The change from
catch (e)to a barecatchis appropriate since the error parameter was never used in the catch block. This aligns with modern ESLint best practices.apps/admin-x-design-system/src/global/sortable-list.tsx (1)
17-17: ESLint directive correctly updated for the new plugin version.The change from
@typescript-eslint/ban-typesto@typescript-eslint/no-unsafe-function-typealigns with TypeScript ESLint v8's migration path, whereban-typeswas removed and split into focused rules.no-unsafe-function-typeis the appropriate replacement for suppressing warnings about the unsafeFunctiontype on line 18.ghost/core/core/server/services/recommendations/service/UnsafeData.ts (1)
175-190: Bare catch inurlgetter preserves behaviorSwitching to a bare
catch {}here doesn’t change behavior—the method still normalizes all URL parse/protocol failures into aValidationErrorwith the same message. Looks good.apps/activitypub/src/utils/get-username.ts (1)
5-8:getUsernamebare catch is safe and keeps existing fallbackThe switch to
catch {}keeps the same behavior—invalidactor.idvalues still fall back to@unknown@unknownwithout leaking errors. All good.apps/activitypub/src/views/preferences/components/bluesky-sharing.tsx (1)
48-58:handleEnablebare catch keeps error UX the sameThe move to
catch {}doesn’t alter behavior—loadingis reset and the generic error toast still shows on failure. This remains consistent with the interval-based confirmation logic below.apps/activitypub/src/utils/image.ts (1)
10-28:imageUrlToDataUrlbare catch keeps graceful fallbackSwitching to
catch {}keeps the same “fallback to original URL on any failure” behavior. The FileReader and fetch failures are still safely handled, so this change looks good.ghost/core/core/server/services/recommendations/service/RecommendationMetadataService.ts (1)
44-71: Bare catches in#fetchJSON/#castUrlkeep existing fallbacksThe updated
catch {}blocks continue to:
- Treat JSON parse/HTTP/network failures as
undefinedfrom#fetchJSON, and- Treat invalid URLs as
nullfrom#castUrl.Callers already handle those cases, so this is a pure syntax cleanup with no behavioral impact.
Also applies to: 73-82
apps/admin-x-design-system/src/utils/format-url.ts (1)
48-48: LGTM! Bare catch is appropriate.The error parameter was never used, so removing it aligns with the ESLint update and maintains the same fallback behavior.
apps/admin-x-framework/src/api/config.ts (1)
6-7: LGTM! JSONArray type properly models JSON arrays.The interface correctly defines recursive array structures for JSON values, and the lint suppression is appropriate for the empty-object-type pattern when extending built-in types.
apps/shade/src/components/layout/header.tsx (3)
11-11: LGTM! ESLint suppressions are consistently applied.The suppressions are appropriate for interfaces that extend base types without adding new properties, which is a pattern required by the updated ESLint rules.
Also applies to: 24-24, 40-40, 53-53, 66-66, 79-79
104-104: LGTM! HeaderProps properly integrates CVA variants.The interface correctly combines base props with variant support, enabling the Header component to accept the
variantprop for layout variations.
116-121: Excellent! Compound component pattern aligns perfectly with coding guidelines.The static subcomponent bindings enable the recommended compound component pattern (e.g.,
<Header.Title>,<Header.Meta>,<Header.Actions>), which improves API discoverability and follows the project's preference for multi-region components. Based on coding guidelines, this is the preferred approach over prop-heavy configuration.
fff3de2 to
bdf4848
Compare
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (2)
apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx (1)
782-783: Remove the errant backticks instead of suppressing ESLint.The two backticks at the end of line 783 create an empty template literal expression, which is why the
no-unused-expressionsrule fires. The correct fix is to remove the backticks, not suppress the linter.Apply this diff:
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions - const {meta: {sent_email_verification: [emailToVerify] = []} = {}} = await editNewsletter(formState); ``; + const {meta: {sent_email_verification: [emailToVerify] = []} = {}} = await editNewsletter(formState);apps/stats/src/types/svg.d.ts (1)
1-6: Consistent with other SVG typings; existing refactor suggestion is optional.This change aligns this file with the other
*.svgtypings and cleanly suppresses the new rule, which is enough to satisfy the eslint-plugin-ghost upgrade. There’s already a prior comment here suggesting switching to an ESimport typeto avoid the disable; that’s a nice-to-have refactor rather than a blocker—feel free to pick it up separately if you want to remove the suppression.
🧹 Nitpick comments (5)
apps/activitypub/src/views/profile/profile.tsx (1)
13-14: Consider removing the unused interface or converting to a type alias.The
ProfilePropsinterface is empty and theProfilecomponent doesn't actually receive or use any props (line 140 destructures an empty object). Rather than suppressing the lint warning, you could:
- Remove entirely (preferred): Since no props are passed, just use
React.FCwithout a type parameter- Type alias: If keeping for future extensibility, use
type ProfileProps = Record<string, never>;Option 1: Remove the unused interface
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface ProfileProps {} - ... -const Profile: React.FC<ProfileProps> = ({}) => { +const Profile: React.FC = () => {Option 2: Use a type alias
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface ProfileProps {} +type ProfileProps = Record<string, never>;apps/admin-x-settings/src/typings.d.ts (1)
4-9: SVG typing change is fine; optional: avoid disable by usingimport type.This matches the pattern used in other typings and unblocks the updated ESLint plugin, so I’m fine with it as-is. If you later want to reduce eslint-disable comments, you could switch to a type-only ES import and drop the suppression:
-declare module '*.svg' { - // eslint-disable-next-line @typescript-eslint/no-require-imports - import React = require('react'); +declare module '*.svg' { + import type * as React from 'react';The rest of the declarations can stay the same.
apps/posts/src/views/PostAnalytics/Growth/growth.tsx (1)
16-19: Empty props interface + ESLint suppression are fine; Biome hint is purely stylisticUsing an explicit
postAnalyticsPropsand suppressing@typescript-eslint/no-empty-object-typekeeps this in line with the other PostAnalytics views and doesn’t affect behavior. Biome’snoEmptyInterfacewarning here is stylistic—if you ever want to appease it, you could switch to a type alias (e.g.type postAnalyticsProps = {};) or add a Biome-specific ignore, but it’s reasonable to leave as-is given the ESLint plugin constraints and existing pattern.apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx (1)
17-19: ESLint suppression around empty props interface looks appropriate; Biome warning is low-priorityAdding the
@typescript-eslint/no-empty-object-typesuppression overpostAnalyticsPropsis a pragmatic way to keep the existingReact.FC<postAnalyticsProps>signature without fighting the updated ESLint plugin. Biome also complains about empty interfaces, but that’s purely stylistic—if you care about Biome noise later, you could convert this to a type alias or add a Biome-specific ignore; it’s fine to keep as-is for this ESLint-focused PR.apps/posts/src/views/PostAnalytics/Web/web.tsx (1)
26-29: Consistent props typing pattern; Biome’snoEmptyInterfacenote can be ignored or addressed laterThis mirrors the other PostAnalytics views: an explicit
postAnalyticsPropsplus an ESLint disable for@typescript-eslint/no-empty-object-type, with no runtime impact. Biome’s suggestion to avoid empty interfaces is just style-level—if you want to satisfy it in future, you could switch to a type alias or add a Biome ignore, but it’s reasonable to keep this pattern unchanged for the ESLint plugin upgrade.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (54)
apps/activitypub/src/api/activitypub.ts(1 hunks)apps/activitypub/src/components/modals/new-note-modal.tsx(1 hunks)apps/activitypub/src/hooks/use-activity-pub-queries.ts(3 hunks)apps/activitypub/src/utils/get-username.ts(1 hunks)apps/activitypub/src/utils/image.ts(1 hunks)apps/activitypub/src/views/preferences/components/bluesky-sharing.tsx(1 hunks)apps/activitypub/src/views/preferences/components/profile.tsx(1 hunks)apps/activitypub/src/views/profile/profile.tsx(1 hunks)apps/admin-x-design-system/src/global/sortable-list.tsx(1 hunks)apps/admin-x-design-system/src/typings.d.ts(1 hunks)apps/admin-x-design-system/src/utils/format-url.ts(1 hunks)apps/admin-x-framework/src/api/config.ts(1 hunks)apps/admin-x-framework/src/api/recommendations.ts(1 hunks)apps/admin-x-framework/src/test/acceptance.ts(1 hunks)apps/admin-x-framework/src/test/test-utils.tsx(1 hunks)apps/admin-x-framework/test/unit/hooks/use-form.test.ts(2 hunks)apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/incoming-recommendation-list.tsx(1 hunks)apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx(2 hunks)apps/admin-x-settings/src/typings.d.ts(1 hunks)apps/admin-x-settings/src/utils/link-to-github-releases.ts(2 hunks)apps/admin-x-settings/src/utils/url.ts(1 hunks)apps/comments-ui/src/actions.ts(2 hunks)apps/comments-ui/src/app-context.ts(1 hunks)apps/comments-ui/src/components/content/forms/form.tsx(1 hunks)apps/comments-ui/src/components/popup-box.tsx(1 hunks)apps/comments-ui/src/typings.d.ts(1 hunks)apps/comments-ui/src/utils/admin-api.ts(1 hunks)apps/comments-ui/src/utils/api.ts(1 hunks)apps/posts/src/hooks/use-post-success-modal.ts(1 hunks)apps/posts/src/utils/link-helpers.ts(1 hunks)apps/posts/src/views/PostAnalytics/Growth/growth.tsx(1 hunks)apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx(1 hunks)apps/posts/src/views/PostAnalytics/Web/web.tsx(1 hunks)apps/shade/src/components/features/color-picker/color-picker.tsx(1 hunks)apps/shade/src/components/layout/header.tsx(7 hunks)apps/shade/src/components/layout/heading.tsx(1 hunks)apps/shade/src/components/layout/page.tsx(1 hunks)apps/shade/src/components/layout/view-header.tsx(2 hunks)apps/shade/src/components/ui/card.tsx(1 hunks)apps/shade/src/lib/utils.ts(1 hunks)apps/shade/src/typings.d.ts(1 hunks)apps/signup-form/src/components/pages/form-page.tsx(1 hunks)apps/signup-form/src/typings.d.ts(1 hunks)apps/stats/src/hooks/use-feature-flag.tsx(1 hunks)apps/stats/src/types/svg.d.ts(1 hunks)apps/stats/src/utils/url-helpers.ts(5 hunks)apps/stats/test/utils/tinybird-helpers.ts(1 hunks)ghost/core/core/server/services/recommendations/service/RecommendationMetadataService.ts(2 hunks)ghost/core/core/server/services/recommendations/service/UnsafeData.ts(1 hunks)package.json(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (31)
- apps/activitypub/src/utils/get-username.ts
- apps/stats/test/utils/tinybird-helpers.ts
- package.json
- apps/activitypub/src/components/modals/new-note-modal.tsx
- apps/signup-form/src/typings.d.ts
- apps/admin-x-design-system/src/global/sortable-list.tsx
- apps/shade/src/components/ui/card.tsx
- apps/shade/src/components/features/color-picker/color-picker.tsx
- ghost/core/core/server/services/recommendations/service/UnsafeData.ts
- apps/admin-x-framework/src/test/acceptance.ts
- apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx
- apps/admin-x-design-system/src/typings.d.ts
- apps/comments-ui/src/utils/api.ts
- apps/comments-ui/src/actions.ts
- apps/admin-x-settings/src/utils/url.ts
- apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx
- apps/admin-x-framework/src/test/test-utils.tsx
- apps/shade/src/lib/utils.ts
- apps/admin-x-framework/test/unit/hooks/use-form.test.ts
- apps/comments-ui/src/app-context.ts
- apps/activitypub/src/hooks/use-activity-pub-queries.ts
- apps/comments-ui/src/utils/admin-api.ts
- apps/stats/src/hooks/use-feature-flag.tsx
- apps/stats/src/utils/url-helpers.ts
- apps/shade/src/components/layout/header.tsx
- apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx
- apps/admin-x-framework/src/api/config.ts
- apps/comments-ui/src/typings.d.ts
- apps/shade/src/typings.d.ts
- apps/posts/src/hooks/use-post-success-modal.ts
- apps/admin-x-settings/src/components/settings/growth/recommendations/incoming-recommendation-list.tsx
🧰 Additional context used
📓 Path-based instructions (4)
apps/shade/src/components/layout/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
Reusable layout containers (Page, Heading, Header, ViewHeader, ErrorPage) should be placed in
src/components/layout/*
Files:
apps/shade/src/components/layout/page.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/view-header.tsx
apps/shade/src/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/src/components/**/*.{ts,tsx}: UsePascalCasefor component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Always forward and mergeclassNameprop withcn(...)utility function
Use CVA (Class Variance Authority) for component variants when useful instead of heavy prop configuration
Prefer compound subcomponents (e.g.,Header.Title,Header.Meta,Header.Actions) for multi-region components instead of many props
Use Tailwind CSS scoped via.shadeclass; dark mode uses.dark
Files:
apps/shade/src/components/layout/page.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/view-header.tsx
apps/shade/src/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/src/**/*.{ts,tsx,js}: UsecamelCasefor function and variable names
Use the@alias for internal imports (e.g.,@/lib/utils)
Files:
apps/shade/src/components/layout/page.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/view-header.tsx
apps/shade/{src,test}/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/{src,test}/**/*.{ts,tsx,js}: Runyarn lintafter making changes to fix any ESLint errors and warnings before committing
Follow ESLint andtailwindcss/*plugin rules when writing styles
Files:
apps/shade/src/components/layout/page.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/view-header.tsx
🧠 Learnings (19)
📓 Common learnings
Learnt from: cmraible
Repo: TryGhost/Ghost PR: 24658
File: ghost/admin/package.json:3-3
Timestamp: 2025-08-12T18:33:15.524Z
Learning: In Ghost's admin package.json, third-party packages like ember-cli-postcss, ember-exam, and ember-power-select have their own independent versioning schemes that are unrelated to Ghost's version numbers. Version number coincidences between Ghost versions and these packages should not trigger update suggestions.
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Follow ESLint and `tailwindcss/*` plugin rules when writing styles
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Run `yarn lint` after making changes to fix any ESLint errors and warnings before committing
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 24651
File: ghost/core/test/utils/urlUtils.js:53-57
Timestamp: 2025-08-11T19:39:00.428Z
Learning: In Ghost's test utilities, when fixing specific issues like async behavior, it's preferred to maintain existing error handling patterns (even if suboptimal) to keep PRs focused on their primary objective. Error handling improvements can be addressed in separate, dedicated PRs.
Learnt from: sam-lord
Repo: TryGhost/Ghost PR: 25303
File: ghost/core/core/server/services/email-service/BatchSendingService.js:19-19
Timestamp: 2025-10-30T17:13:26.190Z
Learning: In ghost/core/core/server/services/email-service/BatchSendingService.js and similar files in the Ghost codebase, prefer using `{...options}` spread syntax without explicit guards like `...(options || {})` when spreading potentially undefined objects, as the maintainer prefers cleaner syntax over defensive patterns when the behavior is safe.
Learnt from: niranjan-uma-shankar
Repo: TryGhost/Ghost PR: 24557
File: apps/admin-x-settings/src/components/settings/general/TimeZone.tsx:7-7
Timestamp: 2025-08-01T12:44:07.467Z
Learning: In Ghost development, PRs may depend on unpublished changes from SDK packages. When this occurs, TypeScript compilation errors for missing exports are expected and documented in the PR description until the dependency packages are published and updated. This is normal workflow for cross-repository feature development.
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Prefer compound subcomponents (e.g., `Header.Title`, `Header.Meta`, `Header.Actions`) for multi-region components instead of many props
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use `PascalCase` for component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Learnt from: sagzy
Repo: TryGhost/Ghost PR: 24673
File: ghost/i18n/lib/i18n.js:34-35
Timestamp: 2025-11-24T11:12:15.712Z
Learning: In the Ghost i18n package (ghost/i18n/lib/i18n.js), changing existing locale codes requires backwards compatibility handling for users who have already configured those locales. Such changes should be done in a separate PR with migration logic rather than included in feature PRs.
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/**/*.{ts,tsx,js} : Use the `@` alias for internal imports (e.g., `@/lib/utils`)
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/layout/**/*.{ts,tsx} : Reusable layout containers (Page, Heading, Header, ViewHeader, ErrorPage) should be placed in `src/components/layout/*`
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.{ts,tsx} : Prefer less comments and give things clear names
Applied to files:
apps/admin-x-settings/src/typings.d.tsapps/stats/src/types/svg.d.tsapps/shade/src/components/layout/heading.tsxapps/activitypub/src/views/profile/profile.tsx
📚 Learning: 2025-03-13T09:02:50.102Z
Learnt from: mike182uk
Repo: TryGhost/Ghost PR: 22471
File: apps/admin-x-activitypub/src/views/Feed/components/NewPostModal.tsx:29-34
Timestamp: 2025-03-13T09:02:50.102Z
Learning: In the Ghost ActivityPub module, error handling for mutations is handled at the hook level (in use-activity-pub-queries.ts) rather than in individual components. This allows for centralized error handling across the application.
Applied to files:
apps/activitypub/src/views/preferences/components/profile.tsxapps/activitypub/src/views/preferences/components/bluesky-sharing.tsxapps/activitypub/src/api/activitypub.ts
📚 Learning: 2025-03-13T09:02:50.102Z
Learnt from: mike182uk
Repo: TryGhost/Ghost PR: 22471
File: apps/admin-x-activitypub/src/views/Feed/components/NewPostModal.tsx:29-34
Timestamp: 2025-03-13T09:02:50.102Z
Learning: In the ActivityPub module, error handling for mutations is handled at the hook level (in use-activity-pub-queries.ts) rather than in individual components. This allows for centralized error handling across the application.
Applied to files:
apps/activitypub/src/views/preferences/components/profile.tsxapps/activitypub/src/api/activitypub.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/**/*.{ts,tsx,js} : Use the `@` alias for internal imports (e.g., `@/lib/utils`)
Applied to files:
apps/stats/src/types/svg.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/hooks/**/*.{ts,tsx} : Custom React hooks should be placed in `src/hooks/*`
Applied to files:
apps/stats/src/types/svg.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/layout/**/*.{ts,tsx} : Reusable layout containers (Page, Heading, Header, ViewHeader, ErrorPage) should be placed in `src/components/layout/*`
Applied to files:
apps/shade/src/components/layout/page.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use CVA (Class Variance Authority) for component variants when useful instead of heavy prop configuration
Applied to files:
apps/shade/src/components/layout/page.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/view-header.tsxapps/comments-ui/src/components/popup-box.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/index.ts : Place new UI components under `src/components/ui` and export them from `src/index.ts`
Applied to files:
apps/shade/src/components/layout/page.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/view-header.tsxapps/comments-ui/src/components/popup-box.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use Tailwind CSS scoped via `.shade` class; dark mode uses `.dark`
Applied to files:
apps/shade/src/components/layout/page.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Prefer compound subcomponents (e.g., `Header.Title`, `Header.Meta`, `Header.Actions`) for multi-region components instead of many props
Applied to files:
apps/shade/src/components/layout/page.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use `PascalCase` for component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Applied to files:
apps/shade/src/components/layout/page.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/ui/**/*.{ts,tsx} : Atomic UI components should be placed in `src/components/ui/*` and each component must have a corresponding `*.stories.tsx` file next to it for Storybook documentation
Applied to files:
apps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/features/**/*.{ts,tsx} : Higher-level, opinionated components (e.g., PostShareModal, SourceTabs) should be placed in `src/components/features/*`
Applied to files:
apps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Always forward and merge `className` prop with `cn(...)` utility function
Applied to files:
apps/shade/src/components/layout/page.tsxapps/shade/src/components/layout/heading.tsx
📚 Learning: 2025-12-09T12:37:23.267Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 25501
File: apps/shade/src/hooks/use-mobile.tsx:5-10
Timestamp: 2025-12-09T12:37:23.267Z
Learning: In the Ghost repository, this guideline applies to the shade admin app. For files under apps/shade that access browser globals (navigator, window, document) at module load time, SSR is not used, so typeof guards are not required. Reviewers should verify that such files remain client-side only and that no SSR context is introduced; apply this understanding to similarly structured files under apps/shade.
Applied to files:
apps/shade/src/components/layout/page.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Follow ESLint and `tailwindcss/*` plugin rules when writing styles
Applied to files:
apps/shade/src/components/layout/heading.tsx
📚 Learning: 2025-07-14T12:20:35.268Z
Learnt from: sagzy
Repo: TryGhost/Ghost PR: 24346
File: apps/admin-x-settings/src/components/settings/growth/Network.tsx:8-12
Timestamp: 2025-07-14T12:20:35.268Z
Learning: The Network component toggle in `apps/admin-x-settings/src/components/settings/growth/Network.tsx` is intentionally implemented as static UI with a no-op onChange handler, as part of a UI-first development approach before connecting actual ActivityPub functionality.
Applied to files:
apps/activitypub/src/views/profile/profile.tsx
📚 Learning: 2025-10-30T17:13:26.190Z
Learnt from: sam-lord
Repo: TryGhost/Ghost PR: 25303
File: ghost/core/core/server/services/email-service/BatchSendingService.js:19-19
Timestamp: 2025-10-30T17:13:26.190Z
Learning: In ghost/core/core/server/services/email-service/BatchSendingService.js and similar files in the Ghost codebase, prefer using `{...options}` spread syntax without explicit guards like `...(options || {})` when spreading potentially undefined objects, as the maintainer prefers cleaner syntax over defensive patterns when the behavior is safe.
Applied to files:
apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx
🪛 Biome (2.1.2)
apps/activitypub/src/views/profile/profile.tsx
[error] 13-14: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/posts/src/views/PostAnalytics/Web/web.tsx
[error] 26-27: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/posts/src/views/PostAnalytics/Growth/growth.tsx
[error] 16-17: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx
[error] 17-18: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
🔇 Additional comments (18)
apps/comments-ui/src/components/popup-box.tsx (1)
7-8: ESLint rule update on empty object type looks correctSwitching the directive to
@typescript-eslint/no-empty-object-typeis consistent with the updated ESLint/TS rules and keeps the existing TODO without introducing runtime changes. This is appropriate for this PR’s scope.apps/activitypub/src/views/preferences/components/bluesky-sharing.tsx (1)
48-60: LGTM! Error binding correctly removed.The unused error parameter has been removed from the catch block while preserving the error handling behavior (loading state reset and toast notification).
apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx (1)
19-33: LGTM! Unused error binding removed.The catch block correctly removes the unused error parameter while maintaining the URL validation error handling.
apps/comments-ui/src/components/content/forms/form.tsx (1)
67-91: LGTM! Error binding correctly removed.The unused error parameter has been removed while preserving the error state management in the form submission handler.
apps/activitypub/src/views/preferences/components/profile.tsx (1)
258-315: LGTM! Unused error bindings removed from nested error handling.Both catch blocks in the nested try-catch structure correctly remove unused error parameters while preserving the toast error notifications and processing state cleanup.
apps/activitypub/src/api/activitypub.ts (1)
252-261: LGTM! Unused error binding removed.The catch block correctly removes the unused error parameter while maintaining the null return behavior. The TODO comment about Sentry remains relevant if error logging is needed in the future.
apps/admin-x-settings/src/utils/link-to-github-releases.ts (2)
1-2: LGTM! TypeScript suppression added.The
@ts-expect-errorcomment correctly documents that the semver subpath import lacks type definitions.
8-36: LGTM! Unused error binding removed.The catch block correctly removes the unused error parameter while preserving the fallback behavior (empty string return).
apps/signup-form/src/components/pages/form-page.tsx (1)
14-40: LGTM! Unused error binding removed.The catch block correctly removes the unused error parameter (previously marked with underscore) while preserving the error state management and toast notification.
apps/posts/src/utils/link-helpers.ts (1)
15-34: LGTM! Unused error binding removed.The catch block correctly removes the unused error parameter while preserving the fallback behavior (returning the original URL when parsing fails).
apps/activitypub/src/utils/image.ts (1)
25-28: LGTM!The bare
catchblock is appropriate here since the error was unused — the function simply returns the original URL as a fallback regardless of the error type. No loss of functionality or debugging capability.ghost/core/core/server/services/recommendations/service/RecommendationMetadataService.ts (2)
64-70: LGTM!The bare
catchblocks in#fetchJSONappropriately swallow parsing and network errors, returningundefinedas a fallback. The error objects were unused, so this change has no functional impact.
77-81: LGTM!The
#castUrlmethod correctly returnsnullfor invalid URLs. The barecatchis appropriate since the error details are irrelevant to the fallback behavior.apps/admin-x-design-system/src/utils/format-url.ts (1)
46-50: LGTM!The bare
catchis appropriate — the function gracefully handles invalid URLs by returning the original input, and the specific error details aren't needed for this fallback behavior.apps/admin-x-framework/src/api/recommendations.ts (1)
25-29: LGTM!The
eslint-disable-next-linecomments are appropriate here.RecommendationEditResponseTypeserves as a semantic type alias for the response type, andRecommendationDeleteResponseTypecorrectly represents a DELETE response with no body. These intentionally empty interfaces improve API documentation and type safety.apps/shade/src/components/layout/heading.tsx (1)
4-5: Scoped ESLint suppression forHeadingPropslooks goodThe
@typescript-eslint/no-empty-object-typedisable is correctly limited toHeadingProps, letting you keep the exported interface alias overReact.HTMLAttributes<HTMLHeadingElement>with no runtime impact. Please just verifyyarn lintpasses with the updated eslint-plugin-ghost.apps/shade/src/components/layout/page.tsx (1)
4-5: ESLint disable aroundPagePropsis minimal and appropriateThe empty-object-type suppression is narrowly scoped to
PageProps, preserving the existinginterface-based props alias without changing the Page component’s runtime behavior. Please confirm the updated eslint-plugin-ghost runs cleanly (yarn lint).apps/shade/src/components/layout/view-header.tsx (1)
4-6:ViewHeaderActionsPropslint suppression and exports are consistentThe added
@typescript-eslint/no-empty-object-typedisable is correctly scoped toViewHeaderActionsProps, allowing the existing interface alias pattern without altering theViewHeader/ViewHeaderActionsAPI or behavior; the named exports remain unchanged. Please verify the new eslint-plugin-ghost configuration passes lint for this file.Also applies to: 32-32
bdf4848 to
57d944e
Compare
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
apps/stats/src/types/svg.d.ts (1)
2-3: Same refactor suggestion applies here.A previous review comment already suggested using
import type * as React from 'react';instead of suppressing the linter. Please refer to that comment for the recommended change.
🧹 Nitpick comments (8)
apps/admin-x-settings/src/typings.d.ts (1)
5-6: Prefer ES6import typesyntax over suppressing the linter.Since React is only used for type references here, using
import typeis cleaner and avoids the need for ESLint suppression.- // eslint-disable-next-line @typescript-eslint/no-require-imports - import React = require('react'); + import type * as React from 'react';apps/comments-ui/src/components/content/forms/form.tsx (1)
78-81: Consider logging the error for better observability.While the removal of the unused error binding aligns with the ESLint update, the catch block silently swallows errors without any logging. This could make debugging submit failures difficult in production environments.
Consider adding error logging to improve observability:
- } catch { + } catch (error) { + console.error('Failed to submit comment:', error); setProgress('error'); return; }apps/activitypub/src/views/profile/profile.tsx (1)
13-14: Align empty props type with Biome and avoid the ESLint suppression
interface ProfileProps {}is effectively{}and is being flagged by Biome (noEmptyInterface), while the new ESLint disable only silences@typescript-eslint/no-empty-object-type. To keep the component’s public API unchanged but simplify linting, consider switching to a type alias and dropping the suppression:-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface ProfileProps {} +type ProfileProps = Record<string, never>;
React.FC<ProfileProps>will still work as before (includingchildrenviaPropsWithChildren), but both ESLint and Biome should be happier without ignores. If you intentionally want an “extendable marker” interface, you may instead want to keep the interface and add a matching Biome ignore comment alongside this ESLint disable.apps/posts/src/views/PostAnalytics/Growth/growth.tsx (1)
16-19: Consider removing the empty interface or using a type alias.The ESLint suppression and empty interface pattern is consistent with the ESLint update, but per Biome's suggestion, empty interfaces are semantically unclear. You have cleaner alternatives:
Option 1 (simplest): Remove the interface entirely and use
React.FCdirectly (it defaults to empty props):-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} - -const Growth: React.FC<postAnalyticsProps> = () => { +const Growth: React.FC = () => {Option 2: Use a type alias if you want to keep the named type:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} +type postAnalyticsProps = Record<string, never>;apps/posts/src/views/PostAnalytics/Web/web.tsx (1)
26-29: Consider removing the empty interface or using a type alias.Same pattern as in
growth.tsx. Empty interfaces are semantically unclear—cleaner alternatives:
Option 1 (simplest): Use
React.FCdirectly (defaults to empty props):-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} - -const Web: React.FC<postAnalyticsProps> = () => { +const Web: React.FC = () => {Option 2: Use a type alias:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} +type postAnalyticsProps = Record<string, never>;apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx (1)
17-18: Consider removing the empty interface or using a type alias.This pattern appears in all three PostAnalytics view files (
growth.tsx,web.tsx, andnewsletter.tsx). Empty interfaces are semantically unclear—cleaner alternatives:
Option 1 (simplest): Use
React.FCdirectly (defaults to empty props):-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {}Then update line 67:
-const Newsletter: React.FC<postAnalyticsProps> = () => { +const Newsletter: React.FC = () => {Option 2: Use a type alias:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} +type postAnalyticsProps = Record<string, never>;Since this pattern is consistent across all three files, you might want to apply the same refactor to all of them in one pass.
apps/shade/src/components/layout/view-header.tsx (2)
4-5: Consider refactoring to avoid the ESLint suppression.The interface extends
React.HTMLAttributes<HTMLElement>but adds no additional properties, triggering the new ESLint rule. Additionally,ViewHeaderActions(lines 7-13) doesn't forward these inherited attributes to the rendereddiv.Consider one of these approaches:
Option 1: Remove the interface and use the base type directly
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface ViewHeaderActionsProps extends React.HTMLAttributes<HTMLElement> {} - -const ViewHeaderActions:React.FC<ViewHeaderActionsProps> = ({children}) => { +const ViewHeaderActions: React.FC<React.HTMLAttributes<HTMLElement>> = ({children}) => {Option 2: Forward the HTML attributes properly
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface ViewHeaderActionsProps extends React.HTMLAttributes<HTMLElement> {} -const ViewHeaderActions:React.FC<ViewHeaderActionsProps> = ({children}) => { +const ViewHeaderActions: React.FC<ViewHeaderActionsProps> = ({children, ...props}) => { return ( - <div className='flex items-center gap-2'> + <div className='flex items-center gap-2' {...props}> {children} </div> );As per coding guidelines for apps/shade components, if HTMLAttributes are declared, they should be forwarded to enable standard DOM props like
data-*,aria-*, etc.
15-30: Consider forwarding HTML attributes from the interface.
ViewHeaderPropsextendsReact.HTMLAttributes<HTMLElement>but onlyclassNameis forwarded (line 19-24). Other inherited attributes likedata-*,aria-*,id, etc. are not passed to the rendered element.Apply this diff to forward all HTML attributes:
-const ViewHeader:React.FC<ViewHeaderProps> = ({className, children}) => { +const ViewHeader: React.FC<ViewHeaderProps> = ({className, children, ...props}) => { const [headerComponent, actionsComponent] = React.Children.toArray(children); return ( - <header className='sticky top-0 z-50 -mx-8 bg-white/70 backdrop-blur-md dark:bg-black'> + <header className='sticky top-0 z-50 -mx-8 bg-white/70 backdrop-blur-md dark:bg-black' {...props}>Also note:
className?: string;on line 16 is redundant since it's already included inReact.HTMLAttributes<HTMLElement>.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (55)
apps/activitypub/src/api/activitypub.ts(1 hunks)apps/activitypub/src/components/modals/new-note-modal.tsx(1 hunks)apps/activitypub/src/hooks/use-activity-pub-queries.ts(3 hunks)apps/activitypub/src/utils/get-username.ts(1 hunks)apps/activitypub/src/utils/image.ts(1 hunks)apps/activitypub/src/views/preferences/components/bluesky-sharing.tsx(1 hunks)apps/activitypub/src/views/preferences/components/profile.tsx(1 hunks)apps/activitypub/src/views/profile/profile.tsx(1 hunks)apps/admin-x-design-system/src/global/sortable-list.tsx(1 hunks)apps/admin-x-design-system/src/typings.d.ts(1 hunks)apps/admin-x-design-system/src/utils/format-url.ts(1 hunks)apps/admin-x-framework/src/api/config.ts(1 hunks)apps/admin-x-framework/src/api/recommendations.ts(1 hunks)apps/admin-x-framework/src/test/acceptance.ts(1 hunks)apps/admin-x-framework/src/test/test-utils.tsx(1 hunks)apps/admin-x-framework/test/unit/hooks/use-form.test.ts(2 hunks)apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/incoming-recommendation-list.tsx(1 hunks)apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx(2 hunks)apps/admin-x-settings/src/typings.d.ts(1 hunks)apps/admin-x-settings/src/utils/link-to-github-releases.ts(2 hunks)apps/admin-x-settings/src/utils/url.ts(1 hunks)apps/admin/package.json(1 hunks)apps/comments-ui/src/actions.ts(2 hunks)apps/comments-ui/src/app-context.ts(1 hunks)apps/comments-ui/src/components/content/forms/form.tsx(1 hunks)apps/comments-ui/src/components/popup-box.tsx(1 hunks)apps/comments-ui/src/typings.d.ts(1 hunks)apps/comments-ui/src/utils/admin-api.ts(1 hunks)apps/comments-ui/src/utils/api.ts(1 hunks)apps/posts/src/hooks/use-post-success-modal.ts(1 hunks)apps/posts/src/utils/link-helpers.ts(1 hunks)apps/posts/src/views/PostAnalytics/Growth/growth.tsx(1 hunks)apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx(1 hunks)apps/posts/src/views/PostAnalytics/Web/web.tsx(1 hunks)apps/shade/src/components/features/color-picker/color-picker.tsx(1 hunks)apps/shade/src/components/layout/header.tsx(7 hunks)apps/shade/src/components/layout/heading.tsx(1 hunks)apps/shade/src/components/layout/page.tsx(1 hunks)apps/shade/src/components/layout/view-header.tsx(2 hunks)apps/shade/src/components/ui/card.tsx(1 hunks)apps/shade/src/lib/utils.ts(1 hunks)apps/shade/src/typings.d.ts(1 hunks)apps/signup-form/src/components/pages/form-page.tsx(1 hunks)apps/signup-form/src/typings.d.ts(1 hunks)apps/stats/src/hooks/use-feature-flag.tsx(1 hunks)apps/stats/src/types/svg.d.ts(1 hunks)apps/stats/src/utils/url-helpers.ts(5 hunks)apps/stats/test/utils/tinybird-helpers.ts(1 hunks)e2e/package.json(1 hunks)ghost/core/core/server/services/recommendations/service/RecommendationMetadataService.ts(2 hunks)ghost/core/core/server/services/recommendations/service/UnsafeData.ts(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- apps/comments-ui/src/typings.d.ts
🚧 Files skipped from review as they are similar to previous changes (32)
- apps/signup-form/src/components/pages/form-page.tsx
- apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx
- apps/admin-x-framework/test/unit/hooks/use-form.test.ts
- apps/admin-x-design-system/src/utils/format-url.ts
- apps/posts/src/utils/link-helpers.ts
- apps/admin-x-framework/src/test/test-utils.tsx
- apps/activitypub/src/hooks/use-activity-pub-queries.ts
- apps/signup-form/src/typings.d.ts
- apps/activitypub/src/api/activitypub.ts
- apps/admin-x-settings/src/utils/link-to-github-releases.ts
- apps/activitypub/src/components/modals/new-note-modal.tsx
- apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx
- apps/shade/src/components/layout/heading.tsx
- apps/stats/src/utils/url-helpers.ts
- apps/comments-ui/src/actions.ts
- apps/admin-x-design-system/src/typings.d.ts
- ghost/core/core/server/services/recommendations/service/UnsafeData.ts
- apps/shade/src/components/layout/page.tsx
- apps/shade/src/components/ui/card.tsx
- apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx
- apps/posts/src/hooks/use-post-success-modal.ts
- apps/comments-ui/src/components/popup-box.tsx
- apps/admin-x-design-system/src/global/sortable-list.tsx
- apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx
- apps/shade/src/lib/utils.ts
- apps/admin-x-framework/src/api/config.ts
- apps/shade/src/typings.d.ts
- apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx
- apps/comments-ui/src/utils/admin-api.ts
- apps/admin-x-settings/src/components/settings/growth/recommendations/incoming-recommendation-list.tsx
- apps/shade/src/components/layout/header.tsx
- ghost/core/core/server/services/recommendations/service/RecommendationMetadataService.ts
🧰 Additional context used
📓 Path-based instructions (5)
apps/shade/src/components/layout/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
Reusable layout containers (Page, Heading, Header, ViewHeader, ErrorPage) should be placed in
src/components/layout/*
Files:
apps/shade/src/components/layout/view-header.tsx
apps/shade/src/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/src/components/**/*.{ts,tsx}: UsePascalCasefor component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Always forward and mergeclassNameprop withcn(...)utility function
Use CVA (Class Variance Authority) for component variants when useful instead of heavy prop configuration
Prefer compound subcomponents (e.g.,Header.Title,Header.Meta,Header.Actions) for multi-region components instead of many props
Use Tailwind CSS scoped via.shadeclass; dark mode uses.dark
Files:
apps/shade/src/components/layout/view-header.tsxapps/shade/src/components/features/color-picker/color-picker.tsx
apps/shade/src/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/src/**/*.{ts,tsx,js}: UsecamelCasefor function and variable names
Use the@alias for internal imports (e.g.,@/lib/utils)
Files:
apps/shade/src/components/layout/view-header.tsxapps/shade/src/components/features/color-picker/color-picker.tsx
apps/shade/{src,test}/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/{src,test}/**/*.{ts,tsx,js}: Runyarn lintafter making changes to fix any ESLint errors and warnings before committing
Follow ESLint andtailwindcss/*plugin rules when writing styles
Files:
apps/shade/src/components/layout/view-header.tsxapps/shade/src/components/features/color-picker/color-picker.tsx
apps/shade/src/components/features/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
Higher-level, opinionated components (e.g., PostShareModal, SourceTabs) should be placed in
src/components/features/*
Files:
apps/shade/src/components/features/color-picker/color-picker.tsx
🧠 Learnings (21)
📓 Common learnings
Learnt from: cmraible
Repo: TryGhost/Ghost PR: 24658
File: ghost/admin/package.json:3-3
Timestamp: 2025-08-12T18:33:15.524Z
Learning: In Ghost's admin package.json, third-party packages like ember-cli-postcss, ember-exam, and ember-power-select have their own independent versioning schemes that are unrelated to Ghost's version numbers. Version number coincidences between Ghost versions and these packages should not trigger update suggestions.
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Follow ESLint and `tailwindcss/*` plugin rules when writing styles
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Run `yarn lint` after making changes to fix any ESLint errors and warnings before committing
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Prefer compound subcomponents (e.g., `Header.Title`, `Header.Meta`, `Header.Actions`) for multi-region components instead of many props
Learnt from: niranjan-uma-shankar
Repo: TryGhost/Ghost PR: 24557
File: apps/admin-x-settings/src/components/settings/general/TimeZone.tsx:7-7
Timestamp: 2025-08-01T12:44:07.467Z
Learning: In Ghost development, PRs may depend on unpublished changes from SDK packages. When this occurs, TypeScript compilation errors for missing exports are expected and documented in the PR description until the dependency packages are published and updated. This is normal workflow for cross-repository feature development.
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T14:28:50.351Z
Learning: Applies to ghost/i18n/locales/en/ghost.json : Add UI translations to `ghost/i18n/locales/en/ghost.json` for Admin UI features
Learnt from: sam-lord
Repo: TryGhost/Ghost PR: 25303
File: ghost/core/core/server/services/email-service/BatchSendingService.js:19-19
Timestamp: 2025-10-30T17:13:26.190Z
Learning: In ghost/core/core/server/services/email-service/BatchSendingService.js and similar files in the Ghost codebase, prefer using `{...options}` spread syntax without explicit guards like `...(options || {})` when spreading potentially undefined objects, as the maintainer prefers cleaner syntax over defensive patterns when the behavior is safe.
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 24651
File: ghost/core/test/utils/urlUtils.js:53-57
Timestamp: 2025-08-11T19:39:00.428Z
Learning: In Ghost's test utilities, when fixing specific issues like async behavior, it's preferred to maintain existing error handling patterns (even if suboptimal) to keep PRs focused on their primary objective. Error handling improvements can be addressed in separate, dedicated PRs.
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use `PascalCase` for component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/**/*.{ts,tsx,js} : Use the `@` alias for internal imports (e.g., `@/lib/utils`)
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 25501
File: apps/shade/src/hooks/use-mobile.tsx:5-10
Timestamp: 2025-12-09T12:37:30.664Z
Learning: The Ghost admin apps/shade/** components do not use SSR, so accessing browser APIs like `navigator`, `window`, or `document` at module load time is safe and does not require typeof guards.
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.{ts,tsx} : Prefer less comments and give things clear names
Applied to files:
apps/comments-ui/src/app-context.tsapps/admin-x-settings/src/typings.d.tsapps/stats/src/types/svg.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use CVA (Class Variance Authority) for component variants when useful instead of heavy prop configuration
Applied to files:
apps/comments-ui/src/app-context.tsapps/shade/src/components/layout/view-header.tsxapps/shade/src/components/features/color-picker/color-picker.tsx
📚 Learning: 2025-08-12T18:33:15.524Z
Learnt from: cmraible
Repo: TryGhost/Ghost PR: 24658
File: ghost/admin/package.json:3-3
Timestamp: 2025-08-12T18:33:15.524Z
Learning: In Ghost's admin package.json, third-party packages like ember-cli-postcss, ember-exam, and ember-power-select have their own independent versioning schemes that are unrelated to Ghost's version numbers. Version number coincidences between Ghost versions and these packages should not trigger update suggestions.
Applied to files:
e2e/package.json
📚 Learning: 2025-08-26T16:47:28.150Z
Learnt from: troyciesco
Repo: TryGhost/Ghost PR: 24749
File: ghost/core/core/server/services/members/SingleUseTokenProvider.js:3-5
Timestamp: 2025-08-26T16:47:28.150Z
Learning: When checking for dependencies in Ghost project, ensure to look directly in the specific package.json files rather than relying only on automated searches, as otplib dependency exists at line 204 in ghost/core/package.json version "12.0.1"
Applied to files:
e2e/package.json
📚 Learning: 2025-11-25T14:28:50.351Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T14:28:50.351Z
Learning: Analytics using Tinybird should reference scripts in `ghost/core/core/server/data/tinybird/scripts/` and datafiles in `ghost/core/core/server/data/tinybird/`
Applied to files:
apps/stats/test/utils/tinybird-helpers.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Prefer compound subcomponents (e.g., `Header.Title`, `Header.Meta`, `Header.Actions`) for multi-region components instead of many props
Applied to files:
apps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/index.ts : Place new UI components under `src/components/ui` and export them from `src/index.ts`
Applied to files:
apps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/layout/**/*.{ts,tsx} : Reusable layout containers (Page, Heading, Header, ViewHeader, ErrorPage) should be placed in `src/components/layout/*`
Applied to files:
apps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use `PascalCase` for component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Applied to files:
apps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use Tailwind CSS scoped via `.shade` class; dark mode uses `.dark`
Applied to files:
apps/shade/src/components/layout/view-header.tsxapps/shade/src/components/features/color-picker/color-picker.tsx
📚 Learning: 2025-11-25T11:58:51.652Z
Learnt from: ibalosh
Repo: TryGhost/Ghost PR: 25525
File: apps/shade/src/shade-app.tsx:4-4
Timestamp: 2025-11-25T11:58:51.652Z
Learning: In apps/shade, the app wrapper file should be named `src/shade-app.tsx` (kebab-case) while the component itself is exported as `ShadeApp` (PascalCase). Context providers should be placed in `src/providers/*` using kebab-case filenames.
Applied to files:
apps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-12-09T12:37:23.267Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 25501
File: apps/shade/src/hooks/use-mobile.tsx:5-10
Timestamp: 2025-12-09T12:37:23.267Z
Learning: In the Ghost repository, this guideline applies to the shade admin app. For files under apps/shade that access browser globals (navigator, window, document) at module load time, SSR is not used, so typeof guards are not required. Reviewers should verify that such files remain client-side only and that no SSR context is introduced; apply this understanding to similarly structured files under apps/shade.
Applied to files:
apps/shade/src/components/layout/view-header.tsxapps/shade/src/components/features/color-picker/color-picker.tsx
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Always follow ADRs in `../adr/` folder (ADR-0001: AAA pattern, ADR-0002: Page Objects)
Applied to files:
apps/admin-x-framework/src/test/acceptance.ts
📚 Learning: 2025-10-09T15:31:06.587Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 25118
File: apps/portal/src/actions.js:160-173
Timestamp: 2025-10-09T15:31:06.587Z
Learning: When reviewing PRs that introduce feature-flagged changes (e.g., `labs?.membersSigninOTCAlpha`), avoid suggesting modifications to non-flagged code paths unless they're directly related to the PR's objectives. Keep the scope focused on the feature-flag-specific changes only.
Applied to files:
apps/admin-x-framework/src/test/acceptance.ts
📚 Learning: 2025-10-21T13:04:40.040Z
Learnt from: jonatansberg
Repo: TryGhost/Ghost PR: 24967
File: apps/admin/vite.config.ts:1-8
Timestamp: 2025-10-21T13:04:40.040Z
Learning: In Vite config files (vite.config.ts, vite.config.js), __dirname can be used directly even when the package.json has "type": "module". Vite handles config file transpilation in a way that makes __dirname available, so no ESM shim (fileURLToPath/dirname) is needed.
Applied to files:
apps/admin/package.json
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/lib/utils.ts : Shared utilities (class merging, formatting, chart helpers) should be centralized in `src/lib/utils.ts`
Applied to files:
apps/shade/src/components/features/color-picker/color-picker.tsx
📚 Learning: 2025-09-10T07:05:34.606Z
Learnt from: jonatansberg
Repo: TryGhost/Ghost PR: 24838
File: apps/shade/src/components/features/color-picker/color-picker.tsx:0-0
Timestamp: 2025-09-10T07:05:34.606Z
Learning: The Color library used in the color picker component handles input validation and clamping automatically, so manual validation of HSL and RGB values is not necessary when using Color constructors.
Applied to files:
apps/shade/src/components/features/color-picker/color-picker.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/**/*.{ts,tsx,js} : Use the `@` alias for internal imports (e.g., `@/lib/utils`)
Applied to files:
apps/stats/src/types/svg.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/hooks/**/*.{ts,tsx} : Custom React hooks should be placed in `src/hooks/*`
Applied to files:
apps/stats/src/types/svg.d.ts
📚 Learning: 2025-03-13T09:02:50.102Z
Learnt from: mike182uk
Repo: TryGhost/Ghost PR: 22471
File: apps/admin-x-activitypub/src/views/Feed/components/NewPostModal.tsx:29-34
Timestamp: 2025-03-13T09:02:50.102Z
Learning: In the Ghost ActivityPub module, error handling for mutations is handled at the hook level (in use-activity-pub-queries.ts) rather than in individual components. This allows for centralized error handling across the application.
Applied to files:
apps/activitypub/src/views/preferences/components/profile.tsxapps/activitypub/src/views/preferences/components/bluesky-sharing.tsx
🪛 Biome (2.1.2)
apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx
[error] 17-18: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/posts/src/views/PostAnalytics/Web/web.tsx
[error] 26-27: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/activitypub/src/views/profile/profile.tsx
[error] 13-14: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/posts/src/views/PostAnalytics/Growth/growth.tsx
[error] 16-17: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
🔇 Additional comments (14)
apps/comments-ui/src/app-context.ts (1)
114-121: BarecatchinuseLabskeeps behavior while cleaning up unused variableSwitching to a parameterless
catchis correct here: the error object wasn’t used and the function still safely falls back to{}when context is unavailable. This aligns with modern JS and the ESLint update without changing runtime behavior.apps/admin-x-settings/src/utils/url.ts (1)
30-32: LGTM!Using optional catch binding (bare
catch) is appropriate here since the error object was never used. This aligns with modern ES2019+ conventions and the ESLint plugin update.e2e/package.json (1)
32-32: Version bump aligns with broader ESLint tooling upgrade.The typescript-eslint update from 8.46.1 to 8.49.0 is a patch-level bump consistent with the PR's goal of updating ESLint tooling across the monorepo. Verify that the concurrent updates to eslint-plugin-ghost and the widespread catch block refactoring mentioned in the PR description work correctly with this version.
apps/admin/package.json (1)
41-41: Version bump consistent across the monorepo.The typescript-eslint update to 8.49.0 matches the corresponding bump in e2e/package.json and supports the PR's goal of aligning ESLint tooling. The version is compatible with the already-pinned eslint 9.37.0. Ensure the ESLint configuration changes and linting rules work correctly with this version across the admin application.
apps/activitypub/src/views/preferences/components/profile.tsx (1)
307-314: Barecatchblocks here are fine and keep behavior unchangedBoth inner and outer
catchblocks inhandleCopynever referenced the error value, so switching to parameterlesscatch {}is safe and keeps the same toasts andsetIsProcessing(false)behavior while satisfying the updated ESLint rules.apps/activitypub/src/views/preferences/components/bluesky-sharing.tsx (1)
53-58: LGTM!The removal of the unused
errorparameter from the catch block is valid. The error object was never referenced, and this change aligns with ESLint's no-unused-vars rule while maintaining identical behavior. Based on learnings, error handling for ActivityPub mutations is centralized at the hook level, so this component-level catch appropriately focuses on local state management and user feedback.apps/admin-x-framework/src/test/acceptance.ts (1)
127-132: Barecatchhere is safe and behavior‑neutralThe caught error value wasn’t used, so switching to a parameterless
catchkeeps the same failure behavior while satisfying the lint rule. No concerns with this change.apps/stats/test/utils/tinybird-helpers.ts (1)
84-89: LGTM! Bare catch is appropriate here.The error parameter was unused, so removing it aligns with the updated ESLint rules. The behavior is preserved—JSON parse failures still result in
errorMessage = bodyText.apps/comments-ui/src/utils/api.ts (1)
312-319: LGTM! Bare catch is appropriate here.The error parameter was unused, so the bare catch syntax aligns with the updated ESLint rules. The fallback behavior is preserved—failures default to an empty labs object.
apps/stats/src/hooks/use-feature-flag.tsx (1)
20-25: LGTM! Bare catch is appropriate here.The error parameter was unused, so removing it aligns with the updated ESLint rules. The behavior is preserved—JSON parse failures still fall back to an empty object.
apps/activitypub/src/utils/image.ts (1)
11-28: LGTM! Bare catch is appropriate here.The error parameter was unused, so the bare catch syntax aligns with the updated ESLint rules. The fallback behavior is preserved—conversion failures still return the original URL.
apps/activitypub/src/utils/get-username.ts (1)
5-9: LGTM! Bare catch is appropriate here.The error parameter was unused, so removing it aligns with the updated ESLint rules. The behavior is preserved—URL parsing failures still return the default
'@unknown@unknown'value.apps/admin-x-framework/src/api/recommendations.ts (1)
25-29: LGTM! ESLint suppressions are appropriate for marker interfaces.The
@typescript-eslint/no-empty-object-typesuppressions are correctly applied to these marker interfaces. BothRecommendationEditResponseTypeandRecommendationDeleteResponseTypeserve as nominal types for API responses, so the empty object types are intentional.apps/shade/src/components/features/color-picker/color-picker.tsx (1)
369-390: Barecatchis appropriate here and keeps behavior unchangedSwitching from
catch (error)tocatch {is safe: the error value was never used, and invalid color inputs are still intentionally ignored. This cleanly satisfies the updated ESLint rules without altering runtime behavior.Please confirm your usual lint/build pipeline (e.g.
yarn lint apps/shade) passes with the updated ESLint plugin and this syntax in place.
57d944e to
571f135
Compare
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (3)
apps/admin-x-settings/src/typings.d.ts (1)
5-6: Consider using ES6import typesyntax instead of suppressing the linter.A past review comment on a similar file suggested refactoring to modern ES6 import syntax. Instead of suppressing
@typescript-eslint/no-require-imports, you can useimport type * as React from 'react'which eliminates the need for the ESLint directive.Apply this diff:
- // eslint-disable-next-line @typescript-eslint/no-require-imports - import React = require('react'); + import type * as React from 'react';Note: This same pattern appears in
apps/admin-x-design-system/src/typings.d.tsandapps/signup-form/src/typings.d.ts. Consider applying this refactor consistently across all three files.apps/admin-x-design-system/src/typings.d.ts (1)
2-3: Duplicate: ES6import typesyntax preferred.This issue was already identified in a previous review comment. The suggestion to use
import type * as React from 'react'instead of suppressing the linter applies here.apps/signup-form/src/typings.d.ts (1)
2-3: Consider ES6import typesyntax (same as other files).This follows the same pattern as the other typings files. As suggested in previous reviews, refactoring to
import type * as React from 'react'would eliminate the need for the ESLint suppression comment.Apply this diff:
- // eslint-disable-next-line @typescript-eslint/no-require-imports - import React = require('react'); + import type * as React from 'react';
🧹 Nitpick comments (4)
apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx (2)
39-40: Consider refactoring to an if statement for clarity.While the ESLint suppression correctly addresses the warning, using a logical-AND expression for control flow is less clear than an explicit if statement. Refactoring would eliminate the need for the suppression and improve readability.
Apply this diff:
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions - !!item.errors.label && clearError?.('label'); + if (item.errors.label) { + clearError?.('label'); + }
67-68: Consider refactoring to an if statement for clarity.Similar to the previous occurrence, this logical-AND expression for control flow would be clearer as an explicit if statement.
Apply this diff:
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions - !!item.errors.url && clearError?.('url'); + if (item.errors.url) { + clearError?.('url'); + }apps/activitypub/src/views/profile/profile.tsx (1)
13-14: Address the root cause instead of suppressing the warning.The empty
ProfilePropsinterface serves no purpose since the component takes no props. Rather than suppressing the ESLint rule, consider one of these solutions:Option 1 (simplest): Remove the interface and type parameter entirely:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface ProfileProps {} - -const Profile: React.FC<ProfileProps> = ({}) => { +const Profile: React.FC = () => {Option 2: If you want to be explicit about no props, use a type alias:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface ProfileProps {} +type ProfileProps = Record<string, never>;apps/posts/src/views/PostAnalytics/Growth/growth.tsx (1)
16-17: Consider replacing empty interfaces with type aliases or removing them.The ESLint suppressions silence the rule rather than addressing the underlying code smell. Empty interfaces are equivalent to
{}and add unnecessary complexity. This pattern appears in three files:
apps/posts/src/views/PostAnalytics/Growth/growth.tsx(lines 16-17)apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx(lines 17-18)apps/posts/src/views/PostAnalytics/Web/web.tsx(lines 26-27)Option 1 (Simplest): Use React.FC without type parameter
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} - -const Growth: React.FC<postAnalyticsProps> = () => { +const Growth: React.FC = () => {Option 2: Use type alias (as suggested by Biome)
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} +type postAnalyticsProps = {};Apply similar changes to the other two files.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (57)
apps/activitypub/src/api/activitypub.ts(1 hunks)apps/activitypub/src/components/modals/new-note-modal.tsx(1 hunks)apps/activitypub/src/hooks/use-activity-pub-queries.ts(3 hunks)apps/activitypub/src/utils/get-username.ts(1 hunks)apps/activitypub/src/utils/image.ts(1 hunks)apps/activitypub/src/views/preferences/components/bluesky-sharing.tsx(1 hunks)apps/activitypub/src/views/preferences/components/profile.tsx(1 hunks)apps/activitypub/src/views/profile/profile.tsx(1 hunks)apps/admin-x-design-system/src/global/sortable-list.tsx(1 hunks)apps/admin-x-design-system/src/typings.d.ts(1 hunks)apps/admin-x-design-system/src/utils/format-url.ts(1 hunks)apps/admin-x-framework/src/api/config.ts(1 hunks)apps/admin-x-framework/src/api/recommendations.ts(1 hunks)apps/admin-x-framework/src/test/acceptance.ts(1 hunks)apps/admin-x-framework/src/test/test-utils.tsx(1 hunks)apps/admin-x-framework/test/unit/hooks/use-form.test.ts(2 hunks)apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/incoming-recommendation-list.tsx(1 hunks)apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx(2 hunks)apps/admin-x-settings/src/typings.d.ts(1 hunks)apps/admin-x-settings/src/utils/link-to-github-releases.ts(2 hunks)apps/admin-x-settings/src/utils/url.ts(1 hunks)apps/admin/eslint.config.js(0 hunks)apps/admin/package.json(1 hunks)apps/comments-ui/src/actions.ts(2 hunks)apps/comments-ui/src/app-context.ts(1 hunks)apps/comments-ui/src/components/content/forms/form.tsx(1 hunks)apps/comments-ui/src/components/popup-box.tsx(1 hunks)apps/comments-ui/src/typings.d.ts(1 hunks)apps/comments-ui/src/utils/admin-api.ts(1 hunks)apps/comments-ui/src/utils/api.ts(1 hunks)apps/posts/src/hooks/use-post-success-modal.ts(1 hunks)apps/posts/src/utils/link-helpers.ts(1 hunks)apps/posts/src/views/PostAnalytics/Growth/growth.tsx(1 hunks)apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx(1 hunks)apps/posts/src/views/PostAnalytics/Web/web.tsx(1 hunks)apps/shade/src/components/features/color-picker/color-picker.tsx(1 hunks)apps/shade/src/components/layout/header.tsx(7 hunks)apps/shade/src/components/layout/heading.tsx(1 hunks)apps/shade/src/components/layout/page.tsx(1 hunks)apps/shade/src/components/layout/view-header.tsx(2 hunks)apps/shade/src/components/ui/card.tsx(1 hunks)apps/shade/src/lib/utils.ts(1 hunks)apps/shade/src/typings.d.ts(1 hunks)apps/signup-form/src/components/pages/form-page.tsx(1 hunks)apps/signup-form/src/typings.d.ts(1 hunks)apps/stats/src/hooks/use-feature-flag.tsx(1 hunks)apps/stats/src/types/svg.d.ts(1 hunks)apps/stats/src/utils/url-helpers.ts(5 hunks)apps/stats/test/utils/tinybird-helpers.ts(1 hunks)e2e/package.json(1 hunks)ghost/core/core/server/services/recommendations/service/RecommendationMetadataService.ts(2 hunks)ghost/core/core/server/services/recommendations/service/UnsafeData.ts(1 hunks)package.json(1 hunks)
💤 Files with no reviewable changes (1)
- apps/admin/eslint.config.js
✅ Files skipped from review due to trivial changes (1)
- apps/stats/src/utils/url-helpers.ts
🚧 Files skipped from review as they are similar to previous changes (31)
- apps/stats/src/hooks/use-feature-flag.tsx
- apps/admin-x-design-system/src/utils/format-url.ts
- apps/comments-ui/src/components/popup-box.tsx
- apps/admin-x-framework/src/test/test-utils.tsx
- apps/activitypub/src/hooks/use-activity-pub-queries.ts
- ghost/core/core/server/services/recommendations/service/RecommendationMetadataService.ts
- apps/posts/src/hooks/use-post-success-modal.ts
- apps/comments-ui/src/app-context.ts
- apps/comments-ui/src/utils/admin-api.ts
- apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx
- apps/comments-ui/src/typings.d.ts
- apps/admin/package.json
- apps/stats/src/types/svg.d.ts
- apps/comments-ui/src/utils/api.ts
- apps/activitypub/src/api/activitypub.ts
- apps/admin-x-framework/src/api/recommendations.ts
- apps/activitypub/src/views/preferences/components/profile.tsx
- apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx
- apps/shade/src/typings.d.ts
- apps/admin-x-framework/src/api/config.ts
- apps/shade/src/lib/utils.ts
- apps/admin-x-settings/src/components/settings/growth/recommendations/incoming-recommendation-list.tsx
- apps/comments-ui/src/actions.ts
- ghost/core/core/server/services/recommendations/service/UnsafeData.ts
- apps/shade/src/components/ui/card.tsx
- apps/activitypub/src/utils/get-username.ts
- apps/admin-x-framework/src/test/acceptance.ts
- package.json
- apps/activitypub/src/utils/image.ts
- apps/stats/test/utils/tinybird-helpers.ts
- apps/shade/src/components/layout/header.tsx
🧰 Additional context used
📓 Path-based instructions (5)
apps/shade/src/components/layout/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
Reusable layout containers (Page, Heading, Header, ViewHeader, ErrorPage) should be placed in
src/components/layout/*
Files:
apps/shade/src/components/layout/page.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/view-header.tsx
apps/shade/src/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/src/components/**/*.{ts,tsx}: UsePascalCasefor component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Always forward and mergeclassNameprop withcn(...)utility function
Use CVA (Class Variance Authority) for component variants when useful instead of heavy prop configuration
Prefer compound subcomponents (e.g.,Header.Title,Header.Meta,Header.Actions) for multi-region components instead of many props
Use Tailwind CSS scoped via.shadeclass; dark mode uses.dark
Files:
apps/shade/src/components/layout/page.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/view-header.tsx
apps/shade/src/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/src/**/*.{ts,tsx,js}: UsecamelCasefor function and variable names
Use the@alias for internal imports (e.g.,@/lib/utils)
Files:
apps/shade/src/components/layout/page.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/view-header.tsx
apps/shade/{src,test}/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/{src,test}/**/*.{ts,tsx,js}: Runyarn lintafter making changes to fix any ESLint errors and warnings before committing
Follow ESLint andtailwindcss/*plugin rules when writing styles
Files:
apps/shade/src/components/layout/page.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/view-header.tsx
apps/shade/src/components/features/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
Higher-level, opinionated components (e.g., PostShareModal, SourceTabs) should be placed in
src/components/features/*
Files:
apps/shade/src/components/features/color-picker/color-picker.tsx
🧠 Learnings (31)
📓 Common learnings
Learnt from: cmraible
Repo: TryGhost/Ghost PR: 24658
File: ghost/admin/package.json:3-3
Timestamp: 2025-08-12T18:33:15.524Z
Learning: In Ghost's admin package.json, third-party packages like ember-cli-postcss, ember-exam, and ember-power-select have their own independent versioning schemes that are unrelated to Ghost's version numbers. Version number coincidences between Ghost versions and these packages should not trigger update suggestions.
Learnt from: sagzy
Repo: TryGhost/Ghost PR: 24673
File: ghost/i18n/lib/i18n.js:34-35
Timestamp: 2025-11-24T11:12:15.712Z
Learning: In the Ghost i18n package (ghost/i18n/lib/i18n.js), changing existing locale codes requires backwards compatibility handling for users who have already configured those locales. Such changes should be done in a separate PR with migration logic rather than included in feature PRs.
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Follow ESLint and `tailwindcss/*` plugin rules when writing styles
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Run `yarn lint` after making changes to fix any ESLint errors and warnings before committing
Learnt from: niranjan-uma-shankar
Repo: TryGhost/Ghost PR: 24557
File: apps/admin-x-settings/src/components/settings/general/TimeZone.tsx:7-7
Timestamp: 2025-08-01T12:44:07.467Z
Learning: In Ghost development, PRs may depend on unpublished changes from SDK packages. When this occurs, TypeScript compilation errors for missing exports are expected and documented in the PR description until the dependency packages are published and updated. This is normal workflow for cross-repository feature development.
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Prefer compound subcomponents (e.g., `Header.Title`, `Header.Meta`, `Header.Actions`) for multi-region components instead of many props
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T14:28:50.351Z
Learning: Admin-x React apps build to `apps/*/dist` using Vite, which are then copied by `ghost/admin/lib/asset-delivery` to `ghost/core/core/built/admin/assets/*`
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T14:28:50.351Z
Learning: Applies to ghost/i18n/locales/en/ghost.json : Add UI translations to `ghost/i18n/locales/en/ghost.json` for Admin UI features
Learnt from: sam-lord
Repo: TryGhost/Ghost PR: 25303
File: ghost/core/core/server/services/email-service/BatchSendingService.js:19-19
Timestamp: 2025-10-30T17:13:26.190Z
Learning: In ghost/core/core/server/services/email-service/BatchSendingService.js and similar files in the Ghost codebase, prefer using `{...options}` spread syntax without explicit guards like `...(options || {})` when spreading potentially undefined objects, as the maintainer prefers cleaner syntax over defensive patterns when the behavior is safe.
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use CVA (Class Variance Authority) for component variants when useful instead of heavy prop configuration
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Use factory pattern for all test data creation instead of hard-coded data or direct database manipulation
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Follow the AAA (Arrange, Act, Assert) pattern in test structure
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Test names should be lowercase and follow the format 'what is tested - expected outcome'
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Manual login should not be used - authentication is automatic via fixture
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Always follow ADRs in `../adr/` folder (ADR-0001: AAA pattern, ADR-0002: Page Objects)
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Use `getByTestId()` only when semantic locators are unavailable, and suggest adding `data-testid` to Ghost codebase when needed
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-03-13T09:02:50.102Z
Learnt from: mike182uk
Repo: TryGhost/Ghost PR: 22471
File: apps/admin-x-activitypub/src/views/Feed/components/NewPostModal.tsx:29-34
Timestamp: 2025-03-13T09:02:50.102Z
Learning: In the Ghost ActivityPub module, error handling for mutations is handled at the hook level (in use-activity-pub-queries.ts) rather than in individual components. This allows for centralized error handling across the application.
Applied to files:
apps/activitypub/src/components/modals/new-note-modal.tsx
📚 Learning: 2025-03-13T09:02:50.102Z
Learnt from: mike182uk
Repo: TryGhost/Ghost PR: 22471
File: apps/admin-x-activitypub/src/views/Feed/components/NewPostModal.tsx:29-34
Timestamp: 2025-03-13T09:02:50.102Z
Learning: In the ActivityPub module, error handling for mutations is handled at the hook level (in use-activity-pub-queries.ts) rather than in individual components. This allows for centralized error handling across the application.
Applied to files:
apps/activitypub/src/components/modals/new-note-modal.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/layout/**/*.{ts,tsx} : Reusable layout containers (Page, Heading, Header, ViewHeader, ErrorPage) should be placed in `src/components/layout/*`
Applied to files:
apps/shade/src/components/layout/page.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use CVA (Class Variance Authority) for component variants when useful instead of heavy prop configuration
Applied to files:
apps/shade/src/components/layout/page.tsxapps/admin-x-design-system/src/typings.d.tsapps/shade/src/components/layout/heading.tsxapps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/index.ts : Place new UI components under `src/components/ui` and export them from `src/index.ts`
Applied to files:
apps/shade/src/components/layout/page.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use Tailwind CSS scoped via `.shade` class; dark mode uses `.dark`
Applied to files:
apps/shade/src/components/layout/page.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Prefer compound subcomponents (e.g., `Header.Title`, `Header.Meta`, `Header.Actions`) for multi-region components instead of many props
Applied to files:
apps/shade/src/components/layout/page.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use `PascalCase` for component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Applied to files:
apps/shade/src/components/layout/page.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.{ts,tsx} : Prefer less comments and give things clear names
Applied to files:
apps/shade/src/components/layout/page.tsxapps/admin-x-design-system/src/typings.d.tsapps/posts/src/views/PostAnalytics/Growth/growth.tsxapps/shade/src/components/layout/heading.tsxapps/signup-form/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/ui/**/*.{ts,tsx} : Atomic UI components should be placed in `src/components/ui/*` and each component must have a corresponding `*.stories.tsx` file next to it for Storybook documentation
Applied to files:
apps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/**/*.{ts,tsx,js} : Use the `@` alias for internal imports (e.g., `@/lib/utils`)
Applied to files:
apps/shade/src/components/layout/page.tsxapps/admin-x-settings/src/typings.d.tsapps/admin-x-design-system/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/features/**/*.{ts,tsx} : Higher-level, opinionated components (e.g., PostShareModal, SourceTabs) should be placed in `src/components/features/*`
Applied to files:
apps/shade/src/components/layout/page.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Always forward and merge `className` prop with `cn(...)` utility function
Applied to files:
apps/shade/src/components/layout/page.tsxapps/shade/src/components/layout/heading.tsx
📚 Learning: 2025-12-09T12:37:23.267Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 25501
File: apps/shade/src/hooks/use-mobile.tsx:5-10
Timestamp: 2025-12-09T12:37:23.267Z
Learning: In the Ghost repository, this guideline applies to the shade admin app. For files under apps/shade that access browser globals (navigator, window, document) at module load time, SSR is not used, so typeof guards are not required. Reviewers should verify that such files remain client-side only and that no SSR context is introduced; apply this understanding to similarly structured files under apps/shade.
Applied to files:
apps/shade/src/components/layout/page.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/view-header.tsx
📚 Learning: 2025-07-14T12:20:35.268Z
Learnt from: sagzy
Repo: TryGhost/Ghost PR: 24346
File: apps/admin-x-settings/src/components/settings/growth/Network.tsx:8-12
Timestamp: 2025-07-14T12:20:35.268Z
Learning: The Network component toggle in `apps/admin-x-settings/src/components/settings/growth/Network.tsx` is intentionally implemented as static UI with a no-op onChange handler, as part of a UI-first development approach before connecting actual ActivityPub functionality.
Applied to files:
apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx
📚 Learning: 2025-11-06T05:35:41.162Z
Learnt from: danielraffel
Repo: TryGhost/Ghost PR: 25366
File: apps/admin/src/layout/app-sidebar/NavHeader.tsx:13-23
Timestamp: 2025-11-06T05:35:41.162Z
Learning: In apps/admin/src/layout/app-sidebar/NavHeader.tsx, the React component dispatches a synthetic KeyboardEvent to trigger the Ember keymaster.js search modal shortcut. This approach is known to have cross-browser reliability issues but was deferred for architectural refactoring in a separate PR. The recommended fix is to expose a global function or custom DOM event from the Ember app instead of relying on synthetic keyboard events with keymaster.js.
Applied to files:
apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/hooks/**/*.{ts,tsx} : Custom React hooks should be placed in `src/hooks/*`
Applied to files:
apps/admin-x-design-system/src/typings.d.ts
📚 Learning: 2025-11-25T14:28:50.351Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T14:28:50.351Z
Learning: Ember admin uses `AdminXComponent` to dynamically import React apps with Suspense and error boundaries
Applied to files:
apps/admin-x-design-system/src/typings.d.ts
📚 Learning: 2025-08-11T19:39:00.428Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 24651
File: ghost/core/test/utils/urlUtils.js:53-57
Timestamp: 2025-08-11T19:39:00.428Z
Learning: In Ghost's test utilities, when fixing specific issues like async behavior, it's preferred to maintain existing error handling patterns (even if suboptimal) to keep PRs focused on their primary objective. Error handling improvements can be addressed in separate, dedicated PRs.
Applied to files:
apps/posts/src/utils/link-helpers.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Follow ESLint and `tailwindcss/*` plugin rules when writing styles
Applied to files:
apps/shade/src/components/layout/heading.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/lib/utils.ts : Shared utilities (class merging, formatting, chart helpers) should be centralized in `src/lib/utils.ts`
Applied to files:
apps/shade/src/components/features/color-picker/color-picker.tsx
📚 Learning: 2025-09-10T07:05:34.606Z
Learnt from: jonatansberg
Repo: TryGhost/Ghost PR: 24838
File: apps/shade/src/components/features/color-picker/color-picker.tsx:0-0
Timestamp: 2025-09-10T07:05:34.606Z
Learning: The Color library used in the color picker component handles input validation and clamping automatically, so manual validation of HSL and RGB values is not necessary when using Color constructors.
Applied to files:
apps/shade/src/components/features/color-picker/color-picker.tsx
📚 Learning: 2025-08-12T18:33:15.524Z
Learnt from: cmraible
Repo: TryGhost/Ghost PR: 24658
File: ghost/admin/package.json:3-3
Timestamp: 2025-08-12T18:33:15.524Z
Learning: In Ghost's admin package.json, third-party packages like ember-cli-postcss, ember-exam, and ember-power-select have their own independent versioning schemes that are unrelated to Ghost's version numbers. Version number coincidences between Ghost versions and these packages should not trigger update suggestions.
Applied to files:
e2e/package.json
📚 Learning: 2025-08-26T16:47:28.150Z
Learnt from: troyciesco
Repo: TryGhost/Ghost PR: 24749
File: ghost/core/core/server/services/members/SingleUseTokenProvider.js:3-5
Timestamp: 2025-08-26T16:47:28.150Z
Learning: When checking for dependencies in Ghost project, ensure to look directly in the specific package.json files rather than relying only on automated searches, as otplib dependency exists at line 204 in ghost/core/package.json version "12.0.1"
Applied to files:
e2e/package.json
🪛 Biome (2.1.2)
apps/posts/src/views/PostAnalytics/Web/web.tsx
[error] 26-27: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/posts/src/views/PostAnalytics/Growth/growth.tsx
[error] 16-17: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/activitypub/src/views/profile/profile.tsx
[error] 13-14: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx
[error] 17-18: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
⏰ 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). (2)
- GitHub Check: Build & Push Docker Image
- GitHub Check: Setup
🔇 Additional comments (17)
apps/posts/src/utils/link-helpers.ts (1)
30-30: LGTM! Clean removal of unused catch parameter.The parameterless catch syntax is appropriate here since the error wasn't being used. This aligns with the ESLint upgrade and removes unnecessary variable declarations.
apps/signup-form/src/components/pages/form-page.tsx (1)
36-39: LGTM! Clean refactor removing unused error parameter.The change to a bare
catchblock is appropriate since the error parameter was never used. The error handling logic remains intact—setting loading state and displaying a user-friendly message.apps/shade/src/components/features/color-picker/color-picker.tsx (1)
388-390: LGTM! Unused error binding removed.The error parameter was unused in the catch block, and removing it aligns with the updated ESLint rules. The behavior remains unchanged—invalid colors are still ignored as intended.
apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx (1)
29-29: LGTM! Unused error variable correctly removed.The error parameter was unused in the catch block, and removing it aligns with the ESLint 9+ upgrade. The error handling behavior remains unchanged.
apps/admin-x-settings/src/utils/url.ts (1)
30-30: LGTM! Unused error variable correctly removed.The error parameter was unused in the catch block, and removing it aligns with the ESLint 9+ upgrade. The error handling behavior (returning false) remains unchanged.
apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx (1)
112-112: LGTM! Unused error variable correctly removed.The error parameter was unused in the catch block, and removing it aligns with the ESLint 9+ upgrade. The error handling behavior (showing a generic error toast) remains unchanged.
apps/comments-ui/src/components/content/forms/form.tsx (1)
78-78: LGTM! Unused catch parameter correctly removed.The error parameter was never referenced in the catch block, so removing it satisfies the updated ESLint rules without changing behavior.
apps/admin-x-settings/src/utils/link-to-github-releases.ts (2)
1-1: LGTM - appropriate type suppression for untyped subpath import.The
@ts-expect-errordirective correctly handles the missing type definitions for the semver subpath import.
33-33: LGTM - removed unused error parameter.Switching to a parameterless
catchblock is cleaner since the error wasn't being used.apps/shade/src/components/layout/page.tsx (1)
4-5: LGTM - appropriate ESLint suppression for type alias pattern.The
no-empty-object-typesuppression is correct for this interface, which serves as a named type alias extendingReact.HTMLAttributes<HTMLDivElement>. This pattern provides better API documentation and allows for future extensibility without breaking changes.apps/shade/src/components/layout/heading.tsx (1)
4-5: LGTM - consistent ESLint suppression for type alias.The
no-empty-object-typesuppression follows the same pattern as other layout components, providing a named type alias forReact.HTMLAttributes<HTMLHeadingElement>that supports future extensibility.apps/shade/src/components/layout/view-header.tsx (1)
4-5: LGTM - consistent ESLint suppression for subcomponent props.The
no-empty-object-typesuppression is appropriate forViewHeaderActionsProps, maintaining consistency with other layout component prop interfaces while providing a named type for the compound subcomponent pattern.apps/admin-x-design-system/src/global/sortable-list.tsx (1)
16-18: ESLint directive update aligns with the plugin upgrade.The change from
@typescript-eslint/ban-typesto@typescript-eslint/no-unsafe-function-typeis the correct replacement for typescript-eslint v8. The TODO comment indicates awareness that a stricter type could be used, though this may be constrained by the @dnd-kit library's API.apps/admin-x-framework/test/unit/hooks/use-form.test.ts (1)
206-208: LGTM - proper ESLint compliance fix.Removing the unused error variable from these catch blocks is appropriate since the error is not referenced and these blocks only handle expected test exceptions.
Also applies to: 233-235
apps/activitypub/src/views/preferences/components/bluesky-sharing.tsx (1)
55-58: LGTM - ESLint compliance with proper error handling.The error variable was unused, and user-facing error handling via the toast message is preserved.
apps/activitypub/src/components/modals/new-note-modal.tsx (1)
96-104: LGTM - consistent with centralized error handling pattern.The unused error variable is removed while preserving the error handling flow. Based on learnings, error handling for ActivityPub mutations is centralized at the hook level in
use-activity-pub-queries.ts, making the error binding unnecessary here.e2e/package.json (1)
32-32: Version 8.49.0 is current and secure.The package version 8.49.0 is the latest release, with no direct vulnerabilities found in Snyk's vulnerability database. The minor version bump from 8.46.1 aligns with the PR objective to resolve dependency conflicts.
React E2E Tests FailedTo view the Playwright test report locally, run: REPORT_DIR=$(mktemp -d) && gh run download 20262880714 -n playwright-report-react -D "$REPORT_DIR" && npx playwright show-report "$REPORT_DIR" |
1 similar comment
React E2E Tests FailedTo view the Playwright test report locally, run: REPORT_DIR=$(mktemp -d) && gh run download 20262880714 -n playwright-report-react -D "$REPORT_DIR" && npx playwright show-report "$REPORT_DIR" |
b26ccd4 to
1d9b041
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (2)
apps/comments-ui/src/typings.d.ts (1)
2-2: Previous review suggestion still applies.The ESLint suppression is valid for this declaration file syntax. However, as noted in the previous review, consider implementing a config-level override for
*.d.tsfiles to eliminate the need for individual suppressions across multiple declaration files.apps/shade/src/typings.d.ts (1)
2-3: Use ES6import typesyntax instead of suppressing the linter.A previous review comment already suggested replacing this CommonJS-style import with modern ES6 syntax. Since this PR is specifically updating ESLint to enforce stricter rules, now is the ideal time to fix the underlying issue rather than suppressing it.
As per coding guidelines, follow ESLint rules. Apply this diff:
- // eslint-disable-next-line @typescript-eslint/no-require-imports - import React = require('react'); + import type * as React from 'react';
🧹 Nitpick comments (11)
apps/comments-ui/src/components/popup-box.tsx (1)
6-8: Address the TODO: use proper typing for components with no props.The ESLint directive update is correct for the migration. However, the TODO comment indicates this type definition needs attention. In TypeScript,
{}doesn't mean "no props"—it means "any non-nullish value."Consider one of these alternatives:
-// TODO: figure out what this type should be? -// eslint-disable-next-line @typescript-eslint/no-empty-object-type -type Props = {}; - -const PopupBox: React.FC<Props> = () => { +const PopupBox: React.FC = () => {Or, if you prefer explicit typing:
-// TODO: figure out what this type should be? -// eslint-disable-next-line @typescript-eslint/no-empty-object-type -type Props = {}; +type Props = Record<string, never>; const PopupBox: React.FC<Props> = () => {Do you want me to open an issue to track removing this TODO and fixing the Props type?
apps/admin-x-framework/src/api/config.ts (1)
6-7: Consider usingtypeinstead ofinterfaceto avoid the ESLint suppression.The
interfacewith an empty body triggers theno-empty-object-typerule. SinceJSONArrayis a simple recursive type alias with no need for declaration merging, usingtypeis more idiomatic and eliminates the suppression:-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface JSONArray extends Array<string|number|boolean|Date|JSONObject|JSONValue> {} +type JSONArray = Array<string|number|boolean|Date|JSONObject|JSONValue>;TypeScript handles circular references equally well with both approaches, but
typeis generally preferred for simple aliases in modern TypeScript.apps/posts/src/views/PostAnalytics/Growth/growth.tsx (1)
16-17: Consider using a type alias instead of an empty interface.The empty
postAnalyticsPropsinterface could be replaced with a type alias to avoid the ESLint suppression. Additionally, follow PascalCase convention for type names.Apply this diff:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} +type PostAnalyticsProps = Record<string, never>;And update the component signature:
-const Growth: React.FC<postAnalyticsProps> = () => { +const Growth: React.FC<PostAnalyticsProps> = () => {apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx (1)
17-18: Consider using a type alias instead of an empty interface.The empty
postAnalyticsPropsinterface could be replaced with a type alias to avoid the ESLint suppression. Additionally, follow PascalCase convention for type names.Apply this diff:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} +type PostAnalyticsProps = Record<string, never>;And update the component signature:
-const Newsletter: React.FC<postAnalyticsProps> = () => { +const Newsletter: React.FC<PostAnalyticsProps> = () => {apps/posts/src/views/PostAnalytics/Web/web.tsx (1)
26-27: Consider using a type alias instead of an empty interface.The empty
postAnalyticsPropsinterface could be replaced with a type alias to avoid the ESLint suppression. Additionally, follow PascalCase convention for type names.Apply this diff:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} +type PostAnalyticsProps = Record<string, never>;And update the component signature:
-const Web: React.FC<postAnalyticsProps> = () => { +const Web: React.FC<PostAnalyticsProps> = () => {apps/shade/src/components/layout/header.tsx (1)
11-12: Consider using type aliases for interfaces that don't add properties.The six props interfaces (
HeaderAboveProps,HeaderTitleProps,HeaderMetaProps,HeaderActionGroupProps,HeaderActionsProps,HeaderNavProps) extendPropsWithChildrenAndClassNamewithout adding additional properties. Type aliases would be cleaner and avoid ESLint suppressions.Apply this diff:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface HeaderAboveProps extends PropsWithChildrenAndClassName {} +type HeaderAboveProps = PropsWithChildrenAndClassName; -// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface HeaderTitleProps extends PropsWithChildrenAndClassName {} +type HeaderTitleProps = PropsWithChildrenAndClassName; -// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface HeaderMetaProps extends PropsWithChildrenAndClassName {} +type HeaderMetaProps = PropsWithChildrenAndClassName; -// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface HeaderActionGroupProps extends PropsWithChildrenAndClassName {} +type HeaderActionGroupProps = PropsWithChildrenAndClassName; -// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface HeaderActionsProps extends PropsWithChildrenAndClassName {} +type HeaderActionsProps = PropsWithChildrenAndClassName; -// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface HeaderNavProps extends PropsWithChildrenAndClassName {} +type HeaderNavProps = PropsWithChildrenAndClassName;Also applies to: 24-25, 40-41, 53-54, 66-67, 79-80
apps/activitypub/src/views/profile/profile.tsx (1)
13-14: Consider refactoring to a type alias.The ESLint suppression resolves the immediate linting issue, but as Biome suggests, an empty interface is semantically equivalent to
{}. If no props are expected, consider using a type alias instead:type ProfileProps = Record<string, never>;Or simply omit the props type if the component truly requires no props.
apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx (1)
39-40: ESLint suppressions are justified.The suppressions are necessary for the side-effect expressions (
!!item.errors.X && clearError?.('X')). While unconventional, this pattern is functionally correct.Optionally, consider refactoring to if statements for better readability:
-// eslint-disable-next-line @typescript-eslint/no-unused-expressions -!!item.errors.label && clearError?.('label'); +if (item.errors.label) { + clearError?.('label'); +}This avoids the need for ESLint suppressions and makes the intent clearer.
Also applies to: 67-68
apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx (1)
87-87: Bare catch is appropriate, but consider logging for debugging.The error binding was unused, so the bare catch block is correct. However, for production debugging, consider logging the error even when showing a generic message to users.
Optionally add error logging:
-} catch { +} catch (error) { + console.error('Failed to save recommendation:', error); // eslint-disable-line no-console showToast({ghost/core/core/server/services/recommendations/service/RecommendationMetadataService.ts (1)
64-64: Bare catch blocks are appropriate, but consider logging for observability.The error bindings were unused, so the bare catch blocks are correct. The service gracefully handles failures by returning
undefinedornull.For server-side observability, consider adding error logging in the
#fetchJSONmethod:} catch { + // Log network/DNS errors for observability + // (avoid logging in #castUrl as URL parse errors are expected) return undefined; }This helps diagnose issues in production without changing the public API.
Also applies to: 68-68, 79-79
apps/comments-ui/src/actions.ts (1)
262-262: Bare catch blocks are appropriate for optimistic UI pattern.The error bindings were unused—the catch blocks only revert the optimistic state changes. The bare catch syntax is correct.
For debugging failed like/unlike actions, consider logging errors:
-} catch { +} catch (error) { + console.error('Failed to like comment:', error); // eslint-disable-line no-console dispatchAction('updateCommentLikeState', {id: comment.id, liked: false}); }This helps diagnose API failures while maintaining the same user experience.
Also applies to: 273-273
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (56)
apps/activitypub/src/api/activitypub.ts(1 hunks)apps/activitypub/src/components/modals/new-note-modal.tsx(1 hunks)apps/activitypub/src/hooks/use-activity-pub-queries.ts(3 hunks)apps/activitypub/src/utils/get-username.ts(1 hunks)apps/activitypub/src/utils/image.ts(1 hunks)apps/activitypub/src/views/preferences/components/bluesky-sharing.tsx(1 hunks)apps/activitypub/src/views/preferences/components/profile.tsx(1 hunks)apps/activitypub/src/views/profile/profile.tsx(1 hunks)apps/admin-x-design-system/src/global/sortable-list.tsx(1 hunks)apps/admin-x-design-system/src/typings.d.ts(1 hunks)apps/admin-x-design-system/src/utils/format-url.ts(1 hunks)apps/admin-x-framework/src/api/config.ts(1 hunks)apps/admin-x-framework/src/api/recommendations.ts(1 hunks)apps/admin-x-framework/src/test/acceptance.ts(1 hunks)apps/admin-x-framework/src/test/test-utils.tsx(1 hunks)apps/admin-x-framework/test/unit/hooks/use-form.test.ts(2 hunks)apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/incoming-recommendation-list.tsx(1 hunks)apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx(2 hunks)apps/admin-x-settings/src/typings.d.ts(1 hunks)apps/admin-x-settings/src/utils/link-to-github-releases.ts(2 hunks)apps/admin-x-settings/src/utils/url.ts(1 hunks)apps/admin/package.json(1 hunks)apps/comments-ui/src/actions.ts(2 hunks)apps/comments-ui/src/app-context.ts(1 hunks)apps/comments-ui/src/components/content/forms/form.tsx(1 hunks)apps/comments-ui/src/components/popup-box.tsx(1 hunks)apps/comments-ui/src/typings.d.ts(1 hunks)apps/comments-ui/src/utils/admin-api.ts(1 hunks)apps/comments-ui/src/utils/api.ts(1 hunks)apps/posts/src/hooks/use-post-success-modal.ts(1 hunks)apps/posts/src/utils/link-helpers.ts(1 hunks)apps/posts/src/views/PostAnalytics/Growth/growth.tsx(1 hunks)apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx(1 hunks)apps/posts/src/views/PostAnalytics/Web/web.tsx(1 hunks)apps/shade/src/components/features/color-picker/color-picker.tsx(1 hunks)apps/shade/src/components/layout/header.tsx(7 hunks)apps/shade/src/components/layout/heading.tsx(1 hunks)apps/shade/src/components/layout/page.tsx(1 hunks)apps/shade/src/components/layout/view-header.tsx(2 hunks)apps/shade/src/components/ui/card.tsx(1 hunks)apps/shade/src/lib/utils.ts(1 hunks)apps/shade/src/typings.d.ts(1 hunks)apps/signup-form/src/components/pages/form-page.tsx(1 hunks)apps/signup-form/src/typings.d.ts(1 hunks)apps/stats/src/hooks/use-feature-flag.tsx(1 hunks)apps/stats/src/types/svg.d.ts(1 hunks)apps/stats/src/utils/url-helpers.ts(5 hunks)apps/stats/test/utils/tinybird-helpers.ts(1 hunks)e2e/package.json(1 hunks)ghost/core/core/server/services/recommendations/service/RecommendationMetadataService.ts(2 hunks)ghost/core/core/server/services/recommendations/service/UnsafeData.ts(1 hunks)package.json(2 hunks)
✅ Files skipped from review due to trivial changes (1)
- apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx
🚧 Files skipped from review as they are similar to previous changes (28)
- apps/shade/src/lib/utils.ts
- apps/comments-ui/src/utils/api.ts
- apps/posts/src/utils/link-helpers.ts
- apps/stats/src/utils/url-helpers.ts
- apps/signup-form/src/components/pages/form-page.tsx
- apps/activitypub/src/hooks/use-activity-pub-queries.ts
- apps/activitypub/src/api/activitypub.ts
- apps/comments-ui/src/utils/admin-api.ts
- apps/admin-x-framework/src/api/recommendations.ts
- ghost/core/core/server/services/recommendations/service/UnsafeData.ts
- apps/admin-x-settings/src/utils/link-to-github-releases.ts
- apps/shade/src/components/ui/card.tsx
- apps/admin-x-design-system/src/typings.d.ts
- apps/admin-x-framework/test/unit/hooks/use-form.test.ts
- apps/activitypub/src/views/preferences/components/profile.tsx
- apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx
- e2e/package.json
- apps/admin-x-settings/src/components/settings/growth/recommendations/incoming-recommendation-list.tsx
- apps/stats/src/types/svg.d.ts
- apps/activitypub/src/utils/image.ts
- apps/shade/src/components/layout/page.tsx
- apps/shade/src/components/layout/view-header.tsx
- apps/activitypub/src/utils/get-username.ts
- apps/shade/src/components/layout/heading.tsx
- apps/admin-x-settings/src/utils/url.ts
- apps/admin/package.json
- apps/shade/src/components/features/color-picker/color-picker.tsx
- apps/signup-form/src/typings.d.ts
🧰 Additional context used
📓 Path-based instructions (4)
apps/shade/src/components/layout/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
Reusable layout containers (Page, Heading, Header, ViewHeader, ErrorPage) should be placed in
src/components/layout/*
Files:
apps/shade/src/components/layout/header.tsx
apps/shade/src/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/src/components/**/*.{ts,tsx}: UsePascalCasefor component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Always forward and mergeclassNameprop withcn(...)utility function
Use CVA (Class Variance Authority) for component variants when useful instead of heavy prop configuration
Prefer compound subcomponents (e.g.,Header.Title,Header.Meta,Header.Actions) for multi-region components instead of many props
Use Tailwind CSS scoped via.shadeclass; dark mode uses.dark
Files:
apps/shade/src/components/layout/header.tsx
apps/shade/src/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/src/**/*.{ts,tsx,js}: UsecamelCasefor function and variable names
Use the@alias for internal imports (e.g.,@/lib/utils)
Files:
apps/shade/src/components/layout/header.tsxapps/shade/src/typings.d.ts
apps/shade/{src,test}/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/{src,test}/**/*.{ts,tsx,js}: Runyarn lintafter making changes to fix any ESLint errors and warnings before committing
Follow ESLint andtailwindcss/*plugin rules when writing styles
Files:
apps/shade/src/components/layout/header.tsxapps/shade/src/typings.d.ts
🧠 Learnings (33)
📓 Common learnings
Learnt from: cmraible
Repo: TryGhost/Ghost PR: 24658
File: ghost/admin/package.json:3-3
Timestamp: 2025-08-12T18:33:15.524Z
Learning: In Ghost's admin package.json, third-party packages like ember-cli-postcss, ember-exam, and ember-power-select have their own independent versioning schemes that are unrelated to Ghost's version numbers. Version number coincidences between Ghost versions and these packages should not trigger update suggestions.
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Run `yarn lint` after making changes to fix any ESLint errors and warnings before committing
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Prefer compound subcomponents (e.g., `Header.Title`, `Header.Meta`, `Header.Actions`) for multi-region components instead of many props
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Follow ESLint and `tailwindcss/*` plugin rules when writing styles
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use `PascalCase` for component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/**/*.{ts,tsx,js} : Use the `@` alias for internal imports (e.g., `@/lib/utils`)
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use Tailwind CSS scoped via `.shade` class; dark mode uses `.dark`
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use CVA (Class Variance Authority) for component variants when useful instead of heavy prop configuration
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/**/*.{ts,tsx,js} : Use `camelCase` for function and variable names
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/layout/**/*.{ts,tsx} : Reusable layout containers (Page, Heading, Header, ViewHeader, ErrorPage) should be placed in `src/components/layout/*`
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/lib/utils.ts : Shared utilities (class merging, formatting, chart helpers) should be centralized in `src/lib/utils.ts`
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Always follow ADRs in `../adr/` folder (ADR-0001: AAA pattern, ADR-0002: Page Objects)
Applied to files:
apps/admin-x-framework/src/test/acceptance.ts
📚 Learning: 2025-10-09T15:31:06.587Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 25118
File: apps/portal/src/actions.js:160-173
Timestamp: 2025-10-09T15:31:06.587Z
Learning: When reviewing PRs that introduce feature-flagged changes (e.g., `labs?.membersSigninOTCAlpha`), avoid suggesting modifications to non-flagged code paths unless they're directly related to the PR's objectives. Keep the scope focused on the feature-flag-specific changes only.
Applied to files:
apps/admin-x-framework/src/test/acceptance.ts
📚 Learning: 2025-11-06T05:35:41.162Z
Learnt from: danielraffel
Repo: TryGhost/Ghost PR: 25366
File: apps/admin/src/layout/app-sidebar/NavHeader.tsx:13-23
Timestamp: 2025-11-06T05:35:41.162Z
Learning: In apps/admin/src/layout/app-sidebar/NavHeader.tsx, the React component dispatches a synthetic KeyboardEvent to trigger the Ember keymaster.js search modal shortcut. This approach is known to have cross-browser reliability issues but was deferred for architectural refactoring in a separate PR. The recommended fix is to expose a global function or custom DOM event from the Ember app instead of relying on synthetic keyboard events with keymaster.js.
Applied to files:
apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.{ts,tsx} : Prefer less comments and give things clear names
Applied to files:
apps/comments-ui/src/app-context.tsapps/comments-ui/src/typings.d.tsapps/comments-ui/src/actions.tsapps/shade/src/typings.d.tsapps/admin-x-settings/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use CVA (Class Variance Authority) for component variants when useful instead of heavy prop configuration
Applied to files:
apps/comments-ui/src/app-context.tsapps/comments-ui/src/typings.d.tsapps/shade/src/components/layout/header.tsxapps/shade/src/typings.d.tsapps/comments-ui/src/components/popup-box.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/**/*.{ts,tsx,js} : Use the `@` alias for internal imports (e.g., `@/lib/utils`)
Applied to files:
apps/comments-ui/src/typings.d.tsapps/shade/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/index.ts : Place new UI components under `src/components/ui` and export them from `src/index.ts`
Applied to files:
apps/comments-ui/src/typings.d.tsapps/shade/src/components/layout/header.tsxapps/shade/src/typings.d.tsapps/comments-ui/src/components/popup-box.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Follow ESLint and `tailwindcss/*` plugin rules when writing styles
Applied to files:
apps/comments-ui/src/typings.d.tsapps/shade/src/typings.d.ts
📚 Learning: 2025-08-01T12:44:07.467Z
Learnt from: niranjan-uma-shankar
Repo: TryGhost/Ghost PR: 24557
File: apps/admin-x-settings/src/components/settings/general/TimeZone.tsx:7-7
Timestamp: 2025-08-01T12:44:07.467Z
Learning: In Ghost development, PRs may depend on unpublished changes from SDK packages. When this occurs, TypeScript compilation errors for missing exports are expected and documented in the PR description until the dependency packages are published and updated. This is normal workflow for cross-repository feature development.
Applied to files:
apps/comments-ui/src/typings.d.tspackage.json
📚 Learning: 2025-03-13T09:02:50.102Z
Learnt from: mike182uk
Repo: TryGhost/Ghost PR: 22471
File: apps/admin-x-activitypub/src/views/Feed/components/NewPostModal.tsx:29-34
Timestamp: 2025-03-13T09:02:50.102Z
Learning: In the Ghost ActivityPub module, error handling for mutations is handled at the hook level (in use-activity-pub-queries.ts) rather than in individual components. This allows for centralized error handling across the application.
Applied to files:
apps/activitypub/src/components/modals/new-note-modal.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Prefer compound subcomponents (e.g., `Header.Title`, `Header.Meta`, `Header.Actions`) for multi-region components instead of many props
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/layout/**/*.{ts,tsx} : Reusable layout containers (Page, Heading, Header, ViewHeader, ErrorPage) should be placed in `src/components/layout/*`
Applied to files:
apps/shade/src/components/layout/header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use `PascalCase` for component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use Tailwind CSS scoped via `.shade` class; dark mode uses `.dark`
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/typings.d.ts
📚 Learning: 2025-11-25T11:58:51.652Z
Learnt from: ibalosh
Repo: TryGhost/Ghost PR: 25525
File: apps/shade/src/shade-app.tsx:4-4
Timestamp: 2025-11-25T11:58:51.652Z
Learning: In apps/shade, the app wrapper file should be named `src/shade-app.tsx` (kebab-case) while the component itself is exported as `ShadeApp` (PascalCase). Context providers should be placed in `src/providers/*` using kebab-case filenames.
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/features/**/*.{ts,tsx} : Higher-level, opinionated components (e.g., PostShareModal, SourceTabs) should be placed in `src/components/features/*`
Applied to files:
apps/shade/src/components/layout/header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/ui/**/*.{ts,tsx} : Atomic UI components should be placed in `src/components/ui/*` and each component must have a corresponding `*.stories.tsx` file next to it for Storybook documentation
Applied to files:
apps/shade/src/components/layout/header.tsxapps/shade/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/lib/utils.ts : Shared utilities (class merging, formatting, chart helpers) should be centralized in `src/lib/utils.ts`
Applied to files:
apps/shade/src/components/layout/header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Always forward and merge `className` prop with `cn(...)` utility function
Applied to files:
apps/shade/src/components/layout/header.tsx
📚 Learning: 2025-12-09T12:37:23.267Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 25501
File: apps/shade/src/hooks/use-mobile.tsx:5-10
Timestamp: 2025-12-09T12:37:23.267Z
Learning: In the Ghost repository, this guideline applies to the shade admin app. For files under apps/shade that access browser globals (navigator, window, document) at module load time, SSR is not used, so typeof guards are not required. Reviewers should verify that such files remain client-side only and that no SSR context is introduced; apply this understanding to similarly structured files under apps/shade.
Applied to files:
apps/shade/src/components/layout/header.tsx
📚 Learning: 2025-11-25T14:28:50.351Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T14:28:50.351Z
Learning: Analytics using Tinybird should reference scripts in `ghost/core/core/server/data/tinybird/scripts/` and datafiles in `ghost/core/core/server/data/tinybird/`
Applied to files:
apps/stats/test/utils/tinybird-helpers.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Run `yarn lint` after making changes to fix any ESLint errors and warnings before committing
Applied to files:
apps/shade/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/hooks/**/*.{ts,tsx} : Custom React hooks should be placed in `src/hooks/*`
Applied to files:
apps/shade/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/**/*.{ts,tsx,js} : Use `camelCase` for function and variable names
Applied to files:
apps/shade/src/typings.d.ts
📚 Learning: 2025-11-05T16:42:12.989Z
Learnt from: rob-ghost
Repo: TryGhost/Ghost PR: 25356
File: apps/admin/test-utils/fixtures/query-client.tsx:17-35
Timestamp: 2025-11-05T16:42:12.989Z
Learning: In apps/admin/test-utils/fixtures/query-client.tsx, the createTestQueryClient function is intentionally duplicated from admin-x-framework to reduce external dependencies in the admin app's test utilities.
Applied to files:
apps/admin-x-framework/src/test/test-utils.tsx
📚 Learning: 2025-05-27T15:35:31.779Z
Learnt from: 9larsons
Repo: TryGhost/Ghost PR: 23550
File: apps/admin-x-framework/test/utils/mockFetch.ts:9-9
Timestamp: 2025-05-27T15:35:31.779Z
Learning: The codebase is currently using Vitest 0.34.3, which has limited type definitions. Modern Vitest types like MockedFunction are not available in this version, so `any` types are used as a temporary workaround in test utilities.
Applied to files:
apps/admin-x-framework/src/test/test-utils.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Use the existing setup (Vitest + Testing Library + jsdom) when adding tests
Applied to files:
apps/admin-x-framework/src/test/test-utils.tsx
📚 Learning: 2025-09-02T13:06:50.918Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 24779
File: ghost/core/test/unit/server/services/members/members-api/controllers/RouterController.test.js:1388-1392
Timestamp: 2025-09-02T13:06:50.918Z
Learning: In Ghost's test files, sinon.restore() in afterEach hooks handles cleanup of all sinon modifications including fake timers, spies, and stubs, so explicit restoration of individual sinon features like clock.restore() is typically not needed when there's a top-level sinon.restore() call.
Applied to files:
apps/admin-x-framework/src/test/test-utils.tsx
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Never use hard-coded waits like `waitForTimeout()`
Applied to files:
apps/admin-x-framework/src/test/test-utils.tsx
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Use Playwright's auto-waiting capabilities and run tests multiple times to ensure stability
Applied to files:
apps/admin-x-framework/src/test/test-utils.tsx
📚 Learning: 2025-08-12T18:33:15.524Z
Learnt from: cmraible
Repo: TryGhost/Ghost PR: 24658
File: ghost/admin/package.json:3-3
Timestamp: 2025-08-12T18:33:15.524Z
Learning: In Ghost's admin package.json, third-party packages like ember-cli-postcss, ember-exam, and ember-power-select have their own independent versioning schemes that are unrelated to Ghost's version numbers. Version number coincidences between Ghost versions and these packages should not trigger update suggestions.
Applied to files:
package.json
📚 Learning: 2025-08-26T16:47:28.150Z
Learnt from: troyciesco
Repo: TryGhost/Ghost PR: 24749
File: ghost/core/core/server/services/members/SingleUseTokenProvider.js:3-5
Timestamp: 2025-08-26T16:47:28.150Z
Learning: When checking for dependencies in Ghost project, ensure to look directly in the specific package.json files rather than relying only on automated searches, as otplib dependency exists at line 204 in ghost/core/package.json version "12.0.1"
Applied to files:
package.json
🪛 Biome (2.1.2)
apps/posts/src/views/PostAnalytics/Growth/growth.tsx
[error] 16-17: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/posts/src/views/PostAnalytics/Web/web.tsx
[error] 26-27: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/activitypub/src/views/profile/profile.tsx
[error] 13-14: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx
[error] 17-18: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
🔇 Additional comments (14)
apps/admin-x-settings/src/typings.d.ts (1)
5-5: LGTM! Targeted suppression for declaration file syntax.The suppression is appropriately scoped and necessary for the legacy TypeScript import syntax used in this SVG module declaration. This is a standard pattern in
.d.tsfiles.apps/shade/src/components/layout/header.tsx (1)
92-122: Excellent compound component architecture!The Header component implementation follows best practices:
- Uses compound subcomponents (
Header.Title,Header.Meta,Header.Actions) as recommended in the coding guidelines- Implements CVA for variant management
- Properly forwards and merges
classNamewithcn()utility- Uses grid-area attributes for flexible layout control
Based on learnings and coding guidelines.
apps/activitypub/src/components/modals/new-note-modal.tsx (1)
96-104: LGTM! Bare catch block is appropriate here.The error variable was unused in the catch block, so removing the binding aligns with modern ESLint best practices. The error handling behavior (calling
onReplyErrorand managing loading state) is preserved.apps/admin-x-design-system/src/global/sortable-list.tsx (1)
16-18: LGTM! ESLint directive updated for TypeScript-ESLint v8.The rule name change from
ban-typestono-unsafe-function-typereflects the update to TypeScript-ESLint v8. The TODO comment correctly notes this is known tech debt for future refinement.apps/activitypub/src/views/preferences/components/bluesky-sharing.tsx (1)
53-59: LGTM! Appropriate bare catch block.The error variable was not used in the catch block. The error handling (toast notification and loading state management) functions correctly without the error binding.
apps/stats/test/utils/tinybird-helpers.ts (1)
84-89: LGTM! Bare catch is appropriate for intentionally ignored errors.The error was already marked as unused with the underscore prefix. The bare catch syntax is cleaner and the fallback to
bodyTexton JSON parse failure is preserved.apps/comments-ui/src/app-context.ts (1)
114-121: LGTM! Bare catch with appropriate fallback.The error variable was unused, and the fallback behavior (returning an empty object) is preserved. This is a clean simplification.
apps/admin-x-framework/src/test/test-utils.tsx (1)
238-241: LGTM! ESLint directive correctly updated.The rule name changed from
no-var-requirestono-require-importsin TypeScript-ESLint v8. The dynamic require is appropriate for this test utility context.apps/posts/src/hooks/use-post-success-modal.ts (1)
156-169: LGTM! Bare catch appropriate for silently handling localStorage errors.The error was intentionally ignored as indicated by the comment. The bare catch syntax is cleaner for this use case where localStorage failures should be silently handled.
apps/stats/src/hooks/use-feature-flag.tsx (1)
22-22: LGTM!The transition to a bare catch block is appropriate here. The error was already being ignored, and the fallback behavior remains correct.
apps/admin-x-design-system/src/utils/format-url.ts (1)
48-48: LGTM!The bare catch block is appropriate for URL parsing errors. The fallback behavior correctly preserves the original URL when parsing fails.
apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx (1)
29-29: LGTM!The bare catch block is appropriate for URL validation. The error message is set regardless of the specific parse error, making the error binding unnecessary.
apps/admin-x-framework/src/test/acceptance.ts (1)
130-130: LGTM!The bare catch block is appropriate in this test utility. The original error is re-thrown as a more descriptive error message, so the caught error binding was unused.
package.json (1)
81-83: Resolution pinning looks correct.Pinning all three @typescript-eslint packages to 8.49.0 ensures compatibility across the monorepo. These versions are current, published recently as the latest releases, and no security vulnerabilities are present. This is the correct approach when resolving peer dependency conflicts with the updated ghost plugin.
| } catch { | ||
| setProgress('error'); | ||
| return; | ||
| } |
There was a problem hiding this comment.
Add error logging for observability.
The bare catch block swallows the error without logging, making it impossible to debug form submission failures in production. While the UI correctly shows an error state, developers need visibility into why submissions fail (network issues, validation errors, server errors, etc.).
Consider adding at least console error logging:
- } catch {
+ } catch (error) {
+ console.error('Form submission failed:', error);
setProgress('error');
return;
}📝 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.
| } catch { | |
| setProgress('error'); | |
| return; | |
| } | |
| } catch (error) { | |
| console.error('Form submission failed:', error); | |
| setProgress('error'); | |
| return; | |
| } |
🤖 Prompt for AI Agents
In apps/comments-ui/src/components/content/forms/form.tsx around lines 78 to 81,
the catch block suppresses errors; update it to accept the caught error (e) and
log it for observability before setting progress to 'error' and returning. Use a
clear, contextual log entry (e.g., console.error or logger.error) that includes
the error object and a short message indicating form submission failure so
developers can see stack/response details in production logs.
1d9b041 to
b586a7f
Compare
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (4)
apps/admin-x-design-system/src/typings.d.ts (1)
2-3: Prefer ES6import typesyntax over suppressing the linter.Instead of suppressing the
@typescript-eslint/no-require-importsrule, refactor to use modern ES6 import syntax. Since React is only used for type references here,import typeis appropriate.Apply this diff:
- // eslint-disable-next-line @typescript-eslint/no-require-imports - import React = require('react'); + import type * as React from 'react';package.json (1)
96-96: Verify that version 3.4.4 exists on npm.The version 3.4.4 may not be available on the npm registry. This will cause installation failures if the version doesn't exist.
Run the following script to verify:
#!/bin/bash # Check available versions of eslint-plugin-ghost npm view eslint-plugin-ghost versions --json | jq -r '.[]' | grep -E '^3\.4\.'apps/shade/src/typings.d.ts (1)
2-3: Prefer ES6import typesyntax over suppressing the linter.Instead of suppressing the
@typescript-eslint/no-require-importsrule, refactor to use modern ES6 import syntax. Since React is only used for type references here,import typeis appropriate.As per coding guidelines, run
yarn lintafter making changes to ensure ESLint compliance.Apply this diff:
- // eslint-disable-next-line @typescript-eslint/no-require-imports - import React = require('react'); + import type * as React from 'react';apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx (1)
782-783: Remove errant backticks instead of suppressing ESLint.The line has two backticks (
``) at the end that create an empty template literal expression, which triggers theno-unused-expressionsrule. Rather than suppressing the rule, remove the backticks.Apply this diff:
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions - const {meta: {sent_email_verification: [emailToVerify] = []} = {}} = await editNewsletter(formState); ``; + const {meta: {sent_email_verification: [emailToVerify] = []} = {}} = await editNewsletter(formState);
🧹 Nitpick comments (13)
apps/activitypub/src/utils/image.ts (1)
25-28: LGTM! Bare catch is appropriate here.The removal of the unused error binding is correct and aligns with ESLint best practices. The fallback behavior is preserved.
For improved observability during debugging, consider logging the error before returning the fallback:
- } catch { + } catch (error) { + console.warn('Failed to convert image URL to data URL:', error); // Return original URL as fallback if conversion fails return url; }However, this is entirely optional and depends on your observability strategy.
apps/activitypub/src/views/profile/profile.tsx (1)
13-14: Consider converting to a type alias to eliminate the ESLint suppression.Both Biome and TypeScript ESLint flag empty interfaces. Since
ProfilePropshas no properties, a type alias is more appropriate and removes the need for the suppression comment.Apply this diff:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface ProfileProps {} +type ProfileProps = Record<string, never>;Alternatively, if the interface is a placeholder for future props, you could use:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface ProfileProps {} +// Placeholder for future props +type ProfileProps = Record<string, never>;apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx (1)
112-112: LGTM! Clean lint fix.Removing the unused error binding is correct and aligns with the ESLint upgrade. The error was not being used in the catch block, so this change makes that explicit.
Optional suggestion: Consider logging the error to the console for debugging purposes, even though it's not displayed to users:
- } catch { + } catch (error) { + // eslint-disable-next-line no-console + console.error('Failed to add recommendation:', error); showToast({This would help with debugging in development without changing the user experience, though it's outside the scope of this ESLint upgrade PR.
apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx (1)
39-40: Consider refactoring to explicit if statements.The ESLint suppressions silence warnings about unused expressions in the
condition && sideEffect()pattern. While this pattern is idiomatic, refactoring to explicit if statements would be clearer and eliminate the need for suppression comments.Apply this diff to refactor both occurrences:
if (e.key === 'Enter') { e.preventDefault(); addItem?.(); } - // eslint-disable-next-line @typescript-eslint/no-unused-expressions - !!item.errors.label && clearError?.('label'); + if (item.errors.label) { + clearError?.('label'); + } }}if (e.key === 'Enter') { e.preventDefault(); const urls = formatUrl((e.target as HTMLInputElement).value, baseUrl, true); updateItem?.({url: urls.save || ''}); addItem?.(); } - // eslint-disable-next-line @typescript-eslint/no-unused-expressions - !!item.errors.url && clearError?.('url'); + if (item.errors.url) { + clearError?.('url'); + } }}Also applies to: 67-68
apps/admin-x-framework/src/test/test-utils.tsx (1)
239-240: ESLint directive update looks good.The updated rule name correctly aligns with the newer TypeScript ESLint plugin.
Optional: Consider modernizing to dynamic import.
The
require()could be replaced with a dynamicimport()for better TypeScript alignment:- // eslint-disable-next-line @typescript-eslint/no-require-imports - const vitest = require('vitest'); + const vitest = await import('vitest');Note: This would require making
mockTimers()async or restructuring the function. Given the current approach works and the PR focuses on ESLint updates, this can be deferred.ghost/core/core/server/services/recommendations/service/RecommendationMetadataService.ts (1)
47-70: Consider adding error logging for observability.The removal of unused error bindings is correct and aligns with the ESLint update. However, the comment on lines 45-46 mentions catching DNS errors specifically, and these errors are now silently swallowed without any logging.
Consider adding basic error logging to aid debugging in production:
- } catch { + } catch (err) { + // Log for observability, but don't throw to avoid HTTP 500 + // (covers DNS errors and other request failures) return undefined; }If logging infrastructure is available, capturing these errors would make troubleshooting recommendation fetching issues much easier.
apps/posts/src/views/PostAnalytics/Web/web.tsx (1)
26-27: Consider using a type alias instead of suppressing the linter.Rather than suppressing the
no-empty-object-typerule, you can use a more idiomatic approach:Option 1 (simplest): Remove the interface entirely and use
React.FCwithout explicit props:-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} - -const Web: React.FC<postAnalyticsProps> = () => { +const Web: React.FC = () => {Option 2: Use a type alias with PascalCase naming:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} +type PostAnalyticsProps = Record<string, never>; -const Web: React.FC<postAnalyticsProps> = () => { +const Web: React.FC<PostAnalyticsProps> = () => {apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx (1)
17-18: Consider using a type alias instead of suppressing the linter.Rather than suppressing the
no-empty-object-typerule, you can use a more idiomatic approach:Option 1 (simplest): Remove the interface entirely and use
React.FCwithout explicit props:-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} - -const Newsletter: React.FC<postAnalyticsProps> = () => { +const Newsletter: React.FC = () => {Option 2: Use a type alias with PascalCase naming:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} +type PostAnalyticsProps = Record<string, never>; -const Newsletter: React.FC<postAnalyticsProps> = () => { +const Newsletter: React.FC<PostAnalyticsProps> = () => {apps/posts/src/views/PostAnalytics/Growth/growth.tsx (1)
16-17: Consider using a type alias instead of suppressing the linter.Rather than suppressing the
no-empty-object-typerule, you can use a more idiomatic approach:Option 1 (simplest): Remove the interface entirely and use
React.FCwithout explicit props:-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} - -const Growth: React.FC<postAnalyticsProps> = () => { +const Growth: React.FC = () => {Option 2: Use a type alias with PascalCase naming:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface postAnalyticsProps {} +type PostAnalyticsProps = Record<string, never>; -const Growth: React.FC<postAnalyticsProps> = () => { +const Growth: React.FC<PostAnalyticsProps> = () => {apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx (1)
87-87: LGTM: Unused error binding removed for ESLint compliance.The error variable was not used in the catch block, so removing it aligns with the ESLint update objectives.
Optional: Consider logging the error for debugging.
While the generic user-facing message is appropriate, consider at least logging the error or passing it to
handleErrorfor debugging purposes, similar to how the delete operation handles errors (line 60). This would preserve error details for troubleshooting without exposing them to users.- } catch { + } catch (error) { showToast({ title: 'Something went wrong', type: 'error', message: 'Please try again later.' }); + handleError(error, {withToast: false}); }apps/shade/src/components/layout/header.tsx (1)
11-90: Consider using type aliases to avoid ESLint suppressions.The six subcomponent interfaces extend
PropsWithChildrenAndClassNamewithout adding properties, requiring ESLint suppression comments. Usingtypealiases instead ofinterfacewould accomplish the same goal without triggering theno-empty-object-typerule.Apply this pattern to eliminate the suppression comments:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface HeaderAboveProps extends PropsWithChildrenAndClassName {} +type HeaderAboveProps = PropsWithChildrenAndClassName;Repeat for
HeaderTitleProps,HeaderMetaProps,HeaderActionGroupProps,HeaderActionsProps, andHeaderNavProps.apps/shade/src/components/ui/card.tsx (2)
219-220: Consider using a type alias instead of an empty interface.The empty interface with an ESLint suppression can be replaced with a type alias for a cleaner implementation:
-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -export interface EmptyCardProps extends React.ComponentPropsWithoutRef<'div'> {} +export type EmptyCardProps = React.ComponentPropsWithoutRef<'div'>;This eliminates the need for the suppression comment while achieving the same result.
222-232: Consider leveraging the existing Card component to reduce duplication.The
EmptyCardcomponent duplicates styling that exists in theCardcomponent's 'outline' variant. While the current implementation is correct, you could reduce duplication by either:
- Using the
Cardcomponent directly with variant="outline"- Extracting shared styling into a reusable CVA variant
This would make future style updates easier to maintain across related components.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (56)
apps/activitypub/src/api/activitypub.ts(1 hunks)apps/activitypub/src/components/modals/new-note-modal.tsx(1 hunks)apps/activitypub/src/hooks/use-activity-pub-queries.ts(3 hunks)apps/activitypub/src/utils/get-username.ts(1 hunks)apps/activitypub/src/utils/image.ts(1 hunks)apps/activitypub/src/views/preferences/components/bluesky-sharing.tsx(1 hunks)apps/activitypub/src/views/preferences/components/profile.tsx(1 hunks)apps/activitypub/src/views/profile/profile.tsx(1 hunks)apps/admin-x-design-system/src/global/sortable-list.tsx(1 hunks)apps/admin-x-design-system/src/typings.d.ts(1 hunks)apps/admin-x-design-system/src/utils/format-url.ts(1 hunks)apps/admin-x-framework/src/api/config.ts(1 hunks)apps/admin-x-framework/src/api/recommendations.ts(1 hunks)apps/admin-x-framework/src/test/acceptance.ts(1 hunks)apps/admin-x-framework/src/test/test-utils.tsx(1 hunks)apps/admin-x-framework/test/unit/hooks/use-form.test.ts(2 hunks)apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx(1 hunks)apps/admin-x-settings/src/components/settings/growth/recommendations/incoming-recommendation-list.tsx(1 hunks)apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx(2 hunks)apps/admin-x-settings/src/typings.d.ts(1 hunks)apps/admin-x-settings/src/utils/link-to-github-releases.ts(2 hunks)apps/admin-x-settings/src/utils/url.ts(1 hunks)apps/admin/package.json(1 hunks)apps/comments-ui/src/actions.ts(2 hunks)apps/comments-ui/src/app-context.ts(1 hunks)apps/comments-ui/src/components/content/forms/form.tsx(1 hunks)apps/comments-ui/src/components/popup-box.tsx(1 hunks)apps/comments-ui/src/typings.d.ts(1 hunks)apps/comments-ui/src/utils/admin-api.ts(1 hunks)apps/comments-ui/src/utils/api.ts(1 hunks)apps/posts/src/hooks/use-post-success-modal.ts(1 hunks)apps/posts/src/utils/link-helpers.ts(1 hunks)apps/posts/src/views/PostAnalytics/Growth/growth.tsx(1 hunks)apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx(1 hunks)apps/posts/src/views/PostAnalytics/Web/web.tsx(1 hunks)apps/shade/src/components/features/color-picker/color-picker.tsx(1 hunks)apps/shade/src/components/layout/header.tsx(7 hunks)apps/shade/src/components/layout/heading.tsx(1 hunks)apps/shade/src/components/layout/page.tsx(1 hunks)apps/shade/src/components/layout/view-header.tsx(2 hunks)apps/shade/src/components/ui/card.tsx(1 hunks)apps/shade/src/lib/utils.ts(1 hunks)apps/shade/src/typings.d.ts(1 hunks)apps/signup-form/src/components/pages/form-page.tsx(1 hunks)apps/signup-form/src/typings.d.ts(1 hunks)apps/stats/src/hooks/use-feature-flag.tsx(1 hunks)apps/stats/src/types/svg.d.ts(1 hunks)apps/stats/src/utils/url-helpers.ts(5 hunks)apps/stats/test/utils/tinybird-helpers.ts(1 hunks)e2e/package.json(1 hunks)ghost/core/core/server/services/recommendations/service/RecommendationMetadataService.ts(2 hunks)ghost/core/core/server/services/recommendations/service/UnsafeData.ts(1 hunks)package.json(2 hunks)
✅ Files skipped from review due to trivial changes (1)
- apps/stats/src/types/svg.d.ts
🚧 Files skipped from review as they are similar to previous changes (32)
- e2e/package.json
- apps/stats/test/utils/tinybird-helpers.ts
- apps/comments-ui/src/components/popup-box.tsx
- apps/admin-x-framework/src/test/acceptance.ts
- apps/activitypub/src/views/preferences/components/bluesky-sharing.tsx
- apps/activitypub/src/components/modals/new-note-modal.tsx
- apps/activitypub/src/api/activitypub.ts
- apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx
- apps/signup-form/src/typings.d.ts
- apps/comments-ui/src/components/content/forms/form.tsx
- apps/shade/src/lib/utils.ts
- apps/admin-x-design-system/src/utils/format-url.ts
- apps/stats/src/hooks/use-feature-flag.tsx
- apps/posts/src/utils/link-helpers.ts
- apps/admin-x-design-system/src/global/sortable-list.tsx
- apps/activitypub/src/views/preferences/components/profile.tsx
- apps/shade/src/components/layout/view-header.tsx
- apps/activitypub/src/hooks/use-activity-pub-queries.ts
- apps/comments-ui/src/utils/admin-api.ts
- apps/posts/src/hooks/use-post-success-modal.ts
- apps/admin/package.json
- apps/admin-x-framework/src/api/config.ts
- apps/comments-ui/src/utils/api.ts
- apps/admin-x-settings/src/utils/url.ts
- apps/shade/src/components/layout/page.tsx
- apps/stats/src/utils/url-helpers.ts
- apps/admin-x-settings/src/typings.d.ts
- apps/signup-form/src/components/pages/form-page.tsx
- apps/comments-ui/src/typings.d.ts
- apps/admin-x-settings/src/components/settings/growth/recommendations/incoming-recommendation-list.tsx
- apps/comments-ui/src/app-context.ts
- apps/activitypub/src/utils/get-username.ts
🧰 Additional context used
📓 Path-based instructions (6)
apps/shade/src/components/features/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
Higher-level, opinionated components (e.g., PostShareModal, SourceTabs) should be placed in
src/components/features/*
Files:
apps/shade/src/components/features/color-picker/color-picker.tsx
apps/shade/src/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/src/components/**/*.{ts,tsx}: UsePascalCasefor component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Always forward and mergeclassNameprop withcn(...)utility function
Use CVA (Class Variance Authority) for component variants when useful instead of heavy prop configuration
Prefer compound subcomponents (e.g.,Header.Title,Header.Meta,Header.Actions) for multi-region components instead of many props
Use Tailwind CSS scoped via.shadeclass; dark mode uses.dark
Files:
apps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/header.tsxapps/shade/src/components/ui/card.tsx
apps/shade/src/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/src/**/*.{ts,tsx,js}: UsecamelCasefor function and variable names
Use the@alias for internal imports (e.g.,@/lib/utils)
Files:
apps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/typings.d.tsapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/header.tsxapps/shade/src/components/ui/card.tsx
apps/shade/{src,test}/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
apps/shade/{src,test}/**/*.{ts,tsx,js}: Runyarn lintafter making changes to fix any ESLint errors and warnings before committing
Follow ESLint andtailwindcss/*plugin rules when writing styles
Files:
apps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/typings.d.tsapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/header.tsxapps/shade/src/components/ui/card.tsx
apps/shade/src/components/layout/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
Reusable layout containers (Page, Heading, Header, ViewHeader, ErrorPage) should be placed in
src/components/layout/*
Files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/header.tsx
apps/shade/src/components/ui/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/shade/AGENTS.md)
Atomic UI components should be placed in
src/components/ui/*and each component must have a corresponding*.stories.tsxfile next to it for Storybook documentation
Files:
apps/shade/src/components/ui/card.tsx
🧠 Learnings (38)
📓 Common learnings
Learnt from: cmraible
Repo: TryGhost/Ghost PR: 24658
File: ghost/admin/package.json:3-3
Timestamp: 2025-08-12T18:33:15.524Z
Learning: In Ghost's admin package.json, third-party packages like ember-cli-postcss, ember-exam, and ember-power-select have their own independent versioning schemes that are unrelated to Ghost's version numbers. Version number coincidences between Ghost versions and these packages should not trigger update suggestions.
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Run `yarn lint` after making changes to fix any ESLint errors and warnings before committing
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Follow ESLint and `tailwindcss/*` plugin rules when writing styles
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Prefer compound subcomponents (e.g., `Header.Title`, `Header.Meta`, `Header.Actions`) for multi-region components instead of many props
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/**/*.{ts,tsx,js} : Use the `@` alias for internal imports (e.g., `@/lib/utils`)
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use Tailwind CSS scoped via `.shade` class; dark mode uses `.dark`
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use `PascalCase` for component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/**/*.{ts,tsx,js} : Use `camelCase` for function and variable names
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/lib/utils.ts : Shared utilities (class merging, formatting, chart helpers) should be centralized in `src/lib/utils.ts`
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/index.ts : Place new UI components under `src/components/ui` and export them from `src/index.ts`
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use CVA (Class Variance Authority) for component variants when useful instead of heavy prop configuration
📚 Learning: 2025-11-05T16:42:12.989Z
Learnt from: rob-ghost
Repo: TryGhost/Ghost PR: 25356
File: apps/admin/test-utils/fixtures/query-client.tsx:17-35
Timestamp: 2025-11-05T16:42:12.989Z
Learning: In apps/admin/test-utils/fixtures/query-client.tsx, the createTestQueryClient function is intentionally duplicated from admin-x-framework to reduce external dependencies in the admin app's test utilities.
Applied to files:
apps/admin-x-framework/src/test/test-utils.tsx
📚 Learning: 2025-05-27T15:35:31.779Z
Learnt from: 9larsons
Repo: TryGhost/Ghost PR: 23550
File: apps/admin-x-framework/test/utils/mockFetch.ts:9-9
Timestamp: 2025-05-27T15:35:31.779Z
Learning: The codebase is currently using Vitest 0.34.3, which has limited type definitions. Modern Vitest types like MockedFunction are not available in this version, so `any` types are used as a temporary workaround in test utilities.
Applied to files:
apps/admin-x-framework/src/test/test-utils.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Use the existing setup (Vitest + Testing Library + jsdom) when adding tests
Applied to files:
apps/admin-x-framework/src/test/test-utils.tsx
📚 Learning: 2025-09-02T13:06:50.918Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 24779
File: ghost/core/test/unit/server/services/members/members-api/controllers/RouterController.test.js:1388-1392
Timestamp: 2025-09-02T13:06:50.918Z
Learning: In Ghost's test files, sinon.restore() in afterEach hooks handles cleanup of all sinon modifications including fake timers, spies, and stubs, so explicit restoration of individual sinon features like clock.restore() is typically not needed when there's a top-level sinon.restore() call.
Applied to files:
apps/admin-x-framework/src/test/test-utils.tsx
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Never use hard-coded waits like `waitForTimeout()`
Applied to files:
apps/admin-x-framework/src/test/test-utils.tsx
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Use Playwright's auto-waiting capabilities and run tests multiple times to ensure stability
Applied to files:
apps/admin-x-framework/src/test/test-utils.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use CVA (Class Variance Authority) for component variants when useful instead of heavy prop configuration
Applied to files:
apps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/typings.d.tsapps/admin-x-design-system/src/typings.d.tsapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/header.tsxapps/shade/src/components/ui/card.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/lib/utils.ts : Shared utilities (class merging, formatting, chart helpers) should be centralized in `src/lib/utils.ts`
Applied to files:
apps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use Tailwind CSS scoped via `.shade` class; dark mode uses `.dark`
Applied to files:
apps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/typings.d.tsapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/header.tsx
📚 Learning: 2025-09-10T07:05:34.606Z
Learnt from: jonatansberg
Repo: TryGhost/Ghost PR: 24838
File: apps/shade/src/components/features/color-picker/color-picker.tsx:0-0
Timestamp: 2025-09-10T07:05:34.606Z
Learning: The Color library used in the color picker component handles input validation and clamping automatically, so manual validation of HSL and RGB values is not necessary when using Color constructors.
Applied to files:
apps/shade/src/components/features/color-picker/color-picker.tsx
📚 Learning: 2025-12-09T12:37:23.267Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 25501
File: apps/shade/src/hooks/use-mobile.tsx:5-10
Timestamp: 2025-12-09T12:37:23.267Z
Learning: In the Ghost repository, this guideline applies to the shade admin app. For files under apps/shade that access browser globals (navigator, window, document) at module load time, SSR is not used, so typeof guards are not required. Reviewers should verify that such files remain client-side only and that no SSR context is introduced; apply this understanding to similarly structured files under apps/shade.
Applied to files:
apps/shade/src/components/features/color-picker/color-picker.tsxapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/header.tsxapps/shade/src/components/ui/card.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/**/*.{ts,tsx,js} : Use the `@` alias for internal imports (e.g., `@/lib/utils`)
Applied to files:
apps/shade/src/typings.d.tsapps/admin-x-design-system/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/index.ts : Place new UI components under `src/components/ui` and export them from `src/index.ts`
Applied to files:
apps/shade/src/typings.d.tsapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/header.tsxapps/shade/src/components/ui/card.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Follow ESLint and `tailwindcss/*` plugin rules when writing styles
Applied to files:
apps/shade/src/typings.d.tsapps/shade/src/components/layout/heading.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Use `PascalCase` for component identifiers in filenames while keeping ShadCN-generated files in kebab-case
Applied to files:
apps/shade/src/typings.d.tsapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/{src,test}/**/*.{ts,tsx,js} : Run `yarn lint` after making changes to fix any ESLint errors and warnings before committing
Applied to files:
apps/shade/src/typings.d.ts
📚 Learning: 2025-11-25T11:58:51.652Z
Learnt from: ibalosh
Repo: TryGhost/Ghost PR: 25525
File: apps/shade/src/shade-app.tsx:4-4
Timestamp: 2025-11-25T11:58:51.652Z
Learning: In apps/shade, the app wrapper file should be named `src/shade-app.tsx` (kebab-case) while the component itself is exported as `ShadeApp` (PascalCase). Context providers should be placed in `src/providers/*` using kebab-case filenames.
Applied to files:
apps/shade/src/typings.d.tsapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/hooks/**/*.{ts,tsx} : Custom React hooks should be placed in `src/hooks/*`
Applied to files:
apps/shade/src/typings.d.tsapps/admin-x-design-system/src/typings.d.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/ui/**/*.{ts,tsx} : Atomic UI components should be placed in `src/components/ui/*` and each component must have a corresponding `*.stories.tsx` file next to it for Storybook documentation
Applied to files:
apps/shade/src/typings.d.tsapps/shade/src/components/layout/header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Prefer compound subcomponents (e.g., `Header.Title`, `Header.Meta`, `Header.Actions`) for multi-region components instead of many props
Applied to files:
apps/shade/src/typings.d.tsapps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/header.tsx
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.{ts,tsx} : Prefer less comments and give things clear names
Applied to files:
apps/shade/src/typings.d.tsapps/admin-x-design-system/src/typings.d.tsapps/shade/src/components/layout/heading.tsxapps/comments-ui/src/actions.ts
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/**/*.{ts,tsx,js} : Use `camelCase` for function and variable names
Applied to files:
apps/shade/src/typings.d.ts
📚 Learning: 2025-11-25T14:28:50.351Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T14:28:50.351Z
Learning: Ember admin uses `AdminXComponent` to dynamically import React apps with Suspense and error boundaries
Applied to files:
apps/admin-x-design-system/src/typings.d.ts
📚 Learning: 2025-10-30T17:13:26.190Z
Learnt from: sam-lord
Repo: TryGhost/Ghost PR: 25303
File: ghost/core/core/server/services/email-service/BatchSendingService.js:19-19
Timestamp: 2025-10-30T17:13:26.190Z
Learning: In ghost/core/core/server/services/email-service/BatchSendingService.js and similar files in the Ghost codebase, prefer using `{...options}` spread syntax without explicit guards like `...(options || {})` when spreading potentially undefined objects, as the maintainer prefers cleaner syntax over defensive patterns when the behavior is safe.
Applied to files:
apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx
📚 Learning: 2025-07-14T12:20:35.268Z
Learnt from: sagzy
Repo: TryGhost/Ghost PR: 24346
File: apps/admin-x-settings/src/components/settings/growth/Network.tsx:8-12
Timestamp: 2025-07-14T12:20:35.268Z
Learning: The Network component toggle in `apps/admin-x-settings/src/components/settings/growth/Network.tsx` is intentionally implemented as static UI with a no-op onChange handler, as part of a UI-first development approach before connecting actual ActivityPub functionality.
Applied to files:
apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx
📚 Learning: 2025-11-06T05:35:41.162Z
Learnt from: danielraffel
Repo: TryGhost/Ghost PR: 25366
File: apps/admin/src/layout/app-sidebar/NavHeader.tsx:13-23
Timestamp: 2025-11-06T05:35:41.162Z
Learning: In apps/admin/src/layout/app-sidebar/NavHeader.tsx, the React component dispatches a synthetic KeyboardEvent to trigger the Ember keymaster.js search modal shortcut. This approach is known to have cross-browser reliability issues but was deferred for architectural refactoring in a separate PR. The recommended fix is to expose a global function or custom DOM event from the Ember app instead of relying on synthetic keyboard events with keymaster.js.
Applied to files:
apps/admin-x-settings/src/components/settings/site/navigation/navigation-item-editor.tsx
📚 Learning: 2025-08-12T18:33:15.524Z
Learnt from: cmraible
Repo: TryGhost/Ghost PR: 24658
File: ghost/admin/package.json:3-3
Timestamp: 2025-08-12T18:33:15.524Z
Learning: In Ghost's admin package.json, third-party packages like ember-cli-postcss, ember-exam, and ember-power-select have their own independent versioning schemes that are unrelated to Ghost's version numbers. Version number coincidences between Ghost versions and these packages should not trigger update suggestions.
Applied to files:
package.json
📚 Learning: 2025-08-01T12:44:07.467Z
Learnt from: niranjan-uma-shankar
Repo: TryGhost/Ghost PR: 24557
File: apps/admin-x-settings/src/components/settings/general/TimeZone.tsx:7-7
Timestamp: 2025-08-01T12:44:07.467Z
Learning: In Ghost development, PRs may depend on unpublished changes from SDK packages. When this occurs, TypeScript compilation errors for missing exports are expected and documented in the PR description until the dependency packages are published and updated. This is normal workflow for cross-repository feature development.
Applied to files:
package.json
📚 Learning: 2025-08-26T16:47:28.150Z
Learnt from: troyciesco
Repo: TryGhost/Ghost PR: 24749
File: ghost/core/core/server/services/members/SingleUseTokenProvider.js:3-5
Timestamp: 2025-08-26T16:47:28.150Z
Learning: When checking for dependencies in Ghost project, ensure to look directly in the specific package.json files rather than relying only on automated searches, as otplib dependency exists at line 204 in ghost/core/package.json version "12.0.1"
Applied to files:
package.json
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/layout/**/*.{ts,tsx} : Reusable layout containers (Page, Heading, Header, ViewHeader, ErrorPage) should be placed in `src/components/layout/*`
Applied to files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/features/**/*.{ts,tsx} : Higher-level, opinionated components (e.g., PostShareModal, SourceTabs) should be placed in `src/components/features/*`
Applied to files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/header.tsx
📚 Learning: 2025-11-26T11:05:59.314Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-11-26T11:05:59.314Z
Learning: Applies to apps/shade/src/components/**/*.{ts,tsx} : Always forward and merge `className` prop with `cn(...)` utility function
Applied to files:
apps/shade/src/components/layout/heading.tsxapps/shade/src/components/layout/header.tsx
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Test names should be lowercase and follow the format 'what is tested - expected outcome'
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Use factory pattern for all test data creation instead of hard-coded data or direct database manipulation
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Follow the AAA (Arrange, Act, Assert) pattern in test structure
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Always follow ADRs in `../adr/` folder (ADR-0001: AAA pattern, ADR-0002: Page Objects)
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
📚 Learning: 2025-11-24T17:29:43.865Z
Learnt from: CR
Repo: TryGhost/Ghost PR: 0
File: e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T17:29:43.865Z
Learning: Applies to e2e/**/*.test.ts : Use `getByTestId()` only when semantic locators are unavailable, and suggest adding `data-testid` to Ghost codebase when needed
Applied to files:
apps/admin-x-framework/test/unit/hooks/use-form.test.ts
🪛 Biome (2.1.2)
apps/posts/src/views/PostAnalytics/Growth/growth.tsx
[error] 16-17: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/posts/src/views/PostAnalytics/Web/web.tsx
[error] 26-27: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/activitypub/src/views/profile/profile.tsx
[error] 13-14: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
apps/posts/src/views/PostAnalytics/Newsletter/newsletter.tsx
[error] 17-18: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
🔇 Additional comments (13)
apps/shade/src/components/features/color-picker/color-picker.tsx (1)
388-390: LGTM! Clean lint fix aligned with ESLint 9+ upgrade.Removing the unused
errorbinding from the catch clause is correct since the error is intentionally ignored. This change preserves the existing behavior while satisfying the new ESLint rules.apps/admin-x-framework/test/unit/hooks/use-form.test.ts (1)
206-206: LGTM! Clean ESLint compliance update.The catch blocks correctly use bare
catch {}syntax since the error objects were never referenced. The test behavior remains unchanged—both tests still verify that errors are properly thrown and handled.Also applies to: 233-233
ghost/core/core/server/services/recommendations/service/UnsafeData.ts (1)
188-188: LGTM! Valid ESLint compliance fix.Removing the unused error variable in the catch block is correct. The error was never referenced, and bare
catchsyntax is the appropriate choice here.apps/comments-ui/src/actions.ts (1)
257-276: LGTM! Clean removal of unused error bindings.The bare
catch {}blocks are appropriate here since the error objects were never used. Both functions handle failures by reverting the optimistic state update, which is the intended behavior.ghost/core/core/server/services/recommendations/service/RecommendationMetadataService.ts (2)
62-66: LGTM! Error binding correctly removed.The unused error binding has been removed while preserving the error handling behavior. JSON parse failures will continue to return
undefinedas expected.
73-82: LGTM! URL parsing error handling is appropriate.The removal of the unused error binding is correct. Returning
nullfor invalid URLs is a sensible defensive pattern.apps/shade/src/components/layout/header.tsx (1)
116-123: Excellent implementation of the compound subcomponent pattern.The static property assignments and dual export approach (both
Header.TitleandHeaderTitle) provide flexibility while adhering to the compound component guideline. This creates a clean, composable API for header layouts.Based on coding guidelines, the compound subcomponent pattern is the preferred approach for multi-region components.
apps/shade/src/components/ui/card.tsx (1)
219-245: Verify ESLint compliance.As per coding guidelines, ensure you run
yarn lintafter these changes to confirm all ESLint errors and warnings are resolved with the new plugin version.Based on learnings, apps/shade files should be linted before committing.
apps/admin-x-settings/src/utils/link-to-github-releases.ts (2)
33-33: LGTM!The bare
catch {}is appropriate since the error object is not used. The function simply returns an empty string on any error, which is consistent with the existing error handling pattern.
1-1: Remove the unnecessary@ts-expect-errordirective.The @types/semver package provides type definitions that explicitly import and export types for
semver/functions/parse, so the subpath has proper type support. The directive should be removed unless the project explicitly does not use@types/semver.Likely an incorrect or invalid review comment.
package.json (1)
81-81: LGTM!The parser resolution ensures consistent
@typescript-eslint/parserversion across all workspaces, which helps prevent conflicts with the updated ESLint plugin.apps/shade/src/components/layout/heading.tsx (1)
4-5: LGTM!The ESLint suppression is appropriate here. The
HeadingPropsinterface serves as a semantic type alias forReact.HTMLAttributes<HTMLHeadingElement>, providing clear documentation and type identity even though it adds no additional properties. This is a common pattern in component libraries.apps/admin-x-framework/src/api/recommendations.ts (1)
25-26: LGTM!The ESLint suppressions are appropriate for these API response type definitions.
RecommendationEditResponseTypeprovides semantic clarity by extending the base response type, whileRecommendationDeleteResponseTypedefines the contract for delete operations that return no data. These empty interfaces serve as documentation and maintain type safety for API mutations.Also applies to: 28-29
b586a7f to
781b6ab
Compare
Uh oh!
There was an error while loading. Please reload this page.