Skip to content

Commit 39c8d72

Browse files
change: [UIE-9701] - Add Back Navigation functionality in Drawer & Integrate the change with PrefixList Drawer (#13151)
* upcoming: [UIE-9698] - Add Beta Chip for Drawer * Add Storybook * PR feedback * PR feedback @pmakode-akamai * upcoming: [UIE-9701] - Add Back Navigation Icon to Drawer title * Added changeset: Add Back Navigation functionality in Drawer * pr feedback * Fix: test failure and back icon while `isFetching` is true * Add test for back icon in PrefixList Drawer * Added changeset: Add back navigation functionality to Drawer and integrate it with PrefixList Drawer * Remove changed changeset * Update comment for clarity --------- Co-authored-by: pmakode-akamai <[email protected]>
1 parent ef127cb commit 39c8d72

File tree

6 files changed

+125
-7
lines changed

6 files changed

+125
-7
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@linode/manager": Upcoming Features
3+
---
4+
5+
Add back navigation functionality to Drawer and integrate it with PrefixList Drawer ([#13151](https://github.com/linode/manager/pull/13151))

packages/manager/src/features/Firewalls/FirewallDetail/Rules/FirewallPrefixListDrawer.test.tsx

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,35 +47,40 @@ const computeExpectedElements = (
4747
let title = 'Prefix List details';
4848
let button = 'Close';
4949
let label = 'Name:';
50+
let hasBackNavigation = false;
5051

5152
if (context?.type === 'ruleset' && context.modeViewedFrom === 'create') {
5253
title = `Add an ${capitalize(category)} Rule or Rule Set`;
5354
button = `Back to ${capitalize(category)} Rule Set`;
5455
label = 'Prefix List Name:';
56+
hasBackNavigation = true;
5557
}
5658

5759
if (context?.type === 'rule' && context.modeViewedFrom === 'create') {
5860
title = `Add an ${capitalize(category)} Rule or Rule Set`;
5961
button = `Back to ${capitalize(category)} Rule`;
6062
label = 'Prefix List Name:';
63+
hasBackNavigation = true;
6164
}
6265

6366
if (context?.type === 'ruleset' && context.modeViewedFrom === 'view') {
6467
title = `${capitalize(category)} Rule Set details`;
6568
button = 'Back to the Rule Set';
6669
label = 'Prefix List Name:';
70+
hasBackNavigation = true;
6771
}
6872

6973
if (context?.type === 'rule' && context.modeViewedFrom === 'edit') {
7074
title = 'Edit Rule';
7175
button = 'Back to Rule';
7276
label = 'Prefix List Name:';
77+
hasBackNavigation = true;
7378
}
7479

7580
// Default values when there is no specific drawer context
7681
// (e.g., type === 'rule' and modeViewedFrom === undefined,
7782
// meaning the drawer is opened directly from the Firewall Table row)
78-
return { title, button, label };
83+
return { title, button, label, hasBackNavigation };
7984
};
8085

8186
describe('FirewallPrefixListDrawer', () => {
@@ -158,7 +163,7 @@ describe('FirewallPrefixListDrawer', () => {
158163
mockData,
159164
]);
160165

161-
const { getByText, getByRole } = renderWithTheme(
166+
const { getByText, getByRole, queryByLabelText } = renderWithTheme(
162167
<FirewallPrefixListDrawer
163168
category={category}
164169
context={context}
@@ -169,10 +174,16 @@ describe('FirewallPrefixListDrawer', () => {
169174
);
170175

171176
// Compute expectations
172-
const { title, button, label } = computeExpectedElements(
173-
category,
174-
context
175-
);
177+
const { title, button, label, hasBackNavigation } =
178+
computeExpectedElements(category, context);
179+
180+
// Back Navigation (Expected only for second-level drawers)
181+
const backIconButton = queryByLabelText('back navigation');
182+
if (hasBackNavigation) {
183+
expect(backIconButton).toBeVisible();
184+
} else {
185+
expect(backIconButton).not.toBeInTheDocument();
186+
}
176187

177188
// Title
178189
expect(getByText(title)).toBeVisible();

packages/manager/src/features/Firewalls/FirewallDetail/Rules/FirewallPrefixListDrawer.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,9 @@ export const FirewallPrefixListDrawer = React.memo(
210210
return (
211211
<Drawer
212212
error={error}
213+
handleBackNavigation={
214+
backButtonText ? () => onClose({ closeAll: false }) : undefined
215+
}
213216
isFetching={isFetching}
214217
onClose={() => onClose({ closeAll: true })}
215218
open={isOpen}

packages/ui/src/components/Drawer/Drawer.stories.tsx

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,70 @@ export const WithError: Story = {
183183
},
184184
};
185185

186+
export const WithBackNavigation: Story = {
187+
args: {
188+
isFetching: false,
189+
open: false,
190+
title: 'My Drawer',
191+
},
192+
render: (args) => {
193+
const DrawerExampleWrapper = () => {
194+
const [open, setOpen] = React.useState(args.open);
195+
196+
return (
197+
<>
198+
<Button
199+
buttonType="primary"
200+
onClick={() => setOpen(true)}
201+
sx={{ m: 4 }}
202+
>
203+
Click to open Drawer
204+
</Button>
205+
<Drawer
206+
{...args}
207+
handleBackNavigation={() => {}}
208+
onClose={() => setOpen(true)}
209+
open={open}
210+
>
211+
<Typography sx={{ mb: 2 }}>
212+
I smirked at their Kale chips banh-mi fingerstache brunch in
213+
Williamsburg.
214+
</Typography>
215+
<Typography sx={{ mb: 2 }}>
216+
Meanwhile in my closet-style flat in Red-Hook, my pour-over coffee
217+
glitched on my vinyl record player while I styled the bottom left
218+
corner of my beard. Those artisan tacos I ordered were infused
219+
with turmeric and locally sourced honey, a true farm-to-table
220+
vibe. Pabst Blue Ribbon in hand, I sat on my reclaimed wood bench
221+
next to the macramé plant holder.
222+
</Typography>
223+
<Typography sx={{ mb: 2 }}>
224+
Narwhal selfies dominated my Instagram feed, hashtagged with "slow
225+
living" and "normcore aesthetics". My kombucha brewing kit arrived
226+
just in time for me to ferment my own chai-infused blend. As I
227+
adjusted my vintage round glasses, a tiny house documentary
228+
started playing softly in the background. The retro typewriter
229+
clacked as I typed out my minimalist poetry on sustainably sourced
230+
paper. The sun glowed through the window, shining light on the
231+
delightful cracks of my Apple watch.
232+
</Typography>
233+
<Typography sx={{ mb: 2 }}>It was Saturday.</Typography>
234+
<ActionsPanel
235+
primaryButtonProps={{ label: 'Save' }}
236+
secondaryButtonProps={{
237+
label: 'Cancel',
238+
onClick: () => setOpen(false),
239+
}}
240+
/>
241+
</Drawer>
242+
</>
243+
);
244+
};
245+
246+
return DrawerExampleWrapper();
247+
},
248+
};
249+
186250
export const WithTitleSuffix: Story = {
187251
args: {
188252
isFetching: false,

packages/ui/src/components/Drawer/Drawer.test.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,13 @@ describe('Drawer', () => {
8383

8484
expect(getByText('beta')).toBeVisible();
8585
});
86+
87+
it('should render a Dailog with back button if handleBackNavigation is provided', () => {
88+
const { getByLabelText } = renderWithTheme(
89+
<Drawer {...defaultArgs} handleBackNavigation={() => {}} open={true} />,
90+
);
91+
const iconButton = getByLabelText('back navigation');
92+
93+
expect(iconButton).toBeVisible();
94+
});
8695
});

packages/ui/src/components/Drawer/Drawer.tsx

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Grid from '@mui/material/Grid';
44
import { useTheme } from '@mui/material/styles';
55
import * as React from 'react';
66

7+
import ChevronLeftIcon from '../../assets/icons/chevron-left.svg';
78
import { getErrorText } from '../../utilities/error';
89
import { convertForAria } from '../../utilities/stringUtils';
910
import { Box } from '../Box';
@@ -23,6 +24,11 @@ export interface DrawerProps extends _DrawerProps {
2324
* It prevents the drawer from showing broken content.
2425
*/
2526
error?: APIError[] | null | string;
27+
/**
28+
* An optional prop that handles back navigation for second-level drawers.
29+
* It can act as a visual indicator, similar to a back button or `onClose` handler.
30+
*/
31+
handleBackNavigation?: () => void;
2632
/**
2733
* Whether the drawer is fetching the entity's data.
2834
*
@@ -62,12 +68,13 @@ export const Drawer = React.forwardRef<HTMLDivElement, DrawerProps>(
6268
const {
6369
children,
6470
error,
65-
titleSuffix,
71+
handleBackNavigation,
6672
isFetching,
6773
onClose,
6874
open,
6975
sx,
7076
title,
77+
titleSuffix,
7178
wide,
7279
...rest
7380
} = props;
@@ -159,6 +166,25 @@ export const Drawer = React.forwardRef<HTMLDivElement, DrawerProps>(
159166
data-testid="drawer-title-container"
160167
display="flex"
161168
>
169+
{handleBackNavigation && (
170+
<IconButton
171+
aria-label="back navigation"
172+
data-qa-back-navigation
173+
disableRipple
174+
onClick={handleBackNavigation}
175+
sx={(theme) => ({
176+
color: theme.palette.text.primary,
177+
padding: 0,
178+
marginRight: theme.spacingFunction(8),
179+
'& svg': {
180+
width: 24,
181+
height: 24,
182+
},
183+
})}
184+
>
185+
<ChevronLeftIcon />
186+
</IconButton>
187+
)}
162188
<Typography
163189
data-qa-drawer-title={lastTitleRef.current}
164190
data-testid="drawer-title"

0 commit comments

Comments
 (0)