Issue views (List / Board / Calendar / Activity)
View on GitHubIssue views (List / Board / Calendar / Activity)
A project's issues render as a sortable table, a status-grouped Kanban
board, a calendar laid out by issue dates, or a chronological activity
feed — the same issues.data array (plus, for Calendar and Activity, their own
calendarIssues and activityLogs props) presented four different ways, switched with no
page reload via a flat IssuePageLooks string type. This category
documents how the switch works and what it takes to add a fifth view.
Guides, in the order you'd actually need them
-
Add a new issue viewIssue views (List / Board / Calendar / Activity)Add a new issue viewWorked example: adding a fifth view, Timeline, alongside the existing List/Board/Calendar/Activity four. Six places need it — miss one and the new view eit… — worked example adding a fifth view,
Timeline, across every place the existing four are wired: the type, the render switch, the nav button (plus its keyboard shortcut), and the Account settings default-view picker. -
Load a view's data lazilyIssue views (List / Board / Calendar / Activity)Load a view's data lazilyThe project page does not send every view's data on every visit. The table and board read issues (one page), Activity reads activityLogs, and the calendar'… — optional Inertia props, a date-ranged calendar query and why the dashboard only receives counts.
The architecture in one paragraph
IssuePageLooks (resources/js/types/Issues.ts) is 'List' | 'Board' | 'Calendar' | 'Activity' — a closed union with no registry array
behind it (unlike settings tabs'Settings tabs/settings is not one page — every tab under it (Preferences, Profile, Notifications, Security & access, Export in the Account section; Labels, Issue Types,…
SETTINGS_TABS), so every consumer hardcodes its own list of the four
values. Pages/Projects/Show.tsx owns the actual selectedLook state
for a project page visit, seeded once from
localStorage.getItem('selectedLook') on mount and rendered via a
flat ternary chain (selectedLook === 'List' ? <IssueTable /> : selectedLook === 'Board' ? <IssueBoard /> : selectedLook === 'Calendar' ? <CalendarView /> : <ActivityLogs logs={activityLogs.data} />) — List
and Board receive the same issues.data, just presented differently,
Calendar reads its own date-ranged, optional calendarIssues (see
guide 2Issue views (List / Board / Calendar / Activity)Load a view's data lazilyThe project page does not send every view's data on every visit. The table and board read issues (one page), Activity reads activityLogs, and the calendar'…), and Activity instead reads
activityLogs (a paginator of ActivityLogEntry, threaded down from
ProjectController::show() via ActivityLogService::paginateForProject()
— see ../activity-log/README.mdActivity logEvery project-changing action across the app writes a plain-text ActivityLog row — "Changed Jane's role to admin", "Deleted the \"Owner\" role" — and it's… for
that read path). Non-obviously, switching the view from the project
page's header only updates this page's React state — it never writes
back to localStorage — only Account settings → Preferences'
issue-view picker (AccountSettingsPreferencesTab) does that, which is
why switching views mid-session doesn't "stick" across a reload the
way changing your default view in Settings does. 1/2/3/4 are
registered as global keyboard shortcutsKeyboard shortcutsEvery keyboard shortcut in Orbit — ? for help, mod+k, alt+p, a page-scoped p for "create project" — goes through one system: ShortcutContext. There's no pe… for
the four views directly inside Layouts/MainLayout.tsx, categorized
'View', which also builds the tabs array PageHeader renders for
the List/Board/Calendar/Activity toggle.
