From fe49acb67099341b1e6ae4bd076982b231d30eda Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Sun, 6 Sep 2026 03:55:29 -0700 Subject: [PATCH] refactor(desktop): import-session entry is a sidebar nav row; browser module named as a foreign_sessions sibling - Sidebar: the entry joins SIDEBAR_NAV (same chrome, active state, data-tour handle as the other rows) instead of a one-off Button below the rail; i18n moves to sidebar.nav['session-import']. - Reuse common.retry / common.refresh / common.back instead of duplicating them under sessionImport in six locales. - hermes_cli/foreign_session_browser.py -> foreign_sessions_browser.py so it sorts as a sibling of the foreign_sessions module it extends. --- apps/desktop/src/app/chat/sidebar/index.tsx | 19 +++++++++---------- apps/desktop/src/app/session-import/index.tsx | 8 ++++---- apps/desktop/src/app/types.ts | 3 ++- apps/desktop/src/i18n/ar.ts | 6 ++---- apps/desktop/src/i18n/en.ts | 6 ++---- apps/desktop/src/i18n/ja.ts | 6 ++---- apps/desktop/src/i18n/ru.ts | 6 ++---- apps/desktop/src/i18n/types.ts | 3 --- apps/desktop/src/i18n/zh-hant.ts | 6 ++---- apps/desktop/src/i18n/zh.ts | 6 ++---- ...browser.py => foreign_sessions_browser.py} | 0 ...er.py => test_foreign_sessions_browser.py} | 2 +- tests/tui_gateway/test_session_foreign.py | 2 +- tui_gateway/methods_session_foreign.py | 4 ++-- 14 files changed, 31 insertions(+), 46 deletions(-) rename hermes_cli/{foreign_session_browser.py => foreign_sessions_browser.py} (100%) rename tests/hermes_cli/{test_foreign_session_browser.py => test_foreign_sessions_browser.py} (94%) diff --git a/apps/desktop/src/app/chat/sidebar/index.tsx b/apps/desktop/src/app/chat/sidebar/index.tsx index 0aefa90e30..6fcd656da3 100644 --- a/apps/desktop/src/app/chat/sidebar/index.tsx +++ b/apps/desktop/src/app/chat/sidebar/index.tsx @@ -3,10 +3,9 @@ import { sortableKeyboardCoordinates } from '@dnd-kit/sortable' import { useStore } from '@nanostores/react' import type * as React from 'react' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { useLocation, useNavigate } from 'react-router' +import { useLocation } from 'react-router' import { PlatformAvatar } from '@/app/messaging/platform-icon' -import { SESSION_IMPORT_ROUTE } from '@/app/routes' import { Button } from '@/components/ui/button' import { Codicon } from '@/components/ui/codicon' import { ContextMenu, ContextMenuContent, ContextMenuTrigger } from '@/components/ui/context-menu' @@ -140,6 +139,7 @@ import { ARTIFACTS_ROUTE, CRON_ROUTE, MESSAGING_ROUTE, + SESSION_IMPORT_ROUTE, SIDEBAR_NAV_AREA, type SidebarNavContribution, SKILLS_ROUTE @@ -226,6 +226,12 @@ const SIDEBAR_NAV: SidebarNavItem[] = [ icon: props => , route: CRON_ROUTE, keybindActionId: 'nav.cron' + }, + { + id: 'session-import', + label: '', + icon: props => , + route: SESSION_IMPORT_ROUTE } ] @@ -334,7 +340,6 @@ export function ChatSidebar({ const { t } = useI18n() const s = t.sidebar const { pathname } = useLocation() - const navigate = useNavigate() // Contributed nav rows (plugins pairing a page with a sidebar entry) render // below the built-ins with the same chrome; active = at their route. const navContributions = useContributions(SIDEBAR_NAV_AREA) @@ -1499,6 +1504,7 @@ export function ChatSidebar({ (item.id === 'messaging' && currentView === 'messaging') || (item.id === 'artifacts' && currentView === 'artifacts') || (item.id === 'cron' && currentView === 'cron') || + (item.id === 'session-import' && currentView === 'session-import') || // Contributed rows light up at their own route. (Boolean(item.route) && pathname === item.route) @@ -1619,13 +1625,6 @@ export function ChatSidebar({ -
- -
- {showSessionSections && (
{ void sessions.refetch() @@ -183,7 +183,7 @@ export function SessionImportView({ owner, onClose, onOpenSession }: SessionImpo {sessions.isError && ( )} @@ -261,7 +261,7 @@ export function SessionImportView({ owner, onClose, onOpenSession }: SessionImpo

{current.title}

@@ -274,7 +274,7 @@ export function SessionImportView({ owner, onClose, onOpenSession }: SessionImpo {preview.isError && ( )} diff --git a/apps/desktop/src/app/types.ts b/apps/desktop/src/app/types.ts index 57e85a0a9c..4d3f7545f1 100644 --- a/apps/desktop/src/app/types.ts +++ b/apps/desktop/src/app/types.ts @@ -162,7 +162,8 @@ export type CommandDispatchResponse = | SendCommandDispatchResponse | PrefillCommandDispatchResponse -export type SidebarNavId = 'artifacts' | 'command-center' | 'cron' | 'messaging' | 'new-session' | 'settings' | 'skills' +export type SidebarNavId = + 'artifacts' | 'command-center' | 'cron' | 'messaging' | 'new-session' | 'session-import' | 'settings' | 'skills' export interface SidebarNavItem { /** Built-in view id, or a contributed row's namespaced contribution id. */ diff --git a/apps/desktop/src/i18n/ar.ts b/apps/desktop/src/i18n/ar.ts index 007e631917..abc18ada1b 100644 --- a/apps/desktop/src/i18n/ar.ts +++ b/apps/desktop/src/i18n/ar.ts @@ -2,7 +2,6 @@ import { defineLocale } from './define-locale' export const ar = defineLocale({ sessionImport: { - refresh: 'تحديث الجلسات', title: 'المتابعة من تطبيق آخر', subtitle: 'انقل محادثة إلى Hermes وتابع من حيث توقفت.', action: 'استيراد جلسة', @@ -12,7 +11,6 @@ export const ar = defineLocale({ all: 'الكل', search: 'البحث في الجلسات المحملة', scanning: 'جارٍ البحث عن المحادثات', - retry: 'حاول مرة أخرى', scanError: 'تعذر العثور على الجلسات', scanHelp: 'تحقق من اتصال الخادم ثم أعد المحاولة. قد تحتاج الخوادم القديمة إلى تحديث.', empty: 'لا توجد محادثات', @@ -24,7 +22,6 @@ export const ar = defineLocale({ messages: 'رسائل', choose: 'محادثة تستحق المتابعة', chooseHelp: 'اختر جلسة لقراءة سجلها قبل نقلها إلى Hermes.', - back: 'العودة إلى الجلسات', previewLoading: 'جارٍ فتح المعاينة', previewError: 'المعاينة غير متاحة', previewHelp: 'ربما تم نقل الملف الأصلي أو تغييره. حدّث القائمة وحاول مرة أخرى.', @@ -1734,7 +1731,8 @@ export const ar = defineLocale({ chat: 'المحادثة', settings: 'الإعدادات', cron: 'المهام المجدولة', - agents: 'الوكلاء' + agents: 'الوكلاء', + 'session-import': 'استيراد جلسة' }, searchAria: 'البحث في الجلسات', searchPlaceholder: 'البحث في الجلسات...', diff --git a/apps/desktop/src/i18n/en.ts b/apps/desktop/src/i18n/en.ts index 7a1eef6084..a3d966fb3f 100644 --- a/apps/desktop/src/i18n/en.ts +++ b/apps/desktop/src/i18n/en.ts @@ -4,7 +4,6 @@ import type { Translations } from './types' export const en: Translations = { sessionImport: { - refresh: 'Refresh sessions', title: 'Continue from another app', subtitle: 'Bring a conversation into Hermes and pick up where you left off.', action: 'Import session', @@ -14,7 +13,6 @@ export const en: Translations = { all: 'All', search: 'Search loaded sessions', scanning: 'Finding conversations', - retry: 'Try again', scanError: 'Could not find sessions', scanHelp: 'Check your backend connection, then try again. Older backends may need an update.', empty: 'No conversations found', @@ -26,7 +24,6 @@ export const en: Translations = { messages: 'messages', choose: 'A conversation worth continuing', chooseHelp: 'Choose a session to read its history before bringing it into Hermes.', - back: 'Back to sessions', previewLoading: 'Opening preview', previewError: 'Preview unavailable', previewHelp: 'The source may have moved or changed. Refresh the list and try again.', @@ -2360,7 +2357,8 @@ export const en: Translations = { skills: 'Capabilities', messaging: 'Messaging', artifacts: 'Artifacts', - cron: 'Scheduled jobs' + cron: 'Scheduled jobs', + 'session-import': 'Import session' }, searchAria: 'Search sessions', searchPlaceholder: 'Search sessions…', diff --git a/apps/desktop/src/i18n/ja.ts b/apps/desktop/src/i18n/ja.ts index e7f5c7cbf4..f49de611dc 100644 --- a/apps/desktop/src/i18n/ja.ts +++ b/apps/desktop/src/i18n/ja.ts @@ -4,7 +4,6 @@ import { defineLocale } from './define-locale' export const ja = defineLocale({ sessionImport: { - refresh: '一覧を更新', title: '別のアプリから続ける', subtitle: '会話をHermesに取り込み、続きを始めましょう。', action: 'セッションを取り込む', @@ -14,7 +13,6 @@ export const ja = defineLocale({ all: 'すべて', search: '読み込み済みのセッションを検索', scanning: '会話を検索中', - retry: '再試行', scanError: 'セッションを取得できません', scanHelp: 'バックエンドの接続を確認して再試行してください。古いバックエンドは更新が必要な場合があります。', empty: '会話が見つかりません', @@ -26,7 +24,6 @@ export const ja = defineLocale({ messages: 'メッセージ', choose: '会話の続きを始めましょう', chooseHelp: 'セッションを選び、取り込む前に履歴を確認できます。', - back: 'セッションに戻る', previewLoading: 'プレビューを開いています', previewError: 'プレビューできません', previewHelp: '元のファイルが移動または変更された可能性があります。一覧を更新してください。', @@ -2034,7 +2031,8 @@ export const ja = defineLocale({ skills: 'スキルとツール', messaging: 'メッセージング', artifacts: 'アーティファクト', - cron: 'スケジュール済みジョブ' + cron: 'スケジュール済みジョブ', + 'session-import': 'セッションを取り込む' }, searchAria: 'セッションを検索', searchPlaceholder: 'セッションを検索…', diff --git a/apps/desktop/src/i18n/ru.ts b/apps/desktop/src/i18n/ru.ts index a82750482a..a43567045f 100644 --- a/apps/desktop/src/i18n/ru.ts +++ b/apps/desktop/src/i18n/ru.ts @@ -25,7 +25,6 @@ const RU_NOUN = (count: number | string, one: string, few: string, many: string) export const ru = defineLocale({ sessionImport: { - refresh: 'Обновить сессии', title: 'Продолжить из другого приложения', subtitle: 'Перенесите разговор в Hermes и продолжите с того места, где остановились.', action: 'Импортировать сессию', @@ -35,7 +34,6 @@ export const ru = defineLocale({ all: 'Все', search: 'Поиск по загруженным сессиям', scanning: 'Поиск разговоров', - retry: 'Повторить', scanError: 'Не удалось найти сессии', scanHelp: 'Проверьте подключение к серверу и повторите попытку. Старому серверу может требоваться обновление.', empty: 'Разговоров пока нет', @@ -47,7 +45,6 @@ export const ru = defineLocale({ messages: 'сообщений', choose: 'Разговор, который стоит продолжить', chooseHelp: 'Выберите сессию, чтобы прочитать историю перед импортом в Hermes.', - back: 'Назад к сессиям', previewLoading: 'Открываем просмотр', previewError: 'Просмотр недоступен', previewHelp: 'Исходный файл мог переместиться или измениться. Обновите список и повторите попытку.', @@ -2396,7 +2393,8 @@ export const ru = defineLocale({ skills: 'Возможности', messaging: 'Сообщения', artifacts: 'Артефакты', - cron: 'Запланированные задачи' + cron: 'Запланированные задачи', + 'session-import': 'Импортировать сессию' }, searchAria: 'Поиск сеансов', searchPlaceholder: 'Поиск сеансов…', diff --git a/apps/desktop/src/i18n/types.ts b/apps/desktop/src/i18n/types.ts index b8dcc14adf..40557297a9 100644 --- a/apps/desktop/src/i18n/types.ts +++ b/apps/desktop/src/i18n/types.ts @@ -52,7 +52,6 @@ interface AuxTaskCopy { export interface Translations { sessionImport: { - refresh: string title: string subtitle: string action: string @@ -62,7 +61,6 @@ export interface Translations { all: string search: string scanning: string - retry: string scanError: string scanHelp: string empty: string @@ -74,7 +72,6 @@ export interface Translations { messages: string choose: string chooseHelp: string - back: string previewLoading: string previewError: string previewHelp: string diff --git a/apps/desktop/src/i18n/zh-hant.ts b/apps/desktop/src/i18n/zh-hant.ts index 50a5a8b689..f73e8883ef 100644 --- a/apps/desktop/src/i18n/zh-hant.ts +++ b/apps/desktop/src/i18n/zh-hant.ts @@ -4,7 +4,6 @@ import { defineLocale } from './define-locale' export const zhHant = defineLocale({ sessionImport: { - refresh: '重新整理工作階段', title: '從其他應用程式繼續', subtitle: '將對話匯入 Hermes,接著上次的進度繼續。', action: '匯入工作階段', @@ -14,7 +13,6 @@ export const zhHant = defineLocale({ all: '全部', search: '搜尋已載入的工作階段', scanning: '正在尋找對話', - retry: '重試', scanError: '無法尋找工作階段', scanHelp: '請檢查後端連線並重試。舊版後端可能需要更新。', empty: '找不到對話', @@ -26,7 +24,6 @@ export const zhHant = defineLocale({ messages: '則訊息', choose: '繼續一段對話', chooseHelp: '選擇工作階段,在匯入 Hermes 前查看歷程記錄。', - back: '返回工作階段', previewLoading: '正在開啟預覽', previewError: '無法預覽', previewHelp: '來源檔案可能已移動或變更。請重新整理清單後重試。', @@ -1959,7 +1956,8 @@ export const zhHant = defineLocale({ skills: '技能與工具', messaging: '訊息平台', artifacts: '成品', - cron: '排程工作' + cron: '排程工作', + 'session-import': '匯入工作階段' }, searchAria: '搜尋工作階段', searchPlaceholder: '搜尋工作階段…', diff --git a/apps/desktop/src/i18n/zh.ts b/apps/desktop/src/i18n/zh.ts index 9ca3534e73..501e19b3a6 100644 --- a/apps/desktop/src/i18n/zh.ts +++ b/apps/desktop/src/i18n/zh.ts @@ -4,7 +4,6 @@ import type { Translations } from './types' export const zh: Translations = { sessionImport: { - refresh: '刷新会话', title: '从其他应用继续', subtitle: '将对话导入 Hermes,接着上次的进度继续。', action: '导入会话', @@ -14,7 +13,6 @@ export const zh: Translations = { all: '全部', search: '搜索已加载的会话', scanning: '正在查找对话', - retry: '重试', scanError: '无法查找会话', scanHelp: '请检查后端连接并重试。旧版后端可能需要更新。', empty: '未找到对话', @@ -26,7 +24,6 @@ export const zh: Translations = { messages: '条消息', choose: '继续一段对话', chooseHelp: '选择会话,在导入 Hermes 前查看历史记录。', - back: '返回会话列表', previewLoading: '正在打开预览', previewError: '预览不可用', previewHelp: '源文件可能已移动或更改。请刷新列表后重试。', @@ -2526,7 +2523,8 @@ export const zh: Translations = { skills: '技能与工具', messaging: '消息平台', artifacts: '产物', - cron: '定时任务' + cron: '定时任务', + 'session-import': '导入会话' }, searchAria: '搜索会话', searchPlaceholder: '搜索会话…', diff --git a/hermes_cli/foreign_session_browser.py b/hermes_cli/foreign_sessions_browser.py similarity index 100% rename from hermes_cli/foreign_session_browser.py rename to hermes_cli/foreign_sessions_browser.py diff --git a/tests/hermes_cli/test_foreign_session_browser.py b/tests/hermes_cli/test_foreign_sessions_browser.py similarity index 94% rename from tests/hermes_cli/test_foreign_session_browser.py rename to tests/hermes_cli/test_foreign_sessions_browser.py index 9f2565799e..e43ba6eb2f 100644 --- a/tests/hermes_cli/test_foreign_session_browser.py +++ b/tests/hermes_cli/test_foreign_sessions_browser.py @@ -5,7 +5,7 @@ from pathlib import Path import pytest -from hermes_cli.foreign_session_browser import list_foreign_sessions +from hermes_cli.foreign_sessions_browser import list_foreign_sessions @pytest.mark.parametrize("operation", ["resolve", "stat"]) diff --git a/tests/tui_gateway/test_session_foreign.py b/tests/tui_gateway/test_session_foreign.py index fa8b4b93df..355d2053c5 100644 --- a/tests/tui_gateway/test_session_foreign.py +++ b/tests/tui_gateway/test_session_foreign.py @@ -60,7 +60,7 @@ def test_foreign_rpc_preview_import_and_profile_isolation(tmp_path, monkeypatch) def test_foreign_pages_confine_handles_and_failed_import_rolls_back(tmp_path, monkeypatch): - from hermes_cli import foreign_session_browser as browser + from hermes_cli import foreign_sessions_browser as browser from hermes_state import SessionDB monkeypatch.setattr(Path, "home", lambda: tmp_path) diff --git a/tui_gateway/methods_session_foreign.py b/tui_gateway/methods_session_foreign.py index 82fc7edf15..ba37ad8580 100644 --- a/tui_gateway/methods_session_foreign.py +++ b/tui_gateway/methods_session_foreign.py @@ -8,7 +8,7 @@ method = _registry.method @method("session.foreign.list") def _foreign_list(rid, params): - from hermes_cli.foreign_session_browser import list_foreign_sessions + from hermes_cli.foreign_sessions_browser import list_foreign_sessions try: return _ok(rid, list_foreign_sessions(params.get("source"), params.get("offset", 0), params.get("limit", 25))) except ValueError as exc: @@ -18,7 +18,7 @@ def _foreign_list(rid, params): def _foreign_history_request(rid, params, importing): - from hermes_cli.foreign_session_browser import import_browser_session, preview_foreign_session + from hermes_cli.foreign_sessions_browser import import_browser_session, preview_foreign_session try: with _profile_db(params) as db: if db is None: