diff --git a/frontend/packages/console-app/src/components/favorite/FavoriteButton.tsx b/frontend/packages/console-app/src/components/favorite/FavoriteButton.tsx index 534bc81ee31..4a932bbfc00 100644 --- a/frontend/packages/console-app/src/components/favorite/FavoriteButton.tsx +++ b/frontend/packages/console-app/src/components/favorite/FavoriteButton.tsx @@ -9,10 +9,13 @@ import { HelperTextItem, TextInput, Tooltip, + Modal, + ModalVariant, + ModalHeader, + ModalBody, + ModalFooter, } from '@patternfly/react-core'; -import { ModalVariant } from '@patternfly/react-core/deprecated'; import { useTranslation } from 'react-i18next'; -import Modal from '@console/shared/src/components/modal/Modal'; import { useTelemetry } from '@console/shared/src/hooks/useTelemetry'; import { useUserSettingsCompatibility } from '@console/shared/src/hooks/useUserSettingsCompatibility'; import { FAVORITES_CONFIG_MAP_KEY, FAVORITES_LOCAL_STORAGE_KEY } from '../../consts'; @@ -78,7 +81,8 @@ export const FavoriteButton = ({ defaultName }: FavoriteButtonProps) => { setIsModalOpen(false); }; - const handleConfirmStar = () => { + const handleConfirmStar = (e?: React.FormEvent) => { + e?.preventDefault(); const trimmedName = name.trim(); if (!trimmedName) { setError(t('Name is required.')); @@ -151,46 +155,44 @@ export const FavoriteButton = ({ defaultName }: FavoriteButtonProps) => { {isModalOpen && ( - + + +
+ + handleNameChange(v)} + value={name || ''} + autoFocus + required + /> + {error && ( + + + {error} + + + )} + +
+
+ , + , - ]} - variant={ModalVariant.small} - > -
- - handleNameChange(v)} - value={name || ''} - autoFocus - required - /> - {error && ( - - - {error} - - - )} - -
+ +
)} diff --git a/frontend/packages/console-app/src/components/modals/add-group-users-modal.tsx b/frontend/packages/console-app/src/components/modals/add-group-users-modal.tsx index da15972b46c..8e045f1825a 100644 --- a/frontend/packages/console-app/src/components/modals/add-group-users-modal.tsx +++ b/frontend/packages/console-app/src/components/modals/add-group-users-modal.tsx @@ -91,9 +91,6 @@ const AddGroupUsersModal: OverlayComponent = ({ group, )} - + ); diff --git a/frontend/packages/console-app/src/components/tour/TourStepComponent.tsx b/frontend/packages/console-app/src/components/tour/TourStepComponent.tsx index 4d629e3e479..03acc787c28 100644 --- a/frontend/packages/console-app/src/components/tour/TourStepComponent.tsx +++ b/frontend/packages/console-app/src/components/tour/TourStepComponent.tsx @@ -3,6 +3,7 @@ import { useContext } from 'react'; import { Grid, GridItem, + Modal, ModalBody, ModalFooter, ModalHeader, @@ -10,7 +11,6 @@ import { } from '@patternfly/react-core'; import { useTranslation } from 'react-i18next'; import { ThemeContext } from '@console/internal/components/ThemeProvider'; -import Modal from '@console/shared/src/components/modal/Modal'; import type { PopoverPlacement } from '@console/shared/src/components/popover/const'; import Popover from '@console/shared/src/components/popover/Popover'; import Spotlight from '@console/shared/src/components/spotlight/Spotlight'; @@ -108,7 +108,6 @@ const TourStepComponent: FC = ({ id="guided-tour-modal" data-test="guided-tour-modal" aria-label={t('console-app~guided tour {{step, number}}', { step })} - isFullScreen > diff --git a/frontend/packages/console-shared/src/components/modal/Modal.scss b/frontend/packages/console-shared/src/components/catalog/details/CatalogDetailsModal.scss similarity index 100% rename from frontend/packages/console-shared/src/components/modal/Modal.scss rename to frontend/packages/console-shared/src/components/catalog/details/CatalogDetailsModal.scss diff --git a/frontend/packages/console-shared/src/components/catalog/details/CatalogDetailsModal.tsx b/frontend/packages/console-shared/src/components/catalog/details/CatalogDetailsModal.tsx index 5377e70f759..07983dc679f 100644 --- a/frontend/packages/console-shared/src/components/catalog/details/CatalogDetailsModal.tsx +++ b/frontend/packages/console-shared/src/components/catalog/details/CatalogDetailsModal.tsx @@ -1,14 +1,23 @@ import type { FC } from 'react'; import { CatalogItemHeader } from '@patternfly/react-catalog-view-extension'; -import { Split, SplitItem, Divider, Stack, StackItem } from '@patternfly/react-core'; +import { + Split, + SplitItem, + Divider, + Stack, + StackItem, + Modal, + ModalBody, + ModalHeader, +} from '@patternfly/react-core'; import { useTranslation } from 'react-i18next'; import { Link } from 'react-router-dom-v5-compat'; import type { CatalogItem } from '@console/dynamic-plugin-sdk/src/extensions'; -import { Modal } from '../../modal'; import CatalogBadges from '../CatalogBadges'; import { useCtaLink } from '../hooks/useCtaLink'; import { getIconProps } from '../utils/catalog-utils'; import CatalogDetailsPanel from './CatalogDetailsPanel'; +import './CatalogDetailsModal.scss'; type CatalogDetailsModalProps = { item: CatalogItem; @@ -42,43 +51,45 @@ const CatalogDetailsModal: FC = ({ item, onClose }) => return ( - - - - - {to && ( -
- - {label} - -
- )} -
- - - {badges?.length > 0 ? : undefined} - -
-
- - - - - - -
+ {modalHeader} + + + + + + {to && ( +
+ + {label} + +
+ )} +
+ + + {badges?.length > 0 ? : undefined} + +
+
+ + + + + + +
+
); }; diff --git a/frontend/packages/console-shared/src/components/index.ts b/frontend/packages/console-shared/src/components/index.ts index 8a4b3e379b6..c1fdd23fe00 100644 --- a/frontend/packages/console-shared/src/components/index.ts +++ b/frontend/packages/console-shared/src/components/index.ts @@ -15,7 +15,6 @@ export * from './virtualized-grid'; export * from './alerts'; export * from './popover'; export * from './utils'; -export * from './modal'; export * from './modals'; export * from './hpa'; export * from './multi-tab-list'; diff --git a/frontend/packages/console-shared/src/components/modal/Modal.tsx b/frontend/packages/console-shared/src/components/modal/Modal.tsx deleted file mode 100644 index 76d2388c6f3..00000000000 --- a/frontend/packages/console-shared/src/components/modal/Modal.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import type { LegacyRef, FC } from 'react'; -import type { ModalProps as PfModalProps } from '@patternfly/react-core/deprecated'; -import { Modal as PfModal } from '@patternfly/react-core/deprecated'; -import { css } from '@patternfly/react-styles'; -import './Modal.scss'; - -type ModalProps = { - isFullScreen?: boolean; - ref?: LegacyRef; -} & PfModalProps; - -const Modal: FC = ({ isFullScreen = false, className, ...props }) => ( - (isFullScreen ? document.body : document.querySelector('#modal-container'))} - /> -); - -export default Modal; diff --git a/frontend/packages/console-shared/src/components/modal/index.ts b/frontend/packages/console-shared/src/components/modal/index.ts deleted file mode 100644 index c6b35681c7e..00000000000 --- a/frontend/packages/console-shared/src/components/modal/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Modal } from './Modal'; diff --git a/frontend/packages/console-shared/src/components/modals/CreateNamespaceModal.tsx b/frontend/packages/console-shared/src/components/modals/CreateNamespaceModal.tsx index a444efba571..d87252ece1e 100644 --- a/frontend/packages/console-shared/src/components/modals/CreateNamespaceModal.tsx +++ b/frontend/packages/console-shared/src/components/modals/CreateNamespaceModal.tsx @@ -169,7 +169,7 @@ export const CreateNamespaceModal: ModalComponent = ({ ,     - @@ -64,7 +64,7 @@ const TestFunctionModal: FC = (props) => {   - diff --git a/frontend/packages/metal3-plugin/src/components/modals/RestartHostModal.tsx b/frontend/packages/metal3-plugin/src/components/modals/RestartHostModal.tsx index 5c0aa2f8048..802271bfdd1 100644 --- a/frontend/packages/metal3-plugin/src/components/modals/RestartHostModal.tsx +++ b/frontend/packages/metal3-plugin/src/components/modals/RestartHostModal.tsx @@ -56,7 +56,7 @@ const RestartHostModal: OverlayComponent = (props) => { - diff --git a/frontend/packages/metal3-plugin/src/components/modals/StartNodeMaintenanceModal.tsx b/frontend/packages/metal3-plugin/src/components/modals/StartNodeMaintenanceModal.tsx index 288889d01ff..52b47a2858d 100644 --- a/frontend/packages/metal3-plugin/src/components/modals/StartNodeMaintenanceModal.tsx +++ b/frontend/packages/metal3-plugin/src/components/modals/StartNodeMaintenanceModal.tsx @@ -105,7 +105,7 @@ export const StartNodeMaintenanceModal: OverlayComponent {t('metal3-plugin~Start Maintenance')} - diff --git a/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-items.tsx b/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-items.tsx index 443ab4338b1..32406693a97 100644 --- a/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-items.tsx +++ b/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-items.tsx @@ -8,6 +8,9 @@ import { EmptyStateFooter, EmptyStateVariant, Truncate, + Modal, + ModalBody, + ModalHeader, } from '@patternfly/react-core'; import { css } from '@patternfly/react-styles'; import * as _ from 'lodash'; @@ -19,7 +22,6 @@ import { TileViewPage } from '@console/internal/components/utils/tile-view-page' import i18n from '@console/internal/i18n'; import { GreenCheckCircleIcon, - Modal, COMMUNITY_PROVIDERS_WARNING_LOCAL_STORAGE_KEY as storeKey, COMMUNITY_PROVIDERS_WARNING_USERSETTINGS_KEY as userSettingsKey, useUserSettingsCompatibility, @@ -42,8 +44,9 @@ import { sourceSort, validSubscriptionSort, } from './operator-hub-utils'; -import type { OperatorHubItem, TokenizedAuthProvider } from './index'; import { InfrastructureFeature } from './index'; +import type { OperatorHubItem, TokenizedAuthProvider } from './index'; +import '@console/shared/src/components/catalog/details/CatalogDetailsModal.scss'; // Scoring and priority code no longer used and will be removed with Operator Hub catalog files cleanup effort const SCORE = { @@ -1038,65 +1041,64 @@ export const OperatorHubTileView: FC = (props) => { /> {detailsItem && ( - - -
- {!detailsItem.installed ? ( - - {t('olm~Install')} - - ) : ( - - )} -
- - } > - + + + +
+ {!detailsItem.installed ? ( + + {t('olm~Install')} + + ) : ( + + )} +
+
+ + +
)} diff --git a/frontend/packages/operator-lifecycle-manager/src/components/registry-poll-interval-details.tsx b/frontend/packages/operator-lifecycle-manager/src/components/registry-poll-interval-details.tsx index 9fdbac45f6a..66075df5c91 100644 --- a/frontend/packages/operator-lifecycle-manager/src/components/registry-poll-interval-details.tsx +++ b/frontend/packages/operator-lifecycle-manager/src/components/registry-poll-interval-details.tsx @@ -143,7 +143,7 @@ export const RegistryPollIntervalDetailItem: FC + + + ); }; @@ -104,11 +116,17 @@ const EditApplicationModal: FC = (props) => { }; const EditApplicationModalProvider: OverlayComponent = (props) => { - return ( - - - - ); + const [isOpen, setIsOpen] = useState(true); + const handleClose = () => { + setIsOpen(false); + props.closeOverlay(); + }; + + return isOpen ? ( + + + + ) : null; }; export const useEditApplicationModalLauncher = (props) => { diff --git a/frontend/packages/topology/src/components/modals/MoveConnectionModal.tsx b/frontend/packages/topology/src/components/modals/MoveConnectionModal.tsx index 923a93d6fe5..3814e16045e 100644 --- a/frontend/packages/topology/src/components/modals/MoveConnectionModal.tsx +++ b/frontend/packages/topology/src/components/modals/MoveConnectionModal.tsx @@ -2,7 +2,13 @@ import type { FC, Ref } from 'react'; import { useState, useCallback } from 'react'; import type { MenuToggleElement } from '@patternfly/react-core'; import { + Button, + Form, FormGroup, + Modal, + ModalBody, + ModalHeader, + ModalVariant, Title, Select, SelectList, @@ -15,12 +21,6 @@ import { Formik } from 'formik'; import { Trans, useTranslation } from 'react-i18next'; import type { OverlayComponent } from '@console/dynamic-plugin-sdk/src/app/modal-support/OverlayProvider'; import { useOverlay } from '@console/dynamic-plugin-sdk/src/app/modal-support/useOverlay'; -import { - ModalTitle, - ModalBody, - ModalSubmitFooter, - ModalWrapper, -} from '@console/internal/components/factory/modal'; import { ResourceIcon } from '@console/internal/components/utils'; import type { K8sResourceKind } from '@console/internal/module/k8s'; import { @@ -31,6 +31,7 @@ import { createEventSourceKafkaConnection, createSinkConnection, } from '@console/knative-plugin/src/topology/knative-topology-utils'; +import { ModalFooterWithAlerts } from '@console/shared/src/components/modals/ModalFooterWithAlerts'; import { usePromiseHandler } from '@console/shared/src/hooks/promise-handler'; import { TYPE_CONNECTS_TO } from '../../const'; import { createConnection } from '../../utils'; @@ -79,15 +80,15 @@ const MoveConnectionForm: FC & MoveConnectionModalProp const sourceLabel = edge.getSource().getLabel(); return ( -
- {t('topology~Move connector')} + <> + - - <Trans ns="topology" t={t}> - Connect <strong>{{ sourceLabel }}</strong> to - </Trans> - -
+ + + <Trans ns="topology" t={t}> + Connect <strong>{{ sourceLabel }}</strong> to + </Trans> + -
+
- - + + + + + ); }; @@ -179,11 +189,17 @@ const MoveConnectionModal: FC = (props) => { }; const MoveConnectionModalProvider: OverlayComponent = (props) => { - return ( - - - - ); + const [isOpen, setIsOpen] = useState(true); + const handleClose = () => { + setIsOpen(false); + props.closeOverlay(); + }; + + return isOpen ? ( + + + + ) : null; }; export const useMoveConnectionModalLauncher = (props: MoveConnectionModalProps) => { diff --git a/frontend/public/components/masthead/masthead-toolbar.tsx b/frontend/public/components/masthead/masthead-toolbar.tsx index ef56e0ae9be..83f7b979c46 100644 --- a/frontend/public/components/masthead/masthead-toolbar.tsx +++ b/frontend/public/components/masthead/masthead-toolbar.tsx @@ -207,6 +207,10 @@ const MastheadToolbarContents: FC = ({ const handleGuidedTourClick = (e) => { e.preventDefault(); + // Move focus away from the dropdown menu item to prevent aria-hidden warning + if (document.activeElement instanceof HTMLElement) { + document.activeElement.blur(); + } fireTelemetryEvent('launch-guided-tour-form-help', { id: 'guided-tour-help', perspective: activePerspective, diff --git a/frontend/public/components/modals/configure-count-modal.tsx b/frontend/public/components/modals/configure-count-modal.tsx index cc4ad21c343..5b65afe3cc9 100644 --- a/frontend/public/components/modals/configure-count-modal.tsx +++ b/frontend/public/components/modals/configure-count-modal.tsx @@ -1,23 +1,14 @@ import * as _ from 'lodash'; import { useTranslation } from 'react-i18next'; import { useState, useCallback } from 'react'; -import { - Modal, - ModalHeader, - ModalBody, - ModalFooter, - Button, - HelperText, - HelperTextItem, - FormGroup, - Form, -} from '@patternfly/react-core'; +import { Modal, ModalHeader, ModalBody, Button, FormGroup, Form } from '@patternfly/react-core'; import { useOverlay } from '@console/dynamic-plugin-sdk/src/app/modal-support/useOverlay'; import { OverlayComponent } from '@console/dynamic-plugin-sdk/src/app/modal-support/OverlayProvider'; import { k8sPatchResource } from '@console/dynamic-plugin-sdk/src/utils/k8s'; import { K8sResourceKind, K8sModel } from '../../module/k8s'; import { NumberSpinner, NumberSpinnerProps } from '../utils/number-spinner'; import { usePromiseHandler } from '@console/shared/src/hooks/promise-handler'; +import { ModalFooterWithAlerts } from '@console/shared/src/components/modals/ModalFooterWithAlerts'; export const ConfigureCountModal: OverlayComponent = (props) => { const { @@ -90,7 +81,7 @@ export const ConfigureCountModal: OverlayComponent = ( description={messageKey ? t(messageKey, messageVariablesSafe) : message} /> -
+ = ( required min={0} /> - {errorMessage && ( - - {errorMessage} - - )}
- - - - + + ); }; diff --git a/frontend/public/components/modals/configure-machine-autoscaler-modal.tsx b/frontend/public/components/modals/configure-machine-autoscaler-modal.tsx index 447c9a79520..363319c5467 100644 --- a/frontend/public/components/modals/configure-machine-autoscaler-modal.tsx +++ b/frontend/public/components/modals/configure-machine-autoscaler-modal.tsx @@ -2,17 +2,7 @@ import { useState, useCallback } from 'react'; import * as _ from 'lodash'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom-v5-compat'; -import { - Modal, - ModalHeader, - ModalBody, - ModalFooter, - Button, - HelperText, - HelperTextItem, - FormGroup, - Form, -} from '@patternfly/react-core'; +import { Modal, ModalHeader, ModalBody, Button, FormGroup, Form } from '@patternfly/react-core'; import { OverlayComponent } from '@console/dynamic-plugin-sdk/src/app/modal-support/OverlayProvider'; import { MachineAutoscalerModel } from '../../models'; import { NumberSpinner } from '../utils/number-spinner'; @@ -20,6 +10,7 @@ import { resourcePathFromModel } from '../utils/resource-link'; import { K8sResourceKind } from '../../module/k8s'; import { k8sCreateResource } from '@console/dynamic-plugin-sdk/src/utils/k8s'; import { usePromiseHandler } from '@console/shared/src/hooks/promise-handler'; +import { ModalFooterWithAlerts } from '@console/shared/src/components/modals/ModalFooterWithAlerts'; export const ConfigureMachineAutoscalerModal: OverlayComponent = ({ machineSet, @@ -116,7 +107,7 @@ export const ConfigureMachineAutoscalerModal: OverlayComponent -
+ - {errorMessage && ( - - {errorMessage} - - )}
- - - - + + ); }; diff --git a/frontend/public/components/modals/delete-modal.tsx b/frontend/public/components/modals/delete-modal.tsx index d7023fb00c3..1d0320478cb 100644 --- a/frontend/public/components/modals/delete-modal.tsx +++ b/frontend/public/components/modals/delete-modal.tsx @@ -1,17 +1,19 @@ import * as _ from 'lodash'; import type { ReactNode } from 'react'; import { useState, useCallback, useEffect } from 'react'; -import { Alert, Checkbox } from '@patternfly/react-core'; +import { + Alert, + Button, + Checkbox, + Modal, + ModalBody, + ModalHeader, + ModalVariant, +} from '@patternfly/react-core'; import { Trans, useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom-v5-compat'; import { OverlayComponent } from '@console/dynamic-plugin-sdk/src/app/modal-support/OverlayProvider'; -import { - ModalTitle, - ModalBody, - ModalSubmitFooter, - ModalWrapper, - ModalComponentProps, -} from '../factory/modal'; +import { ModalComponentProps } from '../factory/modal'; import { resourceListPathFromModel, ResourceLink } from '../utils/resource-link'; import { k8sKill, @@ -27,6 +29,7 @@ import { findOwner } from '../../module/k8s/managed-by'; import { LocationDescriptor } from 'history'; import { usePromiseHandler } from '@console/shared/src/hooks/promise-handler'; +import { ModalFooterWithAlerts } from '@console/shared/src/components/modals/ModalFooterWithAlerts'; //Modal for resource deletion and allows cascading deletes if propagationPolicy is provided for the enum export const DeleteModal = (props: DeleteModalProps) => { @@ -87,93 +90,116 @@ export const DeleteModal = (props: DeleteModalProps) => { }); const { kind, resource, message } = props; + return ( -
- - {' '} - {t('public~Delete {{kind}}?', { - kind: kind ? (kind.labelKey ? t(kind.labelKey) : kind.label) : '', - })} - - - {message} -
- {_.has(resource.metadata, 'namespace') ? ( - - Are you sure you want to delete{' '} - - {{ resourceName: resource?.metadata?.name }} - {' '} - in namespace {{ namespace: resource?.metadata?.namespace }}? - - ) : ( - - Are you sure you want to delete{' '} - - {{ resourceName: resource?.metadata?.name }} - - ? - - )} - {_.has(kind, 'propagationPolicy') && ( - setIsChecked(checked)} - isChecked={isChecked} - name="deleteDependentObjects" - id="deleteDependentObjects" - /> - )} - {props.deleteAllResources && ( - setIsDeleteOtherResourcesChecked(checked)} - isChecked={isDeleteOtherResourcesChecked} - name="deleteOtherResources" - id="deleteOtherResources" - /> - )} - {owner && ( - + <> + + {' '} + {t('public~Delete {{kind}}?', { + kind: kind ? (kind.labelKey ? t(kind.labelKey) : kind.label) : '', + })} + + } + data-test-id="modal-title" + /> + + + {message} +
+ {_.has(resource.metadata, 'namespace') ? ( - This resource is managed by{' '} - {' '} - and any modifications may be overwritten. Edit the managing resource to preserve - changes. + Are you sure you want to delete{' '} + + {{ resourceName: resource?.metadata?.name }} + {' '} + in namespace {{ namespace: resource?.metadata?.namespace }}? - - )} -
+ ) : ( + + Are you sure you want to delete{' '} + + {{ resourceName: resource?.metadata?.name }} + + ? + + )} + {_.has(kind, 'propagationPolicy') && ( + setIsChecked(checked)} + isChecked={isChecked} + name="deleteDependentObjects" + id="deleteDependentObjects" + /> + )} + {props.deleteAllResources && ( + setIsDeleteOtherResourcesChecked(checked)} + isChecked={isDeleteOtherResourcesChecked} + name="deleteOtherResources" + id="deleteOtherResources" + /> + )} + {owner && ( + + + This resource is managed by{' '} + {' '} + and any modifications may be overwritten. Edit the managing resource to preserve + changes. + + + )} +
+
- - + + + + + ); }; export const DeleteModalOverlay: OverlayComponent = (props) => { - return ( - - - - ); + const [isOpen, setIsOpen] = useState(true); + const handleClose = () => { + setIsOpen(false); + props.closeOverlay(); + }; + + return isOpen ? ( + + + + ) : null; }; export type DeleteModalProps = { diff --git a/frontend/public/components/modals/delete-namespace-modal.tsx b/frontend/public/components/modals/delete-namespace-modal.tsx index 667b11365fc..1038373ce3e 100644 --- a/frontend/public/components/modals/delete-namespace-modal.tsx +++ b/frontend/public/components/modals/delete-namespace-modal.tsx @@ -120,7 +120,7 @@ export const DeleteNamespaceModal: OverlayComponent = > {t('public~Delete')} - diff --git a/frontend/public/components/secrets/create-secret/SecretFormWrapper.tsx b/frontend/public/components/secrets/create-secret/SecretFormWrapper.tsx index 1a7d50ca467..b0e056d82bc 100644 --- a/frontend/public/components/secrets/create-secret/SecretFormWrapper.tsx +++ b/frontend/public/components/secrets/create-secret/SecretFormWrapper.tsx @@ -205,7 +205,7 @@ export const SecretFormWrapper: FC = (props) => { > {props.saveButtonText || t('public~Create')} - diff --git a/frontend/public/components/utils/button-bar.tsx b/frontend/public/components/utils/button-bar.tsx index 23ffe0c55b3..1cc41c9d64a 100644 --- a/frontend/public/components/utils/button-bar.tsx +++ b/frontend/public/components/utils/button-bar.tsx @@ -29,7 +29,7 @@ export const ErrorMessage = ({ message }) => { ); }; -const InfoMessage = ({ message }) => ( +export const InfoMessage = ({ message }) => (