Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
a21adae
define render attachment xml element server side
chrisbmar Feb 16, 2026
7fc050b
update attachment ui definition interface with new methods
chrisbmar Feb 16, 2026
574285c
markdown plugin initial implementation
chrisbmar Feb 16, 2026
489ef34
wire up markdown plugin with dependencies
chrisbmar Feb 16, 2026
28fa891
implement attachment with actions base logic
chrisbmar Feb 16, 2026
e6e9de1
rename file
chrisbmar Feb 16, 2026
b042eb5
remove console logs
chrisbmar Feb 16, 2026
319ff23
Merge branch 'main' into ab-attachment-inline-rendering-12939
chrisbmar Feb 16, 2026
92e310c
Merge branch 'main' into ab-attachment-inline-rendering-12939
chrisbmar Feb 17, 2026
06fbbfc
update action button contract to include an icon
chrisbmar Feb 18, 2026
237e745
update ui attachment registry contract
chrisbmar Feb 18, 2026
e60d98f
create canvas mode flyout
chrisbmar Feb 18, 2026
11c4571
wire up attachment with actions to flyout
chrisbmar Feb 18, 2026
658e72f
small updates to canvas mode flyout
chrisbmar Feb 18, 2026
8156bff
define render attachment xml element server side
chrisbmar Feb 16, 2026
f7f5ed4
update attachment ui definition interface with new methods
chrisbmar Feb 16, 2026
3575341
markdown plugin initial implementation
chrisbmar Feb 16, 2026
94e015f
wire up markdown plugin with dependencies
chrisbmar Feb 16, 2026
5b89a2a
implement attachment with actions base logic
chrisbmar Feb 16, 2026
061c6dc
rename file
chrisbmar Feb 16, 2026
67eb2b5
remove console logs
chrisbmar Feb 16, 2026
52470d0
update action button contract to include an icon
chrisbmar Feb 18, 2026
806ae0c
revert prompt changes for now
chrisbmar Feb 19, 2026
34ca193
Merge branch 'ab-attachment-inline-rendering-clean' into ab-canvas-mo…
chrisbmar Feb 19, 2026
f4be5c4
fix type of flyout
chrisbmar Feb 19, 2026
be2e19d
revert these prompt changes
chrisbmar Feb 19, 2026
ae1fb6d
Merge branch 'main' into ab-canvas-mode-12944
chrisbmar Feb 19, 2026
06fa798
remove experimental feature flag guard
chrisbmar Feb 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export interface GetActionButtonsParams<TAttachment extends UnknownAttachment =
isSidebar: boolean;
/** Function to update the attachment's origin reference */
updateOrigin: (originId: string) => Promise<void>;
/** Callback to open the attachment in canvas mode (expanded flyout view) */
openCanvas: () => void;
}

/**
Expand Down Expand Up @@ -72,7 +74,12 @@ export interface AttachmentUIDefinition<TAttachment extends UnknownAttachment =
* When provided, attachments can be rendered inline in the conversation
* using the <render_attachment> tag.
*/
renderContent?: (props: AttachmentRenderProps<TAttachment>) => ReactNode;
renderInlineContent?: (props: AttachmentRenderProps<TAttachment>) => ReactNode;
/**
* Optional custom content renderer for canvas mode (expanded flyout view).
* When provided, attachments can be opened in an expanded view via action buttons.
*/
renderCanvasContent?: (props: AttachmentRenderProps<TAttachment>) => ReactNode;
/**
* Optional function to provide action buttons for inline-rendered attachments.
* Buttons will appear alongside or below the rendered content.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@
* 2.0.
*/

import React from 'react';
import React, { useCallback, useState } from 'react';
import type { UnknownAttachment } from '@kbn/agent-builder-common/attachments';
import { EuiButton } from '@elastic/eui';
import { AGENT_BUILDER_EXPERIMENTAL_FEATURES_SETTING_ID } from '@kbn/management-settings-ids';
import type { AttachmentsService } from '../../../../../services/attachments/attachements_service';
import { useKibana } from '../../../../hooks/use_kibana';
import { CanvasModeFlyout } from './canvas_mode_flyout';

interface AttachmentWithActionsProps {
attachment: UnknownAttachment;
Expand All @@ -28,17 +27,15 @@ export const AttachmentWithActions: React.FC<AttachmentWithActionsProps> = ({
isSidebar,
conversationId,
}) => {
const {
services: { settings },
} = useKibana();
const isExperimentalFeaturesEnabled = settings?.client.get<boolean>(
AGENT_BUILDER_EXPERIMENTAL_FEATURES_SETTING_ID,
false
);
const [isCanvasFlyoutOpen, setIsCanvasFlyoutOpen] = useState(false);

if (isExperimentalFeaturesEnabled === false) {
return null;
}
const openCanvas = useCallback(() => {
setIsCanvasFlyoutOpen(true);
}, []);

const closeCanvas = useCallback(() => {
setIsCanvasFlyoutOpen(false);
}, []);

const uiDefinition = attachmentsService.getAttachmentUiDefinition(attachment.type);

Expand All @@ -53,6 +50,7 @@ export const AttachmentWithActions: React.FC<AttachmentWithActionsProps> = ({
// TODO: Implement updateOrigin
// attachmentsService.updateOrigin(conversationId, attachment.id, originId);
},
openCanvas,
});

return (
Expand All @@ -62,7 +60,17 @@ export const AttachmentWithActions: React.FC<AttachmentWithActionsProps> = ({
{button.label}
</EuiButton>
))}
{uiDefinition?.renderContent?.({ attachment, isSidebar })}
{uiDefinition?.renderInlineContent?.({ attachment, isSidebar })}
{isCanvasFlyoutOpen && uiDefinition?.renderCanvasContent && (
<CanvasModeFlyout
isOpen={isCanvasFlyoutOpen}
onClose={closeCanvas}
title={attachment.type}
isSidebar={isSidebar}
>
{uiDefinition.renderCanvasContent({ attachment, isSidebar })}
</CanvasModeFlyout>
)}
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';
import { EuiFlyout, EuiFlyoutHeader, EuiFlyoutBody, EuiTitle } from '@elastic/eui';
import { css } from '@emotion/react';
import { i18n } from '@kbn/i18n';

interface CanvasModeFlyoutProps {
isOpen: boolean;
onClose: () => void;
title?: string;
children: React.ReactNode;
isSidebar?: boolean;
}

/**
* Flyout component for displaying attachments in canvas mode (expanded view).
* In full-screen context, renders at 50% screen width. In sidebar context, uses default flyout width.
*/
export const CanvasModeFlyout: React.FC<CanvasModeFlyoutProps> = ({
isOpen,
onClose,
title,
children,
isSidebar,
}) => {
// Only apply custom width in full-screen context (not sidebar)
const flyoutStyles = !isSidebar
? css`
width: 50vw;
`
: undefined;

if (!isOpen) {
return null;
}

return (
<EuiFlyout
onClose={onClose}
aria-labelledby="canvasModeFlyoutTitle"
ownFocus={false}
outsideClickCloses={true}
css={flyoutStyles}
type={isSidebar ? 'overlay' : 'push'}
>
<EuiFlyoutHeader hasBorder>
<EuiTitle size="m">
<h2 id="canvasModeFlyoutTitle">
{title ||
i18n.translate('xpack.agentBuilder.canvasMode.defaultTitle', {
defaultMessage: 'Canvas Mode',
})}
</h2>
</EuiTitle>
</EuiFlyoutHeader>
<EuiFlyoutBody>{children}</EuiFlyoutBody>
</EuiFlyout>
);
};
Loading