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

Requested changes to the TTA Overview widgets - add non-grantees, combine tta hours, fix region order #485

Merged
merged 35 commits into from
Jun 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
b8f662f
TTAHUB-138: WIP Added custom survey button.
AdamAdHocTeam Jun 15, 2021
4e489ec
Fix lint errors.
AdamAdHocTeam Jun 15, 2021
a59b6f5
CSS fix for modal
AdamAdHocTeam Jun 15, 2021
985c102
added unit test
AdamAdHocTeam Jun 15, 2021
e410331
Merge branch 'HHS:main' into TTAHUB-138-AL-TP-Survey-On-AR-Landing
AdamAdHocTeam Jun 15, 2021
5ba493e
Merge branch 'main' into TTAHUB-138-AL-TP-Survey-On-AR-Landing
AdamAdHocTeam Jun 15, 2021
0cc41d1
change button name.
AdamAdHocTeam Jun 15, 2021
0a5719f
TTAHUB-138: Fix survey button showing only on AR Landing.
AdamAdHocTeam Jun 16, 2021
4de8ef7
TTAHUB-138: Fix Z index of survey button.
AdamAdHocTeam Jun 16, 2021
8e0fd59
Merge pull request #334 from adhocteam/TTAHUB-138-AL-TP-Survey-On-AR-…
AdamAdHocTeam Jun 16, 2021
715a860
TTAHUB-138/al-fix-csp-for-script: Test possible fix for TP Script.
AdamAdHocTeam Jun 21, 2021
6b6440a
linter fix
AdamAdHocTeam Jun 21, 2021
104ba14
omit csp directive
AdamAdHocTeam Jun 21, 2021
05eb80e
fix lint
AdamAdHocTeam Jun 21, 2021
8d29e5f
add img src
AdamAdHocTeam Jun 21, 2021
06d6de8
attemp to fix img-src for csp
AdamAdHocTeam Jun 21, 2021
3e52a1a
more SCP testing with data
AdamAdHocTeam Jun 22, 2021
3730a00
fix lint
AdamAdHocTeam Jun 22, 2021
fc6ceb0
fix audit vul
AdamAdHocTeam Jun 22, 2021
6153edb
more fixes for scripts
AdamAdHocTeam Jun 22, 2021
6694aa2
more csp updates'
AdamAdHocTeam Jun 22, 2021
e3a41cc
fix wildcard
AdamAdHocTeam Jun 22, 2021
c71978e
remove comment
AdamAdHocTeam Jun 22, 2021
773c3ef
Merge pull request #336 from adhocteam/TTAHUB-138/al-fix-csp-for-script
AdamAdHocTeam Jun 22, 2021
2f527a1
Fix region order and add non-grantees. (#335)
kryswisnaskas Jun 24, 2021
a3be4d3
Merge branch 'main' of https://github.com/HHS/Head-Start-TTADP into main
kryswisnaskas Jun 24, 2021
0d213ee
Merge pull request #339 from adhocteam/kw-conflict
kryswisnaskas Jun 25, 2021
13ca480
Debug intermittent rendering issue
kryswisnaskas Jun 25, 2021
c95b183
Merge branch 'main' into kw-test
kryswisnaskas Jun 25, 2021
ce4ffb1
Debug intermittent rendering issue
kryswisnaskas Jun 25, 2021
b64ae0a
Reverting to the state at 6b48a0fdf7a35eb6d8cf6f427af0046ea022023c
kryswisnaskas Jun 25, 2021
abb0b2b
Revert and cherry pick
kryswisnaskas Jun 24, 2021
7e9d224
Ignore vulnerabilities (#333)
kryswisnaskas Jun 15, 2021
7c700ef
audit vulnerabilities
kryswisnaskas Jun 25, 2021
a256385
Merge pull request #340 from adhocteam/kw-test
kryswisnaskas Jun 25, 2021
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
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: "kw-overview-widget"
default: "kw-test"
type: string
prod_new_relic_app_id:
default: "877570491"
Expand Down
12 changes: 10 additions & 2 deletions frontend/src/pages/Landing/RegionalSelect.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,19 @@ function RegionalSelect(props) {
};

CustomOption.propTypes = {
data: PropTypes.object.isRequired,
innerRef: PropTypes.string.isRequired,
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
Expand Down
3 changes: 1 addition & 2 deletions frontend/src/pages/Landing/mocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -302,10 +302,9 @@ export const generateXFakeReports = (count) => {
export const overviewRegionOne = {
numReports: '1',
numGrants: '2',
numNonGrantees: '2',
numTotalGrants: '4',
numParticipants: '3',
sumTrainingDuration: '5.0',
sumTaDuration: '1.0',
sumDuration: '0.5',
};

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/setupTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ import MutationObserver from '@sheerun/mutationobserver-shim';

window.MutationObserver = MutationObserver;

jest.setTimeout(10000);
jest.setTimeout(30000);
3 changes: 1 addition & 2 deletions frontend/src/widgets/Overview.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
}

.smart-hub--overview-data {
margin-left: -20px;
margin-bottom: -20px;
margin-left: -36px !important;
}

.smart-hub--overview-nowrap {
Expand Down
26 changes: 14 additions & 12 deletions frontend/src/widgets/Overview.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,17 @@ function Field({
Field.propTypes = {
label: PropTypes.string.isRequired,
labelExt: PropTypes.string,
data: PropTypes.string.isRequired,
col: PropTypes.number,
data: PropTypes.string,
col: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]),
};

Field.defaultProps = {
labelExt: '',
col: 2,
data: '',
};

/*
Expand All @@ -49,15 +53,14 @@ function Overview({ data, region }) {
{' '}
TTA Overview
</h2>
<span className="smart-hub--overview-period"> 3/17/21 to Today</span>
<span className="smart-hub--overview-period"> 9/15/2020 to Today</span>
</Grid>
<Grid row className="smart-hub--overview-data">
<Field label="Grants served " labelExt={`(of ${data.numTotalGrants})`} data={data.numGrants} />
<Field label="Activity reports" data={data.numReports} />
<Field label="Participants" data={data.numParticipants} />
<Field label="Hours of Training" data={data.sumTrainingDuration} />
<Field label="Hours of TA" data={data.sumTaDuration} />
<Field label="Hours of TTA" data={data.sumDuration} />
<Grid row gap className="smart-hub--overview-data">
<Field col="fill" tablet={{ col: true }} label="Grants served " labelExt={`(of ${data.numTotalGrants})`} data={data.numGrants} />
<Field col="fill" label="Non-grantees served" data={data.numNonGrantees} />
<Field col="fill" label="Activity reports" data={data.numReports} />
<Field col="fill" label="Participants" data={data.numParticipants} />
<Field col={2} label="Hours of TTA" data={data.sumDuration} />
</Grid>
</Container>
);
Expand All @@ -67,10 +70,9 @@ Overview.propTypes = {
data: PropTypes.shape({
numReports: PropTypes.string,
numGrants: PropTypes.string,
numNonGrantees: PropTypes.string,
numTotalGrants: PropTypes.string,
numParticipants: PropTypes.string,
sumTrainingDuration: PropTypes.string,
sumTaDuration: PropTypes.string,
sumDuration: PropTypes.string,
}).isRequired,
region: PropTypes.number.isRequired,
Expand Down
2 changes: 1 addition & 1 deletion frontend/yarn-audit-known-issues

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@
"import:hses:local": "./node_modules/.bin/babel-node ./src/tools/importGrantGranteesCLI.js --skipdownload",
"import:hses": "node ./build/server/tools/importGrantGranteesCLI.js",
"reconcile:legacy": "node ./build/server/tools/reconcileLegacyReports.js",
"reconcile:legacy:local": "./node_modules/.bin/babel-node ./src/tools/reconcileLegacyReports.js"
"reconcile:legacy:local": "./node_modules/.bin/babel-node ./src/tools/reconcileLegacyReports.js",
"populateLegacyNonGrantees": "node ./build/server/tools/populateLegacyNonGranteesCLI.js",
"populateLegacyNonGrantees:local": "./node_modules/.bin/babel-node ./src/tools/populateLegacyNonGranteesCLI.js"
},
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion src/routes/widgets/handlers.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ describe('Widget handlers', () => {
query: { 'region.in': ['1'] },
};
const response = {
numGrants: '0', numParticipants: '0', numReports: '0', numTotalGrants: '2', sumDuration: '0', sumTaDuration: '0', sumTrainingDuration: '0',
numGrants: '0', numNonGrantees: '0', numParticipants: '0', numReports: '0', numTotalGrants: '2', sumDuration: '0',
};

beforeEach(() => {
Expand Down
3 changes: 3 additions & 0 deletions src/services/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ export async function userById(userId) {
include: [
{ model: Permission, as: 'permissions', attributes: ['userId', 'scopeId', 'regionId'] },
],
order: [
[{ model: Permission, as: 'permissions' }, 'regionId', 'ASC'],
],
});
}

Expand Down
57 changes: 57 additions & 0 deletions src/tools/populateLegacyNonGrantees.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/* eslint-disable no-restricted-syntax */
/* eslint-disable no-loop-func */
import { Op } from 'sequelize';
import { auditLogger } from '../logger';
import { ActivityReport, ActivityRecipient, NonGrantee } from '../models';

const hubNonGrantees = {
HSCO: 'Head Start Collaboration Office',
'Local/State Education System': 'State Education System',
'State Early Learning System / Guidelines': 'State Early Learning Standards',
'State Advisory Council': 'QRIS System',
'Regional TTA Team / Specialists': 'Regional TTA/Other Specialists',
'State Early Learning Standards / Guidelines':
'State Early Learning Standards',
};

const populateLegacyNonGrantees = async () => {
const nonGranteeReports = await ActivityReport.findAll({
where: {
[Op.and]: [
{ legacyId: { [Op.ne]: null } },
{
imported: {
nonGranteeActivity: {
[Op.ne]: '',
},
},
},
],
},
});

for await (const nonGranteeReport of nonGranteeReports) {
const nonGranteeArray = nonGranteeReport.imported.nonGranteeActivity.split(
'\n',
);
for await (const nonGranteeName of nonGranteeArray) {
const translatedNonGranteeName = hubNonGrantees[nonGranteeName] || nonGranteeName;
const nonGrantee = await NonGrantee.findOne({
where: { name: translatedNonGranteeName },
});
if (nonGrantee) {
auditLogger.info(
`Processing non-grantee ${nonGrantee.id} for activity report ${nonGranteeReport.id}`,
);
await ActivityRecipient.findOrCreate({
where: {
activityReportId: nonGranteeReport.id,
nonGranteeId: nonGrantee.id,
},
});
}
}
}
};

export default populateLegacyNonGrantees;
7 changes: 7 additions & 0 deletions src/tools/populateLegacyNonGranteesCLI.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import populateLegacyNonGrantees from './populateLegacyNonGrantees';
import { auditLogger } from '../logger';

populateLegacyNonGrantees().catch((e) => {
auditLogger.error(e);
process.exit(1);
});
65 changes: 52 additions & 13 deletions src/widgets/overview.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Op } from 'sequelize';
import {
ActivityReport, ActivityRecipient, Grant, NonGrantee, sequelize,
} from '../models';
import { REPORT_STATUSES } from '../constants';
/*
Widgets on the backend should only have to worry about fetching data in the format required
by the widget. In this case we return a single object but other widgets my require an array
Expand All @@ -12,25 +13,63 @@ import {
If adding a new widget be sure to add the widget to ./index.js
*/
export default async function overview(scopes, region) {
const grantsWhere = `WHERE "status" = 'Active' AND "regionId" in (${region})`;
const trainingWhere = '"ttaType" = \'{"training"}\'';
const taWhere = '"ttaType" = \'{"technical-assistance"}\'';
const ttaWhere = '"ttaType" = \'{"training", "technical-assistance"}\'';
const baseWhere = `WHERE "regionId" IN (${region}) AND "legacyId" IS NULL AND "status" != 'deleted'`;
const grantsWhere = `WHERE "regionId" in (${region})`;
const baseWhere = `${grantsWhere} AND "status" = '${REPORT_STATUSES.APPROVED}'`;
// There could be a better way, but using sequelize.literal was the only way I could get correct
// numbers for SUM
// FIXME: see if there is a better way to get totals using SUM
const res = await ActivityReport.findAll({
attributes: [
[sequelize.fn('COUNT', sequelize.fn('DISTINCT', sequelize.col('"ActivityReport".id'))), 'numReports'],
[sequelize.fn('COUNT', sequelize.fn('DISTINCT', sequelize.col('"activityRecipients->grant"."id"'))), 'numGrants'],
[sequelize.literal(`(SELECT COUNT(*) from "Grants" ${grantsWhere})`), 'numTotalGrants'],
[sequelize.literal(`(SELECT COALESCE(SUM("numberOfParticipants"), 0) FROM "ActivityReports" ${baseWhere})`), 'numParticipants'],
[sequelize.literal(`(SELECT COALESCE(SUM(duration), 0) FROM "ActivityReports" ${baseWhere} AND ${trainingWhere})`), 'sumTrainingDuration'],
[sequelize.literal(`(SELECT COALESCE(SUM(duration), 0) FROM "ActivityReports" ${baseWhere} AND ${taWhere})`), 'sumTaDuration'],
[sequelize.literal(`(SELECT COALESCE(SUM(duration), 0) FROM "ActivityReports" ${baseWhere} AND ${ttaWhere})`), 'sumDuration'],
[
sequelize.fn(
'COUNT',
sequelize.fn('DISTINCT', sequelize.col('"ActivityReport".id')),
),
'numReports',
],
[
sequelize.fn(
'COUNT',
sequelize.fn(
'DISTINCT',
sequelize.col('"activityRecipients->grant"."id"'),
),
),
'numGrants',
],
[
sequelize.literal(`(SELECT COUNT(*) from "Grants" ${grantsWhere})`),
'numTotalGrants',
],
[
sequelize.fn(
'COUNT',
sequelize.fn(
'DISTINCT',
sequelize.col('"activityRecipients"."nonGranteeId"'),
),
),
'numNonGrantees',
],
[
sequelize.literal(
`(SELECT COALESCE(SUM("numberOfParticipants"), 0) FROM "ActivityReports" ${baseWhere})`,
),
'numParticipants',
],
[
sequelize.literal(
`(SELECT COALESCE(SUM(duration), 0) FROM "ActivityReports" ${baseWhere})`,
),
'sumDuration',
],
],
where: { [Op.and]: [scopes, { legacyId: null }] },
where: {
[Op.and]: [
scopes,
{ status: REPORT_STATUSES.APPROVED },
],
},
raw: true,
// without 'includeIgnoreAttributes' the attributes from the join table
// "activityReportObjectives" are included which causes postgres to error when
Expand Down
11 changes: 5 additions & 6 deletions src/widgets/overview.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,21 +120,20 @@ describe('Overview widget', () => {
await createOrUpdate({ ...regionTwoReport, duration: 1.5 }, reportOneR2);

const scopes = filtersToScopes({ 'region.in': ['17'] });
const data = await overview(scopes, 17);
const {
numReports,
numGrants,
numTotalGrants,
numNonGrantees,
numParticipants,
sumTrainingDuration,
sumTaDuration,
sumDuration,
} = await overview(scopes, 17);
} = data;
expect(numReports).toBe('4');
expect(numGrants).toBe('2');
expect(numTotalGrants).toBe('2');
expect(numNonGrantees).toBe('0');
expect(numParticipants).toBe('44');
expect(sumTrainingDuration).toBe('4.0');
expect(sumTaDuration).toBe('3.0');
expect(sumDuration).toBe('5.0');
expect(sumDuration).toBe('12.0');
});
});