From 0a04986bc726ce99217f49a66a6e915a1a060a19 Mon Sep 17 00:00:00 2001 From: Lizzie Salita Date: Tue, 12 Jan 2021 12:03:12 -0500 Subject: [PATCH 01/69] link from single agency statistics page --- src/js/components/aboutTheData/AgencyDownloadLinkCell.jsx | 3 +-- src/js/containers/aboutTheData/AgencyDetailsContainer.jsx | 2 +- src/js/models/v2/aboutTheData/BaseReportingPeriodRow.js | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/js/components/aboutTheData/AgencyDownloadLinkCell.jsx b/src/js/components/aboutTheData/AgencyDownloadLinkCell.jsx index b62334ed1a..1263c22546 100644 --- a/src/js/components/aboutTheData/AgencyDownloadLinkCell.jsx +++ b/src/js/components/aboutTheData/AgencyDownloadLinkCell.jsx @@ -1,7 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import kGlobalConstants from 'GlobalConstants'; const propTypes = { file: PropTypes.string @@ -11,7 +10,7 @@ const AgencyDownloadLinkCell = ({ file }) => ( Download diff --git a/src/js/containers/aboutTheData/AgencyDetailsContainer.jsx b/src/js/containers/aboutTheData/AgencyDetailsContainer.jsx index a5f0e36cfd..c3cd9888f9 100644 --- a/src/js/containers/aboutTheData/AgencyDetailsContainer.jsx +++ b/src/js/containers/aboutTheData/AgencyDetailsContainer.jsx @@ -157,7 +157,7 @@ const AgencyDetailsContainer = ({ }} />), (
{rowData.unlinkedContracts}
), (
{rowData.unlinkedAssistance}
), - (
) + (
) ]); }) ); diff --git a/src/js/models/v2/aboutTheData/BaseReportingPeriodRow.js b/src/js/models/v2/aboutTheData/BaseReportingPeriodRow.js index 2e4d2fafd2..dd3ca030c4 100644 --- a/src/js/models/v2/aboutTheData/BaseReportingPeriodRow.js +++ b/src/js/models/v2/aboutTheData/BaseReportingPeriodRow.js @@ -21,6 +21,7 @@ const BaseReportingPeriodRow = { this._unlinkedContracts = data.unlinked_contract_award_count || 0; this._unlinkedAssistance = data.unlinked_assistance_award_count || 0; this._percentOfBudget = data.percent_of_total_budgetary_resources || 0; + this.assuranceStatement = data.assurance_statement_url || ''; }, get reportingPeriod() { return `FY ${this.fiscalYear}: ${getPeriodWithTitleById(`${this.fiscalPeriod}`).title}`; From 1d28d86e0ab8729bd65c77ec2dc0e95845d725f1 Mon Sep 17 00:00:00 2001 From: Lizzie Salita Date: Tue, 12 Jan 2021 12:05:17 -0500 Subject: [PATCH 02/69] handle a falsy value for the url --- .../aboutTheData/AgencyDownloadLinkCell.jsx | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/js/components/aboutTheData/AgencyDownloadLinkCell.jsx b/src/js/components/aboutTheData/AgencyDownloadLinkCell.jsx index 1263c22546..b335dce92a 100644 --- a/src/js/components/aboutTheData/AgencyDownloadLinkCell.jsx +++ b/src/js/components/aboutTheData/AgencyDownloadLinkCell.jsx @@ -6,16 +6,18 @@ const propTypes = { file: PropTypes.string }; -const AgencyDownloadLinkCell = ({ file }) => ( -
- Download - -); +const AgencyDownloadLinkCell = ({ file }) => { + return file ? ( + + Download + + ) : '--'; +} AgencyDownloadLinkCell.propTypes = propTypes; export default AgencyDownloadLinkCell; From a8c83d8509d1adb34e489bf05ac3e007daf31012 Mon Sep 17 00:00:00 2001 From: Lizzie Salita Date: Tue, 12 Jan 2021 13:17:14 -0500 Subject: [PATCH 03/69] refactored models to use a shared CoreReportingRow --- .../aboutTheData/AgencyDownloadLinkCell.jsx | 22 ++++---- .../aboutTheData/AgenciesContainer.jsx | 12 ++--- .../aboutTheData/AgencyDetailsContainer.jsx | 2 +- .../models/v2/aboutTheData/BaseAgencyRow.js | 25 +++++++++ .../v2/aboutTheData/BaseReportingPeriodRow.js | 52 +++++-------------- .../v2/aboutTheData/CoreReportingRow.js | 48 +++++++++++++++++ .../v2/aboutTheData/ReportingOverviewRow.js | 49 ----------------- 7 files changed, 102 insertions(+), 108 deletions(-) create mode 100644 src/js/models/v2/aboutTheData/BaseAgencyRow.js create mode 100644 src/js/models/v2/aboutTheData/CoreReportingRow.js delete mode 100644 src/js/models/v2/aboutTheData/ReportingOverviewRow.js diff --git a/src/js/components/aboutTheData/AgencyDownloadLinkCell.jsx b/src/js/components/aboutTheData/AgencyDownloadLinkCell.jsx index b335dce92a..439119442a 100644 --- a/src/js/components/aboutTheData/AgencyDownloadLinkCell.jsx +++ b/src/js/components/aboutTheData/AgencyDownloadLinkCell.jsx @@ -6,18 +6,16 @@ const propTypes = { file: PropTypes.string }; -const AgencyDownloadLinkCell = ({ file }) => { - return file ? ( - - Download - - ) : '--'; -} +const AgencyDownloadLinkCell = ({ file }) => (file ? ( + + Download + +) : '--'); AgencyDownloadLinkCell.propTypes = propTypes; export default AgencyDownloadLinkCell; diff --git a/src/js/containers/aboutTheData/AgenciesContainer.jsx b/src/js/containers/aboutTheData/AgenciesContainer.jsx index 1faeefa181..bffdd85d89 100644 --- a/src/js/containers/aboutTheData/AgenciesContainer.jsx +++ b/src/js/containers/aboutTheData/AgenciesContainer.jsx @@ -8,7 +8,7 @@ import DrilldownCell from 'components/aboutTheData/DrilldownCell'; import CellWithModal from 'components/aboutTheData/CellWithModal'; import { setTableData, setTableSort, setTotals, setSearchResults } from 'redux/actions/aboutTheData'; import { getTotalBudgetaryResources, getAgenciesReportingData, getSubmissionPublicationDates, usePagination, isPeriodSelectable } from 'helpers/aboutTheDataHelper'; -import ReportingOverviewRow from 'models/v2/aboutTheData/ReportingOverviewRow'; +import BaseAgencyRow from 'models/v2/aboutTheData/BaseAgencyRow'; import PublicationOverviewRow from 'models/v2/aboutTheData/PublicationOverviewRow'; import { agenciesTableColumns } from './AgencyTableMapping'; @@ -81,7 +81,7 @@ const AgenciesContainer = ({ return submissionsReq.current.promise .then(({ data: { results, page_metadata: { total: totalItems, page, limit } } }) => { const parsedResults = results.map((d) => { - const row = Object.create(ReportingOverviewRow); + const row = Object.create(BaseAgencyRow); const federalTotal = federalTotals.find(({ fiscal_year: y, fiscal_period: p }) => ( y === parseInt(selectedFy, 10) && p === parseInt(selectedPeriod, 10) @@ -209,10 +209,10 @@ const AgenciesContainer = ({ .map(({ name: agencyName, code, - publicationDate, + mostRecentPublicationDate, discrepancyCount: GtasNotInFileA, obligationDifference, - tasTotals, + _gtasObligationTotal, percentageOfTotalFederalBudget, unlinkedContractAwards, unlinkedAssistanceAwards @@ -220,7 +220,7 @@ const AgenciesContainer = ({ (), (
{percentageOfTotalFederalBudget}
), (), ( Date: Tue, 12 Jan 2021 13:28:42 -0500 Subject: [PATCH 04/69] added Assurance Statement column --- src/_scss/pages/aboutTheData/agenciesPage.scss | 5 +++++ src/js/containers/aboutTheData/AgenciesContainer.jsx | 12 +++++++----- .../containers/aboutTheData/AgencyTableMapping.jsx | 9 ++++++++- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/_scss/pages/aboutTheData/agenciesPage.scss b/src/_scss/pages/aboutTheData/agenciesPage.scss index fbdd91779e..a607546891 100644 --- a/src/_scss/pages/aboutTheData/agenciesPage.scss +++ b/src/_scss/pages/aboutTheData/agenciesPage.scss @@ -353,6 +353,11 @@ border: none; } } + .agency-table-download { + svg { + margin-right: 0.5rem; + } + } } // Pagination .usa-dt-pagination { diff --git a/src/js/containers/aboutTheData/AgenciesContainer.jsx b/src/js/containers/aboutTheData/AgenciesContainer.jsx index bffdd85d89..a60e628d77 100644 --- a/src/js/containers/aboutTheData/AgenciesContainer.jsx +++ b/src/js/containers/aboutTheData/AgenciesContainer.jsx @@ -10,7 +10,7 @@ import { setTableData, setTableSort, setTotals, setSearchResults } from 'redux/a import { getTotalBudgetaryResources, getAgenciesReportingData, getSubmissionPublicationDates, usePagination, isPeriodSelectable } from 'helpers/aboutTheDataHelper'; import BaseAgencyRow from 'models/v2/aboutTheData/BaseAgencyRow'; import PublicationOverviewRow from 'models/v2/aboutTheData/PublicationOverviewRow'; - +import AgencyDownloadLinkCell from 'components/aboutTheData/AgencyDownloadLinkCell'; import { agenciesTableColumns } from './AgencyTableMapping'; const propTypes = { @@ -214,8 +214,9 @@ const AgenciesContainer = ({ obligationDifference, _gtasObligationTotal, percentageOfTotalFederalBudget, - unlinkedContractAwards, - unlinkedAssistanceAwards + unlinkedContracts, + unlinkedAssistance, + assuranceStatement }) => [ (), (
{percentageOfTotalFederalBudget}
), @@ -250,8 +251,9 @@ const AgenciesContainer = ({ fiscalYear: selectedFy, fiscalPeriod: selectedPeriod?.id }} />), - (
{unlinkedContractAwards}
), - (
{unlinkedAssistanceAwards}
) + (
{unlinkedContracts}
), + (
{unlinkedAssistance}
), + (
) ]); const handlePageChange = (page) => { diff --git a/src/js/containers/aboutTheData/AgencyTableMapping.jsx b/src/js/containers/aboutTheData/AgencyTableMapping.jsx index 6c78ee13a0..5e4f319ed9 100644 --- a/src/js/containers/aboutTheData/AgencyTableMapping.jsx +++ b/src/js/containers/aboutTheData/AgencyTableMapping.jsx @@ -1,5 +1,5 @@ /** - * agencyTables.js + * AgencyTableMapping.jsx * Created by Lizzie Salita 11/25/20 */ @@ -104,6 +104,13 @@ export const agenciesTableColumns = { icon: ( ) + }, + { + title: "assurance_statements", + displayName: "Assurance Statements", + icon: ( + + ) } ] }; From 03535dc3ec6c22fe23d61f4590c083ad57fc1759 Mon Sep 17 00:00:00 2001 From: Lizzie Salita Date: Tue, 12 Jan 2021 14:11:12 -0500 Subject: [PATCH 05/69] Updated unit tests for models --- .../v2/aboutTheData/CoreReportingRow.js | 2 +- .../models/aboutTheData/BaseAgencyRow-test.js | 32 +++++++++++++++ .../BaseReportingPeriodRow-test.js | 21 ++++------ .../aboutTheData/CoreReportingRow-test.js | 34 ++++++++++++++++ .../aboutTheData/ReportingOverviewRow-test.js | 40 ------------------- 5 files changed, 75 insertions(+), 54 deletions(-) create mode 100644 tests/models/aboutTheData/BaseAgencyRow-test.js create mode 100644 tests/models/aboutTheData/CoreReportingRow-test.js delete mode 100644 tests/models/aboutTheData/ReportingOverviewRow-test.js diff --git a/src/js/models/v2/aboutTheData/CoreReportingRow.js b/src/js/models/v2/aboutTheData/CoreReportingRow.js index 017d32d23e..79bf1928e2 100644 --- a/src/js/models/v2/aboutTheData/CoreReportingRow.js +++ b/src/js/models/v2/aboutTheData/CoreReportingRow.js @@ -41,7 +41,7 @@ const CoreReportingRow = { if (!this._unlinkedAssistance && this._unlinkedAssistance !== 0) { return '--'; } - return formatNumber(this._unlinkedContracts); + return formatNumber(this._unlinkedAssistance); } }; diff --git a/tests/models/aboutTheData/BaseAgencyRow-test.js b/tests/models/aboutTheData/BaseAgencyRow-test.js new file mode 100644 index 0000000000..c666abf3bc --- /dev/null +++ b/tests/models/aboutTheData/BaseAgencyRow-test.js @@ -0,0 +1,32 @@ +/** + * BaseAgencyRow-test.js + * Created by Lizzie Salita 11/20/20 + */ + +import BaseAgencyRow from 'models/v2/aboutTheData/BaseAgencyRow'; +import CoreReportingRow from 'models/v2/aboutTheData/CoreReportingRow'; +import { mockAPI } from 'containers/aboutTheData/AgencyTableMapping'; + +// TODO - update when API contracts are finalized +const mockAgencyRow = { ...mockAPI.submissions.data.results[0] }; + +const agencyRow = Object.create(BaseAgencyRow); +agencyRow.populate(mockAgencyRow); + +describe('BaseAgencyRow', () => { + it('should format the agency name', () => { + expect(agencyRow.name).toEqual('Department of Health and Human Services (DHHS)'); + }); + it('should handle an agency with no abbreviation', () => { + const missingAbbrev = { + ...mockAgencyRow, + abbreviation: '' + }; + const agencyRowMod = Object.create(BaseAgencyRow); + agencyRowMod.populate(missingAbbrev); + expect(agencyRowMod.name).toEqual('Department of Health and Human Services'); + }); + it('should have CoreReportingRow in its prototype chain', () => { + expect(Object.getPrototypeOf(agencyRow)).toMatchObject(CoreReportingRow); + }); +}); diff --git a/tests/models/aboutTheData/BaseReportingPeriodRow-test.js b/tests/models/aboutTheData/BaseReportingPeriodRow-test.js index c105665703..8003ec3454 100644 --- a/tests/models/aboutTheData/BaseReportingPeriodRow-test.js +++ b/tests/models/aboutTheData/BaseReportingPeriodRow-test.js @@ -4,8 +4,9 @@ */ import BaseReportingPeriodRow from 'models/v2/aboutTheData/BaseReportingPeriodRow'; +import CoreReportingRow from 'models/v2/aboutTheData/CoreReportingRow'; -const mockReportingPeriodRow = { +export const mockReportingPeriodRow = { fiscal_year: 2020, fiscal_period: 12, current_total_budget_authority_amount: 8361447130497.72, @@ -15,7 +16,10 @@ const mockReportingPeriodRow = { gtas_obligation_total: 234567 }, percent_of_total_budgetary_resources: 2.189, - obligation_difference: 436376232652.87 + obligation_difference: 436376232652.87, + unlinked_contract_award_count: 20002, + unlinked_assistance_award_count: 10001, + assurance_statement_url: 'https://files.usaspending.gov/agency_submissions/Raw%20DATA%20Act%20Files/2020/Q1/097%20-%20Department%20of%20Defense%20(DOD)/2020-Q1-097_Department%20of%20Defense%20(DOD)-Assurance_Statement.txt' }; const reportingPeriodRow = Object.create(BaseReportingPeriodRow); @@ -43,19 +47,10 @@ describe('BaseReportingPeriodRow', () => { reportingPeriodRowMod.populate(period2); expect(reportingPeriodRowMod.reportingPeriod).toEqual('FY 2020: P01 - P02'); }); - it('should format the obligation difference to the cent', () => { - expect(reportingPeriodRow.obligationDifference).toEqual('$436,376,232,652.87'); - }); - it('should format missing TAS count', () => { - expect(reportingPeriodRow.missingTASCount).toEqual('1,000'); - }); - it('should format the most recent publication date', () => { - expect(reportingPeriodRow.mostRecentPublicationDate).toEqual('01/10/2020'); - }); it('should format the percent of budgetary resources', () => { expect(reportingPeriodRow.percentOfBudget).toEqual('2.19%'); }); - it('should store the raw GTAS Obligation Total', () => { - expect(reportingPeriodRow._gtasObligationTotal).toEqual(234567); + it('should have CoreReportingRow in its prototype chain', () => { + expect(Object.getPrototypeOf(reportingPeriodRow)).toMatchObject(CoreReportingRow); }); }); diff --git a/tests/models/aboutTheData/CoreReportingRow-test.js b/tests/models/aboutTheData/CoreReportingRow-test.js new file mode 100644 index 0000000000..c8ed5f1735 --- /dev/null +++ b/tests/models/aboutTheData/CoreReportingRow-test.js @@ -0,0 +1,34 @@ +/** + * CoreReportingRow-test.js + * Created by Lizzie Salita 1/12/21 + */ + +import CoreReportingRow from 'models/v2/aboutTheData/CoreReportingRow'; +import { mockReportingPeriodRow } from './BaseReportingPeriodRow-test'; + +const row = Object.create(CoreReportingRow); +row.populateCore(mockReportingPeriodRow); + +describe('Core Reporting Row model', () => { + it('should format the budget authority', () => { + expect(row.budgetAuthority).toEqual('$8,361,447,130,497.72'); + }); + it('should format the obligation difference', () => { + expect(row.obligationDifference).toEqual('$436,376,232,652.87'); + }); + it('should format the discrepancy count', () => { + expect(row.discrepancyCount).toEqual('1,000'); + }); + it('should format the publication date', () => { + expect(row.mostRecentPublicationDate).toEqual('01/10/2020'); + }); + it('should store the raw GTAS Obligation Total', () => { + expect(row._gtasObligationTotal).toEqual(234567); + }); + it('should format the unlinked contracts count', () => { + expect(row.unlinkedContracts).toEqual('20,002'); + }); + it('should format the unlinked assistance awards count', () => { + expect(row.unlinkedAssistance).toEqual('10,001'); + }); + }); \ No newline at end of file diff --git a/tests/models/aboutTheData/ReportingOverviewRow-test.js b/tests/models/aboutTheData/ReportingOverviewRow-test.js deleted file mode 100644 index ca09a3d6af..0000000000 --- a/tests/models/aboutTheData/ReportingOverviewRow-test.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * ReportingOverviewRow-test.js - * Created by Lizzie Salita 11/20/20 - */ - -import ReportingOverviewRow from 'models/v2/aboutTheData/ReportingOverviewRow'; -import { mockAPI } from 'containers/aboutTheData/AgencyTableMapping'; - -// TODO - update when API contracts are finalized -const mockAgencyRow = { ...mockAPI.submissions.data.results[0] }; - -const agencyRow = Object.create(ReportingOverviewRow); -agencyRow.populate(mockAgencyRow); - -describe('ReportingOverviewRow', () => { - it('should format the agency name', () => { - expect(agencyRow.name).toEqual('Department of Health and Human Services (DHHS)'); - }); - it('should handle an agency with no abbreviation', () => { - const missingAbbrev = { - ...mockAgencyRow, - abbreviation: '' - }; - const agencyRowMod = Object.create(ReportingOverviewRow); - agencyRowMod.populate(missingAbbrev); - expect(agencyRowMod.name).toEqual('Department of Health and Human Services'); - }); - it('should format the budget authority', () => { - expect(agencyRow.budgetAuthority).toEqual('$8,361,447,130,498'); - }); - it('should format the obligation difference', () => { - expect(agencyRow.obligationDifference).toEqual('$436,376,232,653'); - }); - it('should format the discrepancy count', () => { - expect(agencyRow.discrepancyCount).toEqual('20'); - }); - it('should format the publication date', () => { - expect(agencyRow.publicationDate).toEqual('01/10/2020'); - }); -}); From e3cad3ee37c7c41c171d71eba3e960a2cb43d5be Mon Sep 17 00:00:00 2001 From: Jonathan Hill Date: Wed, 13 Jan 2021 14:24:51 -0500 Subject: [PATCH 06/69] updates loading message text to be centered inline with viz --- src/_scss/pages/modals/aboutTheData/_aboutTheData.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss b/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss index 4c9343e5bc..47dc2a8f83 100644 --- a/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss +++ b/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss @@ -64,6 +64,11 @@ tr { td { border: none; + .usda-loading-animation__container { + .loading-message { + text-align: center; + } + } } } font-size: rem(12); From ec6f9b3e2306565d624cb218f05e722f73d5fdca Mon Sep 17 00:00:00 2001 From: Lizzie Salita Date: Thu, 14 Jan 2021 13:38:47 -0500 Subject: [PATCH 07/69] Hide sorting for the assurance statements col --- src/_scss/pages/aboutTheData/agenciesPage.scss | 13 +++++++++++++ src/_scss/pages/aboutTheData/agencyDetailsPage.scss | 9 ++++++--- .../containers/aboutTheData/AgenciesContainer.jsx | 2 +- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/_scss/pages/aboutTheData/agenciesPage.scss b/src/_scss/pages/aboutTheData/agenciesPage.scss index a607546891..31918d2a82 100644 --- a/src/_scss/pages/aboutTheData/agenciesPage.scss +++ b/src/_scss/pages/aboutTheData/agenciesPage.scss @@ -358,6 +358,19 @@ margin-right: 0.5rem; } } + &.table-container_submissions { + // Styles specific to the "Statistics by Reporting Period" tab + thead { + th { + &:last-of-type { + // Hide sorting for the Assurance Statements column + .table-header__sort { + display: none; + } + } + } + } + } } // Pagination .usa-dt-pagination { diff --git a/src/_scss/pages/aboutTheData/agencyDetailsPage.scss b/src/_scss/pages/aboutTheData/agencyDetailsPage.scss index 7b27787b69..241ea49078 100644 --- a/src/_scss/pages/aboutTheData/agencyDetailsPage.scss +++ b/src/_scss/pages/aboutTheData/agencyDetailsPage.scss @@ -46,9 +46,12 @@ tr th { min-width: rem(300); } - .nested-header { - .table-header__content { - padding: 1rem 0; + th { + &:last-of-type { + // Hide sorting for the Assurance Statements column + .table-header__sort { + display: none; + } } } } diff --git a/src/js/containers/aboutTheData/AgenciesContainer.jsx b/src/js/containers/aboutTheData/AgenciesContainer.jsx index a60e628d77..8c0d427fb3 100644 --- a/src/js/containers/aboutTheData/AgenciesContainer.jsx +++ b/src/js/containers/aboutTheData/AgenciesContainer.jsx @@ -276,7 +276,7 @@ const AgenciesContainer = ({ return ( <> -
+
{activeTab === 'submissions' && ( Date: Thu, 14 Jan 2021 14:01:22 -0500 Subject: [PATCH 08/69] added test for download link cell component --- .../pages/aboutTheData/agenciesPage.scss | 10 +++++----- .../AgencyDownloadLinkCell-test.jsx | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 tests/components/aboutTheData/AgencyDownloadLinkCell-test.jsx diff --git a/src/_scss/pages/aboutTheData/agenciesPage.scss b/src/_scss/pages/aboutTheData/agenciesPage.scss index 31918d2a82..2bdfa5e63f 100644 --- a/src/_scss/pages/aboutTheData/agenciesPage.scss +++ b/src/_scss/pages/aboutTheData/agenciesPage.scss @@ -353,11 +353,6 @@ border: none; } } - .agency-table-download { - svg { - margin-right: 0.5rem; - } - } &.table-container_submissions { // Styles specific to the "Statistics by Reporting Period" tab thead { @@ -370,6 +365,11 @@ } } } + .agency-table-download { + svg { + margin-right: 0.5rem; + } + } } } // Pagination diff --git a/tests/components/aboutTheData/AgencyDownloadLinkCell-test.jsx b/tests/components/aboutTheData/AgencyDownloadLinkCell-test.jsx new file mode 100644 index 0000000000..1534ee513a --- /dev/null +++ b/tests/components/aboutTheData/AgencyDownloadLinkCell-test.jsx @@ -0,0 +1,19 @@ +/** + * AgencyDownloadLinkCell-test.jsx + * Created by Lizzie Salita 1/14/21 + */ + +import React from 'react'; +import AgencyDownloadLinkCell from 'components/aboutTheData/AgencyDownloadLinkCell'; +import { render, screen } from '@test-utils'; + +describe('AgencyDownloadLinkCell', () => { + it('should render the download link when a file is provided', () => { + render(); + expect(screen.queryByText('Download')).toBeTruthy(); + }); + it('should not render the download link when the file prop is falsy', () => { + render(); + expect(screen.queryByText('--')).toBeTruthy(); + }); +}); From 7494b25949f6e205306dc36e4226e4b7491b60d5 Mon Sep 17 00:00:00 2001 From: Lizzie Salita Date: Thu, 14 Jan 2021 14:09:55 -0500 Subject: [PATCH 09/69] changed column name to "Agency Comments" --- src/_scss/pages/aboutTheData/agenciesPage.scss | 2 +- src/_scss/pages/aboutTheData/agencyDetailsPage.scss | 2 +- .../aboutTheData/dataMapping/tooltipContentMapping.jsx | 2 +- src/js/containers/aboutTheData/AgencyDetailsContainer.jsx | 4 ++-- src/js/containers/aboutTheData/AgencyTableMapping.jsx | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/_scss/pages/aboutTheData/agenciesPage.scss b/src/_scss/pages/aboutTheData/agenciesPage.scss index 2bdfa5e63f..89e878a531 100644 --- a/src/_scss/pages/aboutTheData/agenciesPage.scss +++ b/src/_scss/pages/aboutTheData/agenciesPage.scss @@ -358,7 +358,7 @@ thead { th { &:last-of-type { - // Hide sorting for the Assurance Statements column + // Hide sorting for the Agency Comments column .table-header__sort { display: none; } diff --git a/src/_scss/pages/aboutTheData/agencyDetailsPage.scss b/src/_scss/pages/aboutTheData/agencyDetailsPage.scss index 241ea49078..7845ddc531 100644 --- a/src/_scss/pages/aboutTheData/agencyDetailsPage.scss +++ b/src/_scss/pages/aboutTheData/agencyDetailsPage.scss @@ -48,7 +48,7 @@ } th { &:last-of-type { - // Hide sorting for the Assurance Statements column + // Hide sorting for the Agency Comments column .table-header__sort { display: none; } diff --git a/src/js/components/aboutTheData/dataMapping/tooltipContentMapping.jsx b/src/js/components/aboutTheData/dataMapping/tooltipContentMapping.jsx index 3617f0a039..1eb85cce85 100644 --- a/src/js/components/aboutTheData/dataMapping/tooltipContentMapping.jsx +++ b/src/js/components/aboutTheData/dataMapping/tooltipContentMapping.jsx @@ -97,7 +97,7 @@ export const columnTooltips = {

), - 'Agency Disclosures': ( + 'Agency Comments': (

Agency Assurance Statements are optional and provided by agencies at the time they submit their data to USAspending.gov in the required dataset formats (File A, B, C, D1, and D2). For more information about the DATA Act reporting flow, visit https://fiscal.treasury.gov/files/data-transparency/daims-information-flow-diagram.pdf

diff --git a/src/js/containers/aboutTheData/AgencyDetailsContainer.jsx b/src/js/containers/aboutTheData/AgencyDetailsContainer.jsx index c300a01eee..d840b5983f 100644 --- a/src/js/containers/aboutTheData/AgencyDetailsContainer.jsx +++ b/src/js/containers/aboutTheData/AgencyDetailsContainer.jsx @@ -78,9 +78,9 @@ const columns = [ }, { title: "assurance_statements", - displayName: "Assurance Statements", + displayName: "Agency Comments", icon: ( - + ) } ]; diff --git a/src/js/containers/aboutTheData/AgencyTableMapping.jsx b/src/js/containers/aboutTheData/AgencyTableMapping.jsx index 5e4f319ed9..9146e59530 100644 --- a/src/js/containers/aboutTheData/AgencyTableMapping.jsx +++ b/src/js/containers/aboutTheData/AgencyTableMapping.jsx @@ -107,9 +107,9 @@ export const agenciesTableColumns = { }, { title: "assurance_statements", - displayName: "Assurance Statements", + displayName: "Agency Comments", icon: ( - + ) } ] From 197fcfb7ff756b2c9ea437b7a0b943e968fc6099 Mon Sep 17 00:00:00 2001 From: Lizzie Salita Date: Thu, 14 Jan 2021 14:14:11 -0500 Subject: [PATCH 10/69] fixed link label; additional tests --- .../aboutTheData/AgencyDownloadLinkCell.jsx | 2 +- .../aboutTheData/CoreReportingRow-test.js | 32 ++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/js/components/aboutTheData/AgencyDownloadLinkCell.jsx b/src/js/components/aboutTheData/AgencyDownloadLinkCell.jsx index 439119442a..0a72478ffe 100644 --- a/src/js/components/aboutTheData/AgencyDownloadLinkCell.jsx +++ b/src/js/components/aboutTheData/AgencyDownloadLinkCell.jsx @@ -12,7 +12,7 @@ const AgencyDownloadLinkCell = ({ file }) => (file ? ( target="_blank" href={file} rel="noopener noreferrer" - aria-label="Raw quarterly submission files"> + aria-label="Download agency comments"> Download ) : '--'); diff --git a/tests/models/aboutTheData/CoreReportingRow-test.js b/tests/models/aboutTheData/CoreReportingRow-test.js index c8ed5f1735..082900454a 100644 --- a/tests/models/aboutTheData/CoreReportingRow-test.js +++ b/tests/models/aboutTheData/CoreReportingRow-test.js @@ -31,4 +31,34 @@ describe('Core Reporting Row model', () => { it('should format the unlinked assistance awards count', () => { expect(row.unlinkedAssistance).toEqual('10,001'); }); - }); \ No newline at end of file + describe('missing counts', () => { + const missingCounts = { + ...mockReportingPeriodRow, + unlinked_contract_award_count: null, + unlinked_assistance_award_count: null + }; + const missingCountsRow = Object.create(CoreReportingRow); + missingCountsRow.populateCore(missingCounts); + it('should display -- if the unlinked contracts count is null', () => { + expect(missingCountsRow.unlinkedContracts).toEqual('--'); + }); + it('should display -- if the unlinked assistance awards count is null', () => { + expect(missingCountsRow.unlinkedAssistance).toEqual('--'); + }); + }); + describe('zero counts', () => { + const zeroCounts = { + ...mockReportingPeriodRow, + unlinked_contract_award_count: 0, + unlinked_assistance_award_count: 0 + }; + const zeroCountsRow = Object.create(CoreReportingRow); + zeroCountsRow.populateCore(zeroCounts); + it('should display -- if the unlinked contracts count is null', () => { + expect(zeroCountsRow.unlinkedContracts).toEqual('0'); + }); + it('should display -- if the unlinked assistance awards count is null', () => { + expect(zeroCountsRow.unlinkedAssistance).toEqual('0'); + }); + }); +}); From 82847d5910153420c03b0f98b3e8c03a74b5885e Mon Sep 17 00:00:00 2001 From: Jonathan Hill Date: Thu, 14 Jan 2021 15:18:15 -0500 Subject: [PATCH 11/69] dev-6481 integrate api with discrepancie modal --- .../modals/aboutTheData/_aboutTheData.scss | 1 - .../modals/MissingAccountBalanceContainer.jsx | 39 ++++---- src/js/dataMapping/aboutTheData/modals.js | 96 ------------------- src/js/helpers/aboutTheDataHelper.js | 2 +- .../MissingAccountBalanceContainer-test.jsx | 17 +++- tests/helpers/aboutTheDataHelper-test.js | 2 +- 6 files changed, 31 insertions(+), 126 deletions(-) diff --git a/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss b/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss index 47dc2a8f83..2737c52e2a 100644 --- a/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss +++ b/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss @@ -100,7 +100,6 @@ .usda-table__body { .usda-table__row { .usda-table__cell:not(:first-child) { - text-align: right; padding-right: rem(42); } } diff --git a/src/js/containers/aboutTheData/modals/MissingAccountBalanceContainer.jsx b/src/js/containers/aboutTheData/modals/MissingAccountBalanceContainer.jsx index 82f5a1f4b9..647b204dc4 100644 --- a/src/js/containers/aboutTheData/modals/MissingAccountBalanceContainer.jsx +++ b/src/js/containers/aboutTheData/modals/MissingAccountBalanceContainer.jsx @@ -7,20 +7,19 @@ import React, { useState, useEffect, useRef } from 'react'; import PropTypes from 'prop-types'; import { Table, Pagination } from 'data-transparency-ui'; import { isCancel } from 'axios'; -import { mockAPIMissingAccountBalances, missingAccountBalanceColumns } from 'dataMapping/aboutTheData/modals'; -import { formatMissingAccountBalancesData } from 'helpers/aboutTheDataHelper'; +import { missingAccountBalanceColumns } from 'dataMapping/aboutTheData/modals'; +import { formatMissingAccountBalancesData, fetchMissingAccountBalances } from 'helpers/aboutTheDataHelper'; const propTypes = { - agencyCode: PropTypes.string, - fiscalYear: PropTypes.string, - fiscalPeriod: PropTypes.string, - agencyData: PropTypes.object + agencyData: PropTypes.shape({ + gtasObligationTotal: PropTypes.number, + agencyCode: PropTypes.string, + fiscalYear: PropTypes.number, + fiscalPeriod: PropTypes.number + }) }; const MissingAccountBalanceContainer = ({ - agencyCode, - fiscalYear, - fiscalPeriod, agencyData }) => { const [sort, setSort] = useState('amount'); @@ -46,12 +45,11 @@ const MissingAccountBalanceContainer = ({ limit, sort, order, - agencyCode, - fiscalYear, - fiscalPeriod + fiscal_year: agencyData.fiscalYear, + fiscal_period: agencyData.fiscalPeriod }; try { - missingAccBalancesRequest.current = mockAPIMissingAccountBalances(params); + missingAccBalancesRequest.current = fetchMissingAccountBalances(agencyData.agencyCode, params); const { data } = await missingAccBalancesRequest.current.promise; setTotal(data.page_metadata.total); setRows(formatMissingAccountBalancesData({ results: data.results, gtasObligationTotal: agencyData.gtasObligationTotal })); @@ -59,10 +57,10 @@ const MissingAccountBalanceContainer = ({ missingAccBalancesRequest.current = null; } catch (e) { - console.error(e); if (!isCancel(e)) { setLoading(false); setError({ error: true, message: e.message }); + console.error(e); } missingAccBalancesRequest.current = null; } @@ -86,15 +84,10 @@ const MissingAccountBalanceContainer = ({ missingAccountBalancesRequest(); }, [page]); // do not show deadlines in column headers if we do not have the data - const columns = missingAccountBalanceColumns.map((column) => ({ - displayName: ( -
-
- {column.displayName} -
-
- ), - title: column.title + const columns = missingAccountBalanceColumns.map((column, i) => ({ + displayName: column.displayName, + title: column.title, + right: i !== 0 })); return ( diff --git a/src/js/dataMapping/aboutTheData/modals.js b/src/js/dataMapping/aboutTheData/modals.js index 07aca22e6b..b391cad552 100644 --- a/src/js/dataMapping/aboutTheData/modals.js +++ b/src/js/dataMapping/aboutTheData/modals.js @@ -33,99 +33,3 @@ export const reportingDifferencesColumns = [ { displayName: 'Account Spending Obligations', title: 'file_b_obligation' }, { displayName: 'Difference', title: 'difference' } ]; - -const mockDataMissingAccountBalances = [ - { - tas: "123-X-3409/3490-456", - amount: 12 - }, - { - tas: "123-X-3409", - amount: "2020-11-11T11:59:21Z" - }, - { - tas: "234-X-3409/45-456", - amount: 123 - }, - { - tas: "123-34-3409/324-456", - amount: 543 - }, - { - tas: "123-3434-3409", - amount: 789 - }, - { - tas: "123-X-35/22-456", - amount: 23 - }, - { - tas: "123-096-3409/22-456", - amount: 234 - }, - { - tas: "123-X-00/3490-456", - amount: 56 - }, - { - tas: "007-X-3409/3490-456", - amount: 754 - }, - { - tas: "008-X-3409/3490-456", - amount: 345 - }, - { - tas: "009-X-3409/3490-456", - amount: 765 - }, - { - tas: "200-X-3409/3490-456", - amount: 758 - }, - { - tas: "444-X-3409/3490-456", - amount: 234 - } -]; - -// TODO - delete this when API is integrated -export const mockAPIMissingAccountBalances = (params) => { - const pageMetaData = { - page: 1, - next: 2, - previous: 0, - hasNext: false, - hasPrevious: false, - total: 16, - limit: 10 - }; - pageMetaData.page = params.page; - pageMetaData.next = params.next; - pageMetaData.previous = params.page - 1; - pageMetaData.hasNext = params.page === 1; - pageMetaData.hasPrevious = params.page === 2; - pageMetaData.limite = params.limit; - - return { - promise: new Promise((resolve) => { - setTimeout(() => { - if (params.page === 1) { - const data = { - page_metadata: pageMetaData, - results: mockDataMissingAccountBalances.slice(0, params.limit) - }; - resolve({ data }); - } - else { - const data = { - page_metadata: pageMetaData, - results: mockDataMissingAccountBalances.slice(params.limit, params.limit * 2) - }; - resolve({ data }); - } - }, 1000); - }), - cancel: () => console.log(' :wave: ') - }; -}; diff --git a/src/js/helpers/aboutTheDataHelper.js b/src/js/helpers/aboutTheDataHelper.js index cbc52c9ddf..1a24fbab47 100644 --- a/src/js/helpers/aboutTheDataHelper.js +++ b/src/js/helpers/aboutTheDataHelper.js @@ -147,7 +147,7 @@ export const formatMissingAccountBalancesData = (data) => { return data.results.map((tasData) => { let amount = '--'; let percent = '--'; - if (typeof tasData.amount === 'number' && weHaveTotalData) percent = calculatePercentage(tasData.amount, data.gtasObligationTotal); + if (typeof tasData.amount === 'number' && weHaveTotalData) percent = calculatePercentage(tasData.amount, data.gtasObligationTotal, null, 2); if (typeof tasData.amount === 'number') amount = formatMoney(tasData.amount); return [tasData.tas, amount, percent]; }); diff --git a/tests/containers/aboutTheData/MissingAccountBalanceContainer-test.jsx b/tests/containers/aboutTheData/MissingAccountBalanceContainer-test.jsx index f7ecb0fde2..2b3bd80674 100644 --- a/tests/containers/aboutTheData/MissingAccountBalanceContainer-test.jsx +++ b/tests/containers/aboutTheData/MissingAccountBalanceContainer-test.jsx @@ -1,11 +1,15 @@ import React from 'react'; -import { render, screen } from 'test-utils'; +import { render, screen, waitFor } from 'test-utils'; +import * as aboutTheDataHelper from 'helpers/aboutTheDataHelper'; import MissingAccountBalanceContainer from 'containers/aboutTheData/modals/MissingAccountBalanceContainer'; const defaultProps = { - fiscalYear: 2020, - fiscalPeriod: 8, - agencyCode: '020' + agencyData: { + fiscalYear: 2020, + fiscalPeriod: 8, + agencyCode: '020', + gtasObligationTotal: 1011010 + } }; describe('Missing Account Balance Container', () => { @@ -15,4 +19,9 @@ describe('Missing Account Balance Container', () => { expect(screen.queryByText('Obligated Amount')).toBeTruthy(); expect(screen.queryByText('% of Agency Total in GTAS')).toBeTruthy(); }); + it('should call the api one time on mount', () => { + const pubicationDatesRequest = jest.spyOn(aboutTheDataHelper, 'fetchPublishDates'); + render(); + waitFor(() => expect(pubicationDatesRequest).toHaveBeenCalledTimes(1)); + }); }); diff --git a/tests/helpers/aboutTheDataHelper-test.js b/tests/helpers/aboutTheDataHelper-test.js index d4fc76c835..8e4f0b52c2 100644 --- a/tests/helpers/aboutTheDataHelper-test.js +++ b/tests/helpers/aboutTheDataHelper-test.js @@ -89,7 +89,7 @@ describe('About The Data Helper', () => { it('should handle percent and money formatting', () => { const data = formatMissingAccountBalancesData(mockBalanceData); expect(data[0][1]).toBe('$2,323'); - expect(data[0][2]).toBe('5.2%'); + expect(data[0][2]).toBe('5.16%'); expect(data[1][1]).toBe('$0'); expect(data[1][2]).toBe('0.0%'); }); From f521fc7d970975bcdc5354ec76c4bec5a73658f1 Mon Sep 17 00:00:00 2001 From: Jonathan Hill Date: Thu, 14 Jan 2021 15:39:39 -0500 Subject: [PATCH 12/69] udpate test --- tests/helpers/aboutTheDataHelper-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/helpers/aboutTheDataHelper-test.js b/tests/helpers/aboutTheDataHelper-test.js index 8e4f0b52c2..8eab16ce96 100644 --- a/tests/helpers/aboutTheDataHelper-test.js +++ b/tests/helpers/aboutTheDataHelper-test.js @@ -91,7 +91,7 @@ describe('About The Data Helper', () => { expect(data[0][1]).toBe('$2,323'); expect(data[0][2]).toBe('5.16%'); expect(data[1][1]).toBe('$0'); - expect(data[1][2]).toBe('0.0%'); + expect(data[1][2]).toBe('0.00%'); }); }); describe('showQuarterText', () => { From 65b4b0445f2129456709074890e5de2dc8f19ac7 Mon Sep 17 00:00:00 2001 From: Jonathan Hill Date: Wed, 13 Jan 2021 14:24:51 -0500 Subject: [PATCH 13/69] updates loading message text to be centered inline with viz --- src/_scss/pages/modals/aboutTheData/_aboutTheData.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss b/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss index edfdbaa6ce..2f8802a3cb 100644 --- a/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss +++ b/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss @@ -64,6 +64,11 @@ tr { td { border: none; + .usda-loading-animation__container { + .loading-message { + text-align: center; + } + } } } font-size: rem(12); From 2833b74a4b2c8be315e8709a519ce71355ff498e Mon Sep 17 00:00:00 2001 From: Lizzie Salita Date: Fri, 15 Jan 2021 11:30:33 -0500 Subject: [PATCH 14/69] Removed unnecessary logic for null counts --- .../v2/aboutTheData/CoreReportingRow.js | 10 ++----- .../aboutTheData/CoreReportingRow-test.js | 30 ------------------- 2 files changed, 2 insertions(+), 38 deletions(-) diff --git a/src/js/models/v2/aboutTheData/CoreReportingRow.js b/src/js/models/v2/aboutTheData/CoreReportingRow.js index 79bf1928e2..2c83b119ba 100644 --- a/src/js/models/v2/aboutTheData/CoreReportingRow.js +++ b/src/js/models/v2/aboutTheData/CoreReportingRow.js @@ -15,8 +15,8 @@ const CoreReportingRow = { this._discrepancyCount = data.tas_account_discrepancies_totals?.missing_tas_accounts_count || 0; /* eslint-enable camelcase */ this._obligationDifference = data.obligation_difference || 0; - this._unlinkedContracts = data.unlinked_contract_award_count; - this._unlinkedAssistance = data.unlinked_assistance_award_count; + this._unlinkedContracts = data.unlinked_contract_award_count || 0; + this._unlinkedAssistance = data.unlinked_assistance_award_count || 0; this.assuranceStatement = data.assurance_statement_url || ''; }, get budgetAuthority() { @@ -32,15 +32,9 @@ const CoreReportingRow = { return formatNumber(this._discrepancyCount); }, get unlinkedContracts() { - if (!this._unlinkedContracts && this._unlinkedContracts !== 0) { - return '--'; - } return formatNumber(this._unlinkedContracts); }, get unlinkedAssistance() { - if (!this._unlinkedAssistance && this._unlinkedAssistance !== 0) { - return '--'; - } return formatNumber(this._unlinkedAssistance); } }; diff --git a/tests/models/aboutTheData/CoreReportingRow-test.js b/tests/models/aboutTheData/CoreReportingRow-test.js index 082900454a..ab12edf52a 100644 --- a/tests/models/aboutTheData/CoreReportingRow-test.js +++ b/tests/models/aboutTheData/CoreReportingRow-test.js @@ -31,34 +31,4 @@ describe('Core Reporting Row model', () => { it('should format the unlinked assistance awards count', () => { expect(row.unlinkedAssistance).toEqual('10,001'); }); - describe('missing counts', () => { - const missingCounts = { - ...mockReportingPeriodRow, - unlinked_contract_award_count: null, - unlinked_assistance_award_count: null - }; - const missingCountsRow = Object.create(CoreReportingRow); - missingCountsRow.populateCore(missingCounts); - it('should display -- if the unlinked contracts count is null', () => { - expect(missingCountsRow.unlinkedContracts).toEqual('--'); - }); - it('should display -- if the unlinked assistance awards count is null', () => { - expect(missingCountsRow.unlinkedAssistance).toEqual('--'); - }); - }); - describe('zero counts', () => { - const zeroCounts = { - ...mockReportingPeriodRow, - unlinked_contract_award_count: 0, - unlinked_assistance_award_count: 0 - }; - const zeroCountsRow = Object.create(CoreReportingRow); - zeroCountsRow.populateCore(zeroCounts); - it('should display -- if the unlinked contracts count is null', () => { - expect(zeroCountsRow.unlinkedContracts).toEqual('0'); - }); - it('should display -- if the unlinked assistance awards count is null', () => { - expect(zeroCountsRow.unlinkedAssistance).toEqual('0'); - }); - }); }); From 06b5ecb7a3b3d61f631a29958d04c5de2d2ec8ec Mon Sep 17 00:00:00 2001 From: Lizzie Salita Date: Fri, 15 Jan 2021 13:44:53 -0500 Subject: [PATCH 15/69] Moved mock API data to /tests; added tests for percentage --- .../aboutTheData/AgencyTableMapping.jsx | 339 ------------------ .../models/v2/aboutTheData/BaseAgencyRow.js | 4 +- .../aboutTheData/AboutTheDataPage-test.jsx | 2 +- .../aboutTheData/AgenciesContainer-test.jsx | 4 +- tests/containers/aboutTheData/mockData.js | 337 +++++++++++++++++ .../models/aboutTheData/BaseAgencyRow-test.js | 42 ++- .../PublicationOverviewRow-test.js | 3 +- 7 files changed, 382 insertions(+), 349 deletions(-) create mode 100644 tests/containers/aboutTheData/mockData.js diff --git a/src/js/containers/aboutTheData/AgencyTableMapping.jsx b/src/js/containers/aboutTheData/AgencyTableMapping.jsx index 9146e59530..6f57e26a11 100644 --- a/src/js/containers/aboutTheData/AgencyTableMapping.jsx +++ b/src/js/containers/aboutTheData/AgencyTableMapping.jsx @@ -114,342 +114,3 @@ export const agenciesTableColumns = { } ] }; - -// TODO - move under tests/ dir once API integration is complete. -export const mockAPI = { - totals: { - data: { - results: [ - { - total_budgetary_resources: 8361447130497.72, - fiscal_year: 2020, - fiscal_period: 6 - }, - { - total_budgetary_resources: 234525.72, - fiscal_year: 2020, - fiscal_period: 5 - } - ] - } - }, - publications: { - data: { - page_metadata: { - page: 1, - hasNext: false, - limit: 10, - hasPrevious: false, - total: 2 - }, - results: [ - { - agency_name: "Department of Health and Human Services", - abbreviation: "DHHS", - agency_code: "020", - current_total_budget_authority_amount: 8361447130497.72, - periods: [ - { - period: 2, - quarter: 1, - submission_dates: { - publication_date: "2020-01-20T11:59:21Z", - certification_date: "2020-01-21T10:58:21Z" - }, - quarterly: false - } - ] - }, - { - agency_name: "Department of Treasury", - abbreviation: "DOT", - agency_code: "021", - current_total_budget_authority_amount: 8361447130497.72, - periods: [ - { - period: 1, - quarter: 1, - submission_dates: { - publication_date: "2020-01-20T11:59:21Z", - certification_date: "2020-01-21T10:58:21Z" - }, - quarterly: true - }, - { - period: 2, - quarter: 1, - submission_dates: { - publication_date: "2020-01-20T11:59:21Z", - certification_date: "2020-01-21T10:58:21Z" - }, - quarterly: true - }, - { - period: 3, - quarter: 1, - submission_dates: { - publication_date: "2020-01-20T11:59:21Z", - certification_date: "2020-01-21T10:58:21Z" - }, - quarterly: false - }, - { - period: 4, - quarter: 2, - submission_dates: { - publication_date: "2020-01-20T11:59:21Z", - certification_date: "2020-01-21T10:58:21Z" - }, - quarterly: false - }, - { - period: 5, - quarter: 2, - submission_dates: { - publication_date: "2020-01-20T11:59:21Z", - certification_date: "2020-01-21T10:58:21Z" - }, - quarterly: false - }, - { - period: 6, - quarter: 2, - submission_dates: { - publication_date: "2020-01-20T11:59:21Z", - certification_date: "2020-01-21T10:58:21Z" - }, - quarterly: false - }, - { - period: 7, - quarter: 3, - submission_dates: { - publication_date: "2020-01-20T11:59:21Z", - certification_date: "2020-01-21T10:58:21Z" - }, - quarterly: false - }, - { - period: 8, - quarter: 3, - submission_dates: { - publication_date: "2020-01-20T11:59:21Z", - certification_date: "2020-01-21T10:58:21Z" - }, - quarterly: false - }, - { - period: 9, - quarter: 3, - submission_dates: { - publication_date: "2020-01-20T11:59:21Z", - certification_date: "2025-01-21T10:58:21Z" - }, - quarterly: false - }, - { - period: 10, - quarter: 4, - submission_dates: { - publication_date: null, - certification_date: null - }, - quarterly: false - }, - { - period: 11, - quarter: 4, - submission_dates: { - publication_date: null, - certification_date: null - }, - quarterly: false - }, - { - period: 12, - quarter: 4, - submission_dates: { - publication_date: null, - certification_date: null - }, - quarterly: false - } - ] - } - ] - } - }, - submissions: { - data: { - page_metadata: { - page: 1, - hasNext: false, - hasPrevious: false, - limit: 10, - total: 2 - }, - results: [ - { - agency_name: "Department of Health and Human Services", - abbreviation: "DHHS", - agency_code: "020", - agency_id: 123, - current_total_budget_authority_amount: 8361447130497.72, - recent_publication_date: "2020-01-10T11:59:21Z", - recent_publication_date_certified: false, - tas_account_discrepancies_totals: { - gtas_obligation_total: 55234, - tas_accounts_total: 23923, - tas_obligation_not_in_gtas_total: 343345, - missing_tas_accounts_count: 20 - }, - obligation_difference: 436376232652.87 - }, - { - agency_name: "Department of Treasury", - abbreviation: "DOT", - agency_code: "021", - agency_id: 789, - current_total_budget_authority_amount: 8361447130497.72, - recent_publication_date: null, - recent_publication_date_certified: true, - tas_account_discrepancies_totals: { - gtas_obligation_total: 66432, - tas_accounts_total: 23913, - tas_obligation_not_in_gtas_total: 11543, - missing_tas_accounts_count: 10 - }, - obligation_difference: 436376232652.87 - }, - { - agency_name: "Department of Treasury", - abbreviation: "DOT", - agency_code: "021", - agency_id: 789, - current_total_budget_authority_amount: 8361447130497.72, - recent_publication_date: null, - recent_publication_date_certified: true, - tas_account_discrepancies_totals: { - gtas_obligation_total: 66432, - tas_accounts_total: 23913, - tas_obligation_not_in_gtas_total: 11543, - missing_tas_accounts_count: 10 - }, - obligation_difference: 436376232652.87 - }, - { - agency_name: "Department of Treasury", - abbreviation: "DOT", - agency_code: "021", - agency_id: 789, - current_total_budget_authority_amount: 8361447130497.72, - recent_publication_date: null, - recent_publication_date_certified: true, - tas_account_discrepancies_totals: { - gtas_obligation_total: 66432, - tas_accounts_total: 23913, - tas_obligation_not_in_gtas_total: 11543, - missing_tas_accounts_count: 10 - }, - obligation_difference: 436376232652.87 - }, - { - agency_name: "Department of Treasury", - abbreviation: "DOT", - agency_code: "021", - agency_id: 789, - current_total_budget_authority_amount: 8361447130497.72, - recent_publication_date: null, - recent_publication_date_certified: true, - tas_account_discrepancies_totals: { - gtas_obligation_total: 66432, - tas_accounts_total: 23913, - tas_obligation_not_in_gtas_total: 11543, - missing_tas_accounts_count: 10 - }, - obligation_difference: 436376232652.87 - }, - { - agency_name: "Department of Treasury", - abbreviation: "DOT", - agency_code: "021", - agency_id: 789, - current_total_budget_authority_amount: 8361447130497.72, - recent_publication_date: null, - recent_publication_date_certified: true, - tas_account_discrepancies_totals: { - gtas_obligation_total: 66432, - tas_accounts_total: 23913, - tas_obligation_not_in_gtas_total: 11543, - missing_tas_accounts_count: 10 - }, - obligation_difference: 436376232652.87 - }, - { - agency_name: "Department of Treasury", - abbreviation: "DOT", - agency_code: "021", - agency_id: 789, - current_total_budget_authority_amount: 8361447130497.72, - recent_publication_date: null, - recent_publication_date_certified: true, - tas_account_discrepancies_totals: { - gtas_obligation_total: 66432, - tas_accounts_total: 23913, - tas_obligation_not_in_gtas_total: 11543, - missing_tas_accounts_count: 10 - }, - obligation_difference: 436376232652.87 - }, - { - agency_name: "Department of Treasury", - abbreviation: "DOT", - agency_code: "021", - agency_id: 789, - current_total_budget_authority_amount: 8361447130497.72, - recent_publication_date: null, - recent_publication_date_certified: true, - tas_account_discrepancies_totals: { - gtas_obligation_total: 66432, - tas_accounts_total: 23913, - tas_obligation_not_in_gtas_total: 11543, - missing_tas_accounts_count: 10 - }, - obligation_difference: 436376232652.87 - }, - { - agency_name: "Department of Treasury", - abbreviation: "DOT", - agency_code: "021", - agency_id: 789, - current_total_budget_authority_amount: 8361447130497.72, - recent_publication_date: null, - recent_publication_date_certified: true, - tas_account_discrepancies_totals: { - gtas_obligation_total: 66432, - tas_accounts_total: 23913, - tas_obligation_not_in_gtas_total: 11543, - missing_tas_accounts_count: 10 - }, - obligation_difference: 436376232652.87 - }, - { - agency_name: "Department of Treasury", - abbreviation: "DOT", - agency_code: "021", - agency_id: 789, - current_total_budget_authority_amount: 8361447130497.72, - recent_publication_date: null, - recent_publication_date_certified: true, - tas_account_discrepancies_totals: { - gtas_obligation_total: 66432, - tas_accounts_total: 23913, - tas_obligation_not_in_gtas_total: 11543, - missing_tas_accounts_count: 10 - }, - obligation_difference: 436376232652.87 - } - ] - } - } -}; diff --git a/src/js/models/v2/aboutTheData/BaseAgencyRow.js b/src/js/models/v2/aboutTheData/BaseAgencyRow.js index 90f148f342..ee0b8caf1a 100644 --- a/src/js/models/v2/aboutTheData/BaseAgencyRow.js +++ b/src/js/models/v2/aboutTheData/BaseAgencyRow.js @@ -18,8 +18,8 @@ BaseAgencyRow.populate = function populate(data) { : this._name; this.certified = data.recent_publication_date_certified || false; // eslint-disable-next-line camelcase - this._federalTotal = data.federalTotal?.total_budgetary_resources; - this.percentageOfTotalFederalBudget = calculatePercentage(this._budgetAuthority, this._federalTotal, 2); + this._federalTotal = data?.federalTotal?.total_budgetary_resources; + this.percentageOfTotalFederalBudget = calculatePercentage(this._budgetAuthority, this._federalTotal, '--', 2); }; export default BaseAgencyRow; diff --git a/tests/components/aboutTheData/AboutTheDataPage-test.jsx b/tests/components/aboutTheData/AboutTheDataPage-test.jsx index 3f704a4f01..121d9ea66e 100644 --- a/tests/components/aboutTheData/AboutTheDataPage-test.jsx +++ b/tests/components/aboutTheData/AboutTheDataPage-test.jsx @@ -8,7 +8,7 @@ import * as accountHelpers from 'helpers/accountHelper'; import * as helpers from "containers/account/WithLatestFy"; import * as glossaryHelpers from 'helpers/glossaryHelper'; import * as aboutTheDataHelpers from 'helpers/aboutTheDataHelper'; -import { mockAPI } from 'containers/aboutTheData/AgencyTableMapping'; +import { mockAPI } from '../../containers/aboutTheData/mockData'; import { mockSubmissions } from '../../mockData/helpers/aboutTheDataHelper'; // latest fy of 2020; latest period is 12 diff --git a/tests/containers/aboutTheData/AgenciesContainer-test.jsx b/tests/containers/aboutTheData/AgenciesContainer-test.jsx index e98072d31c..8da0634fd4 100644 --- a/tests/containers/aboutTheData/AgenciesContainer-test.jsx +++ b/tests/containers/aboutTheData/AgenciesContainer-test.jsx @@ -1,12 +1,12 @@ import React from 'react'; -import { render, screen, waitFor } from 'test-utils'; +import { render, waitFor } from 'test-utils'; import * as redux from 'react-redux'; import { List } from 'immutable'; import * as aboutTheDataHelper from 'helpers/aboutTheDataHelper'; import AgenciesContainer from 'containers/aboutTheData/AgenciesContainer'; -import { mockAPI } from 'containers/aboutTheData/AgencyTableMapping'; +import { mockAPI } from './mockData'; const defaultProps = { selectedFy: '2020', diff --git a/tests/containers/aboutTheData/mockData.js b/tests/containers/aboutTheData/mockData.js new file mode 100644 index 0000000000..77137406df --- /dev/null +++ b/tests/containers/aboutTheData/mockData.js @@ -0,0 +1,337 @@ +export const mockAPI = { + totals: { + data: { + results: [ + { + total_budgetary_resources: 8361447130497.72, + fiscal_year: 2020, + fiscal_period: 6 + }, + { + total_budgetary_resources: 234525.72, + fiscal_year: 2020, + fiscal_period: 5 + } + ] + } + }, + publications: { + data: { + page_metadata: { + page: 1, + hasNext: false, + limit: 10, + hasPrevious: false, + total: 2 + }, + results: [ + { + agency_name: "Department of Health and Human Services", + abbreviation: "DHHS", + agency_code: "020", + current_total_budget_authority_amount: 8361447130497.72, + periods: [ + { + period: 2, + quarter: 1, + submission_dates: { + publication_date: "2020-01-20T11:59:21Z", + certification_date: "2020-01-21T10:58:21Z" + }, + quarterly: false + } + ] + }, + { + agency_name: "Department of Treasury", + abbreviation: "DOT", + agency_code: "021", + current_total_budget_authority_amount: 8361447130497.72, + periods: [ + { + period: 1, + quarter: 1, + submission_dates: { + publication_date: "2020-01-20T11:59:21Z", + certification_date: "2020-01-21T10:58:21Z" + }, + quarterly: true + }, + { + period: 2, + quarter: 1, + submission_dates: { + publication_date: "2020-01-20T11:59:21Z", + certification_date: "2020-01-21T10:58:21Z" + }, + quarterly: true + }, + { + period: 3, + quarter: 1, + submission_dates: { + publication_date: "2020-01-20T11:59:21Z", + certification_date: "2020-01-21T10:58:21Z" + }, + quarterly: false + }, + { + period: 4, + quarter: 2, + submission_dates: { + publication_date: "2020-01-20T11:59:21Z", + certification_date: "2020-01-21T10:58:21Z" + }, + quarterly: false + }, + { + period: 5, + quarter: 2, + submission_dates: { + publication_date: "2020-01-20T11:59:21Z", + certification_date: "2020-01-21T10:58:21Z" + }, + quarterly: false + }, + { + period: 6, + quarter: 2, + submission_dates: { + publication_date: "2020-01-20T11:59:21Z", + certification_date: "2020-01-21T10:58:21Z" + }, + quarterly: false + }, + { + period: 7, + quarter: 3, + submission_dates: { + publication_date: "2020-01-20T11:59:21Z", + certification_date: "2020-01-21T10:58:21Z" + }, + quarterly: false + }, + { + period: 8, + quarter: 3, + submission_dates: { + publication_date: "2020-01-20T11:59:21Z", + certification_date: "2020-01-21T10:58:21Z" + }, + quarterly: false + }, + { + period: 9, + quarter: 3, + submission_dates: { + publication_date: "2020-01-20T11:59:21Z", + certification_date: "2025-01-21T10:58:21Z" + }, + quarterly: false + }, + { + period: 10, + quarter: 4, + submission_dates: { + publication_date: null, + certification_date: null + }, + quarterly: false + }, + { + period: 11, + quarter: 4, + submission_dates: { + publication_date: null, + certification_date: null + }, + quarterly: false + }, + { + period: 12, + quarter: 4, + submission_dates: { + publication_date: null, + certification_date: null + }, + quarterly: false + } + ] + } + ] + } + }, + submissions: { + data: { + page_metadata: { + page: 1, + hasNext: false, + hasPrevious: false, + limit: 10, + total: 2 + }, + results: [ + { + agency_name: "Department of Health and Human Services", + abbreviation: "DHHS", + agency_code: "020", + agency_id: 123, + current_total_budget_authority_amount: 8361447130497.72, + recent_publication_date: "2020-01-10T11:59:21Z", + recent_publication_date_certified: false, + tas_account_discrepancies_totals: { + gtas_obligation_total: 55234, + tas_accounts_total: 23923, + tas_obligation_not_in_gtas_total: 343345, + missing_tas_accounts_count: 20 + }, + obligation_difference: 436376232652.87 + }, + { + agency_name: "Department of Treasury", + abbreviation: "DOT", + agency_code: "021", + agency_id: 789, + current_total_budget_authority_amount: 8361447130497.72, + recent_publication_date: null, + recent_publication_date_certified: true, + tas_account_discrepancies_totals: { + gtas_obligation_total: 66432, + tas_accounts_total: 23913, + tas_obligation_not_in_gtas_total: 11543, + missing_tas_accounts_count: 10 + }, + obligation_difference: 436376232652.87 + }, + { + agency_name: "Department of Treasury", + abbreviation: "DOT", + agency_code: "021", + agency_id: 789, + current_total_budget_authority_amount: 8361447130497.72, + recent_publication_date: null, + recent_publication_date_certified: true, + tas_account_discrepancies_totals: { + gtas_obligation_total: 66432, + tas_accounts_total: 23913, + tas_obligation_not_in_gtas_total: 11543, + missing_tas_accounts_count: 10 + }, + obligation_difference: 436376232652.87 + }, + { + agency_name: "Department of Treasury", + abbreviation: "DOT", + agency_code: "021", + agency_id: 789, + current_total_budget_authority_amount: 8361447130497.72, + recent_publication_date: null, + recent_publication_date_certified: true, + tas_account_discrepancies_totals: { + gtas_obligation_total: 66432, + tas_accounts_total: 23913, + tas_obligation_not_in_gtas_total: 11543, + missing_tas_accounts_count: 10 + }, + obligation_difference: 436376232652.87 + }, + { + agency_name: "Department of Treasury", + abbreviation: "DOT", + agency_code: "021", + agency_id: 789, + current_total_budget_authority_amount: 8361447130497.72, + recent_publication_date: null, + recent_publication_date_certified: true, + tas_account_discrepancies_totals: { + gtas_obligation_total: 66432, + tas_accounts_total: 23913, + tas_obligation_not_in_gtas_total: 11543, + missing_tas_accounts_count: 10 + }, + obligation_difference: 436376232652.87 + }, + { + agency_name: "Department of Treasury", + abbreviation: "DOT", + agency_code: "021", + agency_id: 789, + current_total_budget_authority_amount: 8361447130497.72, + recent_publication_date: null, + recent_publication_date_certified: true, + tas_account_discrepancies_totals: { + gtas_obligation_total: 66432, + tas_accounts_total: 23913, + tas_obligation_not_in_gtas_total: 11543, + missing_tas_accounts_count: 10 + }, + obligation_difference: 436376232652.87 + }, + { + agency_name: "Department of Treasury", + abbreviation: "DOT", + agency_code: "021", + agency_id: 789, + current_total_budget_authority_amount: 8361447130497.72, + recent_publication_date: null, + recent_publication_date_certified: true, + tas_account_discrepancies_totals: { + gtas_obligation_total: 66432, + tas_accounts_total: 23913, + tas_obligation_not_in_gtas_total: 11543, + missing_tas_accounts_count: 10 + }, + obligation_difference: 436376232652.87 + }, + { + agency_name: "Department of Treasury", + abbreviation: "DOT", + agency_code: "021", + agency_id: 789, + current_total_budget_authority_amount: 8361447130497.72, + recent_publication_date: null, + recent_publication_date_certified: true, + tas_account_discrepancies_totals: { + gtas_obligation_total: 66432, + tas_accounts_total: 23913, + tas_obligation_not_in_gtas_total: 11543, + missing_tas_accounts_count: 10 + }, + obligation_difference: 436376232652.87 + }, + { + agency_name: "Department of Treasury", + abbreviation: "DOT", + agency_code: "021", + agency_id: 789, + current_total_budget_authority_amount: 8361447130497.72, + recent_publication_date: null, + recent_publication_date_certified: true, + tas_account_discrepancies_totals: { + gtas_obligation_total: 66432, + tas_accounts_total: 23913, + tas_obligation_not_in_gtas_total: 11543, + missing_tas_accounts_count: 10 + }, + obligation_difference: 436376232652.87 + }, + { + agency_name: "Department of Treasury", + abbreviation: "DOT", + agency_code: "021", + agency_id: 789, + current_total_budget_authority_amount: 8361447130497.72, + recent_publication_date: null, + recent_publication_date_certified: true, + tas_account_discrepancies_totals: { + gtas_obligation_total: 66432, + tas_accounts_total: 23913, + tas_obligation_not_in_gtas_total: 11543, + missing_tas_accounts_count: 10 + }, + obligation_difference: 436376232652.87 + } + ] + } + } +}; diff --git a/tests/models/aboutTheData/BaseAgencyRow-test.js b/tests/models/aboutTheData/BaseAgencyRow-test.js index c666abf3bc..a30ae1d56a 100644 --- a/tests/models/aboutTheData/BaseAgencyRow-test.js +++ b/tests/models/aboutTheData/BaseAgencyRow-test.js @@ -5,10 +5,28 @@ import BaseAgencyRow from 'models/v2/aboutTheData/BaseAgencyRow'; import CoreReportingRow from 'models/v2/aboutTheData/CoreReportingRow'; -import { mockAPI } from 'containers/aboutTheData/AgencyTableMapping'; -// TODO - update when API contracts are finalized -const mockAgencyRow = { ...mockAPI.submissions.data.results[0] }; +const mockAgencyRow = { + agency_name: "Department of Health and Human Services", + abbreviation: "DHHS", + agency_code: "020", + agency_id: 123, + current_total_budget_authority_amount: 8361.72, + recent_publication_date: "2020-01-10T11:59:21Z", + recent_publication_date_certified: false, + tas_account_discrepancies_totals: { + gtas_obligation_total: 55234, + tas_accounts_total: 23923, + tas_obligation_not_in_gtas_total: 343345, + missing_tas_accounts_count: 20 + }, + obligation_difference: 436376232652.87, + federalTotal: { + fiscal_year: 2018, + fiscal_period: 3, + total_budgetary_resources: 10000 + } +}; const agencyRow = Object.create(BaseAgencyRow); agencyRow.populate(mockAgencyRow); @@ -26,6 +44,24 @@ describe('BaseAgencyRow', () => { agencyRowMod.populate(missingAbbrev); expect(agencyRowMod.name).toEqual('Department of Health and Human Services'); }); + describe('percentage of total federal budget', () => { + it('should calculate and format the percent of the federal budget', () => { + expect(agencyRow._federalTotal).toEqual(10000); + expect(agencyRow._budgetAuthority).toEqual(8361.72); + expect(agencyRow.percentageOfTotalFederalBudget).toEqual('83.62%'); + }); + it('should display -- if the percent cannot be computed', () => { + const missingFederalBudget = { + ...mockAgencyRow, + federalTotal: { + total_budgetary_resources: 0 + } + }; + const agencyMissingBudget = Object.create(BaseAgencyRow); + agencyMissingBudget.populate(missingFederalBudget); + expect(agencyMissingBudget.percentageOfTotalFederalBudget).toEqual('--'); + }); + }); it('should have CoreReportingRow in its prototype chain', () => { expect(Object.getPrototypeOf(agencyRow)).toMatchObject(CoreReportingRow); }); diff --git a/tests/models/aboutTheData/PublicationOverviewRow-test.js b/tests/models/aboutTheData/PublicationOverviewRow-test.js index cb9b9b18a6..028429e686 100644 --- a/tests/models/aboutTheData/PublicationOverviewRow-test.js +++ b/tests/models/aboutTheData/PublicationOverviewRow-test.js @@ -4,9 +4,8 @@ */ import PublicationOverviewRow from 'models/v2/aboutTheData/PublicationOverviewRow'; -import { mockAPI } from 'containers/aboutTheData/AgencyTableMapping'; +import { mockAPI } from '../../containers/aboutTheData/mockData'; -// TODO - update when API contracts are finalized const mockRow = mockAPI.publications.data.results[0]; const mockTotals = mockAPI.totals.data.results; From ac80c20ce218133120bc1425aac05bbaafdb994a Mon Sep 17 00:00:00 2001 From: Lizzie Salita Date: Fri, 15 Jan 2021 14:45:41 -0500 Subject: [PATCH 16/69] simplified mock data --- .../v2/aboutTheData/PublicationOverviewRow.js | 2 +- tests/containers/aboutTheData/mockData.js | 261 ++---------------- .../models/aboutTheData/BaseAgencyRow-test.js | 26 +- .../BaseReportingPeriodRow-test.js | 13 +- .../aboutTheData/CoreReportingRow-test.js | 12 +- .../PublicationOverviewRow-test.js | 7 +- 6 files changed, 55 insertions(+), 266 deletions(-) diff --git a/src/js/models/v2/aboutTheData/PublicationOverviewRow.js b/src/js/models/v2/aboutTheData/PublicationOverviewRow.js index 20449da077..a95aecbba9 100644 --- a/src/js/models/v2/aboutTheData/PublicationOverviewRow.js +++ b/src/js/models/v2/aboutTheData/PublicationOverviewRow.js @@ -63,7 +63,7 @@ const DatesRow = { }, get percentageOfTotalFederalBudget() { // eslint-disable-next-line camelcase - return calculatePercentage(this._budgetAuthority, this._federalTotal, "N/A for Time (try FY 2020 P06)", 2); + return calculatePercentage(this._budgetAuthority, this._federalTotal, "--", 2); } }; diff --git a/tests/containers/aboutTheData/mockData.js b/tests/containers/aboutTheData/mockData.js index 77137406df..51bee9edf4 100644 --- a/tests/containers/aboutTheData/mockData.js +++ b/tests/containers/aboutTheData/mockData.js @@ -3,12 +3,12 @@ export const mockAPI = { data: { results: [ { - total_budgetary_resources: 8361447130497.72, + total_budgetary_resources: 8000.72, fiscal_year: 2020, fiscal_period: 6 }, { - total_budgetary_resources: 234525.72, + total_budgetary_resources: 4000.00, fiscal_year: 2020, fiscal_period: 5 } @@ -26,10 +26,10 @@ export const mockAPI = { }, results: [ { - agency_name: "Department of Health and Human Services", - abbreviation: "DHHS", + agency_name: "Mock Agency", + abbreviation: "ABC", agency_code: "020", - current_total_budget_authority_amount: 8361447130497.72, + current_total_budget_authority_amount: 8000.72, periods: [ { period: 2, @@ -43,10 +43,10 @@ export const mockAPI = { ] }, { - agency_name: "Department of Treasury", - abbreviation: "DOT", - agency_code: "021", - current_total_budget_authority_amount: 8361447130497.72, + agency_name: "Mock Agency", + abbreviation: "ABC", + agency_code: "123", + current_total_budget_authority_amount: 8000.72, periods: [ { period: 1, @@ -66,87 +66,6 @@ export const mockAPI = { }, quarterly: true }, - { - period: 3, - quarter: 1, - submission_dates: { - publication_date: "2020-01-20T11:59:21Z", - certification_date: "2020-01-21T10:58:21Z" - }, - quarterly: false - }, - { - period: 4, - quarter: 2, - submission_dates: { - publication_date: "2020-01-20T11:59:21Z", - certification_date: "2020-01-21T10:58:21Z" - }, - quarterly: false - }, - { - period: 5, - quarter: 2, - submission_dates: { - publication_date: "2020-01-20T11:59:21Z", - certification_date: "2020-01-21T10:58:21Z" - }, - quarterly: false - }, - { - period: 6, - quarter: 2, - submission_dates: { - publication_date: "2020-01-20T11:59:21Z", - certification_date: "2020-01-21T10:58:21Z" - }, - quarterly: false - }, - { - period: 7, - quarter: 3, - submission_dates: { - publication_date: "2020-01-20T11:59:21Z", - certification_date: "2020-01-21T10:58:21Z" - }, - quarterly: false - }, - { - period: 8, - quarter: 3, - submission_dates: { - publication_date: "2020-01-20T11:59:21Z", - certification_date: "2020-01-21T10:58:21Z" - }, - quarterly: false - }, - { - period: 9, - quarter: 3, - submission_dates: { - publication_date: "2020-01-20T11:59:21Z", - certification_date: "2025-01-21T10:58:21Z" - }, - quarterly: false - }, - { - period: 10, - quarter: 4, - submission_dates: { - publication_date: null, - certification_date: null - }, - quarterly: false - }, - { - period: 11, - quarter: 4, - submission_dates: { - publication_date: null, - certification_date: null - }, - quarterly: false - }, { period: 12, quarter: 4, @@ -172,164 +91,42 @@ export const mockAPI = { }, results: [ { - agency_name: "Department of Health and Human Services", - abbreviation: "DHHS", - agency_code: "020", + agency_name: "Mock Agency", + abbreviation: "ABC", + agency_code: "123", agency_id: 123, - current_total_budget_authority_amount: 8361447130497.72, + current_total_budget_authority_amount: 8000.72, recent_publication_date: "2020-01-10T11:59:21Z", recent_publication_date_certified: false, tas_account_discrepancies_totals: { - gtas_obligation_total: 55234, + gtas_obligation_total: 50000, tas_accounts_total: 23923, tas_obligation_not_in_gtas_total: 343345, - missing_tas_accounts_count: 20 - }, - obligation_difference: 436376232652.87 - }, - { - agency_name: "Department of Treasury", - abbreviation: "DOT", - agency_code: "021", - agency_id: 789, - current_total_budget_authority_amount: 8361447130497.72, - recent_publication_date: null, - recent_publication_date_certified: true, - tas_account_discrepancies_totals: { - gtas_obligation_total: 66432, - tas_accounts_total: 23913, - tas_obligation_not_in_gtas_total: 11543, - missing_tas_accounts_count: 10 - }, - obligation_difference: 436376232652.87 - }, - { - agency_name: "Department of Treasury", - abbreviation: "DOT", - agency_code: "021", - agency_id: 789, - current_total_budget_authority_amount: 8361447130497.72, - recent_publication_date: null, - recent_publication_date_certified: true, - tas_account_discrepancies_totals: { - gtas_obligation_total: 66432, - tas_accounts_total: 23913, - tas_obligation_not_in_gtas_total: 11543, - missing_tas_accounts_count: 10 - }, - obligation_difference: 436376232652.87 - }, - { - agency_name: "Department of Treasury", - abbreviation: "DOT", - agency_code: "021", - agency_id: 789, - current_total_budget_authority_amount: 8361447130497.72, - recent_publication_date: null, - recent_publication_date_certified: true, - tas_account_discrepancies_totals: { - gtas_obligation_total: 66432, - tas_accounts_total: 23913, - tas_obligation_not_in_gtas_total: 11543, - missing_tas_accounts_count: 10 - }, - obligation_difference: 436376232652.87 - }, - { - agency_name: "Department of Treasury", - abbreviation: "DOT", - agency_code: "021", - agency_id: 789, - current_total_budget_authority_amount: 8361447130497.72, - recent_publication_date: null, - recent_publication_date_certified: true, - tas_account_discrepancies_totals: { - gtas_obligation_total: 66432, - tas_accounts_total: 23913, - tas_obligation_not_in_gtas_total: 11543, - missing_tas_accounts_count: 10 - }, - obligation_difference: 436376232652.87 - }, - { - agency_name: "Department of Treasury", - abbreviation: "DOT", - agency_code: "021", - agency_id: 789, - current_total_budget_authority_amount: 8361447130497.72, - recent_publication_date: null, - recent_publication_date_certified: true, - tas_account_discrepancies_totals: { - gtas_obligation_total: 66432, - tas_accounts_total: 23913, - tas_obligation_not_in_gtas_total: 11543, - missing_tas_accounts_count: 10 - }, - obligation_difference: 436376232652.87 - }, - { - agency_name: "Department of Treasury", - abbreviation: "DOT", - agency_code: "021", - agency_id: 789, - current_total_budget_authority_amount: 8361447130497.72, - recent_publication_date: null, - recent_publication_date_certified: true, - tas_account_discrepancies_totals: { - gtas_obligation_total: 66432, - tas_accounts_total: 23913, - tas_obligation_not_in_gtas_total: 11543, - missing_tas_accounts_count: 10 - }, - obligation_difference: 436376232652.87 - }, - { - agency_name: "Department of Treasury", - abbreviation: "DOT", - agency_code: "021", - agency_id: 789, - current_total_budget_authority_amount: 8361447130497.72, - recent_publication_date: null, - recent_publication_date_certified: true, - tas_account_discrepancies_totals: { - gtas_obligation_total: 66432, - tas_accounts_total: 23913, - tas_obligation_not_in_gtas_total: 11543, - missing_tas_accounts_count: 10 - }, - obligation_difference: 436376232652.87 - }, - { - agency_name: "Department of Treasury", - abbreviation: "DOT", - agency_code: "021", - agency_id: 789, - current_total_budget_authority_amount: 8361447130497.72, - recent_publication_date: null, - recent_publication_date_certified: true, - tas_account_discrepancies_totals: { - gtas_obligation_total: 66432, - tas_accounts_total: 23913, - tas_obligation_not_in_gtas_total: 11543, - missing_tas_accounts_count: 10 + missing_tas_accounts_count: 2000 }, - obligation_difference: 436376232652.87 + obligation_difference: 4000.00, + unlinked_contract_award_count: 20002, + unlinked_assistance_award_count: 10001, + assurance_statement_url: 'https://files.usaspending.gov/agency_submissions/Raw%20DATA%20Act%20Files/2020/Q1/MockAgency(ABC)-Assurance_Statement.txt' }, { - agency_name: "Department of Treasury", - abbreviation: "DOT", - agency_code: "021", + agency_name: "Mock Agency 2", + abbreviation: "XYZ", + agency_code: "456", agency_id: 789, - current_total_budget_authority_amount: 8361447130497.72, + current_total_budget_authority_amount: 8000.72, recent_publication_date: null, recent_publication_date_certified: true, tas_account_discrepancies_totals: { - gtas_obligation_total: 66432, + gtas_obligation_total: 60000, tas_accounts_total: 23913, tas_obligation_not_in_gtas_total: 11543, - missing_tas_accounts_count: 10 + missing_tas_accounts_count: 1000 }, - obligation_difference: 436376232652.87 + obligation_difference: 4000.00, + unlinked_contract_award_count: 20002, + unlinked_assistance_award_count: 10001, + assurance_statement_url: 'https://files.usaspending.gov/agency_submissions/Raw%20DATA%20Act%20Files/2020/Q1/MockAgency(ABC)-Assurance_Statement.txt' } ] } diff --git a/tests/models/aboutTheData/BaseAgencyRow-test.js b/tests/models/aboutTheData/BaseAgencyRow-test.js index a30ae1d56a..e4e4ea5f1e 100644 --- a/tests/models/aboutTheData/BaseAgencyRow-test.js +++ b/tests/models/aboutTheData/BaseAgencyRow-test.js @@ -5,25 +5,11 @@ import BaseAgencyRow from 'models/v2/aboutTheData/BaseAgencyRow'; import CoreReportingRow from 'models/v2/aboutTheData/CoreReportingRow'; +import { mockAPI } from '../../containers/aboutTheData/mockData'; const mockAgencyRow = { - agency_name: "Department of Health and Human Services", - abbreviation: "DHHS", - agency_code: "020", - agency_id: 123, - current_total_budget_authority_amount: 8361.72, - recent_publication_date: "2020-01-10T11:59:21Z", - recent_publication_date_certified: false, - tas_account_discrepancies_totals: { - gtas_obligation_total: 55234, - tas_accounts_total: 23923, - tas_obligation_not_in_gtas_total: 343345, - missing_tas_accounts_count: 20 - }, - obligation_difference: 436376232652.87, + ...mockAPI.submissions.data.results[0], federalTotal: { - fiscal_year: 2018, - fiscal_period: 3, total_budgetary_resources: 10000 } }; @@ -33,7 +19,7 @@ agencyRow.populate(mockAgencyRow); describe('BaseAgencyRow', () => { it('should format the agency name', () => { - expect(agencyRow.name).toEqual('Department of Health and Human Services (DHHS)'); + expect(agencyRow.name).toEqual('Mock Agency (ABC)'); }); it('should handle an agency with no abbreviation', () => { const missingAbbrev = { @@ -42,13 +28,13 @@ describe('BaseAgencyRow', () => { }; const agencyRowMod = Object.create(BaseAgencyRow); agencyRowMod.populate(missingAbbrev); - expect(agencyRowMod.name).toEqual('Department of Health and Human Services'); + expect(agencyRowMod.name).toEqual('Mock Agency'); }); describe('percentage of total federal budget', () => { it('should calculate and format the percent of the federal budget', () => { expect(agencyRow._federalTotal).toEqual(10000); - expect(agencyRow._budgetAuthority).toEqual(8361.72); - expect(agencyRow.percentageOfTotalFederalBudget).toEqual('83.62%'); + expect(agencyRow._budgetAuthority).toEqual(8000.72); + expect(agencyRow.percentageOfTotalFederalBudget).toEqual('80.01%'); }); it('should display -- if the percent cannot be computed', () => { const missingFederalBudget = { diff --git a/tests/models/aboutTheData/BaseReportingPeriodRow-test.js b/tests/models/aboutTheData/BaseReportingPeriodRow-test.js index 8003ec3454..af42fd266c 100644 --- a/tests/models/aboutTheData/BaseReportingPeriodRow-test.js +++ b/tests/models/aboutTheData/BaseReportingPeriodRow-test.js @@ -9,17 +9,20 @@ import CoreReportingRow from 'models/v2/aboutTheData/CoreReportingRow'; export const mockReportingPeriodRow = { fiscal_year: 2020, fiscal_period: 12, - current_total_budget_authority_amount: 8361447130497.72, + current_total_budget_authority_amount: 8000.72, recent_publication_date: "2020-01-10T11:59:21Z", + recent_publication_date_certified: false, tas_account_discrepancies_totals: { - missing_tas_accounts_count: 1000, - gtas_obligation_total: 234567 + gtas_obligation_total: 55234, + tas_accounts_total: 23923, + tas_obligation_not_in_gtas_total: 343345, + missing_tas_accounts_count: 20 }, percent_of_total_budgetary_resources: 2.189, - obligation_difference: 436376232652.87, + obligation_difference: 4000.00, unlinked_contract_award_count: 20002, unlinked_assistance_award_count: 10001, - assurance_statement_url: 'https://files.usaspending.gov/agency_submissions/Raw%20DATA%20Act%20Files/2020/Q1/097%20-%20Department%20of%20Defense%20(DOD)/2020-Q1-097_Department%20of%20Defense%20(DOD)-Assurance_Statement.txt' + assurance_statement_url: 'https://files.usaspending.gov/agency_submissions/Raw%20DATA%20Act%20Files/2020/Q1/MockAgency(ABC)-Assurance_Statement.txt' }; const reportingPeriodRow = Object.create(BaseReportingPeriodRow); diff --git a/tests/models/aboutTheData/CoreReportingRow-test.js b/tests/models/aboutTheData/CoreReportingRow-test.js index ab12edf52a..c5158e59a8 100644 --- a/tests/models/aboutTheData/CoreReportingRow-test.js +++ b/tests/models/aboutTheData/CoreReportingRow-test.js @@ -4,26 +4,28 @@ */ import CoreReportingRow from 'models/v2/aboutTheData/CoreReportingRow'; -import { mockReportingPeriodRow } from './BaseReportingPeriodRow-test'; +import { mockAPI } from '../../containers/aboutTheData/mockData'; + +const mockReportingPeriodRow = mockAPI.submissions.data.results[0]; const row = Object.create(CoreReportingRow); row.populateCore(mockReportingPeriodRow); describe('Core Reporting Row model', () => { it('should format the budget authority', () => { - expect(row.budgetAuthority).toEqual('$8,361,447,130,497.72'); + expect(row.budgetAuthority).toEqual('$8,000.72'); }); it('should format the obligation difference', () => { - expect(row.obligationDifference).toEqual('$436,376,232,652.87'); + expect(row.obligationDifference).toEqual('$4,000.00'); }); it('should format the discrepancy count', () => { - expect(row.discrepancyCount).toEqual('1,000'); + expect(row.discrepancyCount).toEqual('2,000'); }); it('should format the publication date', () => { expect(row.mostRecentPublicationDate).toEqual('01/10/2020'); }); it('should store the raw GTAS Obligation Total', () => { - expect(row._gtasObligationTotal).toEqual(234567); + expect(row._gtasObligationTotal).toEqual(50000); }); it('should format the unlinked contracts count', () => { expect(row.unlinkedContracts).toEqual('20,002'); diff --git a/tests/models/aboutTheData/PublicationOverviewRow-test.js b/tests/models/aboutTheData/PublicationOverviewRow-test.js index 028429e686..f32a7b6983 100644 --- a/tests/models/aboutTheData/PublicationOverviewRow-test.js +++ b/tests/models/aboutTheData/PublicationOverviewRow-test.js @@ -13,7 +13,7 @@ const mockDatesRow = Object.create(PublicationOverviewRow); mockDatesRow.populate(2020, mockRow, mockTotals); test('should format the agency name', () => { - expect(mockDatesRow.name).toEqual('Department of Health and Human Services (DHHS)'); + expect(mockDatesRow.name).toEqual('Mock Agency (ABC)'); }); test('should handle an agency with no abbreviation', () => { @@ -23,11 +23,12 @@ test('should handle an agency with no abbreviation', () => { }; const mockDatesRowMod = Object.create(mockDatesRow); mockDatesRowMod.populate('2020', missingAbbrev, mockTotals); - expect(mockDatesRowMod.name).toEqual('Department of Health and Human Services'); + expect(mockDatesRowMod.name).toEqual('Mock Agency'); }); test('should format the percent of total federal budget', () => { - expect(mockDatesRow.percentageOfTotalFederalBudget).toEqual('100.00%'); + // 8000.72 / 1200.72 + expect(mockDatesRow.percentageOfTotalFederalBudget).toEqual('66.67%'); }); test('should always have 12 periods', () => { From 47be2b9a9f8015983e89ebaea9cd3088db339de3 Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Fri, 15 Jan 2021 15:29:25 -0500 Subject: [PATCH 17/69] [DEV-6464] consolidating styles --- src/_scss/components/_stickyTable.scss | 135 +++++++++++++++++ .../pages/aboutTheData/agenciesPage.scss | 136 +----------------- .../pages/aboutTheData/agencyDetailsPage.scss | 88 +----------- 3 files changed, 143 insertions(+), 216 deletions(-) create mode 100644 src/_scss/components/_stickyTable.scss diff --git a/src/_scss/components/_stickyTable.scss b/src/_scss/components/_stickyTable.scss new file mode 100644 index 0000000000..3130927a1d --- /dev/null +++ b/src/_scss/components/_stickyTable.scss @@ -0,0 +1,135 @@ +.table-container { + height: rem(500); + overflow: scroll; + margin: 0; + border: rem(1) solid $color-gray-border; + .usda-table.usda-table-w-grid { + border-collapse: separate; + margin-top:0; + margin-bottom:0; + &.table-loading { + height: 100%; + } + thead { + tr th { + min-width: rem(300); + } + .nested-header { + .table-header__content { + padding: 1rem 0; + } + } + } + tbody { + .loading-message { + text-align: center; + } + .usda-table__row { + height: 4.8rem; + .usda-table__cell { + font-size: 1.4rem; + padding: 0; // to allow entire cell to be hoverable + @import './actionCell'; + @include flex-wrap(no-wrap); + .generic-cell-content { + padding: 1.2rem; + .not-certified { + margin-left: rem(5); + background: #DCE4EE; + border-radius: rem(2); + color: $color-base; + padding: rem(5); + font-size: rem(10); + font-weight: $font-semibold; + line-height: rem(13); + } + } + .matched-str { + font-weight: 600; + text-decoration: underline; + } + } + } + } + &.sticky-y-table { + @media(min-width: $medium-screen) { + thead { + tr th { + position: sticky; + position: -webkit-sticky; + top: 0; + z-index: 9; + border: rem(1) solid $color-gray-lighter; + // Set a higher z-index on the
the user is hovering over so + // tooltips display above the stacking context of the other headers + &:hover { + z-index: 10; + } + } + tr:last-of-type th { + top: rem(57); + border: rem(1) solid $color-gray-lighter; + } + } + } + } + &.sticky-x-table { + @media(min-width: $medium-screen) { + thead { + tr:first-of-type { + .table-header:first-of-type { + position: sticky; + position: -webkit-sticky; + left: 0px; + z-index: 11; + box-shadow: 2px 1px 4px rgba(0,0,0,.20); + border-right: 1px solid $color-gray-lightest; + } + } + } + tbody { + .usda-table__row .usda-table__cell { + &:first-of-type { + position: sticky; + position: -webkit-sticky; + z-index: 10; + left: 0px; + box-shadow: 2px 1px 4px rgba(0,0,0,.20); + border-right: rem(1) solid $color-gray-lightest; + } + } + } + } + } + &.table-loading .usda-table__body tr td { + border: none; + } + } +} +// Pagination +.usa-dt-pagination { + padding: rem(20); + .usa-dt-pagination__totals { + text-align: center; + padding: rem(20); // extra padding on mobile + @media(min-width: $tablet-screen) { + text-align: left; + padding: rem(0); + } + } + .usa-dt-pagination__wrapper { + @include justify-content(center); // center on mobile + @media(min-width: $tablet-screen) { + @include justify-content(flex-end); + } + .pager { + padding: rem(20); // extra padding on mobile + @media(min-width: $tablet-screen) { + padding: 0; + } + .pager__item { + margin: 0; + } + } + } +} \ No newline at end of file diff --git a/src/_scss/pages/aboutTheData/agenciesPage.scss b/src/_scss/pages/aboutTheData/agenciesPage.scss index fbdd91779e..cb94317a1e 100644 --- a/src/_scss/pages/aboutTheData/agenciesPage.scss +++ b/src/_scss/pages/aboutTheData/agenciesPage.scss @@ -246,141 +246,7 @@ max-width: rem(500); } } - .table-container { - height: rem(500); - overflow: scroll; - margin: 0; - border: rem(1) solid $color-gray-border; - .usda-table.usda-table-w-grid { - border-collapse: separate; - margin-top:0; - margin-bottom:0; - &.table-loading { - height: 100%; - } - thead { - tr th { - min-width: rem(300); - } - .nested-header { - .table-header__content { - padding: 1rem 0; - } - } - } - tbody { - .loading-message { - text-align: center; - } - .usda-table__row { - height: 4.8rem; - .usda-table__cell { - font-size: 1.4rem; - padding: 0; // to allow entire cell to be hoverable - @import './actionCell'; - @include flex-wrap(no-wrap); - .generic-cell-content { - padding: 1.2rem; - .not-certified { - margin-left: rem(5); - background: #DCE4EE; - border-radius: rem(2); - color: $color-base; - padding: rem(5); - font-size: rem(10); - font-weight: $font-semibold; - line-height: rem(13); - } - } - .matched-str { - font-weight: 600; - text-decoration: underline; - } - } - } - } - &.sticky-y-table { - @media(min-width: $medium-screen) { - thead { - tr th { - position: sticky; - position: -webkit-sticky; - top: 0; - z-index: 9; - border: rem(1) solid $color-gray-lighter; - // Set a higher z-index on the the user is hovering over so - // tooltips display above the stacking context of the other headers - &:hover { - z-index: 10; - } - } - tr:last-of-type th { - top: rem(57); - border: rem(1) solid $color-gray-lighter; - } - } - } - } - &.sticky-x-table { - @media(min-width: $medium-screen) { - thead { - tr:first-of-type { - .table-header:first-of-type { - position: sticky; - position: -webkit-sticky; - left: 0px; - z-index: 11; - box-shadow: 2px 1px 4px rgba(0,0,0,.20); - border-right: 1px solid $color-gray-lightest; - } - } - } - tbody { - .usda-table__row .usda-table__cell { - &:first-of-type { - position: sticky; - position: -webkit-sticky; - z-index: 10; - left: 0px; - box-shadow: 2px 1px 4px rgba(0,0,0,.20); - border-right: rem(1) solid $color-gray-lightest; - } - } - } - } - } - &.table-loading .usda-table__body tr td { - border: none; - } - } - } - // Pagination - .usa-dt-pagination { - padding: rem(20); - .usa-dt-pagination__totals { - text-align: center; - padding: rem(20); // extra padding on mobile - @media(min-width: $tablet-screen) { - text-align: left; - padding: rem(0); - } - } - .usa-dt-pagination__wrapper { - @include justify-content(center); // center on mobile - @media(min-width: $tablet-screen) { - @include justify-content(flex-end); - } - .pager { - padding: rem(20); // extra padding on mobile - @media(min-width: $tablet-screen) { - padding: 0; - } - .pager__item { - margin: 0; - } - } - } - } + @import 'components/stickyTable'; @import 'components/Note'; .default-note { font-style: italic; diff --git a/src/_scss/pages/aboutTheData/agencyDetailsPage.scss b/src/_scss/pages/aboutTheData/agencyDetailsPage.scss index 7b27787b69..d6820aa697 100644 --- a/src/_scss/pages/aboutTheData/agencyDetailsPage.scss +++ b/src/_scss/pages/aboutTheData/agencyDetailsPage.scss @@ -1,4 +1,4 @@ -.usa-da__about-the-data__agencies-page { +.usa-da__about-the-data__agency-details-page { @import "all"; @import "layouts/default/default"; @import "layouts/default/stickyHeader/header"; @@ -35,88 +35,14 @@ } } } - .table-container { - overflow-x: scroll; - overflow-y: default; - border: rem(1) solid $color-gray-border; - .usda-table.usda-table-w-grid { - border-collapse: separate; - margin: 0; - thead { - tr th { - min-width: rem(300); - } - .nested-header { - .table-header__content { - padding: 1rem 0; - } - } - } - tbody { - .usda-table__row { - height: 4.8rem; - .usda-table__cell { - &:nth-of-type(2) { - // center-align the percentage column - text-align: center; - } - font-size: 1.4rem; - padding: 0; // to allow entire cell to be hoverable - @import './actionCell'; - .generic-cell-content { - padding: 1.2rem; - } - } - } - } - &.sticky-y-table { - @media(min-width: $medium-screen) { - thead { - th { - position: sticky; - position: -webkit-sticky; - z-index: 9; - top: 0; - border: rem(1) solid $color-gray-lighter; - // Set a higher z-index on the the user is hovering over so - // tooltips display above the stacking context of the other headers - &:hover { - z-index: 10; - } - } - } - } - } - &.sticky-x-table { - @media(min-width: $medium-screen) { - thead { - tr:first-of-type { - .table-header:first-of-type { - position: sticky; - position: -webkit-sticky; - left: 0px; - z-index: 11; - box-shadow: 2px 1px 4px rgba(0,0,0,.20); - border-right: 1px solid $color-gray-lightest; - } - } - } - tbody { - .usda-table__row .usda-table__cell { - &:first-of-type { - position: sticky; - position: -webkit-sticky; - z-index: 10; - left: 0px; - box-shadow: 2px 1px 4px rgba(0,0,0,.20); - border-right: rem(1) solid $color-gray-lightest; - } - } - } - } + @import 'components/stickyTable'; + .table-container .usda-table.usda-table-w-grid tbody .usda-table__row { + .usda-table__cell:nth-of-type(2) { + // center-align the percentage column + padding: 0; // to allow entire cell to be hoverable + text-align: center; } } - } .agency-table-download { svg { From 653d0ff093adf4e0f0b10af322b85ba9fd956ae2 Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Fri, 15 Jan 2021 15:29:55 -0500 Subject: [PATCH 18/69] [DEV-6464] new class namespace for AgencyDetailsPg --- src/js/components/aboutTheData/AgencyDetailsPage.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/components/aboutTheData/AgencyDetailsPage.jsx b/src/js/components/aboutTheData/AgencyDetailsPage.jsx index f5aebf55b3..cb83af60dc 100644 --- a/src/js/components/aboutTheData/AgencyDetailsPage.jsx +++ b/src/js/components/aboutTheData/AgencyDetailsPage.jsx @@ -78,7 +78,7 @@ const AgencyDetailsPage = () => { }, [agencyCode]); return ( -
+
From c1cc856f3568e61658e3f63da29bcf37586557c7 Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Fri, 15 Jan 2021 15:31:47 -0500 Subject: [PATCH 19/69] [DEV-6464] fixing bug w/ period dropdown - generatePeriods was expecting JS array, was getting an immutable list. This is a bug leftover from a hotfix (PR #2322) --- src/js/components/aboutTheData/TimeFilters.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/components/aboutTheData/TimeFilters.jsx b/src/js/components/aboutTheData/TimeFilters.jsx index 63af93ffba..5bfd09052a 100644 --- a/src/js/components/aboutTheData/TimeFilters.jsx +++ b/src/js/components/aboutTheData/TimeFilters.jsx @@ -118,7 +118,7 @@ const TimePeriodFilters = ({ }, [submissionPeriods, urlFy, urlPeriod, latestPeriod, latestFy]); const generatePeriodDropdown = (fy, periods) => ( - parsePeriods(fy, periods) + parsePeriods(fy, periods.toJS()) .map((p) => ({ ...p, component: p.component, From 1a7d97687388aef5589bd3490d3432253c7b6a48 Mon Sep 17 00:00:00 2001 From: Jonathan Hill Date: Fri, 15 Jan 2021 15:57:28 -0500 Subject: [PATCH 20/69] dev-6539 add unlinked data modals --- .../modals/aboutTheData/_aboutTheData.scss | 36 +++++++++ .../aboutTheData/AboutTheDataPage.jsx | 2 +- .../aboutTheData/AgencyDetailsPage.jsx | 2 +- .../components/aboutTheData/CellWithModal.jsx | 4 +- .../modals/modalContentMapping.jsx | 4 +- .../aboutTheData/AgenciesContainer.jsx | 24 +++++- .../aboutTheData/AgencyDetailsContainer.jsx | 24 +++++- .../modals/UnlinkedDataContainer.jsx | 78 +++++++++++++++++++ src/js/dataMapping/aboutTheData/modals.js | 17 +++- src/js/helpers/aboutTheDataHelper.js | 38 +++++++++ .../ReportingDifferencesContainer-test.jsx | 2 +- .../UnlinkedDataContainer-test.jsx | 20 +++++ 12 files changed, 237 insertions(+), 14 deletions(-) create mode 100644 src/js/containers/aboutTheData/modals/UnlinkedDataContainer.jsx create mode 100644 tests/containers/aboutTheData/UnlinkedDataContainer-test.jsx diff --git a/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss b/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss index 2f8802a3cb..6f701af72b 100644 --- a/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss +++ b/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss @@ -158,4 +158,40 @@ } } } + // unlinked data modal + &.unlinked-data-modal { + @include media($tablet-screen) { + max-width: rem(699); + + } + @include media($large-screen) { + max-width: rem(699); + min-width: rem(699); + } + .usa-dt-modal__section { + .usda-table { + margin-bottom: 0; + .usda-table__head { + border-bottom: none; + .usda-table__row { + .table-header { + padding-top: 0; + } + .table-header:not(:first-child) { + border-bottom: solid rem(1) $color-gray-light; + } + } + } + .usda-table__body { + .usda-table__row { + .table-header { + text-align: right; + border: none; + padding-left: 0; + } + } + } + } + } + } } diff --git a/src/js/components/aboutTheData/AboutTheDataPage.jsx b/src/js/components/aboutTheData/AboutTheDataPage.jsx index 161d2b6957..5232dddb3e 100644 --- a/src/js/components/aboutTheData/AboutTheDataPage.jsx +++ b/src/js/components/aboutTheData/AboutTheDataPage.jsx @@ -150,7 +150,7 @@ const AboutTheDataPage = ({ mounted={!!showModal.length} type={showModal} className={modalClassNames[showModal]} - title={modalTitles[showModal]} + title={modalTitles(modalData?.type)[showModal]} agencyData={{ ...modalData, fiscalYear: parseInt(selectedFy, 10), diff --git a/src/js/components/aboutTheData/AgencyDetailsPage.jsx b/src/js/components/aboutTheData/AgencyDetailsPage.jsx index f5aebf55b3..c93a164a19 100644 --- a/src/js/components/aboutTheData/AgencyDetailsPage.jsx +++ b/src/js/components/aboutTheData/AgencyDetailsPage.jsx @@ -132,7 +132,7 @@ const AgencyDetailsPage = () => { mounted={!!showModal.length} type={showModal} className={modalClassNames[showModal]} - title={modalTitles[showModal]} + title={modalTitles(modalData?.type)[showModal]} agencyData={modalData} closeModal={closeModal} totalObligationsNotInGTAS={45999} /> diff --git a/src/js/components/aboutTheData/CellWithModal.jsx b/src/js/components/aboutTheData/CellWithModal.jsx index 630301c3ef..0941032251 100644 --- a/src/js/components/aboutTheData/CellWithModal.jsx +++ b/src/js/components/aboutTheData/CellWithModal.jsx @@ -8,9 +8,9 @@ import PropTypes, { oneOfType, oneOf } from 'prop-types'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; const propTypes = { - data: oneOfType([PropTypes.string, PropTypes.object]), + data: oneOfType([PropTypes.string, PropTypes.object, PropTypes.number]), openModal: PropTypes.func.isRequired, - modalType: oneOf(['publicationDates', 'missingAccountBalance', 'reportingDifferences']).isRequired, + modalType: oneOf(['publicationDates', 'missingAccountBalance', 'reportingDifferences', 'unlinkedData']).isRequired, agencyData: PropTypes.object }; diff --git a/src/js/components/aboutTheData/dataMapping/modals/modalContentMapping.jsx b/src/js/components/aboutTheData/dataMapping/modals/modalContentMapping.jsx index 4cd777f08d..013f9bd0d1 100644 --- a/src/js/components/aboutTheData/dataMapping/modals/modalContentMapping.jsx +++ b/src/js/components/aboutTheData/dataMapping/modals/modalContentMapping.jsx @@ -2,9 +2,11 @@ import React from 'react'; import PublicationDatesContainer from 'containers/aboutTheData/modals/PublicationDatesContainer'; import MissingAccountBalanceContainer from 'containers/aboutTheData/modals/MissingAccountBalanceContainer'; import ReportingDifferencesContainer from 'containers/aboutTheData/modals/ReportingDifferencesContainer'; +import UnlinkedDataContainer from 'containers/aboutTheData/modals/UnlinkedDataContainer'; export const modalContentMapping = (data) => ({ publicationDates: (), missingAccountBalance: (), - reportingDifferences: () + reportingDifferences: (), + unlinkedData: () }); diff --git a/src/js/containers/aboutTheData/AgenciesContainer.jsx b/src/js/containers/aboutTheData/AgenciesContainer.jsx index 391404252c..3e26c9da7a 100644 --- a/src/js/containers/aboutTheData/AgenciesContainer.jsx +++ b/src/js/containers/aboutTheData/AgenciesContainer.jsx @@ -263,8 +263,28 @@ const AgenciesContainer = ({ fiscalYear: selectedFy, fiscalPeriod: selectedPeriod?.id }} />), - (
{unlinkedContractAwards}
), - (
{unlinkedAssistanceAwards}
) + (), + () ]); const handlePageChange = (page) => { diff --git a/src/js/containers/aboutTheData/AgencyDetailsContainer.jsx b/src/js/containers/aboutTheData/AgencyDetailsContainer.jsx index a5f0e36cfd..c2a2c2671e 100644 --- a/src/js/containers/aboutTheData/AgencyDetailsContainer.jsx +++ b/src/js/containers/aboutTheData/AgencyDetailsContainer.jsx @@ -155,8 +155,28 @@ const AgencyDetailsContainer = ({ agencyName, agencyCode }} />), - (
{rowData.unlinkedContracts}
), - (
{rowData.unlinkedAssistance}
), + (), + (), (
) ]); }) diff --git a/src/js/containers/aboutTheData/modals/UnlinkedDataContainer.jsx b/src/js/containers/aboutTheData/modals/UnlinkedDataContainer.jsx new file mode 100644 index 0000000000..a74f012bc6 --- /dev/null +++ b/src/js/containers/aboutTheData/modals/UnlinkedDataContainer.jsx @@ -0,0 +1,78 @@ +/** + * UnlinkedDataContainer.jsx + * Created by Jonathan Hill 01/15/21 + */ + +import React, { useState, useEffect, useRef } from 'react'; +import PropTypes from 'prop-types'; +import { Table } from 'data-transparency-ui'; +import { isCancel } from 'axios'; +import { unlinkedDataColumns } from 'dataMapping/aboutTheData/modals'; +import { formatUnlinkedDataRows, fetchMockUnlinkedData } from 'helpers/aboutTheDataHelper'; + +const propTypes = { + agencyData: PropTypes.shape({ + agencyName: PropTypes.string, + agencyCode: PropTypes.string, + fiscalYear: PropTypes.number, + fiscalPeriod: PropTypes.number, + type: PropTypes.string + }) +}; + +const UnlinkedDataContainer = ({ agencyData }) => { + const [loading, setLoading] = useState(true); + const [error, setError] = useState({ error: false, message: '' }); + const [rows, setRows] = useState([]); + const unlinkedDataReq = useRef(null); + + const unlinkedDataRequest = async () => { + if (error.error) setError({ error: false, message: '' }); + if (!loading) setLoading(true); + if (unlinkedDataReq.current) unlinkedDataReq.current.cancel(); + try { + unlinkedDataReq.current = fetchMockUnlinkedData( + agencyData.agencyCode, + agencyData.fiscalYear, + agencyData.fiscalPeriod, + agencyData.type === 'Contract' ? 'procurement' : 'assistance' + ); + const res = await unlinkedDataReq.current.promise; + setRows(formatUnlinkedDataRows(res, agencyData.type)); + setLoading(false); + unlinkedDataReq.current = null; + } + catch (e) { + if (!isCancel(e)) { + setLoading(false); + setError({ error: true, message: e.message }); + console.error(e); + } + unlinkedDataReq.current = null; + } + }; + useEffect(() => { + unlinkedDataRequest(); + return () => { + if (unlinkedDataReq.current) unlinkedDataReq.current.cancel(); + }; + }, []); + const columns = unlinkedDataColumns(agencyData.type).map((column, i) => ({ + displayName: column.displayName, + title: '', + right: true, + header: i === 0 + })); + + return ( + + ); +}; + +UnlinkedDataContainer.propTypes = propTypes; +export default UnlinkedDataContainer; diff --git a/src/js/dataMapping/aboutTheData/modals.js b/src/js/dataMapping/aboutTheData/modals.js index 07aca22e6b..697819637d 100644 --- a/src/js/dataMapping/aboutTheData/modals.js +++ b/src/js/dataMapping/aboutTheData/modals.js @@ -4,16 +4,18 @@ */ -export const modalTitles = { +export const modalTitles = (type) => ({ publicationDates: 'Publication and Certification History', missingAccountBalance: 'Number of TASs Missing from Account Balance Data', - reportingDifferences: 'Reporting Difference in Obligations' -}; + reportingDifferences: 'Reporting Difference in Obligations', + unlinkedData: `Number of Unlinked ${type} Awards` +}); export const modalClassNames = { publicationDates: 'publication-dates-modal', missingAccountBalance: 'missing-account-balance-modal', - reportingDifferences: 'reporting-differences-modal' + reportingDifferences: 'reporting-differences-modal', + unlinkedData: 'unlinked-data-modal' }; export const publicationDatesColumns = [ @@ -34,6 +36,13 @@ export const reportingDifferencesColumns = [ { displayName: 'Difference', title: 'difference' } ]; +export const unlinkedDataColumns = (type) => ([ + { displayName: '' }, + { displayName: `Unlinked ${type} Awards in ${type === 'Contract' ? type : 'Financial Assistance'} Data` }, + { displayName: `Unlinked ${type} Awards in Award Spending Breakdown Data` }, + { displayName: 'Total' } +]); + const mockDataMissingAccountBalances = [ { tas: "123-X-3409/3490-456", diff --git a/src/js/helpers/aboutTheDataHelper.js b/src/js/helpers/aboutTheDataHelper.js index cbc52c9ddf..23b30f8a88 100644 --- a/src/js/helpers/aboutTheDataHelper.js +++ b/src/js/helpers/aboutTheDataHelper.js @@ -122,6 +122,24 @@ export const fetchAgency = (agencyCode, params) => apiRequest({ url: `v2/reporting/agencies/${agencyCode}/overview/?${stringify(params)}` }); +export const fetchUnlinkedData = ( + agencyCode, + fiscalYear, + fiscalPeriod, + type +) => apiRequest({ + url: `v2/reporting/agencies/${agencyCode}/${fiscalYear}/${fiscalPeriod}/unlinked_awards/?type=${type}` +}); + +export const fetchMockUnlinkedData = () => ({ + promise: new Promise((resolve) => resolve({ + unlinked_file_c_award_count: 123213, + unlinked_file_d_award_count: 43543, + total_linkable_file_c_award_count: 12321312, + total_linkable_file_d_award_count: 23987443892 + })) +}); + export const dateFormattedMonthDayYear = (date) => { if (!date) return null; const newDate = new Date(date); @@ -171,4 +189,24 @@ export const convertDatesToMilliseconds = (data) => data.map((datesObj) => { return { publication_date: publicationDate.getTime(), certification_date: certificationDate.getTime() }; }); +export const formatUnlinkedDataRows = (data, type) => ([ + [ + { displayName: 'Count', title: '', rowSpan: '0' }, + data.unlinked_file_c_award_count, + data.unlinked_file_d_award_count, + data.unlinked_file_c_award_count + data.unlinked_file_d_award_count + ], + [ + { displayName: `as a Percentage of All ${type} Awards`, title: '', rowSpan: '0' }, + calculatePercentage(data.unlinked_file_c_award_count, data.total_linkable_file_c_award_count, null, 2), + calculatePercentage(data.unlinked_file_d_award_count, data.total_linkable_file_d_award_count, null, 2), + calculatePercentage( + data.unlinked_file_c_award_count + data.unlinked_file_d_award_count, + data.total_linkable_file_c_award_count + data.total_linkable_file_d_award_count, + null, + 2 + ) + ] +]); + export const showQuarterText = (period) => [3, 6, 9, 12].includes(period); diff --git a/tests/containers/aboutTheData/ReportingDifferencesContainer-test.jsx b/tests/containers/aboutTheData/ReportingDifferencesContainer-test.jsx index 9bea9a19d9..ae2abd3c01 100644 --- a/tests/containers/aboutTheData/ReportingDifferencesContainer-test.jsx +++ b/tests/containers/aboutTheData/ReportingDifferencesContainer-test.jsx @@ -11,7 +11,7 @@ const defaultProps = { } }; -describe('Publication Dates Container', () => { +describe('Reporting Differences Container', () => { it('should call api one time on mount', () => { const differencesRequest = jest.spyOn(aboutTheDataHelper, 'fetchReportingDifferences'); render(); diff --git a/tests/containers/aboutTheData/UnlinkedDataContainer-test.jsx b/tests/containers/aboutTheData/UnlinkedDataContainer-test.jsx new file mode 100644 index 0000000000..43faae4dca --- /dev/null +++ b/tests/containers/aboutTheData/UnlinkedDataContainer-test.jsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { render, waitFor } from 'test-utils'; +import * as aboutTheDataHelper from 'helpers/aboutTheDataHelper'; +import UnlinkedDataContainer from 'containers/aboutTheData/modals/UnlinkedDataContainer'; + +const defaultProps = { + agencyData: { + fiscalYear: 2020, + fiscalPeriod: 8, + agencyCode: '012' + } +}; + +describe('Unlinked Data Container', () => { + it('should call api one time on mount', () => { + const unlinkedDataRequest = jest.spyOn(aboutTheDataHelper, 'fetchMockUnlinkedData'); + render(); + waitFor(() => expect(unlinkedDataRequest).toHaveBeenCalledTimes(1)); + }); +}); From 8100abcebf6fb50eb967dc00ae81922d879e1e9d Mon Sep 17 00:00:00 2001 From: Jonathan Hill Date: Fri, 15 Jan 2021 16:49:17 -0500 Subject: [PATCH 21/69] update mock api with cancel --- src/js/helpers/aboutTheDataHelper.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/js/helpers/aboutTheDataHelper.js b/src/js/helpers/aboutTheDataHelper.js index deca2b41bf..9245257f3c 100644 --- a/src/js/helpers/aboutTheDataHelper.js +++ b/src/js/helpers/aboutTheDataHelper.js @@ -137,7 +137,8 @@ export const fetchMockUnlinkedData = () => ({ unlinked_file_d_award_count: 43543, total_linkable_file_c_award_count: 12321312, total_linkable_file_d_award_count: 23987443892 - })) + })), + cancel: () => console.log(' Hi Jon :wave: ') }); export const dateFormattedMonthDayYear = (date) => { From 9cb125c4f90dc75a5f7e020e04f94160c82b9813 Mon Sep 17 00:00:00 2001 From: Jonathan Hill Date: Tue, 19 Jan 2021 13:03:44 -0500 Subject: [PATCH 22/69] dev-6539 format numbers and updates to css from design review --- .../modals/aboutTheData/_aboutTheData.scss | 23 +++++++++++++------ .../modals/UnlinkedDataContainer.jsx | 13 +++++------ src/js/helpers/aboutTheDataHelper.js | 10 ++++---- 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss b/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss index 300dd727ab..8a266a7a51 100644 --- a/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss +++ b/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss @@ -19,7 +19,7 @@ } .usa-dt-modal__title { font-size: rem(22); - line-height: rem(28); + line-height: rem(15); padding: rem(11) 0; } .about-the-data-modal__fiscal-year-quarter-period { @@ -61,6 +61,11 @@ } } .usda-table__body { // removes loading border + .usda-table__row { + .usda-table__cell { + font-size: rem(14); + } + } tr { td { border: none; @@ -160,22 +165,25 @@ // unlinked data modal &.unlinked-data-modal { @include media($tablet-screen) { - max-width: rem(699); + max-width: rem(730); } @include media($large-screen) { - max-width: rem(699); - min-width: rem(699); + max-width: rem(730); + min-width: rem(730); } .usa-dt-modal__section { - .usda-table { + table.usda-table { margin-bottom: 0; - .usda-table__head { + thead.usda-table__head { border-bottom: none; .usda-table__row { - .table-header { + th.table-header { padding-top: 0; } + .table-header:last-child { + vertical-align: top; + } .table-header:not(:first-child) { border-bottom: solid rem(1) $color-gray-light; } @@ -184,6 +192,7 @@ .usda-table__body { .usda-table__row { .table-header { + font-size: rem(14); text-align: right; border: none; padding-left: 0; diff --git a/src/js/containers/aboutTheData/modals/UnlinkedDataContainer.jsx b/src/js/containers/aboutTheData/modals/UnlinkedDataContainer.jsx index a74f012bc6..a3eff8258b 100644 --- a/src/js/containers/aboutTheData/modals/UnlinkedDataContainer.jsx +++ b/src/js/containers/aboutTheData/modals/UnlinkedDataContainer.jsx @@ -57,12 +57,6 @@ const UnlinkedDataContainer = ({ agencyData }) => { if (unlinkedDataReq.current) unlinkedDataReq.current.cancel(); }; }, []); - const columns = unlinkedDataColumns(agencyData.type).map((column, i) => ({ - displayName: column.displayName, - title: '', - right: true, - header: i === 0 - })); return (
{ error={error.error} message={error.message} rows={rows} - columns={columns} /> + columns={unlinkedDataColumns(agencyData.type).map((column, i) => ({ + displayName: column.displayName, + title: '', + right: true, + header: i === 0 + }))} /> ); }; diff --git a/src/js/helpers/aboutTheDataHelper.js b/src/js/helpers/aboutTheDataHelper.js index 8fa375beed..804619c75b 100644 --- a/src/js/helpers/aboutTheDataHelper.js +++ b/src/js/helpers/aboutTheDataHelper.js @@ -6,7 +6,7 @@ import { useState } from 'react'; import { stringify } from 'querystring'; -import { calculatePercentage, formatMoney } from 'helpers/moneyFormatter'; +import { calculatePercentage, formatMoney, formatNumber } from 'helpers/moneyFormatter'; import { periodsPerQuarter, lastPeriods @@ -193,14 +193,14 @@ export const convertDatesToMilliseconds = (data) => data.map((datesObj) => { export const formatUnlinkedDataRows = (data, type) => ([ [ { displayName: 'Count', title: '', rowSpan: '0' }, - data.unlinked_file_c_award_count, - data.unlinked_file_d_award_count, - data.unlinked_file_c_award_count + data.unlinked_file_d_award_count + formatNumber(data.unlinked_file_d_award_count), + formatNumber(data.unlinked_file_c_award_count), + formatNumber(data.unlinked_file_c_award_count + data.unlinked_file_d_award_count) ], [ { displayName: `as a Percentage of All ${type} Awards`, title: '', rowSpan: '0' }, - calculatePercentage(data.unlinked_file_c_award_count, data.total_linkable_file_c_award_count, null, 2), calculatePercentage(data.unlinked_file_d_award_count, data.total_linkable_file_d_award_count, null, 2), + calculatePercentage(data.unlinked_file_c_award_count, data.total_linkable_file_c_award_count, null, 2), calculatePercentage( data.unlinked_file_c_award_count + data.unlinked_file_d_award_count, data.total_linkable_file_c_award_count + data.total_linkable_file_d_award_count, From ef726a489f7fa2caa7e92d0ba21a2076a16eca3e Mon Sep 17 00:00:00 2001 From: Jonathan Hill Date: Tue, 19 Jan 2021 13:46:55 -0500 Subject: [PATCH 23/69] dev-6539 update test --- tests/containers/aboutTheData/UnlinkedDataContainer-test.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/containers/aboutTheData/UnlinkedDataContainer-test.jsx b/tests/containers/aboutTheData/UnlinkedDataContainer-test.jsx index 43faae4dca..84dee00c43 100644 --- a/tests/containers/aboutTheData/UnlinkedDataContainer-test.jsx +++ b/tests/containers/aboutTheData/UnlinkedDataContainer-test.jsx @@ -15,6 +15,6 @@ describe('Unlinked Data Container', () => { it('should call api one time on mount', () => { const unlinkedDataRequest = jest.spyOn(aboutTheDataHelper, 'fetchMockUnlinkedData'); render(); - waitFor(() => expect(unlinkedDataRequest).toHaveBeenCalledTimes(1)); + expect(unlinkedDataRequest).toHaveBeenCalledTimes(1); }); }); From 93c55e7e8ecf98dca659e324251ee82aa586d6e7 Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Tue, 19 Jan 2021 13:48:30 -0500 Subject: [PATCH 24/69] [DEV-6464] updating className for agency detail pg --- src/_scss/pages/aboutTheData/agencyDetailsPage.scss | 2 +- src/js/components/aboutTheData/AgencyDetailsPage.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/_scss/pages/aboutTheData/agencyDetailsPage.scss b/src/_scss/pages/aboutTheData/agencyDetailsPage.scss index 69c2010d9b..a2ea751f96 100644 --- a/src/_scss/pages/aboutTheData/agencyDetailsPage.scss +++ b/src/_scss/pages/aboutTheData/agencyDetailsPage.scss @@ -1,4 +1,4 @@ -.usa-da__about-the-data__agency-details-page { +.usa-da-about-the-data_agency-details-page { @import "all"; @import "layouts/default/default"; @import "layouts/default/stickyHeader/header"; diff --git a/src/js/components/aboutTheData/AgencyDetailsPage.jsx b/src/js/components/aboutTheData/AgencyDetailsPage.jsx index cb83af60dc..11900d7727 100644 --- a/src/js/components/aboutTheData/AgencyDetailsPage.jsx +++ b/src/js/components/aboutTheData/AgencyDetailsPage.jsx @@ -78,7 +78,7 @@ const AgencyDetailsPage = () => { }, [agencyCode]); return ( -
+
From 6f0816be28947f71c85fadfbf4b7eb384eeaa172 Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Tue, 19 Jan 2021 12:18:50 -0500 Subject: [PATCH 25/69] [DEV-6464] All Agencies Pg: Submissions Tab: - Center the percent of total column - apply zindex to tab tooltip - update column names (exposing tooltip content) Publications Tab: - show active fy in the column header - P3 inside Q1 --- .../pages/aboutTheData/agenciesPage.scss | 3 +- .../dataMapping/tooltipContentMapping.jsx | 2 +- .../aboutTheData/AgenciesContainer.jsx | 2 +- .../aboutTheData/AgencyTableMapping.jsx | 40 +++++++++++-------- 4 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/_scss/pages/aboutTheData/agenciesPage.scss b/src/_scss/pages/aboutTheData/agenciesPage.scss index 2fdea62dc9..dc2c5ac8c5 100644 --- a/src/_scss/pages/aboutTheData/agenciesPage.scss +++ b/src/_scss/pages/aboutTheData/agenciesPage.scss @@ -39,7 +39,8 @@ max-width: 100%; } .table-controls { - .usa-dt-tabs-mobile .usa-dt-picker__list { + .usa-dt-tabs-mobile .usa-dt-picker__list, + .tooltip-spacer { z-index: 12; } .usa-dt-tab-toggle:focus { diff --git a/src/js/components/aboutTheData/dataMapping/tooltipContentMapping.jsx b/src/js/components/aboutTheData/dataMapping/tooltipContentMapping.jsx index 1eb85cce85..fc1756d5e3 100644 --- a/src/js/components/aboutTheData/dataMapping/tooltipContentMapping.jsx +++ b/src/js/components/aboutTheData/dataMapping/tooltipContentMapping.jsx @@ -45,7 +45,7 @@ export const columnTooltips = {

), - 'Number of TASs Missing in Account Balance Data': ( + 'Number of TASs Missing from Account Balance Data': ( <>

Agencies submit account balance data grouped by Treasury Account Symbols (TAS) in two ways: 1) to USAspending.gov in File A and 2) to GTAS, a separate system that is the authoritative source of governmentwide TAS account balances. This column shows the number of TAS that are in GTAS but missing in USAspending.gov data. diff --git a/src/js/containers/aboutTheData/AgenciesContainer.jsx b/src/js/containers/aboutTheData/AgenciesContainer.jsx index ca5521081f..226d8dea2f 100644 --- a/src/js/containers/aboutTheData/AgenciesContainer.jsx +++ b/src/js/containers/aboutTheData/AgenciesContainer.jsx @@ -307,7 +307,7 @@ const AgenciesContainer = ({

Test content for tooltip
} /> }, + publications: (fy) => ([ + { title: 'agency_name', displayName: 'Agency Name' }, { title: 'current_total_budget_authority_amount', displayName: 'Percent of Total Federal Budget' }, { title: 'Q1', - displayName: 'FY 2020 Q1', - columnSpan: "2", + displayName: `FY ${fy} Q1`, + columnSpan: "3", subColumnNames: [ { displayName: 'P1', title: 'publication_date,1' }, - { displayName: 'P2', title: 'publication_date,2' } + { displayName: 'P2', title: 'publication_date,2' }, + { displayName: 'P3', title: 'publication_date,3' } ] }, { title: 'Q2', - displayName: 'FY 2020 Q2', - columnSpan: "4", + displayName: `FY ${fy} Q2`, + columnSpan: "3", subColumnNames: [ - { displayName: 'P3', title: 'publication_date,3' }, { displayName: 'P4', title: 'publication_date,4' }, { displayName: 'P5', title: 'publication_date,5' }, { displayName: 'P6', title: 'publication_date,6' } @@ -50,7 +50,7 @@ export const agenciesTableColumns = { }, { title: 'Q3', - displayName: 'FY 2020 Q3', + displayName: `FY ${fy} Q3`, columnSpan: "3", subColumnNames: [ { displayName: 'P7', title: 'publication_date,7' }, @@ -60,7 +60,7 @@ export const agenciesTableColumns = { }, { title: 'Q4', - displayName: 'FY 2020 Q4', + displayName: `FY ${fy} Q4`, columnSpan: "3", subColumnNames: [ { displayName: 'P10', title: 'publication_date,10' }, @@ -68,7 +68,7 @@ export const agenciesTableColumns = { { displayName: 'P12', title: 'publication_date,12' } ] } - ], + ]), submissions: [ { title: "agency_name", @@ -80,29 +80,35 @@ export const agenciesTableColumns = { }, { title: "recent_publication_date", - displayName: "Most Recent Publication Date", + displayName: "Most Recent Update", icon: () }, { title: "missing_tas_accounts_count", - displayName: "Count of Agency TAS in GTAS Not in File A", + displayName: "Number of TAS Missing from Account Balance Data", icon: ( - + ) }, { title: "obligation_difference", - displayName: "Difference in File A and File B Obligations" + displayName: "Reporting Difference in Obligations", + icon: ( + + ) }, { title: "unlinked_contract_award_count", - displayName: "Number of Unlinked Contract Awards" + displayName: "Number of Unlinked Contract Awards", + icon: ( + + ) }, { title: "unlinked_assistance_award_count", displayName: "Count of Unlinked Assistance Awards", icon: ( - + ) }, { From b1e51653225ef2a9f196f487c049107dd7e9c4cb Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Tue, 19 Jan 2021 12:22:02 -0500 Subject: [PATCH 26/69] [DEV-6464] sort fiscal years in desc order --- src/js/helpers/fiscalYearHelper.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/js/helpers/fiscalYearHelper.js b/src/js/helpers/fiscalYearHelper.js index a03c33eddf..ae863fd30f 100644 --- a/src/js/helpers/fiscalYearHelper.js +++ b/src/js/helpers/fiscalYearHelper.js @@ -149,5 +149,6 @@ export const allFiscalYears = (earliestYear = earliestFiscalYear, latestYear = c .reduce((listOfYears, _, i) => { listOfYears.push(earliestYear + i + 1); return listOfYears; - }, [earliestYear]); + }, [earliestYear]) + .sort((a, b) => b - a); }; From c2c4e6a5a7d0f86a0e12a2269089f7ca970a5aa3 Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Tue, 19 Jan 2021 12:25:39 -0500 Subject: [PATCH 27/69] [DEV-6464] uppercase agency name in modals --- src/js/components/aboutTheData/AboutTheDataModal.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/components/aboutTheData/AboutTheDataModal.jsx b/src/js/components/aboutTheData/AboutTheDataModal.jsx index 09fe9e3ef2..2a1966fa56 100644 --- a/src/js/components/aboutTheData/AboutTheDataModal.jsx +++ b/src/js/components/aboutTheData/AboutTheDataModal.jsx @@ -44,7 +44,7 @@ const AboutTheDataModal = ({
-
{agencyData.agencyName}
+
{agencyData.agencyName ? agencyData.agencyName.toUpperCase() : ''}

{title}

From a906298502047c57c17d0f28b302ebc813d87fed Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Tue, 19 Jan 2021 13:17:04 -0500 Subject: [PATCH 28/69] [DEV-6464] Agency Detail Pg: in --> from Column name update: Number of TASs Missing in Account Balance Data --> Number of TASs Missing from Account Balance Data --- src/js/containers/aboutTheData/AgencyDetailsContainer.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/containers/aboutTheData/AgencyDetailsContainer.jsx b/src/js/containers/aboutTheData/AgencyDetailsContainer.jsx index d840b5983f..f85b4defff 100644 --- a/src/js/containers/aboutTheData/AgencyDetailsContainer.jsx +++ b/src/js/containers/aboutTheData/AgencyDetailsContainer.jsx @@ -48,7 +48,7 @@ const columns = [ title: "missing_tas_accounts_count", displayName: "Number of TASs Missing from Account Balance Data", icon: ( - + ), right: true }, @@ -72,7 +72,7 @@ const columns = [ title: "unlinked_asst_award_count", displayName: "Number of Unlinked Assistance Awards", icon: ( - + ), right: true }, From 1ae9c0b96c2cc4b6aaef2987fef1fefe2ded01b7 Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Tue, 19 Jan 2021 13:21:47 -0500 Subject: [PATCH 29/69] [DEV-6464] Modals Font Size Updated font size from 12px to 14px --- src/_scss/pages/modals/aboutTheData/_aboutTheData.scss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss b/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss index 259c00dd0c..b40f3357bb 100644 --- a/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss +++ b/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss @@ -52,7 +52,7 @@ font-size: rem(14); line-height: rem(18); .publication-dates__column-header-sub-title { - font-size: rem(12); + font-size: rem(14); line-height: rem(15); font-weight: $font-normal; } @@ -71,7 +71,7 @@ } } } - font-size: rem(12); + font-size: rem(14); .usda-table__row { .usda-table__cell { padding: rem(10) rem(15); @@ -123,7 +123,7 @@ .table-header__content { .table-header__label { .publication-dates__column-header-sub-title { - font-size: rem(12); + font-size: rem(14); line-height: rem(15); font-weight: $font-normal; } From 001597a0f912fc8424c19f1b4d69bdf7b5f76a99 Mon Sep 17 00:00:00 2001 From: Jonathan Hill Date: Tue, 19 Jan 2021 17:54:23 -0500 Subject: [PATCH 30/69] dev-6539 give blank column a title --- src/js/dataMapping/aboutTheData/modals.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/dataMapping/aboutTheData/modals.js b/src/js/dataMapping/aboutTheData/modals.js index 00fef71b5c..d77387e653 100644 --- a/src/js/dataMapping/aboutTheData/modals.js +++ b/src/js/dataMapping/aboutTheData/modals.js @@ -37,7 +37,7 @@ export const reportingDifferencesColumns = [ ]; export const unlinkedDataColumns = (type) => ([ - { displayName: '' }, + { displayName: '', title: 'blank' }, { displayName: `Unlinked ${type} Awards in ${type === 'Contract' ? type : 'Financial Assistance'} Data` }, { displayName: `Unlinked ${type} Awards in Award Spending Breakdown Data` }, { displayName: 'Total' } From 9e8ee3c7f0ac40d390fa000277fbc016730e9fcf Mon Sep 17 00:00:00 2001 From: Lizzie Salita Date: Wed, 20 Jan 2021 09:49:54 -0500 Subject: [PATCH 31/69] Reformatting, background for all cells, removed border --- src/_scss/components/_stickyTable.scss | 200 +++++++++--------- src/_scss/pages/aboutTheData/_actionCell.scss | 4 +- 2 files changed, 102 insertions(+), 102 deletions(-) diff --git a/src/_scss/components/_stickyTable.scss b/src/_scss/components/_stickyTable.scss index 3130927a1d..c7a8732354 100644 --- a/src/_scss/components/_stickyTable.scss +++ b/src/_scss/components/_stickyTable.scss @@ -1,135 +1,137 @@ -.table-container { +.table-container { height: rem(500); overflow: scroll; margin: 0; border: rem(1) solid $color-gray-border; .usda-table.usda-table-w-grid { border-collapse: separate; - margin-top:0; - margin-bottom:0; + margin-top: 0; + margin-bottom: 0; &.table-loading { height: 100%; } thead { tr th { - min-width: rem(300); + min-width: rem(300); } .nested-header { - .table-header__content { + .table-header__content { padding: 1rem 0; } } } - tbody { - .loading-message { - text-align: center; - } - .usda-table__row { - height: 4.8rem; - .usda-table__cell { - font-size: 1.4rem; - padding: 0; // to allow entire cell to be hoverable - @import './actionCell'; - @include flex-wrap(no-wrap); - .generic-cell-content { - padding: 1.2rem; - .not-certified { - margin-left: rem(5); - background: #DCE4EE; - border-radius: rem(2); - color: $color-base; - padding: rem(5); - font-size: rem(10); - font-weight: $font-semibold; - line-height: rem(13); - } - } - .matched-str { - font-weight: 600; - text-decoration: underline; - } - } - } - } - &.sticky-y-table { - @media(min-width: $medium-screen) { - thead { - tr th { - position: sticky; - position: -webkit-sticky; - top: 0; - z-index: 9; - border: rem(1) solid $color-gray-lighter; - // Set a higher z-index on the
the user is hovering over so - // tooltips display above the stacking context of the other headers - &:hover { - z-index: 10; - } + tbody { + .loading-message { + text-align: center; } - tr:last-of-type th { - top: rem(57); - border: rem(1) solid $color-gray-lighter; + .usda-table__row { + height: 4.8rem; + .usda-table__cell { + font-size: 1.4rem; + padding: 0; // to allow entire cell to be hoverable + @import '../pages/aboutTheData/actionCell'; + .generic-cell-content { + padding: 1.2rem; + .not-certified { + margin-left: rem(5); + background: #dce4ee; + border-radius: rem(2); + color: $color-base; + padding: rem(5); + font-size: rem(10); + font-weight: $font-semibold; + line-height: rem(13); + } + } + .matched-str { + font-weight: 600; + text-decoration: underline; + } + &:hover { + background-color: $color-primary-alt-lightest; + } + } } } - } - } - &.sticky-x-table { - @media(min-width: $medium-screen) { - thead { - tr:first-of-type { - .table-header:first-of-type { - position: sticky; - position: -webkit-sticky; - left: 0px; - z-index: 11; - box-shadow: 2px 1px 4px rgba(0,0,0,.20); - border-right: 1px solid $color-gray-lightest; - } + &.sticky-y-table { + @media (min-width: $medium-screen) { + thead { + tr th { + position: sticky; + position: -webkit-sticky; + top: 0; + z-index: 9; + border: rem(1) solid $color-gray-lighter; + // Set a higher z-index on the the user is hovering over so + // tooltips display above the stacking context of the other headers + &:hover { + z-index: 10; + } + } + tr:last-of-type th { + top: rem(57); + border: rem(1) solid $color-gray-lighter; + } + } } } - tbody { - .usda-table__row .usda-table__cell { - &:first-of-type { - position: sticky; - position: -webkit-sticky; - z-index: 10; - left: 0px; - box-shadow: 2px 1px 4px rgba(0,0,0,.20); - border-right: rem(1) solid $color-gray-lightest; - } + &.sticky-x-table { + @media (min-width: $medium-screen) { + thead { + tr:first-of-type { + .table-header:first-of-type { + position: sticky; + position: -webkit-sticky; + left: 0px; + z-index: 11; + box-shadow: 2px 1px 4px rgba(0, 0, 0, 0.2); + border-right: 1px solid $color-gray-lightest; + } + } + } + tbody { + .usda-table__row .usda-table__cell { + &:first-of-type { + position: sticky; + position: -webkit-sticky; + z-index: 10; + left: 0px; + box-shadow: 2px 1px 4px rgba(0, 0, 0, 0.2); + border-right: rem(1) solid $color-gray-lightest; + } + } + } } } + &.table-loading .usda-table__body tr td { + border: none; } } - &.table-loading .usda-table__body tr td { - border: none; - } - } } // Pagination .usa-dt-pagination { padding: rem(20); .usa-dt-pagination__totals { - text-align: center; - padding: rem(20); // extra padding on mobile - @media(min-width: $tablet-screen) { - text-align: left; - padding: rem(0); - } + text-align: center; + padding: rem(20); // extra padding on mobile + @media (min-width: $tablet-screen) { + text-align: left; + padding: rem(0); + } } .usa-dt-pagination__wrapper { - @include justify-content(center); // center on mobile - @media(min-width: $tablet-screen) { - @include justify-content(flex-end); - } - .pager { - padding: rem(20); // extra padding on mobile - @media(min-width: $tablet-screen) { - padding: 0; + @include justify-content(center); // center on mobile + @media (min-width: $tablet-screen) { + @include justify-content(flex-end); } - .pager__item { - margin: 0; + .pager { + padding: rem(20); // extra padding on mobile + @media (min-width: $tablet-screen) { + padding: 0; + } + .pager__item { + margin: 0; + } } } - } -} \ No newline at end of file +} diff --git a/src/_scss/pages/aboutTheData/_actionCell.scss b/src/_scss/pages/aboutTheData/_actionCell.scss index 4cd069997a..febc7faaea 100644 --- a/src/_scss/pages/aboutTheData/_actionCell.scss +++ b/src/_scss/pages/aboutTheData/_actionCell.scss @@ -11,7 +11,6 @@ color: $color-base; padding: 1.2rem; height: 6.6rem; - border: solid 3px transparent; .action-cell__text { padding-right: .8rem; } @@ -32,11 +31,10 @@ } &:hover { text-decoration: none; - background-color: $color-primary-alt-lightest; + background-color: $color-primary-alt-light; } } &:hover { - border-color: $color-primary; .action-cell__button { svg { @include display(flex); From 1b59463144a03c5efd46a2a0c967a163001f3efb Mon Sep 17 00:00:00 2001 From: Lizzie Salita Date: Wed, 20 Jan 2021 09:58:12 -0500 Subject: [PATCH 32/69] Updated title text --- src/js/components/aboutTheData/CellWithModal.jsx | 2 +- src/js/components/aboutTheData/DrilldownCell.jsx | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/js/components/aboutTheData/CellWithModal.jsx b/src/js/components/aboutTheData/CellWithModal.jsx index 630301c3ef..d210abc137 100644 --- a/src/js/components/aboutTheData/CellWithModal.jsx +++ b/src/js/components/aboutTheData/CellWithModal.jsx @@ -23,7 +23,7 @@ const CellWithModal = ({ {data} - diff --git a/src/js/components/aboutTheData/DrilldownCell.jsx b/src/js/components/aboutTheData/DrilldownCell.jsx index 4c29329ace..ee0c5c23b6 100644 --- a/src/js/components/aboutTheData/DrilldownCell.jsx +++ b/src/js/components/aboutTheData/DrilldownCell.jsx @@ -25,7 +25,10 @@ const DrilldownCell = ({ {searchTerm ? replaceString(data, searchTerm, 'matched-str') : data} - + From cfa4091c48c168c806fe583e000b4410914315a6 Mon Sep 17 00:00:00 2001 From: Lizzie Salita Date: Wed, 20 Jan 2021 10:24:06 -0500 Subject: [PATCH 33/69] Simplified padding; allow varied row heights --- src/_scss/components/_stickyTable.scss | 3 +-- src/_scss/pages/aboutTheData/_actionCell.scss | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/_scss/components/_stickyTable.scss b/src/_scss/components/_stickyTable.scss index c7a8732354..ce1ded73ca 100644 --- a/src/_scss/components/_stickyTable.scss +++ b/src/_scss/components/_stickyTable.scss @@ -28,10 +28,9 @@ height: 4.8rem; .usda-table__cell { font-size: 1.4rem; - padding: 0; // to allow entire cell to be hoverable + padding: 1.2rem; @import '../pages/aboutTheData/actionCell'; .generic-cell-content { - padding: 1.2rem; .not-certified { margin-left: rem(5); background: #dce4ee; diff --git a/src/_scss/pages/aboutTheData/_actionCell.scss b/src/_scss/pages/aboutTheData/_actionCell.scss index febc7faaea..009cdef901 100644 --- a/src/_scss/pages/aboutTheData/_actionCell.scss +++ b/src/_scss/pages/aboutTheData/_actionCell.scss @@ -9,8 +9,6 @@ @include justify-content(space-between); @include align-items(center); color: $color-base; - padding: 1.2rem; - height: 6.6rem; .action-cell__text { padding-right: .8rem; } From 78791929add36db7f2922a490cc55f6052e15a2c Mon Sep 17 00:00:00 2001 From: Jonathan Hill Date: Wed, 20 Jan 2021 15:16:00 -0500 Subject: [PATCH 34/69] dev-6539 updates for mobile, component library properties, and titles css --- src/_scss/pages/modals/aboutTheData/_aboutTheData.scss | 9 +++++---- .../aboutTheData/modals/UnlinkedDataContainer.jsx | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss b/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss index 8a266a7a51..3a2e965650 100644 --- a/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss +++ b/src/_scss/pages/modals/aboutTheData/_aboutTheData.scss @@ -19,8 +19,8 @@ } .usa-dt-modal__title { font-size: rem(22); - line-height: rem(15); - padding: rem(11) 0; + line-height: rem(28); + padding: rem(5) 0; } .about-the-data-modal__fiscal-year-quarter-period { font-size: rem(16); @@ -166,7 +166,9 @@ &.unlinked-data-modal { @include media($tablet-screen) { max-width: rem(730); - + table.usda-table { + margin-bottom: 0; + } } @include media($large-screen) { max-width: rem(730); @@ -174,7 +176,6 @@ } .usa-dt-modal__section { table.usda-table { - margin-bottom: 0; thead.usda-table__head { border-bottom: none; .usda-table__row { diff --git a/src/js/containers/aboutTheData/modals/UnlinkedDataContainer.jsx b/src/js/containers/aboutTheData/modals/UnlinkedDataContainer.jsx index a3eff8258b..eb066858e8 100644 --- a/src/js/containers/aboutTheData/modals/UnlinkedDataContainer.jsx +++ b/src/js/containers/aboutTheData/modals/UnlinkedDataContainer.jsx @@ -68,7 +68,7 @@ const UnlinkedDataContainer = ({ agencyData }) => { displayName: column.displayName, title: '', right: true, - header: i === 0 + bodyHeader: i === 0 }))} /> ); }; From 93c2e77e65e848608efad8f2271e46b7296958b6 Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Wed, 20 Jan 2021 10:45:56 -0500 Subject: [PATCH 35/69] [DEV-6464] centering the table loading container & fixing tests & right-align column --- src/_scss/components/_stickyTable.scss | 60 +++++++++++-------- .../aboutTheData/AgencyTableMapping.jsx | 17 ++++-- .../aboutTheData/AboutTheDataModal-test.jsx | 2 +- .../aboutTheData/AboutTheDataPage-test.jsx | 2 +- 4 files changed, 47 insertions(+), 34 deletions(-) diff --git a/src/_scss/components/_stickyTable.scss b/src/_scss/components/_stickyTable.scss index 3130927a1d..8aa45d318c 100644 --- a/src/_scss/components/_stickyTable.scss +++ b/src/_scss/components/_stickyTable.scss @@ -14,42 +14,50 @@ tr th { min-width: rem(300); } + .table-header__content_right .tooltip-wrapper div:first-of-type .tooltip-spacer .tooltip .tooltip__interior .tooltip-pointer { + &.left { + left: rem(-24); + } + &.right { + right: rem(8); + } + } .nested-header { .table-header__content { padding: 1rem 0; } } } - tbody { - .loading-message { - text-align: center; + &.table-loading tbody tr:first-of-type td div:not(.usda-loading-animation__container):not(.usda-loading-animation):not(.loading-message) { + width: 100vw; } + tbody { .usda-table__row { - height: 4.8rem; - .usda-table__cell { - font-size: 1.4rem; - padding: 0; // to allow entire cell to be hoverable - @import './actionCell'; - @include flex-wrap(no-wrap); - .generic-cell-content { - padding: 1.2rem; - .not-certified { - margin-left: rem(5); - background: #DCE4EE; - border-radius: rem(2); - color: $color-base; - padding: rem(5); - font-size: rem(10); - font-weight: $font-semibold; - line-height: rem(13); - } - } - .matched-str { - font-weight: 600; - text-decoration: underline; + height: 4.8rem; + .usda-table__cell { + font-size: 1.4rem; + padding: 0; // to allow entire cell to be hoverable + @import './actionCell'; + @include flex-wrap(nowrap); + .generic-cell-content { + padding: 1.2rem; + .not-certified { + margin-left: rem(5); + background: #DCE4EE; + border-radius: rem(2); + color: $color-base; + padding: rem(5); + font-size: rem(10); + font-weight: $font-semibold; + line-height: rem(13); + } + } + .matched-str { + font-weight: 600; + text-decoration: underline; + } } } - } } &.sticky-y-table { @media(min-width: $medium-screen) { diff --git a/src/js/containers/aboutTheData/AgencyTableMapping.jsx b/src/js/containers/aboutTheData/AgencyTableMapping.jsx index 9e76d15bd4..59f3402b27 100644 --- a/src/js/containers/aboutTheData/AgencyTableMapping.jsx +++ b/src/js/containers/aboutTheData/AgencyTableMapping.jsx @@ -88,35 +88,40 @@ export const agenciesTableColumns = { displayName: "Number of TAS Missing from Account Balance Data", icon: ( - ) + ), + right: true }, { title: "obligation_difference", displayName: "Reporting Difference in Obligations", icon: ( - ) + ), + right: true }, { title: "unlinked_contract_award_count", displayName: "Number of Unlinked Contract Awards", icon: ( - ) + ), + right: true }, { title: "unlinked_assistance_award_count", - displayName: "Count of Unlinked Assistance Awards", + displayName: "Number of Unlinked Assistance Awards", icon: ( - ) + ), + right: true }, { title: "assurance_statements", displayName: "Agency Comments", icon: ( - ) + ), + right: true } ] }; diff --git a/tests/components/aboutTheData/AboutTheDataModal-test.jsx b/tests/components/aboutTheData/AboutTheDataModal-test.jsx index 530fd25326..a0c5fc8662 100644 --- a/tests/components/aboutTheData/AboutTheDataModal-test.jsx +++ b/tests/components/aboutTheData/AboutTheDataModal-test.jsx @@ -19,7 +19,7 @@ const defaultProps = { describe('About The Data Modal', () => { it('should render agency name', () => { render(); - expect(screen.queryByText('Assaley & Hill School of Business')).toBeTruthy(); + expect(screen.queryByText(defaultProps.agencyData.agencyName.toUpperCase())).toBeTruthy(); }); it('should render title', () => { render(); diff --git a/tests/components/aboutTheData/AboutTheDataPage-test.jsx b/tests/components/aboutTheData/AboutTheDataPage-test.jsx index 121d9ea66e..1aa76a47fa 100644 --- a/tests/components/aboutTheData/AboutTheDataPage-test.jsx +++ b/tests/components/aboutTheData/AboutTheDataPage-test.jsx @@ -97,7 +97,7 @@ beforeEach(() => { test('renders the details table first', async () => { render(); // shows the correct table - const [table] = screen.getAllByText('Count of Agency TAS in GTAS Not in File A'); + const [table] = screen.getAllByText('Number of TAS Missing from Account Balance Data'); expect(table).toBeDefined(); }); From c0059affcf030565bc1c167bf03ae7526b4b2e08 Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Thu, 21 Jan 2021 09:55:32 -0500 Subject: [PATCH 36/69] [DEV-6464] make table column headers top-aligned --- src/_scss/components/_stickyTable.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/_scss/components/_stickyTable.scss b/src/_scss/components/_stickyTable.scss index 8aa45d318c..e1b2c08f5d 100644 --- a/src/_scss/components/_stickyTable.scss +++ b/src/_scss/components/_stickyTable.scss @@ -12,7 +12,8 @@ } thead { tr th { - min-width: rem(300); + min-width: rem(300); + vertical-align: top; } .table-header__content_right .tooltip-wrapper div:first-of-type .tooltip-spacer .tooltip .tooltip__interior .tooltip-pointer { &.left { From ccfdbfd0aa96df0175da92056ab52853d5e2f358 Mon Sep 17 00:00:00 2001 From: Jonathan Hill Date: Thu, 21 Jan 2021 10:55:25 -0500 Subject: [PATCH 37/69] dev-6539 bump dtui --- package-lock.json | 204 +++++++++++++++++++++------------------------- package.json | 2 +- 2 files changed, 94 insertions(+), 112 deletions(-) diff --git a/package-lock.json b/package-lock.json index face3ee336..e40e8d70a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2057,9 +2057,9 @@ } }, "parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -3114,9 +3114,9 @@ } }, "parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -3683,9 +3683,9 @@ "integrity": "sha512-dyQxe6ukILV6qaEvxoKCIwhblgRjYp1ZGlClo4xvfbmxzFO5LYu7Tnrg2AZrRgN7VsSragsGcNjzUe9kCdKHYQ==" }, "@mapbox/tiny-sdf": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-1.1.1.tgz", - "integrity": "sha512-Ihn1nZcGIswJ5XGbgFAvVumOgWpvIjBX9jiRlIl46uQG9vJOF51ViBYHF95rEZupuyQbEmhLaDPLQlU7fUTsBg==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-1.2.0.tgz", + "integrity": "sha512-gy4o8kxsIQLSbY1etb+swWeXTateN6C9DrHeArrHsxuAnQFCh9MEKvy3b0C6QyMYZcrG6QEz4sJ/zr/ud9Zlgw==" }, "@mapbox/unitbezier": { "version": "0.0.0", @@ -4272,9 +4272,9 @@ } }, "@testing-library/user-event": { - "version": "12.6.0", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-12.6.0.tgz", - "integrity": "sha512-FNEH/HLmOk5GO70I52tKjs7WvGYckeE/SrnLX/ip7z2IGbffyd5zOUM1tZ10vsTphqm+VbDFI0oaXu0wcfQsAQ==", + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-12.6.1.tgz", + "integrity": "sha512-wirJeUQ1QE9jSdARFu3riFeBPac2SDhHNKMt1MSfmBb4xNfpVIiaMqfP5mTNlMQHq1ULCD7sxtmyfQrzQYFDpQ==", "dev": true, "requires": { "@babel/runtime": "^7.12.5" @@ -4513,9 +4513,9 @@ } }, "@types/json-schema": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", - "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==" + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", + "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==" }, "@types/json5": { "version": "0.0.29", @@ -4538,9 +4538,9 @@ "dev": true }, "@types/node": { - "version": "14.14.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.21.tgz", - "integrity": "sha512-cHYfKsnwllYhjOzuC5q1VpguABBeecUp24yFluHpn/BQaVxB1CuQ1FSRZCzrPxrkIfWISXV2LbeoBthLWg0+0A==", + "version": "14.14.22", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.22.tgz", + "integrity": "sha512-g+f/qj/cNcqKkc3tFqlXOYjrmZA+jNBiDzbP3kH+B+otKFqAdPgVTGP1IeKRdMml/aE69as5S4FqtxAbl+LaMw==", "dev": true }, "@types/normalize-package-data": { @@ -6586,14 +6586,14 @@ } }, "caniuse-db": { - "version": "1.0.30001177", - "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30001177.tgz", - "integrity": "sha512-bu5ZkVbh3c1i17W/AtuQ2O16jeDKIS8aTtAW1x+b+nYBWLb6x0lMrHfSHXuD+0eJnuKUBYFsZW4BlmvGoT0KgA==" + "version": "1.0.30001179", + "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30001179.tgz", + "integrity": "sha512-YgqeMhTgW75OI7emeIpVTol3E2EQTQJqUJp/R1uA6aYzXOSyvGAGAkadvSdYqB/JPDBkXWwT3fLSxA+AuqttlA==" }, "caniuse-lite": { - "version": "1.0.30001177", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001177.tgz", - "integrity": "sha512-6Ld7t3ifCL02jTj3MxPMM5wAYjbo4h/TAQGFTgv1inihP1tWnWp8mxxT4ut4JBEHLbpFXEXJJQ119JCJTBkYDw==" + "version": "1.0.30001179", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001179.tgz", + "integrity": "sha512-blMmO0QQujuUWZKyVrD1msR4WNDAqb/UPO1Sw2WWsQ7deoM5bJiicKnWJ1Y0NS/aGINSnKPIWBMw5luX+NDUCA==" }, "canvas-composite-types": { "version": "1.0.4", @@ -7456,16 +7456,16 @@ } }, "core-js": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.8.2.tgz", - "integrity": "sha512-FfApuSRgrR6G5s58casCBd9M2k+4ikuu4wbW6pJyYU7bd9zvFc9qf7vr5xmrZOhT9nn+8uwlH1oRR9jTnFoA3A==" + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.8.3.tgz", + "integrity": "sha512-KPYXeVZYemC2TkNEkX/01I+7yd+nX3KddKwZ1Ww7SKWdI2wQprSgLmrTddT8nw92AjEklTsPBoSdQBhbI1bQ6Q==" }, "core-js-compat": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.2.tgz", - "integrity": "sha512-LO8uL9lOIyRRrQmZxHZFl1RV+ZbcsAkFWTktn5SmH40WgLtSNYN4m4W2v9ONT147PxBY/XrRhrWq8TlvObyUjQ==", + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.3.tgz", + "integrity": "sha512-1sCb0wBXnBIL16pfFG1Gkvei6UzvKyTNYpiC41yrdjEv0UoJoq9E/abTMzyYJ6JpTkAj15dLjbqifIzEBDVvog==", "requires": { - "browserslist": "^4.16.0", + "browserslist": "^4.16.1", "semver": "7.0.0" }, "dependencies": { @@ -7489,9 +7489,9 @@ } }, "core-js-pure": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.8.2.tgz", - "integrity": "sha512-v6zfIQqL/pzTVAbZvYUozsxNfxcFb6Ks3ZfEbuneJl3FW9Jb8F6vLWB6f+qTmAu72msUdyb84V8d/yBFf7FNnw==", + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.8.3.tgz", + "integrity": "sha512-V5qQZVAr9K0xu7jXg1M7qTEwuxUgqr7dUOezGaNa7i+Xn9oXAU/d1fzqD9ObuwpVQOaorO5s70ckyi1woP9lVA==", "dev": true }, "core-util-is": { @@ -8288,8 +8288,8 @@ } }, "data-transparency-ui": { - "version": "github:fedspendingtransparency/data-transparency-ui#5e44f7f1b069aaace61cd161dd5d220fb05a42fc", - "from": "github:fedspendingtransparency/data-transparency-ui#v1.3.6", + "version": "github:fedspendingtransparency/data-transparency-ui#4c2ce1c0fb0e8071a2e55e15204e5dae464e06f9", + "from": "github:fedspendingtransparency/data-transparency-ui#v1.3.7", "requires": { "@fortawesome/fontawesome-svg-core": "^1.2.25", "@fortawesome/free-solid-svg-icons": "^5.11.2", @@ -8833,9 +8833,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.640", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.640.tgz", - "integrity": "sha512-cU6wQdXYzuSPzLdszsa4whStYfmU7CVNnG6c5z6/z9YlCOQ2Xh/uKB1gTxlIRr0ubgSg1/dZuSbUAoeESeQ3sQ==" + "version": "1.3.642", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.642.tgz", + "integrity": "sha512-cev+jOrz/Zm1i+Yh334Hed6lQVOkkemk2wRozfMF4MtTR7pxf3r3L5Rbd7uX1zMcEqVJ7alJBnJL7+JffkC6FQ==" }, "elliptic": { "version": "6.5.3", @@ -8980,16 +8980,16 @@ } }, "enzyme-adapter-react-16": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.15.5.tgz", - "integrity": "sha512-33yUJGT1nHFQlbVI5qdo5Pfqvu/h4qPwi1o0a6ZZsjpiqq92a3HjynDhwd1IeED+Su60HDWV8mxJqkTnLYdGkw==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.15.6.tgz", + "integrity": "sha512-yFlVJCXh8T+mcQo8M6my9sPgeGzj85HSHi6Apgf1Cvq/7EL/J9+1JoJmJsRxZgyTvPMAqOEpRSu/Ii/ZpyOk0g==", "dev": true, "requires": { - "enzyme-adapter-utils": "^1.13.1", + "enzyme-adapter-utils": "^1.14.0", "enzyme-shallow-equal": "^1.0.4", "has": "^1.0.3", - "object.assign": "^4.1.0", - "object.values": "^1.1.1", + "object.assign": "^4.1.2", + "object.values": "^1.1.2", "prop-types": "^15.7.2", "react-is": "^16.13.1", "react-test-renderer": "^16.0.0-0", @@ -9058,22 +9058,24 @@ } }, "es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "version": "1.18.0-next.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.2.tgz", + "integrity": "sha512-Ih4ZMFHEtZupnUh6497zEL4y2+w8+1ljnCyaTa+adcoafI1GOvMwFlDjBLfWR7y9VLfrjRJe9ocuHY1PSR9jjw==", "requires": { + "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2", "has": "^1.0.3", "has-symbols": "^1.0.1", "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", + "is-negative-zero": "^2.0.1", "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", + "object-inspect": "^1.9.0", "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.3", + "string.prototype.trimstart": "^1.0.3" } }, "es-to-primitive": { @@ -10241,9 +10243,9 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "fast-glob": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", - "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", + "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -10550,9 +10552,9 @@ } }, "flow-parser": { - "version": "0.142.0", - "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.142.0.tgz", - "integrity": "sha512-gkdbagtuYQw7fo/D1AwCsDpMyxp/bdZkgfq95ev2MoETD1OW84PhU+vitupwte+6AJc2MRJyCdgfWhan8AGhzA==" + "version": "0.143.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.143.0.tgz", + "integrity": "sha512-PCKiRLALyu/L7b8vN63TCgvpV+vZJVAijPna2SAsSjzDDvQryZjiQMGUIEbbkpGpWVjEtQqyImBK7vSK49ufMg==" }, "flow-remove-types": { "version": "1.2.3", @@ -13533,9 +13535,9 @@ } }, "parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -14827,9 +14829,9 @@ } }, "parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -15591,9 +15593,9 @@ } }, "parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -16038,9 +16040,9 @@ } }, "parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -16683,9 +16685,9 @@ } }, "parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -19280,9 +19282,9 @@ } }, "node-releases": { - "version": "1.1.69", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.69.tgz", - "integrity": "sha512-DGIjo79VDEyAnRlfSqYTsy+yoHd2IOjJiKUozD2MV2D85Vso6Bug56mb9tT/fY5Urt0iqk01H7x+llAruDR2zA==" + "version": "1.1.70", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.70.tgz", + "integrity": "sha512-Slf2s69+2/uAD79pVVQo8uSiC34+g8GWY8UH2Qtqv34ZfhYrxpYpfzs9Js9d6O0mbDmALuxaTlplnBTnSELcrw==" }, "node-sass": { "version": "4.14.1", @@ -20313,9 +20315,9 @@ }, "dependencies": { "parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "requires": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -22936,9 +22938,9 @@ } }, "protocol-buffers-schema": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.4.0.tgz", - "integrity": "sha512-G/2kcamPF2S49W5yaMGdIpkG6+5wZF0fzBteLKgEHjbNzqjZQ85aAs1iJGto31EJaSTkNvHs5IXuHSaTLWBAiA==" + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.5.1.tgz", + "integrity": "sha512-YVCvdhxWNDP8/nJDyXLuM+UFsuPk4+1PB7WGPVDzm3HTHbzFLxQYeW2iZpS4mmnXrQJGBzt230t/BbEb7PrQaw==" }, "protoduck": { "version": "5.0.1", @@ -23750,32 +23752,12 @@ "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==" }, "regexp.prototype.flags": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", - "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", + "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.7", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", - "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" } }, "regexpp": { @@ -28202,9 +28184,9 @@ }, "dependencies": { "mime": { - "version": "2.4.7", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.7.tgz", - "integrity": "sha512-dhNd1uA2u397uQk3Nv5LM4lm93WYDUXFn3Fu291FJerns4jyTudqhIWe4W04YLy7Uk1tm1Ore04NpjRvQp/NPA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.0.tgz", + "integrity": "sha512-ft3WayFSFUVBuJj7BMLKAQcSlItKtfjsKDDsii3rqFDAZ7t11zRe8ASw/GlmivGwVUYtwkQrxiGGpL6gFvB0ag==", "dev": true } } diff --git a/package.json b/package.json index 67c97f53ba..a44947b025 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "d3-sankey0.12.3": "npm:d3-sankey@0.12.3", "d3-scale": "^1.0.4", "d3-time": "^1.0.11", - "data-transparency-ui": "github:fedspendingtransparency/data-transparency-ui#v1.3.6", + "data-transparency-ui": "github:fedspendingtransparency/data-transparency-ui#v1.3.7", "date-fns": "^2.16.1", "file-loader": "^3.0.1", "fixed-data-table": "0.6.3", From 33c1653c9e5810c70553dec9caa333da10357e8f Mon Sep 17 00:00:00 2001 From: Lizzie Salita Date: Thu, 21 Jan 2021 11:02:58 -0500 Subject: [PATCH 38/69] Hide the modal button when number of unlinked awards is 0 --- src/js/containers/aboutTheData/AgenciesContainer.jsx | 8 ++++---- src/js/containers/aboutTheData/AgencyDetailsContainer.jsx | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/js/containers/aboutTheData/AgenciesContainer.jsx b/src/js/containers/aboutTheData/AgenciesContainer.jsx index 69fc331f03..0aa62bb064 100644 --- a/src/js/containers/aboutTheData/AgenciesContainer.jsx +++ b/src/js/containers/aboutTheData/AgenciesContainer.jsx @@ -264,7 +264,7 @@ const AgenciesContainer = ({ fiscalYear: selectedFy, fiscalPeriod: selectedPeriod?.id }} />), - (), - () : (
{unlinkedContracts}
), + unlinkedAssistance !== '0' ? (), + }} />) : (
{unlinkedAssistance}
), (
) ]); diff --git a/src/js/containers/aboutTheData/AgencyDetailsContainer.jsx b/src/js/containers/aboutTheData/AgencyDetailsContainer.jsx index 1f3800be8b..8ef7e211e0 100644 --- a/src/js/containers/aboutTheData/AgencyDetailsContainer.jsx +++ b/src/js/containers/aboutTheData/AgencyDetailsContainer.jsx @@ -155,7 +155,7 @@ const AgencyDetailsContainer = ({ agencyName, agencyCode }} />), - (), - () : (
{rowData.unlinkedContracts}
), + rowData._unlinkedAssistance !== 0 ? (), + }} />) : (
{rowData.unlinkedAssistance}
), (
) ]); }) From 6e1c545175cc8f90a7707f4dbedd3d3a048ef5c7 Mon Sep 17 00:00:00 2001 From: Lizzie Salita Date: Thu, 21 Jan 2021 12:05:42 -0500 Subject: [PATCH 39/69] design review feedback - right-align percent col --- src/_scss/components/_stickyTable.scss | 1 + .../pages/aboutTheData/agencyDetailsPage.scss | 5 - .../aboutTheData/AgencyDetailsContainer.jsx | 172 ++++++------------ .../aboutTheData/AgencyTableMapping.jsx | 132 +++++++++----- 4 files changed, 143 insertions(+), 167 deletions(-) diff --git a/src/_scss/components/_stickyTable.scss b/src/_scss/components/_stickyTable.scss index f718d3f143..d3c9f76dd7 100644 --- a/src/_scss/components/_stickyTable.scss +++ b/src/_scss/components/_stickyTable.scss @@ -49,6 +49,7 @@ padding: 1.2rem; @import '../pages/aboutTheData/actionCell'; .generic-cell-content { + padding-right: 2.4rem; .not-certified { margin-left: rem(5); background: #dce4ee; diff --git a/src/_scss/pages/aboutTheData/agencyDetailsPage.scss b/src/_scss/pages/aboutTheData/agencyDetailsPage.scss index a2ea751f96..23d30d5623 100644 --- a/src/_scss/pages/aboutTheData/agencyDetailsPage.scss +++ b/src/_scss/pages/aboutTheData/agencyDetailsPage.scss @@ -45,11 +45,6 @@ display: none; } } - tbody .usda-table__row .usda-table__cell:nth-of-type(2) { - // center-align the percentage column - padding: 0; // to allow entire cell to be hoverable - text-align: center; - } } .agency-table-download { diff --git a/src/js/containers/aboutTheData/AgencyDetailsContainer.jsx b/src/js/containers/aboutTheData/AgencyDetailsContainer.jsx index c7ef5d4115..53123c6cf7 100644 --- a/src/js/containers/aboutTheData/AgencyDetailsContainer.jsx +++ b/src/js/containers/aboutTheData/AgencyDetailsContainer.jsx @@ -5,85 +5,14 @@ import React, { useRef, useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import { isCancel } from 'axios'; -import { Table, TooltipComponent, TooltipWrapper, Pagination } from 'data-transparency-ui'; +import { Table, Pagination } from 'data-transparency-ui'; import { throttle } from 'lodash'; import { fetchAgency } from 'helpers/aboutTheDataHelper'; import BaseReportingPeriodRow from 'models/v2/aboutTheData/BaseReportingPeriodRow'; import AgencyDownloadLinkCell from 'components/aboutTheData/AgencyDownloadLinkCell'; import CellWithModal from 'components/aboutTheData/CellWithModal'; -import { columnTooltips } from 'components/aboutTheData/dataMapping/tooltipContentMapping'; - -const Tooltip = ({ title, position = "right" }) => ( - - {columnTooltips[title]} - - )} /> -); - -Tooltip.propTypes = { - title: PropTypes.string.isRequired, - position: PropTypes.oneOf(['left', 'right']) -}; - -const columns = [ - { - title: "fiscal_year", - displayName: "Reporting Period" - }, - { - title: "percent_of_total_budgetary_resources", - displayName: "Percent of Total Federal Budget" - }, - { - title: "recent_publication_date", - displayName: "Most Recent Update", - icon: () - }, - { - title: "missing_tas_accounts_count", - displayName: "Number of TASs Missing from Account Balance Data", - icon: ( - - ), - right: true - }, - { - title: "obligation_difference", - displayName: "Reporting Difference in Obligations", - icon: ( - - ), - right: true - }, - { - title: "unlinked_cont_award_count", - displayName: "Number of Unlinked Contract Awards", - icon: ( - - ), - right: true - }, - { - title: "unlinked_asst_award_count", - displayName: "Number of Unlinked Assistance Awards", - icon: ( - - ), - right: true - }, - { - title: "assurance_statements", - displayName: "Agency Comments", - icon: ( - - ) - } -]; +import { agencyDetailsColumns } from './AgencyTableMapping'; const propTypes = { agencyName: PropTypes.string, @@ -91,11 +20,15 @@ const propTypes = { agencyCode: PropTypes.string }; -const AgencyDetailsContainer = ({ - modalClick, agencyName, agencyCode -}) => { - const [sortStatus, updateSort] = useState({ field: 'current_total_budget_authority_amount', direction: 'desc' }); - const [{ vertical: isVertialSticky, horizontal: isHorizontalSticky }, setIsSticky] = useState({ vertical: false, horizontal: false }); +const AgencyDetailsContainer = ({ modalClick, agencyName, agencyCode }) => { + const [sortStatus, updateSort] = useState({ + field: 'current_total_budget_authority_amount', + direction: 'desc' + }); + const [{ vertical: isVertialSticky, horizontal: isHorizontalSticky }, setIsSticky] = useState({ + vertical: false, + horizontal: false + }); const [rows, setRows] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(false); @@ -117,14 +50,14 @@ const AgencyDetailsContainer = ({ const verticalStickyClass = isVertialSticky ? 'sticky-y-table' : ''; const horizontalStickyClass = isHorizontalSticky ? 'sticky-x-table' : ''; - const parseRows = (results) => ( + const parseRows = (results) => results.map((row) => { const rowData = Object.create(BaseReportingPeriodRow); rowData.populate(row); - return ([ - (
{ rowData.reportingPeriod }
), - (
{ rowData.percentOfBudget }
), - ({rowData.reportingPeriod}, +
{rowData.percentOfBudget}
, + ), - (, + ), - (, + ), - rowData._unlinkedContracts !== 0 ? () : (
{rowData.unlinkedContracts}
), - rowData._unlinkedAssistance !== 0 ? () : (
{rowData.unlinkedAssistance}
), - (
) - ]); - }) - ); + }} />, + rowData._unlinkedContracts !== 0 ? ( + + ) : ( +
{rowData.unlinkedContracts}
+ ), + rowData._unlinkedAssistance !== 0 ? ( + + ) : ( +
{rowData.unlinkedAssistance}
+ ), +
+ +
+ ]; + }); const fetchTableData = () => { if (tableRequest.current) { @@ -230,7 +172,7 @@ const AgencyDetailsContainer = ({ ( +const Tooltip = ({ title, position = 'right' }) => ( - {columnTooltips[title]} - - )} /> + tooltipComponent={ + {columnTooltips[title]} + } /> ); Tooltip.propTypes = { @@ -25,13 +23,16 @@ Tooltip.propTypes = { }; export const agenciesTableColumns = { - publications: (fy) => ([ - { title: 'agency_name', displayName: 'Agency Name' }, - { title: 'current_total_budget_authority_amount', displayName: 'Percent of Total Federal Budget' }, + publications: (fy) => [ + { title: 'agency_name', displayName: 'Agency Name' }, + { + title: 'current_total_budget_authority_amount', + displayName: 'Percent of Total Federal Budget' + }, { title: 'Q1', displayName: `FY ${fy} Q1`, - columnSpan: "3", + columnSpan: '3', subColumnNames: [ { displayName: 'P1', title: 'publication_date,1' }, { displayName: 'P2', title: 'publication_date,2' }, @@ -41,7 +42,7 @@ export const agenciesTableColumns = { { title: 'Q2', displayName: `FY ${fy} Q2`, - columnSpan: "3", + columnSpan: '3', subColumnNames: [ { displayName: 'P4', title: 'publication_date,4' }, { displayName: 'P5', title: 'publication_date,5' }, @@ -51,7 +52,7 @@ export const agenciesTableColumns = { { title: 'Q3', displayName: `FY ${fy} Q3`, - columnSpan: "3", + columnSpan: '3', subColumnNames: [ { displayName: 'P7', title: 'publication_date,7' }, { displayName: 'P8', title: 'publication_date,8' }, @@ -61,67 +62,104 @@ export const agenciesTableColumns = { { title: 'Q4', displayName: `FY ${fy} Q4`, - columnSpan: "3", + columnSpan: '3', subColumnNames: [ { displayName: 'P10', title: 'publication_date,10' }, { displayName: 'P11', title: 'publication_date,11' }, { displayName: 'P12', title: 'publication_date,12' } ] } - ]), + ], submissions: [ { - title: "agency_name", - displayName: "Agency Name" + title: 'agency_name', + displayName: 'Agency Name' }, { - title: "current_total_budget_authority_amount", - displayName: "Percent of Total Federal Budget" + title: 'current_total_budget_authority_amount', + displayName: 'Percent of Total Federal Budget', + right: true }, { - title: "recent_publication_date", - displayName: "Most Recent Update", - icon: () + title: 'recent_publication_date', + displayName: 'Most Recent Update', + icon: }, { - title: "missing_tas_accounts_count", - displayName: "Number of TAS Missing from Account Balance Data", - icon: ( - - ), + title: 'missing_tas_accounts_count', + displayName: 'Number of TAS Missing from Account Balance Data', + icon: , right: true }, { - title: "obligation_difference", - displayName: "Reporting Difference in Obligations", - icon: ( - - ), + title: 'obligation_difference', + displayName: 'Reporting Difference in Obligations', + icon: , right: true }, { - title: "unlinked_contract_award_count", - displayName: "Number of Unlinked Contract Awards", - icon: ( - - ), + title: 'unlinked_contract_award_count', + displayName: 'Number of Unlinked Contract Awards', + icon: , right: true }, { - title: "unlinked_assistance_award_count", - displayName: "Number of Unlinked Assistance Awards", - icon: ( - - ), + title: 'unlinked_assistance_award_count', + displayName: 'Number of Unlinked Assistance Awards', + icon: , right: true }, { - title: "assurance_statements", - displayName: "Agency Comments", - icon: ( - - ), + title: 'assurance_statements', + displayName: 'Agency Comments', + icon: , right: true } ] }; + +export const agencyDetailsColumns = [ + { + title: 'fiscal_year', + displayName: 'Reporting Period' + }, + { + title: 'percent_of_total_budgetary_resources', + displayName: 'Percent of Total Federal Budget', + right: true + }, + { + title: 'recent_publication_date', + displayName: 'Most Recent Update', + icon: + }, + { + title: 'missing_tas_accounts_count', + displayName: 'Number of TASs Missing from Account Balance Data', + icon: , + right: true + }, + { + title: 'obligation_difference', + displayName: 'Reporting Difference in Obligations', + icon: , + right: true + }, + { + title: 'unlinked_cont_award_count', + displayName: 'Number of Unlinked Contract Awards', + icon: , + right: true + }, + { + title: 'unlinked_asst_award_count', + displayName: 'Number of Unlinked Assistance Awards', + icon: , + right: true + }, + { + title: 'assurance_statements', + displayName: 'Agency Comments', + icon: + } +]; From bca3872ad40ec6e6b3fc3269a85da4394564f0d4 Mon Sep 17 00:00:00 2001 From: Lizzie Salita Date: Thu, 21 Jan 2021 13:18:26 -0500 Subject: [PATCH 40/69] further consolidated scss --- .../pages/aboutTheData/_agenciesPage.scss | 30 ++ .../aboutTheData/_agencyDetailsPage.scss | 62 ++++ .../pages/aboutTheData/_tableControls.scss | 210 +++++++++++++ .../pages/aboutTheData/aboutTheData.scss | 59 ++++ .../pages/aboutTheData/agenciesPage.scss | 284 ------------------ .../pages/aboutTheData/agencyDetailsPage.scss | 131 -------- .../aboutTheData/AboutTheDataPage.jsx | 4 +- .../aboutTheData/AgencyDetailsPage.jsx | 4 +- 8 files changed, 365 insertions(+), 419 deletions(-) create mode 100644 src/_scss/pages/aboutTheData/_agenciesPage.scss create mode 100644 src/_scss/pages/aboutTheData/_agencyDetailsPage.scss create mode 100644 src/_scss/pages/aboutTheData/_tableControls.scss create mode 100644 src/_scss/pages/aboutTheData/aboutTheData.scss delete mode 100644 src/_scss/pages/aboutTheData/agenciesPage.scss delete mode 100644 src/_scss/pages/aboutTheData/agencyDetailsPage.scss diff --git a/src/_scss/pages/aboutTheData/_agenciesPage.scss b/src/_scss/pages/aboutTheData/_agenciesPage.scss new file mode 100644 index 0000000000..1d06aeb30e --- /dev/null +++ b/src/_scss/pages/aboutTheData/_agenciesPage.scss @@ -0,0 +1,30 @@ +.heading-container { + .header { + margin-top: rem(30); + font-size: rem(24); + } + .sub-header { + color: $color-base; + font-size: rem(16); + font-weight: 300; + letter-spacing: 0; + line-height: rem(24); + margin-top: 0; + margin-bottom: rem(30); + max-width: rem(769); + } +} +@import './tableControls'; +.table-container.table-container_submissions .usda-table.usda-table-w-grid { + // Styles specific to the "Statistics by Reporting Period" tab + thead { + th { + &:last-of-type { + // Hide sorting for the Agency Comments column + .table-header__sort { + display: none; + } + } + } + } +} diff --git a/src/_scss/pages/aboutTheData/_agencyDetailsPage.scss b/src/_scss/pages/aboutTheData/_agencyDetailsPage.scss new file mode 100644 index 0000000000..6b3c6bc39e --- /dev/null +++ b/src/_scss/pages/aboutTheData/_agencyDetailsPage.scss @@ -0,0 +1,62 @@ +.heading-container { + .header { + margin-top: rem(10); + font-size: rem(32); + } + .back-link { + margin-top: rem(20); + margin-bottom: rem(20); + font-size: rem(18); + font-weight: 400; + letter-spacing: 0; + line-height: rem(23); + a { + text-decoration: none; + } + } + .agency-info { + width: 100%; + @include display(inline-flex); + @include flex-wrap(wrap); + margin-bottom: rem(30); + @media (max-width: $tablet-screen) { + margin-top: rem(10); + } + .more-info-note { + margin: 0; + padding: 0; + letter-spacing: 0; + font-size: rem(14); + line-height: rem(18); + } + + .agency-info__group { + &:first-of-type { + padding-right: rem(60); + } + h5 { + @include flex-wrap(wrap); + font-size: rem(16); + font-weight: 600; + line-height: rem(20); + margin: rem(5) 0; + } + + .agency-info__website { + font-size: rem(14); + line-height: rem(20); + margin: rem(14) 0; + @import 'components/externalLink'; + } + } + } +} + +.table-container .usda-table.usda-table-w-grid { + thead th:last-of-type { + // Hide sorting for the Agency Comments column + .table-header__sort { + display: none; + } + } +} diff --git a/src/_scss/pages/aboutTheData/_tableControls.scss b/src/_scss/pages/aboutTheData/_tableControls.scss new file mode 100644 index 0000000000..79dd9f99b8 --- /dev/null +++ b/src/_scss/pages/aboutTheData/_tableControls.scss @@ -0,0 +1,210 @@ +.table-controls { + max-width: 100%; + .usa-dt-tabs-mobile .usa-dt-picker__list, + .tooltip-spacer { + z-index: 12; + } + .usa-dt-tab-toggle:focus { + outline: none; + } + .table-controls__time-and-search { + padding-left: 0; + @media (min-width: $medium-screen) { + padding-left: rem(25); + } + margin-top: rem(25); + @include display(flex); + @include justify-content(flex-start); + @include align-items(flex-start); + @include flex-wrap(wrap); + @include media($tablet-screen) { + @include flex-wrap(nowrap); + } + .filter-container { + @include display(flex); + @include flex-direction(column); + .filter__title { + font-size: rem(14); + margin-left: rem(15); + color: #8c8c8c; + } + .period-picker, + .fy-picker { + .usa-dt-picker__button-icon svg { + color: #0074be; + } + .fy-loading { + svg { + margin-left: rem(10); + } + } + .usa-dt-picker__list { + z-index: 12; + min-width: rem(110); + } + .usa-dt-picker__button { + border-bottom: rem(2) solid #0074be; + margin-bottom: rem(20); + padding-bottom: rem(2); + .usa-dt-picker__button-text { + font-size: rem(18); + font-weight: 500; + line-height: rem(23); + color: $color-base; + } + } + .usa-dt-picker__list li.usa-dt-picker__list-item { + border: none; + .usa-dt-picker__item { + font-size: rem(14); + } + } + } + .period-picker { + .order-1 { + order: 1; + } + .order-2 { + order: 2; + } + .order-3 { + order: 3; + } + .order-4 { + order: 4; + } + .order-5 { + order: 5; + } + .order-6 { + order: 6; + } + .order-7 { + order: 7; + } + .order-8 { + order: 8; + } + .order-9 { + order: 9; + } + .order-10 { + order: 10; + } + .order-11 { + order: 11; + } + .usa-dt-picker__list { + @include display(flex); + @include flex-direction(column); + } + .usa-dt-picker__list li.usa-dt-picker__list-item { + &.last { + border-bottom: 1px solid $color-gray-lighter; + } + + button.usa-dt-picker__item { + padding: 0; + .period { + padding: rem(10) rem(15); + @include display(flex); + @include justify-content(flex-end); + &:not(.last) span { + width: 75%; + } + &.last span { + &:first-of-type { + font-weight: $font-semibold; + margin-right: auto; + } + &:last-of-type { + width: 75%; + } + } + &.disabled { + cursor: not-allowed; + span { + opacity: 0.4; + } + &:hover { + background-color: $color-white; + } + span { + color: $color-base; + } + } + } + } + &.quarter-selected-3:hover ~ .not-individually-selectable-p2 { + .usa-dt-picker__item .period.disabled { + background-color: $color-gray-lightest; + } + } + &.quarter-selected-6:hover { + & ~ .not-individually-selectable-p4, + & ~ .not-individually-selectable-p5 { + .usa-dt-picker__item .period.disabled { + background-color: $color-gray-lightest; + } + } + } + &.quarter-selected-9:hover { + & ~ .not-individually-selectable-p7, + & ~ .not-individually-selectable-p8 { + .usa-dt-picker__item .period.disabled { + background-color: $color-gray-lightest; + } + } + } + &.quarter-selected-12:hover { + & ~ .not-individually-selectable-p10, + & ~ .not-individually-selectable-p11 { + .usa-dt-picker__item .period.disabled { + background-color: $color-gray-lightest; + } + } + } + } + } + .usa-dt-search-bar { + padding: 0; + margin: rem(10) 0 rem(10) rem(15); + width: 100%; + height: rem(30); + border-radius: rem(3); + @include media($tablet-screen) { + width: rem(273); + margin: rem(10) 0 0 rem(15); + } + .usa-dt-search-bar__input { + padding: 0; + text-indent: rem(3); + &:focus { + outline: none; + } + } + .usa-dt-search-bar__button { + @include display(flex); + svg { + font-size: rem(17); + } + } + } + } + } + .table-type-toggle:focus { + outline: none; + } + .table-tab-label { + @include display(flex); + } + .tooltip-wrapper { + display: none; + @media (min-width: $tablet-screen) { + @include display(flex); + } + } + .usa-dt-picker__list { + max-width: rem(500); + } +} diff --git a/src/_scss/pages/aboutTheData/aboutTheData.scss b/src/_scss/pages/aboutTheData/aboutTheData.scss new file mode 100644 index 0000000000..a7de7dc00b --- /dev/null +++ b/src/_scss/pages/aboutTheData/aboutTheData.scss @@ -0,0 +1,59 @@ +.about-the-data { + @import 'all'; + @import 'layouts/default/default'; + @import 'layouts/default/stickyHeader/header'; + .main-content { + @import '../../mixins/fullSectionWrap'; + @include display(flex); + @include flex-wrap(wrap); + @include flex-direction(column); + width: 100%; + max-width: 160rem; + border-radius: rem(5) rem(5) 0 0; + background: $color-white; + padding: 0 rem(20); + margin: rem(40) auto; + .heading-container { + width: 100%; + .header { + margin-bottom: 0; + font-weight: $font-semibold; + letter-spacing: 0; + line-height: rem(59); + } + } + } + &.about-the-data_agencies-page { + @import './_agenciesPage'; + } + &.about-the-data_agency-details-page { + @import './_agencyDetailsPage'; + } + @import 'components/Note'; + .default-note { + font-style: italic; + margin-top: 0; + padding: 0; + letter-spacing: 0; + max-width: rem(873); + line-height: rem(22); + font-size: rem(14); + margin-bottom: rem(10); + @media (min-width: $tablet-screen) { + margin-bottom: rem(30); + } + } + .table-container { + max-width: 100%; + } + .usda-message { + background-color: $color-white; + width: 100vw; + } + @import 'components/stickyTable'; + .agency-table-download { + svg { + margin-right: rem(5); + } + } +} diff --git a/src/_scss/pages/aboutTheData/agenciesPage.scss b/src/_scss/pages/aboutTheData/agenciesPage.scss deleted file mode 100644 index dc2c5ac8c5..0000000000 --- a/src/_scss/pages/aboutTheData/agenciesPage.scss +++ /dev/null @@ -1,284 +0,0 @@ -.usa-da__about-the-data__agencies-page { - @import "all"; - @import "layouts/default/default"; - @import "layouts/default/stickyHeader/header"; - .main-content { - @import "../../mixins/fullSectionWrap"; - @include display(flex); - @include flex-wrap(wrap); - @include flex-direction(column); - width: 100%; - max-width: 160rem; - border-radius: rem(5) rem(5) 0 0; - background: $color-white; - padding: 0 rem(20); - margin: rem(40) auto; - .heading-container { - width: 100%; - .header { - margin-top: rem(30); - margin-bottom: 0; - font-weight: $font-semibold; - font-size: rem(24); - letter-spacing: 0; - line-height: rem(59); - } - .sub-header { - color: $color-base; - font-size: rem(16); - font-weight: 300; - letter-spacing: 0; - line-height: rem(24); - margin-top: 0; - margin-bottom: rem(30); - max-width: rem(769); - } - } - .table-container, - .table-controls { - max-width: 100%; - } - .table-controls { - .usa-dt-tabs-mobile .usa-dt-picker__list, - .tooltip-spacer { - z-index: 12; - } - .usa-dt-tab-toggle:focus { - outline: none; - } - .table-controls__time-and-search { - padding-left: 0; - @media (min-width: $medium-screen) { - padding-left: rem(25); - } - margin-top: rem(25); - @include display(flex); - @include justify-content(flex-start); - @include align-items(flex-start); - @include flex-wrap(wrap); - @include media($tablet-screen) { - @include flex-wrap(nowrap); - } - .filter-container { - @include display(flex); - @include flex-direction(column); - .filter__title { - font-size: rem(14); - margin-left: rem(15); - color: #8C8C8C; - } - .period-picker, - .fy-picker { - .usa-dt-picker__button-icon svg { - color: #0074BE; - } - .fy-loading { - svg { - margin-left: rem(10); - } - } - .usa-dt-picker__list { - z-index: 12; - min-width: rem(110); - } - .usa-dt-picker__button { - border-bottom: rem(2) solid #0074BE; - margin-bottom: rem(20); - padding-bottom: rem(2); - .usa-dt-picker__button-text { - font-size: rem(18); - font-weight: 500; - line-height: rem(23); - color: $color-base; - } - } - .usa-dt-picker__list li.usa-dt-picker__list-item { - border: none; - .usa-dt-picker__item { - font-size: rem(14); - } - } - } - .period-picker { - .order-1 { - order: 1; - } - .order-2 { - order: 2; - } - .order-3 { - order: 3; - } - .order-4 { - order: 4; - } - .order-5 { - order: 5; - } - .order-6 { - order: 6; - } - .order-7 { - order: 7; - } - .order-8 { - order: 8; - } - .order-9 { - order: 9; - } - .order-10 { - order: 10; - } - .order-11 { - order: 11; - } - .usa-dt-picker__list { - @include display(flex); - @include flex-direction(column); - } - .usa-dt-picker__list li.usa-dt-picker__list-item { - &.last { - border-bottom: 1px solid $color-gray-lighter; - } - - button.usa-dt-picker__item { - padding: 0; - .period { - padding: rem(10) rem(15); - @include display(flex); - @include justify-content(flex-end); - &:not(.last) span { - width: 75%; - } - &.last span { - &:first-of-type { - font-weight: $font-semibold; - margin-right: auto; - } - &:last-of-type { - width: 75%; - } - } - &.disabled { - cursor: not-allowed; - span { - opacity: 0.4; - } - &:hover { - background-color: $color-white; - } - span { - color: $color-base; - } - } - } - } - &.quarter-selected-3:hover ~ .not-individually-selectable-p2 { - .usa-dt-picker__item .period.disabled { - background-color: $color-gray-lightest; - } - } - &.quarter-selected-6:hover { - & ~ .not-individually-selectable-p4, - & ~ .not-individually-selectable-p5 { - .usa-dt-picker__item .period.disabled { - background-color: $color-gray-lightest; - } - } - } - &.quarter-selected-9:hover { - & ~ .not-individually-selectable-p7, - & ~ .not-individually-selectable-p8 { - .usa-dt-picker__item .period.disabled { - background-color: $color-gray-lightest; - } - } - } - &.quarter-selected-12:hover { - & ~ .not-individually-selectable-p10, - & ~ .not-individually-selectable-p11 { - .usa-dt-picker__item .period.disabled { - background-color: $color-gray-lightest; - } - } - } - } - } - .usa-dt-search-bar { - padding: 0; - margin: rem(10) 0 rem(10) rem(15); - width: 100%; - height: rem(30); - border-radius: rem(3); - @include media($tablet-screen) { - width: rem(273); - margin: rem(10) 0 0 rem(15); - } - .usa-dt-search-bar__input { - padding: 0; - text-indent: rem(3); - &:focus { - outline: none; - } - } - .usa-dt-search-bar__button { - @include display(flex); - svg { - font-size: rem(17); - } - } - } - } - } - .table-type-toggle:focus { - outline: none; - } - .table-tab-label { - @include display(flex); - } - .tooltip-wrapper { - display: none; - @media (min-width: $tablet-screen) { - @include display(flex); - } - } - .usa-dt-picker__list { - max-width: rem(500); - } - } - @import 'components/stickyTable'; - .table-container.table-container_submissions .usda-table.usda-table-w-grid { - // Styles specific to the "Statistics by Reporting Period" tab - thead { - th { - &:last-of-type { - // Hide sorting for the Agency Comments column - .table-header__sort { - display: none; - } - } - } - } - .agency-table-download { - svg { - margin-right: rem(5); - } - } - } - @import 'components/Note'; - .default-note { - font-style: italic; - margin-top: 0; - padding: 0; - letter-spacing: 0; - max-width: rem(873); - line-height: rem(22); - font-size: rem(14); - margin-bottom: rem(10); - @media(min-width: $tablet-screen) { - margin-bottom: rem(30); - } - } - } -} diff --git a/src/_scss/pages/aboutTheData/agencyDetailsPage.scss b/src/_scss/pages/aboutTheData/agencyDetailsPage.scss deleted file mode 100644 index 23d30d5623..0000000000 --- a/src/_scss/pages/aboutTheData/agencyDetailsPage.scss +++ /dev/null @@ -1,131 +0,0 @@ -.usa-da-about-the-data_agency-details-page { - @import "all"; - @import "layouts/default/default"; - @import "layouts/default/stickyHeader/header"; - .main-content { - @import "../../mixins/fullSectionWrap"; - @include display(flex); - @include flex-wrap(wrap); - @include flex-direction(column); - margin: rem(40) auto; - background: $color-white; - border-radius: 0.5rem 0.5rem 0 0; - padding: 0 rem(20); - width: 100%; - max-width: 160rem; - .usda-message { - background-color: $color-white; - width: 100vw; - } - .table-container, - .table-controls { - width: 100%; - } - .table-controls { - .table-type-toggle:focus { - outline: none; - } - .table-tab-label { - @include display(flex); - } - .tooltip-wrapper { - display: none; - @media (min-width: $tablet-screen) { - @include display(flex); - } - } - } - - @import 'components/stickyTable'; - - .table-container .usda-table.usda-table-w-grid { - thead th:last-of-type { - // Hide sorting for the Agency Comments column - .table-header__sort { - display: none; - } - } - } - - .agency-table-download { - svg { - margin-right: rem(5); - } - } - - .heading-container { - .header { - margin-top: rem(10); - margin-bottom: 0; - font-weight: $font-semibold; - font-size: rem(32); - letter-spacing: 0; - line-height: rem(59); - } - .back-link { - margin-top: rem(20); - margin-bottom: rem(20); - font-size: rem(18); - font-weight: 400; - letter-spacing: 0; - line-height: rem(23); - a { - text-decoration: none; - } - } - .sub-header { - margin-top: 0; - margin-bottom: rem(30); - font-size: rem(47); - font-weight: 300; - letter-spacing: 0; - line-height: rem(59); - } - .agency-info { - width: 100%; - @include display(inline-flex); - @include flex-wrap(wrap); - margin-bottom: rem(30); - @media (max-width: $tablet-screen) { - margin-top: rem(10); - } - .more-info-note { - margin: 0; - padding: 0; - letter-spacing: 0; - font-size: rem(14); - line-height: rem(18); - } - - .agency-info__group { - &:first-of-type { - padding-right: rem(60); - } - h5 { - @include flex-wrap(wrap); - font-size: rem(16); - font-weight: 600; - line-height: rem(20); - margin: rem(5) 0; - } - - .agency-info__website { - font-size: rem(14); - line-height: rem(20); - margin: rem(14) 0; - @import 'components/externalLink'; - } - } - } - } - @import 'components/Note'; - .default-note { - font-style: italic; - margin: 0; - padding: rem(30) rem(15); - letter-spacing: 0; - line-height: rem(22); - max-width: rem(873); - } - } - } diff --git a/src/js/components/aboutTheData/AboutTheDataPage.jsx b/src/js/components/aboutTheData/AboutTheDataPage.jsx index 8fba6517ba..8e7d29c928 100644 --- a/src/js/components/aboutTheData/AboutTheDataPage.jsx +++ b/src/js/components/aboutTheData/AboutTheDataPage.jsx @@ -20,7 +20,7 @@ import { modalTitles, modalClassNames } from 'dataMapping/aboutTheData/modals'; import { tabTooltips } from './dataMapping/tooltipContentMapping'; import TimeFilters from "./TimeFilters"; -require("pages/aboutTheData/agenciesPage.scss"); +require("pages/aboutTheData/aboutTheData.scss"); const TableTabLabel = ({ label }) => { const tooltipComponent = ( @@ -98,7 +98,7 @@ const AboutTheDataPage = ({ }; return ( -
+
diff --git a/src/js/components/aboutTheData/AgencyDetailsPage.jsx b/src/js/components/aboutTheData/AgencyDetailsPage.jsx index 3cc50c1dcb..954ddc6324 100644 --- a/src/js/components/aboutTheData/AgencyDetailsPage.jsx +++ b/src/js/components/aboutTheData/AgencyDetailsPage.jsx @@ -21,7 +21,7 @@ import BaseAgencyOverview from 'models/v2/agencyV2/BaseAgencyOverview'; import ExternalLink from 'components/sharedComponents/ExternalLink'; import AboutTheDataModal from './AboutTheDataModal'; -require('pages/aboutTheData/agencyDetailsPage.scss'); +require('pages/aboutTheData/aboutTheData.scss'); const message = 'All numeric figures in this table are calculated based on the set of TAS owned by each agency, as opposed to the set of TAS that the agency directly reported to USAspending.gov. In the vast majority of cases, these are exactly the same (upwards of 95% of TAS—with these TAS representing over 99% of spending—are submitted and owned by the same agency). This display decision is consistent with our practice throughout the website of grouping TAS by the owning agency rather than the reporting agency. While reporting agencies are not identified in this table, they are available in the Custom Account Download in the reporting_agency_name field.'; @@ -78,7 +78,7 @@ const AgencyDetailsPage = () => { }, [agencyCode]); return ( -
+
From d5a69f7a8fb358c88cbe6b98b97a8ff97733f884 Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Wed, 20 Jan 2021 14:33:25 -0500 Subject: [PATCH 41/69] [DEV-6662] removing glossary from header FloatingGlossaryButton -- using .site-logo for measuring when to show the glossary button on the bottom of the screen. This was necessary because we are no longer showing the glossary button in the header NavBar -- removing Glossary Button from header --- .../FloatingGlossaryButton.jsx | 2 +- .../sharedComponents/header/Dropdown.jsx | 138 +++++++-------- .../sharedComponents/header/DropdownItem.jsx | 160 ++++++++++-------- .../sharedComponents/header/NavBar.jsx | 13 +- src/js/dataMapping/navigation/menuOptions.jsx | 71 ++++++-- 5 files changed, 214 insertions(+), 170 deletions(-) diff --git a/src/js/components/sharedComponents/FloatingGlossaryButton.jsx b/src/js/components/sharedComponents/FloatingGlossaryButton.jsx index 75f594fd19..9eda11f533 100644 --- a/src/js/components/sharedComponents/FloatingGlossaryButton.jsx +++ b/src/js/components/sharedComponents/FloatingGlossaryButton.jsx @@ -47,7 +47,7 @@ export default class FloatingGlossaryButton extends React.Component { pageScrolled() { // find the header glossary button - const header = document.getElementById('header-glossary-button'); + const header = document.querySelector('.site-logo'); const headerBottom = header.getBoundingClientRect().top + (header.offsetHeight * 0.5); if (headerBottom <= 0 && this.state.hide) { diff --git a/src/js/components/sharedComponents/header/Dropdown.jsx b/src/js/components/sharedComponents/header/Dropdown.jsx index e46977f477..b3a170e432 100644 --- a/src/js/components/sharedComponents/header/Dropdown.jsx +++ b/src/js/components/sharedComponents/header/Dropdown.jsx @@ -3,12 +3,12 @@ * Created by Kevin Li 1/18/18 */ -import React from 'react'; +import React, { useState } from 'react'; import PropTypes from 'prop-types'; -import kGlobalConstants from 'GlobalConstants'; import { AngleDown } from 'components/sharedComponents/icons/Icons'; import DropdownItem from './DropdownItem'; +import { labelsWithNewBadge } from '../../../dataMapping/navigation/menuOptions'; const propTypes = { label: PropTypes.string.isRequired, @@ -16,88 +16,74 @@ const propTypes = { items: PropTypes.array.isRequired }; -export default class Dropdown extends React.Component { - constructor(props) { - super(props); +const Dropdown = ({ + label, + title, + items +}) => { + const [expanded, setExpanded] = useState(false); - this.state = { - expanded: false - }; + const clickedButton = () => { + setExpanded(!expanded); + }; - this.clickedButton = this.clickedButton.bind(this); - this.expandMenu = this.expandMenu.bind(this); - this.collapseMenu = this.collapseMenu.bind(this); - } - - clickedButton() { - this.setState({ - expanded: !this.state.expanded - }); - } + const expandMenu = () => { + setExpanded(true); + }; - expandMenu() { - this.setState({ - expanded: true - }); - } + const collapseMenu = () => { + setExpanded(false); + }; - collapseMenu() { - this.setState({ - expanded: false - }); + let activeChildren = ''; + let activeParent = ''; + let iconAlt = 'Collapsed menu'; + if (expanded) { + activeChildren = 'nav-children_active'; + activeParent = 'nav-dropdown__parent_active'; + iconAlt = 'Expanded menu'; } - render() { - let activeChildren = ''; - let activeParent = ''; - let iconAlt = 'Collapsed menu'; - if (this.state.expanded) { - activeChildren = 'nav-children_active'; - activeParent = 'nav-dropdown__parent_active'; - iconAlt = 'Expanded menu'; - } - - const items = this.props.items.map((item, index) => ( - - )); - - return ( -
- -
-
    - {items} -
+
+ } + {label}
+
+ +
+ +
+
    + {items.map((item, index) => ( + + ))} +
- ); - } -} +
+ ); +}; Dropdown.propTypes = propTypes; + +export default Dropdown; + diff --git a/src/js/components/sharedComponents/header/DropdownItem.jsx b/src/js/components/sharedComponents/header/DropdownItem.jsx index ed75cac05a..ae0f94bef9 100644 --- a/src/js/components/sharedComponents/header/DropdownItem.jsx +++ b/src/js/components/sharedComponents/header/DropdownItem.jsx @@ -5,7 +5,7 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { Link } from 'react-router-dom'; +import { Link, useLocation } from 'react-router-dom'; import Analytics from 'helpers/analytics/Analytics'; import * as redirectHelper from 'helpers/redirectHelper'; @@ -16,9 +16,11 @@ const propTypes = { url: PropTypes.string, label: PropTypes.node, enabled: PropTypes.bool, - newTab: PropTypes.bool, + shouldOpenNewTab: PropTypes.bool, + isNewTab: PropTypes.bool, isFirst: PropTypes.bool, - externalLink: PropTypes.bool + externalLink: PropTypes.bool, + appendToExistingUrl: PropTypes.bool }; const clickedHeaderLink = (route) => { @@ -28,84 +30,102 @@ const clickedHeaderLink = (route) => { }); }; -export default class DropdownItem extends React.Component { - constructor(props) { - super(props); - - this.redirect = this.redirect.bind(this); +const DropdownItem = ({ + url, + label, + enabled = true, + shouldOpenNewTab = false, + externalLink = false, + isFirst = false, + isNewTab = false, + appendToExistingUrl = false +}) => { + const { pathname } = useLocation(); + const newUrl = appendToExistingUrl ? `${pathname}/${url}` : url; + + const handleClick = () => { + redirectHelper.showRedirectModal(newUrl); + clickedHeaderLink(newUrl); + }; + + let className = 'nav-children__link_disabled'; + let comingSoon = ( +
+ +
+ ); + + const newLabel = isNewTab && enabled + ? ( + + {label} + NEW + + ) + : null; + + if (enabled) { + className = ''; + comingSoon = null; } - redirect() { - redirectHelper.showRedirectModal(this.props.url); - clickedHeaderLink(`${this.props.url}`); + const newTabProps = {}; + if (shouldOpenNewTab) { + newTabProps.target = '_blank'; + newTabProps.rel = 'noopener noreferrer'; } - render() { - let className = 'nav-children__link_disabled'; - let comingSoon = ( -
- -
+ let link = ( + + {label} + {comingSoon} + {newLabel} + + ); + + if (enabled && externalLink) { + // Trigger the redirect modal + link = ( + ); + } - if (this.props.enabled) { - className = ''; - comingSoon = null; - } - - const newTabProps = {}; - if (this.props.newTab) { - newTabProps.target = '_blank'; - newTabProps.rel = 'noopener noreferrer'; - } - - let link = ( - - {this.props.label} + {label} {comingSoon} - + {newLabel} + ); + } - if (this.props.enabled && this.props.externalLink) { - // Trigger the redirect modal - link = ( - - ); - } - - if (this.props.url.includes('http')) { - link = ( - - {this.props.label} - {comingSoon} - - ); - } - - let firstClass = ''; - if (this.props.isFirst) { - firstClass = 'nav-children__list-separator_hidden'; - } - - return ( -
  • -
    - {link} -
  • - ); + let firstClass = ''; + if (isFirst) { + firstClass = 'nav-children__list-separator_hidden'; } -} + + return ( +
  • +
    + {link} +
  • + ); +}; DropdownItem.propTypes = propTypes; + +export default DropdownItem; diff --git a/src/js/components/sharedComponents/header/NavBar.jsx b/src/js/components/sharedComponents/header/NavBar.jsx index 9055d5442b..ecd76ac0cc 100644 --- a/src/js/components/sharedComponents/header/NavBar.jsx +++ b/src/js/components/sharedComponents/header/NavBar.jsx @@ -6,12 +6,10 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faEnvelope } from "@fortawesome/free-regular-svg-icons"; import Analytics from 'helpers/analytics/Analytics'; -import GlossaryButtonWrapperContainer from 'containers/glossary/GlossaryButtonWrapperContainer'; -import { searchOptions, profileOptions, downloadOptions } from 'dataMapping/navigation/menuOptions'; +import { searchOptions, profileOptions, downloadOptions, resourceOptions } from 'dataMapping/navigation/menuOptions'; import EmailSignUp from 'components/homepage/EmailSignUp'; import { DEV } from '../../../GlobalConstants'; -import NavBarGlossaryLink from './NavBarGlossaryLink'; import Dropdown from './Dropdown'; import MobileNav from './mobile/MobileNav'; @@ -184,14 +182,17 @@ export default class NavBar extends React.Component { className="full-menu__item" role="menuitem">
  • - +
  • diff --git a/src/js/dataMapping/navigation/menuOptions.jsx b/src/js/dataMapping/navigation/menuOptions.jsx index 8833292518..94ac830ca3 100644 --- a/src/js/dataMapping/navigation/menuOptions.jsx +++ b/src/js/dataMapping/navigation/menuOptions.jsx @@ -3,15 +3,8 @@ * Created by Kevin Li 1/18/18 */ -import React from 'react'; import kGlobalConstants from 'GlobalConstants'; -const New = () => ( - - COVID-19 Spending - NEW - ); - export const searchOptions = [ { label: 'Advanced Search', @@ -47,12 +40,43 @@ export const profileOptions = [ enabled: true }, { - label: , + label: "COVID-19 Spending", url: '/disaster/covid-19', - enabled: kGlobalConstants.CARES_ACT_RELEASED + enabled: kGlobalConstants.CARES_ACT_RELEASED, + isNewTab: true } ]; +export const resourceOptions = [ + { + label: 'Glossary', + url: '/?glossary', + enabled: true, + appendToExistingUrl: true + }, + { + label: 'Data Dictionary', + type: 'data_dictionary', + url: '/download_center/data_dictionary' + }, + { + label: 'Data Model', + url: 'https://fiscal.treasury.gov/data-transparency/DAIMS-current.html', + shouldOpenNewTab: true + }, + { + label: "Agency Submission Statistics", + url: '/about-the-data/agencies', + enabled: false + }, + { + label: 'API Tutorial', + url: 'https://api.usaspending.gov/docs/intro-tutorial', + enabled: true + } +]; + + export const downloadOptions = [ { label: 'Award Data Archive', @@ -61,7 +85,7 @@ export const downloadOptions = [ code: 'archive', description: 'The quickest way to grab award data. Pre-generated award files for each major agency (by fiscal year) save on download time.', callToAction: 'Grab Award Files', - newTab: false, + shouldOpenNewTab: false, enabled: true, externalLink: false }, @@ -72,7 +96,7 @@ export const downloadOptions = [ code: 'award', description: 'The best way to grab detailed slices of award data. Specify the agency, timeframe, award type, award level, and more.', callToAction: 'Download Award Data', - newTab: false, + shouldOpenNewTab: false, enabled: true, externalLink: false }, @@ -83,7 +107,7 @@ export const downloadOptions = [ code: 'account', description: 'The best way to grab detailed subsets of account data, which offer a broad view of how the government allocates funding from top to bottom.', callToAction: 'Download Account Data', - newTab: false, + shouldOpenNewTab: false, enabled: true, externalLink: false }, @@ -94,7 +118,7 @@ export const downloadOptions = [ code: 'submission', description: 'Raw, unadulterated data submitted by federal agencies in compliance with the DATA Act.', callToAction: 'Download Raw Files', - newTab: true, + shouldOpenNewTab: true, enabled: true, internalDomain: true }, @@ -105,7 +129,7 @@ export const downloadOptions = [ code: 'database', description: 'Our entire database available as a download – the most complete download option available for advanced users.', callToAction: 'Explore Database Download', - newTab: true, + shouldOpenNewTab: true, enabled: true, internalDomain: true }, @@ -116,7 +140,7 @@ export const downloadOptions = [ code: 'api', description: 'An automated way for advanced users to access all the data behind USAspending.gov. Accessible documentation includes tutorials, best practices, and more.', callToAction: 'Explore Our API', - newTab: true, + shouldOpenNewTab: true, enabled: true, internalDomain: true }, @@ -127,7 +151,7 @@ export const downloadOptions = [ code: 'dictionary', description: '', callToAction: 'Explore the Data Dictionary', - newTab: false, + shouldOpenNewTab: false, enabled: true, externalLink: false }, @@ -138,8 +162,21 @@ export const downloadOptions = [ code: 'metadata', description: '', callToAction: 'Explore Dataset Metadata', - newTab: false, + shouldOpenNewTab: false, enabled: true, externalLink: false } ]; + +export const labelsWithNewBadge = searchOptions + .concat(profileOptions) + .concat(resourceOptions) + .concat(downloadOptions) + .filter((obj) => Object.entries(obj).some(([key, value]) => { + console.log('key', key, value); + return key === 'isNewTab' && value; + })) + .map(({ label }) => { + console.log('label', label); + return label.toLowerCase(); + }); From 0f5127100c559779bf7042870e93e39d0900dbb8 Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Wed, 20 Jan 2021 17:39:40 -0500 Subject: [PATCH 42/69] [DEV-6662] refactoring dropdown and dropdownitem Dropdown -- remove hardcoding showing of new badge DropdownItem -- using newLabel & introducing some new props. Notably, appendToExistingUrl for glossary nav item click and when you're just adding to the existing url. --- .../components/sharedComponents/header/Dropdown.jsx | 9 ++++----- .../sharedComponents/header/DropdownItem.jsx | 12 ++++++------ src/js/dataMapping/navigation/menuOptions.jsx | 13 ------------- 3 files changed, 10 insertions(+), 24 deletions(-) diff --git a/src/js/components/sharedComponents/header/Dropdown.jsx b/src/js/components/sharedComponents/header/Dropdown.jsx index b3a170e432..ec58c77b16 100644 --- a/src/js/components/sharedComponents/header/Dropdown.jsx +++ b/src/js/components/sharedComponents/header/Dropdown.jsx @@ -8,7 +8,6 @@ import PropTypes from 'prop-types'; import { AngleDown } from 'components/sharedComponents/icons/Icons'; import DropdownItem from './DropdownItem'; -import { labelsWithNewBadge } from '../../../dataMapping/navigation/menuOptions'; const propTypes = { label: PropTypes.string.isRequired, @@ -44,6 +43,8 @@ const Dropdown = ({ iconAlt = 'Expanded menu'; } + const containsNewNavItem = items.some(({ isNewTab }) => isNewTab); + return (
    - { - labelsWithNewBadge.includes(label.toLowerCase()) && + {containsNewNavItem &&
    -
    - } +
    } {label}
    diff --git a/src/js/components/sharedComponents/header/DropdownItem.jsx b/src/js/components/sharedComponents/header/DropdownItem.jsx index ae0f94bef9..d55344470c 100644 --- a/src/js/components/sharedComponents/header/DropdownItem.jsx +++ b/src/js/components/sharedComponents/header/DropdownItem.jsx @@ -41,7 +41,7 @@ const DropdownItem = ({ appendToExistingUrl = false }) => { const { pathname } = useLocation(); - const newUrl = appendToExistingUrl ? `${pathname}/${url}` : url; + const newUrl = appendToExistingUrl && pathname !== '/' ? `${pathname}/${url}` : url; const handleClick = () => { redirectHelper.showRedirectModal(newUrl); @@ -81,9 +81,9 @@ const DropdownItem = ({ to={newUrl} onClick={clickedHeaderLink.bind(null, `${newUrl}`)} {...newTabProps}> - {label} - {comingSoon} + {!newLabel && label} {newLabel} + {comingSoon} ); @@ -93,7 +93,7 @@ const DropdownItem = ({ ); @@ -106,9 +106,9 @@ const DropdownItem = ({ href={newUrl} onClick={clickedHeaderLink.bind(null, `${newUrl}`)} {...newTabProps}> - {label} - {comingSoon} + {!newLabel && label} {newLabel} + {comingSoon} ); } diff --git a/src/js/dataMapping/navigation/menuOptions.jsx b/src/js/dataMapping/navigation/menuOptions.jsx index 94ac830ca3..fbc9f3e356 100644 --- a/src/js/dataMapping/navigation/menuOptions.jsx +++ b/src/js/dataMapping/navigation/menuOptions.jsx @@ -167,16 +167,3 @@ export const downloadOptions = [ externalLink: false } ]; - -export const labelsWithNewBadge = searchOptions - .concat(profileOptions) - .concat(resourceOptions) - .concat(downloadOptions) - .filter((obj) => Object.entries(obj).some(([key, value]) => { - console.log('key', key, value); - return key === 'isNewTab' && value; - })) - .map(({ label }) => { - console.log('label', label); - return label.toLowerCase(); - }); From 1fba034ecaec3d8e74db2366c625970b418645b6 Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Thu, 21 Jan 2021 11:32:52 -0500 Subject: [PATCH 43/69] [DEV-6662] New Badge Style clean up --- src/_scss/components/_newBadge.scss | 17 +++-------------- .../default/header/nav/_dropdownMenu.scss | 7 +------ .../sharedComponents/header/DropdownItem.jsx | 6 +++--- 3 files changed, 7 insertions(+), 23 deletions(-) diff --git a/src/_scss/components/_newBadge.scss b/src/_scss/components/_newBadge.scss index 0a09a0a8e4..c57edca04c 100644 --- a/src/_scss/components/_newBadge.scss +++ b/src/_scss/components/_newBadge.scss @@ -10,20 +10,9 @@ color: #FFF; font-weight: 600; margin-right: rem(35); -} - -.covid-newbadge { - height: rem(24); - width: rem(47); - border-radius: rem(4); - background-color: $color-secondary-dark; - @include display(inline-flex); - @include justify-content(center); - @include align-items(center); - font-size: rem(14); - color: #FFF; - font-weight: 600; - margin-left: rem(10); + &.dropdown-item { + margin: auto; + } } .new-badge-outer { diff --git a/src/_scss/layouts/default/header/nav/_dropdownMenu.scss b/src/_scss/layouts/default/header/nav/_dropdownMenu.scss index a5a25a2b62..f8ca73b151 100644 --- a/src/_scss/layouts/default/header/nav/_dropdownMenu.scss +++ b/src/_scss/layouts/default/header/nav/_dropdownMenu.scss @@ -52,7 +52,6 @@ width: rem(230); background-color: $color-white; box-shadow: 0 4px 5px 0 rgba(0,0,0,0.5); - border-top: 1px solid $dropdown-border; } @@ -67,15 +66,12 @@ } a.nav-children__link { - display: block; - + @include display(flex); font-size: rem(15); line-height: rem(19); color: $nav-color; font-weight: $font-semibold; - padding: rem(15) rem(20); - &:hover, &:active { text-decoration: none; background-color: $dropdown-hover; @@ -99,7 +95,6 @@ color: $nav-color; font-weight: $font-semibold; padding: rem(15) rem(20); - &:hover, &:active { background-color: $dropdown-hover; } diff --git a/src/js/components/sharedComponents/header/DropdownItem.jsx b/src/js/components/sharedComponents/header/DropdownItem.jsx index d55344470c..b376248442 100644 --- a/src/js/components/sharedComponents/header/DropdownItem.jsx +++ b/src/js/components/sharedComponents/header/DropdownItem.jsx @@ -57,10 +57,10 @@ const DropdownItem = ({ const newLabel = isNewTab && enabled ? ( - + <> {label} - NEW - + NEW + ) : null; From ada2580a6ee78f750bd4cdf8d53a41e474b466dd Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Thu, 21 Jan 2021 11:34:51 -0500 Subject: [PATCH 44/69] [DEV-6662] Dark Release Logic for Agency Submission Stats Navigation --- .../sharedComponents/header/NavBar.jsx | 31 ++++++++++++------- src/js/dataMapping/navigation/menuOptions.jsx | 19 +++++++----- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/js/components/sharedComponents/header/NavBar.jsx b/src/js/components/sharedComponents/header/NavBar.jsx index ecd76ac0cc..23dee30820 100644 --- a/src/js/components/sharedComponents/header/NavBar.jsx +++ b/src/js/components/sharedComponents/header/NavBar.jsx @@ -6,12 +6,14 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faEnvelope } from "@fortawesome/free-regular-svg-icons"; import Analytics from 'helpers/analytics/Analytics'; +import GlossaryButtonWrapperContainer from 'containers/glossary/GlossaryButtonWrapperContainer'; import { searchOptions, profileOptions, downloadOptions, resourceOptions } from 'dataMapping/navigation/menuOptions'; import EmailSignUp from 'components/homepage/EmailSignUp'; -import { DEV } from '../../../GlobalConstants'; +import { DEV, QAT } from '../../../GlobalConstants'; import Dropdown from './Dropdown'; import MobileNav from './mobile/MobileNav'; +import NavBarGlossaryLink from './NavBarGlossaryLink'; const clickedHeaderLink = (route) => { Analytics.event({ @@ -20,6 +22,8 @@ const clickedHeaderLink = (route) => { }); }; +const isDevOrQat = (DEV || QAT); + export default class NavBar extends React.Component { constructor(props) { super(props); @@ -182,18 +186,23 @@ export default class NavBar extends React.Component { className="full-menu__item" role="menuitem"> -
  • - -
  • + {isDevOrQat && ( +
  • + +
  • + )} + {!isDevOrQat && ( + + )}
    diff --git a/src/js/dataMapping/navigation/menuOptions.jsx b/src/js/dataMapping/navigation/menuOptions.jsx index fbc9f3e356..03ab51a177 100644 --- a/src/js/dataMapping/navigation/menuOptions.jsx +++ b/src/js/dataMapping/navigation/menuOptions.jsx @@ -3,7 +3,9 @@ * Created by Kevin Li 1/18/18 */ -import kGlobalConstants from 'GlobalConstants'; +import { QAT, DEV, FILES_SERVER_BASE_URL, API } from 'GlobalConstants'; + +const isLowerEnv = (QAT || DEV); export const searchOptions = [ { @@ -42,7 +44,7 @@ export const profileOptions = [ { label: "COVID-19 Spending", url: '/disaster/covid-19', - enabled: kGlobalConstants.CARES_ACT_RELEASED, + enabled: true, isNewTab: true } ]; @@ -67,7 +69,8 @@ export const resourceOptions = [ { label: "Agency Submission Statistics", url: '/about-the-data/agencies', - enabled: false + enabled: true, + isNewTab: true }, { label: 'API Tutorial', @@ -76,6 +79,7 @@ export const resourceOptions = [ } ]; +const underResourcesInLowerEnv = ["api", "data dictionary"]; export const downloadOptions = [ { @@ -114,7 +118,7 @@ export const downloadOptions = [ { label: 'Agency Submission Files', type: 'snapshots', - url: `${kGlobalConstants.FILES_SERVER_BASE_URL}/agency_submissions/`, + url: `${FILES_SERVER_BASE_URL}/agency_submissions/`, code: 'submission', description: 'Raw, unadulterated data submitted by federal agencies in compliance with the DATA Act.', callToAction: 'Download Raw Files', @@ -125,7 +129,7 @@ export const downloadOptions = [ { label: 'Database Download', type: '', - url: `${kGlobalConstants.FILES_SERVER_BASE_URL}/database_download/`, + url: `${FILES_SERVER_BASE_URL}/database_download/`, code: 'database', description: 'Our entire database available as a download – the most complete download option available for advanced users.', callToAction: 'Explore Database Download', @@ -136,7 +140,7 @@ export const downloadOptions = [ { label: 'API', type: '', - url: kGlobalConstants.API.replace("api/", ""), + url: API.replace("api/", ""), code: 'api', description: 'An automated way for advanced users to access all the data behind USAspending.gov. Accessible documentation includes tutorials, best practices, and more.', callToAction: 'Explore Our API', @@ -166,4 +170,5 @@ export const downloadOptions = [ enabled: true, externalLink: false } -]; +] + .filter(({ label }) => !(isLowerEnv && underResourcesInLowerEnv.includes(label.toLowerCase()))); From cea0ba286aeb98c92fd6a8cb1fe6cc214ab61359 Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Thu, 21 Jan 2021 12:40:45 -0500 Subject: [PATCH 45/69] [DEV-6662] Renaming url & using query params MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - /about-the-data/agencies/:fy/:period --> /submission-statistics/?fy=&period= - /about-the-data/agency/:agencyCode --> /submission-statistics/:agencyCode 👀 RouterRoutes & AboutTheDataPage Elswhere just updating href values etc... --- .../aboutTheData/AboutTheDataPage.jsx | 18 +++++++++++++----- .../aboutTheData/AgencyDetailsPage.jsx | 4 +++- .../components/aboutTheData/DrilldownCell.jsx | 2 +- src/js/containers/router/RouterRoutes.js | 16 ++-------------- src/js/dataMapping/navigation/menuOptions.jsx | 2 +- .../aboutTheData/AboutTheDataPage-test.jsx | 4 ++-- 6 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/js/components/aboutTheData/AboutTheDataPage.jsx b/src/js/components/aboutTheData/AboutTheDataPage.jsx index 161d2b6957..d0d0bb55b7 100644 --- a/src/js/components/aboutTheData/AboutTheDataPage.jsx +++ b/src/js/components/aboutTheData/AboutTheDataPage.jsx @@ -6,7 +6,7 @@ import React, { useEffect, useState } from "react"; import PropTypes from 'prop-types'; import { TooltipComponent, TooltipWrapper, Tabs } from "data-transparency-ui"; -import { useParams } from "react-router-dom"; +import { useLocation } from "react-router-dom"; import Header from "containers/shared/HeaderContainer"; import Footer from "containers/Footer"; @@ -45,7 +45,9 @@ const message = "All numeric figures in this table are calculated based on the s const AboutTheDataPage = ({ history }) => { - const { fy: urlFy, period: urlPeriod } = useParams(); + const query = new URLSearchParams(useLocation().search); + const urlFy = query.get('fy'); + const urlPeriod = query.get('period'); const [, submissionPeriods, { year: latestFy, period: latestPeriod }] = useLatestAccountData(); const [selectedFy, setSelectedFy] = useState(null); const [selectedPeriod, setSelectedPeriod] = useState(null); @@ -66,12 +68,18 @@ const AboutTheDataPage = ({ useEffect(() => { if ((!urlFy || !urlPeriod) && submissionPeriods.size && latestFy && latestPeriod) { - history.replace(`about-the-data/agencies/${latestFy}/${latestPeriod}`); + history.replace({ + pathanme: `/submission-statistics/`, + search: `?${new URLSearchParams({ fy: latestFy, period: latestPeriod }).toString()}` + }); } - }, []); + }, [history, latestFy, latestPeriod, submissionPeriods.size, urlFy, urlPeriod]); const updateUrl = (newFy, newPeriod) => { - history.push({ pathname: `/about-the-data/agencies/${newFy}/${newPeriod}` }); + history.push({ + pathname: `/submission-statistics/`, + search: `?${new URLSearchParams({ fy: newFy, period: newPeriod }).toString()}` + }); }; const handleSwitchTab = (tab) => { diff --git a/src/js/components/aboutTheData/AgencyDetailsPage.jsx b/src/js/components/aboutTheData/AgencyDetailsPage.jsx index 11900d7727..3db25e94aa 100644 --- a/src/js/components/aboutTheData/AgencyDetailsPage.jsx +++ b/src/js/components/aboutTheData/AgencyDetailsPage.jsx @@ -95,7 +95,9 @@ const AgencyDetailsPage = () => { <>
    -  Back to All Agencies + +  Back to All Agencies +

    {agencyOverview.name}

    diff --git a/src/js/components/aboutTheData/DrilldownCell.jsx b/src/js/components/aboutTheData/DrilldownCell.jsx index 4c29329ace..fbc2df62b3 100644 --- a/src/js/components/aboutTheData/DrilldownCell.jsx +++ b/src/js/components/aboutTheData/DrilldownCell.jsx @@ -25,7 +25,7 @@ const DrilldownCell = ({ {searchTerm ? replaceString(data, searchTerm, 'matched-str') : data} - +
    diff --git a/src/js/containers/router/RouterRoutes.js b/src/js/containers/router/RouterRoutes.js index 8eb750f041..f299b4f85f 100644 --- a/src/js/containers/router/RouterRoutes.js +++ b/src/js/containers/router/RouterRoutes.js @@ -169,25 +169,13 @@ export const routes = [ exact: true }, { - path: '/about-the-data/agencies', + path: '/submission-statistics', component: AboutTheDataPage, exact: true, hide: !kGlobalConstants.DEV && !kGlobalConstants.QAT // Not DEV and not QAT === Production, so we hide }, { - path: '/about-the-data/agencies/:fy', - component: AboutTheDataPage, - exact: true, - hide: !kGlobalConstants.DEV && !kGlobalConstants.QAT // Not DEV and not QAT === Production, so we hide - }, - { - path: '/about-the-data/agencies/:fy/:period', - component: AboutTheDataPage, - exact: true, - hide: !kGlobalConstants.DEV && !kGlobalConstants.QAT // Not DEV and not QAT === Production, so we hide - }, - { - path: '/about-the-data/agency/:agencyCode', + path: '/submission-statistics/:agencyCode', component: AgencyDetailsPage, exact: true, hide: !kGlobalConstants.DEV && !kGlobalConstants.QAT // Not DEV and not QAT === Production, so we hide diff --git a/src/js/dataMapping/navigation/menuOptions.jsx b/src/js/dataMapping/navigation/menuOptions.jsx index 03ab51a177..02150226af 100644 --- a/src/js/dataMapping/navigation/menuOptions.jsx +++ b/src/js/dataMapping/navigation/menuOptions.jsx @@ -68,7 +68,7 @@ export const resourceOptions = [ }, { label: "Agency Submission Statistics", - url: '/about-the-data/agencies', + url: '/submission-statistics', enabled: true, isNewTab: true }, diff --git a/tests/components/aboutTheData/AboutTheDataPage-test.jsx b/tests/components/aboutTheData/AboutTheDataPage-test.jsx index 121d9ea66e..eca0a926f2 100644 --- a/tests/components/aboutTheData/AboutTheDataPage-test.jsx +++ b/tests/components/aboutTheData/AboutTheDataPage-test.jsx @@ -110,9 +110,9 @@ test('on tab change updates the table view', async () => { expect(table).toBeDefined(); }); -test('redirects about-the-data/agencies to url w/ latest fy and period in params', async () => { +test('redirects submission-statistics to url w/ latest fy and period in params', async () => { render(); return waitFor(() => { - expect(mockReplace).toHaveBeenCalledWith('about-the-data/agencies/2020/12'); + expect(mockReplace).toHaveBeenCalledWith('submission-statistics/2020/12'); }); }); From 0eecd9f53f0739ce2adb0d2934e0e0b6d7cba488 Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Thu, 21 Jan 2021 13:35:32 -0500 Subject: [PATCH 46/69] [DEV-6662] Mobile Nav Update .scss files: -- newBadge: Cleaner styles for new badge in mobile -- _dropdownMenu & _dropdown: cleaning up centered alignment .jsx: implmenting same changes as done for dropdown and dropdownitem, for analgous mobile components: -- MobileDropdown: using isNewTab & removing hard coded display of new indicator -- MobileDropdownItem: reusing newBadge styles on span w/ className -- MobileNav: dark release logic --- src/_scss/components/_newBadge.scss | 11 +++++-- .../default/header/nav/_dropdownMenu.scss | 1 + .../default/header/nav/mobile/_dropdown.scss | 3 ++ .../header/mobile/MobileDropdown.jsx | 7 +++-- .../header/mobile/MobileDropdownItem.jsx | 4 ++- .../header/mobile/MobileNav.jsx | 31 ++++++++++++++----- src/js/dataMapping/navigation/menuOptions.jsx | 2 ++ 7 files changed, 45 insertions(+), 14 deletions(-) diff --git a/src/_scss/components/_newBadge.scss b/src/_scss/components/_newBadge.scss index c57edca04c..775d662a7c 100644 --- a/src/_scss/components/_newBadge.scss +++ b/src/_scss/components/_newBadge.scss @@ -10,8 +10,15 @@ color: #FFF; font-weight: 600; margin-right: rem(35); - &.dropdown-item { - margin: auto; + @media(max-width: $medium-screen) { + &.dropdown-item { + margin: 0 0 0 rem(5); + } + } + @include media($medium-screen) { + &.dropdown-item { + margin: auto; + } } } diff --git a/src/_scss/layouts/default/header/nav/_dropdownMenu.scss b/src/_scss/layouts/default/header/nav/_dropdownMenu.scss index f8ca73b151..05eb4d639d 100644 --- a/src/_scss/layouts/default/header/nav/_dropdownMenu.scss +++ b/src/_scss/layouts/default/header/nav/_dropdownMenu.scss @@ -67,6 +67,7 @@ a.nav-children__link { @include display(flex); + @include align-items(center); font-size: rem(15); line-height: rem(19); color: $nav-color; diff --git a/src/_scss/layouts/default/header/nav/mobile/_dropdown.scss b/src/_scss/layouts/default/header/nav/mobile/_dropdown.scss index e819acb7db..7271792eb8 100644 --- a/src/_scss/layouts/default/header/nav/mobile/_dropdown.scss +++ b/src/_scss/layouts/default/header/nav/mobile/_dropdown.scss @@ -68,6 +68,9 @@ line-height: rem(28); color: $color-base; text-decoration: none; + @include display(flex); + @include justify-content(center); + @include align-items(center); &:hover, &:active, &.mobile-dropdown__link_active { text-decoration: none; diff --git a/src/js/components/sharedComponents/header/mobile/MobileDropdown.jsx b/src/js/components/sharedComponents/header/mobile/MobileDropdown.jsx index f7b7307df4..f8d7639893 100644 --- a/src/js/components/sharedComponents/header/mobile/MobileDropdown.jsx +++ b/src/js/components/sharedComponents/header/mobile/MobileDropdown.jsx @@ -61,12 +61,15 @@ export default class MobileDropdown extends React.Component { key={item.url} comingSoon={!item.enabled} title={item.label} + isNewTab={item.isNewTab} url={item.url} active={item.url === this.props.active} externalLink={item.externalLink} hideMobileNav={this.props.hideMobileNav} /> )); + const containsNewNavItem = this.props.items.some(({ isNewTab }) => isNewTab); + return (
    -
      +
        {items.map((item, index) => ( + items={downloadGlobalNavigationOptions} /> {isDevOrQat && (

      • diff --git a/src/js/dataMapping/navigation/menuOptions.jsx b/src/js/dataMapping/navigation/menuOptions.jsx index 50028d3a7f..9dd971f539 100644 --- a/src/js/dataMapping/navigation/menuOptions.jsx +++ b/src/js/dataMapping/navigation/menuOptions.jsx @@ -65,9 +65,14 @@ export const resourceOptions = [ }, { label: 'Data Dictionary', - enabled: true, type: 'data_dictionary', - url: '/download_center/data_dictionary' + url: '/download_center/data_dictionary', + code: 'dictionary', + description: '', + callToAction: 'Explore the Data Dictionary', + shouldOpenNewTab: false, + enabled: true, + externalLink: false }, { label: 'Data Model', @@ -179,5 +184,7 @@ export const downloadOptions = [ enabled: true, externalLink: false } -] +]; + +export const downloadGlobalNavigationOptions = downloadOptions .filter(({ label }) => !(isLowerEnv && underResourcesInLowerEnv.includes(label.toLowerCase()))); From 994d1906cbdf8ba92abb7d1850403357c3d81961 Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Thu, 21 Jan 2021 16:55:17 -0500 Subject: [PATCH 49/69] [DEV-6291] Updating footer - Removing the Resources tab - Add our sites as the last option in footer w/ links to fiscal data and data lab - Under developers tab, adding release notes Ticket #: https://federal-spending-transparency.atlassian.net/browse/DEV-6291 --- src/js/containers/Footer.jsx | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/src/js/containers/Footer.jsx b/src/js/containers/Footer.jsx index 8c24868972..1f976a34d2 100644 --- a/src/js/containers/Footer.jsx +++ b/src/js/containers/Footer.jsx @@ -115,45 +115,36 @@ const Footer = ({
    - Resources + Developers
      -
    • - - Data Dictionary - -
    • + link="https://api.usaspending.gov" + title="API" />
    • + link="https://github.com/fedspendingtransparency/usaspending-website/tree/master" + title="Explore the Code" />
    • + link="https://github.com/fedspendingtransparency/usaspending-website/releases" + title="Release Notes" />
    - Developers + Our Sites
    From d3385d980092f4cf88f3a22dc3e8c524efb2b892 Mon Sep 17 00:00:00 2001 From: Lizzie Salita Date: Thu, 21 Jan 2021 18:01:49 -0500 Subject: [PATCH 50/69] Removed hard-coded DEFC from COVID modal and homepage feature --- src/js/components/homepage/features/Features.jsx | 2 +- src/js/containers/covid19/CovidModalContainer.jsx | 7 +++---- .../{covid19 => }/homepage/CovidFeatureContainer.jsx | 9 ++++----- src/js/dataMapping/covid19/covid19.js | 1 - 4 files changed, 8 insertions(+), 11 deletions(-) rename src/js/containers/{covid19 => }/homepage/CovidFeatureContainer.jsx (97%) diff --git a/src/js/components/homepage/features/Features.jsx b/src/js/components/homepage/features/Features.jsx index b04c58864c..cebeb26f8d 100644 --- a/src/js/components/homepage/features/Features.jsx +++ b/src/js/components/homepage/features/Features.jsx @@ -5,7 +5,7 @@ import React from 'react'; -import CovidFeatureContainer from 'containers/covid19/homepage/CovidFeatureContainer'; +import CovidFeatureContainer from 'containers/homepage/CovidFeatureContainer'; import kGlobalConstants from 'GlobalConstants'; import SpendingExplorerFeature from './SpendingExplorerFeature'; import SearchFeature from './SearchFeature'; diff --git a/src/js/containers/covid19/CovidModalContainer.jsx b/src/js/containers/covid19/CovidModalContainer.jsx index c84e992b7e..d356355758 100644 --- a/src/js/containers/covid19/CovidModalContainer.jsx +++ b/src/js/containers/covid19/CovidModalContainer.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { connect } from 'react-redux'; +import { connect, useSelector } from 'react-redux'; import PropTypes from 'prop-types'; import { useHistory, Link } from 'react-router-dom'; import Modal from 'react-aria-modal'; @@ -10,8 +10,6 @@ import { clearAllFilters } from 'redux/actions/search/searchFilterActions'; import { applyStagedFilters, resetAppliedFilters, setAppliedFilterCompletion } from 'redux/actions/search/appliedFilterActions'; import { initialState as defaultFilters, CheckboxTreeSelections } from 'redux/reducers/search/searchFiltersReducer'; -import { defCodes } from 'dataMapping/covid19/covid19'; - const CovidModalContainer = ({ mounted, hideModal, @@ -21,6 +19,7 @@ const CovidModalContainer = ({ setAppliedFilters }) => { const history = useHistory(); + const defCodes = useSelector((state) => state.covid19.defCodes); const handleGoToAdvancedSearch = (e) => { e.preventDefault(); @@ -31,7 +30,7 @@ const CovidModalContainer = ({ stageDefCodesForAdvancedSearch({ ...defaultFilters, defCodes: new CheckboxTreeSelections({ - require: defCodes, + require: defCodes.map((code) => code.code), exclude: [], counts: [{ value: "COVID-19", count: defCodes.length, label: "COVID-19 Spending" }] }) diff --git a/src/js/containers/covid19/homepage/CovidFeatureContainer.jsx b/src/js/containers/homepage/CovidFeatureContainer.jsx similarity index 97% rename from src/js/containers/covid19/homepage/CovidFeatureContainer.jsx rename to src/js/containers/homepage/CovidFeatureContainer.jsx index 0313793832..3c0edbe74d 100644 --- a/src/js/containers/covid19/homepage/CovidFeatureContainer.jsx +++ b/src/js/containers/homepage/CovidFeatureContainer.jsx @@ -4,7 +4,7 @@ */ import React from 'react'; -import { connect } from 'react-redux'; +import { connect, useSelector } from 'react-redux'; import PropTypes from 'prop-types'; import { useHistory, Link } from 'react-router-dom'; import { clearAllFilters } from 'redux/actions/search/searchFilterActions'; @@ -12,8 +12,6 @@ import { showModal } from 'redux/actions/modal/modalActions'; import { applyStagedFilters, resetAppliedFilters, setAppliedFilterCompletion } from 'redux/actions/search/appliedFilterActions'; import { initialState as defaultFilters, CheckboxTreeSelections } from 'redux/reducers/search/searchFiltersReducer'; -import { defCodes } from 'dataMapping/covid19/covid19'; - import Analytics from 'helpers/analytics/Analytics'; const clickedHomepageLink = (route) => { @@ -31,6 +29,7 @@ const CovidFeatureContainer = ({ setAppliedFilters }) => { const history = useHistory(); + const reduxDefCodes = useSelector((state) => state.covid19.defCodes); const handleGoToAdvancedSearch = (e) => { e.preventDefault(); @@ -41,9 +40,9 @@ const CovidFeatureContainer = ({ stageDefCodesForAdvancedSearch({ ...defaultFilters, defCodes: new CheckboxTreeSelections({ - require: defCodes, + require: reduxDefCodes.map((code) => code.code), exclude: [], - counts: [{ value: "COVID-19", count: defCodes.length, label: "COVID-19 Spending" }] + counts: [{ value: "COVID-19", count: reduxDefCodes.length || 0, label: "COVID-19 Spending" }] }) }); history.push('/search'); diff --git a/src/js/dataMapping/covid19/covid19.js b/src/js/dataMapping/covid19/covid19.js index 2041be3c97..1c2dcde47c 100644 --- a/src/js/dataMapping/covid19/covid19.js +++ b/src/js/dataMapping/covid19/covid19.js @@ -21,7 +21,6 @@ export const globalBannerHeight = 90; // result of document.querySelector('.site-header').clientHeight + sticky header height when not sticky export const siteHeaderHeight = 97 + stickyHeaderHeight; -export const defCodes = ['L', 'M', 'N', 'O', 'P']; export const allDefCAwardTypeCodes = ['02', '03', '04', '05', '06', '07', '08', '09', '10', '11']; export const amountsHeight = 400; From 4807de1b0ca87e8039ee3d1bb3c22269cc2fbc70 Mon Sep 17 00:00:00 2001 From: Lizzie Salita Date: Thu, 21 Jan 2021 18:04:07 -0500 Subject: [PATCH 51/69] Moved homepage container --- src/js/components/homepage/Homepage.jsx | 12 ++---------- .../{covid19 => }/homepage/CovidHighlights.jsx | 0 2 files changed, 2 insertions(+), 10 deletions(-) rename src/js/containers/{covid19 => }/homepage/CovidHighlights.jsx (100%) diff --git a/src/js/components/homepage/Homepage.jsx b/src/js/components/homepage/Homepage.jsx index c33d2512ab..dc950559a4 100644 --- a/src/js/components/homepage/Homepage.jsx +++ b/src/js/components/homepage/Homepage.jsx @@ -7,15 +7,12 @@ import React from 'react'; import * as MetaTagHelper from 'helpers/metaTagHelper'; import Footer from 'containers/Footer'; -import GlobalConstants from 'GlobalConstants'; -import CovidHighlights from 'containers/covid19/homepage/CovidHighlights'; +import CovidHighlights from 'containers/homepage/CovidHighlights'; import Header from 'containers/shared/HeaderContainer'; import GlobalModalContainer from 'containers/globalModal/GlobalModalContainer'; import MetaTags from '../sharedComponents/metaTags/MetaTags'; - -import Hero from './hero/Hero'; import Features from './features/Features'; import Download from './download/Download'; import Community from './community/Community'; @@ -29,12 +26,7 @@ export default class Homepage extends React.Component {
    - {GlobalConstants.CARES_ACT_RELEASED_2 && ( - - )} - {!GlobalConstants.CARES_ACT_RELEASED_2 && ( - - )} + diff --git a/src/js/containers/covid19/homepage/CovidHighlights.jsx b/src/js/containers/homepage/CovidHighlights.jsx similarity index 100% rename from src/js/containers/covid19/homepage/CovidHighlights.jsx rename to src/js/containers/homepage/CovidHighlights.jsx From 2c93517c32559556c7e2b852d7429e1838488ea2 Mon Sep 17 00:00:00 2001 From: Lizzie Salita Date: Fri, 22 Jan 2021 11:07:58 -0500 Subject: [PATCH 52/69] remove hard-coded DEFC from the Award data model --- src/js/components/award/Award.jsx | 12 +++-- .../award/contract/ContractContent.jsx | 9 ++-- .../FinancialAssistanceContent.jsx | 8 ++-- .../charts/SharedBarComponents.jsx | 2 +- src/js/containers/award/AwardContainer.jsx | 40 ++++++++++++++-- .../idv/IdvAwardAmountsSectionContainer.jsx | 7 +-- src/js/models/v2/award/BaseAwardAmounts.js | 47 ++++++++++--------- 7 files changed, 84 insertions(+), 41 deletions(-) diff --git a/src/js/components/award/Award.jsx b/src/js/components/award/Award.jsx index e2231349ec..3c193947eb 100644 --- a/src/js/components/award/Award.jsx +++ b/src/js/components/award/Award.jsx @@ -34,7 +34,8 @@ const propTypes = { isDownloadPending: PropTypes.bool, isSubAwardIdClicked: PropTypes.bool, subAwardIdClicked: PropTypes.func, - isLoading: PropTypes.bool + isLoading: PropTypes.bool, + defCodes: PropTypes.array }; const awardSections = [ @@ -108,7 +109,8 @@ export default class Award extends React.Component { counts={{ subawardCount: overview.subawardCount }} jumpToSection={this.jumpToSection} isSubAwardIdClicked={this.props.isSubAwardIdClicked} - subAwardIdClicked={this.props.subAwardIdClicked} /> + subAwardIdClicked={this.props.subAwardIdClicked} + defCodes={this.props.defCodes} /> ); } else if (overview.category === 'idv') { @@ -117,7 +119,8 @@ export default class Award extends React.Component { awardId={awardId} overview={overview} details={this.props.award.idvDetails} - jumpToSection={this.jumpToSection} /> + jumpToSection={this.jumpToSection} + defCodes={this.props.defCodes} /> ); } else if (this.props.noAward) { @@ -136,7 +139,8 @@ export default class Award extends React.Component { overview={overview} jumpToSection={this.jumpToSection} isSubAwardIdClicked={this.props.isSubAwardIdClicked} - subAwardIdClicked={this.props.subAwardIdClicked} /> + subAwardIdClicked={this.props.subAwardIdClicked} + defCodes={this.props.defCodes} /> ); } diff --git a/src/js/components/award/contract/ContractContent.jsx b/src/js/components/award/contract/ContractContent.jsx index db70cffb4d..00a339e924 100644 --- a/src/js/components/award/contract/ContractContent.jsx +++ b/src/js/components/award/contract/ContractContent.jsx @@ -26,7 +26,8 @@ const propTypes = { jumpToSection: PropTypes.func, counts: PropTypes.object, isSubAwardIdClicked: PropTypes.bool, - subAwardIdClicked: PropTypes.func + subAwardIdClicked: PropTypes.func, + defCodes: PropTypes.array }; const ContractContent = ({ @@ -35,7 +36,8 @@ const ContractContent = ({ jumpToSection, counts, isSubAwardIdClicked, - subAwardIdClicked + subAwardIdClicked, + defCodes }) => { const [activeTab, setActiveTab] = useState('transaction'); @@ -49,7 +51,8 @@ const ContractContent = ({ }; const awardAmountData = Object.create(BaseAwardAmounts); - awardAmountData.populate(overview, overview.category); + console.log('contract defCodes', defCodes); + awardAmountData.populate(overview, overview.category, defCodes.map((defc) => defc.code)); const jumpToTransactionHistoryTable = () => { setActiveTab('transaction'); diff --git a/src/js/components/award/financialAssistance/FinancialAssistanceContent.jsx b/src/js/components/award/financialAssistance/FinancialAssistanceContent.jsx index bb739f6fb7..87451648bc 100644 --- a/src/js/components/award/financialAssistance/FinancialAssistanceContent.jsx +++ b/src/js/components/award/financialAssistance/FinancialAssistanceContent.jsx @@ -26,7 +26,8 @@ const propTypes = { overview: PropTypes.object, jumpToSection: PropTypes.func, isSubAwardIdClicked: PropTypes.bool, - subAwardIdClicked: PropTypes.func + subAwardIdClicked: PropTypes.func, + defCodes: PropTypes.array }; const FinancialAssistanceContent = ({ @@ -34,7 +35,8 @@ const FinancialAssistanceContent = ({ overview = { generatedId: '', fileC: { obligations: [] } }, jumpToSection, isSubAwardIdClicked, - subAwardIdClicked + subAwardIdClicked, + defCodes }) => { const [activeTab, setActiveTab] = useState("transaction"); const [CFDAOverviewLinkClicked, setCFDAOverviewLinkClicked] = useState(false); @@ -70,7 +72,7 @@ const FinancialAssistanceContent = ({ }); const awardAmountData = Object.create(BaseAwardAmounts); - awardAmountData.populate(overview, overview.category); + awardAmountData.populate(overview, overview.category, defCodes.map((defc) => defc.code)); const [idLabel, identifier] = isAwardAggregate(overview.generatedId) ? ['URI', overview.uri] : ['FAIN', overview.fain]; const isGrant = overview.category === 'grant'; diff --git a/src/js/components/award/shared/awardAmountsSection/charts/SharedBarComponents.jsx b/src/js/components/award/shared/awardAmountsSection/charts/SharedBarComponents.jsx index 6059e8a9a8..d4bda42263 100644 --- a/src/js/components/award/shared/awardAmountsSection/charts/SharedBarComponents.jsx +++ b/src/js/components/award/shared/awardAmountsSection/charts/SharedBarComponents.jsx @@ -21,7 +21,7 @@ const BarValue = ({ onKeyPress={onEnter} onMouseMove={onEnter} onMouseEnter={onEnter} - onMousedown={onEnter} + onMouseDown={onEnter} onMouseLeave={onLeave} onClick={onEnter}>
    diff --git a/src/js/containers/award/AwardContainer.jsx b/src/js/containers/award/AwardContainer.jsx index 2ff459b176..33fa5048f3 100644 --- a/src/js/containers/award/AwardContainer.jsx +++ b/src/js/containers/award/AwardContainer.jsx @@ -20,6 +20,7 @@ import { setDownloadExpectedUrl } from 'redux/actions/bulkDownload/bulkDownloadActions'; import { subAwardIdClicked } from 'redux/actions/search/searchSubAwardTableActions'; +import { setDEFCodes } from 'redux/actions/covid19/covid19Actions'; import BaseContract from 'models/v2/award/BaseContract'; import BaseIdv from 'models/v2/award/BaseIdv'; @@ -29,6 +30,7 @@ import { fetchContractDownloadFile, fetchAssistanceDownloadFile } from 'helpers/downloadHelper'; +import { fetchDEFCodes } from 'helpers/disasterHelper'; require('pages/award/awardPage.scss'); @@ -44,7 +46,9 @@ const propTypes = { award: PropTypes.object, isDownloadPending: PropTypes.bool, isSubAwardIdClicked: PropTypes.bool, - match: PropTypes.object + match: PropTypes.object, + defCodes: PropTypes.array, + setDEFCodes: PropTypes.func }; export class AwardContainer extends React.Component { @@ -53,6 +57,7 @@ export class AwardContainer extends React.Component { this.awardRequest = null; this.downloadRequest = null; + this.defcRequest = null; this.state = { noAward: false, @@ -60,10 +65,15 @@ export class AwardContainer extends React.Component { }; this.downloadData = this.downloadData.bind(this); this.fetchAwardDownloadFile = this.fetchAwardDownloadFile.bind(this); + this.fetchCodes = this.fetchCodes.bind(this); } componentDidMount() { this.getSelectedAward(this.props.match.params.awardId); + if (!this.props.defCodes || this.props.defCodes.length === 0) { + // If we don't already have COVID-19 DEF Codes in redux, make a request for them + this.fetchCodes(); + } } componentDidUpdate(prevProps) { @@ -183,6 +193,25 @@ export class AwardContainer extends React.Component { } } + async fetchCodes() { + if (this.defcRequest) { + this.defcRequest.cancel(); + } + + this.defcRequest = fetchDEFCodes(); + + try { + const { data } = await this.defcRequest.promise; + const defCodes = data.codes.filter((c) => c.disaster === 'covid_19'); + this.props.setDEFCodes(defCodes); + this.defcRequest = null; + } + catch (err) { + console.err('Error fetching DEF Codes', err); + this.defcRequest = null; + } + } + render() { return ( + noAward={this.state.noAward} + defCodes={this.props.defCodes} /> ); } } @@ -205,7 +235,8 @@ export default connect( (state) => ({ award: state.award, isDownloadPending: state.bulkDownload.download.pendingDownload, - isSubAwardIdClicked: state.searchSubAwardTable.isSubAwardIdClicked + isSubAwardIdClicked: state.searchSubAwardTable.isSubAwardIdClicked, + defCodes: state.covid19.defCodes }), (dispatch) => bindActionCreators({ setDownloadExpectedUrl, @@ -214,6 +245,7 @@ export default connect( setDownloadCollapsed, setAward, subAwardIdClicked, - resetAward + resetAward, + setDEFCodes }, dispatch) )(AwardContainerWithRouter); diff --git a/src/js/containers/award/idv/IdvAwardAmountsSectionContainer.jsx b/src/js/containers/award/idv/IdvAwardAmountsSectionContainer.jsx index a5b6ada56a..9842889930 100644 --- a/src/js/containers/award/idv/IdvAwardAmountsSectionContainer.jsx +++ b/src/js/containers/award/idv/IdvAwardAmountsSectionContainer.jsx @@ -26,7 +26,8 @@ import { awardAmountsInfo } from 'components/award/shared/InfoTooltipContent'; const propTypes = { award: PropTypes.object, setIdvDetails: PropTypes.func, - jumpToSection: PropTypes.func + jumpToSection: PropTypes.func, + defCodes: PropTypes.array }; const tabTypes = [ @@ -110,7 +111,7 @@ export class IdvAmountsContainer extends React.Component { parseChildAwardAmounts(data) { const awardAmounts = Object.create(BaseAwardAmounts); - awardAmounts.populate(data, 'idv_aggregated'); + awardAmounts.populate(data, 'idv_aggregated', this.props.defCodes.map((defc) => defc.code)); this.setState({ awardAmounts, error: false, @@ -137,7 +138,7 @@ export class IdvAmountsContainer extends React.Component { render() { const thisIdv = Object.create(BaseAwardAmounts); - thisIdv.populate(this.props.award.overview, 'idv'); + thisIdv.populate(this.props.award.overview, 'idv', this.props.defCodes.map((defc) => defc.code)); const tabsClassName = 'idv-award-amounts-tabs'; const thisIdvHasFileC = ( thisIdv._fileCObligated !== 0 || diff --git a/src/js/models/v2/award/BaseAwardAmounts.js b/src/js/models/v2/award/BaseAwardAmounts.js index eb9fe9c105..4e09bed18e 100644 --- a/src/js/models/v2/award/BaseAwardAmounts.js +++ b/src/js/models/v2/award/BaseAwardAmounts.js @@ -4,9 +4,8 @@ */ import * as MoneyFormatter from 'helpers/moneyFormatter'; -import { defCodes } from 'dataMapping/covid19/covid19'; -const getCovid19Totals = (arr) => arr +const getCovid19Totals = (arr, defCodes = []) => arr .filter((obj) => defCodes.includes(obj?.code)) .reduce((acc, obj) => acc + obj?.amount || 0, 0); @@ -20,7 +19,7 @@ const BaseAwardAmounts = { ? encodeURIComponent(`${data.generated_unique_award_id}`) : ''; }, - populateAggIdv(data) { + populateAggIdv(data, defCodes) { this.childIDVCount = data.child_idv_count || 0; this.childAwardCount = data.child_award_count || 0; this.grandchildAwardCount = data.grandchild_award_count || 0; @@ -35,58 +34,60 @@ const BaseAwardAmounts = { ) || 0; this._fileCOutlay = getCovid19Totals( data.child_account_outlays_by_defc - .concat(data.grandchild_account_outlays_by_defc) + .concat(data.grandchild_account_outlays_by_defc), + defCodes ); this._fileCObligated = getCovid19Totals( data.child_account_obligations_by_defc - .concat(data.grandchild_account_obligations_by_defc) + .concat(data.grandchild_account_obligations_by_defc), + defCodes ); }, - populateIdv(data) { + populateIdv(data, defCodes) { this._totalObligation = data._totalObligation; this._baseExercisedOptions = data._baseExercisedOptions; this._baseAndAllOptions = data._baseAndAllOptions; - this._fileCOutlay = getCovid19Totals(data.fileC.outlays); - this._fileCObligated = getCovid19Totals(data.fileC.obligations); + this._fileCOutlay = getCovid19Totals(data.fileC.outlays, defCodes); + this._fileCObligated = getCovid19Totals(data.fileC.obligations, defCodes); }, - populateLoan(data) { + populateLoan(data, defCodes) { this._subsidy = data._subsidy; this._faceValue = data._faceValue; - this._fileCOutlay = getCovid19Totals(data.fileC.outlays); - this._fileCObligated = getCovid19Totals(data.fileC.obligations); + this._fileCOutlay = getCovid19Totals(data.fileC.outlays, defCodes); + this._fileCObligated = getCovid19Totals(data.fileC.obligations, defCodes); }, - populateAsst(data) { + populateAsst(data, defCodes) { this._totalObligation = data._totalObligation; this._totalFunding = data._totalFunding; this._nonFederalFunding = data._nonFederalFunding; - this._fileCOutlay = getCovid19Totals(data.fileC.outlays); - this._fileCObligated = getCovid19Totals(data.fileC.obligations); + this._fileCOutlay = getCovid19Totals(data.fileC.outlays, defCodes); + this._fileCObligated = getCovid19Totals(data.fileC.obligations, defCodes); }, - populateContract(data) { + populateContract(data, defCodes) { this._totalObligation = data._totalObligation; this._baseExercisedOptions = data._baseExercisedOptions; this._baseAndAllOptions = data._baseAndAllOptions; - this._fileCOutlay = getCovid19Totals(data.fileC.outlays); - this._fileCObligated = getCovid19Totals(data.fileC.obligations); + this._fileCOutlay = getCovid19Totals(data.fileC.outlays, defCodes); + this._fileCObligated = getCovid19Totals(data.fileC.obligations, defCodes); }, - populate(data, awardAmountType) { + populate(data, awardAmountType, defCodes) { this.populateBase(data, awardAmountType); if (awardAmountType === 'idv_aggregated') { // In every other context, the data has been parsed by CoreAward; here, it's payload straight from the API. - this.populateAggIdv(data); + this.populateAggIdv(data, defCodes); } else if (awardAmountType === 'idv') { - this.populateIdv(data); + this.populateIdv(data, defCodes); } else if (awardAmountType === 'contract') { - this.populateContract(data); + this.populateContract(data, defCodes); } else if (awardAmountType === 'loan') { - this.populateLoan(data); + this.populateLoan(data, defCodes); } else { // grants, direct payment, insurance, other all use populateAsst - this.populateAsst(data); + this.populateAsst(data, defCodes); } }, get baseAndAllOptionsFormatted() { From 3a3c5562557a676ebcd2dfa791b3291f2f27cae9 Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Thu, 21 Jan 2021 18:20:40 -0500 Subject: [PATCH 53/69] [DEV-6662] Glossary Trigger Edge Case Logic: When we're on a page that has query params, triggering the glossary is semi more complex. The glossary was previously the only place where we were using query params. When we trigger the glossary we are updating the url like `/?glossary=glossary-term`, updating redux to set that as the active term, and then removing the query params from the url. This commit introduces a helper called getNewUrlForGlossary which is called when seeking to trigger the glossary on a page with query params. It provides a new url with the glossary param appended to any existing params. Tests included. --- .../sharedComponents/header/DropdownItem.jsx | 9 +- .../header/mobile/MobileDropdown.jsx | 2 +- .../header/mobile/MobileDropdownItem.jsx | 115 ++++++++++-------- .../header/mobile/MobileNav.jsx | 2 +- src/js/helpers/glossaryHelper.js | 14 +++ tests/helpers/glossaryHelper-test.js | 10 ++ 6 files changed, 95 insertions(+), 57 deletions(-) create mode 100644 tests/helpers/glossaryHelper-test.js diff --git a/src/js/components/sharedComponents/header/DropdownItem.jsx b/src/js/components/sharedComponents/header/DropdownItem.jsx index b376248442..7ad97a1716 100644 --- a/src/js/components/sharedComponents/header/DropdownItem.jsx +++ b/src/js/components/sharedComponents/header/DropdownItem.jsx @@ -9,6 +9,7 @@ import { Link, useLocation } from 'react-router-dom'; import Analytics from 'helpers/analytics/Analytics'; import * as redirectHelper from 'helpers/redirectHelper'; +import { getNewUrlForGlossary } from 'helpers/glossaryHelper'; import DropdownComingSoon from './DropdownComingSoon'; @@ -31,7 +32,7 @@ const clickedHeaderLink = (route) => { }; const DropdownItem = ({ - url, + url = '', label, enabled = true, shouldOpenNewTab = false, @@ -40,8 +41,10 @@ const DropdownItem = ({ isNewTab = false, appendToExistingUrl = false }) => { - const { pathname } = useLocation(); - const newUrl = appendToExistingUrl && pathname !== '/' ? `${pathname}/${url}` : url; + const { pathname, search } = useLocation(); + const newUrl = appendToExistingUrl + ? getNewUrlForGlossary(pathname, url, search) + : url; const handleClick = () => { redirectHelper.showRedirectModal(newUrl); diff --git a/src/js/components/sharedComponents/header/mobile/MobileDropdown.jsx b/src/js/components/sharedComponents/header/mobile/MobileDropdown.jsx index f8d7639893..81199ede26 100644 --- a/src/js/components/sharedComponents/header/mobile/MobileDropdown.jsx +++ b/src/js/components/sharedComponents/header/mobile/MobileDropdown.jsx @@ -6,7 +6,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import kGlobalConstants from 'GlobalConstants'; import { AngleUp, AngleDown } from 'components/sharedComponents/icons/Icons'; @@ -58,6 +57,7 @@ export default class MobileDropdown extends React.Component { const items = this.props.items.map((item) => ( { @@ -29,67 +32,75 @@ const clickedHeaderLink = (route) => { }); }; -export default class MobileDropdownItem extends React.Component { - constructor(props) { - super(props); +const MobileDropdownItem = ({ + url, + title = '', + active = false, + comingSoon = false, + hideMobileNav = false, + externalLink = false, + isNewTab = false, + appendToExistingUrl = false +}) => { + const { pathname, search } = useLocation(); + const newUrl = appendToExistingUrl + ? getNewUrlForGlossary(pathname, url, search) + : url; - this.clickedLink = this.clickedLink.bind(this); - } - - clickedLink() { - clickedHeaderLink(this.props.url); - this.props.hideMobileNav(); - if (this.props.externalLink) { - redirectHelper.showRedirectModal(this.props.url); + const clickedLink = () => { + clickedHeaderLink(newUrl); + hideMobileNav(); + if (externalLink) { + redirectHelper.showRedirectModal(newUrl); } + }; + + let activeClass = ''; + if (active) { + activeClass = 'mobile-dropdown__link_active'; } - render() { - let activeClass = ''; - if (this.props.active) { - activeClass = 'mobile-dropdown__link_active'; - } + let comingSoonClass = ''; + let comingSoonDecorator = null; + if (comingSoon) { + comingSoonClass = 'mobile-dropdown__item_coming-soon'; + comingSoonDecorator = ( +
    + +
    + ); + } - let comingSoonClass = ''; - let comingSoonDecorator = null; - if (this.props.comingSoon) { - comingSoonClass = 'mobile-dropdown__item_coming-soon'; - comingSoonDecorator = ( -
    - -
    - ); - } + let link = ( +
  • + + {title} + {isNewTab && NEW} + + {comingSoonDecorator} +
  • + ); - let link = ( + if (externalLink) { + // Trigger the redirect modal + link = (
  • - - {this.props.title} - {this.props.isNewTab && NEW} - + onClick={clickedLink}> + {title} + {comingSoonDecorator}
  • ); - - if (this.props.externalLink) { - // Trigger the redirect modal - link = ( -
  • - - {comingSoonDecorator} -
  • - ); - } - - return link; } -} + + return link; +}; MobileDropdownItem.propTypes = propTypes; + +export default MobileDropdownItem; diff --git a/src/js/components/sharedComponents/header/mobile/MobileNav.jsx b/src/js/components/sharedComponents/header/mobile/MobileNav.jsx index 0273b00294..bcb91aba30 100644 --- a/src/js/components/sharedComponents/header/mobile/MobileNav.jsx +++ b/src/js/components/sharedComponents/header/mobile/MobileNav.jsx @@ -30,7 +30,7 @@ const propTypes = { location: PropTypes.object }; -const isDevOrQat = (DEV, QAT); +const isDevOrQat = (DEV || QAT); export class MobileNav extends React.Component { constructor(props) { diff --git a/src/js/helpers/glossaryHelper.js b/src/js/helpers/glossaryHelper.js index 95937e49f1..78f7d9a5d2 100644 --- a/src/js/helpers/glossaryHelper.js +++ b/src/js/helpers/glossaryHelper.js @@ -15,3 +15,17 @@ export const fetchSearchResults = (params) => apiRequest({ method: 'post', data: params }); + +export const getNewUrlForGlossary = (pathname, url, queryParams = '') => { + if (pathname === '/' && !queryParams) return url; + if (pathname[pathname.length - 1] === '/' && !queryParams) { + return `${pathname.substr(0, pathname.length - 1)}${url}`; + } + if (queryParams && pathname[pathname.length - 1] === '/') { + const cleanQueryParams = queryParams[0] === '?' + ? queryParams.substr(1) + : queryParams; + return `${pathname.substr(0, pathname.length - 1)}${url}&${cleanQueryParams}`; + } + return `${pathname}${url}`; +}; diff --git a/tests/helpers/glossaryHelper-test.js b/tests/helpers/glossaryHelper-test.js new file mode 100644 index 0000000000..691e43a0fb --- /dev/null +++ b/tests/helpers/glossaryHelper-test.js @@ -0,0 +1,10 @@ +import { getNewUrlForGlossary } from 'helpers/glossaryHelper'; + +test.each([ + // name, fn + ['/', '/?glossary=', ''], + ['/search', '/search/?glossary=', ''], + ['/submission-statistics/', '/submission-statistics/?glossary=&fy=2020&period=12', '?fy=2020&period=12'] +])('when existing url is %s, the glossary query param is appended correctly as %s', (existingUrl, expected, search = '') => { + expect(getNewUrlForGlossary(existingUrl, '/?glossary=', search)).toEqual(expected); +}); From eeaedd876c48939a85edb73f1f2e875c9a764dc8 Mon Sep 17 00:00:00 2001 From: Lizzie Salita Date: Fri, 22 Jan 2021 11:19:56 -0500 Subject: [PATCH 54/69] remove unused helper function --- src/js/containers/covid19/Covid19Container.jsx | 2 -- src/js/helpers/covid19Helper.js | 10 ---------- 2 files changed, 12 deletions(-) diff --git a/src/js/containers/covid19/Covid19Container.jsx b/src/js/containers/covid19/Covid19Container.jsx index 397239a8f6..4c754ccf31 100644 --- a/src/js/containers/covid19/Covid19Container.jsx +++ b/src/js/containers/covid19/Covid19Container.jsx @@ -55,8 +55,6 @@ require('pages/covid19/index.scss'); const Covid19Container = () => { const [isLoading, setIsLoading] = useState(true); const [dataDisclaimerBanner, setDataDisclaimerBanner] = useState(Cookies.get('usaspending_data_disclaimer')); - // const [selectedDEF, setselectedDEF] = useState('All'); - // const DEFOptions = getDEFOptions(setselectedDEF, defaultSortFy); const defCodesRequest = useRef(null); const overviewRequest = useRef(null); const lastSectionRef = useRef(null); diff --git a/src/js/helpers/covid19Helper.js b/src/js/helpers/covid19Helper.js index 33c00b199f..edc741550b 100644 --- a/src/js/helpers/covid19Helper.js +++ b/src/js/helpers/covid19Helper.js @@ -7,7 +7,6 @@ import { useState } from 'react'; import { snakeCase } from 'lodash'; import { apiRequest } from 'helpers/apiRequest'; import { - defCodes, dataDisclaimerHeight, stickyHeaderHeight, globalBannerHeight, @@ -92,15 +91,6 @@ export const getVerticalOffset = () => { return siteHeaderHeight + globalBannerHeight + dataDisclaimerHeight; }; -export const getDEFOptions = (setSelectedDEF, defaultSortDEF) => defCodes.map((year) => { - const onClickHandler = () => setSelectedDEF(year); - return { - name: `${year}`, - value: year, - onClick: onClickHandler - }; -}).sort((a, b) => defaultSortDEF(a.value, b.value)); - export const jumpToSection = ( section = '', verticalOffset = getVerticalOffset(), From ecc9e354e6b8cc74e8662eb0f75561ad8412d556 Mon Sep 17 00:00:00 2001 From: Lizzie Salita Date: Fri, 22 Jan 2021 12:54:11 -0500 Subject: [PATCH 55/69] fix existing tests; refactoring --- .../award/contract/ContractContent.jsx | 3 +- .../FinancialAssistanceContent.jsx | 2 +- src/js/containers/award/AwardContainer.jsx | 2 +- .../idv/IdvAwardAmountsSectionContainer.jsx | 4 +- .../award/idv/IdvActivityContainer-test.jsx | 8 ++- tests/containers/award/mockAward.js | 6 ++ .../homepage/CovidHighlights-test.jsx | 4 +- tests/models/award/BaseAwardAmounts-test.js | 31 ++++---- tests/models/awards/BaseSubawardRow-test.js | 30 -------- .../transactions/BaseTransactions-test.js | 70 ------------------- 10 files changed, 36 insertions(+), 124 deletions(-) rename tests/containers/{covid19 => }/homepage/CovidHighlights-test.jsx (90%) delete mode 100644 tests/models/awards/BaseSubawardRow-test.js delete mode 100644 tests/models/awards/transactions/BaseTransactions-test.js diff --git a/src/js/components/award/contract/ContractContent.jsx b/src/js/components/award/contract/ContractContent.jsx index 00a339e924..387e7dced8 100644 --- a/src/js/components/award/contract/ContractContent.jsx +++ b/src/js/components/award/contract/ContractContent.jsx @@ -51,8 +51,7 @@ const ContractContent = ({ }; const awardAmountData = Object.create(BaseAwardAmounts); - console.log('contract defCodes', defCodes); - awardAmountData.populate(overview, overview.category, defCodes.map((defc) => defc.code)); + awardAmountData.populate(overview, overview.category, defCodes); const jumpToTransactionHistoryTable = () => { setActiveTab('transaction'); diff --git a/src/js/components/award/financialAssistance/FinancialAssistanceContent.jsx b/src/js/components/award/financialAssistance/FinancialAssistanceContent.jsx index 87451648bc..f59cf0a4a8 100644 --- a/src/js/components/award/financialAssistance/FinancialAssistanceContent.jsx +++ b/src/js/components/award/financialAssistance/FinancialAssistanceContent.jsx @@ -72,7 +72,7 @@ const FinancialAssistanceContent = ({ }); const awardAmountData = Object.create(BaseAwardAmounts); - awardAmountData.populate(overview, overview.category, defCodes.map((defc) => defc.code)); + awardAmountData.populate(overview, overview.category, defCodes); const [idLabel, identifier] = isAwardAggregate(overview.generatedId) ? ['URI', overview.uri] : ['FAIN', overview.fain]; const isGrant = overview.category === 'grant'; diff --git a/src/js/containers/award/AwardContainer.jsx b/src/js/containers/award/AwardContainer.jsx index 33fa5048f3..7e3c506b5d 100644 --- a/src/js/containers/award/AwardContainer.jsx +++ b/src/js/containers/award/AwardContainer.jsx @@ -223,7 +223,7 @@ export class AwardContainer extends React.Component { award={this.props.award} isLoading={this.state.inFlight} noAward={this.state.noAward} - defCodes={this.props.defCodes} /> + defCodes={this.props.defCodes?.map((defc) => defc.code)} /> ); } } diff --git a/src/js/containers/award/idv/IdvAwardAmountsSectionContainer.jsx b/src/js/containers/award/idv/IdvAwardAmountsSectionContainer.jsx index 9842889930..b48783162e 100644 --- a/src/js/containers/award/idv/IdvAwardAmountsSectionContainer.jsx +++ b/src/js/containers/award/idv/IdvAwardAmountsSectionContainer.jsx @@ -111,7 +111,7 @@ export class IdvAmountsContainer extends React.Component { parseChildAwardAmounts(data) { const awardAmounts = Object.create(BaseAwardAmounts); - awardAmounts.populate(data, 'idv_aggregated', this.props.defCodes.map((defc) => defc.code)); + awardAmounts.populate(data, 'idv_aggregated', this.props.defCodes); this.setState({ awardAmounts, error: false, @@ -138,7 +138,7 @@ export class IdvAmountsContainer extends React.Component { render() { const thisIdv = Object.create(BaseAwardAmounts); - thisIdv.populate(this.props.award.overview, 'idv', this.props.defCodes.map((defc) => defc.code)); + thisIdv.populate(this.props.award.overview, 'idv', this.props.defCodes); const tabsClassName = 'idv-award-amounts-tabs'; const thisIdvHasFileC = ( thisIdv._fileCObligated !== 0 || diff --git a/tests/containers/award/idv/IdvActivityContainer-test.jsx b/tests/containers/award/idv/IdvActivityContainer-test.jsx index b84c1d71b4..5a4832e05f 100644 --- a/tests/containers/award/idv/IdvActivityContainer-test.jsx +++ b/tests/containers/award/idv/IdvActivityContainer-test.jsx @@ -16,11 +16,17 @@ jest.mock('helpers/idvHelper', () => require('../awardHelper')); // mock the child component by replacing it with a function that returns a null element // jest.mock('components/award/idv/amounts/AggregatedAwardAmounts.jsx', () => jest.fn(() => null)); +const mockProps = { + ...mockActions, + ...mockRedux, + defCodes: ['L', 'M', 'N', 'O', 'P', 'R'] +}; + describe('IdvActivityContainer', () => { const loadAwards = jest.fn(); const parseAwards = jest.fn(); it('should make an API call for the awards on mount', async () => { - const container = mount(); + const container = mount(); container.instance().loadAwards = loadAwards; container.instance().parseAwards = parseAwards; diff --git a/tests/containers/award/mockAward.js b/tests/containers/award/mockAward.js index 1df2273495..4f811dfd9d 100644 --- a/tests/containers/award/mockAward.js +++ b/tests/containers/award/mockAward.js @@ -38,5 +38,11 @@ export const mockRedux = { idvs: 45, contracts: 52 } + }, + covid19: { + defCodes: [ + { code: 'L' }, + { code: 'M' } + ] } }; diff --git a/tests/containers/covid19/homepage/CovidHighlights-test.jsx b/tests/containers/homepage/CovidHighlights-test.jsx similarity index 90% rename from tests/containers/covid19/homepage/CovidHighlights-test.jsx rename to tests/containers/homepage/CovidHighlights-test.jsx index 08877ba5da..c1e0704f58 100644 --- a/tests/containers/covid19/homepage/CovidHighlights-test.jsx +++ b/tests/containers/homepage/CovidHighlights-test.jsx @@ -6,9 +6,9 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { CovidHighlights } from 'containers/covid19/homepage/CovidHighlights'; +import { CovidHighlights } from 'containers/homepage/CovidHighlights'; -jest.mock("helpers/disasterHelper", () => ({ +jest.mock('helpers/disasterHelper', () => ({ fetchOverview: jest.fn(), fetchDisasterSpending: jest.fn(), fetchDEFCodes: jest.fn() diff --git a/tests/models/award/BaseAwardAmounts-test.js b/tests/models/award/BaseAwardAmounts-test.js index 6131863fe3..efea97cb13 100644 --- a/tests/models/award/BaseAwardAmounts-test.js +++ b/tests/models/award/BaseAwardAmounts-test.js @@ -27,8 +27,9 @@ mockIdv.populate(mockApiData.mockIdv); const mockLoan = Object.create(BaseFinancialAssistance); mockLoan.populate(mockApiData.mockLoan); +const mockDefc = ['L', 'M', 'N', 'O', 'P', 'R']; const awardAmounts = Object.create(BaseAwardAmounts); -awardAmounts.populate(mockAwardAmounts, "idv_aggregated"); +awardAmounts.populate(mockAwardAmounts, "idv_aggregated", mockDefc); const awardAmountsNeg = Object.create(BaseAwardAmounts); const negativeObligationAgg = { @@ -94,24 +95,24 @@ const extremeOverspentIdv = { _totalObligation: 0.0 }; -awardAmountsNeg.populate(negativeObligationAgg, "idv_aggregated"); -awardAmountsOverspent.populate(overspendingAgg, "idv_aggregated"); -awardAmountsExtremeOverspent.populate(extremeOverspendingAgg, "idv_aggregated"); +awardAmountsNeg.populate(negativeObligationAgg, "idv_aggregated", mockDefc); +awardAmountsOverspent.populate(overspendingAgg, "idv_aggregated", mockDefc); +awardAmountsExtremeOverspent.populate(extremeOverspendingAgg, "idv_aggregated", mockDefc); -nonAggregateIdvNormal.populate(normalIdv, 'idv'); -nonAggregateIdvOverspent.populate(overspentIdv, 'idv'); -nonAggregateIdvExtremeOverspent.populate(extremeOverspentIdv, 'idv'); +nonAggregateIdvNormal.populate(normalIdv, 'idv', mockDefc); +nonAggregateIdvOverspent.populate(overspentIdv, 'idv', mockDefc); +nonAggregateIdvExtremeOverspent.populate(extremeOverspentIdv, 'idv', mockDefc); describe('BaseAwardAmounts', () => { describe('All Award Types', () => { const awardAmountsWithId = Object.create(BaseAwardAmounts); - awardAmountsWithId.populate({ ...mockContract, generated_unique_award_id: decodedAwardId }, 'grant'); + awardAmountsWithId.populate({ ...mockContract, generated_unique_award_id: decodedAwardId }, 'grant', mockDefc); it('should encode the generated_unique_award_id when it is defined', () => { expect(awardAmountsWithId.generatedId).toEqual(encodedAwardId); }); it('should handle case where the generatedId is undefined by making it an empty string', () => { const noId = Object.create(BaseAwardAmounts); - noId.populate({ ...mockContract, generated_unique_award_id: null }, 'grant'); + noId.populate({ ...mockContract, generated_unique_award_id: null }, 'grant', mockDefc); expect(noId.generatedId).toEqual(''); }); }); @@ -193,7 +194,7 @@ describe('BaseAwardAmounts', () => { */ describe('Contract Award Amounts', () => { const contractAwardAmounts = Object.create(BaseAwardAmounts); - contractAwardAmounts.populate(mockContract, "contract"); + contractAwardAmounts.populate(mockContract, "contract", mockDefc); const arrayOfObjectProperties = Object.keys(contractAwardAmounts); it('does not create IDV specific properties', () => { expect(arrayOfObjectProperties.includes("childIDVCount")).toEqual(false); @@ -203,7 +204,7 @@ describe('BaseAwardAmounts', () => { }); describe('Grant Award Amounts', () => { const grantAwardAmounts = Object.create(BaseAwardAmounts); - grantAwardAmounts.populate(mockGrant, "grant"); + grantAwardAmounts.populate(mockGrant, "grant", mockDefc); const arrayOfObjectProperties = Object.keys(grantAwardAmounts); it('does not create IDV specific properties', () => { @@ -222,7 +223,7 @@ describe('BaseAwardAmounts', () => { }); describe('Loan Award Amounts', () => { const loanAwardAmounts = Object.create(BaseAwardAmounts); - loanAwardAmounts.populate(mockLoan, "loan"); + loanAwardAmounts.populate(mockLoan, "loan", mockDefc); it('creates loan specific properties w/ correct formatting', () => { expect(loanAwardAmounts._subsidy).toEqual(1290000.00); expect(loanAwardAmounts.subsidyFormatted).toEqual("$1,290,000.00"); @@ -262,7 +263,7 @@ describe('BaseAwardAmounts', () => { mockAward ) => { const mockAwardAmount = Object.create(BaseAwardAmounts); - mockAwardAmount.populate({ ...mockAward, generatedId: id }, awardType); + mockAwardAmount.populate({ ...mockAward, generatedId: id }, awardType, mockDefc); expect(mockAwardAmount.fileCObligatedFormatted).toEqual("$5,000,000.00"); expect(mockAwardAmount.fileCObligatedAbbreviated).toEqual("$5.0 M"); @@ -281,7 +282,7 @@ describe('BaseAwardAmounts', () => { obligations: [{ amount: 1, code: 'not-covid' }, { amount: 10, code: 'M' }], outlays: [{ amount: 1, code: 'not-covid' }, { amount: 10, code: 'M' }] } - }, 'contract'); + }, 'contract', mockDefc); expect(mockAwardAmount._fileCObligated).toEqual(10); expect(mockAwardAmount._fileCOutlay).toEqual(10); }); @@ -295,7 +296,7 @@ describe('BaseAwardAmounts', () => { obligations: [{ amount: 1, code: 'N' }, { amount: 10, code: 'M' }], outlays: [{ amount: 1, code: 'N' }, { amount: 10, code: 'M' }] } - }, 'contract'); + }, 'contract', mockDefc); expect(mockAwardAmount._fileCObligated).toEqual(11); expect(mockAwardAmount._fileCOutlay).toEqual(11); }); diff --git a/tests/models/awards/BaseSubawardRow-test.js b/tests/models/awards/BaseSubawardRow-test.js deleted file mode 100644 index dd91ab7e56..0000000000 --- a/tests/models/awards/BaseSubawardRow-test.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * BaseSubawardRow-test.js - * Created by Lizzie Salita 3/13/18 - */ - -import BaseSubawardRow from 'models/v2/award/subawards/BaseSubawardRow'; - -const mockSubaward = { - id: '456789', - subaward_number: '123', - description: null, - action_date: '1987-01-02', - amount: '2023.67', - recipient_name: 'Mock Recipient Name' -}; - -const subawardRow = Object.create(BaseSubawardRow); -subawardRow.populate(mockSubaward); - -describe('BaseSubawardRow', () => { - it('should return -- for a null description', () => { - expect(subawardRow.description).toEqual('--'); - }); - it('should format the action date', () => { - expect(subawardRow.actionDate).toEqual('01/02/1987'); - }); - it('should format the subaward amount', () => { - expect(subawardRow.amount).toEqual('$2,024'); - }); -}); diff --git a/tests/models/awards/transactions/BaseTransactions-test.js b/tests/models/awards/transactions/BaseTransactions-test.js deleted file mode 100644 index d97763d0d0..0000000000 --- a/tests/models/awards/transactions/BaseTransactions-test.js +++ /dev/null @@ -1,70 +0,0 @@ -/** - * BaseTransactions-test.js - * Created by Lizzie Salita 3/13/18 - */ - -import BaseContractTransaction from "models/v2/award/transactions/BaseContractTransaction"; -import BaseAssistanceTransaction from "models/v2/award/transactions/BaseAssistanceTransaction"; -import BaseLoanTransaction from "models/v2/award/transactions/BaseLoanTransaction"; - -const mockContractTransaction = { - federal_action_obligation: '1230.4' -}; - -const mockAssistanceTransaction = { - federal_action_obligation: '1230.4', - original_loan_subsidy_cost: '1230.4', - action_type: 'a', - cfda_number: '12.345' -}; - -const mockLoanTransaction = { - face_value_loan_guarantee: '1230.4', - original_loan_subsidy_cost: '234.58', - cfda_number: '12.345' -}; - -const contractTransaction = Object.create(BaseContractTransaction); -contractTransaction.populate(mockContractTransaction); - -const assistanceTransaction = Object.create(BaseAssistanceTransaction); -assistanceTransaction.populate(mockAssistanceTransaction); - -const loanTransaction = Object.create(BaseLoanTransaction); -loanTransaction.populate(mockLoanTransaction); - -describe('Base Transactions', () => { - describe('BaseContractTransaction', () => { - it('should format the federal action obligation', () => { - expect(contractTransaction.federalActionObligation).toEqual('$1,230'); - }); - it('should format the original loan subsidy cost', () => { - expect(assistanceTransaction.originalLoanSubsidyCost).toEqual('$1,230'); - }); - }); - describe('BaseAssistanceTransaction', () => { - it('should format the federal action obligation', () => { - expect(assistanceTransaction.federalActionObligation).toEqual('$1,230'); - }); - it('should format the original loan subsidy cost', () => { - expect(assistanceTransaction.originalLoanSubsidyCost).toEqual('$1,230'); - }); - it('should convert the action type', () => { - expect(assistanceTransaction._actionTypeDescription).toEqual('New'); - }); - it('should contain the cfda number', () => { - expect(assistanceTransaction.cfdaNumber).toEqual('12.345'); - }); - }); - describe('BaseLoanTransaction', () => { - it('should format the face value', () => { - expect(loanTransaction.faceValue).toEqual('$1,230'); - }); - it('should format the subsidy value', () => { - expect(loanTransaction.subsidy).toEqual('$235'); - }); - it('should contain the cfda number', () => { - expect(assistanceTransaction.cfdaNumber).toEqual('12.345'); - }); - }); -}); From 42d2a220420231045ea9ab1b7b47d74a780b5a29 Mon Sep 17 00:00:00 2001 From: Lizzie Salita Date: Fri, 22 Jan 2021 14:21:58 -0500 Subject: [PATCH 56/69] Added award container tests --- src/js/containers/award/AwardContainer.jsx | 2 +- .../containers/award/AwardContainer-test.jsx | 32 +++++++++++++++++-- tests/containers/award/awardHelper.js | 17 ++++++++++ tests/containers/award/mockAward.js | 15 ++++----- 4 files changed, 55 insertions(+), 11 deletions(-) diff --git a/src/js/containers/award/AwardContainer.jsx b/src/js/containers/award/AwardContainer.jsx index 7e3c506b5d..a83212e871 100644 --- a/src/js/containers/award/AwardContainer.jsx +++ b/src/js/containers/award/AwardContainer.jsx @@ -207,7 +207,7 @@ export class AwardContainer extends React.Component { this.defcRequest = null; } catch (err) { - console.err('Error fetching DEF Codes', err); + console.error('Error fetching DEF Codes', err); this.defcRequest = null; } } diff --git a/tests/containers/award/AwardContainer-test.jsx b/tests/containers/award/AwardContainer-test.jsx index 50ca0e55bc..23ee81427f 100644 --- a/tests/containers/award/AwardContainer-test.jsx +++ b/tests/containers/award/AwardContainer-test.jsx @@ -9,13 +9,14 @@ import { shallow } from 'enzyme'; import { AwardContainer } from 'containers/award/AwardContainer'; import BaseContract from 'models/v2/award/BaseContract'; import BaseIdv from 'models/v2/award/BaseIdv'; -import BaseFinancialAssistance from "models/v2/award/BaseFinancialAssistance"; +import BaseFinancialAssistance from 'models/v2/award/BaseFinancialAssistance'; import { mockParams, mockActions } from './mockAward'; import { mockContract, mockLoan, mockIdv } from '../../models/award/mockAwardApi'; jest.mock('helpers/searchHelper', () => require('./awardHelper')); -jest.mock("helpers/downloadHelper", () => require("./awardHelper")); +jest.mock('helpers/downloadHelper', () => require('./awardHelper')); +jest.mock('helpers/disasterHelper', () => require('./awardHelper')); // mock the child components by replacing them with functions that return null elements jest.mock('components/award/Award', () => jest.fn(() => null)); @@ -67,6 +68,25 @@ describe('awardContainer', () => { expect(getSelectedAward).toHaveBeenLastCalledWith('1234'); }); + it('should not make an API call for DEF Codes if they are already in Redux', () => { + const fetchCodes = jest.fn(); + const container = getAwardContainer(); // defCodes are populated in mockParams + container.instance().fetchCodes = fetchCodes; + container.instance().componentDidMount(); + expect(fetchCodes).toHaveBeenCalledTimes(0); + }); + + it('should make an API call for DEF Codes if they are not already in Redux', () => { + const fetchCodes = jest.fn(); + const container = shallow(); + container.instance().fetchCodes = fetchCodes; + container.instance().componentDidMount(); + expect(fetchCodes).toHaveBeenCalled(); + }); + describe('parseAward', () => { it('should parse returned contract data and send to the Redux store', () => { const awardContainer = getAwardContainer(); @@ -142,4 +162,12 @@ describe('awardContainer', () => { expect(result.data.file_name).toEqual('assistance.zip'); }); }); + + describe('fetchCodes', () => { + it('should call the setDEFCodes action creator', async () => { + const awardContainer = getAwardContainer(); + await awardContainer.instance().fetchCodes(); + expect(mockActions.setDEFCodes).toHaveBeenCalled(); + }); + }); }); diff --git a/tests/containers/award/awardHelper.js b/tests/containers/award/awardHelper.js index 9b3b5d4bf7..b410481e75 100644 --- a/tests/containers/award/awardHelper.js +++ b/tests/containers/award/awardHelper.js @@ -67,3 +67,20 @@ export const fetchAssistanceDownloadFile = () => ({ }); export const getChildAwardFileCDetails = (data) => data; + +export const fetchDEFCodes = () => ({ + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: { + codes: [ + { code: 'L', disaster: 'covid-19' }, + { code: 'M', disaster: 'covid-19' }, + { code: 'A', disaster: 'not_covid-19' } + ] + } + }); + }); + }), + cancel: jest.fn() +}); diff --git a/tests/containers/award/mockAward.js b/tests/containers/award/mockAward.js index 4f811dfd9d..ce1312dff7 100644 --- a/tests/containers/award/mockAward.js +++ b/tests/containers/award/mockAward.js @@ -15,7 +15,11 @@ export const mockParams = { id: '1234', category: 'contract', overview: mockContract - } + }, + defCodes: [ + { code: 'L' }, + { code: 'M' } + ] }; export const mockActions = { @@ -26,7 +30,8 @@ export const mockActions = { setDownloadExpectedFile: jest.fn(), setDownloadPending: jest.fn(), setDownloadCollapsed: jest.fn(), - setIdvDetails: jest.fn() + setIdvDetails: jest.fn(), + setDEFCodes: jest.fn() }; export const mockRedux = { @@ -38,11 +43,5 @@ export const mockRedux = { idvs: 45, contracts: 52 } - }, - covid19: { - defCodes: [ - { code: 'L' }, - { code: 'M' } - ] } }; From e0ff3b9fac480662a14cd8f1c92504a0d5646b31 Mon Sep 17 00:00:00 2001 From: Keith Hickey Date: Fri, 22 Jan 2021 16:13:11 -0500 Subject: [PATCH 57/69] Add Docker Instructions to README & Clean up Dockerfile (PR #2350) --- .dockerignore | 3 ++ .gitignore | 2 +- Dockerfile | 19 ++++++-- README.md | 130 +++++++++++++++++++++++++++----------------------- 4 files changed, 89 insertions(+), 65 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..209440ea29 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +# Keep docker image clean of any development-generated artifacts by ignoring them on COPY +node_modules +public diff --git a/.gitignore b/.gitignore index 631d92dd9d..2f61b085dc 100644 --- a/.gitignore +++ b/.gitignore @@ -61,7 +61,7 @@ usa_spending.sh /scripts/sitemaps/sitemapFiles/*.xml # direnv -.envrc +\.envrc # IDE stuff .vscode diff --git a/Dockerfile b/Dockerfile index 05c2fa71ac..f4da5ffdae 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,22 @@ FROM node:12.18.4 -RUN mkdir /node-workspace -COPY package.json /node-workspace -COPY package-lock.json /node-workspace +# Default environment variables +ENV ENV=prod USASPENDING_API=https://api.usaspending.gov/api/ MAPBOX_TOKEN='' GA_TRACKING_ID='' + +RUN mkdir /node-workspace && mkdir /test-results + +# Copy JUST the package files first. +# This allows Docker to NOT re-fetch all NPM packages if neither of these two files +# have changed, and instead use the cached layer containing all those dependent packages. +# Greatly speeds up repeated docker build calls on the same machine (like CI/CD boxes) +# by leveraging the docker image cache +COPY package.json package-lock.json /node-workspace/ WORKDIR /node-workspace +# Clean Node module dependencies and install them fresh RUN npm ci +# Now copy the remaining source files +# Files in .dockerignore will not be copied COPY . /node-workspace - -RUN mkdir /test-results diff --git a/README.md b/README.md index 23f260dfa8..4dd99dbdb5 100644 --- a/README.md +++ b/README.md @@ -5,74 +5,86 @@ [The USAspending website](https://www.usaspending.gov/) is the public-facing site offering information on Government spending for the United States. It utilizes the [Data Transparency User Interface Library](https://github.com/fedspendingtransparency/data-transparency-ui). ## Development Set Up -To run the USAspending website locally, follow the directions below. +- To contribute to frontend development, follow _Install and Configure_ below. +- To simply run the USAspending website locally, jump to _Build and Run with Docker_ below. -Assumptions: +_Assumptions_: * You're able to install software on your machine. * You have git installed on your machine and are able to clone code repositories from GitHub. If this isn't the case, the easiest way to get started is to install [GitHub Desktop](https://desktop.github.com/ "GitHub desktop"), available for Windows or Mac. * You're familiar with opening a terminal on your machine and using the command line as needed. -### Install Prerequisites and Code - -1. If you're not already running Node.js, download and run the installer for your operating system. We build using **Node.js 10.15.3 (LTS)** which we recommend downloading using [Node Version Manager (nvm)](https://github.com/nvm-sh/nvm). - -2. You also need npm. We use version `6.14.5`. - -```shell - npm i -g npm@6.14.5 -``` - -3. From the command line, clone the USAspending website repository from GitHub to your local machine: - -```shell - git clone https://github.com/fedspendingtransparency/usaspending-website.git -``` - -4. Change to the `usaspending-website` directory that was created when you cloned the USAspending Website repository. - -```shell - cd usaspending-website -``` - -5. Perform a clean install to get an exact dependency tree: - -```shell - npm ci -``` - -### Configuration File - -The USAspending website expects a certain number of environment variables to be defined at runtime. The important ones are listed below along with their default values: - -| ENV VAR | VALUE | -|----------------|----------------------------------| -| USASPENDING_API| https://api.usaspending.gov/api/ | -| MAPBOX_TOKEN | '' | -| GA_TRACKING_ID | '' | +### Install and Configure +_Get the code and install the runtime and dependencies_ + +1. From the command line, clone the USAspending website repository from GitHub to your local machine, and get into the root directory: + ```shell + $ git clone https://github.com/fedspendingtransparency/usaspending-website + $ cd usaspending-website + ``` +1. Download [Node Version Manager (`nvm`)](https://github.com/nvm-sh/nvm) and install **Node.js `12.18.4`** + ```shell + $ nvm install 12.18.4 + ``` +1. Set Node Package Manager (`npm`) CLI to version `6.14.5`. + ```shell + $ npm i -g npm@6.14.5 + ``` +1. Perform a clean install to get an exact dependency tree: + ```shell + $ npm ci + ``` +1. Run the site in a local dev server: + ```shell + $ npm start + ``` + +### Configuration +_Alter configuration to non-default values by changing environment variable values._ + +Our site makes use of certain environment variables. Defaults are provided, but can be overridden by `export` of new values in your local shell. These are the important ones: + +| ENV VAR | DEFAULT VALUE (if not set) | PURPOSE +|-------------------|----------------------------------|-----------------------------------------------------| +| `ENV` | prod | Determine bundling optimizations and feature flags | +| `USASPENDING_API` | https://api.usaspending.gov/api/ | API URL to get backend data | +| `MAPBOX_TOKEN` | '' | Product key for use of MapBox features | +| `GA_TRACKING_ID` | '' | Google Analytics key for anonymously tracking usage | ### Scripts +_Custom and life-cycle scripts to execute, as defined under the `scripts` property in `package.json`_ + +| Script | Output | +|--------------|-------------------------------------------------------------| +| `npm start` | dev server with hot reloading | +| `npm prod` | generates static assets w/ production optimization | +| `npm dev` | generates static assets w/ development optimization | +| `npm lint` | executes linter | +| `npm test` | executes unit tests | +| `npm sass` | dev server w/ scss source maps | +| `npm travis` | executes travis validation script | +| `npm ci` | clean existing Node dependencies and install dependencies | + +### Build and Run with Docker +Docker can be used to build static site artifacts and/or run the site locally. Ensure your environment variables are configured and use this "one-liner" (or decompose and run each `docker` command separately): + +```bash +docker build -t usaspending-website . && \ +docker run --rm -v $(pwd)/public:/node-workspace/public \ + -e ENV \ + -e USASPENDING_API \ + -e MAPBOX_TOKEN \ + -e GA_TRACKING_ID \ + usaspending-website npm run ${ENV} && \ +docker run --rm -v $(pwd)/public:/usr/share/nginx/html:ro -p 8020:80 nginx:1.18 +``` -| Script | Output | -|------------|-----------------------------------------------------| -| `npm start` | dev server with hot reloading | -| `npm prod` | generates static assets w/ production optimization | -| `npm dev` | generates static assets w/ development optimization | -| `npm lint` | executes linter | -| `npm test` | executes unit tests | -| `npm sass` | dev server w/ scss source maps | -| `npm travis` | executes travis validation script | +_The first two steps can take 5+ minutes each, so this could be a total of ~10 minutes before ready._ -### Deployment Build Step with DockerFile -When deploying we use the dockerfile for our build step. We can simulate that process as follows: +What this does: +1. Ensure your `usaspending-website` Docker image has the latest dependencies: +1. Generate and bundle static artifacts and output to `./public` +1. Mount the static artifacts to a running container of an nginx image and host at port `8020` -``` -# from usaspending-website root, build the container image -docker build -t usaspending-website . -# generate static artifacts in ./public -docker run -i --rm=true -v $(pwd)/public:/node-workspace/public usaspending-website /bin/sh -c 'npm run dev' -# mount the static artifacts to an nginx image and run -docker run -p 8020:80 -v $(pwd)/public:/usr/share/nginx/html:ro nginx -``` -The app should now be running at `http://localhost:8020`. +You should see console logs, and the app should now be running at `http://localhost:8020`. From 556d660083d3f74f5ccb10c1de77fca26da8371e Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Tue, 26 Jan 2021 14:24:43 -0500 Subject: [PATCH 58/69] [DEV-6291] Dark Release Footer Updates Only show updates in QAT / DEV --- src/js/containers/Footer.jsx | 70 +++++++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 17 deletions(-) diff --git a/src/js/containers/Footer.jsx b/src/js/containers/Footer.jsx index 1f976a34d2..670f7c6153 100644 --- a/src/js/containers/Footer.jsx +++ b/src/js/containers/Footer.jsx @@ -9,6 +9,7 @@ import React from 'react'; import { Link } from 'react-router-dom'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faFacebookSquare, faLinkedin, faGithub, faTwitter } from "@fortawesome/free-brands-svg-icons"; +import { QAT, DEV } from 'GlobalConstants'; import { showModal } from 'redux/actions/modal/modalActions'; @@ -34,6 +35,8 @@ const clickedFooterLink = (route) => { }); }; +const isDevOrQat = (DEV || QAT); + const Footer = ({ filters, redirectUser @@ -113,6 +116,35 @@ const Footer = ({
    + {!isDevOrQat && ( +
    +
    + Resources +
    +
      +
    • + + Data Dictionary + +
    • +
    • + +
    • +
    • + +
    • +
    • + +
    • +
    +
    + )}
    Developers @@ -128,26 +160,30 @@ const Footer = ({ link="https://github.com/fedspendingtransparency/usaspending-website/tree/master" title="Explore the Code" /> -
  • - -
  • + {isDevOrQat && ( +
  • + +
  • + )}
    -
    -
    - Our Sites + {isDevOrQat && ( +
    +
    + Our Sites +
    +
    - -
    + )}
    • From 6487a104d03d1f1c37fde0c8a02c17dcae31ef9e Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Tue, 26 Jan 2021 14:42:30 -0500 Subject: [PATCH 59/69] [DEV-6662] Open API Tutorial in new tab --- src/js/dataMapping/navigation/menuOptions.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/js/dataMapping/navigation/menuOptions.jsx b/src/js/dataMapping/navigation/menuOptions.jsx index 9dd971f539..bc750d1888 100644 --- a/src/js/dataMapping/navigation/menuOptions.jsx +++ b/src/js/dataMapping/navigation/menuOptions.jsx @@ -89,7 +89,8 @@ export const resourceOptions = [ { label: 'API Tutorial', url: 'https://api.usaspending.gov/docs/intro-tutorial', - enabled: true + enabled: true, + shouldOpenNewTab: true } ]; From 374db4b26c597c47c7e5a022d1b0ef52fa816177 Mon Sep 17 00:00:00 2001 From: Lizzie Salita Date: Tue, 26 Jan 2021 14:43:47 -0500 Subject: [PATCH 60/69] left-align the Agency Comments column --- src/js/containers/aboutTheData/AgencyTableMapping.jsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/js/containers/aboutTheData/AgencyTableMapping.jsx b/src/js/containers/aboutTheData/AgencyTableMapping.jsx index c27f955f91..1eb45a700c 100644 --- a/src/js/containers/aboutTheData/AgencyTableMapping.jsx +++ b/src/js/containers/aboutTheData/AgencyTableMapping.jsx @@ -111,8 +111,7 @@ export const agenciesTableColumns = { { title: 'assurance_statements', displayName: 'Agency Comments', - icon: , - right: true + icon: } ] }; From 003140cb0aee79f3c25d6a44d00ebd2cbae92173 Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Fri, 29 Jan 2021 14:14:24 -0500 Subject: [PATCH 61/69] [DEV-6748] adv search w/ query params ptI: new route for /search/:hash. Will just redirect this to /search/?hash= in next commit! --- src/js/containers/router/RouterRoutes.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/js/containers/router/RouterRoutes.js b/src/js/containers/router/RouterRoutes.js index 8eb750f041..ee51de9760 100644 --- a/src/js/containers/router/RouterRoutes.js +++ b/src/js/containers/router/RouterRoutes.js @@ -9,6 +9,7 @@ import kGlobalConstants from 'GlobalConstants'; const Homepage = React.lazy(() => import('components/homepage/Homepage').then((comp) => comp)); const SearchContainer = React.lazy(() => import('containers/search/SearchContainer').then((comp) => comp)); +const SearchContainerRedirect = React.lazy(() => import('containers/search/SearchContainer').then((module) => ({ default: module.SearchContainerRedirect }))); const ExplorerLanding = React.lazy(() => import('components/explorer/landing/ExplorerLanding').then((comp) => comp)); const ExplorerDetailPageContainer = React.lazy(() => import('containers/explorer/detail/ExplorerDetailPageContainer').then((comp) => comp)); const AwardContainer = React.lazy(() => import('containers/award/AwardContainer').then((comp) => comp)); @@ -49,7 +50,7 @@ export const routes = [ }, { path: '/search/:urlHash', - component: SearchContainer, + component: SearchContainerRedirect, exact: true }, { From 342ab9fd91302d150798963260011191a8553246 Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Fri, 29 Jan 2021 14:22:07 -0500 Subject: [PATCH 62/69] [DEV-6748] adv search w/ query params pt II: -- SearchContainerRedirect: export named component to handle redirect -- line 164: setAppliedFilterEmptiness after restoring the hashed filters so that when ResultsTableContainer mounts with filters defined. (ResultsTableContainer changes in next commit!) -- line 162-163: handle case where applied filters are present from special link. In this case we ensure the filters are both applied and staged. -- line 174-177: clear filters on unmount. This fixes an existing bug in production where if you go back to advanced search the previous search populates -- manually clear the download state when removing filters. Prior, we were relying on the remount to clear out this state. Now, using query params, we arent actually remounting so we do this manually. -- lines 208-211: using .push instead of .replace b/c this seems nicer/better. TESTS refactored to use query params --- src/js/containers/search/SearchContainer.jsx | 43 ++++++++++++++++--- .../search/SearchContainer-test.jsx | 31 +++++++------ 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/src/js/containers/search/SearchContainer.jsx b/src/js/containers/search/SearchContainer.jsx index 8ac3a85967..8353001fa1 100644 --- a/src/js/containers/search/SearchContainer.jsx +++ b/src/js/containers/search/SearchContainer.jsx @@ -7,7 +7,7 @@ import React, { useState, useEffect, useCallback, useRef } from 'react'; import PropTypes from 'prop-types'; import { useDispatch, useSelector } from 'react-redux'; import { isCancel } from 'axios'; -import { useParams } from 'react-router-dom'; +import { Redirect, useLocation, useParams } from 'react-router-dom'; import { filterStoreVersion, requiredTypes, initialState } from 'redux/reducers/search/searchFiltersReducer'; import { restoreHashedFilters } from 'redux/actions/search/searchHashActions'; @@ -71,7 +71,8 @@ export const parseRemoteFilters = (data) => { }; const SearchContainer = ({ history }) => { - const { urlHash } = useParams(); + const { hash: urlHash } = SearchHelper.getObjFromQueryParams(useLocation().search); + const dispatch = useDispatch(); const { filters: stagedFilters, @@ -138,11 +139,11 @@ const SearchContainer = ({ history }) => { }); request.current.promise .then((res) => { - dispatch(setAppliedFilterEmptiness(false)); const filtersInImmutableStructure = parseRemoteFilters(res.data.filter); if (filtersInImmutableStructure) { // apply the filters to both the staged and applied stores dispatch(restoreHashedFilters(filtersInImmutableStructure)); + dispatch(setAppliedFilterEmptiness(false)); // set download availability setDownloadAvailability(filtersInImmutableStructure); } @@ -158,6 +159,9 @@ const SearchContainer = ({ history }) => { } }); } + else if (SearchHelper.areFiltersSelected(appliedFilters) && SearchHelper.areFiltersEmpty(stagedFilters)) { + dispatch(restoreHashedFilters(appliedFilters)); + } else if (!urlHash) { dispatch(resetAppliedFilters()); dispatch(clearAllFilters()); @@ -167,15 +171,23 @@ const SearchContainer = ({ history }) => { if (request.current) { request.current.cancel(); } + // clear selected filters so we don't fetch previous search + // only when query hash is defined b/c if its a urlHash, we cant know if we're remounting w/ the query hash or going somewhere else + dispatch(resetAppliedFilters()); + dispatch(clearAllFilters()); }; }, []); useEffect(() => { if (areAppliedFiltersEmpty && prevAreAppliedFiltersEmpty === false) { // all the filters were cleared, reset to a blank hash - history.replace('/search'); + history.replace({ + pathname: '/search', + search: '' + }); + setDownloadAvailable(false); } - }, [areAppliedFiltersEmpty]); + }, [areAppliedFiltersEmpty, urlHash]); const generateHash = useCallback(() => { // POST an API request to retrieve the Redux state @@ -193,8 +205,10 @@ const SearchContainer = ({ history }) => { request.current.promise .then((res) => { // update the URL with the received hash - const newHash = res.data.hash; - history.replace(`/search/${newHash}`); + history.push({ + pathname: `/search/`, + search: `?${new URLSearchParams({ hash: res.data.hash }).toString()}` + }); setGenerateHashInFlight(false); }) .catch((err) => { @@ -238,3 +252,18 @@ const SearchContainer = ({ history }) => { SearchContainer.propTypes = propTypes; export default SearchContainer; + +export const SearchContainerRedirect = () => { + const { urlHash: pathHash } = useParams(); + return ( + + ); +}; + +SearchContainer.propTypes = { + history: PropTypes.object.isRequired +}; diff --git a/tests/containers/search/SearchContainer-test.jsx b/tests/containers/search/SearchContainer-test.jsx index d74074c310..2e21a295ab 100644 --- a/tests/containers/search/SearchContainer-test.jsx +++ b/tests/containers/search/SearchContainer-test.jsx @@ -5,7 +5,7 @@ import React from 'react'; import { render, waitFor } from '@testing-library/react'; import { Set } from 'immutable'; -import { useParams } from 'react-router-dom'; +import { useLocation } from 'react-router-dom'; import * as redux from 'react-redux'; import SearchContainer, { parseRemoteFilters } from 'containers/search/SearchContainer'; @@ -23,6 +23,8 @@ jest.mock('components/search/SearchPage', () => ( jest.fn(() => null) )); +jest.spyOn(URLSearchParams.prototype, 'toString').mockImplementation(() => 'str'); + jest.mock('helpers/searchHelper', () => ({ ...jest.requireActual('helpers/searchHelper'), ...require('./filters/searchHelper') @@ -41,7 +43,7 @@ jest.mock('react-redux', () => { jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), - useParams: jest.fn().mockReturnValue({ urlHash: 'abc' }) + useLocation: jest.fn().mockReturnValue({ search: '' }) })); jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; @@ -71,16 +73,9 @@ test('parseRemoteFilters should return an immutable data structure when versions expect(parseRemoteFilters(mock.filter).timePeriodFY).toEqual(expectedFilter); }); -test('a non-hashed does not make a request to the api', async () => { - useParams.mockReturnValueOnce({ urlHash: null }); - render(, {}); - await waitFor(() => { - expect(restoreUrlHash).not.toHaveBeenCalled(); - expect(generateUrlHash).not.toHaveBeenCalled(); - }); -}); - -test('a hashed url makes a request to the api & sets loading state', async () => { +test('a hashed url (as a query param) makes a request to the api & sets loading state', async () => { + restoreUrlHash.mockClear(); + useLocation.mockReturnValueOnce({ search: '?hash=abc' }); const setLoadingStateFn = jest.spyOn(appliedFilterActions, 'setAppliedFilterEmptiness'); render(, {}); await waitFor(() => { @@ -92,9 +87,8 @@ test('a hashed url makes a request to the api & sets loading state', async () => test('when filters change (a) hash is generated, (b) loading is set & (c) url is updated', async () => { restoreUrlHash.mockClear(); - useParams.mockReturnValueOnce({ urlHash: null }); const setLoading = jest.spyOn(appliedFilterActions, 'setAppliedFilterEmptiness'); - const mockReplace = jest.fn(); + const mockPush = jest.fn(); jest.spyOn(redux, 'useSelector').mockReturnValue({ ...mockRedux, appliedFilters: { @@ -105,11 +99,16 @@ test('when filters change (a) hash is generated, (b) loading is set & (c) url is } }); - render(, {}); + render(, {}); await waitFor(() => { expect(generateUrlHash).toHaveBeenCalledTimes(1); - expect(mockReplace).toHaveBeenCalledTimes(1); + expect(mockPush).toHaveBeenCalledTimes(1); + expect(mockPush).toHaveBeenLastCalledWith({ + pathname: '/search/', + // not ?hash=str because we aren't mocking out new URLSearchParams + search: '?str' + }); expect(setLoading).toHaveBeenCalledWith(false); expect(restoreUrlHash).not.toHaveBeenCalled(); }); From 74bc64a45e107d151068f077f32cc1c46fc4161b Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Fri, 29 Jan 2021 15:08:25 -0500 Subject: [PATCH 63/69] put p4 in q2 --- src/js/containers/aboutTheData/AgencyTableMapping.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/containers/aboutTheData/AgencyTableMapping.jsx b/src/js/containers/aboutTheData/AgencyTableMapping.jsx index 1eb45a700c..710ce8e6ce 100644 --- a/src/js/containers/aboutTheData/AgencyTableMapping.jsx +++ b/src/js/containers/aboutTheData/AgencyTableMapping.jsx @@ -32,7 +32,7 @@ export const agenciesTableColumns = { { title: 'Q1', displayName: `FY ${fy} Q1`, - columnSpan: '3', + columnSpan: '2', subColumnNames: [ { displayName: 'P01 - P02', title: 'publication_date,2' }, { displayName: 'P03', title: 'publication_date,3' } From ead3af81b1907108c76bd598ce8605e2857ed9eb Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Fri, 29 Jan 2021 17:32:01 -0500 Subject: [PATCH 64/69] [DEV-6536] About the Data Publication Dates Table: -- when no publication date present: show -- previously not submitted was shown -- last period for quarterly submissions still shows the calendar date -- right align % of total budget --- src/js/containers/aboutTheData/AgenciesContainer.jsx | 7 +++---- src/js/containers/aboutTheData/AgencyTableMapping.jsx | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/js/containers/aboutTheData/AgenciesContainer.jsx b/src/js/containers/aboutTheData/AgenciesContainer.jsx index 914d5d55fa..f2fca6358c 100644 --- a/src/js/containers/aboutTheData/AgenciesContainer.jsx +++ b/src/js/containers/aboutTheData/AgenciesContainer.jsx @@ -21,11 +21,10 @@ const propTypes = { }; const parsePeriods = (periods) => periods - .map(({ publicationDate, showNotCertified, isQuarterly }) => ( + .map(({ publicationDate, showNotCertified }) => (
      - {(!isQuarterly && publicationDate) && publicationDate} - {isQuarterly && "Submitted quarterly"} - {!publicationDate && "Not submitted"} + {(publicationDate) && publicationDate} + {!publicationDate && "--"} {showNotCertified && publicationDate && NOT CERTIFIED}
      )); diff --git a/src/js/containers/aboutTheData/AgencyTableMapping.jsx b/src/js/containers/aboutTheData/AgencyTableMapping.jsx index 710ce8e6ce..7fa58fd72f 100644 --- a/src/js/containers/aboutTheData/AgencyTableMapping.jsx +++ b/src/js/containers/aboutTheData/AgencyTableMapping.jsx @@ -27,6 +27,7 @@ export const agenciesTableColumns = { { title: 'agency_name', displayName: 'Agency Name' }, { title: 'current_total_budget_authority_amount', + right: true, displayName: 'Percent of Total Federal Budget' }, { From fa0dcc46338d2ded343cc9f0d69ea6be8dfb1d91 Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Tue, 2 Feb 2021 16:37:15 -0500 Subject: [PATCH 65/69] [dev-6464] fixing copy --- src/js/components/aboutTheData/AboutTheDataPage.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/components/aboutTheData/AboutTheDataPage.jsx b/src/js/components/aboutTheData/AboutTheDataPage.jsx index 950f89f580..aaba61cf4d 100644 --- a/src/js/components/aboutTheData/AboutTheDataPage.jsx +++ b/src/js/components/aboutTheData/AboutTheDataPage.jsx @@ -125,8 +125,8 @@ const AboutTheDataPage = ({ types={[ { internal: 'submissions', - label: "Statistics by Reporting Period", - labelContent: + label: "Statistics by Submission Period", + labelContent: }, { internal: 'publications', From ee3edaf3f1058cfcf794a12abad3824000132fed Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Fri, 29 Jan 2021 14:26:08 -0500 Subject: [PATCH 66/69] [DEV-6748] adv search w/ query params pt III: -- ResultsTableContainer: we simplify detection of new filters just by looking at the hash. If the hash changes, we trust we have new filters, otherwise we assume we dont. We've improved logic in SearchContainer so that we can reliably do this. TESTS refactored to expect query param --- .../search/table/ResultsTableContainer.jsx | 11 +++++------ .../search/table/ResultsTableContainer-test.jsx | 12 ++++-------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/js/containers/search/table/ResultsTableContainer.jsx b/src/js/containers/search/table/ResultsTableContainer.jsx index 069924040e..36d4f31096 100644 --- a/src/js/containers/search/table/ResultsTableContainer.jsx +++ b/src/js/containers/search/table/ResultsTableContainer.jsx @@ -122,19 +122,18 @@ export class ResultsTableContainer extends React.Component { // we can't hide the table entirely because the viewport is required to calculate the // row rendering this.loadColumns(); - if (SearchHelper.isSearchHashReady(this.props.location.pathname)) { + if (SearchHelper.isSearchHashReady(this.props.location)) { this.pickDefaultTab(); } } componentDidUpdate(prevProps) { - const filtersChanged = !SearchHelper.areFiltersEqual(prevProps.filters, this.props.filters); - if (filtersChanged && !this.props.noApplied) { - // filters changed, update the search object + if (prevProps.subaward !== this.props.subaward && !this.props.noApplied) { + // subaward toggle changed, update the search object this.pickDefaultTab(); } - else if (prevProps.subaward !== this.props.subaward && !this.props.noApplied) { - // subaward toggle changed, update the search object + else if (SearchHelper.isSearchHashReady(this.props.location) && this.props.location.search !== prevProps.location.search) { + // hash is (a) defined and (b) new this.pickDefaultTab(); } } diff --git a/tests/containers/search/table/ResultsTableContainer-test.jsx b/tests/containers/search/table/ResultsTableContainer-test.jsx index fe29e57182..26f61505f2 100644 --- a/tests/containers/search/table/ResultsTableContainer-test.jsx +++ b/tests/containers/search/table/ResultsTableContainer-test.jsx @@ -39,19 +39,15 @@ jest.mock('helpers/textMeasurement', () => ( )); describe('ResultsTableContainer', () => { - it('should pick a default tab whenever the Redux filters change & hash is present', async () => { + it('should pick a default tab whenever the hash changes', async () => { const container = mount(); container.instance().parseTabCounts = jest.fn(); - // update the filters - const newFilters = Object.assign({}, mockRedux.filters, { - timePeriodFY: new Set(['1987']) - }); - container.setProps({ filters: newFilters }); + container.setProps({ location: { search: '?hash=456' } }); await container.instance().tabCountRequest.promise; @@ -60,7 +56,7 @@ describe('ResultsTableContainer', () => { it('should pick a default tab whenever the subaward toggle changes & hash is present', async () => { const container = mount(); From d189499f5bf96c4780f6e0dca4b794665f97e601 Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Fri, 29 Jan 2021 14:27:05 -0500 Subject: [PATCH 67/69] [DEV-6748] adv search w/ query params pt IV: searchHelper: isSearchHashReady refactored to expect queryParam TESTS included --- src/js/helpers/searchHelper.js | 25 +++++++++++++++++++++---- tests/helpers/searchHelper-test.js | 12 ++++++++---- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/js/helpers/searchHelper.js b/src/js/helpers/searchHelper.js index ce27cfb66e..47b0357025 100644 --- a/src/js/helpers/searchHelper.js +++ b/src/js/helpers/searchHelper.js @@ -177,7 +177,24 @@ export const areFiltersSelected = (filters) => !areFiltersEqual(filters); export const areFiltersDifferent = (a, b) => !areFiltersEqual(a, b); -export const isSearchHashReady = (str) => str - .split('/search/') - .filter((s) => s && s !== "/search") - .length > 0; +export const isSearchHashReady = ({ search }) => { + if (search) { + const params = new URLSearchParams(search); + for (const [key, value] of params.entries()) { + if (key === 'hash' && value) { + return true; + } + } + return false; + } + return false; +}; + +export const getObjFromQueryParams = (str) => { + const params = new URLSearchParams(str); + const obj = {}; + for (const [key, value] of params.entries()) { + obj[key] = value; + } + return obj; +}; diff --git a/tests/helpers/searchHelper-test.js b/tests/helpers/searchHelper-test.js index f218c77c74..353643ce0d 100644 --- a/tests/helpers/searchHelper-test.js +++ b/tests/helpers/searchHelper-test.js @@ -19,8 +19,12 @@ test('areFiltersEqual should return false when filters are selected', () => { })).toBeFalsy(); }); -test('isSearchHashReady knows when theres a hash', () => { - expect(isSearchHashReady('/search')).toEqual(false); - expect(isSearchHashReady('/search/')).toEqual(false); - expect(isSearchHashReady('/search/test')).toEqual(true); +test.each([ + ['', false], + ['/?', false], + ['/?fy=2020&period=12&hash=', false], + ['/?fy=2020&period=12&hash=t', true] +])('when input (a query param) is %s return value is %s', (input, rtrn) => { + expect(isSearchHashReady({ search: input })).toEqual(rtrn); }); + From de857f86fb5fdc9c3c7612c9ad707d06ccedaee6 Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Mon, 1 Feb 2021 16:45:31 -0500 Subject: [PATCH 68/69] [DEV-6748] refactor areFiltersEqual to use both lodash.isEqual and immutable.is(). areFiltersEqual depended on the Immutable.is() operator. It is constrained to primitive (non object/array) values or immutable data structures for accurate nested object comaprisons. We were using an immutable.Record w/ non immutable, non-primitive values for the checkboxTree filters. This resulted in wrong returns on the immutable.is() invocations inside areFiltersEqual. This refactor adds a new path for non-immutable objects in our redux.appliedFilters and redux.filters keyspace that allows for an accurate comparison using lodash.isEqual. Tests were added to throughouly demonstrate this. We add a new invocation of this fn, areFiltersEqual, inside SearchContainer to handle the case where a user is on adv search and clicks the pre-poulate adv search link in the COVID Modal. --- src/js/containers/search/SearchContainer.jsx | 6 ++ .../shared/checkboxTree/checkboxTree.jsx | 7 ++ src/js/helpers/searchHelper.js | 27 +++++-- .../search/SearchContainer-test.jsx | 19 ++++- tests/helpers/searchHelper-test.js | 71 +++++++++++++++---- 5 files changed, 108 insertions(+), 22 deletions(-) diff --git a/src/js/containers/search/SearchContainer.jsx b/src/js/containers/search/SearchContainer.jsx index 8353001fa1..00f8d58a71 100644 --- a/src/js/containers/search/SearchContainer.jsx +++ b/src/js/containers/search/SearchContainer.jsx @@ -238,6 +238,12 @@ const SearchContainer = ({ history }) => { } }, [appliedFilters, urlHash]); + useEffect(() => { + if (SearchHelper.areFiltersDifferent(appliedFilters, stagedFilters) && SearchHelper.areFiltersDifferent(prevAppliedFilters, appliedFilters)) { + dispatch(restoreHashedFilters(appliedFilters)); + } + }, [appliedFilters, stagedFilters]); + return ( apiRequest({ url: 'v2/awards/last_updated/' }); +const areCheckboxSelectionsEqual = ({ exclude: exclude1, require: require1 }, { exclude: exclude2, require: require2 }) => { + if (!isEqual(sortBy(require1), sortBy(require2))) return false; + if (!isEqual(sortBy(exclude1), sortBy(exclude2))) return false; + return true; +}; + /** * Equality Comparison of two objects: * @param {Object} filters object to be measured for equality * @param {Object} filterReference object by which equality is measured against * @returns {boolean} */ -export const areFiltersEqual = (filters, filterReference = initialState) => { +export const areFiltersEqual = (filters = initialState, filterReference = initialState) => { if (!filterReference && filters) return false; const referenceObject = Object.assign({}, filterReference); const comparisonObject = Object.assign({}, filters); @@ -161,14 +170,24 @@ export const areFiltersEqual = (filters, filterReference = initialState) => { // we need to iterate through each of the filter Redux keys in order to perform equality // comparisons on Immutable children (via the Immutable is() function) - const filterKeys = Object.keys(comparisonObject); + const immutableFilterKeys = Object + .keys(comparisonObject) + .filter((k) => !checkboxTreeFilters.includes(k)); - for (let i = 0; i < filterKeys.length; i++) { - const key = filterKeys[i]; + for (let i = 0; i < immutableFilterKeys.length; i++) { + const key = immutableFilterKeys[i]; const unfilteredValue = comparisonObject[key]; const currentValue = referenceObject[key]; if (!is(unfilteredValue, currentValue)) return false; } + + for (let i = 0; i < checkboxTreeFilters.length; i++) { + const key = checkboxTreeFilters[i]; + const unfilteredValue = comparisonObject[key].toObject(); + const currentValue = referenceObject[key].toObject(); + if (!areCheckboxSelectionsEqual(unfilteredValue, currentValue)) return false; + } + return true; }; diff --git a/tests/containers/search/SearchContainer-test.jsx b/tests/containers/search/SearchContainer-test.jsx index 2e21a295ab..2a8613d24d 100644 --- a/tests/containers/search/SearchContainer-test.jsx +++ b/tests/containers/search/SearchContainer-test.jsx @@ -73,7 +73,17 @@ test('parseRemoteFilters should return an immutable data structure when versions expect(parseRemoteFilters(mock.filter).timePeriodFY).toEqual(expectedFilter); }); -test('a hashed url (as a query param) makes a request to the api & sets loading state', async () => { +test('a non-hashed url does not make a request to the api', async () => { + restoreUrlHash.mockClear(); + generateUrlHash.mockClear(); + render(, {}); + await waitFor(() => { + expect(restoreUrlHash).not.toHaveBeenCalled(); + expect(generateUrlHash).not.toHaveBeenCalled(); + }); +}); + +test('a hashed url makes a request to the api & sets loading state', async () => { restoreUrlHash.mockClear(); useLocation.mockReturnValueOnce({ search: '?hash=abc' }); const setLoadingStateFn = jest.spyOn(appliedFilterActions, 'setAppliedFilterEmptiness'); @@ -85,21 +95,24 @@ test('a hashed url (as a query param) makes a request to the api & sets loading }); }); + test('when filters change (a) hash is generated, (b) loading is set & (c) url is updated', async () => { restoreUrlHash.mockClear(); const setLoading = jest.spyOn(appliedFilterActions, 'setAppliedFilterEmptiness'); const mockPush = jest.fn(); + const { rerender } = render(, {}); + jest.spyOn(redux, 'useSelector').mockReturnValue({ ...mockRedux, appliedFilters: { filters: { - ...mockRedux.appliedFilters, + ...mockRedux.appliedFilters.filters, timePeriodFY: Set(['2020']) } } }); - render(, {}); + rerender(, {}); await waitFor(() => { expect(generateUrlHash).toHaveBeenCalledTimes(1); diff --git a/tests/helpers/searchHelper-test.js b/tests/helpers/searchHelper-test.js index 353643ce0d..d76c2cab65 100644 --- a/tests/helpers/searchHelper-test.js +++ b/tests/helpers/searchHelper-test.js @@ -1,22 +1,63 @@ -import { initialState } from 'redux/reducers/search/searchFiltersReducer'; +import { initialState, CheckboxTreeSelections } from 'redux/reducers/search/searchFiltersReducer'; import { areFiltersEqual, isSearchHashReady } from 'helpers/searchHelper'; -test('areFiltersEqual should return true when selected filters are effectively blank', () => { - expect(areFiltersEqual(initialState, initialState)).toBeTruthy(); -}); - -test('areFiltersEqual should return false when filters are selected', () => { - expect(areFiltersEqual(initialState, { +test.each([ + ['obj1 & obj2 are both initial state', true, initialState, initialState], + ['obj1 is initial state and obj2 has timePeriodFY changed', false, initialState, { ...initialState, timePeriodFY: new Set(['2020']) }], + ['empty vs defined def codes', false, initialState, { ...initialState, - timePeriodFY: new Set(['2020']) - })).toBeFalsy(); -}); - -test('areFiltersEqual should return false when filters are selected', () => { - expect(areFiltersEqual(initialState, { + defCodes: CheckboxTreeSelections({ require: ['12'], counts: [], exclude: [] }) + }], + ['same def codes', true, { + ...initialState, + defCodes: CheckboxTreeSelections({ require: ['21', '12'], counts: [], exclude: [] }) + }, + { + ...initialState, + defCodes: CheckboxTreeSelections({ require: ['12', '21'], counts: [], exclude: [] }) + }], + ['same def codes (w/ 2d array)', true, { + ...initialState, + defCodes: CheckboxTreeSelections({ require: [['21', '2121'], ['64', '6464']], counts: [], exclude: [] }) + }, + { + ...initialState, + defCodes: CheckboxTreeSelections({ require: [['64', '6464'], ['21', '2121']], counts: [], exclude: [] }) + }], + ['different def codes on require', false, { + ...initialState, + defCodes: CheckboxTreeSelections({ require: ['21'], counts: [], exclude: [] }) + }, + { + ...initialState, + defCodes: CheckboxTreeSelections({ require: ['22'], counts: [], exclude: [] }) + }], + ['different def codes on require (w/ 2d array)', false, { + ...initialState, + defCodes: CheckboxTreeSelections({ require: [['21', '2121']], counts: [], exclude: [] }) + }, + { + ...initialState, + defCodes: CheckboxTreeSelections({ require: [['22', '2222']], counts: [], exclude: [] }) + }], + ['different def codes on exclude', false, { + ...initialState, + defCodes: CheckboxTreeSelections({ require: ['21'], counts: [], exclude: ['1'] }) + }, + { + ...initialState, + defCodes: CheckboxTreeSelections({ require: ['21'], counts: [], exclude: ['2'] }) + }], + ['different def codes on exclude (w/ 2d array)', false, { + ...initialState, + defCodes: CheckboxTreeSelections({ require: [['21', '2121']], counts: [], exclude: [['20', '2020']] }) + }, + { ...initialState, - timePeriodFY: new Set(['2020']) - })).toBeFalsy(); + defCodes: CheckboxTreeSelections({ require: [['21', '2121']], counts: [], exclude: [['19', '1919']] }) + }] +])('%s, returns %s', (str, rtrn, obj1, obj2) => { + expect(areFiltersEqual(obj1, obj2)).toEqual(rtrn); }); test.each([ From 74b5b931bad78b70296ff785d516b24aff9149ca Mon Sep 17 00:00:00 2001 From: Maxwell Kendall Date: Tue, 2 Feb 2021 11:24:52 -0500 Subject: [PATCH 69/69] [DEV-6748] keeping history.replace() UX in place. I tried to do history.push() so you could reload previous hashes, but it's not as straight forward as I thought it would be, so I'm removing it from the scope of this PR and into [DEV-6783](https://federal-spending-transparency.atlassian.net/browse/DEV-6783) --- src/js/containers/search/SearchContainer.jsx | 2 +- tests/containers/search/SearchContainer-test.jsx | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/js/containers/search/SearchContainer.jsx b/src/js/containers/search/SearchContainer.jsx index 00f8d58a71..4d616a412c 100644 --- a/src/js/containers/search/SearchContainer.jsx +++ b/src/js/containers/search/SearchContainer.jsx @@ -205,7 +205,7 @@ const SearchContainer = ({ history }) => { request.current.promise .then((res) => { // update the URL with the received hash - history.push({ + history.replace({ pathname: `/search/`, search: `?${new URLSearchParams({ hash: res.data.hash }).toString()}` }); diff --git a/tests/containers/search/SearchContainer-test.jsx b/tests/containers/search/SearchContainer-test.jsx index 2a8613d24d..d9805e0f9e 100644 --- a/tests/containers/search/SearchContainer-test.jsx +++ b/tests/containers/search/SearchContainer-test.jsx @@ -99,8 +99,8 @@ test('a hashed url makes a request to the api & sets loading state', async () => test('when filters change (a) hash is generated, (b) loading is set & (c) url is updated', async () => { restoreUrlHash.mockClear(); const setLoading = jest.spyOn(appliedFilterActions, 'setAppliedFilterEmptiness'); - const mockPush = jest.fn(); - const { rerender } = render(, {}); + const mockReplace = jest.fn(); + const { rerender } = render(, {}); jest.spyOn(redux, 'useSelector').mockReturnValue({ ...mockRedux, @@ -112,12 +112,12 @@ test('when filters change (a) hash is generated, (b) loading is set & (c) url is } }); - rerender(, {}); + rerender(, {}); await waitFor(() => { expect(generateUrlHash).toHaveBeenCalledTimes(1); - expect(mockPush).toHaveBeenCalledTimes(1); - expect(mockPush).toHaveBeenLastCalledWith({ + expect(mockReplace).toHaveBeenCalledTimes(1); + expect(mockReplace).toHaveBeenLastCalledWith({ pathname: '/search/', // not ?hash=str because we aren't mocking out new URLSearchParams search: '?str'