diff --git a/apps/desktop/src/app/chat/hooks/use-composer-actions.ts b/apps/desktop/src/app/chat/hooks/use-composer-actions.ts index ecc13808413..a8afdd12830 100644 --- a/apps/desktop/src/app/chat/hooks/use-composer-actions.ts +++ b/apps/desktop/src/app/chat/hooks/use-composer-actions.ts @@ -5,6 +5,7 @@ import { droppedFileInlineRef } from '@/app/chat/composer/inline-refs' import { formatRefValue } from '@/components/assistant-ui/directive-text' import { useI18n } from '@/i18n' import { attachmentId, contextPath, pathLabel } from '@/lib/chat-runtime' +import { readDesktopFileDataUrl, selectDesktopPaths } from '@/lib/desktop-fs' import { addComposerAttachment, type ComposerAttachment, @@ -262,7 +263,7 @@ export function useComposerActions({ activeSessionId, currentCwd, requestGateway const pickContextPaths = useCallback( async (kind: 'file' | 'folder') => { - const paths = await window.hermesDesktop?.selectPaths({ + const paths = await selectDesktopPaths({ title: kind === 'file' ? 'Add files as context' : 'Add folders as context', defaultPath: currentCwd || undefined, directories: kind === 'folder' @@ -347,7 +348,7 @@ export function useComposerActions({ activeSessionId, currentCwd, requestGateway attachToMain(baseAttachment) try { - const previewUrl = await window.hermesDesktop?.readFileDataUrl(filePath) + const previewUrl = await readDesktopFileDataUrl(filePath) if (previewUrl) { addComposerAttachment({ ...baseAttachment, previewUrl }) @@ -395,7 +396,7 @@ export function useComposerActions({ activeSessionId, currentCwd, requestGateway ) const pickImages = useCallback(async () => { - const paths = await window.hermesDesktop?.selectPaths({ + const paths = await selectDesktopPaths({ title: copy.attachImages, defaultPath: currentCwd || undefined, filters: [ diff --git a/apps/desktop/src/app/chat/sidebar/index.tsx b/apps/desktop/src/app/chat/sidebar/index.tsx index 19665341f3d..ca38d65908b 100644 --- a/apps/desktop/src/app/chat/sidebar/index.tsx +++ b/apps/desktop/src/app/chat/sidebar/index.tsx @@ -1149,7 +1149,8 @@ export function ChatSidebar({ const showSessionSkeletons = sessionsLoading && sortedSessions.length === 0 - const showSessionSections = showSessionSkeletons || sortedSessions.length > 0 + const showSessionSections = + showSessionSkeletons || sortedSessions.length > 0 || projectModel.length > 0 // Each reorderable list reports its OWN new id order; persisting is a direct, // typed write — no id-prefix sniffing to figure out which level moved. @@ -1537,7 +1538,7 @@ export function ChatSidebar({ )} - {contentVisible && !showSessionSections &&
} + {contentVisible && !showSessionSections && } {contentVisible && (
@@ -1618,6 +1619,29 @@ function SidebarSessionSkeletons() { ) } +function SidebarBlankState({ onNewProject }: { onNewProject: () => void }) { + const { t } = useI18n() + const s = t.sidebar + + return ( +
+
+ +

{s.noSessions}

+ +
+
+ ) +} + function SidebarPinnedEmptyState() { const { t } = useI18n() diff --git a/apps/desktop/src/app/chat/sidebar/project-dialog.tsx b/apps/desktop/src/app/chat/sidebar/project-dialog.tsx index 16cbb04983d..dcd9f067f43 100644 --- a/apps/desktop/src/app/chat/sidebar/project-dialog.tsx +++ b/apps/desktop/src/app/chat/sidebar/project-dialog.tsx @@ -87,21 +87,25 @@ export function ProjectDialog() { } const pickFolder = async () => { - const dir = await pickProjectFolder() + try { + const dir = await pickProjectFolder() - if (!dir) { - return + if (!dir) { + return + } + + const projectId = state?.projectId + + if (mode === 'add-folder' && projectId) { + await runSubmit(() => addProjectFolder(projectId, dir)) + + return + } + + setFolders(prev => (prev.includes(dir) ? prev : [...prev, dir])) + } catch (err) { + notifyError(err, p.createFailed) } - - const projectId = state?.projectId - - if (mode === 'add-folder' && projectId) { - await runSubmit(() => addProjectFolder(projectId, dir)) - - return - } - - setFolders(prev => (prev.includes(dir) ? prev : [...prev, dir])) } const submit = async () => { @@ -145,7 +149,10 @@ export function ProjectDialog() { return ( - + event.preventDefault()} + > {title} {mode === 'create' && {p.createDesc}} diff --git a/apps/desktop/src/app/chat/sidebar/projects/model.ts b/apps/desktop/src/app/chat/sidebar/projects/model.ts index e5931f0bcb8..1c17c676e0c 100644 --- a/apps/desktop/src/app/chat/sidebar/projects/model.ts +++ b/apps/desktop/src/app/chat/sidebar/projects/model.ts @@ -3,6 +3,7 @@ import { useEffect, useMemo, useState } from 'react' import type { HermesGitWorktree } from '@/global' import type { SessionInfo } from '@/hermes' +import { desktopGit } from '@/lib/desktop-git' import { mapPool } from '@/lib/pool' import { $sidebarWorkspaceCollapsedIds, toggleWorkspaceNodeCollapsed } from '@/store/layout' import { $worktreeRefreshToken } from '@/store/projects' @@ -88,7 +89,7 @@ export function useRepoWorktreeMap( const refreshToken = useStore($worktreeRefreshToken) useEffect(() => { - const git = window.hermesDesktop?.git + const git = desktopGit() if (!enabled || !repoPaths.length || !git?.worktreeList) { setMap({}) diff --git a/apps/desktop/src/app/desktop-controller.tsx b/apps/desktop/src/app/desktop-controller.tsx index 9df44d628ce..f9dc2d8320b 100644 --- a/apps/desktop/src/app/desktop-controller.tsx +++ b/apps/desktop/src/app/desktop-controller.tsx @@ -124,6 +124,7 @@ import { ModelVisibilityOverlay } from './model-visibility-overlay' import { PetGenerateOverlay } from './pet-generate/pet-generate-overlay' import { RightSidebarPane } from './right-sidebar' import { FileActionDialogs } from './right-sidebar/file-actions' +import { RemoteFolderPicker } from './right-sidebar/files/remote-picker' import { ReviewPane } from './right-sidebar/review' import { $terminalTakeover } from './right-sidebar/store' import { PersistentTerminal, TerminalSlot } from './right-sidebar/terminal/persistent' @@ -1127,6 +1128,7 @@ export function DesktopController() { + {settingsOpen && ( diff --git a/apps/desktop/src/app/right-sidebar/files/remote-picker.tsx b/apps/desktop/src/app/right-sidebar/files/remote-picker.tsx index 9f7244693bc..66c24ed40a2 100644 --- a/apps/desktop/src/app/right-sidebar/files/remote-picker.tsx +++ b/apps/desktop/src/app/right-sidebar/files/remote-picker.tsx @@ -120,14 +120,14 @@ export function RemoteFolderPicker() { return ( !open && close()} open={Boolean(pending)}> - -
+ +
{pending?.title || r.remotePickerTitle} {r.remotePickerDescription}
-
-
+
+
{crumbs.map((crumb, index) => (
-
+
{currentPath}