-
Notifications
You must be signed in to change notification settings - Fork 367
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
tech-story: [M3-8939] - Get rid of DrawerContent
#11338
Changes from all commits
f064d2a
05efcc0
368c7ec
06b5690
550bfd2
e9eb6a2
dbef87e
a9ebc5c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,10 +7,15 @@ import { makeStyles } from 'tss-react/mui'; | |
|
||
import { convertForAria } from 'src/utilities/stringUtils'; | ||
|
||
import { ErrorState } from './ErrorState/ErrorState'; | ||
import { NotFound } from './NotFound'; | ||
|
||
import type { APIError } from '@linode/api-v4'; | ||
import type { DrawerProps as _DrawerProps } from '@mui/material/Drawer'; | ||
import type { Theme } from '@mui/material/styles'; | ||
|
||
export interface DrawerProps extends _DrawerProps { | ||
error?: APIError[] | null | string; | ||
/** | ||
* Whether the drawer is fetching the entity's data. | ||
* | ||
|
@@ -39,93 +44,113 @@ export interface DrawerProps extends _DrawerProps { | |
* - Clicking a button on the screen opens the drawer. | ||
* - Drawers can be closed by pressing the `esc` key, clicking the βXβ icon, or clicking the βCancelβ button. | ||
*/ | ||
export const Drawer = (props: DrawerProps) => { | ||
const { classes, cx } = useStyles(); | ||
const { children, isFetching, onClose, open, title, wide, ...rest } = props; | ||
const titleID = convertForAria(title); | ||
export const Drawer = React.forwardRef<HTMLDivElement, DrawerProps>( | ||
(props: DrawerProps, ref) => { | ||
const { classes, cx } = useStyles(); | ||
const { | ||
children, | ||
error, | ||
isFetching, | ||
onClose, | ||
open, | ||
title, | ||
wide, | ||
...rest | ||
} = props; | ||
const titleID = convertForAria(title); | ||
|
||
// Store the last valid children and title in refs | ||
// This is to prevent flashes of content during the drawer's closing transition, | ||
// and its content becomes potentially undefined | ||
const lastChildrenRef = React.useRef(children); | ||
const lastTitleRef = React.useRef(title); | ||
// Update refs when the drawer is open and content is matched | ||
if (open && children) { | ||
lastChildrenRef.current = children; | ||
lastTitleRef.current = title; | ||
} | ||
// Store the last valid children and title in refs | ||
// This is to prevent flashes of content during the drawer's closing transition, | ||
// and its content becomes potentially undefined | ||
const lastChildrenRef = React.useRef(children); | ||
const lastTitleRef = React.useRef(title); | ||
// Update refs when the drawer is open and content is matched | ||
if (open && children) { | ||
lastChildrenRef.current = children; | ||
lastTitleRef.current = title; | ||
} | ||
|
||
return ( | ||
<_Drawer | ||
classes={{ | ||
paper: cx(classes.common, { | ||
[classes.default]: !wide, | ||
[classes.wide]: wide, | ||
}), | ||
}} | ||
onClose={(_, reason) => { | ||
if (onClose && reason !== 'backdropClick') { | ||
onClose({}, 'escapeKeyDown'); | ||
} | ||
}} | ||
anchor="right" | ||
open={open} | ||
{...rest} | ||
aria-labelledby={titleID} | ||
data-qa-drawer | ||
data-testid="drawer" | ||
role="dialog" | ||
> | ||
<Grid | ||
sx={{ | ||
position: 'relative', | ||
return ( | ||
<_Drawer | ||
classes={{ | ||
paper: cx(classes.common, { | ||
[classes.default]: !wide, | ||
[classes.wide]: wide, | ||
}), | ||
}} | ||
onClose={(_, reason) => { | ||
if (onClose && reason !== 'backdropClick') { | ||
onClose({}, 'escapeKeyDown'); | ||
} | ||
}} | ||
alignItems="flex-start" | ||
className={classes.drawerHeader} | ||
container | ||
justifyContent="space-between" | ||
wrap="nowrap" | ||
anchor="right" | ||
open={open} | ||
ref={ref} | ||
{...rest} | ||
aria-labelledby={titleID} | ||
data-qa-drawer | ||
data-testid="drawer" | ||
role="dialog" | ||
> | ||
<Grid> | ||
{isFetching ? null : ( | ||
<Typography | ||
className={classes.title} | ||
data-qa-drawer-title={title} | ||
data-testid="drawer-title" | ||
id={titleID} | ||
variant="h2" | ||
<Grid | ||
sx={{ | ||
position: 'relative', | ||
}} | ||
alignItems="flex-start" | ||
className={classes.drawerHeader} | ||
container | ||
justifyContent="space-between" | ||
wrap="nowrap" | ||
> | ||
<Grid> | ||
{isFetching ? null : ( | ||
<Typography | ||
className={classes.title} | ||
data-qa-drawer-title={title} | ||
data-testid="drawer-title" | ||
id={titleID} | ||
variant="h2" | ||
> | ||
{title} | ||
</Typography> | ||
)} | ||
</Grid> | ||
<Grid> | ||
<IconButton | ||
sx={{ | ||
position: 'absolute', | ||
right: '-12px', | ||
top: '-12px', | ||
}} | ||
aria-label="Close drawer" | ||
color="primary" | ||
data-qa-close-drawer | ||
onClick={() => onClose?.({}, 'escapeKeyDown')} | ||
size="large" | ||
> | ||
{title} | ||
</Typography> | ||
)} | ||
<Close /> | ||
</IconButton> | ||
</Grid> | ||
</Grid> | ||
<Grid> | ||
<IconButton | ||
sx={{ | ||
position: 'absolute', | ||
right: '-12px', | ||
top: '-12px', | ||
}} | ||
aria-label="Close drawer" | ||
color="primary" | ||
data-qa-close-drawer | ||
onClick={() => onClose?.({}, 'escapeKeyDown')} | ||
size="large" | ||
> | ||
<Close /> | ||
</IconButton> | ||
</Grid> | ||
</Grid> | ||
{isFetching ? ( | ||
<Box display="flex" justifyContent="center" mt={8}> | ||
<CircleProgress size="md" /> | ||
</Box> | ||
) : ( | ||
children | ||
)} | ||
</_Drawer> | ||
); | ||
}; | ||
{error ? ( | ||
error === 'Not Found' ? ( | ||
<NotFound /> | ||
) : ( | ||
<ErrorState | ||
errorText={Array.isArray(error) ? error[0].reason : error} | ||
/> | ||
) | ||
) : isFetching ? ( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. addition of error handling is the change here |
||
<Box display="flex" justifyContent="center" mt={12}> | ||
<CircleProgress size="md" /> | ||
</Box> | ||
) : ( | ||
children | ||
)} | ||
</_Drawer> | ||
); | ||
} | ||
); | ||
|
||
const useStyles = makeStyles()((theme: Theme) => ({ | ||
button: { | ||
|
This file was deleted.
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,14 +34,15 @@ describe('Database Backups', () => { | |
|
||
const { findByText, getAllByRole } = renderWithTheme(<DatabaseBackups />); | ||
|
||
for (const backup of backups) { | ||
const backupPromises = backups.map((backup) => { | ||
const expectedDate = formatDate(backup.created, { timezone: 'utc' }); | ||
return findByText(expectedDate); | ||
}); | ||
|
||
// eslint-disable-next-line no-await-in-loop | ||
const backupItem = await findByText(expectedDate); | ||
|
||
const backupElements = await Promise.all(backupPromises); | ||
backupElements.forEach((backupItem) => { | ||
expect(backupItem).toBeVisible(); | ||
} | ||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This a pattern we ought to employ instead of await in loops to avoid flakiness (esp with dates). Hopefully this fixes this one for good |
||
|
||
// Verify there is a table row for each backup (and a row for the table header) | ||
expect(getAllByRole('row')).toHaveLength(backups.length + 1); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this change indentation but is a minor change
this should remove A LOT of warnings through the APP with mounted drawers