Skip to content

Commit 4cb8c92

Browse files
committed
Switch to PF4 toast notifications
1 parent 7715df2 commit 4cb8c92

File tree

6 files changed

+64
-22
lines changed

6 files changed

+64
-22
lines changed

src/actions/error.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export function extractErrorText (exception: Object): string {
1313
: (exception.statusText || 'UNKNOWN')
1414
}
1515

16-
export function failedExternalAction ({ message, messageDescriptor, exception, failedAction }: FailedExternalActionInputType): FailedExternalActionType {
16+
export function failedExternalAction ({ message, titleDescriptor, messageDescriptor, exception, failedAction }: FailedExternalActionInputType): FailedExternalActionType {
1717
if (exception) {
1818
message = message || extractErrorText(exception)
1919
message = customizeErrorMessage(message)
@@ -25,6 +25,7 @@ export function failedExternalAction ({ message, messageDescriptor, exception, f
2525
payload: {
2626
message,
2727
messageDescriptor,
28+
titleDescriptor,
2829
type,
2930
failedAction,
3031
},
@@ -34,8 +35,9 @@ export function failedExternalAction ({ message, messageDescriptor, exception, f
3435
return {
3536
type: FAILED_EXTERNAL_ACTION,
3637
payload: {
37-
messageDescriptor,
3838
message,
39+
messageDescriptor,
40+
titleDescriptor,
3941
failedAction,
4042
},
4143
}

src/actions/types.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export type MessageDescriptorType = {
3838
export type FailedExternalActionInputType = {
3939
message: string,
4040
messageDescriptor: ?MessageDescriptorType,
41+
titleDescriptor: ?MessageDescriptorType,
4142
exception?: Object,
4243
failedAction?: Object
4344
}
@@ -48,6 +49,7 @@ export type FailedExternalActionType = {
4849
message: string,
4950
failedAction?: Object,
5051
messageDescriptor: ?MessageDescriptorType,
52+
titleDescriptor: ?MessageDescriptorType,
5153
type?: number | 'ERROR'
5254
}
5355
}

src/components/ToastNotifications.js

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,68 @@ import React from 'react'
22
import PropTypes from 'prop-types'
33
import { connect } from 'react-redux'
44

5-
import { TimedToastNotification, ToastNotificationList } from 'patternfly-react'
5+
import { Alert, AlertGroup, AlertActionCloseButton } from '@patternfly/react-core'
66
import { setNotificationNotified } from '_/actions'
77
import { withMsg } from '_/intl'
8-
import { buildMessageFromRecord } from '_/helpers'
8+
import { buildMessageFromRecord, translate } from '_/helpers'
99

1010
import style from './sharedStyle.css'
1111

1212
function normalizeType (theType) {
1313
theType = String(theType).toLowerCase()
14-
const isExpected = ['error', 'warning', 'success', 'info', 'danger'].includes(theType)
15-
return isExpected ? theType : 'warning'
14+
// PF4 statuses
15+
if (['default', 'warning', 'success', 'info', 'danger'].includes(theType)) {
16+
return theType
17+
}
18+
19+
// 'error' (used in PF3) was replaced by 'danger'
20+
return theType === 'error' ? 'danger' : 'warning'
21+
}
22+
23+
function buildTitle ({ id, params } = {}, msg, type) {
24+
if (!id) {
25+
// no title provide - generate one based on type
26+
return mapTypeToTitle(msg, type)
27+
}
28+
return translate({ id, params, msg })
29+
}
30+
31+
function mapTypeToTitle (msg, type) {
32+
switch (type) {
33+
case 'warning':
34+
return msg.warning()
35+
case 'danger':
36+
return msg.error()
37+
case 'success':
38+
return msg.success()
39+
case 'info':
40+
default:
41+
return msg.info()
42+
}
1643
}
1744

1845
const ToastNotifications = ({ userMessages, onDismissNotification, msg }) => {
1946
return (
20-
<ToastNotificationList>
21-
{ userMessages.get('records').filter(r => !r.get('notified')).map(r => (
22-
<TimedToastNotification
47+
<AlertGroup isToast isLiveRegion>
48+
{ userMessages.get('records').toJS().filter(({ notified }) => !notified).map(r => (
49+
<Alert
50+
variant={normalizeType(r.type)}
2351
className={style['toast-margin-top']}
24-
type={normalizeType(r.get('type'))}
25-
onDismiss={() => onDismissNotification(r.get('id'))}
26-
key={r.get('time')}
52+
title={buildTitle(r.titleDescriptor, msg, normalizeType(r.type))}
53+
timeout={true}
54+
onTimeout={() => onDismissNotification(r.id)}
55+
actionClose={(
56+
<AlertActionCloseButton
57+
onClose={() => onDismissNotification(r.id)}
58+
/>
59+
)}
60+
key={r.time}
2761
>
28-
<span>
29-
{buildMessageFromRecord(r.toJS(), msg)}
30-
</span>
31-
</TimedToastNotification>
62+
{buildMessageFromRecord(r, msg)}
63+
</Alert>
3264
)
3365
)}
34-
</ToastNotificationList>
66+
</AlertGroup>
3567
)
3668
}
3769

src/intl/messages.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ export const messages: { [messageId: string]: MessageType } = {
343343
message: 'Not responding',
344344
description: 'VM is not responding. One of states of a virtual machine. Other are e.g. Up, Down, Powering-Up',
345345
},
346+
error: 'Error',
346347
errorWhileCreatingNewDisk: 'Error while creating new disk:',
347348
every30Seconds: 'Every 30 seconds',
348349
everyMinute: 'Every minute',
@@ -405,6 +406,7 @@ export const messages: { [messageId: string]: MessageType } = {
405406
htmlUnsupportedOvirtVersionFoundButVersionAtLeastRequired: '<strong>Unsupported {version} {productName} version</strong> found, but at least version {requiredVersion} is required.',
406407
icon: 'Icon',
407408
ifVmIsRunningClickToAccessItsGraphicsConsole: 'If the virtual machine is running, click the protocol name to access its Graphical Console.',
409+
info: 'Information',
408410
inPreview: 'In Preview',
409411
ieNotSupported: 'Internet Explorer is not a supported browser.',
410412
ipAddress: { message: 'IP Address', description: 'Label for IP addresses reported by VM guest agent' },
@@ -649,6 +651,7 @@ export const messages: { [messageId: string]: MessageType } = {
649651
message: '({size} {unit} free)',
650652
description: 'Show the amount of free space a storage domain has when rendered in a select list of storage domains',
651653
},
654+
success: 'Success',
652655
suspend: 'Suspend',
653656
suspendVm: 'Suspend the VM',
654657
suspendVmQuestion: 'Are you sure you want to Suspend the VM?',
@@ -783,6 +786,7 @@ export const messages: { [messageId: string]: MessageType } = {
783786
vncOptions: 'VNC Options',
784787
vnicProfile: 'VNIC Profile',
785788
vnicProfileEmpty: '<Empty>',
789+
warning: 'Warning',
786790
yes: 'Yes',
787791
youHaveNoAllowedVnicProfiles: 'You cannot create or edit NICs because you do not have permission to use any vNIC Profiles in the VM\'s Data Center.',
788792
}

src/reducers/userMessages.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@ import uniqueId from 'lodash/uniqueId'
1616

1717
import type { FailedExternalActionType } from '_/actions/types'
1818

19-
function addLogEntry ({ state, message, type = 'ERROR', failedAction, messageDescriptor }: any): any {
19+
function addLogEntry ({ state, message, type = 'ERROR', failedAction, messageDescriptor, titleDescriptor }: any): any {
2020
// TODO: use seq
2121
return state
2222
.update('records', records => records.unshift(Immutable.fromJS({
2323
id: uniqueId(),
2424
message,
2525
messageDescriptor,
26+
titleDescriptor,
2627
type,
2728
failedAction,
2829
time: Date.now(),
@@ -42,11 +43,12 @@ const initialState = Immutable.fromJS({
4243

4344
const userMessages: any = actionReducer(initialState, {
4445
// Log external action failures (i.e. AJAX calls) as user messages
45-
[FAILED_EXTERNAL_ACTION] (state: any, { payload: { message, messageDescriptor, type, failedAction } }: FailedExternalActionType): any {
46+
[FAILED_EXTERNAL_ACTION] (state: any, { payload: { message, messageDescriptor, titleDescriptor, type, failedAction } }: FailedExternalActionType): any {
4647
return addLogEntry({
4748
state,
4849
message,
4950
messageDescriptor,
51+
titleDescriptor,
5052
type,
5153
failedAction,
5254
})

src/sagas/utils.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,15 @@ export function* callExternalAction (method, action = {}, canBeMissing = false)
7777
yield put(checkTokenExpired())
7878
}
7979

80-
let messageDescriptor = shortErrorMessage({ action })
80+
let titleDescriptor = shortErrorMessage({ action })
8181
if (e.status === 0 && e.statusText === 'error') { // special case, mixing https and http
82-
messageDescriptor = { id: 'apiConnectionFailed' }
82+
titleDescriptor = { id: 'apiConnectionFailed' }
8383
e.statusText = 'Unable to connect to oVirt REST API. Please check URL and protocol (https).'
8484
}
8585

8686
yield put(failedExternalAction({
8787
exception: e,
88-
messageDescriptor,
88+
titleDescriptor,
8989
failedAction: action,
9090
}))
9191
}

0 commit comments

Comments
 (0)