Migrated Tags list page to new ListPage + PageHeader pattern#27896
Conversation
ref https://linear.app/tryghost/issue/DES-1382/ - Replaced deprecated Header primitive and wrapper components (TagsLayout, TagsHeader, TagsContent) with ListPage + PageHeader - Public/internal tab toggle moved into PageHeader.Actions - Updated ListPage: uses Stack primitives internally, grows to fill its flex parent, removes Pagination slot, exports ViewBar/FilterBar from the patterns barrel - Empty/loading/error states vertically centred in ListPage.Body Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
WalkthroughThis PR removes three tags-specific components (TagsContent, TagsHeader, TagsLayout) and refactors the Tags page to use MainLayout + ListPage. The Tags page now derives its filter from useSearchParams, renders a PageHeader with a ToggleGroup and mobile menu, and moves loading/error/empty/list states into ListPage.Body. ListPage was refactored to use the shared Stack primitive, accept passthrough div props, and the Pagination slot was removed. patterns.ts now re-exports view-bar and filter-bar. Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/posts/src/views/Tags/tags.tsx (1)
12-26:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winValidate the
typequery param before using it in the API filter.
typecurrently accepts any query value and is passed straight intovisibility. Unsupported values can produce inconsistent toggle selection and unexpected API filtering.Suggested fix
- const qs = new URLSearchParams(search); - const type = qs.get('type') ?? 'public'; + const qs = new URLSearchParams(search); + const rawType = qs.get('type'); + const type = rawType === 'internal' ? 'internal' : 'public';🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/posts/src/views/Tags/tags.tsx` around lines 12 - 26, Validate the raw query param before passing it to the API: read the raw type via useLocation()/URLSearchParams, check it against an allowed set (e.g. ['public','private'] or the enum your API expects), and if it’s not a supported value fall back to the default ('public'); then pass this validated value into useBrowseTags filter.visibility so toggle selection and API filtering remain consistent (refer to the variables type, useLocation, URLSearchParams, and the useBrowseTags call with filter.visibility).
🧹 Nitpick comments (2)
apps/shade/src/patterns.ts (1)
3-4: ⚡ Quick winUse
@/alias for new Shade internal re-exports.Please switch these new re-exports to the
@/alias to match the Shade internal import/export rule.Proposed change
-export * from './components/patterns/view-bar'; -export * from './components/patterns/filter-bar'; +export * from '@/components/patterns/view-bar'; +export * from '@/components/patterns/filter-bar';As per coding guidelines, "Use the
@/alias for cross-file imports within Shade itself".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/shade/src/patterns.ts` around lines 3 - 4, Update the re-exports in patterns.ts to use the Shade internal alias instead of relative paths: replace export * from './components/patterns/view-bar' and export * from './components/patterns/filter-bar' with the equivalent exports using the '@/...' alias (e.g., export * from '@/components/patterns/view-bar' and export * from '@/components/patterns/filter-bar') so imports follow the internal cross-file import/export rule.apps/shade/src/components/page-templates/list-page.stories.tsx (1)
137-165: ⚡ Quick winAdd a one-line Storybook description for the updated
EmptyStatestory.This story was modified but still doesn’t include
parameters.docs.description.story.Suggested fix
export const EmptyState: Story = { name: 'Empty state', + parameters: { + docs: { + description: { + story: 'Use when the list has no items and you want a centered empty-state CTA.' + } + } + }, render: () => (As per coding guidelines:
apps/shade/src/components/**/*.stories.tsx— “Add per-storyparameters.docs.description.storyas one-liner explaining when to use that variant”.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/shade/src/components/page-templates/list-page.stories.tsx` around lines 137 - 165, Add a one-line Storybook description to the EmptyState story by attaching parameters.docs.description.story to the EmptyState export; locate the EmptyState constant (export const EmptyState: Story) and set EmptyState.parameters = { docs: { description: { story: 'One-line explanation of when to use the Empty state variant' } } } (use an appropriate one-liner describing when to use this empty-members variant).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@apps/posts/src/views/Tags/tags.tsx`:
- Around line 12-26: Validate the raw query param before passing it to the API:
read the raw type via useLocation()/URLSearchParams, check it against an allowed
set (e.g. ['public','private'] or the enum your API expects), and if it’s not a
supported value fall back to the default ('public'); then pass this validated
value into useBrowseTags filter.visibility so toggle selection and API filtering
remain consistent (refer to the variables type, useLocation, URLSearchParams,
and the useBrowseTags call with filter.visibility).
---
Nitpick comments:
In `@apps/shade/src/components/page-templates/list-page.stories.tsx`:
- Around line 137-165: Add a one-line Storybook description to the EmptyState
story by attaching parameters.docs.description.story to the EmptyState export;
locate the EmptyState constant (export const EmptyState: Story) and set
EmptyState.parameters = { docs: { description: { story: 'One-line explanation of
when to use the Empty state variant' } } } (use an appropriate one-liner
describing when to use this empty-members variant).
In `@apps/shade/src/patterns.ts`:
- Around line 3-4: Update the re-exports in patterns.ts to use the Shade
internal alias instead of relative paths: replace export * from
'./components/patterns/view-bar' and export * from
'./components/patterns/filter-bar' with the equivalent exports using the '@/...'
alias (e.g., export * from '@/components/patterns/view-bar' and export * from
'@/components/patterns/filter-bar') so imports follow the internal cross-file
import/export rule.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: e89bef58-4095-45da-9e9e-3df353ede4e5
📒 Files selected for processing (7)
apps/posts/src/views/Tags/components/tags-content.tsxapps/posts/src/views/Tags/components/tags-header.tsxapps/posts/src/views/Tags/components/tags-layout.tsxapps/posts/src/views/Tags/tags.tsxapps/shade/src/components/page-templates/list-page.stories.tsxapps/shade/src/components/page-templates/list-page.tsxapps/shade/src/patterns.ts
💤 Files with no reviewable changes (3)
- apps/posts/src/views/Tags/components/tags-layout.tsx
- apps/posts/src/views/Tags/components/tags-content.tsx
- apps/posts/src/views/Tags/components/tags-header.tsx
ref https://linear.app/tryghost/issue/DES-1382/ - On mobile, the Public/Internal toggle collapses into a ··· dropdown with DropdownMenuCheckboxItem entries for each tab - On mobile, the New tag button shows a + icon only (text hidden below sm) - Switched from useLocation + URLSearchParams to useSearchParams for cleaner search param updates from the dropdown handlers Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ref https://linear.app/ghost/issue/DES-1382/tags-list-page-header-migration
Headerprimitive and thin wrapper components (TagsLayout,TagsHeader,TagsContent) with the newListPagetemplate +PageHeaderpattern from ShadePageHeader.Actionsalongside the "New tag" button