From d5c959a83feef7e4f3e521cf141f67ad00442cff Mon Sep 17 00:00:00 2001 From: Wu Yue Date: Tue, 8 Jul 2025 17:39:53 +0800 Subject: [PATCH] feat(core): add ai history loading placeholder (#13092) Close [AI-324](https://linear.app/affine-design/issue/AI-324) ## Summary by CodeRabbit * **New Features** * Added a loading state indicator to the chat panel, displaying a styled message and icon while history is loading. * Enhanced the session history component with clear loading and empty state messages for improved user feedback. --- .../src/blocksuite/ai/chat-panel/index.ts | 32 +++++++++++++- .../ai-chat-toolbar/ai-session-history.ts | 42 +++++++++++++++++-- 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/packages/frontend/core/src/blocksuite/ai/chat-panel/index.ts b/packages/frontend/core/src/blocksuite/ai/chat-panel/index.ts index 09563a0c5..ad0f7ba87 100644 --- a/packages/frontend/core/src/blocksuite/ai/chat-panel/index.ts +++ b/packages/frontend/core/src/blocksuite/ai/chat-panel/index.ts @@ -18,6 +18,7 @@ import { css, html, nothing, type PropertyValues } from 'lit'; import { property, state } from 'lit/decorators.js'; import { keyed } from 'lit/directives/keyed.js'; +import { AffineIcon } from '../_common/icons'; import type { DocDisplayConfig, SearchMenuConfig, @@ -50,6 +51,28 @@ export class ChatPanel extends SignalWatcher( color: var(--affine-text-secondary-color); } + .chat-loading-container { + position: relative; + padding: 44px 0 166px 0; + height: 100%; + display: flex; + align-items: center; + } + + .chat-loading { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + gap: 12px; + } + + .chat-loading-title { + font-weight: 600; + font-size: var(--affine-font-sm); + color: var(--affine-text-secondary-color); + } + .chat-panel-playground { cursor: pointer; padding: 2px; @@ -394,7 +417,14 @@ export class ChatPanel extends SignalWatcher( override render() { if (!this.isInitialized) { - return nothing; + return html`
+
+ ${AffineIcon('var(--affine-icon-secondary)')} +
+ AFFiNE AI is loading history... +
+
+
`; } return html`
diff --git a/packages/frontend/core/src/blocksuite/ai/components/ai-chat-toolbar/ai-session-history.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-toolbar/ai-session-history.ts index 6b22b41ed..9e791ef08 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/ai-chat-toolbar/ai-session-history.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-toolbar/ai-session-history.ts @@ -30,6 +30,21 @@ export class AISessionHistory extends WithDisposable(ShadowlessElement) { background: ${unsafeCSSVarV2('layer/background/overlayPanel')}; box-shadow: ${unsafeCSSVar('overlayPanelShadow')}; + .loading-container, + .empty-container { + display: flex; + align-items: center; + justify-content: center; + height: 344px; + } + + .loading-title, + .empty-title { + font-weight: 600; + font-size: var(--affine-font-sm); + color: var(--affine-text-secondary-color); + } + .ai-session-group { display: flex; flex-direction: column; @@ -125,6 +140,9 @@ export class AISessionHistory extends WithDisposable(ShadowlessElement) { @state() private accessor sessions: BlockSuitePresets.AIRecentSession[] = []; + @state() + private accessor loading = true; + private groupSessionsByTime( sessions: BlockSuitePresets.AIRecentSession[] ): GroupedSessions { @@ -174,6 +192,7 @@ export class AISessionHistory extends WithDisposable(ShadowlessElement) { } private async getRecentSessions() { + this.loading = true; const limit = 50; const sessions = await AIProvider.session?.getRecentSessions( this.workspaceId, @@ -182,6 +201,7 @@ export class AISessionHistory extends WithDisposable(ShadowlessElement) { if (sessions) { this.sessions = sessions; } + this.loading = false; } override connectedCallback() { @@ -241,11 +261,27 @@ export class AISessionHistory extends WithDisposable(ShadowlessElement) { } override render() { - if (this.sessions.length === 0) { - return nothing; + if (this.loading) { + return html` +
+
+
Loading history...
+
+
+ `; } - const groupedSessions = this.groupSessionsByTime(this.sessions); + if (this.sessions.length === 0) { + return html` +
+
+
Empty history
+
+
+ `; + } + + const groupedSessions = this.groupSessionsByTime(this.sessions); return html`
${this.renderSessionGroup('Today', groupedSessions.today)}