Skip to content

Commit

Permalink
[Obs AI Assistant] Add chat context menu and copy URL functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
viduni94 committed Feb 19, 2025
1 parent 3b2b78e commit 2c8d3cb
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,10 @@ import { useKnowledgeBase } from '../hooks';

export function ChatActionsMenu({
connectors,
conversationId,
disabled,
onCopyConversationClick,
}: {
connectors: UseGenAIConnectorsResult;
conversationId?: string;
disabled: boolean;
onCopyConversationClick: () => void;
}) {
const { application, http } = useKibana().services;
const knowledgeBase = useKnowledgeBase();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export function ChatBody({
const chatService = useAIAssistantChatService();

const {
services: { uiSettings, notifications },
services: { uiSettings, notifications, http },
} = useKibana();

const simulateFunctionCalling = uiSettings!.get<boolean>(
Expand Down Expand Up @@ -251,7 +251,7 @@ export function ChatBody({
}
});

const handleCopyConversation = () => {
const handleCopyConversationToClipboard = () => {
try {
const deserializedMessages = (conversation.value?.messages ?? messages).map(
deserializeMessage
Expand Down Expand Up @@ -280,16 +280,21 @@ export function ChatBody({

const handleCopyUrl = () => {
try {
const deserializedMessages = (conversation.value?.messages ?? messages).map(
deserializeMessage
const conversationId = conversation.value?.conversation?.id;
if (!conversationId) {
throw new Error('Cannot copy URL if the conversation is not stored');
}

const conversationUrl = http?.basePath.prepend(
`/app/observabilityAIAssistant/conversations/${conversationId}`
);

const content = JSON.stringify({
title: initialTitle,
messages: deserializedMessages,
});
if (!conversationUrl) {
throw new Error('Conversation URL does not exist');
}

navigator.clipboard?.writeText(content || '');
const urlToCopy = new URL(conversationUrl, window.location.origin).toString();
navigator.clipboard?.writeText(urlToCopy);

notifications!.toasts.addSuccess({
title: i18n.translate('xpack.aiAssistant.copyUrlSuccessToast', {
Expand Down Expand Up @@ -566,7 +571,8 @@ export function ChatBody({
licenseInvalid={!hasCorrectLicense && !initialConversationId}
loading={isLoading}
title={title}
onCopyConversation={handleCopyConversation}
onCopyConversationToClipboard={handleCopyConversationToClipboard}
onCopyUrl={handleCopyUrl}
onSaveTitle={(newTitle) => {
saveTitle(newTitle);
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ import {
import { i18n } from '@kbn/i18n';

export function ChatContextMenu({
onCopyConversationClick,
onCopyToClipboardClick,
onCopyUrlClick,
disabled,
}: {
onCopyConversationClick: () => void;
onCopyToClipboardClick: () => void;
onCopyUrlClick: () => void;
disabled: boolean;
}) {
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
Expand Down Expand Up @@ -53,26 +55,26 @@ export function ChatContextMenu({
size="s"
items={[
<EuiContextMenuItem
key="copyConversation"
key="copyConversationToClipboard"
icon="copyClipboard"
onClick={() => {
onCopyConversationClick();
onCopyToClipboardClick();
setIsPopoverOpen(false);
}}
>
{i18n.translate('xpack.aiAssistant.chatHeader.contextMenu.copyConversation', {
defaultMessage: 'Copy conversation',
{i18n.translate('xpack.aiAssistant.chatHeader.contextMenu.copyToClipboard', {
defaultMessage: 'Copy to clipboard',
})}
</EuiContextMenuItem>,
<EuiContextMenuItem
key="copyURL"
icon="link"
onClick={() => {
navigator.clipboard.writeText(window.location.href);
onCopyUrlClick();
setIsPopoverOpen(false);
}}
>
{i18n.translate('xpack.aiAssistant.chatHeader.contextMenu.copyURL', {
{i18n.translate('xpack.aiAssistant.chatHeader.contextMenu.copyUrl', {
defaultMessage: 'Copy URL',
})}
</EuiContextMenuItem>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,21 +49,23 @@ export function ChatHeader({
licenseInvalid,
loading,
title,
onCopyConversation,
onCopyConversationToClipboard,
onSaveTitle,
onToggleFlyoutPositionMode,
navigateToConversation,
onCopyUrl,
}: {
connectors: UseGenAIConnectorsResult;
conversationId?: string;
flyoutPositionMode?: FlyoutPositionMode;
licenseInvalid: boolean;
loading: boolean;
title: string;
onCopyConversation: () => void;
onCopyConversationToClipboard: () => void;
onSaveTitle: (title: string) => void;
onToggleFlyoutPositionMode?: (newFlyoutPositionMode: FlyoutPositionMode) => void;
navigateToConversation?: (nextConversationId?: string) => void;
onCopyUrl: () => void;
}) {
const theme = useEuiTheme();
const breakpoint = useCurrentEuiBreakpoint();
Expand Down Expand Up @@ -152,7 +154,8 @@ export function ChatHeader({
{conversationId ? (
<EuiFlexItem grow={false}>
<ChatContextMenu
onCopyConversationClick={onCopyConversation}
onCopyToClipboardClick={onCopyConversationToClipboard}
onCopyUrlClick={onCopyUrl}
disabled={licenseInvalid}
/>
</EuiFlexItem>
Expand Down Expand Up @@ -224,12 +227,7 @@ export function ChatHeader({
) : null}

<EuiFlexItem grow={false}>
<ChatActionsMenu
connectors={connectors}
conversationId={conversationId}
disabled={licenseInvalid}
onCopyConversationClick={onCopyConversation}
/>
<ChatActionsMenu connectors={connectors} disabled={licenseInvalid} />
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,9 @@ export class ObservabilityAIAssistantAppPlugin
const appService = (this.appService = createAppService({
pluginsStart,
}));

const isEnabled = appService.isEnabled();

if (isEnabled) {
coreStart.chrome.navControls.registerRight({
mount: (element) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export function ConversationViewWithProps() {
const { path } = useObservabilityAIAssistantParams('/conversations/*');
const conversationId = 'conversationId' in path ? path.conversationId : undefined;
const observabilityAIAssistantRouter = useObservabilityAIAssistantRouter();

function navigateToConversation(nextConversationId?: string) {
if (nextConversationId) {
observabilityAIAssistantRouter.push('/conversations/{conversationId}', {
Expand All @@ -26,6 +27,7 @@ export function ConversationViewWithProps() {
observabilityAIAssistantRouter.push('/conversations/new', { path: {}, query: {} });
}
}

return (
<ConversationView
conversationId={conversationId}
Expand Down

0 comments on commit 2c8d3cb

Please sign in to comment.