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 = ({ , + + + ); }; diff --git a/frontend/packages/knative-plugin/src/components/revisions/DeleteRevisionModal.tsx b/frontend/packages/knative-plugin/src/components/revisions/DeleteRevisionModal.tsx index fec64373a2b..631b1c00cf7 100644 --- a/frontend/packages/knative-plugin/src/components/revisions/DeleteRevisionModal.tsx +++ b/frontend/packages/knative-plugin/src/components/revisions/DeleteRevisionModal.tsx @@ -1,14 +1,9 @@ import type { FC } from 'react'; -import { Alert } from '@patternfly/react-core'; +import { Alert, Button, Form, ModalBody, ModalHeader } from '@patternfly/react-core'; import type { FormikProps, FormikValues } from 'formik'; import { useTranslation } from 'react-i18next'; -import { - ModalTitle, - ModalBody, - ModalSubmitFooter, -} from '@console/internal/components/factory/modal'; import type { K8sResourceKind } from '@console/internal/module/k8s'; -import { YellowExclamationTriangleIcon } from '@console/shared'; +import { ModalFooterWithAlerts } from '@console/shared/src/components/modals/ModalFooterWithAlerts'; import { KNATIVE_SERVING_LABEL } from '../../const'; import { RevisionModel } from '../../models'; import type { RevisionItems } from '../../utils/traffic-splitting-utils'; @@ -29,42 +24,52 @@ const DeleteRevisionModal: FC = (props) => { const serviceName = deleteRevision.metadata.labels[KNATIVE_SERVING_LABEL]; return ( -
- - {' '} - {t('knative-plugin~Delete {{revlabel}}?', { revlabel: RevisionModel.label })} - + <> + -

- {t('knative-plugin~Are you sure you want to delete ')} - {deleteRevision.metadata.name}{' '} - {t('knative-plugin~from ')} {serviceName}{' '} - {t('knative-plugin~in namespace ')} {deleteRevision.metadata.namespace}? -

- {showTraffic && ( - <> - - - - )} + +

+ {t('knative-plugin~Are you sure you want to delete ')} + {deleteRevision.metadata.name}{' '} + {t('knative-plugin~from ')} {serviceName}{' '} + {t('knative-plugin~in namespace ')} {deleteRevision.metadata.namespace} + ? +

+ {showTraffic && ( + <> + + + + )} +
- - + + + + + ); }; diff --git a/frontend/packages/knative-plugin/src/components/revisions/DeleteRevisionModalController.tsx b/frontend/packages/knative-plugin/src/components/revisions/DeleteRevisionModalController.tsx index b5f5625a3fc..e57b5fa1f40 100644 --- a/frontend/packages/knative-plugin/src/components/revisions/DeleteRevisionModalController.tsx +++ b/frontend/packages/knative-plugin/src/components/revisions/DeleteRevisionModalController.tsx @@ -1,23 +1,16 @@ import type { FC } from 'react'; import { useCallback, useMemo } from 'react'; -import { ActionGroup, Button } from '@patternfly/react-core'; +import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from '@patternfly/react-core'; import type { FormikHelpers, FormikValues } from 'formik'; import { Formik } from 'formik'; import { 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 type { ModalComponentProps } from '@console/internal/components/factory'; -import { - ModalBody, - ModalFooter, - ModalTitle, - ModalWrapper, -} from '@console/internal/components/factory'; import { history, resourceListPathFromModel } from '@console/internal/components/utils'; import { useK8sWatchResources } from '@console/internal/components/utils/k8s-watch-hook'; import type { K8sResourceKind } from '@console/internal/module/k8s'; import { k8sKill, k8sPatch, referenceForModel } from '@console/internal/module/k8s'; -import { RedExclamationCircleIcon } from '@console/shared'; import { KNATIVE_SERVING_LABEL } from '../../const'; import { ConfigurationModel, RevisionModel, ServiceModel } from '../../models'; import { getKnativeRevisionsData } from '../../topology/knative-topology-utils'; @@ -87,11 +80,15 @@ const DeleteRevisionModalController: FC = ({ if (revisions.length === 0) { return ( -
- - - {t('knative-plugin~Unable to delete {{revlabel}}', { revlabel: RevisionModel.label })} - + <> +

{t('knative-plugin~You cannot delete the last {{revlabel}} for the {{serviceLabel}}.', { @@ -100,19 +97,17 @@ const DeleteRevisionModalController: FC = ({ })}

- - - - + + - + ); } @@ -203,13 +198,13 @@ type Props = DeleteRevisionModalControllerProps & ModalComponentProps; const DeleteRevisionModalProvider: OverlayComponent = (props) => { return ( - + - + ); }; diff --git a/frontend/packages/knative-plugin/src/components/sink-pubsub/SinkPubsubController.tsx b/frontend/packages/knative-plugin/src/components/sink-pubsub/SinkPubsubController.tsx index 1804bb0e9e2..7836c79918e 100644 --- a/frontend/packages/knative-plugin/src/components/sink-pubsub/SinkPubsubController.tsx +++ b/frontend/packages/knative-plugin/src/components/sink-pubsub/SinkPubsubController.tsx @@ -1,9 +1,9 @@ import type { FC } from 'react'; import { useCallback } from 'react'; +import { Modal } from '@patternfly/react-core'; 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 type { ModalComponentProps } from '@console/internal/components/factory'; -import { ModalWrapper } from '@console/internal/components/factory'; import type { K8sResourceKind } from '@console/internal/module/k8s'; import SinkPubsub from './SinkPubsub'; @@ -18,13 +18,11 @@ const SinkPubsubController: FC = ({ source, ...props type Props = SinkPubsubControllerProps & ModalComponentProps; -const SinkPubsubModalProvider: OverlayComponent = (props) => { - return ( - - - - ); -}; +const SinkPubsubModalProvider: OverlayComponent = (props) => ( + + + +); export const useSinkPubsubModalLauncher = (props: Props) => { const launcher = useOverlay(); diff --git a/frontend/packages/knative-plugin/src/components/sink-pubsub/SinkPubsubModal.tsx b/frontend/packages/knative-plugin/src/components/sink-pubsub/SinkPubsubModal.tsx index c73e49ced82..7d535692529 100644 --- a/frontend/packages/knative-plugin/src/components/sink-pubsub/SinkPubsubModal.tsx +++ b/frontend/packages/knative-plugin/src/components/sink-pubsub/SinkPubsubModal.tsx @@ -1,16 +1,13 @@ import type { FC } from 'react'; import { useCallback } from 'react'; +import { Button, Form, ModalBody, ModalHeader } from '@patternfly/react-core'; import type { FormikProps, FormikValues } from 'formik'; import * as fuzzy from 'fuzzysearch'; import { Trans, useTranslation } from 'react-i18next'; import FormSection from '@console/dev-console/src/components/import/section/FormSection'; -import { - ModalTitle, - ModalBody, - ModalSubmitFooter, -} from '@console/internal/components/factory/modal'; import type { FirehoseResource } from '@console/internal/components/utils'; import { ResourceDropdownField } from '@console/shared'; +import { ModalFooterWithAlerts } from '@console/shared/src/components/modals/ModalFooterWithAlerts'; import { craftResourceKey } from '../pub-sub/pub-sub-utils'; export interface SinkPubsubModalProps { @@ -60,40 +57,56 @@ const SinkPubsubModal: FC = ({ const dirty = values?.ref?.name !== initialValues.ref.name; return ( -
- {labelTitle} + <> + -

- - Connects {{ resourceName }} to - -

- - - + +

+ + Connects {{ resourceName }} to + +

+ + + +
- - + + + + + ); }; diff --git a/frontend/packages/knative-plugin/src/components/sink-pubsub/__tests__/SinkPubsubModal.spec.tsx b/frontend/packages/knative-plugin/src/components/sink-pubsub/__tests__/SinkPubsubModal.spec.tsx index 0606431ae8c..ecb21b34faa 100644 --- a/frontend/packages/knative-plugin/src/components/sink-pubsub/__tests__/SinkPubsubModal.spec.tsx +++ b/frontend/packages/knative-plugin/src/components/sink-pubsub/__tests__/SinkPubsubModal.spec.tsx @@ -1,10 +1,16 @@ import { render } from '@testing-library/react'; import SinkPubsubModal from '../SinkPubsubModal'; -jest.mock('@console/internal/components/factory/modal', () => ({ - ModalTitle: jest.fn(() => null), - ModalBody: jest.fn(() => null), - ModalSubmitFooter: jest.fn(() => null), +jest.mock('@patternfly/react-core', () => ({ + ...jest.requireActual('@patternfly/react-core'), + ModalHeader: jest.fn(() => null), + ModalBody: jest.fn(({ children }) =>
{children}
), + Button: jest.fn(() => null), + Form: jest.fn(({ children, ...props }) =>
{children}
), +})); + +jest.mock('@console/shared/src/components/modals/ModalFooterWithAlerts', () => ({ + ModalFooterWithAlerts: jest.fn(({ children }) =>
{children}
), })); jest.mock('@console/shared', () => ({ diff --git a/frontend/packages/knative-plugin/src/components/sink-source/SinkSourceController.tsx b/frontend/packages/knative-plugin/src/components/sink-source/SinkSourceController.tsx index c8389234bf5..3082379bd65 100644 --- a/frontend/packages/knative-plugin/src/components/sink-source/SinkSourceController.tsx +++ b/frontend/packages/knative-plugin/src/components/sink-source/SinkSourceController.tsx @@ -1,9 +1,9 @@ import type { FC } from 'react'; import { useCallback } from 'react'; +import { Modal } from '@patternfly/react-core'; 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 type { ModalComponentProps } from '@console/internal/components/factory'; -import { ModalWrapper } from '@console/internal/components/factory'; import type { K8sResourceKind } from '@console/internal/module/k8s'; import SinkSource from './SinkSource'; @@ -17,13 +17,11 @@ const SinkSourceController: FC = ({ source, ...props type Props = SinkSourceControllerProps & ModalComponentProps; -const SinkSourceModalProvider: OverlayComponent = (props) => { - return ( - - - - ); -}; +const SinkSourceModalProvider: OverlayComponent = (props) => ( + + + +); export const useSinkSourceModalLauncher = (props: Props) => { const launcher = useOverlay(); diff --git a/frontend/packages/knative-plugin/src/components/sink-source/SinkSourceModal.tsx b/frontend/packages/knative-plugin/src/components/sink-source/SinkSourceModal.tsx index fef4bdc3438..26a1bc90e49 100644 --- a/frontend/packages/knative-plugin/src/components/sink-source/SinkSourceModal.tsx +++ b/frontend/packages/knative-plugin/src/components/sink-source/SinkSourceModal.tsx @@ -1,13 +1,10 @@ import type { FC } from 'react'; +import { Button, Form, ModalBody, ModalHeader } from '@patternfly/react-core'; import type { FormikProps, FormikValues } from 'formik'; import * as _ from 'lodash'; import { Trans, useTranslation } from 'react-i18next'; import FormSection from '@console/dev-console/src/components/import/section/FormSection'; -import { - ModalTitle, - ModalBody, - ModalSubmitFooter, -} from '@console/internal/components/factory/modal'; +import { ModalFooterWithAlerts } from '@console/shared/src/components/modals/ModalFooterWithAlerts'; import SinkUriResourcesGroup from '../add/event-sources/form-fields/SinkUriResourcesGroup'; export interface SinkSourceModalProps { @@ -35,27 +32,43 @@ const SinkSourceModal: FC = ({ values?.formData?.sink?.uri !== initialValues.formData.sink.uri; return ( -
- {t('knative-plugin~Move sink')} + <> + -

- - Connects {{ resourceName }} to - -

- - - + +

+ + Connects {{ resourceName }} to + +

+ + + +
- - + + + + + ); }; diff --git a/frontend/packages/knative-plugin/src/components/sink-source/__tests__/SinkSourceModal.spec.tsx b/frontend/packages/knative-plugin/src/components/sink-source/__tests__/SinkSourceModal.spec.tsx index 0c75359b358..b055f64e6c6 100644 --- a/frontend/packages/knative-plugin/src/components/sink-source/__tests__/SinkSourceModal.spec.tsx +++ b/frontend/packages/knative-plugin/src/components/sink-source/__tests__/SinkSourceModal.spec.tsx @@ -4,10 +4,16 @@ import { formikFormProps } from '@console/shared/src/test-utils/formik-props-uti import { ServiceModel } from '../../../models'; import SinkSourceModal from '../SinkSourceModal'; -jest.mock('@console/internal/components/factory/modal', () => ({ - ModalTitle: jest.fn(() => null), - ModalBody: jest.fn(() => null), - ModalSubmitFooter: jest.fn(() => null), +jest.mock('@patternfly/react-core', () => ({ + ...jest.requireActual('@patternfly/react-core'), + ModalHeader: jest.fn(() => null), + ModalBody: jest.fn(({ children }) =>
{children}
), + Button: jest.fn(() => null), + Form: jest.fn(({ children, ...props }) =>
{children}
), +})); + +jest.mock('@console/shared/src/components/modals/ModalFooterWithAlerts', () => ({ + ModalFooterWithAlerts: jest.fn(({ children }) =>
{children}
), })); jest.mock('../../add/event-sources/form-fields/SinkUriResourcesGroup', () => ({ @@ -52,10 +58,11 @@ describe('SinkSourceModal Form', () => { }; }); - it('should render form with modal structure', () => { + it('should render form with id', () => { const { container } = render(); - expect(container.querySelector('form')).toBeInTheDocument(); - expect(container.querySelector('form')).toHaveClass('modal-content'); + const form = container.querySelector('form'); + expect(form).toBeInTheDocument(); + expect(form).toHaveAttribute('id', 'sink-source-form'); }); it('should call handleSubmit on form submit', () => { diff --git a/frontend/packages/knative-plugin/src/components/sink-uri/SinkUriController.tsx b/frontend/packages/knative-plugin/src/components/sink-uri/SinkUriController.tsx index e1cdb949d12..e2ff1e9b67a 100644 --- a/frontend/packages/knative-plugin/src/components/sink-uri/SinkUriController.tsx +++ b/frontend/packages/knative-plugin/src/components/sink-uri/SinkUriController.tsx @@ -1,9 +1,9 @@ import type { FC } from 'react'; import { useCallback } from 'react'; +import { Modal } from '@patternfly/react-core'; 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 type { ModalComponentProps } from '@console/internal/components/factory'; -import { ModalWrapper } from '@console/internal/components/factory'; import type { K8sResourceKind } from '@console/internal/module/k8s'; import SinkUri from './SinkUri'; @@ -20,9 +20,9 @@ type Props = SinkUriControllerProps & ModalComponentProps; const SinkUriModalProvider: OverlayComponent = (props) => { return ( - + - + ); }; diff --git a/frontend/packages/knative-plugin/src/components/sink-uri/SinkUriModal.tsx b/frontend/packages/knative-plugin/src/components/sink-uri/SinkUriModal.tsx index 7b860a0334b..67d83b8ed05 100644 --- a/frontend/packages/knative-plugin/src/components/sink-uri/SinkUriModal.tsx +++ b/frontend/packages/knative-plugin/src/components/sink-uri/SinkUriModal.tsx @@ -1,21 +1,20 @@ import type { FC } from 'react'; import { + Button, Form, FormGroup, FormHelperText, HelperText, HelperTextItem, + ModalBody, + ModalHeader, TextInputTypes, } from '@patternfly/react-core'; import type { FormikProps, FormikValues } from 'formik'; import { useTranslation } from 'react-i18next'; import FormSection from '@console/dev-console/src/components/import/section/FormSection'; -import { - ModalTitle, - ModalBody, - ModalSubmitFooter, -} from '@console/internal/components/factory/modal'; import { InputField, getFieldId } from '@console/shared'; +import { ModalFooterWithAlerts } from '@console/shared/src/components/modals/ModalFooterWithAlerts'; export interface SinkUriModalProps { cancel?: () => void; @@ -35,10 +34,14 @@ const SinkUriModal: FC = ({ const fieldId = getFieldId('sink-name', 'uri'); const dirty = values?.uri !== initialValues.uri; return ( -
-
- {t('knative-plugin~Edit URI')} - + <> + + + = ({ - - -
-
+ +
+ + + + + ); }; diff --git a/frontend/packages/knative-plugin/src/components/sink-uri/__tests__/SinkUriModal.spec.tsx b/frontend/packages/knative-plugin/src/components/sink-uri/__tests__/SinkUriModal.spec.tsx index 9019a17deec..dd7dc2051fc 100644 --- a/frontend/packages/knative-plugin/src/components/sink-uri/__tests__/SinkUriModal.spec.tsx +++ b/frontend/packages/knative-plugin/src/components/sink-uri/__tests__/SinkUriModal.spec.tsx @@ -3,10 +3,24 @@ import { render } from '@testing-library/react'; import { formikFormProps } from '@console/shared/src/test-utils/formik-props-utils'; import SinkUriModal from '../SinkUriModal'; -jest.mock('@console/internal/components/factory/modal', () => ({ - ModalTitle: jest.fn(() => null), - ModalBody: jest.fn(() => null), - ModalSubmitFooter: jest.fn(() => null), +jest.mock('@patternfly/react-core', () => ({ + ...jest.requireActual('@patternfly/react-core'), + ModalHeader: jest.fn(() => null), + ModalBody: jest.fn(({ children }) =>
{children}
), + Button: jest.fn(() => null), + Form: jest.fn(({ children, ...props }) =>
{children}
), + FormGroup: jest.fn(({ children }) =>
{children}
), + FormHelperText: jest.fn(() => null), + HelperText: jest.fn(() => null), + HelperTextItem: jest.fn(() => null), + TextInputTypes: { + text: 'text', + url: 'url', + }, +})); + +jest.mock('@console/shared/src/components/modals/ModalFooterWithAlerts', () => ({ + ModalFooterWithAlerts: jest.fn(({ children }) =>
{children}
), })); jest.mock('@console/shared', () => ({ @@ -19,17 +33,6 @@ jest.mock('@console/dev-console/src/components/import/section/FormSection', () = default: jest.fn(() => null), })); -jest.mock('@patternfly/react-core', () => ({ - Form: jest.fn(() => null), - FormGroup: jest.fn(() => null), - FormHelperText: jest.fn(() => null), - HelperText: jest.fn(() => null), - HelperTextItem: jest.fn(() => null), - TextInputTypes: { - url: 'url', - }, -})); - jest.mock('react-i18next', () => ({ useTranslation: () => ({ t: (key: string) => key, diff --git a/frontend/packages/knative-plugin/src/components/test-function/RequestPane.tsx b/frontend/packages/knative-plugin/src/components/test-function/RequestPane.tsx index aa330072299..e1693d558b2 100644 --- a/frontend/packages/knative-plugin/src/components/test-function/RequestPane.tsx +++ b/frontend/packages/knative-plugin/src/components/test-function/RequestPane.tsx @@ -87,58 +87,56 @@ const RequestPane: FC> = ({ setFieldValue, values }) = required /> -
- - - - - + + + + + -
- {showCustomHeaders || !checkCustomHeadersIsEmpty() ? ( - - ) : ( - - )} -
-
-
+
+ {showCustomHeaders || !checkCustomHeadersIsEmpty() ? ( + + ) : ( + + )} +
+
= ({ service, cancel, close }) => { - const svcName = service.data.metadata.name; - const svcNamespace = service.data.metadata.namespace; + const svcName = service.metadata.name; + const svcNamespace = service.metadata.namespace; const initialValues: TestFunctionFormikValues = { request: { format: InvokeFormat.CloudEvent, diff --git a/frontend/packages/knative-plugin/src/components/test-function/TestFunctionController.tsx b/frontend/packages/knative-plugin/src/components/test-function/TestFunctionController.tsx index a7b57f331e0..2510c41eca9 100644 --- a/frontend/packages/knative-plugin/src/components/test-function/TestFunctionController.tsx +++ b/frontend/packages/knative-plugin/src/components/test-function/TestFunctionController.tsx @@ -1,9 +1,9 @@ import type { FC } from 'react'; import { useCallback } from 'react'; +import { Modal } from '@patternfly/react-core'; 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 type { ModalComponentProps } from '@console/internal/components/factory'; -import { ModalWrapper } from '@console/internal/components/factory'; import { useK8sWatchResource } from '@console/internal/components/utils/k8s-watch-hook'; import { referenceForModel } from '@console/internal/module/k8s'; import { ServiceModel } from '../../models'; @@ -39,9 +39,9 @@ type Props = TestFunctionControllerProps & ModalComponentProps; const TestFunctionModalProvider: OverlayComponent = (props) => { return ( - + - + ); }; diff --git a/frontend/packages/knative-plugin/src/components/test-function/TestFunctionModal.scss b/frontend/packages/knative-plugin/src/components/test-function/TestFunctionModal.scss index 4581d3c734a..46423b057a8 100644 --- a/frontend/packages/knative-plugin/src/components/test-function/TestFunctionModal.scss +++ b/frontend/packages/knative-plugin/src/components/test-function/TestFunctionModal.scss @@ -13,12 +13,6 @@ padding-bottom: var(--pf-t--global--spacer--md); } -.kn-test-sf-modal { - &__body { - padding-bottom: var(--pf-t--global--font--size--3xl); - } -} - .kn-test-sf-modal__editor { @media screen and (max-width: 768px) { margin-top: var(--pf-t--global--font--size--4xl); @@ -27,14 +21,8 @@ } } -.kn-test-sf-modal-request { - &__advanced-settings { - margin-top: var(--pf-t--global--spacer--md); - margin-bottom: var(--pf-t--global--spacer--md); - } - &__custom-headers { - margin-top: var(--pf-t--global--spacer--xl); - } +.kn-test-sf-modal-request__custom-headers { + margin-top: var(--pf-t--global--spacer--xl); } .kn-test-sf-modal-response { @@ -53,7 +41,8 @@ .header-section { color: var(--pf-t--global--text--color--regular); - border: var(--pf-t--global--border--width--divider--default) solid var(--pf-t--global--border--color--default); + border: var(--pf-t--global--border--width--divider--default) solid + var(--pf-t--global--border--color--default); padding: var(--pf-t--global--spacer--md); } diff --git a/frontend/packages/knative-plugin/src/components/test-function/TestFunctionModal.tsx b/frontend/packages/knative-plugin/src/components/test-function/TestFunctionModal.tsx index 36371cdfd7a..49a1f38e143 100644 --- a/frontend/packages/knative-plugin/src/components/test-function/TestFunctionModal.tsx +++ b/frontend/packages/knative-plugin/src/components/test-function/TestFunctionModal.tsx @@ -1,7 +1,6 @@ import type { FC } from 'react'; import { useState } from 'react'; -import { Button, Title, TitleSizes } from '@patternfly/react-core'; -import { Modal, ModalVariant } from '@patternfly/react-core/deprecated'; +import { Button, Form, ModalHeader, ModalBody, ModalFooter } from '@patternfly/react-core'; import type { FormikProps, FormikValues } from 'formik'; import { useTranslation } from 'react-i18next'; import type { ModalComponentProps } from '@console/internal/components/factory/modal'; @@ -23,80 +22,82 @@ const TestFunctionModal: FC = (props) => { const { t } = useTranslation(); const { handleSubmit, cancel, close, isSubmitting } = props; const [currentView, setCurrentView] = useState(ModalPanel.Request); - const header = ( - <> - - {t(`knative-plugin~Test Serverless Function`)} - - - ); - const footer = ( + return ( <> - {currentView === ModalPanel.Request ? ( -
+ + { handleSubmit(); setCurrentView(ModalPanel.Response); }} + className="pf-v6-u-mr-md" > - -     - - - ) : ( - <> - -   - - - )} - - ); - - return ( - -
+ <> + {currentView === ModalPanel.Request ? ( + + ) : ( + + )} + + + + {currentView === ModalPanel.Request ? ( - + <> + + + ) : ( - + <> + + + )} -
-
+ + ); }; diff --git a/frontend/packages/knative-plugin/src/components/traffic-splitting/TrafficSplittingController.tsx b/frontend/packages/knative-plugin/src/components/traffic-splitting/TrafficSplittingController.tsx index 7ebd1ab9a13..b395834cea7 100644 --- a/frontend/packages/knative-plugin/src/components/traffic-splitting/TrafficSplittingController.tsx +++ b/frontend/packages/knative-plugin/src/components/traffic-splitting/TrafficSplittingController.tsx @@ -1,9 +1,9 @@ import type { FC } from 'react'; import { useCallback, useMemo } from 'react'; +import { Modal } from '@patternfly/react-core'; 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 type { ModalComponentProps } from '@console/internal/components/factory'; -import { ModalWrapper } from '@console/internal/components/factory'; import { useK8sWatchResources } from '@console/internal/components/utils/k8s-watch-hook'; import type { K8sResourceKind } from '@console/internal/module/k8s'; import { referenceForModel } from '@console/internal/module/k8s'; @@ -56,13 +56,13 @@ type Props = TrafficSplittingControllerProps & ModalComponentProps; const TrafficSplittingModalProvider: OverlayComponent = (props) => { return ( - + - + ); }; diff --git a/frontend/packages/knative-plugin/src/components/traffic-splitting/TrafficSplittingModal.tsx b/frontend/packages/knative-plugin/src/components/traffic-splitting/TrafficSplittingModal.tsx index 9a3b5d741d8..f55284dd3b7 100644 --- a/frontend/packages/knative-plugin/src/components/traffic-splitting/TrafficSplittingModal.tsx +++ b/frontend/packages/knative-plugin/src/components/traffic-splitting/TrafficSplittingModal.tsx @@ -1,12 +1,9 @@ import type { FC } from 'react'; +import { Button, Form, ModalBody, ModalHeader } from '@patternfly/react-core'; import type { FormikProps, FormikValues } from 'formik'; import { useTranslation } from 'react-i18next'; import type { ModalComponentProps } from '@console/internal/components/factory/modal'; -import { - ModalTitle, - ModalBody, - ModalSubmitFooter, -} from '@console/internal/components/factory/modal'; +import { ModalFooterWithAlerts } from '@console/shared/src/components/modals/ModalFooterWithAlerts'; import type { RevisionItems } from '../../utils/traffic-splitting-utils'; import TrafficSplittingFields from './TrafficSplittingFields'; @@ -20,23 +17,35 @@ const TrafficSplittingModal: FC = (props) => { const { t } = useTranslation(); const { handleSubmit, cancel, isSubmitting, status } = props; return ( -
- {t('knative-plugin~Set traffic distribution')} + <> + -

- {t('knative-plugin~Set traffic distribution for the Revisions of the Knative Service')} -

- + +

+ {t('knative-plugin~Set traffic distribution for the Revisions of the Knative Service')} +

+ +
- - + + + + + ); }; diff --git a/frontend/packages/knative-plugin/src/components/traffic-splitting/__tests__/TrafficSplittingModal.spec.tsx b/frontend/packages/knative-plugin/src/components/traffic-splitting/__tests__/TrafficSplittingModal.spec.tsx index 65433608d12..d2f8b55267e 100644 --- a/frontend/packages/knative-plugin/src/components/traffic-splitting/__tests__/TrafficSplittingModal.spec.tsx +++ b/frontend/packages/knative-plugin/src/components/traffic-splitting/__tests__/TrafficSplittingModal.spec.tsx @@ -7,10 +7,16 @@ import { } from '../../../utils/__mocks__/traffic-splitting-utils-mock'; import TrafficSplittingModal from '../TrafficSplittingModal'; -jest.mock('@console/internal/components/factory/modal', () => ({ - ModalTitle: jest.fn(() => null), - ModalBody: jest.fn(() => null), - ModalSubmitFooter: jest.fn(() => null), +jest.mock('@patternfly/react-core', () => ({ + ...jest.requireActual('@patternfly/react-core'), + ModalHeader: jest.fn(() => null), + ModalBody: jest.fn(({ children }) =>
{children}
), + Button: jest.fn(() => null), + Form: jest.fn(({ children, ...props }) =>
{children}
), +})); + +jest.mock('@console/shared/src/components/modals/ModalFooterWithAlerts', () => ({ + ModalFooterWithAlerts: jest.fn(({ children }) =>
{children}
), })); jest.mock('../TrafficSplittingFields', () => ({ @@ -42,7 +48,7 @@ describe('TrafficSplittingModal', () => { it('should render form with modal structure', () => { const { container } = render(); expect(container.querySelector('form')).toBeInTheDocument(); - expect(container.querySelector('form')).toHaveClass('modal-content'); + expect(container.querySelector('form')).toHaveAttribute('id', 'traffic-splitting-form'); }); it('should call handleSubmit on form submit', () => { diff --git a/frontend/packages/metal3-plugin/src/components/modals/PowerOffHostModal.tsx b/frontend/packages/metal3-plugin/src/components/modals/PowerOffHostModal.tsx index 23b9515a646..95519d76dd4 100644 --- a/frontend/packages/metal3-plugin/src/components/modals/PowerOffHostModal.tsx +++ b/frontend/packages/metal3-plugin/src/components/modals/PowerOffHostModal.tsx @@ -240,7 +240,7 @@ const PowerOffHostModal: OverlayComponent = (props) => { > {t('metal3-plugin~Power Off')} - 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 - - + + ); }; 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 }) => (