refactor(core): open embedding settings when click check-status button (#12772)
> CLOSE BS-3582 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added a "Check status" button in the AI chat interface that opens the embedding settings panel for improved user access. - **Refactor** - Simplified the embedding status tooltip to display static information and a direct link to settings, removing dynamic progress updates. - Integrated workspace dialog service across AI chat components for consistent dialog management. - **Tests** - Updated end-to-end tests to verify that clicking the "Check status" button opens the embedding settings panel. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import './chat-panel-messages';
|
import './chat-panel-messages';
|
||||||
|
|
||||||
|
import type { WorkspaceDialogService } from '@affine/core/modules/dialogs';
|
||||||
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
||||||
import type { ContextEmbedStatus, CopilotSessionType } from '@affine/graphql';
|
import type { ContextEmbedStatus, CopilotSessionType } from '@affine/graphql';
|
||||||
import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/lit';
|
import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/lit';
|
||||||
@@ -241,6 +242,9 @@ export class ChatPanel extends SignalWatcher(
|
|||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor affineFeatureFlagService!: FeatureFlagService;
|
accessor affineFeatureFlagService!: FeatureFlagService;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
accessor affineWorkspaceDialogService!: WorkspaceDialogService;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
accessor isLoading = false;
|
accessor isLoading = false;
|
||||||
|
|
||||||
@@ -481,6 +485,7 @@ export class ChatPanel extends SignalWatcher(
|
|||||||
.playgroundConfig=${this.playgroundConfig}
|
.playgroundConfig=${this.playgroundConfig}
|
||||||
.docDisplayConfig=${this.docDisplayConfig}
|
.docDisplayConfig=${this.docDisplayConfig}
|
||||||
.searchMenuConfig=${this.searchMenuConfig}
|
.searchMenuConfig=${this.searchMenuConfig}
|
||||||
|
.affineWorkspaceDialogService=${this.affineWorkspaceDialogService}
|
||||||
.trackOptions=${{
|
.trackOptions=${{
|
||||||
where: 'chat-panel',
|
where: 'chat-panel',
|
||||||
control: 'chat-send',
|
control: 'chat-send',
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import './ai-chat-composer-tip';
|
import './ai-chat-composer-tip';
|
||||||
|
|
||||||
|
import type { WorkspaceDialogService } from '@affine/core/modules/dialogs';
|
||||||
import type {
|
import type {
|
||||||
ContextEmbedStatus,
|
ContextEmbedStatus,
|
||||||
ContextWorkspaceEmbeddingStatus,
|
ContextWorkspaceEmbeddingStatus,
|
||||||
@@ -104,11 +105,11 @@ export class AIChatComposer extends SignalWatcher(
|
|||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor panelWidth: Signal<number | undefined> = signal(undefined);
|
accessor panelWidth: Signal<number | undefined> = signal(undefined);
|
||||||
|
|
||||||
@state()
|
@property({ attribute: false })
|
||||||
accessor chips: ChatChip[] = [];
|
accessor affineWorkspaceDialogService!: WorkspaceDialogService;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
accessor embeddingProgressText = 'Loading embedding status...';
|
accessor chips: ChatChip[] = [];
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
accessor embeddingCompleted = false;
|
accessor embeddingCompleted = false;
|
||||||
@@ -160,7 +161,8 @@ export class AIChatComposer extends SignalWatcher(
|
|||||||
this.embeddingCompleted
|
this.embeddingCompleted
|
||||||
? null
|
? null
|
||||||
: html`<ai-chat-embedding-status-tooltip
|
: html`<ai-chat-embedding-status-tooltip
|
||||||
.progressText=${this.embeddingProgressText}
|
.affineWorkspaceDialogService=${this
|
||||||
|
.affineWorkspaceDialogService}
|
||||||
/>`,
|
/>`,
|
||||||
].filter(Boolean)}
|
].filter(Boolean)}
|
||||||
.loop=${false}
|
.loop=${false}
|
||||||
@@ -348,24 +350,20 @@ export class AIChatComposer extends SignalWatcher(
|
|||||||
this.host.std.workspace.id,
|
this.host.std.workspace.id,
|
||||||
(status: ContextWorkspaceEmbeddingStatus) => {
|
(status: ContextWorkspaceEmbeddingStatus) => {
|
||||||
if (!status) {
|
if (!status) {
|
||||||
this.embeddingProgressText = 'Loading embedding status...';
|
|
||||||
this.embeddingCompleted = false;
|
this.embeddingCompleted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const completed = status.embedded === status.total;
|
const completed = status.embedded === status.total;
|
||||||
this.embeddingCompleted = completed;
|
this.embeddingCompleted = completed;
|
||||||
if (completed) {
|
if (completed) {
|
||||||
this.embeddingProgressText =
|
this.embeddingCompleted = true;
|
||||||
'Embedding finished. You are getting the best results!';
|
|
||||||
} else {
|
} else {
|
||||||
this.embeddingProgressText =
|
this.embeddingCompleted = false;
|
||||||
'File not embedded yet. Results will improve after embedding.';
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
signal
|
signal
|
||||||
);
|
);
|
||||||
} catch {
|
} catch {
|
||||||
this.embeddingProgressText = 'Failed to load embedding status...';
|
|
||||||
this.embeddingCompleted = false;
|
this.embeddingCompleted = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
import type { WorkspaceDialogService } from '@affine/core/modules/dialogs';
|
||||||
import { SignalWatcher } from '@blocksuite/affine/global/lit';
|
import { SignalWatcher } from '@blocksuite/affine/global/lit';
|
||||||
import { unsafeCSSVar } from '@blocksuite/affine/shared/theme';
|
import { unsafeCSSVar } from '@blocksuite/affine/shared/theme';
|
||||||
import { css, html, LitElement } from 'lit';
|
import { css, html, LitElement } from 'lit';
|
||||||
import { property } from 'lit/decorators.js';
|
import { property } from 'lit/decorators.js';
|
||||||
|
import { debounce } from 'lodash-es';
|
||||||
|
|
||||||
export class AIChatEmbeddingStatusTooltip extends SignalWatcher(LitElement) {
|
export class AIChatEmbeddingStatusTooltip extends SignalWatcher(LitElement) {
|
||||||
static override styles = css`
|
static override styles = css`
|
||||||
@@ -34,7 +36,21 @@ export class AIChatEmbeddingStatusTooltip extends SignalWatcher(LitElement) {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor progressText = 'Loading embedding status...';
|
accessor affineWorkspaceDialogService!: WorkspaceDialogService;
|
||||||
|
|
||||||
|
override connectedCallback() {
|
||||||
|
super.connectedCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly _handleCheckStatusClick = debounce(
|
||||||
|
() => {
|
||||||
|
this.affineWorkspaceDialogService.open('setting', {
|
||||||
|
activeTab: 'workspace:embedding',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
1000,
|
||||||
|
{ leading: true }
|
||||||
|
);
|
||||||
|
|
||||||
override render() {
|
override render() {
|
||||||
return html`
|
return html`
|
||||||
@@ -48,11 +64,9 @@ export class AIChatEmbeddingStatusTooltip extends SignalWatcher(LitElement) {
|
|||||||
<div
|
<div
|
||||||
class="check-status"
|
class="check-status"
|
||||||
data-testid="ai-chat-embedding-status-tooltip-check"
|
data-testid="ai-chat-embedding-status-tooltip-check"
|
||||||
|
@click=${this._handleCheckStatusClick}
|
||||||
>
|
>
|
||||||
Check status
|
Check status
|
||||||
<affine-tooltip tip-position="top-start"
|
|
||||||
>${this.progressText}</affine-tooltip
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type { WorkspaceDialogService } from '@affine/core/modules/dialogs';
|
||||||
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
||||||
import type { ContextEmbedStatus } from '@affine/graphql';
|
import type { ContextEmbedStatus } from '@affine/graphql';
|
||||||
import {
|
import {
|
||||||
@@ -593,6 +594,7 @@ export class AIChatBlockPeekView extends LitElement {
|
|||||||
.networkSearchConfig=${networkSearchConfig}
|
.networkSearchConfig=${networkSearchConfig}
|
||||||
.docDisplayConfig=${this.docDisplayConfig}
|
.docDisplayConfig=${this.docDisplayConfig}
|
||||||
.searchMenuConfig=${this.searchMenuConfig}
|
.searchMenuConfig=${this.searchMenuConfig}
|
||||||
|
.affineWorkspaceDialogService=${this.affineWorkspaceDialogService}
|
||||||
.onChatSuccess=${this._onChatSuccess}
|
.onChatSuccess=${this._onChatSuccess}
|
||||||
.trackOptions=${{
|
.trackOptions=${{
|
||||||
where: 'ai-chat-block',
|
where: 'ai-chat-block',
|
||||||
@@ -628,6 +630,9 @@ export class AIChatBlockPeekView extends LitElement {
|
|||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor affineFeatureFlagService!: FeatureFlagService;
|
accessor affineFeatureFlagService!: FeatureFlagService;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
accessor affineWorkspaceDialogService!: WorkspaceDialogService;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
accessor _historyMessages: ChatMessage[] = [];
|
accessor _historyMessages: ChatMessage[] = [];
|
||||||
|
|
||||||
@@ -657,7 +662,8 @@ export const AIChatBlockPeekViewTemplate = (
|
|||||||
searchMenuConfig: SearchMenuConfig,
|
searchMenuConfig: SearchMenuConfig,
|
||||||
networkSearchConfig: AINetworkSearchConfig,
|
networkSearchConfig: AINetworkSearchConfig,
|
||||||
reasoningConfig: AIReasoningConfig,
|
reasoningConfig: AIReasoningConfig,
|
||||||
affineFeatureFlagService: FeatureFlagService
|
affineFeatureFlagService: FeatureFlagService,
|
||||||
|
affineWorkspaceDialogService: WorkspaceDialogService
|
||||||
) => {
|
) => {
|
||||||
return html`<ai-chat-block-peek-view
|
return html`<ai-chat-block-peek-view
|
||||||
.blockModel=${blockModel}
|
.blockModel=${blockModel}
|
||||||
@@ -667,5 +673,6 @@ export const AIChatBlockPeekViewTemplate = (
|
|||||||
.searchMenuConfig=${searchMenuConfig}
|
.searchMenuConfig=${searchMenuConfig}
|
||||||
.reasoningConfig=${reasoningConfig}
|
.reasoningConfig=${reasoningConfig}
|
||||||
.affineFeatureFlagService=${affineFeatureFlagService}
|
.affineFeatureFlagService=${affineFeatureFlagService}
|
||||||
|
.affineWorkspaceDialogService=${affineWorkspaceDialogService}
|
||||||
></ai-chat-block-peek-view>`;
|
></ai-chat-block-peek-view>`;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { ChatPanel } from '@affine/core/blocksuite/ai';
|
import { ChatPanel } from '@affine/core/blocksuite/ai';
|
||||||
import type { AffineEditorContainer } from '@affine/core/blocksuite/block-suite-editor';
|
import type { AffineEditorContainer } from '@affine/core/blocksuite/block-suite-editor';
|
||||||
import { useAIChatConfig } from '@affine/core/components/hooks/affine/use-ai-chat-config';
|
import { useAIChatConfig } from '@affine/core/components/hooks/affine/use-ai-chat-config';
|
||||||
|
import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
|
||||||
import { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
import { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
||||||
import { WorkbenchService } from '@affine/core/modules/workbench';
|
import { WorkbenchService } from '@affine/core/modules/workbench';
|
||||||
import { ViewExtensionManagerIdentifier } from '@blocksuite/affine/ext-loader';
|
import { ViewExtensionManagerIdentifier } from '@blocksuite/affine/ext-loader';
|
||||||
@@ -80,6 +81,9 @@ export const EditorChatPanel = forwardRef(function EditorChatPanel(
|
|||||||
.get('preview-page');
|
.get('preview-page');
|
||||||
chatPanelRef.current.affineFeatureFlagService =
|
chatPanelRef.current.affineFeatureFlagService =
|
||||||
framework.get(FeatureFlagService);
|
framework.get(FeatureFlagService);
|
||||||
|
chatPanelRef.current.affineWorkspaceDialogService = framework.get(
|
||||||
|
WorkspaceDialogService
|
||||||
|
);
|
||||||
|
|
||||||
containerRef.current?.append(chatPanelRef.current);
|
containerRef.current?.append(chatPanelRef.current);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { toReactNode } from '@affine/component';
|
|||||||
import { AIChatBlockPeekViewTemplate } from '@affine/core/blocksuite/ai';
|
import { AIChatBlockPeekViewTemplate } from '@affine/core/blocksuite/ai';
|
||||||
import type { AIChatBlockModel } from '@affine/core/blocksuite/ai/blocks/ai-chat-block/model/ai-chat-model';
|
import type { AIChatBlockModel } from '@affine/core/blocksuite/ai/blocks/ai-chat-block/model/ai-chat-model';
|
||||||
import { useAIChatConfig } from '@affine/core/components/hooks/affine/use-ai-chat-config';
|
import { useAIChatConfig } from '@affine/core/components/hooks/affine/use-ai-chat-config';
|
||||||
|
import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
|
||||||
import { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
import { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
||||||
import type { EditorHost } from '@blocksuite/affine/std';
|
import type { EditorHost } from '@blocksuite/affine/std';
|
||||||
import { useFramework } from '@toeverything/infra';
|
import { useFramework } from '@toeverything/infra';
|
||||||
@@ -25,6 +26,7 @@ export const AIChatBlockPeekView = ({
|
|||||||
|
|
||||||
const framework = useFramework();
|
const framework = useFramework();
|
||||||
const affineFeatureFlagService = framework.get(FeatureFlagService);
|
const affineFeatureFlagService = framework.get(FeatureFlagService);
|
||||||
|
const affineWorkspaceDialogService = framework.get(WorkspaceDialogService);
|
||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
const template = AIChatBlockPeekViewTemplate(
|
const template = AIChatBlockPeekViewTemplate(
|
||||||
@@ -34,7 +36,8 @@ export const AIChatBlockPeekView = ({
|
|||||||
searchMenuConfig,
|
searchMenuConfig,
|
||||||
networkSearchConfig,
|
networkSearchConfig,
|
||||||
reasoningConfig,
|
reasoningConfig,
|
||||||
affineFeatureFlagService
|
affineFeatureFlagService,
|
||||||
|
affineWorkspaceDialogService
|
||||||
);
|
);
|
||||||
return toReactNode(template);
|
return toReactNode(template);
|
||||||
}, [
|
}, [
|
||||||
@@ -45,5 +48,6 @@ export const AIChatBlockPeekView = ({
|
|||||||
networkSearchConfig,
|
networkSearchConfig,
|
||||||
reasoningConfig,
|
reasoningConfig,
|
||||||
affineFeatureFlagService,
|
affineFeatureFlagService,
|
||||||
|
affineWorkspaceDialogService,
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ test.describe('AIBasic/Chat', () => {
|
|||||||
await expect(page.getByTestId('ai-onboarding')).toBeVisible();
|
await expect(page.getByTestId('ai-onboarding')).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should display embedding status tooltip', async ({
|
test('should open embedding settings when clicking check status button', async ({
|
||||||
loggedInPage: page,
|
loggedInPage: page,
|
||||||
utils,
|
utils,
|
||||||
}) => {
|
}) => {
|
||||||
@@ -32,12 +32,8 @@ test.describe('AIBasic/Chat', () => {
|
|||||||
);
|
);
|
||||||
await expect(check).toBeVisible({ timeout: 50 * 1000 });
|
await expect(check).toBeVisible({ timeout: 50 * 1000 });
|
||||||
|
|
||||||
await check.hover();
|
await check.click();
|
||||||
const tooltip = await page.getByTestId('ai-chat-embedding-status-tooltip');
|
await expect(page.getByTestId('workspace-setting:embedding')).toBeVisible();
|
||||||
await expect(tooltip).toBeVisible();
|
|
||||||
await expect(tooltip).toHaveText(
|
|
||||||
/Results will improve after embedding|Embedding finished/
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test(`should send message and receive AI response:
|
test(`should send message and receive AI response:
|
||||||
|
|||||||
Reference in New Issue
Block a user