Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -86,21 +86,23 @@ export const AgentAvatar: React.FC<AgentAvatarProps> = (props) => {
const isDefaultAgent = agentId === agentBuilderDefaultAgentId;
const shouldUseIcon = !symbol && (isBuiltIn || isDefaultAgent || Boolean(icon));

const borderAndShapeStyles = css`
border: 1px solid ${euiTheme.colors.borderBaseSubdued};
${shape === 'circle' ? 'border-radius: 50%;' : roundedBorderRadiusStyles}
`;

if (shouldUseIcon) {
const iconType = icon ?? 'logoElastic';
const iconSize = getIconSize({ size });
if (hasBackground) {
const panelStyles = css`
background-color: ${color};
${roundedBorderRadiusStyles}
`;
return (
<EuiPanel hasBorder={false} hasShadow={false} css={panelStyles} paddingSize="xs">
<EuiIcon type={iconType} size={iconSize} />
</EuiPanel>
);
}
return <EuiIcon type={iconType} size={iconSize} />;
const panelStyles = css`
${hasBackground ? `background-color: ${color};` : ''}
${borderAndShapeStyles}
`;
return (
<EuiPanel hasBorder={false} hasShadow={false} css={panelStyles} paddingSize="xs">
<EuiIcon type={iconType} size={iconSize} />
</EuiPanel>
);
}

let type: 'user' | 'space' | undefined;
Expand All @@ -109,15 +111,14 @@ export const AgentAvatar: React.FC<AgentAvatarProps> = (props) => {
} else if (shape === 'square') {
type = 'space';
}
const avatarStyles = shape === 'square' && roundedBorderRadiusStyles;
return (
<EuiAvatar
size={size}
name={name}
initials={symbol}
type={type}
color={color}
css={avatarStyles}
css={borderAndShapeStyles}
/>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
/*
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just moved from another location, not new

* 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, { useState } from 'react';

import {
EuiButtonEmpty,
EuiFlexGroup,
EuiFlexItem,
EuiPopover,
EuiPopoverFooter,
EuiSelectable,
} from '@elastic/eui';
import type { EuiPopoverProps } from '@elastic/eui';
import { css } from '@emotion/react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import type { AgentDefinition } from '@kbn/agent-builder-common';

import { useUiPrivileges } from '../../hooks/use_ui_privileges';
import { useNavigation } from '../../hooks/use_navigation';
import { appPaths } from '../../utils/app_paths';
import {
getMaxListHeight,
selectorPopoverPanelStyles,
useSelectorListStyles,
} from '../conversations/conversation_input/input_actions/input_actions.styles';
import { useAgentOptions } from '../conversations/conversation_input/input_actions/agent_selector/use_agent_options';

const AGENT_OPTION_ROW_HEIGHT = 44;

const selectAgentAriaLabel = i18n.translate(
'xpack.agentBuilder.agentSelectorDropdown.selectAgent.ariaLabel',
{ defaultMessage: 'Select an agent' }
);
const createAgentAriaLabel = i18n.translate(
'xpack.agentBuilder.agentSelectorDropdown.createAgent.ariaLabel',
{ defaultMessage: 'Create an agent' }
);
const manageAgentsAriaLabel = i18n.translate(
'xpack.agentBuilder.agentSelectorDropdown.manageAgents.ariaLabel',
{ defaultMessage: 'Manage agents' }
);

const agentSelectId = 'agentBuilderAgentSelectorDropdown';
const agentListId = `${agentSelectId}_listbox`;

const AgentListFooter: React.FC = () => {
const { manageAgents } = useUiPrivileges();
const { createAgentBuilderUrl } = useNavigation();
const createAgentHref = createAgentBuilderUrl(appPaths.agents.new);
const manageAgentsHref = createAgentBuilderUrl(appPaths.agents.list);
return (
<EuiPopoverFooter paddingSize="s">
<EuiFlexGroup responsive={false} justifyContent="spaceBetween" gutterSize="s">
<EuiFlexItem>
<EuiButtonEmpty
size="s"
iconType="gear"
color="text"
aria-label={manageAgentsAriaLabel}
href={manageAgentsHref}
disabled={!manageAgents}
>
<FormattedMessage
id="xpack.agentBuilder.agentSelectorDropdown.manageAgents"
defaultMessage="Manage"
/>
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem>
<EuiButtonEmpty
size="s"
iconType="plus"
aria-label={createAgentAriaLabel}
href={createAgentHref}
disabled={!manageAgents}
>
<FormattedMessage
id="xpack.agentBuilder.agentSelectorDropdown.createNewAgent"
defaultMessage="New"
/>
</EuiButtonEmpty>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPopoverFooter>
);
};

export interface AgentSelectorDropdownProps {
agents: AgentDefinition[];
selectedAgent?: AgentDefinition;
onAgentChange: (agentId: string) => void;
anchorPosition?: EuiPopoverProps['anchorPosition'];
/** Shown in the trigger button when selectedAgent is undefined (e.g. deleted agent) */
fallbackLabel?: string;
}

export const AgentSelectorDropdown: React.FC<AgentSelectorDropdownProps> = ({
agents,
selectedAgent,
onAgentChange,
anchorPosition = 'downLeft',
fallbackLabel,
}) => {
const [isPopoverOpen, setIsPopoverOpen] = useState(false);

const { agentOptions, renderAgentOption } = useAgentOptions({
agents,
selectedAgentId: selectedAgent?.id,
});

const selectorListStyles = css`
${useSelectorListStyles({ listId: agentListId })}
&#${agentListId} .euiSelectableListItem {
align-items: flex-start;
}
`;

const listItemsHeight = agentOptions.length * AGENT_OPTION_ROW_HEIGHT;
const listHeight = Math.min(listItemsHeight, getMaxListHeight({ withFooter: true }));

const triggerButton = (
<EuiButtonEmpty
size="s"
iconType="arrowDown"
iconSide="right"
flush="both"
color="text"
onClick={() => setIsPopoverOpen((v) => !v)}
>
{selectedAgent?.name ?? fallbackLabel}
</EuiButtonEmpty>
);

return (
<EuiPopover
panelProps={{ css: selectorPopoverPanelStyles }}
panelPaddingSize="none"
button={triggerButton}
isOpen={isPopoverOpen}
anchorPosition={anchorPosition}
closePopover={() => setIsPopoverOpen(false)}
>
<EuiSelectable
id={agentSelectId}
aria-label={selectAgentAriaLabel}
options={agentOptions}
onChange={(_options, _event, changedOption) => {
const { checked, key: agentId } = changedOption;
if (checked === 'on' && agentId) {
onAgentChange(agentId);
setIsPopoverOpen(false);
}
}}
singleSelection
renderOption={(option) => renderAgentOption({ agent: option.agent })}
height={listHeight}
listProps={{
id: agentListId,
isVirtualized: true,
rowHeight: AGENT_OPTION_ROW_HEIGHT,
onFocusBadge: false,
css: selectorListStyles,
}}
>
{(list) => (
<>
{list}
<AgentListFooter />
</>
)}
</EuiSelectable>
</EuiPopover>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const AgentOptionPrepend: React.FC<{ agent: AgentDefinition }> = ({ agent }) =>
return (
<EuiFlexGroup direction="column" justifyContent="flexStart">
<EuiFlexItem grow={false}>
<AgentAvatar agent={agent} size="m" color="subdued" shape="square" />
<AgentAvatar agent={agent} size="m" color="subdued" shape="circle" />
</EuiFlexItem>
</EuiFlexGroup>
);
Expand All @@ -44,25 +44,31 @@ const AgentOption: React.FC<AgentOptionProps> = ({ agent }) => {

return (
<OptionText>
<EuiFlexGroup component="span" responsive={false} alignItems="center" gutterSize="s">
<EuiFlexGroup
component="span"
responsive={false}
alignItems="center"
gutterSize="s"
direction="row"
justifyContent="spaceBetween"
>
<EuiFlexItem component="span" grow={false}>
{agent.name}
</EuiFlexItem>
{agent.readonly && (
<EuiFlexItem component="span" grow={false}>
<EuiIconTip
type="lock"
size="m"
content={readonlyAgentTooltip}
anchorProps={{
css: css`
display: flex;
justify-content: center;
`,
}}
/>
</EuiFlexItem>
)}
<EuiFlexItem component="span" grow={false}>
<EuiIconTip
type="info"
size="s"
content={agent.description}
position="right"
anchorProps={{
css: css`
display: flex;
justify-content: center;
`,
}}
/>
</EuiFlexItem>
</EuiFlexGroup>
</OptionText>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const getMaxListHeight = ({
return height;
};

const SELECTOR_POPOVER_WIDTH = 275;
const SELECTOR_POPOVER_WIDTH = 400;
export const selectorPopoverPanelStyles = css`
inline-size: ${SELECTOR_POPOVER_WIDTH}px;
`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@

import { useEuiTheme } from '@elastic/eui';
import { css } from '@emotion/react';
import { i18n } from '@kbn/i18n';
import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';
import React from 'react';
import { Conversation } from './conversation';
import { ConversationHeader } from './conversation_header/conversation_header';
Expand All @@ -20,68 +18,43 @@ import { conversationBackgroundStyles, headerHeight } from './conversation.style
export const AgentBuilderConversationsView: React.FC<{}> = () => {
const { euiTheme } = useEuiTheme();

const mainStyles = css`
border: none;
const containerStyles = css`
display: flex;
flex-direction: column;
height: var(--kbn-application--content-height);
${conversationBackgroundStyles(euiTheme)}
`;

const headerStyles = css`
justify-content: center;
flex-shrink: 0;
height: ${headerHeight}px;
display: flex;
align-items: center;
padding: ${euiTheme.size.m};
`;

const contentStyles = css`
width: 100%;
height: 100%;
flex: 1;
max-block-size: calc(var(--kbn-application--content-height) - ${headerHeight}px);
display: flex;
justify-content: center;
align-items: center;
padding: 0 ${euiTheme.size.base} ${euiTheme.size.base} ${euiTheme.size.base};
`;

const labels = {
header: i18n.translate('xpack.agentBuilder.conversationsView.header', {
defaultMessage: 'Conversation header',
}),
content: i18n.translate('xpack.agentBuilder.conversationsView.content', {
defaultMessage: 'Conversation content',
}),
};

return (
<RoutedConversationsProvider>
<SendMessageProvider>
<AgentBuilderTourProvider>
<KibanaPageTemplate
offset={0}
restrictWidth={false}
data-test-subj="agentBuilderPageConversations"
grow={false}
panelled={false}
mainProps={{
css: mainStyles,
}}
responsive={[]}
>
<KibanaPageTemplate.Header
css={headerStyles}
bottomBorder={false}
aria-label={labels.header}
paddingSize="m"
responsive={false}
>
Comment on lines -54 to -71
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These components should not be here anymore, they now live in the AppLayout

<div css={containerStyles} data-test-subj="agentBuilderPageConversations">
<div css={headerStyles}>
<ConversationHeader />
</KibanaPageTemplate.Header>
<KibanaPageTemplate.Section
paddingSize="none"
grow
contentProps={{
css: contentStyles,
}}
aria-label={labels.content}
>
</div>
<div css={contentStyles}>
<Conversation />
</KibanaPageTemplate.Section>
</KibanaPageTemplate>
</div>
</div>
</AgentBuilderTourProvider>
</SendMessageProvider>
</RoutedConversationsProvider>
Expand Down
Loading
Loading