From 670a9a26e2b4c52a62c043692bc95941cb4850db Mon Sep 17 00:00:00 2001 From: Matt Pua Date: Tue, 30 Jun 2026 10:56:38 -0400 Subject: [PATCH 01/14] feat(command-menu): show keyboard shortcuts right-aligned per item Generated-By: PostHog Code Task-Id: 98391aef-093c-485d-a01e-ce8dc7f407e9 --- .../ui/src/features/command/CommandMenu.tsx | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/packages/ui/src/features/command/CommandMenu.tsx b/packages/ui/src/features/command/CommandMenu.tsx index f0b33b6040..1d8820adfa 100644 --- a/packages/ui/src/features/command/CommandMenu.tsx +++ b/packages/ui/src/features/command/CommandMenu.tsx @@ -10,6 +10,8 @@ import { AutocompleteStatus, Dialog, DialogContent, + Kbd, + KbdGroup, } from "@posthog/quill"; import { PROJECT_BLUEBIRD_FLAG } from "@posthog/shared"; import { @@ -21,6 +23,10 @@ import { useChannels } from "@posthog/ui/features/canvas/hooks/useChannels"; import { useTaskChannelMap } from "@posthog/ui/features/canvas/hooks/useTaskChannelMap"; import { useReviewNavigationStore } from "@posthog/ui/features/code-review/reviewNavigationStore"; import { CommandKeyHints } from "@posthog/ui/features/command/CommandKeyHints"; +import { + formatHotkeyParts, + SHORTCUTS, +} from "@posthog/ui/features/command/keyboard-shortcuts"; import { useFeatureFlag } from "@posthog/ui/features/feature-flags/useFeatureFlag"; import { useFolders } from "@posthog/ui/features/folders/useFolders"; import { @@ -62,6 +68,8 @@ type Command = { action: CommandMenuAction; /** Channel in scope for the bluebird open-channel / open-task actions. */ channelId?: string; + /** Hotkey string (e.g. "mod+b") shown right-aligned when present. */ + shortcut?: string; onRun: () => void; }; @@ -208,6 +216,7 @@ export function CommandMenu({ open, onOpenChange }: CommandMenuProps) { label: "Settings", icon: , action: "settings", + shortcut: SHORTCUTS.SETTINGS, onRun: () => openSettingsDialog(), }, ]; @@ -219,6 +228,7 @@ export function CommandMenu({ open, onOpenChange }: CommandMenuProps) { label: "Toggle left sidebar", icon: , action: "toggle-left-sidebar", + shortcut: SHORTCUTS.TOGGLE_LEFT_SIDEBAR, onRun: toggleLeftSidebar, }, ...(reviewTaskId @@ -230,6 +240,7 @@ export function CommandMenu({ open, onOpenChange }: CommandMenuProps) { ), action: "open-review-panel" as CommandMenuAction, + shortcut: SHORTCUTS.TOGGLE_REVIEW_PANEL, onRun: openReviewPanel, }, ] @@ -240,6 +251,7 @@ export function CommandMenu({ open, onOpenChange }: CommandMenuProps) { keywords: "create", icon: , action: "new-task", + shortcut: SHORTCUTS.NEW_TASK, onRun: () => { closeSettingsDialog(); openTaskInput(); @@ -421,6 +433,15 @@ export function CommandMenu({ open, onOpenChange }: CommandMenuProps) { · #{cmd.detail} )} + {cmd.shortcut && ( + + + {formatHotkeyParts(cmd.shortcut).map((part) => ( + {part} + ))} + + + )} )} From 61597ea51e9a913f9e58923f2ff705523432c808 Mon Sep 17 00:00:00 2001 From: Matt Pua Date: Tue, 30 Jun 2026 10:56:40 -0400 Subject: [PATCH 02/14] fix(command-menu): right-align shortcuts with full-width flex row Generated-By: PostHog Code Task-Id: 98391aef-093c-485d-a01e-ce8dc7f407e9 --- packages/ui/src/features/command/CommandMenu.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/features/command/CommandMenu.tsx b/packages/ui/src/features/command/CommandMenu.tsx index 1d8820adfa..5fa2f8a308 100644 --- a/packages/ui/src/features/command/CommandMenu.tsx +++ b/packages/ui/src/features/command/CommandMenu.tsx @@ -421,8 +421,10 @@ export function CommandMenu({ open, onOpenChange }: CommandMenuProps) { value={cmd.id} onClick={() => handleSelect(cmd.id)} // Long task names wrap instead of truncating, so the - // item must grow: min-height, not a fixed height. - className="h-auto! min-h-7 py-1.5 text-left" + // item must grow: min-height, not a fixed height. Full- + // width flex so a trailing shortcut can `ml-auto` to the + // end of the row. + className="flex h-auto! min-h-7 w-full items-center gap-2 py-1.5 text-left" > {cmd.icon} From c0dface948d1df76a54fd84644e6e4108e55c5ce Mon Sep 17 00:00:00 2001 From: Matt Pua Date: Tue, 30 Jun 2026 10:56:41 -0400 Subject: [PATCH 03/14] fix(command-menu): use array index as Kbd key per review Generated-By: PostHog Code Task-Id: 98391aef-093c-485d-a01e-ce8dc7f407e9 --- packages/ui/src/features/command/CommandMenu.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/features/command/CommandMenu.tsx b/packages/ui/src/features/command/CommandMenu.tsx index 5fa2f8a308..2b46145e09 100644 --- a/packages/ui/src/features/command/CommandMenu.tsx +++ b/packages/ui/src/features/command/CommandMenu.tsx @@ -438,8 +438,8 @@ export function CommandMenu({ open, onOpenChange }: CommandMenuProps) { {cmd.shortcut && ( - {formatHotkeyParts(cmd.shortcut).map((part) => ( - {part} + {formatHotkeyParts(cmd.shortcut).map((part, i) => ( + {part} ))} From 1c62fba918af20d1748563f32308a50031561267 Mon Sep 17 00:00:00 2001 From: Matt Pua Date: Tue, 30 Jun 2026 10:56:43 -0400 Subject: [PATCH 04/14] fix(command-menu): right-align shortcuts without clipping Kbd Generated-By: PostHog Code Task-Id: fcb4960f-501b-4784-aab9-c264bebe1755 --- packages/ui/src/features/command/CommandMenu.tsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/ui/src/features/command/CommandMenu.tsx b/packages/ui/src/features/command/CommandMenu.tsx index 2b46145e09..38f8db2bb0 100644 --- a/packages/ui/src/features/command/CommandMenu.tsx +++ b/packages/ui/src/features/command/CommandMenu.tsx @@ -421,10 +421,12 @@ export function CommandMenu({ open, onOpenChange }: CommandMenuProps) { value={cmd.id} onClick={() => handleSelect(cmd.id)} // Long task names wrap instead of truncating, so the - // item must grow: min-height, not a fixed height. Full- - // width flex so a trailing shortcut can `ml-auto` to the - // end of the row. - className="flex h-auto! min-h-7 w-full items-center gap-2 py-1.5 text-left" + // item must grow: min-height, not a fixed height. Quill + // wraps our children in an inner content span; force it to + // fill the row (so a trailing shortcut can `ml-auto` to the + // end) and let it overflow visibly so the shortcut Kbd + // boxes aren't clipped by the wrapper's `truncate`. + className="flex h-auto! min-h-7 w-full items-center gap-2 py-1.5 pr-2 text-left [&>span]:w-full [&>span]:overflow-visible" > {cmd.icon} @@ -438,8 +440,8 @@ export function CommandMenu({ open, onOpenChange }: CommandMenuProps) { {cmd.shortcut && ( - {formatHotkeyParts(cmd.shortcut).map((part, i) => ( - {part} + {formatHotkeyParts(cmd.shortcut).map((part) => ( + {part} ))} From 9e24e2ac9c1b54cc30f29964ffc1e0d93e6958bb Mon Sep 17 00:00:00 2001 From: Matt Pua Date: Tue, 30 Jun 2026 10:56:45 -0400 Subject: [PATCH 05/14] fix(command-menu): use array index as Kbd key Re-applies Greptile's P2 suggestion (positional, static list) on top of the clipping fix, which had reverted it to the formatted-string key. Generated-By: PostHog Code Task-Id: 98391aef-093c-485d-a01e-ce8dc7f407e9 --- packages/ui/src/features/command/CommandMenu.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/features/command/CommandMenu.tsx b/packages/ui/src/features/command/CommandMenu.tsx index 38f8db2bb0..a64a6a6d0e 100644 --- a/packages/ui/src/features/command/CommandMenu.tsx +++ b/packages/ui/src/features/command/CommandMenu.tsx @@ -440,8 +440,8 @@ export function CommandMenu({ open, onOpenChange }: CommandMenuProps) { {cmd.shortcut && ( - {formatHotkeyParts(cmd.shortcut).map((part) => ( - {part} + {formatHotkeyParts(cmd.shortcut).map((part, i) => ( + {part} ))} From e22f7a3207f298d7aad188a6b87a996341606f14 Mon Sep 17 00:00:00 2001 From: Matt Pua Date: Tue, 30 Jun 2026 10:56:47 -0400 Subject: [PATCH 06/14] fix(command-menu): revert Kbd key to formatted part to satisfy Biome Biome's required `noArrayIndexKey` check rejects `key={i}`, which conflicts with the earlier Greptile suggestion. The formatted part is a safe key here: a shortcut never yields duplicate formatted parts (no repeated modifiers). Generated-By: PostHog Code Task-Id: 98391aef-093c-485d-a01e-ce8dc7f407e9 --- packages/ui/src/features/command/CommandMenu.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/features/command/CommandMenu.tsx b/packages/ui/src/features/command/CommandMenu.tsx index a64a6a6d0e..38f8db2bb0 100644 --- a/packages/ui/src/features/command/CommandMenu.tsx +++ b/packages/ui/src/features/command/CommandMenu.tsx @@ -440,8 +440,8 @@ export function CommandMenu({ open, onOpenChange }: CommandMenuProps) { {cmd.shortcut && ( - {formatHotkeyParts(cmd.shortcut).map((part, i) => ( - {part} + {formatHotkeyParts(cmd.shortcut).map((part) => ( + {part} ))} From de50fcde5b481010b91be8c4ab19adbc8b17c2ca Mon Sep 17 00:00:00 2001 From: Matt Pua Date: Tue, 30 Jun 2026 10:56:49 -0400 Subject: [PATCH 07/14] fix(command-menu): add spacing between shortcut keys Match the keyboard shortcuts sheet, which renders key parts with a gap-1 (4px) between them, by giving the command menu's KbdGroup an explicit gap-1 so the keys aren't cramped together. Generated-By: PostHog Code Task-Id: 85b2e7d0-e251-47ac-81bf-217751cd480a --- packages/ui/src/features/command/CommandMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/src/features/command/CommandMenu.tsx b/packages/ui/src/features/command/CommandMenu.tsx index 38f8db2bb0..8ed768e65f 100644 --- a/packages/ui/src/features/command/CommandMenu.tsx +++ b/packages/ui/src/features/command/CommandMenu.tsx @@ -439,7 +439,7 @@ export function CommandMenu({ open, onOpenChange }: CommandMenuProps) { )} {cmd.shortcut && ( - + {formatHotkeyParts(cmd.shortcut).map((part) => ( {part} ))} From ad0603af53312c92726ab0a5fcd3c6ae9030151a Mon Sep 17 00:00:00 2001 From: Matt Pua Date: Tue, 30 Jun 2026 11:05:07 -0400 Subject: [PATCH 08/14] fix(command-menu): space shortcut keys with explicit flex gap The quill KbdGroup wrapper wasn't honoring the gap-1 utility, so the shortcut keys still rendered flush against each other. Drop KbdGroup and render the Kbd keycaps directly in a flex container with gap-1, matching the spacing in the keyboard shortcuts sheet. Generated-By: PostHog Code Task-Id: 85b2e7d0-e251-47ac-81bf-217751cd480a --- packages/ui/src/features/command/CommandMenu.tsx | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/ui/src/features/command/CommandMenu.tsx b/packages/ui/src/features/command/CommandMenu.tsx index 8ed768e65f..d77a3d4a6e 100644 --- a/packages/ui/src/features/command/CommandMenu.tsx +++ b/packages/ui/src/features/command/CommandMenu.tsx @@ -11,7 +11,6 @@ import { Dialog, DialogContent, Kbd, - KbdGroup, } from "@posthog/quill"; import { PROJECT_BLUEBIRD_FLAG } from "@posthog/shared"; import { @@ -438,12 +437,10 @@ export function CommandMenu({ open, onOpenChange }: CommandMenuProps) { )} {cmd.shortcut && ( - - - {formatHotkeyParts(cmd.shortcut).map((part) => ( - {part} - ))} - + + {formatHotkeyParts(cmd.shortcut).map((part) => ( + {part} + ))} )} From 0134afa9e5ce3a92ef8adc4ff158d6478e3d4022 Mon Sep 17 00:00:00 2001 From: Matt Pua Date: Tue, 30 Jun 2026 11:07:07 -0400 Subject: [PATCH 09/14] feat(command-menu): add Go back / Go forward navigation actions Surface history navigation in the command menu's Navigation section with "Go back" and "Go forward" entries, wired to the existing goBackInHistory / goForwardInHistory router bridge and showing their GO_BACK (mod+[) and GO_FORWARD (mod+]) shortcuts right-aligned. Adds the two new action types to CommandMenuAction for analytics. Generated-By: PostHog Code Task-Id: 85b2e7d0-e251-47ac-81bf-217751cd480a --- packages/shared/src/analytics-events.ts | 2 ++ .../ui/src/features/command/CommandMenu.tsx | 30 +++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/packages/shared/src/analytics-events.ts b/packages/shared/src/analytics-events.ts index b174c15a1f..eddc6c2093 100644 --- a/packages/shared/src/analytics-events.ts +++ b/packages/shared/src/analytics-events.ts @@ -47,6 +47,8 @@ export type CommandMenuAction = | "toggle-theme" | "toggle-left-sidebar" | "open-review-panel" + | "go-back" + | "go-forward" | "open-task" | "open-channel"; diff --git a/packages/ui/src/features/command/CommandMenu.tsx b/packages/ui/src/features/command/CommandMenu.tsx index d77a3d4a6e..97cdd06518 100644 --- a/packages/ui/src/features/command/CommandMenu.tsx +++ b/packages/ui/src/features/command/CommandMenu.tsx @@ -1,4 +1,8 @@ -import { HashIcon } from "@phosphor-icons/react"; +import { + CaretLeftIcon, + CaretRightIcon, + HashIcon, +} from "@phosphor-icons/react"; import { Autocomplete, AutocompleteCollection, @@ -36,7 +40,11 @@ import { TaskIcon } from "@posthog/ui/features/sidebar/components/items/TaskIcon import { useSidebarStore } from "@posthog/ui/features/sidebar/sidebarStore"; import { useTaskPrStatus } from "@posthog/ui/features/sidebar/useTaskPrStatus"; import { useTasks } from "@posthog/ui/features/tasks/useTasks"; -import { navigateToChannel } from "@posthog/ui/router/navigationBridge"; +import { + goBackInHistory, + goForwardInHistory, + navigateToChannel, +} from "@posthog/ui/router/navigationBridge"; import { useAppView } from "@posthog/ui/router/useAppView"; import { openTask, openTaskInput } from "@posthog/ui/router/useOpenTask"; import { track } from "@posthog/ui/shell/analytics"; @@ -210,6 +218,24 @@ export function CommandMenu({ open, onOpenChange }: CommandMenuProps) { openTaskInput(); }, }, + { + id: "go-back", + label: "Go back", + keywords: "navigate history previous", + icon: , + action: "go-back", + shortcut: SHORTCUTS.GO_BACK, + onRun: goBackInHistory, + }, + { + id: "go-forward", + label: "Go forward", + keywords: "navigate history next", + icon: , + action: "go-forward", + shortcut: SHORTCUTS.GO_FORWARD, + onRun: goForwardInHistory, + }, { id: "settings", label: "Settings", From 63c3b41fdc0676374b4c6749a37b863d8e2200e9 Mon Sep 17 00:00:00 2001 From: Matt Pua Date: Tue, 30 Jun 2026 11:09:48 -0400 Subject: [PATCH 10/14] fix(command-menu): widen gap between shortcut keys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bump the flex gap between Kbd keycaps from gap-1 to gap-2 so the spacing between keys (e.g. ⌘ and [) is clearly visible. Generated-By: PostHog Code Task-Id: 85b2e7d0-e251-47ac-81bf-217751cd480a --- packages/ui/src/features/command/CommandMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/src/features/command/CommandMenu.tsx b/packages/ui/src/features/command/CommandMenu.tsx index 97cdd06518..7300d0109a 100644 --- a/packages/ui/src/features/command/CommandMenu.tsx +++ b/packages/ui/src/features/command/CommandMenu.tsx @@ -463,7 +463,7 @@ export function CommandMenu({ open, onOpenChange }: CommandMenuProps) { )} {cmd.shortcut && ( - + {formatHotkeyParts(cmd.shortcut).map((part) => ( {part} ))} From 58d34f1964d55c2665d5f54734353010508682fb Mon Sep 17 00:00:00 2001 From: Matt Pua Date: Tue, 30 Jun 2026 11:15:13 -0400 Subject: [PATCH 11/14] style(command-menu): collapse phosphor import to single line Biome's formatter wants the @phosphor-icons/react import on one line since it fits within the print width. Fixes the failing quality check. Generated-By: PostHog Code Task-Id: 85b2e7d0-e251-47ac-81bf-217751cd480a --- packages/ui/src/features/command/CommandMenu.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/ui/src/features/command/CommandMenu.tsx b/packages/ui/src/features/command/CommandMenu.tsx index 7300d0109a..67da59a03d 100644 --- a/packages/ui/src/features/command/CommandMenu.tsx +++ b/packages/ui/src/features/command/CommandMenu.tsx @@ -1,8 +1,4 @@ -import { - CaretLeftIcon, - CaretRightIcon, - HashIcon, -} from "@phosphor-icons/react"; +import { CaretLeftIcon, CaretRightIcon, HashIcon } from "@phosphor-icons/react"; import { Autocomplete, AutocompleteCollection, From ee518806982282d6a631b51755633adbf41e7209 Mon Sep 17 00:00:00 2001 From: Matt Pua Date: Tue, 30 Jun 2026 11:16:28 -0400 Subject: [PATCH 12/14] fix(command-menu): move Go back / Go forward below Settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reorder the Navigation section to Home → Settings → Go back → Go forward so the history actions sit beneath Settings. Generated-By: PostHog Code Task-Id: 85b2e7d0-e251-47ac-81bf-217751cd480a --- packages/ui/src/features/command/CommandMenu.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/ui/src/features/command/CommandMenu.tsx b/packages/ui/src/features/command/CommandMenu.tsx index 67da59a03d..224f0ecf3e 100644 --- a/packages/ui/src/features/command/CommandMenu.tsx +++ b/packages/ui/src/features/command/CommandMenu.tsx @@ -214,6 +214,14 @@ export function CommandMenu({ open, onOpenChange }: CommandMenuProps) { openTaskInput(); }, }, + { + id: "settings", + label: "Settings", + icon: , + action: "settings", + shortcut: SHORTCUTS.SETTINGS, + onRun: () => openSettingsDialog(), + }, { id: "go-back", label: "Go back", @@ -232,14 +240,6 @@ export function CommandMenu({ open, onOpenChange }: CommandMenuProps) { shortcut: SHORTCUTS.GO_FORWARD, onRun: goForwardInHistory, }, - { - id: "settings", - label: "Settings", - icon: , - action: "settings", - shortcut: SHORTCUTS.SETTINGS, - onRun: () => openSettingsDialog(), - }, ]; const actions: Command[] = [ From cf81f7e1cc9e334ae86698ead90952110dd589b3 Mon Sep 17 00:00:00 2001 From: Matt Pua Date: Tue, 30 Jun 2026 11:17:28 -0400 Subject: [PATCH 13/14] fix(command-menu): show Actions section before Navigation Swap the section order so Actions appears first, followed by Navigation. Generated-By: PostHog Code Task-Id: 85b2e7d0-e251-47ac-81bf-217751cd480a --- packages/ui/src/features/command/CommandMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/src/features/command/CommandMenu.tsx b/packages/ui/src/features/command/CommandMenu.tsx index 224f0ecf3e..c1fa5b9aba 100644 --- a/packages/ui/src/features/command/CommandMenu.tsx +++ b/packages/ui/src/features/command/CommandMenu.tsx @@ -281,8 +281,8 @@ export function CommandMenu({ open, onOpenChange }: CommandMenuProps) { ]; const out: CommandSection[] = [ - { label: "Navigation", items: navigation }, { label: "Actions", items: actions }, + { label: "Navigation", items: navigation }, ]; if (folders.length > 0) { From e327ae639fcc35c2f4a97f82e916f4ce22bf4be1 Mon Sep 17 00:00:00 2001 From: Matt Pua Date: Tue, 30 Jun 2026 12:10:54 -0400 Subject: [PATCH 14/14] feat(command-menu): add Developer section with reload window and show log folder (#3031) --- .../electron-storage-paths.ts | 6 +++++ packages/host-router/src/routers/os.router.ts | 4 ++++ packages/platform/src/storage-paths.ts | 1 + packages/shared/src/analytics-events.ts | 4 +++- .../ui/src/features/command/CommandMenu.tsx | 23 +++++++++++++++++++ .../features/command/keyboard-shortcuts.ts | 1 + packages/ui/src/shell/GlobalEventHandlers.tsx | 5 ++++ packages/ui/src/shell/openExternal.ts | 6 +++++ .../src/services/os/os.test.ts | 15 ++++++++++++ .../workspace-server/src/services/os/os.ts | 13 +++++++++++ 10 files changed, 77 insertions(+), 1 deletion(-) diff --git a/apps/code/src/main/platform-adapters/electron-storage-paths.ts b/apps/code/src/main/platform-adapters/electron-storage-paths.ts index 4bdbf639b2..e92e1e4d86 100644 --- a/apps/code/src/main/platform-adapters/electron-storage-paths.ts +++ b/apps/code/src/main/platform-adapters/electron-storage-paths.ts @@ -1,6 +1,8 @@ +import { dirname } from "node:path"; import type { IStoragePaths } from "@posthog/platform/storage-paths"; import { app } from "electron"; import { injectable } from "inversify"; +import { getLogFilePath } from "../utils/logger"; @injectable() export class ElectronStoragePaths implements IStoragePaths { @@ -11,4 +13,8 @@ export class ElectronStoragePaths implements IStoragePaths { public get logsPath(): string { return app.getPath("logs"); } + + public get logFolderPath(): string { + return dirname(getLogFilePath()); + } } diff --git a/packages/host-router/src/routers/os.router.ts b/packages/host-router/src/routers/os.router.ts index d4d541d158..77cd41f094 100644 --- a/packages/host-router/src/routers/os.router.ts +++ b/packages/host-router/src/routers/os.router.ts @@ -59,6 +59,10 @@ export const osRouter = router({ ctx.container.get(OS_SERVICE).openExternal(input.url), ), + showLogFolder: publicProcedure.mutation(({ ctx }) => + ctx.container.get(OS_SERVICE).showLogFolder(), + ), + searchDirectories: publicProcedure .input(searchDirectoriesInput) .query(({ ctx, input }) => diff --git a/packages/platform/src/storage-paths.ts b/packages/platform/src/storage-paths.ts index 23e6c9340d..b877c50301 100644 --- a/packages/platform/src/storage-paths.ts +++ b/packages/platform/src/storage-paths.ts @@ -1,6 +1,7 @@ export interface IStoragePaths { readonly appDataPath: string; readonly logsPath: string; + readonly logFolderPath: string; } export const STORAGE_PATHS_SERVICE = Symbol.for( diff --git a/packages/shared/src/analytics-events.ts b/packages/shared/src/analytics-events.ts index eddc6c2093..47d81f2ddc 100644 --- a/packages/shared/src/analytics-events.ts +++ b/packages/shared/src/analytics-events.ts @@ -50,7 +50,9 @@ export type CommandMenuAction = | "go-back" | "go-forward" | "open-task" - | "open-channel"; + | "open-channel" + | "reload-window" + | "show-log-folder"; // Event property interfaces export interface TaskListViewProperties { diff --git a/packages/ui/src/features/command/CommandMenu.tsx b/packages/ui/src/features/command/CommandMenu.tsx index c1fa5b9aba..43a7cf7e26 100644 --- a/packages/ui/src/features/command/CommandMenu.tsx +++ b/packages/ui/src/features/command/CommandMenu.tsx @@ -44,6 +44,7 @@ import { import { useAppView } from "@posthog/ui/router/useAppView"; import { openTask, openTaskInput } from "@posthog/ui/router/useOpenTask"; import { track } from "@posthog/ui/shell/analytics"; +import { showLogFolder } from "@posthog/ui/shell/openExternal"; import { useThemeStore } from "@posthog/ui/shell/themeStore"; import { DesktopIcon, @@ -51,6 +52,7 @@ import { GearIcon, HomeIcon, MoonIcon, + ReloadIcon, SunIcon, ViewVerticalIcon, } from "@radix-ui/react-icons"; @@ -280,9 +282,30 @@ export function CommandMenu({ open, onOpenChange }: CommandMenuProps) { }, ]; + const developer: Command[] = [ + { + id: "show-log-folder", + label: "Show log folder", + keywords: "logs debug files finder", + icon: , + action: "show-log-folder", + onRun: showLogFolder, + }, + { + id: "reload-window", + label: "Reload window", + keywords: "refresh restart", + icon: , + action: "reload-window", + shortcut: SHORTCUTS.RELOAD_WINDOW, + onRun: () => window.location.reload(), + }, + ]; + const out: CommandSection[] = [ { label: "Actions", items: actions }, { label: "Navigation", items: navigation }, + { label: "Developer", items: developer }, ]; if (folders.length > 0) { diff --git a/packages/ui/src/features/command/keyboard-shortcuts.ts b/packages/ui/src/features/command/keyboard-shortcuts.ts index adc2bc2c19..87ecb99e35 100644 --- a/packages/ui/src/features/command/keyboard-shortcuts.ts +++ b/packages/ui/src/features/command/keyboard-shortcuts.ts @@ -25,6 +25,7 @@ export const SHORTCUTS = { BLUR: "escape", SUBMIT_BLUR: "mod+enter", SWITCH_MESSAGING_MODE: "mod+s", + RELOAD_WINDOW: "mod+shift+r", } as const; export type ShortcutCategory = "general" | "navigation" | "panels" | "editor"; diff --git a/packages/ui/src/shell/GlobalEventHandlers.tsx b/packages/ui/src/shell/GlobalEventHandlers.tsx index 7c1552752c..4664c87964 100644 --- a/packages/ui/src/shell/GlobalEventHandlers.tsx +++ b/packages/ui/src/shell/GlobalEventHandlers.tsx @@ -167,6 +167,11 @@ export function GlobalEventHandlers({ setReviewMode(currentTaskId, mode === "closed" ? "split" : "closed"); }, [currentTaskId, getReviewMode, setReviewMode]); + useHotkeys( + SHORTCUTS.RELOAD_WINDOW, + () => window.location.reload(), + globalOptions, + ); useHotkeys(SHORTCUTS.TOGGLE_LEFT_SIDEBAR, toggleLeftSidebar, globalOptions); useHotkeys(SHORTCUTS.TOGGLE_REVIEW_PANEL, handleToggleReview, globalOptions); useHotkeys(SHORTCUTS.SHORTCUTS_SHEET, onToggleShortcutsSheet, globalOptions); diff --git a/packages/ui/src/shell/openExternal.ts b/packages/ui/src/shell/openExternal.ts index c566ed861b..3d6613a45c 100644 --- a/packages/ui/src/shell/openExternal.ts +++ b/packages/ui/src/shell/openExternal.ts @@ -9,3 +9,9 @@ export function openExternalUrl(url: string): void { url, }); } + +export function showLogFolder(): void { + void resolveService( + HOST_TRPC_CLIENT, + ).os.showLogFolder.mutate(); +} diff --git a/packages/workspace-server/src/services/os/os.test.ts b/packages/workspace-server/src/services/os/os.test.ts index 88ced62bce..dc0b0ce676 100644 --- a/packages/workspace-server/src/services/os/os.test.ts +++ b/packages/workspace-server/src/services/os/os.test.ts @@ -32,12 +32,19 @@ function createService() { getWorktreeLocation: vi.fn(() => "/tmp/worktrees"), }; + const storagePaths = { + appDataPath: "/data", + logsPath: "/logs", + logFolderPath: "/logs", + }; + const service = new OsService( dialog as never, urlLauncher as never, appMeta as never, imageProcessor as never, workspaceSettings as never, + storagePaths as never, ); return { service, dialog, urlLauncher, appMeta, workspaceSettings }; @@ -152,6 +159,14 @@ describe("OsService simple delegations", () => { await service.openExternal("https://posthog.com"); expect(urlLauncher.launch).toHaveBeenCalledWith("https://posthog.com"); }); + + it("opens the log folder as a file URL via the url launcher", async () => { + const { service, urlLauncher } = createService(); + await service.showLogFolder(); + expect(urlLauncher.launch).toHaveBeenCalledWith( + expect.stringMatching(/^file:\/\//), + ); + }); }); describe("OsService.getClaudePermissions", () => { diff --git a/packages/workspace-server/src/services/os/os.ts b/packages/workspace-server/src/services/os/os.ts index 73cc7cca14..08a3b1d065 100644 --- a/packages/workspace-server/src/services/os/os.ts +++ b/packages/workspace-server/src/services/os/os.ts @@ -1,6 +1,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; +import { pathToFileURL } from "node:url"; import { APP_META_SERVICE, type IAppMeta } from "@posthog/platform/app-meta"; import { DIALOG_SERVICE, @@ -11,6 +12,10 @@ import { type IImageProcessor, IMAGE_PROCESSOR_SERVICE, } from "@posthog/platform/image-processor"; +import { + type IStoragePaths, + STORAGE_PATHS_SERVICE, +} from "@posthog/platform/storage-paths"; import { type IUrlLauncher, URL_LAUNCHER_SERVICE, @@ -55,6 +60,8 @@ export class OsService { private readonly imageProcessor: IImageProcessor, @inject(WORKSPACE_SETTINGS_SERVICE) private readonly workspaceSettings: IWorkspaceSettings, + @inject(STORAGE_PATHS_SERVICE) + private readonly storagePaths: IStoragePaths, ) {} async getClaudePermissions(): Promise { @@ -162,6 +169,12 @@ export class OsService { await this.urlLauncher.launch(url); } + async showLogFolder(): Promise { + await this.urlLauncher.launch( + pathToFileURL(this.storagePaths.logFolderPath).href, + ); + } + async searchDirectories(query: string): Promise { if (!query?.trim()) return [];