mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-07 01:09:54 +08:00
fix: chat session cannot delete (#14312)
fix #14309 #### PR Dependency Tree * **PR #14312** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added AI chat session deletion with confirmation dialogs and success/failure notifications. * Localized AI chat panel labels, loading messages, and session management text across multiple languages. * **Documentation** * Added internationalization support for chat panel titles, history loading states, and deletion confirmations. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
+44
@@ -0,0 +1,44 @@
|
|||||||
|
import type { CopilotChatHistoryFragment } from '@affine/graphql';
|
||||||
|
import type { NotificationService } from '@blocksuite/affine/shared/services';
|
||||||
|
|
||||||
|
import type { DocDisplayConfig } from '../ai-chat-chips';
|
||||||
|
import type { ChatStatus } from '../ai-chat-messages';
|
||||||
|
import { AIChatToolbar } from './ai-chat-toolbar';
|
||||||
|
|
||||||
|
export type ConfigureAIChatToolbarOptions = {
|
||||||
|
session: CopilotChatHistoryFragment | null | undefined;
|
||||||
|
workspaceId: string;
|
||||||
|
docId?: string;
|
||||||
|
status: ChatStatus;
|
||||||
|
docDisplayConfig: DocDisplayConfig;
|
||||||
|
notificationService: NotificationService;
|
||||||
|
onNewSession: () => void;
|
||||||
|
onTogglePin: () => Promise<void>;
|
||||||
|
onOpenSession: (sessionId: string) => void;
|
||||||
|
onOpenDoc: (docId: string, sessionId: string) => void;
|
||||||
|
onSessionDelete: (session: BlockSuitePresets.AIRecentSession) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getOrCreateAIChatToolbar(
|
||||||
|
current: AIChatToolbar | null | undefined
|
||||||
|
): AIChatToolbar {
|
||||||
|
return current ?? new AIChatToolbar();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function configureAIChatToolbar(
|
||||||
|
tool: AIChatToolbar,
|
||||||
|
options: ConfigureAIChatToolbarOptions
|
||||||
|
): AIChatToolbar {
|
||||||
|
tool.session = options.session;
|
||||||
|
tool.workspaceId = options.workspaceId;
|
||||||
|
tool.docId = options.docId;
|
||||||
|
tool.status = options.status;
|
||||||
|
tool.docDisplayConfig = options.docDisplayConfig;
|
||||||
|
tool.notificationService = options.notificationService;
|
||||||
|
tool.onNewSession = options.onNewSession;
|
||||||
|
tool.onTogglePin = options.onTogglePin;
|
||||||
|
tool.onOpenSession = options.onOpenSession;
|
||||||
|
tool.onOpenDoc = options.onOpenDoc;
|
||||||
|
tool.onSessionDelete = options.onSessionDelete;
|
||||||
|
return tool;
|
||||||
|
}
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
export * from './ai-chat-toolbar';
|
export * from './ai-chat-toolbar';
|
||||||
export * from './ai-session-history';
|
export * from './ai-session-history';
|
||||||
|
export * from './configure-ai-chat-toolbar';
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ const AllDocsButton = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const AIChatButton = () => {
|
const AIChatButton = () => {
|
||||||
|
const t = useI18n();
|
||||||
const featureFlagService = useService(FeatureFlagService);
|
const featureFlagService = useService(FeatureFlagService);
|
||||||
const serverService = useService(ServerService);
|
const serverService = useService(ServerService);
|
||||||
const serverFeatures = useLiveData(serverService.server.features$);
|
const serverFeatures = useLiveData(serverService.server.features$);
|
||||||
@@ -108,7 +109,9 @@ const AIChatButton = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<MenuLinkItem icon={<AiOutlineIcon />} active={aiChatActive} to={'/chat'}>
|
<MenuLinkItem icon={<AiOutlineIcon />} active={aiChatActive} to={'/chat'}>
|
||||||
<span data-testid="ai-chat">Intelligence</span>
|
<span data-testid="ai-chat">
|
||||||
|
{t['com.affine.workspaceSubPath.chat']()}
|
||||||
|
</span>
|
||||||
</MenuLinkItem>
|
</MenuLinkItem>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import type { I18nInstance } from '@affine/i18n';
|
||||||
|
import type { NotificationService } from '@blocksuite/affine/shared/services';
|
||||||
|
|
||||||
|
export type SessionDeleteCleanupFn = (
|
||||||
|
session: BlockSuitePresets.AIRecentSession
|
||||||
|
) => Promise<void>;
|
||||||
|
|
||||||
|
export type CreateSessionDeleteHandlerOptions = {
|
||||||
|
t: I18nInstance;
|
||||||
|
notificationService: NotificationService;
|
||||||
|
cleanupSession: SessionDeleteCleanupFn;
|
||||||
|
canDeleteSession?: (session: BlockSuitePresets.AIRecentSession) => boolean;
|
||||||
|
isActiveSession?: (session: BlockSuitePresets.AIRecentSession) => boolean;
|
||||||
|
onActiveSessionDeleted?: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function createSessionDeleteHandler({
|
||||||
|
t,
|
||||||
|
notificationService,
|
||||||
|
cleanupSession,
|
||||||
|
canDeleteSession,
|
||||||
|
isActiveSession,
|
||||||
|
onActiveSessionDeleted,
|
||||||
|
}: CreateSessionDeleteHandlerOptions) {
|
||||||
|
return async (sessionToDelete: BlockSuitePresets.AIRecentSession) => {
|
||||||
|
if (canDeleteSession && !canDeleteSession(sessionToDelete)) {
|
||||||
|
notificationService.toast(
|
||||||
|
t['com.affine.ai.chat-panel.session.delete.toast.failed']()
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const confirm = await notificationService.confirm({
|
||||||
|
title: t['com.affine.ai.chat-panel.session.delete.confirm.title'](),
|
||||||
|
message: t['com.affine.ai.chat-panel.session.delete.confirm.message'](),
|
||||||
|
confirmText: t['Delete'](),
|
||||||
|
cancelText: t['Cancel'](),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!confirm) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await cleanupSession(sessionToDelete);
|
||||||
|
notificationService.toast(
|
||||||
|
t['com.affine.ai.chat-panel.session.delete.toast.success']()
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
notificationService.toast(
|
||||||
|
t['com.affine.ai.chat-panel.session.delete.toast.failed']()
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isActiveSession?.(sessionToDelete)) {
|
||||||
|
onActiveSessionDeleted?.();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -5,7 +5,11 @@ import {
|
|||||||
type ChatContextValue,
|
type ChatContextValue,
|
||||||
} from '@affine/core/blocksuite/ai/components/ai-chat-content';
|
} from '@affine/core/blocksuite/ai/components/ai-chat-content';
|
||||||
import type { ChatStatus } from '@affine/core/blocksuite/ai/components/ai-chat-messages';
|
import type { ChatStatus } from '@affine/core/blocksuite/ai/components/ai-chat-messages';
|
||||||
import { AIChatToolbar } from '@affine/core/blocksuite/ai/components/ai-chat-toolbar';
|
import {
|
||||||
|
AIChatToolbar,
|
||||||
|
configureAIChatToolbar,
|
||||||
|
getOrCreateAIChatToolbar,
|
||||||
|
} from '@affine/core/blocksuite/ai/components/ai-chat-toolbar';
|
||||||
import type { PromptKey } from '@affine/core/blocksuite/ai/provider/prompt';
|
import type { PromptKey } from '@affine/core/blocksuite/ai/provider/prompt';
|
||||||
import { getViewManager } from '@affine/core/blocksuite/manager/view';
|
import { getViewManager } from '@affine/core/blocksuite/manager/view';
|
||||||
import { NotificationServiceImpl } from '@affine/core/blocksuite/view-extensions/editor-view/notification-service';
|
import { NotificationServiceImpl } from '@affine/core/blocksuite/view-extensions/editor-view/notification-service';
|
||||||
@@ -37,6 +41,7 @@ import {
|
|||||||
WorkbenchService,
|
WorkbenchService,
|
||||||
} from '@affine/core/modules/workbench';
|
} from '@affine/core/modules/workbench';
|
||||||
import { WorkspaceService } from '@affine/core/modules/workspace';
|
import { WorkspaceService } from '@affine/core/modules/workspace';
|
||||||
|
import { useI18n } from '@affine/i18n';
|
||||||
import { RefNodeSlotsProvider } from '@blocksuite/affine/inlines/reference';
|
import { RefNodeSlotsProvider } from '@blocksuite/affine/inlines/reference';
|
||||||
import { BlockStdScope } from '@blocksuite/affine/std';
|
import { BlockStdScope } from '@blocksuite/affine/std';
|
||||||
import type { Workspace } from '@blocksuite/affine/store';
|
import type { Workspace } from '@blocksuite/affine/store';
|
||||||
@@ -45,6 +50,7 @@ import { useFramework, useService } from '@toeverything/infra';
|
|||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
|
||||||
|
import { createSessionDeleteHandler } from '../chat-panel-utils';
|
||||||
import * as styles from './index.css';
|
import * as styles from './index.css';
|
||||||
|
|
||||||
type CopilotSession = Awaited<ReturnType<CopilotClient['getSession']>>;
|
type CopilotSession = Awaited<ReturnType<CopilotClient['getSession']>>;
|
||||||
@@ -88,6 +94,7 @@ function useMockStd() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const Component = () => {
|
export const Component = () => {
|
||||||
|
const t = useI18n();
|
||||||
const framework = useFramework();
|
const framework = useFramework();
|
||||||
const [isBodyProvided, setIsBodyProvided] = useState(false);
|
const [isBodyProvided, setIsBodyProvided] = useState(false);
|
||||||
const [isHeaderProvided, setIsHeaderProvided] = useState(false);
|
const [isHeaderProvided, setIsHeaderProvided] = useState(false);
|
||||||
@@ -193,10 +200,46 @@ export const Component = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const confirmModal = useConfirmModal();
|
const confirmModal = useConfirmModal();
|
||||||
|
const notificationService = useMemo(
|
||||||
|
() =>
|
||||||
|
new NotificationServiceImpl(
|
||||||
|
confirmModal.closeConfirmModal,
|
||||||
|
confirmModal.openConfirmModal
|
||||||
|
),
|
||||||
|
[confirmModal.closeConfirmModal, confirmModal.openConfirmModal]
|
||||||
|
);
|
||||||
const specs = useAISpecs();
|
const specs = useAISpecs();
|
||||||
const mockStd = useMockStd();
|
const mockStd = useMockStd();
|
||||||
const handleAISubscribe = useAISubscribe();
|
const handleAISubscribe = useAISubscribe();
|
||||||
|
|
||||||
|
const deleteSession = useMemo(
|
||||||
|
() =>
|
||||||
|
createSessionDeleteHandler({
|
||||||
|
t,
|
||||||
|
notificationService,
|
||||||
|
cleanupSession: async sessionToDelete => {
|
||||||
|
await client.cleanupSessions({
|
||||||
|
workspaceId: sessionToDelete.workspaceId,
|
||||||
|
docId: sessionToDelete.docId || undefined,
|
||||||
|
sessionIds: [sessionToDelete.sessionId],
|
||||||
|
});
|
||||||
|
},
|
||||||
|
isActiveSession: sessionToDelete =>
|
||||||
|
sessionToDelete.sessionId === currentSession?.sessionId,
|
||||||
|
onActiveSessionDeleted: () => {
|
||||||
|
setCurrentSession(null);
|
||||||
|
reMountChatContent();
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
[
|
||||||
|
client,
|
||||||
|
currentSession?.sessionId,
|
||||||
|
notificationService,
|
||||||
|
reMountChatContent,
|
||||||
|
t,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
// init or update ai-chat-content
|
// init or update ai-chat-content
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isBodyProvided) {
|
if (!isBodyProvided) {
|
||||||
@@ -223,10 +266,7 @@ export const Component = () => {
|
|||||||
);
|
);
|
||||||
content.peekViewService = framework.get(PeekViewService);
|
content.peekViewService = framework.get(PeekViewService);
|
||||||
content.affineThemeService = framework.get(AppThemeService);
|
content.affineThemeService = framework.get(AppThemeService);
|
||||||
content.notificationService = new NotificationServiceImpl(
|
content.notificationService = notificationService;
|
||||||
confirmModal.closeConfirmModal,
|
|
||||||
confirmModal.openConfirmModal
|
|
||||||
);
|
|
||||||
content.aiDraftService = framework.get(AIDraftService);
|
content.aiDraftService = framework.get(AIDraftService);
|
||||||
content.aiToolsConfigService = framework.get(AIToolsConfigService);
|
content.aiToolsConfigService = framework.get(AIToolsConfigService);
|
||||||
content.serverService = framework.get(ServerService);
|
content.serverService = framework.get(ServerService);
|
||||||
@@ -258,6 +298,7 @@ export const Component = () => {
|
|||||||
workspaceId,
|
workspaceId,
|
||||||
confirmModal,
|
confirmModal,
|
||||||
onContextChange,
|
onContextChange,
|
||||||
|
notificationService,
|
||||||
specs,
|
specs,
|
||||||
onOpenDoc,
|
onOpenDoc,
|
||||||
handleAISubscribe,
|
handleAISubscribe,
|
||||||
@@ -268,39 +309,31 @@ export const Component = () => {
|
|||||||
if (!isHeaderProvided || !chatToolContainerRef.current) {
|
if (!isHeaderProvided || !chatToolContainerRef.current) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let tool = chatTool;
|
const tool = getOrCreateAIChatToolbar(chatTool);
|
||||||
|
configureAIChatToolbar(tool, {
|
||||||
if (!tool) {
|
session: currentSession,
|
||||||
tool = new AIChatToolbar();
|
workspaceId,
|
||||||
}
|
status,
|
||||||
|
docDisplayConfig,
|
||||||
tool.session = currentSession;
|
notificationService,
|
||||||
tool.workspaceId = workspaceId;
|
onOpenSession,
|
||||||
tool.status = status;
|
onNewSession: () => {
|
||||||
tool.docDisplayConfig = docDisplayConfig;
|
if (!currentSession) return;
|
||||||
tool.onOpenSession = onOpenSession;
|
setCurrentSession(null);
|
||||||
tool.notificationService = new NotificationServiceImpl(
|
reMountChatContent();
|
||||||
confirmModal.closeConfirmModal,
|
},
|
||||||
confirmModal.openConfirmModal
|
onTogglePin: togglePin,
|
||||||
);
|
onOpenDoc: (docId: string, sessionId: string) => {
|
||||||
|
const { workbench } = framework.get(WorkbenchService);
|
||||||
tool.onNewSession = () => {
|
const viewService = framework.get(ViewService);
|
||||||
if (!currentSession) return;
|
workbench.open(`/${docId}?sessionId=${sessionId}`, { at: 'active' });
|
||||||
setCurrentSession(null);
|
workbench.openSidebar();
|
||||||
reMountChatContent();
|
viewService.view.activeSidebarTab('chat');
|
||||||
};
|
},
|
||||||
|
onSessionDelete: (sessionToDelete: BlockSuitePresets.AIRecentSession) => {
|
||||||
tool.onTogglePin = async () => {
|
deleteSession(sessionToDelete).catch(console.error);
|
||||||
await togglePin();
|
},
|
||||||
};
|
});
|
||||||
|
|
||||||
tool.onOpenDoc = (docId: string, sessionId: string) => {
|
|
||||||
const { workbench } = framework.get(WorkbenchService);
|
|
||||||
const viewService = framework.get(ViewService);
|
|
||||||
workbench.open(`/${docId}?sessionId=${sessionId}`, { at: 'active' });
|
|
||||||
workbench.openSidebar();
|
|
||||||
viewService.view.activeSidebarTab('chat');
|
|
||||||
};
|
|
||||||
|
|
||||||
// initial props
|
// initial props
|
||||||
if (!chatTool) {
|
if (!chatTool) {
|
||||||
@@ -318,8 +351,10 @@ export const Component = () => {
|
|||||||
workspaceId,
|
workspaceId,
|
||||||
confirmModal,
|
confirmModal,
|
||||||
framework,
|
framework,
|
||||||
|
deleteSession,
|
||||||
status,
|
status,
|
||||||
reMountChatContent,
|
reMountChatContent,
|
||||||
|
notificationService,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -390,7 +425,7 @@ export const Component = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ViewTitle title="Intelligence" />
|
<ViewTitle title={t['com.affine.workspaceSubPath.chat']()} />
|
||||||
<ViewIcon icon="ai" />
|
<ViewIcon icon="ai" />
|
||||||
<ViewHeader>
|
<ViewHeader>
|
||||||
<div className={styles.chatHeader}>
|
<div className={styles.chatHeader}>
|
||||||
|
|||||||
@@ -6,7 +6,11 @@ import {
|
|||||||
type ChatContextValue,
|
type ChatContextValue,
|
||||||
} from '@affine/core/blocksuite/ai/components/ai-chat-content';
|
} from '@affine/core/blocksuite/ai/components/ai-chat-content';
|
||||||
import type { ChatStatus } from '@affine/core/blocksuite/ai/components/ai-chat-messages';
|
import type { ChatStatus } from '@affine/core/blocksuite/ai/components/ai-chat-messages';
|
||||||
import { AIChatToolbar } from '@affine/core/blocksuite/ai/components/ai-chat-toolbar';
|
import {
|
||||||
|
AIChatToolbar,
|
||||||
|
configureAIChatToolbar,
|
||||||
|
getOrCreateAIChatToolbar,
|
||||||
|
} from '@affine/core/blocksuite/ai/components/ai-chat-toolbar';
|
||||||
import { createPlaygroundModal } from '@affine/core/blocksuite/ai/components/playground/modal';
|
import { createPlaygroundModal } from '@affine/core/blocksuite/ai/components/playground/modal';
|
||||||
import { registerAIAppEffects } from '@affine/core/blocksuite/ai/effects/app';
|
import { registerAIAppEffects } from '@affine/core/blocksuite/ai/effects/app';
|
||||||
import type { AffineEditorContainer } from '@affine/core/blocksuite/block-suite-editor';
|
import type { AffineEditorContainer } from '@affine/core/blocksuite/block-suite-editor';
|
||||||
@@ -31,6 +35,7 @@ import type {
|
|||||||
CopilotChatHistoryFragment,
|
CopilotChatHistoryFragment,
|
||||||
UpdateChatSessionInput,
|
UpdateChatSessionInput,
|
||||||
} from '@affine/graphql';
|
} from '@affine/graphql';
|
||||||
|
import { useI18n } from '@affine/i18n';
|
||||||
import { RefNodeSlotsProvider } from '@blocksuite/affine/inlines/reference';
|
import { RefNodeSlotsProvider } from '@blocksuite/affine/inlines/reference';
|
||||||
import { DocModeProvider } from '@blocksuite/affine/shared/services';
|
import { DocModeProvider } from '@blocksuite/affine/shared/services';
|
||||||
import { createSignalFromObservable } from '@blocksuite/affine/shared/utils';
|
import { createSignalFromObservable } from '@blocksuite/affine/shared/utils';
|
||||||
@@ -40,6 +45,7 @@ import { useFramework, useService } from '@toeverything/infra';
|
|||||||
import { html } from 'lit';
|
import { html } from 'lit';
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
|
||||||
|
import { createSessionDeleteHandler } from '../../chat-panel-utils';
|
||||||
import * as styles from './chat.css';
|
import * as styles from './chat.css';
|
||||||
import {
|
import {
|
||||||
resolveInitialSession,
|
resolveInitialSession,
|
||||||
@@ -56,6 +62,7 @@ export interface SidebarTabProps {
|
|||||||
export const EditorChatPanel = ({ editor, onLoad }: SidebarTabProps) => {
|
export const EditorChatPanel = ({ editor, onLoad }: SidebarTabProps) => {
|
||||||
const framework = useFramework();
|
const framework = useFramework();
|
||||||
const workbench = useService(WorkbenchService).workbench;
|
const workbench = useService(WorkbenchService).workbench;
|
||||||
|
const t = useI18n();
|
||||||
|
|
||||||
const { closeConfirmModal, openConfirmModal } = useConfirmModal();
|
const { closeConfirmModal, openConfirmModal } = useConfirmModal();
|
||||||
const notificationService = useMemo(
|
const notificationService = useMemo(
|
||||||
@@ -230,30 +237,24 @@ export const EditorChatPanel = ({ editor, onLoad }: SidebarTabProps) => {
|
|||||||
[doc, openSession, session?.pinned, session?.sessionId, workbench]
|
[doc, openSession, session?.pinned, session?.sessionId, workbench]
|
||||||
);
|
);
|
||||||
|
|
||||||
const deleteSession = useCallback(
|
const deleteSession = useMemo(
|
||||||
async (sessionToDelete: BlockSuitePresets.AIRecentSession) => {
|
() =>
|
||||||
if (!AIProvider.histories) {
|
createSessionDeleteHandler({
|
||||||
return;
|
t,
|
||||||
}
|
notificationService,
|
||||||
const confirm = await notificationService.confirm({
|
canDeleteSession: () => Boolean(AIProvider.histories),
|
||||||
title: 'Delete this history?',
|
cleanupSession: async sessionToDelete => {
|
||||||
message:
|
await AIProvider.histories?.cleanup(
|
||||||
'Do you want to delete this AI conversation history? Once deleted, it cannot be recovered.',
|
sessionToDelete.workspaceId,
|
||||||
confirmText: 'Delete',
|
sessionToDelete.docId || undefined,
|
||||||
cancelText: 'Cancel',
|
[sessionToDelete.sessionId]
|
||||||
});
|
);
|
||||||
if (confirm) {
|
},
|
||||||
await AIProvider.histories.cleanup(
|
isActiveSession: sessionToDelete =>
|
||||||
sessionToDelete.workspaceId,
|
sessionToDelete.sessionId === session?.sessionId,
|
||||||
sessionToDelete.docId || undefined,
|
onActiveSessionDeleted: newSession,
|
||||||
[sessionToDelete.sessionId]
|
}),
|
||||||
);
|
[newSession, notificationService, session?.sessionId, t]
|
||||||
if (sessionToDelete.sessionId === session?.sessionId) {
|
|
||||||
newSession();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[newSession, notificationService, session?.sessionId]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const togglePin = useCallback(async () => {
|
const togglePin = useCallback(async () => {
|
||||||
@@ -460,31 +461,26 @@ export const EditorChatPanel = ({ editor, onLoad }: SidebarTabProps) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let tool = chatToolbar;
|
const tool = getOrCreateAIChatToolbar(chatToolbar);
|
||||||
|
configureAIChatToolbar(tool, {
|
||||||
if (!tool) {
|
session,
|
||||||
tool = new AIChatToolbar();
|
workspaceId: doc.workspace.id,
|
||||||
}
|
docId: doc.id,
|
||||||
|
status,
|
||||||
tool.session = session;
|
docDisplayConfig,
|
||||||
tool.workspaceId = doc.workspace.id;
|
notificationService,
|
||||||
tool.docId = doc.id;
|
onNewSession: newSession,
|
||||||
tool.status = status;
|
onTogglePin: togglePin,
|
||||||
tool.docDisplayConfig = docDisplayConfig;
|
onOpenSession: (sessionId: string) => {
|
||||||
tool.notificationService = notificationService;
|
openSession(sessionId).catch(console.error);
|
||||||
tool.onNewSession = newSession;
|
},
|
||||||
tool.onTogglePin = togglePin;
|
onOpenDoc: (docId: string, sessionId: string) => {
|
||||||
tool.onOpenSession = (sessionId: string) => {
|
openDoc(docId, sessionId).catch(console.error);
|
||||||
openSession(sessionId).catch(console.error);
|
},
|
||||||
};
|
onSessionDelete: (sessionToDelete: BlockSuitePresets.AIRecentSession) => {
|
||||||
tool.onOpenDoc = (docId: string, sessionId: string) => {
|
deleteSession(sessionToDelete).catch(console.error);
|
||||||
openDoc(docId, sessionId).catch(console.error);
|
},
|
||||||
};
|
});
|
||||||
tool.onSessionDelete = (
|
|
||||||
sessionToDelete: BlockSuitePresets.AIRecentSession
|
|
||||||
) => {
|
|
||||||
deleteSession(sessionToDelete).catch(console.error);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!chatToolbar) {
|
if (!chatToolbar) {
|
||||||
chatToolbarContainerRef.current.append(tool);
|
chatToolbarContainerRef.current.append(tool);
|
||||||
@@ -618,7 +614,7 @@ export const EditorChatPanel = ({ editor, onLoad }: SidebarTabProps) => {
|
|||||||
<div className={styles.loading}>
|
<div className={styles.loading}>
|
||||||
<Logo1Icon className={styles.loadingIcon} />
|
<Logo1Icon className={styles.loadingIcon} />
|
||||||
<div className={styles.loadingTitle}>
|
<div className={styles.loadingTitle}>
|
||||||
AFFiNE AI is loading history...
|
{t['com.affine.ai.chat-panel.loading-history']()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -628,10 +624,13 @@ export const EditorChatPanel = ({ editor, onLoad }: SidebarTabProps) => {
|
|||||||
<div className={styles.title}>
|
<div className={styles.title}>
|
||||||
{isEmbedding ? (
|
{isEmbedding ? (
|
||||||
<span data-testid="chat-panel-embedding-progress">
|
<span data-testid="chat-panel-embedding-progress">
|
||||||
Embedding {done}/{total}
|
{t.t('com.affine.ai.chat-panel.embedding-progress', {
|
||||||
|
done,
|
||||||
|
total,
|
||||||
|
})}
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
'AFFiNE AI'
|
t['com.affine.ai.chat-panel.title']()
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{playgroundVisible ? (
|
{playgroundVisible ? (
|
||||||
|
|||||||
@@ -1,26 +1,26 @@
|
|||||||
{
|
{
|
||||||
"ar": 99,
|
"ar": 98,
|
||||||
"ca": 100,
|
"ca": 100,
|
||||||
"da": 4,
|
"da": 4,
|
||||||
"de": 100,
|
"de": 99,
|
||||||
"el-GR": 99,
|
"el-GR": 98,
|
||||||
"en": 100,
|
"en": 100,
|
||||||
"es-AR": 99,
|
"es-AR": 98,
|
||||||
"es-CL": 100,
|
"es-CL": 100,
|
||||||
"es": 99,
|
"es": 98,
|
||||||
"fa": 99,
|
"fa": 98,
|
||||||
"fr": 100,
|
"fr": 100,
|
||||||
"hi": 2,
|
"hi": 2,
|
||||||
"it-IT": 100,
|
"it-IT": 100,
|
||||||
"it": 1,
|
"it": 1,
|
||||||
"ja": 99,
|
"ja": 98,
|
||||||
"ko": 100,
|
"ko": 99,
|
||||||
"nb-NO": 49,
|
"nb-NO": 48,
|
||||||
"pl": 100,
|
"pl": 100,
|
||||||
"pt-BR": 99,
|
"pt-BR": 98,
|
||||||
"ru": 100,
|
"ru": 100,
|
||||||
"sv-SE": 99,
|
"sv-SE": 99,
|
||||||
"uk": 99,
|
"uk": 98,
|
||||||
"ur": 2,
|
"ur": 2,
|
||||||
"zh-Hans": 100,
|
"zh-Hans": 100,
|
||||||
"zh-Hant": 99
|
"zh-Hant": 99
|
||||||
|
|||||||
@@ -867,6 +867,37 @@ export function useAFFiNEI18N(): {
|
|||||||
* `Failed to insert template, please try again.`
|
* `Failed to insert template, please try again.`
|
||||||
*/
|
*/
|
||||||
["com.affine.ai.template-insert.failed"](): string;
|
["com.affine.ai.template-insert.failed"](): string;
|
||||||
|
/**
|
||||||
|
* `AFFiNE AI`
|
||||||
|
*/
|
||||||
|
["com.affine.ai.chat-panel.title"](): string;
|
||||||
|
/**
|
||||||
|
* `AFFiNE AI is loading history...`
|
||||||
|
*/
|
||||||
|
["com.affine.ai.chat-panel.loading-history"](): string;
|
||||||
|
/**
|
||||||
|
* `Embedding {{done}}/{{total}}`
|
||||||
|
*/
|
||||||
|
["com.affine.ai.chat-panel.embedding-progress"](options: Readonly<{
|
||||||
|
done: string;
|
||||||
|
total: string;
|
||||||
|
}>): string;
|
||||||
|
/**
|
||||||
|
* `Delete this history?`
|
||||||
|
*/
|
||||||
|
["com.affine.ai.chat-panel.session.delete.confirm.title"](): string;
|
||||||
|
/**
|
||||||
|
* `Do you want to delete this AI conversation history? Once deleted, it cannot be recovered.`
|
||||||
|
*/
|
||||||
|
["com.affine.ai.chat-panel.session.delete.confirm.message"](): string;
|
||||||
|
/**
|
||||||
|
* `History deleted`
|
||||||
|
*/
|
||||||
|
["com.affine.ai.chat-panel.session.delete.toast.success"](): string;
|
||||||
|
/**
|
||||||
|
* `Failed to delete history`
|
||||||
|
*/
|
||||||
|
["com.affine.ai.chat-panel.session.delete.toast.failed"](): string;
|
||||||
/**
|
/**
|
||||||
* `All docs`
|
* `All docs`
|
||||||
*/
|
*/
|
||||||
@@ -7246,6 +7277,10 @@ export function useAFFiNEI18N(): {
|
|||||||
* `All docs`
|
* `All docs`
|
||||||
*/
|
*/
|
||||||
["com.affine.workspaceSubPath.all"](): string;
|
["com.affine.workspaceSubPath.all"](): string;
|
||||||
|
/**
|
||||||
|
* `Intelligence`
|
||||||
|
*/
|
||||||
|
["com.affine.workspaceSubPath.chat"](): string;
|
||||||
/**
|
/**
|
||||||
* `Trash`
|
* `Trash`
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -206,6 +206,13 @@
|
|||||||
"com.affine.ai.login-required.dialog-content": "To use AFFiNE AI, please sign in to your AFFiNE Cloud account.",
|
"com.affine.ai.login-required.dialog-content": "To use AFFiNE AI, please sign in to your AFFiNE Cloud account.",
|
||||||
"com.affine.ai.login-required.dialog-title": "Sign in to continue",
|
"com.affine.ai.login-required.dialog-title": "Sign in to continue",
|
||||||
"com.affine.ai.template-insert.failed": "Failed to insert template, please try again.",
|
"com.affine.ai.template-insert.failed": "Failed to insert template, please try again.",
|
||||||
|
"com.affine.ai.chat-panel.title": "AFFiNE AI",
|
||||||
|
"com.affine.ai.chat-panel.loading-history": "AFFiNE AI is loading history...",
|
||||||
|
"com.affine.ai.chat-panel.embedding-progress": "Embedding {{done}}/{{total}}",
|
||||||
|
"com.affine.ai.chat-panel.session.delete.confirm.title": "Delete this history?",
|
||||||
|
"com.affine.ai.chat-panel.session.delete.confirm.message": "Do you want to delete this AI conversation history? Once deleted, it cannot be recovered.",
|
||||||
|
"com.affine.ai.chat-panel.session.delete.toast.success": "History deleted",
|
||||||
|
"com.affine.ai.chat-panel.session.delete.toast.failed": "Failed to delete history",
|
||||||
"com.affine.all-pages.header": "All docs",
|
"com.affine.all-pages.header": "All docs",
|
||||||
"com.affine.app-sidebar.learn-more": "Learn more",
|
"com.affine.app-sidebar.learn-more": "Learn more",
|
||||||
"com.affine.app-sidebar.star-us": "Star us",
|
"com.affine.app-sidebar.star-us": "Star us",
|
||||||
@@ -1813,6 +1820,7 @@
|
|||||||
"com.affine.workspaceList.workspaceListType.local": "Local storage",
|
"com.affine.workspaceList.workspaceListType.local": "Local storage",
|
||||||
"com.affine.workspaceList.addServer": "Add Server",
|
"com.affine.workspaceList.addServer": "Add Server",
|
||||||
"com.affine.workspaceSubPath.all": "All docs",
|
"com.affine.workspaceSubPath.all": "All docs",
|
||||||
|
"com.affine.workspaceSubPath.chat": "Intelligence",
|
||||||
"com.affine.workspaceSubPath.trash": "Trash",
|
"com.affine.workspaceSubPath.trash": "Trash",
|
||||||
"com.affine.workspaceSubPath.trash.empty-description": "Deleted docs will appear here.",
|
"com.affine.workspaceSubPath.trash.empty-description": "Deleted docs will appear here.",
|
||||||
"com.affine.write_with_a_blank_page": "Write with a blank page",
|
"com.affine.write_with_a_blank_page": "Write with a blank page",
|
||||||
|
|||||||
@@ -206,6 +206,13 @@
|
|||||||
"com.affine.ai.login-required.dialog-content": "要使用 AFFiNE AI,请先登录您的 AFFiNE Cloud 帐户。",
|
"com.affine.ai.login-required.dialog-content": "要使用 AFFiNE AI,请先登录您的 AFFiNE Cloud 帐户。",
|
||||||
"com.affine.ai.login-required.dialog-title": "登录以继续",
|
"com.affine.ai.login-required.dialog-title": "登录以继续",
|
||||||
"com.affine.ai.template-insert.failed": "插入模板失败,请重试。",
|
"com.affine.ai.template-insert.failed": "插入模板失败,请重试。",
|
||||||
|
"com.affine.ai.chat-panel.title": "AFFiNE AI",
|
||||||
|
"com.affine.ai.chat-panel.loading-history": "AFFiNE AI 正在加载历史记录...",
|
||||||
|
"com.affine.ai.chat-panel.embedding-progress": "嵌入 {{done}}/{{total}}",
|
||||||
|
"com.affine.ai.chat-panel.session.delete.confirm.title": "删除此历史记录?",
|
||||||
|
"com.affine.ai.chat-panel.session.delete.confirm.message": "确定要删除这段 AI 对话历史记录吗?删除后无法恢复。",
|
||||||
|
"com.affine.ai.chat-panel.session.delete.toast.success": "已删除历史记录",
|
||||||
|
"com.affine.ai.chat-panel.session.delete.toast.failed": "删除历史记录失败",
|
||||||
"com.affine.all-pages.header": "所有文档",
|
"com.affine.all-pages.header": "所有文档",
|
||||||
"com.affine.app-sidebar.learn-more": "了解更多",
|
"com.affine.app-sidebar.learn-more": "了解更多",
|
||||||
"com.affine.app-sidebar.star-us": "给我们点亮星标",
|
"com.affine.app-sidebar.star-us": "给我们点亮星标",
|
||||||
@@ -1808,6 +1815,7 @@
|
|||||||
"com.affine.workspaceList.workspaceListType.local": "本地储存",
|
"com.affine.workspaceList.workspaceListType.local": "本地储存",
|
||||||
"com.affine.workspaceList.addServer": "添加服务器",
|
"com.affine.workspaceList.addServer": "添加服务器",
|
||||||
"com.affine.workspaceSubPath.all": "全部文档",
|
"com.affine.workspaceSubPath.all": "全部文档",
|
||||||
|
"com.affine.workspaceSubPath.chat": "Intelligence",
|
||||||
"com.affine.workspaceSubPath.trash": "回收站",
|
"com.affine.workspaceSubPath.trash": "回收站",
|
||||||
"com.affine.workspaceSubPath.trash.empty-description": "已删除的文档将显示在此处。",
|
"com.affine.workspaceSubPath.trash.empty-description": "已删除的文档将显示在此处。",
|
||||||
"com.affine.write_with_a_blank_page": "在空白页面书写",
|
"com.affine.write_with_a_blank_page": "在空白页面书写",
|
||||||
|
|||||||
@@ -205,6 +205,13 @@
|
|||||||
"com.affine.ai.login-required.dialog-content": "要使用 AFFiNE AI,請先登入您的 AFFiNE Cloud 帳戶。",
|
"com.affine.ai.login-required.dialog-content": "要使用 AFFiNE AI,請先登入您的 AFFiNE Cloud 帳戶。",
|
||||||
"com.affine.ai.login-required.dialog-title": "登入以繼續",
|
"com.affine.ai.login-required.dialog-title": "登入以繼續",
|
||||||
"com.affine.ai.template-insert.failed": "插入模板失敗,請重試。",
|
"com.affine.ai.template-insert.failed": "插入模板失敗,請重試。",
|
||||||
|
"com.affine.ai.chat-panel.title": "AFFiNE AI",
|
||||||
|
"com.affine.ai.chat-panel.loading-history": "AFFiNE AI 正在載入歷史記錄...",
|
||||||
|
"com.affine.ai.chat-panel.embedding-progress": "嵌入 {{done}}/{{total}}",
|
||||||
|
"com.affine.ai.chat-panel.session.delete.confirm.title": "刪除此歷史記錄?",
|
||||||
|
"com.affine.ai.chat-panel.session.delete.confirm.message": "確定要刪除這段 AI 對話歷史記錄嗎?刪除後無法復原。",
|
||||||
|
"com.affine.ai.chat-panel.session.delete.toast.success": "已刪除歷史記錄",
|
||||||
|
"com.affine.ai.chat-panel.session.delete.toast.failed": "刪除歷史記錄失敗",
|
||||||
"com.affine.all-pages.header": "所有文件",
|
"com.affine.all-pages.header": "所有文件",
|
||||||
"com.affine.app-sidebar.learn-more": "了解更多",
|
"com.affine.app-sidebar.learn-more": "了解更多",
|
||||||
"com.affine.app-sidebar.star-us": "給我們點亮星標",
|
"com.affine.app-sidebar.star-us": "給我們點亮星標",
|
||||||
@@ -1785,6 +1792,7 @@
|
|||||||
"com.affine.workspaceList.workspaceListType.local": "本地儲存",
|
"com.affine.workspaceList.workspaceListType.local": "本地儲存",
|
||||||
"com.affine.workspaceList.addServer": "新增伺服器",
|
"com.affine.workspaceList.addServer": "新增伺服器",
|
||||||
"com.affine.workspaceSubPath.all": "所有頁面",
|
"com.affine.workspaceSubPath.all": "所有頁面",
|
||||||
|
"com.affine.workspaceSubPath.chat": "Intelligence",
|
||||||
"com.affine.workspaceSubPath.trash": "廢紙簍",
|
"com.affine.workspaceSubPath.trash": "廢紙簍",
|
||||||
"com.affine.workspaceSubPath.trash.empty-description": "已刪除的文件將顯示在此處。",
|
"com.affine.workspaceSubPath.trash.empty-description": "已刪除的文件將顯示在此處。",
|
||||||
"com.affine.write_with_a_blank_page": "在空白頁書寫",
|
"com.affine.write_with_a_blank_page": "在空白頁書寫",
|
||||||
|
|||||||
Reference in New Issue
Block a user