Skip to content

Commit

Permalink
Merge pull request #486 from HHS/main
Browse files Browse the repository at this point in the history
Prod - Requested changes to the TTA Overview widgets - add non-grantees, tta hours, fix region order
  • Loading branch information
OHS-christine-nguyen authored Jun 28, 2021
2 parents 7e3341d + 608967f commit 0525290
Show file tree
Hide file tree
Showing 47 changed files with 1,448 additions and 205 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ parameters:
default: "main"
type: string
sandbox_git_branch: # change to feature branch to test deployment
default: "AL-MB-Fix-Sequelize-Join-Issue"
default: "kw-test"
type: string
prod_new_relic_app_id:
default: "877570491"
Expand Down
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ those services are already running on your machine.

1. Make sure Docker is installed. To check run `docker ps`.
2. Make sure you have Node 14.16.1 installed.
4. Copy `.env.example` to `.env`.
4. Copy `.env.example` to `.env`.
6. Change the `AUTH_CLIENT_ID` and `AUTH_CLIENT_SECRET` variables to to values found in the "Values for local development" section of the "Development Credentials" document. If you don't have access to this document, please ask in the hs-vendors-ohs-tta channel of the gsa-tts slack channel.
7. Optionally, set `CURRENT_USER` to your current user's uid:gid. This will cause files created by docker compose to be owned by your user instead of root.
3. Run `yarn docker:reset`. This builds the frontend and backend, installs dependencies, then runs database migrations and seeders. If this returns errors that the version of nodejs is incorrect, you may have older versions of the containers built. Delete those images and it should rebuild them.
Expand All @@ -57,9 +57,9 @@ You must also install and run minio locally to use the file upload functionality

#### Docker

If switching branches for code review, run `yarn docker:reset` before running your tests.
If switching branches for code review, run `yarn docker:reset` before running your tests.

Run `yarn docker:test` to run all tests for the frontend and backend.
Run `yarn docker:test` to run all tests for the frontend and backend.

To only run the frontend tests run `yarn docker:test frontend`.

Expand Down Expand Up @@ -258,6 +258,8 @@ If your env variable is secret or the value is dependent on the deployment envir

**Interacting with a deployed database**

Read [TTAHUB-System-Operations](https://github.com/HHS/Head-Start-TTADP/wiki/TTAHUB-System-Operations) for information on how production may be accessed.

Our project includes four deployed Postgres databases, one to interact with each application environment (sandbox, dev, staging, prod). For instructions on how to create and modify databases instances within the cloud.gov ecosystem see the [terraform/README.md](terraform/README.md).

You can run psql commands directly against a deployed database by following these directions.
Expand Down Expand Up @@ -312,7 +314,7 @@ The script takes two flags
- \-e | \-\-environment controls which environment you are targeting.
- Options are "sandbox", "dev", "staging", and "prod"
Ex.
Ex.
```
# Puts the dev environment into maintenance mode
./bin/maintenance -e dev -m on
Expand All @@ -324,6 +326,7 @@ If you are not logged into the cf cli, it will ask you for an sso temporary pass
<!-- Links -->
[adhoc-main]: https://github.com/adhocteam/Head-Start-TTADP/tree/main
[TTAHUB-System-Operations](https://github.com/HHS/Head-Start-TTADP/wiki/TTAHUB-System-Operations)
[circleci-envvar]: https://app.circleci.com/settings/project/github/adhocteam/Head-Start-TTADP/environment-variables?return-to=https%3A%2F%2Fcircleci.com%2Fdashboard
[cloudgov]: https://dashboard.fr.cloud.gov/home
[cloudgov-deployer]: https://cloud.gov/docs/services/cloud-gov-service-account/
Expand Down
1 change: 1 addition & 0 deletions frontend/.env
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ BACKEND_PROXY=http://localhost:8080
REACT_APP_INACTIVE_MODAL_TIMEOUT=1500000
REACT_APP_SESSION_TIMEOUT=1800000
REACT_APP_TTA_SMART_HUB_URI=http://localhost:3000
REACT_APP_ENABLE_WIDGETS=true
12 changes: 11 additions & 1 deletion frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import Home from './pages/Home';
import Landing from './pages/Landing';
import ActivityReport from './pages/ActivityReport';
import LegacyReport from './pages/LegacyReport';
import Widgets from './pages/Widgets';

import isAdmin from './permissions';
import 'react-dates/initialize';
import 'react-dates/lib/css/_datepicker.css';
Expand Down Expand Up @@ -76,6 +78,7 @@ function App() {
}

const admin = isAdmin(user);
const enableWidgets = process.env.REACT_APP_ENABLE_WIDGETS === 'true';

const renderAuthenticatedRoutes = () => (
<div role="main" id="main-content">
Expand Down Expand Up @@ -113,7 +116,14 @@ function App() {
<ActivityReport location={location} match={match} user={user} />
)}
/>

{enableWidgets && (
<Route
path="/widgets"
render={() => (
<Widgets />
)}
/>
)}
{admin && (
<Route
path="/admin"
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/__tests__/permissions.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ describe('permissions', () => {
},
],
};
const regions = allRegionsUserHasPermissionTo(user);
const includeAdmin = true;
const regions = allRegionsUserHasPermissionTo(user, includeAdmin);
expect(regions).toEqual(expect.arrayContaining([14, 3, 4]));
});

Expand Down
24 changes: 24 additions & 0 deletions frontend/src/components/RegionDropdown.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.smart-hub--region-dropdown {
background-color: #0166AB;
border: none;
border-radius: 5px;
color: #FFFFFF;
padding-left: 18px;
font-weight: 700;
font-size: 17px;
display:inline-block;
background-image: url(../images/triange_down.png);
}

.smart-hub--region-dropdown option{
background-color: white;
border: none;
border-radius: 5px;
padding: 0px;
}

/* .arrow-down {
border-left:5px solid rgba(0,0,0,0);
border-right:5px solid rgba(0,0,0,0);
color: #FFFFFF;
} */
10 changes: 10 additions & 0 deletions frontend/src/fetchers/Widgets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import join from 'url-join';
import { get } from './index';

const fetchWidget = async (widgetId, region, query = '') => {
const queryStr = query ? `?${query}&` : '?&';
const res = await get(join('/', 'api', 'widgets', `${widgetId}${queryStr}region.in[]=${region}`));
return res.json();
};

export default fetchWidget;
1 change: 1 addition & 0 deletions frontend/src/images/check.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/src/images/triange_down.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion frontend/src/pages/Landing/Filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
DATE_FMT,
QUERY_CONDITIONS,
} from './constants';
import { DECIMAL_BASE } from '../../Constants';
import './Filter.css';

const defaultFilter = () => (
Expand Down Expand Up @@ -186,7 +187,7 @@ Filter.defaultProps = {
forMyAlerts: false,
};

export function filtersToQueryString(filters) {
export function filtersToQueryString(filters, region) {
const filtersWithValues = filters.filter((f) => {
if (f.condition === WITHIN) {
const [startDate, endDate] = f.query.split('-');
Expand All @@ -198,6 +199,9 @@ export function filtersToQueryString(filters) {
const con = QUERY_CONDITIONS[filter.condition];
return `${filter.topic}.${con}=${filter.query}`;
});
if (region && (parseInt(region, DECIMAL_BASE) !== -1)) {
queryFragments.push(`region.in[]=${parseInt(region, DECIMAL_BASE)}`);
}
return queryFragments.join('&');
}

Expand Down
160 changes: 160 additions & 0 deletions frontend/src/pages/Landing/RegionalSelect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/* eslint-disable react/forbid-prop-types */
/* eslint-disable react/jsx-props-no-spreading */
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import Select, { components } from 'react-select';
import { Button } from '@trussworks/react-uswds';

import 'uswds/dist/css/uswds.css';
import '@trussworks/react-uswds/lib/index.css';
import './index.css';

import triangleDown from '../../images/triange_down.png';
import check from '../../images/check.svg';

const DropdownIndicator = (props) => (
<components.DropdownIndicator {...props}>
<img alt="" style={{ width: '22px' }} src={triangleDown} />
</components.DropdownIndicator>
);

const Placeholder = (props) => <components.Placeholder {...props} />;

export const getUserOptions = (regions) => regions.map((region) => ({ value: region, label: `Region ${region}` }));

const styles = {
container: (provided, state) => {
// To match the focus indicator provided by uswds
const outline = state.isFocused ? '0.25rem solid #2491ff;' : '';
return {
...provided,
outline,
};
},
input: () => ({ display: 'none' }),
control: (provided) => ({
...provided,
borderColor: '#0166AB',
backgroundColor: '#0166AB',
borderRadius: '5px',
paddingLeft: '5px',
paddingTop: '4px',
paddingBottom: '4px',
whiteSpace: 'nowrap',
color: 'white',
width: '120px',
}),
indicatorSeparator: () => ({ display: 'none' }),
menu: (provided) => ({
...provided,
width: '200px',
}),
option: (provided, state) => ({
...provided,
color: state.isSelected ? '#0166AB' : 'black',
fontWeight: state.isSelected ? '700' : 'normal',
backgroundColor: state.isSelected ? '#F8F8F8' : '#FFFFFF',
padding: 11,
}),
singleValue: (provided) => {
const single = { color: '#FFFFFF', fontWeight: 600 };

return {
...provided, ...single,
};
},
valueContainer: () => ({ padding: '10px 8px' }),
};

function RegionalSelect(props) {
const {
regions, onApply,
} = props;

const [selectedItem, setSelectedItem] = useState();
const [appliedItem, setAppliedItem] = useState();
const [menuIsOpen, setMenuIsOpen] = useState(false);

// const delayedCloseMenu = () => setTimeout(setMenuIsOpen(false), 1000);

const CustomOption = (customOptionProps) => {
const {
data, innerRef, innerProps, isSelected,
} = customOptionProps;
return data.custom ? (
<div ref={innerRef} {...innerProps}>
<Button
type="button"
className="float-left margin-2 smart-hub--filter-button"
onClick={() => {
onApply(selectedItem);
setAppliedItem(selectedItem);
setMenuIsOpen(false);
}}
>
Apply
</Button>
</div>
) : (
<components.Option {...customOptionProps}>
{data.label}
{isSelected && (
<img
className="tta-smarthub--check"
src={check}
style={{
width: 32,
float: 'right',
marginTop: '-9px ',
}}
alt={data.label}
/>
)}
</components.Option>
);
};

CustomOption.propTypes = {
data: PropTypes.shape({
value: PropTypes.number,
label: PropTypes.string,
}),
innerRef: PropTypes.func,
innerProps: PropTypes.object.isRequired,
};

CustomOption.defaultProps = {
data: {},
innerRef: () => 0,
};

const options = [...getUserOptions(regions), { custom: true }];
return (
<Select
options={options}
menuIsOpen={menuIsOpen}
onChange={(value) => { if (value && value.value) setSelectedItem(value); }}
onMenuOpen={() => setMenuIsOpen(true)}
onBlur={() => setMenuIsOpen(false)}
// onBlur={() => delayedCloseMenu()}
name="RegionalSelect"
defaultValue={options[0]}
value={{
value: selectedItem ? selectedItem.value : options[0].value,
label: appliedItem ? appliedItem.label : options[0].label,
}}
styles={styles}
components={{ Placeholder, DropdownIndicator, Option: CustomOption }}
placeholder="Select Region"
closeMenuOnSelect={false}
maxMenuHeight={600}
/>
);
}

RegionalSelect.propTypes = {
regions: PropTypes.arrayOf(PropTypes.number).isRequired,
onApply: PropTypes.func.isRequired,
};

export default RegionalSelect;
5 changes: 5 additions & 0 deletions frontend/src/pages/Landing/__tests__/MyAlerts.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ const renderMyAlerts = () => {
const alertsPerPage = ALERTS_PER_PAGE;
const alertsActivePage = 1;
const alertReportsCount = 10;
const updateReportAlerts = jest.fn();
const setAlertReportsCount = jest.fn();
const requestAlertsSort = jest.fn();

render(
<Router history={history}>
<MyAlerts
Expand All @@ -31,6 +34,8 @@ const renderMyAlerts = () => {
alertsActivePage={alertsActivePage}
alertReportsCount={alertReportsCount}
sortHandler={requestAlertsSort}
updateReportAlerts={updateReportAlerts}
setAlertReportsCount={setAlertReportsCount}
fetchReports={() => {}}
updateReportFilters={() => {}}
handleDownloadAllAlerts={() => {}}
Expand Down
44 changes: 44 additions & 0 deletions frontend/src/pages/Landing/__tests__/RegionalSelect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import '@testing-library/jest-dom';
import React from 'react';
import {
render, screen, fireEvent,
} from '@testing-library/react';
import { Router } from 'react-router';
import { createMemoryHistory } from 'history';

import selectEvent from 'react-select-event';
import RegionalSelect from '../RegionalSelect';

const renderRegionalSelect = () => {
const history = createMemoryHistory();
const onApplyRegion = jest.fn();

render(
<Router history={history}>
<RegionalSelect
regions={[1, 2]}
onApply={onApplyRegion}
/>
</Router>,
);
return history;
};

describe('Regional Select', () => {
test('displays correct region in input', async () => {
renderRegionalSelect();
const input = await screen.findByText(/region 1/i);
expect(input).toBeVisible();
});

test('changes input value on apply', async () => {
renderRegionalSelect();
let input = await screen.findByText(/region 1/i);
expect(input).toBeVisible();
await selectEvent.select(screen.getByText(/region 1/i), [/region 2/i]);
const applyButton = await screen.findByText(/apply/i);
fireEvent.click(applyButton);
input = await screen.findByText(/region 2/i);
expect(input).toBeVisible();
});
});
Loading

0 comments on commit 0525290

Please sign in to comment.