From 58f99c89188b2b3be85465eea40ef77c6c2b0491 Mon Sep 17 00:00:00 2001 From: mabashian Date: Mon, 21 Jan 2019 13:13:09 -0500 Subject: [PATCH 1/6] Adds notification list to orgs --- __tests__/components/CapitalizeText.test.jsx | 16 + __tests__/components/DataListToolbar.test.jsx | 1 + .../components/NotificationList.test.jsx | 160 ++++++++ .../components/NotificationListItem.test.jsx | 103 +++++ .../Organization/OrganizationDetail.test.jsx | 1 + src/api.js | 30 ++ src/app.scss | 21 +- src/components/CapitalizeText.jsx | 14 + .../DataListToolbar/DataListToolbar.jsx | 52 +-- .../NotificationListItem.jsx | 88 +++++ .../NotificationsList/Notifications.list.jsx | 353 ++++++++++++++++++ src/pages/Organizations/Organizations.jsx | 5 +- .../screens/Organization/Organization.jsx | 8 +- .../Organization/OrganizationDetail.jsx | 76 ++-- .../screens/OrganizationsList.jsx | 22 +- 15 files changed, 870 insertions(+), 80 deletions(-) create mode 100644 __tests__/components/CapitalizeText.test.jsx create mode 100644 __tests__/components/NotificationList.test.jsx create mode 100644 __tests__/components/NotificationListItem.test.jsx create mode 100644 src/components/CapitalizeText.jsx create mode 100644 src/components/NotificationsList/NotificationListItem.jsx create mode 100644 src/components/NotificationsList/Notifications.list.jsx diff --git a/__tests__/components/CapitalizeText.test.jsx b/__tests__/components/CapitalizeText.test.jsx new file mode 100644 index 0000000000..30e3fcb7ce --- /dev/null +++ b/__tests__/components/CapitalizeText.test.jsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { mount } from 'enzyme'; +import CapitalizeText from '../../src/components/CapitalizeText'; + +describe('', () => { + let capitalizeTextWrapper; + + test('initially renders without crashing', () => { + capitalizeTextWrapper = mount( + + ); + expect(capitalizeTextWrapper.length).toBe(1); + expect(capitalizeTextWrapper.text()).toEqual('Foo'); + capitalizeTextWrapper.unmount(); + }); +}); diff --git a/__tests__/components/DataListToolbar.test.jsx b/__tests__/components/DataListToolbar.test.jsx index facc3b1128..958573e2f1 100644 --- a/__tests__/components/DataListToolbar.test.jsx +++ b/__tests__/components/DataListToolbar.test.jsx @@ -36,6 +36,7 @@ describe('', () => { onSearch={onSearch} onSort={onSort} onSelectAll={onSelectAll} + showSelectAll /> ); diff --git a/__tests__/components/NotificationList.test.jsx b/__tests__/components/NotificationList.test.jsx new file mode 100644 index 0000000000..bbe6a912dc --- /dev/null +++ b/__tests__/components/NotificationList.test.jsx @@ -0,0 +1,160 @@ +import React from 'react'; +import { mount } from 'enzyme'; +import { MemoryRouter } from 'react-router-dom'; +import { I18nProvider } from '@lingui/react'; +import Notifications from '../../src/components/NotificationsList/Notifications.list'; + +describe('', () => { + test('initially renders succesfully', () => { + mount( + + + + + + ); + }); + test('fetches notifications on mount', () => { + const spy = jest.spyOn(Notifications.prototype, 'fetchNotifications'); + mount( + + + + + + ); + expect(spy).toHaveBeenCalled(); + }); + test('toggle success calls post', () => { + const spy = jest.spyOn(Notifications.prototype, 'postToSuccess'); + const wrapper = mount( + + + + + + ).find('Notifications'); + wrapper.instance().toggleSuccess(1, true); + expect(spy).toHaveBeenCalledWith(1, true); + }); + test('post success makes request and updates state properly', async () => { + const postSuccessFn = jest.fn(); + const wrapper = mount( + + + + + + ).find('Notifications'); + wrapper.setState({ successTemplateIds: [44] }); + await wrapper.instance().postToSuccess(44, true); + expect(postSuccessFn).toHaveBeenCalledWith(1, { id: 44, disassociate: true }); + expect(wrapper.state('successTemplateIds')).not.toContain(44); + await wrapper.instance().postToSuccess(44, false); + expect(postSuccessFn).toHaveBeenCalledWith(1, { id: 44 }); + expect(wrapper.state('successTemplateIds')).toContain(44); + }); + test('toggle error calls post', () => { + const spy = jest.spyOn(Notifications.prototype, 'postToError'); + const wrapper = mount( + + + + + + ).find('Notifications'); + wrapper.instance().toggleError(1, true); + expect(spy).toHaveBeenCalledWith(1, true); + }); + test('post error makes request and updates state properly', async () => { + const postErrorFn = jest.fn(); + const wrapper = mount( + + + + + + ).find('Notifications'); + wrapper.setState({ errorTemplateIds: [44] }); + await wrapper.instance().postToError(44, true); + expect(postErrorFn).toHaveBeenCalledWith(1, { id: 44, disassociate: true }); + expect(wrapper.state('errorTemplateIds')).not.toContain(44); + await wrapper.instance().postToError(44, false); + expect(postErrorFn).toHaveBeenCalledWith(1, { id: 44 }); + expect(wrapper.state('errorTemplateIds')).toContain(44); + }); + test('fetchNotifications', async () => { + const mockQueryParams = { + page: 44, + page_size: 10, + order_by: 'name' + }; + const getNotificationsFn = jest.fn().mockResolvedValue({ + data: { + results: [ + { id: 1 }, + { id: 2 }, + { id: 3 } + ] + } + }); + const getSuccessFn = jest.fn().mockResolvedValue({ + data: { + results: [ + { id: 1 } + ] + } + }); + const getErrorFn = jest.fn().mockResolvedValue({ + data: { + results: [ + { id: 2 } + ] + } + }); + const wrapper = mount( + + + + + + ).find('Notifications'); + wrapper.instance().updateUrl = jest.fn(); + await wrapper.instance().fetchNotifications(mockQueryParams); + expect(getNotificationsFn).toHaveBeenCalledWith(1, mockQueryParams); + expect(getSuccessFn).toHaveBeenCalledWith(1, { + id__in: '1,2,3' + }); + expect(getErrorFn).toHaveBeenCalledWith(1, { + id__in: '1,2,3' + }); + expect(wrapper.state('successTemplateIds')).toContain(1); + expect(wrapper.state('errorTemplateIds')).toContain(2); + }); +}); diff --git a/__tests__/components/NotificationListItem.test.jsx b/__tests__/components/NotificationListItem.test.jsx new file mode 100644 index 0000000000..d184b0a28e --- /dev/null +++ b/__tests__/components/NotificationListItem.test.jsx @@ -0,0 +1,103 @@ +import React from 'react'; +import { mount } from 'enzyme'; +import { MemoryRouter } from 'react-router-dom'; +import { I18nProvider } from '@lingui/react'; +import NotificationListItem from '../../src/components/NotificationsList/NotificationListItem'; + +describe('', () => { + let wrapper; + + afterEach(() => { + if (wrapper) { + wrapper.unmount(); + wrapper = null; + } + }); + + test('initially renders succesfully', () => { + wrapper = mount( + + + + + + ); + expect(wrapper.length).toBe(1); + }); + + test('handles success click when toggle is on', () => { + const successToggleClickSpy = jest.spyOn(NotificationListItem.prototype, 'successToggleClick'); + const toggleSuccessPropFn = jest.fn(); + wrapper = mount( + + + + + + ); + wrapper.find('Switch').first().find('input').simulate('change'); + expect(successToggleClickSpy).toHaveBeenCalledWith(true); + expect(toggleSuccessPropFn).toHaveBeenCalledWith(9000, true); + }); + + test('handles success click when toggle is off', () => { + const successToggleClickSpy = jest.spyOn(NotificationListItem.prototype, 'successToggleClick'); + const toggleSuccessPropFn = jest.fn(); + wrapper = mount( + + + + + + ); + wrapper.find('Switch').first().find('input').simulate('change'); + expect(successToggleClickSpy).toHaveBeenCalledWith(false); + expect(toggleSuccessPropFn).toHaveBeenCalledWith(9000, false); + }); + + test('handles error click when toggle is on', () => { + const errorToggleClickSpy = jest.spyOn(NotificationListItem.prototype, 'errorToggleClick'); + const toggleErrorPropFn = jest.fn(); + wrapper = mount( + + + + + + ); + wrapper.find('Switch').at(1).find('input').simulate('change'); + expect(errorToggleClickSpy).toHaveBeenCalledWith(true); + expect(toggleErrorPropFn).toHaveBeenCalledWith(9000, true); + }); + + test('handles error click when toggle is off', () => { + const errorToggleClickSpy = jest.spyOn(NotificationListItem.prototype, 'errorToggleClick'); + const toggleErrorPropFn = jest.fn(); + wrapper = mount( + + + + + + ); + wrapper.find('Switch').at(1).find('input').simulate('change'); + expect(errorToggleClickSpy).toHaveBeenCalledWith(false); + expect(toggleErrorPropFn).toHaveBeenCalledWith(9000, false); + }); +}); diff --git a/__tests__/pages/Organizations/screens/Organization/OrganizationDetail.test.jsx b/__tests__/pages/Organizations/screens/Organization/OrganizationDetail.test.jsx index aaaa7adde4..7262ae85a9 100644 --- a/__tests__/pages/Organizations/screens/Organization/OrganizationDetail.test.jsx +++ b/__tests__/pages/Organizations/screens/Organization/OrganizationDetail.test.jsx @@ -12,6 +12,7 @@ describe('', () => { diff --git a/src/api.js b/src/api.js index ce915bd136..bc8821dce3 100644 --- a/src/api.js +++ b/src/api.js @@ -70,6 +70,36 @@ class APIClient { return this.http.get(endpoint); } + getOrganizationNotifications (id, params = {}) { + const endpoint = `${API_ORGANIZATIONS}${id}/notification_templates/`; + + return this.http.get(endpoint, { params }); + } + + getOrganizationNotificationSuccess (id, params = {}) { + const endpoint = `${API_ORGANIZATIONS}${id}/notification_templates_success/`; + + return this.http.get(endpoint, { params }); + } + + getOrganizationNotificationError (id, params = {}) { + const endpoint = `${API_ORGANIZATIONS}${id}/notification_templates_error/`; + + return this.http.get(endpoint, { params }); + } + + postOrganizationNotificationSuccess (id, data) { + const endpoint = `${API_ORGANIZATIONS}${id}/notification_templates_success/`; + + return this.http.post(endpoint, data); + } + + postOrganizationNotificationError (id, data) { + const endpoint = `${API_ORGANIZATIONS}${id}/notification_templates_error/`; + + return this.http.post(endpoint, data); + } + getInstanceGroups () { return this.http.get(API_INSTANCE_GROUPS); } diff --git a/src/app.scss b/src/app.scss index 5d2f72d701..b4b176f3d3 100644 --- a/src/app.scss +++ b/src/app.scss @@ -82,6 +82,10 @@ --pf-c-data-list__item--PaddingTop: 16px; --pf-c-data-list__item--PaddingBottom: 16px; + + .pf-c-badge:not(:last-child), .pf-c-switch:not(:last-child) { + margin-right: 18px; + } } .pf-c-data-list__item { @@ -107,10 +111,6 @@ margin-right: 8px; } -.pf-c-data-list__cell span { - margin-right: 18px; -} - // // about modal overrides // @@ -119,13 +119,6 @@ --pf-c-about-modal-box--MaxWidth: 63rem; } -.pf-c-list { - li { - list-style-type: none; - margin: 0; - padding: 0; - } -} .awx-lookup { min-height: 36px; @@ -157,6 +150,12 @@ .awx-c-list { border-top: 1px solid #d7d7d7; border-bottom: 1px solid #d7d7d7; + + li { + list-style-type: none; + margin: 0; + padding: 0; + } } // // pf modal overrides diff --git a/src/components/CapitalizeText.jsx b/src/components/CapitalizeText.jsx new file mode 100644 index 0000000000..9411f395e6 --- /dev/null +++ b/src/components/CapitalizeText.jsx @@ -0,0 +1,14 @@ +import React from 'react'; + +class CapitalizeText extends React.Component { + upperCaseFirstLetter = (string) => (typeof string === 'string' ? string.charAt(0).toUpperCase() + string.slice(1) : ''); + + render () { + const { text } = this.props; + return ( + this.upperCaseFirstLetter(text) + ); + } +} + +export default CapitalizeText; diff --git a/src/components/DataListToolbar/DataListToolbar.jsx b/src/components/DataListToolbar/DataListToolbar.jsx index 0936e7bdc8..8ea46641a8 100644 --- a/src/components/DataListToolbar/DataListToolbar.jsx +++ b/src/components/DataListToolbar/DataListToolbar.jsx @@ -106,7 +106,9 @@ class DataListToolbar extends React.Component { sortedColumnKey, sortOrder, addUrl, - showExpandCollapse + showExpandCollapse, + showDelete, + showSelectAll } = this.props; const { // isActionDropdownOpen, @@ -149,19 +151,19 @@ class DataListToolbar extends React.Component {
- - - - - - + + { showSelectAll && ( + + + + + + )}
@@ -248,17 +250,19 @@ class DataListToolbar extends React.Component { - - - + + + )} {addUrl && (
- {' '} - - {' '} + {notificationType}
diff --git a/src/components/NotificationsList/Notifications.list.jsx b/src/components/NotificationsList/Notifications.list.jsx index af6d2a9a61..83be6f2c5d 100644 --- a/src/components/NotificationsList/Notifications.list.jsx +++ b/src/components/NotificationsList/Notifications.list.jsx @@ -2,7 +2,7 @@ import React, { Component, Fragment } from 'react'; -import { Title, EmptyState, EmptyStateIcon } from '@patternfly/react-core'; +import { Title, EmptyState, EmptyStateIcon, EmptyStateBody } from '@patternfly/react-core'; import { CubesIcon } from '@patternfly/react-icons'; import { I18n, i18nMark } from '@lingui/react'; import { Trans, t } from '@lingui/macro'; @@ -289,8 +289,11 @@ class Notifications extends Component { - <Trans>NO NOTIFICATIONS HAVE BEEN CREATED</Trans> + <Trans>No Notifictions Found</Trans> + + Please add a notification template to populate this list + )} diff --git a/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx b/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx index 74c0c1286d..1c011d7c33 100644 --- a/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx +++ b/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx @@ -107,7 +107,7 @@ const OrganizationDetail = ({ )} - + deleteResourceView()} /> addResourceView()} /> From c97dfeb725aad5e07336d85374c29cefa88ff6b9 Mon Sep 17 00:00:00 2001 From: mabashian Date: Mon, 21 Jan 2019 15:46:11 -0500 Subject: [PATCH 4/6] Cleanup after change post... to create... --- .../Organizations/screens/Organization/OrganizationDetail.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx b/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx index 1c011d7c33..5d79c27e3f 100644 --- a/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx +++ b/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx @@ -59,8 +59,8 @@ const OrganizationDetail = ({ getNotifications={(id, reqParams) => api.getOrganizationNotifications(id, reqParams)} getSuccess={(id, reqParams) => api.getOrganizationNotificationSuccess(id, reqParams)} getError={(id, reqParams) => api.getOrganizationNotificationError(id, reqParams)} - postSuccess={(id, data) => api.postOrganizationNotificationSuccess(id, data)} - postError={(id, data) => api.postOrganizationNotificationError(id, data)} + postSuccess={(id, data) => api.createOrganizationNotificationSuccess(id, data)} + postError={(id, data) => api.createOrganizationNotificationError(id, data)} match={match} location={location} history={history} From 6c19d6ae4ebfe8de2dc1904065b173b51df45e4c Mon Sep 17 00:00:00 2001 From: mabashian Date: Wed, 23 Jan 2019 14:13:51 -0500 Subject: [PATCH 5/6] Removes unnecessary fragment elements. Fixes vertical alignment on notif row item. Bind notification list functions to constructor --- .../NotificationListItem.jsx | 2 +- .../NotificationsList/Notifications.list.jsx | 115 ++++++++++-------- .../Organization/OrganizationDetail.jsx | 22 ++-- 3 files changed, 74 insertions(+), 65 deletions(-) diff --git a/src/components/NotificationsList/NotificationListItem.jsx b/src/components/NotificationsList/NotificationListItem.jsx index 48229acd8b..caf95b9998 100644 --- a/src/components/NotificationsList/NotificationListItem.jsx +++ b/src/components/NotificationsList/NotificationListItem.jsx @@ -44,7 +44,7 @@ class NotificationListItem extends React.Component { return ( {({ i18n }) => ( -
  • +
  • )} - - {( - typeof noInitialResults !== 'undefined' - && !noInitialResults - && !loading - && !error - ) && ( - - - - {({ i18n }) => ( -
      - {results.map(o => ( - this.onSelect(o.id)} - errorTurnedOn={errorTemplateIds.includes(o.id)} - toggleError={this.toggleError} - successTurnedOn={successTemplateIds.includes(o.id)} - toggleSuccess={this.toggleSuccess} - /> - ))} -
    - )} -
    - -
    - )} - {loading ?
    loading...
    : ''} - {error ?
    error
    : ''} -
    + {( + typeof noInitialResults !== 'undefined' + && !noInitialResults + && !loading + && !error + ) && ( + + + + {({ i18n }) => ( +
      + {results.map(o => ( + this.onSelect(o.id)} + errorTurnedOn={errorTemplateIds.includes(o.id)} + toggleError={this.toggleError} + successTurnedOn={successTemplateIds.includes(o.id)} + toggleSuccess={this.toggleSuccess} + /> + ))} +
    + )} +
    + +
    + )} + {loading ?
    loading...
    : ''} + {error ?
    error
    : ''} ); } diff --git a/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx b/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx index 5d79c27e3f..54c8bc79a6 100644 --- a/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx +++ b/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx @@ -54,18 +54,16 @@ const OrganizationDetail = ({ switch (currentTab) { case 'notifications': relatedTemplate = ( - - api.getOrganizationNotifications(id, reqParams)} - getSuccess={(id, reqParams) => api.getOrganizationNotificationSuccess(id, reqParams)} - getError={(id, reqParams) => api.getOrganizationNotificationError(id, reqParams)} - postSuccess={(id, data) => api.createOrganizationNotificationSuccess(id, data)} - postError={(id, data) => api.createOrganizationNotificationError(id, data)} - match={match} - location={location} - history={history} - /> - + api.getOrganizationNotifications(id, reqParams)} + getSuccess={(id, reqParams) => api.getOrganizationNotificationSuccess(id, reqParams)} + getError={(id, reqParams) => api.getOrganizationNotificationError(id, reqParams)} + postSuccess={(id, data) => api.createOrganizationNotificationSuccess(id, data)} + postError={(id, data) => api.createOrganizationNotificationError(id, data)} + match={match} + location={location} + history={history} + /> ); break; default: From 47719776f225e74b9c8fb511c85e6800fcadd19f Mon Sep 17 00:00:00 2001 From: mabashian Date: Wed, 23 Jan 2019 16:52:14 -0500 Subject: [PATCH 6/6] More cleanup based on pr feedback. Adds org notif list page and tests --- .../components/NotificationList.test.jsx | 4 +- .../components/NotificationListItem.test.jsx | 32 ++++------ .../OrganizationNotifications.jsx | 58 +++++++++++++++++ .../NotificationListItem.jsx | 27 ++------ .../NotificationsList/Notifications.list.jsx | 21 +++---- .../Organization/OrganizationDetail.jsx | 10 +-- .../OrganizationNotifications.jsx | 63 +++++++++++++++++++ 7 files changed, 151 insertions(+), 64 deletions(-) create mode 100644 __tests__/pages/Organizations/screens/Organization/OrganizationNotifications.jsx create mode 100644 src/pages/Organizations/screens/Organization/OrganizationNotifications.jsx diff --git a/__tests__/components/NotificationList.test.jsx b/__tests__/components/NotificationList.test.jsx index bbe6a912dc..893f7a58a0 100644 --- a/__tests__/components/NotificationList.test.jsx +++ b/__tests__/components/NotificationList.test.jsx @@ -43,7 +43,7 @@ describe('', () => { ).find('Notifications'); - wrapper.instance().toggleSuccess(1, true); + wrapper.instance().toggleNotification(1, true, 'success'); expect(spy).toHaveBeenCalledWith(1, true); }); test('post success makes request and updates state properly', async () => { @@ -79,7 +79,7 @@ describe('', () => { ).find('Notifications'); - wrapper.instance().toggleError(1, true); + wrapper.instance().toggleNotification(1, true, 'error'); expect(spy).toHaveBeenCalledWith(1, true); }); test('post error makes request and updates state properly', async () => { diff --git a/__tests__/components/NotificationListItem.test.jsx b/__tests__/components/NotificationListItem.test.jsx index d184b0a28e..f162782338 100644 --- a/__tests__/components/NotificationListItem.test.jsx +++ b/__tests__/components/NotificationListItem.test.jsx @@ -26,78 +26,70 @@ describe('', () => { }); test('handles success click when toggle is on', () => { - const successToggleClickSpy = jest.spyOn(NotificationListItem.prototype, 'successToggleClick'); - const toggleSuccessPropFn = jest.fn(); + const toggleNotification = jest.fn(); wrapper = mount( ); wrapper.find('Switch').first().find('input').simulate('change'); - expect(successToggleClickSpy).toHaveBeenCalledWith(true); - expect(toggleSuccessPropFn).toHaveBeenCalledWith(9000, true); + expect(toggleNotification).toHaveBeenCalledWith(9000, true, 'success'); }); test('handles success click when toggle is off', () => { - const successToggleClickSpy = jest.spyOn(NotificationListItem.prototype, 'successToggleClick'); - const toggleSuccessPropFn = jest.fn(); + const toggleNotification = jest.fn(); wrapper = mount( ); wrapper.find('Switch').first().find('input').simulate('change'); - expect(successToggleClickSpy).toHaveBeenCalledWith(false); - expect(toggleSuccessPropFn).toHaveBeenCalledWith(9000, false); + expect(toggleNotification).toHaveBeenCalledWith(9000, false, 'success'); }); test('handles error click when toggle is on', () => { - const errorToggleClickSpy = jest.spyOn(NotificationListItem.prototype, 'errorToggleClick'); - const toggleErrorPropFn = jest.fn(); + const toggleNotification = jest.fn(); wrapper = mount( ); wrapper.find('Switch').at(1).find('input').simulate('change'); - expect(errorToggleClickSpy).toHaveBeenCalledWith(true); - expect(toggleErrorPropFn).toHaveBeenCalledWith(9000, true); + expect(toggleNotification).toHaveBeenCalledWith(9000, true, 'error'); }); test('handles error click when toggle is off', () => { - const errorToggleClickSpy = jest.spyOn(NotificationListItem.prototype, 'errorToggleClick'); - const toggleErrorPropFn = jest.fn(); + const toggleNotification = jest.fn(); wrapper = mount( ); wrapper.find('Switch').at(1).find('input').simulate('change'); - expect(errorToggleClickSpy).toHaveBeenCalledWith(false); - expect(toggleErrorPropFn).toHaveBeenCalledWith(9000, false); + expect(toggleNotification).toHaveBeenCalledWith(9000, false, 'error'); }); }); diff --git a/__tests__/pages/Organizations/screens/Organization/OrganizationNotifications.jsx b/__tests__/pages/Organizations/screens/Organization/OrganizationNotifications.jsx new file mode 100644 index 0000000000..9716eadf8a --- /dev/null +++ b/__tests__/pages/Organizations/screens/Organization/OrganizationNotifications.jsx @@ -0,0 +1,58 @@ +import React from 'react'; +import { mount } from 'enzyme'; +import { MemoryRouter } from 'react-router-dom'; +import OrganizationNotifications from '../../../../../src/pages/Organizations/screens/Organization/OrganizationNotifications'; + +describe('', () => { + test('initially renders succesfully', () => { + mount( + + + + ); + }); + test('handles api requests', () => { + const getOrganizationNotifications = jest.fn(); + const getOrganizationNotificationSuccess = jest.fn(); + const getOrganizationNotificationError = jest.fn(); + const createOrganizationNotificationSuccess = jest.fn(); + const createOrganizationNotificationError = jest.fn(); + const wrapper = mount( + + + + ).find('OrganizationNotifications'); + wrapper.instance().getOrgNotifications(1, { foo: 'bar' }); + expect(getOrganizationNotifications).toHaveBeenCalledWith(1, { foo: 'bar' }); + wrapper.instance().getOrgNotificationSuccess(1, { foo: 'bar' }); + expect(getOrganizationNotificationSuccess).toHaveBeenCalledWith(1, { foo: 'bar' }); + wrapper.instance().getOrgNotificationError(1, { foo: 'bar' }); + expect(getOrganizationNotificationError).toHaveBeenCalledWith(1, { foo: 'bar' }); + wrapper.instance().createOrgNotificationSuccess(1, { id: 2 }); + expect(createOrganizationNotificationSuccess).toHaveBeenCalledWith(1, { id: 2 }); + wrapper.instance().createOrgNotificationError(1, { id: 2 }); + expect(createOrganizationNotificationError).toHaveBeenCalledWith(1, { id: 2 }); + }); +}); diff --git a/src/components/NotificationsList/NotificationListItem.jsx b/src/components/NotificationsList/NotificationListItem.jsx index caf95b9998..9535a4c1e4 100644 --- a/src/components/NotificationsList/NotificationListItem.jsx +++ b/src/components/NotificationsList/NotificationListItem.jsx @@ -10,31 +10,15 @@ import { } from '@patternfly/react-core'; class NotificationListItem extends React.Component { - constructor (props) { - super(props); - this.errorToggleClick = this.errorToggleClick.bind(this); - this.successToggleClick = this.successToggleClick.bind(this); - } - - errorToggleClick (flag) { - const { itemId, toggleError } = this.props; - toggleError(itemId, flag); - } - - successToggleClick (flag) { - const { itemId, toggleSuccess } = this.props; - toggleSuccess(itemId, flag); - } - render () { const { itemId, name, notificationType, detailUrl, - parentBreadcrumb, successTurnedOn, - errorTurnedOn + errorTurnedOn, + toggleNotification } = this.props; const capText = { @@ -49,8 +33,7 @@ class NotificationListItem extends React.Component {
    {name} @@ -69,13 +52,13 @@ class NotificationListItem extends React.Component { this.successToggleClick(successTurnedOn)} + onChange={() => toggleNotification(itemId, successTurnedOn, 'success')} aria-label={i18n._(t`Notification success toggle`)} /> this.errorToggleClick(errorTurnedOn)} + onChange={() => toggleNotification(itemId, errorTurnedOn, 'error')} aria-label={i18n._(t`Notification failure toggle`)} />
    diff --git a/src/components/NotificationsList/Notifications.list.jsx b/src/components/NotificationsList/Notifications.list.jsx index 695b672c02..5b3cbb8635 100644 --- a/src/components/NotificationsList/Notifications.list.jsx +++ b/src/components/NotificationsList/Notifications.list.jsx @@ -56,8 +56,7 @@ class Notifications extends Component { this.onSetPage = this.onSetPage.bind(this); this.onSelectAll = this.onSelectAll.bind(this); this.onSelect = this.onSelect.bind(this); - this.toggleError = this.toggleError.bind(this); - this.toggleSuccess = this.toggleSuccess.bind(this); + this.toggleNotification = this.toggleNotification.bind(this); this.updateUrl = this.updateUrl.bind(this); this.postToError = this.postToError.bind(this); this.postToSuccess = this.postToSuccess.bind(this); @@ -131,12 +130,12 @@ class Notifications extends Component { } }; - toggleError = (id, isCurrentlyOn) => { - this.postToError(id, isCurrentlyOn); - }; - - toggleSuccess = (id, isCurrentlyOn) => { - this.postToSuccess(id, isCurrentlyOn); + toggleNotification = (id, isCurrentlyOn, status) => { + if (status === 'success') { + this.postToSuccess(id, isCurrentlyOn); + } else if (status === 'error') { + this.postToError(id, isCurrentlyOn); + } }; updateUrl (queryParams) { @@ -293,8 +292,6 @@ class Notifications extends Component { successTemplateIds, errorTemplateIds } = this.state; - const { match } = this.props; - const parentBreadcrumb = { name: i18nMark('Organizations'), url: match.url }; return ( @@ -335,13 +332,11 @@ class Notifications extends Component { name={o.name} notificationType={o.notification_type} detailUrl={`notifications/${o.id}`} - parentBreadcrumb={parentBreadcrumb} isSelected={selected.includes(o.id)} onSelect={() => this.onSelect(o.id)} + toggleNotification={this.toggleNotification} errorTurnedOn={errorTemplateIds.includes(o.id)} - toggleError={this.toggleError} successTurnedOn={successTemplateIds.includes(o.id)} - toggleSuccess={this.toggleSuccess} /> ))} diff --git a/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx b/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx index 54c8bc79a6..4c9b4727e7 100644 --- a/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx +++ b/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx @@ -12,7 +12,7 @@ import { Route } from 'react-router-dom'; -import NotificationsList from '../../../../components/NotificationsList/Notifications.list'; +import OrganizationNotifications from './OrganizationNotifications'; import Tab from '../../../../components/Tabs/Tab'; import Tabs from '../../../../components/Tabs/Tabs'; @@ -54,12 +54,8 @@ const OrganizationDetail = ({ switch (currentTab) { case 'notifications': relatedTemplate = ( - api.getOrganizationNotifications(id, reqParams)} - getSuccess={(id, reqParams) => api.getOrganizationNotificationSuccess(id, reqParams)} - getError={(id, reqParams) => api.getOrganizationNotificationError(id, reqParams)} - postSuccess={(id, data) => api.createOrganizationNotificationSuccess(id, data)} - postError={(id, data) => api.createOrganizationNotificationError(id, data)} + + ); + } +} + +export default OrganizationNotifications;