From 53bd6750af55f175760b38850b616dce32a68821 Mon Sep 17 00:00:00 2001 From: digua Date: Wed, 22 Jul 2026 18:20:17 +0800 Subject: [PATCH] feat(analysis): merge session overview into insights --- apps/cli/src/query/register.test.ts | 2 +- .../session/insights/SessionInsights.vue | 18 +++--- apps/web-wasm/src/pages/SessionDetailPage.vue | 2 +- packages/config/src/schema.test.ts | 19 +++++++ packages/config/src/schema.ts | 5 +- packages/shared-types/index.ts | 2 +- .../common/Settings/BasicSettingsTab.vue | 2 +- src/composables/useUiConfig.ts | 2 +- src/i18n/locales/en-US/analysis.json | 4 +- src/i18n/locales/en-US/settings.json | 2 +- src/i18n/locales/ja-JP/analysis.json | 4 +- src/i18n/locales/ja-JP/settings.json | 2 +- src/i18n/locales/zh-CN/analysis.json | 4 +- src/i18n/locales/zh-CN/settings.json | 2 +- src/i18n/locales/zh-TW/analysis.json | 4 +- src/i18n/locales/zh-TW/settings.json | 2 +- .../components/insights/GroupChatInsights.vue | 57 +++++++++++++++---- .../components/insights/GroupChatOverview.vue | 2 - src/pages/group-chat/index.vue | 27 ++------- .../insights/PrivateChatInsights.vue | 49 ++++++++++++---- src/pages/private-chat/index.vue | 20 ++----- src/services/preferences/browser.test.ts | 13 ++++- src/services/preferences/browser.ts | 12 +++- src/stores/settings.ts | 2 +- 24 files changed, 167 insertions(+), 91 deletions(-) create mode 100644 packages/config/src/schema.test.ts diff --git a/apps/cli/src/query/register.test.ts b/apps/cli/src/query/register.test.ts index 309ba358..3f9dcf91 100644 --- a/apps/cli/src/query/register.test.ts +++ b/apps/cli/src/query/register.test.ts @@ -11,7 +11,7 @@ function configWithSql(allowSql: boolean): ChatLabConfig { data: { user_data_dir: '', electron_migration_done: false }, api: { port: 3110, host: '127.0.0.1', token: '', require_auth: false }, locale: { lang: '' }, - ui: { default_session_tab: 'overview', session_gap_threshold: 1800, summary_strategy: 'standard' }, + ui: { default_session_tab: 'insights', session_gap_threshold: 1800, summary_strategy: 'standard' }, cli: { allow_raw: false, allow_sql: allowSql }, } } diff --git a/apps/web-wasm/src/components/session/insights/SessionInsights.vue b/apps/web-wasm/src/components/session/insights/SessionInsights.vue index 3cf1401c..f055fb41 100644 --- a/apps/web-wasm/src/components/session/insights/SessionInsights.vue +++ b/apps/web-wasm/src/components/session/insights/SessionInsights.vue @@ -25,23 +25,23 @@ const persistKey = computed(() => (isPrivateChat.value ? 'webWasmPrivateInsights const subTabs = computed(() => isPrivateChat.value ? [ - { id: 'relationship', label: t('analysis.subTabs.view.relationship'), icon: 'i-heroicons-heart' }, - { id: 'type-analysis', label: t('analysis.subTabs.view.typeAnalysis'), icon: 'i-heroicons-chart-pie' }, - { id: 'time-analysis', label: t('analysis.subTabs.view.timeAnalysis'), icon: 'i-heroicons-clock' }, - { id: 'topic', label: t('analysis.subTabs.view.topic'), icon: 'i-heroicons-cloud' }, + { id: 'relationship', label: t('analysis.subTabs.insights.relationship'), icon: 'i-heroicons-heart' }, + { id: 'type-analysis', label: t('analysis.subTabs.insights.typeAnalysis'), icon: 'i-heroicons-chart-pie' }, + { id: 'time-analysis', label: t('analysis.subTabs.insights.timeAnalysis'), icon: 'i-heroicons-clock' }, + { id: 'topic', label: t('analysis.subTabs.insights.topic'), icon: 'i-heroicons-cloud' }, { id: 'language-preference', - label: t('analysis.subTabs.view.languagePreference'), + label: t('analysis.subTabs.insights.languagePreference'), icon: 'i-heroicons-language', }, ] : [ - { id: 'type-analysis', label: t('analysis.subTabs.view.typeAnalysis'), icon: 'i-heroicons-chart-pie' }, - { id: 'time-analysis', label: t('analysis.subTabs.view.timeAnalysis'), icon: 'i-heroicons-clock' }, - { id: 'topic', label: t('analysis.subTabs.view.topic'), icon: 'i-heroicons-cloud' }, + { id: 'type-analysis', label: t('analysis.subTabs.insights.typeAnalysis'), icon: 'i-heroicons-chart-pie' }, + { id: 'time-analysis', label: t('analysis.subTabs.insights.timeAnalysis'), icon: 'i-heroicons-clock' }, + { id: 'topic', label: t('analysis.subTabs.insights.topic'), icon: 'i-heroicons-cloud' }, { id: 'group-relationships', - label: t('analysis.subTabs.view.groupRelationships'), + label: t('analysis.subTabs.insights.groupRelationships'), icon: 'i-heroicons-heart', }, ] diff --git a/apps/web-wasm/src/pages/SessionDetailPage.vue b/apps/web-wasm/src/pages/SessionDetailPage.vue index 40739e33..7fe5338b 100644 --- a/apps/web-wasm/src/pages/SessionDetailPage.vue +++ b/apps/web-wasm/src/pages/SessionDetailPage.vue @@ -19,7 +19,7 @@ const { currentSessionId } = storeToRefs(sessionStore) const tabs = [ { id: 'overview', labelKey: 'analysis.tabs.overview', icon: 'i-heroicons-chart-pie' }, - { id: 'view', labelKey: 'analysis.tabs.view', icon: 'i-heroicons-presentation-chart-bar' }, + { id: 'view', labelKey: 'analysis.tabs.insights', icon: 'i-heroicons-presentation-chart-bar' }, ] const { diff --git a/packages/config/src/schema.test.ts b/packages/config/src/schema.test.ts new file mode 100644 index 00000000..84d535b1 --- /dev/null +++ b/packages/config/src/schema.test.ts @@ -0,0 +1,19 @@ +import assert from 'node:assert/strict' +import test from 'node:test' +import { configSchema } from './schema' + +test('defaults the session landing tab to insights', () => { + const config = configSchema.parse({}) + + assert.equal(config.ui.default_session_tab, 'insights') +}) + +test('normalizes the released overview preference to insights', () => { + const config = configSchema.parse({ ui: { default_session_tab: 'overview' } }) + + assert.equal(config.ui.default_session_tab, 'insights') +}) + +test('rejects unknown session landing tabs', () => { + assert.throws(() => configSchema.parse({ ui: { default_session_tab: 'unknown' } })) +}) diff --git a/packages/config/src/schema.ts b/packages/config/src/schema.ts index cc2592bc..6b2591bd 100644 --- a/packages/config/src/schema.ts +++ b/packages/config/src/schema.ts @@ -31,7 +31,10 @@ export const localeConfigSchema = z.object({ }) export const uiConfigSchema = z.object({ - default_session_tab: z.enum(['overview', 'ai-chat']).default('overview'), + default_session_tab: z.preprocess( + (value) => (value === 'overview' ? 'insights' : value), + z.enum(['insights', 'ai-chat']).default('insights') + ), session_gap_threshold: z.number().int().min(60).max(86400).default(1800), summary_strategy: z.enum(['brief', 'standard']).default('standard'), }) diff --git a/packages/shared-types/index.ts b/packages/shared-types/index.ts index 4e883482..4e186e68 100644 --- a/packages/shared-types/index.ts +++ b/packages/shared-types/index.ts @@ -668,7 +668,7 @@ export interface Preferences { } export interface UiConfig { - default_session_tab: 'overview' | 'ai-chat' + default_session_tab: 'insights' | 'ai-chat' session_gap_threshold: number summary_strategy?: 'brief' | 'standard' } diff --git a/src/components/common/Settings/BasicSettingsTab.vue b/src/components/common/Settings/BasicSettingsTab.vue index 763965e3..5878f7fe 100644 --- a/src/components/common/Settings/BasicSettingsTab.vue +++ b/src/components/common/Settings/BasicSettingsTab.vue @@ -74,7 +74,7 @@ const currentLocale = computed({ // Default session tab options const defaultTabOptions = computed(() => [ - { label: t('settings.basic.defaultTab.overview'), value: 'overview' }, + { label: t('settings.basic.defaultTab.insights'), value: 'insights' }, { label: t('settings.basic.defaultTab.aiChat'), value: 'ai-chat' }, ]) diff --git a/src/composables/useUiConfig.ts b/src/composables/useUiConfig.ts index bebe66fd..dc3dba1a 100644 --- a/src/composables/useUiConfig.ts +++ b/src/composables/useUiConfig.ts @@ -10,7 +10,7 @@ import type { UiConfig } from '@/services/preferences/types' export type SummaryStrategy = 'brief' | 'standard' const _uiConfig = ref({ - default_session_tab: 'overview', + default_session_tab: 'insights', session_gap_threshold: 1800, summary_strategy: 'standard', }) diff --git a/src/i18n/locales/en-US/analysis.json b/src/i18n/locales/en-US/analysis.json index 261609f7..a5a7a1e3 100644 --- a/src/i18n/locales/en-US/analysis.json +++ b/src/i18n/locales/en-US/analysis.json @@ -9,7 +9,7 @@ }, "tabs": { "overview": "Overview", - "view": "Insights", + "insights": "Insights", "ranking": "Rankings", "aiChat": "AI Chat", "memory": "Memory", @@ -63,7 +63,7 @@ "failed": "Import failed" }, "subTabs": { - "view": { + "insights": { "typeAnalysis": "Types", "timeAnalysis": "Time", "topic": "Topics", diff --git a/src/i18n/locales/en-US/settings.json b/src/i18n/locales/en-US/settings.json index 46d01114..750d50db 100644 --- a/src/i18n/locales/en-US/settings.json +++ b/src/i18n/locales/en-US/settings.json @@ -40,7 +40,7 @@ }, "defaultTab": { "description": "Default page when entering a chat conversation", - "overview": "Overview", + "insights": "Insights", "aiChat": "AI Chat" }, "autoLaunch": { diff --git a/src/i18n/locales/ja-JP/analysis.json b/src/i18n/locales/ja-JP/analysis.json index 6f8988ca..4fdee4de 100644 --- a/src/i18n/locales/ja-JP/analysis.json +++ b/src/i18n/locales/ja-JP/analysis.json @@ -9,7 +9,7 @@ }, "tabs": { "overview": "概要", - "view": "インサイト", + "insights": "インサイト", "ranking": "ランキング", "aiChat": "AIチャット", "memory": "メモリー", @@ -63,7 +63,7 @@ "failed": "インポートに失敗しました" }, "subTabs": { - "view": { + "insights": { "typeAnalysis": "タイプ", "timeAnalysis": "時間", "topic": "トピック", diff --git a/src/i18n/locales/ja-JP/settings.json b/src/i18n/locales/ja-JP/settings.json index 1231fffb..53c97353 100644 --- a/src/i18n/locales/ja-JP/settings.json +++ b/src/i18n/locales/ja-JP/settings.json @@ -40,7 +40,7 @@ }, "defaultTab": { "description": "チャットに入った時に表示するページ", - "overview": "概要", + "insights": "インサイト", "aiChat": "AI チャット" }, "autoLaunch": { diff --git a/src/i18n/locales/zh-CN/analysis.json b/src/i18n/locales/zh-CN/analysis.json index f8e91b8d..eae9e989 100644 --- a/src/i18n/locales/zh-CN/analysis.json +++ b/src/i18n/locales/zh-CN/analysis.json @@ -9,7 +9,7 @@ }, "tabs": { "overview": "总览", - "view": "洞察", + "insights": "洞察", "ranking": "榜单", "aiChat": "AI对话", "memory": "记忆", @@ -64,7 +64,7 @@ "failed": "导入失败" }, "subTabs": { - "view": { + "insights": { "typeAnalysis": "类型", "timeAnalysis": "时间", "topic": "话题", diff --git a/src/i18n/locales/zh-CN/settings.json b/src/i18n/locales/zh-CN/settings.json index 38db7293..793fc1a7 100644 --- a/src/i18n/locales/zh-CN/settings.json +++ b/src/i18n/locales/zh-CN/settings.json @@ -40,7 +40,7 @@ }, "defaultTab": { "description": "进入聊天对话后默认显示的页面", - "overview": "总览", + "insights": "洞察", "aiChat": "AI 对话" }, "autoLaunch": { diff --git a/src/i18n/locales/zh-TW/analysis.json b/src/i18n/locales/zh-TW/analysis.json index 18355203..6d95bfa9 100644 --- a/src/i18n/locales/zh-TW/analysis.json +++ b/src/i18n/locales/zh-TW/analysis.json @@ -9,7 +9,7 @@ }, "tabs": { "overview": "總覽", - "view": "洞察", + "insights": "洞察", "ranking": "榜單", "aiChat": "AI 對話", "memory": "記憶", @@ -63,7 +63,7 @@ "failed": "匯入失敗" }, "subTabs": { - "view": { + "insights": { "typeAnalysis": "類型", "timeAnalysis": "時間", "topic": "話題", diff --git a/src/i18n/locales/zh-TW/settings.json b/src/i18n/locales/zh-TW/settings.json index a5487763..a32b23da 100644 --- a/src/i18n/locales/zh-TW/settings.json +++ b/src/i18n/locales/zh-TW/settings.json @@ -40,7 +40,7 @@ }, "defaultTab": { "description": "進入聊天對話後預設顯示的頁面", - "overview": "總覽", + "insights": "洞察", "aiChat": "AI 對話" }, "autoLaunch": { diff --git a/src/pages/group-chat/components/insights/GroupChatInsights.vue b/src/pages/group-chat/components/insights/GroupChatInsights.vue index ade2379b..d759dd2b 100644 --- a/src/pages/group-chat/components/insights/GroupChatInsights.vue +++ b/src/pages/group-chat/components/insights/GroupChatInsights.vue @@ -8,25 +8,40 @@ import TimeAnalysisView from '@/components/analysis/message/TimeAnalysisView.vue import GroupRelationships from './GroupRelationships.vue' import { WordcloudTab } from '@/components/analysis/quotes' import type { TimeFilter } from '@openchatlab/shared-types' +import type { AnalysisSession, MessageType } from '@/types/base' +import type { DailyActivity, HourlyActivity, MemberActivity } from '@/types/analysis' +import GroupChatOverview from './GroupChatOverview.vue' const { t } = useI18n() const props = defineProps<{ sessionId: string - sessionName?: string + session: AnalysisSession + memberActivity: MemberActivity[] + messageTypes: Array<{ type: MessageType; count: number }> + hourlyActivity: HourlyActivity[] + dailyActivity: DailyActivity[] + timeRange: { start: number; end: number } | null + filteredMessageCount: number + filteredMemberCount: number timeFilter?: TimeFilter }>() const subTabs = computed(() => { return [ - { id: 'type-analysis', label: t('analysis.subTabs.view.typeAnalysis'), icon: 'i-heroicons-chart-pie' }, - { id: 'time-analysis', label: t('analysis.subTabs.view.timeAnalysis'), icon: 'i-heroicons-clock' }, - { id: 'topic', label: t('analysis.subTabs.view.topic'), icon: 'i-heroicons-cloud' }, - { id: 'group-relationships', label: t('analysis.subTabs.view.groupRelationships'), icon: 'i-heroicons-heart' }, + { id: 'overview', label: t('analysis.tabs.overview'), icon: 'i-heroicons-squares-2x2' }, + { id: 'type-analysis', label: t('analysis.subTabs.insights.typeAnalysis'), icon: 'i-heroicons-chart-pie' }, + { id: 'time-analysis', label: t('analysis.subTabs.insights.timeAnalysis'), icon: 'i-heroicons-clock' }, + { id: 'topic', label: t('analysis.subTabs.insights.topic'), icon: 'i-heroicons-cloud' }, + { + id: 'group-relationships', + label: t('analysis.subTabs.insights.groupRelationships'), + icon: 'i-heroicons-heart', + }, ] }) -const activeSubTab = ref('type-analysis') +const activeSubTab = ref('overview') const selectedMemberId = ref(null) @@ -38,24 +53,44 @@ const viewTimeFilter = computed(() => ({