diff --git a/app/package-lock.json b/app/package-lock.json index 678a1f73eb..03409e99e9 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -12,7 +12,7 @@ "@formatjs/intl-pluralrules": "1.3.9", "@formatjs/intl-relativetimeformat": "4.5.1", "@formatjs/intl-utils": "1.6.0", - "@reportportal/ui-kit": "^0.0.1-alpha.26", + "@reportportal/ui-kit": "^0.0.1-alpha.38", "axios": "1.6.4", "c3": "0.7.20", "chart.js": "2.9.4", @@ -3677,9 +3677,9 @@ "integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==" }, "node_modules/@reportportal/ui-kit": { - "version": "0.0.1-alpha.26", - "resolved": "https://registry.npmjs.org/@reportportal/ui-kit/-/ui-kit-0.0.1-alpha.26.tgz", - "integrity": "sha512-RvwuUUjJrLFZEFHmFff29RfCowr13Z8Hr+ejzvp/nLEurM23poIcur/LGlBQGcwbxWb9epsFbeGLLP7Y+aj8zg==", + "version": "0.0.1-alpha.38", + "resolved": "https://registry.npmjs.org/@reportportal/ui-kit/-/ui-kit-0.0.1-alpha.38.tgz", + "integrity": "sha512-v3q8v1EkCmF4VY4QEpVesIzzUU6DZ5ZCX7r5G8H921IM0onO2awrdBS8Oqm0Dsc/Ww4eTKs6Wpn1sXJ1GllQ4A==", "dependencies": { "@floating-ui/react": "^0.26.16", "@floating-ui/react-dom": "^2.0.1", diff --git a/app/package.json b/app/package.json index e93d55af76..7a970ef390 100644 --- a/app/package.json +++ b/app/package.json @@ -25,7 +25,7 @@ "@formatjs/intl-pluralrules": "1.3.9", "@formatjs/intl-relativetimeformat": "4.5.1", "@formatjs/intl-utils": "1.6.0", - "@reportportal/ui-kit": "^0.0.1-alpha.26", + "@reportportal/ui-kit": "^0.0.1-alpha.38", "axios": "1.6.4", "c3": "0.7.20", "chart.js": "2.9.4", diff --git a/app/src/components/main/notification/notificationList/notificationList.jsx b/app/src/components/main/notification/notificationList/notificationList.jsx index 805283da54..bbeb6df4fc 100644 --- a/app/src/components/main/notification/notificationList/notificationList.jsx +++ b/app/src/components/main/notification/notificationList/notificationList.jsx @@ -20,11 +20,132 @@ import { CSSTransition, TransitionGroup } from 'react-transition-group'; import classNames from 'classnames/bind'; import { connect } from 'react-redux'; import { hideNotification } from 'controllers/notification'; -import { NotificationItem } from './notificationListItem'; +import { SystemAlert } from '@reportportal/ui-kit'; +import Parser from 'html-react-parser'; +import DOMPurify from 'dompurify'; +import { defineMessages, injectIntl } from 'react-intl'; import styles from './notificationList.scss'; const cx = classNames.bind(styles); +const messages = defineMessages({ + successLogin: { id: 'NotificationItem.successLogin', defaultMessage: 'Signed in successfully' }, + failureDefault: { + id: 'NotificationItem.failureDefault', + defaultMessage: 'An error occurred while connecting to server: {error}', + }, + infoLogout: { id: 'NotificationItem.infoLogout', defaultMessage: 'You have been logged out' }, + assignSuccess: { + id: 'ProjectsPage.assignSuccess', + defaultMessage: 'You have been assigned to the project', + }, + assignError: { + id: 'ProjectsPage.assignError', + defaultMessage: 'An error occurred during assigning to the project', + }, + unassignSuccess: { + id: 'ProjectsPage.unassignSuccess', + defaultMessage: 'You have been unassigned from the project', + }, + unassignError: { + id: 'ProjectsPage.unassignError', + defaultMessage: 'An error occurred during unassigning from the project', + }, + deleteError: { + id: 'ProjectsPage.deleteError', + defaultMessage: 'An error occurred during deleting the project', + }, + addDefectTypeSuccess: { + id: 'Project.addDefectTypeSuccess', + defaultMessage: 'Defect Type has been successfully created', + }, + updateDefectTypeSuccess: { + id: 'Project.updateDefectTypeSuccess', + defaultMessage: 'Defect Type has been successfully updated', + }, + deleteDefectTypeSuccess: { + id: 'Project.deleteDefectTypeSuccess', + defaultMessage: 'Defect Type has been deleted successfully', + }, + updateProjectNotificationsConfigurationSuccess: { + id: 'NotificationsTab.updateProjectNotificationsConfigurationSuccess', + defaultMessage: 'Notification settings were successfully updated!', + }, + addProjectSuccess: { + id: 'ProjectsPage.addProjectSuccess', + defaultMessage: "The project ''{name}'' was successfully created", + }, + projectExists: { + id: 'ProjectsPage.projectExists', + defaultMessage: "The project ''{name}'' is already exists", + }, + resetToGlobalSuccess: { + id: 'InstancesSection.resetToGlobalSuccess', + defaultMessage: 'Global integrations successfully applied', + }, + addIntegrationSuccess: { + id: 'InstancesSection.addIntegrationSuccess', + defaultMessage: 'Integration successfully added', + }, + removePluginSuccess: { + id: 'InstancesSection.removePluginSuccess', + defaultMessage: 'Plugin has been uninstalled successfully', + }, + updateIntegrationSuccess: { + id: 'IntegrationSettingsContainer.updateIntegrationSuccess', + defaultMessage: 'Integration successfully updated', + }, + removeIntegrationSuccess: { + id: 'ConnectionSection.removeIntegrationSuccess', + defaultMessage: 'Integration successfully deleted', + }, + addDashboardSuccess: { + id: 'DashboardPage.addDashboardSuccess', + defaultMessage: 'Dashboard has been added', + }, + deleteDashboardSuccess: { + id: 'DashboardPage.deleteDashboardSuccess', + defaultMessage: 'Dashboard has been deleted', + }, + addPatternSuccess: { + id: 'PatternAnalysis.addPatternSuccess', + defaultMessage: 'Pattern rule has been created', + }, + updatePatternSuccess: { + id: 'PatternAnalysis.updatePatternSuccess', + defaultMessage: 'Pattern rule updated successfully', + }, + deletePatternSuccess: { + id: 'PatternAnalysis.deletePatternSuccess', + defaultMessage: 'Pattern rule deleted successfully', + }, + updatePAStateSuccess: { + id: 'PatternAnalysis.updatePAStateSuccess', + defaultMessage: 'Pattern analysis settings were successfully updated', + }, + saveFilterSuccess: { + id: 'LaunchFiltersToolbar.saveFilterSuccess', + defaultMessage: 'Filter has been saved', + }, + updateFilterSuccess: { + id: 'LaunchFiltersToolbar.updateFilterSuccess', + defaultMessage: 'Filter has been updated', + }, + deleteTestItemSuccess: { + id: 'TestItemsPage.success', + defaultMessage: 'Item was deleted', + }, + deleteTestItemMultipleSuccess: { + id: 'TestItemsPage.successMultiple', + defaultMessage: 'Items were deleted', + }, + fetchApiKeysError: { + id: 'ProfilePage.apiKeys.fetchApiKeysError', + defaultMessage: 'An error occurred during fetch API keys', + }, +}); + +@injectIntl @connect( (state) => ({ notifications: state.notifications, @@ -37,15 +158,28 @@ export class NotificationList extends PureComponent { static propTypes = { notifications: PropTypes.arrayOf(PropTypes.object).isRequired, hideNotification: PropTypes.func.isRequired, + intl: PropTypes.object.isRequired, }; render() { + const { formatMessage } = this.props.intl; return (
- {this.props.notifications.map((m) => ( - - + {this.props.notifications.map(({ uid, type, messageId, values, message }) => ( + +
+ this.props.hideNotification(uid)} + className={cx('notification-item')} + /> +
))}
diff --git a/app/src/components/main/notification/notificationList/notificationList.scss b/app/src/components/main/notification/notificationList/notificationList.scss index c1db5cffca..040dd2719f 100644 --- a/app/src/components/main/notification/notificationList/notificationList.scss +++ b/app/src/components/main/notification/notificationList/notificationList.scss @@ -16,29 +16,53 @@ .notification-list { position: fixed; - bottom: 0; - left: 0; - right: 0; + bottom: 48px; + left: 50%; opacity: 0.8; + max-width: 600px; + transform: translateX(-50%); +} + +.notification-item-wrapper { + margin-top: 16px; + overflow: hidden; + opacity: 0; + max-height: 0; + min-height: 0; } :global { .notification-transition-enter { opacity: 0.01; - height: 0; + max-height: 0; + min-height: 0; + } + + .notification-transition-enter-done { + opacity: 1; + transform: translateY(0); + max-height: 80px; + min-height: 56px; } + .notification-transition-enter-active { opacity: 1; - height: 36px; + max-height: 80px; + min-height: 56px; transition: all 200ms ease-in; } + .notification-transition-exit { opacity: 1; - height: 36px; + max-height: 80px; + min-height: 56px; } + .notification-transition-exit-active { opacity: 0.01; - height: 0; + transform: translateY(20px); transition: all 700ms ease-in; + max-height: 0; + min-height: 0; } } diff --git a/app/src/components/main/notification/notificationList/notificationListItem/index.js b/app/src/components/main/notification/notificationList/notificationListItem/index.js deleted file mode 100644 index 4898baca96..0000000000 --- a/app/src/components/main/notification/notificationList/notificationListItem/index.js +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2019 EPAM Systems - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export { NotificationItem } from './notificationItem'; diff --git a/app/src/components/main/notification/notificationList/notificationListItem/notificationItem.jsx b/app/src/components/main/notification/notificationList/notificationListItem/notificationItem.jsx deleted file mode 100644 index 6ec6b30aca..0000000000 --- a/app/src/components/main/notification/notificationList/notificationListItem/notificationItem.jsx +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright 2019 EPAM Systems - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import React, { PureComponent } from 'react'; -import PropTypes from 'prop-types'; -import classNames from 'classnames/bind'; -import { defineMessages, injectIntl } from 'react-intl'; -import DOMPurify from 'dompurify'; -import Parser from 'html-react-parser'; -import { NOTIFICATION_TYPES } from 'controllers/notification/constants'; -import styles from './notificationItem.scss'; - -const cx = classNames.bind(styles); - -const messages = defineMessages({ - successLogin: { id: 'NotificationItem.successLogin', defaultMessage: 'Signed in successfully' }, - failureDefault: { - id: 'NotificationItem.failureDefault', - defaultMessage: 'An error occurred while connecting to server: {error}', - }, - infoLogout: { id: 'NotificationItem.infoLogout', defaultMessage: 'You have been logged out' }, - assignSuccess: { - id: 'ProjectsPage.assignSuccess', - defaultMessage: 'You have been assigned to the project', - }, - assignError: { - id: 'ProjectsPage.assignError', - defaultMessage: 'An error occurred during assigning to the project', - }, - unassignSuccess: { - id: 'ProjectsPage.unassignSuccess', - defaultMessage: 'You have been unassigned from the project', - }, - unassignError: { - id: 'ProjectsPage.unassignError', - defaultMessage: 'An error occurred during unassigning from the project', - }, - deleteError: { - id: 'ProjectsPage.deleteError', - defaultMessage: 'An error occurred during deleting the project', - }, - addDefectTypeSuccess: { - id: 'Project.addDefectTypeSuccess', - defaultMessage: 'Defect Type has been successfully created', - }, - updateDefectTypeSuccess: { - id: 'Project.updateDefectTypeSuccess', - defaultMessage: 'Defect Type has been successfully updated', - }, - deleteDefectTypeSuccess: { - id: 'Project.deleteDefectTypeSuccess', - defaultMessage: 'Defect Type has been deleted successfully', - }, - updateProjectNotificationsConfigurationSuccess: { - id: 'NotificationsTab.updateProjectNotificationsConfigurationSuccess', - defaultMessage: 'Notification settings were successfully updated!', - }, - addProjectSuccess: { - id: 'ProjectsPage.addProjectSuccess', - defaultMessage: "The project ''{name}'' was successfully created", - }, - projectExists: { - id: 'ProjectsPage.projectExists', - defaultMessage: "The project ''{name}'' is already exists", - }, - resetToGlobalSuccess: { - id: 'InstancesSection.resetToGlobalSuccess', - defaultMessage: 'Global integrations successfully applied', - }, - addIntegrationSuccess: { - id: 'InstancesSection.addIntegrationSuccess', - defaultMessage: 'Integration successfully added', - }, - removePluginSuccess: { - id: 'InstancesSection.removePluginSuccess', - defaultMessage: 'Plugin has been uninstalled successfully', - }, - updateIntegrationSuccess: { - id: 'IntegrationSettingsContainer.updateIntegrationSuccess', - defaultMessage: 'Integration successfully updated', - }, - removeIntegrationSuccess: { - id: 'ConnectionSection.removeIntegrationSuccess', - defaultMessage: 'Integration successfully deleted', - }, - addDashboardSuccess: { - id: 'DashboardPage.addDashboardSuccess', - defaultMessage: 'Dashboard has been added', - }, - deleteDashboardSuccess: { - id: 'DashboardPage.deleteDashboardSuccess', - defaultMessage: 'Dashboard has been deleted', - }, - addPatternSuccess: { - id: 'PatternAnalysis.addPatternSuccess', - defaultMessage: 'Pattern rule has been created', - }, - updatePatternSuccess: { - id: 'PatternAnalysis.updatePatternSuccess', - defaultMessage: 'Pattern rule updated successfully', - }, - deletePatternSuccess: { - id: 'PatternAnalysis.deletePatternSuccess', - defaultMessage: 'Pattern rule deleted successfully', - }, - updatePAStateSuccess: { - id: 'PatternAnalysis.updatePAStateSuccess', - defaultMessage: 'Pattern analysis settings were successfully updated', - }, - saveFilterSuccess: { - id: 'LaunchFiltersToolbar.saveFilterSuccess', - defaultMessage: 'Filter has been saved', - }, - updateFilterSuccess: { - id: 'LaunchFiltersToolbar.updateFilterSuccess', - defaultMessage: 'Filter has been updated', - }, - deleteTestItemSuccess: { - id: 'TestItemsPage.success', - defaultMessage: 'Item was deleted', - }, - deleteTestItemMultipleSuccess: { - id: 'TestItemsPage.successMultiple', - defaultMessage: 'Items were deleted', - }, - fetchApiKeysError: { - id: 'ProfilePage.apiKeys.fetchApiKeysError', - defaultMessage: 'An error occurred during fetch API keys', - }, -}); - -@injectIntl -export class NotificationItem extends PureComponent { - static propTypes = { - intl: PropTypes.object.isRequired, - uid: PropTypes.number.isRequired, - onMessageClick: PropTypes.func.isRequired, - message: PropTypes.string, - messageId: PropTypes.string, - type: PropTypes.oneOf([ - NOTIFICATION_TYPES.ERROR, - NOTIFICATION_TYPES.INFO, - NOTIFICATION_TYPES.SUCCESS, - ]), - values: PropTypes.object, - }; - static defaultProps = { - message: '', - messageId: '', - type: NOTIFICATION_TYPES.INFO, - values: {}, - }; - - messageClick = () => { - this.props.onMessageClick(this.props.uid); - }; - - render() { - const { - intl: { formatMessage }, - message, - type, - messageId, - values, - } = this.props; - - if (message === '' && messageId === '') { - return null; - } - return ( -
-
-

- {Parser( - DOMPurify.sanitize(messageId ? formatMessage(messages[messageId], values) : message), - )} -

-
-
- ); - } -} diff --git a/app/src/components/main/notification/notificationList/notificationListItem/notificationItem.scss b/app/src/components/main/notification/notificationList/notificationListItem/notificationItem.scss deleted file mode 100644 index 8a524c3766..0000000000 --- a/app/src/components/main/notification/notificationList/notificationListItem/notificationItem.scss +++ /dev/null @@ -1,43 +0,0 @@ -@use "sass:color"; -/*! - * Copyright 2019 EPAM Systems - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -.message-container { - overflow: hidden; - font-family: $FONT-REGULAR; - font-size: 14px; - line-height: 16px; - text-align: center; - color: $COLOR--white; - padding: 10px; - background: $COLOR--topaz; - text-shadow: 0 1px 1px color.adjust($COLOR--topaz, $lightness: -10%); - &.success { - background: $COLOR--dark-pastel-green; - text-shadow: 0 1px 1px color.adjust($COLOR--dark-pastel-green, $lightness: -10%); - } - &.error { - background: $COLOR--tomato; - text-shadow: 0 1px 1px color.adjust($COLOR--tomato, $lightness: -10%); - } - &.opacity-enter-active { - opacity: 1; - transition: opacity 5500ms ease-in; - } - &.opacity-leave-active { - transition: opacity 5300ms ease-in; - } -}