diff --git a/packages/shared/src/types/issue.ts b/packages/shared/src/types/issue.ts index 9ef7f2d4..d55f8e15 100644 --- a/packages/shared/src/types/issue.ts +++ b/packages/shared/src/types/issue.ts @@ -143,7 +143,6 @@ export interface Issue { mentionedProjects?: Project[]; myLastTouchAt?: Date | null; lastExternalCommentAt?: Date | null; - lastActivityAt?: Date | null; isUnreadForMe?: boolean; createdAt: Date; updatedAt: Date; diff --git a/server/src/routes/agents.ts b/server/src/routes/agents.ts index c2ed8ee2..8ec5ffb1 100644 --- a/server/src/routes/agents.ts +++ b/server/src/routes/agents.ts @@ -1075,7 +1075,6 @@ export function agentRoutes(db: Db) { projectId: issue.projectId, goalId: issue.goalId, parentId: issue.parentId, - lastActivityAt: (issue as typeof issue & { lastActivityAt?: Date | null }).lastActivityAt ?? issue.updatedAt, updatedAt: issue.updatedAt, activeRun: issue.activeRun, })), diff --git a/ui/src/components/Layout.tsx b/ui/src/components/Layout.tsx index 69457356..be39adb7 100644 --- a/ui/src/components/Layout.tsx +++ b/ui/src/components/Layout.tsx @@ -17,6 +17,7 @@ import { MobileBottomNav } from "./MobileBottomNav"; import { WorktreeBanner } from "./WorktreeBanner"; import { DevRestartBanner } from "./DevRestartBanner"; import { useDialog } from "../context/DialogContext"; +import { GeneralSettingsProvider } from "../context/GeneralSettingsContext"; import { usePanel } from "../context/PanelContext"; import { useCompany } from "../context/CompanyContext"; import { useSidebar } from "../context/SidebarContext"; @@ -265,12 +266,13 @@ export function Layout() { }, [location.hash, location.pathname, location.search]); return ( -
+
+ > -
+
+ ); } diff --git a/ui/src/context/GeneralSettingsContext.tsx b/ui/src/context/GeneralSettingsContext.tsx new file mode 100644 index 00000000..a3917ed6 --- /dev/null +++ b/ui/src/context/GeneralSettingsContext.tsx @@ -0,0 +1,28 @@ +import type { ReactNode } from "react"; +import { createContext, useContext } from "react"; + +export interface GeneralSettingsContextValue { + keyboardShortcutsEnabled: boolean; +} + +const GeneralSettingsContext = createContext({ + keyboardShortcutsEnabled: false, +}); + +export function GeneralSettingsProvider({ + value, + children, +}: { + value: GeneralSettingsContextValue; + children: ReactNode; +}) { + return ( + + {children} + + ); +} + +export function useGeneralSettings() { + return useContext(GeneralSettingsContext); +} diff --git a/ui/src/lib/inbox.test.ts b/ui/src/lib/inbox.test.ts index 784e38cb..2cdd8721 100644 --- a/ui/src/lib/inbox.test.ts +++ b/ui/src/lib/inbox.test.ts @@ -180,7 +180,6 @@ function makeIssue(id: string, isUnreadForMe: boolean): Issue { labelIds: [], myLastTouchAt: new Date("2026-03-11T00:00:00.000Z"), lastExternalCommentAt: new Date("2026-03-11T01:00:00.000Z"), - lastActivityAt: new Date("2026-03-11T01:00:00.000Z"), isUnreadForMe, }; } @@ -358,10 +357,10 @@ describe("inbox helpers", () => { it("mixes approvals into the inbox feed by most recent activity", () => { const newerIssue = makeIssue("1", true); - newerIssue.lastActivityAt = new Date("2026-03-11T04:00:00.000Z"); + newerIssue.lastExternalCommentAt = new Date("2026-03-11T04:00:00.000Z"); const olderIssue = makeIssue("2", false); - olderIssue.lastActivityAt = new Date("2026-03-11T02:00:00.000Z"); + olderIssue.lastExternalCommentAt = new Date("2026-03-11T02:00:00.000Z"); const approval = makeApprovalWithTimestamps( "approval-between", @@ -386,21 +385,19 @@ describe("inbox helpers", () => { ]); }); - it("prefers canonical lastActivityAt over comment-only timestamps", () => { - const activityIssue = makeIssue("1", true); - activityIssue.lastExternalCommentAt = new Date("2026-03-11T01:00:00.000Z"); - activityIssue.lastActivityAt = new Date("2026-03-11T05:00:00.000Z"); + it("sorts touched issues by latest external comment timestamp", () => { + const newerIssue = makeIssue("1", true); + newerIssue.lastExternalCommentAt = new Date("2026-03-11T05:00:00.000Z"); - const commentIssue = makeIssue("2", true); - commentIssue.lastExternalCommentAt = new Date("2026-03-11T04:00:00.000Z"); - commentIssue.lastActivityAt = new Date("2026-03-11T04:00:00.000Z"); + const olderIssue = makeIssue("2", true); + olderIssue.lastExternalCommentAt = new Date("2026-03-11T04:00:00.000Z"); - expect(getRecentTouchedIssues([commentIssue, activityIssue]).map((issue) => issue.id)).toEqual(["1", "2"]); + expect(getRecentTouchedIssues([olderIssue, newerIssue]).map((issue) => issue.id)).toEqual(["1", "2"]); }); it("mixes join requests into the inbox feed by most recent activity", () => { const issue = makeIssue("1", true); - issue.lastActivityAt = new Date("2026-03-11T04:00:00.000Z"); + issue.lastExternalCommentAt = new Date("2026-03-11T04:00:00.000Z"); const joinRequest = makeJoinRequest("join-1"); joinRequest.createdAt = new Date("2026-03-11T03:00:00.000Z"); @@ -485,7 +482,7 @@ describe("inbox helpers", () => { it("limits recent touched issues before unread badge counting", () => { const issues = Array.from({ length: RECENT_ISSUES_LIMIT + 5 }, (_, index) => { const issue = makeIssue(String(index + 1), index < 3); - issue.lastActivityAt = new Date(Date.UTC(2026, 2, 31, 0, 0, 0, 0) - index * 60_000); + issue.lastExternalCommentAt = new Date(Date.UTC(2026, 2, 31, 0, 0, 0, 0) - index * 60_000); return issue; }); diff --git a/ui/src/lib/inbox.ts b/ui/src/lib/inbox.ts index 9f26e998..647b6bea 100644 --- a/ui/src/lib/inbox.ts +++ b/ui/src/lib/inbox.ts @@ -217,9 +217,6 @@ export function normalizeTimestamp(value: string | Date | null | undefined): num } export function issueLastActivityTimestamp(issue: Issue): number { - const lastActivityAt = normalizeTimestamp(issue.lastActivityAt); - if (lastActivityAt > 0) return lastActivityAt; - const lastExternalCommentAt = normalizeTimestamp(issue.lastExternalCommentAt); if (lastExternalCommentAt > 0) return lastExternalCommentAt; diff --git a/ui/src/pages/Inbox.test.tsx b/ui/src/pages/Inbox.test.tsx index adb161c2..10ac47d7 100644 --- a/ui/src/pages/Inbox.test.tsx +++ b/ui/src/pages/Inbox.test.tsx @@ -56,7 +56,6 @@ function createIssue(overrides: Partial = {}): Issue { labelIds: [], myLastTouchAt: null, lastExternalCommentAt: null, - lastActivityAt: new Date("2026-03-11T00:00:00.000Z"), isUnreadForMe: false, ...overrides, }; diff --git a/ui/src/pages/Inbox.tsx b/ui/src/pages/Inbox.tsx index 1a356580..d8bbccfa 100644 --- a/ui/src/pages/Inbox.tsx +++ b/ui/src/pages/Inbox.tsx @@ -15,6 +15,7 @@ import { instanceSettingsApi } from "../api/instanceSettings"; import { projectsApi } from "../api/projects"; import { useCompany } from "../context/CompanyContext"; import { useBreadcrumbs } from "../context/BreadcrumbContext"; +import { useGeneralSettings } from "../context/GeneralSettingsContext"; import { queryKeys } from "../lib/queryKeys"; import { armIssueDetailInboxQuickArchive, @@ -213,7 +214,7 @@ export function InboxIssueMetaLeading({ } function issueActivityText(issue: Issue): string { - return `Updated ${timeAgo(issue.lastActivityAt ?? issue.lastExternalCommentAt ?? issue.updatedAt)}`; + return `Updated ${timeAgo(issue.lastExternalCommentAt ?? issue.updatedAt)}`; } function issueTrailingGridTemplate(columns: InboxIssueColumn[]): string { @@ -245,7 +246,7 @@ export function InboxIssueTrailingColumns({ assigneeName: string | null; currentUserId: string | null; }) { - const activityText = timeAgo(issue.lastActivityAt ?? issue.lastExternalCommentAt ?? issue.updatedAt); + const activityText = timeAgo(issue.lastExternalCommentAt ?? issue.updatedAt); const userLabel = formatAssigneeUserLabel(issue.assigneeUserId, currentUserId) ?? "User"; return ( @@ -791,10 +792,7 @@ export function Inbox() { const location = useLocation(); const queryClient = useQueryClient(); const [actionError, setActionError] = useState(null); - const keyboardShortcutsEnabled = useQuery({ - queryKey: queryKeys.instance.generalSettings, - queryFn: () => instanceSettingsApi.getGeneral(), - }).data?.keyboardShortcuts === true; + const { keyboardShortcutsEnabled } = useGeneralSettings(); const { data: experimentalSettings } = useQuery({ queryKey: queryKeys.instance.experimentalSettings, queryFn: () => instanceSettingsApi.getExperimental(), @@ -1778,7 +1776,7 @@ export function Inbox() {
- Today + Earlier
, );