From aff159a11fc43cf928e7ce854f35ae3ef881f626 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Tue, 16 Apr 2019 14:27:40 +0200 Subject: [PATCH 1/4] add errordialog and test for errordialog --- .../__snapshots__/errordialog.js.snap | 341 ++++++++++++++++++ .../dialog/__tests__/errordialog.js | 96 +++++ gsa/src/web/components/dialog/errordialog.js | 83 +++++ 3 files changed, 520 insertions(+) create mode 100644 gsa/src/web/components/dialog/__tests__/__snapshots__/errordialog.js.snap create mode 100644 gsa/src/web/components/dialog/__tests__/errordialog.js create mode 100644 gsa/src/web/components/dialog/errordialog.js diff --git a/gsa/src/web/components/dialog/__tests__/__snapshots__/errordialog.js.snap b/gsa/src/web/components/dialog/__tests__/__snapshots__/errordialog.js.snap new file mode 100644 index 0000000000..acdf34e4eb --- /dev/null +++ b/gsa/src/web/components/dialog/__tests__/__snapshots__/errordialog.js.snap @@ -0,0 +1,341 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ErrorDialog component tests should render ErrorDialog with text and title 1`] = ` +.c1 { + position: relative; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + margin: 10% auto; + border: 0; + outline: 0; + width: 400px; + height: autopx; +} + +.c0 { + position: fixed; + font-family: Trebuchet MS,Tahoma,Verdana,Arial,sans-serif; + font-size: 1.1em; + top: 0; + right: 0; + bottom: 0; + left: 0; + margin: 0; + background: rgba(102,102,102,0.5); + z-index: 600; + -webkit-transition: opacity 1s ease-in; + transition: opacity 1s ease-in; + width: 100%; + height: 100%; +} + +.c2 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + height: inherit; + padding: 0; + background: #fff; + box-shadow: 5px 5px 10px #787878; + border-radius: 3px; + border: 1px solid #787878; +} + +.c4 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.c8 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-align-items: flex-start; + -webkit-box-align: flex-start; + -ms-flex-align: flex-start; + align-items: flex-start; +} + +.c11 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + -webkit-box-pack: end; + -webkit-justify-content: flex-end; + -ms-flex-pack: end; + justify-content: flex-end; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.c9 { + overflow: auto; + padding: 0 15px; + width: 100%; + height: 100%; +} + +.c7 { + overflow: hidden; + height: 100%; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + border: 1px solid #519032; + font-weight: bold; + font-size: 12px; + font-family: Verdana,sans-serif; + color: #519032; + cursor: pointer; + border-radius: 2px; + padding: 0; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; +} + +.c6:hover { + color: #fff; + background: #519032; +} + +.c5 { + height: 24px; + width: 24px; + line-height: 24px; +} + +.c5 * { + height: inherit; + width: inherit; +} + +.c3 { + padding: 5px 5px 5px 10px; + margin-bottom: 15px; + border-radius: 2px 2px 0 0; + border-bottom: 1px solid #787878; + color: #fff; + font-weight: bold; + background: #66c430; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + cursor: -webkit-grab; + cursor: -moz-grab; + cursor: grab; +} + +.c14 { + display: inline-block; + padding: 0 15px; + color: #393637; + text-align: center; + vertical-align: middle; + font-size: 11px; + font-weight: bold; + line-height: 30px; + -webkit-text-decoration: none; + text-decoration: none; + white-space: nowrap; + background-color: #fff; + border-radius: 2px; + border: 1px solid #aaaaaa; + cursor: pointer; + overflow: visible; + z-index: 1; +} + +.c14:focus, +.c14:hover { + border: 1px solid #393637; +} + +.c14:hover { + -webkit-text-decoration: none; + text-decoration: none; + background: #66c430; + font-weight: bold; + color: #fff; +} + +.c14[disabled] { + cursor: not-allowed; + opacity: 0.65; + box-shadow: none; +} + +.c14 img { + height: 32px; + width: 32px; + margin-top: 5px 10px 5px -10px; + vertical-align: middle; +} + +.c14:link { + -webkit-text-decoration: none; + text-decoration: none; + color: #393637; +} + +.c13 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.c12 { + border: 1px solid #787878; + color: #519032; + background: #87d050; +} + +.c12:hover { + color: #fff; + background: #519032; +} + +.c10 { + border-width: 1px 0 0 0; + border-style: solid; + border-color: #c8d3d9; + margin-top: 15px; + padding: 10px 20px 10px 20px; +} + + +
+
+
+ +
+
+
+
+ +`; diff --git a/gsa/src/web/components/dialog/__tests__/errordialog.js b/gsa/src/web/components/dialog/__tests__/errordialog.js new file mode 100644 index 0000000000..29188d01e9 --- /dev/null +++ b/gsa/src/web/components/dialog/__tests__/errordialog.js @@ -0,0 +1,96 @@ +/* Copyright (C) 2019 Greenbone Networks GmbH + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ +import React from 'react'; + +import {render, fireEvent} from 'web/utils/testing'; + +import ErrorDialog from '../errordialog'; +import {KeyCode} from 'gmp/utils/event'; + +describe('ErrorDialog component tests', () => { + test('should render ErrorDialog with text and title', () => { + const handleClose = jest.fn(); + + const {baseElement, getByTestId} = render( + , + ); + + expect(baseElement).toMatchSnapshot(); + const contentElement = getByTestId('errordialog-content'); + const titleElement = getByTestId('dialog-title-bar'); + expect(contentElement).toHaveTextContent('foo'); + expect(titleElement).toHaveTextContent('bar'); + }); + + test('should close ErrorDialog with close button', () => { + const handleClose = jest.fn(); + + const {getByTestId} = render( + , + ); + + const closeButton = getByTestId('dialog-title-close-button'); + fireEvent.click(closeButton); + expect(handleClose).toHaveBeenCalled(); + }); + + /* test('should close ErrorDialog with cancel button', () => { + const handleClose = jest.fn(); + const handleResumeClick = jest.fn(); + + const {baseElement} = render( + , + ); + + const buttons = baseElement.querySelectorAll('button'); + fireEvent.click(buttons[0]); + expect(handleClose).toHaveBeenCalled(); + }); */ + + test('should close ErrorDialog with resume button', () => { + const handleClose = jest.fn(); + + const {baseElement} = render( + , + ); + + const buttons = baseElement.querySelectorAll('button'); + fireEvent.click(buttons[0]); + expect(handleClose).toHaveBeenCalled(); + }); + + test('should close ErrorDialog on escape key', () => { + const handleClose = jest.fn(); + + const {getByRole} = render( + , + ); + + fireEvent.keyDown(getByRole('dialog'), { + key: 'Escape', + keyCode: KeyCode.ESC, + }); + + expect(handleClose).toHaveBeenCalled(); + }); +}); diff --git a/gsa/src/web/components/dialog/errordialog.js b/gsa/src/web/components/dialog/errordialog.js new file mode 100644 index 0000000000..04bed26df9 --- /dev/null +++ b/gsa/src/web/components/dialog/errordialog.js @@ -0,0 +1,83 @@ +/* Copyright (C) 2019 Greenbone Networks GmbH + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ +import React from 'react'; + +import _ from 'gmp/locale'; + +import PropTypes from 'web/utils/proptypes'; + +import Dialog from 'web/components/dialog/dialog'; +import DialogContent from 'web/components/dialog/content'; +import ScrollableContent from 'web/components/dialog/scrollablecontent'; +import DialogTitle from 'web/components/dialog/title'; +import DialogFooter from 'web/components/dialog/footer'; + +const DEFAULT_DIALOG_WIDTH = '400px'; + +const ErrorDialogContent = ({moveprops, text, title, buttonTitle, close}) => { + return ( + + + + {text} + + + + ); +}; + +ErrorDialogContent.propTypes = { + buttonTitle: PropTypes.string, + close: PropTypes.func.isRequired, + moveprops: PropTypes.object, + text: PropTypes.string, + title: PropTypes.string.isRequired, +}; + +const ErrorDialog = ({ + width = DEFAULT_DIALOG_WIDTH, + text, + title, + buttonTitle = _('OK'), + onClose, +}) => { + return ( + + {({close, moveProps}) => ( + + )} + + ); +}; + +ErrorDialog.propTypes = { + buttonTitle: PropTypes.string, + text: PropTypes.string, + title: PropTypes.string.isRequired, + width: PropTypes.string, + onClose: PropTypes.func.isRequired, +}; + +export default ErrorDialog; From 49a5ab5d97cee7bd20c50d73f6b5663ae6ec3ba0 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Tue, 16 Apr 2019 14:30:33 +0200 Subject: [PATCH 2/4] fix no error messages in trashcan --- gsa/src/web/pages/extras/trashcanpage.js | 48 ++++++++++++++++++++---- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/gsa/src/web/pages/extras/trashcanpage.js b/gsa/src/web/pages/extras/trashcanpage.js index 8f4089514c..deb8224b5a 100644 --- a/gsa/src/web/pages/extras/trashcanpage.js +++ b/gsa/src/web/pages/extras/trashcanpage.js @@ -27,7 +27,7 @@ import _ from 'gmp/locale'; import {isDefined} from 'gmp/utils/identity'; import ErrorBoundary from 'web/components/errorboundary/errorboundary'; -import ErrorContainer from 'web/components/errorboundary/errorcontainer'; +import ErrorDialog from 'web/components/dialog/errordialog'; import Button from 'web/components/form/button'; @@ -110,6 +110,7 @@ class Trashcan extends React.Component { this.handleEmpty = this.handleEmpty.bind(this); this.handleDelete = this.handleDelete.bind(this); this.handleRestore = this.handleRestore.bind(this); + this.handleErrorClose = this.handleErrorClose.bind(this); } componentDidMount() { @@ -142,7 +143,14 @@ class Trashcan extends React.Component { this.handleInteraction(); - gmp.trashcan.restore(entity).then(this.getTrash); + gmp.trashcan + .restore(entity) + .then(this.getTrash) + .catch(error => { + this.setState({ + error: error, + }); + }); } handleDelete(entity) { @@ -150,7 +158,14 @@ class Trashcan extends React.Component { this.handleInteraction(); - gmp.trashcan.delete(entity).then(this.getTrash); + gmp.trashcan + .delete(entity) + .then(this.getTrash) + .catch(error => { + this.setState({ + error: error, + }); + }); } handleEmpty() { @@ -158,7 +173,20 @@ class Trashcan extends React.Component { this.handleInteraction(); - gmp.trashcan.empty().then(this.getTrash); + gmp.trashcan + .empty() + .then(this.getTrash) + .catch(error => { + this.setState({ + error: error, + }); + }); + } + + handleErrorClose() { + this.setState({ + error: undefined, + }); } createContentRow(type, title, count) { @@ -265,10 +293,7 @@ class Trashcan extends React.Component { render() { const {error, trash} = this.state; - if (isDefined(error)) { - return {error.message}; - } - if (!isDefined(trash)) { + if (!isDefined(trash) && !isDefined(error)) { return ; } @@ -287,6 +312,13 @@ class Trashcan extends React.Component { + {error && ( + + )}
} title={_('Trashcan')} /> From 8fb3875cf1b3dea82cf30cb55c096bab773d9218 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Tue, 16 Apr 2019 14:38:01 +0200 Subject: [PATCH 3/4] update changelog --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 75558c74a9..e339c94c87 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,6 +8,7 @@ $ cd gsa && git checkout gsa-8.0 && git log ## gsa 8.0.1 (unreleased) + * Add errordialog to fix missing error messages in trashcan #1286 * Display current result, comparable result and diff between results for delta reports and their results in delta state "changed" #1284 * Fix New Target dialog contains value from Edit Target #1281 From 06d2702426dc1470644bd7ab8df7902dc2e11ccd Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Tue, 16 Apr 2019 14:58:37 +0200 Subject: [PATCH 4/4] apply requested changes --- .../components/dialog/__tests__/errordialog.js | 17 ----------------- gsa/src/web/pages/extras/trashcanpage.js | 2 +- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/gsa/src/web/components/dialog/__tests__/errordialog.js b/gsa/src/web/components/dialog/__tests__/errordialog.js index 29188d01e9..f44fc3a552 100644 --- a/gsa/src/web/components/dialog/__tests__/errordialog.js +++ b/gsa/src/web/components/dialog/__tests__/errordialog.js @@ -50,23 +50,6 @@ describe('ErrorDialog component tests', () => { expect(handleClose).toHaveBeenCalled(); }); - /* test('should close ErrorDialog with cancel button', () => { - const handleClose = jest.fn(); - const handleResumeClick = jest.fn(); - - const {baseElement} = render( - , - ); - - const buttons = baseElement.querySelectorAll('button'); - fireEvent.click(buttons[0]); - expect(handleClose).toHaveBeenCalled(); - }); */ - test('should close ErrorDialog with resume button', () => { const handleClose = jest.fn(); diff --git a/gsa/src/web/pages/extras/trashcanpage.js b/gsa/src/web/pages/extras/trashcanpage.js index deb8224b5a..50d231d8c6 100644 --- a/gsa/src/web/pages/extras/trashcanpage.js +++ b/gsa/src/web/pages/extras/trashcanpage.js @@ -315,7 +315,7 @@ class Trashcan extends React.Component { {error && ( )}