Skip to content
Closed
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
58 changes: 54 additions & 4 deletions packages/eui/src/components/flyout/flyout.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ describe('EuiFlyout', () => {
});

describe('flyout routing logic', () => {
it('routes to child flyout when session is undefined and there is an active session', () => {
it('routes to child flyout when session is "inherit" and there is an active session', () => {
// First render with just the main flyout to establish a session
const { rerender, getByTestSubject } = render(
<EuiFlyoutManager>
Expand All @@ -463,7 +463,7 @@ describe('EuiFlyout', () => {
<EuiFlyout
onClose={() => {}}
data-test-subj="child-flyout"
// session is undefined (not explicitly set)
session="inherit"
/>
</EuiFlyoutManager>
);
Expand Down Expand Up @@ -514,7 +514,27 @@ describe('EuiFlyout', () => {
expect(flyout).not.toHaveAttribute('data-managed-flyout-level');
});

it('routes to child flyout when in managed context and there is an active session', () => {
it('routes to standard flyout when session undefined and there is an active session', () => {
const { getByTestSubject } = render(
<EuiFlyoutManager>
{/* Create an active session */}
<EuiFlyout
onClose={() => {}}
session="start"
flyoutMenuProps={{ title: 'Main Flyout' }}
data-test-subj="main-flyout"
/>
{/* This flyout opted out of session management by default */}
<EuiFlyout onClose={() => {}} data-test-subj="standard-flyout" />
</EuiFlyoutManager>
);

// Should render as standard flyout (EuiFlyoutComponent)
const flyout = getByTestSubject('standard-flyout');
expect(flyout).not.toHaveAttribute('data-managed-flyout-level');
});

it('routes to child flyout when session is "inherit" in a managed context and there is an active session', () => {
// First render with just the main flyout to establish a session
const { rerender, getByTestSubject } = render(
<EuiFlyoutManager>
Expand All @@ -539,7 +559,7 @@ describe('EuiFlyout', () => {
<EuiFlyout
onClose={() => {}}
data-test-subj="child-flyout"
session={undefined} // Not explicitly set, should inherit
session="inherit"
/>
</EuiFlyoutManager>
);
Expand All @@ -562,5 +582,35 @@ describe('EuiFlyout', () => {
const flyout = getByTestSubject('flyout');
expect(flyout).not.toHaveAttribute('data-managed-flyout-level');
});

it('routes to standard flyout when session="inherit" but there is no active session', () => {
const { getByTestSubject } = render(
<EuiFlyout
onClose={() => {}}
data-test-subj="flyout"
session="inherit" // Explicitly set to inherit, but no session to inherit from
/>
);

// Should gracefully degrade to standard flyout (EuiFlyoutComponent) when no session exists
const flyout = getByTestSubject('flyout');
expect(flyout).not.toHaveAttribute('data-managed-flyout-level');
});

it('routes to standard flyout when session="inherit" within Manager but no active session', () => {
const { getByTestSubject } = render(
<EuiFlyoutManager>
<EuiFlyout
onClose={() => {}}
data-test-subj="flyout"
session="inherit" // Manager context exists but no main flyout has been created
/>
</EuiFlyoutManager>
);

// Should gracefully degrade to standard flyout when Manager exists but no session is active
const flyout = getByTestSubject('flyout');
expect(flyout).not.toHaveAttribute('data-managed-flyout-level');
});
});
});
6 changes: 3 additions & 3 deletions packages/eui/src/components/flyout/flyout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ export type EuiFlyoutProps<T extends ElementType = 'div' | 'nav'> = Omit<
/**
* Controls the way the session is managed for this flyout.
* - `start`: Creates a new flyout session. Use this for the main flyout.
* - `inherit`: (default) Inherits an existing session if one is active, otherwise functions as a standard flyout.
* - `never`: Opts out of session management and always functions as a standard flyout.
* - `inherit`: Inherits an existing session if one is active, otherwise functions as a standard flyout.
* - `never`: (default) Disregards session management and always functions as a standard flyout.
*
* Check out [EuiFlyout session management](https://eui.elastic.co/docs/components/containers/flyout/session-management)
* documentation to learn more.
Expand Down Expand Up @@ -67,7 +67,7 @@ export const EuiFlyout = forwardRef<
as,
onClose,
onActive,
session = SESSION_INHERIT,
session = SESSION_NEVER,
...rest
} = usePropsWithComponentDefaults('EuiFlyout', props);
const hasActiveSession = useRef(useHasActiveSession());
Expand Down
3 changes: 0 additions & 3 deletions packages/eui/src/components/flyout/manager/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@

/**
* Allowed values for `session` prop to control the way the session is managed for a flyout.
* - `session="start"`: Creates a new flyout session. Use this for the main flyout.
* - `session="inherit"`: (default) Inherits an existing session if one is active, otherwise functions as a standard flyout.
* - `session="never"`: Opts out of session management and always functions as a standard flyout.
*/
export const SESSION_START = 'start';
export const SESSION_INHERIT = 'inherit';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ const FlyoutSession: React.FC<FlyoutSessionProps> = React.memo((props) => {
},
{
title: 'session',
description: 'start',
description: <EuiCode>start</EuiCode>,
},
]}
/>
Expand All @@ -187,42 +187,42 @@ const FlyoutSession: React.FC<FlyoutSessionProps> = React.memo((props) => {
)}
</EuiText>
</EuiFlyoutBody>
{childSize && isChildFlyoutVisible && (
<EuiFlyout
id={`childFlyout-${title}`}
flyoutMenuProps={{ title: `${title} - Child` }}
aria-labelledby="childFlyoutTitle"
size={childSize}
maxWidth={childMaxWidth}
onActive={childFlyoutOnActive}
onClose={childFlyoutOnClose}
hasChildBackground={hasChildBackground}
>
<EuiFlyoutBody>
<EuiText>
<p>This is the content of the child flyout of {title}.</p>
<EuiSpacer size="s" />
<EuiDescriptionList
type="column"
listItems={[
{
title: 'Child flyout size',
description: childSize ?? 'N/A',
},
{
title: 'Child flyout maxWidth',
description: childMaxWidth ?? 'N/A',
},
{
title: 'session',
description: 'inherit',
},
]}
/>
</EuiText>
</EuiFlyoutBody>
</EuiFlyout>
)}
</EuiFlyout>
)}
{childSize && isChildFlyoutVisible && (
<EuiFlyout
id={`childFlyout-${title}`}
session="inherit"
flyoutMenuProps={{ title: `${title} - Child` }}
size={childSize}
maxWidth={childMaxWidth}
onActive={childFlyoutOnActive}
onClose={childFlyoutOnClose}
hasChildBackground={hasChildBackground}
>
<EuiFlyoutBody>
<EuiText>
<p>This is the content of the child flyout of {title}.</p>
<EuiSpacer size="s" />
<EuiDescriptionList
type="column"
listItems={[
{
title: 'Child flyout size',
description: childSize ?? 'N/A',
},
{
title: 'Child flyout maxWidth',
description: childMaxWidth ?? 'N/A',
},
{
title: 'session',
description: <EuiCode>inherit</EuiCode>,
},
]}
/>
</EuiText>
</EuiFlyoutBody>
</EuiFlyout>
)}
</>
Expand Down Expand Up @@ -252,6 +252,7 @@ const NonSessionFlyout: React.FC<{
Open non-session flyout
</EuiButton>
</EuiText>
{/* Using default EuiFlyout session behavior of 'never' */}
{isFlyoutVisible && (
<EuiFlyout
id="nonSessionFlyout"
Expand All @@ -261,7 +262,6 @@ const NonSessionFlyout: React.FC<{
ownFocus={false}
pushAnimation={true}
onClose={flyoutOnClose}
session="never"
side="left"
>
<EuiFlyoutHeader>
Expand All @@ -272,17 +272,24 @@ const NonSessionFlyout: React.FC<{
<EuiFlyoutBody>
<EuiText>
<p>
This is the content of a non-session flyout. We assure it will
never become a managed flyout by setting{' '}
<EuiCode>{'session={never}'}</EuiCode>.
This is the content of a non-session flyout. It is assured to
not be a managed flyout using the{' '}
<EuiCode>{'session={never}'}</EuiCode> behavior.
</p>
<EuiSpacer size="s" />
<EuiDescriptionList
type="column"
listItems={[
{ title: 'Flyout type', description: flyoutType },
{ title: 'Size', description: 'm' },
{ title: 'session', description: 'never' },
{
title: 'session',
description: (
<>
<EuiCode>never</EuiCode> (using default)
</>
),
},
]}
/>
</EuiText>
Expand Down Expand Up @@ -467,6 +474,7 @@ const ExternalRootChildFlyout: React.FC<{ parentId: string }> = ({
{isOpen && (
<EuiFlyout
id={`child-flyout-${parentId}`}
session="inherit"
size="s"
onClose={handleClose}
ownFocus={false}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,10 @@ export default () => {
<EuiFlyout
session="start"
size="s"
aria-label="Flyout A - main"
flyoutMenuProps={{
title: 'Welcome to the flyout session management journey!',
}}
onClose={() => setIsOpenFlyoutA(false)}
>
<EuiFlyoutBody>
<EuiText>This flyout is rendered with the <EuiCode>{'session="start"'}</EuiCode> prop set which creates a new flyout session and marks this flyout as main.</EuiText>
<EuiText>This is <strong>Flyout A</strong>. This flyout is rendered with the <EuiCode>{'session="start"'}</EuiCode> prop set which created a new flyout session and marks this flyout as main.</EuiText>
<EuiSpacer />
<EuiFormRow label="What's your name?" fullWidth>
<EuiFieldText value={name} onChange={(e) => setName(e.target.value)} />
Expand All @@ -68,17 +64,22 @@ export default () => {
>
<EuiFlyoutBody>
<EuiText>
This flyout is also rendered with the <EuiCode>{'session="start"'}</EuiCode> prop added which creates a <strong>second flyout session</strong> and marks this flyout as main in that session.
This is <strong>Flyout B</strong>. This flyout is also rendered with the <EuiCode>{'session="start"'}</EuiCode> prop added which creates a <strong>second flyout session</strong> and marks this flyout as main in that session.
<br /><br />
The first flyout still exists but is currently hidden since this one took precedence. You can jump back to it by clicking the <i>Back</i> button above if you'd like.
<strong>Flyout A</strong> exists but is currently hidden since this one took precedence. You can jump back to it by clicking the <i>Back</i> button above if you'd like.
</EuiText>
<EuiSpacer />
<EuiButton onClick={() => setIsOpenFlyoutBChild((val) => !val)}>
{isOpenFlyoutBChild ? 'Close child flyout' : 'Open child flyout'}
</EuiButton>
</EuiFlyoutBody>
{isOpenFlyoutBChild && (
<EuiFlyout size="s" aria-label="Flyout B - child" onClose={() => setIsOpenFlyoutBChild(false)}>
<EuiFlyout
session="inherit"
size="s"
aria-label="Flyout B - child"
onClose={() => setIsOpenFlyoutBChild(false)}
>
<EuiFlyoutBody>
<EuiText>
This is a <strong>child flyout</strong> of Flyout B. It belongs to the same session as Flyout B because it's rendered inside of it and doesn't have the <EuiCode>session</EuiCode> prop set.
Expand Down Expand Up @@ -113,8 +114,7 @@ about compatibility issues.
Each time you set `session="start"`, you create a new flyout session and mark
the rendered flyout as [main](#main-flyouts).
To create a [child flyout](#child-flyouts) - a flyout that belongs to the same
session as the main flyout - you can set `session="inherit"` or omit the `session` prop entirely,
as "inherit" is the default behavior.
session as the main flyout - set `session="inherit"`.
All bindings and configuration will be handled automatically.

### Session title
Expand All @@ -134,8 +134,8 @@ field of the `flyoutMenuProps` to set the title of the flyout.
<EuiFlyoutBody>
I'm the main flyout
</EuiFlyoutBody>
{/* Render a new child flyout - notice the lack of the `session` prop */}
<EuiFlyout
session="inherit"
flyoutMenuProps={{
title: 'My child flyout'
}}
Expand All @@ -145,8 +145,9 @@ field of the `flyoutMenuProps` to set the title of the flyout.
</EuiFlyout>
```

To prevent a flyout from being a part of the session management system, you
can set `session="never"` which will render it as a regular unmanaged flyout.
To prevent a flyout from being a part of the session management system, you can
set `session="never"`, or you can omit the `session` prop as `never` is the
default. This will will render it as a regular unmanaged flyout.

```tsx
<>
Expand Down Expand Up @@ -186,9 +187,10 @@ of an alert.

### Child flyouts

Child flyouts are directly related to a main flyout in their session.
They're created by rendering a `EuiFlyout` **without the session prop** inside
a [main flyout](#main-flyouts) - a flyout with `session="start"` prop set.
Child flyouts are directly related to a main flyout in their session. They're
created by rendering a `EuiFlyout` with the `session="inherit"` prop set while
there is an active [main flyout](#main-flyouts) - a flyout with
`session="start"` prop set.

They're meant to display secondary level information like the alert visualization.

Expand Down