From e0ce85ae6f84f61ecb4e7173475089d9b3fad05f Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Tue, 4 Jun 2019 17:00:26 +0200 Subject: [PATCH 01/66] Add basic pages for policies and audits --- gsa/src/web/components/bar/menubar.js | 4 + gsa/src/web/pages/audits/actions.js | 95 ++ gsa/src/web/pages/audits/component.js | 1028 +++++++++++++++++ gsa/src/web/pages/audits/filterdialog.js | 131 +++ gsa/src/web/pages/audits/listpage.js | 180 +++ gsa/src/web/pages/audits/row.js | 185 +++ gsa/src/web/pages/audits/table.js | 124 ++ gsa/src/web/pages/policies/component.js | 628 ++++++++++ .../web/pages/policies/createauditdialog.js | 607 ++++++++++ gsa/src/web/pages/policies/header.js | 70 ++ gsa/src/web/pages/policies/listpage.js | 126 ++ gsa/src/web/pages/policies/row.js | 126 ++ gsa/src/web/pages/policies/table.js | 50 + gsa/src/web/routes.js | 6 + 14 files changed, 3360 insertions(+) create mode 100644 gsa/src/web/pages/audits/actions.js create mode 100644 gsa/src/web/pages/audits/component.js create mode 100644 gsa/src/web/pages/audits/filterdialog.js create mode 100644 gsa/src/web/pages/audits/listpage.js create mode 100644 gsa/src/web/pages/audits/row.js create mode 100644 gsa/src/web/pages/audits/table.js create mode 100644 gsa/src/web/pages/policies/component.js create mode 100644 gsa/src/web/pages/policies/createauditdialog.js create mode 100644 gsa/src/web/pages/policies/header.js create mode 100644 gsa/src/web/pages/policies/listpage.js create mode 100644 gsa/src/web/pages/policies/row.js create mode 100644 gsa/src/web/pages/policies/table.js diff --git a/gsa/src/web/components/bar/menubar.js b/gsa/src/web/components/bar/menubar.js index ed676a6d66..3ee89ff93c 100644 --- a/gsa/src/web/components/bar/menubar.js +++ b/gsa/src/web/components/bar/menubar.js @@ -149,6 +149,10 @@ const MenuBar = ({isLoggedIn, capabilities}) => { )} )} + + + + {capabilities.mayAccess('assets') && ( diff --git a/gsa/src/web/pages/audits/actions.js b/gsa/src/web/pages/audits/actions.js new file mode 100644 index 0000000000..62053c0a45 --- /dev/null +++ b/gsa/src/web/pages/audits/actions.js @@ -0,0 +1,95 @@ +/* Copyright (C) 2017-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 {isDefined} from 'gmp/utils/identity'; + +import IconDivider from 'web/components/layout/icondivider'; + +import ExportIcon from 'web/components/icon/exporticon'; + +import withEntitiesActions from 'web/entities/withEntitiesActions'; + +import CloneIcon from 'web/entity/icon/cloneicon'; +import EditIcon from 'web/entity/icon/editicon'; +import TrashIcon from 'web/entity/icon/trashicon'; + +import ImportReportIcon from 'web/pages/tasks/icons/importreporticon'; +import ResumeIcon from 'web/pages/tasks/icons/resumeicon'; +import ScheduleIcon from 'web/pages/tasks/icons/scheduleicon'; +import StartIcon from 'web/pages/tasks/icons/starticon'; +import StopIcon from 'web/pages/tasks/icons/stopicon'; + +import PropTypes from 'web/utils/proptypes'; + +const Actions = ({ + entity, + links, + onReportImportClick, + onTaskCloneClick, + onTaskDeleteClick, + onTaskDownloadClick, + onTaskEditClick, + onTaskResumeClick, + onTaskStartClick, + onTaskStopClick, +}) => ( + + {isDefined(entity.schedule) ? ( + + ) : ( + + )} + + + + + + + + + + + + {/* TODO: dowload greenbone compliance report button*/} + +); + +Actions.propTypes = { + entity: PropTypes.model.isRequired, + links: PropTypes.bool, + onReportImportClick: PropTypes.func.isRequired, + onTaskCloneClick: PropTypes.func.isRequired, + onTaskDeleteClick: PropTypes.func.isRequired, + onTaskDownloadClick: PropTypes.func.isRequired, + onTaskEditClick: PropTypes.func.isRequired, + onTaskResumeClick: PropTypes.func.isRequired, + onTaskStartClick: PropTypes.func.isRequired, + onTaskStopClick: PropTypes.func.isRequired, +}; + +export default withEntitiesActions(Actions); + +// vim: set ts=2 sw=2 tw=80: diff --git a/gsa/src/web/pages/audits/component.js b/gsa/src/web/pages/audits/component.js new file mode 100644 index 0000000000..42e98d50ac --- /dev/null +++ b/gsa/src/web/pages/audits/component.js @@ -0,0 +1,1028 @@ +/* Copyright (C) 2017-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 {connect} from 'react-redux'; + +import _ from 'gmp/locale'; + +import {ALL_FILTER} from 'gmp/models/filter'; + +import {NO_VALUE} from 'gmp/parser'; + +import {map} from 'gmp/utils/array'; +import {isDefined} from 'gmp/utils/identity'; +import {selectSaveId, hasId} from 'gmp/utils/id'; + +import date from 'gmp/models/date'; + +import {FULL_AND_FAST_SCAN_CONFIG_ID} from 'gmp/models/scanconfig'; + +import {OPENVAS_DEFAULT_SCANNER_ID} from 'gmp/models/scanner'; + +import { + loadEntities as loadAlerts, + selector as alertSelector, +} from 'web/store/entities/alerts'; + +import { + loadEntities as loadCredentials, + selector as credentialsSelector, +} from 'web/store/entities/credentials'; + +import { + loadEntities as loadScanConfigs, + selector as scanConfigsSelector, +} from 'web/store/entities/scanconfigs'; + +import { + loadEntities as loadScanners, + selector as scannerSelector, +} from 'web/store/entities/scanners'; + +import { + loadEntities as loadSchedules, + selector as scheduleSelector, +} from 'web/store/entities/schedules'; + +import { + loadEntities as loadTags, + selector as tagsSelector, +} from 'web/store/entities/tags'; + +import { + loadEntities as loadTargets, + selector as targetSelector, +} from 'web/store/entities/targets'; + +import {getTimezone} from 'web/store/usersettings/selectors'; + +import {loadUserSettingDefaults} from 'web/store/usersettings/defaults/actions'; +import {getUserSettingsDefaults} from 'web/store/usersettings/defaults/selectors'; + +import compose from 'web/utils/compose'; +import PropTypes from 'web/utils/proptypes'; +import withCapabilities from 'web/utils/withCapabilities'; +import withGmp from 'web/utils/withGmp'; +import {UNSET_VALUE} from 'web/utils/render'; + +import EntityComponent from 'web/entity/component'; + +import ImportReportDialog from 'web/pages/reports/importdialog'; + +/* import AdvancedTaskWizard from 'web/wizard/advancedtaskwizard'; +import ModifyTaskWizard from 'web/wizard/modifytaskwizard'; +import TaskWizard from 'web/wizard/taskwizard'; */ + +import ScheduleComponent from 'web/pages/schedules/component'; +import AlertComponent from 'web/pages/alerts/component'; +import TargetComponent from 'web/pages/targets/component'; + +import TaskDialog from 'web/pages/tasks/dialog'; +import ContainerTaskDialog from 'web/pages/tasks/containerdialog'; + +class TaskComponent extends React.Component { + constructor(...args) { + super(...args); + + this.state = { + // advancedTaskWizardVisible: false, + containerTaskDialogVisible: false, + // modifyTaskWizardVisible: false, + reportImportDialogVisible: false, + taskDialogVisible: false, + //taskWizardVisible: false, + }; + + const {gmp} = this.props; + + this.cmd = gmp.task; + + this.handleReportImport = this.handleReportImport.bind(this); + this.handleTaskResume = this.handleTaskResume.bind(this); + /*this.handleSaveAdvancedTaskWizard = this.handleSaveAdvancedTaskWizard.bind( + this, + );*/ + this.handleSaveTask = this.handleSaveTask.bind(this); + this.handleSaveContainerTask = this.handleSaveContainerTask.bind(this); + /*this.handleSaveModifyTaskWizard = this.handleSaveModifyTaskWizard.bind( + this, + );*/ + //this.handleSaveTaskWizard = this.handleSaveTaskWizard.bind(this); + this.handleTaskStart = this.handleTaskStart.bind(this); + this.handleTaskStop = this.handleTaskStop.bind(this); + //this.handleTaskWizardNewClick = this.handleTaskWizardNewClick.bind(this); + + //this.openAdvancedTaskWizard = this.openAdvancedTaskWizard.bind(this); + /*this.handleCloseAdvancedTaskWizard = this.handleCloseAdvancedTaskWizard.bind( + this, + );*/ + this.openContainerTaskDialog = this.openContainerTaskDialog.bind(this); + this.handleCloseContainerTaskDialog = this.handleCloseContainerTaskDialog.bind( + this, + ); + this.openReportImportDialog = this.openReportImportDialog.bind(this); + this.handleCloseReportImportDialog = this.handleCloseReportImportDialog.bind( + this, + ); + /*this.openModifyTaskWizard = this.openModifyTaskWizard.bind(this); + this.handleCloseModifyTaskWizard = this.handleCloseModifyTaskWizard.bind( + this, + );*/ + this.openStandardTaskDialog = this.openStandardTaskDialog.bind(this); + this.openTaskDialog = this.openTaskDialog.bind(this); + this.handleCloseTaskDialog = this.handleCloseTaskDialog.bind(this); + //this.openTaskWizard = this.openTaskWizard.bind(this); + //this.handleCloseTaskWizard = this.handleCloseTaskWizard.bind(this); + + this.handleAlertsChange = this.handleAlertsChange.bind(this); + this.handleTargetChange = this.handleTargetChange.bind(this); + this.handleScheduleChange = this.handleScheduleChange.bind(this); + + this.handleAlertCreated = this.handleAlertCreated.bind(this); + this.handleTargetCreated = this.handleTargetCreated.bind(this); + this.handleScheduleCreated = this.handleScheduleCreated.bind(this); + + this.handleInteraction = this.handleInteraction.bind(this); + + this.handleScanConfigChange = this.handleScanConfigChange.bind(this); + this.handleScannerChange = this.handleScannerChange.bind(this); + } + + componentDidMount() { + this.props.loadUserSettingsDefaults(); + } + + handleInteraction() { + const {onInteraction} = this.props; + if (isDefined(onInteraction)) { + onInteraction(); + } + } + + handleTargetChange(target_id) { + this.setState({target_id}); + } + + handleAlertsChange(alert_ids) { + this.setState({alert_ids}); + } + + handleScheduleChange(schedule_id) { + this.setState({schedule_id}); + } + + handleTaskStart(task) { + const {onStarted, onStartError} = this.props; + + this.handleInteraction(); + + return this.cmd.start(task).then(onStarted, onStartError); + } + + handleTaskStop(task) { + const {onStopped, onStopError} = this.props; + + this.handleInteraction(); + + return this.cmd.stop(task).then(onStopped, onStopError); + } + + handleTaskResume(task) { + const {onResumed, onResumeError} = this.props; + + this.handleInteraction(); + + return this.cmd.resume(task).then(onResumed, onResumeError); + } + + /* handleTaskWizardNewClick() { + this.openTaskDialog(); + this.closeTaskWizard(); + } */ + + handleAlertCreated(resp) { + const {data} = resp; + + this.props.loadAlerts(); + + this.setState(({alert_ids}) => ({alert_ids: [data.id, ...alert_ids]})); + } + + handleScheduleCreated(resp) { + const {data} = resp; + + this.props.loadSchedules(); + + this.setState({schedule_id: data.id}); + } + + handleTargetCreated(resp) { + const {data} = resp; + + this.props.loadTargets(); + + this.setState({target_id: data.id}); + } + + openContainerTaskDialog(task) { + this.setState({ + containerTaskDialogVisible: true, + task, + name: task ? task.name : _('Unnamed'), + comment: task ? task.comment : '', + id: task ? task.id : undefined, + in_assets: task ? task.in_assets : undefined, + auto_delete: task ? task.auto_delete : undefined, + auto_delete_data: task ? task.auto_delete_data : undefined, + title: task + ? _('Edit Container Task {{name}}', task) + : _('New Container Task'), + }); + this.handleInteraction(); + } + + closeContainerTaskDialog() { + this.setState({containerTaskDialogVisible: false}); + } + + handleCloseContainerTaskDialog() { + this.closeContainerTaskDialog(); + this.handleInteraction(); + } + + handleSaveContainerTask(data) { + this.handleInteraction(); + + if (isDefined(data.id)) { + const {onContainerSaved, onContainerSaveError} = this.props; + return this.cmd + .saveContainer(data) + .then(onContainerSaved, onContainerSaveError) + .then(() => this.closeContainerTaskDialog()); + } + + const {onContainerCreated, onContainerCreateError} = this.props; + return this.cmd + .createContainer(data) + .then(onContainerCreated, onContainerCreateError) + .then(() => this.closeContainerTaskDialog()); + } + + handleSaveTask({ + add_tag, + alert_ids, + alterable, + auto_delete, + auto_delete_data, + apply_overrides, + comment, + config_id, + hosts_ordering, + id, + in_assets, + min_qod, + max_checks, + max_hosts, + name, + scanner_id, + scanner_type, + schedule_id, + schedule_periods, + source_iface, + tag_id, + target_id, + task, + }) { + const {gmp} = this.props; + + this.handleInteraction(); + + if (isDefined(id)) { + // save edit part + if (isDefined(task) && !task.isChangeable()) { + // arguments need to be undefined if the task is not changeable + target_id = undefined; + scanner_id = undefined; + config_id = undefined; + } + const {onSaved, onSaveError} = this.props; + return gmp.task + .save({ + alert_ids, + alterable, + auto_delete, + auto_delete_data, + apply_overrides, + comment, + config_id, + hosts_ordering, + id, + in_assets, + max_checks, + max_hosts, + min_qod, + name, + scanner_id, + scanner_type, + schedule_id, + schedule_periods, + target_id, + source_iface, + }) + .then(onSaved, onSaveError) + .then(() => this.closeTaskDialog()); + } + + const {onCreated, onCreateError} = this.props; + return gmp.task + .create({ + add_tag, + alert_ids, + alterable, + apply_overrides, + auto_delete, + auto_delete_data, + comment, + config_id, + hosts_ordering, + in_assets, + max_checks, + max_hosts, + min_qod, + name, + scanner_type, + scanner_id, + schedule_id, + schedule_periods, + source_iface, + tag_id, + target_id, + }) + .then(onCreated, onCreateError) + .then(() => this.closeTaskDialog()); + } + + openTaskDialog(task) { + if (isDefined(task) && task.isContainer()) { + this.openContainerTaskDialog(task); + } else { + this.openStandardTaskDialog(task); + } + } + + closeTaskDialog() { + this.setState({taskDialogVisible: false}); + } + + handleCloseTaskDialog() { + this.closeTaskDialog(); + this.handleInteraction(); + } + + openStandardTaskDialog(task) { + const {capabilities} = this.props; + + this.props.loadAlerts(); + this.props.loadScanConfigs(); + this.props.loadScanners(); + this.props.loadSchedules(); + this.props.loadTargets(); + this.props.loadTags(); + + if (isDefined(task)) { + const canAccessSchedules = + capabilities.mayAccess('schedules') && isDefined(task.schedule); + const schedule_id = canAccessSchedules ? task.schedule.id : UNSET_VALUE; + const schedule_periods = canAccessSchedules + ? task.schedule_periods + : undefined; + + this.setState({ + taskDialogVisible: true, + alert_ids: map(task.alerts, alert => alert.id), + alterable: task.alterable, + apply_overrides: task.apply_overrides, + auto_delete: task.auto_delete, + auto_delete_data: task.auto_delete_data, + comment: task.comment, + config_id: hasId(task.config) ? task.config.id : undefined, + hosts_ordering: task.hosts_ordering, + id: task.id, + in_assets: task.in_assets, + max_checks: task.max_checks, + max_hosts: task.max_hosts, + min_qod: task.min_qod, + name: task.name, + scanner_id: hasId(task.scanner) ? task.scanner.id : undefined, + schedule_id, + schedule_periods, + source_iface: task.source_iface, + target_id: hasId(task.target) ? task.target.id : undefined, + task, + title: _('Edit Task {{name}}', task), + }); + } else { + const { + defaultAlertId, + defaultScanConfigId = FULL_AND_FAST_SCAN_CONFIG_ID, + defaultScannerId = OPENVAS_DEFAULT_SCANNER_ID, + defaultScheduleId, + defaultTargetId, + } = this.props; + + const alert_ids = isDefined(defaultAlertId) ? [defaultAlertId] : []; + + this.setState({ + taskDialogVisible: true, + alert_ids, + alterable: undefined, + apply_overrides: undefined, + auto_delete: undefined, + auto_delete_data: undefined, + comment: undefined, + config_id: defaultScanConfigId, + hosts_ordering: undefined, + id: undefined, + in_assets: undefined, + max_checks: undefined, + max_hosts: undefined, + min_qod: undefined, + name: undefined, + scanner_id: defaultScannerId, + schedule_id: defaultScheduleId, + schedule_periods: undefined, + source_iface: undefined, + target_id: defaultTargetId, + task: undefined, + title: _('New Task'), + }); + } + this.handleInteraction(); + } + + /* openTaskWizard() { + const { + gmp, + defaultAlertId, + defaultEsxiCredential, + defaultPortListId, + defaultScanConfigId, + defaultScannerId, + defaultSshCredential, + defaultSmbCredential, + } = this.props; + + gmp.wizard.task().then(response => { + const settings = response.data; + this.setState({ + taskWizardVisible: true, + hosts: settings.client_address, + port_list_id: defaultPortListId, + alert_id: defaultAlertId, + config_id: defaultScanConfigId, + ssh_credential: defaultSshCredential, + smb_credential: defaultSmbCredential, + esxi_credential: defaultEsxiCredential, + scanner_id: defaultScannerId, + }); + }); + this.handleInteraction(); + } + + closeTaskWizard() { + this.setState({taskWizardVisible: false}); + } + + handleCloseTaskWizard() { + this.closeTaskWizard(); + this.handleInteraction(); + } + + handleSaveTaskWizard(data) { + const {onTaskWizardSaved, onTaskWizardError, gmp} = this.props; + + this.handleInteraction(); + + return gmp.wizard + .runQuickFirstScan(data) + .then(onTaskWizardSaved, onTaskWizardError) + .then(() => this.closeTaskWizard()); + } + + openAdvancedTaskWizard() { + const { + gmp, + timezone, + defaultAlertId, + defaultEsxiCredential, + defaultPortListId, + defaultScanConfigId = FULL_AND_FAST_SCAN_CONFIG_ID, + defaultScannerId, + defaultSshCredential, + defaultSmbCredential, + } = this.props; + + this.props.loadCredentials(); + this.props.loadScanConfigs(); + + gmp.wizard.advancedTask().then(response => { + const settings = response.data; + + const now = date().tz(timezone); + + this.setState({ + advancedTaskWizardVisible: true, + task_name: _('New Quick Task'), + target_hosts: settings.client_address, + port_list_id: defaultPortListId, + alert_id: defaultAlertId, + config_id: defaultScanConfigId, + ssh_credential: defaultSshCredential, + smb_credential: defaultSmbCredential, + esxi_credential: defaultEsxiCredential, + scanner_id: defaultScannerId, + start_date: now, + start_minute: now.minutes(), + start_hour: now.hours(), + start_timezone: timezone, + }); + }); + this.handleInteraction(); + } + + closeAdvancedTaskWizard() { + this.setState({advancedTaskWizardVisible: false}); + } + + handleCloseAdvancedTaskWizard() { + this.closeAdvancedTaskWizard(); + this.handleInteraction(); + } + + handleSaveAdvancedTaskWizard(data) { + const { + gmp, + onAdvancedTaskWizardSaved, + onAdvancedTaskWizardError, + } = this.props; + + this.handleInteraction(); + + return gmp.wizard + .runQuickTask(data) + .then(onAdvancedTaskWizardSaved, onAdvancedTaskWizardError) + .then(() => this.closeAdvancedTaskWizard()); + } + + openModifyTaskWizard() { + const {gmp, timezone} = this.props; + + gmp.wizard.modifyTask().then(response => { + const settings = response.data; + const now = date().tz(timezone); + + this.setState({ + modifyTaskWizardVisible: true, + tasks: settings.tasks, + reschedule: NO_VALUE, + task_id: selectSaveId(settings.tasks), + start_date: now, + start_minute: now.minutes(), + start_hour: now.hours(), + start_timezone: timezone, + }); + }); + this.handleInteraction(); + } + + closeModifyTaskWizard() { + this.setState({modifyTaskWizardVisible: false}); + } + + handleCloseModifyTaskWizard() { + this.closeModifyTaskWizard(); + this.handleInteraction(); + } + + handleSaveModifyTaskWizard(data) { + const {onModifyTaskWizardSaved, onModifyTaskWizardError, gmp} = this.props; + + this.handleInteraction(); + + return gmp.wizard + .runModifyTask(data) + .then(onModifyTaskWizardSaved, onModifyTaskWizardError) + .then(() => this.closeModifyTaskWizard()); + } */ + + openReportImportDialog(task) { + this.setState({ + reportImportDialogVisible: true, + task_id: task.id, + tasks: [task], + }); + this.handleInteraction(); + } + + closeReportImportDialog() { + this.setState({reportImportDialogVisible: false}); + } + + handleCloseReportImportDialog() { + this.closeReportImportDialog(); + this.handleInteraction(); + } + + handleReportImport(data) { + const {onReportImported, onReportImportError, gmp} = this.props; + + this.handleInteraction(); + + return gmp.report + .import(data) + .then(onReportImported, onReportImportError) + .then(() => this.closeReportImportDialog()); + } + + handleScanConfigChange(config_id) { + this.setState({config_id}); + } + + handleScannerChange(scanner_id) { + this.setState({scanner_id}); + } + + render() { + const { + alerts, + credentials, + scanConfigs, + scanners, + schedules, + tags, + targets, + children, + onCloned, + onCloneError, + onCreated, + onCreateError, + onDeleted, + onDeleteError, + onDownloaded, + onDownloadError, + onInteraction, + } = this.props; + + const { + advancedTaskWizardVisible, + alert_id, + alert_ids, + alterable, + apply_overrides, + auto_delete, + auto_delete_data, + config_id, + containerTaskDialogVisible, + comment, + esxi_credential, + hosts, + hosts_ordering, + id, + in_assets, + max_checks, + max_hosts, + min_qod, + modifyTaskWizardVisible, + name, + port_list_id, + reportImportDialogVisible, + reschedule, + scanner_id, + schedule_id, + schedule_periods, + source_iface, + ssh_credential, + smb_credential, + start_date, + start_minute, + start_hour, + start_timezone, + tag_id, + target_id, + target_hosts, + task_id, + task_name, + task, + tasks, + taskDialogVisible, + taskWizardVisible, + title = _('Edit Task {{name}}', task), + } = this.state; + return ( + + + {other => ( + + {children({ + ...other, + create: this.openTaskDialog, + createcontainer: this.openContainerTaskDialog, + edit: this.openTaskDialog, + start: this.handleTaskStart, + stop: this.handleTaskStop, + resume: this.handleTaskResume, + reportimport: this.openReportImportDialog, + //advancedtaskwizard: this.openAdvancedTaskWizard, + //modifytaskwizard: this.openModifyTaskWizard, + //taskwizard: this.openTaskWizard, + })} + + {taskDialogVisible && ( + + {({create: createtarget}) => ( + + {({create: createalert}) => ( + + {({create: createschedule}) => ( + + )} + + )} + + )} + + )} + + )} + + + {containerTaskDialogVisible && ( + + )} + + {/* {taskWizardVisible && ( + + )} + + {advancedTaskWizardVisible && ( + + )} + + {modifyTaskWizardVisible && ( + + )} */} + + {reportImportDialogVisible && ( + + )} + + ); + } +} + +TaskComponent.propTypes = { + alerts: PropTypes.arrayOf(PropTypes.model), + capabilities: PropTypes.capabilities.isRequired, + children: PropTypes.func.isRequired, + credentials: PropTypes.arrayOf(PropTypes.model), + defaultAlertId: PropTypes.id, + defaultEsxiCredential: PropTypes.id, + defaultPortListId: PropTypes.id, + defaultScanConfigId: PropTypes.id, + defaultScannerId: PropTypes.id, + defaultScheduleId: PropTypes.id, + defaultSmbCredential: PropTypes.id, + defaultSshCredential: PropTypes.id, + defaultTargetId: PropTypes.id, + gmp: PropTypes.gmp.isRequired, + loadAlerts: PropTypes.func.isRequired, + loadCredentials: PropTypes.func.isRequired, + loadScanConfigs: PropTypes.func.isRequired, + loadScanners: PropTypes.func.isRequired, + loadSchedules: PropTypes.func.isRequired, + loadTags: PropTypes.func.isRequired, + loadTargets: PropTypes.func.isRequired, + loadUserSettingsDefaults: PropTypes.func.isRequired, + scanConfigs: PropTypes.arrayOf(PropTypes.model), + scanners: PropTypes.arrayOf(PropTypes.model), + schedules: PropTypes.arrayOf(PropTypes.model), + tags: PropTypes.arrayOf(PropTypes.model), + targets: PropTypes.arrayOf(PropTypes.model), + timezone: PropTypes.string.isRequired, + onAdvancedTaskWizardError: PropTypes.func, + onAdvancedTaskWizardSaved: PropTypes.func, + onCloneError: PropTypes.func, + onCloned: PropTypes.func, + onContainerCreateError: PropTypes.func, + onContainerCreated: PropTypes.func, + onContainerSaveError: PropTypes.func, + onContainerSaved: PropTypes.func, + onCreateError: PropTypes.func, + onCreated: PropTypes.func, + onDeleteError: PropTypes.func, + onDeleted: PropTypes.func, + onDownloadError: PropTypes.func, + onDownloaded: PropTypes.func, + onInteraction: PropTypes.func.isRequired, + onModifyTaskWizardError: PropTypes.func, + onModifyTaskWizardSaved: PropTypes.func, + onReportImportError: PropTypes.func, + onReportImported: PropTypes.func, + onResumeError: PropTypes.func, + onResumed: PropTypes.func, + onSaveError: PropTypes.func, + onSaved: PropTypes.func, + onStartError: PropTypes.func, + onStarted: PropTypes.func, + onStopError: PropTypes.func, + onStopped: PropTypes.func, + onTaskWizardError: PropTypes.func, + onTaskWizardSaved: PropTypes.func, +}; + +const TAGS_FILTER = ALL_FILTER.copy().set('resource_type', 'task'); + +const mapStateToProps = rootState => { + const alertSel = alertSelector(rootState); + const credentialsSel = credentialsSelector(rootState); + const userDefaults = getUserSettingsDefaults(rootState); + const scanConfigsSel = scanConfigsSelector(rootState); + const scannersSel = scannerSelector(rootState); + const scheduleSel = scheduleSelector(rootState); + const tagsSel = tagsSelector(rootState); + const targetSel = targetSelector(rootState); + return { + timezone: getTimezone(rootState), + alerts: alertSel.getEntities(ALL_FILTER), + credentials: credentialsSel.getEntities(ALL_FILTER), + defaultAlertId: userDefaults.getValueByName('defaultalert'), + defaultEsxiCredential: userDefaults.getValueByName('defaultesxicredential'), + defaultPortListId: userDefaults.getValueByName('defaultportlist'), + defaultScanConfigId: userDefaults.getValueByName( + 'defaultopenvasscanconfig', + ), + defaultScannerId: userDefaults.getValueByName('defaultopenvasscanner'), + defaultScheduleId: userDefaults.getValueByName('defaultschedule'), + defaultSshCredential: userDefaults.getValueByName('defaultsshcredential'), + defaultSmbCredential: userDefaults.getValueByName('defaultsmbcredential'), + defaultTargetId: userDefaults.getValueByName('defaulttarget'), + scanConfigs: scanConfigsSel.getEntities(ALL_FILTER), + scanners: scannersSel.getEntities(ALL_FILTER), + schedules: scheduleSel.getEntities(ALL_FILTER), + tags: tagsSel.getEntities(TAGS_FILTER), + targets: targetSel.getEntities(ALL_FILTER), + }; +}; + +const mapDispatchToProp = (dispatch, {gmp}) => ({ + loadAlerts: () => dispatch(loadAlerts(gmp)(ALL_FILTER)), + loadCredentials: () => dispatch(loadCredentials(gmp)(ALL_FILTER)), + loadScanConfigs: () => dispatch(loadScanConfigs(gmp)(ALL_FILTER)), + loadScanners: () => dispatch(loadScanners(gmp)(ALL_FILTER)), + loadSchedules: () => dispatch(loadSchedules(gmp)(ALL_FILTER)), + loadTags: () => dispatch(loadTags(gmp)(TAGS_FILTER)), + loadTargets: () => dispatch(loadTargets(gmp)(ALL_FILTER)), + loadUserSettingsDefaults: () => dispatch(loadUserSettingDefaults(gmp)()), +}); + +export default compose( + withGmp, + withCapabilities, + connect( + mapStateToProps, + mapDispatchToProp, + ), +)(TaskComponent); diff --git a/gsa/src/web/pages/audits/filterdialog.js b/gsa/src/web/pages/audits/filterdialog.js new file mode 100644 index 0000000000..9b75a5823d --- /dev/null +++ b/gsa/src/web/pages/audits/filterdialog.js @@ -0,0 +1,131 @@ +/* Copyright (C) 2016-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 {_l} from 'gmp/locale/lang'; + +import Layout from 'web/components/layout/layout'; + +import compose from 'web/utils/compose'; +import withCapabilities from 'web/utils/withCapabilities'; + +/* eslint-disable max-len */ + +import ApplyOverridesGroup from 'web/components/powerfilter/applyoverridesgroup'; +import CreateNamedFilterGroup from 'web/components/powerfilter/createnamedfiltergroup'; +import FilterStringGroup from 'web/components/powerfilter/filterstringgroup'; +import FirstResultGroup from 'web/components/powerfilter/firstresultgroup'; +import MinQodGroup from 'web/components/powerfilter/minqodgroup'; +import ResultsPerPageGroup from 'web/components/powerfilter/resultsperpagegroup'; +import SortByGroup from 'web/components/powerfilter/sortbygroup'; +import FilterDialogPropTypes from 'web/components/powerfilter/dialogproptypes'; +import withFilterDialog from 'web/components/powerfilter/withFilterDialog'; + +/* eslint-enable */ + +const SORT_FIELDS = [ + { + name: 'name', + displayName: _l('Name'), + }, + { + name: 'status', + displayName: _l('Status'), + }, + { + name: 'report', + displayName: _l('Reports: Total'), + }, + { + name: 'complianceStatus', + displayName: _l('Compliance Status'), + } /* + { + name: 'severity', + displayName: _l('Severity'), + }, + { + name: 'trend', + displayName: _l('Trend'), + }, */, +]; + +const TaskFilterDialogComponent = ({ + capabilities, + filter, + filterName, + filterstring, + saveNamedFilter, + onFilterStringChange, + onFilterValueChange, + onSortOrderChange, + onSortByChange, + onValueChange, +}) => { + if (!filter) { + return null; + } + + return ( + + + + + + + + + + + + + + {capabilities.mayCreate('filter') && ( + + )} + + ); +}; + +TaskFilterDialogComponent.propTypes = FilterDialogPropTypes; + +export default compose( + withCapabilities, + withFilterDialog(), +)(TaskFilterDialogComponent); + +// vim: set ts=2 sw=2 tw=80: diff --git a/gsa/src/web/pages/audits/listpage.js b/gsa/src/web/pages/audits/listpage.js new file mode 100644 index 0000000000..e904a20192 --- /dev/null +++ b/gsa/src/web/pages/audits/listpage.js @@ -0,0 +1,180 @@ +/* Copyright (C) 2016-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 {TASKS_FILTER_FILTER} from 'gmp/models/filter'; + +import PropTypes from 'web/utils/proptypes'; +import withCapabilities from 'web/utils/withCapabilities'; + +import { + loadEntities, + selector as entitiesSelector, +} from 'web/store/entities/tasks'; + +import EntitiesPage from 'web/entities/page'; +import withEntitiesContainer from 'web/entities/withEntitiesContainer'; + +import DashboardControls from 'web/components/dashboard/controls'; + +import ManualIcon from 'web/components/icon/manualicon'; + +import IconDivider from 'web/components/layout/icondivider'; + +import {DEFAULT_RELOAD_INTERVAL_ACTIVE} from 'web/utils/constants'; + +import NewIconMenu from 'web/pages/tasks/icons/newiconmenu'; + +import AuditComponent from './component'; +//import TaskDashboard, {TASK_DASHBOARD_ID} from './dashboard'; +import TaskFilterDialog from './filterdialog'; +import Table from './table'; +import TaskIcon from 'web/components/icon/taskicon'; + +const ToolBarIcons = withCapabilities(({capabilities}) => ( + + + +)); + +/* ToolBarIcons.propTypes = { + onAdvancedTaskWizardClick: PropTypes.func.isRequired, + onContainerTaskCreateClick: PropTypes.func.isRequired, + onModifyTaskWizardClick: PropTypes.func.isRequired, + onTaskCreateClick: PropTypes.func.isRequired, + onTaskWizardClick: PropTypes.func.isRequired, +}; */ + +const Page = ({ + filter, + onFilterChanged, + onInteraction, + onChanged, + onDownloaded, + onError, + ...props +}) => ( + + {({ + clone, + //create, + //createcontainer, + delete: delete_func, + download, + edit, + start, + stop, + resume, + reportimport, + //advancedtaskwizard, + //modifytaskwizard, + //taskwizard, + }) => ( + ( + + )} + dashboardControls={() => ( + + )} */ + filter={filter} + filterEditDialog={TaskFilterDialog} + filtersFilter={TASKS_FILTER_FILTER} + sectionIcon={} + table={Table} + title={_('Audits')} + toolBarIcons={ToolBarIcons} + //onAdvancedTaskWizardClick={advancedtaskwizard} + //onContainerTaskCreateClick={createcontainer} + onError={onError} + onFilterChanged={onFilterChanged} + onInteraction={onInteraction} + //onModifyTaskWizardClick={modifytaskwizard} + onReportImportClick={reportimport} + onTaskCloneClick={clone} + //onTaskCreateClick={create} + onTaskDeleteClick={delete_func} + onTaskDownloadClick={download} + onTaskEditClick={edit} + onTaskResumeClick={resume} + onTaskStartClick={start} + onTaskStopClick={stop} + //onTaskWizardClick={taskwizard} + /> + )} + +); + +Page.propTypes = { + filter: PropTypes.filter, + onChanged: PropTypes.func.isRequired, + onDownloaded: PropTypes.func.isRequired, + onError: PropTypes.func.isRequired, + onFilterChanged: PropTypes.func.isRequired, + onInteraction: PropTypes.func.isRequired, +}; + +const taskReloadInterval = ({entities = [], defaultReloadInterval}) => + entities.some(task => task.isActive()) + ? DEFAULT_RELOAD_INTERVAL_ACTIVE + : defaultReloadInterval; + +export default withEntitiesContainer('task', { + entitiesSelector, + loadEntities, + reloadInterval: taskReloadInterval, +})(Page); + +// vim: set ts=2 sw=2 tw=80: diff --git a/gsa/src/web/pages/audits/row.js b/gsa/src/web/pages/audits/row.js new file mode 100644 index 0000000000..aff35ba0e4 --- /dev/null +++ b/gsa/src/web/pages/audits/row.js @@ -0,0 +1,185 @@ +/* Copyright (C) 2017-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 {isDefined, isString} from 'gmp/utils/identity'; + +import PropTypes from 'web/utils/proptypes'; +import withUserName from 'web/utils/withUserName'; + +import {RowDetailsToggle} from 'web/entities/row'; + +import ObserverIcon from 'web/entity/icon/observericon'; + +import SeverityBar from 'web/components/bar/severitybar'; + +import Comment from 'web/components/comment/comment'; + +import DateTime from 'web/components/date/datetime'; + +import AlterableIcon from 'web/components/icon/alterableicon'; +import ProvideViewIcon from 'web/components/icon/provideviewicon'; +import SensorIcon from 'web/components/icon/sensoricon'; + +import IconDivider from 'web/components/layout/icondivider'; +import Layout from 'web/components/layout/layout'; + +import DetailsLink from 'web/components/link/detailslink'; +import Link from 'web/components/link/link'; + +import TableRow from 'web/components/table/row'; +import TableData from 'web/components/table/data'; + +import Actions from './actions'; +import TaskStatus from 'web/pages/tasks/status'; +//import Trend from './trend'; + +import {GMP_SCANNER_TYPE} from 'gmp/models/scanner'; + +const render_report = (report, links) => { + if (!isDefined(report)) { + return null; + } + return ( + + + + + + ); +}; + +const render_report_total = (entity, links) => { + if (entity.report_count.total <= 0) { + return null; + } + return ( + + + {entity.report_count.total} + + + ); +}; + +const Row = ({ + actionsComponent: ActionsComponent = Actions, + entity, + links = true, + username, + onToggleDetailsClick, + ...props +}) => { + const {scanner, observers} = entity; + + const obs = []; + if (isDefined(observers)) { + if (isString(observers)) { + obs.push(_('User {{name}}', {name: observers})); + } else { + if (isDefined(observers.role)) { + obs.push(_('Role {{name}}', {name: observers.role.name})); + } + if (isDefined(observers.group)) { + obs.push(_('Group {{name}}', {name: observers.group.name})); + } + } + } + return ( + + + + + {entity.name} + + + {entity.alterable === 1 && ( + + )} + {isDefined(scanner) && scanner.type === GMP_SCANNER_TYPE && ( + + )} + + {isDefined(observers) && observers.length > 0 && ( + + ) // TODO observer roles and groups + } + + + {entity.comment && ({entity.comment})} + + + + + {/* {render_report_total(entity, links)} */} + {render_report(entity.last_report, links)} + {/* + {!entity.isContainer() && isDefined(entity.last_report) && ( + + )} + + + {!entity.isContainer() && } + */} + + {/*TODO: Compliance Status Bar */} + + + + + ); +}; + +Row.propTypes = { + actionsComponent: PropTypes.component, + entity: PropTypes.model.isRequired, + links: PropTypes.bool, + username: PropTypes.string.isRequired, + onToggleDetailsClick: PropTypes.func.isRequired, +}; + +export default withUserName(Row); + +// vim: set ts=2 sw=2 tw=80: diff --git a/gsa/src/web/pages/audits/table.js b/gsa/src/web/pages/audits/table.js new file mode 100644 index 0000000000..3d36d906c0 --- /dev/null +++ b/gsa/src/web/pages/audits/table.js @@ -0,0 +1,124 @@ +/* Copyright (C) 2017-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 {_, _l} from 'gmp/locale/lang'; + +import PropTypes from 'web/utils/proptypes'; + +import {createEntitiesFooter} from 'web/entities/footer'; +import {withEntitiesHeader} from 'web/entities/header'; +import {createEntitiesTable} from 'web/entities/table'; +import withRowDetails from 'web/entities/withRowDetails'; + +import TableHead from 'web/components/table/head'; +import TableHeader from 'web/components/table/header'; +import TableRow from 'web/components/table/row'; + +import Row from './row'; +import TaskDetails from 'web/pages/tasks/details'; + +const Header = ({ + actionsColumn, + links = true, + sort = true, + currentSortBy, + currentSortDir, + onSortChange, +}) => { + const sortProps = { + currentSortBy, + currentSortDir, + sort, + onSortChange, + }; + return ( + + + + + {/* */} + + {/* + */} + {/* TODO: sort by compliance status*/} + + {actionsColumn} + + + ); +}; + +Header.propTypes = { + actionsColumn: PropTypes.element, + currentSortBy: PropTypes.string, + currentSortDir: PropTypes.string, + links: PropTypes.bool, + sort: PropTypes.bool, + onSortChange: PropTypes.func, +}; + +const actionsColumn = ( + +); + +export default createEntitiesTable({ + emptyTitle: _l('No Tasks available'), + row: Row, + rowDetails: withRowDetails('task', 10)(TaskDetails), + header: withEntitiesHeader(actionsColumn)(Header), + footer: createEntitiesFooter({ + span: 10, + trash: true, + download: 'tasks.xml', + }), +}); + +// vim: set ts=2 sw=2 tw=80: diff --git a/gsa/src/web/pages/policies/component.js b/gsa/src/web/pages/policies/component.js new file mode 100644 index 0000000000..d7e6301f39 --- /dev/null +++ b/gsa/src/web/pages/policies/component.js @@ -0,0 +1,628 @@ +/* Copyright (C) 2017-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 {forEach} from 'gmp/utils/array'; +import {isDefined} from 'gmp/utils/identity'; +import {isEmpty, shorten} from 'gmp/utils/string'; +import {selectSaveId} from 'gmp/utils/id'; + +import {parseYesNo, YES_VALUE, NO_VALUE} from 'gmp/parser'; + +import {ospScannersFilter} from 'gmp/models/scanner'; + +import PropTypes from 'web/utils/proptypes'; +import withGmp from 'web/utils/withGmp'; + +import EntityComponent from 'web/entity/component'; + +import EditConfigFamilyDialog from 'web/pages/scanconfigs/editconfigfamilydialog'; +import EditScanConfigDialog from 'web/pages/scanconfigs/editdialog'; +import EditNvtDetailsDialog from 'web/pages/scanconfigs/editnvtdetailsdialog'; +//import ImportDialog from './importdialog'; +import ScanConfigDialog from 'web/pages/scanconfigs/dialog'; +import AuditDialog from './createauditdialog'; + +import TaskComponent from 'web/pages/tasks/component'; + +class PolicyComponent extends React.Component { + constructor(...args) { + super(...args); + + this.state = { + //createConfigDialogVisible: false, + editConfigDialogVisible: false, + editConfigFamilyDialogVisible: false, + editNvtDetailsDialogVisible: false, + //importDialogVisible: false, + createAuditDialogVisible: false, + }; + + //this.handleImportConfig = this.handleImportConfig.bind(this); + this.handleSaveConfigFamily = this.handleSaveConfigFamily.bind(this); + this.handleSaveConfigNvt = this.handleSaveConfigNvt.bind(this); + //this.openCreateConfigDialog = this.openCreateConfigDialog.bind(this); + /*this.handleCloseCreateConfigDialog = this.handleCloseCreateConfigDialog.bind( + this, + );*/ + this.openEditConfigDialog = this.openEditConfigDialog.bind(this); + this.handleCloseEditConfigDialog = this.handleCloseEditConfigDialog.bind( + this, + ); + this.openEditConfigFamilyDialog = this.openEditConfigFamilyDialog.bind( + this, + ); + this.handleCloseEditConfigFamilyDialog = this.handleCloseEditConfigFamilyDialog.bind( + this, + ); + this.openEditNvtDetailsDialog = this.openEditNvtDetailsDialog.bind(this); + this.handleCloseEditNvtDetailsDialog = this.handleCloseEditNvtDetailsDialog.bind( + this, + ); + //this.openImportDialog = this.openImportDialog.bind(this); + //this.handleCloseImportDialog = this.handleCloseImportDialog.bind(this); + this.openCreateAuditDialog = this.openCreateAuditDialog.bind(this); + this.handleCloseCreateAuditDialog = this.handleCloseCreateAuditDialog.bind( + this, + ); + } + + openEditConfigDialog(config) { + Promise.all([ + this.loadEditScanConfigSettings(config), + this.loadScanners(), + ]).then(([scanConfigState, scannerState]) => { + this.setState({ + ...scannerState, + ...scanConfigState, + base: config.base, + editConfigDialogVisible: true, + title: _('Edit Scan Config {{name}}', {name: shorten(config.name)}), + }); + }); + + this.handleInteraction(); + } + + closeEditConfigDialog() { + this.setState({editConfigDialogVisible: false}); + } + + handleCloseEditConfigDialog() { + this.closeEditConfigDialog(); + this.handleInteraction(); + } + + /* openCreateConfigDialog() { + this.loadScanners().then(state => + this.setState({ + ...state, + createConfigDialogVisible: true, + }), + ); + + this.handleInteraction(); + } + + closeCreateConfigDialog() { + this.setState({createConfigDialogVisible: false}); + } + + handleCloseCreateConfigDialog() { + this.closeCreateConfigDialog(); + this.handleInteraction(); + } + + openImportDialog() { + this.setState({importDialogVisible: true}); + this.handleInteraction(); + } + + closeImportDialog() { + this.setState({importDialogVisible: false}); + } + + handleCloseImportDialog() { + this.closeImportDialog(); + this.handleInteraction(); + } + */ + + openCreateAuditDialog() { + this.loadScanners().then(state => + this.setState({ + ...state, + createAuditDialogVisible: true, + }), + ); + + this.handleInteraction(); + } + + closeCreateAuditDialog() { + this.setState({createAuditDialogVisible: false}); + } + + handleCloseCreateAuditDialog() { + this.closeCreateAuditDialog(); + this.handleInteraction(); + } + + //handleSaveAudit + + openEditConfigFamilyDialog({config, name}) { + this.loadEditScanConfigFamilySettings(config, name).then(state => { + this.setState({ + ...state, + config, + editConfigFamilyDialogVisible: true, + editConfigFamilyDialogTitle: _('Edit Scan Config Family {{name}}', { + name: shorten(name), + }), + }); + }); + this.handleInteraction(); + } + + closeEditConfigFamilyDialog() { + this.setState({editConfigFamilyDialogVisible: false}); + } + + handleCloseEditConfigFamilyDialog() { + this.closeEditConfigFamilyDialog(); + this.handleInteraction(); + } + + openEditNvtDetailsDialog({config, nvt}) { + this.loadEditScanConfigNvtSettings(config, nvt).then(state => { + this.setState({ + ...state, + config, + editNvtDetailsDialogVisible: true, + editNvtDetailsDialogTitle: _('Edit Scan Config NVT {{name}}', { + name: shorten(nvt.name), + }), + }); + }); + this.handleInteraction(); + } + + closeEditNvtDetailsDialog() { + this.setState({editNvtDetailsDialogVisible: false}); + } + + handleCloseEditNvtDetailsDialog() { + this.closeEditNvtDetailsDialog(); + this.handleInteraction(); + } + + /* handleImportConfig(data) { + const {gmp, onImported, onImportError} = this.props; + + this.handleInteraction(); + + return gmp.scanconfig + .import(data) + .then(onImported, onImportError) + .then(() => this.closeImportDialog()); + } */ + + handleSaveConfigFamily(data) { + const {gmp} = this.props; + + this.handleInteraction(); + + return gmp.scanconfig + .saveScanConfigFamily(data) + .then(() => { + return this.loadEditScanConfigSettings(data.config); + }) + .then(state => { + this.closeEditConfigFamilyDialog(); + this.setState({...state}); + }); + } + + handleSaveConfigNvt(values) { + const {gmp} = this.props; + + this.handleInteraction(); + + return gmp.scanconfig + .saveScanConfigNvt(values) + .then(response => { + // update nvt timeouts in nvt family dialog + this.loadEditScanConfigFamilySettings( + values.config, + values.family_name, + ).then(state => { + this.setState({state}); + }); + + // update nvt preference values in edit dialog + this.loadEditScanConfigSettings(values.config).then(state => { + this.setState({state}); + }); + }) + .then(() => this.closeEditNvtDetailsDialog()); + } + + handleInteraction() { + const {onInteraction} = this.props; + if (isDefined(onInteraction)) { + onInteraction(); + } + } + + loadScanners(dialog) { + const {gmp} = this.props; + + return gmp.scanners.getAll().then(response => { + let {data: scanners} = response; + scanners = scanners.filter(ospScannersFilter); + return { + scanners, + scanner_id: selectSaveId(scanners), + }; + }); + } + + loadEditScanConfigSettings(config) { + const {gmp} = this.props; + + return gmp.scanconfig.editScanConfigSettings(config).then(response => { + const {data} = response; + const {families, scanconfig} = data; + const trend = {}; + const select = {}; + + forEach(families, family => { + const {name} = family; + const config_family = scanconfig.families[name]; + + if (isDefined(config_family)) { + trend[name] = parseYesNo(config_family.trend); + select[name] = + config_family.nvts.count === family.max ? YES_VALUE : NO_VALUE; + } else { + trend[name] = NO_VALUE; + select[name] = NO_VALUE; + } + }); + + const scanner_preference_values = {}; + + forEach(scanconfig.preferences.scanner, preference => { + scanner_preference_values[preference.name] = preference.value; + }); + + const state = { + comment: scanconfig.comment, + id: config.id, + name: config.name, + config: scanconfig, + families, + trend, + select, + scanner_preference_values, + }; + return state; + }); + } + + loadEditScanConfigFamilySettings(config, name) { + const {gmp} = this.props; + const {select} = this.state; + + return gmp.scanconfig + .editScanConfigFamilySettings({ + id: config.id, + family_name: name, + config_name: config.name, + }) + .then(response => { + const {data} = response; + const {nvts} = data; + const selected = {}; + + if (select[name]) { + forEach(nvts, nvt => { + selected[nvt.oid] = YES_VALUE; + }); + } else { + forEach(nvts, nvt => { + selected[nvt.oid] = nvt.selected; + }); + } + + const state = { + config: data.config, + config_name: config.name, + family_name: name, + id: config.id, + nvts: data.nvts, + selected, + }; + + return state; + }); + } + + loadEditScanConfigNvtSettings(config, nvt) { + const {gmp} = this.props; + + return gmp.scanconfig + .editScanConfigNvtSettings({ + id: config.id, + oid: nvt.oid, + config_name: config.name, + name: nvt.name, + }) + .then(response => { + const {data} = response; + const preference_values = {}; + + forEach(data.nvt.preferences, pref => { + let {value, type} = pref; + + if (type === 'password' || type === 'file') { + value = undefined; + } + + preference_values[pref.name] = { + value, + type, + }; + }); + + const state = { + config: data.config, + config_name: data.config.name, + family_name: data.nvt.family, + id: data.config.id, + oid: data.nvt.oid, + manual_timeout: data.nvt.timeout, + nvt: data.nvt, + nvt_name: data.nvt.name, + preference_values, + timeout: isEmpty(data.nvt.timeout) ? '0' : '1', + }; + + return state; + }); + } + + render() { + const { + children, + onCloned, + onCloneError, + onCreated, + onCreateError, + onDeleted, + onDeleteError, + onDownloaded, + onDownloadError, + onInteraction, + onSaved, + onSaveError, + } = this.props; + + const { + base, + comment, + config, + config_name, + //createConfigDialogVisible, + createAuditDialogVisible, + editConfigDialogVisible, + editConfigFamilyDialogVisible, + editConfigFamilyDialogTitle, + editNvtDetailsDialogVisible, + editNvtDetailsDialogTitle, + families, + family_name, + id, + //importDialogVisible, + manual_timeout, + name, + nvt, + nvts, + preference_values, + scanner_id, + scanner_preference_values, + scanners, + select, + selected, + timeout, + title, + trend, + } = this.state; + + return ( + + + {({save, ...other}) => ( + + {children({ + ...other, + //create: this.openCreateConfigDialog, + create: this.openCreateAuditDialog, + edit: this.openEditConfigDialog, + import: this.openImportDialog, + })} + {/* {createConfigDialogVisible && ( + { + this.handleInteraction(); + return save(d).then(() => this.closeCreateConfigDialog()); + }} + /> + )} */} + {/* {createAuditDialogVisible && ( + { + this.handleInteraction(); + return save(d).then(() => this.closeCreateAuditDialog()); + }} + /> + )} */} + {createAuditDialogVisible && ( + + )} + {editConfigDialogVisible && ( + { + this.handleInteraction(); + return save(d).then(() => this.closeEditConfigDialog()); + }} + /> + )} + + )} + + {/* {importDialogVisible && ( + + )} */} + {editConfigFamilyDialogVisible && ( + + )} + {editNvtDetailsDialogVisible && ( + + )} + + ); + } +} + +PolicyComponent.propTypes = { + children: PropTypes.func.isRequired, + gmp: PropTypes.gmp.isRequired, + onCloneError: PropTypes.func, + onCloned: PropTypes.func, + onCreateError: PropTypes.func, + onCreated: PropTypes.func, + onDeleteError: PropTypes.func, + onDeleted: PropTypes.func, + onDownloadError: PropTypes.func, + onDownloaded: PropTypes.func, + onImportError: PropTypes.func, + onImported: PropTypes.func, + onInteraction: PropTypes.func.isRequired, + onSaveError: PropTypes.func, + onSaved: PropTypes.func, +}; + +//export default withGmp(PoliciesComponent); + +PolicyComponent = withGmp(PolicyComponent); + +const PolicyWithTaskComponent = ({ + onInteraction, + onTaskCreated, + onTaskCreateError, + ...props +}) => { + return ( + + {({create}) => ( + + )} + + ); +}; + +PolicyWithTaskComponent.propTypes = { + onInteraction: PropTypes.func.isRequired, + onTargetCreateError: PropTypes.func.isRequired, + onTargetCreated: PropTypes.func.isRequired, +}; + +export default PolicyWithTaskComponent; diff --git a/gsa/src/web/pages/policies/createauditdialog.js b/gsa/src/web/pages/policies/createauditdialog.js new file mode 100644 index 0000000000..d2079a8548 --- /dev/null +++ b/gsa/src/web/pages/policies/createauditdialog.js @@ -0,0 +1,607 @@ +/* Copyright (C) 2016-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 logger from 'gmp/log'; + +import {forEach, first} from 'gmp/utils/array'; +import {isDefined, isArray} from 'gmp/utils/identity'; +import {selectSaveId} from 'gmp/utils/id'; + +import {NO_VALUE, YES_VALUE} from 'gmp/parser'; + +import { + AUTO_DELETE_KEEP_DEFAULT_VALUE, + HOSTS_ORDERING_SEQUENTIAL, + AUTO_DELETE_NO, +} from 'gmp/models/task'; + +import { + OPENVAS_SCANNER_TYPE, + OSP_SCANNER_TYPE, + GMP_SCANNER_TYPE, + OPENVAS_DEFAULT_SCANNER_ID, +} from 'gmp/models/scanner'; + +import { + FULL_AND_FAST_SCAN_CONFIG_ID, + OPENVAS_SCAN_CONFIG_TYPE, + OSP_SCAN_CONFIG_TYPE, + filterEmptyScanConfig, +} from 'gmp/models/scanconfig'; + +import PropTypes from 'web/utils/proptypes'; +import withCapabilities from 'web/utils/withCapabilities'; +import {renderSelectItems, UNSET_VALUE} from 'web/utils/render'; + +import SaveDialog from 'web/components/dialog/savedialog'; + +import MultiSelect from 'web/components/form/multiselect'; +import Select from 'web/components/form/select'; +import Spinner from 'web/components/form/spinner'; +import FormGroup from 'web/components/form/formgroup'; +import Checkbox from 'web/components/form/checkbox'; +import YesNoRadio from 'web/components/form/yesnoradio'; +import TextField from 'web/components/form/textfield'; + +import NewIcon from 'web/components/icon/newicon'; + +import Divider from 'web/components/layout/divider'; +import Layout from 'web/components/layout/layout'; + +import AddResultsToAssetsGroup from 'web/pages/tasks/addresultstoassetsgroup'; +import AutoDeleteReportsGroup from 'web/pages/tasks/autodeletereportsgroup'; + +const log = logger.getLogger('web.tasks.dialog'); + +const sort_scan_configs = (scan_configs = []) => { + const sorted_scan_configs = { + [OPENVAS_SCAN_CONFIG_TYPE]: [], + [OSP_SCAN_CONFIG_TYPE]: [], + }; + + scan_configs = scan_configs.filter(filterEmptyScanConfig); + + forEach(scan_configs, config => { + const type = config.scan_config_type; + if (!isArray(sorted_scan_configs[type])) { + sorted_scan_configs[type] = []; + } + sorted_scan_configs[type].push(config); + }); + return sorted_scan_configs; +}; + +const get_scanner = (scanners, scanner_id) => { + if (!isDefined(scanners)) { + return undefined; + } + + return scanners.find(sc => { + return sc.id === scanner_id; + }); +}; + +class ScannerSelect extends React.Component { + constructor(...args) { + super(...args); + + this.handleScannerChange = this.handleScannerChange.bind(this); + } + + handleScannerChange(value, name) { + const { + scanners, + scanConfigs, + onScanConfigChange, + onScannerChange, + } = this.props; + let config_id; + + const scanner = get_scanner(scanners, value); + const scanner_type = isDefined(scanner) ? scanner.scannerType : undefined; + + if ( + scanner_type === OPENVAS_SCANNER_TYPE || + scanner_type === GMP_SCANNER_TYPE + ) { + config_id = selectSaveId( + scanConfigs[OPENVAS_SCAN_CONFIG_TYPE], + FULL_AND_FAST_SCAN_CONFIG_ID, + ); + } else if (scanner_type === OSP_SCANNER_TYPE) { + config_id = selectSaveId(scanConfigs[OSP_SCAN_CONFIG_TYPE], UNSET_VALUE); + } else { + config_id = UNSET_VALUE; + } + + log.debug('on scanner change', value, config_id, scanner); + + if (isDefined(onScannerChange)) { + onScannerChange(value); + } + if (isDefined(onScanConfigChange)) { + onScanConfigChange(config_id); + } + } + + render() { + const {changeTask, scannerId, scanners} = this.props; + return ( + + + {change_task && ( + + + + )} + + + + {capabilities.mayOp('get_alerts') && ( + + + + + + + + + )} + + {capabilities.mayOp('get_schedules') && ( + + + + + + + + + + + )} + + {capabilities.mayAccess('tags') && + capabilities.mayCreate('tag') && + showTagSelection && ( + + + + + - - ); - } -} - -ScannerSelect.propTypes = { - changeTask: PropTypes.bool.isRequired, - scanConfigs: PropTypes.shape({ - [OPENVAS_SCANNER_TYPE]: PropTypes.array, - [OSP_SCANNER_TYPE]: PropTypes.array, - }), - scannerId: PropTypes.id.isRequired, - scanners: PropTypes.array.isRequired, - onScanConfigChange: PropTypes.func.isRequired, - onScannerChange: PropTypes.func.isRequired, -}; - const DEFAULT_MAX_CHECKS = 4; const DEFAULT_MAX_HOSTS = 20; const DEFAULT_MIN_QOD = 70; -const TaskDialog = ({ +const CreateAuditDialog = ({ add_tag = NO_VALUE, alert_ids = [], alerts = [], @@ -187,6 +109,7 @@ const TaskDialog = ({ capabilities, comment = '', config_id = FULL_AND_FAST_SCAN_CONFIG_ID, + //config_id = scan_configs[0].id, hosts_ordering = HOSTS_ORDERING_SEQUENTIAL, in_assets = YES_VALUE, max_checks = DEFAULT_MAX_CHECKS, @@ -198,7 +121,7 @@ const TaskDialog = ({ scanners = [ { id: OPENVAS_DEFAULT_SCANNER_ID, - scanner_type: OPENVAS_SCANNER_TYPE, + scannerType: OPENVAS_SCANNER_TYPE, }, ], schedule_id = UNSET_VALUE, @@ -209,10 +132,10 @@ const TaskDialog = ({ target_id, targets, task, - title = _('New Task'), - onAlertsChange, + title = _('New Audit'), + //onAlertsChange, onClose, - onNewAlertClick, + //onNewAlertClick, onNewScheduleClick, onNewTargetClick, onSave, @@ -223,7 +146,9 @@ const TaskDialog = ({ ...data }) => { const scanner = get_scanner(scanners, scanner_id); - const scanner_type = isDefined(scanner) ? scanner.scannerType : undefined; + const scanner_type = isDefined(scanner) ? scanner.scannerType : undefined; //scannerType + + console.log('scanner=', scanner, 'scanner type=', scanner_type); const tag_items = renderSelectItems(tags); @@ -241,7 +166,7 @@ const TaskDialog = ({ sorted_scan_configs[OPENVAS_SCAN_CONFIG_TYPE], ); - const alert_items = renderSelectItems(alerts); + //const alert_items = renderSelectItems(alerts); // having a task means we are editing a task const hasTask = isDefined(task); @@ -292,7 +217,7 @@ const TaskDialog = ({ values={controlledData} > {({values: state, onValueChange}) => { - const osp_config_id = selectSaveId( + /* const osp_config_id = selectSaveId( sorted_scan_configs[OSP_SCAN_CONFIG_TYPE], state.config_id, ); @@ -305,7 +230,7 @@ const TaskDialog = ({ const use_openvas_scan_config = state.scanner_type === OPENVAS_SCANNER_TYPE || - state.scanner_type === GMP_SCANNER_TYPE; + state.scanner_type === GMP_SCANNER_TYPE; */ return ( @@ -317,7 +242,6 @@ const TaskDialog = ({ onChange={onValueChange} /> - - - - - - - - - )} - - - - - - - - - - % - - - {change_task && ( - - - - )} - - - - - - {use_openvas_scan_config && ( - - - - - - - - - - - - )} - - {is_osp_scanner && ( - - - - - - )} ); }} @@ -560,7 +277,7 @@ const TaskDialog = ({ ); }; -TaskDialog.propTypes = { +CreateAuditDialog.propTypes = { add_tag: PropTypes.yesno, alert_ids: PropTypes.array, alerts: PropTypes.array, @@ -590,18 +307,18 @@ TaskDialog.propTypes = { targets: PropTypes.array, task: PropTypes.model, title: PropTypes.string, - onAlertsChange: PropTypes.func.isRequired, + //onAlertsChange: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired, - onNewAlertClick: PropTypes.func.isRequired, - onNewScheduleClick: PropTypes.func.isRequired, + //onNewAlertClick: PropTypes.func.isRequired, + //onNewScheduleClick: PropTypes.func.isRequired, onNewTargetClick: PropTypes.func.isRequired, onSave: PropTypes.func.isRequired, - onScanConfigChange: PropTypes.func.isRequired, - onScannerChange: PropTypes.func.isRequired, - onScheduleChange: PropTypes.func.isRequired, + // onScanConfigChange: PropTypes.func.isRequired, + // onScannerChange: PropTypes.func.isRequired, + // onScheduleChange: PropTypes.func.isRequired, onTargetChange: PropTypes.func.isRequired, }; -export default withCapabilities(TaskDialog); +export default withCapabilities(CreateAuditDialog); // vim: set ts=2 sw=2 tw=80: From e549e4679faac8b60af7b485d6f5dc82dcc9118a Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Thu, 6 Jun 2019 16:47:41 +0200 Subject: [PATCH 03/66] add policy as scanconfig and compliance tag to dialog --- gsa/src/web/pages/policies/component.js | 69 +++------------ .../web/pages/policies/createauditdialog.js | 85 ++++--------------- 2 files changed, 31 insertions(+), 123 deletions(-) diff --git a/gsa/src/web/pages/policies/component.js b/gsa/src/web/pages/policies/component.js index 2b1d816172..ccf675ac85 100644 --- a/gsa/src/web/pages/policies/component.js +++ b/gsa/src/web/pages/policies/component.js @@ -128,6 +128,7 @@ class PolicyComponent extends React.Component { } openEditConfigDialog(config) { + console.log(config); Promise.all([ this.loadEditScanConfigSettings(config), this.loadScanners(), @@ -156,6 +157,8 @@ class PolicyComponent extends React.Component { openCreateAuditDialog(config) { const {capabilities} = this.props; + console.log(config); + this.props.loadScanConfigs(); this.props.loadScanners(); this.props.loadTargets(); @@ -180,8 +183,8 @@ class PolicyComponent extends React.Component { auto_delete: undefined, auto_delete_data: undefined, comment: '', - config_id: defaultScanConfigId, - //config_id: scanConfig.id, + //config_id: defaultScanConfigId, + config_id: isDefined(config) ? config.id : defaultScanConfigId, hosts_ordering: undefined, id: undefined, in_assets: undefined, @@ -201,17 +204,6 @@ class PolicyComponent extends React.Component { this.handleInteraction(); } - /* openCreateAuditDialog() { - this.loadScanners().then(state => - this.setState({ - ...state, - createAuditDialogVisible: true, - }), - ); - - this.handleInteraction(); - } */ - closeCreateAuditDialog() { this.setState({createAuditDialogVisible: false}); } @@ -350,17 +342,6 @@ class PolicyComponent extends React.Component { this.handleInteraction(); } - /* handleImportConfig(data) { - const {gmp, onImported, onImportError} = this.props; - - this.handleInteraction(); - - return gmp.scanconfig - .import(data) - .then(onImported, onImportError) - .then(() => this.closeImportDialog()); - } */ - handleSaveConfigFamily(data) { const {gmp} = this.props; @@ -550,6 +531,7 @@ class PolicyComponent extends React.Component { const { children, targets, + tags, onCloned, onCloneError, onCreated, @@ -567,6 +549,7 @@ class PolicyComponent extends React.Component { base, comment, config, + config_id, config_name, createAuditDialogVisible, editConfigDialogVisible, @@ -613,33 +596,10 @@ class PolicyComponent extends React.Component { {children({ ...other, - //create: this.openCreateConfigDialog, create: this.openCreateAuditDialog, edit: this.openEditConfigDialog, import: this.openImportDialog, })} - {/* {createConfigDialogVisible && ( - { - this.handleInteraction(); - return save(d).then(() => this.closeCreateConfigDialog()); - }} - /> - )} */} - {/* {createAuditDialogVisible && ( - { - this.handleInteraction(); - return save(d).then(() => this.closeCreateAuditDialog()); - }} - /> - )} */} {createAuditDialogVisible && ( {({create: createtarget}) => ( )} - {console.log('config=', config)} )} - {/* {importDialogVisible && ( - - )} */} {editConfigFamilyDialogVisible && ( { - const sorted_scan_configs = { - [OPENVAS_SCAN_CONFIG_TYPE]: [], - [OSP_SCAN_CONFIG_TYPE]: [], - }; - - scan_configs = scan_configs.filter(filterEmptyScanConfig); - - forEach(scan_configs, config => { - const type = config.scan_config_type; - if (!isArray(sorted_scan_configs[type])) { - sorted_scan_configs[type] = []; - } - sorted_scan_configs[type].push(config); - }); - return sorted_scan_configs; -}; - const get_scanner = (scanners, scanner_id) => { if (!isDefined(scanners)) { return undefined; @@ -108,7 +80,8 @@ const CreateAuditDialog = ({ auto_delete_data = AUTO_DELETE_KEEP_DEFAULT_VALUE, capabilities, comment = '', - config_id = FULL_AND_FAST_SCAN_CONFIG_ID, + //config_id = FULL_AND_FAST_SCAN_CONFIG_ID, + config_id = undefined, //config_id = scan_configs[0].id, hosts_ordering = HOSTS_ORDERING_SEQUENTIAL, in_assets = YES_VALUE, @@ -136,12 +109,12 @@ const CreateAuditDialog = ({ //onAlertsChange, onClose, //onNewAlertClick, - onNewScheduleClick, + //onNewScheduleClick, onNewTargetClick, onSave, - onScanConfigChange, - onScannerChange, - onScheduleChange, + //onScanConfigChange, + //onScannerChange, + //onScheduleChange, onTargetChange, ...data }) => { @@ -149,33 +122,28 @@ const CreateAuditDialog = ({ const scanner_type = isDefined(scanner) ? scanner.scannerType : undefined; //scannerType console.log('scanner=', scanner, 'scanner type=', scanner_type); - - const tag_items = renderSelectItems(tags); + console.log('scan_configs=', scan_configs); const target_items = renderSelectItems(targets); - const schedule_items = renderSelectItems(schedules, UNSET_VALUE); + const tag = tags.find(element => { + return element.name === 'task:compliance'; + }); - const sorted_scan_configs = sort_scan_configs(scan_configs); + console.log('tag=', tag); - const osp_scan_config_items = renderSelectItems( - sorted_scan_configs[OSP_SCAN_CONFIG_TYPE], - ); + const tag_id = tag ? tag.id : undefined; - const openvas_scan_config_items = renderSelectItems( - sorted_scan_configs[OPENVAS_SCAN_CONFIG_TYPE], - ); - - //const alert_items = renderSelectItems(alerts); + console.log('tags=', tags, 'tag_id=', tag_id); // having a task means we are editing a task const hasTask = isDefined(task); const change_task = hasTask ? task.isChangeable() : true; - const showTagSelection = !hasTask && tags.length > 0; + /* const showTagSelection = !hasTask && tags.length > 0; - const tag_id = showTagSelection ? first(tags).id : undefined; + const tag_id = showTagSelection ? first(tags).id : undefined; */ const uncontrolledData = { ...data, @@ -205,6 +173,7 @@ const CreateAuditDialog = ({ schedule_id, scanner_id, scanner_type, + tag_id, target_id, }; @@ -217,20 +186,6 @@ const CreateAuditDialog = ({ values={controlledData} > {({values: state, onValueChange}) => { - /* const osp_config_id = selectSaveId( - sorted_scan_configs[OSP_SCAN_CONFIG_TYPE], - state.config_id, - ); - const openvas_config_id = selectSaveId( - sorted_scan_configs[OPENVAS_SCAN_CONFIG_TYPE], - state.config_id, - ); - - const is_osp_scanner = state.scanner_type === OSP_SCANNER_TYPE; - - const use_openvas_scan_config = - state.scanner_type === OPENVAS_SCANNER_TYPE || - state.scanner_type === GMP_SCANNER_TYPE; */ return ( @@ -307,15 +262,9 @@ CreateAuditDialog.propTypes = { targets: PropTypes.array, task: PropTypes.model, title: PropTypes.string, - //onAlertsChange: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired, - //onNewAlertClick: PropTypes.func.isRequired, - //onNewScheduleClick: PropTypes.func.isRequired, onNewTargetClick: PropTypes.func.isRequired, onSave: PropTypes.func.isRequired, - // onScanConfigChange: PropTypes.func.isRequired, - // onScannerChange: PropTypes.func.isRequired, - // onScheduleChange: PropTypes.func.isRequired, onTargetChange: PropTypes.func.isRequired, }; From 54fcb3f9098c09d7f4c11ee9f2f2b50453a62d31 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Thu, 13 Jun 2019 08:46:06 +0200 Subject: [PATCH 04/66] improve dialog and add import and delete for policies --- gsa/src/web/pages/policies/component.js | 265 +++++++++++------- .../web/pages/policies/createauditdialog.js | 180 ++---------- gsa/src/web/pages/policies/header.js | 2 +- gsa/src/web/pages/policies/listpage.js | 46 +-- gsa/src/web/pages/policies/row.js | 9 +- gsa/src/web/pages/policies/table.js | 6 +- 6 files changed, 236 insertions(+), 272 deletions(-) diff --git a/gsa/src/web/pages/policies/component.js b/gsa/src/web/pages/policies/component.js index ccf675ac85..e371d3f887 100644 --- a/gsa/src/web/pages/policies/component.js +++ b/gsa/src/web/pages/policies/component.js @@ -31,6 +31,12 @@ import {selectSaveId} from 'gmp/utils/id'; import {parseYesNo, YES_VALUE, NO_VALUE} from 'gmp/parser'; +import { + AUTO_DELETE_KEEP_DEFAULT_VALUE, + HOSTS_ORDERING_SEQUENTIAL, + AUTO_DELETE_NO, +} from 'gmp/models/task'; + import { ospScannersFilter, OPENVAS_DEFAULT_SCANNER_ID, @@ -67,31 +73,53 @@ import compose from 'web/utils/compose'; import PropTypes from 'web/utils/proptypes'; import withCapabilities from 'web/utils/withCapabilities'; import withGmp from 'web/utils/withGmp'; +import {UNSET_VALUE} from 'web/utils/render'; import EntityComponent from 'web/entity/component'; import EditConfigFamilyDialog from 'web/pages/scanconfigs/editconfigfamilydialog'; import EditScanConfigDialog from 'web/pages/scanconfigs/editdialog'; import EditNvtDetailsDialog from 'web/pages/scanconfigs/editnvtdetailsdialog'; -// import ScanConfigDialog from 'web/pages/scanconfigs/dialog'; import AuditDialog from './createauditdialog'; +import ImportDialog from 'web/pages/scanconfigs/importdialog'; +import ScanConfigDialog from 'web/pages/scanconfigs/dialog'; -// import TaskComponent from 'web/pages/tasks/component'; import TargetComponent from 'web/pages/targets/component'; +const DEFAULT_MAX_CHECKS = 4; +const DEFAULT_MAX_HOSTS = 20; +const DEFAULT_MIN_QOD = 70; + +const get_scanner = (scanners, scanner_id) => { + if (!isDefined(scanners)) { + return undefined; + } + + return scanners.find(sc => { + return sc.id === scanner_id; + }); +}; + class PolicyComponent extends React.Component { constructor(...args) { super(...args); this.state = { + //createConfigDialogVisible: false, editConfigDialogVisible: false, editConfigFamilyDialogVisible: false, editNvtDetailsDialogVisible: false, createAuditDialogVisible: false, + importDialogVisible: false, }; + this.handleImportConfig = this.handleImportConfig.bind(this); this.handleSaveConfigFamily = this.handleSaveConfigFamily.bind(this); this.handleSaveConfigNvt = this.handleSaveConfigNvt.bind(this); + /* this.openCreateConfigDialog = this.openCreateConfigDialog.bind(this); + this.handleCloseCreateConfigDialog = this.handleCloseCreateConfigDialog.bind( + this, + ); */ this.openEditConfigDialog = this.openEditConfigDialog.bind(this); this.handleCloseEditConfigDialog = this.handleCloseEditConfigDialog.bind( this, @@ -106,6 +134,8 @@ class PolicyComponent extends React.Component { this.handleCloseEditNvtDetailsDialog = this.handleCloseEditNvtDetailsDialog.bind( this, ); + this.openImportDialog = this.openImportDialog.bind(this); + this.handleCloseImportDialog = this.handleCloseImportDialog.bind(this); this.openCreateAuditDialog = this.openCreateAuditDialog.bind(this); this.handleCloseCreateAuditDialog = this.handleCloseCreateAuditDialog.bind( this, @@ -128,7 +158,6 @@ class PolicyComponent extends React.Component { } openEditConfigDialog(config) { - console.log(config); Promise.all([ this.loadEditScanConfigSettings(config), this.loadScanners(), @@ -154,50 +183,87 @@ class PolicyComponent extends React.Component { this.handleInteraction(); } + /* openCreateConfigDialog() { + this.loadScanners().then(state => + this.setState({ + ...state, + createConfigDialogVisible: true, + }), + ); + + this.handleInteraction(); + } + + closeCreateConfigDialog() { + this.setState({createConfigDialogVisible: false}); + } + + handleCloseCreateConfigDialog() { + this.closeCreateConfigDialog(); + this.handleInteraction(); + } */ + + openImportDialog() { + this.setState({importDialogVisible: true}); + this.handleInteraction(); + } + + closeImportDialog() { + this.setState({importDialogVisible: false}); + } + + handleCloseImportDialog() { + this.closeImportDialog(); + this.handleInteraction(); + } + openCreateAuditDialog(config) { - const {capabilities} = this.props; + // const {capabilities} = this.props; - console.log(config); + // console.log(config); this.props.loadScanConfigs(); - this.props.loadScanners(); + //this.props.loadScanners(); this.props.loadTargets(); this.props.loadTags(); const { - defaultAlertId, - defaultScanConfigId = FULL_AND_FAST_SCAN_CONFIG_ID, - defaultScannerId = OPENVAS_DEFAULT_SCANNER_ID, - defaultScheduleId, + // defaultAlertId, + // defaultScanConfigId = FULL_AND_FAST_SCAN_CONFIG_ID, + // defaultScannerId = OPENVAS_DEFAULT_SCANNER_ID, + // defaultScheduleId, defaultTargetId, } = this.props; - console.log('default=', defaultScannerId); - const alert_ids = isDefined(defaultAlertId) ? [defaultAlertId] : []; + //console.log('defaults', defaultAlertId, defaultScheduleId, defaultTargetId); + + // console.log('default=', defaultScannerId); + // const alert_ids = isDefined(defaultAlertId) ? [defaultAlertId] : []; this.setState({ createAuditDialogVisible: true, - alert_ids, - alterable: undefined, - apply_overrides: undefined, - auto_delete: undefined, - auto_delete_data: undefined, + // alert_ids, + // alterable: undefined, + // apply_overrides: undefined, + // auto_delete: undefined, + // auto_delete_data: undefined, comment: '', - //config_id: defaultScanConfigId, - config_id: isDefined(config) ? config.id : defaultScanConfigId, - hosts_ordering: undefined, - id: undefined, - in_assets: undefined, - max_checks: undefined, - max_hosts: undefined, - min_qod: undefined, + // config_id: defaultScanConfigId, + //config_id: isDefined(config) ? config.id : defaultScanConfigId, + config_id: isDefined(config) ? config.id : undefined, //must not use default because the scanconfig has to be the policy + // hosts_ordering: undefined, + // id: undefined, + // in_assets: undefined, + // max_checks: undefined, + // max_hosts: undefined, + // min_qod: undefined, name: undefined, - scanner_id: defaultScannerId, - schedule_id: defaultScheduleId, - schedule_periods: undefined, - source_iface: undefined, + // scanner_id: defaultScannerId, + // schedule_id: defaultScheduleId, + // schedule_periods: undefined, + // source_iface: undefined, target_id: defaultTargetId, - task: undefined, + //task: undefined, title: _('New Task'), }); @@ -213,60 +279,44 @@ class PolicyComponent extends React.Component { this.handleInteraction(); } - handleSaveAudit({ - add_tag, - alert_ids, - alterable, - auto_delete, - auto_delete_data, - apply_overrides, - comment, - config_id, - hosts_ordering, - id, - in_assets, - min_qod, - max_checks, - max_hosts, - name, - scanner_id, - scanner_type, - schedule_id, - schedule_periods, - source_iface, - tag_id, - target_id, - task, - }) { - const {gmp} = this.props; + handleSaveAudit({comment, name, target_id}) { + const {gmp, defaultAlertId, defaultScheduleId} = this.props; + const {config_id} = this.state; + + const scanner_id = OPENVAS_DEFAULT_SCANNER_ID; + const scanners = [ + { + id: OPENVAS_DEFAULT_SCANNER_ID, + scannerType: OPENVAS_SCANNER_TYPE, + }, + ]; + const scanner = get_scanner(scanners, scanner_id); + const scanner_type = isDefined(scanner) ? scanner.scannerType : undefined; + + const tag = this.props.tags.find(element => { + return element.name === 'task:compliance'; + }); + const tag_id = tag ? tag.id : undefined; + const add_tag = YES_VALUE; + + const alert_ids = isDefined(defaultAlertId) ? [defaultAlertId] : []; + const alterable = NO_VALUE; + const apply_overrides = YES_VALUE; + const auto_delete = AUTO_DELETE_NO; + const auto_delete_data = AUTO_DELETE_KEEP_DEFAULT_VALUE; + const hosts_ordering = HOSTS_ORDERING_SEQUENTIAL; + const in_assets = YES_VALUE; + const max_checks = DEFAULT_MAX_CHECKS; + const max_hosts = DEFAULT_MAX_HOSTS; + const min_qod = DEFAULT_MIN_QOD; + const schedule_id = isDefined(defaultScheduleId) + ? defaultScheduleId + : UNSET_VALUE; + const schedule_periods = NO_VALUE; + const source_iface = ''; this.handleInteraction(); - console.log('input=', { - add_tag, - alert_ids, - alterable, - auto_delete, - auto_delete_data, - apply_overrides, - comment, - config_id, - hosts_ordering, - id, - in_assets, - min_qod, - max_checks, - max_hosts, - name, - scanner_id, - scanner_type, - schedule_id, - schedule_periods, - source_iface, - tag_id, - target_id, - task, - }); const {onCreated, onCreateError} = this.props; return gmp.task .create({ @@ -342,6 +392,17 @@ class PolicyComponent extends React.Component { this.handleInteraction(); } + handleImportConfig(data) { + const {gmp, onImported, onImportError} = this.props; + + this.handleInteraction(); + + return gmp.scanconfig + .import(data) + .then(onImported, onImportError) + .then(() => this.closeImportDialog()); + } + handleSaveConfigFamily(data) { const {gmp} = this.props; @@ -531,7 +592,6 @@ class PolicyComponent extends React.Component { const { children, targets, - tags, onCloned, onCloneError, onCreated, @@ -549,8 +609,8 @@ class PolicyComponent extends React.Component { base, comment, config, - config_id, config_name, + //createConfigDialogVisible, createAuditDialogVisible, editConfigDialogVisible, editConfigFamilyDialogVisible, @@ -560,6 +620,7 @@ class PolicyComponent extends React.Component { families, family_name, id, + importDialogVisible, manual_timeout, name, nvt, @@ -607,18 +668,6 @@ class PolicyComponent extends React.Component { > {({create: createtarget}) => ( )} + {/* {createConfigDialogVisible && ( + { + this.handleInteraction(); + return save(d).then(() => this.closeCreateConfigDialog()); + }} + /> + )} */} {editConfigDialogVisible && ( )} + {importDialogVisible && ( + + )} {editConfigFamilyDialogVisible && ( { diff --git a/gsa/src/web/pages/policies/createauditdialog.js b/gsa/src/web/pages/policies/createauditdialog.js index da0e74288e..b55546a15f 100644 --- a/gsa/src/web/pages/policies/createauditdialog.js +++ b/gsa/src/web/pages/policies/createauditdialog.js @@ -21,29 +21,9 @@ import React from 'react'; import _ from 'gmp/locale'; -import logger from 'gmp/log'; - -import {forEach, first} from 'gmp/utils/array'; -import {isDefined, isArray} from 'gmp/utils/identity'; - -import {NO_VALUE, YES_VALUE} from 'gmp/parser'; - -import { - AUTO_DELETE_KEEP_DEFAULT_VALUE, - HOSTS_ORDERING_SEQUENTIAL, - AUTO_DELETE_NO, -} from 'gmp/models/task'; - -import { - OPENVAS_SCANNER_TYPE, - OPENVAS_DEFAULT_SCANNER_ID, -} from 'gmp/models/scanner'; - -import {FULL_AND_FAST_SCAN_CONFIG_ID} from 'gmp/models/scanconfig'; - import PropTypes from 'web/utils/proptypes'; import withCapabilities from 'web/utils/withCapabilities'; -import {renderSelectItems, UNSET_VALUE} from 'web/utils/render'; +import {renderSelectItems} from 'web/utils/render'; import SaveDialog from 'web/components/dialog/savedialog'; @@ -56,124 +36,27 @@ import NewIcon from 'web/components/icon/newicon'; import Divider from 'web/components/layout/divider'; import Layout from 'web/components/layout/layout'; -const get_scanner = (scanners, scanner_id) => { - if (!isDefined(scanners)) { - return undefined; - } - - return scanners.find(sc => { - return sc.id === scanner_id; - }); -}; - -const DEFAULT_MAX_CHECKS = 4; -const DEFAULT_MAX_HOSTS = 20; -const DEFAULT_MIN_QOD = 70; - const CreateAuditDialog = ({ - add_tag = NO_VALUE, - alert_ids = [], - alerts = [], - alterable = NO_VALUE, - apply_overrides = YES_VALUE, - auto_delete = AUTO_DELETE_NO, - auto_delete_data = AUTO_DELETE_KEEP_DEFAULT_VALUE, - capabilities, comment = '', - //config_id = FULL_AND_FAST_SCAN_CONFIG_ID, - config_id = undefined, - //config_id = scan_configs[0].id, - hosts_ordering = HOSTS_ORDERING_SEQUENTIAL, - in_assets = YES_VALUE, - max_checks = DEFAULT_MAX_CHECKS, - max_hosts = DEFAULT_MAX_HOSTS, - min_qod = DEFAULT_MIN_QOD, name = _('Unnamed'), - scan_configs = [], - scanner_id = OPENVAS_DEFAULT_SCANNER_ID, - scanners = [ - { - id: OPENVAS_DEFAULT_SCANNER_ID, - scannerType: OPENVAS_SCANNER_TYPE, - }, - ], - schedule_id = UNSET_VALUE, - schedule_periods = NO_VALUE, - schedules = [], - source_iface = '', - tags = [], target_id, targets, - task, title = _('New Audit'), - //onAlertsChange, onClose, - //onNewAlertClick, - //onNewScheduleClick, onNewTargetClick, onSave, - //onScanConfigChange, - //onScannerChange, - //onScheduleChange, onTargetChange, ...data }) => { - const scanner = get_scanner(scanners, scanner_id); - const scanner_type = isDefined(scanner) ? scanner.scannerType : undefined; //scannerType - - console.log('scanner=', scanner, 'scanner type=', scanner_type); - console.log('scan_configs=', scan_configs); - const target_items = renderSelectItems(targets); - const tag = tags.find(element => { - return element.name === 'task:compliance'; - }); - - console.log('tag=', tag); - - const tag_id = tag ? tag.id : undefined; - - console.log('tags=', tags, 'tag_id=', tag_id); - - // having a task means we are editing a task - const hasTask = isDefined(task); - - const change_task = hasTask ? task.isChangeable() : true; - - /* const showTagSelection = !hasTask && tags.length > 0; - - const tag_id = showTagSelection ? first(tags).id : undefined; */ - const uncontrolledData = { ...data, - add_tag, - alterable, - apply_overrides, - auto_delete, - auto_delete_data, comment, - hosts_ordering, - in_assets, - max_checks, - max_hosts, - min_qod, name, - scanner_type, - scanner_id, - source_iface, - tag_id, - tags, - task, }; const controlledData = { - alert_ids, - config_id, - schedule_id, - scanner_id, - scanner_type, - tag_id, target_id, }; @@ -210,19 +93,16 @@ const CreateAuditDialog = ({ + + ); + } +} + +ScannerSelect.propTypes = { + changeTask: PropTypes.bool.isRequired, + scanConfigs: PropTypes.shape({ + [OPENVAS_SCANNER_TYPE]: PropTypes.array, + [OSP_SCANNER_TYPE]: PropTypes.array, + }), + scannerId: PropTypes.id.isRequired, + scanners: PropTypes.array.isRequired, + onScanConfigChange: PropTypes.func.isRequired, + onScannerChange: PropTypes.func.isRequired, +}; + +const DEFAULT_MAX_CHECKS = 4; +const DEFAULT_MAX_HOSTS = 20; +const DEFAULT_MIN_QOD = 70; + +const TaskDialog = ({ + add_tag = NO_VALUE, + alert_ids = [], + alerts = [], + alterable = NO_VALUE, + apply_overrides = YES_VALUE, + auto_delete = AUTO_DELETE_NO, + auto_delete_data = AUTO_DELETE_KEEP_DEFAULT_VALUE, + capabilities, + comment = '', + config_id = FULL_AND_FAST_SCAN_CONFIG_ID, + hosts_ordering = HOSTS_ORDERING_SEQUENTIAL, + in_assets = YES_VALUE, + max_checks = DEFAULT_MAX_CHECKS, + max_hosts = DEFAULT_MAX_HOSTS, + min_qod = DEFAULT_MIN_QOD, + name = _('Unnamed'), + scan_configs = [], + scanner_id = OPENVAS_DEFAULT_SCANNER_ID, + scanners = [ + { + id: OPENVAS_DEFAULT_SCANNER_ID, + scanner_type: OPENVAS_SCANNER_TYPE, + }, + ], + schedule_id = UNSET_VALUE, + schedule_periods = NO_VALUE, + schedules = [], + source_iface = '', + tags = [], + target_id, + targets, + task, + title = _('New Task'), + onAlertsChange, + onClose, + onNewAlertClick, + onNewScheduleClick, + onNewTargetClick, + onSave, + onScanConfigChange, + onScannerChange, + onScheduleChange, + onTargetChange, + ...data +}) => { + const scanner = get_scanner(scanners, scanner_id); + const scanner_type = isDefined(scanner) ? scanner.scannerType : undefined; + + const tag_items = renderSelectItems(tags); + + const target_items = renderSelectItems(targets); + + const schedule_items = renderSelectItems(schedules, UNSET_VALUE); + + const sorted_scan_configs = sort_scan_configs(scan_configs); + + const osp_scan_config_items = renderSelectItems( + sorted_scan_configs[OSP_SCAN_CONFIG_TYPE], + ); + + const openvas_scan_config_items = renderSelectItems( + sorted_scan_configs[OPENVAS_SCAN_CONFIG_TYPE], + ); + + const alert_items = renderSelectItems(alerts); + + // having a task means we are editing a task + const hasTask = isDefined(task); + + const change_task = hasTask ? task.isChangeable() : true; + + const showTagSelection = !hasTask && tags.length > 0; + + const tag_id = showTagSelection ? first(tags).id : undefined; + + const uncontrolledData = { + ...data, + add_tag, + alterable, + apply_overrides, + auto_delete, + auto_delete_data, + comment, + hosts_ordering, + in_assets, + max_checks, + max_hosts, + min_qod, + name, + scanner_type, + scanner_id, + source_iface, + tag_id, + tags, + task, + }; + + const controlledData = { + alert_ids, + config_id, + schedule_id, + scanner_id, + scanner_type, + target_id, + }; + + return ( + + {({values: state, onValueChange}) => { + const osp_config_id = selectSaveId( + sorted_scan_configs[OSP_SCAN_CONFIG_TYPE], + state.config_id, + ); + const openvas_config_id = selectSaveId( + sorted_scan_configs[OPENVAS_SCAN_CONFIG_TYPE], + state.config_id, + ); + + const is_osp_scanner = state.scanner_type === OSP_SCANNER_TYPE; + + const use_openvas_scan_config = + state.scanner_type === OPENVAS_SCANNER_TYPE || + state.scanner_type === GMP_SCANNER_TYPE; + return ( + + + + + + + + + + + + + + + + + + + )} + + + + + + + + + + % + + + {change_task && ( + + + + )} + + + + + + {use_openvas_scan_config && ( + + + + + + + + + + + + )} + + {is_osp_scanner && ( + + + + + + )} + + ); + }} + + ); +}; + +TaskDialog.propTypes = { + add_tag: PropTypes.yesno, + alert_ids: PropTypes.array, + alerts: PropTypes.array, + alterable: PropTypes.yesno, + apply_overrides: PropTypes.yesno, + auto_delete: PropTypes.oneOf(['keep', 'no']), + auto_delete_data: PropTypes.number, + capabilities: PropTypes.capabilities.isRequired, + comment: PropTypes.string, + config_id: PropTypes.idOrZero, + hosts_ordering: PropTypes.oneOf(['sequential', 'random', 'reverse']), + in_assets: PropTypes.yesno, + max_checks: PropTypes.number, + max_hosts: PropTypes.number, + min_qod: PropTypes.number, + name: PropTypes.string, + scan_configs: PropTypes.arrayOf(PropTypes.model), + scanner_id: PropTypes.idOrZero, + scanners: PropTypes.array, + schedule_id: PropTypes.idOrZero, + schedule_periods: PropTypes.yesno, + schedules: PropTypes.array, + source_iface: PropTypes.string, + tag_id: PropTypes.id, + tags: PropTypes.array, + target_id: PropTypes.idOrZero, + targets: PropTypes.array, + task: PropTypes.model, + title: PropTypes.string, + onAlertsChange: PropTypes.func.isRequired, + onClose: PropTypes.func.isRequired, + onNewAlertClick: PropTypes.func.isRequired, + onNewScheduleClick: PropTypes.func.isRequired, + onNewTargetClick: PropTypes.func.isRequired, + onSave: PropTypes.func.isRequired, + onScanConfigChange: PropTypes.func.isRequired, + onScannerChange: PropTypes.func.isRequired, + onScheduleChange: PropTypes.func.isRequired, + onTargetChange: PropTypes.func.isRequired, +}; + +export default withCapabilities(TaskDialog); + +// vim: set ts=2 sw=2 tw=80: diff --git a/gsa/src/web/pages/audits/filterdialog.js b/gsa/src/web/pages/audits/filterdialog.js index 9b75a5823d..7447a127b6 100644 --- a/gsa/src/web/pages/audits/filterdialog.js +++ b/gsa/src/web/pages/audits/filterdialog.js @@ -55,15 +55,7 @@ const SORT_FIELDS = [ { name: 'complianceStatus', displayName: _l('Compliance Status'), - } /* - { - name: 'severity', - displayName: _l('Severity'), }, - { - name: 'trend', - displayName: _l('Trend'), - }, */, ]; const TaskFilterDialogComponent = ({ diff --git a/gsa/src/web/pages/audits/listpage.js b/gsa/src/web/pages/audits/listpage.js index e904a20192..479d9b76fa 100644 --- a/gsa/src/web/pages/audits/listpage.js +++ b/gsa/src/web/pages/audits/listpage.js @@ -44,7 +44,7 @@ import {DEFAULT_RELOAD_INTERVAL_ACTIVE} from 'web/utils/constants'; import NewIconMenu from 'web/pages/tasks/icons/newiconmenu'; import AuditComponent from './component'; -//import TaskDashboard, {TASK_DASHBOARD_ID} from './dashboard'; +// import TaskDashboard, {TASK_DASHBOARD_ID} from './dashboard'; import TaskFilterDialog from './filterdialog'; import Table from './table'; import TaskIcon from 'web/components/icon/taskicon'; @@ -77,18 +77,18 @@ const Page = ({ ...props }) => ( {({ clone, - //create, - //createcontainer, + // create, + // createcontainer, delete: delete_func, download, edit, @@ -110,9 +110,9 @@ const Page = ({ stop, resume, reportimport, - //advancedtaskwizard, - //modifytaskwizard, - //taskwizard, + // advancedtaskwizard, + // modifytaskwizard, + // taskwizard, }) => ( )} diff --git a/gsa/src/web/pages/audits/row.js b/gsa/src/web/pages/audits/row.js index aff35ba0e4..804c761ab6 100644 --- a/gsa/src/web/pages/audits/row.js +++ b/gsa/src/web/pages/audits/row.js @@ -30,8 +30,6 @@ import {RowDetailsToggle} from 'web/entities/row'; import ObserverIcon from 'web/entity/icon/observericon'; -import SeverityBar from 'web/components/bar/severitybar'; - import Comment from 'web/components/comment/comment'; import DateTime from 'web/components/date/datetime'; @@ -44,14 +42,12 @@ import IconDivider from 'web/components/layout/icondivider'; import Layout from 'web/components/layout/layout'; import DetailsLink from 'web/components/link/detailslink'; -import Link from 'web/components/link/link'; import TableRow from 'web/components/table/row'; import TableData from 'web/components/table/data'; import Actions from './actions'; import TaskStatus from 'web/pages/tasks/status'; -//import Trend from './trend'; import {GMP_SCANNER_TYPE} from 'gmp/models/scanner'; @@ -68,28 +64,6 @@ const render_report = (report, links) => { ); }; -const render_report_total = (entity, links) => { - if (entity.report_count.total <= 0) { - return null; - } - return ( - - - {entity.report_count.total} - - - ); -}; - const Row = ({ actionsComponent: ActionsComponent = Actions, entity, @@ -153,18 +127,9 @@ const Row = ({ - {/* {render_report_total(entity, links)} */} {render_report(entity.last_report, links)} - {/* - {!entity.isContainer() && isDefined(entity.last_report) && ( - - )} - - - {!entity.isContainer() && } - */} - {/*TODO: Compliance Status Bar */} + {/* TODO: Compliance Status Bar */} diff --git a/gsa/src/web/pages/audits/table.js b/gsa/src/web/pages/audits/table.js index 3d36d906c0..ae48f11e93 100644 --- a/gsa/src/web/pages/audits/table.js +++ b/gsa/src/web/pages/audits/table.js @@ -58,31 +58,12 @@ const Header = ({ sortBy="status" title={_('Status')} /> - {/* */} - {/* - */} {/* TODO: sort by compliance status*/} Date: Tue, 18 Jun 2019 16:33:53 +0200 Subject: [PATCH 06/66] add greenbone compliance report download --- gsa/src/web/pages/audits/actions.js | 12 ++- gsa/src/web/pages/audits/component.js | 115 +++++++++++++++++++++++--- gsa/src/web/pages/audits/listpage.js | 9 +- gsa/src/web/pages/audits/row.js | 5 +- gsa/src/web/pages/audits/table.js | 10 +-- 5 files changed, 124 insertions(+), 27 deletions(-) diff --git a/gsa/src/web/pages/audits/actions.js b/gsa/src/web/pages/audits/actions.js index 62053c0a45..7cdbef0188 100644 --- a/gsa/src/web/pages/audits/actions.js +++ b/gsa/src/web/pages/audits/actions.js @@ -31,6 +31,7 @@ import withEntitiesActions from 'web/entities/withEntitiesActions'; import CloneIcon from 'web/entity/icon/cloneicon'; import EditIcon from 'web/entity/icon/editicon'; import TrashIcon from 'web/entity/icon/trashicon'; +import DownloadIcon from 'web/components/icon/downloadicon'; import ImportReportIcon from 'web/pages/tasks/icons/importreporticon'; import ResumeIcon from 'web/pages/tasks/icons/resumeicon'; @@ -43,6 +44,8 @@ import PropTypes from 'web/utils/proptypes'; const Actions = ({ entity, links, + gcrFormatDefined, + onReportDownloadClick, onReportImportClick, onTaskCloneClick, onTaskDeleteClick, @@ -73,13 +76,20 @@ const Actions = ({ title={_('Export Task')} onClick={onTaskDownloadClick} /> - {/* TODO: dowload greenbone compliance report button*/} + ); Actions.propTypes = { entity: PropTypes.model.isRequired, + gcrFormatDefined: PropTypes.bool, links: PropTypes.bool, + onReportDownloadClick: PropTypes.func.isRequired, onReportImportClick: PropTypes.func.isRequired, onTaskCloneClick: PropTypes.func.isRequired, onTaskDeleteClick: PropTypes.func.isRequired, diff --git a/gsa/src/web/pages/audits/component.js b/gsa/src/web/pages/audits/component.js index fcff961a63..8ebf1fb951 100644 --- a/gsa/src/web/pages/audits/component.js +++ b/gsa/src/web/pages/audits/component.js @@ -22,15 +22,14 @@ import {connect} from 'react-redux'; import _ from 'gmp/locale'; -import {ALL_FILTER} from 'gmp/models/filter'; - -// import {NO_VALUE} from 'gmp/parser'; +import Filter, {ALL_FILTER, RESULTS_FILTER_FILTER} from 'gmp/models/filter'; import {map} from 'gmp/utils/array'; import {isDefined} from 'gmp/utils/identity'; -import {selectSaveId, hasId} from 'gmp/utils/id'; +import {hasId} from 'gmp/utils/id'; -// import date from 'gmp/models/date'; +import withDownload from 'web/components/form/withDownload'; +import {withRouter} from 'react-router-dom'; import {FULL_AND_FAST_SCAN_CONFIG_ID} from 'gmp/models/scanconfig'; @@ -71,7 +70,20 @@ import { selector as targetSelector, } from 'web/store/entities/targets'; -import {getTimezone} from 'web/store/usersettings/selectors'; +import { + loadAllEntities as loadReportFormats, + selector as reportFormatsSelector, +} from 'web/store/entities/reportformats'; + +import { + loadAllEntities as loadFilters, + // selector as filterSelector, +} from 'web/store/entities/filters'; + +import { + // getReportComposerDefaults, + getTimezone, +} from 'web/store/usersettings/selectors'; import {loadUserSettingDefaults} from 'web/store/usersettings/defaults/actions'; import {getUserSettingsDefaults} from 'web/store/usersettings/defaults/selectors'; @@ -86,10 +98,6 @@ import EntityComponent from 'web/entity/component'; import ImportReportDialog from 'web/pages/reports/importdialog'; -/* import AdvancedTaskWizard from 'web/wizard/advancedtaskwizard'; -import ModifyTaskWizard from 'web/wizard/modifytaskwizard'; -import TaskWizard from 'web/wizard/taskwizard'; */ - import ScheduleComponent from 'web/pages/schedules/component'; import AlertComponent from 'web/pages/alerts/component'; import TargetComponent from 'web/pages/targets/component'; @@ -97,6 +105,8 @@ import TargetComponent from 'web/pages/targets/component'; import TaskDialog from 'web/pages/audits/dialog'; import ContainerTaskDialog from 'web/pages/tasks/containerdialog'; +const REPORT_FORMATS_FILTER = Filter.fromString('active=1 trust=1 rows=-1'); + class TaskComponent extends React.Component { constructor(...args) { super(...args); @@ -104,7 +114,9 @@ class TaskComponent extends React.Component { this.state = { containerTaskDialogVisible: false, reportImportDialogVisible: false, + showDownloadReportDialog: false, taskDialogVisible: false, + gcrFormatDefined: undefined, }; const {gmp} = this.props; @@ -129,6 +141,9 @@ class TaskComponent extends React.Component { this, ); + this.handleReportDownloadClick = this.handleReportDownloadClick.bind(this); + this.handleReportDownload = this.handleReportDownload.bind(this); + this.openStandardTaskDialog = this.openStandardTaskDialog.bind(this); this.openTaskDialog = this.openTaskDialog.bind(this); this.handleCloseTaskDialog = this.handleCloseTaskDialog.bind(this); @@ -149,6 +164,24 @@ class TaskComponent extends React.Component { componentDidMount() { this.props.loadUserSettingsDefaults(); + + this.props.loadFilters(); + this.props.loadReportFormats(); + } + + componentDidUpdate() { + const {reportFormats} = this.props; + if ( + !isDefined(this.state.gcrFormatDefined) && + isDefined(reportFormats) && + reportFormats.length > 0 + ) { + const gcrFormat = reportFormats.find(format => { + return format.name === 'GCR PDF'; + }); + const gcrFormatDefined = isDefined(gcrFormat); + this.setState({gcrFormatDefined: gcrFormatDefined}); + } } handleInteraction() { @@ -483,6 +516,45 @@ class TaskComponent extends React.Component { .then(() => this.closeReportImportDialog()); } + handleReportDownloadClick(task) { + this.setState({ + task: task, + }); + + this.handleReportDownload(this.state, task); + } + + handleReportDownload(state, task) { + const {gmp, reportFormats = [], onDownload} = this.props; + + const report_format = reportFormats.find( + format => format.name === 'GCR PDF', + ); + + const extension = isDefined(report_format) + ? report_format.extension + : 'unknown'; // unknown should never happen but we should be save here + + this.handleInteraction(); + + const {id} = task.last_report; + + gmp.report + .download( + {id}, + { + reportFormatId: report_format.id, + deltaReportId: undefined, + filter: undefined, + }, + ) + .then(response => { + const {data} = response; + const filename = 'report-' + id + '.' + extension; + onDownload({filename, data}); + }, this.handleError); + } + handleScanConfigChange(config_id) { this.setState({config_id}); } @@ -494,7 +566,8 @@ class TaskComponent extends React.Component { render() { const { alerts, - credentials, + // credentials, + // entity, scanConfigs, scanners, schedules, @@ -510,6 +583,9 @@ class TaskComponent extends React.Component { onDownloaded, onDownloadError, onInteraction, + // reportFilter, + // reportFormats, + // reportComposerDefaults, } = this.props; const { @@ -528,6 +604,7 @@ class TaskComponent extends React.Component { hosts_ordering, id, in_assets, + gcrFormatDefined, max_checks, max_hosts, min_qod, @@ -539,6 +616,7 @@ class TaskComponent extends React.Component { scanner_id, schedule_id, schedule_periods, + // showDownloadReportDialog, source_iface, ssh_credential, smb_credential, @@ -546,6 +624,7 @@ class TaskComponent extends React.Component { start_minute, start_hour, start_timezone, + // storeAsDefault, tag_id, target_id, target_hosts, @@ -582,6 +661,9 @@ class TaskComponent extends React.Component { stop: this.handleTaskStop, resume: this.handleTaskResume, reportimport: this.openReportImportDialog, + //reportDownload: this.handleOpenDownloadReportDialog, + reportDownload: this.handleReportDownloadClick, + gcrFormatDefined: gcrFormatDefined, })} {taskDialogVisible && ( @@ -742,7 +824,7 @@ TaskComponent.propTypes = { const TAGS_FILTER = ALL_FILTER.copy().set('resource_type', 'task'); -const mapStateToProps = rootState => { +const mapStateToProps = (rootState, {match}) => { const alertSel = alertSelector(rootState); const credentialsSel = credentialsSelector(rootState); const userDefaults = getUserSettingsDefaults(rootState); @@ -751,6 +833,9 @@ const mapStateToProps = rootState => { const scheduleSel = scheduleSelector(rootState); const tagsSel = tagsSelector(rootState); const targetSel = targetSelector(rootState); + + const reportFormatsSel = reportFormatsSelector(rootState); + return { timezone: getTimezone(rootState), alerts: alertSel.getEntities(ALL_FILTER), @@ -766,6 +851,7 @@ const mapStateToProps = rootState => { defaultSshCredential: userDefaults.getValueByName('defaultsshcredential'), defaultSmbCredential: userDefaults.getValueByName('defaultsmbcredential'), defaultTargetId: userDefaults.getValueByName('defaulttarget'), + reportFormats: reportFormatsSel.getAllEntities(REPORT_FORMATS_FILTER), scanConfigs: scanConfigsSel.getEntities(ALL_FILTER), scanners: scannersSel.getEntities(ALL_FILTER), schedules: scheduleSel.getEntities(ALL_FILTER), @@ -777,17 +863,22 @@ const mapStateToProps = rootState => { const mapDispatchToProp = (dispatch, {gmp}) => ({ loadAlerts: () => dispatch(loadAlerts(gmp)(ALL_FILTER)), loadCredentials: () => dispatch(loadCredentials(gmp)(ALL_FILTER)), + loadFilters: () => dispatch(loadFilters(gmp)(RESULTS_FILTER_FILTER)), loadScanConfigs: () => dispatch(loadScanConfigs(gmp)(ALL_FILTER)), loadScanners: () => dispatch(loadScanners(gmp)(ALL_FILTER)), loadSchedules: () => dispatch(loadSchedules(gmp)(ALL_FILTER)), loadTags: () => dispatch(loadTags(gmp)(TAGS_FILTER)), loadTargets: () => dispatch(loadTargets(gmp)(ALL_FILTER)), loadUserSettingsDefaults: () => dispatch(loadUserSettingDefaults(gmp)()), + loadReportFormats: () => + dispatch(loadReportFormats(gmp)(REPORT_FORMATS_FILTER)), }); export default compose( withGmp, withCapabilities, + withDownload, + withRouter, connect( mapStateToProps, mapDispatchToProp, diff --git a/gsa/src/web/pages/audits/listpage.js b/gsa/src/web/pages/audits/listpage.js index 479d9b76fa..f0998cd810 100644 --- a/gsa/src/web/pages/audits/listpage.js +++ b/gsa/src/web/pages/audits/listpage.js @@ -33,7 +33,7 @@ import { import EntitiesPage from 'web/entities/page'; import withEntitiesContainer from 'web/entities/withEntitiesContainer'; -import DashboardControls from 'web/components/dashboard/controls'; +// import DashboardControls from 'web/components/dashboard/controls'; import ManualIcon from 'web/components/icon/manualicon'; @@ -41,7 +41,7 @@ import IconDivider from 'web/components/layout/icondivider'; import {DEFAULT_RELOAD_INTERVAL_ACTIVE} from 'web/utils/constants'; -import NewIconMenu from 'web/pages/tasks/icons/newiconmenu'; +// import NewIconMenu from 'web/pages/tasks/icons/newiconmenu'; import AuditComponent from './component'; // import TaskDashboard, {TASK_DASHBOARD_ID} from './dashboard'; @@ -89,6 +89,7 @@ const Page = ({ onDownloadError={onError} onInteraction={onInteraction} // onModifyTaskWizardSaved={onChanged} + // on Report Dowloaded??? onReportImported={onChanged} onResumed={onChanged} onResumeError={onError} @@ -109,7 +110,9 @@ const Page = ({ start, stop, resume, + reportDownload, reportimport, + gcrFormatDefined, // advancedtaskwizard, // modifytaskwizard, // taskwizard, @@ -132,6 +135,7 @@ const Page = ({ filter={filter} filterEditDialog={TaskFilterDialog} filtersFilter={TASKS_FILTER_FILTER} + gcrFormatDefined={gcrFormatDefined} sectionIcon={} table={Table} title={_('Audits')} @@ -142,6 +146,7 @@ const Page = ({ onFilterChanged={onFilterChanged} onInteraction={onInteraction} // onModifyTaskWizardClick={modifytaskwizard} + onReportDownloadClick={reportDownload} onReportImportClick={reportimport} onTaskCloneClick={clone} // onTaskCreateClick={create} diff --git a/gsa/src/web/pages/audits/row.js b/gsa/src/web/pages/audits/row.js index 804c761ab6..5c4eb5408f 100644 --- a/gsa/src/web/pages/audits/row.js +++ b/gsa/src/web/pages/audits/row.js @@ -128,10 +128,7 @@ const Row = ({ {render_report(entity.last_report, links)} - - {/* TODO: Compliance Status Bar */} - - + {/* TODO: Compliance Status Bar */} ); diff --git a/gsa/src/web/pages/audits/table.js b/gsa/src/web/pages/audits/table.js index ae48f11e93..be607498b5 100644 --- a/gsa/src/web/pages/audits/table.js +++ b/gsa/src/web/pages/audits/table.js @@ -51,7 +51,7 @@ const Header = ({ return ( - + - {/* TODO: sort by compliance status*/} - + {/* TODO: compliance status*/} {actionsColumn} From 16b15327479a43773c092c1e749a5f962ccaf2bd Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Tue, 18 Jun 2019 16:35:09 +0200 Subject: [PATCH 07/66] add create and import policy --- gsa/src/web/pages/policies/component.js | 33 ++++---- gsa/src/web/pages/policies/dialog.js | 108 ++++++++++++++++++++++++ gsa/src/web/pages/policies/listpage.js | 10 ++- 3 files changed, 131 insertions(+), 20 deletions(-) create mode 100644 gsa/src/web/pages/policies/dialog.js diff --git a/gsa/src/web/pages/policies/component.js b/gsa/src/web/pages/policies/component.js index e371d3f887..1205d21bd7 100644 --- a/gsa/src/web/pages/policies/component.js +++ b/gsa/src/web/pages/policies/component.js @@ -42,7 +42,7 @@ import { OPENVAS_DEFAULT_SCANNER_ID, OPENVAS_SCANNER_TYPE, } from 'gmp/models/scanner'; -import {FULL_AND_FAST_SCAN_CONFIG_ID} from 'gmp/models/scanconfig'; +// import {FULL_AND_FAST_SCAN_CONFIG_ID} from 'gmp/models/scanconfig'; import { loadEntities as loadScanConfigs, @@ -82,7 +82,7 @@ import EditScanConfigDialog from 'web/pages/scanconfigs/editdialog'; import EditNvtDetailsDialog from 'web/pages/scanconfigs/editnvtdetailsdialog'; import AuditDialog from './createauditdialog'; import ImportDialog from 'web/pages/scanconfigs/importdialog'; -import ScanConfigDialog from 'web/pages/scanconfigs/dialog'; +import ScanConfigDialog from 'web/pages/policies/dialog'; import TargetComponent from 'web/pages/targets/component'; @@ -105,7 +105,7 @@ class PolicyComponent extends React.Component { super(...args); this.state = { - //createConfigDialogVisible: false, + createConfigDialogVisible: false, editConfigDialogVisible: false, editConfigFamilyDialogVisible: false, editNvtDetailsDialogVisible: false, @@ -116,10 +116,10 @@ class PolicyComponent extends React.Component { this.handleImportConfig = this.handleImportConfig.bind(this); this.handleSaveConfigFamily = this.handleSaveConfigFamily.bind(this); this.handleSaveConfigNvt = this.handleSaveConfigNvt.bind(this); - /* this.openCreateConfigDialog = this.openCreateConfigDialog.bind(this); + this.openCreateConfigDialog = this.openCreateConfigDialog.bind(this); this.handleCloseCreateConfigDialog = this.handleCloseCreateConfigDialog.bind( this, - ); */ + ); this.openEditConfigDialog = this.openEditConfigDialog.bind(this); this.handleCloseEditConfigDialog = this.handleCloseEditConfigDialog.bind( this, @@ -183,7 +183,7 @@ class PolicyComponent extends React.Component { this.handleInteraction(); } - /* openCreateConfigDialog() { + openCreateConfigDialog() { this.loadScanners().then(state => this.setState({ ...state, @@ -201,7 +201,7 @@ class PolicyComponent extends React.Component { handleCloseCreateConfigDialog() { this.closeCreateConfigDialog(); this.handleInteraction(); - } */ + } openImportDialog() { this.setState({importDialogVisible: true}); @@ -223,7 +223,7 @@ class PolicyComponent extends React.Component { // console.log(config); this.props.loadScanConfigs(); - //this.props.loadScanners(); + // this.props.loadScanners(); this.props.loadTargets(); this.props.loadTags(); @@ -235,7 +235,7 @@ class PolicyComponent extends React.Component { defaultTargetId, } = this.props; - //console.log('defaults', defaultAlertId, defaultScheduleId, defaultTargetId); + // console.log('defaults', defaultAlertId, defaultScheduleId, defaultTargetId); // console.log('default=', defaultScannerId); // const alert_ids = isDefined(defaultAlertId) ? [defaultAlertId] : []; @@ -249,8 +249,8 @@ class PolicyComponent extends React.Component { // auto_delete_data: undefined, comment: '', // config_id: defaultScanConfigId, - //config_id: isDefined(config) ? config.id : defaultScanConfigId, - config_id: isDefined(config) ? config.id : undefined, //must not use default because the scanconfig has to be the policy + // config_id: isDefined(config) ? config.id : defaultScanConfigId, + config_id: isDefined(config) ? config.id : undefined, // must not use default because the scanconfig has to be the policy // hosts_ordering: undefined, // id: undefined, // in_assets: undefined, @@ -263,7 +263,7 @@ class PolicyComponent extends React.Component { // schedule_periods: undefined, // source_iface: undefined, target_id: defaultTargetId, - //task: undefined, + // task: undefined, title: _('New Task'), }); @@ -610,7 +610,7 @@ class PolicyComponent extends React.Component { comment, config, config_name, - //createConfigDialogVisible, + createConfigDialogVisible, createAuditDialogVisible, editConfigDialogVisible, editConfigFamilyDialogVisible, @@ -657,7 +657,8 @@ class PolicyComponent extends React.Component { {children({ ...other, - create: this.openCreateAuditDialog, + createAudit: this.openCreateAuditDialog, + create: this.openCreateConfigDialog, edit: this.openEditConfigDialog, import: this.openImportDialog, })} @@ -678,7 +679,7 @@ class PolicyComponent extends React.Component { )} )} - {/* {createConfigDialogVisible && ( + {createConfigDialogVisible && ( this.closeCreateConfigDialog()); }} /> - )} */} + )} {editConfigDialogVisible && ( { + const data = { + base, + comment, + name, + scanner_id, + }; + + return ( + + {({values: state, onValueChange}) => { + return ( + + + + + + + + + + ); + }} + + ); +}; + +Dialog.propTypes = { + base: PropTypes.oneOf([ + FULL_AND_FAST_SCAN_CONFIG_ID, + EMPTY_SCAN_CONFIG_ID, + '0', + ]), + comment: PropTypes.string, + name: PropTypes.string, + scanner_id: PropTypes.id, + scanners: PropTypes.array, + title: PropTypes.string, + onClose: PropTypes.func.isRequired, + onSave: PropTypes.func.isRequired, +}; + +export default Dialog; + +// vim: set ts=2 sw=2 tw=80: diff --git a/gsa/src/web/pages/policies/listpage.js b/gsa/src/web/pages/policies/listpage.js index ab9ba9ae96..bc9caaeb99 100644 --- a/gsa/src/web/pages/policies/listpage.js +++ b/gsa/src/web/pages/policies/listpage.js @@ -53,12 +53,12 @@ const ToolBarIcons = withCapabilities( anchor="scan-configuration" title={_('Help: Scan Configs')} /> - {/* {capabilities.mayCreate('config') && ( + {capabilities.mayCreate('config') && ( - )} */} + )} {capabilities.mayCreate('config') && ( )} @@ -67,8 +67,8 @@ const ToolBarIcons = withCapabilities( ); ToolBarIcons.propTypes = { - //onScanConfigCreateClick: PropTypes.func.isRequired, onPolicyImportClick: PropTypes.func.isRequired, + onScanConfigCreateClick: PropTypes.func.isRequired, }; const ScanConfigFilterDialog = createFilterDialog({ @@ -97,6 +97,7 @@ const PoliciesPage = ({ {({ clone, create, + createAudit, delete: delete_func, download, edit, @@ -114,7 +115,8 @@ const PoliciesPage = ({ onInteraction={onInteraction} onPolicyImportClick={import_func} onScanConfigCloneClick={clone} - onCreateAuditClick={create} + onScanConfigCreateClick={create} + onCreateAuditClick={createAudit} onScanConfigDeleteClick={delete_func} onScanConfigDownloadClick={download} onScanConfigEditClick={edit} From 900c815020a188eb7c3fe143219c04d6a3d3622c Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Wed, 19 Jun 2019 12:32:44 +0200 Subject: [PATCH 08/66] clean up policy files and add basis for detailspage --- gsa/src/web/pages/policies/component.js | 34 +- gsa/src/web/pages/policies/details.js | 101 +++++ gsa/src/web/pages/policies/detailspage.js | 443 ++++++++++++++++++++++ gsa/src/web/pages/policies/listpage.js | 21 +- gsa/src/web/pages/policies/row.js | 38 +- gsa/src/web/pages/policies/table.js | 6 +- gsa/src/web/routes.js | 2 + 7 files changed, 595 insertions(+), 50 deletions(-) create mode 100644 gsa/src/web/pages/policies/details.js create mode 100644 gsa/src/web/pages/policies/detailspage.js diff --git a/gsa/src/web/pages/policies/component.js b/gsa/src/web/pages/policies/component.js index 1205d21bd7..c415785edd 100644 --- a/gsa/src/web/pages/policies/component.js +++ b/gsa/src/web/pages/policies/component.js @@ -82,7 +82,7 @@ import EditScanConfigDialog from 'web/pages/scanconfigs/editdialog'; import EditNvtDetailsDialog from 'web/pages/scanconfigs/editnvtdetailsdialog'; import AuditDialog from './createauditdialog'; import ImportDialog from 'web/pages/scanconfigs/importdialog'; -import ScanConfigDialog from 'web/pages/policies/dialog'; +import PolicyDialog from 'web/pages/policies/dialog'; import TargetComponent from 'web/pages/targets/component'; @@ -105,7 +105,7 @@ class PolicyComponent extends React.Component { super(...args); this.state = { - createConfigDialogVisible: false, + createPolicyDialogVisible: false, editConfigDialogVisible: false, editConfigFamilyDialogVisible: false, editNvtDetailsDialogVisible: false, @@ -116,8 +116,8 @@ class PolicyComponent extends React.Component { this.handleImportConfig = this.handleImportConfig.bind(this); this.handleSaveConfigFamily = this.handleSaveConfigFamily.bind(this); this.handleSaveConfigNvt = this.handleSaveConfigNvt.bind(this); - this.openCreateConfigDialog = this.openCreateConfigDialog.bind(this); - this.handleCloseCreateConfigDialog = this.handleCloseCreateConfigDialog.bind( + this.openCreatePolicyDialog = this.openCreatePolicyDialog.bind(this); + this.handleCloseCreatePolicyDialog = this.handleCloseCreatePolicyDialog.bind( this, ); this.openEditConfigDialog = this.openEditConfigDialog.bind(this); @@ -183,23 +183,23 @@ class PolicyComponent extends React.Component { this.handleInteraction(); } - openCreateConfigDialog() { + openCreatePolicyDialog() { this.loadScanners().then(state => this.setState({ ...state, - createConfigDialogVisible: true, + createPolicyDialogVisible: true, }), ); this.handleInteraction(); } - closeCreateConfigDialog() { - this.setState({createConfigDialogVisible: false}); + closeCreatePolicyDialog() { + this.setState({createPolicyDialogVisible: false}); } - handleCloseCreateConfigDialog() { - this.closeCreateConfigDialog(); + handleCloseCreatePolicyDialog() { + this.closeCreatePolicyDialog(); this.handleInteraction(); } @@ -264,7 +264,7 @@ class PolicyComponent extends React.Component { // source_iface: undefined, target_id: defaultTargetId, // task: undefined, - title: _('New Task'), + title: _('New Audit'), }); this.handleInteraction(); @@ -610,7 +610,7 @@ class PolicyComponent extends React.Component { comment, config, config_name, - createConfigDialogVisible, + createPolicyDialogVisible, createAuditDialogVisible, editConfigDialogVisible, editConfigFamilyDialogVisible, @@ -658,7 +658,7 @@ class PolicyComponent extends React.Component { {children({ ...other, createAudit: this.openCreateAuditDialog, - create: this.openCreateConfigDialog, + create: this.openCreatePolicyDialog, edit: this.openEditConfigDialog, import: this.openImportDialog, })} @@ -679,14 +679,14 @@ class PolicyComponent extends React.Component { )} )} - {createConfigDialogVisible && ( - { this.handleInteraction(); - return save(d).then(() => this.closeCreateConfigDialog()); + return save(d).then(() => this.closeCreatePolicyDialog()); }} /> )} diff --git a/gsa/src/web/pages/policies/details.js b/gsa/src/web/pages/policies/details.js new file mode 100644 index 0000000000..dbbcbc1501 --- /dev/null +++ b/gsa/src/web/pages/policies/details.js @@ -0,0 +1,101 @@ +/* Copyright (C) 2017-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 {isDefined} from 'gmp/utils/identity'; + +import {OSP_SCAN_CONFIG_TYPE} from 'gmp/models/scanconfig'; + +import PropTypes from 'web/utils/proptypes'; + +import Divider from 'web/components/layout/divider'; +import Layout from 'web/components/layout/layout'; + +import DetailsLink from 'web/components/link/detailslink'; + +import InfoTable from 'web/components/table/infotable'; +import TableBody from 'web/components/table/body'; +import TableData from 'web/components/table/data'; +import TableRow from 'web/components/table/row'; + +import {Col} from 'web/entity/page'; + +const PolicyDetails = ({entity}) => { + const {comment, scan_config_type, scanner, tasks = []} = entity; + return ( + + + + + + + + {isDefined(comment) && ( + + {_('Comment')} + {comment} + + )} + {scan_config_type === OSP_SCAN_CONFIG_TYPE && isDefined(scanner) && ( + + {_('Scanner')} + + + + {scanner.name} + + + + + )} + + {tasks.length > 0 && ( + + {_('Tasks using this Policy')} + + + {tasks.map((task, index) => { + return ( + + + {task.name} + + {index !== tasks.length - 1 && ','} + + ); + })} + + + + )} + + + + ); +}; + +PolicyDetails.propTypes = { + entity: PropTypes.model.isRequired, +}; + +export default PolicyDetails; + +// vim: set ts=2 sw=2 tw=80: diff --git a/gsa/src/web/pages/policies/detailspage.js b/gsa/src/web/pages/policies/detailspage.js new file mode 100644 index 0000000000..7009d08282 --- /dev/null +++ b/gsa/src/web/pages/policies/detailspage.js @@ -0,0 +1,443 @@ +/* Copyright (C) 2017-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 styled from 'styled-components'; + +import DetailsLink from 'web/components/link/detailslink'; + +import Divider from 'web/components/layout/divider'; +import IconDivider from 'web/components/layout/icondivider'; +import Layout from 'web/components/layout/layout'; + +import ExportIcon from 'web/components/icon/exporticon'; +import ManualIcon from 'web/components/icon/manualicon'; +// import UploadIcon from 'web/components/icon/uploadicon'; +import ListIcon from 'web/components/icon/listicon'; +import ScanConfigIcon from 'web/components/icon/scanconfigicon'; + +import Link from 'web/components/link/link'; + +import StripedTable from 'web/components/table/stripedtable'; +import TableBody from 'web/components/table/body'; +import TableData from 'web/components/table/data'; +import TableHead from 'web/components/table/head'; +import TableHeader from 'web/components/table/header'; +import TableRow from 'web/components/table/row'; + +import Tab from 'web/components/tab/tab'; +import TabLayout from 'web/components/tab/tablayout'; +import TabList from 'web/components/tab/tablist'; +import TabPanel from 'web/components/tab/tabpanel'; +import TabPanels from 'web/components/tab/tabpanels'; +import Tabs from 'web/components/tab/tabs'; + +import EntityPage from 'web/entity/page'; +import {goto_details, goto_list} from 'web/entity/component'; +import EntityPermissions from 'web/entity/permissions'; +import EntitiesTab from 'web/entity/tab'; +import EntityTags from 'web/entity/tags'; +import withEntityContainer, { + permissionsResourceFilter, +} from 'web/entity/withEntityContainer'; + +import CloneIcon from 'web/entity/icon/cloneicon'; +// import CreateIcon from 'web/entity/icon/createicon'; +import EditIcon from 'web/entity/icon/editicon'; +import TrashIcon from 'web/entity/icon/trashicon'; + +import {selector, loadEntity} from 'web/store/entities/scanconfigs'; + +import { + selector as permissionsSelector, + loadEntities as loadPermissions, +} from 'web/store/entities/permissions'; + +import PropTypes from 'web/utils/proptypes'; +import withCapabilities from 'web/utils/withCapabilities'; + +import PolicyDetails from './details'; +import PolicyComponent from './component'; +import Trend from 'web/pages/scanconfigs/trend'; + +const ToolBarIcons = withCapabilities( + ({ + capabilities, + entity, + onPolicyCloneClick, + // onPolicyCreateClick, + onPolicyDeleteClick, + onPolicyDownloadClick, + onPolicyEditClick, + // onPolicyImportClick, + }) => ( + + + + + + + {/* */} + + + + + {/* {capabilities.mayCreate('config') && ( + + )} */} + + + ), +); + +ToolBarIcons.propTypes = { + entity: PropTypes.model.isRequired, + onPolicyCloneClick: PropTypes.func.isRequired, + // onPolicyCreateClick: PropTypes.func.isRequired, + onPolicyDeleteClick: PropTypes.func.isRequired, + onPolicyDownloadClick: PropTypes.func.isRequired, + onPolicyEditClick: PropTypes.func.isRequired, + // onPolicyImportClick: PropTypes.func.isRequired, +}; + +const NvtFamilies = ({entity}) => { + const {family_list = [], families} = entity; + return ( + + {family_list.length > 0 && ( + + + + {_('Family')} + {_('NVTs selected')} + + + {_('Trend')} + + + + + + + {family_list.map(family => ( + + + + + {family.name} + + + + + {_('{{count}} of {{max}}', family.nvts)} + + + + + + ))} + + + )} + + ); +}; + +NvtFamilies.propTypes = { + entity: PropTypes.model.isRequired, +}; + +const ScannerPreferences = ({entity}) => { + const {preferences} = entity; + + return ( + + {preferences.scanner.length > 0 && ( + + + + {_('Name')} + {_('Value')} + {_('Default Value')} + + + + {preferences.scanner.map(pref => ( + + {pref.name} + {pref.value} + {pref.default} + + ))} + + + )} + + ); +}; + +ScannerPreferences.propTypes = { + entity: PropTypes.model.isRequired, +}; + +const StyledTableData = styled(TableData)` + word-break: break-all; +`; + +const NvtPreferences = ({entity}) => { + const {preferences} = entity; + + return ( + + {preferences.nvt.length > 0 && ( + + + + {_('NVT')} + {_('Name')} + {_('Value')} + {_('Default Value')} + + + + {preferences.nvt.map(pref => ( + + + + + {pref.nvt.name} + + + + {pref.name} + {pref.value} + {pref.default} + + ))} + + + )} + + ); +}; + +NvtPreferences.propTypes = { + entity: PropTypes.model.isRequired, +}; + +const Details = ({entity, ...props}) => { + return ( + + + + ); +}; + +Details.propTypes = { + entity: PropTypes.model.isRequired, +}; + +const Page = ({ + entity, + permissions = [], + onChanged, + onDownloaded, + onError, + onInteraction, + ...props +}) => { + return ( + + {({ + clone, + create, + delete: delete_func, + download, + edit, + // import: import_func, + save, + }) => ( + } + toolBarIcons={ToolBarIcons} + title={_('Policy')} + onInteraction={onInteraction} + onPolicyCloneClick={clone} + onPolicyCreateClick={create} + onPolicyDeleteClick={delete_func} + onPolicyDownloadClick={download} + onPolicyEditClick={edit} + onPolicySaveClick={save} + // onPolicyImportClick={import_func} + > + {({activeTab = 0, onActivateTab}) => { + const {preferences} = entity; + return ( + + + + {_('Information')} + + {_('Scanner Preferences')} + + + {_('NVT Families')} + + + {_('NVT Preferences')} + + + {_('User Tags')} + + + {_('Permissions')} + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + ); + }} + + )} + + ); +}; + +Page.propTypes = { + entity: PropTypes.model, + permissions: PropTypes.array, + onChanged: PropTypes.func.isRequired, + onDownloaded: PropTypes.func.isRequired, + onError: PropTypes.func.isRequired, + onInteraction: PropTypes.func.isRequired, +}; + +const load = gmp => { + const loadEntityFunc = loadEntity(gmp); + const loadPermissionsFunc = loadPermissions(gmp); + return id => dispatch => + Promise.all([ + dispatch(loadEntityFunc(id)), + dispatch(loadPermissionsFunc(permissionsResourceFilter(id))), + ]); +}; + +const mapStateToProps = (rootState, {id}) => { + const permissionsSel = permissionsSelector(rootState); + return { + permissions: permissionsSel.getEntities(permissionsResourceFilter(id)), + }; +}; + +export default withEntityContainer('scanconfig', { + entitySelector: selector, + load, + mapStateToProps, +})(Page); + +// vim: set ts=2 sw=2 tw=80: diff --git a/gsa/src/web/pages/policies/listpage.js b/gsa/src/web/pages/policies/listpage.js index bc9caaeb99..2fba8ac880 100644 --- a/gsa/src/web/pages/policies/listpage.js +++ b/gsa/src/web/pages/policies/listpage.js @@ -46,18 +46,15 @@ import PoliciesComponent from './component'; import Table, {SORT_FIELDS} from './table'; const ToolBarIcons = withCapabilities( - ({capabilities, onScanConfigCreateClick, onPolicyImportClick}) => ( + ({capabilities, onPolicyCreateClick, onPolicyImportClick}) => ( {capabilities.mayCreate('config') && ( - + )} {capabilities.mayCreate('config') && ( @@ -67,8 +64,8 @@ const ToolBarIcons = withCapabilities( ); ToolBarIcons.propTypes = { + onPolicyCreateClick: PropTypes.func.isRequired, onPolicyImportClick: PropTypes.func.isRequired, - onScanConfigCreateClick: PropTypes.func.isRequired, }; const ScanConfigFilterDialog = createFilterDialog({ @@ -114,12 +111,12 @@ const PoliciesPage = ({ onError={onError} onInteraction={onInteraction} onPolicyImportClick={import_func} - onScanConfigCloneClick={clone} - onScanConfigCreateClick={create} + onPolicyCloneClick={clone} + onPolicyCreateClick={create} onCreateAuditClick={createAudit} - onScanConfigDeleteClick={delete_func} - onScanConfigDownloadClick={download} - onScanConfigEditClick={edit} + onPolicyDeleteClick={delete_func} + onPolicyDownloadClick={download} + onPolicyEditClick={edit} /> )} diff --git a/gsa/src/web/pages/policies/row.js b/gsa/src/web/pages/policies/row.js index 6d9ca18341..504fa2a7fe 100644 --- a/gsa/src/web/pages/policies/row.js +++ b/gsa/src/web/pages/policies/row.js @@ -44,40 +44,40 @@ const PoliciesActions = compose( )( ({ entity, - onScanConfigDeleteClick, - onScanConfigDownloadClick, - onScanConfigCloneClick, - onScanConfigEditClick, + onPolicyDeleteClick, + onPolicyDownloadClick, + onPolicyCloneClick, + onPolicyEditClick, onCreateAuditClick, capabilities, }) => ( - {capabilities.mayCreate('config') && ( + {capabilities.mayCreate('task') && ( diff --git a/gsa/src/web/pages/policies/table.js b/gsa/src/web/pages/policies/table.js index 9ec77f7fd6..d807ced2cf 100644 --- a/gsa/src/web/pages/policies/table.js +++ b/gsa/src/web/pages/policies/table.js @@ -24,6 +24,7 @@ import withRowDetails from 'web/entities/withRowDetails'; import Header from './header'; import Row from './row'; +// import PolicyDetails from 'web/pages/policies/details'; import ScanConfigDetails from 'web/pages/scanconfigs/details'; export const SORT_FIELDS = [ @@ -34,12 +35,13 @@ export const SORT_FIELDS = [ ]; const PoliciesTable = createEntitiesTable({ - emptyTitle: _l('No Scan Configs available'), + emptyTitle: _l('No Policies available'), header: Header, row: Row, + // rowDetails: withRowDetails('policy')(PolicyDetails), rowDetails: withRowDetails('scanconfig')(ScanConfigDetails), footer: createEntitiesFooter({ - download: 'scanconfigs.xml', + download: 'policies.xml', span: 7, trash: true, }), diff --git a/gsa/src/web/routes.js b/gsa/src/web/routes.js index 14ac8a3bd9..476c2342d3 100644 --- a/gsa/src/web/routes.js +++ b/gsa/src/web/routes.js @@ -73,6 +73,7 @@ import PerformancePage from './pages/performance/performancepage'; import PermissionsPage from './pages/permissions/listpage'; import PermissionDetailsPage from './pages/permissions/detailspage'; import PoliciesPage from './pages/policies/listpage'; +import PoliciesDetailsPage from './pages/policies/detailspage'; import PortListsPage from './pages/portlists/listpage'; import PortListDetailsPage from './pages/portlists/detailspage'; import RadiusPage from './pages/radius/radiuspage'; @@ -198,6 +199,7 @@ const Routes = () => ( + From d2755d20cc2ad5491261b2e2b499bca0262873e4 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Thu, 20 Jun 2019 13:23:18 +0200 Subject: [PATCH 09/66] clean up audit files and add basis for detailspage --- gsa/src/web/pages/audits/actions.js | 27 +- gsa/src/web/pages/audits/component.js | 108 ++-- gsa/src/web/pages/audits/details.js | 361 +++++++++++++ gsa/src/web/pages/audits/detailspage.js | 513 +++++++++++++++++++ gsa/src/web/pages/audits/dialog.js | 2 +- gsa/src/web/pages/audits/icons/resumeicon.js | 81 +++ gsa/src/web/pages/audits/icons/starticon.js | 53 ++ gsa/src/web/pages/audits/table.js | 4 +- 8 files changed, 1081 insertions(+), 68 deletions(-) create mode 100644 gsa/src/web/pages/audits/details.js create mode 100644 gsa/src/web/pages/audits/detailspage.js create mode 100644 gsa/src/web/pages/audits/icons/resumeicon.js create mode 100644 gsa/src/web/pages/audits/icons/starticon.js diff --git a/gsa/src/web/pages/audits/actions.js b/gsa/src/web/pages/audits/actions.js index 7cdbef0188..5b29f1a7fa 100644 --- a/gsa/src/web/pages/audits/actions.js +++ b/gsa/src/web/pages/audits/actions.js @@ -34,9 +34,9 @@ import TrashIcon from 'web/entity/icon/trashicon'; import DownloadIcon from 'web/components/icon/downloadicon'; import ImportReportIcon from 'web/pages/tasks/icons/importreporticon'; -import ResumeIcon from 'web/pages/tasks/icons/resumeicon'; +import ResumeIcon from 'web/pages/audits/icons/resumeicon'; import ScheduleIcon from 'web/pages/tasks/icons/scheduleicon'; -import StartIcon from 'web/pages/tasks/icons/starticon'; +import StartIcon from 'web/pages/audits/icons/starticon'; import StopIcon from 'web/pages/tasks/icons/stopicon'; import PropTypes from 'web/utils/proptypes'; @@ -68,12 +68,27 @@ const Actions = ({ - - - + + + { return format.name === 'GCR PDF'; }); - const gcrFormatDefined = isDefined(gcrFormat); + const gcrFormatDefined = isDefined(gcrFormat) + ? gcrFormat.active === 1 && gcrFormat.trust.value === 'yes' + : false; this.setState({gcrFormatDefined: gcrFormatDefined}); } } @@ -357,7 +349,7 @@ class TaskComponent extends React.Component { source_iface, }) .then(onSaved, onSaveError) - .then(() => this.closeTaskDialog()); + .then(() => this.closeAuditDialog()); } const {onCreated, onCreateError} = this.props; @@ -386,27 +378,27 @@ class TaskComponent extends React.Component { target_id, }) .then(onCreated, onCreateError) - .then(() => this.closeTaskDialog()); + .then(() => this.closeAuditDialog()); } - openTaskDialog(task) { + openAuditDialog(task) { if (isDefined(task) && task.isContainer()) { this.openContainerTaskDialog(task); } else { - this.openStandardTaskDialog(task); + this.openStandardAuditDialog(task); } } - closeTaskDialog() { - this.setState({taskDialogVisible: false}); + closeAuditDialog() { + this.setState({auditDialogVisible: false}); } - handleCloseTaskDialog() { - this.closeTaskDialog(); + handleCloseAuditDialog() { + this.closeAuditDialog(); this.handleInteraction(); } - openStandardTaskDialog(task) { + openStandardAuditDialog(task) { const {capabilities} = this.props; this.props.loadAlerts(); @@ -425,7 +417,7 @@ class TaskComponent extends React.Component { : undefined; this.setState({ - taskDialogVisible: true, + auditDialogVisible: true, alert_ids: map(task.alerts, alert => alert.id), alterable: task.alterable, apply_overrides: task.apply_overrides, @@ -446,7 +438,7 @@ class TaskComponent extends React.Component { source_iface: task.source_iface, target_id: hasId(task.target) ? task.target.id : undefined, task, - title: _('Edit Task {{name}}', task), + title: _('Edit Audit {{name}}', task), }); } else { const { @@ -460,7 +452,7 @@ class TaskComponent extends React.Component { const alert_ids = isDefined(defaultAlertId) ? [defaultAlertId] : []; this.setState({ - taskDialogVisible: true, + auditDialogVisible: true, alert_ids, alterable: undefined, apply_overrides: undefined, @@ -481,7 +473,7 @@ class TaskComponent extends React.Component { source_iface: undefined, target_id: defaultTargetId, task: undefined, - title: _('New Task'), + title: _('New Audit'), }); } this.handleInteraction(); @@ -583,14 +575,11 @@ class TaskComponent extends React.Component { onDownloaded, onDownloadError, onInteraction, - // reportFilter, - // reportFormats, - // reportComposerDefaults, } = this.props; const { - advancedTaskWizardVisible, - alert_id, + // advancedTaskWizardVisible, + // alert_id, alert_ids, alterable, apply_overrides, @@ -599,8 +588,8 @@ class TaskComponent extends React.Component { config_id, containerTaskDialogVisible, comment, - esxi_credential, - hosts, + // esxi_credential, + // hosts, hosts_ordering, id, in_assets, @@ -608,33 +597,33 @@ class TaskComponent extends React.Component { max_checks, max_hosts, min_qod, - modifyTaskWizardVisible, + // modifyTaskWizardVisible, name, - port_list_id, + // port_list_id, reportImportDialogVisible, - reschedule, + // reschedule, scanner_id, schedule_id, schedule_periods, // showDownloadReportDialog, source_iface, - ssh_credential, - smb_credential, - start_date, - start_minute, - start_hour, - start_timezone, + // ssh_credential, + // smb_credential, + // start_date, + // start_minute, + // start_hour, + // start_timezone, // storeAsDefault, tag_id, target_id, - target_hosts, + // target_hosts, task_id, - task_name, + // task_name, task, tasks, - taskDialogVisible, - taskWizardVisible, - title = _('Edit Task {{name}}', task), + auditDialogVisible, + // taskWizardVisible, + title = _('Edit Audit {{name}}', task), } = this.state; return ( @@ -654,19 +643,18 @@ class TaskComponent extends React.Component { {children({ ...other, - create: this.openTaskDialog, + create: this.openAuditDialog, createcontainer: this.openContainerTaskDialog, - edit: this.openTaskDialog, + edit: this.openAuditDialog, start: this.handleTaskStart, stop: this.handleTaskStop, resume: this.handleTaskResume, reportimport: this.openReportImportDialog, - //reportDownload: this.handleOpenDownloadReportDialog, reportDownload: this.handleReportDownloadClick, gcrFormatDefined: gcrFormatDefined, })} - {taskDialogVisible && ( + {auditDialogVisible && ( {({create: createschedule}) => ( - )} @@ -779,12 +767,14 @@ TaskComponent.propTypes = { gmp: PropTypes.gmp.isRequired, loadAlerts: PropTypes.func.isRequired, loadCredentials: PropTypes.func.isRequired, + loadReportFormats: PropTypes.func.isRequired, loadScanConfigs: PropTypes.func.isRequired, loadScanners: PropTypes.func.isRequired, loadSchedules: PropTypes.func.isRequired, loadTags: PropTypes.func.isRequired, loadTargets: PropTypes.func.isRequired, loadUserSettingsDefaults: PropTypes.func.isRequired, + reportFormats: PropTypes.array, scanConfigs: PropTypes.arrayOf(PropTypes.model), scanners: PropTypes.arrayOf(PropTypes.model), schedules: PropTypes.arrayOf(PropTypes.model), @@ -803,6 +793,7 @@ TaskComponent.propTypes = { onCreated: PropTypes.func, onDeleteError: PropTypes.func, onDeleted: PropTypes.func, + onDownload: PropTypes.func.isRequired, onDownloadError: PropTypes.func, onDownloaded: PropTypes.func, onInteraction: PropTypes.func.isRequired, @@ -863,7 +854,6 @@ const mapStateToProps = (rootState, {match}) => { const mapDispatchToProp = (dispatch, {gmp}) => ({ loadAlerts: () => dispatch(loadAlerts(gmp)(ALL_FILTER)), loadCredentials: () => dispatch(loadCredentials(gmp)(ALL_FILTER)), - loadFilters: () => dispatch(loadFilters(gmp)(RESULTS_FILTER_FILTER)), loadScanConfigs: () => dispatch(loadScanConfigs(gmp)(ALL_FILTER)), loadScanners: () => dispatch(loadScanners(gmp)(ALL_FILTER)), loadSchedules: () => dispatch(loadSchedules(gmp)(ALL_FILTER)), diff --git a/gsa/src/web/pages/audits/details.js b/gsa/src/web/pages/audits/details.js new file mode 100644 index 0000000000..e7db64d187 --- /dev/null +++ b/gsa/src/web/pages/audits/details.js @@ -0,0 +1,361 @@ +/* Copyright (C) 2017-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 {connect} from 'react-redux'; + +import _ from 'gmp/locale'; +import {dateTimeWithTimeZone} from 'gmp/locale/date'; + +import {isDefined} from 'gmp/utils/identity'; + +import {YES_VALUE} from 'gmp/parser'; + +import {duration} from 'gmp/models/date'; +import {OPENVAS_SCAN_CONFIG_TYPE} from 'gmp/models/scanconfig'; +import {scannerTypeName} from 'gmp/models/scanner'; + +import { + loadEntity as loadSchedule, + selector as scheduleSelector, +} from 'web/store/entities/schedules'; + +import { + loadEntity as loadScanConfig, + selector as scanConfigSelector, +} from 'web/store/entities/scanconfigs'; + +import PropTypes from 'web/utils/proptypes'; +import compose from 'web/utils/compose'; +import withGmp from 'web/utils/withGmp'; +import {renderYesNo} from 'web/utils/render'; + +import Divider from 'web/components/layout/divider'; +import Layout from 'web/components/layout/layout'; + +import DetailsLink from 'web/components/link/detailslink'; + +import DetailsTable from 'web/components/table/detailstable'; +import TableBody from 'web/components/table/body'; +import TableData from 'web/components/table/data'; +import TableRow from 'web/components/table/row'; + +import DetailsBlock from 'web/entity/block'; + +const compareAlerts = (alertA, alertB) => { + const nameA = alertA.name.toLowerCase(); + const nameB = alertB.name.toLowerCase(); + if (nameA > nameB) { + return 1; + } + if (nameA < nameB) { + return -1; + } + return 0; +}; + +class AuditDetails extends React.Component { + componentDidMount() { + const {entity} = this.props; + + if (isDefined(entity.config)) { + this.props.loadScanConfig(entity.config.id); + } + if (isDefined(entity.schedule)) { + this.props.loadSchedule(entity.schedule.id); + } + } + + render() { + const {links = true, entity, scanConfig, schedule} = this.props; + const { + alerts, + apply_overrides, + auto_delete, + auto_delete_data, + average_duration, + config, + hosts_ordering, + in_assets, + last_report, + min_qod, + preferences, + scanner, + schedule_periods, + target, + } = entity; + const {max_checks = {}, iface = {}, max_hosts = {}} = preferences; + + let dur; + const has_duration = + isDefined(last_report) && isDefined(last_report.scan_start); + if (has_duration) { + if (isDefined(last_report.scan_end)) { + const diff = last_report.scan_end.diff(last_report.scan_start); + dur = duration(diff).humanize(); + } else { + dur = _('Not finished yet'); + } + } else { + dur = _('No scans yet'); + } + + const has_av_duration = isDefined(average_duration) && average_duration > 0; + const av_duration = has_av_duration ? average_duration.humanize() : ''; + + return ( + + {isDefined(target) && ( + + + {target.name} + + + )} + + {isDefined(alerts) && ( + + + {alerts.sort(compareAlerts).map(alert => ( + + {alert.name} + + ))} + + + )} + + {isDefined(scanner) && ( + + + + + {_('Name')} + + + + {scanner.name} + + + + + + {_('Type')} + {scannerTypeName(scanner.scannerType)} + + {isDefined(config) && ( + + {_('Policy')} + + + + {config.name} + + + + + )} + {isDefined(scanConfig) && + scanConfig.scan_config_type === OPENVAS_SCAN_CONFIG_TYPE && ( + + {_('Order for target hosts')} + {hosts_ordering} + + )} + {isDefined(scanConfig) && + scanConfig.scan_config_type === OPENVAS_SCAN_CONFIG_TYPE && ( + + {_('Network Source Interface')} + {iface.value} + + )} + {isDefined(scanConfig) && + scanConfig.scan_config_type === OPENVAS_SCAN_CONFIG_TYPE && + isDefined(max_checks.name) && ( + + + {_('Maximum concurrently executed NVTs per host')} + + {max_checks.value} + + )} + {isDefined(scanConfig) && + scanConfig.scan_config_type === OPENVAS_SCAN_CONFIG_TYPE && + isDefined(max_hosts.name) && ( + + + {_('Maximum concurrently scanned hosts')} + + {max_hosts.value} + + )} + + + + )} + + + + + + {_('Add to Assets')} + {renderYesNo(in_assets)} + + + {in_assets === YES_VALUE && ( + + {_('Apply to Overrides')} + {renderYesNo(apply_overrides)} + + )} + + {in_assets === YES_VALUE && ( + + {_('Min QoD')} + {min_qod + ' %'} + + )} + + + + + {isDefined(schedule) && ( + + + + + {_('Name')} + + + + {schedule.name} + + + + + {isDefined(schedule.event) && ( + + {_('Next')} + + {dateTimeWithTimeZone(schedule.event.nextDate)} + + + )} + + + + )} + + + + + + {_('Duration of last Scan')} + {dur} + + {has_av_duration && ( + + {_('Average Scan duration')} + {av_duration} + + )} + {schedule_periods > 0 && ( + + {_('Period')} + + {schedule_periods > 1 + ? _('{{nr}} more times', {nr: schedule_periods}) + : _('Once')} + + + )} + + {_('Auto delete Reports')} + + {auto_delete === 'keep' + ? _( + 'Automatically delete oldest reports but always keep ' + + 'newest {{nr}} reports', + {nr: auto_delete_data}, + ) + : _('Do not automatically delete reports')} + + + + + + + ); + } +} + +AuditDetails.propTypes = { + entity: PropTypes.model.isRequired, + gmp: PropTypes.gmp.isRequired, + links: PropTypes.bool, + loadScanConfig: PropTypes.func.isRequired, + loadSchedule: PropTypes.func.isRequired, + scanConfig: PropTypes.model, + schedule: PropTypes.model, +}; + +const mapStateToProps = (rootState, {entity = {}}) => { + const scheduleSel = scheduleSelector(rootState); + const scanConfigSel = scanConfigSelector(rootState); + return { + scanConfig: isDefined(entity.config) + ? scanConfigSel.getEntity(entity.config.id) + : undefined, + schedule: isDefined(entity.schedule) + ? scheduleSel.getEntity(entity.schedule.id) + : undefined, + }; +}; + +const mapDispatchToProps = (dispatch, {gmp}) => ({ + loadScanConfig: id => dispatch(loadScanConfig(gmp)(id)), + loadSchedule: id => dispatch(loadSchedule(gmp)(id)), +}); + +export default compose( + withGmp, + connect( + mapStateToProps, + mapDispatchToProps, + ), +)(AuditDetails); + +// vim: set ts=2 sw=2 tw=80: diff --git a/gsa/src/web/pages/audits/detailspage.js b/gsa/src/web/pages/audits/detailspage.js new file mode 100644 index 0000000000..a85834eaf1 --- /dev/null +++ b/gsa/src/web/pages/audits/detailspage.js @@ -0,0 +1,513 @@ +/* Copyright (C) 2017-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 {shortDate} from 'gmp/locale/date'; + +import Filter from 'gmp/models/filter'; + +import {isDefined} from 'gmp/utils/identity'; + +import {TARGET_CREDENTIAL_NAMES} from 'gmp/models/target'; + +import Badge from 'web/components/badge/badge'; + +import Divider from 'web/components/layout/divider'; +import IconDivider from 'web/components/layout/icondivider'; +import Layout from 'web/components/layout/layout'; + +import DetailsLink from 'web/components/link/detailslink'; +import Link from 'web/components/link/link'; + +import AlterableIcon from 'web/components/icon/alterableicon'; +import ExportIcon from 'web/components/icon/exporticon'; +import ListIcon from 'web/components/icon/listicon'; +import ManualIcon from 'web/components/icon/manualicon'; +import NoteIcon from 'web/components/icon/noteicon'; +import OverrideIcon from 'web/components/icon/overrideicon'; +import ReportIcon from 'web/components/icon/reporticon'; +import ResultIcon from 'web/components/icon/resulticon'; +import TaskIcon from 'web/components/icon/taskicon'; + +import Tab from 'web/components/tab/tab'; +import TabLayout from 'web/components/tab/tablayout'; +import TabList from 'web/components/tab/tablist'; +import TabPanel from 'web/components/tab/tabpanel'; +import TabPanels from 'web/components/tab/tabpanels'; +import Tabs from 'web/components/tab/tabs'; + +import InfoTable from 'web/components/table/infotable'; +import TableBody from 'web/components/table/body'; +import TableData from 'web/components/table/data'; +import TableRow from 'web/components/table/row'; + +import EntityPage, {Col} from 'web/entity/page'; +import EntityPermissions from 'web/entity/permissions'; +import {goto_details, goto_list} from 'web/entity/component'; +import EntitiesTab from 'web/entity/tab'; +import EntityTags from 'web/entity/tags'; +import withEntityContainer, { + permissionsResourceFilter, +} from 'web/entity/withEntityContainer'; + +import CloneIcon from 'web/entity/icon/cloneicon'; +import EditIcon from 'web/entity/icon/editicon'; +import TrashIcon from 'web/entity/icon/trashicon'; + +import { + selector as notesSelector, + loadEntities as loadNotes, +} from 'web/store/entities/notes'; +import { + selector as overridesSelector, + loadEntities as loadOverrides, +} from 'web/store/entities/overrides'; +import { + selector as permissionsSelector, + loadEntities as loadPermissions, +} from 'web/store/entities/permissions'; +import { + selector as taskSelector, + loadEntity as loadTask, +} from 'web/store/entities/tasks'; + +import {DEFAULT_RELOAD_INTERVAL_ACTIVE} from 'web/utils/constants'; +import PropTypes from 'web/utils/proptypes'; +import {renderYesNo} from 'web/utils/render'; +import withComponentDefaults from 'web/utils/withComponentDefaults'; + +// import ImportReportIcon from './icons/importreporticon'; +// import NewIconMenu from './icons/newiconmenu'; +import ResumeIcon from './icons/resumeicon'; +import ScheduleIcon from './icons/scheduleicon'; +import StartIcon from './icons/starticon'; +import StopIcon from './icons/stopicon'; + +import AuditDetails from './details'; +import TaskStatus from 'web/pages/tasks/status'; +import AuditComponent from './component'; + +const ToolBarIcons = ({ + entity, + links, + notes = [], + overrides = [], + onTaskDeleteClick, + onTaskCloneClick, + onTaskDownloadClick, + onTaskEditClick, + // onReportImportClick, + // onTaskCreateClick, + // onContainerTaskCreateClick, + onTaskStartClick, + onTaskStopClick, + onTaskResumeClick, +}) => { + return ( + + + + + {entity.isAlterable() && !entity.isNew() && ( + + )} + + + + {/* */} + + + + + + + + {isDefined(entity.schedule) && ( + + )} + + + {/* */} + + + + {!entity.isContainer() && ( + + )} + + + + + {isDefined(entity.current_report) && ( + + + + )} + + {!isDefined(entity.current_report) && isDefined(entity.last_report) && ( + + + + )} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +ToolBarIcons.propTypes = { + entity: PropTypes.model.isRequired, + links: PropTypes.bool, + notes: PropTypes.array, + overrides: PropTypes.array, + onContainerTaskCreateClick: PropTypes.func.isRequired, + onReportImportClick: PropTypes.func.isRequired, + onTaskCloneClick: PropTypes.func.isRequired, + onTaskCreateClick: PropTypes.func.isRequired, + onTaskDeleteClick: PropTypes.func.isRequired, + onTaskDownloadClick: PropTypes.func.isRequired, + onTaskEditClick: PropTypes.func.isRequired, + onTaskResumeClick: PropTypes.func.isRequired, + onTaskStartClick: PropTypes.func.isRequired, + onTaskStopClick: PropTypes.func.isRequired, +}; + +const Details = ({entity, ...props}) => { + return ( + + + + + + + + + {_('Name')} + {entity.name} + + + + {_('Comment')} + {entity.comment} + + + + {_('Alterable')} + {renderYesNo(entity.isAlterable())} + + + + {_('Status')} + + + + + + + + + + ); +}; + +Details.propTypes = { + entity: PropTypes.model.isRequired, +}; + +const Page = ({ + entity, + permissions = [], + onChanged, + onDownloaded, + onError, + onInteraction, + ...props +}) => ( + + {({ + clone, + create, + createcontainer, + delete: delete_func, + download, + edit, + start, + stop, + resume, + reportimport, + }) => ( + } + title={_('Audit')} + toolBarIcons={ToolBarIcons} + onChanged={onChanged} + onContainerTaskCreateClick={createcontainer} + onError={onError} + onInteraction={onInteraction} + onReportImportClick={reportimport} + onTaskCloneClick={clone} + onTaskCreateClick={create} + onTaskDeleteClick={delete_func} + onTaskDownloadClick={download} + onTaskEditClick={edit} + onTaskResumeClick={resume} + onTaskStartClick={start} + onTaskStopClick={stop} + > + {({activeTab = 0, onActivateTab}) => { + return ( + + + + {_('Information')} + + {_('User Tags')} + + + {_('Permissions')} + + + + + + + +
+ + + + + + + + + + + ); + }} + + )} + +); + +Page.propTypes = { + entity: PropTypes.model, + permissions: PropTypes.array, + onChanged: PropTypes.func.isRequired, + onDownloaded: PropTypes.func.isRequired, + onError: PropTypes.func.isRequired, + onInteraction: PropTypes.func.isRequired, +}; + +const TaskPermissions = withComponentDefaults({ + relatedResourcesLoaders: [ + ({entity, gmp}) => + isDefined(entity.alerts) + ? Promise.resolve([...entity.alerts]) + : Promise.resolve([]), + ({entity, gmp}) => { + const resources = []; + const names = ['config', 'scanner', 'schedule']; + + for (const name of names) { + if (isDefined(entity[name])) { + resources.push(entity[name]); + } + } + return Promise.resolve(resources); + }, + ({entity, gmp}) => { + if (isDefined(entity.target)) { + return gmp.target.get(entity.target).then(response => { + const target = response.data; + const resources = [target]; + + for (const name of ['port_list', ...TARGET_CREDENTIAL_NAMES]) { + const cred = target[name]; + if (isDefined(cred)) { + resources.push(cred); + } + } + return resources; + }); + } + return Promise.resolve([]); + }, + ], +})(EntityPermissions); + +const taskIdFilter = id => Filter.fromString('task_id=' + id).all(); + +const mapStateToProps = (rootState, {id}) => { + const permSel = permissionsSelector(rootState); + const notesSel = notesSelector(rootState); + const overridesSel = overridesSelector(rootState); + return { + notes: notesSel.getEntities(taskIdFilter(id)), + overrides: overridesSel.getEntities(taskIdFilter(id)), + permissions: permSel.getEntities(permissionsResourceFilter(id)), + }; +}; + +const load = gmp => { + const loadTaskFunc = loadTask(gmp); + const loadPermissionsFunc = loadPermissions(gmp); + const loadNotesFunc = loadNotes(gmp); + const loadOverridesFunc = loadOverrides(gmp); + return id => dispatch => + Promise.all([ + dispatch(loadTaskFunc(id)), + dispatch(loadPermissionsFunc(permissionsResourceFilter(id))), + dispatch(loadNotesFunc(taskIdFilter(id))), + dispatch(loadOverridesFunc(taskIdFilter(id))), + ]); +}; + +const reloadInterval = ({defaultReloadInterval, entity}) => { + if (!isDefined(entity)) { + return 0; + } + return entity.isActive() + ? DEFAULT_RELOAD_INTERVAL_ACTIVE + : defaultReloadInterval; +}; + +export default withEntityContainer('task', { + load, + entitySelector: taskSelector, + mapStateToProps, + reloadInterval, +})(Page); + +// vim: set ts=2 sw=2 tw=80: diff --git a/gsa/src/web/pages/audits/dialog.js b/gsa/src/web/pages/audits/dialog.js index 11a9c04e66..253b6fcb3c 100644 --- a/gsa/src/web/pages/audits/dialog.js +++ b/gsa/src/web/pages/audits/dialog.js @@ -209,7 +209,7 @@ const TaskDialog = ({ target_id, targets, task, - title = _('New Task'), + title = _('New Audit'), onAlertsChange, onClose, onNewAlertClick, diff --git a/gsa/src/web/pages/audits/icons/resumeicon.js b/gsa/src/web/pages/audits/icons/resumeicon.js new file mode 100644 index 0000000000..173badbde4 --- /dev/null +++ b/gsa/src/web/pages/audits/icons/resumeicon.js @@ -0,0 +1,81 @@ +/* Copyright (C) 2017-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 {isDefined} from 'gmp/utils/identity'; + +import PropTypes from 'web/utils/proptypes'; +import withCapabilities from 'web/utils/withCapabilities'; + +import ResumeIcon from 'web/components/icon/resumeicon'; + +const TaskResumeIcon = ({capabilities, task, onClick}) => { + if (task.isContainer()) { + return ( + + ); + } + + if (isDefined(task.schedule)) { + return ( + + ); + } + + if (task.isStopped() || task.isInterrupted()) { + if (capabilities.mayOp('resume_task')) { + return ; + } + return ( + + ); + } + + return ( + + ); +}; + +TaskResumeIcon.propTypes = { + capabilities: PropTypes.capabilities.isRequired, + task: PropTypes.model.isRequired, + onClick: PropTypes.func, +}; + +export default withCapabilities(TaskResumeIcon); + +// vim: set ts=2 sw=2 tw=80: diff --git a/gsa/src/web/pages/audits/icons/starticon.js b/gsa/src/web/pages/audits/icons/starticon.js new file mode 100644 index 0000000000..5b7e90b9ab --- /dev/null +++ b/gsa/src/web/pages/audits/icons/starticon.js @@ -0,0 +1,53 @@ +/* Copyright (C) 2017-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 withCapabilities from 'web/utils/withCapabilities'; + +import StartIcon from 'web/components/icon/starticon'; + +const TaskStartIcon = ({capabilities, task, onClick}) => { + if (task.isRunning() || task.isContainer()) { + return null; + } + + if (!capabilities.mayOp('start_task')) { + return ( + + ); + } + + if (!task.isActive()) { + return ; + } + return ; +}; + +TaskStartIcon.propTypes = { + capabilities: PropTypes.capabilities.isRequired, + task: PropTypes.model.isRequired, + onClick: PropTypes.func, +}; + +export default withCapabilities(TaskStartIcon); + +// vim: set ts=2 sw=2 tw=80: diff --git a/gsa/src/web/pages/audits/table.js b/gsa/src/web/pages/audits/table.js index be607498b5..e2cb56796d 100644 --- a/gsa/src/web/pages/audits/table.js +++ b/gsa/src/web/pages/audits/table.js @@ -85,13 +85,13 @@ const actionsColumn = ( ); export default createEntitiesTable({ - emptyTitle: _l('No Tasks available'), + emptyTitle: _l('No Audits available'), row: Row, rowDetails: withRowDetails('task', 10)(TaskDetails), header: withEntitiesHeader(actionsColumn)(Header), footer: createEntitiesFooter({ span: 10, trash: true, - download: 'tasks.xml', + download: 'audits.xml', }), }); From b92e1825aa9ed4cc3d8d80a9ecd12710920115c4 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Fri, 21 Jun 2019 11:08:02 +0200 Subject: [PATCH 10/66] add import and edit dialog for policies --- gsa/src/web/pages/policies/component.js | 18 +- .../pages/policies/editnvtdetailsdialog.js | 276 +++++++++++++++ .../pages/policies/editpolicyfamilydialog.js | 323 ++++++++++++++++++ gsa/src/web/pages/policies/importdialog.js | 61 ++++ 4 files changed, 669 insertions(+), 9 deletions(-) create mode 100644 gsa/src/web/pages/policies/editnvtdetailsdialog.js create mode 100644 gsa/src/web/pages/policies/editpolicyfamilydialog.js create mode 100644 gsa/src/web/pages/policies/importdialog.js diff --git a/gsa/src/web/pages/policies/component.js b/gsa/src/web/pages/policies/component.js index c415785edd..5f3babd399 100644 --- a/gsa/src/web/pages/policies/component.js +++ b/gsa/src/web/pages/policies/component.js @@ -77,11 +77,11 @@ import {UNSET_VALUE} from 'web/utils/render'; import EntityComponent from 'web/entity/component'; -import EditConfigFamilyDialog from 'web/pages/scanconfigs/editconfigfamilydialog'; +import EditConfigFamilyDialog from 'web/pages/policies/editpolicyfamilydialog'; import EditScanConfigDialog from 'web/pages/scanconfigs/editdialog'; -import EditNvtDetailsDialog from 'web/pages/scanconfigs/editnvtdetailsdialog'; +import EditNvtDetailsDialog from 'web/pages/policies/editnvtdetailsdialog'; import AuditDialog from './createauditdialog'; -import ImportDialog from 'web/pages/scanconfigs/importdialog'; +import ImportDialog from 'web/pages/policies/importdialog'; import PolicyDialog from 'web/pages/policies/dialog'; import TargetComponent from 'web/pages/targets/component'; @@ -113,7 +113,7 @@ class PolicyComponent extends React.Component { importDialogVisible: false, }; - this.handleImportConfig = this.handleImportConfig.bind(this); + this.handleImportPolicy = this.handleImportPolicy.bind(this); this.handleSaveConfigFamily = this.handleSaveConfigFamily.bind(this); this.handleSaveConfigNvt = this.handleSaveConfigNvt.bind(this); this.openCreatePolicyDialog = this.openCreatePolicyDialog.bind(this); @@ -167,7 +167,7 @@ class PolicyComponent extends React.Component { ...scanConfigState, base: config.base, editConfigDialogVisible: true, - title: _('Edit Scan Config {{name}}', {name: shorten(config.name)}), + title: _('Edit Policy {{name}}', {name: shorten(config.name)}), }); }); @@ -352,7 +352,7 @@ class PolicyComponent extends React.Component { ...state, config, editConfigFamilyDialogVisible: true, - editConfigFamilyDialogTitle: _('Edit Scan Config Family {{name}}', { + editConfigFamilyDialogTitle: _('Edit Policy Family {{name}}', { name: shorten(name), }), }); @@ -375,7 +375,7 @@ class PolicyComponent extends React.Component { ...state, config, editNvtDetailsDialogVisible: true, - editNvtDetailsDialogTitle: _('Edit Scan Config NVT {{name}}', { + editNvtDetailsDialogTitle: _('Edit Policy NVT {{name}}', { name: shorten(nvt.name), }), }); @@ -392,7 +392,7 @@ class PolicyComponent extends React.Component { this.handleInteraction(); } - handleImportConfig(data) { + handleImportPolicy(data) { const {gmp, onImported, onImportError} = this.props; this.handleInteraction(); @@ -718,7 +718,7 @@ class PolicyComponent extends React.Component { {importDialogVisible && ( )} {editConfigFamilyDialogVisible && ( diff --git a/gsa/src/web/pages/policies/editnvtdetailsdialog.js b/gsa/src/web/pages/policies/editnvtdetailsdialog.js new file mode 100644 index 0000000000..89c1914bda --- /dev/null +++ b/gsa/src/web/pages/policies/editnvtdetailsdialog.js @@ -0,0 +1,276 @@ +/* Copyright (C) 2017-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 {isDefined} from 'gmp/utils/identity'; + +import PropTypes from 'web/utils/proptypes'; + +import SeverityBar from 'web/components/bar/severitybar'; + +import SaveDialog from 'web/components/dialog/savedialog'; + +import Radio from 'web/components/form/radio'; +import TextField from 'web/components/form/textfield'; + +import Divider from 'web/components/layout/divider'; +import Layout from 'web/components/layout/layout'; + +import DetailsLink from 'web/components/link/detailslink'; +import Link from 'web/components/link/link'; + +import SimpleTable from 'web/components/table/simpletable'; +import Table from 'web/components/table/stripedtable'; +import TableBody from 'web/components/table/body'; +import TableData from 'web/components/table/data'; +import TableHead from 'web/components/table/head'; +import TableHeader from 'web/components/table/header'; +import TableRow from 'web/components/table/row'; + +import NvtPreference from '../nvts/nvtpreference'; +import Preformatted from '../nvts/preformatted'; + +class EditDialog extends React.Component { + constructor(...args) { + super(...args); + + this.handlePreferenceChange = this.handlePreferenceChange.bind(this); + } + + handlePreferenceChange(value, name, onValueChange) { + const {preference_values} = this.props; + preference_values[name].value = value.value; + + onValueChange(preference_values, 'preference_values'); + } + + render() { + const { + config, + config_name, + family_name, + nvt, + timeout, + manual_timeout = '', + preference_values, + title, + onClose, + onSave, + } = this.props; + + const controlledData = { + config, + config_name, + family_name, + id: config.id, + nvt_name: nvt.name, + oid: nvt.oid, + preference_values, + }; + + return ( + + {({values: state, onValueChange}) => { + return ( + + + + + {_('Name')} + + + + {nvt.name} + + + + + + {_('Policy')} + {config.name} + + + {_('Family')} + {nvt.family} + + + {_('OID')} + {nvt.oid} + + + {_('Version')} + {nvt.version} + + + {_('Notes')} + {nvt.notes_counts.length} + + + {_('Overrides')} + {nvt.overrides_counts.length} + + + + + {isDefined(nvt.tags.summary) && ( +
+

{_('Summary')}

+ {nvt.tags.summary} +
+ )} + + {isDefined(nvt.tags.affected) && ( +
+

{_('Affected Software/OS')}

+ {nvt.tags.affected} +
+ )} + +
+

{_('Vulnerability Scoring')}

+ + + + {_('CVSS base')} + + + + + {isDefined(nvt.tags.cvss_base_vector) && ( + + {_('CVSS base vector')} + + + {nvt.tags.cvss_base_vector} + + + + )} + + +
+ + + + + {_('Name')} + {_('New Value')} + {_('Default Value')} + + + + + {_('Timeout')} + + + + + + {_('Apply default timeout')} + {isDefined(nvt.default_timeout) + ? ' (' + nvt.default_timeout + ')' + : ''} + + + + + + + + + + {isDefined(nvt.default_timeout) + ? nvt.default_timeout + : ''} + + + {nvt.preferences.map(pref => { + const prefValue = isDefined(preference_values[pref.name]) + ? preference_values[pref.name].value + : undefined; + return ( + + this.handlePreferenceChange( + value, + pref.name, + onValueChange, + ) + } + /> + ); + })} + +
+
+ ); + }} +
+ ); + } +} + +EditDialog.propTypes = { + config: PropTypes.model.isRequired, + config_name: PropTypes.string, + family_name: PropTypes.string, + manual_timeout: PropTypes.string, + nvt: PropTypes.object.isRequired, + preference_values: PropTypes.object.isRequired, + timeout: PropTypes.string.isRequired, + title: PropTypes.string.isRequired, + onClose: PropTypes.func.isRequired, + onSave: PropTypes.func.isRequired, +}; + +export default EditDialog; + +// vim: set ts=2 sw=2 tw=80: diff --git a/gsa/src/web/pages/policies/editpolicyfamilydialog.js b/gsa/src/web/pages/policies/editpolicyfamilydialog.js new file mode 100644 index 0000000000..ccd8b6ed74 --- /dev/null +++ b/gsa/src/web/pages/policies/editpolicyfamilydialog.js @@ -0,0 +1,323 @@ +/* Copyright (C) 2017-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 {isDefined} from 'gmp/utils/identity'; +import {isEmpty} from 'gmp/utils/string'; + +import {YES_VALUE, NO_VALUE} from 'gmp/parser'; + +import PropTypes from 'web/utils/proptypes'; + +import SeverityBar from 'web/components/bar/severitybar'; + +import SaveDialog from 'web/components/dialog/savedialog'; + +import Checkbox from 'web/components/form/checkbox'; + +import EditIcon from 'web/components/icon/editicon'; + +import Layout from 'web/components/layout/layout'; + +import Section from 'web/components/section/section'; + +import SortBy from 'web/components/sortby/sortby'; + +import SimpleTable from 'web/components/table/simpletable'; +import Table from 'web/components/table/stripedtable'; +import TableBody from 'web/components/table/body'; +import TableData from 'web/components/table/data'; +import TableHeader from 'web/components/table/header'; +import TableHead from 'web/components/table/head'; +import TableRow from 'web/components/table/row'; + +import {makeCompareSeverity, makeCompareString} from 'web/utils/sort'; + +class Nvt extends React.Component { + shouldComponentUpdate(nextProps) { + return ( + this.props.selected !== nextProps.selected || + this.props.nvt !== nextProps.nvt + ); + } + + render() { + const { + config, + nvt, + selected, + onSelectedChange, + onEditNvtDetailsClick, + } = this.props; + + let pref_count = nvt.preference_count; + if (pref_count === '0') { + pref_count = ''; + } + + const {name, oid, severity, timeout, default_timeout} = nvt; + return ( + + {name} + {oid} + + + + + {isEmpty(timeout) ? _('default') : timeout} + {isEmpty(default_timeout) ? '' : ' (' + default_timeout + ')'} + + {pref_count} + + {/* wrap in span to allow centering */} +
+ +
+
+ + + +
+ ); + } +} + +Nvt.propTypes = { + config: PropTypes.model.isRequired, + nvt: PropTypes.object.isRequired, + selected: PropTypes.yesno.isRequired, + onEditNvtDetailsClick: PropTypes.func, + onSelectedChange: PropTypes.func, +}; + +const sortFunctions = { + name: makeCompareString('name'), + oid: makeCompareString('oid'), + severity: makeCompareSeverity(), + timeout: makeCompareString('timeout'), +}; + +const sortNvts = ({nvts = [], sortBy, sortReverse, selected}) => { + if (sortBy === 'selected') { + return [...nvts].sort((a, b) => { + if (selected[a.oid] && !selected[b.oid]) { + return sortReverse ? 1 : -1; + } + if (selected[b.oid] && !selected[a.oid]) { + return sortReverse ? -1 : 1; + } + + let {name: aname = ''} = a; + let {name: bname = ''} = b; + aname = aname.toLowerCase(); + bname = bname.toLowerCase(); + + if (aname > bname) { + return sortReverse ? -1 : 1; + } + if (bname > aname) { + return sortReverse ? 1 : -1; + } + return 0; + }); + } + + const compareFunc = sortFunctions[sortBy]; + + if (!isDefined(compareFunc)) { + return nvts; + } + + const compare = compareFunc(sortReverse); + return [...nvts].sort(compare); +}; + +class EditDialogComponent extends React.Component { + constructor(...args) { + super(...args); + + this.state = { + sortBy: 'name', + sortReverse: false, + selected: {...this.props.selected}, + }; + + this.handleSelectedChange = this.handleSelectedChange.bind(this); + this.handleSortChange = this.handleSortChange.bind(this); + } + + handleSelectedChange(value, name) { + const {selected} = this.props; + + selected[name] = value; + + this.setState({selected}); + } + + handleSortChange(sortBy) { + this.setState(({sortBy: prevSortBy, sortReverse: prevSortReverse}) => ({ + sortBy, + sortReverse: prevSortBy === sortBy ? !prevSortReverse : false, + })); + } + + render() { + const {sortBy, sortReverse, selected} = this.state; + const { + config, + config_name, + family_name, + id, + title, + onClose, + onEditNvtDetailsClick, + onSave, + } = this.props; + + const data = { + config, + config_name, + family_name, + id, + selected, + }; + + const sortDir = sortReverse ? SortBy.DESC : SortBy.ASC; + + const nvts = sortNvts({ + nvts: this.props.nvts, + sortBy, + sortReverse, + selected, + }); + + return ( + + {() => ( + + + + + {_('Policy')} + {config_name} + + + {_('Family')} + {family_name} + + + + +
+ + + + + + + + {_('Prefs')} + + {_('Actions')} + + + + {nvts.map(nvt => { + const {oid} = nvt; + return ( + + ); + })} + +
+
+
+ )} +
+ ); + } +} + +EditDialogComponent.propTypes = { + config: PropTypes.model.isRequired, + config_name: PropTypes.string, + family_name: PropTypes.string, + id: PropTypes.string, + nvts: PropTypes.array.isRequired, + selected: PropTypes.object.isRequired, + title: PropTypes.string, + onClose: PropTypes.func.isRequired, + onEditNvtDetailsClick: PropTypes.func, + onSave: PropTypes.func.isRequired, +}; + +export default EditDialogComponent; + +// vim: set ts=2 sw=2 tw=80: diff --git a/gsa/src/web/pages/policies/importdialog.js b/gsa/src/web/pages/policies/importdialog.js new file mode 100644 index 0000000000..c45c4e47d7 --- /dev/null +++ b/gsa/src/web/pages/policies/importdialog.js @@ -0,0 +1,61 @@ +/* Copyright (C) 2017-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 SaveDialog from 'web/components/dialog/savedialog'; + +import FileField from 'web/components/form/filefield'; +import FormGroup from 'web/components/form/formgroup'; + +import Layout from 'web/components/layout/layout'; + +const ImportDialog = ({onClose, onSave}) => { + return ( + + {({onValueChange}) => { + return ( + + + + + + ); + }} + + ); +}; + +ImportDialog.propTypes = { + onClose: PropTypes.func.isRequired, + onSave: PropTypes.func.isRequired, +}; + +export default ImportDialog; + +// vim: set ts=2 sw=2 tw=80: From 330db09656878c453b5471ef4944b57ced5883bd Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Fri, 21 Jun 2019 14:36:34 +0200 Subject: [PATCH 11/66] add policy and audit icons --- gsa/src/web/pages/audits/detailspage.js | 4 ++-- gsa/src/web/pages/audits/listpage.js | 4 ++-- gsa/src/web/pages/policies/detailspage.js | 4 ++-- gsa/src/web/pages/policies/listpage.js | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/gsa/src/web/pages/audits/detailspage.js b/gsa/src/web/pages/audits/detailspage.js index a85834eaf1..6874bbfc67 100644 --- a/gsa/src/web/pages/audits/detailspage.js +++ b/gsa/src/web/pages/audits/detailspage.js @@ -45,7 +45,7 @@ import NoteIcon from 'web/components/icon/noteicon'; import OverrideIcon from 'web/components/icon/overrideicon'; import ReportIcon from 'web/components/icon/reporticon'; import ResultIcon from 'web/components/icon/resulticon'; -import TaskIcon from 'web/components/icon/taskicon'; +import AuditIcon from 'web/components/icon/taskicon'; import Tab from 'web/components/tab/tab'; import TabLayout from 'web/components/tab/tablayout'; @@ -352,7 +352,7 @@ const Page = ({ } + sectionIcon={} title={_('Audit')} toolBarIcons={ToolBarIcons} onChanged={onChanged} diff --git a/gsa/src/web/pages/audits/listpage.js b/gsa/src/web/pages/audits/listpage.js index f0998cd810..e5ca516781 100644 --- a/gsa/src/web/pages/audits/listpage.js +++ b/gsa/src/web/pages/audits/listpage.js @@ -47,7 +47,7 @@ import AuditComponent from './component'; // import TaskDashboard, {TASK_DASHBOARD_ID} from './dashboard'; import TaskFilterDialog from './filterdialog'; import Table from './table'; -import TaskIcon from 'web/components/icon/taskicon'; +import AuditIcon from 'web/components/icon/auditicon'; const ToolBarIcons = withCapabilities(({capabilities}) => ( @@ -136,7 +136,7 @@ const Page = ({ filterEditDialog={TaskFilterDialog} filtersFilter={TASKS_FILTER_FILTER} gcrFormatDefined={gcrFormatDefined} - sectionIcon={} + sectionIcon={} table={Table} title={_('Audits')} toolBarIcons={ToolBarIcons} diff --git a/gsa/src/web/pages/policies/detailspage.js b/gsa/src/web/pages/policies/detailspage.js index 7009d08282..2339452352 100644 --- a/gsa/src/web/pages/policies/detailspage.js +++ b/gsa/src/web/pages/policies/detailspage.js @@ -32,7 +32,7 @@ import ExportIcon from 'web/components/icon/exporticon'; import ManualIcon from 'web/components/icon/manualicon'; // import UploadIcon from 'web/components/icon/uploadicon'; import ListIcon from 'web/components/icon/listicon'; -import ScanConfigIcon from 'web/components/icon/scanconfigicon'; +import PolicyIcon from 'web/components/icon/scanconfigicon'; import Link from 'web/components/link/link'; @@ -324,7 +324,7 @@ const Page = ({ } + sectionIcon={} toolBarIcons={ToolBarIcons} title={_('Policy')} onInteraction={onInteraction} diff --git a/gsa/src/web/pages/policies/listpage.js b/gsa/src/web/pages/policies/listpage.js index 2fba8ac880..1564ed18e1 100644 --- a/gsa/src/web/pages/policies/listpage.js +++ b/gsa/src/web/pages/policies/listpage.js @@ -28,7 +28,7 @@ import withCapabilities from 'web/utils/withCapabilities'; import EntitiesPage from 'web/entities/page'; import withEntitiesContainer from 'web/entities/withEntitiesContainer'; -import ScanConfigIcon from 'web/components/icon/scanconfigicon'; +import PolicyIcon from 'web/components/icon/policyicon'; import ManualIcon from 'web/components/icon/manualicon'; import UploadIcon from 'web/components/icon/uploadicon'; import NewIcon from 'web/components/icon/newicon'; @@ -104,7 +104,7 @@ const PoliciesPage = ({ {...props} filterEditDialog={ScanConfigFilterDialog} filtersFilter={SCANCONFIGS_FILTER_FILTER} - sectionIcon={} + sectionIcon={} table={Table} title={_('Policies')} toolBarIcons={ToolBarIcons} From 116f7266014b02af0c8801f4339d515d061afb5f Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Mon, 24 Jun 2019 11:35:00 +0200 Subject: [PATCH 12/66] add more options to create audit dialog --- gsa/src/web/pages/policies/component.js | 225 +++++++++++------- .../web/pages/policies/createauditdialog.js | 218 +++++++++++++++-- gsa/src/web/pages/policies/row.js | 12 +- 3 files changed, 340 insertions(+), 115 deletions(-) diff --git a/gsa/src/web/pages/policies/component.js b/gsa/src/web/pages/policies/component.js index 5f3babd399..047e6124a7 100644 --- a/gsa/src/web/pages/policies/component.js +++ b/gsa/src/web/pages/policies/component.js @@ -31,18 +31,16 @@ import {selectSaveId} from 'gmp/utils/id'; import {parseYesNo, YES_VALUE, NO_VALUE} from 'gmp/parser'; -import { - AUTO_DELETE_KEEP_DEFAULT_VALUE, - HOSTS_ORDERING_SEQUENTIAL, - AUTO_DELETE_NO, -} from 'gmp/models/task'; - import { ospScannersFilter, OPENVAS_DEFAULT_SCANNER_ID, OPENVAS_SCANNER_TYPE, } from 'gmp/models/scanner'; -// import {FULL_AND_FAST_SCAN_CONFIG_ID} from 'gmp/models/scanconfig'; + +import { + loadEntities as loadAlerts, + selector as alertSelector, +} from 'web/store/entities/alerts'; import { loadEntities as loadScanConfigs, @@ -54,6 +52,11 @@ import { selector as scannerSelector, } from 'web/store/entities/scanners'; +import { + loadEntities as loadSchedules, + selector as scheduleSelector, +} from 'web/store/entities/schedules'; + import { loadEntities as loadTags, selector as tagsSelector, @@ -73,7 +76,6 @@ import compose from 'web/utils/compose'; import PropTypes from 'web/utils/proptypes'; import withCapabilities from 'web/utils/withCapabilities'; import withGmp from 'web/utils/withGmp'; -import {UNSET_VALUE} from 'web/utils/render'; import EntityComponent from 'web/entity/component'; @@ -84,22 +86,12 @@ import AuditDialog from './createauditdialog'; import ImportDialog from 'web/pages/policies/importdialog'; import PolicyDialog from 'web/pages/policies/dialog'; +import ScheduleComponent from 'web/pages/schedules/component'; +import AlertComponent from 'web/pages/alerts/component'; import TargetComponent from 'web/pages/targets/component'; -const DEFAULT_MAX_CHECKS = 4; -const DEFAULT_MAX_HOSTS = 20; const DEFAULT_MIN_QOD = 70; -const get_scanner = (scanners, scanner_id) => { - if (!isDefined(scanners)) { - return undefined; - } - - return scanners.find(sc => { - return sc.id === scanner_id; - }); -}; - class PolicyComponent extends React.Component { constructor(...args) { super(...args); @@ -141,14 +133,42 @@ class PolicyComponent extends React.Component { this, ); this.handleSaveAudit = this.handleSaveAudit.bind(this); + this.handleAlertsChange = this.handleAlertsChange.bind(this); + this.handleAlertCreated = this.handleAlertCreated.bind(this); + this.handleScheduleChange = this.handleScheduleChange.bind(this); + this.handleScheduleCreated = this.handleScheduleCreated.bind(this); this.handleTargetChange = this.handleTargetChange.bind(this); this.handleTargetCreated = this.handleTargetCreated.bind(this); } + handleAlertsChange(alert_ids) { + this.setState({alert_ids}); + } + + handleScheduleChange(schedule_id) { + this.setState({schedule_id}); + } + handleTargetChange(target_id) { this.setState({target_id}); } + handleAlertCreated(resp) { + const {data} = resp; + + this.props.loadAlerts(); + + this.setState(({alert_ids}) => ({alert_ids: [data.id, ...alert_ids]})); + } + + handleScheduleCreated(resp) { + const {data} = resp; + + this.props.loadSchedules(); + + this.setState({schedule_id: data.id}); + } + handleTargetCreated(resp) { const {data} = resp; @@ -218,52 +238,34 @@ class PolicyComponent extends React.Component { } openCreateAuditDialog(config) { - // const {capabilities} = this.props; - - // console.log(config); - + this.props.loadAlerts(); this.props.loadScanConfigs(); - // this.props.loadScanners(); + this.props.loadSchedules(); this.props.loadTargets(); this.props.loadTags(); - const { - // defaultAlertId, - // defaultScanConfigId = FULL_AND_FAST_SCAN_CONFIG_ID, - // defaultScannerId = OPENVAS_DEFAULT_SCANNER_ID, - // defaultScheduleId, - defaultTargetId, - } = this.props; - - // console.log('defaults', defaultAlertId, defaultScheduleId, defaultTargetId); + const {defaultAlertId, defaultScheduleId, defaultTargetId} = this.props; - // console.log('default=', defaultScannerId); - // const alert_ids = isDefined(defaultAlertId) ? [defaultAlertId] : []; + const alert_ids = isDefined(defaultAlertId) ? [defaultAlertId] : []; this.setState({ createAuditDialogVisible: true, - // alert_ids, - // alterable: undefined, - // apply_overrides: undefined, - // auto_delete: undefined, - // auto_delete_data: undefined, + alert_ids, + alterable: undefined, + auto_delete: undefined, + auto_delete_data: undefined, comment: '', - // config_id: defaultScanConfigId, - // config_id: isDefined(config) ? config.id : defaultScanConfigId, config_id: isDefined(config) ? config.id : undefined, // must not use default because the scanconfig has to be the policy - // hosts_ordering: undefined, - // id: undefined, - // in_assets: undefined, - // max_checks: undefined, - // max_hosts: undefined, - // min_qod: undefined, + hosts_ordering: undefined, + id: undefined, + in_assets: undefined, + max_checks: undefined, + max_hosts: undefined, name: undefined, - // scanner_id: defaultScannerId, - // schedule_id: defaultScheduleId, - // schedule_periods: undefined, - // source_iface: undefined, + schedule_id: defaultScheduleId, + schedule_periods: undefined, + source_iface: undefined, target_id: defaultTargetId, - // task: undefined, title: _('New Audit'), }); @@ -279,19 +281,27 @@ class PolicyComponent extends React.Component { this.handleInteraction(); } - handleSaveAudit({comment, name, target_id}) { - const {gmp, defaultAlertId, defaultScheduleId} = this.props; + handleSaveAudit({ + alert_ids, + alterable, + auto_delete, + auto_delete_data, + comment, + hosts_ordering, + in_assets, + max_checks, + max_hosts, + name, + schedule_id, + schedule_periods, + source_iface, + target_id, + }) { + const {gmp} = this.props; const {config_id} = this.state; const scanner_id = OPENVAS_DEFAULT_SCANNER_ID; - const scanners = [ - { - id: OPENVAS_DEFAULT_SCANNER_ID, - scannerType: OPENVAS_SCANNER_TYPE, - }, - ]; - const scanner = get_scanner(scanners, scanner_id); - const scanner_type = isDefined(scanner) ? scanner.scannerType : undefined; + const scanner_type = OPENVAS_SCANNER_TYPE; const tag = this.props.tags.find(element => { return element.name === 'task:compliance'; @@ -299,21 +309,8 @@ class PolicyComponent extends React.Component { const tag_id = tag ? tag.id : undefined; const add_tag = YES_VALUE; - const alert_ids = isDefined(defaultAlertId) ? [defaultAlertId] : []; - const alterable = NO_VALUE; const apply_overrides = YES_VALUE; - const auto_delete = AUTO_DELETE_NO; - const auto_delete_data = AUTO_DELETE_KEEP_DEFAULT_VALUE; - const hosts_ordering = HOSTS_ORDERING_SEQUENTIAL; - const in_assets = YES_VALUE; - const max_checks = DEFAULT_MAX_CHECKS; - const max_hosts = DEFAULT_MAX_HOSTS; const min_qod = DEFAULT_MIN_QOD; - const schedule_id = isDefined(defaultScheduleId) - ? defaultScheduleId - : UNSET_VALUE; - const schedule_periods = NO_VALUE; - const source_iface = ''; this.handleInteraction(); @@ -590,7 +587,9 @@ class PolicyComponent extends React.Component { render() { const { + alerts, children, + schedules, targets, onCloned, onCloneError, @@ -606,6 +605,10 @@ class PolicyComponent extends React.Component { } = this.props; const { + alert_ids, + alterable, + auto_delete, + auto_delete_data, base, comment, config, @@ -619,9 +622,13 @@ class PolicyComponent extends React.Component { editNvtDetailsDialogTitle, families, family_name, + hosts_ordering, id, importDialogVisible, + in_assets, manual_timeout, + max_checks, + max_hosts, name, nvt, nvts, @@ -629,6 +636,9 @@ class PolicyComponent extends React.Component { scanner_id, scanner_preference_values, scanners, + schedule_id, + schedule_periods, + source_iface, select, selected, target_id, @@ -668,14 +678,49 @@ class PolicyComponent extends React.Component { onInteraction={onInteraction} > {({create: createtarget}) => ( - + + {({create: createalert}) => ( + + {({create: createschedule}) => ( + + )} + + )} + )} )} @@ -755,6 +800,7 @@ class PolicyComponent extends React.Component { } PolicyComponent.propTypes = { + alerts: PropTypes.arrayOf(PropTypes.model), children: PropTypes.func.isRequired, defaultAlertId: PropTypes.id, defaultScanConfigId: PropTypes.id, @@ -762,10 +808,13 @@ PolicyComponent.propTypes = { defaultScheduleId: PropTypes.id, defaultTargetId: PropTypes.id, gmp: PropTypes.gmp.isRequired, + loadAlerts: PropTypes.func.isRequired, loadScanConfigs: PropTypes.func.isRequired, loadScanners: PropTypes.func.isRequired, + loadSchedules: PropTypes.func.isRequired, loadTags: PropTypes.func.isRequired, loadTargets: PropTypes.func.isRequired, + schedules: PropTypes.arrayOf(PropTypes.model), tags: PropTypes.arrayOf(PropTypes.model), targets: PropTypes.arrayOf(PropTypes.model), onCloneError: PropTypes.func, @@ -786,13 +835,16 @@ PolicyComponent.propTypes = { const TAGS_FILTER = ALL_FILTER.copy().set('resource_type', 'task'); const mapStateToProps = rootState => { + const alertSel = alertSelector(rootState); const userDefaults = getUserSettingsDefaults(rootState); const scanConfigsSel = scanConfigsSelector(rootState); const scannersSel = scannerSelector(rootState); + const scheduleSel = scheduleSelector(rootState); const tagsSel = tagsSelector(rootState); const targetSel = targetSelector(rootState); return { timezone: getTimezone(rootState), + alerts: alertSel.getEntities(ALL_FILTER), defaultAlertId: userDefaults.getValueByName('defaultalert'), defaultEsxiCredential: userDefaults.getValueByName('defaultesxicredential'), defaultPortListId: userDefaults.getValueByName('defaultportlist'), @@ -806,14 +858,17 @@ const mapStateToProps = rootState => { defaultTargetId: userDefaults.getValueByName('defaulttarget'), scanConfigs: scanConfigsSel.getEntities(ALL_FILTER), scanners: scannersSel.getEntities(ALL_FILTER), + schedules: scheduleSel.getEntities(ALL_FILTER), tags: tagsSel.getEntities(TAGS_FILTER), targets: targetSel.getEntities(ALL_FILTER), }; }; const mapDispatchToProp = (dispatch, {gmp}) => ({ + loadAlerts: () => dispatch(loadAlerts(gmp)(ALL_FILTER)), loadScanConfigs: () => dispatch(loadScanConfigs(gmp)(ALL_FILTER)), loadScanners: () => dispatch(loadScanners(gmp)(ALL_FILTER)), + loadSchedules: () => dispatch(loadSchedules(gmp)(ALL_FILTER)), loadTags: () => dispatch(loadTags(gmp)(TAGS_FILTER)), loadTargets: () => dispatch(loadTargets(gmp)(ALL_FILTER)), loadUserSettingsDefaults: () => dispatch(loadUserSettingDefaults(gmp)()), diff --git a/gsa/src/web/pages/policies/createauditdialog.js b/gsa/src/web/pages/policies/createauditdialog.js index b55546a15f..8c3c8dc0e4 100644 --- a/gsa/src/web/pages/policies/createauditdialog.js +++ b/gsa/src/web/pages/policies/createauditdialog.js @@ -21,42 +21,92 @@ import React from 'react'; import _ from 'gmp/locale'; +import {NO_VALUE, YES_VALUE} from 'gmp/parser'; + +import { + AUTO_DELETE_KEEP_DEFAULT_VALUE, + HOSTS_ORDERING_SEQUENTIAL, + AUTO_DELETE_NO, +} from 'gmp/models/task'; + import PropTypes from 'web/utils/proptypes'; import withCapabilities from 'web/utils/withCapabilities'; -import {renderSelectItems} from 'web/utils/render'; +import {renderSelectItems, UNSET_VALUE} from 'web/utils/render'; import SaveDialog from 'web/components/dialog/savedialog'; +import MultiSelect from 'web/components/form/multiselect'; import Select from 'web/components/form/select'; import FormGroup from 'web/components/form/formgroup'; import TextField from 'web/components/form/textfield'; +import Checkbox from 'web/components/form/checkbox'; +import YesNoRadio from 'web/components/form/yesnoradio'; +import Spinner from 'web/components/form/spinner'; import NewIcon from 'web/components/icon/newicon'; import Divider from 'web/components/layout/divider'; import Layout from 'web/components/layout/layout'; +import AddResultsToAssetsGroup from 'web/pages/tasks/addresultstoassetsgroup'; +import AutoDeleteReportsGroup from 'web/pages/tasks/autodeletereportsgroup'; + +const DEFAULT_MAX_CHECKS = 4; +const DEFAULT_MAX_HOSTS = 20; + const CreateAuditDialog = ({ + alert_ids = [], + alerts = [], + alterable = NO_VALUE, + auto_delete = AUTO_DELETE_NO, + auto_delete_data = AUTO_DELETE_KEEP_DEFAULT_VALUE, + capabilities, comment = '', + hosts_ordering = HOSTS_ORDERING_SEQUENTIAL, + in_assets = YES_VALUE, + max_checks = DEFAULT_MAX_CHECKS, + max_hosts = DEFAULT_MAX_HOSTS, name = _('Unnamed'), + schedule_id = UNSET_VALUE, + schedule_periods = NO_VALUE, + schedules = [], + source_iface = '', target_id, targets, title = _('New Audit'), + onAlertsChange, onClose, + onNewAlertClick, + onNewScheduleClick, onNewTargetClick, onSave, + onScheduleChange, onTargetChange, ...data }) => { const target_items = renderSelectItems(targets); + const schedule_items = renderSelectItems(schedules, UNSET_VALUE); + + const alert_items = renderSelectItems(alerts); + const uncontrolledData = { ...data, + alterable, + auto_delete, + auto_delete_data, comment, + hosts_ordering, + in_assets, + max_checks, + max_hosts, name, + source_iface, }; const controlledData = { + alert_ids, + schedule_id, target_id, }; @@ -80,6 +130,7 @@ const CreateAuditDialog = ({ onChange={onValueChange} /> + + + + + + + + + )} + + + + + + + + + + + + + + + + + )} + + {!config.isInUse() && + config.policy_type === OPENVAS_SCAN_CONFIG_TYPE && ( + + )} + + {!config.isInUse() && ( + + )} + + {!config.isInUse() && + config.policy_type === OPENVAS_SCAN_CONFIG_TYPE && ( + + )} + + ); + }} + + ); +}; + +EditDialog.propTypes = { + comment: PropTypes.string, + config: PropTypes.model.isRequired, + families: PropTypes.array, + name: PropTypes.string, + scanner_id: PropTypes.id, + scanner_preference_values: PropTypes.object, + scanners: PropTypes.array, + select: PropTypes.object, + title: PropTypes.string.isRequired, + trend: PropTypes.object, + onClose: PropTypes.func.isRequired, + onEditConfigFamilyClick: PropTypes.func, + onEditNvtDetailsClick: PropTypes.func, + onSave: PropTypes.func.isRequired, +}; + +export default EditDialog; + +// vim: set ts=2 sw=2 tw=80: From 665e6e070f68081142c84b93165a1bc1859d6d97 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Mon, 8 Jul 2019 13:15:46 +0200 Subject: [PATCH 15/66] add detailspage for policies --- gsa/src/gmp/capabilities/capabilities.js | 2 + gsa/src/web/pages/policies/details.js | 6 +-- gsa/src/web/pages/policies/detailspage.js | 55 +++++++++-------------- gsa/src/web/pages/policies/row.js | 1 - gsa/src/web/pages/policies/table.js | 6 +-- 5 files changed, 28 insertions(+), 42 deletions(-) diff --git a/gsa/src/gmp/capabilities/capabilities.js b/gsa/src/gmp/capabilities/capabilities.js index 987cc80d18..4718d99b46 100644 --- a/gsa/src/gmp/capabilities/capabilities.js +++ b/gsa/src/gmp/capabilities/capabilities.js @@ -43,6 +43,8 @@ const types = { certbunds: 'info', secinfo: 'info', secinfos: 'info', + policy: 'config', + policies: 'config', portlist: 'port_list', portlists: 'port_list', reportformat: 'report_format', diff --git a/gsa/src/web/pages/policies/details.js b/gsa/src/web/pages/policies/details.js index dbbcbc1501..2b2a99162b 100644 --- a/gsa/src/web/pages/policies/details.js +++ b/gsa/src/web/pages/policies/details.js @@ -39,7 +39,7 @@ import TableRow from 'web/components/table/row'; import {Col} from 'web/entity/page'; const PolicyDetails = ({entity}) => { - const {comment, scan_config_type, scanner, tasks = []} = entity; + const {comment, policy_type, scanner, tasks = []} = entity; return ( @@ -54,7 +54,7 @@ const PolicyDetails = ({entity}) => { {comment} )} - {scan_config_type === OSP_SCAN_CONFIG_TYPE && isDefined(scanner) && ( + {policy_type === OSP_SCAN_CONFIG_TYPE && isDefined(scanner) && ( {_('Scanner')} @@ -69,7 +69,7 @@ const PolicyDetails = ({entity}) => { {tasks.length > 0 && ( - {_('Tasks using this Policy')} + {_('Audits using this Policy')} {tasks.map((task, index) => { diff --git a/gsa/src/web/pages/policies/detailspage.js b/gsa/src/web/pages/policies/detailspage.js index 2339452352..93c1218fe2 100644 --- a/gsa/src/web/pages/policies/detailspage.js +++ b/gsa/src/web/pages/policies/detailspage.js @@ -30,9 +30,8 @@ import Layout from 'web/components/layout/layout'; import ExportIcon from 'web/components/icon/exporticon'; import ManualIcon from 'web/components/icon/manualicon'; -// import UploadIcon from 'web/components/icon/uploadicon'; import ListIcon from 'web/components/icon/listicon'; -import PolicyIcon from 'web/components/icon/scanconfigicon'; +import PolicyIcon from 'web/components/icon/policyicon'; import Link from 'web/components/link/link'; @@ -60,7 +59,6 @@ import withEntityContainer, { } from 'web/entity/withEntityContainer'; import CloneIcon from 'web/entity/icon/cloneicon'; -// import CreateIcon from 'web/entity/icon/createicon'; import EditIcon from 'web/entity/icon/editicon'; import TrashIcon from 'web/entity/icon/trashicon'; @@ -83,11 +81,9 @@ const ToolBarIcons = withCapabilities( capabilities, entity, onPolicyCloneClick, - // onPolicyCreateClick, onPolicyDeleteClick, onPolicyDownloadClick, onPolicyEditClick, - // onPolicyImportClick, }) => ( @@ -96,24 +92,29 @@ const ToolBarIcons = withCapabilities( anchor="scan-configuration" title={_('Help: Policies')} /> - + - {/* */} - - - + + + - {/* {capabilities.mayCreate('config') && ( - - )} */} ), @@ -122,11 +123,9 @@ const ToolBarIcons = withCapabilities( ToolBarIcons.propTypes = { entity: PropTypes.model.isRequired, onPolicyCloneClick: PropTypes.func.isRequired, - // onPolicyCreateClick: PropTypes.func.isRequired, onPolicyDeleteClick: PropTypes.func.isRequired, onPolicyDownloadClick: PropTypes.func.isRequired, onPolicyEditClick: PropTypes.func.isRequired, - // onPolicyImportClick: PropTypes.func.isRequired, }; const NvtFamilies = ({entity}) => { @@ -301,26 +300,16 @@ const Page = ({ }) => { return ( - {({ - clone, - create, - delete: delete_func, - download, - edit, - // import: import_func, - save, - }) => ( + {({clone, delete: delete_func, download, edit, save}) => ( {({activeTab = 0, onActivateTab}) => { const {preferences} = entity; @@ -434,7 +421,7 @@ const mapStateToProps = (rootState, {id}) => { }; }; -export default withEntityContainer('scanconfig', { +export default withEntityContainer('policy', { entitySelector: selector, load, mapStateToProps, diff --git a/gsa/src/web/pages/policies/row.js b/gsa/src/web/pages/policies/row.js index b97949348b..7f00197611 100644 --- a/gsa/src/web/pages/policies/row.js +++ b/gsa/src/web/pages/policies/row.js @@ -68,7 +68,6 @@ const PoliciesActions = compose( displayName={_('Policy')} name="config" entity={entity} - //title={_('Clone Policy')} value={entity} onClick={onPolicyCloneClick} /> diff --git a/gsa/src/web/pages/policies/table.js b/gsa/src/web/pages/policies/table.js index d807ced2cf..f17c5c6de7 100644 --- a/gsa/src/web/pages/policies/table.js +++ b/gsa/src/web/pages/policies/table.js @@ -24,8 +24,7 @@ import withRowDetails from 'web/entities/withRowDetails'; import Header from './header'; import Row from './row'; -// import PolicyDetails from 'web/pages/policies/details'; -import ScanConfigDetails from 'web/pages/scanconfigs/details'; +import PolicyDetails from 'web/pages/policies/details'; export const SORT_FIELDS = [ { @@ -38,8 +37,7 @@ const PoliciesTable = createEntitiesTable({ emptyTitle: _l('No Policies available'), header: Header, row: Row, - // rowDetails: withRowDetails('policy')(PolicyDetails), - rowDetails: withRowDetails('scanconfig')(ScanConfigDetails), + rowDetails: withRowDetails('policy')(PolicyDetails), footer: createEntitiesFooter({ download: 'policies.xml', span: 7, From 07569c6197534c6d6646abcdba41aac9f8af87d5 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Mon, 8 Jul 2019 14:15:40 +0200 Subject: [PATCH 16/66] remove tags, manual icons and filter dialog from policies --- gsa/src/web/pages/policies/component.js | 20 +++----------------- gsa/src/web/pages/policies/detailspage.js | 6 ------ gsa/src/web/pages/policies/listpage.js | 15 +-------------- 3 files changed, 4 insertions(+), 37 deletions(-) diff --git a/gsa/src/web/pages/policies/component.js b/gsa/src/web/pages/policies/component.js index 55fcf20d7d..dd0c30c2a8 100644 --- a/gsa/src/web/pages/policies/component.js +++ b/gsa/src/web/pages/policies/component.js @@ -57,11 +57,6 @@ import { selector as scheduleSelector, } from 'web/store/entities/schedules'; -import { - loadEntities as loadTags, - selector as tagsSelector, -} from 'web/store/entities/tags'; - import { loadEntities as loadTargets, selector as targetSelector, @@ -242,7 +237,6 @@ class PolicyComponent extends React.Component { this.props.loadScanConfigs(); this.props.loadSchedules(); this.props.loadTargets(); - this.props.loadTags(); const {defaultAlertId, defaultScheduleId, defaultTargetId} = this.props; @@ -303,11 +297,8 @@ class PolicyComponent extends React.Component { const scanner_id = OPENVAS_DEFAULT_SCANNER_ID; const scanner_type = OPENVAS_SCANNER_TYPE; - const tag = this.props.tags.find(element => { - return element.name === 'task:compliance'; - }); - const tag_id = tag ? tag.id : undefined; - const add_tag = YES_VALUE; + const tag_id = undefined; + const add_tag = NO_VALUE; const apply_overrides = YES_VALUE; const min_qod = DEFAULT_MIN_QOD; @@ -814,10 +805,8 @@ PolicyComponent.propTypes = { loadScanConfigs: PropTypes.func.isRequired, loadScanners: PropTypes.func.isRequired, loadSchedules: PropTypes.func.isRequired, - loadTags: PropTypes.func.isRequired, loadTargets: PropTypes.func.isRequired, schedules: PropTypes.arrayOf(PropTypes.model), - tags: PropTypes.arrayOf(PropTypes.model), targets: PropTypes.arrayOf(PropTypes.model), onCloneError: PropTypes.func, onCloned: PropTypes.func, @@ -834,7 +823,7 @@ PolicyComponent.propTypes = { onSaved: PropTypes.func, }; -const TAGS_FILTER = ALL_FILTER.copy().set('resource_type', 'task'); +//const TAGS_FILTER = ALL_FILTER.copy().set('resource_type', 'task'); const mapStateToProps = rootState => { const alertSel = alertSelector(rootState); @@ -842,7 +831,6 @@ const mapStateToProps = rootState => { const scanConfigsSel = scanConfigsSelector(rootState); const scannersSel = scannerSelector(rootState); const scheduleSel = scheduleSelector(rootState); - const tagsSel = tagsSelector(rootState); const targetSel = targetSelector(rootState); return { timezone: getTimezone(rootState), @@ -861,7 +849,6 @@ const mapStateToProps = rootState => { scanConfigs: scanConfigsSel.getEntities(ALL_FILTER), scanners: scannersSel.getEntities(ALL_FILTER), schedules: scheduleSel.getEntities(ALL_FILTER), - tags: tagsSel.getEntities(TAGS_FILTER), targets: targetSel.getEntities(ALL_FILTER), }; }; @@ -871,7 +858,6 @@ const mapDispatchToProp = (dispatch, {gmp}) => ({ loadScanConfigs: () => dispatch(loadScanConfigs(gmp)(ALL_FILTER)), loadScanners: () => dispatch(loadScanners(gmp)(ALL_FILTER)), loadSchedules: () => dispatch(loadSchedules(gmp)(ALL_FILTER)), - loadTags: () => dispatch(loadTags(gmp)(TAGS_FILTER)), loadTargets: () => dispatch(loadTargets(gmp)(ALL_FILTER)), loadUserSettingsDefaults: () => dispatch(loadUserSettingDefaults(gmp)()), }); diff --git a/gsa/src/web/pages/policies/detailspage.js b/gsa/src/web/pages/policies/detailspage.js index 93c1218fe2..35ea3ce383 100644 --- a/gsa/src/web/pages/policies/detailspage.js +++ b/gsa/src/web/pages/policies/detailspage.js @@ -29,7 +29,6 @@ import IconDivider from 'web/components/layout/icondivider'; import Layout from 'web/components/layout/layout'; import ExportIcon from 'web/components/icon/exporticon'; -import ManualIcon from 'web/components/icon/manualicon'; import ListIcon from 'web/components/icon/listicon'; import PolicyIcon from 'web/components/icon/policyicon'; @@ -87,11 +86,6 @@ const ToolBarIcons = withCapabilities( }) => ( - diff --git a/gsa/src/web/pages/policies/listpage.js b/gsa/src/web/pages/policies/listpage.js index 9fc00fff17..079d38f91a 100644 --- a/gsa/src/web/pages/policies/listpage.js +++ b/gsa/src/web/pages/policies/listpage.js @@ -29,30 +29,22 @@ import EntitiesPage from 'web/entities/page'; import withEntitiesContainer from 'web/entities/withEntitiesContainer'; import PolicyIcon from 'web/components/icon/policyicon'; -import ManualIcon from 'web/components/icon/manualicon'; import UploadIcon from 'web/components/icon/uploadicon'; import NewIcon from 'web/components/icon/newicon'; import IconDivider from 'web/components/layout/icondivider'; -import {createFilterDialog} from 'web/components/powerfilter/dialog'; - import { loadEntities, selector as entitiesSelector, } from 'web/store/entities/policies'; import PoliciesComponent from './component'; -import Table, {SORT_FIELDS} from './table'; +import Table from './table'; const ToolBarIcons = withCapabilities( ({capabilities, onPolicyCreateClick, onPolicyImportClick}) => ( - {capabilities.mayCreate('config') && ( )} @@ -68,10 +60,6 @@ ToolBarIcons.propTypes = { onPolicyImportClick: PropTypes.func.isRequired, }; -const ScanConfigFilterDialog = createFilterDialog({ - sortFields: SORT_FIELDS, -}); - const PoliciesPage = ({ onChanged, onDownloaded, @@ -102,7 +90,6 @@ const PoliciesPage = ({ }) => ( } table={Table} From 2397bd40625cf794d38679089264942a32972387 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Tue, 9 Jul 2019 10:52:21 +0200 Subject: [PATCH 17/66] rename some variables --- gsa/src/web/pages/policies/component.js | 123 +++++++++++------------- 1 file changed, 57 insertions(+), 66 deletions(-) diff --git a/gsa/src/web/pages/policies/component.js b/gsa/src/web/pages/policies/component.js index dd0c30c2a8..a490d76602 100644 --- a/gsa/src/web/pages/policies/component.js +++ b/gsa/src/web/pages/policies/component.js @@ -42,11 +42,6 @@ import { selector as alertSelector, } from 'web/store/entities/alerts'; -import { - loadEntities as loadScanConfigs, - selector as scanConfigsSelector, -} from 'web/store/entities/policies'; - import { loadEntities as loadScanners, selector as scannerSelector, @@ -74,8 +69,8 @@ import withGmp from 'web/utils/withGmp'; import EntityComponent from 'web/entity/component'; -import EditConfigFamilyDialog from 'web/pages/policies/editpolicyfamilydialog'; -import EditScanConfigDialog from 'web/pages/policies/editdialog'; +import EditPolicyFamilyDialog from 'web/pages/policies/editpolicyfamilydialog'; +import EditPolicyDialog from 'web/pages/policies/editdialog'; import EditNvtDetailsDialog from 'web/pages/policies/editnvtdetailsdialog'; import AuditDialog from './createauditdialog'; import ImportDialog from 'web/pages/policies/importdialog'; @@ -93,28 +88,28 @@ class PolicyComponent extends React.Component { this.state = { createPolicyDialogVisible: false, - editConfigDialogVisible: false, - editConfigFamilyDialogVisible: false, + editPolicyDialogVisible: false, + editPolicyFamilyDialogVisible: false, editNvtDetailsDialogVisible: false, createAuditDialogVisible: false, importDialogVisible: false, }; this.handleImportPolicy = this.handleImportPolicy.bind(this); - this.handleSaveConfigFamily = this.handleSaveConfigFamily.bind(this); - this.handleSaveConfigNvt = this.handleSaveConfigNvt.bind(this); + this.handleSavePolicyFamily = this.handleSavePolicyFamily.bind(this); + this.handleSavePolicyNvt = this.handleSavePolicyNvt.bind(this); this.openCreatePolicyDialog = this.openCreatePolicyDialog.bind(this); this.handleCloseCreatePolicyDialog = this.handleCloseCreatePolicyDialog.bind( this, ); - this.openEditConfigDialog = this.openEditConfigDialog.bind(this); - this.handleCloseEditConfigDialog = this.handleCloseEditConfigDialog.bind( + this.openEditPolicyDialog = this.openEditPolicyDialog.bind(this); + this.handleCloseEditPolicyDialog = this.handleCloseEditPolicyDialog.bind( this, ); - this.openEditConfigFamilyDialog = this.openEditConfigFamilyDialog.bind( + this.openEditPolicyFamilyDialog = this.openEditPolicyFamilyDialog.bind( this, ); - this.handleCloseEditConfigFamilyDialog = this.handleCloseEditConfigFamilyDialog.bind( + this.handleCloseEditPolicyFamilyDialog = this.handleCloseEditPolicyFamilyDialog.bind( this, ); this.openEditNvtDetailsDialog = this.openEditNvtDetailsDialog.bind(this); @@ -172,16 +167,16 @@ class PolicyComponent extends React.Component { this.setState({target_id: data.id}); } - openEditConfigDialog(config) { + openEditPolicyDialog(config) { Promise.all([ - this.loadEditScanConfigSettings(config), + this.loadEditPolicySettings(config), this.loadScanners(), ]).then(([scanConfigState, scannerState]) => { this.setState({ ...scannerState, ...scanConfigState, base: config.base, - editConfigDialogVisible: true, + editPolicyDialogVisible: true, title: _('Edit Policy {{name}}', {name: shorten(config.name)}), }); }); @@ -189,12 +184,12 @@ class PolicyComponent extends React.Component { this.handleInteraction(); } - closeEditConfigDialog() { - this.setState({editConfigDialogVisible: false}); + closeEditPolicyDialog() { + this.setState({editPolicyDialogVisible: false}); } - handleCloseEditConfigDialog() { - this.closeEditConfigDialog(); + handleCloseEditPolicyDialog() { + this.closeEditPolicyDialog(); this.handleInteraction(); } @@ -232,12 +227,13 @@ class PolicyComponent extends React.Component { this.handleInteraction(); } - openCreateAuditDialog(config) { + openCreateAuditDialog(policy) { this.props.loadAlerts(); - this.props.loadScanConfigs(); this.props.loadSchedules(); this.props.loadTargets(); + console.log('config=', policy); + const {defaultAlertId, defaultScheduleId, defaultTargetId} = this.props; const alert_ids = isDefined(defaultAlertId) ? [defaultAlertId] : []; @@ -249,7 +245,7 @@ class PolicyComponent extends React.Component { auto_delete: undefined, auto_delete_data: undefined, comment: '', - config_id: isDefined(config) ? config.id : undefined, // must not use default because the scanconfig has to be the policy + policy_id: isDefined(policy) ? policy.id : undefined, hosts_ordering: undefined, id: undefined, in_assets: undefined, @@ -292,7 +288,7 @@ class PolicyComponent extends React.Component { target_id, }) { const {gmp} = this.props; - const {config_id} = this.state; + const config_id = this.state.policy_id; const scanner_id = OPENVAS_DEFAULT_SCANNER_ID; const scanner_type = OPENVAS_SCANNER_TYPE; @@ -334,13 +330,13 @@ class PolicyComponent extends React.Component { .then(() => this.closeCreateAuditDialog()); } - openEditConfigFamilyDialog({config, name}) { - this.loadEditScanConfigFamilySettings(config, name).then(state => { + openEditPolicyFamilyDialog({config, name}) { + this.loadEditPolicyFamilySettings(config, name).then(state => { this.setState({ ...state, config, - editConfigFamilyDialogVisible: true, - editConfigFamilyDialogTitle: _('Edit Policy Family {{name}}', { + editPolicyFamilyDialogVisible: true, + editPolicyFamilyDialogTitle: _('Edit Policy Family {{name}}', { name: shorten(name), }), }); @@ -348,17 +344,17 @@ class PolicyComponent extends React.Component { this.handleInteraction(); } - closeEditConfigFamilyDialog() { - this.setState({editConfigFamilyDialogVisible: false}); + closeEditPolicyFamilyDialog() { + this.setState({editPolicyFamilyDialogVisible: false}); } - handleCloseEditConfigFamilyDialog() { - this.closeEditConfigFamilyDialog(); + handleCloseEditPolicyFamilyDialog() { + this.closeEditPolicyFamilyDialog(); this.handleInteraction(); } openEditNvtDetailsDialog({config, nvt}) { - this.loadEditScanConfigNvtSettings(config, nvt).then(state => { + this.loadEditPolicyNvtSettings(config, nvt).then(state => { this.setState({ ...state, config, @@ -391,7 +387,7 @@ class PolicyComponent extends React.Component { .then(() => this.closeImportDialog()); } - handleSaveConfigFamily(data) { + handleSavePolicyFamily(data) { const {gmp} = this.props; this.handleInteraction(); @@ -399,15 +395,15 @@ class PolicyComponent extends React.Component { return gmp.policy .savePolicyFamily(data) .then(() => { - return this.loadEditScanConfigSettings(data.config); + return this.loadEditPolicySettings(data.config); }) .then(state => { - this.closeEditConfigFamilyDialog(); + this.closeEditPolicyFamilyDialog(); this.setState({...state}); }); } - handleSaveConfigNvt(values) { + handleSavePolicyNvt(values) { const {gmp} = this.props; this.handleInteraction(); @@ -416,7 +412,7 @@ class PolicyComponent extends React.Component { .savePolicyNvt(values) .then(response => { // update nvt timeouts in nvt family dialog - this.loadEditScanConfigFamilySettings( + this.loadEditPolicyFamilySettings( values.config, values.family_name, ).then(state => { @@ -424,7 +420,7 @@ class PolicyComponent extends React.Component { }); // update nvt preference values in edit dialog - this.loadEditScanConfigSettings(values.config).then(state => { + this.loadEditPolicySettings(values.config).then(state => { this.setState({state}); }); }) @@ -451,7 +447,7 @@ class PolicyComponent extends React.Component { }); } - loadEditScanConfigSettings(config) { + loadEditPolicySettings(config) { const {gmp} = this.props; return Promise.all([gmp.policy.get(config), gmp.nvtfamilies.get()]).then( @@ -496,7 +492,7 @@ class PolicyComponent extends React.Component { ); } - loadEditScanConfigFamilySettings(config, name) { + loadEditPolicyFamilySettings(config, name) { const {gmp} = this.props; const {select} = this.state; @@ -534,7 +530,7 @@ class PolicyComponent extends React.Component { }); } - loadEditScanConfigNvtSettings(config, nvt) { + loadEditPolicyNvtSettings(config, nvt) { const {gmp} = this.props; return gmp.policy @@ -542,7 +538,7 @@ class PolicyComponent extends React.Component { id: config.id, oid: nvt.oid, policy_name: config.name, - family_name: nvt.name, + name: nvt.name, }) .then(response => { const {data} = response; @@ -608,9 +604,9 @@ class PolicyComponent extends React.Component { config_name, createPolicyDialogVisible, createAuditDialogVisible, - editConfigDialogVisible, - editConfigFamilyDialogVisible, - editConfigFamilyDialogTitle, + editPolicyDialogVisible, + editPolicyFamilyDialogVisible, + editPolicyFamilyDialogTitle, editNvtDetailsDialogVisible, editNvtDetailsDialogTitle, families, @@ -662,9 +658,10 @@ class PolicyComponent extends React.Component { ...other, createAudit: this.openCreateAuditDialog, create: this.openCreatePolicyDialog, - edit: this.openEditConfigDialog, + edit: this.openEditPolicyDialog, import: this.openImportDialog, })} + {console.log('config=', config)} {createAuditDialogVisible && ( )} - {editConfigDialogVisible && ( - { this.handleInteraction(); - return save(d).then(() => this.closeEditConfigDialog()); + return save(d).then(() => this.closeEditPolicyDialog()); }} /> )} @@ -759,18 +756,18 @@ class PolicyComponent extends React.Component { onSave={this.handleImportPolicy} /> )} - {editConfigFamilyDialogVisible && ( - )} {editNvtDetailsDialogVisible && ( @@ -784,7 +781,7 @@ class PolicyComponent extends React.Component { timeout={timeout} title={editNvtDetailsDialogTitle} onClose={this.handleCloseEditNvtDetailsDialog} - onSave={this.handleSaveConfigNvt} + onSave={this.handleSavePolicyNvt} /> )} @@ -802,7 +799,6 @@ PolicyComponent.propTypes = { defaultTargetId: PropTypes.id, gmp: PropTypes.gmp.isRequired, loadAlerts: PropTypes.func.isRequired, - loadScanConfigs: PropTypes.func.isRequired, loadScanners: PropTypes.func.isRequired, loadSchedules: PropTypes.func.isRequired, loadTargets: PropTypes.func.isRequired, @@ -823,12 +819,9 @@ PolicyComponent.propTypes = { onSaved: PropTypes.func, }; -//const TAGS_FILTER = ALL_FILTER.copy().set('resource_type', 'task'); - const mapStateToProps = rootState => { const alertSel = alertSelector(rootState); const userDefaults = getUserSettingsDefaults(rootState); - const scanConfigsSel = scanConfigsSelector(rootState); const scannersSel = scannerSelector(rootState); const scheduleSel = scheduleSelector(rootState); const targetSel = targetSelector(rootState); @@ -846,7 +839,6 @@ const mapStateToProps = rootState => { defaultSshCredential: userDefaults.getValueByName('defaultsshcredential'), defaultSmbCredential: userDefaults.getValueByName('defaultsmbcredential'), defaultTargetId: userDefaults.getValueByName('defaulttarget'), - scanConfigs: scanConfigsSel.getEntities(ALL_FILTER), scanners: scannersSel.getEntities(ALL_FILTER), schedules: scheduleSel.getEntities(ALL_FILTER), targets: targetSel.getEntities(ALL_FILTER), @@ -855,7 +847,6 @@ const mapStateToProps = rootState => { const mapDispatchToProp = (dispatch, {gmp}) => ({ loadAlerts: () => dispatch(loadAlerts(gmp)(ALL_FILTER)), - loadScanConfigs: () => dispatch(loadScanConfigs(gmp)(ALL_FILTER)), loadScanners: () => dispatch(loadScanners(gmp)(ALL_FILTER)), loadSchedules: () => dispatch(loadSchedules(gmp)(ALL_FILTER)), loadTargets: () => dispatch(loadTargets(gmp)(ALL_FILTER)), From 92711cd7d5dee0366d35713ca5072debcfa721c6 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Tue, 9 Jul 2019 16:31:28 +0200 Subject: [PATCH 18/66] add create audit dialog to audit page --- gsa/src/web/pages/audits/component.js | 20 +-- gsa/src/web/pages/audits/dialog.js | 198 +------------------------- gsa/src/web/pages/audits/listpage.js | 55 ++----- 3 files changed, 29 insertions(+), 244 deletions(-) diff --git a/gsa/src/web/pages/audits/component.js b/gsa/src/web/pages/audits/component.js index ec90ae2b0a..f228466c14 100644 --- a/gsa/src/web/pages/audits/component.js +++ b/gsa/src/web/pages/audits/component.js @@ -33,7 +33,10 @@ import {withRouter} from 'react-router-dom'; import {FULL_AND_FAST_SCAN_CONFIG_ID} from 'gmp/models/scanconfig'; -import {OPENVAS_DEFAULT_SCANNER_ID} from 'gmp/models/scanner'; +import { + OPENVAS_DEFAULT_SCANNER_ID, + OPENVAS_SCANNER_TYPE, +} from 'gmp/models/scanner'; import { loadEntities as loadAlerts, @@ -99,7 +102,7 @@ import ContainerTaskDialog from 'web/pages/tasks/containerdialog'; const REPORT_FORMATS_FILTER = Filter.fromString('active=1 trust=1 rows=-1'); -class TaskComponent extends React.Component { +class AuditComponent extends React.Component { constructor(...args) { super(...args); @@ -303,8 +306,6 @@ class TaskComponent extends React.Component { max_checks, max_hosts, name, - scanner_id, - scanner_type, schedule_id, schedule_periods, source_iface, @@ -313,6 +314,7 @@ class TaskComponent extends React.Component { task, }) { const {gmp} = this.props; + let {scanner_id, scanner_type} = this.state; this.handleInteraction(); @@ -451,6 +453,8 @@ class TaskComponent extends React.Component { const alert_ids = isDefined(defaultAlertId) ? [defaultAlertId] : []; + const defaultScannerType = OPENVAS_SCANNER_TYPE; + this.setState({ auditDialogVisible: true, alert_ids, @@ -468,6 +472,7 @@ class TaskComponent extends React.Component { min_qod: undefined, name: undefined, scanner_id: defaultScannerId, + scanner_type: defaultScannerType, schedule_id: defaultScheduleId, schedule_periods: undefined, source_iface: undefined, @@ -578,7 +583,6 @@ class TaskComponent extends React.Component { } = this.props; const { - // advancedTaskWizardVisible, // alert_id, alert_ids, alterable, @@ -597,7 +601,6 @@ class TaskComponent extends React.Component { max_checks, max_hosts, min_qod, - // modifyTaskWizardVisible, name, // port_list_id, reportImportDialogVisible, @@ -622,7 +625,6 @@ class TaskComponent extends React.Component { task, tasks, auditDialogVisible, - // taskWizardVisible, title = _('Edit Audit {{name}}', task), } = this.state; return ( @@ -750,7 +752,7 @@ class TaskComponent extends React.Component { } } -TaskComponent.propTypes = { +AuditComponent.propTypes = { alerts: PropTypes.arrayOf(PropTypes.model), capabilities: PropTypes.capabilities.isRequired, children: PropTypes.func.isRequired, @@ -873,4 +875,4 @@ export default compose( mapStateToProps, mapDispatchToProp, ), -)(TaskComponent); +)(AuditComponent); diff --git a/gsa/src/web/pages/audits/dialog.js b/gsa/src/web/pages/audits/dialog.js index 253b6fcb3c..ff2991e68c 100644 --- a/gsa/src/web/pages/audits/dialog.js +++ b/gsa/src/web/pages/audits/dialog.js @@ -21,8 +21,6 @@ import React from 'react'; import _ from 'gmp/locale'; -import logger from 'gmp/log'; - import {forEach, first} from 'gmp/utils/array'; import {isDefined, isArray} from 'gmp/utils/identity'; import {selectSaveId} from 'gmp/utils/id'; @@ -35,13 +33,6 @@ import { AUTO_DELETE_NO, } from 'gmp/models/task'; -import { - OPENVAS_SCANNER_TYPE, - OSP_SCANNER_TYPE, - GMP_SCANNER_TYPE, - OPENVAS_DEFAULT_SCANNER_ID, -} from 'gmp/models/scanner'; - import { FULL_AND_FAST_SCAN_CONFIG_ID, OPENVAS_SCAN_CONFIG_TYPE, @@ -71,8 +62,6 @@ import Layout from 'web/components/layout/layout'; import AddResultsToAssetsGroup from 'web/pages/tasks/addresultstoassetsgroup'; import AutoDeleteReportsGroup from 'web/pages/tasks/autodeletereportsgroup'; -const log = logger.getLogger('web.tasks.dialog'); - const sort_scan_configs = (scan_configs = []) => { const sorted_scan_configs = { [OPENVAS_SCAN_CONFIG_TYPE]: [], @@ -91,87 +80,6 @@ const sort_scan_configs = (scan_configs = []) => { return sorted_scan_configs; }; -const get_scanner = (scanners, scanner_id) => { - if (!isDefined(scanners)) { - return undefined; - } - - return scanners.find(sc => { - return sc.id === scanner_id; - }); -}; - -class ScannerSelect extends React.Component { - constructor(...args) { - super(...args); - - this.handleScannerChange = this.handleScannerChange.bind(this); - } - - handleScannerChange(value, name) { - const { - scanners, - scanConfigs, - onScanConfigChange, - onScannerChange, - } = this.props; - let config_id; - - const scanner = get_scanner(scanners, value); - const scanner_type = isDefined(scanner) ? scanner.scannerType : undefined; - - if ( - scanner_type === OPENVAS_SCANNER_TYPE || - scanner_type === GMP_SCANNER_TYPE - ) { - config_id = selectSaveId( - scanConfigs[OPENVAS_SCAN_CONFIG_TYPE], - FULL_AND_FAST_SCAN_CONFIG_ID, - ); - } else if (scanner_type === OSP_SCANNER_TYPE) { - config_id = selectSaveId(scanConfigs[OSP_SCAN_CONFIG_TYPE], UNSET_VALUE); - } else { - config_id = UNSET_VALUE; - } - - log.debug('on scanner change', value, config_id, scanner); - - if (isDefined(onScannerChange)) { - onScannerChange(value); - } - if (isDefined(onScanConfigChange)) { - onScanConfigChange(config_id); - } - } - - render() { - const {changeTask, scannerId, scanners} = this.props; - return ( - - )} - - {is_osp_scanner && ( - - - - - - )} ); }} diff --git a/gsa/src/web/pages/audits/listpage.js b/gsa/src/web/pages/audits/listpage.js index e5ca516781..200c38bd24 100644 --- a/gsa/src/web/pages/audits/listpage.js +++ b/gsa/src/web/pages/audits/listpage.js @@ -33,39 +33,37 @@ import { import EntitiesPage from 'web/entities/page'; import withEntitiesContainer from 'web/entities/withEntitiesContainer'; -// import DashboardControls from 'web/components/dashboard/controls'; - import ManualIcon from 'web/components/icon/manualicon'; import IconDivider from 'web/components/layout/icondivider'; import {DEFAULT_RELOAD_INTERVAL_ACTIVE} from 'web/utils/constants'; -// import NewIconMenu from 'web/pages/tasks/icons/newiconmenu'; +import NewIcon from 'web/components/icon/newicon'; import AuditComponent from './component'; -// import TaskDashboard, {TASK_DASHBOARD_ID} from './dashboard'; import TaskFilterDialog from './filterdialog'; import Table from './table'; + import AuditIcon from 'web/components/icon/auditicon'; -const ToolBarIcons = withCapabilities(({capabilities}) => ( +const ToolBarIcons = withCapabilities(({capabilities, onAuditCreateClick}) => ( + + {capabilities.mayCreate('task') && ( + + )} )); -/* ToolBarIcons.propTypes = { - onAdvancedTaskWizardClick: PropTypes.func.isRequired, - onContainerTaskCreateClick: PropTypes.func.isRequired, - onModifyTaskWizardClick: PropTypes.func.isRequired, - onTaskCreateClick: PropTypes.func.isRequired, - onTaskWizardClick: PropTypes.func.isRequired, -}; */ +ToolBarIcons.propTypes = { + onAuditCreateClick: PropTypes.func.isRequired, +}; const Page = ({ filter, @@ -77,19 +75,14 @@ const Page = ({ ...props }) => ( {({ clone, - // create, - // createcontainer, + create, delete: delete_func, download, edit, @@ -113,25 +104,9 @@ const Page = ({ reportDownload, reportimport, gcrFormatDefined, - // advancedtaskwizard, - // modifytaskwizard, - // taskwizard, }) => ( ( - - )} - dashboardControls={() => ( - - )} */ filter={filter} filterEditDialog={TaskFilterDialog} filtersFilter={TASKS_FILTER_FILTER} @@ -140,23 +115,19 @@ const Page = ({ table={Table} title={_('Audits')} toolBarIcons={ToolBarIcons} - // onAdvancedTaskWizardClick={advancedtaskwizard} - // onContainerTaskCreateClick={createcontainer} onError={onError} onFilterChanged={onFilterChanged} onInteraction={onInteraction} - // onModifyTaskWizardClick={modifytaskwizard} onReportDownloadClick={reportDownload} onReportImportClick={reportimport} onTaskCloneClick={clone} - // onTaskCreateClick={create} + onAuditCreateClick={create} onTaskDeleteClick={delete_func} onTaskDownloadClick={download} onTaskEditClick={edit} onTaskResumeClick={resume} onTaskStartClick={start} onTaskStopClick={stop} - // onTaskWizardClick={taskwizard} /> )} From 794c3cf248dc8220d245729fdf703e428c9fb4ee Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Wed, 10 Jul 2019 12:00:26 +0200 Subject: [PATCH 19/66] separate audits and tasks and use audit model and commands --- gsa/src/gmp/capabilities/capabilities.js | 2 + gsa/src/gmp/commands/audits.js | 252 ++++++++++++++++++++++ gsa/src/gmp/gmp.js | 2 +- gsa/src/gmp/models/audit.js | 256 +++++++++++++++++++++++ gsa/src/web/pages/audits/component.js | 6 +- gsa/src/web/pages/audits/detailspage.js | 16 +- gsa/src/web/pages/audits/dialog.js | 2 +- gsa/src/web/pages/audits/listpage.js | 7 +- gsa/src/web/pages/audits/table.js | 4 +- gsa/src/web/pages/policies/component.js | 5 +- gsa/src/web/routes.js | 4 +- gsa/src/web/store/entities/audits.js | 41 ++++ gsa/src/web/store/entities/reducers.js | 2 + 13 files changed, 576 insertions(+), 23 deletions(-) create mode 100644 gsa/src/gmp/commands/audits.js create mode 100644 gsa/src/gmp/models/audit.js create mode 100644 gsa/src/web/store/entities/audits.js diff --git a/gsa/src/gmp/capabilities/capabilities.js b/gsa/src/gmp/capabilities/capabilities.js index 4718d99b46..82c3a0a718 100644 --- a/gsa/src/gmp/capabilities/capabilities.js +++ b/gsa/src/gmp/capabilities/capabilities.js @@ -24,6 +24,8 @@ import {map} from '../utils/array'; import {pluralizeType} from '../utils/entitytype'; const types = { + audit: 'task', + audits: 'task', host: 'asset', hosts: 'asset', os: 'asset', diff --git a/gsa/src/gmp/commands/audits.js b/gsa/src/gmp/commands/audits.js new file mode 100644 index 0000000000..721333a818 --- /dev/null +++ b/gsa/src/gmp/commands/audits.js @@ -0,0 +1,252 @@ +/* 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 logger from '../log'; + +import registerCommand from '../command'; + +import {NO_VALUE} from '../parser'; + +import Audit, {HOSTS_ORDERING_SEQUENTIAL} from '../models/audit'; + +import EntitiesCommand from './entities'; +import EntityCommand from './entity'; + +const log = logger.getLogger('gmp.commands.audits'); + +export class AuditCommand extends EntityCommand { + constructor(http) { + super(http, 'task', Audit); + } + + start({id}) { + log.debug('Starting audit...'); + + return this.httpPost({ + cmd: 'start_task', + id, + }) + .then(() => { + log.debug('Started audit'); + return this.get({id}); + }) + .catch(err => { + log.error('An error occurred while starting the audit', id, err); + throw err; + }); + } + + stop({id}) { + log.debug('Stopping audit'); + + return this.httpPost({ + cmd: 'stop_task', + id, + }) + .then(() => { + log.debug('Stopped audit'); + return this.get({id}); + }) + .catch(err => { + log.error('An error occurred while stopping the audit', id, err); + throw err; + }); + } + + resume({id}) { + return this.httpPost({ + cmd: 'resume_task', + id, + }) + .then(() => { + log.debug('Resumed audit'); + return this.get({id}); + }) + .catch(err => { + log.error('An error occurred while resuming the audit', id, err); + throw err; + }); + } + + create(args) { + const { + add_tag, + alert_ids = [], + alterable, + apply_overrides, + auto_delete, + auto_delete_data, + comment = '', + config_id, + hosts_ordering, + in_assets, + max_checks, + max_hosts, + min_qod, + name, + scanner_type, + scanner_id, + schedule_id, + schedule_periods, + source_iface, + tag_id, + target_id, + } = args; + + const data = { + cmd: 'create_task', + add_tag, + 'alert_ids:': alert_ids, + alterable, + apply_overrides, + auto_delete, + auto_delete_data, + comment, + config_id, + hosts_ordering, + in_assets, + max_checks, + max_hosts, + min_qod, + name, + scanner_id, + scanner_type, + schedule_id, + schedule_periods, + source_iface, + tag_id, + target_id, + usage_type: 'audit', + }; + log.debug('Creating audit', args, data); + return this.action(data); + } + + createContainer(args) { + const {name, comment = ''} = args; + log.debug('Creating container audit', args); + return this.action({ + cmd: 'create_container_task', + name, + comment, + usage_type: 'audit', + }); + } + + save(args) { + const { + alert_ids = [], + alterable, + auto_delete, + auto_delete_data, + apply_overrides, + comment = '', + config_id = NO_VALUE, + hosts_ordering = HOSTS_ORDERING_SEQUENTIAL, + id, + in_assets, + max_checks, + max_hosts, + min_qod, + name, + scanner_id = NO_VALUE, + scanner_type, + schedule_id = NO_VALUE, + schedule_periods, + target_id = NO_VALUE, + source_iface, + } = args; + const data = { + alterable, + 'alert_ids:': alert_ids, + apply_overrides, + auto_delete, + auto_delete_data, + comment, + config_id, + cmd: 'save_task', + hosts_ordering, + in_assets, + max_checks, + max_hosts, + min_qod, + name, + scanner_id, + scanner_type, + schedule_id, + schedule_periods, + source_iface, + target_id, + task_id: id, + usage_type: 'audit', + }; + log.debug('Saving audit', args, data); + return this.action(data); + } + + saveContainer(args) { + const { + name, + comment = '', + in_assets = '1', + auto_delete = 'no', + auto_delete_data, + id, + } = args; + log.debug('Saving container audit', args); + return this.action({ + cmd: 'save_container_task', + name, + comment, + in_assets, + auto_delete, + auto_delete_data, + task_id: id, + usage_type: 'audit', + }); + } + + getElementFromRoot(root) { + return root.get_task.get_tasks_response.task; + } +} + +class AuditsCommand extends EntitiesCommand { + constructor(http) { + super(http, 'task', Audit); + } + + getEntitiesResponse(root) { + return root.get_tasks.get_tasks_response; + } + + get(params, options) { + params = {...params, usage_type: 'audit'}; + return this.httpGet(params, options).then(response => { + const {entities, filter, counts} = this.getCollectionListFromRoot( + response.data, + ); + return response.set(entities, {filter, counts}); + }); + } +} + +registerCommand('audit', AuditCommand); +registerCommand('audits', AuditsCommand); + +// vim: set ts=2 sw=2 tw=80: diff --git a/gsa/src/gmp/gmp.js b/gsa/src/gmp/gmp.js index b123ef04e7..0d7e2d9877 100644 --- a/gsa/src/gmp/gmp.js +++ b/gsa/src/gmp/gmp.js @@ -25,7 +25,7 @@ import logger from './log.js'; import './commands/agents.js'; import './commands/alerts.js'; -// import './commands/audits.js'; +import './commands/audits.js'; import './commands/auth.js'; import './commands/certbund.js'; import './commands/credentials.js'; diff --git a/gsa/src/gmp/models/audit.js b/gsa/src/gmp/models/audit.js new file mode 100644 index 0000000000..739638772e --- /dev/null +++ b/gsa/src/gmp/models/audit.js @@ -0,0 +1,256 @@ +/* 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 {_l} from 'gmp/locale/lang'; + +import {isDefined, isArray} from '../utils/identity'; +import {isEmpty} from '../utils/string'; +import {map} from '../utils/array'; +import {normalizeType} from '../utils/entitytype'; + +import { + parseInt, + parseProgressElement, + parseYesNo, + parseDuration, + NO_VALUE, + YES_VALUE, +} from '../parser'; + +import Model from '../model'; + +import Report from './report'; +import Schedule from './schedule'; +import Scanner from './scanner'; + +export const AUTO_DELETE_KEEP = 'keep'; +export const AUTO_DELETE_NO = 'no'; +export const AUTO_DELETE_KEEP_DEFAULT_VALUE = 5; + +export const HOSTS_ORDERING_SEQUENTIAL = 'sequential'; +export const HOSTS_ORDERING_RANDOM = 'random'; +export const HOSTS_ORDERING_REVERSE = 'reverse'; + +export const TASK_STATUS = { + running: 'Running', + stoprequested: 'Stop Requested', + deleterequested: 'Delete Requested', + ultimatedeleterequested: 'Ultimate Delete Requested', + resumerequested: 'Resume Requested', + requested: 'Requested', + stopped: 'Stopped', + new: 'New', + interrupted: 'Interrupted', + container: 'Container', + uploading: 'Uploading', + done: 'Done', +}; + +/* eslint-disable quote-props */ +const TASK_STATUS_TRANSLATIONS = { + Running: _l('Running'), + 'Stop Requested': _l('Stop Requested'), + 'Delete Requested': _l('Delete Requested'), + 'Ultimate Delete Requested': _l('Ultimate Delete Requested'), + 'Resume Requested': _l('Resume Requested'), + Requested: _l('Requested'), + Stopped: _l('Stopped'), + New: _l('New'), + Interrupted: _l('Interrupted'), + Container: _l('Container'), + Uploading: _l('Uploading'), + Done: _l('Done'), +}; +/* eslint-disable quote-props */ + +function parse_yes(value) { + return value === 'yes' ? YES_VALUE : NO_VALUE; +} + +export const getTranslatableTaskStatus = status => + `${TASK_STATUS_TRANSLATIONS[status]}`; + +export const isActive = status => + status === TASK_STATUS.running || + status === TASK_STATUS.stoprequested || + status === TASK_STATUS.deleterequested || + status === TASK_STATUS.ultimatedeleterequested || + status === TASK_STATUS.resumerequested || + status === TASK_STATUS.requested; + +class Audit extends Model { + static entityType = 'audit'; + + isActive() { + return isActive(this.status); + } + + isRunning() { + return this.status === TASK_STATUS.running; + } + + isStopped() { + return this.status === TASK_STATUS.stopped; + } + + isInterrupted() { + return this.status === TASK_STATUS.interrupted; + } + + isNew() { + return this.status === TASK_STATUS.new; + } + + isChangeable() { + return this.isNew() || this.isAlterable(); + } + + isAlterable() { + return this.alterable !== NO_VALUE; + } + + isContainer() { + return !isDefined(this.target); + } + + getTranslatableStatus() { + return getTranslatableTaskStatus(this.status); + } + + parseProperties(elem) { + const copy = super.parseProperties(elem); + + const {report_count} = elem; + + if (isDefined(report_count)) { + copy.report_count = {...report_count}; + copy.report_count.total = parseInt(report_count.__text); + copy.report_count.finished = parseInt(report_count.finished); + } + + copy.alterable = parseYesNo(elem.alterable); + copy.result_count = parseInt(elem.result_count); + + const reports = [ + 'first_report', + 'last_report', + 'second_last_report', + 'current_report', + ]; + + reports.forEach(name => { + const report = elem[name]; + if (isDefined(report)) { + copy[name] = new Report(report.report); + } + }); + + const models = ['config', 'slave', 'target']; + models.forEach(item => { + const name = item; + + const data = elem[name]; + if (isDefined(data) && !isEmpty(data._id)) { + copy[name] = new Model(data, normalizeType(name)); + } else { + delete copy[name]; + } + }); + + if (isDefined(elem.alert)) { + copy.alerts = map(elem.alert, alert => new Model(alert, 'alert')); + delete copy.alert; + } + + if (isDefined(elem.scanner) && !isEmpty(elem.scanner._id)) { + copy.scanner = new Scanner(elem.scanner); + } else { + delete copy.scanner; + } + + if (isDefined(elem.schedule) && !isEmpty(elem.schedule._id)) { + copy.schedule = new Schedule(elem.schedule); + } else { + delete copy.schedule; + } + + copy.schedule_periods = parseInt(elem.schedule_periods); + + copy.progress = parseProgressElement(elem.progress); + + const prefs = {}; + + if (copy.preferences && isArray(elem.preferences.preference)) { + for (const pref of elem.preferences.preference) { + switch (pref.scanner_name) { + case 'in_assets': + copy.in_assets = parse_yes(pref.value); + break; + case 'assets_apply_overrides': + copy.apply_overrides = parse_yes(pref.value); + break; + case 'assets_min_qod': + copy.min_qod = parseInt(pref.value); + break; + case 'auto_delete': + copy.auto_delete = + pref.value === AUTO_DELETE_KEEP + ? AUTO_DELETE_KEEP + : AUTO_DELETE_NO; + break; + case 'auto_delete_data': + copy.auto_delete_data = + pref.value === '0' + ? AUTO_DELETE_KEEP_DEFAULT_VALUE + : parseInt(pref.value); + break; + case 'max_hosts': + case 'max_checks': + copy[pref.scanner_name] = parseInt(pref.value); + break; + case 'source_iface': + copy.source_iface = pref.value; + break; + default: + prefs[pref.scanner_name] = {value: pref.value, name: pref.name}; + break; + } + } + } + + copy.preferences = prefs; + + if (isDefined(elem.average_duration)) { + copy.average_duration = parseDuration(elem.average_duration); + } + + if ( + copy.hosts_ordering !== HOSTS_ORDERING_RANDOM && + copy.hosts_ordering !== HOSTS_ORDERING_REVERSE && + copy.hosts_ordering !== HOSTS_ORDERING_SEQUENTIAL + ) { + delete copy.hosts_ordering; + } + + return copy; + } +} + +export default Audit; + +// vim: set ts=2 sw=2 tw=80: diff --git a/gsa/src/web/pages/audits/component.js b/gsa/src/web/pages/audits/component.js index f228466c14..d185093823 100644 --- a/gsa/src/web/pages/audits/component.js +++ b/gsa/src/web/pages/audits/component.js @@ -116,7 +116,7 @@ class AuditComponent extends React.Component { const {gmp} = this.props; - this.cmd = gmp.task; + this.cmd = gmp.audit; this.handleReportImport = this.handleReportImport.bind(this); this.handleTaskResume = this.handleTaskResume.bind(this); @@ -327,7 +327,7 @@ class AuditComponent extends React.Component { config_id = undefined; } const {onSaved, onSaveError} = this.props; - return gmp.task + return gmp.audit .save({ alert_ids, alterable, @@ -355,7 +355,7 @@ class AuditComponent extends React.Component { } const {onCreated, onCreateError} = this.props; - return gmp.task + return gmp.audit .create({ add_tag, alert_ids, diff --git a/gsa/src/web/pages/audits/detailspage.js b/gsa/src/web/pages/audits/detailspage.js index 6874bbfc67..81bfbb3249 100644 --- a/gsa/src/web/pages/audits/detailspage.js +++ b/gsa/src/web/pages/audits/detailspage.js @@ -45,7 +45,7 @@ import NoteIcon from 'web/components/icon/noteicon'; import OverrideIcon from 'web/components/icon/overrideicon'; import ReportIcon from 'web/components/icon/reporticon'; import ResultIcon from 'web/components/icon/resulticon'; -import AuditIcon from 'web/components/icon/taskicon'; +import AuditIcon from 'web/components/icon/auditicon'; import Tab from 'web/components/tab/tab'; import TabLayout from 'web/components/tab/tablayout'; @@ -87,7 +87,7 @@ import { import { selector as taskSelector, loadEntity as loadTask, -} from 'web/store/entities/tasks'; +} from 'web/store/entities/audits'; import {DEFAULT_RELOAD_INTERVAL_ACTIVE} from 'web/utils/constants'; import PropTypes from 'web/utils/proptypes'; @@ -97,9 +97,9 @@ import withComponentDefaults from 'web/utils/withComponentDefaults'; // import ImportReportIcon from './icons/importreporticon'; // import NewIconMenu from './icons/newiconmenu'; import ResumeIcon from './icons/resumeicon'; -import ScheduleIcon from './icons/scheduleicon'; +import ScheduleIcon from 'web/pages/tasks/icons/scheduleicon'; import StartIcon from './icons/starticon'; -import StopIcon from './icons/stopicon'; +import StopIcon from 'web/pages/tasks/icons/stopicon'; import AuditDetails from './details'; import TaskStatus from 'web/pages/tasks/status'; @@ -129,7 +129,7 @@ const ToolBarIcons = ({ anchor="creating-a-task" title={_('Help: Audits')} /> - + {entity.isAlterable() && !entity.isNew() && ( ( { : defaultReloadInterval; }; -export default withEntityContainer('task', { +export default withEntityContainer('audit', { load, entitySelector: taskSelector, mapStateToProps, diff --git a/gsa/src/web/pages/audits/dialog.js b/gsa/src/web/pages/audits/dialog.js index ff2991e68c..36bdb7ef72 100644 --- a/gsa/src/web/pages/audits/dialog.js +++ b/gsa/src/web/pages/audits/dialog.js @@ -31,7 +31,7 @@ import { AUTO_DELETE_KEEP_DEFAULT_VALUE, HOSTS_ORDERING_SEQUENTIAL, AUTO_DELETE_NO, -} from 'gmp/models/task'; +} from 'gmp/models/audit'; import { FULL_AND_FAST_SCAN_CONFIG_ID, diff --git a/gsa/src/web/pages/audits/listpage.js b/gsa/src/web/pages/audits/listpage.js index 200c38bd24..e3808d0d13 100644 --- a/gsa/src/web/pages/audits/listpage.js +++ b/gsa/src/web/pages/audits/listpage.js @@ -20,7 +20,7 @@ import React from 'react'; import _ from 'gmp/locale'; -import {TASKS_FILTER_FILTER} from 'gmp/models/filter'; +import {RESET_FILTER, TASKS_FILTER_FILTER} from 'gmp/models/filter'; import PropTypes from 'web/utils/proptypes'; import withCapabilities from 'web/utils/withCapabilities'; @@ -28,7 +28,7 @@ import withCapabilities from 'web/utils/withCapabilities'; import { loadEntities, selector as entitiesSelector, -} from 'web/store/entities/tasks'; +} from 'web/store/entities/audits'; import EntitiesPage from 'web/entities/page'; import withEntitiesContainer from 'web/entities/withEntitiesContainer'; @@ -147,9 +147,10 @@ const taskReloadInterval = ({entities = [], defaultReloadInterval}) => ? DEFAULT_RELOAD_INTERVAL_ACTIVE : defaultReloadInterval; -export default withEntitiesContainer('task', { +export default withEntitiesContainer('audit', { entitiesSelector, loadEntities, + defaultFilter: RESET_FILTER, reloadInterval: taskReloadInterval, })(Page); diff --git a/gsa/src/web/pages/audits/table.js b/gsa/src/web/pages/audits/table.js index e2cb56796d..1fd187fa70 100644 --- a/gsa/src/web/pages/audits/table.js +++ b/gsa/src/web/pages/audits/table.js @@ -32,7 +32,7 @@ import TableHeader from 'web/components/table/header'; import TableRow from 'web/components/table/row'; import Row from './row'; -import TaskDetails from 'web/pages/tasks/details'; +import TaskDetails from 'web/pages/audits/details'; const Header = ({ actionsColumn, @@ -87,7 +87,7 @@ const actionsColumn = ( export default createEntitiesTable({ emptyTitle: _l('No Audits available'), row: Row, - rowDetails: withRowDetails('task', 10)(TaskDetails), + rowDetails: withRowDetails('audit', 10)(TaskDetails), header: withEntitiesHeader(actionsColumn)(Header), footer: createEntitiesFooter({ span: 10, diff --git a/gsa/src/web/pages/policies/component.js b/gsa/src/web/pages/policies/component.js index a490d76602..eee957a300 100644 --- a/gsa/src/web/pages/policies/component.js +++ b/gsa/src/web/pages/policies/component.js @@ -232,8 +232,6 @@ class PolicyComponent extends React.Component { this.props.loadSchedules(); this.props.loadTargets(); - console.log('config=', policy); - const {defaultAlertId, defaultScheduleId, defaultTargetId} = this.props; const alert_ids = isDefined(defaultAlertId) ? [defaultAlertId] : []; @@ -302,7 +300,7 @@ class PolicyComponent extends React.Component { this.handleInteraction(); const {onCreated, onCreateError} = this.props; - return gmp.task + return gmp.audit .create({ add_tag, alert_ids, @@ -661,7 +659,6 @@ class PolicyComponent extends React.Component { edit: this.openEditPolicyDialog, import: this.openImportDialog, })} - {console.log('config=', config)} {createAuditDialogVisible && ( ( - @@ -213,6 +213,8 @@ const Routes = () => ( + + diff --git a/gsa/src/web/store/entities/audits.js b/gsa/src/web/store/entities/audits.js new file mode 100644 index 0000000000..b00fb3b8fb --- /dev/null +++ b/gsa/src/web/store/entities/audits.js @@ -0,0 +1,41 @@ +/* Copyright (C) 2018-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 {createAll} from './utils/main'; + +const { + loadAllEntities, + loadEntities, + loadEntity, + reducer, + selector, + entitiesActions, + entityActions, +} = createAll('audit'); + +export { + loadAllEntities, + loadEntities, + loadEntity, + reducer, + selector, + entitiesActions, + entityActions, +}; + +// vim: set ts=2 sw=2 tw=80: diff --git a/gsa/src/web/store/entities/reducers.js b/gsa/src/web/store/entities/reducers.js index 4c7e3832f9..bf8402e100 100644 --- a/gsa/src/web/store/entities/reducers.js +++ b/gsa/src/web/store/entities/reducers.js @@ -20,6 +20,7 @@ import {combineReducers} from 'redux'; import {reducer as agent} from './agents'; import {reducer as alert} from './alerts'; +import {reducer as audit} from './audits'; import {reducer as certbund} from './certbund'; import {reducer as cpe} from './cpes'; import {reducer as credential} from './credentials'; @@ -54,6 +55,7 @@ import {reducer as vuln} from './vulns'; const entitiesReducer = combineReducers({ agent, alert, + audit, certbund, cpe, credential, From 4d342387365de76147e0822fd086a234a45b1fa9 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Wed, 10 Jul 2019 15:45:47 +0200 Subject: [PATCH 20/66] add detailspage for audits and adjust detailspage for policies --- gsa/src/gmp/models/policy.js | 4 +- gsa/src/web/pages/audits/details.js | 4 +- gsa/src/web/pages/audits/detailspage.js | 126 ++++++++-------------- gsa/src/web/pages/policies/details.js | 14 +-- gsa/src/web/pages/policies/detailspage.js | 2 +- 5 files changed, 58 insertions(+), 92 deletions(-) diff --git a/gsa/src/gmp/models/policy.js b/gsa/src/gmp/models/policy.js index d2d438e0cc..9f307fefe1 100644 --- a/gsa/src/gmp/models/policy.js +++ b/gsa/src/gmp/models/policy.js @@ -125,8 +125,8 @@ class Policy extends Model { ret.scanner = new Model(scanner, 'scanner'); } - if (isDefined(elem.audits)) { - ret.audits = map(elem.audits.audit, audit => new Model(audit, 'audit')); + if (isDefined(elem.tasks)) { + ret.audits = map(elem.tasks.task, task => new Model(task, 'audit')); } else { ret.audits = []; } diff --git a/gsa/src/web/pages/audits/details.js b/gsa/src/web/pages/audits/details.js index e7db64d187..05a238b140 100644 --- a/gsa/src/web/pages/audits/details.js +++ b/gsa/src/web/pages/audits/details.js @@ -39,7 +39,7 @@ import { import { loadEntity as loadScanConfig, selector as scanConfigSelector, -} from 'web/store/entities/scanconfigs'; +} from 'web/store/entities/policies'; import PropTypes from 'web/utils/proptypes'; import compose from 'web/utils/compose'; @@ -175,7 +175,7 @@ class AuditDetails extends React.Component { {config.name} diff --git a/gsa/src/web/pages/audits/detailspage.js b/gsa/src/web/pages/audits/detailspage.js index 81bfbb3249..727020e3e6 100644 --- a/gsa/src/web/pages/audits/detailspage.js +++ b/gsa/src/web/pages/audits/detailspage.js @@ -40,9 +40,7 @@ import Link from 'web/components/link/link'; import AlterableIcon from 'web/components/icon/alterableicon'; import ExportIcon from 'web/components/icon/exporticon'; import ListIcon from 'web/components/icon/listicon'; -import ManualIcon from 'web/components/icon/manualicon'; import NoteIcon from 'web/components/icon/noteicon'; -import OverrideIcon from 'web/components/icon/overrideicon'; import ReportIcon from 'web/components/icon/reporticon'; import ResultIcon from 'web/components/icon/resulticon'; import AuditIcon from 'web/components/icon/auditicon'; @@ -94,8 +92,6 @@ import PropTypes from 'web/utils/proptypes'; import {renderYesNo} from 'web/utils/render'; import withComponentDefaults from 'web/utils/withComponentDefaults'; -// import ImportReportIcon from './icons/importreporticon'; -// import NewIconMenu from './icons/newiconmenu'; import ResumeIcon from './icons/resumeicon'; import ScheduleIcon from 'web/pages/tasks/icons/scheduleicon'; import StartIcon from './icons/starticon'; @@ -109,49 +105,51 @@ const ToolBarIcons = ({ entity, links, notes = [], - overrides = [], - onTaskDeleteClick, - onTaskCloneClick, - onTaskDownloadClick, - onTaskEditClick, - // onReportImportClick, - // onTaskCreateClick, - // onContainerTaskCreateClick, - onTaskStartClick, - onTaskStopClick, - onTaskResumeClick, + onAuditDeleteClick, + onAuditCloneClick, + onAuditDownloadClick, + onAuditEditClick, + onAuditStartClick, + onAuditStopClick, + onAuditResumeClick, }) => { return ( - {entity.isAlterable() && !entity.isNew() && ( )} - {/* */} - - - + + + @@ -163,14 +161,12 @@ const ToolBarIcons = ({ links={links} /> )} - - - {/* */} + - + {!entity.isContainer() && ( - + )} @@ -233,16 +229,6 @@ const ToolBarIcons = ({ - - - - - - @@ -254,16 +240,13 @@ ToolBarIcons.propTypes = { links: PropTypes.bool, notes: PropTypes.array, overrides: PropTypes.array, - onContainerTaskCreateClick: PropTypes.func.isRequired, - onReportImportClick: PropTypes.func.isRequired, - onTaskCloneClick: PropTypes.func.isRequired, - onTaskCreateClick: PropTypes.func.isRequired, - onTaskDeleteClick: PropTypes.func.isRequired, - onTaskDownloadClick: PropTypes.func.isRequired, - onTaskEditClick: PropTypes.func.isRequired, - onTaskResumeClick: PropTypes.func.isRequired, - onTaskStartClick: PropTypes.func.isRequired, - onTaskStopClick: PropTypes.func.isRequired, + onAuditCloneClick: PropTypes.func.isRequired, + onAuditDeleteClick: PropTypes.func.isRequired, + onAuditDownloadClick: PropTypes.func.isRequired, + onAuditEditClick: PropTypes.func.isRequired, + onAuditResumeClick: PropTypes.func.isRequired, + onAuditStartClick: PropTypes.func.isRequired, + onAuditStopClick: PropTypes.func.isRequired, }; const Details = ({entity, ...props}) => { @@ -320,15 +303,12 @@ const Page = ({ - {({ - clone, - create, - createcontainer, - delete: delete_func, - download, - edit, - start, - stop, - resume, - reportimport, - }) => ( + {({clone, delete: delete_func, download, edit, start, stop, resume}) => ( {({activeTab = 0, onActivateTab}) => { return ( diff --git a/gsa/src/web/pages/policies/details.js b/gsa/src/web/pages/policies/details.js index 2b2a99162b..6eac9dc885 100644 --- a/gsa/src/web/pages/policies/details.js +++ b/gsa/src/web/pages/policies/details.js @@ -39,7 +39,7 @@ import TableRow from 'web/components/table/row'; import {Col} from 'web/entity/page'; const PolicyDetails = ({entity}) => { - const {comment, policy_type, scanner, tasks = []} = entity; + const {comment, policy_type, scanner, audits = []} = entity; return ( @@ -67,18 +67,18 @@ const PolicyDetails = ({entity}) => { )} - {tasks.length > 0 && ( + {audits.length > 0 && ( {_('Audits using this Policy')} - {tasks.map((task, index) => { + {audits.map((audit, index) => { return ( - - - {task.name} + + + {audit.name} - {index !== tasks.length - 1 && ','} + {index !== audits.length - 1 && ','} ); })} diff --git a/gsa/src/web/pages/policies/detailspage.js b/gsa/src/web/pages/policies/detailspage.js index 35ea3ce383..23011ac8a7 100644 --- a/gsa/src/web/pages/policies/detailspage.js +++ b/gsa/src/web/pages/policies/detailspage.js @@ -61,7 +61,7 @@ import CloneIcon from 'web/entity/icon/cloneicon'; import EditIcon from 'web/entity/icon/editicon'; import TrashIcon from 'web/entity/icon/trashicon'; -import {selector, loadEntity} from 'web/store/entities/scanconfigs'; +import {selector, loadEntity} from 'web/store/entities/policies'; import { selector as permissionsSelector, From 2cc59e58b7b09298c45cb11266f0f23a9f3cb975 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Thu, 11 Jul 2019 10:32:56 +0200 Subject: [PATCH 21/66] rename some variables --- gsa/src/web/pages/audits/component.js | 2 +- gsa/src/web/pages/audits/dialog.js | 2 +- gsa/src/web/pages/audits/row.js | 12 ++++++------ gsa/src/web/pages/audits/table.js | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/gsa/src/web/pages/audits/component.js b/gsa/src/web/pages/audits/component.js index d185093823..8b49b9f346 100644 --- a/gsa/src/web/pages/audits/component.js +++ b/gsa/src/web/pages/audits/component.js @@ -630,7 +630,7 @@ class AuditComponent extends React.Component { return ( - {change_task && ( + {changeAudit && ( - {change_task && ( - + {changeAudit && ( + @@ -297,74 +247,72 @@ const TaskDialog = ({ onChange={onValueChange} /> - {use_openvas_scan_config && ( - - - - - - - - - - - - )} + + + + + + + + + + + ); }} @@ -372,48 +320,40 @@ const TaskDialog = ({ ); }; -TaskDialog.propTypes = { - add_tag: PropTypes.yesno, +AuditDialog.propTypes = { alert_ids: PropTypes.array, alerts: PropTypes.array, alterable: PropTypes.yesno, - apply_overrides: PropTypes.yesno, + audit: PropTypes.model, auto_delete: PropTypes.oneOf(['keep', 'no']), auto_delete_data: PropTypes.number, capabilities: PropTypes.capabilities.isRequired, comment: PropTypes.string, - config_id: PropTypes.idOrZero, hosts_ordering: PropTypes.oneOf(['sequential', 'random', 'reverse']), in_assets: PropTypes.yesno, max_checks: PropTypes.number, max_hosts: PropTypes.number, - min_qod: PropTypes.number, name: PropTypes.string, - scan_configs: PropTypes.arrayOf(PropTypes.model), - scanner_id: PropTypes.idOrZero, - scanners: PropTypes.array, + policies: PropTypes.arrayOf(PropTypes.model), + policy_id: PropTypes.idOrZero, schedule_id: PropTypes.idOrZero, schedule_periods: PropTypes.yesno, schedules: PropTypes.array, source_iface: PropTypes.string, - tag_id: PropTypes.id, - tags: PropTypes.array, target_id: PropTypes.idOrZero, targets: PropTypes.array, - task: PropTypes.model, title: PropTypes.string, onAlertsChange: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired, onNewAlertClick: PropTypes.func.isRequired, onNewScheduleClick: PropTypes.func.isRequired, onNewTargetClick: PropTypes.func.isRequired, + onPolicyChange: PropTypes.func.isRequired, onSave: PropTypes.func.isRequired, - onScanConfigChange: PropTypes.func.isRequired, - onScannerChange: PropTypes.func.isRequired, onScheduleChange: PropTypes.func.isRequired, onTargetChange: PropTypes.func.isRequired, }; -export default withCapabilities(TaskDialog); +export default withCapabilities(AuditDialog); // vim: set ts=2 sw=2 tw=80: From 3e3bdb970ebde780a9a4055f4d69a60368479a8f Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Tue, 16 Jul 2019 15:04:51 +0200 Subject: [PATCH 28/66] add usage_type to scanconfig and task commands --- gsa/src/gmp/commands/scanconfigs.js | 10 ++++++++++ gsa/src/gmp/commands/tasks.js | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/gsa/src/gmp/commands/scanconfigs.js b/gsa/src/gmp/commands/scanconfigs.js index 2964e1206a..dd2d66e6b6 100644 --- a/gsa/src/gmp/commands/scanconfigs.js +++ b/gsa/src/gmp/commands/scanconfigs.js @@ -230,6 +230,16 @@ class ScanConfigsCommand extends EntitiesCommand { getEntitiesResponse(root) { return root.get_configs.get_configs_response; } + + get(params, options) { + params = {...params, usage_type: 'scan'}; + return this.httpGet(params, options).then(response => { + const {entities, filter, counts} = this.getCollectionListFromRoot( + response.data, + ); + return response.set(entities, {filter, counts}); + }); + } } registerCommand('scanconfig', ScanConfigCommand); diff --git a/gsa/src/gmp/commands/tasks.js b/gsa/src/gmp/commands/tasks.js index 588490f1b1..1514f31d60 100644 --- a/gsa/src/gmp/commands/tasks.js +++ b/gsa/src/gmp/commands/tasks.js @@ -193,6 +193,7 @@ export class TaskCommand extends EntityCommand { source_iface, target_id, task_id: id, + usage_type: 'scan', }; log.debug('Saving task', args, data); return this.action(data); @@ -216,6 +217,7 @@ export class TaskCommand extends EntityCommand { auto_delete, auto_delete_data, task_id: id, + usage_type: 'scan', }); } @@ -233,6 +235,16 @@ class TasksCommand extends EntitiesCommand { return root.get_tasks.get_tasks_response; } + get(params, options) { + params = {...params, usage_type: 'scan'}; + return this.httpGet(params, options).then(response => { + const {entities, filter, counts} = this.getCollectionListFromRoot( + response.data, + ); + return response.set(entities, {filter, counts}); + }); + } + getSeverityAggregates({filter} = {}) { return this.getAggregates({ aggregate_type: 'task', From 11b5c32ef89a829f195edd532fc8ec9fbe9bc4f5 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Tue, 16 Jul 2019 16:58:58 +0200 Subject: [PATCH 29/66] rename some variables for policies --- gsa/src/web/pages/policies/component.js | 98 +++++++++---------- gsa/src/web/pages/policies/editdialog.js | 88 ++++++++--------- .../pages/policies/editnvtdetailsdialog.js | 16 +-- .../pages/policies/editpolicyfamilydialog.js | 22 ++--- gsa/src/web/pages/policies/listpage.js | 2 +- 5 files changed, 111 insertions(+), 115 deletions(-) diff --git a/gsa/src/web/pages/policies/component.js b/gsa/src/web/pages/policies/component.js index 4f276d2f97..72cd352ace 100644 --- a/gsa/src/web/pages/policies/component.js +++ b/gsa/src/web/pages/policies/component.js @@ -167,17 +167,17 @@ class PolicyComponent extends React.Component { this.setState({target_id: data.id}); } - openEditPolicyDialog(config) { + openEditPolicyDialog(policy) { Promise.all([ - this.loadEditPolicySettings(config), + this.loadEditPolicySettings(policy), this.loadScanners(), - ]).then(([scanConfigState, scannerState]) => { + ]).then(([policyState, scannerState]) => { this.setState({ ...scannerState, - ...scanConfigState, - base: config.base, + ...policyState, + base: policy.base, editPolicyDialogVisible: true, - title: _('Edit Policy {{name}}', {name: shorten(config.name)}), + title: _('Edit Policy {{name}}', {name: shorten(policy.name)}), }); }); @@ -328,11 +328,11 @@ class PolicyComponent extends React.Component { .then(() => this.closeCreateAuditDialog()); } - openEditPolicyFamilyDialog({config, name}) { - this.loadEditPolicyFamilySettings(config, name).then(state => { + openEditPolicyFamilyDialog({policy, name}) { + this.loadEditPolicyFamilySettings(policy, name).then(state => { this.setState({ ...state, - config, + policy: policy, editPolicyFamilyDialogVisible: true, editPolicyFamilyDialogTitle: _('Edit Policy Family {{name}}', { name: shorten(name), @@ -351,11 +351,11 @@ class PolicyComponent extends React.Component { this.handleInteraction(); } - openEditNvtDetailsDialog({config, nvt}) { - this.loadEditPolicyNvtSettings(config, nvt).then(state => { + openEditNvtDetailsDialog({policy, nvt}) { + this.loadEditPolicyNvtSettings(policy, nvt).then(state => { this.setState({ ...state, - config, + policy: policy, editNvtDetailsDialogVisible: true, editNvtDetailsDialogTitle: _('Edit Policy NVT {{name}}', { name: shorten(nvt.name), @@ -393,7 +393,7 @@ class PolicyComponent extends React.Component { return gmp.policy .savePolicyFamily(data) .then(() => { - return this.loadEditPolicySettings(data.config); + return this.loadEditPolicySettings(data.policy); }) .then(state => { this.closeEditPolicyFamilyDialog(); @@ -411,14 +411,14 @@ class PolicyComponent extends React.Component { .then(response => { // update nvt timeouts in nvt family dialog this.loadEditPolicyFamilySettings( - values.config, + values.policy, values.family_name, ).then(state => { this.setState({state}); }); // update nvt preference values in edit dialog - this.loadEditPolicySettings(values.config).then(state => { + this.loadEditPolicySettings(values.policy).then(state => { this.setState({state}); }); }) @@ -445,24 +445,24 @@ class PolicyComponent extends React.Component { }); } - loadEditPolicySettings(config) { + loadEditPolicySettings(policy) { const {gmp} = this.props; - return Promise.all([gmp.policy.get(config), gmp.nvtfamilies.get()]).then( - ([configResponse, familiesResponse]) => { - const {data: scanconfig} = configResponse; + return Promise.all([gmp.policy.get(policy), gmp.nvtfamilies.get()]).then( + ([policyResponse, familiesResponse]) => { + const {data: responsePolicy} = policyResponse; const {data: families} = familiesResponse; const trend = {}; const select = {}; forEach(families, family => { const {name} = family; - const config_family = scanconfig.families[name]; + const policyFamily = responsePolicy.families[name]; - if (isDefined(config_family)) { - trend[name] = parseYesNo(config_family.trend); + if (isDefined(policyFamily)) { + trend[name] = parseYesNo(policyFamily.trend); select[name] = - config_family.nvts.count === family.max ? YES_VALUE : NO_VALUE; + policyFamily.nvts.count === family.max ? YES_VALUE : NO_VALUE; } else { trend[name] = NO_VALUE; select[name] = NO_VALUE; @@ -471,15 +471,15 @@ class PolicyComponent extends React.Component { const scanner_preference_values = {}; - forEach(scanconfig.preferences.scanner, preference => { + forEach(responsePolicy.preferences.scanner, preference => { scanner_preference_values[preference.name] = preference.value; }); const state = { - comment: scanconfig.comment, - id: config.id, - name: config.name, - config: scanconfig, + comment: responsePolicy.comment, + id: policy.id, + name: policy.name, + policy: responsePolicy, families, trend, select, @@ -490,15 +490,15 @@ class PolicyComponent extends React.Component { ); } - loadEditPolicyFamilySettings(config, name) { + loadEditPolicyFamilySettings(policy, name) { const {gmp} = this.props; const {select} = this.state; return gmp.policy .editPolicyFamilySettings({ - id: config.id, + id: policy.id, family_name: name, - policy_name: config.name, + policy_name: policy.name, }) .then(response => { const {data} = response; @@ -516,10 +516,10 @@ class PolicyComponent extends React.Component { } const state = { - config: data.config, - config_name: config.name, + policy: data.policy, + policyName: policy.name, family_name: name, - id: config.id, + id: policy.id, nvts: data.nvts, selected, }; @@ -528,14 +528,14 @@ class PolicyComponent extends React.Component { }); } - loadEditPolicyNvtSettings(config, nvt) { + loadEditPolicyNvtSettings(policy, nvt) { const {gmp} = this.props; return gmp.policy .editPolicyNvtSettings({ - id: config.id, + id: policy.id, oid: nvt.oid, - policy_name: config.name, + policy_name: policy.name, name: nvt.name, }) .then(response => { @@ -557,8 +557,8 @@ class PolicyComponent extends React.Component { }); const state = { - config: data.policy, - config_name: data.policy.name, + policy: data.policy, + policyName: data.policy.name, family_name: data.nvt.family, id: data.policy.id, oid: data.nvt.oid, @@ -599,8 +599,8 @@ class PolicyComponent extends React.Component { auto_delete_data, base, comment, - config, - config_name, + policy, + policyName, createPolicyDialogVisible, createAuditDialogVisible, editPolicyDialogVisible, @@ -727,7 +727,7 @@ class PolicyComponent extends React.Component { { this.handleInteraction(); @@ -756,8 +756,8 @@ class PolicyComponent extends React.Component { )} {editPolicyFamilyDialogVisible && ( { defaultAlertId: userDefaults.getValueByName('defaultalert'), defaultEsxiCredential: userDefaults.getValueByName('defaultesxicredential'), defaultPortListId: userDefaults.getValueByName('defaultportlist'), - defaultScanConfigId: userDefaults.getValueByName( - 'defaultopenvasscanconfig', - ), defaultScannerId: userDefaults.getValueByName('defaultopenvasscanner'), defaultScheduleId: userDefaults.getValueByName('defaultschedule'), defaultSshCredential: userDefaults.getValueByName('defaultsshcredential'), diff --git a/gsa/src/web/pages/policies/editdialog.js b/gsa/src/web/pages/policies/editdialog.js index 296ad65c3e..06d1407416 100644 --- a/gsa/src/web/pages/policies/editdialog.js +++ b/gsa/src/web/pages/policies/editdialog.js @@ -73,7 +73,7 @@ class NvtPreferenceDisplay extends React.Component { } render() { - const {config, preference, onEditNvtDetailsClick} = this.props; + const {policy, preference, onEditNvtDetailsClick} = this.props; return ( {preference.nvt.name} @@ -81,8 +81,8 @@ class NvtPreferenceDisplay extends React.Component { {preference.value} @@ -92,12 +92,12 @@ class NvtPreferenceDisplay extends React.Component { } NvtPreferenceDisplay.propTypes = { - config: PropTypes.model.isRequired, + policy: PropTypes.model.isRequired, preference: PropTypes.object.isRequired, onEditNvtDetailsClick: PropTypes.func.isRequired, }; -const NvtPreferences = ({config, preferences = [], onEditNvtDetailsClick}) => { +const NvtPreferences = ({policy, preferences = [], onEditNvtDetailsClick}) => { return (
{ {preferences.map(pref => ( @@ -133,7 +133,7 @@ const NvtPreferences = ({config, preferences = [], onEditNvtDetailsClick}) => { }; NvtPreferences.propTypes = { - config: PropTypes.model.isRequired, + policy: PropTypes.model.isRequired, preferences: PropTypes.array.isRequired, onEditNvtDetailsClick: PropTypes.func.isRequired, }; @@ -267,7 +267,7 @@ ScannerPreferences.propTypes = { class NvtFamily extends React.Component { shouldComponentUpdate(nextProps, nextState) { return ( - nextProps.config !== this.props.config || + nextProps.policy !== this.props.policy || nextProps.family !== this.props.family || nextProps.select !== this.props.select || nextProps.trend !== this.props.trend @@ -276,24 +276,24 @@ class NvtFamily extends React.Component { render() { const { - config, + policy, family, select, trend, - onEditConfigFamilyClick, + onEditPolicyFamilyClick, onSelectChange, onTrendChange, } = this.props; const {name} = family; - const config_family = config.families[name]; + const policyFamily = policy.families[name]; const counts = { count: 0, max: family.maxNvtCount, }; - if (isDefined(config_family)) { - counts.count = config_family.nvts.count; - counts.max = config_family.nvts.max; + if (isDefined(policyFamily)) { + counts.count = policyFamily.nvts.count; + counts.max = policyFamily.nvts.max; } return ( @@ -334,9 +334,9 @@ class NvtFamily extends React.Component { @@ -345,11 +345,11 @@ class NvtFamily extends React.Component { } NvtFamily.propTypes = { - config: PropTypes.model.isRequired, family: PropTypes.object.isRequired, + policy: PropTypes.model.isRequired, select: PropTypes.yesno.isRequired, trend: PropTypes.yesno.isRequired, - onEditConfigFamilyClick: PropTypes.func, + onEditPolicyFamilyClick: PropTypes.func, onSelectChange: PropTypes.func, onTrendChange: PropTypes.func, }; @@ -380,11 +380,11 @@ class NvtFamilies extends React.Component { render() { const { - config, + policy, families = [], trend, select, - onEditConfigFamilyClick, + onEditPolicyFamilyClick, } = this.props; return ( @@ -410,11 +410,11 @@ class NvtFamilies extends React.Component { return ( @@ -422,10 +422,10 @@ class NvtFamilies extends React.Component { })} - {_('Total: {{count}}', {count: config.families.count})} + {_('Total: {{count}}', {count: policy.families.count})} - {_('{{known}} of {{max}}', config.nvts)} + {_('{{known}} of {{max}}', policy.nvts)} {/* add empty cells to spread row to end of table */} @@ -440,17 +440,17 @@ class NvtFamilies extends React.Component { } NvtFamilies.propTypes = { - config: PropTypes.model.isRequired, families: PropTypes.array.isRequired, + policy: PropTypes.model.isRequired, select: PropTypes.object.isRequired, trend: PropTypes.object.isRequired, - onEditConfigFamilyClick: PropTypes.func, + onEditPolicyFamilyClick: PropTypes.func, onValueChange: PropTypes.func, }; const EditDialog = ({ comment = '', - config, + policy, families, name, scanner_id, @@ -460,19 +460,19 @@ const EditDialog = ({ title, trend, onClose, - onEditConfigFamilyClick, + onEditPolicyFamilyClick, onEditNvtDetailsClick, onSave, }) => { const uncontrolledData = { - base: config.policy_type, + base: policy.policy_type, comment, name, scanner_id, }; const controlledData = { - id: config.id, + id: policy.id, scanner_preference_values, select, trend, @@ -509,7 +509,7 @@ const EditDialog = ({ /> - {!config.isInUse() && config.policy_type === OSP_SCAN_CONFIG_TYPE && ( + {!policy.isInUse() && policy.policy_type === OSP_SCAN_CONFIG_TYPE && ( {changeAudit && ( @@ -183,9 +183,9 @@ const AuditDialog = ({ @@ -202,14 +202,14 @@ const AuditDialog = ({ @@ -162,9 +162,9 @@ const CreateAuditDialog = ({ @@ -181,14 +181,14 @@ const CreateAuditDialog = ({ @@ -257,11 +257,11 @@ const CreateAuditDialog = ({ title={_('Maximum concurrently executed NVTs per host')} > @@ -270,12 +270,12 @@ const CreateAuditDialog = ({ title={_('Maximum concurrently scanned hosts')} > @@ -288,24 +288,24 @@ const CreateAuditDialog = ({ }; CreateAuditDialog.propTypes = { - alert_ids: PropTypes.array, + alertIds: PropTypes.array, alerts: PropTypes.array, alterable: PropTypes.yesno, auto_delete: PropTypes.oneOf(['keep', 'no']), auto_delete_data: PropTypes.number, capabilities: PropTypes.capabilities.isRequired, comment: PropTypes.string, - hosts_ordering: PropTypes.oneOf(['sequential', 'random', 'reverse']), + hostsOrdering: PropTypes.oneOf(['sequential', 'random', 'reverse']), in_assets: PropTypes.yesno, - max_checks: PropTypes.number, - max_hosts: PropTypes.number, - min_qod: PropTypes.number, + maxChecks: PropTypes.number, + maxHosts: PropTypes.number, + minQod: PropTypes.number, name: PropTypes.string, - schedule_id: PropTypes.idOrZero, - schedule_periods: PropTypes.yesno, + scheduleId: PropTypes.idOrZero, + schedulePeriods: PropTypes.yesno, schedules: PropTypes.array, - source_iface: PropTypes.string, - target_id: PropTypes.idOrZero, + sourceIface: PropTypes.string, + targetId: PropTypes.idOrZero, targets: PropTypes.array, title: PropTypes.string, onAlertsChange: PropTypes.func.isRequired, diff --git a/gsa/src/web/pages/policies/listpage.js b/gsa/src/web/pages/policies/listpage.js index 0ee40489f9..591f8b1c7e 100644 --- a/gsa/src/web/pages/policies/listpage.js +++ b/gsa/src/web/pages/policies/listpage.js @@ -83,10 +83,10 @@ const PoliciesPage = ({ clone, create, createAudit, - delete: delete_func, + delete: deleteFunc, download, edit, - import: import_func, + import: importFunc, }) => ( From bd8596560e8d73dd3c1774e3b000e54cf7bbcb35 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Fri, 19 Jul 2019 16:22:02 +0200 Subject: [PATCH 36/66] add new themes for compliance status --- gsa/src/web/utils/theme.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gsa/src/web/utils/theme.js b/gsa/src/web/utils/theme.js index 667f7fd804..d9176f5d10 100644 --- a/gsa/src/web/utils/theme.js +++ b/gsa/src/web/utils/theme.js @@ -21,12 +21,14 @@ const Theme = { /* source styleguide */ lightGreen: '#87d050', green: '#66c430', + paleGreen: '#99BE48', lightGray: '#c8d3d9', // used by: disabled inputs mediumGray: '#787878', darkGray: '#393637', goldYellow: '#fdc300', + warnYellow: '#f0a519', redBrown: '#a54317', /* source own */ @@ -40,6 +42,7 @@ const Theme = { mediumLightRed: '#ebccd1', // used by: dialog errors border warningRed: '#d83636', // used for warning font color at login dialog darkRed: '#a94442', // used by: dialog errors font + errorRed: '#c83814', // used by: compliance status bar lightBlue: '#bce8f1', // used by InfoPanel and dashboard hovering mediumBlue: '#5897fb', // used by active/hovered items in Select From 2dd44e63606b375a64075d99891b7fc37eaf3ef4 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Fri, 19 Jul 2019 16:58:38 +0200 Subject: [PATCH 37/66] update task command test and datepicker snapshot --- gsa/src/gmp/commands/__tests__/task.js | 2 ++ .../form/__tests__/__snapshots__/datepicker.js.snap | 5 ++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/gsa/src/gmp/commands/__tests__/task.js b/gsa/src/gmp/commands/__tests__/task.js index 895f12e286..faeebc03a6 100644 --- a/gsa/src/gmp/commands/__tests__/task.js +++ b/gsa/src/gmp/commands/__tests__/task.js @@ -225,6 +225,7 @@ describe('TaskCommand tests', () => { source_iface: undefined, task_id: 'task1', target_id: 0, + usage_type: 'scan', }, }); @@ -287,6 +288,7 @@ describe('TaskCommand tests', () => { source_iface: 'eth0', task_id: 'task1', target_id: 't1', + usage_type: 'scan', }, }); diff --git a/gsa/src/web/components/form/__tests__/__snapshots__/datepicker.js.snap b/gsa/src/web/components/form/__tests__/__snapshots__/datepicker.js.snap index 7f2844656f..6ce7c48bf6 100644 --- a/gsa/src/web/components/form/__tests__/__snapshots__/datepicker.js.snap +++ b/gsa/src/web/components/form/__tests__/__snapshots__/datepicker.js.snap @@ -61,13 +61,12 @@ exports[`DatePicker component tests should render 2`] = ` class="react-datepicker__input-container" >
2018/11/11 calendar.svg From 2b4dbe4f1e3e1c44f0f303ee02dea01649e72174 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Mon, 22 Jul 2019 09:24:56 +0200 Subject: [PATCH 38/66] update reducers test --- gsa/src/web/store/entities/__tests__/reducers.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gsa/src/web/store/entities/__tests__/reducers.js b/gsa/src/web/store/entities/__tests__/reducers.js index 4e051e7ec1..c6bd59d87f 100644 --- a/gsa/src/web/store/entities/__tests__/reducers.js +++ b/gsa/src/web/store/entities/__tests__/reducers.js @@ -35,6 +35,7 @@ describe('entities reducer tests', () => { expect(entitiesReducer(undefined, {})).toEqual({ agent: initState, alert: initState, + audit: initState, certbund: initState, cpe: initState, credential: initState, @@ -50,6 +51,7 @@ describe('entities reducer tests', () => { ovaldef: initState, override: initState, permission: initState, + policy: initState, portlist: initState, reportformat: initState, report: initState, From 8948ba493d36a1abbe40999c64890b6641130880 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Mon, 22 Jul 2019 12:45:29 +0200 Subject: [PATCH 39/66] adjust date in copyright --- gsa/src/web/pages/audits/actions.js | 2 +- gsa/src/web/pages/audits/component.js | 2 +- gsa/src/web/pages/audits/details.js | 2 +- gsa/src/web/pages/audits/detailspage.js | 2 +- gsa/src/web/pages/audits/dialog.js | 2 +- gsa/src/web/pages/audits/icons/resumeicon.js | 2 +- gsa/src/web/pages/audits/icons/starticon.js | 2 +- gsa/src/web/pages/audits/listpage.js | 2 +- gsa/src/web/pages/audits/row.js | 2 +- gsa/src/web/pages/audits/table.js | 2 +- gsa/src/web/pages/policies/component.js | 2 +- gsa/src/web/pages/policies/createauditdialog.js | 2 +- gsa/src/web/pages/policies/details.js | 2 +- gsa/src/web/pages/policies/detailspage.js | 2 +- gsa/src/web/pages/policies/dialog.js | 2 +- gsa/src/web/pages/policies/editdialog.js | 2 +- gsa/src/web/pages/policies/editnvtdetailsdialog.js | 2 +- gsa/src/web/pages/policies/editpolicyfamilydialog.js | 2 +- gsa/src/web/pages/policies/header.js | 2 +- gsa/src/web/pages/policies/importdialog.js | 2 +- gsa/src/web/pages/policies/listpage.js | 2 +- gsa/src/web/pages/policies/row.js | 2 +- gsa/src/web/pages/policies/table.js | 2 +- gsa/src/web/store/entities/audits.js | 2 +- gsa/src/web/store/entities/policies.js | 2 +- 25 files changed, 25 insertions(+), 25 deletions(-) diff --git a/gsa/src/web/pages/audits/actions.js b/gsa/src/web/pages/audits/actions.js index 883c9ec1ca..c5e2bd9e0e 100644 --- a/gsa/src/web/pages/audits/actions.js +++ b/gsa/src/web/pages/audits/actions.js @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2019 Greenbone Networks GmbH +/* Copyright (C) 2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * diff --git a/gsa/src/web/pages/audits/component.js b/gsa/src/web/pages/audits/component.js index f8c48044df..4f63231b48 100644 --- a/gsa/src/web/pages/audits/component.js +++ b/gsa/src/web/pages/audits/component.js @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2019 Greenbone Networks GmbH +/* Copyright (C) 2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * diff --git a/gsa/src/web/pages/audits/details.js b/gsa/src/web/pages/audits/details.js index d720890bfa..651e767707 100644 --- a/gsa/src/web/pages/audits/details.js +++ b/gsa/src/web/pages/audits/details.js @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2019 Greenbone Networks GmbH +/* Copyright (C) 2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * diff --git a/gsa/src/web/pages/audits/detailspage.js b/gsa/src/web/pages/audits/detailspage.js index be86d616b2..a039d08f73 100644 --- a/gsa/src/web/pages/audits/detailspage.js +++ b/gsa/src/web/pages/audits/detailspage.js @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2019 Greenbone Networks GmbH +/* Copyright (C) 2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * diff --git a/gsa/src/web/pages/audits/dialog.js b/gsa/src/web/pages/audits/dialog.js index bfea58b6b0..d6d54374ca 100644 --- a/gsa/src/web/pages/audits/dialog.js +++ b/gsa/src/web/pages/audits/dialog.js @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2019 Greenbone Networks GmbH +/* Copyright (C) 2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * diff --git a/gsa/src/web/pages/audits/icons/resumeicon.js b/gsa/src/web/pages/audits/icons/resumeicon.js index 49a028fa40..304bfa3fd3 100644 --- a/gsa/src/web/pages/audits/icons/resumeicon.js +++ b/gsa/src/web/pages/audits/icons/resumeicon.js @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2019 Greenbone Networks GmbH +/* Copyright (C) 2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * diff --git a/gsa/src/web/pages/audits/icons/starticon.js b/gsa/src/web/pages/audits/icons/starticon.js index bc23d3f7e2..9e1a9986eb 100644 --- a/gsa/src/web/pages/audits/icons/starticon.js +++ b/gsa/src/web/pages/audits/icons/starticon.js @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2019 Greenbone Networks GmbH +/* Copyright (C) 2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * diff --git a/gsa/src/web/pages/audits/listpage.js b/gsa/src/web/pages/audits/listpage.js index 1956fe1c77..2a58257b0a 100644 --- a/gsa/src/web/pages/audits/listpage.js +++ b/gsa/src/web/pages/audits/listpage.js @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2019 Greenbone Networks GmbH +/* Copyright (C) 2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * diff --git a/gsa/src/web/pages/audits/row.js b/gsa/src/web/pages/audits/row.js index 0c38fa84d4..01f004f3d8 100644 --- a/gsa/src/web/pages/audits/row.js +++ b/gsa/src/web/pages/audits/row.js @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2019 Greenbone Networks GmbH +/* Copyright (C) 2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * diff --git a/gsa/src/web/pages/audits/table.js b/gsa/src/web/pages/audits/table.js index 3baa802981..8b2d19c264 100644 --- a/gsa/src/web/pages/audits/table.js +++ b/gsa/src/web/pages/audits/table.js @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2019 Greenbone Networks GmbH +/* Copyright (C) 2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * diff --git a/gsa/src/web/pages/policies/component.js b/gsa/src/web/pages/policies/component.js index ee28b7751a..b8f2b6a267 100644 --- a/gsa/src/web/pages/policies/component.js +++ b/gsa/src/web/pages/policies/component.js @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2019 Greenbone Networks GmbH +/* Copyright (C) 2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * diff --git a/gsa/src/web/pages/policies/createauditdialog.js b/gsa/src/web/pages/policies/createauditdialog.js index fbc37834ad..ce3e79fb54 100644 --- a/gsa/src/web/pages/policies/createauditdialog.js +++ b/gsa/src/web/pages/policies/createauditdialog.js @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2019 Greenbone Networks GmbH +/* Copyright (C) 2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * diff --git a/gsa/src/web/pages/policies/details.js b/gsa/src/web/pages/policies/details.js index 6eac9dc885..0af7ff1141 100644 --- a/gsa/src/web/pages/policies/details.js +++ b/gsa/src/web/pages/policies/details.js @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2019 Greenbone Networks GmbH +/* Copyright (C) 2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * diff --git a/gsa/src/web/pages/policies/detailspage.js b/gsa/src/web/pages/policies/detailspage.js index 5f6b0073b8..c6666ad9fe 100644 --- a/gsa/src/web/pages/policies/detailspage.js +++ b/gsa/src/web/pages/policies/detailspage.js @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2019 Greenbone Networks GmbH +/* Copyright (C) 2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * diff --git a/gsa/src/web/pages/policies/dialog.js b/gsa/src/web/pages/policies/dialog.js index dacec8d9f2..0fe153ec34 100644 --- a/gsa/src/web/pages/policies/dialog.js +++ b/gsa/src/web/pages/policies/dialog.js @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2019 Greenbone Networks GmbH +/* Copyright (C) 2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * diff --git a/gsa/src/web/pages/policies/editdialog.js b/gsa/src/web/pages/policies/editdialog.js index 06d1407416..c073dcbfb1 100644 --- a/gsa/src/web/pages/policies/editdialog.js +++ b/gsa/src/web/pages/policies/editdialog.js @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2019 Greenbone Networks GmbH +/* Copyright (C) 2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * diff --git a/gsa/src/web/pages/policies/editnvtdetailsdialog.js b/gsa/src/web/pages/policies/editnvtdetailsdialog.js index bcc243ee7b..69c9e90073 100644 --- a/gsa/src/web/pages/policies/editnvtdetailsdialog.js +++ b/gsa/src/web/pages/policies/editnvtdetailsdialog.js @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2019 Greenbone Networks GmbH +/* Copyright (C) 2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * diff --git a/gsa/src/web/pages/policies/editpolicyfamilydialog.js b/gsa/src/web/pages/policies/editpolicyfamilydialog.js index c0438e4c7b..60e082a366 100644 --- a/gsa/src/web/pages/policies/editpolicyfamilydialog.js +++ b/gsa/src/web/pages/policies/editpolicyfamilydialog.js @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2019 Greenbone Networks GmbH +/* Copyright (C) 2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * diff --git a/gsa/src/web/pages/policies/header.js b/gsa/src/web/pages/policies/header.js index 7fdf7e1ba0..095f39747d 100644 --- a/gsa/src/web/pages/policies/header.js +++ b/gsa/src/web/pages/policies/header.js @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2019 Greenbone Networks GmbH +/* Copyright (C) 2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * diff --git a/gsa/src/web/pages/policies/importdialog.js b/gsa/src/web/pages/policies/importdialog.js index c45c4e47d7..37a32e503d 100644 --- a/gsa/src/web/pages/policies/importdialog.js +++ b/gsa/src/web/pages/policies/importdialog.js @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2019 Greenbone Networks GmbH +/* Copyright (C) 2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * diff --git a/gsa/src/web/pages/policies/listpage.js b/gsa/src/web/pages/policies/listpage.js index 591f8b1c7e..2e5f02da47 100644 --- a/gsa/src/web/pages/policies/listpage.js +++ b/gsa/src/web/pages/policies/listpage.js @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2019 Greenbone Networks GmbH +/* Copyright (C) 2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * diff --git a/gsa/src/web/pages/policies/row.js b/gsa/src/web/pages/policies/row.js index 7f00197611..f3f67ec2eb 100644 --- a/gsa/src/web/pages/policies/row.js +++ b/gsa/src/web/pages/policies/row.js @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2019 Greenbone Networks GmbH +/* Copyright (C) 2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * diff --git a/gsa/src/web/pages/policies/table.js b/gsa/src/web/pages/policies/table.js index c8b17f65f0..380bfa0ad6 100644 --- a/gsa/src/web/pages/policies/table.js +++ b/gsa/src/web/pages/policies/table.js @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2019 Greenbone Networks GmbH +/* Copyright (C) 2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * diff --git a/gsa/src/web/store/entities/audits.js b/gsa/src/web/store/entities/audits.js index b00fb3b8fb..e07b80025d 100644 --- a/gsa/src/web/store/entities/audits.js +++ b/gsa/src/web/store/entities/audits.js @@ -1,4 +1,4 @@ -/* Copyright (C) 2018-2019 Greenbone Networks GmbH +/* Copyright (C) 2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * diff --git a/gsa/src/web/store/entities/policies.js b/gsa/src/web/store/entities/policies.js index 27c7327c8b..f8937be1c8 100644 --- a/gsa/src/web/store/entities/policies.js +++ b/gsa/src/web/store/entities/policies.js @@ -1,4 +1,4 @@ -/* Copyright (C) 2018-2019 Greenbone Networks GmbH +/* Copyright (C) 2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * From 07d54835a20d7cd78f42c76b9f3e1c545411afd5 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Mon, 22 Jul 2019 14:11:16 +0200 Subject: [PATCH 40/66] add tests for compliance status bar --- .../__snapshots__/compliancestatusbar.js.snap | 65 +++++++++++++ .../bar/__tests__/compliancestatusbar.js | 94 +++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 gsa/src/web/components/bar/__tests__/__snapshots__/compliancestatusbar.js.snap create mode 100644 gsa/src/web/components/bar/__tests__/compliancestatusbar.js diff --git a/gsa/src/web/components/bar/__tests__/__snapshots__/compliancestatusbar.js.snap b/gsa/src/web/components/bar/__tests__/__snapshots__/compliancestatusbar.js.snap new file mode 100644 index 0000000000..b6371e3eb5 --- /dev/null +++ b/gsa/src/web/components/bar/__tests__/__snapshots__/compliancestatusbar.js.snap @@ -0,0 +1,65 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ComplianceStatusBar tests should render 1`] = ` +.c0 { + height: 13px; + box-sizing: content-box; + display: inline-block; + width: 100px; + background: #393637; + vertical-align: middle; + text-align: center; +} + +.c2 { + z-index: 1; + font-weight: bold; + color: #fff; + font-size: 9px; + margin: 0; + position: relative; + top: -13px; + padding-top: 1px; +} + +.c1 { + height: 13px; + width: 75%; + background: #f0a519; +} + +@media print { + .c0 { + background: none; + border: 0; + } +} + +@media print { + .c2 { + color: black; + } +} + +@media print { + .c1 { + background: none; + } +} + +
+
+
+ 75% +
+
+`; diff --git a/gsa/src/web/components/bar/__tests__/compliancestatusbar.js b/gsa/src/web/components/bar/__tests__/compliancestatusbar.js new file mode 100644 index 0000000000..53fadabd39 --- /dev/null +++ b/gsa/src/web/components/bar/__tests__/compliancestatusbar.js @@ -0,0 +1,94 @@ +/* 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} from 'web/utils/testing'; +import Theme from 'web/utils/theme'; + +import ComplianceStatusBar from '../compliancestatusbar'; + +describe('ComplianceStatusBar tests', () => { + test('should render', () => { + const {element} = render(); + + expect(element).toMatchSnapshot(); + }); + + test('should render text content', () => { + const {element} = render(); + expect(element).toHaveTextContent('75%'); + }); + + test('should render title', () => { + const {getByTestId} = render(); + const progressbarBox = getByTestId('progressbar-box'); + + expect(progressbarBox).toHaveAttribute('title', '75%'); + }); + + test('should render progress', () => { + const {getByTestId} = render(); + const progress = getByTestId('progress'); + + expect(progress).toHaveStyleRule('width', '75%'); + }); + + test('should not render progress > 100', () => { + const {element, getByTestId} = render( + , + ); + const progress = getByTestId('progress'); + + expect(progress).toHaveStyleRule('width', '100%'); + expect(element).toHaveTextContent('N/A'); + }); + + test('should not render progress < 0', () => { + const {element, getByTestId} = render( + , + ); + const progress = getByTestId('progress'); + + expect(progress).toHaveStyleRule('width', '0%'); + expect(element).toHaveTextContent('N/A'); + }); + + test('should render background for high compliance', () => { + const {getByTestId} = render( + , + ); + const progress = getByTestId('progress'); + + expect(progress).toHaveStyleRule('background', Theme.paleGreen); + }); + + test('should render background for medium compliance', () => { + const {getByTestId} = render(); + const progress = getByTestId('progress'); + + expect(progress).toHaveStyleRule('background', Theme.warnYellow); + }); + + test('should render background for low compliance', () => { + const {getByTestId} = render(); + const progress = getByTestId('progress'); + + expect(progress).toHaveStyleRule('background', Theme.errorRed); + }); +}); From a9a50beae576b8aa2de56ce007eb2d1baa351857 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Mon, 22 Jul 2019 14:14:11 +0200 Subject: [PATCH 41/66] add tests for store for audits and policies --- .../web/store/entities/__tests__/audits.js | 25 +++++++++++++++++++ .../web/store/entities/__tests__/policies.js | 25 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 gsa/src/web/store/entities/__tests__/audits.js create mode 100644 gsa/src/web/store/entities/__tests__/policies.js diff --git a/gsa/src/web/store/entities/__tests__/audits.js b/gsa/src/web/store/entities/__tests__/audits.js new file mode 100644 index 0000000000..21c7570a54 --- /dev/null +++ b/gsa/src/web/store/entities/__tests__/audits.js @@ -0,0 +1,25 @@ +/* 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 {testAll} from '../utils/testing'; + +import * as audits from '../audits'; + +testAll('audit', audits); + +// vim: set ts=2 sw=2 tw=80: diff --git a/gsa/src/web/store/entities/__tests__/policies.js b/gsa/src/web/store/entities/__tests__/policies.js new file mode 100644 index 0000000000..e108b85e48 --- /dev/null +++ b/gsa/src/web/store/entities/__tests__/policies.js @@ -0,0 +1,25 @@ +/* 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 {testAll} from '../utils/testing'; + +import * as policy from '../policies'; + +testAll('policy', policy); + +// vim: set ts=2 sw=2 tw=80: From 253fccd242499110014511fcf3e315e3ddaa4c26 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Mon, 22 Jul 2019 14:16:31 +0200 Subject: [PATCH 42/66] add tests for audit and policy models --- gsa/src/gmp/models/__tests__/audit.js | 178 ++++++++++++++++++ gsa/src/gmp/models/__tests__/policy.js | 250 +++++++++++++++++++++++++ 2 files changed, 428 insertions(+) create mode 100644 gsa/src/gmp/models/__tests__/audit.js create mode 100644 gsa/src/gmp/models/__tests__/policy.js diff --git a/gsa/src/gmp/models/__tests__/audit.js b/gsa/src/gmp/models/__tests__/audit.js new file mode 100644 index 0000000000..4b792561ac --- /dev/null +++ b/gsa/src/gmp/models/__tests__/audit.js @@ -0,0 +1,178 @@ +/* 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 'core-js/fn/object/entries'; + +import Audit, { + HOSTS_ORDERING_RANDOM, + HOSTS_ORDERING_REVERSE, + HOSTS_ORDERING_SEQUENTIAL, + TASK_STATUS, +} from 'gmp/models/audit'; +import {testModelProperties} from '../testing'; + +testModelProperties(Audit, 'audit', {testIsActive: false}); + +describe('Audit model tests', () => { + test('should parse undefined hosts_ordering', () => { + const obj = {hosts_ordering: undefined}; + const audit = new Audit(obj); + expect(audit.hosts_ordering).toBeUndefined(); + }); + + test('should parse unknown hosts_ordering as undefined', () => { + const obj = {hosts_ordering: 'foo'}; + const audit = new Audit(obj); + expect(audit.hosts_ordering).toBeUndefined(); + }); + + test('should parse known hosts_ordering', () => { + let obj = {hosts_ordering: HOSTS_ORDERING_RANDOM}; + let audit = new Audit(obj); + expect(audit.hosts_ordering).toEqual(HOSTS_ORDERING_RANDOM); + + obj = {hosts_ordering: HOSTS_ORDERING_REVERSE}; + audit = new Audit(obj); + expect(audit.hosts_ordering).toEqual(HOSTS_ORDERING_REVERSE); + + obj = {hosts_ordering: HOSTS_ORDERING_SEQUENTIAL}; + audit = new Audit(obj); + expect(audit.hosts_ordering).toEqual(HOSTS_ORDERING_SEQUENTIAL); + }); +}); + +describe(`Audit Model methods tests`, () => { + test('should use status for isActive', () => { + const statusList = { + [TASK_STATUS.running]: true, + [TASK_STATUS.stoprequested]: true, + [TASK_STATUS.deleterequested]: true, + [TASK_STATUS.ultimatedeleterequested]: true, + [TASK_STATUS.resumerequested]: true, + [TASK_STATUS.requested]: true, + [TASK_STATUS.stopped]: false, + [TASK_STATUS.new]: false, + [TASK_STATUS.interrupted]: false, + [TASK_STATUS.container]: false, + [TASK_STATUS.uploading]: false, + [TASK_STATUS.done]: false, + }; + + for (const [status, exp] of Object.entries(statusList)) { + const audit = new Audit({status}); + expect(audit.isActive()).toEqual(exp); + } + }); + + test('should use status for isRunning', () => { + const statusList = { + [TASK_STATUS.running]: true, + [TASK_STATUS.stoprequested]: false, + [TASK_STATUS.deleterequested]: false, + [TASK_STATUS.ultimatedeleterequested]: false, + [TASK_STATUS.resumerequested]: false, + [TASK_STATUS.requested]: false, + [TASK_STATUS.stopped]: false, + [TASK_STATUS.new]: false, + [TASK_STATUS.interrupted]: false, + [TASK_STATUS.container]: false, + [TASK_STATUS.uploading]: false, + [TASK_STATUS.done]: false, + }; + + for (const [status, exp] of Object.entries(statusList)) { + const audit = new Audit({status}); + expect(audit.isRunning()).toEqual(exp); + } + }); + + test('should use status for isStopped', () => { + const statusList = { + [TASK_STATUS.running]: false, + [TASK_STATUS.stoprequested]: false, + [TASK_STATUS.deleterequested]: false, + [TASK_STATUS.ultimatedeleterequested]: false, + [TASK_STATUS.resumerequested]: false, + [TASK_STATUS.requested]: false, + [TASK_STATUS.stopped]: true, + [TASK_STATUS.new]: false, + [TASK_STATUS.interrupted]: false, + [TASK_STATUS.container]: false, + [TASK_STATUS.uploading]: false, + [TASK_STATUS.done]: false, + }; + + for (const [status, exp] of Object.entries(statusList)) { + const audit = new Audit({status}); + expect(audit.isStopped()).toEqual(exp); + } + }); + + test('should use status for isInterrupted', () => { + const statusList = { + [TASK_STATUS.running]: false, + [TASK_STATUS.stoprequested]: false, + [TASK_STATUS.deleterequested]: false, + [TASK_STATUS.ultimatedeleterequested]: false, + [TASK_STATUS.resumerequested]: false, + [TASK_STATUS.requested]: false, + [TASK_STATUS.stopped]: false, + [TASK_STATUS.new]: false, + [TASK_STATUS.interrupted]: true, + [TASK_STATUS.container]: false, + [TASK_STATUS.uploading]: false, + [TASK_STATUS.done]: false, + }; + + for (const [status, exp] of Object.entries(statusList)) { + const audit = new Audit({status}); + expect(audit.isInterrupted()).toEqual(exp); + } + }); + + test('should use status for isNew', () => { + const statusList = { + [TASK_STATUS.running]: false, + [TASK_STATUS.stoprequested]: false, + [TASK_STATUS.deleterequested]: false, + [TASK_STATUS.ultimatedeleterequested]: false, + [TASK_STATUS.resumerequested]: false, + [TASK_STATUS.requested]: false, + [TASK_STATUS.stopped]: false, + [TASK_STATUS.new]: true, + [TASK_STATUS.interrupted]: false, + [TASK_STATUS.container]: false, + [TASK_STATUS.uploading]: false, + [TASK_STATUS.done]: false, + }; + + for (const [status, exp] of Object.entries(statusList)) { + const audit = new Audit({status}); + expect(audit.isNew()).toEqual(exp); + } + }); + + test('should be changeable if alterable or new', () => { + let audit = new Audit({status: TASK_STATUS.new, alterable: '0'}); + expect(audit.isChangeable()).toEqual(true); + + audit = new Audit({status: TASK_STATUS.done, alterable: '1'}); + expect(audit.isChangeable()).toEqual(true); + }); +}); diff --git a/gsa/src/gmp/models/__tests__/policy.js b/gsa/src/gmp/models/__tests__/policy.js new file mode 100644 index 0000000000..0cc04f264a --- /dev/null +++ b/gsa/src/gmp/models/__tests__/policy.js @@ -0,0 +1,250 @@ +/* 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. + */ + +/* eslint-disable max-len */ + +import Model from 'gmp/model'; +import Policy from 'gmp/models/policy'; +import {testModel} from 'gmp/models/testing'; + +testModel(Policy, 'policy'); + +describe('Policy model tests', () => { + test('should parse families', () => { + const elem = { + families: { + family: [ + { + name: 'foo', + nvt_count: '42', + max_nvt_count: '42', + growing: '1', + }, + ], + }, + }; + const res = [ + { + name: 'foo', + trend: '1', + nvts: { + count: 42, + max: 42, + }, + }, + ]; + const policy = new Policy(elem); + + expect(policy.family_list).toEqual(res); + }); + + test('should parse special nvt counts', () => { + const elem = { + families: { + family: [ + { + name: 'foo', + nvt_count: '-1', + max_nvt_count: '', + growing: '1', + }, + ], + }, + }; + const policy = new Policy(elem); + + expect(policy.family_list[0].nvts.count).toBeUndefined(); + expect(policy.family_list[0].nvts.max).toBeUndefined(); + }); + + test('should parse to families', () => { + const elem = { + families: { + family: [ + { + name: 'foo', + nvt_count: '42', + max_nvt_count: '42', + growing: '1', + }, + ], + }, + }; + const res = { + name: 'foo', + trend: '1', + nvts: { + count: 42, + max: 42, + }, + }; + const policy = new Policy(elem); + + expect(policy.families.foo).toEqual(res); + }); + + test('should return empty family_list array if no families are given', () => { + const policy = new Policy({}); + + expect(policy.family_list).toEqual([]); + }); + + test('should parse family_count', () => { + const elem = { + family_count: { + __text: '42', + growing: '1', + }, + }; + const policy = new Policy(elem); + + expect(policy.families.count).toEqual(42); + expect(policy.families.trend).toEqual('1'); + expect(policy.family_count).toBeUndefined(); + }); + + test('should parse nvt_count', () => { + const elem = { + nvt_count: { + __text: '42', + growing: '1', + }, + known_nvt_count: '21', + max_nvt_count: '1337', + }; + const res = { + count: 42, + trend: '1', + known: 21, + max: 1337, + }; + const policy = new Policy(elem); + + expect(policy.nvts).toEqual(res); + expect(policy.nvt_count).toBeUndefined(); + expect(policy.known_nvt_count).toBeUndefined(); + expect(policy.max_nvt_count).toBeUndefined(); + }); + + test('should return empty object if no nvt_counts are given', () => { + const policy = new Policy({}); + + expect(policy.nvts).toEqual({}); + }); + + test('should parse preferences', () => { + const elem = { + preferences: { + preference: [ + { + nvt: { + _oid: '123abc', + name: '', + }, + name: 'bar', + value: '42', + }, + { + nvt: { + _oid: '456def', + name: 'foo', + }, + name: 'lorem', + value: 'ipsum', + }, + ], + }, + }; + const nvtPreferences = [ + { + name: 'lorem', + nvt: { + name: 'foo', + oid: '456def', + }, + value: 'ipsum', + }, + ]; + const scannerPreferences = [ + { + name: 'bar', + value: '42', + }, + ]; + + const policy = new Policy(elem); + + expect(policy.preferences.scanner).toEqual(scannerPreferences); + expect(policy.preferences.nvt).toEqual(nvtPreferences); + }); + + test('should return empty arrays if no preferences are given', () => { + const policy = new Policy({}); + + expect(policy.preferences.scanner).toEqual([]); + expect(policy.preferences.nvt).toEqual([]); + }); + + test('should parse type', () => { + const policy = new Policy({type: '21'}); + + expect(policy.policy_type).toEqual(21); + }); + + test('should parse scanner', () => { + const elem = { + scanner: { + __text: 'foo', + id: '123abc', + }, + }; + const policy = new Policy(elem); + const policy2 = new Policy({}); + + expect(policy.scanner).toBeInstanceOf(Model); + expect(policy.scanner.entityType).toEqual('scanner'); + expect(policy.scanner.name).toEqual('foo'); + expect(policy2.scanner).toBeUndefined(); + }); + + test('should parse audits', () => { + const elem = { + tasks: { + task: [ + { + _id: '123', + name: 'foo', + }, + ], + }, + }; + const policy = new Policy(elem); + + expect(policy.audits[0]).toBeInstanceOf(Model); + expect(policy.audits[0].entityType).toEqual('audit'); + }); + + test('should return empty array if no tasks are given', () => { + const policy = new Policy({}); + + expect(policy.audits).toEqual([]); + }); +}); + +// vim: set ts=2 sw=2 tw=80: From 2f327234caf2f38cfa72892068117ce4f40ce58a Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Tue, 23 Jul 2019 13:31:08 +0200 Subject: [PATCH 43/66] remove import report for audits --- gsa/src/web/pages/audits/actions.js | 5 ----- gsa/src/web/pages/audits/listpage.js | 3 --- 2 files changed, 8 deletions(-) diff --git a/gsa/src/web/pages/audits/actions.js b/gsa/src/web/pages/audits/actions.js index c5e2bd9e0e..948af336a9 100644 --- a/gsa/src/web/pages/audits/actions.js +++ b/gsa/src/web/pages/audits/actions.js @@ -33,7 +33,6 @@ import EditIcon from 'web/entity/icon/editicon'; import TrashIcon from 'web/entity/icon/trashicon'; import DownloadIcon from 'web/components/icon/downloadicon'; -import ImportReportIcon from 'web/pages/tasks/icons/importreporticon'; import ResumeIcon from 'web/pages/audits/icons/resumeicon'; import ScheduleIcon from 'web/pages/tasks/icons/scheduleicon'; import StartIcon from 'web/pages/audits/icons/starticon'; @@ -46,7 +45,6 @@ const Actions = ({ links, gcrFormatDefined, onReportDownloadClick, - onReportImportClick, onAuditCloneClick, onAuditDeleteClick, onAuditDownloadClick, @@ -62,8 +60,6 @@ const Actions = ({ )} - - @@ -112,7 +108,6 @@ Actions.propTypes = { onAuditStartClick: PropTypes.func.isRequired, onAuditStopClick: PropTypes.func.isRequired, onReportDownloadClick: PropTypes.func.isRequired, - onReportImportClick: PropTypes.func.isRequired, }; export default withEntitiesActions(Actions); diff --git a/gsa/src/web/pages/audits/listpage.js b/gsa/src/web/pages/audits/listpage.js index 2a58257b0a..a15a3a72dc 100644 --- a/gsa/src/web/pages/audits/listpage.js +++ b/gsa/src/web/pages/audits/listpage.js @@ -66,7 +66,6 @@ const Page = ({onInteraction, onChanged, onDownloaded, onError, ...props}) => ( onDownloaded={onDownloaded} onDownloadError={onError} onInteraction={onInteraction} - onReportImported={onChanged} onResumed={onChanged} onResumeError={onError} onSaved={onChanged} @@ -85,7 +84,6 @@ const Page = ({onInteraction, onChanged, onDownloaded, onError, ...props}) => ( stop, resume, reportDownload, - reportimport, gcrFormatDefined, }) => ( ( onError={onError} onInteraction={onInteraction} onReportDownloadClick={reportDownload} - onReportImportClick={reportimport} onAuditCloneClick={clone} onAuditCreateClick={create} onAuditDeleteClick={deleteFunc} From a4c83662f5be481f277398113aa82b69d4a79112 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Wed, 24 Jul 2019 10:14:04 +0200 Subject: [PATCH 44/66] add tests for audit start icon and audit resume icon --- .../__snapshots__/resumeicon.js.snap | 34 +++++ .../__tests__/__snapshots__/starticon.js.snap | 34 +++++ .../audits/icons/__tests__/resumeicon.js | 120 ++++++++++++++++++ .../pages/audits/icons/__tests__/starticon.js | 109 ++++++++++++++++ 4 files changed, 297 insertions(+) create mode 100644 gsa/src/web/pages/audits/icons/__tests__/__snapshots__/resumeicon.js.snap create mode 100644 gsa/src/web/pages/audits/icons/__tests__/__snapshots__/starticon.js.snap create mode 100644 gsa/src/web/pages/audits/icons/__tests__/resumeicon.js create mode 100644 gsa/src/web/pages/audits/icons/__tests__/starticon.js diff --git a/gsa/src/web/pages/audits/icons/__tests__/__snapshots__/resumeicon.js.snap b/gsa/src/web/pages/audits/icons/__tests__/__snapshots__/resumeicon.js.snap new file mode 100644 index 0000000000..383db5c294 --- /dev/null +++ b/gsa/src/web/pages/audits/icons/__tests__/__snapshots__/resumeicon.js.snap @@ -0,0 +1,34 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Audit ResumeIcon component tests should render in active state with correct permissions 1`] = ` +.c1 { + cursor: pointer; +} + +.c0 { + height: 16px; + width: 16px; + line-height: 16px; +} + +.c0 * { + height: inherit; + width: inherit; +} + +@media print { + .c1 { + display: none; + } +} + + + + resume.svg + + +`; diff --git a/gsa/src/web/pages/audits/icons/__tests__/__snapshots__/starticon.js.snap b/gsa/src/web/pages/audits/icons/__tests__/__snapshots__/starticon.js.snap new file mode 100644 index 0000000000..8ed47ce477 --- /dev/null +++ b/gsa/src/web/pages/audits/icons/__tests__/__snapshots__/starticon.js.snap @@ -0,0 +1,34 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Audit StartIcon component tests should render in active state with correct permissions 1`] = ` +.c1 { + cursor: pointer; +} + +.c0 { + height: 16px; + width: 16px; + line-height: 16px; +} + +.c0 * { + height: inherit; + width: inherit; +} + +@media print { + .c1 { + display: none; + } +} + + + + start.svg + + +`; diff --git a/gsa/src/web/pages/audits/icons/__tests__/resumeicon.js b/gsa/src/web/pages/audits/icons/__tests__/resumeicon.js new file mode 100644 index 0000000000..199aa23011 --- /dev/null +++ b/gsa/src/web/pages/audits/icons/__tests__/resumeicon.js @@ -0,0 +1,120 @@ +/* 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 Capabilities from 'gmp/capabilities/capabilities'; + +import Audit, {TASK_STATUS} from 'gmp/models/audit'; + +import {rendererWith, fireEvent} from 'web/utils/testing'; + +import Theme from 'web/utils/theme'; + +import ResumeIcon from '../resumeicon'; + +describe('Audit ResumeIcon component tests', () => { + test('should render in active state with correct permissions', () => { + const caps = new Capabilities(['everything']); + const audit = new Audit({status: TASK_STATUS.stopped}); + const clickHandler = jest.fn(); + + const {render} = rendererWith({capabilities: caps}); + + const {element} = render( + , + ); + + expect(element).toMatchSnapshot(); + expect(caps.mayOp('resume_task')).toEqual(true); + + fireEvent.click(element); + + expect(clickHandler).toHaveBeenCalled(); + expect(element).toHaveAttribute('title', 'Resume'); + expect(element).not.toHaveStyleRule('fill', Theme.inputBorderGray, { + modifier: `svg path`, + }); + }); + + test('should render in inactive state if wrong command level permissions are given', () => { + const caps = new Capabilities(['authenticate']); + const audit = new Audit({status: TASK_STATUS.stopped}); + const clickHandler = jest.fn(); + + const {render} = rendererWith({capabilities: caps}); + + const {element} = render(); + + expect(caps.mayOp('resume_task')).toEqual(false); + fireEvent.click(element); + + expect(clickHandler).not.toHaveBeenCalled(); + expect(element).toHaveAttribute( + 'title', + 'Permission to resume audit denied', + ); + expect(element).toHaveStyleRule('fill', Theme.inputBorderGray, { + modifier: `svg path`, + }); + }); + + test('should render in inactive state if audit is not stopped', () => { + const caps = new Capabilities(['everything']); + const audit = new Audit({status: TASK_STATUS.new}); + const clickHandler = jest.fn(); + + const {render} = rendererWith({capabilities: caps}); + + const {element} = render(); + + expect(caps.mayOp('resume_task')).toEqual(true); + fireEvent.click(element); + + expect(clickHandler).not.toHaveBeenCalled(); + expect(element).toHaveAttribute('title', 'Audit is not stopped'); + expect(element).toHaveStyleRule('fill', Theme.inputBorderGray, { + modifier: `svg path`, + }); + }); + + test('should render in inactive state if audit is scheduled', () => { + const caps = new Capabilities(['everything']); + const elem = { + status: TASK_STATUS.new, + schedule: { + _id: 'schedule1', + }, + }; + const audit = new Audit(elem); + const clickHandler = jest.fn(); + + const {render} = rendererWith({capabilities: caps}); + + const {element} = render(); + + expect(caps.mayOp('resume_task')).toEqual(true); + fireEvent.click(element); + + expect(clickHandler).not.toHaveBeenCalled(); + expect(element).toHaveAttribute('title', 'Audit is scheduled'); + expect(element).toHaveStyleRule('fill', Theme.inputBorderGray, { + modifier: `svg path`, + }); + }); +}); diff --git a/gsa/src/web/pages/audits/icons/__tests__/starticon.js b/gsa/src/web/pages/audits/icons/__tests__/starticon.js new file mode 100644 index 0000000000..2abdfe646a --- /dev/null +++ b/gsa/src/web/pages/audits/icons/__tests__/starticon.js @@ -0,0 +1,109 @@ +/* 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 Capabilities from 'gmp/capabilities/capabilities'; + +import Audit, {TASK_STATUS} from 'gmp/models/audit'; + +import {rendererWith, fireEvent} from 'web/utils/testing'; + +import Theme from 'web/utils/theme'; + +import StartIcon from '../starticon'; + +describe('Audit StartIcon component tests', () => { + test('should render in active state with correct permissions', () => { + const caps = new Capabilities(['everything']); + const audit = new Audit({status: TASK_STATUS.new}); + const clickHandler = jest.fn(); + + const {render} = rendererWith({capabilities: caps}); + + const {element} = render( + , + ); + + expect(element).toMatchSnapshot(); + expect(caps.mayOp('start_task')).toEqual(true); + + fireEvent.click(element); + + expect(clickHandler).toHaveBeenCalled(); + expect(element).toHaveAttribute('title', 'Start'); + expect(element).not.toHaveStyleRule('fill', Theme.inputBorderGray, { + modifier: `svg path`, + }); + }); + + test('should render in inactive state if wrong command level permissions are given', () => { + const caps = new Capabilities(['authenticate']); + const audit = new Audit({status: TASK_STATUS.new}); + const clickHandler = jest.fn(); + + const {render} = rendererWith({capabilities: caps}); + + const {element} = render(); + + expect(caps.mayOp('start_task')).toEqual(false); + fireEvent.click(element); + + expect(clickHandler).not.toHaveBeenCalled(); + expect(element).toHaveAttribute( + 'title', + 'Permission to start Audit denied', + ); + expect(element).toHaveStyleRule('fill', Theme.inputBorderGray, { + modifier: `svg path`, + }); + }); + + test('should render in inactive state if audit is already active', () => { + const caps = new Capabilities(['everything']); + const audit = new Audit({status: TASK_STATUS.requested}); + const clickHandler = jest.fn(); + + const {render} = rendererWith({capabilities: caps}); + + const {element} = render(); + + expect(caps.mayOp('start_task')).toEqual(true); + fireEvent.click(element); + + expect(clickHandler).not.toHaveBeenCalled(); + expect(element).toHaveAttribute('title', 'Audit is already active'); + expect(element).toHaveStyleRule('fill', Theme.inputBorderGray, { + modifier: `svg path`, + }); + }); + + test('should not be rendered if audit is running', () => { + const caps = new Capabilities(['everything']); + const audit = new Audit({status: TASK_STATUS.running}); + + const {render} = rendererWith({capabilities: caps}); + + const {element} = render(); + + expect(caps.mayOp('start_task')).toEqual(true); + expect(element).toEqual(null); + }); +}); + +// vim: set ts=2 sw=2 tw=80: From ebc9475050281eaa335b954d604cba5e475f20be Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Thu, 25 Jul 2019 15:31:17 +0200 Subject: [PATCH 45/66] Fix empty tables in trashcan are not visible --- gsa/src/web/pages/extras/trashcanpage.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/gsa/src/web/pages/extras/trashcanpage.js b/gsa/src/web/pages/extras/trashcanpage.js index 3e02023df1..729212f0f8 100644 --- a/gsa/src/web/pages/extras/trashcanpage.js +++ b/gsa/src/web/pages/extras/trashcanpage.js @@ -236,14 +236,14 @@ class Trashcan extends React.Component { const {scan: tasks, compliance: audits} = separateByUsageType( trash.task_list, ); - const renderTasks = isDefined(tasks) ? tasks.length > 0 : false; - const renderAudits = isDefined(audits) ? audits.length > 0 : false; + const renderTasks = isDefined(trash.task_list); + const renderAudits = isDefined(trash.task_list); const {scan: configs, compliance: policies} = separateByUsageType( trash.config_list, ); - const renderConfigs = isDefined(configs) ? configs.length > 0 : false; - const renderPolicies = isDefined(policies) ? policies.length > 0 : false; + const renderConfigs = isDefined(trash.config_list); + const renderPolicies = isDefined(trash.config_list); return ( @@ -280,7 +280,7 @@ class Trashcan extends React.Component { trash.permission_list.length, )} {renderPolicies && - this.createContentRow('policies', 'Policies', policies.length)} + this.createContentRow('policy', 'Policies', policies.length)} {render_port_lists && this.createContentRow( 'port_list', @@ -386,14 +386,14 @@ class Trashcan extends React.Component { )} - {audits.length > 0 && ( + {isDefined(trash.task_list) && (

{_('Audits')}

)} - {configs.length > 0 && ( + {isDefined(trash.config_list) && (

{_('Scan Configs')}

@@ -448,7 +448,7 @@ class Trashcan extends React.Component { />
)} - {policies.length > 0 && ( + {isDefined(trash.config_list) > 0 && (

{_('Policies')}

@@ -507,7 +507,7 @@ class Trashcan extends React.Component {
)} - {tasks.length > 0 && ( + {isDefined(trash.task_list) > 0 && (

{_('Tasks')}

From de93455231032c8c8441898e89dead87febd4c3f Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Fri, 26 Jul 2019 09:08:17 +0200 Subject: [PATCH 46/66] add tests for audit actions and fix icon tooltips --- gsa/src/web/pages/audits/__tests__/actions.js | 470 ++++++++++++++++++ gsa/src/web/pages/audits/actions.js | 15 +- 2 files changed, 478 insertions(+), 7 deletions(-) create mode 100644 gsa/src/web/pages/audits/__tests__/actions.js diff --git a/gsa/src/web/pages/audits/__tests__/actions.js b/gsa/src/web/pages/audits/__tests__/actions.js new file mode 100644 index 0000000000..43ea158cee --- /dev/null +++ b/gsa/src/web/pages/audits/__tests__/actions.js @@ -0,0 +1,470 @@ +/* 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. + */ +/* eslint-disable no-console */ +import React from 'react'; + +import Capabilities from 'gmp/capabilities/capabilities'; +import {setLocale} from 'gmp/locale/lang'; + +import {rendererWith, fireEvent} from 'web/utils/testing'; +import Theme from 'web/utils/theme'; + +import Actions from '../actions'; +import Audit, {TASK_STATUS} from 'gmp/models/audit'; + +setLocale('en'); + +const caps = new Capabilities(['everything']); +const wrongCaps = new Capabilities(['authenticate']); + +describe('Audit Actions tests', () => { + // deactivate console.error for tests + // to make it possible to test actions without a table + const consoleError = console.error; + console.error = () => {}; + + test('should render', () => { + const audit = new Audit({ + status: TASK_STATUS.new, + alterable: '0', + last_report: {report: {_id: 'id'}}, + permissions: {permission: [{name: 'everything'}]}, + target: {_id: 'id', name: 'target'}, + }); + + const handleAuditClone = jest.fn(); + const handleAuditDelete = jest.fn(); + const handleAuditDownload = jest.fn(); + const handleAuditEdit = jest.fn(); + const handleAuditResume = jest.fn(); + const handleAuditStart = jest.fn(); + const handleAuditStop = jest.fn(); + const handleReportDownload = jest.fn(); + + const {render} = rendererWith({capabilities: caps}); + const {baseElement} = render( + , + ); + + expect(baseElement).toMatchSnapshot(); + }); + + test('should call click handlers', () => { + const audit = new Audit({ + status: TASK_STATUS.done, + alterable: '0', + last_report: {report: {_id: 'id'}}, + permissions: {permission: [{name: 'everything'}]}, + target: {_id: 'id', name: 'target'}, + }); + + const handleAuditClone = jest.fn(); + const handleAuditDelete = jest.fn(); + const handleAuditDownload = jest.fn(); + const handleAuditEdit = jest.fn(); + const handleAuditResume = jest.fn(); + const handleAuditStart = jest.fn(); + const handleAuditStop = jest.fn(); + const handleReportDownload = jest.fn(); + + const {render} = rendererWith({capabilities: true}); + const {getAllByTestId} = render( + , + ); + + const icons = getAllByTestId('svg-icon'); + + fireEvent.click(icons[0]); + expect(handleAuditStart).toHaveBeenCalledWith(audit); + expect(icons[0]).toHaveAttribute('title', 'Start'); + + fireEvent.click(icons[1]); + expect(handleAuditResume).not.toHaveBeenCalledWith(audit); + expect(icons[1]).toHaveAttribute('title', 'Audit is not stopped'); + + fireEvent.click(icons[2]); + expect(handleAuditDelete).toHaveBeenCalledWith(audit); + expect(icons[2]).toHaveAttribute('title', 'Move Audit to trashcan'); + + fireEvent.click(icons[3]); + expect(handleAuditEdit).toHaveBeenCalledWith(audit); + expect(icons[3]).toHaveAttribute('title', 'Edit Audit'); + + fireEvent.click(icons[4]); + expect(handleAuditClone).toHaveBeenCalledWith(audit); + expect(icons[4]).toHaveAttribute('title', 'Clone Audit'); + + fireEvent.click(icons[5]); + expect(handleAuditDownload).toHaveBeenCalledWith(audit); + expect(icons[5]).toHaveAttribute('title', 'Export Audit'); + + fireEvent.click(icons[6]); + expect(handleReportDownload).toHaveBeenCalledWith(audit); + expect(icons[6]).toHaveAttribute( + 'title', + 'Download Greenbone Compliance Report', + ); + }); + + test('should not call click handlers without permissions', () => { + const audit = new Audit({ + status: TASK_STATUS.done, + alterable: '0', + last_report: {report: {_id: 'id'}}, + permissions: {permission: [{name: 'authenticate'}]}, + target: {_id: 'id', name: 'target'}, + }); + + const handleAuditClone = jest.fn(); + const handleAuditDelete = jest.fn(); + const handleAuditDownload = jest.fn(); + const handleAuditEdit = jest.fn(); + const handleAuditResume = jest.fn(); + const handleAuditStart = jest.fn(); + const handleAuditStop = jest.fn(); + const handleReportDownload = jest.fn(); + + const {render} = rendererWith({capabilities: wrongCaps}); + const {getAllByTestId} = render( + , + ); + + const icons = getAllByTestId('svg-icon'); + + fireEvent.click(icons[0]); + expect(handleAuditStart).not.toHaveBeenCalledWith(audit); + expect(icons[0]).toHaveAttribute( + 'title', + 'Permission to start Audit denied', + ); + + fireEvent.click(icons[1]); + expect(handleAuditResume).not.toHaveBeenCalledWith(audit); + expect(icons[1]).toHaveAttribute('title', 'Audit is not stopped'); + + fireEvent.click(icons[2]); + expect(handleAuditDelete).not.toHaveBeenCalledWith(audit); + expect(icons[2]).toHaveAttribute( + 'title', + 'Permission to move Audit to trashcan denied', + ); + + fireEvent.click(icons[3]); + expect(handleAuditEdit).not.toHaveBeenCalledWith(audit); + expect(icons[3]).toHaveAttribute( + 'title', + 'Permission to edit Audit denied', + ); + + fireEvent.click(icons[4]); + expect(handleAuditClone).not.toHaveBeenCalledWith(audit); + expect(icons[4]).toHaveAttribute( + 'title', + 'Permission to clone Audit denied', + ); + + fireEvent.click(icons[5]); + expect(handleAuditDownload).toHaveBeenCalledWith(audit); + expect(icons[5]).toHaveAttribute('title', 'Export Audit'); + + fireEvent.click(icons[6]); + expect(handleReportDownload).toHaveBeenCalledWith(audit); + expect(icons[6]).toHaveAttribute( + 'title', + 'Download Greenbone Compliance Report', + ); + }); + + test('should call click handlers for running audit', () => { + const audit = new Audit({ + status: TASK_STATUS.running, + alterable: '0', + in_use: true, + permissions: {permission: [{name: 'everything'}]}, + target: {_id: 'id', name: 'target'}, + }); + + const handleAuditClone = jest.fn(); + const handleAuditDelete = jest.fn(); + const handleAuditDownload = jest.fn(); + const handleAuditEdit = jest.fn(); + const handleAuditResume = jest.fn(); + const handleAuditStart = jest.fn(); + const handleAuditStop = jest.fn(); + const handleReportDownload = jest.fn(); + + const {render} = rendererWith({capabilities: true}); + const {getAllByTestId} = render( + , + ); + + const icons = getAllByTestId('svg-icon'); + + fireEvent.click(icons[0]); + expect(handleAuditStop).toHaveBeenCalledWith(audit); + expect(icons[0]).toHaveAttribute('title', 'Stop'); + + fireEvent.click(icons[1]); + expect(handleAuditResume).not.toHaveBeenCalledWith(audit); + expect(icons[1]).toHaveAttribute('title', 'Audit is not stopped'); + + fireEvent.click(icons[2]); + expect(handleAuditDelete).not.toHaveBeenCalledWith(audit); + expect(icons[2]).toHaveAttribute('title', 'Audit is still in use'); + + fireEvent.click(icons[3]); + expect(handleAuditEdit).toHaveBeenCalledWith(audit); + expect(icons[3]).toHaveAttribute('title', 'Edit Audit'); + + fireEvent.click(icons[4]); + expect(handleAuditClone).toHaveBeenCalledWith(audit); + expect(icons[4]).toHaveAttribute('title', 'Clone Audit'); + + fireEvent.click(icons[5]); + expect(handleAuditDownload).toHaveBeenCalledWith(audit); + expect(icons[5]).toHaveAttribute('title', 'Export Audit'); + + // should not be called because the audit does not have a report yet + fireEvent.click(icons[6]); + expect(handleReportDownload).not.toHaveBeenCalledWith(audit); + expect(icons[6]).toHaveAttribute('title', 'Report download not available'); + }); + + test('should call click handlers for stopped audit', () => { + const audit = new Audit({ + status: TASK_STATUS.stopped, + alterable: '0', + last_report: {report: {_id: 'id'}}, + permissions: {permission: [{name: 'everything'}]}, + target: {_id: 'id', name: 'target'}, + }); + + const handleAuditClone = jest.fn(); + const handleAuditDelete = jest.fn(); + const handleAuditDownload = jest.fn(); + const handleAuditEdit = jest.fn(); + const handleAuditResume = jest.fn(); + const handleAuditStart = jest.fn(); + const handleAuditStop = jest.fn(); + const handleReportDownload = jest.fn(); + + const {render} = rendererWith({capabilities: true}); + const {getAllByTestId} = render( + , + ); + + const icons = getAllByTestId('svg-icon'); + + fireEvent.click(icons[0]); + expect(handleAuditStart).toHaveBeenCalledWith(audit); + expect(icons[0]).toHaveAttribute('title', 'Start'); + + fireEvent.click(icons[1]); + expect(handleAuditResume).toHaveBeenCalledWith(audit); + expect(icons[1]).toHaveAttribute('title', 'Resume'); + + fireEvent.click(icons[2]); + expect(handleAuditDelete).toHaveBeenCalledWith(audit); + expect(icons[2]).toHaveAttribute('title', 'Move Audit to trashcan'); + + fireEvent.click(icons[3]); + expect(handleAuditEdit).toHaveBeenCalledWith(audit); + expect(icons[3]).toHaveAttribute('title', 'Edit Audit'); + + fireEvent.click(icons[4]); + expect(handleAuditClone).toHaveBeenCalledWith(audit); + expect(icons[4]).toHaveAttribute('title', 'Clone Audit'); + + fireEvent.click(icons[5]); + expect(handleAuditDownload).toHaveBeenCalledWith(audit); + expect(icons[5]).toHaveAttribute('title', 'Export Audit'); + + fireEvent.click(icons[6]); + expect(handleReportDownload).toHaveBeenCalledWith(audit); + expect(icons[6]).toHaveAttribute( + 'title', + 'Download Greenbone Compliance Report', + ); + }); + + test('should disable report download if grc format is not defined', () => { + const audit = new Audit({ + status: TASK_STATUS.stopped, + alterable: '0', + last_report: {report: {_id: 'id'}}, + permissions: {permission: [{name: 'everything'}]}, + target: {_id: 'id', name: 'target'}, + }); + + const handleAuditClone = jest.fn(); + const handleAuditDelete = jest.fn(); + const handleAuditDownload = jest.fn(); + const handleAuditEdit = jest.fn(); + const handleAuditResume = jest.fn(); + const handleAuditStart = jest.fn(); + const handleAuditStop = jest.fn(); + const handleReportDownload = jest.fn(); + + const {render} = rendererWith({capabilities: true}); + const {getAllByTestId} = render( + , + ); + + const icons = getAllByTestId('svg-icon'); + + fireEvent.click(icons[6]); + expect(handleReportDownload).not.toHaveBeenCalledWith(audit); + expect(icons[6]).toHaveAttribute('title', 'Report download not available'); + expect(icons[6]).toHaveStyleRule('fill', Theme.inputBorderGray, { + modifier: `svg path`, + }); + }); + + test('should render schedule icon if task is scheduled', () => { + const audit = new Audit({ + status: TASK_STATUS.stopped, + alterable: '0', + last_report: {report: {_id: 'id'}}, + permissions: {permission: [{name: 'everything'}]}, + target: {_id: 'id', name: 'target'}, + schedule: { + _id: 'schedule1', + name: 'schedule1', + permissions: {permission: [{name: 'everything'}]}, + }, + }); + + const handleAuditClone = jest.fn(); + const handleAuditDelete = jest.fn(); + const handleAuditDownload = jest.fn(); + const handleAuditEdit = jest.fn(); + const handleAuditResume = jest.fn(); + const handleAuditStart = jest.fn(); + const handleAuditStop = jest.fn(); + const handleReportDownload = jest.fn(); + + const {render} = rendererWith({ + capabilities: true, + store: true, + router: true, + }); + const {getAllByTestId} = render( + , + ); + + const detailslinks = getAllByTestId('details-link'); + const icons = getAllByTestId('svg-icon'); + + fireEvent.click(detailslinks[0]); + expect(detailslinks[0]).toHaveAttribute( + 'title', + 'View Details of Schedule schedule1 (Next due: over)', + ); + + fireEvent.click(icons[1]); + expect(handleAuditResume).not.toHaveBeenCalledWith(audit); + expect(icons[1]).toHaveAttribute('title', 'Audit is scheduled'); + }); + + console.warn = consoleError; +}); diff --git a/gsa/src/web/pages/audits/actions.js b/gsa/src/web/pages/audits/actions.js index 948af336a9..604e5c0a2f 100644 --- a/gsa/src/web/pages/audits/actions.js +++ b/gsa/src/web/pages/audits/actions.js @@ -59,27 +59,24 @@ const Actions = ({ ) : ( )} - - - From 383cd5d17e59281c5bcf54d7b8f5c3959458c600 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Fri, 26 Jul 2019 11:55:22 +0200 Subject: [PATCH 47/66] adjust gcr report download --- gsa/src/web/pages/audits/component.js | 41 ++++++++++----------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/gsa/src/web/pages/audits/component.js b/gsa/src/web/pages/audits/component.js index 4f63231b48..292c85f731 100644 --- a/gsa/src/web/pages/audits/component.js +++ b/gsa/src/web/pages/audits/component.js @@ -80,7 +80,10 @@ import TargetComponent from 'web/pages/targets/component'; import AuditDialog from 'web/pages/audits/dialog'; -const REPORT_FORMATS_FILTER = Filter.fromString('active=1 trust=1 rows=-1'); +// TODO: use id instead of name when a unique id becomes available +const REPORT_FORMATS_FILTER = Filter.fromString( + 'name="GCR PDF" and active=1 and trust=1 and rows=-1', +); const DEFAULT_MIN_QOD = 70; @@ -91,7 +94,7 @@ class AuditComponent extends React.Component { this.state = { showDownloadReportDialog: false, auditDialogVisible: false, - gcrFormatDefined: undefined, + gcrFormatDefined: false, }; const {gmp} = this.props; @@ -126,24 +129,11 @@ class AuditComponent extends React.Component { componentDidMount() { this.props.loadUserSettingsDefaults(); - this.props.loadReportFormats(); - } - - componentDidUpdate() { - const {reportFormats} = this.props; - if ( - !isDefined(this.state.gcrFormatDefined) && - isDefined(reportFormats) && - reportFormats.length > 0 - ) { - const gcrFormat = reportFormats.find(format => { - return format.name === 'GCR PDF'; - }); - const gcrFormatDefined = isDefined(gcrFormat) - ? gcrFormat.active === 1 && gcrFormat.trust.value === 'yes' - : false; - this.setState({gcrFormatDefined: gcrFormatDefined}); - } + this.props.loadReportFormats().then(() => { + const {reportFormats} = this.props; + const gcrFormatDefined = isDefined(reportFormats[0]); + this.setState({gcrFormatDefined}); + }); } handleInteraction() { @@ -406,18 +396,17 @@ class AuditComponent extends React.Component { handleReportDownloadClick(audit) { this.setState({ - audit: audit, + audit, }); - this.handleReportDownload(this.state, audit); + this.handleReportDownload(audit); } - handleReportDownload(state, audit) { + handleReportDownload(audit) { + // TODO: use generateFilename when it becomes available for master const {gmp, reportFormats = [], onDownload} = this.props; - const reportFormat = reportFormats.find( - format => format.name === 'GCR PDF', - ); + const [reportFormat] = reportFormats; const extension = isDefined(reportFormat) ? reportFormat.extension From 68c8032348ab82e21769b2416a84be3bbb73bcab Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Fri, 26 Jul 2019 14:07:10 +0200 Subject: [PATCH 48/66] use same change handler for all entities in audit component --- gsa/src/web/pages/audits/component.js | 27 ++++----------------------- gsa/src/web/pages/audits/dialog.js | 18 ++++++------------ 2 files changed, 10 insertions(+), 35 deletions(-) diff --git a/gsa/src/web/pages/audits/component.js b/gsa/src/web/pages/audits/component.js index 292c85f731..7a8b2d2258 100644 --- a/gsa/src/web/pages/audits/component.js +++ b/gsa/src/web/pages/audits/component.js @@ -114,17 +114,13 @@ class AuditComponent extends React.Component { this.openAuditDialog = this.openAuditDialog.bind(this); this.handleCloseAuditDialog = this.handleCloseAuditDialog.bind(this); - this.handleAlertsChange = this.handleAlertsChange.bind(this); - this.handleTargetChange = this.handleTargetChange.bind(this); - this.handleScheduleChange = this.handleScheduleChange.bind(this); - this.handleAlertCreated = this.handleAlertCreated.bind(this); this.handleTargetCreated = this.handleTargetCreated.bind(this); this.handleScheduleCreated = this.handleScheduleCreated.bind(this); this.handleInteraction = this.handleInteraction.bind(this); - this.handlePolicyChange = this.handlePolicyChange.bind(this); + this.handleChange = this.handleChange.bind(this); } componentDidMount() { @@ -143,20 +139,8 @@ class AuditComponent extends React.Component { } } - handleTargetChange(targetId) { - this.setState({targetId}); - } - - handleAlertsChange(alertIds) { - this.setState({alertIds}); - } - - handleScheduleChange(scheduleId) { - this.setState({scheduleId}); - } - - handlePolicyChange(policyId) { - this.setState({policyId}); + handleChange(value, name) { + this.setState({[name]: value}); } handleAuditStart(audit) { @@ -538,13 +522,10 @@ class AuditComponent extends React.Component { targets={targets} audit={audit} title={title} - onAlertsChange={this.handleAlertsChange} onNewAlertClick={createalert} onNewTargetClick={createtarget} onNewScheduleClick={createschedule} - onPolicyChange={this.handlePolicyChange} - onScheduleChange={this.handleScheduleChange} - onTargetChange={this.handleTargetChange} + onChange={this.handleChange} onClose={this.handleCloseAuditDialog} onSave={this.handleSaveAudit} /> diff --git a/gsa/src/web/pages/audits/dialog.js b/gsa/src/web/pages/audits/dialog.js index d6d54374ca..bb463e5c91 100644 --- a/gsa/src/web/pages/audits/dialog.js +++ b/gsa/src/web/pages/audits/dialog.js @@ -80,15 +80,12 @@ const AuditDialog = ({ targets, audit, title = _('New Audit'), - onAlertsChange, onClose, onNewAlertClick, onNewScheduleClick, onNewTargetClick, onSave, - onPolicyChange, - onScheduleChange, - onTargetChange, + onChange, ...data }) => { const targetItems = renderSelectItems(targets); @@ -166,7 +163,7 @@ const AuditDialog = ({ disabled={!changeAudit} items={targetItems} value={state.targetId} - onChange={onTargetChange} + onChange={onChange} /> {changeAudit && ( @@ -186,7 +183,7 @@ const AuditDialog = ({ name="alertIds" items={alertItems} value={state.alertIds} - onChange={onAlertsChange} + onChange={onChange} /> @@ -343,15 +340,12 @@ AuditDialog.propTypes = { targetId: PropTypes.idOrZero, targets: PropTypes.array, title: PropTypes.string, - onAlertsChange: PropTypes.func.isRequired, + onChange: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired, onNewAlertClick: PropTypes.func.isRequired, onNewScheduleClick: PropTypes.func.isRequired, onNewTargetClick: PropTypes.func.isRequired, - onPolicyChange: PropTypes.func.isRequired, onSave: PropTypes.func.isRequired, - onScheduleChange: PropTypes.func.isRequired, - onTargetChange: PropTypes.func.isRequired, }; export default withCapabilities(AuditDialog); From 68dbef81831dd24394596c5f9ab2f3ad2c3279cc Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Fri, 26 Jul 2019 14:53:51 +0200 Subject: [PATCH 49/66] use new filename format for report download --- gsa/src/web/pages/audits/component.js | 31 +++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/gsa/src/web/pages/audits/component.js b/gsa/src/web/pages/audits/component.js index 7a8b2d2258..890dc9e6f6 100644 --- a/gsa/src/web/pages/audits/component.js +++ b/gsa/src/web/pages/audits/component.js @@ -66,11 +66,13 @@ import { import {loadUserSettingDefaults} from 'web/store/usersettings/defaults/actions'; import {getUserSettingsDefaults} from 'web/store/usersettings/defaults/selectors'; +import {getUsername} from 'web/store/usersettings/selectors'; + import compose from 'web/utils/compose'; import PropTypes from 'web/utils/proptypes'; import withCapabilities from 'web/utils/withCapabilities'; import withGmp from 'web/utils/withGmp'; -import {UNSET_VALUE} from 'web/utils/render'; +import {UNSET_VALUE, generateFilename} from 'web/utils/render'; import EntityComponent from 'web/entity/component'; @@ -387,8 +389,13 @@ class AuditComponent extends React.Component { } handleReportDownload(audit) { - // TODO: use generateFilename when it becomes available for master - const {gmp, reportFormats = [], onDownload} = this.props; + const { + gmp, + reportExportFileName, + username, + reportFormats = [], + onDownload, + } = this.props; const [reportFormat] = reportFormats; @@ -411,7 +418,15 @@ class AuditComponent extends React.Component { ) .then(response => { const {data} = response; - const filename = 'report-' + id + '.' + extension; + const filename = generateFilename({ + extension, + fileNameFormat: reportExportFileName, + id: id, + reportFormat: reportFormat.name, + resourceName: audit.name, + resourceType: 'report', + username, + }); onDownload({filename, data}); }, this.handleError); } @@ -560,9 +575,11 @@ AuditComponent.propTypes = { loadTargets: PropTypes.func.isRequired, loadUserSettingsDefaults: PropTypes.func.isRequired, policies: PropTypes.arrayOf(PropTypes.model), + reportExportFileName: PropTypes.object, reportFormats: PropTypes.array, schedules: PropTypes.arrayOf(PropTypes.model), targets: PropTypes.arrayOf(PropTypes.model), + username: PropTypes.string, onCloneError: PropTypes.func, onCloned: PropTypes.func, onCreateError: PropTypes.func, @@ -589,6 +606,8 @@ const mapStateToProps = (rootState, {match}) => { const policiesSel = policiesSelector(rootState); const scheduleSel = scheduleSelector(rootState); const targetSel = targetSelector(rootState); + const userDefaultsSelector = getUserSettingsDefaults(rootState); + const username = getUsername(rootState); const reportFormatsSel = reportFormatsSelector(rootState); @@ -597,10 +616,14 @@ const mapStateToProps = (rootState, {match}) => { defaultAlertId: userDefaults.getValueByName('defaultalert'), defaultScheduleId: userDefaults.getValueByName('defaultschedule'), defaultTargetId: userDefaults.getValueByName('defaulttarget'), + reportExportFileName: userDefaultsSelector.getValueByName( + 'reportexportfilename', + ), reportFormats: reportFormatsSel.getAllEntities(REPORT_FORMATS_FILTER), policies: policiesSel.getEntities(ALL_FILTER), schedules: scheduleSel.getEntities(ALL_FILTER), targets: targetSel.getEntities(ALL_FILTER), + username, }; }; From 3357d47ee746492a47a150fa24c5afc88a10111b Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Fri, 26 Jul 2019 15:05:47 +0200 Subject: [PATCH 50/66] add missing details to audits --- gsa/src/web/pages/audits/details.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/gsa/src/web/pages/audits/details.js b/gsa/src/web/pages/audits/details.js index 651e767707..1570ff5e03 100644 --- a/gsa/src/web/pages/audits/details.js +++ b/gsa/src/web/pages/audits/details.js @@ -99,8 +99,10 @@ class AuditDetails extends React.Component { scanner, schedule_periods, target, + max_checks, + max_hosts, } = entity; - const {max_checks = {}, iface = {}, max_hosts = {}} = preferences; + const {iface = {}} = preferences; let dur; const has_duration = @@ -200,22 +202,22 @@ class AuditDetails extends React.Component { )} {isDefined(policy) && policy.policy_type === OPENVAS_SCAN_CONFIG_TYPE && - isDefined(max_checks.name) && ( + isDefined(max_checks) && ( {_('Maximum concurrently executed NVTs per host')} - {max_checks.value} + {max_checks} )} {isDefined(policy) && policy.policy_type === OPENVAS_SCAN_CONFIG_TYPE && - isDefined(max_hosts.name) && ( + isDefined(max_hosts) && ( {_('Maximum concurrently scanned hosts')} - {max_hosts.value} + {max_hosts} )}
From fa65e6a9ae4516305b9c17ef6caf60ebf24b5fe0 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Fri, 26 Jul 2019 16:42:50 +0200 Subject: [PATCH 51/66] adjust audit table --- gsa/src/web/pages/audits/table.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gsa/src/web/pages/audits/table.js b/gsa/src/web/pages/audits/table.js index 8b2d19c264..a57ee36a9b 100644 --- a/gsa/src/web/pages/audits/table.js +++ b/gsa/src/web/pages/audits/table.js @@ -51,7 +51,7 @@ const Header = ({ return ( - + Date: Mon, 29 Jul 2019 11:44:04 +0200 Subject: [PATCH 52/66] fix permissions command --- gsa/src/gmp/commands/permissions.js | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/gsa/src/gmp/commands/permissions.js b/gsa/src/gmp/commands/permissions.js index 5b77cbc636..badcabe519 100644 --- a/gsa/src/gmp/commands/permissions.js +++ b/gsa/src/gmp/commands/permissions.js @@ -48,12 +48,11 @@ class PermissionCommand extends EntityCommand { resourceType, subjectType, }) { - resourceType = - resourceType === 'policy' - ? 'config' - : resourceType === 'audit' - ? 'task' - : resourceType; + if (resourceType === 'policy') { + resourceType = 'config'; + } else if (resourceType === 'audit') { + resourceType = 'task'; + } const data = { cmd: 'create_permission', @@ -116,12 +115,11 @@ class PermissionsCommand extends EntitiesCommand { includeRelated, related = [], }) { - entityType = - entityType === 'policy' - ? 'config' - : entityType === 'audit' - ? 'task' - : entityType; + if (entityType === 'policy') { + entityType = 'config'; + } else if (entityType === 'audit') { + entityType = 'task'; + } const data = { cmd: 'create_permissions', From a83c7274d94bab044e6f68851c5fc9b9340c94f9 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Mon, 29 Jul 2019 12:04:33 +0200 Subject: [PATCH 53/66] update actions and datepicker snapshots --- .../__snapshots__/datepicker.js.snap | 5 +- .../__tests__/__snapshots__/actions.js.snap | 197 ++++++++++++++++++ 2 files changed, 200 insertions(+), 2 deletions(-) create mode 100644 gsa/src/web/pages/audits/__tests__/__snapshots__/actions.js.snap diff --git a/gsa/src/web/components/form/__tests__/__snapshots__/datepicker.js.snap b/gsa/src/web/components/form/__tests__/__snapshots__/datepicker.js.snap index 6ce7c48bf6..5408662fb8 100644 --- a/gsa/src/web/components/form/__tests__/__snapshots__/datepicker.js.snap +++ b/gsa/src/web/components/form/__tests__/__snapshots__/datepicker.js.snap @@ -61,12 +61,13 @@ exports[`DatePicker component tests should render 2`] = ` class="react-datepicker__input-container" >
2018/11/11 calendar.svg diff --git a/gsa/src/web/pages/audits/__tests__/__snapshots__/actions.js.snap b/gsa/src/web/pages/audits/__tests__/__snapshots__/actions.js.snap new file mode 100644 index 0000000000..e7822807ce --- /dev/null +++ b/gsa/src/web/pages/audits/__tests__/__snapshots__/actions.js.snap @@ -0,0 +1,197 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Audit Actions tests should render 1`] = ` +.c0 { + 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: stretch; + -webkit-box-align: stretch; + -ms-flex-align: stretch; + align-items: stretch; +} + +.c2 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -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: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-left: -5px; +} + +.c2 > * { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; +} + +.c2 > * { + margin-left: 5px; +} + +.c1 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -webkit-box-pack: start; + -webkit-justify-content: start; + -ms-flex-pack: start; + justify-content: start; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; +} + +.c4 { + cursor: pointer; +} + +.c5 svg path { + fill: #aaaaaa; +} + +.c3 { + height: 16px; + width: 16px; + line-height: 16px; +} + +.c3 * { + height: inherit; + width: inherit; +} + +@media print { + .c4 { + display: none; + } +} + + +
+
+ +
+
+
+ + + start.svg + + + + + resume.svg + + + + + trashcan.svg + + + + + edit.svg + + + + + clone.svg + + + + + export.svg + + + + + download.svg + + +
+
+
+ +
+ +`; From 51393406f9d13de982abf1549d79ccbf8a65951d Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Mon, 29 Jul 2019 15:43:51 +0200 Subject: [PATCH 54/66] update policy model and commands --- gsa/src/gmp/commands/policies.js | 38 +---------------------------- gsa/src/gmp/commands/scanconfigs.js | 6 ++--- gsa/src/gmp/models/policy.js | 5 +--- 3 files changed, 5 insertions(+), 44 deletions(-) diff --git a/gsa/src/gmp/commands/policies.js b/gsa/src/gmp/commands/policies.js index f816c46afa..601ff68db3 100644 --- a/gsa/src/gmp/commands/policies.js +++ b/gsa/src/gmp/commands/policies.js @@ -21,7 +21,6 @@ import 'core-js/fn/object/entries'; import logger from '../log'; import {forEach, map} from '../utils/array'; -import {isDefined} from '../utils/identity'; import Model from '../model'; import registerCommand from '../command'; @@ -34,45 +33,10 @@ import Policy from '../models/policy'; import EntitiesCommand from './entities'; import EntityCommand from './entity'; +import {convert, convert_select, convert_preferences} from './scanconfigs'; const log = logger.getLogger('gmp.commands.policies'); -const convert = (values, prefix) => { - const ret = {}; - for (const [key, value] of Object.entries(values)) { - ret[prefix + key] = value; - } - return ret; -}; - -const convert_select = (values, prefix) => { - const ret = {}; - for (const [key, value] of Object.entries(values)) { - if (value === YES_VALUE) { - ret[prefix + key] = value; - } - } - return ret; -}; - -const convert_preferences = (values, nvt_oid) => { - const ret = {}; - for (const prop in values) { - const data = values[prop]; - const {id, type, value} = data; - if (isDefined(value)) { - const typestring = nvt_oid + ':' + id + ':' + type + ':' + prop; - if (type === 'password') { - ret['password:' + typestring] = 'yes'; - } else if (type === 'file') { - ret['file:' + typestring] = 'yes'; - } - ret['preference:' + typestring] = value; - } - } - return ret; -}; - class PolicyCommand extends EntityCommand { constructor(http) { super(http, 'config', Policy); diff --git a/gsa/src/gmp/commands/scanconfigs.js b/gsa/src/gmp/commands/scanconfigs.js index dd2d66e6b6..ce44ef51fd 100644 --- a/gsa/src/gmp/commands/scanconfigs.js +++ b/gsa/src/gmp/commands/scanconfigs.js @@ -37,7 +37,7 @@ import EntityCommand from './entity'; const log = logger.getLogger('gmp.commands.scanconfigs'); -const convert = (values, prefix) => { +export const convert = (values, prefix) => { const ret = {}; for (const [key, value] of Object.entries(values)) { ret[prefix + key] = value; @@ -45,7 +45,7 @@ const convert = (values, prefix) => { return ret; }; -const convert_select = (values, prefix) => { +export const convert_select = (values, prefix) => { const ret = {}; for (const [key, value] of Object.entries(values)) { if (value === YES_VALUE) { @@ -55,7 +55,7 @@ const convert_select = (values, prefix) => { return ret; }; -const convert_preferences = (values, nvt_oid) => { +export const convert_preferences = (values, nvt_oid) => { const ret = {}; for (const prop in values) { const data = values[prop]; diff --git a/gsa/src/gmp/models/policy.js b/gsa/src/gmp/models/policy.js index 9f307fefe1..712e1bb8ae 100644 --- a/gsa/src/gmp/models/policy.js +++ b/gsa/src/gmp/models/policy.js @@ -24,10 +24,7 @@ import {isEmpty} from '../utils/string'; import {parseInt} from '../parser'; import Model from '../model'; - -export const parse_count = count => { - return !isEmpty(count) && count !== '-1' ? parseInt(count) : undefined; -}; +import {parse_count} from './scanconfig'; class Policy extends Model { static entityType = 'policy'; From e15bae87ae20bda2b74a004c04e0e81dd2639eef Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Tue, 30 Jul 2019 09:35:33 +0200 Subject: [PATCH 55/66] update audit model --- gsa/src/gmp/models/__tests__/audit.js | 126 +++++++++--------- gsa/src/gmp/models/audit.js | 79 ++++------- gsa/src/gmp/models/task.js | 2 +- gsa/src/web/pages/audits/__tests__/actions.js | 16 +-- .../audits/icons/__tests__/resumeicon.js | 10 +- .../pages/audits/icons/__tests__/starticon.js | 10 +- 6 files changed, 105 insertions(+), 138 deletions(-) diff --git a/gsa/src/gmp/models/__tests__/audit.js b/gsa/src/gmp/models/__tests__/audit.js index 4b792561ac..058a301bbe 100644 --- a/gsa/src/gmp/models/__tests__/audit.js +++ b/gsa/src/gmp/models/__tests__/audit.js @@ -23,7 +23,7 @@ import Audit, { HOSTS_ORDERING_RANDOM, HOSTS_ORDERING_REVERSE, HOSTS_ORDERING_SEQUENTIAL, - TASK_STATUS, + AUDIT_STATUS, } from 'gmp/models/audit'; import {testModelProperties} from '../testing'; @@ -60,18 +60,18 @@ describe('Audit model tests', () => { describe(`Audit Model methods tests`, () => { test('should use status for isActive', () => { const statusList = { - [TASK_STATUS.running]: true, - [TASK_STATUS.stoprequested]: true, - [TASK_STATUS.deleterequested]: true, - [TASK_STATUS.ultimatedeleterequested]: true, - [TASK_STATUS.resumerequested]: true, - [TASK_STATUS.requested]: true, - [TASK_STATUS.stopped]: false, - [TASK_STATUS.new]: false, - [TASK_STATUS.interrupted]: false, - [TASK_STATUS.container]: false, - [TASK_STATUS.uploading]: false, - [TASK_STATUS.done]: false, + [AUDIT_STATUS.running]: true, + [AUDIT_STATUS.stoprequested]: true, + [AUDIT_STATUS.deleterequested]: true, + [AUDIT_STATUS.ultimatedeleterequested]: true, + [AUDIT_STATUS.resumerequested]: true, + [AUDIT_STATUS.requested]: true, + [AUDIT_STATUS.stopped]: false, + [AUDIT_STATUS.new]: false, + [AUDIT_STATUS.interrupted]: false, + [AUDIT_STATUS.container]: false, + [AUDIT_STATUS.uploading]: false, + [AUDIT_STATUS.done]: false, }; for (const [status, exp] of Object.entries(statusList)) { @@ -82,18 +82,18 @@ describe(`Audit Model methods tests`, () => { test('should use status for isRunning', () => { const statusList = { - [TASK_STATUS.running]: true, - [TASK_STATUS.stoprequested]: false, - [TASK_STATUS.deleterequested]: false, - [TASK_STATUS.ultimatedeleterequested]: false, - [TASK_STATUS.resumerequested]: false, - [TASK_STATUS.requested]: false, - [TASK_STATUS.stopped]: false, - [TASK_STATUS.new]: false, - [TASK_STATUS.interrupted]: false, - [TASK_STATUS.container]: false, - [TASK_STATUS.uploading]: false, - [TASK_STATUS.done]: false, + [AUDIT_STATUS.running]: true, + [AUDIT_STATUS.stoprequested]: false, + [AUDIT_STATUS.deleterequested]: false, + [AUDIT_STATUS.ultimatedeleterequested]: false, + [AUDIT_STATUS.resumerequested]: false, + [AUDIT_STATUS.requested]: false, + [AUDIT_STATUS.stopped]: false, + [AUDIT_STATUS.new]: false, + [AUDIT_STATUS.interrupted]: false, + [AUDIT_STATUS.container]: false, + [AUDIT_STATUS.uploading]: false, + [AUDIT_STATUS.done]: false, }; for (const [status, exp] of Object.entries(statusList)) { @@ -104,18 +104,18 @@ describe(`Audit Model methods tests`, () => { test('should use status for isStopped', () => { const statusList = { - [TASK_STATUS.running]: false, - [TASK_STATUS.stoprequested]: false, - [TASK_STATUS.deleterequested]: false, - [TASK_STATUS.ultimatedeleterequested]: false, - [TASK_STATUS.resumerequested]: false, - [TASK_STATUS.requested]: false, - [TASK_STATUS.stopped]: true, - [TASK_STATUS.new]: false, - [TASK_STATUS.interrupted]: false, - [TASK_STATUS.container]: false, - [TASK_STATUS.uploading]: false, - [TASK_STATUS.done]: false, + [AUDIT_STATUS.running]: false, + [AUDIT_STATUS.stoprequested]: false, + [AUDIT_STATUS.deleterequested]: false, + [AUDIT_STATUS.ultimatedeleterequested]: false, + [AUDIT_STATUS.resumerequested]: false, + [AUDIT_STATUS.requested]: false, + [AUDIT_STATUS.stopped]: true, + [AUDIT_STATUS.new]: false, + [AUDIT_STATUS.interrupted]: false, + [AUDIT_STATUS.container]: false, + [AUDIT_STATUS.uploading]: false, + [AUDIT_STATUS.done]: false, }; for (const [status, exp] of Object.entries(statusList)) { @@ -126,18 +126,18 @@ describe(`Audit Model methods tests`, () => { test('should use status for isInterrupted', () => { const statusList = { - [TASK_STATUS.running]: false, - [TASK_STATUS.stoprequested]: false, - [TASK_STATUS.deleterequested]: false, - [TASK_STATUS.ultimatedeleterequested]: false, - [TASK_STATUS.resumerequested]: false, - [TASK_STATUS.requested]: false, - [TASK_STATUS.stopped]: false, - [TASK_STATUS.new]: false, - [TASK_STATUS.interrupted]: true, - [TASK_STATUS.container]: false, - [TASK_STATUS.uploading]: false, - [TASK_STATUS.done]: false, + [AUDIT_STATUS.running]: false, + [AUDIT_STATUS.stoprequested]: false, + [AUDIT_STATUS.deleterequested]: false, + [AUDIT_STATUS.ultimatedeleterequested]: false, + [AUDIT_STATUS.resumerequested]: false, + [AUDIT_STATUS.requested]: false, + [AUDIT_STATUS.stopped]: false, + [AUDIT_STATUS.new]: false, + [AUDIT_STATUS.interrupted]: true, + [AUDIT_STATUS.container]: false, + [AUDIT_STATUS.uploading]: false, + [AUDIT_STATUS.done]: false, }; for (const [status, exp] of Object.entries(statusList)) { @@ -148,18 +148,18 @@ describe(`Audit Model methods tests`, () => { test('should use status for isNew', () => { const statusList = { - [TASK_STATUS.running]: false, - [TASK_STATUS.stoprequested]: false, - [TASK_STATUS.deleterequested]: false, - [TASK_STATUS.ultimatedeleterequested]: false, - [TASK_STATUS.resumerequested]: false, - [TASK_STATUS.requested]: false, - [TASK_STATUS.stopped]: false, - [TASK_STATUS.new]: true, - [TASK_STATUS.interrupted]: false, - [TASK_STATUS.container]: false, - [TASK_STATUS.uploading]: false, - [TASK_STATUS.done]: false, + [AUDIT_STATUS.running]: false, + [AUDIT_STATUS.stoprequested]: false, + [AUDIT_STATUS.deleterequested]: false, + [AUDIT_STATUS.ultimatedeleterequested]: false, + [AUDIT_STATUS.resumerequested]: false, + [AUDIT_STATUS.requested]: false, + [AUDIT_STATUS.stopped]: false, + [AUDIT_STATUS.new]: true, + [AUDIT_STATUS.interrupted]: false, + [AUDIT_STATUS.container]: false, + [AUDIT_STATUS.uploading]: false, + [AUDIT_STATUS.done]: false, }; for (const [status, exp] of Object.entries(statusList)) { @@ -169,10 +169,10 @@ describe(`Audit Model methods tests`, () => { }); test('should be changeable if alterable or new', () => { - let audit = new Audit({status: TASK_STATUS.new, alterable: '0'}); + let audit = new Audit({status: AUDIT_STATUS.new, alterable: '0'}); expect(audit.isChangeable()).toEqual(true); - audit = new Audit({status: TASK_STATUS.done, alterable: '1'}); + audit = new Audit({status: AUDIT_STATUS.done, alterable: '1'}); expect(audit.isChangeable()).toEqual(true); }); }); diff --git a/gsa/src/gmp/models/audit.js b/gsa/src/gmp/models/audit.js index 739638772e..9cc96c510e 100644 --- a/gsa/src/gmp/models/audit.js +++ b/gsa/src/gmp/models/audit.js @@ -16,8 +16,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ -import {_l} from 'gmp/locale/lang'; - import {isDefined, isArray} from '../utils/identity'; import {isEmpty} from '../utils/string'; import {map} from '../utils/array'; @@ -29,7 +27,6 @@ import { parseYesNo, parseDuration, NO_VALUE, - YES_VALUE, } from '../parser'; import Model from '../model'; @@ -38,60 +35,30 @@ import Report from './report'; import Schedule from './schedule'; import Scanner from './scanner'; -export const AUTO_DELETE_KEEP = 'keep'; -export const AUTO_DELETE_NO = 'no'; -export const AUTO_DELETE_KEEP_DEFAULT_VALUE = 5; - -export const HOSTS_ORDERING_SEQUENTIAL = 'sequential'; -export const HOSTS_ORDERING_RANDOM = 'random'; -export const HOSTS_ORDERING_REVERSE = 'reverse'; - -export const TASK_STATUS = { - running: 'Running', - stoprequested: 'Stop Requested', - deleterequested: 'Delete Requested', - ultimatedeleterequested: 'Ultimate Delete Requested', - resumerequested: 'Resume Requested', - requested: 'Requested', - stopped: 'Stopped', - new: 'New', - interrupted: 'Interrupted', - container: 'Container', - uploading: 'Uploading', - done: 'Done', -}; - -/* eslint-disable quote-props */ -const TASK_STATUS_TRANSLATIONS = { - Running: _l('Running'), - 'Stop Requested': _l('Stop Requested'), - 'Delete Requested': _l('Delete Requested'), - 'Ultimate Delete Requested': _l('Ultimate Delete Requested'), - 'Resume Requested': _l('Resume Requested'), - Requested: _l('Requested'), - Stopped: _l('Stopped'), - New: _l('New'), - Interrupted: _l('Interrupted'), - Container: _l('Container'), - Uploading: _l('Uploading'), - Done: _l('Done'), +import { + AUTO_DELETE_KEEP, + AUTO_DELETE_NO, + AUTO_DELETE_KEEP_DEFAULT_VALUE, + HOSTS_ORDERING_SEQUENTIAL, + HOSTS_ORDERING_RANDOM, + HOSTS_ORDERING_REVERSE, + TASK_STATUS, + getTranslatableTaskStatus, + isActive, + parse_yes, +} from './task'; + +export { + AUTO_DELETE_KEEP, + AUTO_DELETE_NO, + AUTO_DELETE_KEEP_DEFAULT_VALUE, + HOSTS_ORDERING_SEQUENTIAL, + HOSTS_ORDERING_RANDOM, + HOSTS_ORDERING_REVERSE, + TASK_STATUS as AUDIT_STATUS, + getTranslatableTaskStatus as getTranslatableAuditStatus, + isActive, }; -/* eslint-disable quote-props */ - -function parse_yes(value) { - return value === 'yes' ? YES_VALUE : NO_VALUE; -} - -export const getTranslatableTaskStatus = status => - `${TASK_STATUS_TRANSLATIONS[status]}`; - -export const isActive = status => - status === TASK_STATUS.running || - status === TASK_STATUS.stoprequested || - status === TASK_STATUS.deleterequested || - status === TASK_STATUS.ultimatedeleterequested || - status === TASK_STATUS.resumerequested || - status === TASK_STATUS.requested; class Audit extends Model { static entityType = 'audit'; diff --git a/gsa/src/gmp/models/task.js b/gsa/src/gmp/models/task.js index 13ac903a62..29b6176678 100644 --- a/gsa/src/gmp/models/task.js +++ b/gsa/src/gmp/models/task.js @@ -78,7 +78,7 @@ const TASK_STATUS_TRANSLATIONS = { }; /* eslint-disable quote-props */ -function parse_yes(value) { +export function parse_yes(value) { return value === 'yes' ? YES_VALUE : NO_VALUE; } diff --git a/gsa/src/web/pages/audits/__tests__/actions.js b/gsa/src/web/pages/audits/__tests__/actions.js index 43ea158cee..28f137c6f4 100644 --- a/gsa/src/web/pages/audits/__tests__/actions.js +++ b/gsa/src/web/pages/audits/__tests__/actions.js @@ -26,7 +26,7 @@ import {rendererWith, fireEvent} from 'web/utils/testing'; import Theme from 'web/utils/theme'; import Actions from '../actions'; -import Audit, {TASK_STATUS} from 'gmp/models/audit'; +import Audit, {AUDIT_STATUS} from 'gmp/models/audit'; setLocale('en'); @@ -41,7 +41,7 @@ describe('Audit Actions tests', () => { test('should render', () => { const audit = new Audit({ - status: TASK_STATUS.new, + status: AUDIT_STATUS.new, alterable: '0', last_report: {report: {_id: 'id'}}, permissions: {permission: [{name: 'everything'}]}, @@ -79,7 +79,7 @@ describe('Audit Actions tests', () => { test('should call click handlers', () => { const audit = new Audit({ - status: TASK_STATUS.done, + status: AUDIT_STATUS.done, alterable: '0', last_report: {report: {_id: 'id'}}, permissions: {permission: [{name: 'everything'}]}, @@ -148,7 +148,7 @@ describe('Audit Actions tests', () => { test('should not call click handlers without permissions', () => { const audit = new Audit({ - status: TASK_STATUS.done, + status: AUDIT_STATUS.done, alterable: '0', last_report: {report: {_id: 'id'}}, permissions: {permission: [{name: 'authenticate'}]}, @@ -229,7 +229,7 @@ describe('Audit Actions tests', () => { test('should call click handlers for running audit', () => { const audit = new Audit({ - status: TASK_STATUS.running, + status: AUDIT_STATUS.running, alterable: '0', in_use: true, permissions: {permission: [{name: 'everything'}]}, @@ -296,7 +296,7 @@ describe('Audit Actions tests', () => { test('should call click handlers for stopped audit', () => { const audit = new Audit({ - status: TASK_STATUS.stopped, + status: AUDIT_STATUS.stopped, alterable: '0', last_report: {report: {_id: 'id'}}, permissions: {permission: [{name: 'everything'}]}, @@ -365,7 +365,7 @@ describe('Audit Actions tests', () => { test('should disable report download if grc format is not defined', () => { const audit = new Audit({ - status: TASK_STATUS.stopped, + status: AUDIT_STATUS.stopped, alterable: '0', last_report: {report: {_id: 'id'}}, permissions: {permission: [{name: 'everything'}]}, @@ -410,7 +410,7 @@ describe('Audit Actions tests', () => { test('should render schedule icon if task is scheduled', () => { const audit = new Audit({ - status: TASK_STATUS.stopped, + status: AUDIT_STATUS.stopped, alterable: '0', last_report: {report: {_id: 'id'}}, permissions: {permission: [{name: 'everything'}]}, diff --git a/gsa/src/web/pages/audits/icons/__tests__/resumeicon.js b/gsa/src/web/pages/audits/icons/__tests__/resumeicon.js index 199aa23011..a760831214 100644 --- a/gsa/src/web/pages/audits/icons/__tests__/resumeicon.js +++ b/gsa/src/web/pages/audits/icons/__tests__/resumeicon.js @@ -20,7 +20,7 @@ import React from 'react'; import Capabilities from 'gmp/capabilities/capabilities'; -import Audit, {TASK_STATUS} from 'gmp/models/audit'; +import Audit, {AUDIT_STATUS} from 'gmp/models/audit'; import {rendererWith, fireEvent} from 'web/utils/testing'; @@ -31,7 +31,7 @@ import ResumeIcon from '../resumeicon'; describe('Audit ResumeIcon component tests', () => { test('should render in active state with correct permissions', () => { const caps = new Capabilities(['everything']); - const audit = new Audit({status: TASK_STATUS.stopped}); + const audit = new Audit({status: AUDIT_STATUS.stopped}); const clickHandler = jest.fn(); const {render} = rendererWith({capabilities: caps}); @@ -54,7 +54,7 @@ describe('Audit ResumeIcon component tests', () => { test('should render in inactive state if wrong command level permissions are given', () => { const caps = new Capabilities(['authenticate']); - const audit = new Audit({status: TASK_STATUS.stopped}); + const audit = new Audit({status: AUDIT_STATUS.stopped}); const clickHandler = jest.fn(); const {render} = rendererWith({capabilities: caps}); @@ -76,7 +76,7 @@ describe('Audit ResumeIcon component tests', () => { test('should render in inactive state if audit is not stopped', () => { const caps = new Capabilities(['everything']); - const audit = new Audit({status: TASK_STATUS.new}); + const audit = new Audit({status: AUDIT_STATUS.new}); const clickHandler = jest.fn(); const {render} = rendererWith({capabilities: caps}); @@ -96,7 +96,7 @@ describe('Audit ResumeIcon component tests', () => { test('should render in inactive state if audit is scheduled', () => { const caps = new Capabilities(['everything']); const elem = { - status: TASK_STATUS.new, + status: AUDIT_STATUS.new, schedule: { _id: 'schedule1', }, diff --git a/gsa/src/web/pages/audits/icons/__tests__/starticon.js b/gsa/src/web/pages/audits/icons/__tests__/starticon.js index 2abdfe646a..dd58887dc7 100644 --- a/gsa/src/web/pages/audits/icons/__tests__/starticon.js +++ b/gsa/src/web/pages/audits/icons/__tests__/starticon.js @@ -20,7 +20,7 @@ import React from 'react'; import Capabilities from 'gmp/capabilities/capabilities'; -import Audit, {TASK_STATUS} from 'gmp/models/audit'; +import Audit, {AUDIT_STATUS} from 'gmp/models/audit'; import {rendererWith, fireEvent} from 'web/utils/testing'; @@ -31,7 +31,7 @@ import StartIcon from '../starticon'; describe('Audit StartIcon component tests', () => { test('should render in active state with correct permissions', () => { const caps = new Capabilities(['everything']); - const audit = new Audit({status: TASK_STATUS.new}); + const audit = new Audit({status: AUDIT_STATUS.new}); const clickHandler = jest.fn(); const {render} = rendererWith({capabilities: caps}); @@ -54,7 +54,7 @@ describe('Audit StartIcon component tests', () => { test('should render in inactive state if wrong command level permissions are given', () => { const caps = new Capabilities(['authenticate']); - const audit = new Audit({status: TASK_STATUS.new}); + const audit = new Audit({status: AUDIT_STATUS.new}); const clickHandler = jest.fn(); const {render} = rendererWith({capabilities: caps}); @@ -76,7 +76,7 @@ describe('Audit StartIcon component tests', () => { test('should render in inactive state if audit is already active', () => { const caps = new Capabilities(['everything']); - const audit = new Audit({status: TASK_STATUS.requested}); + const audit = new Audit({status: AUDIT_STATUS.requested}); const clickHandler = jest.fn(); const {render} = rendererWith({capabilities: caps}); @@ -95,7 +95,7 @@ describe('Audit StartIcon component tests', () => { test('should not be rendered if audit is running', () => { const caps = new Capabilities(['everything']); - const audit = new Audit({status: TASK_STATUS.running}); + const audit = new Audit({status: AUDIT_STATUS.running}); const {render} = rendererWith({capabilities: caps}); From d1e44de02725ff2f9683edec7e3c94a48721f2be Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Tue, 30 Jul 2019 10:22:40 +0200 Subject: [PATCH 56/66] fix audit model --- gsa/src/gmp/models/audit.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/gsa/src/gmp/models/audit.js b/gsa/src/gmp/models/audit.js index 9cc96c510e..eb5a71be75 100644 --- a/gsa/src/gmp/models/audit.js +++ b/gsa/src/gmp/models/audit.js @@ -42,8 +42,8 @@ import { HOSTS_ORDERING_SEQUENTIAL, HOSTS_ORDERING_RANDOM, HOSTS_ORDERING_REVERSE, - TASK_STATUS, - getTranslatableTaskStatus, + TASK_STATUS as AUDIT_STATUS, + getTranslatableTaskStatus as getTranslatableAuditStatus, isActive, parse_yes, } from './task'; @@ -55,8 +55,8 @@ export { HOSTS_ORDERING_SEQUENTIAL, HOSTS_ORDERING_RANDOM, HOSTS_ORDERING_REVERSE, - TASK_STATUS as AUDIT_STATUS, - getTranslatableTaskStatus as getTranslatableAuditStatus, + AUDIT_STATUS, + getTranslatableAuditStatus, isActive, }; @@ -68,19 +68,19 @@ class Audit extends Model { } isRunning() { - return this.status === TASK_STATUS.running; + return this.status === AUDIT_STATUS.running; } isStopped() { - return this.status === TASK_STATUS.stopped; + return this.status === AUDIT_STATUS.stopped; } isInterrupted() { - return this.status === TASK_STATUS.interrupted; + return this.status === AUDIT_STATUS.interrupted; } isNew() { - return this.status === TASK_STATUS.new; + return this.status === AUDIT_STATUS.new; } isChangeable() { @@ -96,7 +96,7 @@ class Audit extends Model { } getTranslatableStatus() { - return getTranslatableTaskStatus(this.status); + return getTranslatableAuditStatus(this.status); } parseProperties(elem) { From 0e2f303e4a19479dd43b1a48b51edd2dd963c680 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Tue, 30 Jul 2019 13:37:14 +0200 Subject: [PATCH 57/66] update policy header and table --- gsa/src/web/pages/policies/header.js | 3 +-- gsa/src/web/pages/policies/table.js | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/gsa/src/web/pages/policies/header.js b/gsa/src/web/pages/policies/header.js index 095f39747d..022be3c6a2 100644 --- a/gsa/src/web/pages/policies/header.js +++ b/gsa/src/web/pages/policies/header.js @@ -39,7 +39,6 @@ const Header = ({ {actions && ( - + {_('Actions')} )} diff --git a/gsa/src/web/pages/policies/table.js b/gsa/src/web/pages/policies/table.js index 380bfa0ad6..2bd086dded 100644 --- a/gsa/src/web/pages/policies/table.js +++ b/gsa/src/web/pages/policies/table.js @@ -40,7 +40,7 @@ const PoliciesTable = createEntitiesTable({ rowDetails: withRowDetails('policy')(PolicyDetails), footer: createEntitiesFooter({ download: 'policies.xml', - span: 7, + span: 2, trash: true, tags: false, }), From 35bfb3a3b19cb13c5d54f96100eccf862c031e75 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Tue, 30 Jul 2019 16:27:00 +0200 Subject: [PATCH 58/66] only use one audit dialog --- gsa/src/web/pages/audits/dialog.js | 6 +- gsa/src/web/pages/policies/component.js | 30 +- .../web/pages/policies/createauditdialog.js | 323 ------------------ 3 files changed, 16 insertions(+), 343 deletions(-) delete mode 100644 gsa/src/web/pages/policies/createauditdialog.js diff --git a/gsa/src/web/pages/audits/dialog.js b/gsa/src/web/pages/audits/dialog.js index bb463e5c91..4c0c5e3831 100644 --- a/gsa/src/web/pages/audits/dialog.js +++ b/gsa/src/web/pages/audits/dialog.js @@ -65,13 +65,14 @@ const AuditDialog = ({ auto_delete_data = AUTO_DELETE_KEEP_DEFAULT_VALUE, capabilities, comment = '', - policyId, + fromPolicy = false, hostsOrdering = HOSTS_ORDERING_SEQUENTIAL, in_assets = YES_VALUE, maxChecks = DEFAULT_MAX_CHECKS, maxHosts = DEFAULT_MAX_HOSTS, name = _('Unnamed'), policies = [], + policyId, scheduleId = UNSET_VALUE, schedulePeriods = NO_VALUE, schedules = [], @@ -248,7 +249,7 @@ const AuditDialog = ({ - - - - - - - {capabilities.mayOp('get_alerts') && ( - - - - - - - - - )} - - {capabilities.mayOp('get_schedules') && ( - - - - - - - - - - - - - ); - }} - - ); -}; - -CreateAuditDialog.propTypes = { - alertIds: PropTypes.array, - alerts: PropTypes.array, - alterable: PropTypes.yesno, - auto_delete: PropTypes.oneOf(['keep', 'no']), - auto_delete_data: PropTypes.number, - capabilities: PropTypes.capabilities.isRequired, - comment: PropTypes.string, - hostsOrdering: PropTypes.oneOf(['sequential', 'random', 'reverse']), - in_assets: PropTypes.yesno, - maxChecks: PropTypes.number, - maxHosts: PropTypes.number, - minQod: PropTypes.number, - name: PropTypes.string, - scheduleId: PropTypes.idOrZero, - schedulePeriods: PropTypes.yesno, - schedules: PropTypes.array, - sourceIface: PropTypes.string, - targetId: PropTypes.idOrZero, - targets: PropTypes.array, - title: PropTypes.string, - onAlertsChange: PropTypes.func.isRequired, - onClose: PropTypes.func.isRequired, - onNewAlertClick: PropTypes.func.isRequired, - onNewScheduleClick: PropTypes.func.isRequired, - onNewTargetClick: PropTypes.func.isRequired, - onSave: PropTypes.func.isRequired, - onScheduleChange: PropTypes.func.isRequired, - onTargetChange: PropTypes.func.isRequired, -}; - -export default withCapabilities(CreateAuditDialog); - -// vim: set ts=2 sw=2 tw=80: From ef8103cc76ddec74494c90ebe0f938697d56e8f1 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Tue, 30 Jul 2019 16:45:54 +0200 Subject: [PATCH 59/66] update theme --- .../bar/__tests__/__snapshots__/compliancestatusbar.js.snap | 2 +- gsa/src/web/components/bar/__tests__/compliancestatusbar.js | 2 +- gsa/src/web/components/bar/compliancestatusbar.js | 2 +- gsa/src/web/utils/theme.js | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gsa/src/web/components/bar/__tests__/__snapshots__/compliancestatusbar.js.snap b/gsa/src/web/components/bar/__tests__/__snapshots__/compliancestatusbar.js.snap index b6371e3eb5..6e2da937ab 100644 --- a/gsa/src/web/components/bar/__tests__/__snapshots__/compliancestatusbar.js.snap +++ b/gsa/src/web/components/bar/__tests__/__snapshots__/compliancestatusbar.js.snap @@ -25,7 +25,7 @@ exports[`ComplianceStatusBar tests should render 1`] = ` .c1 { height: 13px; width: 75%; - background: #f0a519; + background: #fdc300; } @media print { diff --git a/gsa/src/web/components/bar/__tests__/compliancestatusbar.js b/gsa/src/web/components/bar/__tests__/compliancestatusbar.js index 53fadabd39..8d82ef5939 100644 --- a/gsa/src/web/components/bar/__tests__/compliancestatusbar.js +++ b/gsa/src/web/components/bar/__tests__/compliancestatusbar.js @@ -82,7 +82,7 @@ describe('ComplianceStatusBar tests', () => { const {getByTestId} = render(); const progress = getByTestId('progress'); - expect(progress).toHaveStyleRule('background', Theme.warnYellow); + expect(progress).toHaveStyleRule('background', Theme.goldYellow); }); test('should render background for low compliance', () => { diff --git a/gsa/src/web/components/bar/compliancestatusbar.js b/gsa/src/web/components/bar/compliancestatusbar.js index 443f7ae2fb..82b0491d15 100644 --- a/gsa/src/web/components/bar/compliancestatusbar.js +++ b/gsa/src/web/components/bar/compliancestatusbar.js @@ -41,7 +41,7 @@ const ComplianceStatusBar = ({complianceStatus}) => { } else if (complianceStatus <= 50) { type = Theme.errorRed; } else { - type = Theme.warnYellow; + type = Theme.goldYellow; } return ( diff --git a/gsa/src/web/utils/theme.js b/gsa/src/web/utils/theme.js index d9176f5d10..3d99ec01f3 100644 --- a/gsa/src/web/utils/theme.js +++ b/gsa/src/web/utils/theme.js @@ -21,14 +21,12 @@ const Theme = { /* source styleguide */ lightGreen: '#87d050', green: '#66c430', - paleGreen: '#99BE48', lightGray: '#c8d3d9', // used by: disabled inputs mediumGray: '#787878', darkGray: '#393637', goldYellow: '#fdc300', - warnYellow: '#f0a519', redBrown: '#a54317', /* source own */ @@ -48,6 +46,8 @@ const Theme = { mediumBlue: '#5897fb', // used by active/hovered items in Select blue: '#0000ff', // used by: links + paleGreen: '#99BE48', // used by: compliance status bar + /* source ? */ darkGreen: '#519032', // RGB: 81, 144, 50 darkGreenTransparent: 'rgba(81, 144, 50, 0.8)', // corresponds to darkGreen From ab71f71799f9e9e06737e09427308130178f2d4e Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Tue, 30 Jul 2019 16:53:10 +0200 Subject: [PATCH 60/66] fix compliance status bar imports --- gsa/src/web/components/bar/compliancestatusbar.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gsa/src/web/components/bar/compliancestatusbar.js b/gsa/src/web/components/bar/compliancestatusbar.js index 82b0491d15..c694824bd9 100644 --- a/gsa/src/web/components/bar/compliancestatusbar.js +++ b/gsa/src/web/components/bar/compliancestatusbar.js @@ -20,10 +20,10 @@ import React from 'react'; import _ from 'gmp/locale'; -import PropTypes from '../../utils/proptypes.js'; +import PropTypes from 'web/utils/proptypes'; import Theme from 'web/utils/theme'; -import ProgressBar from './progressbar.js'; +import ProgressBar from 'web/components/bar/progressbar'; const ComplianceStatusBar = ({complianceStatus}) => { let text; From f1f012e8f08dfa193ee13f577348e4f91de82575 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Wed, 31 Jul 2019 08:16:44 +0200 Subject: [PATCH 61/66] move constants to task model --- gsa/src/gmp/models/audit.js | 6 ++++++ gsa/src/gmp/models/task.js | 4 ++++ gsa/src/web/pages/audits/component.js | 3 +-- gsa/src/web/pages/audits/dialog.js | 5 ++--- gsa/src/web/pages/policies/component.js | 3 +-- gsa/src/web/pages/tasks/dialog.js | 7 +++---- 6 files changed, 17 insertions(+), 11 deletions(-) diff --git a/gsa/src/gmp/models/audit.js b/gsa/src/gmp/models/audit.js index eb5a71be75..9b3ec755d3 100644 --- a/gsa/src/gmp/models/audit.js +++ b/gsa/src/gmp/models/audit.js @@ -42,6 +42,9 @@ import { HOSTS_ORDERING_SEQUENTIAL, HOSTS_ORDERING_RANDOM, HOSTS_ORDERING_REVERSE, + DEFAULT_MAX_CHECKS, + DEFAULT_MAX_HOSTS, + DEFAULT_MIN_QOD, TASK_STATUS as AUDIT_STATUS, getTranslatableTaskStatus as getTranslatableAuditStatus, isActive, @@ -55,6 +58,9 @@ export { HOSTS_ORDERING_SEQUENTIAL, HOSTS_ORDERING_RANDOM, HOSTS_ORDERING_REVERSE, + DEFAULT_MAX_CHECKS, + DEFAULT_MAX_HOSTS, + DEFAULT_MIN_QOD, AUDIT_STATUS, getTranslatableAuditStatus, isActive, diff --git a/gsa/src/gmp/models/task.js b/gsa/src/gmp/models/task.js index 29b6176678..0d37d084a1 100644 --- a/gsa/src/gmp/models/task.js +++ b/gsa/src/gmp/models/task.js @@ -46,6 +46,10 @@ export const HOSTS_ORDERING_SEQUENTIAL = 'sequential'; export const HOSTS_ORDERING_RANDOM = 'random'; export const HOSTS_ORDERING_REVERSE = 'reverse'; +export const DEFAULT_MAX_CHECKS = 4; +export const DEFAULT_MAX_HOSTS = 20; +export const DEFAULT_MIN_QOD = 70; + export const TASK_STATUS = { running: 'Running', stoprequested: 'Stop Requested', diff --git a/gsa/src/web/pages/audits/component.js b/gsa/src/web/pages/audits/component.js index 890dc9e6f6..bcd74c8aa9 100644 --- a/gsa/src/web/pages/audits/component.js +++ b/gsa/src/web/pages/audits/component.js @@ -23,6 +23,7 @@ import {connect} from 'react-redux'; import _ from 'gmp/locale'; import Filter, {ALL_FILTER} from 'gmp/models/filter'; +import {DEFAULT_MIN_QOD} from 'gmp/models/audit'; import {NO_VALUE, YES_VALUE} from 'gmp/parser'; @@ -87,8 +88,6 @@ const REPORT_FORMATS_FILTER = Filter.fromString( 'name="GCR PDF" and active=1 and trust=1 and rows=-1', ); -const DEFAULT_MIN_QOD = 70; - class AuditComponent extends React.Component { constructor(...args) { super(...args); diff --git a/gsa/src/web/pages/audits/dialog.js b/gsa/src/web/pages/audits/dialog.js index 4c0c5e3831..3423f15b3d 100644 --- a/gsa/src/web/pages/audits/dialog.js +++ b/gsa/src/web/pages/audits/dialog.js @@ -30,6 +30,8 @@ import { AUTO_DELETE_KEEP_DEFAULT_VALUE, HOSTS_ORDERING_SEQUENTIAL, AUTO_DELETE_NO, + DEFAULT_MAX_CHECKS, + DEFAULT_MAX_HOSTS, } from 'gmp/models/audit'; import PropTypes from 'web/utils/proptypes'; @@ -54,9 +56,6 @@ import Layout from 'web/components/layout/layout'; import AddResultsToAssetsGroup from 'web/pages/tasks/addresultstoassetsgroup'; import AutoDeleteReportsGroup from 'web/pages/tasks/autodeletereportsgroup'; -const DEFAULT_MAX_CHECKS = 4; -const DEFAULT_MAX_HOSTS = 20; - const AuditDialog = ({ alertIds = [], alerts = [], diff --git a/gsa/src/web/pages/policies/component.js b/gsa/src/web/pages/policies/component.js index ba3f813c06..a178bd63ba 100644 --- a/gsa/src/web/pages/policies/component.js +++ b/gsa/src/web/pages/policies/component.js @@ -23,6 +23,7 @@ import {connect} from 'react-redux'; import _ from 'gmp/locale'; import {ALL_FILTER} from 'gmp/models/filter'; +import {DEFAULT_MIN_QOD} from 'gmp/models/audit'; import {forEach} from 'gmp/utils/array'; import {isDefined} from 'gmp/utils/identity'; @@ -80,8 +81,6 @@ import ScheduleComponent from 'web/pages/schedules/component'; import AlertComponent from 'web/pages/alerts/component'; import TargetComponent from 'web/pages/targets/component'; -const DEFAULT_MIN_QOD = 70; - class PolicyComponent extends React.Component { constructor(...args) { super(...args); diff --git a/gsa/src/web/pages/tasks/dialog.js b/gsa/src/web/pages/tasks/dialog.js index 3283a5fbd0..2358c7592d 100644 --- a/gsa/src/web/pages/tasks/dialog.js +++ b/gsa/src/web/pages/tasks/dialog.js @@ -33,6 +33,9 @@ import { AUTO_DELETE_KEEP_DEFAULT_VALUE, HOSTS_ORDERING_SEQUENTIAL, AUTO_DELETE_NO, + DEFAULT_MAX_CHECKS, + DEFAULT_MAX_HOSTS, + DEFAULT_MIN_QOD, } from 'gmp/models/task'; import { @@ -172,10 +175,6 @@ ScannerSelect.propTypes = { onScannerChange: PropTypes.func.isRequired, }; -const DEFAULT_MAX_CHECKS = 4; -const DEFAULT_MAX_HOSTS = 20; -const DEFAULT_MIN_QOD = 70; - const TaskDialog = ({ add_tag = NO_VALUE, alert_ids = [], From dea4f87052abb07da628ddb3fb6dd154ac3fc000 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Wed, 31 Jul 2019 08:17:45 +0200 Subject: [PATCH 62/66] fix policy row --- gsa/src/web/pages/policies/row.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gsa/src/web/pages/policies/row.js b/gsa/src/web/pages/policies/row.js index f3f67ec2eb..cb3b747c77 100644 --- a/gsa/src/web/pages/policies/row.js +++ b/gsa/src/web/pages/policies/row.js @@ -89,6 +89,7 @@ const PoliciesActions = compose( PoliciesActions.propTypes = { entity: PropTypes.model.isRequired, + onCreateAuditClick: PropTypes.func.isRequired, onPolicyCloneClick: PropTypes.func.isRequired, onPolicyDeleteClick: PropTypes.func.isRequired, onPolicyDownloadClick: PropTypes.func.isRequired, @@ -104,7 +105,6 @@ const PoliciesRow = ({ }) => ( Date: Wed, 31 Jul 2019 12:44:12 +0200 Subject: [PATCH 63/66] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f62726351..1d775453d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] ### Added +- Added Explicit Compliance [#1495](https://github.com/greenbone/gsa/pull/1495) - added tasktrendgroup component for tasks filter dialog [#1511](https://github.com/greenbone/gsa/pull/1511) - Added HorizontalSep component for horizontal lists. [#1494](https://github.com/greenbone/gsa/pull/1494) - added BooleanFilterGroup and changed notes filter dialog [#1493](https://github.com/greenbone/gsa/pull/1493) From 6e9c61b12882ba8a32ca18e602dd7a45b3e7d88c Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Wed, 31 Jul 2019 13:51:11 +0200 Subject: [PATCH 64/66] fix capabilities in menubar --- gsa/src/web/components/bar/menubar.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gsa/src/web/components/bar/menubar.js b/gsa/src/web/components/bar/menubar.js index 9b36d72516..bc9175bec6 100644 --- a/gsa/src/web/components/bar/menubar.js +++ b/gsa/src/web/components/bar/menubar.js @@ -112,7 +112,7 @@ const MenuBar = ({isLoggedIn, capabilities}) => { false, ); - const mayOpResilience = ['tickets', 'scan_configs', 'tasks'].reduce( + const mayOpResilience = ['tickets', 'policies', 'audits'].reduce( (sum, cur) => sum || capabilities.mayAccess(cur), false, ); @@ -161,10 +161,10 @@ const MenuBar = ({isLoggedIn, capabilities}) => { )} - {capabilities.mayAccess('configs') && ( + {capabilities.mayAccess('policies') && ( )} - {capabilities.mayAccess('tasks') && ( + {capabilities.mayAccess('audits') && ( )} From d2dc30ec0a26f5a82789b8abab12fd15b8540814 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Wed, 31 Jul 2019 14:14:02 +0200 Subject: [PATCH 65/66] use scanconfig import dialog for policies --- gsa/src/web/pages/policies/component.js | 4 +- gsa/src/web/pages/policies/importdialog.js | 61 ------------------- gsa/src/web/pages/scanconfigs/component.js | 2 + gsa/src/web/pages/scanconfigs/importdialog.js | 8 ++- 4 files changed, 10 insertions(+), 65 deletions(-) delete mode 100644 gsa/src/web/pages/policies/importdialog.js diff --git a/gsa/src/web/pages/policies/component.js b/gsa/src/web/pages/policies/component.js index a178bd63ba..b59dc1191b 100644 --- a/gsa/src/web/pages/policies/component.js +++ b/gsa/src/web/pages/policies/component.js @@ -74,7 +74,7 @@ import EditPolicyFamilyDialog from 'web/pages/policies/editpolicyfamilydialog'; import EditPolicyDialog from 'web/pages/policies/editdialog'; import EditNvtDetailsDialog from 'web/pages/policies/editnvtdetailsdialog'; import AuditDialog from 'web/pages/audits/dialog'; -import ImportDialog from 'web/pages/policies/importdialog'; +import ImportDialog from 'web/pages/scanconfigs/importdialog'; import PolicyDialog from 'web/pages/policies/dialog'; import ScheduleComponent from 'web/pages/schedules/component'; @@ -743,6 +743,8 @@ class PolicyComponent extends React.Component { {importDialogVisible && ( diff --git a/gsa/src/web/pages/policies/importdialog.js b/gsa/src/web/pages/policies/importdialog.js deleted file mode 100644 index 37a32e503d..0000000000 --- a/gsa/src/web/pages/policies/importdialog.js +++ /dev/null @@ -1,61 +0,0 @@ -/* 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 SaveDialog from 'web/components/dialog/savedialog'; - -import FileField from 'web/components/form/filefield'; -import FormGroup from 'web/components/form/formgroup'; - -import Layout from 'web/components/layout/layout'; - -const ImportDialog = ({onClose, onSave}) => { - return ( - - {({onValueChange}) => { - return ( - - - - - - ); - }} - - ); -}; - -ImportDialog.propTypes = { - onClose: PropTypes.func.isRequired, - onSave: PropTypes.func.isRequired, -}; - -export default ImportDialog; - -// vim: set ts=2 sw=2 tw=80: diff --git a/gsa/src/web/pages/scanconfigs/component.js b/gsa/src/web/pages/scanconfigs/component.js index 2fc8f780b3..6208d2309f 100644 --- a/gsa/src/web/pages/scanconfigs/component.js +++ b/gsa/src/web/pages/scanconfigs/component.js @@ -491,6 +491,8 @@ class ScanConfigComponent extends React.Component { {importDialogVisible && ( diff --git a/gsa/src/web/pages/scanconfigs/importdialog.js b/gsa/src/web/pages/scanconfigs/importdialog.js index 122246a986..7398d2deb4 100644 --- a/gsa/src/web/pages/scanconfigs/importdialog.js +++ b/gsa/src/web/pages/scanconfigs/importdialog.js @@ -29,11 +29,11 @@ import FormGroup from 'web/components/form/formgroup'; import Layout from 'web/components/layout/layout'; -const ImportDialog = ({onClose, onSave}) => { +const ImportDialog = ({title, text, onClose, onSave}) => { return ( { {({onValueChange}) => { return ( - + @@ -52,6 +52,8 @@ const ImportDialog = ({onClose, onSave}) => { }; ImportDialog.propTypes = { + text: PropTypes.string, + title: PropTypes.string, onClose: PropTypes.func.isRequired, onSave: PropTypes.func.isRequired, }; From 4787a67a771507f76f2bd3746e389cd3393ab3c2 Mon Sep 17 00:00:00 2001 From: Sarah Diedrich Date: Wed, 31 Jul 2019 15:05:29 +0200 Subject: [PATCH 66/66] remove unused variables from policy dialog --- gsa/src/web/pages/policies/dialog.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/gsa/src/web/pages/policies/dialog.js b/gsa/src/web/pages/policies/dialog.js index 0fe153ec34..1d8b5462a7 100644 --- a/gsa/src/web/pages/policies/dialog.js +++ b/gsa/src/web/pages/policies/dialog.js @@ -40,7 +40,6 @@ const Dialog = ({ comment = '', name = _('Unnamed'), scanner_id, - scanners = [], title = _('New Policy'), onClose, onSave, @@ -50,7 +49,6 @@ const Dialog = ({ comment, name, scanner_id, - usage_type: 'policy', }; return ( @@ -98,7 +96,6 @@ Dialog.propTypes = { comment: PropTypes.string, name: PropTypes.string, scanner_id: PropTypes.id, - scanners: PropTypes.array, title: PropTypes.string, onClose: PropTypes.func.isRequired, onSave: PropTypes.func.isRequired,