Skip to content

Commit

Permalink
Resolve merge conflicts (merge HHS:main into adhoc:main) (#484)
Browse files Browse the repository at this point in the history
* Bump validator from 13.6.0 to 13.7.0

Bumps [validator](https://github.com/validatorjs/validator.js) from 13.6.0 to 13.7.0.
- [Release notes](https://github.com/validatorjs/validator.js/releases)
- [Changelog](https://github.com/validatorjs/validator.js/blob/master/CHANGELOG.md)
- [Commits](validatorjs/validator.js@13.6.0...13.7.0)

---
updated-dependencies:
- dependency-name: validator
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>

* welcoming robots in certain situations

* Update known vulnerabilities

* trying a different approach in the config

* is this how we set vars?

* fix var name

* test on dev since sandbox does not do what I thought

* need to learn how to do bash

* more bash better

* for christmas sake

* testing complete

* fix bash script var names

* move logic to circlci config

* awaken robot on prod

* Update .circleci/config.yml

Co-authored-by: Josh Salisbury <[email protected]>

* add approvedat migration

* update approvedAt on approval

* clean up constants, add new one

* add approved and created dates to fe landing page

* add approved and created date to csv download

* remove console statement

* fixing tests

* partial fixes for ui tests

* clean up prop type

* cleanup UI tests

* add backend tests

* add target populations to ar

* add approved and created date to ar, table css fixes

* fix failing ui test

* fix failing tooltip test

* update known issues

* Update known vulnerabilities

* fix capitalizations while we're here

* fix css bug w/checkboxes

* update ignored FE vulns

* writing FE tests

* working on more tests

* provide some missing UI tests

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: unknown <[email protected]>
Co-authored-by: Josh Salisbury <[email protected]>
  • Loading branch information
4 people authored Nov 15, 2021
1 parent 46480e2 commit 97a8eae
Show file tree
Hide file tree
Showing 35 changed files with 275 additions and 121 deletions.
13 changes: 11 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,10 @@ parameters:
type: string
dev_git_branch: # change to feature branch to test deployment
description: "Name of github branch that will deploy to dev"
default: "js-fix-plotly-import"
default: "TTAHUB276"
type: string
sandbox_git_branch: # change to feature branch to test deployment
default: "kw-delete-reports-script"
default: "TTAHUB276"
type: string
prod_new_relic_app_id:
default: "877570491"
Expand Down Expand Up @@ -333,6 +333,15 @@ jobs:
- run:
name: Build backend assets
command: yarn build
- when:
condition:
and:
- equal: [<< pipeline.project.git_url >>, << pipeline.parameters.prod_git_url >>]
- equal: [<< pipeline.git.branch >>, << pipeline.parameters.prod_git_branch >>]
steps:
- run:
name: Create production robot
command: ./bin/robot-factory
- run:
name: Build frontend assets
command: yarn --cwd frontend run build
Expand Down
9 changes: 9 additions & 0 deletions bin/robot-factory
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash

echo 'Setting site to be indexable in robots.txt'

cat >frontend/public/robots.txt <<EOL
# Welcome Robots
User-agent: *
Disallow:
EOL
5 changes: 4 additions & 1 deletion frontend/public/robots.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# we disallow everything by default
# in production, we allow indexing by removing the slash from the disallow

# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
Disallow: /
1 change: 1 addition & 0 deletions frontend/src/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,5 @@ export const ESCAPE_KEY_CODE = 27;
export const ESCAPE_KEY_CODES = ['Escape', 'Esc'];

export const DATE_FMT = 'YYYY/MM/DD';
export const DATE_DISPLAY_FORMAT = 'MM/DD/YYYY';
export const EARLIEST_INC_FILTER_DATE = moment('2020-08-31');
35 changes: 20 additions & 15 deletions frontend/src/components/ActivityReportsTable/ReportRow.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
Tag, Checkbox,
} from '@trussworks/react-uswds';
import { Checkbox } from '@trussworks/react-uswds';
import { Link, useHistory } from 'react-router-dom';

import moment from 'moment';
import ContextMenu from '../ContextMenu';
import { getReportsDownloadURL } from '../../fetchers/helpers';
import TooltipWithCollection from '../TooltipWithCollection';
import Tooltip from '../Tooltip';
import { DATE_DISPLAY_FORMAT } from '../../Constants';

function ReportRow({
report, openMenuUp, handleReportSelect, isChecked,
Expand All @@ -22,6 +22,8 @@ function ReportRow({
collaborators,
lastSaved,
calculatedStatus,
approvedAt,
createdAt,
legacyId,
} = report;

Expand Down Expand Up @@ -85,24 +87,21 @@ function ReportRow({
</td>
<td>{startDate}</td>
<td>
<span className="smart-hub--ellipsis" title={authorName}>
{authorName}
</span>
<Tooltip
displayText={authorName}
tooltipText={authorName}
buttonLabel="click to reveal author name"
/>
</td>
<td>{moment(createdAt).format(DATE_DISPLAY_FORMAT)}</td>
<td>
<TooltipWithCollection collection={topics} collectionTitle={`topics for ${displayId}`} />
</td>
<td>
<TooltipWithCollection collection={collaboratorNames} collectionTitle={`collaborators for ${displayId}`} />
</td>
<td>{lastSaved}</td>
<td>
<Tag
className={`smart-hub--table-tag-status smart-hub--status-${calculatedStatus}`}
>
{calculatedStatus === 'needs_action' ? 'Needs action' : calculatedStatus}
</Tag>
</td>
<td>{approvedAt && moment(approvedAt).format(DATE_DISPLAY_FORMAT)}</td>
<td>
<ContextMenu label={contextMenuLabel} menuItems={menuItems} up={openMenuUp} />
</td>
Expand All @@ -122,14 +121,20 @@ export const reportPropTypes = {
}),
}),
})).isRequired,
approvedAt: PropTypes.string,
createdAt: PropTypes.string,
startDate: PropTypes.string.isRequired,
author: PropTypes.shape({
fullName: PropTypes.string,
homeRegionId: PropTypes.number,
name: PropTypes.string,
}).isRequired,
topics: PropTypes.arrayOf(PropTypes.string).isRequired,
collaborators: PropTypes.arrayOf(PropTypes.string).isRequired,
collaborators: PropTypes.arrayOf(
PropTypes.shape({
fullName: PropTypes.string,
}),
).isRequired,
lastSaved: PropTypes.string.isRequired,
calculatedStatus: PropTypes.string.isRequired,
legacyId: PropTypes.string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,12 @@ describe('ActivityReportsTable ColumnHeader', () => {
await act(async () => userEvent.type(shoes, '{enter}'));
expect(onUpdateSort).toHaveBeenCalledTimes(2);
});

it('displays an unsortable column', async () => {
const onUpdateSort = jest.fn();
renderColumnHeader(onUpdateSort, '');

const shoes = await screen.findByRole('columnheader', { name: /fanciest shoes/i });
expect(shoes).toHaveAttribute('aria-sort', 'none');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import '@testing-library/jest-dom';
import React from 'react';
import {
render, screen,
} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Router } from 'react-router';
import { createMemoryHistory } from 'history';
import ReportRow from '../ReportRow';
import { generateXFakeReports } from '../mocks';

const history = createMemoryHistory();

const [report] = generateXFakeReports(1);

describe('ReportRow', () => {
const renderReportRow = () => (
render(
<Router history={history}>
<ReportRow
report={report}
openMenuUp={false}
handleReportSelect={jest.fn()}
isChecked={false}
/>
</Router>,
)
);

beforeAll(async () => {
global.navigator.clipboard = jest.fn();
global.navigator.clipboard.writeText = jest.fn(() => Promise.resolve());
});

afterAll(() => {
delete global.navigator;
});

it('the view link works', async () => {
history.push = jest.fn();
renderReportRow();
userEvent.click(await screen.findByRole('button', { name: 'Actions for activity report R14-AR-1' }));
userEvent.click(await screen.findByRole('button', { name: /view/i }));

expect(history.push).toHaveBeenCalled();
});

it('you can copy', async () => {
renderReportRow();
userEvent.click(await screen.findByRole('button', { name: 'Actions for activity report R14-AR-1' }));
userEvent.click(await screen.findByRole('button', { name: /copy url/i }));

expect(navigator.clipboard.writeText).toHaveBeenCalled();
});
});
41 changes: 9 additions & 32 deletions frontend/src/components/ActivityReportsTable/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -317,28 +317,6 @@ describe('Table sorting', () => {
await screen.findByText('Activity Reports');
});

it('clicking status column header will sort by status', async () => {
const statusColumnHeader = await screen.findByText(/status/i);
fetchMock.reset();
fetchMock.get(
'/api/activity-reports?sortBy=calculatedStatus&sortDir=asc&offset=0&limit=10&region.in[]=1',
{ count: 2, rows: activityReportsSorted },
);

fireEvent.click(statusColumnHeader);
await waitFor(() => expect(screen.getAllByRole('cell')[7]).toHaveTextContent(/needs action/i));
await waitFor(() => expect(screen.getAllByRole('cell')[16]).toHaveTextContent(/draft/i));

fetchMock.get(
'/api/activity-reports?sortBy=calculatedStatus&sortDir=desc&offset=0&limit=10&region.in[]=1',
{ count: 2, rows: activityReports },
);

fireEvent.click(statusColumnHeader);
await waitFor(() => expect(screen.getAllByRole('cell')[7]).toHaveTextContent(/draft/i));
await waitFor(() => expect(screen.getAllByRole('cell')[16]).toHaveTextContent(/needs action/i));
});

it('clicking Last saved column header will sort by updatedAt', async () => {
const columnHeader = await screen.findByText(/last saved/i);

Expand All @@ -348,8 +326,8 @@ describe('Table sorting', () => {
);

fireEvent.click(columnHeader);
await waitFor(() => expect(screen.getAllByRole('cell')[6]).toHaveTextContent(/02\/04\/2021/i));
await waitFor(() => expect(screen.getAllByRole('cell')[15]).toHaveTextContent(/02\/05\/2021/i));
await waitFor(() => expect(screen.getAllByRole('cell')[7]).toHaveTextContent(/02\/04\/2021/i));
await waitFor(() => expect(screen.getAllByRole('cell')[17]).toHaveTextContent(/02\/05\/2021/i));
});

it('clicking Collaborators column header will sort by collaborators', async () => {
Expand All @@ -361,8 +339,8 @@ describe('Table sorting', () => {
);

await act(async () => fireEvent.click(columnHeader));
await waitFor(() => expect(screen.getAllByRole('cell')[5]).toHaveTextContent('Cucumber User, GS Hermione Granger, SS'));
await waitFor(() => expect(screen.getAllByRole('cell')[14]).toHaveTextContent('Orange, GS Hermione Granger, SS'));
await waitFor(() => expect(screen.getAllByRole('cell')[6]).toHaveTextContent('Cucumber User, GS Hermione Granger, SS'));
await waitFor(() => expect(screen.getAllByRole('cell')[16]).toHaveTextContent('Orange, GS Hermione Granger, SS'));
});

it('clicking Topics column header will sort by topics', async () => {
Expand All @@ -374,8 +352,7 @@ describe('Table sorting', () => {
);

await act(async () => fireEvent.click(columnHeader));
await waitFor(() => expect(screen.getAllByRole('cell')[4]).toHaveTextContent(''));
await waitFor(() => expect(screen.getAllByRole('cell')[13]).toHaveTextContent(/Behavioral \/ Mental Health CLASS: Instructional Support click to visually reveal the topics for R14-AR-1$/i));
await waitFor(() => expect(screen.getAllByRole('cell')[15]).toHaveTextContent(/Behavioral \/ Mental Health CLASS: Instructional Support click to visually reveal the topics for R14-AR-1$/i));
});

it('clicking Creator column header will sort by author', async () => {
Expand All @@ -388,7 +365,7 @@ describe('Table sorting', () => {

fireEvent.click(columnHeader);
await waitFor(() => expect(screen.getAllByRole('cell')[3]).toHaveTextContent('Kiwi, GS'));
await waitFor(() => expect(screen.getAllByRole('cell')[12]).toHaveTextContent('Kiwi, TTAC'));
await waitFor(() => expect(screen.getAllByRole('cell')[13]).toHaveTextContent('Kiwi, TTAC'));
});

it('clicking Start date column header will sort by start date', async () => {
Expand All @@ -401,7 +378,7 @@ describe('Table sorting', () => {

fireEvent.click(columnHeader);
await waitFor(() => expect(screen.getAllByRole('cell')[2]).toHaveTextContent('02/01/2021'));
await waitFor(() => expect(screen.getAllByRole('cell')[11]).toHaveTextContent('02/08/2021'));
await waitFor(() => expect(screen.getAllByRole('cell')[12]).toHaveTextContent('02/08/2021'));
});

it('clicking Grantee column header will sort by grantee', async () => {
Expand Down Expand Up @@ -462,8 +439,8 @@ describe('Table sorting', () => {
);

fireEvent.click(pageOne);
await waitFor(() => expect(screen.getAllByRole('cell')[6]).toHaveTextContent(/02\/05\/2021/i));
await waitFor(() => expect(screen.getAllByRole('cell')[15]).toHaveTextContent(/02\/04\/2021/i));
await waitFor(() => expect(screen.getAllByRole('cell')[7]).toHaveTextContent(/02\/05\/2021/i));
await waitFor(() => expect(screen.getAllByRole('cell')[17]).toHaveTextContent(/02\/04\/2021/i));
});

it('clicking on the second page updates to, from and total', async () => {
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/components/ActivityReportsTable/index.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.usa-table-container--scrollable {
.usa-table-container--scrollable,
.usa-checkbox__label {
margin-top: 0px;
}

3 changes: 2 additions & 1 deletion frontend/src/components/ActivityReportsTable/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,10 +299,11 @@ function ActivityReportsTable({
{renderColumnHeader('Grantee', 'activityRecipients')}
{renderColumnHeader('Start date', 'startDate')}
{renderColumnHeader('Creator', 'author')}
{renderColumnHeader('Created date', 'createdAt')}
{renderColumnHeader('Topic(s)', 'topics')}
{renderColumnHeader('Collaborator(s)', 'collaborators')}
{renderColumnHeader('Last saved', 'updatedAt')}
{renderColumnHeader('Status', 'calculatedStatus')}
{renderColumnHeader('Approved date', 'approvedAt')}
<th scope="col" aria-label="context menu" />
</tr>
</thead>
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/components/CheckboxSelect.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,8 @@
height: 1px;
margin: 1em auto;
width: 100%;
}

.smart-hub--checkbox-select label {
margin-top: 0.75em;
}
16 changes: 7 additions & 9 deletions frontend/src/components/DatePicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,9 @@ import { SingleDatePicker } from 'react-dates';
import { OPEN_UP, OPEN_DOWN } from 'react-dates/constants';
import { Controller } from 'react-hook-form/dist/index.ie11';
import moment from 'moment';

import { DATE_DISPLAY_FORMAT } from '../Constants';
import './DatePicker.css';

const dateFmt = 'MM/DD/YYYY';

const DateInput = ({
control, minDate, name, disabled, maxDate, openUp, required, ariaName, maxDateInclusive,
}) => {
Expand All @@ -29,17 +27,17 @@ const DateInput = ({
const openDirection = openUp ? OPEN_UP : OPEN_DOWN;

const isOutsideRange = (date) => {
const isBefore = minDate && date.isBefore(moment(minDate, dateFmt));
const isBefore = minDate && date.isBefore(moment(minDate, DATE_DISPLAY_FORMAT));

// If max date is inclusive (maxDateInclusive == true)
// allow the user to pick a start date that is the same as the maxDate
// otherwise, only the day before is allowed
let isAfter = false;
if (maxDateInclusive) {
const newDate = moment(maxDate, dateFmt).add(1, 'days');
isAfter = maxDate && date.isAfter(newDate, dateFmt);
const newDate = moment(maxDate, DATE_DISPLAY_FORMAT).add(1, 'days');
isAfter = maxDate && date.isAfter(newDate, DATE_DISPLAY_FORMAT);
} else {
isAfter = maxDate && date.isAfter(moment(maxDate, dateFmt));
isAfter = maxDate && date.isAfter(moment(maxDate, DATE_DISPLAY_FORMAT));
}

return isBefore || isAfter;
Expand All @@ -52,7 +50,7 @@ const DateInput = ({
<div className="usa-hint font-body-2xs" id={hintId}>mm/dd/yyyy</div>
<Controller
render={({ onChange, value, ref }) => {
const date = value ? moment(value, dateFmt) : null;
const date = value ? moment(value, DATE_DISPLAY_FORMAT) : null;
return (
<div className="display-flex smart-hub--date-picker-input">
<SingleDatePicker
Expand All @@ -69,7 +67,7 @@ const DateInput = ({
disabled={disabled}
hideKeyboardShortcutsPanel
onDateChange={(d) => {
const newDate = d ? d.format(dateFmt) : d;
const newDate = d ? d.format(DATE_DISPLAY_FORMAT) : d;
onChange(newDate);
const input = document.getElementById(name);
if (input) input.focus();
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/Tooltip.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
display: inline-block;
overflow-x: hidden;
overflow-y: visible;
width: 173.5px;
max-width: 175px;
text-overflow: ellipsis;
vertical-align: middle;
}
Expand Down
6 changes: 5 additions & 1 deletion frontend/src/components/TooltipWithCollection.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ export default function TooltipWithCollection({ collection, collectionTitle }) {

if (collection.length === 1) {
return (
<span className="smarthub-ellipsis">{tooltip}</span>
<Tooltip
displayText={tooltip}
tooltipText={tooltip}
buttonLabel={`click to visually reveal the ${collectionTitle}`}
/>
);
}

Expand Down
Loading

0 comments on commit 97a8eae

Please sign in to comment.