diff --git a/packages/shared/IpcChannel.ts b/packages/shared/IpcChannel.ts index 94f24a7aeb..d5995e9ab9 100644 --- a/packages/shared/IpcChannel.ts +++ b/packages/shared/IpcChannel.ts @@ -300,7 +300,7 @@ export enum IpcChannel { Memory_DeleteAllMemoriesForUser = 'memory:delete-all-memories-for-user', Memory_GetUsersList = 'memory:get-users-list', - // Preference + // Data: Preference Preference_Get = 'preference:get', Preference_Set = 'preference:set', Preference_GetMultiple = 'preference:get-multiple', @@ -309,9 +309,12 @@ export enum IpcChannel { Preference_Subscribe = 'preference:subscribe', Preference_Changed = 'preference:changed', - // Data API channels + // Data: Cache + Cache_Sync = 'cache:sync', + Cache_SyncBatch = 'cache:sync-batch', + + // Data: API Channels DataApi_Request = 'data-api:request', - DataApi_Response = 'data-api:response', DataApi_Batch = 'data-api:batch', DataApi_Transaction = 'data-api:transaction', DataApi_Subscribe = 'data-api:subscribe', diff --git a/packages/shared/data/README.md b/packages/shared/data/README.md index ae05e5d4ce..ab74746361 100644 --- a/packages/shared/data/README.md +++ b/packages/shared/data/README.md @@ -12,7 +12,7 @@ This directory contains shared data structures and API type definitions for the ### API Types (`api/` subdirectory) - **`api/index.ts`** - Barrel export file providing clean imports for all API types -- **`api/apiTypes.ts`** - Core request/response types and API infrastructure +- **`api/apiTypes.ts`** - Core request/response types and API infrastructure - **`api/apiModels.ts`** - Business entity types and Data Transfer Objects (DTOs) - **`api/apiSchemas.ts`** - Complete API endpoint definitions with type mappings - **`api/errorCodes.ts`** - Error handling utilities and standardized error codes @@ -29,6 +29,7 @@ These files are part of the **Renderer-Main Virtual Data Acquisition Architectur ## 🔄 Classification Status **Important**: These files are **NOT classified** in the data refactor system because they are: + - ✅ **Type definitions** - Not actual data storage - ✅ **Compile-time artifacts** - Exist only during TypeScript compilation - ✅ **Framework infrastructure** - Enable the data API architecture @@ -40,13 +41,7 @@ These files are part of the **Renderer-Main Virtual Data Acquisition Architectur ```typescript // Import API types from the api subdirectory -import { - Topic, - CreateTopicDto, - DataRequest, - ApiSchemas, - ErrorCode -} from '@shared/data/api' +import { Topic, CreateTopicDto, DataRequest, ApiSchemas, ErrorCode } from '@shared/data/api' // Import specific groups import type { TopicTypes, MessageTypes } from '@shared/data/api' @@ -64,7 +59,7 @@ import type { ApiSchemas, ApiResponse } from '@shared/data/api' type TopicsListResponse = ApiResponse<'/topics', 'GET'> // Result: PaginatedResponse -type CreateTopicResponse = ApiResponse<'/topics', 'POST'> +type CreateTopicResponse = ApiResponse<'/topics', 'POST'> // Result: Topic ``` @@ -169,18 +164,22 @@ export interface ApiSchemas { ## 🔗 Related Files ### Main Process Implementation + - `src/main/data/DataApiService.ts` - Main process data service - `src/main/data/api/` - Controllers, services, and routing -### Renderer Process Implementation +### Renderer Process Implementation + - `src/renderer/src/data/DataApiService.ts` - Renderer API client - `src/renderer/src/data/hooks/` - React hooks for data fetching ### Shared Data Types + - `packages/shared/data/api/` - API contract definitions - `packages/shared/data/preferences.ts` - User preference schemas ### Architecture Documentation + - `.claude/data-request-arch.md` - Complete architecture documentation - `CLAUDE.md` - Project development guidelines @@ -195,4 +194,4 @@ The type system is designed to support: --- -*This README is part of the Cherry Studio data refactor project. For more information, see the project documentation in `.claude/` directory.* \ No newline at end of file +_This README is part of the Cherry Studio data refactor project. For more information, see the project documentation in `.claude/` directory._ diff --git a/packages/shared/data/cache/cacheSchemas.ts b/packages/shared/data/cache/cacheSchemas.ts new file mode 100644 index 0000000000..eeaa365e12 --- /dev/null +++ b/packages/shared/data/cache/cacheSchemas.ts @@ -0,0 +1,22 @@ +/** + * Persist cache schema defining allowed keys and their value types + * This ensures type safety and prevents key conflicts + */ +export interface PersistCacheSchema { + 'example-1': string + 'example-2': number + 'example-3': boolean + 'example-4': { a: string; b: number; c: boolean } +} + +export const DefaultPersistCache: PersistCacheSchema = { + 'example-1': 'example-1', + 'example-2': 1, + 'example-3': true, + 'example-4': { a: 'example-4', b: 4, c: false } +} + +/** + * Type-safe persist cache key + */ +export type PersistCacheKey = keyof PersistCacheSchema diff --git a/packages/shared/data/cache/cacheTypes.ts b/packages/shared/data/cache/cacheTypes.ts new file mode 100644 index 0000000000..1ae71919bc --- /dev/null +++ b/packages/shared/data/cache/cacheTypes.ts @@ -0,0 +1,43 @@ +/** + * Cache types and interfaces for CacheService + * + * Supports three-layer caching architecture: + * 1. Memory cache (cross-component within renderer) + * 2. Shared cache (cross-window via IPC) + * 3. Persist cache (cross-window with localStorage persistence) + */ + +/** + * Cache entry with optional TTL support + */ +export interface CacheEntry { + value: T + expireAt?: number // Unix timestamp +} + +/** + * Cache synchronization message for IPC communication + */ +export interface CacheSyncMessage { + type: 'shared' | 'persist' + key: string + value: any + ttl?: number +} + +/** + * Batch cache synchronization message + */ +export interface CacheSyncBatchMessage { + type: 'shared' | 'persist' + entries: Array<{ + key: string + value: any + ttl?: number + }> +} + +/** + * Cache subscription callback + */ +export type CacheSubscriber = () => void diff --git a/packages/shared/data/preferences.ts b/packages/shared/data/preference/preferenceSchemas.ts similarity index 99% rename from packages/shared/data/preferences.ts rename to packages/shared/data/preference/preferenceSchemas.ts index 1982c4608e..92483c7652 100644 --- a/packages/shared/data/preferences.ts +++ b/packages/shared/data/preference/preferenceSchemas.ts @@ -10,14 +10,14 @@ */ import { TRANSLATE_PROMPT } from '@shared/config/prompts' -import * as PreferenceTypes from '@shared/data/preferenceTypes' +import * as PreferenceTypes from '@shared/data/preference/preferenceTypes' /* eslint @typescript-eslint/member-ordering: ["error", { "interfaces": { "order": "alphabetically" }, "typeLiterals": { "order": "alphabetically" } }] */ -export interface PreferencesType { +export interface PreferenceSchemas { default: { // redux/settings/enableDeveloperMode 'app.developer_mode.enabled': boolean @@ -413,7 +413,7 @@ export interface PreferencesType { } /* eslint sort-keys: ["error", "asc", {"caseSensitive": true, "natural": false}] */ -export const DefaultPreferences: PreferencesType = { +export const DefaultPreferences: PreferenceSchemas = { default: { 'app.developer_mode.enabled': false, 'app.disable_hardware_acceleration': false, diff --git a/packages/shared/data/preferenceTypes.ts b/packages/shared/data/preference/preferenceTypes.ts similarity index 93% rename from packages/shared/data/preferenceTypes.ts rename to packages/shared/data/preference/preferenceTypes.ts index 0d93b05164..4c289b4fda 100644 --- a/packages/shared/data/preferenceTypes.ts +++ b/packages/shared/data/preference/preferenceTypes.ts @@ -1,6 +1,6 @@ -import { PreferencesType } from './preferences' +import { PreferenceSchemas } from './preferenceSchemas' -export type PreferenceDefaultScopeType = PreferencesType['default'] +export type PreferenceDefaultScopeType = PreferenceSchemas['default'] export type PreferenceKeyType = keyof PreferenceDefaultScopeType export type PreferenceUpdateOptions = { diff --git a/src/main/data/CacheService.ts b/src/main/data/CacheService.ts new file mode 100644 index 0000000000..b4b9da4ad6 --- /dev/null +++ b/src/main/data/CacheService.ts @@ -0,0 +1,170 @@ +import { loggerService } from '@logger' +import type { CacheEntry, CacheSyncMessage } from '@shared/data/cache/cacheTypes' +import { IpcChannel } from '@shared/IpcChannel' +import { BrowserWindow, ipcMain } from 'electron' + +const logger = loggerService.withContext('CacheService') + +/** + * Main process cache service + * + * Features: + * - Main process internal cache with TTL support + * - IPC handlers for cross-window cache synchronization + * - Broadcast mechanism for shared cache sync + * - Minimal storage (persist cache interface reserved for future) + * + * Responsibilities: + * 1. Provide cache for Main process services + * 2. Relay cache sync messages between renderer windows + * 3. Reserve persist cache interface (not implemented yet) + */ +export class CacheService { + private static instance: CacheService + + // Main process cache + private cache = new Map() + + private constructor() { + this.setupIpcHandlers() + logger.debug('CacheService initialized') + } + + /** + * Get singleton instance + */ + public static getInstance(): CacheService { + if (!CacheService.instance) { + CacheService.instance = new CacheService() + } + return CacheService.instance + } + + // ============ Main Process Cache (Internal) ============ + + /** + * Get value from main process cache + */ + get(key: string): T | undefined { + const entry = this.cache.get(key) + if (!entry) return undefined + + // Check TTL (lazy cleanup) + if (entry.expireAt && Date.now() > entry.expireAt) { + this.cache.delete(key) + return undefined + } + + return entry.value as T + } + + /** + * Set value in main process cache + */ + set(key: string, value: T, ttl?: number): void { + const entry: CacheEntry = { + value, + expireAt: ttl ? Date.now() + ttl : undefined + } + + this.cache.set(key, entry) + } + + /** + * Check if key exists in main process cache + */ + has(key: string): boolean { + const entry = this.cache.get(key) + if (!entry) return false + + // Check TTL + if (entry.expireAt && Date.now() > entry.expireAt) { + this.cache.delete(key) + return false + } + + return true + } + + /** + * Delete from main process cache + */ + delete(key: string): boolean { + return this.cache.delete(key) + } + + // ============ Persist Cache Interface (Reserved) ============ + + /** + * Get persist cache value (interface reserved for future) + */ + // eslint-disable-next-line @typescript-eslint/no-unused-vars + getPersist(_key: string): T | undefined { + // TODO: Implement persist cache in future + logger.warn('getPersist not implemented yet') + return undefined + } + + /** + * Set persist cache value (interface reserved for future) + */ + // eslint-disable-next-line @typescript-eslint/no-unused-vars + setPersist(_key: string, _value: T): void { + // TODO: Implement persist cache in future + logger.warn('setPersist not implemented yet') + } + + /** + * Check persist cache key (interface reserved for future) + */ + // eslint-disable-next-line @typescript-eslint/no-unused-vars + hasPersist(_key: string): boolean { + // TODO: Implement persist cache in future + return false + } + + // ============ IPC Handlers for Cache Synchronization ============ + + /** + * Broadcast sync message to all renderer windows + */ + private broadcastSync(message: CacheSyncMessage, senderWindowId?: number): void { + const windows = BrowserWindow.getAllWindows() + for (const window of windows) { + if (!window.isDestroyed() && window.id !== senderWindowId) { + window.webContents.send(IpcChannel.Cache_Sync, message) + } + } + } + + /** + * Setup IPC handlers for cache synchronization + */ + private setupIpcHandlers(): void { + // Handle cache sync broadcast from renderer + ipcMain.on(IpcChannel.Cache_Sync, (event, message: CacheSyncMessage) => { + const senderWindowId = BrowserWindow.fromWebContents(event.sender)?.id + this.broadcastSync(message, senderWindowId) + logger.verbose(`Broadcasted cache sync: ${message.type}:${message.key}`) + }) + + logger.debug('Cache sync IPC handlers registered') + } + + /** + * Cleanup resources + */ + public cleanup(): void { + // Clear cache + this.cache.clear() + + // Remove IPC handlers + ipcMain.removeAllListeners(IpcChannel.Cache_Sync) + + logger.debug('CacheService cleanup completed') + } +} + +// Export singleton instance for main process use +export const cacheService = CacheService.getInstance() +export default cacheService diff --git a/src/main/data/PreferenceService.ts b/src/main/data/PreferenceService.ts index 5b45955954..67662db5af 100644 --- a/src/main/data/PreferenceService.ts +++ b/src/main/data/PreferenceService.ts @@ -1,7 +1,7 @@ import { dbService } from '@data/db/DbService' import { loggerService } from '@logger' -import { DefaultPreferences } from '@shared/data/preferences' -import type { PreferenceDefaultScopeType, PreferenceKeyType } from '@shared/data/preferenceTypes' +import { DefaultPreferences } from '@shared/data/preference/preferenceSchemas' +import type { PreferenceDefaultScopeType, PreferenceKeyType } from '@shared/data/preference/preferenceTypes' import { IpcChannel } from '@shared/IpcChannel' import { and, eq } from 'drizzle-orm' import { BrowserWindow, ipcMain } from 'electron' diff --git a/src/main/data/db/seeding/preferenceSeeding.ts b/src/main/data/db/seeding/preferenceSeeding.ts index 9310704142..c9052807e3 100644 --- a/src/main/data/db/seeding/preferenceSeeding.ts +++ b/src/main/data/db/seeding/preferenceSeeding.ts @@ -1,5 +1,5 @@ import { preferenceTable } from '@data/db/schemas/preference' -import { DefaultPreferences } from '@shared/data/preferences' +import { DefaultPreferences } from '@shared/data/preference/preferenceSchemas' import type { DbType, ISeed } from '../types' diff --git a/src/main/data/migrate/dataRefactor/migrators/PreferencesMigrator.ts b/src/main/data/migrate/dataRefactor/migrators/PreferencesMigrator.ts index a6c9581fd3..02c28e1e2b 100644 --- a/src/main/data/migrate/dataRefactor/migrators/PreferencesMigrator.ts +++ b/src/main/data/migrate/dataRefactor/migrators/PreferencesMigrator.ts @@ -1,7 +1,7 @@ import { dbService } from '@data/db/DbService' import { preferenceTable } from '@data/db/schemas/preference' import { loggerService } from '@logger' -import { DefaultPreferences } from '@shared/data/preferences' +import { DefaultPreferences } from '@shared/data/preference/preferenceSchemas' import { and, eq } from 'drizzle-orm' import { configManager } from '../../../../services/ConfigManager' diff --git a/src/main/ipc.ts b/src/main/ipc.ts index b03fc6e093..80ffc68b9a 100644 --- a/src/main/ipc.ts +++ b/src/main/ipc.ts @@ -12,7 +12,7 @@ import { getBinaryPath, isBinaryExists, runInstallScript } from '@main/utils/pro import { handleZoomFactor } from '@main/utils/zoom' import { SpanEntity, TokenUsage } from '@mcp-trace/trace-core' import { MIN_WINDOW_HEIGHT, MIN_WINDOW_WIDTH } from '@shared/config/constant' -import { UpgradeChannel } from '@shared/data/preferenceTypes' +import { UpgradeChannel } from '@shared/data/preference/preferenceTypes' import { IpcChannel } from '@shared/IpcChannel' import { FileMetadata, Provider, Shortcut } from '@types' import checkDiskSpace from 'check-disk-space' diff --git a/src/main/services/AppUpdater.ts b/src/main/services/AppUpdater.ts index 37733e2ec9..90fe41ca94 100644 --- a/src/main/services/AppUpdater.ts +++ b/src/main/services/AppUpdater.ts @@ -5,7 +5,7 @@ import { getIpCountry } from '@main/utils/ipService' import { getI18n } from '@main/utils/language' import { generateUserAgent } from '@main/utils/systemInfo' import { FeedUrl } from '@shared/config/constant' -import { UpgradeChannel } from '@shared/data/preferenceTypes' +import { UpgradeChannel } from '@shared/data/preference/preferenceTypes' import { IpcChannel } from '@shared/IpcChannel' import { CancellationToken, UpdateInfo } from 'builder-util-runtime' import { app, BrowserWindow, dialog, net } from 'electron' diff --git a/src/main/services/SelectionService.ts b/src/main/services/SelectionService.ts index 048fe58023..96dda36eb6 100644 --- a/src/main/services/SelectionService.ts +++ b/src/main/services/SelectionService.ts @@ -2,8 +2,8 @@ import { preferenceService } from '@data/PreferenceService' import { loggerService } from '@logger' import { SELECTION_FINETUNED_LIST, SELECTION_PREDEFINED_BLACKLIST } from '@main/configs/SelectionConfig' import { isDev, isMac, isWin } from '@main/constant' -import type { SelectionActionItem } from '@shared/data/preferenceTypes' -import { SelectionTriggerMode } from '@shared/data/preferenceTypes' +import type { SelectionActionItem } from '@shared/data/preference/preferenceTypes' +import { SelectionTriggerMode } from '@shared/data/preference/preferenceTypes' import { IpcChannel } from '@shared/IpcChannel' import { app, BrowserWindow, ipcMain, screen, systemPreferences } from 'electron' import { join } from 'path' diff --git a/src/main/services/ThemeService.ts b/src/main/services/ThemeService.ts index a097846484..9213192dea 100644 --- a/src/main/services/ThemeService.ts +++ b/src/main/services/ThemeService.ts @@ -1,5 +1,5 @@ import { preferenceService } from '@data/PreferenceService' -import { ThemeMode } from '@shared/data/preferenceTypes' +import { ThemeMode } from '@shared/data/preference/preferenceTypes' import { IpcChannel } from '@shared/IpcChannel' import { BrowserWindow, nativeTheme } from 'electron' diff --git a/src/main/utils/language.ts b/src/main/utils/language.ts index 5bb7969e23..980c6396ed 100644 --- a/src/main/utils/language.ts +++ b/src/main/utils/language.ts @@ -1,6 +1,6 @@ import { preferenceService } from '@data/PreferenceService' import { defaultLanguage } from '@shared/config/constant' -import { LanguageVarious } from '@shared/data/preferenceTypes' +import { LanguageVarious } from '@shared/data/preference/preferenceTypes' import { app } from 'electron' import EnUs from '../../renderer/src/i18n/locales/en-us.json' diff --git a/src/preload/index.ts b/src/preload/index.ts index ed8184cde8..def95a1a10 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -3,8 +3,13 @@ import { SpanEntity, TokenUsage } from '@mcp-trace/trace-core' import { SpanContext } from '@opentelemetry/api' import type { LogLevel, LogSourceWithContext } from '@shared/config/logger' import type { FileChangeEvent } from '@shared/config/types' -import type { PreferenceDefaultScopeType, PreferenceKeyType, SelectionActionItem } from '@shared/data/preferenceTypes' -import { UpgradeChannel } from '@shared/data/preferenceTypes' +import type { CacheSyncMessage } from '@shared/data/cache/cacheTypes' +import type { + PreferenceDefaultScopeType, + PreferenceKeyType, + SelectionActionItem +} from '@shared/data/preference/preferenceTypes' +import { UpgradeChannel } from '@shared/data/preference/preferenceTypes' import { IpcChannel } from '@shared/IpcChannel' import { AddMemoryOptions, @@ -455,6 +460,19 @@ const api = { } } }, + // CacheService related APIs + cache: { + // Broadcast sync message to other windows + broadcastSync: (message: CacheSyncMessage): void => ipcRenderer.send(IpcChannel.Cache_Sync, message), + + // Listen for sync messages from other windows + onSync: (callback: (message: CacheSyncMessage) => void) => { + const listener = (_: any, message: CacheSyncMessage) => callback(message) + ipcRenderer.on(IpcChannel.Cache_Sync, listener) + return () => ipcRenderer.off(IpcChannel.Cache_Sync, listener) + } + }, + // PreferenceService related APIs // DO NOT MODIFY THIS SECTION preference: { diff --git a/src/renderer/src/aiCore/legacy/clients/BaseApiClient.ts b/src/renderer/src/aiCore/legacy/clients/BaseApiClient.ts index f1128ab812..4c25cd29f1 100644 --- a/src/renderer/src/aiCore/legacy/clients/BaseApiClient.ts +++ b/src/renderer/src/aiCore/legacy/clients/BaseApiClient.ts @@ -45,8 +45,8 @@ import { isJSON, parseJSON } from '@renderer/utils' import { addAbortController, removeAbortController } from '@renderer/utils/abortController' import { findFileBlocks, getMainTextContent } from '@renderer/utils/messageUtils/find' import { defaultTimeout } from '@shared/config/constant' -import { defaultAppHeaders } from '@shared/utils' import { REFERENCE_PROMPT } from '@shared/config/prompts' +import { defaultAppHeaders } from '@shared/utils' import { isEmpty } from 'lodash' import { CompletionsContext } from '../middleware/types' diff --git a/src/renderer/src/components/CodeBlockView/HtmlArtifactsCard.tsx b/src/renderer/src/components/CodeBlockView/HtmlArtifactsCard.tsx index a2e61f6ba0..22ccf73687 100644 --- a/src/renderer/src/components/CodeBlockView/HtmlArtifactsCard.tsx +++ b/src/renderer/src/components/CodeBlockView/HtmlArtifactsCard.tsx @@ -2,7 +2,7 @@ import { CodeOutlined } from '@ant-design/icons' import { loggerService } from '@logger' import { useTheme } from '@renderer/context/ThemeProvider' import { extractHtmlTitle, getFileNameFromHtmlTitle } from '@renderer/utils/formats' -import { ThemeMode } from '@shared/data/preferenceTypes' +import { ThemeMode } from '@shared/data/preference/preferenceTypes' import { Button } from 'antd' import { Code, DownloadIcon, Globe, LinkIcon, Sparkles } from 'lucide-react' import { FC, useState } from 'react' diff --git a/src/renderer/src/components/Tab/TabContainer.tsx b/src/renderer/src/components/Tab/TabContainer.tsx index c1c0dfbd3d..02052c0a9d 100644 --- a/src/renderer/src/components/Tab/TabContainer.tsx +++ b/src/renderer/src/components/Tab/TabContainer.tsx @@ -13,7 +13,7 @@ import { useAppDispatch, useAppSelector } from '@renderer/store' import type { Tab } from '@renderer/store/tabs' import { addTab, removeTab, setActiveTab, setTabs } from '@renderer/store/tabs' import { classNames } from '@renderer/utils' -import { ThemeMode } from '@shared/data/preferenceTypes' +import { ThemeMode } from '@shared/data/preference/preferenceTypes' import { Tooltip } from 'antd' import { FileSearch, diff --git a/src/renderer/src/components/app/Sidebar.tsx b/src/renderer/src/components/app/Sidebar.tsx index ab6d3d0a45..1370ae6c8c 100644 --- a/src/renderer/src/components/app/Sidebar.tsx +++ b/src/renderer/src/components/app/Sidebar.tsx @@ -12,7 +12,7 @@ import { modelGenerating, useRuntime } from '@renderer/hooks/useRuntime' import { useSettings } from '@renderer/hooks/useSettings' import { getSidebarIconLabel, getThemeModeLabel } from '@renderer/i18n/label' import { isEmoji } from '@renderer/utils' -import { ThemeMode } from '@shared/data/preferenceTypes' +import { ThemeMode } from '@shared/data/preference/preferenceTypes' import { Avatar, Tooltip } from 'antd' import { Code, diff --git a/src/renderer/src/config/sidebar.ts b/src/renderer/src/config/sidebar.ts index 910f30108b..fb07f2c99c 100644 --- a/src/renderer/src/config/sidebar.ts +++ b/src/renderer/src/config/sidebar.ts @@ -1,4 +1,4 @@ -import { SidebarIcon } from '@shared/data/preferenceTypes' +import { SidebarIcon } from '@shared/data/preference/preferenceTypes' //TODO 这个文件是否还有存在的价值? fullex @ data refactor diff --git a/src/renderer/src/context/AntdProvider.tsx b/src/renderer/src/context/AntdProvider.tsx index abd202c306..6319b18234 100644 --- a/src/renderer/src/context/AntdProvider.tsx +++ b/src/renderer/src/context/AntdProvider.tsx @@ -1,6 +1,6 @@ import { usePreference } from '@data/hooks/usePreference' import { defaultLanguage } from '@shared/config/constant' -import { LanguageVarious } from '@shared/data/preferenceTypes' +import { LanguageVarious } from '@shared/data/preference/preferenceTypes' import { ConfigProvider, theme } from 'antd' import elGR from 'antd/locale/el_GR' import enUS from 'antd/locale/en_US' diff --git a/src/renderer/src/context/CodeStyleProvider.tsx b/src/renderer/src/context/CodeStyleProvider.tsx index 09c1574240..c09b6bc49b 100644 --- a/src/renderer/src/context/CodeStyleProvider.tsx +++ b/src/renderer/src/context/CodeStyleProvider.tsx @@ -3,7 +3,7 @@ import { useTheme } from '@renderer/context/ThemeProvider' import { useMermaid } from '@renderer/hooks/useMermaid' import { HighlightChunkResult, ShikiPreProperties, shikiStreamService } from '@renderer/services/ShikiStreamService' import { getHighlighter, getMarkdownIt, getShiki, loadLanguageIfNeeded, loadThemeIfNeeded } from '@renderer/utils/shiki' -import { ThemeMode } from '@shared/data/preferenceTypes' +import { ThemeMode } from '@shared/data/preference/preferenceTypes' import * as cmThemes from '@uiw/codemirror-themes-all' import type React from 'react' import { createContext, type PropsWithChildren, use, useCallback, useEffect, useMemo, useState } from 'react' diff --git a/src/renderer/src/context/ThemeProvider.tsx b/src/renderer/src/context/ThemeProvider.tsx index 7112fac2f9..d820608224 100644 --- a/src/renderer/src/context/ThemeProvider.tsx +++ b/src/renderer/src/context/ThemeProvider.tsx @@ -2,7 +2,7 @@ import { usePreference } from '@data/hooks/usePreference' import { isMac, isWin } from '@renderer/config/constant' import { useNavbarPosition } from '@renderer/hooks/useNavbar' import useUserTheme from '@renderer/hooks/useUserTheme' -import { ThemeMode } from '@shared/data/preferenceTypes' +import { ThemeMode } from '@shared/data/preference/preferenceTypes' import { IpcChannel } from '@shared/IpcChannel' import React, { createContext, PropsWithChildren, use, useEffect, useState } from 'react' interface ThemeContextType { diff --git a/src/renderer/src/data/CacheService.ts b/src/renderer/src/data/CacheService.ts new file mode 100644 index 0000000000..c358082e78 --- /dev/null +++ b/src/renderer/src/data/CacheService.ts @@ -0,0 +1,584 @@ +import { loggerService } from '@logger' +import type { PersistCacheKey, PersistCacheSchema } from '@shared/data/cache/cacheSchemas' +import { DefaultPersistCache } from '@shared/data/cache/cacheSchemas' +import type { CacheEntry, CacheSubscriber, CacheSyncMessage } from '@shared/data/cache/cacheTypes' + +const STORAGE_PERSIST_KEY = 'cs_cache_persist' + +const logger = loggerService.withContext('CacheService') + +/** + * Renderer process cache service + * + * Three-layer caching architecture: + * 1. Memory cache (cross-component within renderer) + * 2. Shared cache (cross-window via IPC) + * 3. Persist cache (cross-window with localStorage persistence) + * + * Features: + * - All APIs are synchronous (including shared cache via local copy) + * - TTL lazy cleanup (check on get, not timer-based) + * - Hook reference tracking (prevent deletion of active hooks) + * - Unified sync mechanism for shared and persist + * - Type-safe persist cache with predefined schema + */ +export class CacheService { + private static instance: CacheService + + // Three-layer cache system + private memoryCache = new Map() // Cross-component cache + private sharedCache = new Map() // Cross-window cache (local copy) + private persistCache = new Map() // Persistent cache + + // Hook reference tracking + private activeHooks = new Set() + + // Subscription management + private subscribers = new Map>() + + // Persist cache debounce + private persistSaveTimer?: NodeJS.Timeout + private persistDirty = false + + private constructor() { + this.initialize() + } + + /** + * Get singleton instance + */ + public static getInstance(): CacheService { + if (!CacheService.instance) { + CacheService.instance = new CacheService() + } + return CacheService.instance + } + + public initialize(): void { + this.loadPersistCache() + this.setupIpcListeners() + this.setupWindowUnloadHandler() + logger.debug('CacheService initialized') + } + + // ============ Memory Cache (Cross-component) ============ + + /** + * Get value from memory cache + */ + get(key: string): T | undefined { + const entry = this.memoryCache.get(key) + if (!entry) return undefined + + // Check TTL (lazy cleanup) + if (entry.expireAt && Date.now() > entry.expireAt) { + this.memoryCache.delete(key) + this.notifySubscribers(key) + return undefined + } + + return entry.value as T + } + + /** + * Set value in memory cache + */ + set(key: string, value: T, ttl?: number): void { + const existingEntry = this.memoryCache.get(key) + + // Value comparison optimization + if (existingEntry && Object.is(existingEntry.value, value)) { + // Value is same, only update TTL if needed + const newExpireAt = ttl ? Date.now() + ttl : undefined + if (!Object.is(existingEntry.expireAt, newExpireAt)) { + existingEntry.expireAt = newExpireAt + logger.verbose(`Updated TTL for memory cache key "${key}"`) + } else { + logger.verbose(`Skipped memory cache update for key "${key}" - value and TTL unchanged`) + } + return // Skip notification + } + + const entry: CacheEntry = { + value, + expireAt: ttl ? Date.now() + ttl : undefined + } + + this.memoryCache.set(key, entry) + this.notifySubscribers(key) + logger.verbose(`Updated memory cache for key "${key}"`) + } + + /** + * Check if key exists in memory cache + */ + has(key: string): boolean { + const entry = this.memoryCache.get(key) + if (!entry) return false + + // Check TTL + if (entry.expireAt && Date.now() > entry.expireAt) { + this.memoryCache.delete(key) + this.notifySubscribers(key) + return false + } + + return true + } + + /** + * Delete from memory cache + */ + delete(key: string): boolean { + // Check if key is being used by hooks + if (this.activeHooks.has(key)) { + logger.error(`Cannot delete key "${key}" as it's being used by useCache hook`) + return false + } + + // Check if key exists before attempting deletion + if (!this.memoryCache.has(key)) { + logger.verbose(`Skipped memory cache delete for key "${key}" - not exists`) + return true + } + + this.memoryCache.delete(key) + this.notifySubscribers(key) + logger.verbose(`Deleted memory cache key "${key}"`) + return true + } + + /** + * Check if a key has TTL set (for warning purposes) + */ + hasTTL(key: string): boolean { + const entry = this.memoryCache.get(key) + return entry?.expireAt !== undefined + } + + /** + * Check if a shared cache key has TTL set (for warning purposes) + */ + hasSharedTTL(key: string): boolean { + const entry = this.sharedCache.get(key) + return entry?.expireAt !== undefined + } + + // ============ Shared Cache (Cross-window) ============ + + /** + * Get value from shared cache + */ + getShared(key: string): T | undefined { + const entry = this.sharedCache.get(key) + if (!entry) return undefined + + // Check TTL (lazy cleanup) + if (entry.expireAt && Date.now() > entry.expireAt) { + this.sharedCache.delete(key) + this.notifySubscribers(key) + return undefined + } + + return entry.value as T + } + + /** + * Set value in shared cache + */ + setShared(key: string, value: T, ttl?: number): void { + const existingEntry = this.sharedCache.get(key) + + // Value comparison optimization + if (existingEntry && Object.is(existingEntry.value, value)) { + // Value is same, only update TTL if needed + const newExpireAt = ttl ? Date.now() + ttl : undefined + if (!Object.is(existingEntry.expireAt, newExpireAt)) { + existingEntry.expireAt = newExpireAt + logger.verbose(`Updated TTL for shared cache key "${key}"`) + // TTL change still needs broadcast for consistency + this.broadcastSync({ + type: 'shared', + key, + value, + ttl + }) + } else { + logger.verbose(`Skipped shared cache update for key "${key}" - value and TTL unchanged`) + } + return // Skip local update and notification + } + + const entry: CacheEntry = { + value, + expireAt: ttl ? Date.now() + ttl : undefined + } + + // Update local copy first + this.sharedCache.set(key, entry) + this.notifySubscribers(key) + + // Broadcast to other windows via Main + this.broadcastSync({ + type: 'shared', + key, + value, + ttl + }) + logger.verbose(`Updated shared cache for key "${key}"`) + } + + /** + * Check if key exists in shared cache + */ + hasShared(key: string): boolean { + const entry = this.sharedCache.get(key) + if (!entry) return false + + // Check TTL + if (entry.expireAt && Date.now() > entry.expireAt) { + this.sharedCache.delete(key) + this.notifySubscribers(key) + return false + } + + return true + } + + /** + * Delete from shared cache + */ + deleteShared(key: string): boolean { + // Check if key is being used by hooks + if (this.activeHooks.has(key)) { + logger.error(`Cannot delete key "${key}" as it's being used by useSharedCache hook`) + return false + } + + // Check if key exists before attempting deletion + if (!this.sharedCache.has(key)) { + logger.verbose(`Skipped shared cache delete for key "${key}" - not exists`) + return true + } + + this.sharedCache.delete(key) + this.notifySubscribers(key) + + // Broadcast deletion to other windows + this.broadcastSync({ + type: 'shared', + key, + value: undefined // undefined means deletion + }) + logger.verbose(`Deleted shared cache key "${key}"`) + return true + } + + // ============ Persist Cache (Cross-window + localStorage) ============ + + /** + * Get value from persist cache + */ + getPersist(key: K): PersistCacheSchema[K] { + const value = this.persistCache.get(key) + if (value !== undefined) { + return value + } + + // Fallback to default value if somehow missing + const defaultValue = DefaultPersistCache[key] + this.persistCache.set(key, defaultValue) + this.schedulePersistSave() + logger.warn(`Missing persist cache key "${key}", using default value`) + return defaultValue + } + + /** + * Set value in persist cache + */ + setPersist(key: K, value: PersistCacheSchema[K]): void { + const existingValue = this.persistCache.get(key) + + // Use deep comparison for persist cache (usually objects) + if (this.deepEqual(existingValue, value)) { + logger.verbose(`Skipped persist cache update for key "${key}" - value unchanged`) + return // Skip all updates + } + + this.persistCache.set(key, value) + this.notifySubscribers(key) + + // Broadcast to other windows + this.broadcastSync({ + type: 'persist', + key, + value + }) + + // Schedule persist save + this.schedulePersistSave() + logger.verbose(`Updated persist cache for key "${key}"`) + } + + /** + * Check if key exists in persist cache + */ + hasPersist(key: PersistCacheKey): boolean { + return this.persistCache.has(key) + } + + // Note: No deletePersist method as discussed + + // ============ Hook Reference Management ============ + + /** + * Register a hook as using a specific key + */ + registerHook(key: string): void { + this.activeHooks.add(key) + } + + /** + * Unregister a hook from using a specific key + */ + unregisterHook(key: string): void { + this.activeHooks.delete(key) + } + + // ============ Subscription Management ============ + + /** + * Subscribe to cache changes for specific key + */ + subscribe(key: string, callback: CacheSubscriber): () => void { + if (!this.subscribers.has(key)) { + this.subscribers.set(key, new Set()) + } + + const keySubscribers = this.subscribers.get(key)! + keySubscribers.add(callback) + + return () => { + keySubscribers.delete(callback) + if (keySubscribers.size === 0) { + this.subscribers.delete(key) + } + } + } + + /** + * Notify subscribers for specific key + */ + notifySubscribers(key: string): void { + const keySubscribers = this.subscribers.get(key) + if (keySubscribers) { + keySubscribers.forEach((callback) => { + try { + callback() + } catch (error) { + logger.error(`Subscriber callback error for key ${key}:`, error as Error) + } + }) + } + } + + // ============ Private Methods ============ + + /** + * Deep equality comparison for cache values + */ + private deepEqual(a: any, b: any): boolean { + // Use Object.is for primitive values and same reference + if (Object.is(a, b)) return true + + // Different types or null/undefined cases + if (typeof a !== 'object' || typeof b !== 'object') return false + if (a === null || b === null) return false + + // Array comparison + if (Array.isArray(a) !== Array.isArray(b)) return false + if (Array.isArray(a)) { + if (a.length !== b.length) return false + for (let i = 0; i < a.length; i++) { + if (!this.deepEqual(a[i], b[i])) return false + } + return true + } + + // Object comparison + const keysA = Object.keys(a) + const keysB = Object.keys(b) + + if (keysA.length !== keysB.length) return false + + for (const key of keysA) { + if (!keysB.includes(key)) return false + if (!this.deepEqual(a[key], b[key])) return false + } + + return true + } + + /** + * Load persist cache from localStorage + */ + private loadPersistCache(): void { + // First, initialize with default values + for (const [key, defaultValue] of Object.entries(DefaultPersistCache)) { + this.persistCache.set(key as PersistCacheKey, defaultValue) + } + + try { + const stored = localStorage.getItem(STORAGE_PERSIST_KEY) + if (!stored) { + // No stored data, save defaults to localStorage + this.savePersistCache() + logger.debug('Initialized persist cache with default values') + return + } + + const data = JSON.parse(stored) + + // Only load keys that exist in schema, overriding defaults + const schemaKeys = Object.keys(DefaultPersistCache) as PersistCacheKey[] + for (const key of schemaKeys) { + if (key in data) { + this.persistCache.set(key, data[key]) + } + } + + // Clean up localStorage (remove invalid keys and save merged data) + this.savePersistCache() + logger.debug('Loaded persist cache from localStorage with defaults') + } catch (error) { + logger.error('Failed to load persist cache:', error as Error) + localStorage.removeItem(STORAGE_PERSIST_KEY) + // Fallback to defaults only + logger.debug('Fallback to default persist cache values') + } + } + + /** + * Save persist cache to localStorage + */ + private savePersistCache(): void { + try { + const data: Record = {} + for (const [key, value] of this.persistCache.entries()) { + data[key] = value + } + + const jsonData = JSON.stringify(data) + const size = jsonData.length + if (size > 1024 * 1024 * 2) { + logger.warn( + `Persist cache is too large (${(size / (1024 * 1024)).toFixed( + 2 + )} MB), this may cause performance issues, and may cause data loss, please check your persist cache and reduce the size` + ) + } + + localStorage.setItem(STORAGE_PERSIST_KEY, jsonData) + logger.verbose(`Saved persist cache to localStorage, size: ${(size / (1024 * 1024)).toFixed(2)} MB`) + } catch (error) { + logger.error('Failed to save persist cache:', error as Error) + } + } + + /** + * Schedule persist cache save with debounce + */ + private schedulePersistSave(): void { + this.persistDirty = true + + if (this.persistSaveTimer) { + clearTimeout(this.persistSaveTimer) + } + + this.persistSaveTimer = setTimeout(() => { + this.savePersistCache() + this.persistDirty = false + }, 200) // 200ms debounce + } + + /** + * Broadcast cache sync message to other windows + */ + private broadcastSync(message: CacheSyncMessage): void { + if (window.api?.cache?.broadcastSync) { + window.api.cache.broadcastSync(message) + } + } + + /** + * Setup IPC listeners for cache synchronization + */ + private setupIpcListeners(): void { + if (!window.api?.cache?.onSync) { + logger.warn('Cache sync API not available') + return + } + + // Listen for cache sync messages from other windows + window.api.cache.onSync((message: CacheSyncMessage) => { + if (message.type === 'shared') { + if (message.value === undefined) { + // Handle deletion + this.sharedCache.delete(message.key) + } else { + // Handle set + const entry: CacheEntry = { + value: message.value, + expireAt: message.ttl ? Date.now() + message.ttl : undefined + } + this.sharedCache.set(message.key, entry) + } + this.notifySubscribers(message.key) + } else if (message.type === 'persist') { + // Update persist cache (other windows only update memory, not localStorage) + this.persistCache.set(message.key as PersistCacheKey, message.value) + this.notifySubscribers(message.key) + } + }) + } + + /** + * Setup window unload handler to force save persist cache + */ + private setupWindowUnloadHandler(): void { + window.addEventListener('beforeunload', () => { + if (this.persistDirty) { + this.savePersistCache() + } + }) + } + + /** + * Cleanup service resources + */ + public cleanup(): void { + // Force save persist cache if dirty + if (this.persistDirty) { + this.savePersistCache() + } + + // Clear timers + if (this.persistSaveTimer) { + clearTimeout(this.persistSaveTimer) + } + + // Clear caches + this.memoryCache.clear() + this.sharedCache.clear() + this.persistCache.clear() + + // Clear tracking + this.activeHooks.clear() + this.subscribers.clear() + + logger.debug('CacheService cleanup completed') + } +} + +// Export singleton instance +export const cacheService = CacheService.getInstance() diff --git a/src/renderer/src/data/PreferenceService.ts b/src/renderer/src/data/PreferenceService.ts index 204f09035a..d106f5ddce 100644 --- a/src/renderer/src/data/PreferenceService.ts +++ b/src/renderer/src/data/PreferenceService.ts @@ -1,10 +1,10 @@ import { loggerService } from '@logger' -import { DefaultPreferences } from '@shared/data/preferences' +import { DefaultPreferences } from '@shared/data/preference/preferenceSchemas' import type { PreferenceDefaultScopeType, PreferenceKeyType, PreferenceUpdateOptions -} from '@shared/data/preferenceTypes' +} from '@shared/data/preference/preferenceTypes' const logger = loggerService.withContext('PreferenceService') diff --git a/src/renderer/src/data/hooks/useCache.ts b/src/renderer/src/data/hooks/useCache.ts new file mode 100644 index 0000000000..3c147b9179 --- /dev/null +++ b/src/renderer/src/data/hooks/useCache.ts @@ -0,0 +1,150 @@ +import { cacheService } from '@data/CacheService' +import { loggerService } from '@logger' +import type { PersistCacheKey, PersistCacheSchema } from '@shared/data/cache/cacheSchemas' +import { useCallback, useEffect, useSyncExternalStore } from 'react' + +const logger = loggerService.withContext('useCache') + +/** + * React hook for cross-component memory cache + * + * Features: + * - Synchronous API with useSyncExternalStore + * - Automatic default value setting + * - Hook lifecycle management + * - TTL support with warning when used + * + * @param key - Cache key + * @param defaultValue - Default value (set automatically if not exists) + * @returns [value, setValue] + */ +export function useCache(key: string, defaultValue?: T): [T | undefined, (value: T) => void] { + // Subscribe to cache changes + const value = useSyncExternalStore( + useCallback((callback) => cacheService.subscribe(key, callback), [key]), + useCallback(() => cacheService.get(key), [key]), + useCallback(() => cacheService.get(key), [key]) // SSR snapshot + ) + + // Set default value if not exists + useEffect(() => { + if (defaultValue !== undefined && !cacheService.has(key)) { + cacheService.set(key, defaultValue) + } + }, [key, defaultValue]) + + // Register hook lifecycle + useEffect(() => { + cacheService.registerHook(key) + return () => cacheService.unregisterHook(key) + }, [key]) + + // Check for TTL warning + useEffect(() => { + if (cacheService.hasTTL(key)) { + logger.warn( + `useCache hook for key "${key}" is using a cache with TTL. This may cause unstable behavior as the value can expire between renders.` + ) + } + }, [key]) + + const setValue = useCallback( + (newValue: T) => { + cacheService.set(key, newValue) + }, + [key] + ) + + return [value ?? defaultValue, setValue] +} + +/** + * React hook for cross-window shared cache + * + * Features: + * - Synchronous API (uses local copy) + * - Cross-window synchronization via IPC + * - Automatic default value setting + * - Hook lifecycle management + * + * @param key - Cache key + * @param defaultValue - Default value (set automatically if not exists) + * @returns [value, setValue] + */ +export function useSharedCache(key: string, defaultValue?: T): [T | undefined, (value: T) => void] { + // Subscribe to cache changes + const value = useSyncExternalStore( + useCallback((callback) => cacheService.subscribe(key, callback), [key]), + useCallback(() => cacheService.getShared(key), [key]), + useCallback(() => cacheService.getShared(key), [key]) // SSR snapshot + ) + + // Set default value if not exists + useEffect(() => { + if (defaultValue !== undefined && !cacheService.hasShared(key)) { + cacheService.setShared(key, defaultValue) + } + }, [key, defaultValue]) + + // Register hook lifecycle + useEffect(() => { + cacheService.registerHook(key) + return () => cacheService.unregisterHook(key) + }, [key]) + + // Check for TTL warning + useEffect(() => { + if (cacheService.hasSharedTTL(key)) { + logger.warn( + `useSharedCache hook for key "${key}" is using a cache with TTL. This may cause unstable behavior as the value can expire between renders.` + ) + } + }, [key]) + + const setValue = useCallback( + (newValue: T) => { + cacheService.setShared(key, newValue) + }, + [key] + ) + + return [value ?? defaultValue, setValue] +} + +/** + * React hook for persistent cache with localStorage + * + * Features: + * - Type-safe with predefined schema + * - Cross-window synchronization + * - Automatic default value setting + * - No TTL support (as discussed) + * + * @param key - Predefined persist cache key + * @returns [value, setValue] + */ +export function usePersistCache( + key: K +): [PersistCacheSchema[K], (value: PersistCacheSchema[K]) => void] { + // Subscribe to cache changes + const value = useSyncExternalStore( + useCallback((callback) => cacheService.subscribe(key, callback), [key]), + useCallback(() => cacheService.getPersist(key), [key]), + useCallback(() => cacheService.getPersist(key), [key]) // SSR snapshot + ) + + // Register hook lifecycle (using string key for tracking) + useEffect(() => { + cacheService.registerHook(key) + return () => cacheService.unregisterHook(key) + }, [key]) + + const setValue = useCallback( + (newValue: PersistCacheSchema[K]) => { + cacheService.setPersist(key, newValue) + }, + [key] + ) + + return [value, setValue] +} diff --git a/src/renderer/src/data/hooks/usePreference.ts b/src/renderer/src/data/hooks/usePreference.ts index e6992eb823..4844d2af97 100644 --- a/src/renderer/src/data/hooks/usePreference.ts +++ b/src/renderer/src/data/hooks/usePreference.ts @@ -1,11 +1,11 @@ import { preferenceService } from '@data/PreferenceService' import { loggerService } from '@logger' -import { DefaultPreferences } from '@shared/data/preferences' +import { DefaultPreferences } from '@shared/data/preference/preferenceSchemas' import type { PreferenceDefaultScopeType, PreferenceKeyType, PreferenceUpdateOptions -} from '@shared/data/preferenceTypes' +} from '@shared/data/preference/preferenceTypes' import { useCallback, useEffect, useMemo, useRef, useSyncExternalStore } from 'react' const logger = loggerService.withContext('usePreference') diff --git a/src/renderer/src/hooks/useAppInit.ts b/src/renderer/src/hooks/useAppInit.ts index 1fcdf0b25a..2c39b80692 100644 --- a/src/renderer/src/hooks/useAppInit.ts +++ b/src/renderer/src/hooks/useAppInit.ts @@ -21,8 +21,8 @@ import { useEffect } from 'react' import { useDefaultModel } from './useAssistant' import useFullScreenNotice from './useFullScreenNotice' -import { useRuntime } from './useRuntime' import { useNavbarPosition } from './useNavbar' +import { useRuntime } from './useRuntime' import useUpdateHandler from './useUpdateHandler' const logger = loggerService.withContext('useAppInit') diff --git a/src/renderer/src/hooks/useMermaid.ts b/src/renderer/src/hooks/useMermaid.ts index 081db7f487..a7d76327d8 100644 --- a/src/renderer/src/hooks/useMermaid.ts +++ b/src/renderer/src/hooks/useMermaid.ts @@ -1,5 +1,5 @@ import { useTheme } from '@renderer/context/ThemeProvider' -import { ThemeMode } from '@shared/data/preferenceTypes' +import { ThemeMode } from '@shared/data/preference/preferenceTypes' import { useEffect, useState } from 'react' // 跟踪 mermaid 模块状态,单例模式 diff --git a/src/renderer/src/hooks/useSidebarIcon.ts b/src/renderer/src/hooks/useSidebarIcon.ts index 48f2ec8f28..476c38a3cf 100644 --- a/src/renderer/src/hooks/useSidebarIcon.ts +++ b/src/renderer/src/hooks/useSidebarIcon.ts @@ -1,5 +1,5 @@ import { usePreference } from '@data/hooks/usePreference' -import { SidebarIcon } from '@shared/data/preferenceTypes' +import { SidebarIcon } from '@shared/data/preference/preferenceTypes' export function useSidebarIconShow(icon: SidebarIcon) { const [visibleSidebarIcons] = usePreference('ui.sidebar.icons.visible') diff --git a/src/renderer/src/pages/home/Messages/MessageGroup.tsx b/src/renderer/src/pages/home/Messages/MessageGroup.tsx index afb45eec01..bf17d8b72f 100644 --- a/src/renderer/src/pages/home/Messages/MessageGroup.tsx +++ b/src/renderer/src/pages/home/Messages/MessageGroup.tsx @@ -9,7 +9,7 @@ import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService' import type { Topic } from '@renderer/types' import type { Message } from '@renderer/types/newMessage' import { classNames } from '@renderer/utils' -import type { MultiModelMessageStyle } from '@shared/data/preferenceTypes' +import type { MultiModelMessageStyle } from '@shared/data/preference/preferenceTypes' import { Popover } from 'antd' import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react' import styled from 'styled-components' diff --git a/src/renderer/src/pages/home/Messages/MessageGroupMenuBar.tsx b/src/renderer/src/pages/home/Messages/MessageGroupMenuBar.tsx index f1d0b6d9e0..eb5a293d10 100644 --- a/src/renderer/src/pages/home/Messages/MessageGroupMenuBar.tsx +++ b/src/renderer/src/pages/home/Messages/MessageGroupMenuBar.tsx @@ -13,7 +13,7 @@ import type { Topic } from '@renderer/types' import type { Message } from '@renderer/types/newMessage' import { AssistantMessageStatus } from '@renderer/types/newMessage' import { getMainTextContent } from '@renderer/utils/messageUtils/find' -import { MultiModelMessageStyle } from '@shared/data/preferenceTypes' +import { MultiModelMessageStyle } from '@shared/data/preference/preferenceTypes' import { Button, Tooltip } from 'antd' import { FC, memo } from 'react' import { useTranslation } from 'react-i18next' diff --git a/src/renderer/src/pages/home/Messages/MessageGroupModelList.tsx b/src/renderer/src/pages/home/Messages/MessageGroupModelList.tsx index a5684a13bf..74568aa06d 100644 --- a/src/renderer/src/pages/home/Messages/MessageGroupModelList.tsx +++ b/src/renderer/src/pages/home/Messages/MessageGroupModelList.tsx @@ -6,7 +6,7 @@ import Scrollbar from '@renderer/components/Scrollbar' import type { Model } from '@renderer/types' import { AssistantMessageStatus, type Message } from '@renderer/types/newMessage' import { lightbulbSoftVariants } from '@renderer/utils/motionVariants' -import type { MultiModelFoldDisplayMode } from '@shared/data/preferenceTypes' +import type { MultiModelFoldDisplayMode } from '@shared/data/preference/preferenceTypes' import { Avatar, Segmented as AntdSegmented, Tooltip } from 'antd' import { motion } from 'motion/react' import { FC, memo, useCallback } from 'react' diff --git a/src/renderer/src/pages/home/Messages/NewTopicButton.tsx b/src/renderer/src/pages/home/Messages/NewTopicButton.tsx index 4c956dbddf..ccd4dd3d04 100644 --- a/src/renderer/src/pages/home/Messages/NewTopicButton.tsx +++ b/src/renderer/src/pages/home/Messages/NewTopicButton.tsx @@ -2,7 +2,7 @@ import { FormOutlined } from '@ant-design/icons' import { useTheme } from '@renderer/context/ThemeProvider' import { EventEmitter } from '@renderer/services/EventService' import { EVENT_NAMES } from '@renderer/services/EventService' -import { ThemeMode } from '@shared/data/preferenceTypes' +import { ThemeMode } from '@shared/data/preference/preferenceTypes' import { Button as AntdButton } from 'antd' import { FC } from 'react' import { useTranslation } from 'react-i18next' diff --git a/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx b/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx index 1621128a9b..0da1b79039 100644 --- a/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx +++ b/src/renderer/src/pages/home/Tabs/AssistantsTab.tsx @@ -6,7 +6,7 @@ import { useAssistants } from '@renderer/hooks/useAssistant' import { useAssistantsTabSortType } from '@renderer/hooks/useStore' import { useTags } from '@renderer/hooks/useTags' import { Assistant } from '@renderer/types' -import type { AssistantTabSortType } from '@shared/data/preferenceTypes' +import type { AssistantTabSortType } from '@shared/data/preference/preferenceTypes' import { Tooltip, Typography } from 'antd' import { Plus } from 'lucide-react' import { FC, useCallback, useMemo, useRef, useState } from 'react' diff --git a/src/renderer/src/pages/home/Tabs/SettingsTab.tsx b/src/renderer/src/pages/home/Tabs/SettingsTab.tsx index 73c8b9b6a4..b85b525761 100644 --- a/src/renderer/src/pages/home/Tabs/SettingsTab.tsx +++ b/src/renderer/src/pages/home/Tabs/SettingsTab.tsx @@ -22,8 +22,8 @@ import { setCodeFancyBlock } from '@renderer/store/settings' import { Assistant, AssistantSettings, CodeStyleVarious, MathEngine } from '@renderer/types' import { modalConfirm } from '@renderer/utils' import { getSendMessageShortcutLabel } from '@renderer/utils/input' -import type { SendMessageShortcut } from '@shared/data/preferenceTypes' -import { ThemeMode } from '@shared/data/preferenceTypes' +import type { SendMessageShortcut } from '@shared/data/preference/preferenceTypes' +import { ThemeMode } from '@shared/data/preference/preferenceTypes' import { Button, Col, InputNumber, Row, Slider, Switch } from 'antd' import { Settings2 } from 'lucide-react' import { FC, useCallback, useEffect, useMemo, useState } from 'react' diff --git a/src/renderer/src/pages/home/Tabs/components/AssistantItem.tsx b/src/renderer/src/pages/home/Tabs/components/AssistantItem.tsx index 68a283d427..5c28482d4e 100644 --- a/src/renderer/src/pages/home/Tabs/components/AssistantItem.tsx +++ b/src/renderer/src/pages/home/Tabs/components/AssistantItem.tsx @@ -11,7 +11,7 @@ import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService' import { Assistant } from '@renderer/types' import { getLeadingEmoji, uuid } from '@renderer/utils' import { hasTopicPendingRequests } from '@renderer/utils/queue' -import type { AssistantTabSortType } from '@shared/data/preferenceTypes' +import type { AssistantTabSortType } from '@shared/data/preference/preferenceTypes' import { Dropdown, MenuProps } from 'antd' import { omit } from 'lodash' import { diff --git a/src/renderer/src/pages/settings/AboutSettings.tsx b/src/renderer/src/pages/settings/AboutSettings.tsx index 3bc0000d12..cdd2ba460e 100644 --- a/src/renderer/src/pages/settings/AboutSettings.tsx +++ b/src/renderer/src/pages/settings/AboutSettings.tsx @@ -10,8 +10,8 @@ import i18n from '@renderer/i18n' import { handleSaveData, useAppDispatch } from '@renderer/store' import { setUpdateState } from '@renderer/store/runtime' import { runAsyncFunction } from '@renderer/utils' -import { UpgradeChannel } from '@shared/data/preferenceTypes' -import { ThemeMode } from '@shared/data/preferenceTypes' +import { UpgradeChannel } from '@shared/data/preference/preferenceTypes' +import { ThemeMode } from '@shared/data/preference/preferenceTypes' import { Avatar, Button, Progress, Radio, Row, Switch, Tag, Tooltip } from 'antd' import { debounce } from 'lodash' import { Bug, FileCheck, Github, Globe, Mail, Rss } from 'lucide-react' diff --git a/src/renderer/src/pages/settings/DisplaySettings/DisplaySettings.tsx b/src/renderer/src/pages/settings/DisplaySettings/DisplaySettings.tsx index 18a518dc5a..051dc1aced 100644 --- a/src/renderer/src/pages/settings/DisplaySettings/DisplaySettings.tsx +++ b/src/renderer/src/pages/settings/DisplaySettings/DisplaySettings.tsx @@ -7,9 +7,9 @@ import { isMac, THEME_COLOR_PRESETS } from '@renderer/config/constant' import { useTheme } from '@renderer/context/ThemeProvider' import { useNavbarPosition } from '@renderer/hooks/useNavbar' import useUserTheme from '@renderer/hooks/useUserTheme' -import { DefaultPreferences } from '@shared/data/preferences' -import { AssistantIconType } from '@shared/data/preferenceTypes' -import { ThemeMode } from '@shared/data/preferenceTypes' +import { DefaultPreferences } from '@shared/data/preference/preferenceSchemas' +import { AssistantIconType } from '@shared/data/preference/preferenceTypes' +import { ThemeMode } from '@shared/data/preference/preferenceTypes' import { Button, ColorPicker, Segmented, Select, Switch } from 'antd' import { Minus, Monitor, Moon, Plus, Sun } from 'lucide-react' import { FC, useCallback, useEffect, useMemo, useState } from 'react' diff --git a/src/renderer/src/pages/settings/DisplaySettings/SidebarIconsManager.tsx b/src/renderer/src/pages/settings/DisplaySettings/SidebarIconsManager.tsx index b69074c05c..ccbaa917e8 100644 --- a/src/renderer/src/pages/settings/DisplaySettings/SidebarIconsManager.tsx +++ b/src/renderer/src/pages/settings/DisplaySettings/SidebarIconsManager.tsx @@ -8,7 +8,7 @@ import { DropResult } from '@hello-pangea/dnd' import { getSidebarIconLabel } from '@renderer/i18n/label' -import { SidebarIcon } from '@shared/data/preferenceTypes' +import { SidebarIcon } from '@shared/data/preference/preferenceTypes' import { message } from 'antd' import { Code, diff --git a/src/renderer/src/pages/settings/GeneralSettings.tsx b/src/renderer/src/pages/settings/GeneralSettings.tsx index 0bfdbadc90..3970c06d4e 100644 --- a/src/renderer/src/pages/settings/GeneralSettings.tsx +++ b/src/renderer/src/pages/settings/GeneralSettings.tsx @@ -10,7 +10,7 @@ import { NotificationSource } from '@renderer/types/notification' import { isValidProxyUrl } from '@renderer/utils' import { formatErrorMessage } from '@renderer/utils/error' import { defaultByPassRules, defaultLanguage } from '@shared/config/constant' -import { LanguageVarious } from '@shared/data/preferenceTypes' +import { LanguageVarious } from '@shared/data/preference/preferenceTypes' import { Flex, Input, Switch, Tooltip } from 'antd' import { FC, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/src/renderer/src/pages/settings/SelectionAssistantSettings/SelectionAssistantSettings.tsx b/src/renderer/src/pages/settings/SelectionAssistantSettings/SelectionAssistantSettings.tsx index ede9583c2b..952975ac14 100644 --- a/src/renderer/src/pages/settings/SelectionAssistantSettings/SelectionAssistantSettings.tsx +++ b/src/renderer/src/pages/settings/SelectionAssistantSettings/SelectionAssistantSettings.tsx @@ -3,7 +3,7 @@ import { isMac, isWin } from '@renderer/config/constant' import { useTheme } from '@renderer/context/ThemeProvider' import { getSelectionDescriptionLabel } from '@renderer/i18n/label' import SelectionToolbar from '@renderer/windows/selection/toolbar/SelectionToolbar' -import type { SelectionFilterMode, SelectionTriggerMode } from '@shared/data/preferenceTypes' +import type { SelectionFilterMode, SelectionTriggerMode } from '@shared/data/preference/preferenceTypes' import { Button, Radio, Row, Slider, Switch, Tooltip } from 'antd' import { CircleHelp, Edit2 } from 'lucide-react' import { FC, useEffect, useState } from 'react' diff --git a/src/renderer/src/pages/settings/SelectionAssistantSettings/components/ActionsList.tsx b/src/renderer/src/pages/settings/SelectionAssistantSettings/components/ActionsList.tsx index bab7711582..fa494a67be 100644 --- a/src/renderer/src/pages/settings/SelectionAssistantSettings/components/ActionsList.tsx +++ b/src/renderer/src/pages/settings/SelectionAssistantSettings/components/ActionsList.tsx @@ -1,6 +1,6 @@ import type { DroppableProvided } from '@hello-pangea/dnd' import { Draggable, Droppable } from '@hello-pangea/dnd' -import type { SelectionActionItem } from '@shared/data/preferenceTypes' +import type { SelectionActionItem } from '@shared/data/preference/preferenceTypes' import { memo } from 'react' import styled from 'styled-components' diff --git a/src/renderer/src/pages/settings/SelectionAssistantSettings/components/ActionsListItem.tsx b/src/renderer/src/pages/settings/SelectionAssistantSettings/components/ActionsListItem.tsx index 608aafbe9a..87d56a6b35 100644 --- a/src/renderer/src/pages/settings/SelectionAssistantSettings/components/ActionsListItem.tsx +++ b/src/renderer/src/pages/settings/SelectionAssistantSettings/components/ActionsListItem.tsx @@ -1,5 +1,5 @@ import type { DraggableProvided } from '@hello-pangea/dnd' -import type { SelectionActionItem } from '@shared/data/preferenceTypes' +import type { SelectionActionItem } from '@shared/data/preference/preferenceTypes' import { Button } from 'antd' import { Pencil, Settings2, Trash } from 'lucide-react' import { DynamicIcon } from 'lucide-react/dynamic' diff --git a/src/renderer/src/pages/settings/SelectionAssistantSettings/components/SelectionActionSearchModal.tsx b/src/renderer/src/pages/settings/SelectionAssistantSettings/components/SelectionActionSearchModal.tsx index caacf02209..8a5498eba6 100644 --- a/src/renderer/src/pages/settings/SelectionAssistantSettings/components/SelectionActionSearchModal.tsx +++ b/src/renderer/src/pages/settings/SelectionAssistantSettings/components/SelectionActionSearchModal.tsx @@ -1,5 +1,5 @@ import { loggerService } from '@logger' -import type { SelectionActionItem } from '@shared/data/preferenceTypes' +import type { SelectionActionItem } from '@shared/data/preference/preferenceTypes' import { Button, Form, Input, Modal, Select } from 'antd' import { Globe } from 'lucide-react' import { FC, useEffect } from 'react' diff --git a/src/renderer/src/pages/settings/SelectionAssistantSettings/components/SelectionActionUserModal.tsx b/src/renderer/src/pages/settings/SelectionAssistantSettings/components/SelectionActionUserModal.tsx index c51da3fec4..4c92713837 100644 --- a/src/renderer/src/pages/settings/SelectionAssistantSettings/components/SelectionActionUserModal.tsx +++ b/src/renderer/src/pages/settings/SelectionAssistantSettings/components/SelectionActionUserModal.tsx @@ -2,7 +2,7 @@ import ModelAvatar from '@renderer/components/Avatar/ModelAvatar' import CopyButton from '@renderer/components/CopyButton' import { useAssistants, useDefaultAssistant } from '@renderer/hooks/useAssistant' import { getDefaultModel } from '@renderer/services/AssistantService' -import type { SelectionActionItem } from '@shared/data/preferenceTypes' +import type { SelectionActionItem } from '@shared/data/preference/preferenceTypes' import { Col, Input, Modal, Radio, Row, Select, Space, Tooltip } from 'antd' import { CircleHelp, Dices, OctagonX } from 'lucide-react' import { DynamicIcon, iconNames } from 'lucide-react/dynamic' diff --git a/src/renderer/src/pages/settings/SelectionAssistantSettings/components/SelectionActionsList.tsx b/src/renderer/src/pages/settings/SelectionAssistantSettings/components/SelectionActionsList.tsx index 9323211e0a..dc69028a81 100644 --- a/src/renderer/src/pages/settings/SelectionAssistantSettings/components/SelectionActionsList.tsx +++ b/src/renderer/src/pages/settings/SelectionAssistantSettings/components/SelectionActionsList.tsx @@ -1,8 +1,8 @@ import { DragDropContext } from '@hello-pangea/dnd' import { useTheme } from '@renderer/context/ThemeProvider' import SelectionToolbar from '@renderer/windows/selection/toolbar/SelectionToolbar' -import { DefaultPreferences } from '@shared/data/preferences' -import type { SelectionActionItem } from '@shared/data/preferenceTypes' +import { DefaultPreferences } from '@shared/data/preference/preferenceSchemas' +import type { SelectionActionItem } from '@shared/data/preference/preferenceTypes' import { Row } from 'antd' import { FC } from 'react' import styled from 'styled-components' diff --git a/src/renderer/src/pages/settings/SelectionAssistantSettings/hooks/useSettingsActionsList.ts b/src/renderer/src/pages/settings/SelectionAssistantSettings/hooks/useSettingsActionsList.ts index b825a3312f..9cc970e2e8 100644 --- a/src/renderer/src/pages/settings/SelectionAssistantSettings/hooks/useSettingsActionsList.ts +++ b/src/renderer/src/pages/settings/SelectionAssistantSettings/hooks/useSettingsActionsList.ts @@ -1,7 +1,7 @@ import { DropResult } from '@hello-pangea/dnd' import { loggerService } from '@logger' -import { DefaultPreferences } from '@shared/data/preferences' -import type { SelectionActionItem } from '@shared/data/preferenceTypes' +import { DefaultPreferences } from '@shared/data/preference/preferenceSchemas' +import type { SelectionActionItem } from '@shared/data/preference/preferenceTypes' import { useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/src/renderer/src/pages/settings/SettingGroup.tsx b/src/renderer/src/pages/settings/SettingGroup.tsx index 4e1598e649..e07277a062 100644 --- a/src/renderer/src/pages/settings/SettingGroup.tsx +++ b/src/renderer/src/pages/settings/SettingGroup.tsx @@ -1,4 +1,4 @@ -import { ThemeMode } from '@shared/data/preferenceTypes' +import { ThemeMode } from '@shared/data/preference/preferenceTypes' import { ChevronDown, ChevronRight } from 'lucide-react' import { AnimatePresence, motion } from 'motion/react' import { useState } from 'react' diff --git a/src/renderer/src/pages/settings/index.tsx b/src/renderer/src/pages/settings/index.tsx index ec2d70e1e4..0e91a8dcc7 100644 --- a/src/renderer/src/pages/settings/index.tsx +++ b/src/renderer/src/pages/settings/index.tsx @@ -1,4 +1,4 @@ -import { ThemeMode } from '@shared/data/preferenceTypes' +import { ThemeMode } from '@shared/data/preference/preferenceTypes' import { Divider } from 'antd' import Link from 'antd/es/typography/Link' import styled, { CSSProp } from 'styled-components' diff --git a/src/renderer/src/store/migrate.ts b/src/renderer/src/store/migrate.ts index 5cc5ebd403..d8c91c7c51 100644 --- a/src/renderer/src/store/migrate.ts +++ b/src/renderer/src/store/migrate.ts @@ -33,8 +33,8 @@ import { import { getDefaultGroupName, getLeadingEmoji, runAsyncFunction, uuid } from '@renderer/utils' import { defaultByPassRules } from '@shared/config/constant' import { TRANSLATE_PROMPT } from '@shared/config/prompts' -import { DefaultPreferences } from '@shared/data/preferences' -import { UpgradeChannel } from '@shared/data/preferenceTypes' +import { DefaultPreferences } from '@shared/data/preference/preferenceSchemas' +import { UpgradeChannel } from '@shared/data/preference/preferenceTypes' import { isEmpty } from 'lodash' import { createMigrate } from 'redux-persist' diff --git a/src/renderer/src/store/selectionStore.ts b/src/renderer/src/store/selectionStore.ts index 698532c695..2ae842e126 100644 --- a/src/renderer/src/store/selectionStore.ts +++ b/src/renderer/src/store/selectionStore.ts @@ -2,8 +2,8 @@ * @deprecated The whole file will be removed after data refactoring */ import { createSlice, PayloadAction } from '@reduxjs/toolkit' -import type { SelectionActionItem } from '@shared/data/preferenceTypes' -import { SelectionFilterMode, SelectionTriggerMode } from '@shared/data/preferenceTypes' +import type { SelectionActionItem } from '@shared/data/preference/preferenceTypes' +import { SelectionFilterMode, SelectionTriggerMode } from '@shared/data/preference/preferenceTypes' export interface SelectionState { selectionEnabled: boolean diff --git a/src/renderer/src/store/settings.ts b/src/renderer/src/store/settings.ts index a7f70fd6b6..04c5a738a8 100644 --- a/src/renderer/src/store/settings.ts +++ b/src/renderer/src/store/settings.ts @@ -12,7 +12,7 @@ import { } from '@renderer/types' import { uuid } from '@renderer/utils' import { TRANSLATE_PROMPT } from '@shared/config/prompts' -import { DefaultPreferences } from '@shared/data/preferences' +import { DefaultPreferences } from '@shared/data/preference/preferenceSchemas' import type { AssistantIconType, AssistantTabSortType, @@ -20,8 +20,8 @@ import type { MultiModelMessageStyle, SendMessageShortcut, SidebarIcon -} from '@shared/data/preferenceTypes' -import { ThemeMode, UpgradeChannel } from '@shared/data/preferenceTypes' +} from '@shared/data/preference/preferenceTypes' +import { ThemeMode, UpgradeChannel } from '@shared/data/preference/preferenceTypes' import { OpenAIVerbosity } from '@types' import { RemoteSyncState } from './backup' diff --git a/src/renderer/src/utils/__tests__/input.test.ts b/src/renderer/src/utils/__tests__/input.test.ts index 67cf83425c..b86b1b57c8 100644 --- a/src/renderer/src/utils/__tests__/input.test.ts +++ b/src/renderer/src/utils/__tests__/input.test.ts @@ -1,4 +1,4 @@ -import type { SendMessageShortcut } from '@shared/data/preferenceTypes' +import type { SendMessageShortcut } from '@shared/data/preference/preferenceTypes' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { getFilesFromDropEvent, getSendMessageShortcutLabel, isSendMessageKeyPressed } from '../input' diff --git a/src/renderer/src/utils/input.ts b/src/renderer/src/utils/input.ts index ae09f7d802..0de05123e8 100644 --- a/src/renderer/src/utils/input.ts +++ b/src/renderer/src/utils/input.ts @@ -1,7 +1,7 @@ import { loggerService } from '@logger' import { isMac, isWin } from '@renderer/config/constant' import { FileMetadata } from '@renderer/types' -import type { SendMessageShortcut } from '@shared/data/preferenceTypes' +import type { SendMessageShortcut } from '@shared/data/preference/preferenceTypes' const logger = loggerService.withContext('Utils:Input') diff --git a/src/renderer/src/windows/dataRefactorTest/TestApp.tsx b/src/renderer/src/windows/dataRefactorTest/TestApp.tsx index c213744516..53610eb6b7 100644 --- a/src/renderer/src/windows/dataRefactorTest/TestApp.tsx +++ b/src/renderer/src/windows/dataRefactorTest/TestApp.tsx @@ -1,7 +1,7 @@ import { AppLogo } from '@renderer/config/env' import { usePreference } from '@renderer/data/hooks/usePreference' import { loggerService } from '@renderer/services/LoggerService' -import { ThemeMode } from '@shared/data/preferenceTypes' +import { ThemeMode } from '@shared/data/preference/preferenceTypes' import { Button, Card, Col, Divider, Layout, Row, Space, Typography } from 'antd' import { Activity, AlertTriangle, Database, FlaskConical, Settings, TestTube, TrendingUp, Zap } from 'lucide-react' import React from 'react' diff --git a/src/renderer/src/windows/dataRefactorTest/components/PreferenceBasicTests.tsx b/src/renderer/src/windows/dataRefactorTest/components/PreferenceBasicTests.tsx index 62813eb402..5bd3f5cbe6 100644 --- a/src/renderer/src/windows/dataRefactorTest/components/PreferenceBasicTests.tsx +++ b/src/renderer/src/windows/dataRefactorTest/components/PreferenceBasicTests.tsx @@ -1,5 +1,5 @@ import { usePreference } from '@renderer/data/hooks/usePreference' -import { type PreferenceKeyType, ThemeMode } from '@shared/data/preferenceTypes' +import { type PreferenceKeyType, ThemeMode } from '@shared/data/preference/preferenceTypes' import { Button, Input, message, Select, Slider, Space, Switch, Typography } from 'antd' import React, { useState } from 'react' import styled from 'styled-components' diff --git a/src/renderer/src/windows/dataRefactorTest/components/PreferenceHookTests.tsx b/src/renderer/src/windows/dataRefactorTest/components/PreferenceHookTests.tsx index fbbccc3313..4445b1af42 100644 --- a/src/renderer/src/windows/dataRefactorTest/components/PreferenceHookTests.tsx +++ b/src/renderer/src/windows/dataRefactorTest/components/PreferenceHookTests.tsx @@ -1,7 +1,7 @@ import { usePreference } from '@renderer/data/hooks/usePreference' import { preferenceService } from '@renderer/data/PreferenceService' import { loggerService } from '@renderer/services/LoggerService' -import { type PreferenceKeyType, ThemeMode } from '@shared/data/preferenceTypes' +import { type PreferenceKeyType, ThemeMode } from '@shared/data/preference/preferenceTypes' import { Button, Card, message, Space, Typography } from 'antd' import React, { useState } from 'react' import styled from 'styled-components' diff --git a/src/renderer/src/windows/dataRefactorTest/components/PreferenceServiceTests.tsx b/src/renderer/src/windows/dataRefactorTest/components/PreferenceServiceTests.tsx index 2cf1a8704d..095053e618 100644 --- a/src/renderer/src/windows/dataRefactorTest/components/PreferenceServiceTests.tsx +++ b/src/renderer/src/windows/dataRefactorTest/components/PreferenceServiceTests.tsx @@ -1,6 +1,6 @@ import { usePreference } from '@renderer/data/hooks/usePreference' import { preferenceService } from '@renderer/data/PreferenceService' -import { type PreferenceKeyType, ThemeMode } from '@shared/data/preferenceTypes' +import { type PreferenceKeyType, ThemeMode } from '@shared/data/preference/preferenceTypes' import { Button, Input, message, Space, Typography } from 'antd' import React, { useState } from 'react' import styled from 'styled-components' diff --git a/src/renderer/src/windows/mini/home/HomeWindow.tsx b/src/renderer/src/windows/mini/home/HomeWindow.tsx index 2292636895..5095d048ab 100644 --- a/src/renderer/src/windows/mini/home/HomeWindow.tsx +++ b/src/renderer/src/windows/mini/home/HomeWindow.tsx @@ -20,7 +20,7 @@ import { isAbortError } from '@renderer/utils/error' import { createMainTextBlock, createThinkingBlock } from '@renderer/utils/messageUtils/create' import { getMainTextContent } from '@renderer/utils/messageUtils/find' import { defaultLanguage } from '@shared/config/constant' -import { ThemeMode } from '@shared/data/preferenceTypes' +import { ThemeMode } from '@shared/data/preference/preferenceTypes' import { IpcChannel } from '@shared/IpcChannel' import { Divider } from 'antd' import { cloneDeep, isEmpty } from 'lodash' diff --git a/src/renderer/src/windows/selection/action/SelectionActionApp.tsx b/src/renderer/src/windows/selection/action/SelectionActionApp.tsx index 1de48e9acb..c10f8f30cf 100644 --- a/src/renderer/src/windows/selection/action/SelectionActionApp.tsx +++ b/src/renderer/src/windows/selection/action/SelectionActionApp.tsx @@ -2,7 +2,7 @@ import { usePreference } from '@data/hooks/usePreference' import { isMac } from '@renderer/config/constant' import i18n from '@renderer/i18n' import { defaultLanguage } from '@shared/config/constant' -import type { SelectionActionItem } from '@shared/data/preferenceTypes' +import type { SelectionActionItem } from '@shared/data/preference/preferenceTypes' import { IpcChannel } from '@shared/IpcChannel' import { Button, Slider, Tooltip } from 'antd' import { Droplet, Minus, Pin, X } from 'lucide-react' diff --git a/src/renderer/src/windows/selection/action/components/ActionGeneral.tsx b/src/renderer/src/windows/selection/action/components/ActionGeneral.tsx index 73d5d780ef..28f5445f96 100644 --- a/src/renderer/src/windows/selection/action/components/ActionGeneral.tsx +++ b/src/renderer/src/windows/selection/action/components/ActionGeneral.tsx @@ -13,7 +13,7 @@ import { import { pauseTrace } from '@renderer/services/SpanManagerService' import { Assistant, Topic } from '@renderer/types' import { abortCompletion } from '@renderer/utils/abortController' -import type { SelectionActionItem } from '@shared/data/preferenceTypes' +import type { SelectionActionItem } from '@shared/data/preference/preferenceTypes' import { ChevronDown } from 'lucide-react' import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/src/renderer/src/windows/selection/action/components/ActionTranslate.tsx b/src/renderer/src/windows/selection/action/components/ActionTranslate.tsx index acc809ded7..b9a0c668e5 100644 --- a/src/renderer/src/windows/selection/action/components/ActionTranslate.tsx +++ b/src/renderer/src/windows/selection/action/components/ActionTranslate.tsx @@ -14,7 +14,7 @@ import { runAsyncFunction } from '@renderer/utils' import { abortCompletion } from '@renderer/utils/abortController' import { detectLanguage } from '@renderer/utils/translate' import { defaultLanguage } from '@shared/config/constant' -import type { SelectionActionItem } from '@shared/data/preferenceTypes' +import type { SelectionActionItem } from '@shared/data/preference/preferenceTypes' import { Tooltip } from 'antd' import { ArrowRightFromLine, ArrowRightToLine, ChevronDown, CircleHelp, Globe } from 'lucide-react' import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react' diff --git a/src/renderer/src/windows/selection/toolbar/SelectionToolbar.tsx b/src/renderer/src/windows/selection/toolbar/SelectionToolbar.tsx index 947bb000bd..02ebe673cd 100644 --- a/src/renderer/src/windows/selection/toolbar/SelectionToolbar.tsx +++ b/src/renderer/src/windows/selection/toolbar/SelectionToolbar.tsx @@ -6,7 +6,7 @@ import { AppLogo } from '@renderer/config/env' import { useTimer } from '@renderer/hooks/useTimer' import i18n from '@renderer/i18n' import { defaultLanguage } from '@shared/config/constant' -import type { SelectionActionItem } from '@shared/data/preferenceTypes' +import type { SelectionActionItem } from '@shared/data/preference/preferenceTypes' import { IpcChannel } from '@shared/IpcChannel' import { Avatar } from 'antd' import { ClipboardCheck, ClipboardCopy, ClipboardX, MessageSquareHeart } from 'lucide-react'