Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Managers can add notes and set status of reports #139

Merged
merged 7 commits into from
Feb 4, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions docs/logical_data_model.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Logical Data Model
==================

<img src="http://www.plantuml.com/plantuml/png/nLVRRjms47tNL_2jhG4RHOkYG604ITnDuOTk3TlvW5bfh6LBSjZXoEd2zhzNNAQgg9LTPjNBIsATkHyUNlPD463fhAb23GRLrsVVVrTLNoYu9zqepxGnQ8Fwg6MhmBK66rKpVGpg3b6gyAjs7XYiCjgXx3mgOjbILTK6Gb0V0h9wg9GwKNssLqexmRQ7pizRTCWWsBn-tPkt0KFqlOnEGLYxjaSTM1n_-oqvN7TsWpo6JnHQq6OCYHQ3hnIwpiRiPF4QMqtkSjJ4bzz-yvMwNhrVNQ_M5wiRvRkDqVLPSWndkjcdhXbZbs-b3nHjCGXOlxTqlfcnFFqvUifJClp9PD0XnKrD7e_9e5I3eMRjHPCRq4NZN25R7KBnI5r0Bc0xBlh0DH-vHY7oL12sv_EVMDdVkXvRCHE74ZR8nmzDRhn27UlnfqNPKgP-JcNUKRFBuU391NmElw061tpXe6JcvFUIP6_9wxeyPYYJuegKnMHA5Zjc7TPQOlhBvkzYzbqi5yYF1AQC0wM2W7HXZCI4Tpnnq-4zaxsnm1AsY78hS6KW2cf3P13SeexJihtKTjlR2aYFAVulqXcSOA5UbrTwjixqUZhwL6lJG2Mi9yyKE15KGbX-0C79eEYQ0tGvCL421Hlvc05pQahZKjGH6bx4nPfSwlgO2tnPwRUrw7ijkslqn59IdZ5Gn_N-3PRTGT0qEbvSODOacAag2VtdkojWqRNsaUbiBpHez3toxgU3cwtfXkkmmLfRC9aQut23R3C8XidwWXgTtEuypjoPq_VXuPxmJ2s3ZV4H1sROdITh94I0MvGhyftPTphdmmY1t8p1vunCpEbOd3K8f7aEB3KvmTyb6m1Ql974pY-1tD6FBWD1FYH1lTlzoo-sJs7BfJqINTdsWcnF53ISRwBK-6STEod43ST0GTnwS5vELDR-1Ha36s8Gul-AhyyLP0pfsuz_giV7KtfGIJC9UQBJqyU7qQ-GAlquEiHJr9o1pE2_VtDKwT7vzBY7uh5V9Ve7j-52g-8_1sXAUNQcul-ZbFDGAZfaco2fS9nyAF5fb1pBUOv9db_gHDsBBXdXcTkqLEQJxS3KVBJFc_-IzVC-Rz0rdJL_0000">
<img src="http://www.plantuml.com/plantuml/png/nLVRRkCs47tNL_2jRO04HOkYm29Ox6xgBV9GDqYo7p2M9Z9RaiCEHzaQIVwzeeaGeksaNAkNbyGwSpyy5AbtGO1biAO9BHXKtvxz-4FJVANWddIdFDFAe0tgivQr0jSRx5JBz3ceEqHfmk_QUM2mocY7il6eY6LDJTCQ245z2iZgeL7gH8tPtYZj1FiHEZ_lqI63OFVsxMXU1mpHzp8w1M7j-X5rO77wxDVaS3dO5V8KFb5eGPif95eClb7e1XkpayLhx3MvoqaJNt__tJVgUl5nSRrONYnkb1zMHhTdoJ6SwMwRkcMCNRwNCL2qnI1W_TOo-Ew0vUbvz9IdPlYJdK5pYfkMF1wJGQaEGylQYoQNqLdZN25R7KBrI4D0hc0xBdhccezSen1vgWZRylbFhEmVmuWjc8b33HlauuCcDrsXWVNqqQAigL0_fp8VgDkKSF3a0hw4Nr276PyvA9b3ydjDihVaTLiVaykak2fbCPcQnOvPyrfBJ7_P_LtCjelv0lcPmDHne5GGa25CaPZmZdVSTFZ8P6yii8GrejmAN1c8WbeH6GGtg-EqRA-rtO-s2j9ZYl-BT0OdMAdN-PLUhBDtF1txLklJG3Mi9yyKk2UeYB3y188xWwBhzj3vn4G9L6paOmOigQcDYr77Q7WU5qjogUjZ3l1vfT-tek-rRAxH4qjDUSP00xVRErXn1a7NwNXmWLcIOA6g9FHVxww0HRVQHwQBlT2XqVV8cr_sJhPkoCTXXwssO0ernk6oR0i8ycHZGOrERZSU3voPk_V3_JtXcNe66-CZ3iomEK_MI8W0zoXNv0UpxVIG3oC4SWSClc1arvnUYmSD0ccUFKjBJl1FAGQ07cyaiVDR83T25jm8ShbIHr_630Jvb8JsOVClt-IUmsPBVYB6kcq7nLwfQBZSNAdnBteTfH2NNmyLSSliF9keilqBCWPMn234_nLVNoh863As7t-gnyTJUb19CmbvejFJnuV9rqcJFfhsyHHro40c-s_l8aswZ3uzRg5u73I9_koM3xec_jb3KygpCnN_JrCUX5BHd2qZHU5nybpYUPG2AtcEILvUwaJTgou5uONRRgd2fzY1gVbeFspEiiQNVTwXwmPh_W80">

UML Source
----------
Expand Down Expand Up @@ -150,6 +150,7 @@ class ActivityReport {
ttaType : array<string>
context : string
pageState : json
managerNotes : string
* userId : integer(32) REFERENCES public.Users.id
* lastUpdatedById : integer(32) REFERENCES public.Users.id
* regionId : integer(32) REFERENCES public.Region.id
Expand Down Expand Up @@ -199,7 +200,7 @@ NonGrantee ||-{ ActivityParticipant
Instructions
------------

1. [Edit this diagram with plantuml.com](http://www.plantuml.com/plantuml/umla/nLVRRjms47tNL_2jhG4RHOkYG604ITnDuOTk3TlvW5bfh6LBSjZXoEd2zhzNNAQgg9LTPjNBIsATkHyUNlPD463fhAb23GRLrsVVVrTLNoYu9zqepxGnQ8Fwg6MhmBK66rKpVGpg3b6gyAjs7XYiCjgXx3mgOjbILTK6Gb0V0h9wg9GwKNssLqexmRQ7pizRTCWWsBn-tPkt0KFqlOnEGLYxjaSTM1n_-oqvN7TsWpo6JnHQq6OCYHQ3hnIwpiRiPF4QMqtkSjJ4bzz-yvMwNhrVNQ_M5wiRvRkDqVLPSWndkjcdhXbZbs-b3nHjCGXOlxTqlfcnFFqvUifJClp9PD0XnKrD7e_9e5I3eMRjHPCRq4NZN25R7KBnI5r0Bc0xBlh0DH-vHY7oL12sv_EVMDdVkXvRCHE74ZR8nmzDRhn27UlnfqNPKgP-JcNUKRFBuU391NmElw061tpXe6JcvFUIP6_9wxeyPYYJuegKnMHA5Zjc7TPQOlhBvkzYzbqi5yYF1AQC0wM2W7HXZCI4Tpnnq-4zaxsnm1AsY78hS6KW2cf3P13SeexJihtKTjlR2aYFAVulqXcSOA5UbrTwjixqUZhwL6lJG2Mi9yyKE15KGbX-0C79eEYQ0tGvCL421Hlvc05pQahZKjGH6bx4nPfSwlgO2tnPwRUrw7ijkslqn59IdZ5Gn_N-3PRTGT0qEbvSODOacAag2VtdkojWqRNsaUbiBpHez3toxgU3cwtfXkkmmLfRC9aQut23R3C8XidwWXgTtEuypjoPq_VXuPxmJ2s3ZV4H1sROdITh94I0MvGhyftPTphdmmY1t8p1vunCpEbOd3K8f7aEB3KvmTyb6m1Ql974pY-1tD6FBWD1FYH1lTlzoo-sJs7BfJqINTdsWcnF53ISRwBK-6STEod43ST0GTnwS5vELDR-1Ha36s8Gul-AhyyLP0pfsuz_giV7KtfGIJC9UQBJqyU7qQ-GAlquEiHJr9o1pE2_VtDKwT7vzBY7uh5V9Ve7j-52g-8_1sXAUNQcul-ZbFDGAZfaco2fS9nyAF5fb1pBUOv9db_gHDsBBXdXcTkqLEQJxS3KVBJFc_-IzVC-Rz0rdJL_0000)
1. [Edit this diagram with plantuml.com](http://www.plantuml.com/plantuml/png/nLVRRkCs47tNL_2jRO04HOkYm29Ox6xgBV9GDqYo7p2M9Z9RaiCEHzaQIVwzeeaGeksaNAkNbyGwSpyy5AbtGO1biAO9BHXKtvxz-4FJVANWddIdFDFAe0tgivQr0jSRx5JBz3ceEqHfmk_QUM2mocY7il6eY6LDJTCQ245z2iZgeL7gH8tPtYZj1FiHEZ_lqI63OFVsxMXU1mpHzp8w1M7j-X5rO77wxDVaS3dO5V8KFb5eGPif95eClb7e1XkpayLhx3MvoqaJNt__tJVgUl5nSRrONYnkb1zMHhTdoJ6SwMwRkcMCNRwNCL2qnI1W_TOo-Ew0vUbvz9IdPlYJdK5pYfkMF1wJGQaEGylQYoQNqLdZN25R7KBrI4D0hc0xBdhccezSen1vgWZRylbFhEmVmuWjc8b33HlauuCcDrsXWVNqqQAigL0_fp8VgDkKSF3a0hw4Nr276PyvA9b3ydjDihVaTLiVaykak2fbCPcQnOvPyrfBJ7_P_LtCjelv0lcPmDHne5GGa25CaPZmZdVSTFZ8P6yii8GrejmAN1c8WbeH6GGtg-EqRA-rtO-s2j9ZYl-BT0OdMAdN-PLUhBDtF1txLklJG3Mi9yyKk2UeYB3y188xWwBhzj3vn4G9L6paOmOigQcDYr77Q7WU5qjogUjZ3l1vfT-tek-rRAxH4qjDUSP00xVRErXn1a7NwNXmWLcIOA6g9FHVxww0HRVQHwQBlT2XqVV8cr_sJhPkoCTXXwssO0ernk6oR0i8ycHZGOrERZSU3voPk_V3_JtXcNe66-CZ3iomEK_MI8W0zoXNv0UpxVIG3oC4SWSClc1arvnUYmSD0ccUFKjBJl1FAGQ07cyaiVDR83T25jm8ShbIHr_630Jvb8JsOVClt-IUmsPBVYB6kcq7nLwfQBZSNAdnBteTfH2NNmyLSSliF9keilqBCWPMn234_nLVNoh863As7t-gnyTJUb19CmbvejFJnuV9rqcJFfhsyHHro40c-s_l8aswZ3uzRg5u73I9_koM3xec_jb3KygpCnN_JrCUX5BHd2qZHU5nybpYUPG2AtcEILvUwaJTgou5uONRRgd2fzY1gVbeFspEiiQNVTwXwmPh_W80)
2. Copy and paste the final UML into the UML Source section
3. Update the img src and edit link target to the current values

Expand Down
46 changes: 46 additions & 0 deletions docs/openapi/paths/activity-reports/review.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
put:
tags:
- activity-reports
summary: Review an activity report
description: >
An approving manager reviews an activity report to determine if it requires
any additional updates. If the report needs updates the manager sets the status to
'Needs Action', otherwise to 'Approved'
requestBody:
description: The status and any manager notes
required: true
content:
application/json:
schema:
type: object
properties:
status:
type: string
jasalisbury marked this conversation as resolved.
Show resolved Hide resolved
description: The status of the report after review
enum:
- Approved
- Needs Action
managerNotes:
type: string
description: Any notes the manager needs to relay to the author/collaborators of the report
parameters:
- in: path
name: activityReportId
required: true
schema:
type: number
responses:
200:
description: The new status of the activity report
content:
application/json:
schema:
type: object
properties:
status:
type: string
enum:
- Approved
- Needs Action
managerNotes:
type: string
2 changes: 1 addition & 1 deletion docs/openapi/paths/collaborators.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ get:
schema:
type: array
items:
$ref: '../../index.yaml#/components/schemas/selectableUser'
$ref: '../index.yaml#/components/schemas/selectableUser'
2 changes: 2 additions & 0 deletions docs/openapi/paths/index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,7 @@
$ref: './activity-reports/activity-reports-id.yaml'
'/activity-reports/{activityReportId}/submit':
$ref: './activity-reports/submit.yaml'
'/activity-reports/{activityReportId}/review':
$ref: './activity-reports/review.yaml'
'/files':
$ref: './files.yaml'
2 changes: 1 addition & 1 deletion frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ function App() {
<Route
path="/activity-reports/:activityReportId/:currentPage?"
render={({ match }) => (
<ActivityReport match={match} />
<ActivityReport match={match} user={user} />
)}
/>
{admin
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,5 @@ export const REGIONS = [
11,
12,
];

export const DECIMAL_BASE = 10;
5 changes: 4 additions & 1 deletion frontend/src/components/Navigator/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const pages = [
label: 'review page',
path: 'review',
review: true,
render: (hookForm, allComplete, formData, submitted, onSubmit) => (
render: (hookForm, allComplete, formData, onSubmit) => (
<div>
<button type="button" data-testid="review" onClick={onSubmit}>Continue</button>
</div>
Expand All @@ -59,6 +59,9 @@ describe('Navigator', () => {
<Navigator
submitted={false}
initialData={initialData}
status="draft"
onReview={() => {}}
approvingManager={false}
defaultValues={{ first: '', second: '' }}
pages={pages}
currentPage={currentPage}
Expand Down
7 changes: 6 additions & 1 deletion frontend/src/components/Navigator/components/SideNav.css
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,13 @@
color: #f8f8f8;
}

.smart-hub--tag-needs-action {
background-color: #f9e0e4;
color: #d42240;
}

.smart-hub--tag {
width: 84px;
width: 94px;
text-align: center;
font-weight: normal;
display: inline-block;
Expand Down
8 changes: 6 additions & 2 deletions frontend/src/components/Navigator/components/SideNav.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import moment from 'moment';
import Container from '../../Container';
import './SideNav.css';
import {
NOT_STARTED, IN_PROGRESS, COMPLETE, SUBMITTED,
NOT_STARTED, IN_PROGRESS, COMPLETE, SUBMITTED, APPROVED, NEEDS_ACTION,
} from '../constants';

const tagClass = (state) => {
Expand All @@ -26,6 +26,10 @@ const tagClass = (state) => {
return 'smart-hub--tag-complete';
case SUBMITTED:
return 'smart-hub--tag-submitted';
case APPROVED:
return 'smart-hub--tag-submitted';
case NEEDS_ACTION:
return 'smart-hub--tag-needs-action';
default:
return '';
}
Expand All @@ -46,7 +50,7 @@ function SideNav({
>
<span className="margin-left-2">{page.label}</span>
<span className="margin-left-auto margin-right-2">
{page.state
{page.state !== 'draft'
&& (
<Tag className={`smart-hub--tag ${tagClass(page.state)}`}>
{page.state}
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/components/Navigator/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ export const NOT_STARTED = 'Not started';
export const IN_PROGRESS = 'In progress';
export const COMPLETE = 'Complete';
export const SUBMITTED = 'Submitted';
export const APPROVED = 'Approved';
export const NEEDS_ACTION = 'Needs Action';
16 changes: 10 additions & 6 deletions frontend/src/components/Navigator/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import moment from 'moment';
import Container from '../Container';

import {
IN_PROGRESS, COMPLETE, SUBMITTED,
IN_PROGRESS, COMPLETE,
} from './constants';
import SideNav from './components/SideNav';
import NavigatorHeader from './components/NavigatorHeader';
Expand All @@ -24,19 +24,20 @@ function Navigator({
initialData,
pages,
onFormSubmit,
submitted,
onReview,
currentPage,
additionalData,
onSave,
autoSaveInterval,
approvingManager,
status,
}) {
const [formData, updateFormData] = useState(initialData);
const [errorMessage, updateErrorMessage] = useState();
const [lastSaveTime, updateLastSaveTime] = useState();
const { pageState } = formData;

const page = pages.find((p) => p.path === currentPage);
const submittedNavState = submitted ? SUBMITTED : null;
const allComplete = _.every(pageState, (state) => state === COMPLETE);

const hookForm = useForm({
Expand Down Expand Up @@ -101,7 +102,7 @@ function Navigator({
const navigatorPages = pages.map((p) => {
const current = p.position === page.position;
const stateOfPage = current ? IN_PROGRESS : pageState[p.position];
const state = p.review ? submittedNavState : stateOfPage;
const state = p.review ? status : stateOfPage;
return {
label: p.label,
onNavigation: () => onSaveForm(false, p.position),
Expand All @@ -128,9 +129,10 @@ function Navigator({
hookForm,
allComplete,
formData,
submitted,
onFormSubmit,
additionalData,
onReview,
approvingManager,
)}
{!page.review
&& (
Expand All @@ -156,8 +158,10 @@ function Navigator({
Navigator.propTypes = {
initialData: PropTypes.shape({}),
onFormSubmit: PropTypes.func.isRequired,
submitted: PropTypes.bool.isRequired,
onSave: PropTypes.func.isRequired,
status: PropTypes.string.isRequired,
onReview: PropTypes.func.isRequired,
approvingManager: PropTypes.bool.isRequired,
pages: PropTypes.arrayOf(
PropTypes.shape({
review: PropTypes.bool.isRequired,
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/fetchers/Admin.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import join from 'url-join';
import { get, put } from './index';
import { DECIMAL_BASE } from '../Constants';

export const getUsers = async () => {
const users = await get((join('/', 'api', 'admin', 'users')));
return users.json();
};

export const updateUser = async (userId, data) => {
const user = await put((join('/', 'api', 'admin', 'users', userId.toString(10))), data);
const user = await put((join('/', 'api', 'admin', 'users', userId.toString(DECIMAL_BASE))), data);
return user.json();
};
13 changes: 10 additions & 3 deletions frontend/src/fetchers/activityReports.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import join from 'url-join';
import { get, put, post } from './index';
import { DECIMAL_BASE } from '../Constants';

const activityReportUrl = join('/', 'api', 'activity-reports');

Expand All @@ -9,13 +10,13 @@ export const getApprovers = async (region) => {
};

export const submitReport = async (reportId, data) => {
const url = join(activityReportUrl, reportId.toString(10), 'submit');
const url = join(activityReportUrl, reportId.toString(DECIMAL_BASE), 'submit');
const report = await post(url, data);
return report.json();
};

export const saveReport = async (reportId, data) => {
const report = await put(join(activityReportUrl, reportId.toString(10)), data);
const report = await put(join(activityReportUrl, reportId.toString(DECIMAL_BASE)), data);
return report.json();
};

Expand All @@ -25,7 +26,7 @@ export const createReport = async (data) => {
};

export const getReport = async (reportId) => {
const report = await get(join(activityReportUrl, reportId.toString(10)));
const report = await get(join(activityReportUrl, reportId.toString(DECIMAL_BASE)));
return report.json();
};

Expand All @@ -39,3 +40,9 @@ export const getCollaborators = async (region) => {
const collaborators = await get(url);
return collaborators.json();
};

export const reviewReport = async (reportId, data) => {
const url = join(activityReportUrl, reportId.toString(DECIMAL_BASE), 'review');
const report = await put(url, data);
return report.json();
};
64 changes: 64 additions & 0 deletions frontend/src/pages/ActivityReport/Pages/ApproverReviewPage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
Dropdown, Form, Label, Fieldset, Textarea, Alert, Button,
} from '@trussworks/react-uswds';

const possibleStatus = [
'Approved',
'Needs Action',
];

const ApproverReviewPage = ({
reviewed,
additionalNotes,
register,
valid,
handleSubmit,
onFormReview,
}) => (
<>
{reviewed
&& (
<Alert noIcon className="margin-y-4" type="success">
<b>Success</b>
<br />
Your review of this report was successfully submitted
</Alert>
)}
<h2>Review and approve report</h2>
<div className="smart-hub--creator-notes">
<p>
<span className="text-bold">Creator notes</span>
<br />
<br />
{ additionalNotes || 'No creator notes' }
</p>
</div>
<Form className="smart-hub--form-large" onSubmit={handleSubmit(onFormReview)}>
<Fieldset className="smart-hub--report-legend smart-hub--form-section" legend="Review and submit report">
<Label htmlFor="managerNotes">Manager notes</Label>
<Textarea inputRef={register} id="managerNotes" name="managerNotes" />
</Fieldset>
<Label htmlFor="status">Choose report status</Label>
<Dropdown id="status" name="status" defaultValue="" inputRef={register({ required: true })}>
<option name="default" value="" disabled hidden>- Select -</option>
{possibleStatus.map((status) => (
<option key={status} value={status}>{status}</option>
))}
</Dropdown>
<Button type="submit" disabled={!valid}>Submit</Button>
</Form>
</>
);

ApproverReviewPage.propTypes = {
reviewed: PropTypes.bool.isRequired,
additionalNotes: PropTypes.string.isRequired,
register: PropTypes.func.isRequired,
valid: PropTypes.bool.isRequired,
handleSubmit: PropTypes.func.isRequired,
onFormReview: PropTypes.func.isRequired,
};

export default ApproverReviewPage;
8 changes: 8 additions & 0 deletions frontend/src/pages/ActivityReport/Pages/ReviewSubmit.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.smart-hub--creator-notes {
padding: 1rem;
background-color: #f8f8f8;
}

#status {
max-width: 270px;
}
Loading