feat(sidebar): add per-folder color swatch with picker and neutral conversation rail
- Add `color` column to folder table with migration backfill and hash-based assignment on folder creation - Expose `update_folder_color` via Tauri command and `/update_folder_color` HTTP route - Render a color swatch before each folder name in the sidebar header; offer a 10-color palette (9 hues plus a theme-aware foreground sentinel) through the folder context menu - Show the folder header "new conversation" button only on hover - Drop the expanded-state tint on folder name and count badge; use a fixed neutral rail color for conversation items
This commit is contained in:
@@ -125,10 +125,7 @@ export const SidebarConversationCard = memo(function SidebarConversationCard({
|
||||
<span
|
||||
aria-hidden
|
||||
className={cn(
|
||||
"pointer-events-none absolute z-0",
|
||||
isOpenInTab
|
||||
? "bg-sidebar-primary/85"
|
||||
: "bg-sidebar-primary/30"
|
||||
"pointer-events-none absolute z-0 bg-sidebar-border"
|
||||
)}
|
||||
style={{
|
||||
top: "-0.0625rem",
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
GitBranch,
|
||||
ListChecks,
|
||||
Loader2,
|
||||
Palette,
|
||||
Plus,
|
||||
Rocket,
|
||||
XCircle,
|
||||
@@ -36,6 +37,7 @@ import {
|
||||
openProjectBootWindow,
|
||||
updateConversationTitle,
|
||||
updateConversationStatus,
|
||||
updateFolderColor,
|
||||
deleteConversation,
|
||||
} from "@/lib/api"
|
||||
import { isDesktop, openFileDialog } from "@/lib/platform"
|
||||
@@ -58,6 +60,9 @@ import {
|
||||
ContextMenuContent,
|
||||
ContextMenuItem,
|
||||
ContextMenuSeparator,
|
||||
ContextMenuSub,
|
||||
ContextMenuSubContent,
|
||||
ContextMenuSubTrigger,
|
||||
} from "@/components/ui/context-menu"
|
||||
import {
|
||||
AlertDialog,
|
||||
@@ -106,6 +111,31 @@ function compareByCreatedAtDesc(
|
||||
return right.id - left.id
|
||||
}
|
||||
|
||||
// Sentinel stored in the DB that resolves to the current sidebar foreground
|
||||
// color — the swatch then always reads as the folder name does, across themes.
|
||||
const FOREGROUND_SWATCH = "foreground"
|
||||
|
||||
// Kept in sync with Rust-side `FOLDER_COLOR_PALETTE` in
|
||||
// `src-tauri/src/db/service/folder_service.rs`. Nine well-separated hues
|
||||
// spanning the color wheel (skipping the blue band that reads as muddy),
|
||||
// plus a theme-aware neutral that tracks the sidebar text color.
|
||||
const FOLDER_SWATCH_PALETTE = [
|
||||
"#ef4444", // red
|
||||
"#f97316", // orange
|
||||
"#eab308", // yellow
|
||||
"#84cc16", // lime
|
||||
"#22c55e", // green
|
||||
"#06b6d4", // cyan
|
||||
"#8b5cf6", // violet
|
||||
"#d946ef", // fuchsia
|
||||
"#ec4899", // pink
|
||||
FOREGROUND_SWATCH,
|
||||
] as const
|
||||
|
||||
function resolveSwatchColor(swatch: string): string {
|
||||
return swatch === FOREGROUND_SWATCH ? "var(--sidebar-foreground)" : swatch
|
||||
}
|
||||
|
||||
function formatRelative(iso: string): string {
|
||||
const ts = parseTimestamp(iso)
|
||||
if (!ts) return ""
|
||||
@@ -129,11 +159,13 @@ const FolderHeader = memo(function FolderHeader({
|
||||
count,
|
||||
expanded,
|
||||
importing,
|
||||
color,
|
||||
onToggle,
|
||||
onRemoveFromWorkspace,
|
||||
onNewConversation,
|
||||
onImport,
|
||||
onManageConversations,
|
||||
onChangeColor,
|
||||
isDragging,
|
||||
t,
|
||||
}: {
|
||||
@@ -142,11 +174,13 @@ const FolderHeader = memo(function FolderHeader({
|
||||
count: number
|
||||
expanded: boolean
|
||||
importing: boolean
|
||||
color: string
|
||||
onToggle: (folderId: number) => void
|
||||
onRemoveFromWorkspace: (folderId: number) => void
|
||||
onNewConversation: (folderId: number) => void
|
||||
onImport: (folderId: number) => void
|
||||
onManageConversations: (folderId: number) => void
|
||||
onChangeColor: (folderId: number, color: string) => void
|
||||
isDragging?: boolean
|
||||
t: ReturnType<typeof useTranslations>
|
||||
}) {
|
||||
@@ -156,7 +190,7 @@ const FolderHeader = memo(function FolderHeader({
|
||||
<div className={cn("relative h-[2rem]", isDragging && "opacity-60")}>
|
||||
<div
|
||||
className={cn(
|
||||
"flex h-[1.9375rem] w-full items-center",
|
||||
"group flex h-[1.9375rem] w-full items-center",
|
||||
"rounded-full",
|
||||
"transition-colors duration-150",
|
||||
isDragging
|
||||
@@ -193,12 +227,15 @@ const FolderHeader = memo(function FolderHeader({
|
||||
<ChevronRight className="h-[0.6875rem] w-[0.6875rem]" />
|
||||
)}
|
||||
</span>
|
||||
<div className="flex min-w-0 flex-1 items-center gap-[0.375rem]">
|
||||
<div className="flex min-w-0 flex-1 items-center gap-[0.5rem]">
|
||||
<span
|
||||
aria-hidden
|
||||
className="inline-block h-[0.5rem] w-[0.5rem] shrink-0 rounded-[0.125rem]"
|
||||
style={{ backgroundColor: resolveSwatchColor(color) }}
|
||||
/>
|
||||
<span
|
||||
className={cn(
|
||||
"min-w-0 flex-shrink truncate text-left text-[0.875rem] font-semibold tracking-[-0.00625rem]",
|
||||
"transition-colors duration-150",
|
||||
expanded && "text-sidebar-primary"
|
||||
"min-w-0 flex-shrink truncate text-left text-[0.875rem] font-semibold tracking-[-0.00625rem]"
|
||||
)}
|
||||
>
|
||||
{folderName}
|
||||
@@ -208,10 +245,7 @@ const FolderHeader = memo(function FolderHeader({
|
||||
"inline-flex shrink-0 items-center justify-center",
|
||||
"h-[0.9375rem] min-w-[1rem] rounded-[0.3125rem] px-[0.25rem]",
|
||||
"text-[0.625rem] font-semibold leading-none tabular-nums",
|
||||
"transition-colors duration-150",
|
||||
expanded
|
||||
? "bg-sidebar-primary/20 text-sidebar-primary"
|
||||
: "bg-[color-mix(in_oklab,var(--sidebar-accent),var(--sidebar-foreground)_6%)] text-muted-foreground/80"
|
||||
"bg-[color-mix(in_oklab,var(--sidebar-accent),var(--sidebar-foreground)_6%)] text-muted-foreground/80"
|
||||
)}
|
||||
>
|
||||
{count}
|
||||
@@ -229,10 +263,8 @@ const FolderHeader = memo(function FolderHeader({
|
||||
className={cn(
|
||||
"mr-[0.25rem] flex h-[1.25rem] w-[1.25rem] shrink-0 items-center justify-center",
|
||||
"rounded-[0.25rem] cursor-pointer outline-none text-muted-foreground/80",
|
||||
"transition-colors duration-150",
|
||||
expanded
|
||||
? "hover:text-sidebar-primary"
|
||||
: "hover:text-sidebar-foreground"
|
||||
"opacity-0 group-hover:opacity-100 focus-visible:opacity-100",
|
||||
"transition-opacity duration-150 hover:text-sidebar-foreground"
|
||||
)}
|
||||
>
|
||||
<Plus className="h-[0.75rem] w-[0.75rem]" />
|
||||
@@ -257,6 +289,35 @@ const FolderHeader = memo(function FolderHeader({
|
||||
<ListChecks className="h-4 w-4" />
|
||||
{t("folderHeaderMenu.manageConversations")}
|
||||
</ContextMenuItem>
|
||||
<ContextMenuSub>
|
||||
<ContextMenuSubTrigger>
|
||||
<Palette className="h-4 w-4" />
|
||||
{t("folderHeaderMenu.changeColor")}
|
||||
</ContextMenuSubTrigger>
|
||||
<ContextMenuSubContent className="min-w-[9rem] p-2">
|
||||
<div className="grid grid-cols-10 gap-1">
|
||||
{FOLDER_SWATCH_PALETTE.map((swatch) => {
|
||||
const active = swatch.toLowerCase() === color.toLowerCase()
|
||||
return (
|
||||
<button
|
||||
key={swatch}
|
||||
type="button"
|
||||
title={swatch}
|
||||
aria-label={swatch}
|
||||
onClick={() => onChangeColor(folderId, swatch)}
|
||||
className={cn(
|
||||
"h-[1.125rem] w-[1.125rem] cursor-pointer rounded-[0.25rem]",
|
||||
"outline-none ring-offset-1 ring-offset-popover",
|
||||
"transition-[box-shadow,transform] duration-100 hover:scale-110",
|
||||
active && "ring-2 ring-foreground/60"
|
||||
)}
|
||||
style={{ backgroundColor: resolveSwatchColor(swatch) }}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</ContextMenuSubContent>
|
||||
</ContextMenuSub>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuItem
|
||||
variant="destructive"
|
||||
@@ -281,11 +342,13 @@ interface FolderGroupItemProps {
|
||||
sortMode: SidebarSortMode
|
||||
selectedConversation: { id: number; agentType: string } | null
|
||||
openTabConversationKeys: Set<string>
|
||||
color: string
|
||||
onToggle: (folderId: number) => void
|
||||
onRemoveFromWorkspace: (folderId: number) => void
|
||||
onNewConversationForFolder: (folderId: number) => void
|
||||
onImport: (folderId: number) => void
|
||||
onManageConversations: (folderId: number) => void
|
||||
onChangeColor: (folderId: number, color: string) => void
|
||||
onSelect: (id: number, agentType: string) => void
|
||||
onDoubleClick: (id: number, agentType: string) => void
|
||||
onRename: (id: number, newTitle: string) => Promise<void>
|
||||
@@ -311,11 +374,13 @@ function FolderGroupItem({
|
||||
sortMode,
|
||||
selectedConversation,
|
||||
openTabConversationKeys,
|
||||
color,
|
||||
onToggle,
|
||||
onRemoveFromWorkspace,
|
||||
onNewConversationForFolder,
|
||||
onImport,
|
||||
onManageConversations,
|
||||
onChangeColor,
|
||||
onSelect,
|
||||
onDoubleClick,
|
||||
onRename,
|
||||
@@ -379,11 +444,13 @@ function FolderGroupItem({
|
||||
count={conversations.length}
|
||||
expanded={expanded}
|
||||
importing={importing}
|
||||
color={color}
|
||||
onToggle={handleToggle}
|
||||
onRemoveFromWorkspace={onRemoveFromWorkspace}
|
||||
onNewConversation={onNewConversationForFolder}
|
||||
onImport={onImport}
|
||||
onManageConversations={onManageConversations}
|
||||
onChangeColor={onChangeColor}
|
||||
isDragging={dragging}
|
||||
t={t}
|
||||
/>
|
||||
@@ -449,6 +516,7 @@ export function SidebarConversationList({
|
||||
removeFolderFromWorkspace,
|
||||
reorderFolders,
|
||||
openFolder,
|
||||
refreshFolder,
|
||||
} = useAppWorkspace()
|
||||
const refreshing = loading
|
||||
const { activeFolder } = useActiveFolder()
|
||||
@@ -464,8 +532,9 @@ export function SidebarConversationList({
|
||||
const { addTask, updateTask } = useTaskContext()
|
||||
|
||||
const folderIndex = useMemo(() => {
|
||||
const map = new Map<number, { name: string; path: string }>()
|
||||
for (const f of allFolders) map.set(f.id, { name: f.name, path: f.path })
|
||||
const map = new Map<number, { name: string; path: string; color: string }>()
|
||||
for (const f of allFolders)
|
||||
map.set(f.id, { name: f.name, path: f.path, color: f.color })
|
||||
return map
|
||||
}, [allFolders])
|
||||
|
||||
@@ -513,6 +582,19 @@ export function SidebarConversationList({
|
||||
setFolderExpanded(loadFolderExpanded())
|
||||
}, [])
|
||||
|
||||
const handleChangeFolderColor = useCallback(
|
||||
async (folderId: number, color: string) => {
|
||||
try {
|
||||
await updateFolderColor(folderId, color)
|
||||
await refreshFolder(folderId)
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err)
|
||||
toast.error(t("toasts.changeFolderColorFailed", { message: msg }))
|
||||
}
|
||||
},
|
||||
[refreshFolder, t]
|
||||
)
|
||||
|
||||
const scrollRootRef = useRef<OverlayScrollbarsComponentRef>(null)
|
||||
const scrollToActiveRef = useRef<() => void>(() => {})
|
||||
const pendingScrollRef = useRef(false)
|
||||
@@ -961,6 +1043,7 @@ export function SidebarConversationList({
|
||||
sortMode={sortMode}
|
||||
selectedConversation={selectedConversation}
|
||||
openTabConversationKeys={openTabConversationKeys}
|
||||
color={folderIndex.get(folderId)?.color ?? "#22c55e"}
|
||||
onToggle={toggleFolder}
|
||||
onRemoveFromWorkspace={handleRemoveFolder}
|
||||
onNewConversationForFolder={
|
||||
@@ -968,6 +1051,7 @@ export function SidebarConversationList({
|
||||
}
|
||||
onImport={handleImportForFolder}
|
||||
onManageConversations={handleManageConversations}
|
||||
onChangeColor={handleChangeFolderColor}
|
||||
onSelect={handleSelect}
|
||||
onDoubleClick={handleDoubleClick}
|
||||
onRename={handleRename}
|
||||
|
||||
@@ -782,7 +782,8 @@
|
||||
"folderRemoved": "تمت إزالة المجلد {name}",
|
||||
"openFolderFailed": "فشل فتح المجلد",
|
||||
"removeFolderFailed": "فشل إزالة المجلد: {message}",
|
||||
"reorderFoldersFailed": "فشل إعادة ترتيب المجلدات: {message}"
|
||||
"reorderFoldersFailed": "فشل إعادة ترتيب المجلدات: {message}",
|
||||
"changeFolderColorFailed": "فشل تغيير اللون: {message}"
|
||||
},
|
||||
"statsLabel": "{folders} مجلدات · {convos} محادثة",
|
||||
"reorderHandle": "اسحب لإعادة الترتيب",
|
||||
@@ -802,6 +803,7 @@
|
||||
"removeFolderConfirmDescription": "إزالة \"{name}\" من مساحة العمل؟ سيتم إغلاق علامات التبويب والمحطات المرتبطة.",
|
||||
"folderHeaderMenu": {
|
||||
"manageConversations": "إدارة المحادثات…",
|
||||
"changeColor": "تغيير اللون",
|
||||
"removeFromWorkspace": "إزالة من مساحة العمل"
|
||||
},
|
||||
"manageConversations": {
|
||||
|
||||
@@ -782,7 +782,8 @@
|
||||
"folderRemoved": "Ordner {name} entfernt",
|
||||
"openFolderFailed": "Ordner konnte nicht geöffnet werden",
|
||||
"removeFolderFailed": "Ordner konnte nicht entfernt werden: {message}",
|
||||
"reorderFoldersFailed": "Ordner konnten nicht neu sortiert werden: {message}"
|
||||
"reorderFoldersFailed": "Ordner konnten nicht neu sortiert werden: {message}",
|
||||
"changeFolderColorFailed": "Farbe konnte nicht geändert werden: {message}"
|
||||
},
|
||||
"statsLabel": "{folders} Ordner · {convos} Konversationen",
|
||||
"reorderHandle": "Zum Neuordnen ziehen",
|
||||
@@ -802,6 +803,7 @@
|
||||
"removeFolderConfirmDescription": "\"{name}\" aus dem Arbeitsbereich entfernen? Zugehörige Tabs und Terminals werden geschlossen.",
|
||||
"folderHeaderMenu": {
|
||||
"manageConversations": "Konversationen verwalten…",
|
||||
"changeColor": "Farbe ändern",
|
||||
"removeFromWorkspace": "Aus Arbeitsbereich entfernen"
|
||||
},
|
||||
"manageConversations": {
|
||||
|
||||
@@ -782,7 +782,8 @@
|
||||
"folderRemoved": "Removed folder {name}",
|
||||
"openFolderFailed": "Failed to open folder",
|
||||
"removeFolderFailed": "Failed to remove folder: {message}",
|
||||
"reorderFoldersFailed": "Failed to reorder folders: {message}"
|
||||
"reorderFoldersFailed": "Failed to reorder folders: {message}",
|
||||
"changeFolderColorFailed": "Failed to change folder color: {message}"
|
||||
},
|
||||
"statsLabel": "{folders} folders · {convos} conversations",
|
||||
"reorderHandle": "Drag to reorder",
|
||||
@@ -802,6 +803,7 @@
|
||||
"removeFolderConfirmDescription": "Remove \"{name}\" from the workspace? Its tabs and terminals will close.",
|
||||
"folderHeaderMenu": {
|
||||
"manageConversations": "Manage conversations…",
|
||||
"changeColor": "Change color",
|
||||
"removeFromWorkspace": "Remove from workspace"
|
||||
},
|
||||
"manageConversations": {
|
||||
|
||||
@@ -782,7 +782,8 @@
|
||||
"folderRemoved": "Carpeta {name} eliminada",
|
||||
"openFolderFailed": "Error al abrir carpeta",
|
||||
"removeFolderFailed": "Error al eliminar carpeta: {message}",
|
||||
"reorderFoldersFailed": "Error al reordenar carpetas: {message}"
|
||||
"reorderFoldersFailed": "Error al reordenar carpetas: {message}",
|
||||
"changeFolderColorFailed": "Error al cambiar el color: {message}"
|
||||
},
|
||||
"statsLabel": "{folders} carpetas · {convos} conversaciones",
|
||||
"reorderHandle": "Arrastrar para reordenar",
|
||||
@@ -802,6 +803,7 @@
|
||||
"removeFolderConfirmDescription": "¿Eliminar \"{name}\" del espacio de trabajo? Sus pestañas y terminales se cerrarán.",
|
||||
"folderHeaderMenu": {
|
||||
"manageConversations": "Gestionar conversaciones…",
|
||||
"changeColor": "Cambiar color",
|
||||
"removeFromWorkspace": "Quitar del espacio de trabajo"
|
||||
},
|
||||
"manageConversations": {
|
||||
|
||||
@@ -782,7 +782,8 @@
|
||||
"folderRemoved": "Dossier {name} retiré",
|
||||
"openFolderFailed": "Échec de l'ouverture du dossier",
|
||||
"removeFolderFailed": "Échec de la suppression du dossier : {message}",
|
||||
"reorderFoldersFailed": "Échec du réordonnancement des dossiers : {message}"
|
||||
"reorderFoldersFailed": "Échec du réordonnancement des dossiers : {message}",
|
||||
"changeFolderColorFailed": "Échec du changement de couleur : {message}"
|
||||
},
|
||||
"statsLabel": "{folders} dossiers · {convos} conversations",
|
||||
"reorderHandle": "Glisser pour réorganiser",
|
||||
@@ -802,6 +803,7 @@
|
||||
"removeFolderConfirmDescription": "Retirer \"{name}\" de l'espace de travail ? Les onglets et terminaux associés seront fermés.",
|
||||
"folderHeaderMenu": {
|
||||
"manageConversations": "Gérer les conversations…",
|
||||
"changeColor": "Changer la couleur",
|
||||
"removeFromWorkspace": "Retirer de l'espace de travail"
|
||||
},
|
||||
"manageConversations": {
|
||||
|
||||
@@ -782,7 +782,8 @@
|
||||
"folderRemoved": "フォルダ {name} を削除しました",
|
||||
"openFolderFailed": "フォルダを開けませんでした",
|
||||
"removeFolderFailed": "フォルダの削除に失敗しました: {message}",
|
||||
"reorderFoldersFailed": "フォルダの並べ替えに失敗しました: {message}"
|
||||
"reorderFoldersFailed": "フォルダの並べ替えに失敗しました: {message}",
|
||||
"changeFolderColorFailed": "色の変更に失敗しました: {message}"
|
||||
},
|
||||
"statsLabel": "{folders} フォルダ · {convos} 会話",
|
||||
"reorderHandle": "ドラッグして並べ替え",
|
||||
@@ -802,6 +803,7 @@
|
||||
"removeFolderConfirmDescription": "\"{name}\" をワークスペースから削除しますか?関連するタブとターミナルが閉じられます。",
|
||||
"folderHeaderMenu": {
|
||||
"manageConversations": "会話の管理…",
|
||||
"changeColor": "色を変更",
|
||||
"removeFromWorkspace": "ワークスペースから削除"
|
||||
},
|
||||
"manageConversations": {
|
||||
|
||||
@@ -782,7 +782,8 @@
|
||||
"folderRemoved": "폴더 {name}을(를) 제거했습니다",
|
||||
"openFolderFailed": "폴더를 열 수 없습니다",
|
||||
"removeFolderFailed": "폴더 제거 실패: {message}",
|
||||
"reorderFoldersFailed": "폴더 순서 변경 실패: {message}"
|
||||
"reorderFoldersFailed": "폴더 순서 변경 실패: {message}",
|
||||
"changeFolderColorFailed": "색상 변경 실패: {message}"
|
||||
},
|
||||
"statsLabel": "{folders}개 폴더 · {convos}개 대화",
|
||||
"reorderHandle": "드래그하여 순서 변경",
|
||||
@@ -802,6 +803,7 @@
|
||||
"removeFolderConfirmDescription": "워크스페이스에서 \"{name}\"을(를) 제거하시겠습니까? 관련 탭과 터미널이 닫힙니다.",
|
||||
"folderHeaderMenu": {
|
||||
"manageConversations": "대화 관리…",
|
||||
"changeColor": "색상 변경",
|
||||
"removeFromWorkspace": "워크스페이스에서 제거"
|
||||
},
|
||||
"manageConversations": {
|
||||
|
||||
@@ -782,7 +782,8 @@
|
||||
"folderRemoved": "Pasta {name} removida",
|
||||
"openFolderFailed": "Falha ao abrir pasta",
|
||||
"removeFolderFailed": "Falha ao remover pasta: {message}",
|
||||
"reorderFoldersFailed": "Falha ao reordenar pastas: {message}"
|
||||
"reorderFoldersFailed": "Falha ao reordenar pastas: {message}",
|
||||
"changeFolderColorFailed": "Falha ao alterar a cor: {message}"
|
||||
},
|
||||
"statsLabel": "{folders} pastas · {convos} conversas",
|
||||
"reorderHandle": "Arraste para reordenar",
|
||||
@@ -802,6 +803,7 @@
|
||||
"removeFolderConfirmDescription": "Remover \"{name}\" do espaço de trabalho? As abas e terminais relacionados serão fechados.",
|
||||
"folderHeaderMenu": {
|
||||
"manageConversations": "Gerenciar conversas…",
|
||||
"changeColor": "Alterar cor",
|
||||
"removeFromWorkspace": "Remover do espaço de trabalho"
|
||||
},
|
||||
"manageConversations": {
|
||||
|
||||
@@ -782,7 +782,8 @@
|
||||
"folderRemoved": "已移除文件夹 {name}",
|
||||
"openFolderFailed": "打开文件夹失败",
|
||||
"removeFolderFailed": "移除文件夹失败:{message}",
|
||||
"reorderFoldersFailed": "重新排序文件夹失败:{message}"
|
||||
"reorderFoldersFailed": "重新排序文件夹失败:{message}",
|
||||
"changeFolderColorFailed": "修改颜色失败:{message}"
|
||||
},
|
||||
"statsLabel": "{folders} 个文件夹 · {convos} 个会话",
|
||||
"reorderHandle": "拖拽排序",
|
||||
@@ -802,6 +803,7 @@
|
||||
"removeFolderConfirmDescription": "从工作区移除 \"{name}\"?其相关 Tab 与终端将会关闭。",
|
||||
"folderHeaderMenu": {
|
||||
"manageConversations": "会话管理…",
|
||||
"changeColor": "修改颜色",
|
||||
"removeFromWorkspace": "从工作区移除"
|
||||
},
|
||||
"manageConversations": {
|
||||
|
||||
@@ -782,7 +782,8 @@
|
||||
"folderRemoved": "已移除資料夾 {name}",
|
||||
"openFolderFailed": "開啟資料夾失敗",
|
||||
"removeFolderFailed": "移除資料夾失敗:{message}",
|
||||
"reorderFoldersFailed": "重新排序資料夾失敗:{message}"
|
||||
"reorderFoldersFailed": "重新排序資料夾失敗:{message}",
|
||||
"changeFolderColorFailed": "修改顏色失敗:{message}"
|
||||
},
|
||||
"statsLabel": "{folders} 個資料夾 · {convos} 個對話",
|
||||
"reorderHandle": "拖拽排序",
|
||||
@@ -802,6 +803,7 @@
|
||||
"removeFolderConfirmDescription": "從工作區移除 \"{name}\"?相關分頁與終端機將會關閉。",
|
||||
"folderHeaderMenu": {
|
||||
"manageConversations": "會話管理…",
|
||||
"changeColor": "修改顏色",
|
||||
"removeFromWorkspace": "從工作區移除"
|
||||
},
|
||||
"manageConversations": {
|
||||
|
||||
@@ -644,6 +644,13 @@ export async function reorderFolders(ids: number[]): Promise<void> {
|
||||
return getTransport().call("reorder_folders", { ids })
|
||||
}
|
||||
|
||||
export async function updateFolderColor(
|
||||
folderId: number,
|
||||
color: string
|
||||
): Promise<FolderDetail> {
|
||||
return getTransport().call("update_folder_color", { folderId, color })
|
||||
}
|
||||
|
||||
export async function importLocalConversations(
|
||||
folderId: number
|
||||
): Promise<ImportResult> {
|
||||
|
||||
@@ -163,6 +163,7 @@ export interface FolderDetail {
|
||||
default_agent_type: AgentType | null
|
||||
last_opened_at: string
|
||||
sort_order: number
|
||||
color: string
|
||||
}
|
||||
|
||||
export interface OpenedTab {
|
||||
|
||||
Reference in New Issue
Block a user