mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-18 18:41:52 +08:00
feat(core): center peek doc in chat semantic/keyword search result (#13380)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added the ability to preview documents directly from AI chat search results using a new document peek view. * Search result items in AI chat are now clickable, allowing for quick document previews without leaving the chat interface. * **Style** * Updated clickable item styles in search results for improved visual feedback and consistency. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -4,6 +4,7 @@ import type {
|
|||||||
} from '@affine/core/modules/ai-button';
|
} from '@affine/core/modules/ai-button';
|
||||||
import type { WorkspaceDialogService } from '@affine/core/modules/dialogs';
|
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 { PeekViewService } from '@affine/core/modules/peek-view';
|
||||||
import type { AppThemeService } from '@affine/core/modules/theme';
|
import type { AppThemeService } from '@affine/core/modules/theme';
|
||||||
import type { WorkbenchService } from '@affine/core/modules/workbench';
|
import type { WorkbenchService } from '@affine/core/modules/workbench';
|
||||||
import type {
|
import type {
|
||||||
@@ -125,6 +126,9 @@ export class ChatPanel extends SignalWatcher(
|
|||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor aiToolsConfigService!: AIToolsConfigService;
|
accessor aiToolsConfigService!: AIToolsConfigService;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
accessor peekViewService!: PeekViewService;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
accessor session: CopilotChatHistoryFragment | null | undefined;
|
accessor session: CopilotChatHistoryFragment | null | undefined;
|
||||||
|
|
||||||
@@ -421,6 +425,7 @@ export class ChatPanel extends SignalWatcher(
|
|||||||
.notificationService=${this.notificationService}
|
.notificationService=${this.notificationService}
|
||||||
.aiDraftService=${this.aiDraftService}
|
.aiDraftService=${this.aiDraftService}
|
||||||
.aiToolsConfigService=${this.aiToolsConfigService}
|
.aiToolsConfigService=${this.aiToolsConfigService}
|
||||||
|
.peekViewService=${this.peekViewService}
|
||||||
.onEmbeddingProgressChange=${this.onEmbeddingProgressChange}
|
.onEmbeddingProgressChange=${this.onEmbeddingProgressChange}
|
||||||
.onContextChange=${this.onContextChange}
|
.onContextChange=${this.onContextChange}
|
||||||
.width=${this.sidebarWidth}
|
.width=${this.sidebarWidth}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
||||||
|
import type { PeekViewService } from '@affine/core/modules/peek-view';
|
||||||
import type { AppThemeService } from '@affine/core/modules/theme';
|
import type { AppThemeService } from '@affine/core/modules/theme';
|
||||||
import type { CopilotChatHistoryFragment } from '@affine/graphql';
|
import type { CopilotChatHistoryFragment } from '@affine/graphql';
|
||||||
import { WithDisposable } from '@blocksuite/affine/global/lit';
|
import { WithDisposable } from '@blocksuite/affine/global/lit';
|
||||||
@@ -86,6 +87,9 @@ export class ChatMessageAssistant extends WithDisposable(ShadowlessElement) {
|
|||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor docDisplayService!: DocDisplayConfig;
|
accessor docDisplayService!: DocDisplayConfig;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
accessor peekViewService!: PeekViewService;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor onOpenDoc!: (docId: string, sessionId?: string) => void;
|
accessor onOpenDoc!: (docId: string, sessionId?: string) => void;
|
||||||
|
|
||||||
@@ -150,6 +154,7 @@ export class ChatMessageAssistant extends WithDisposable(ShadowlessElement) {
|
|||||||
.theme=${this.affineThemeService.appTheme.themeSignal}
|
.theme=${this.affineThemeService.appTheme.themeSignal}
|
||||||
.independentMode=${this.independentMode}
|
.independentMode=${this.independentMode}
|
||||||
.docDisplayService=${this.docDisplayService}
|
.docDisplayService=${this.docDisplayService}
|
||||||
|
.peekViewService=${this.peekViewService}
|
||||||
.onOpenDoc=${this.onOpenDoc}
|
.onOpenDoc=${this.onOpenDoc}
|
||||||
></chat-content-stream-objects>`;
|
></chat-content-stream-objects>`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import type {
|
|||||||
import type { AIDraftState } from '@affine/core/modules/ai-button/services/ai-draft';
|
import type { AIDraftState } from '@affine/core/modules/ai-button/services/ai-draft';
|
||||||
import type { WorkspaceDialogService } from '@affine/core/modules/dialogs';
|
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 { PeekViewService } from '@affine/core/modules/peek-view';
|
||||||
import type { AppThemeService } from '@affine/core/modules/theme';
|
import type { AppThemeService } from '@affine/core/modules/theme';
|
||||||
import type {
|
import type {
|
||||||
ContextEmbedStatus,
|
ContextEmbedStatus,
|
||||||
@@ -178,6 +179,9 @@ export class AIChatContent extends SignalWatcher(
|
|||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor width: Signal<number | undefined> | undefined;
|
accessor width: Signal<number | undefined> | undefined;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
accessor peekViewService!: PeekViewService;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
accessor chatContextValue: ChatContextValue = DEFAULT_CHAT_CONTEXT_VALUE;
|
accessor chatContextValue: ChatContextValue = DEFAULT_CHAT_CONTEXT_VALUE;
|
||||||
|
|
||||||
@@ -427,6 +431,7 @@ export class AIChatContent extends SignalWatcher(
|
|||||||
.independentMode=${this.independentMode}
|
.independentMode=${this.independentMode}
|
||||||
.messages=${this.messages}
|
.messages=${this.messages}
|
||||||
.docDisplayService=${this.docDisplayConfig}
|
.docDisplayService=${this.docDisplayConfig}
|
||||||
|
.peekViewService=${this.peekViewService}
|
||||||
.onOpenDoc=${this.onOpenDoc}
|
.onOpenDoc=${this.onOpenDoc}
|
||||||
></ai-chat-messages>
|
></ai-chat-messages>
|
||||||
<ai-chat-composer
|
<ai-chat-composer
|
||||||
|
|||||||
+5
@@ -1,4 +1,5 @@
|
|||||||
import type { AIToolsConfigService } from '@affine/core/modules/ai-button';
|
import type { AIToolsConfigService } from '@affine/core/modules/ai-button';
|
||||||
|
import type { PeekViewService } from '@affine/core/modules/peek-view';
|
||||||
import type { AppThemeService } from '@affine/core/modules/theme';
|
import type { AppThemeService } from '@affine/core/modules/theme';
|
||||||
import type { CopilotChatHistoryFragment } from '@affine/graphql';
|
import type { CopilotChatHistoryFragment } from '@affine/graphql';
|
||||||
import { WithDisposable } from '@blocksuite/affine/global/lit';
|
import { WithDisposable } from '@blocksuite/affine/global/lit';
|
||||||
@@ -210,6 +211,9 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) {
|
|||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor aiToolsConfigService!: AIToolsConfigService;
|
accessor aiToolsConfigService!: AIToolsConfigService;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
accessor peekViewService!: PeekViewService;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor onOpenDoc!: (docId: string, sessionId?: string) => void;
|
accessor onOpenDoc!: (docId: string, sessionId?: string) => void;
|
||||||
|
|
||||||
@@ -340,6 +344,7 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) {
|
|||||||
.width=${this.width}
|
.width=${this.width}
|
||||||
.independentMode=${this.independentMode}
|
.independentMode=${this.independentMode}
|
||||||
.docDisplayService=${this.docDisplayService}
|
.docDisplayService=${this.docDisplayService}
|
||||||
|
.peekViewService=${this.peekViewService}
|
||||||
.onOpenDoc=${this.onOpenDoc}
|
.onOpenDoc=${this.onOpenDoc}
|
||||||
></chat-message-assistant>`;
|
></chat-message-assistant>`;
|
||||||
} else if (isChatAction(item) && this.host) {
|
} else if (isChatAction(item) && this.host) {
|
||||||
|
|||||||
+7
@@ -1,4 +1,5 @@
|
|||||||
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
||||||
|
import type { PeekViewService } from '@affine/core/modules/peek-view';
|
||||||
import { WithDisposable } from '@blocksuite/affine/global/lit';
|
import { WithDisposable } from '@blocksuite/affine/global/lit';
|
||||||
import type { ColorScheme } from '@blocksuite/affine/model';
|
import type { ColorScheme } from '@blocksuite/affine/model';
|
||||||
import {
|
import {
|
||||||
@@ -61,6 +62,9 @@ export class ChatContentStreamObjects extends WithDisposable(
|
|||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor docDisplayService!: DocDisplayConfig;
|
accessor docDisplayService!: DocDisplayConfig;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
accessor peekViewService!: PeekViewService;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor onOpenDoc!: (docId: string, sessionId?: string) => void;
|
accessor onOpenDoc!: (docId: string, sessionId?: string) => void;
|
||||||
|
|
||||||
@@ -115,6 +119,7 @@ export class ChatContentStreamObjects extends WithDisposable(
|
|||||||
return html`<doc-semantic-search-result
|
return html`<doc-semantic-search-result
|
||||||
.data=${streamObject}
|
.data=${streamObject}
|
||||||
.width=${this.width}
|
.width=${this.width}
|
||||||
|
.peekViewService=${this.peekViewService}
|
||||||
></doc-semantic-search-result>`;
|
></doc-semantic-search-result>`;
|
||||||
case 'doc_keyword_search':
|
case 'doc_keyword_search':
|
||||||
return html`<doc-keyword-search-result
|
return html`<doc-keyword-search-result
|
||||||
@@ -201,12 +206,14 @@ export class ChatContentStreamObjects extends WithDisposable(
|
|||||||
.data=${streamObject}
|
.data=${streamObject}
|
||||||
.width=${this.width}
|
.width=${this.width}
|
||||||
.docDisplayService=${this.docDisplayService}
|
.docDisplayService=${this.docDisplayService}
|
||||||
|
.peekViewService=${this.peekViewService}
|
||||||
.onOpenDoc=${this.onOpenDoc}
|
.onOpenDoc=${this.onOpenDoc}
|
||||||
></doc-semantic-search-result>`;
|
></doc-semantic-search-result>`;
|
||||||
case 'doc_keyword_search':
|
case 'doc_keyword_search':
|
||||||
return html`<doc-keyword-search-result
|
return html`<doc-keyword-search-result
|
||||||
.data=${streamObject}
|
.data=${streamObject}
|
||||||
.width=${this.width}
|
.width=${this.width}
|
||||||
|
.peekViewService=${this.peekViewService}
|
||||||
.onOpenDoc=${this.onOpenDoc}
|
.onOpenDoc=${this.onOpenDoc}
|
||||||
></doc-keyword-search-result>`;
|
></doc-keyword-search-result>`;
|
||||||
case 'doc_read':
|
case 'doc_read':
|
||||||
|
|||||||
+12
@@ -1,3 +1,4 @@
|
|||||||
|
import type { PeekViewService } from '@affine/core/modules/peek-view';
|
||||||
import { WithDisposable } from '@blocksuite/global/lit';
|
import { WithDisposable } from '@blocksuite/global/lit';
|
||||||
import { PageIcon, SearchIcon } from '@blocksuite/icons/lit';
|
import { PageIcon, SearchIcon } from '@blocksuite/icons/lit';
|
||||||
import { ShadowlessElement } from '@blocksuite/std';
|
import { ShadowlessElement } from '@blocksuite/std';
|
||||||
@@ -41,6 +42,9 @@ export class DocKeywordSearchResult extends WithDisposable(ShadowlessElement) {
|
|||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor onOpenDoc!: (docId: string, sessionId?: string) => void;
|
accessor onOpenDoc!: (docId: string, sessionId?: string) => void;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
accessor peekViewService!: PeekViewService;
|
||||||
|
|
||||||
renderToolCall() {
|
renderToolCall() {
|
||||||
return html`<tool-call-card
|
return html`<tool-call-card
|
||||||
.name=${`Searching workspace documents for "${this.data.args.query}"`}
|
.name=${`Searching workspace documents for "${this.data.args.query}"`}
|
||||||
@@ -63,6 +67,14 @@ export class DocKeywordSearchResult extends WithDisposable(ShadowlessElement) {
|
|||||||
${item.title}
|
${item.title}
|
||||||
</span>`,
|
</span>`,
|
||||||
icon: PageIcon(),
|
icon: PageIcon(),
|
||||||
|
onClick: () => {
|
||||||
|
this.peekViewService.peekView
|
||||||
|
.open({
|
||||||
|
type: 'doc',
|
||||||
|
docRef: { docId: item.docId },
|
||||||
|
})
|
||||||
|
.catch(console.error);
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Failed to parse result', err);
|
console.error('Failed to parse result', err);
|
||||||
|
|||||||
+14
@@ -1,3 +1,4 @@
|
|||||||
|
import type { PeekViewService } from '@affine/core/modules/peek-view';
|
||||||
import { WithDisposable } from '@blocksuite/global/lit';
|
import { WithDisposable } from '@blocksuite/global/lit';
|
||||||
import { AiEmbeddingIcon, PageIcon } from '@blocksuite/icons/lit';
|
import { AiEmbeddingIcon, PageIcon } from '@blocksuite/icons/lit';
|
||||||
import { ShadowlessElement } from '@blocksuite/std';
|
import { ShadowlessElement } from '@blocksuite/std';
|
||||||
@@ -72,6 +73,9 @@ export class DocSemanticSearchResult extends WithDisposable(ShadowlessElement) {
|
|||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor onOpenDoc!: (docId: string, sessionId?: string) => void;
|
accessor onOpenDoc!: (docId: string, sessionId?: string) => void;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
accessor peekViewService!: PeekViewService;
|
||||||
|
|
||||||
renderToolCall() {
|
renderToolCall() {
|
||||||
return html`<tool-call-card
|
return html`<tool-call-card
|
||||||
.name=${`Finding semantically related pages for "${this.data.args.query}"`}
|
.name=${`Finding semantically related pages for "${this.data.args.query}"`}
|
||||||
@@ -97,6 +101,16 @@ export class DocSemanticSearchResult extends WithDisposable(ShadowlessElement) {
|
|||||||
>
|
>
|
||||||
${this.docDisplayService.getTitle(result.docId)}
|
${this.docDisplayService.getTitle(result.docId)}
|
||||||
</span>`,
|
</span>`,
|
||||||
|
onClick: () => {
|
||||||
|
this.peekViewService.peekView
|
||||||
|
.open({
|
||||||
|
type: 'doc',
|
||||||
|
docRef: {
|
||||||
|
docId: result.docId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.catch(console.error);
|
||||||
|
},
|
||||||
}))
|
}))
|
||||||
.filter(Boolean)}
|
.filter(Boolean)}
|
||||||
></tool-result-card>`;
|
></tool-result-card>`;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export interface ToolResult {
|
|||||||
icon?: string | TemplateResult<1>;
|
icon?: string | TemplateResult<1>;
|
||||||
content?: string;
|
content?: string;
|
||||||
href?: string;
|
href?: string;
|
||||||
|
onClick?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ToolResultCard extends SignalWatcher(
|
export class ToolResultCard extends SignalWatcher(
|
||||||
@@ -95,7 +96,8 @@ export class ToolResultCard extends SignalWatcher(
|
|||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
.result-item[href] {
|
.result-item[href],
|
||||||
|
.result-item[data-clickable] {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,7 +156,9 @@ export class ToolResultCard extends SignalWatcher(
|
|||||||
}
|
}
|
||||||
|
|
||||||
.result-item[href]:hover .result-title,
|
.result-item[href]:hover .result-title,
|
||||||
.result-item[href]:hover .result-content {
|
.result-item[href]:hover .result-content,
|
||||||
|
.result-item[data-clickable]:hover .result-title,
|
||||||
|
.result-item[data-clickable]:hover .result-content {
|
||||||
color: ${unsafeCSSVarV2('text/primary')};
|
color: ${unsafeCSSVarV2('text/primary')};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,6 +188,27 @@ export class ToolResultCard extends SignalWatcher(
|
|||||||
color: ${unsafeCSSVarV2('text/primary')};
|
color: ${unsafeCSSVarV2('text/primary')};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.result-icon,
|
||||||
|
.footer-icon {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
border-radius: 100%;
|
||||||
|
background-color: ${unsafeCSSVarV2('layer/background/primary')};
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
border-radius: 100%;
|
||||||
|
border: 0.5px solid ${unsafeCSSVarV2('layer/insideBorder/border')};
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
color: ${unsafeCSSVarV2('icon/primary')};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.footer-icons {
|
.footer-icons {
|
||||||
display: flex;
|
display: flex;
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -244,11 +269,13 @@ export class ToolResultCard extends SignalWatcher(
|
|||||||
result => html`
|
result => html`
|
||||||
<a
|
<a
|
||||||
class="result-item"
|
class="result-item"
|
||||||
|
data-clickable=${!!result.onClick}
|
||||||
href=${ifDefined(result.href)}
|
href=${ifDefined(result.href)}
|
||||||
target=${ifDefined(result.href ? '_blank' : undefined)}
|
target=${ifDefined(result.href ? '_blank' : undefined)}
|
||||||
rel=${ifDefined(
|
rel=${ifDefined(
|
||||||
result.href ? 'noopener noreferrer' : undefined
|
result.href ? 'noopener noreferrer' : undefined
|
||||||
)}
|
)}
|
||||||
|
@click=${result.onClick}
|
||||||
>
|
>
|
||||||
<div class="result-header">
|
<div class="result-header">
|
||||||
<div class="result-title">${result.title}</div>
|
<div class="result-title">${result.title}</div>
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import {
|
|||||||
} from '@affine/core/modules/cloud';
|
} from '@affine/core/modules/cloud';
|
||||||
import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
|
import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
|
||||||
import { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
import { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
||||||
|
import { PeekViewService } from '@affine/core/modules/peek-view';
|
||||||
import { AppThemeService } from '@affine/core/modules/theme';
|
import { AppThemeService } from '@affine/core/modules/theme';
|
||||||
import {
|
import {
|
||||||
ViewBody,
|
ViewBody,
|
||||||
@@ -220,6 +221,7 @@ export const Component = () => {
|
|||||||
content.affineWorkspaceDialogService = framework.get(
|
content.affineWorkspaceDialogService = framework.get(
|
||||||
WorkspaceDialogService
|
WorkspaceDialogService
|
||||||
);
|
);
|
||||||
|
content.peekViewService = framework.get(PeekViewService);
|
||||||
content.affineThemeService = framework.get(AppThemeService);
|
content.affineThemeService = framework.get(AppThemeService);
|
||||||
content.notificationService = new NotificationServiceImpl(
|
content.notificationService = new NotificationServiceImpl(
|
||||||
confirmModal.closeConfirmModal,
|
confirmModal.closeConfirmModal,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
} from '@affine/core/modules/ai-button';
|
} from '@affine/core/modules/ai-button';
|
||||||
import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
|
import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
|
||||||
import { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
import { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
||||||
|
import { PeekViewService } from '@affine/core/modules/peek-view';
|
||||||
import { AppThemeService } from '@affine/core/modules/theme';
|
import { AppThemeService } from '@affine/core/modules/theme';
|
||||||
import { WorkbenchService } from '@affine/core/modules/workbench';
|
import { WorkbenchService } from '@affine/core/modules/workbench';
|
||||||
import { RefNodeSlotsProvider } from '@blocksuite/affine/inlines/reference';
|
import { RefNodeSlotsProvider } from '@blocksuite/affine/inlines/reference';
|
||||||
@@ -95,6 +96,7 @@ export const EditorChatPanel = forwardRef(function EditorChatPanel(
|
|||||||
chatPanelRef.current.affineWorkbenchService =
|
chatPanelRef.current.affineWorkbenchService =
|
||||||
framework.get(WorkbenchService);
|
framework.get(WorkbenchService);
|
||||||
chatPanelRef.current.affineThemeService = framework.get(AppThemeService);
|
chatPanelRef.current.affineThemeService = framework.get(AppThemeService);
|
||||||
|
chatPanelRef.current.peekViewService = framework.get(PeekViewService);
|
||||||
chatPanelRef.current.notificationService = new NotificationServiceImpl(
|
chatPanelRef.current.notificationService = new NotificationServiceImpl(
|
||||||
confirmModal.closeConfirmModal,
|
confirmModal.closeConfirmModal,
|
||||||
confirmModal.openConfirmModal
|
confirmModal.openConfirmModal
|
||||||
|
|||||||
Reference in New Issue
Block a user