diff --git a/packages/react-core/src/components/Alert/Alert.tsx b/packages/react-core/src/components/Alert/Alert.tsx index c35b3da0e49..182758f1c82 100644 --- a/packages/react-core/src/components/Alert/Alert.tsx +++ b/packages/react-core/src/components/Alert/Alert.tsx @@ -73,6 +73,8 @@ export interface AlertProps extends Omit, 'actio isExpandable?: boolean; /** Adds accessible text to the alert Toggle */ toggleAriaLabel?: string; + /** Uniquely identifies the alert */ + id?: string; } export const Alert: React.FunctionComponent = ({ @@ -100,6 +102,7 @@ export const Alert: React.FunctionComponent = ({ toggleAriaLabel = `${capitalize(variant)} alert details`, onMouseEnter = () => {}, onMouseLeave = () => {}, + id, ...props }: AlertProps) => { const ouiaProps = useOUIAProps(Alert.displayName, ouiaId, ouiaSafe, variant); @@ -211,6 +214,7 @@ export const Alert: React.FunctionComponent = ({ })} onMouseEnter={myOnMouseEnter} onMouseLeave={myOnMouseLeave} + id={id} {...props} > {isExpandable && ( diff --git a/packages/react-core/src/components/AlertGroup/AlertGroupInline.tsx b/packages/react-core/src/components/AlertGroup/AlertGroupInline.tsx index 99487498997..8a828cf416f 100644 --- a/packages/react-core/src/components/AlertGroup/AlertGroupInline.tsx +++ b/packages/react-core/src/components/AlertGroup/AlertGroupInline.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/AlertGroup/alert-group'; import { AlertGroupProps } from './AlertGroup'; +import { AlertProps } from '../Alert'; export const AlertGroupInline: React.FunctionComponent = ({ className, @@ -18,8 +19,8 @@ export const AlertGroupInline: React.FunctionComponent = ({ className={css(styles.alertGroup, className, isToast ? styles.modifiers.toast : '')} {...rest} > - {React.Children.toArray(children).map((Alert: React.ReactNode, index: number) => ( -
  • {Alert}
  • + {React.Children.toArray(children).map((alert, index) => ( +
  • ).props?.id || index}>{alert}
  • ))} {overflowMessage && (
  • diff --git a/packages/react-integration/cypress/integration/alertgrouptimeoutfrombottom.spec.ts b/packages/react-integration/cypress/integration/alertgrouptimeoutfrombottom.spec.ts new file mode 100644 index 00000000000..2fefbdbb29a --- /dev/null +++ b/packages/react-integration/cypress/integration/alertgrouptimeoutfrombottom.spec.ts @@ -0,0 +1,36 @@ +describe('Alert Group Timeout From Bottom Demo Test', () => { + it('Navigate to demo section', () => { + cy.visit('http://localhost:3000/alert-group-timeout-from-bottom-demo-nav-link'); + }); + + it('Adds new alerts from the top of the page down', () => { + cy.contains('Add alert').click(); + cy.wait(1000); + cy.contains('Add alert').click(); + cy.wait(1000); + cy.contains('Add alert').click(); + cy.get('.pf-c-alert') + .first() + .contains('Alert no. 2'); + cy.get('.pf-c-alert') + .last() + .contains('Alert no. 0'); + }); + + it('Removes the alerts in the order they appeared', () => { + cy.wait(1000); + cy.get('.pf-c-alert') + .first() + .contains('Alert no. 2'); + cy.get('.pf-c-alert') + .last() + .contains('Alert no. 1'); + cy.wait(1000); + cy.get('.pf-c-alert') + .first() + .contains('Alert no. 2'); + cy.get('.pf-c-alert') + .last() + .contains('Alert no. 2'); + }); +}); diff --git a/packages/react-integration/demo-app-ts/src/Demos.ts b/packages/react-integration/demo-app-ts/src/Demos.ts index 30fe25311d3..04953db5eb2 100644 --- a/packages/react-integration/demo-app-ts/src/Demos.ts +++ b/packages/react-integration/demo-app-ts/src/Demos.ts @@ -32,6 +32,11 @@ export const Demos: DemoInterface[] = [ name: 'Alert Group Demo', componentType: Examples.AlertGroupDemo }, + { + id: 'alert-group-timeout-from-bottom-demo', + name: 'Alert Group Timeout From Bottom Demo', + componentType: Examples.AlertGroupTimeoutFromBottomDemo + }, { id: 'alert-custom-timeout-demo', name: 'Alert Custom Timeout Demo', diff --git a/packages/react-integration/demo-app-ts/src/components/demos/AlertGroupDemo/AlertGroupTimeoutFromBottomDemo.tsx b/packages/react-integration/demo-app-ts/src/components/demos/AlertGroupDemo/AlertGroupTimeoutFromBottomDemo.tsx new file mode 100644 index 00000000000..03210eb40c3 --- /dev/null +++ b/packages/react-integration/demo-app-ts/src/components/demos/AlertGroupDemo/AlertGroupTimeoutFromBottomDemo.tsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { Alert, AlertActionLink, AlertGroup, Button } from '@patternfly/react-core'; + +export const AlertGroupTimeoutFromBottomDemo: React.FunctionComponent = () => { + const [alerts, setAlerts] = React.useState([]); + const [count, setCount] = React.useState(0); + const onClick = () => { + const timeout = 3000; + setAlerts(prevAlerts => [ + + View details + Ignore + + } + key={`Alert no. ${count}`} + id={`Alert no. ${count}`} + > + This alert will dismiss after {`${timeout / 1000} seconds`} + , + ...prevAlerts + ]); + setCount(count + 1); + }; + + return ( + + + {alerts} + + ); +}; + +AlertGroupTimeoutFromBottomDemo.displayName = 'AlertGroupTimeoutFromBottomDemo'; diff --git a/packages/react-integration/demo-app-ts/src/components/demos/index.ts b/packages/react-integration/demo-app-ts/src/components/demos/index.ts index eb12e6ecbf8..408d5a8a844 100644 --- a/packages/react-integration/demo-app-ts/src/components/demos/index.ts +++ b/packages/react-integration/demo-app-ts/src/components/demos/index.ts @@ -2,6 +2,7 @@ export * from './AboutModal/AboutModalDemo'; export * from './AlertDemo/AlertDemo'; export * from './AlertDemo/AlertTimeoutCloseButtonDemo'; export * from './AlertGroupDemo/AlertGroupDemo'; +export * from './AlertGroupDemo/AlertGroupTimeoutFromBottomDemo'; export * from './AlertDemo/AlertCustomTimeoutDemo'; export * from './AlertDemo/AlertDefaultTimeoutDemo'; export * from './ApplicationLauncherDemo/ApplicationLauncherFavoritesDemo';