원클릭으로
page-header
Add or modify PageHeader layouts on admin pages, including task view integration and cross-org patterns
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Add or modify PageHeader layouts on admin pages, including task view integration and cross-org patterns
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Create or update user-facing documentation for Sayr features in apps/marketing
Work with the Sayr edition system (cloud, community, enterprise) including limits, capabilities, and edition-aware code
Add, remove, or modify commands and sub-views in the Cmd+K command palette
Add, modify, or troubleshoot the right sidebar panel on admin pages
Update GitHub pull request title and description with comprehensive summary
| name | page-header |
| description | Add or modify PageHeader layouts on admin pages, including task view integration and cross-org patterns |
| metadata | {"audience":"developers","workflow":"feature-development"} |
I help you add, modify, or troubleshoot the PageHeader component used on every admin page. This includes setting up the identity zone (icon, title, breadcrumbs, actions), the toolbar zone (filters, view controls), and integrating with the task view system (UnifiedTaskView, TaskFilterDropdown, TaskViewDropdown).
Every admin page renders a PageHeader at the top with a consistent h-11 height per zone. The component has two zones:
| File | Purpose |
|---|---|
apps/start/src/components/generic/PageHeader.tsx | PageHeader, PageHeader.Identity, PageHeader.Toolbar components |
apps/start/src/components/tasks/views/unified-task-view.tsx | UnifiedTaskView -- renders both list and kanban views with grouping, filtering, drag-and-drop |
apps/start/src/components/tasks/views/unified-task-item.tsx | UnifiedTaskItem -- single task row/card, supports personal prop for org badges |
apps/start/src/components/tasks/views/TaskViewDropdown.tsx | TaskViewDropdown -- grouping, sub-grouping, view mode, completed tasks toggle |
apps/start/src/components/tasks/filter/TaskFilterDropdown.tsx | TaskFilterDropdown -- filter badges + filter menu + save view popover |
apps/start/src/hooks/useTaskViewManager.ts | Shared state for filters, grouping, viewMode via TanStack Store + URL params |
PageHeaderContainer. Renders a sticky header with z-30, bg-background. On mobile, adds a SidebarTrigger above the children.
<PageHeader className="optional-extra-classes">
{/* Zone 1 and Zone 2 children */}
</PageHeader>
PageHeader.IdentityZone 1. Fixed height h-11. Two usage modes:
Mode A: icon + title (simple pages)
<PageHeader.Identity
icon={<IconUser className="size-4" />}
title="My Tasks"
actions={<Button>New</Button>} // optional, rendered on the right
/>
Mode B: children (custom breadcrumbs)
When children is provided, icon and title are ignored. Use this for breadcrumb navigation:
<PageHeader.Identity actions={<CreateButton />}>
<Link to="/$orgId/tasks" params={{ orgId }}>
<Button variant="primary" className="text-xs p-1 h-auto rounded-lg bg-transparent" size="sm">
<Avatar className="h-4 w-4">...</Avatar>
<span>{organization.name}</span>
</Button>
</Link>
<span className="text-muted-foreground text-xs">/</span>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="primary" className="text-xs p-1 h-auto rounded-lg bg-transparent gap-1">
{CurrentViewIcon}
<span>{currentViewName}</span>
<IconChevronDown className="size-3" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>...</DropdownMenuContent>
</DropdownMenu>
</PageHeader.Identity>
Props:
| Prop | Type | Description |
|---|---|---|
icon | ReactNode | Icon/avatar before the title |
title | ReactNode | Page title text |
children | ReactNode | Custom content (replaces icon+title) |
actions | ReactNode | Right-side actions (buttons, badges) |
className | string | Extra classes |
PageHeader.ToolbarZone 2. Fixed height h-11 with border-b. Two usage modes:
Mode A: left + right (standard)
<PageHeader.Toolbar
left={<TaskFilterDropdown ... />}
right={
<>
<Separator orientation="vertical" className="h-5" />
<TaskViewDropdown />
</>
}
/>
Mode B: children (fully custom)
<PageHeader.Toolbar>
<div>Custom toolbar content</div>
</PageHeader.Toolbar>
Props:
| Prop | Type | Description |
|---|---|---|
left | ReactNode | Left side (filters, badges) |
right | ReactNode | Right side (view dropdown, toggles) |
children | ReactNode | Custom content (replaces left+right) |
className | string | Extra classes |
Used by Home, Settings pages. Just identity zone.
// apps/start/src/components/pages/admin/home/index.tsx
<PageHeader>
<PageHeader.Identity
icon={<IconHome className="size-4" />}
title={`Welcome, ${name}`}
/>
</PageHeader>
Used by orgid/tasks/index.tsx. Full breadcrumb identity with category/view switcher dropdown, filter toolbar, view controls, and side panel toggle.
// apps/start/src/components/pages/admin/orgid/tasks/index.tsx
<PageHeader>
<PageHeader.Identity actions={<CreateIssueDialog ... />}>
<Link to="/$orgId/tasks" ...>
<Button ...><Avatar .../><span>{organization.name}</span></Button>
</Link>
<span className="text-muted-foreground text-xs">/</span>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button ...>{CurrentViewIcon}<span>{currentViewName}</span><IconChevronDown /></Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
{/* All tasks, Your tasks, Categories, Custom Views */}
</DropdownMenuContent>
</DropdownMenu>
</PageHeader.Identity>
<PageHeader.Toolbar
left={
<TaskFilterDropdown
tasks={tasks} labels={labels} availableUsers={availableUsers}
organizationId={organization.id} views={views} setViews={setViews}
categories={categories} releases={releases}
/>
}
right={
<>
<Separator orientation="vertical" className="h-5" />
<TaskViewDropdown />
<Button onClick={() => setProjectPanelOpen(!isProjectPanelOpen)}>
{isProjectPanelOpen ? <IconLayoutSidebarRightFilled /> : <IconLayoutSidebarRight />}
</Button>
</>
}
/>
</PageHeader>
<UnifiedTaskView
tasks={tasks} setTasks={setTasks} ws={ws}
availableUsers={availableUsers} organization={organization}
categories={categories} releases={releases} views={views}
/>
Used by mine/index.tsx. Simple identity, filter toolbar (no saved views), no side panel. Uses UnifiedTaskView in cross-org mode (personal prop, no organization prop).
// apps/start/src/components/pages/admin/mine/index.tsx
<PageHeader>
<PageHeader.Identity
icon={<IconUser className="size-4" />}
title="My Tasks"
/>
<PageHeader.Toolbar
left={
<TaskFilterDropdown
tasks={tasks} labels={labels} availableUsers={availableUsers}
categories={categories} releases={releases}
// No organizationId, views, or setViews -- cross-org mode
/>
}
right={
<>
<Separator orientation="vertical" className="h-5" />
<TaskViewDropdown />
</>
}
/>
</PageHeader>
<UnifiedTaskView
tasks={tasks} setTasks={setTasks} ws={ws}
availableUsers={availableUsers} categories={categories}
releases={releases} personal
// No organization prop -- uses task.organizationId per-call
/>
Used by inbox/index.tsx. Identity zone has badge and mark-all-read button as actions.
// apps/start/src/components/pages/admin/inbox/index.tsx
<PageHeader>
<PageHeader.Identity
icon={<IconInbox className="size-4" />}
title="Inbox"
actions={
<>
{unreadCount > 0 && <Badge variant="outline">{unreadCount}</Badge>}
{unreadCount > 0 && <Button onClick={markAllRead}>Mark all read</Button>}
</>
}
/>
</PageHeader>
Used by orgid/tasks/taskId.tsx. Identity with breadcrumb children linking back to task list, no toolbar.
// apps/start/src/components/pages/admin/orgid/tasks/taskId.tsx
<PageHeader>
<PageHeader.Identity>
<Link to="/$orgId/tasks" params={{ orgId: organization.id }}>
<Button ...><Avatar .../><span>{organization.name}</span></Button>
</Link>
<span className="text-muted-foreground text-xs">/</span>
<span className="text-xs">#{task.shortId}</span>
</PageHeader.Identity>
</PageHeader>
UnifiedTaskView handles both list and kanban rendering. It lives below the PageHeader and fills the remaining height.
| Prop | Type | Required | Description |
|---|---|---|---|
tasks | TaskWithLabels[] | Yes | Task data |
setTasks | (tasks) => void | Yes | State setter for optimistic updates |
ws | WebSocket | null | Yes | WebSocket for real-time updates |
availableUsers | userType[] | Yes | Users for assignee display/selection |
organization | OrganizationWithMembers | No | When set, uses organization.id for all API calls (single-org mode) |
categories | categoryType[] | Yes | Categories for grouping/filtering |
releases | releaseType[] | No | Releases for grouping/filtering |
views | savedViewType[] | No | Saved views for auto-loading view configs |
compact | boolean | No | Compact rendering (used in release pages) |
forceShowCompleted | boolean | No | Override showCompletedTasks toggle |
personal | boolean | No | When true, shows org badges on each task row |
Single-org mode (org tasks page): Pass organization prop. All updateTaskAction calls use organization.id.
Cross-org mode (My Tasks page): Omit organization prop. The component uses getOrgId(taskId) which looks up task.organizationId from the tasks array for each API call. Pass personal to show org badges.
UnifiedTaskView internally manages:
useTaskViewManager(views) -- shared state for filters, grouping, subGrouping, viewMode, showCompletedTasksapplyFilters(tasks, filters) -- client-side filteringapplyNestedGrouping(grouping, subGrouping, ...) -- groups filtered tasks into NestedTaskGroup[]TaskGroupSectionHeader + UnifiedTaskItem with collapsible sectionsGridBoardProvider with drag-and-drop columns/rowsUPDATE_TASK and UPDATE_TASK_COMMENTSTaskFilterDropdown renders filter badges + a filter menu popover. It slots into PageHeader.Toolbar's left slot.
| Prop | Type | Required | Description |
|---|---|---|---|
tasks | TaskWithLabels[] | Yes | Tasks for deriving filter options |
labels | labelType[] | Yes | Labels for label filter options |
availableUsers | userType[] | Yes | Users for assignee filter options |
categories | categoryType[] | Yes | Categories for category filter options |
releases | releaseType[] | Yes | Releases for release filter options |
organizationId | string | No | When set, enables "Save View" popover |
views | savedViewType[] | No | Saved views for duplicate detection |
setViews | (views) => void | No | Setter for updating views after save |
When organizationId, views, or setViews are omitted (cross-org mode), the "Save View" popover and share URL clipboard button are hidden. Filtering itself works identically.
TaskViewDropdown has NO org dependencies. It reads/writes shared state from useTaskViewManager and can be used anywhere.
Renders controls for: view mode (list/kanban), primary grouping, sub-grouping, show/hide completed tasks.
PageHeader at the top of its content areah-11 per zone -- Identity is always h-11, Toolbar is always h-11 when presentsticky top-0 z-30 ensures the header stays visible during scroll<div className="relative flex flex-col h-full max-h-full overflow-hidden">, with scrollable content below the headerPageHeader auto-adds a SidebarTrigger on mobile. No extra work needed.<Separator orientation="vertical" className="h-5" /> before the TaskViewDropdownUse this skill when:
PageHeader to a new admin pageUnifiedTaskView with a page (single-org or cross-org)TaskFilterDropdown to a pageTell me:
UnifiedTaskView? Single-org or cross-org?