Skip to content

Commit

Permalink
Merge pull request #3496 from NCI-Agency/GH-3480-add-a-back-to-draft-…
Browse files Browse the repository at this point in the history
…capability-for-published-reports

Add a back to draft capability for published reports
  • Loading branch information
gjvoosten authored Apr 14, 2021
2 parents 740ba87 + d94cb3c commit af364cd
Show file tree
Hide file tree
Showing 26 changed files with 396 additions and 156 deletions.
1 change: 1 addition & 0 deletions anet-dictionary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ fields:
height: 200px

report:
canUnpublishReports: true
intent: Engagement purpose
atmosphere: Atmospherics
atmosphereDetails: Atmospherics details
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,26 @@ import React from "react"
import { Button } from "react-bootstrap"
import Confirm from "react-confirm-bootstrap"

const ConfirmDelete = ({
onConfirmDelete,
const ConfirmDestructive = ({
onConfirm,
operation,
objectType,
objectDisplay,
bsStyle,
buttonLabel,
children,
...otherProps
}) => {
const confirmDeleteText = `Yes, I am sure that I want to delete ${objectType} ${objectDisplay}`
const title = `Confirm to delete ${objectType}`
const body = `Are you sure you want to delete this ${objectType}? This cannot be undone.`
const confirmText = `Yes, I am sure that I want to ${operation} ${objectType} ${objectDisplay}`
const title = `Confirm to ${operation} ${objectType}`
const body = `Are you sure you want to ${operation} this ${objectType}? This cannot be undone.`

return (
<Confirm
onConfirm={onConfirmDelete}
onConfirm={onConfirm}
title={title}
body={body}
confirmText={confirmDeleteText}
confirmText={confirmText}
cancelText="No, I am not entirely sure at this point"
dialogClassName="react-confirm-bootstrap-modal"
confirmBSStyle="primary"
Expand All @@ -34,13 +35,17 @@ const ConfirmDelete = ({
</Confirm>
)
}
ConfirmDelete.propTypes = {
onConfirmDelete: PropTypes.func,
objectType: PropTypes.string,
objectDisplay: PropTypes.string,
ConfirmDestructive.propTypes = {
onConfirm: PropTypes.func.isRequired,
objectType: PropTypes.string.isRequired,
operation: PropTypes.string.isRequired,
objectDisplay: PropTypes.string.isRequired,
bsStyle: PropTypes.string,
buttonLabel: PropTypes.string,
children: PropTypes.node
}
ConfirmDestructive.defaultProps = {
operation: "delete"
}

export default ConfirmDelete
export default ConfirmDestructive
6 changes: 3 additions & 3 deletions client/src/components/RelatedObjectNoteModal.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import API from "api"
import ConfirmDelete from "components/ConfirmDelete"
import ConfirmDestructive from "components/ConfirmDestructive"
import * as FieldHelper from "components/FieldHelper"
import Messages from "components/Messages"
import Model, {
Expand Down Expand Up @@ -106,8 +106,8 @@ const RelatedObjectNoteModal = ({
Cancel
</Button>
{_isEmpty(relatedObjects) && onDelete && (
<ConfirmDelete
onConfirmDelete={() => onDelete(note.uuid)}
<ConfirmDestructive
onConfirm={() => onDelete(note.uuid)}
objectType="note"
objectDisplay={"#" + note.uuid}
bsStyle="warning"
Expand Down
8 changes: 4 additions & 4 deletions client/src/components/RelatedObjectNotes.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { IconNames } from "@blueprintjs/icons"
import API from "api"
import { gql } from "apollo-boost"
import AppContext from "components/AppContext"
import ConfirmDelete from "components/ConfirmDelete"
import ConfirmDestructive from "components/ConfirmDestructive"
import { parseHtmlWithLinkTo } from "components/editor/LinkAnet"
import LinkTo from "components/LinkTo"
import Messages from "components/Messages"
Expand Down Expand Up @@ -216,16 +216,16 @@ const RelatedObjectNotes = ({
onSuccess={hideEditRelatedObjectNoteModal}
onDelete={hideDeleteRelatedObjectNoteModal}
/>
<ConfirmDelete
onConfirmDelete={() => deleteNote(note.uuid)}
<ConfirmDestructive
onConfirm={() => deleteNote(note.uuid)}
objectType="note"
objectDisplay={"#" + note.uuid}
title="Delete note"
bsSize="xsmall"
bsStyle="primary"
>
<img src={REMOVE_ICON} height={14} alt="Delete" />
</ConfirmDelete>
</ConfirmDestructive>
</>
)}
</Panel.Heading>
Expand Down
1 change: 1 addition & 0 deletions client/src/components/ReportWorkflow.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const ACTION_TYPE_DETAILS = {
REJECT: { text: "Changes requested", cssClass: "btn-danger rejected" },
SUBMIT: { text: "Submitted", cssClass: "btn-pending submitted" },
PUBLISH: { text: "Published", cssClass: "btn-success published" },
UNPUBLISH: { text: "Unpublished", cssClass: "btn-danger unpublished" },
null: { text: "Pending", cssClass: "btn-pending default" }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { IconNames } from "@blueprintjs/icons"
import API from "api"
import { gql } from "apollo-boost"
import AssessmentModal from "components/assessments/AssessmentModal"
import ConfirmDelete from "components/ConfirmDelete"
import ConfirmDestructive from "components/ConfirmDestructive"
import { ReadonlyCustomFields } from "components/CustomFields"
import LinkTo from "components/LinkTo"
import Model, { NOTE_TYPE } from "components/Model"
Expand Down Expand Up @@ -79,16 +79,16 @@ const PeriodicAssessment = ({
>
<Icon icon={IconNames.EDIT} />
</Button>
<ConfirmDelete
onConfirmDelete={() => deleteNote(note.uuid)}
<ConfirmDestructive
onConfirm={() => deleteNote(note.uuid)}
objectType="note"
objectDisplay={"#" + note.uuid}
title="Delete assessment"
bsSize="xsmall"
bsStyle="primary"
>
<img src={REMOVE_ICON} height={14} alt="Delete" />
</ConfirmDelete>
</ConfirmDestructive>
<AssessmentModal
showModal={showAssessmentModalKey === note.uuid}
note={note}
Expand Down
6 changes: 3 additions & 3 deletions client/src/pages/Home.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
import API from "api"
import { gql } from "apollo-boost"
import AppContext from "components/AppContext"
import ConfirmDelete from "components/ConfirmDelete"
import ConfirmDestructive from "components/ConfirmDestructive"
import Fieldset from "components/Fieldset"
import GuidedTour from "components/GuidedTour"
import Messages from "components/Messages"
Expand Down Expand Up @@ -347,8 +347,8 @@ const SavedSearches = ({ setSearchQuery, pageDispatchers }) => {
<Button style={{ marginRight: 12 }} onClick={showSearch}>
Show Search
</Button>
<ConfirmDelete
onConfirmDelete={onConfirmDelete}
<ConfirmDestructive
onConfirm={onConfirmDelete}
objectType="search"
objectDisplay={selectedSearch.name}
bsStyle="danger"
Expand Down
6 changes: 3 additions & 3 deletions client/src/pages/positions/Show.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import API from "api"
import { gql } from "apollo-boost"
import AppContext from "components/AppContext"
import AssignPersonModal from "components/AssignPersonModal"
import ConfirmDelete from "components/ConfirmDelete"
import ConfirmDestructive from "components/ConfirmDestructive"
import { ReadonlyCustomFields } from "components/CustomFields"
import EditAssociatedPositionsModal from "components/EditAssociatedPositionsModal"
import * as FieldHelper from "components/FieldHelper"
Expand Down Expand Up @@ -302,8 +302,8 @@ const PositionShow = ({ pageDispatchers }) => {
{canDelete && (
<div className="submit-buttons">
<div>
<ConfirmDelete
onConfirmDelete={onConfirmDelete}
<ConfirmDestructive
onConfirm={onConfirmDelete}
objectType="position"
objectDisplay={"#" + position.uuid}
bsStyle="warning"
Expand Down
6 changes: 3 additions & 3 deletions client/src/pages/reports/Form.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
import AdvancedSingleSelect from "components/advancedSelectWidget/AdvancedSingleSelect"
import AppContext from "components/AppContext"
import InstantAssessmentsContainerField from "components/assessments/InstantAssessmentsContainerField"
import ConfirmDelete from "components/ConfirmDelete"
import ConfirmDestructive from "components/ConfirmDestructive"
import CustomDateInput from "components/CustomDateInput"
import {
CustomFieldsContainer,
Expand Down Expand Up @@ -1081,8 +1081,8 @@ const ReportForm = ({
</div>
)}
{canDelete && (
<ConfirmDelete
onConfirmDelete={() => onConfirmDelete(values, resetForm)}
<ConfirmDestructive
onConfirm={() => onConfirmDelete(values, resetForm)}
objectType="report"
objectDisplay={values.uuid}
bsStyle="warning"
Expand Down
80 changes: 51 additions & 29 deletions client/src/pages/reports/Show.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import API from "api"
import { gql } from "apollo-boost"
import AppContext from "components/AppContext"
import InstantAssessmentsContainerField from "components/assessments/InstantAssessmentsContainerField"
import ConfirmDelete from "components/ConfirmDelete"
import ConfirmDestructive from "components/ConfirmDestructive"
import { ReadonlyCustomFields } from "components/CustomFields"
import { parseHtmlWithLinkTo } from "components/editor/LinkAnet"
import * as FieldHelper from "components/FieldHelper"
Expand Down Expand Up @@ -229,23 +229,24 @@ const GQL_DELETE_REPORT = gql`
deleteReport(uuid: $uuid)
}
`
const GQL_UNPUBLISH_REPORT = gql`
mutation($uuid: String!) {
unpublishReport(uuid: $uuid)
}
`
const GQL_EMAIL_REPORT = gql`
mutation($uuid: String!, $email: AnetEmailInput!) {
emailReport(uuid: $uuid, email: $email)
}
`
const GQL_SUBMIT_REPORT = gql`
mutation($uuid: String!) {
submitReport(uuid: $uuid) {
uuid
}
submitReport(uuid: $uuid)
}
`
const GQL_PUBLISH_REPORT = gql`
mutation($uuid: String!) {
publishReport(uuid: $uuid) {
uuid
}
publishReport(uuid: $uuid)
}
`
const GQL_ADD_REPORT_COMMENT = gql`
Expand All @@ -257,16 +258,12 @@ const GQL_ADD_REPORT_COMMENT = gql`
`
const GQL_REJECT_REPORT = gql`
mutation($uuid: String!, $comment: CommentInput!) {
rejectReport(uuid: $uuid, comment: $comment) {
uuid
}
rejectReport(uuid: $uuid, comment: $comment)
}
`
const GQL_APPROVE_REPORT = gql`
mutation($uuid: String!, $comment: CommentInput!) {
approveReport(uuid: $uuid, comment: $comment) {
uuid
}
approveReport(uuid: $uuid, comment: $comment)
}
`

Expand Down Expand Up @@ -335,8 +332,8 @@ const ReportShow = ({ setSearchQuery, pageDispatchers }) => {
Position.isEqual(member, currentUser.position)
)
const canRequestChanges = canApprove || (report.isApproved() && isAdmin)
// Approved reports for not future engagements may be published by an admin user
const canPublish = !report.isFuture() && report.isApproved() && isAdmin
// Approved reports may be published by an admin user
const canPublish = report.isApproved() && isAdmin
// Warn admins when they try to approve their own report
const warnApproveOwnReport = canApprove && isAuthor

Expand Down Expand Up @@ -478,18 +475,16 @@ const ReportShow = ({ setSearchQuery, pageDispatchers }) => {
{report.isApproved() && (
<Fieldset style={{ textAlign: "center" }}>
<h4 className="text-danger">This {reportType} is APPROVED.</h4>
{!report.isFuture() && (
<p>
This report has been approved and will be automatically
published to the ANET community in{" "}
{moment(report.getReportApprovedAt())
.add(
Settings.reportWorkflow.nbOfHoursQuarantineApproved,
"hours"
)
.toNow(true)}
</p>
)}
<p>
This report has been approved and will be automatically
published to the ANET community in{" "}
{moment(report.getReportApprovedAt())
.add(
Settings.reportWorkflow.nbOfHoursQuarantineApproved,
"hours"
)
.toNow(true)}
</p>
{canPublish && (
<p>
You can also {renderPublishButton(!isValid)} it immediately.
Expand Down Expand Up @@ -793,9 +788,23 @@ const ReportShow = ({ setSearchQuery, pageDispatchers }) => {

{currentUser.isAdmin() && (
<div className="submit-buttons">
{report.isPublished() &&
Settings.fields.report.canUnpublishReports && (
<div>
<ConfirmDestructive
onConfirm={onConfirmUnpublish}
objectType="report"
operation="unpublish"
objectDisplay={"#" + uuid}
bsStyle="warning"
buttonLabel={`Unpublish ${reportType}`}
className="pull-left"
/>
</div>
)}
<div>
<ConfirmDelete
onConfirmDelete={onConfirmDelete}
<ConfirmDestructive
onConfirm={onConfirmDelete}
objectType="report"
objectDisplay={"#" + uuid}
bsStyle="warning"
Expand Down Expand Up @@ -844,6 +853,19 @@ const ReportShow = ({ setSearchQuery, pageDispatchers }) => {
)
}
}
function onConfirmUnpublish() {
API.mutation(GQL_UNPUBLISH_REPORT, { uuid })
.then(data => {
history.push("/", {
success: `${reportTypeUpperFirst} unpublished`
})
})
.catch(error => {
setSaveSuccess(null)
setSaveError(error)
jumpToTop()
})
}

function onConfirmDelete() {
API.mutation(GQL_DELETE_REPORT, { uuid })
Expand Down
4 changes: 3 additions & 1 deletion client/tests/webdriver/baseSpecs/printReport.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import ShowReport from "../pages/showReport.page"
describe("Show print report page", () => {
beforeEach("Open the show report page", () => {
MyReports.open()
ShowReport.openAsAdminUser(MyReports.reportWithAssessmentsUrl)
ShowReport.openAsAdminUser(
MyReports.getReportUrl("A test report from Arthur")
)
ShowReport.compactViewButton.click()
ShowReport.compactView.waitForExist()
ShowReport.compactView.waitForDisplayed()
Expand Down
4 changes: 3 additions & 1 deletion client/tests/webdriver/baseSpecs/showReport.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import ShowReport from "../pages/showReport.page"
describe("Show report page", () => {
beforeEach("Open the show report page", () => {
MyReports.open()
ShowReport.openAsAdminUser(MyReports.reportWithAssessmentsUrl)
ShowReport.openAsAdminUser(
MyReports.getReportUrl("A test report from Arthur")
)
})
describe("When on the show page of a report with assessments", () => {
it("We should see a table of tasks instant assessments related to the current report", () => {
Expand Down
18 changes: 18 additions & 0 deletions client/tests/webdriver/baseSpecs/unpublishReport.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { expect } from "chai"
import MyReports from "../pages/myReports.page"
import EditReport from "../pages/report/editReport.page"
import ShowReport from "../pages/report/showReport.page"

describe("When unpublishing a report", () => {
beforeEach("Open the show report page", () => {
MyReports.open()
MyReports.openAsAdminUser(
MyReports.getReportUrl("A test report to be unpublished from Arthur")
)
})
it("Should unpublish the report successfully", () => {
const unpublishedReportUuid = ShowReport.uuid
EditReport.unpublishReport(unpublishedReportUuid)
expect(EditReport.alertSuccess.getText()).to.equal("Report unpublished")
})
})
Loading

0 comments on commit af364cd

Please sign in to comment.