Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@red-hat-developer-hub/backstage-plugin-intelligent-assistant': patch
---

Align Intelligent Assistant Chat/Notebooks shell with PatternFly defaults and fix sticky history close hover.
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,11 @@ export type CustomDrawerProps = {
export const CustomDrawer = (props: CustomDrawerProps) => {
const {
children,
// Defaults align with PatternFly Chatbot (30rem ≈ 480px); callers usually
// pass drawerWidth from Lightspeed provider / AppDrawer defaultWidth.
minWidth = 400,
maxWidth = 800,
initialWidth = 400,
initialWidth = 480,
isDrawerOpen,
drawerWidth,
onWidthChange,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,68 +14,22 @@
* limitations under the License.
*/

import { styled } from '@mui/material/styles';
import { Button, Tooltip } from '@patternfly/react-core';
import { PenIcon } from '@patternfly/react-icons';
import { Button, Flex, FlexItem, Icon, Tooltip } from '@patternfly/react-core';
import { PencilAltIcon } from '@patternfly/react-icons';

import { useTranslation } from '../hooks/useTranslation';
import { SidebarExpandIcon } from './notebooks/SidebarCollapseIcon';

const Strip = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
paddingTop: theme.spacing(1.5),
gap: theme.spacing(1.5),
borderRight: '1px solid var(--pf-t--global--border--color--default)',
width: 48,
minWidth: 48,
flexShrink: 0,
backgroundColor: 'var(--pf-t--global--background--color--primary--default)',
height: '100%',
}));

const IconButton = styled(Button)({
padding: '8px !important',
minWidth: 0,
lineHeight: 1,
borderRadius: '8px !important',
border: '1px solid var(--pf-t--global--border--color--default) !important',
color: 'var(--pf-t--global--icon--color--regular)',
'& svg': {
width: 18,
height: 18,
},
'&:hover': {
color: 'var(--pf-t--global--icon--color--hover) !important',
backgroundColor:
'var(--pf-t--global--background--color--action--plain--hover) !important',
},
});

const NewChatIconButton = styled(Button)({
padding: '8px !important',
minWidth: 0,
lineHeight: 1,
borderRadius: '8px !important',
border: '1px solid var(--pf-t--global--border--color--default) !important',
color: 'var(--pf-t--global--color--brand--default) !important',
'&:hover': {
color: 'var(--pf-t--global--color--brand--hover) !important',
backgroundColor:
'var(--pf-t--global--background--color--action--plain--hover) !important',
},
'&:disabled': {
color: 'var(--pf-t--global--text--color--disabled) !important',
},
});

type CollapsedHistoryStripProps = {
onExpand: () => void;
onNewChat: () => void;
newChatDisabled?: boolean;
};

/**
* Collapsed chat-history rail for fullscreen. Stock PF plain icon buttons
* (rounded-square hover) — no custom button chrome or vertical divider.
*/
export const CollapsedHistoryStrip = ({
onExpand,
onNewChat,
Expand All @@ -84,26 +38,58 @@ export const CollapsedHistoryStrip = ({
const { t } = useTranslation();

return (
<Strip>
<Tooltip content={t('tooltip.expandHistoryPanel')} position="right">
<IconButton
variant="plain"
onClick={onExpand}
aria-label={t('tooltip.expandHistoryPanel')}
>
<SidebarExpandIcon />
</IconButton>
</Tooltip>
<Tooltip content={t('tooltip.quickNewChat')} position="right">
<NewChatIconButton
variant="plain"
onClick={onNewChat}
aria-label={t('tooltip.quickNewChat')}
isDisabled={newChatDisabled}
>
<PenIcon />
</NewChatIconButton>
</Tooltip>
</Strip>
<Flex
direction={{ default: 'column' }}
alignItems={{ default: 'alignItemsCenter' }}
spaceItems={{ default: 'spaceItemsMd' }}
flex={{ default: 'flexNone' }}
style={{
paddingBlockStart: 'var(--pf-t--global--spacer--md)',
paddingInline: 'var(--pf-t--global--spacer--xs)',
height: '100%',
}}
>
<FlexItem>
<Tooltip content={t('tooltip.expandHistoryPanel')} position="right">
<Button
variant="plain"
icon={
<Icon size="lg" isInline>
<SidebarExpandIcon />
</Icon>
}
// PF plain buttons paint :focus like :hover; skip mouse focus so
// the chrome clears on pointer leave.
onMouseDown={event => {
if (event.button === 0) {
event.preventDefault();
}
}}
onClick={onExpand}
aria-label={t('tooltip.expandHistoryPanel')}
/>
</Tooltip>
</FlexItem>
<FlexItem>
<Tooltip content={t('tooltip.quickNewChat')} position="right">
<Button
variant="plain"
icon={
<Icon isInline>
<PencilAltIcon />
</Icon>
}
onMouseDown={event => {
if (event.button === 0) {
event.preventDefault();
}
}}
onClick={onNewChat}
aria-label={t('tooltip.quickNewChat')}
isDisabled={newChatDisabled}
/>
</Tooltip>
</FlexItem>
</Flex>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -50,24 +50,28 @@ const FilePreview = () => {
);
};

// Return null when empty so ChatbotFooter's row-gap does not add a blank
// band above MessageBar (Notebooks has no FilePreview and looked tighter).
if (!fileContents.length) {
return null;
}

return (
<>
{fileContents.length > 0 && <Divider />}
{fileContents && (
<Box sx={{ display: 'flex', gap: '10px' }}>
{fileContents.map((file, index) => (
<FileDetailsLabel
key={index}
fileName={file.name}
isLoading={isLoadingFile[file.name]}
onClick={onAttachmentClick}
onClose={() => {
removeFile(index);
}}
/>
))}
</Box>
)}
<Divider />
<Box sx={{ display: 'flex', gap: '10px' }}>
{fileContents.map((file, index) => (
<FileDetailsLabel
key={index}
fileName={file.name}
isLoading={isLoadingFile[file.name]}
onClick={onAttachmentClick}
onClose={() => {
removeFile(index);
}}
/>
))}
</Box>
</>
);
};
Expand Down
Loading
Loading