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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@
{
"path": "lib/components/internal/widget-exports.js",
"brotli": false,
"limit": "963 kB",
"limit": "964 kB",
"ignore": "react-dom"
}
],
Expand Down
17 changes: 17 additions & 0 deletions pages/app-layout/utils/external-global-left-panel-widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,23 @@ registerLeftDrawer({
`,
},

exitExpandedModeTrigger: {
customIcon: `
<svg width="94" height="24" viewBox="0 0 94 24" fill="none" focusable="false" aria-hidden="true">
<rect width="94" height="24" rx="4" fill="url(#paint0_linear_145_32649)"/>
<defs>
<linearGradient id="paint0_linear_145_32649" x1="135.919" y1="21" x2="108.351" y2="74.1863" gradientUnits="userSpaceOnUse">
<stop stop-color="#B8E7FF"/>
<stop offset="0.255" stop-color="#0099FF"/>
<stop offset="0.514134" stop-color="#5C7FFF"/>
<stop offset="0.732534" stop-color="#8575FF"/>
<stop offset="1" stop-color="#962EFF"/>
</linearGradient>
</defs>
</svg>
`,
},

onResize: event => {
console.log('resize', event.detail);
},
Expand Down
53 changes: 33 additions & 20 deletions src/app-layout/__tests__/runtime-drawers-widgetized.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -191,27 +191,40 @@ describeEachAppLayout({ themes: ['refresh-toolbar'] }, ({ size }) => {
}
});

test('should exit focus mode by clicking on a custom exit button in the AI global drawer', () => {
awsuiWidgetPlugins.registerLeftDrawer({
...drawerDefaults,
ariaLabels: {
exitExpandedModeButton: 'exitExpandedModeButton',
},
isExpandable: true,
});
const { globalDrawersWrapper } = renderComponent(<AppLayout />);

globalDrawersWrapper.findAiDrawerTrigger()!.click();
if (size === 'mobile') {
expect(globalDrawersWrapper.findExpandedModeButtonByActiveDrawerId(drawerDefaults.id)).toBeFalsy();
} else {
createWrapper().findButtonGroup()!.findButtonById('expand')!.click();
expect(globalDrawersWrapper.findDrawerById(drawerDefaults.id)!.isDrawerInExpandedMode()).toBe(true);
expect(globalDrawersWrapper.isLayoutInDrawerExpandedMode()).toBe(true);
globalDrawersWrapper.findLeaveExpandedModeButtonInAIDrawer()!.click();
expect(globalDrawersWrapper.isLayoutInDrawerExpandedMode()).toBe(false);
test.each(['standard', 'custom', 'custom-invalid'] as const)(
'should exit focus mode by clicking on a %s exit button in the AI global drawer',
type => {
awsuiWidgetPlugins.registerLeftDrawer({
...drawerDefaults,
ariaLabels: {
exitExpandedModeButton: 'exitExpandedModeButton',
},
isExpandable: true,
...(type === 'custom' && {
exitExpandedModeTrigger: {
customIcon: `
<svg width="94" height="24" viewBox="0 0 94 24" fill="none" focusable="false" aria-hidden="true"></svg>
`,
},
}),
...(type === 'custom-invalid' && {
exitExpandedModeTrigger: {},
}),
});
const { globalDrawersWrapper } = renderComponent(<AppLayout />);

globalDrawersWrapper.findAiDrawerTrigger()!.click();
if (size === 'mobile') {
expect(globalDrawersWrapper.findExpandedModeButtonByActiveDrawerId(drawerDefaults.id)).toBeFalsy();
} else {
createWrapper().findButtonGroup()!.findButtonById('expand')!.click();
expect(globalDrawersWrapper.findDrawerById(drawerDefaults.id)!.isDrawerInExpandedMode()).toBe(true);
expect(globalDrawersWrapper.isLayoutInDrawerExpandedMode()).toBe(true);
globalDrawersWrapper.findLeaveExpandedModeButtonInAIDrawer()!.click();
expect(globalDrawersWrapper.isLayoutInDrawerExpandedMode()).toBe(false);
}
}
});
);

describe('metrics', () => {
let sendPanoramaMetricSpy: jest.SpyInstance;
Expand Down
33 changes: 19 additions & 14 deletions src/app-layout/runtime-drawer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,14 @@ function checkForUnsupportedProps(headerActions: ReadonlyArray<ButtonGroupProps.
return headerActions;
}

const convertRuntimeTriggerToReactNode = (runtimeTrigger?: string) => {
if (!runtimeTrigger) {
return undefined;
}
// eslint-disable-next-line react/no-danger
return <span style={{ lineHeight: 0 }} dangerouslySetInnerHTML={{ __html: runtimeTrigger }} />;
};

export const mapRuntimeConfigToDrawer = (
runtimeConfig: RuntimeDrawerConfig
): AppLayoutProps.Drawer & {
Expand All @@ -114,10 +122,7 @@ export const mapRuntimeConfigToDrawer = (
trigger: trigger
? {
...(trigger.iconSvg && {
iconSvg: (
// eslint-disable-next-line react/no-danger
<span dangerouslySetInnerHTML={{ __html: trigger.iconSvg }} />
),
iconSvg: convertRuntimeTriggerToReactNode(trigger.iconSvg),
}),
}
: undefined,
Expand All @@ -142,22 +147,22 @@ export const mapRuntimeConfigToAiDrawer = (
orderPriority?: number;
onToggle?: NonCancelableEventHandler<DrawerStateChangeParams>;
headerActions?: ReadonlyArray<ButtonGroupProps.Item>;
exitExpandedModeTrigger?: React.ReactNode;
} => {
const { mountContent, unmountContent, trigger, ...runtimeDrawer } = runtimeConfig;
const { mountContent, unmountContent, trigger, exitExpandedModeTrigger, ...runtimeDrawer } = runtimeConfig;

return {
...runtimeDrawer,
ariaLabels: { drawerName: runtimeDrawer.ariaLabels.content ?? '', ...runtimeDrawer.ariaLabels },
trigger: trigger
...(trigger && {
trigger: {
customIcon: convertRuntimeTriggerToReactNode(trigger?.customIcon),
iconSvg: convertRuntimeTriggerToReactNode(trigger?.iconSvg),
},
}),
exitExpandedModeTrigger: exitExpandedModeTrigger
? {
customIcon: trigger?.customIcon ? (
// eslint-disable-next-line react/no-danger
<span style={{ lineHeight: 0 }} dangerouslySetInnerHTML={{ __html: trigger.customIcon }} />
) : undefined,
iconSvg: trigger.iconSvg ? (
// eslint-disable-next-line react/no-danger
<span dangerouslySetInnerHTML={{ __html: trigger.iconSvg }} />
) : undefined,
customIcon: convertRuntimeTriggerToReactNode(exitExpandedModeTrigger?.customIcon),
}
: undefined,
content: (
Expand Down
43 changes: 32 additions & 11 deletions src/app-layout/visual-refresh-toolbar/drawer/global-ai-drawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,13 @@ interface AIDrawerProps {
interface AppLayoutGlobalAiDrawerImplementationProps {
appLayoutInternals: AppLayoutInternals;
show: boolean;
activeAiDrawer: InternalDrawer | null;
activeAiDrawer:
| (InternalDrawer & {
exitExpandedModeTrigger?: {
customIcon?: React.ReactNode;
Copy link
Member

Choose a reason for hiding this comment

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

Why is this ReactNode? We do not use it on the other triggers because it does not work in micro-frontends, so we also don't do it here

Copy link
Member Author

Choose a reason for hiding this comment

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

This customIcon type is what we get after processing the runtime data. The actual plugin api only works with strings

Copy link
Member

Choose a reason for hiding this comment

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

OK I see, there is a string in src/internal/plugins/widget/interfaces.ts update

};
})
| null;
aiDrawerProps: AIDrawerProps;
}

Expand Down Expand Up @@ -207,16 +213,31 @@ export function AppLayoutGlobalAiDrawerImplementation({
{!isMobile && isExpanded && activeAiDrawer?.ariaLabels?.exitExpandedModeButton && (
<div className={styles['drawer-back-to-console-slot']}>
<div className={styles['drawer-back-to-console-button-wrapper']}>
<button
className={clsx(
testutilStyles['active-ai-drawer-leave-expanded-mode-custom-button'],
styles['drawer-back-to-console-button']
)}
formAction="none"
onClick={() => setExpandedDrawerId(null)}
>
{activeAiDrawer?.ariaLabels?.exitExpandedModeButton}
</button>
{activeAiDrawer?.exitExpandedModeTrigger?.customIcon ? (
<button
className={clsx(
testutilStyles['active-ai-drawer-leave-expanded-mode-custom-button'],
styles['drawer-back-to-console-custom-button']
)}
formAction="none"
onClick={() => setExpandedDrawerId(null)}
aria-label={activeAiDrawer?.ariaLabels?.exitExpandedModeButton}
>
{activeAiDrawer?.exitExpandedModeTrigger?.customIcon}
</button>
) : (
<button
className={clsx(
testutilStyles['active-ai-drawer-leave-expanded-mode-custom-button'],
styles['drawer-back-to-console-button']
)}
formAction="none"
onClick={() => setExpandedDrawerId(null)}
aria-label={activeAiDrawer?.ariaLabels?.exitExpandedModeButton}
>
{activeAiDrawer?.ariaLabels?.exitExpandedModeButton}
</button>
)}
</div>
</div>
)}
Expand Down
7 changes: 7 additions & 0 deletions src/app-layout/visual-refresh-toolbar/drawer/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,13 @@ $ai-drawer-heider-height: 41px;
outline: none;
}
}

> .drawer-back-to-console-custom-button {
all: initial;
display: flex;
cursor: pointer;
text-align: center;
}
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/internal/plugins/widget/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ export interface DrawerPayload {
iconSvg?: string;
customIcon?: string;
};
exitExpandedModeTrigger?: {
customIcon?: string;
};
mountContent: (container: HTMLElement, mountContext: MountContentContext) => void;
unmountContent: (container: HTMLElement) => void;
preserveInactiveContent?: boolean;
Expand Down
Loading