From db5456c0ce5c3c1359cf43e586220ce4312c3bef Mon Sep 17 00:00:00 2001
From: Adam Levin
Date: Thu, 20 Jun 2024 11:28:33 -0400
Subject: [PATCH 01/26] disable scrape
---
src/models/hooks/resource.js | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/models/hooks/resource.js b/src/models/hooks/resource.js
index 12b2cf4d4e..b89bc77528 100644
--- a/src/models/hooks/resource.js
+++ b/src/models/hooks/resource.js
@@ -26,6 +26,8 @@ const afterUpdate = async (sequelize, instance, options) => {
};
const afterCreate = async (sequelize, instance, options) => {
+ // TTAHUB-3102: Temporarily disable the resource scrape job (06/20/2024).
+ /*
if (!instance.title) {
// This is to resolve a recursive reference issue:
// Service: /services/resourceQueue Imports: /lib/resource
@@ -36,6 +38,7 @@ const afterCreate = async (sequelize, instance, options) => {
const { addGetResourceMetadataToQueue } = require('../../services/resourceQueue');
addGetResourceMetadataToQueue(instance.id, instance.url);
}
+ */
};
export {
From 4ab28e3984e72e16a50bc88bf74fd5314185e287 Mon Sep 17 00:00:00 2001
From: Adam Levin
Date: Thu, 20 Jun 2024 11:44:44 -0400
Subject: [PATCH 02/26] comment out test for now
---
src/models/hooks/resource.test.js | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/models/hooks/resource.test.js b/src/models/hooks/resource.test.js
index 6f57981c92..49cd111160 100644
--- a/src/models/hooks/resource.test.js
+++ b/src/models/hooks/resource.test.js
@@ -1,3 +1,5 @@
+/* eslint-disable jest/no-commented-out-tests */
+/*
import {
sequelize,
Resource,
@@ -41,3 +43,4 @@ describe('resource hooks', () => {
});
});
});
+*/
From 419c4c3c1e23d170cc4cc02441a42d383797b449 Mon Sep 17 00:00:00 2001
From: Adam Levin
Date: Thu, 20 Jun 2024 13:54:05 -0400
Subject: [PATCH 03/26] remove test
---
src/models/hooks/resource.test.js | 46 -------------------------------
1 file changed, 46 deletions(-)
delete mode 100644 src/models/hooks/resource.test.js
diff --git a/src/models/hooks/resource.test.js b/src/models/hooks/resource.test.js
deleted file mode 100644
index 49cd111160..0000000000
--- a/src/models/hooks/resource.test.js
+++ /dev/null
@@ -1,46 +0,0 @@
-/* eslint-disable jest/no-commented-out-tests */
-/*
-import {
- sequelize,
- Resource,
-} from '..';
-import { addGetResourceMetadataToQueue } from '../../services/resourceQueue';
-
-jest.mock('bull');
-
-// Mock addGetResourceMetadataToQueue.
-jest.mock('../../services/resourceQueue', () => ({
- addGetResourceMetadataToQueue: jest.fn(),
-}));
-
-describe('resource hooks', () => {
- afterAll(async () => {
- await sequelize.close();
- });
-
- describe('afterCreate', () => {
- let newResource;
-
- afterEach(async () => {
- // reset mocks.
- addGetResourceMetadataToQueue.mockClear();
- });
- afterAll(async () => {
- await Resource.destroy({
- where: { id: [newResource.id] },
- force: true,
- });
- });
-
- it('calls addGetResourceMetadataToQueue when title is missing on create', async () => {
- newResource = await Resource.create({
- url: 'https://www.resource-with-title.com',
- title: null,
- description: 'resource-with-title',
- individualHooks: true,
- });
- expect(addGetResourceMetadataToQueue).toHaveBeenCalledWith(newResource.id, 'https://www.resource-with-title.com');
- });
- });
-});
-*/
From 9bfef849849837aa78289aa25f3591443b4cefc8 Mon Sep 17 00:00:00 2001
From: Adam Levin
Date: Mon, 1 Jul 2024 10:52:53 -0400
Subject: [PATCH 04/26] add something went wrong page WIP
---
frontend/src/App.js | 70 ++++++++++++-------
frontend/src/HideSiteNavContext.js | 6 ++
frontend/src/colors.scss | 3 +-
frontend/src/components/SomethingWentWrong.js | 55 +++++++++++++++
.../src/components/SomethingWentWrong.scss | 22 ++++++
frontend/src/pages/ActivityReport/index.js | 7 ++
6 files changed, 135 insertions(+), 28 deletions(-)
create mode 100644 frontend/src/HideSiteNavContext.js
create mode 100644 frontend/src/components/SomethingWentWrong.js
create mode 100644 frontend/src/components/SomethingWentWrong.scss
diff --git a/frontend/src/App.js b/frontend/src/App.js
index 1c94bedc19..93a6463bb6 100644
--- a/frontend/src/App.js
+++ b/frontend/src/App.js
@@ -10,6 +10,7 @@ import { HTTPError } from './fetchers';
import { getSiteAlerts } from './fetchers/siteAlerts';
import FeatureFlag from './components/FeatureFlag';
import UserContext from './UserContext';
+import HideSiteNavContext from './HideSiteNavContext';
import SiteNav from './components/SiteNav';
import Header from './components/Header';
@@ -58,6 +59,7 @@ import SessionForm from './pages/SessionForm';
import ViewTrainingReport from './pages/ViewTrainingReport';
import useGaUserData from './hooks/useGaUserData';
import QADashboard from './pages/QADashboard';
+import SomethingWentWrong from './components/SomethingWentWrong';
const WHATSNEW_NOTIFICATIONS_KEY = 'whatsnew-read-notifications';
@@ -76,6 +78,7 @@ function App() {
const [notifications, setNotifications] = useState({ whatsNew: '' });
const [areThereUnreadNotifications, setAreThereUnreadNotifications] = useState(false);
+ const [hideSiteNav, setHideSiteNav] = useState(false);
useGaUserData(user);
@@ -438,6 +441,14 @@ function App() {
)}
/>
+ (
+
+
+
+ )}
+ />
(
@@ -456,9 +467,13 @@ function App() {
-
-
- {authenticated && (
+
+
+
+ {authenticated && !hideSiteNav && (
<>
Skip to main content
@@ -475,30 +490,31 @@ function App() {
/>
>
- )}
-
-
-
-
- {!authenticated && (authError === 403
- ?
- : (
-
-
-
- )
- )}
- {authenticated && renderAuthenticatedRoutes()}
-
-
-
-
-
+ )}
+
+
+
+
+ {!authenticated && (authError === 403
+ ?
+ : (
+
+
+
+ )
+ )}
+ {authenticated && renderAuthenticatedRoutes()}
+
+
+
+
+
+
>
);
diff --git a/frontend/src/HideSiteNavContext.js b/frontend/src/HideSiteNavContext.js
new file mode 100644
index 0000000000..23f77b7eb6
--- /dev/null
+++ b/frontend/src/HideSiteNavContext.js
@@ -0,0 +1,6 @@
+import React from 'react';
+
+const HideSiteNavContext = React.createContext({
+});
+
+export default HideSiteNavContext;
diff --git a/frontend/src/colors.scss b/frontend/src/colors.scss
index 80fc0e2643..fac7c72316 100644
--- a/frontend/src/colors.scss
+++ b/frontend/src/colors.scss
@@ -39,4 +39,5 @@ $error-dark: #b50909;
$blue-vivid-focus: #2491FF;
$text-ink: #1b1b1b;
$text-link: #46789B;
-$text-visited: #8C39DB;
\ No newline at end of file
+$text-visited: #8C39DB;
+$response-code: #71767A;
\ No newline at end of file
diff --git a/frontend/src/components/SomethingWentWrong.js b/frontend/src/components/SomethingWentWrong.js
new file mode 100644
index 0000000000..e9706d0a0b
--- /dev/null
+++ b/frontend/src/components/SomethingWentWrong.js
@@ -0,0 +1,55 @@
+/* eslint-disable max-len */
+import React, { useContext } from 'react';
+import ReactRouterPropTypes from 'react-router-prop-types';
+import HideSiteNavContext from '../HideSiteNavContext';
+import './SomethingWentWrong.scss';
+
+function SomethingWentWrong({ match }) {
+ const { setHideSiteNav } = useContext(HideSiteNavContext);
+
+ const { responseCode } = match.params;
+
+ setHideSiteNav(true);
+ return (
+ <>
+ {responseCode && (
+
+
403 error - forbidden
+
Restricted access.
+
+
+ Sorry, but it looks like you're trying to access a restricted area. Here's what you can do:
+
+ If you believe this is an error or need further assistance, get in touch with support.
+
+
+
+ )}
+ >
+ );
+}
+
+SomethingWentWrong.propTypes = {
+ match: ReactRouterPropTypes.match.isRequired,
+};
+
+export default SomethingWentWrong;
diff --git a/frontend/src/components/SomethingWentWrong.scss b/frontend/src/components/SomethingWentWrong.scss
new file mode 100644
index 0000000000..5f0e7691ce
--- /dev/null
+++ b/frontend/src/components/SomethingWentWrong.scss
@@ -0,0 +1,22 @@
+@use '../colors.scss' as *;
+
+.smart-hub--something-went-wrong h3 {
+ color: $response-code;
+ font-size: 1.5rem;
+ font-weight: 700;
+}
+
+.smart-hub--something-went-wrong h1 {
+ font-size: 2.5rem;
+ font-weight: 700;
+}
+
+.smart-hub--something-went-wrong p {
+ color: $base-dark;
+ font-size: 1.25rem;
+ font-weight: 400;
+}
+
+.smart-hub--something-went-wrong li {
+ margin-bottom: .5rem;
+}
\ No newline at end of file
diff --git a/frontend/src/pages/ActivityReport/index.js b/frontend/src/pages/ActivityReport/index.js
index e8902bc549..010e225743 100644
--- a/frontend/src/pages/ActivityReport/index.js
+++ b/frontend/src/pages/ActivityReport/index.js
@@ -45,6 +45,7 @@ import {
import useLocalStorage, { setConnectionActiveWithError } from '../../hooks/useLocalStorage';
import NetworkContext, { isOnlineMode } from '../../NetworkContext';
import UserContext from '../../UserContext';
+import { HTTPError } from '../../fetchers';
const defaultValues = {
ECLKCResourcesUsed: [],
@@ -383,6 +384,12 @@ function ActivityReport({
>
);
const errorMsg = !connection ? networkErrorMessage : <>Unable to load activity report>;
+
+ if (e instanceof HTTPError && [403, 404].includes(e.status)) {
+ // Redirect to the SomethingWentWrong component pass the response code as a param.
+ history.push(`/something-went-wrong/${e.status}`);
+ }
+
updateError(errorMsg);
// If the error was caused by an invalid region, we need a way to communicate that to the
// component so we can redirect the user. We can do this by updating the form data
From 5813197cac67053f68c2ce6b9bb2c1c138068e31 Mon Sep 17 00:00:00 2001
From: Adam Levin
Date: Mon, 1 Jul 2024 16:23:26 -0400
Subject: [PATCH 05/26] updates and test
---
frontend/src/App.js | 4 +-
frontend/src/components/SomethingWentWrong.js | 99 +++++++++++++++++--
.../__tests__/SomethingWentWrong.js | 59 +++++++++++
3 files changed, 152 insertions(+), 10 deletions(-)
create mode 100644 frontend/src/components/__tests__/SomethingWentWrong.js
diff --git a/frontend/src/App.js b/frontend/src/App.js
index 93a6463bb6..756fb6d319 100644
--- a/frontend/src/App.js
+++ b/frontend/src/App.js
@@ -2,7 +2,9 @@ import React, { useState, useEffect, useMemo } from 'react';
import '@trussworks/react-uswds/lib/uswds.css';
import '@trussworks/react-uswds/lib/index.css';
-import { BrowserRouter, Route, Switch } from 'react-router-dom';
+import {
+ BrowserRouter, Route, Switch,
+} from 'react-router-dom';
import { Helmet } from 'react-helmet';
import { fetchUser, fetchLogout } from './fetchers/Auth';
diff --git a/frontend/src/components/SomethingWentWrong.js b/frontend/src/components/SomethingWentWrong.js
index e9706d0a0b..9f8450e094 100644
--- a/frontend/src/components/SomethingWentWrong.js
+++ b/frontend/src/components/SomethingWentWrong.js
@@ -1,18 +1,24 @@
/* eslint-disable max-len */
-import React, { useContext } from 'react';
+import React, { useContext, useEffect } from 'react';
+import { Link } from '@trussworks/react-uswds';
+import { Link as ReactLink } from 'react-router-dom';
import ReactRouterPropTypes from 'react-router-prop-types';
import HideSiteNavContext from '../HideSiteNavContext';
import './SomethingWentWrong.scss';
function SomethingWentWrong({ match }) {
+ const { responseCode } = match.params;
const { setHideSiteNav } = useContext(HideSiteNavContext);
- const { responseCode } = match.params;
+ const supportLink = 'https://app.smartsheetgov.com/b/form/f0b4725683f04f349a939bd2e3f5425a';
+ const getSupportLink = () => (
+ support
+ );
- setHideSiteNav(true);
- return (
- <>
- {responseCode && (
+ const determineMessage = () => {
+ // 403 Forbidden.
+ if (responseCode === '403') {
+ return (
403 error - forbidden
Restricted access.
@@ -25,7 +31,11 @@ function SomethingWentWrong({ match }) {
{' '}
Ensure you have the proper clearance to access this page
- Contact support and ask them to check your permissions.
+ Contact
+ {' '}
+ {getSupportLink()}
+ {' '}
+ and ask them to check your permissions.
@@ -39,11 +49,82 @@ function SomethingWentWrong({ match }) {
Return to the main area and explore other permitted sections.
- If you believe this is an error or need further assistance, get in touch with support.
+ If you believe this is an error or need further assistance, get in touch with
+ {' '}
+ {getSupportLink()}
+ .
- )}
+ );
+ }
+
+ // 404 Not found.
+ if (responseCode === '404') {
+ return (
+
+
404 error
+
Page not found
+
+
+ Well, this is awkward. It seems like the page you're looking for has taken a detour into the unknown. Here's what you can do:
+
+
+ Go back to
+ {' '}
+ home
+
+
+ Contact
+ {' '}
+ {getSupportLink()}
+ {' '}
+ for help
+
+
+ Thanks for your understanding and patience!
+
+
+
+ );
+ }
+
+ // 500 Internal server error (display for everything else).
+ return (
+
+
Something went wrong.
+
+
+ Well, this is awkward. It seems like the page you're looking for has taken a detour into the unknown. Here's what you can do:
+
+
+ Go back to
+ {' '}
+ home
+
+
+ Contact
+ {' '}
+ {getSupportLink()}
+ {' '}
+ for help
+
+
+ Thanks for your understanding and patience!
+
+
+
+ );
+ };
+
+ useEffect(() => {
+ setHideSiteNav(true);
+ return () => setHideSiteNav(false);
+ }, [setHideSiteNav]);
+
+ return (
+ <>
+ {determineMessage(responseCode)}
>
);
}
diff --git a/frontend/src/components/__tests__/SomethingWentWrong.js b/frontend/src/components/__tests__/SomethingWentWrong.js
new file mode 100644
index 0000000000..57ed30345c
--- /dev/null
+++ b/frontend/src/components/__tests__/SomethingWentWrong.js
@@ -0,0 +1,59 @@
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import { createMemoryHistory } from 'history';
+import { Router } from 'react-router';
+import SomethingWentWrong from '../SomethingWentWrong';
+import HideSiteNavContext from '../../HideSiteNavContext';
+
+const history = createMemoryHistory();
+
+const renderSomethingWentWrong = (
+ responseCode,
+ hideSiteNav = false,
+ setHideSiteNav = jest.fn,
+) => render(
+
+
+
+
+ ,
+ ,
+);
+
+describe('SomethingWentWrong component', () => {
+ // Write a test to pass the response code 403 to the component.
+ it('renders a 403 error message', async () => {
+ renderSomethingWentWrong('403');
+
+ expect(screen.getByText('403 error - forbidden')).toBeInTheDocument();
+ expect(screen.getByText('Restricted access.')).toBeInTheDocument();
+ expect(screen.getByText(/Sorry, but it looks like you're trying to access a restricted area./i)).toBeInTheDocument();
+ expect(screen.getByText(/Double-check permissions:/i)).toBeInTheDocument();
+ expect(screen.getByText(/Ensure you have the proper clearance to access this page/i)).toBeInTheDocument();
+ expect(screen.getByText(/Login again:/i)).toBeInTheDocument();
+ expect(screen.getByText(/Try logging in again. Maybe that's the missing key./i)).toBeInTheDocument();
+ expect(screen.getByText(/Explore elsewhere:/i)).toBeInTheDocument();
+ expect(screen.getByText(/Return to the main area and explore other permitted sections./i)).toBeInTheDocument();
+ expect(screen.getByText(/If you believe this is an error or need further/i)).toBeInTheDocument();
+ });
+
+ // Write a test to pass the response code 404 to the component.
+ it('renders a 404 error message', async () => {
+ renderSomethingWentWrong('404');
+
+ expect(screen.getByText('404 error')).toBeInTheDocument();
+ expect(screen.getByText('Page not found')).toBeInTheDocument();
+ expect(screen.getByText(/Well, this is awkward. It seems like the page/i)).toBeInTheDocument();
+ expect(screen.getByText(/home/i)).toBeInTheDocument();
+ expect(screen.getByText(/support/i)).toBeInTheDocument();
+ expect(screen.getByText(/thanks for your understanding and patience/i)).toBeInTheDocument();
+ });
+
+ // Write a test to pass an unknown response code to the component.
+ it('renders a generic error message', async () => {
+ renderSomethingWentWrong('500');
+ expect(screen.getByText('Something went wrong.')).toBeInTheDocument();
+ expect(screen.getByText(/Well, this is awkward. It seems like the page you're looking for has taken a detour into the unknown. Here's what you can do:/i)).toBeInTheDocument();
+ expect(screen.getByText(/Thanks for your understanding and patience!/i)).toBeInTheDocument();
+ });
+});
From c0f85699f9578920ec7bf9c54d01e02dfc1a0bd2 Mon Sep 17 00:00:00 2001
From: Nathan Powell
Date: Tue, 2 Jul 2024 07:38:49 -0700
Subject: [PATCH 06/26] Remove r10 NC ARs plus associated goals, objs not used
elsewhere
---
...240702000000-remove_national_center_ars.js | 526 ++++++++++++++++++
1 file changed, 526 insertions(+)
create mode 100644 src/migrations/20240702000000-remove_national_center_ars.js
diff --git a/src/migrations/20240702000000-remove_national_center_ars.js b/src/migrations/20240702000000-remove_national_center_ars.js
new file mode 100644
index 0000000000..caea78ba64
--- /dev/null
+++ b/src/migrations/20240702000000-remove_national_center_ars.js
@@ -0,0 +1,526 @@
+const {
+ prepMigration,
+} = require('../lib/migration');
+
+/** @type {import('sequelize-cli').Migration} */
+module.exports = {
+ async up(queryInterface) {
+ await queryInterface.sequelize.transaction(async (transaction) => {
+ const sessionSig = __filename;
+ await prepMigration(queryInterface, transaction, sessionSig);
+
+ await queryInterface.sequelize.query(`
+ ---------------------------------------------------
+ -- NOTE:
+ -- Files and Resources are most properly managed by
+ -- maintenance jobs, so this and similar migrations
+ -- won't delete them directly. Deleting the link
+ -- records will give the maintenance job the info
+ -- it needs to perform its housekeeping.
+ ---------------------------------------------------
+ -------- Deleting unwanted ARs --------
+ -- Create the AR deletion list
+ -- Remove AR link records: -------------
+ -- ActivityRecipients
+ -- ActivityReportApprovers
+ -- ActivityReportCollaborators
+ -- ActivityReportFiles (no need to remove Files)
+ -- ActivityReportResources (no need to remove Resources)
+
+ -- Create the NextSteps deletion list
+ -- Remove NextSteps link records: -------------
+ -- NextStepResources
+ -- remove NextSteps -------------
+
+ -- Create the ARO deletion list
+ -- Remove ARO link records: -------------
+ -- ActivityReportObjectiveFiles
+ -- ActivityReportObjectiveResources
+ -- ActivityReportObjectiveTopics
+ -- remove AROs -------------------
+
+ -- Create the orphaned Objective deletion list
+ -- remove Objectives -------------
+
+ -- Create the ARG deletion list
+ -- Remove ARG link records: -------------
+ -- ActivityReportGoalFieldResponses
+ -- ActivityReportGoalResources
+ -- remove ARGs -------------------
+
+ -- Create the orphaned Goal deletions list
+ -- ( check if isFromSmartsheetTtaPlan, isRttapa)
+ -- Remove Goal link records: -------------
+ -- EventReportPilotGoals
+ -- GoalFieldResponses
+ -- GoalResources
+ -- remove Goals ------------------
+
+ -- Create the orphaned ObjectiveTemplate deletion list
+ -- Create the orphaned GoalTemplate deletion list
+ -- Remove GoalTemplate link records: -------------
+ -- GoalTemplateObjectiveTemplates
+ -- Remove ObjectiveTemplates --------
+ -- Remove GoalTemplates -------------
+
+ -- Remove ARs -----------------------
+
+ -------------------------------------------------------------------------------------------------------------------
+ -------- Deleting unwanted ARs --------
+ -- Create the AR deletion list
+ DROP TABLE IF EXISTS ars_to_delete;
+ CREATE TEMP TABLE ars_to_delete
+ AS
+ SELECT id arid
+ FROM "ActivityReports"
+ WHERE id IN (24998, 24645, 24297, 24122, 27517, 30829, 29864, 6442, 23057, 23718, 25205, 25792, 25577, 25573, 26478, 26210, 27117, 26918, 28451, 28117, 27669, 29542, 29101, 29024, 30137, 29762, 31201)
+ AND "regionId" = 10
+ ;
+
+ -- Remove AR link records: -------------
+ DROP TABLE IF EXISTS deleted_activityrecipients;
+ CREATE TEMP TABLE deleted_activityrecipients AS
+ WITH deletes AS (
+ DELETE FROM "ActivityRecipients"
+ USING ars_to_delete
+ WHERE "activityReportId" = arid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+ CREATE TEMP TABLE deleted_activityreportapprovers AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReportApprovers"
+ USING ars_to_delete
+ WHERE "activityReportId" = arid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+ CREATE TEMP TABLE deleted_activityreportcollaborators AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReportCollaborators"
+ USING ars_to_delete
+ WHERE "activityReportId" = arid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+ CREATE TEMP TABLE deleted_activityreportfiles AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReportFiles"
+ USING ars_to_delete
+ WHERE "activityReportId" = arid
+ RETURNING
+ id,
+ "fileId" fid
+ )
+ SELECT id, fid FROM deletes
+ ;
+ CREATE TEMP TABLE deleted_activityreportresources AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReportResources"
+ USING ars_to_delete
+ WHERE "activityReportId" = arid
+ RETURNING
+ id,
+ "resourceId" resourceid
+ )
+ SELECT id, resourceid FROM deletes
+ ;
+
+
+
+ -- Create the NextSteps deletion list
+ DROP TABLE IF EXISTS nextsteps_to_delete;
+ CREATE TEMP TABLE nextsteps_to_delete
+ AS
+ SELECT
+ id nsid
+ FROM "NextSteps"
+ JOIN ars_to_delete
+ ON "activityReportId" = arid
+ ;
+ -- Remove NextSteps link records: -------------
+ CREATE TEMP TABLE deleted_nextstepresources AS
+ WITH deletes AS (
+ DELETE FROM "NextStepResources"
+ USING nextsteps_to_delete
+ WHERE "nextStepId" = nsid
+ RETURNING
+ id,
+ "resourceId" resourceid
+ )
+ SELECT id, resourceid FROM deletes
+ ;
+ -- remove NextSteps -------------
+ CREATE TEMP TABLE deleted_nextsteps AS
+ WITH deletes AS (
+ DELETE FROM "NextSteps"
+ USING nextsteps_to_delete
+ WHERE id = nsid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+
+
+ -- Create the ARO deletion list
+ DROP TABLE IF EXISTS aros_to_delete;
+ CREATE TEMP TABLE aros_to_delete
+ AS
+ SELECT
+ id aroid,
+ "objectiveId" oid
+ FROM "ActivityReportObjectives"
+ JOIN ars_to_delete
+ ON "activityReportId" = arid
+ ;
+ -- Remove ARO link records: -------------
+ CREATE TEMP TABLE deleted_activityreportobjectivefiles AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReportObjectiveFiles"
+ USING aros_to_delete
+ WHERE "activityReportObjectiveId" = aroid
+ RETURNING
+ id,
+ "fileId" fid
+ )
+ SELECT id, fid FROM deletes
+ ;
+ CREATE TEMP TABLE deleted_activityreportobjectiveresources AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReportObjectiveResources"
+ USING aros_to_delete
+ WHERE "activityReportObjectiveId" = aroid
+ RETURNING
+ id,
+ "resourceId" resourceid
+ )
+ SELECT id, resourceid FROM deletes
+ ;
+ CREATE TEMP TABLE deleted_activityreportobjectivetopics AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReportObjectiveTopics"
+ USING aros_to_delete
+ WHERE "activityReportObjectiveId" = aroid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+ -- remove AROs -------------------
+ CREATE TEMP TABLE deleted_aros AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReportObjectives"
+ USING aros_to_delete
+ WHERE id = aroid
+ RETURNING
+ id,
+ "objectiveId" oid
+ )
+ SELECT id, oid FROM deletes
+ ;
+
+ -- Create the orphaned Objective deletion list
+ CREATE TEMP TABLE objectives_to_delete
+ AS
+ SELECT DISTINCT oid
+ FROM deleted_aros
+ EXCEPT
+ SELECT DISTINCT "objectiveId"
+ FROM "ActivityReportObjectives"
+ ;
+
+ -- remove Objectives -------------------
+ CREATE TEMP TABLE deleted_objectives AS
+ WITH deletes AS (
+ DELETE FROM "Objectives"
+ USING objectives_to_delete
+ WHERE id = oid
+ RETURNING
+ id,
+ "goalId" gid,
+ "objectiveTemplateId" otid
+ )
+ SELECT id, gid, otid FROM deletes
+ ;
+
+ -- Create the ARG deletion list
+ DROP TABLE IF EXISTS args_to_delete;
+ CREATE TEMP TABLE args_to_delete
+ AS
+ SELECT DISTINCT
+ id argid,
+ "goalId" gid
+ FROM "ActivityReportGoals"
+ JOIN ars_to_delete
+ ON "activityReportId" = arid
+ ;
+ -- Remove ARG link records: -------------
+ CREATE TEMP TABLE deleted_activityreportgoalfieldresponses AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReportGoalFieldResponses"
+ USING args_to_delete
+ WHERE "activityReportGoalId" = argid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+ CREATE TEMP TABLE deleted_activityreportgoalresources AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReportGoalResources"
+ USING args_to_delete
+ WHERE "activityReportGoalId" = argid
+ RETURNING
+ id,
+ "resourceId" resourceid
+ )
+ SELECT id, resourceid FROM deletes
+ ;
+ -- remove ARGs -------------------
+ CREATE TEMP TABLE deleted_args AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReportGoals"
+ USING args_to_delete
+ WHERE id = argid
+ RETURNING
+ id,
+ "goalId" gid
+ )
+ SELECT id, gid FROM deletes
+ ;
+
+ -- Create the orphaned Goal deletions list
+ CREATE TEMP TABLE goals_to_delete
+ AS
+ SELECT DISTINCT gid
+ FROM deleted_args dargs
+ JOIN "Goals" g
+ ON gid = g.id
+ WHERE (g."isRttapa" IS NULL OR g."isRttapa" != 'Yes')
+ AND g."isFromSmartsheetTtaPlan" != TRUE
+ AND g."createdVia" != 'merge'
+ EXCEPT
+ SELECT gid
+ FROM (
+ SELECT DISTINCT "goalId" gid
+ FROM "ActivityReportGoals"
+ UNION
+ SELECT DISTINCT "goalId"
+ FROM "Objectives"
+ UNION
+ SELECT DISTINCT "goalId"
+ FROM "EventReportPilotGoals"
+ ) keepers
+ ;
+ -- Remove Goal link records: -------------
+ CREATE TEMP TABLE deleted_goalcollaborators AS
+ WITH deletes AS (
+ DELETE FROM "GoalCollaborators"
+ USING goals_to_delete
+ WHERE "goalId" = gid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+ CREATE TEMP TABLE deleted_goalfieldresponses AS
+ WITH deletes AS (
+ DELETE FROM "GoalFieldResponses"
+ USING goals_to_delete
+ WHERE "goalId" = gid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+ CREATE TEMP TABLE deleted_goalresources AS
+ WITH deletes AS (
+ DELETE FROM "GoalResources"
+ USING goals_to_delete
+ WHERE "goalId" = gid
+ RETURNING
+ id,
+ "resourceId" resourceid
+ )
+ SELECT id, resourceid FROM deletes
+ ;
+ CREATE TEMP TABLE deleted_goalstatuschanges AS
+ WITH deletes AS (
+ DELETE FROM "GoalStatusChanges"
+ USING goals_to_delete
+ WHERE "goalId" = gid
+ RETURNING
+ id,
+ "goalId" gid
+ )
+ SELECT id, gid FROM deletes
+ ;
+ -- remove Goals -------------------
+ CREATE TEMP TABLE deleted_goals AS
+ WITH deletes AS (
+ DELETE FROM "Goals"
+ USING goals_to_delete
+ WHERE id = gid
+ RETURNING
+ id,
+ "goalTemplateId" gtid
+ )
+ SELECT id, gtid FROM deletes
+ ;
+
+ -- Create the orphaned ObjectiveTemplate deletion list
+ CREATE TEMP TABLE ots_to_delete
+ AS
+ SELECT DISTINCT otid
+ FROM deleted_objectives
+ EXCEPT
+ SELECT DISTINCT "objectiveTemplateId"
+ FROM "Objectives"
+ ;
+
+ -- Create the orphaned GoalTemplate deletion list
+ CREATE TEMP TABLE gts_to_delete
+ AS
+ SELECT DISTINCT gtid
+ FROM deleted_goals
+ EXCEPT
+ SELECT DISTINCT "goalTemplateId"
+ FROM "Goals"
+ ;
+ -- Remove GoalTemplate link records: -------------
+ CREATE TEMP TABLE deleted_goaltemplateobjectivetemplates AS
+ WITH unified_deletes AS (
+ SELECT DISTINCT id gtotid
+ FROM "GoalTemplateObjectiveTemplates"
+ JOIN ots_to_delete
+ ON otid = "objectiveTemplateId"
+ UNION
+ SELECT DISTINCT id gtotid
+ FROM "GoalTemplateObjectiveTemplates"
+ JOIN gts_to_delete
+ ON gtid = "goalTemplateId"
+ ),
+ deletes AS (
+ DELETE FROM "GoalTemplateObjectiveTemplates"
+ USING unified_deletes
+ WHERE id = gtotid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+ -- Remove ObjectiveTemplates --------
+ CREATE TEMP TABLE deleted_objectivetemplates AS
+ WITH deletes AS (
+ DELETE FROM "ObjectiveTemplates"
+ USING ots_to_delete
+ WHERE id = otid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+ -- Remove GoalTemplates -------------
+ CREATE TEMP TABLE deleted_goaltemplates AS
+ WITH deletes AS (
+ DELETE FROM "GoalTemplates"
+ USING gts_to_delete
+ WHERE id = gtid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+
+ -- Remove ARs -------------
+ CREATE TEMP TABLE deleted_ars AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReports"
+ USING ars_to_delete
+ WHERE id = arid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+
+
+ -- Stats ----------------------------
+ SELECT 1,'ars_to_delete', count(*) FROM ars_to_delete
+ UNION
+ SELECT 2,'deleted_activityreportapprovers', count(*) FROM deleted_activityreportapprovers
+ UNION
+ SELECT 3,'deleted_activityreportcollaborators', count(*) FROM deleted_activityreportcollaborators
+ UNION
+ SELECT 4,'deleted_activityreportfiles', count(*) FROM deleted_activityreportfiles
+ UNION
+ SELECT 5,'deleted_activityreportresources', count(*) FROM deleted_activityreportresources
+ UNION
+ SELECT 6,'nextsteps_to_delete', count(*) FROM nextsteps_to_delete
+ UNION
+ SELECT 7,'deleted_nextstepresources', count(*) FROM deleted_nextstepresources
+ UNION
+ SELECT 8,'deleted_nextsteps', count(*) FROM deleted_nextsteps
+ UNION
+ SELECT 9,'aros_to_delete', count(*) FROM aros_to_delete
+ UNION
+ SELECT 10,'deleted_activityreportobjectivefiles', count(*) FROM deleted_activityreportobjectivefiles
+ UNION
+ SELECT 11,'deleted_activityreportobjectiveresources', count(*) FROM deleted_activityreportobjectiveresources
+ UNION
+ SELECT 12,'deleted_activityreportobjectivetopics', count(*) FROM deleted_activityreportobjectivetopics
+ UNION
+ SELECT 13,'deleted_aros', count(*) FROM deleted_aros
+ UNION
+ SELECT 14,'objectives_to_delete', count(*) FROM objectives_to_delete
+ UNION
+ SELECT 15,'deleted_objectives', count(*) FROM deleted_objectives
+ UNION
+ SELECT 16,'args_to_delete', count(*) FROM args_to_delete
+ UNION
+ SELECT 17,'deleted_activityreportgoalfieldresponses', count(*) FROM deleted_activityreportgoalfieldresponses
+ UNION
+ SELECT 18,'deleted_activityreportgoalresources', count(*) FROM deleted_activityreportgoalresources
+ UNION
+ SELECT 19,'deleted_args', count(*) FROM deleted_args
+ UNION
+ SELECT 20,'goals_to_delete', count(*) FROM goals_to_delete
+ UNION
+ SELECT 21,'deleted_goalcollaborators', count(*) FROM deleted_goalcollaborators
+ UNION
+ SELECT 22,'deleted_goalfieldresponses', count(*) FROM deleted_goalfieldresponses
+ UNION
+ SELECT 23,'deleted_goalresources', count(*) FROM deleted_goalresources
+ UNION
+ SELECT 24,'deleted_goalstatuschanges', count(*) FROM deleted_goalstatuschanges
+ UNION
+ SELECT 25,'deleted_goals', count(*) FROM deleted_goals
+ UNION
+ SELECT 26,'ots_to_delete', count(*) FROM ots_to_delete
+ UNION
+ SELECT 27,'gts_to_delete', count(*) FROM gts_to_delete
+ UNION
+ SELECT 28,'deleted_goaltemplateobjectivetemplates', count(*) FROM deleted_goaltemplateobjectivetemplates
+ UNION
+ SELECT 29,'deleted_objectivetemplates', count(*) FROM deleted_objectivetemplates
+ UNION
+ SELECT 30,'deleted_goaltemplates', count(*) FROM deleted_goaltemplates
+ UNION
+ SELECT 31,'deleted_ars', count(*) FROM deleted_ars
+ ORDER BY 1
+ ;
+
+ `, { transaction });
+ });
+ },
+
+ down: async () => {
+ },
+};
From 38c79e34637f46549a3d655004eefdcb11afa454 Mon Sep 17 00:00:00 2001
From: Nathan Powell
Date: Tue, 2 Jul 2024 07:53:24 -0700
Subject: [PATCH 07/26] add drop table if exists for ci
---
...240702000000-remove_national_center_ars.js | 27 +++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/src/migrations/20240702000000-remove_national_center_ars.js b/src/migrations/20240702000000-remove_national_center_ars.js
index caea78ba64..dae0f8f6e2 100644
--- a/src/migrations/20240702000000-remove_national_center_ars.js
+++ b/src/migrations/20240702000000-remove_national_center_ars.js
@@ -89,6 +89,7 @@ module.exports = {
)
SELECT id FROM deletes
;
+ DROP TABLE IF EXISTS deleted_activityreportapprovers;
CREATE TEMP TABLE deleted_activityreportapprovers AS
WITH deletes AS (
DELETE FROM "ActivityReportApprovers"
@@ -99,6 +100,7 @@ module.exports = {
)
SELECT id FROM deletes
;
+ DROP TABLE IF EXISTS deleted_activityreportcollaborators;
CREATE TEMP TABLE deleted_activityreportcollaborators AS
WITH deletes AS (
DELETE FROM "ActivityReportCollaborators"
@@ -109,6 +111,7 @@ module.exports = {
)
SELECT id FROM deletes
;
+ DROP TABLE IF EXISTS deleted_activityreportfiles;
CREATE TEMP TABLE deleted_activityreportfiles AS
WITH deletes AS (
DELETE FROM "ActivityReportFiles"
@@ -120,6 +123,7 @@ module.exports = {
)
SELECT id, fid FROM deletes
;
+ DROP TABLE IF EXISTS deleted_activityreportresources;
CREATE TEMP TABLE deleted_activityreportresources AS
WITH deletes AS (
DELETE FROM "ActivityReportResources"
@@ -145,6 +149,7 @@ module.exports = {
ON "activityReportId" = arid
;
-- Remove NextSteps link records: -------------
+ DROP TABLE IF EXISTS deleted_nextstepresources;
CREATE TEMP TABLE deleted_nextstepresources AS
WITH deletes AS (
DELETE FROM "NextStepResources"
@@ -157,6 +162,7 @@ module.exports = {
SELECT id, resourceid FROM deletes
;
-- remove NextSteps -------------
+ DROP TABLE IF EXISTS deleted_nextsteps;
CREATE TEMP TABLE deleted_nextsteps AS
WITH deletes AS (
DELETE FROM "NextSteps"
@@ -181,6 +187,7 @@ module.exports = {
ON "activityReportId" = arid
;
-- Remove ARO link records: -------------
+ DROP TABLE IF EXISTS deleted_activityreportobjectivefiles;
CREATE TEMP TABLE deleted_activityreportobjectivefiles AS
WITH deletes AS (
DELETE FROM "ActivityReportObjectiveFiles"
@@ -192,6 +199,7 @@ module.exports = {
)
SELECT id, fid FROM deletes
;
+ DROP TABLE IF EXISTS deleted_activityreportobjectiveresources;
CREATE TEMP TABLE deleted_activityreportobjectiveresources AS
WITH deletes AS (
DELETE FROM "ActivityReportObjectiveResources"
@@ -203,6 +211,7 @@ module.exports = {
)
SELECT id, resourceid FROM deletes
;
+ DROP TABLE IF EXISTS deleted_activityreportobjectivetopics;
CREATE TEMP TABLE deleted_activityreportobjectivetopics AS
WITH deletes AS (
DELETE FROM "ActivityReportObjectiveTopics"
@@ -214,6 +223,7 @@ module.exports = {
SELECT id FROM deletes
;
-- remove AROs -------------------
+ DROP TABLE IF EXISTS deleted_aros;
CREATE TEMP TABLE deleted_aros AS
WITH deletes AS (
DELETE FROM "ActivityReportObjectives"
@@ -227,6 +237,7 @@ module.exports = {
;
-- Create the orphaned Objective deletion list
+ DROP TABLE IF EXISTS objectives_to_delete;
CREATE TEMP TABLE objectives_to_delete
AS
SELECT DISTINCT oid
@@ -237,6 +248,7 @@ module.exports = {
;
-- remove Objectives -------------------
+ DROP TABLE IF EXISTS deleted_objectives;
CREATE TEMP TABLE deleted_objectives AS
WITH deletes AS (
DELETE FROM "Objectives"
@@ -262,6 +274,7 @@ module.exports = {
ON "activityReportId" = arid
;
-- Remove ARG link records: -------------
+ DROP TABLE IF EXISTS deleted_activityreportgoalfieldresponses;
CREATE TEMP TABLE deleted_activityreportgoalfieldresponses AS
WITH deletes AS (
DELETE FROM "ActivityReportGoalFieldResponses"
@@ -272,6 +285,7 @@ module.exports = {
)
SELECT id FROM deletes
;
+ DROP TABLE IF EXISTS deleted_activityreportgoalresources;
CREATE TEMP TABLE deleted_activityreportgoalresources AS
WITH deletes AS (
DELETE FROM "ActivityReportGoalResources"
@@ -284,6 +298,7 @@ module.exports = {
SELECT id, resourceid FROM deletes
;
-- remove ARGs -------------------
+ DROP TABLE IF EXISTS deleted_args;
CREATE TEMP TABLE deleted_args AS
WITH deletes AS (
DELETE FROM "ActivityReportGoals"
@@ -297,6 +312,7 @@ module.exports = {
;
-- Create the orphaned Goal deletions list
+ DROP TABLE IF EXISTS goals_to_delete;
CREATE TEMP TABLE goals_to_delete
AS
SELECT DISTINCT gid
@@ -320,6 +336,7 @@ module.exports = {
) keepers
;
-- Remove Goal link records: -------------
+ DROP TABLE IF EXISTS deleted_goalcollaborators;
CREATE TEMP TABLE deleted_goalcollaborators AS
WITH deletes AS (
DELETE FROM "GoalCollaborators"
@@ -330,6 +347,7 @@ module.exports = {
)
SELECT id FROM deletes
;
+ DROP TABLE IF EXISTS deleted_goalfieldresponses;
CREATE TEMP TABLE deleted_goalfieldresponses AS
WITH deletes AS (
DELETE FROM "GoalFieldResponses"
@@ -340,6 +358,7 @@ module.exports = {
)
SELECT id FROM deletes
;
+ DROP TABLE IF EXISTS deleted_goalresources;
CREATE TEMP TABLE deleted_goalresources AS
WITH deletes AS (
DELETE FROM "GoalResources"
@@ -351,6 +370,7 @@ module.exports = {
)
SELECT id, resourceid FROM deletes
;
+ DROP TABLE IF EXISTS deleted_goalstatuschanges;
CREATE TEMP TABLE deleted_goalstatuschanges AS
WITH deletes AS (
DELETE FROM "GoalStatusChanges"
@@ -363,6 +383,7 @@ module.exports = {
SELECT id, gid FROM deletes
;
-- remove Goals -------------------
+ DROP TABLE IF EXISTS deleted_goals;
CREATE TEMP TABLE deleted_goals AS
WITH deletes AS (
DELETE FROM "Goals"
@@ -376,6 +397,7 @@ module.exports = {
;
-- Create the orphaned ObjectiveTemplate deletion list
+ DROP TABLE IF EXISTS ots_to_delete;
CREATE TEMP TABLE ots_to_delete
AS
SELECT DISTINCT otid
@@ -386,6 +408,7 @@ module.exports = {
;
-- Create the orphaned GoalTemplate deletion list
+ DROP TABLE IF EXISTS gts_to_delete;
CREATE TEMP TABLE gts_to_delete
AS
SELECT DISTINCT gtid
@@ -395,6 +418,7 @@ module.exports = {
FROM "Goals"
;
-- Remove GoalTemplate link records: -------------
+ DROP TABLE IF EXISTS deleted_goaltemplateobjectivetemplates;
CREATE TEMP TABLE deleted_goaltemplateobjectivetemplates AS
WITH unified_deletes AS (
SELECT DISTINCT id gtotid
@@ -417,6 +441,7 @@ module.exports = {
SELECT id FROM deletes
;
-- Remove ObjectiveTemplates --------
+ DROP TABLE IF EXISTS deleted_objectivetemplates;
CREATE TEMP TABLE deleted_objectivetemplates AS
WITH deletes AS (
DELETE FROM "ObjectiveTemplates"
@@ -428,6 +453,7 @@ module.exports = {
SELECT id FROM deletes
;
-- Remove GoalTemplates -------------
+ DROP TABLE IF EXISTS deleted_goaltemplates;
CREATE TEMP TABLE deleted_goaltemplates AS
WITH deletes AS (
DELETE FROM "GoalTemplates"
@@ -440,6 +466,7 @@ module.exports = {
;
-- Remove ARs -------------
+ DROP TABLE IF EXISTS deleted_ars;
CREATE TEMP TABLE deleted_ars AS
WITH deletes AS (
DELETE FROM "ActivityReports"
From f136d48f5adf9981ee9fdb37d13ed7190a029be5 Mon Sep 17 00:00:00 2001
From: Adam Levin
Date: Tue, 2 Jul 2024 11:54:11 -0400
Subject: [PATCH 08/26] changes per Jon and Matt
---
frontend/src/App.js | 26 +-
frontend/src/HideSiteNavContext.js | 6 -
frontend/src/SomethingWentWrongContext.js | 6 +
frontend/src/components/SomethingWentWrong.js | 264 ++++++++++--------
.../__tests__/SomethingWentWrong.js | 36 ++-
frontend/src/pages/ActivityReport/index.js | 2 +
6 files changed, 195 insertions(+), 145 deletions(-)
delete mode 100644 frontend/src/HideSiteNavContext.js
create mode 100644 frontend/src/SomethingWentWrongContext.js
diff --git a/frontend/src/App.js b/frontend/src/App.js
index 756fb6d319..adc57c50c0 100644
--- a/frontend/src/App.js
+++ b/frontend/src/App.js
@@ -12,7 +12,7 @@ import { HTTPError } from './fetchers';
import { getSiteAlerts } from './fetchers/siteAlerts';
import FeatureFlag from './components/FeatureFlag';
import UserContext from './UserContext';
-import HideSiteNavContext from './HideSiteNavContext';
+import SomethingWentWrongContext from './SomethingWentWrongContext';
import SiteNav from './components/SiteNav';
import Header from './components/Header';
@@ -80,7 +80,7 @@ function App() {
const [notifications, setNotifications] = useState({ whatsNew: '' });
const [areThereUnreadNotifications, setAreThereUnreadNotifications] = useState(false);
- const [hideSiteNav, setHideSiteNav] = useState(false);
+ const [errorResponseCode, setErrorResponseCode] = useState(null);
useGaUserData(user);
@@ -443,14 +443,6 @@ function App() {
)}
/>
- (
-
-
-
- )}
- />
(
@@ -469,13 +461,13 @@ function App() {
-
- {authenticated && !hideSiteNav && (
+ {authenticated && !errorResponseCode && (
<>
Skip to main content
@@ -510,13 +502,19 @@ function App() {
)
)}
+ {authenticated && errorResponseCode
+ && (
+
+
+
+ )}
{authenticated && renderAuthenticatedRoutes()}
-
+
>
);
diff --git a/frontend/src/HideSiteNavContext.js b/frontend/src/HideSiteNavContext.js
deleted file mode 100644
index 23f77b7eb6..0000000000
--- a/frontend/src/HideSiteNavContext.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import React from 'react';
-
-const HideSiteNavContext = React.createContext({
-});
-
-export default HideSiteNavContext;
diff --git a/frontend/src/SomethingWentWrongContext.js b/frontend/src/SomethingWentWrongContext.js
new file mode 100644
index 0000000000..f00723564f
--- /dev/null
+++ b/frontend/src/SomethingWentWrongContext.js
@@ -0,0 +1,6 @@
+import React from 'react';
+
+const SomethingWentWrong = React.createContext({
+});
+
+export default SomethingWentWrong;
diff --git a/frontend/src/components/SomethingWentWrong.js b/frontend/src/components/SomethingWentWrong.js
index 9f8450e094..f8b41fa9ed 100644
--- a/frontend/src/components/SomethingWentWrong.js
+++ b/frontend/src/components/SomethingWentWrong.js
@@ -1,136 +1,176 @@
-/* eslint-disable max-len */
-import React, { useContext, useEffect } from 'react';
-import { Link } from '@trussworks/react-uswds';
-import { Link as ReactLink } from 'react-router-dom';
-import ReactRouterPropTypes from 'react-router-prop-types';
-import HideSiteNavContext from '../HideSiteNavContext';
+import React, { useContext } from 'react';
+import { Link, Button } from '@trussworks/react-uswds';
+import { Link as ReactLink, useHistory } from 'react-router-dom';
+import PropTypes from 'prop-types';
+import SomethingWentWrongContext from '../SomethingWentWrongContext';
import './SomethingWentWrong.scss';
-function SomethingWentWrong({ match }) {
- const { responseCode } = match.params;
- const { setHideSiteNav } = useContext(HideSiteNavContext);
+/* eslint-disable max-len */
+
+function SomethingWentWrong({ errorResponseCode }) {
+ const { setErrorResponseCode } = useContext(SomethingWentWrongContext);
+ const history = useHistory();
const supportLink = 'https://app.smartsheetgov.com/b/form/f0b4725683f04f349a939bd2e3f5425a';
const getSupportLink = () => (
support
);
- const determineMessage = () => {
- // 403 Forbidden.
- if (responseCode === '403') {
- return (
-
-
403 error - forbidden
-
Restricted access.
-
-
- Sorry, but it looks like you're trying to access a restricted area. Here's what you can do:
-
- If you believe this is an error or need further assistance, get in touch with
- {' '}
- {getSupportLink()}
- .
-
-
-
- );
- }
-
- // 404 Not found.
- if (responseCode === '404') {
- return (
-
-
404 error
-
Page not found
-
-
- Well, this is awkward. It seems like the page you're looking for has taken a detour into the unknown. Here's what you can do:
-
-
- Go back to
- {' '}
- home
-
-
- Contact
- {' '}
- {getSupportLink()}
- {' '}
- for help
-
-
- Thanks for your understanding and patience!
-
-
-
- );
- }
+ const onHomeClick = () => {
+ setErrorResponseCode(null);
+ history.push('/');
+ };
- // 500 Internal server error (display for everything else).
- return (
-
-
Something went wrong.
-
-
- Well, this is awkward. It seems like the page you're looking for has taken a detour into the unknown. Here's what you can do:
-
-
- Go back to
+ const responseCodeMessages = [
+ {
+ code: 401,
+ message: '401 error - unauthorized',
+ title: 'Unauthorized access',
+ body: (
+
+ Sorry, but it looks like you're trying to access a restricted area. Here's what you can do:
+
+ If you believe this is an error or need further assistance, get in touch with
+ {' '}
+ {getSupportLink()}
+ .
+
+ ),
+ },
+ {
+ code: 403,
+ message: '403 error - forbidden',
+ title: 'Restricted access',
+ body: (
+
+ Sorry, but it looks like you're trying to access a restricted area. Here's what you can do:
+
- );
- };
+ and ask them to check your permissions.
+
+
+
+ Login again:
+ {' '}
+ Try logging in again. Maybe that's the missing key.
+
+
+ Explore elsewhere:
+ {' '}
+ Return to the main area and explore other permitted sections.
+
+
+ If you believe this is an error or need further assistance, get in touch with
+ {' '}
+ {getSupportLink()}
+ .
+
+ ),
+ },
+ {
+ code: 404,
+ message: '404 error',
+ title: 'Page not found',
+ body: (
+
+ Well, this is awkward. It seems like the page you're looking for has taken a detour into the unknown. Here's what you can do:
+
+
+ Go back to
+ {' '}
+ home
+
+
+ Contact
+ {' '}
+ {getSupportLink()}
+ {' '}
+ for help
+
+
+ Thanks for your understanding and patience!
+
+ ),
+ },
+ {
+ code: 500,
+ message: null,
+ title: 'Something went wrong',
+ body: (
+
+ Well, this is awkward. It seems like the page you're looking for has taken a detour into the unknown. Here's what you can do:
+
+
+ Go back to
+ {' '}
+ home
+
+
+ Contact
+ {' '}
+ {getSupportLink()}
+ {' '}
+ for help
+
+
+ Thanks for your understanding and patience!
+
+ ),
+ },
+ ];
- useEffect(() => {
- setHideSiteNav(true);
- return () => setHideSiteNav(false);
- }, [setHideSiteNav]);
+ const messageToDisplay = responseCodeMessages.find((msg) => msg.code === errorResponseCode) || responseCodeMessages.find((msg) => msg.code === 500);
return (
- <>
- {determineMessage(responseCode)}
- >
+
+ {
+ messageToDisplay.message && (
+
{messageToDisplay.message}
+ )
+ }
+
{messageToDisplay.title}
+
+ {
+ messageToDisplay.body
+ }
+
+
);
}
SomethingWentWrong.propTypes = {
- match: ReactRouterPropTypes.match.isRequired,
+ errorResponseCode: PropTypes.number.isRequired,
};
export default SomethingWentWrong;
diff --git a/frontend/src/components/__tests__/SomethingWentWrong.js b/frontend/src/components/__tests__/SomethingWentWrong.js
index 57ed30345c..3902eaf977 100644
--- a/frontend/src/components/__tests__/SomethingWentWrong.js
+++ b/frontend/src/components/__tests__/SomethingWentWrong.js
@@ -3,30 +3,40 @@ import { render, screen } from '@testing-library/react';
import { createMemoryHistory } from 'history';
import { Router } from 'react-router';
import SomethingWentWrong from '../SomethingWentWrong';
-import HideSiteNavContext from '../../HideSiteNavContext';
const history = createMemoryHistory();
const renderSomethingWentWrong = (
- responseCode,
- hideSiteNav = false,
- setHideSiteNav = jest.fn,
+ responseCode = 500,
) => render(
-
-
-
- ,
+
,
);
describe('SomethingWentWrong component', () => {
+ // Write a test to pass the response code 401 to the component.
+ it('renders a 401 error message', async () => {
+ renderSomethingWentWrong(401);
+
+ expect(screen.getByText('401 error - unauthorized')).toBeInTheDocument();
+ expect(screen.getByRole('heading', { name: /unauthorized access/i })).toBeInTheDocument();
+ expect(screen.getByText(/Sorry, but it looks like you're trying to access a restricted area./i)).toBeInTheDocument();
+ expect(screen.getByText(/Double-check permissions:/i)).toBeInTheDocument();
+ expect(screen.getByText(/Ensure you have the proper clearance to access this page/i)).toBeInTheDocument();
+ expect(screen.getByText(/Login again:/i)).toBeInTheDocument();
+ expect(screen.getByText(/Try logging in again. Maybe that's the missing key./i)).toBeInTheDocument();
+ expect(screen.getByText(/Explore elsewhere:/i)).toBeInTheDocument();
+ expect(screen.getByText(/Return to the main area and explore other permitted sections./i)).toBeInTheDocument();
+ expect(screen.getByText(/If you believe this is an error or need further/i)).toBeInTheDocument();
+ });
+
// Write a test to pass the response code 403 to the component.
it('renders a 403 error message', async () => {
- renderSomethingWentWrong('403');
+ renderSomethingWentWrong(403);
expect(screen.getByText('403 error - forbidden')).toBeInTheDocument();
- expect(screen.getByText('Restricted access.')).toBeInTheDocument();
+ expect(screen.getByRole('heading', { name: /restricted access/i })).toBeInTheDocument();
expect(screen.getByText(/Sorry, but it looks like you're trying to access a restricted area./i)).toBeInTheDocument();
expect(screen.getByText(/Double-check permissions:/i)).toBeInTheDocument();
expect(screen.getByText(/Ensure you have the proper clearance to access this page/i)).toBeInTheDocument();
@@ -39,7 +49,7 @@ describe('SomethingWentWrong component', () => {
// Write a test to pass the response code 404 to the component.
it('renders a 404 error message', async () => {
- renderSomethingWentWrong('404');
+ renderSomethingWentWrong(404);
expect(screen.getByText('404 error')).toBeInTheDocument();
expect(screen.getByText('Page not found')).toBeInTheDocument();
@@ -51,8 +61,8 @@ describe('SomethingWentWrong component', () => {
// Write a test to pass an unknown response code to the component.
it('renders a generic error message', async () => {
- renderSomethingWentWrong('500');
- expect(screen.getByText('Something went wrong.')).toBeInTheDocument();
+ renderSomethingWentWrong();
+ expect(screen.getByRole('heading', { name: /something went wrong/i })).toBeInTheDocument();
expect(screen.getByText(/Well, this is awkward. It seems like the page you're looking for has taken a detour into the unknown. Here's what you can do:/i)).toBeInTheDocument();
expect(screen.getByText(/Thanks for your understanding and patience!/i)).toBeInTheDocument();
});
diff --git a/frontend/src/pages/ActivityReport/index.js b/frontend/src/pages/ActivityReport/index.js
index 010e225743..bd93b23531 100644
--- a/frontend/src/pages/ActivityReport/index.js
+++ b/frontend/src/pages/ActivityReport/index.js
@@ -46,6 +46,7 @@ import useLocalStorage, { setConnectionActiveWithError } from '../../hooks/useLo
import NetworkContext, { isOnlineMode } from '../../NetworkContext';
import UserContext from '../../UserContext';
import { HTTPError } from '../../fetchers';
+// import SomethingWentWrongContext from '../../SomethingWentWrongContext';
const defaultValues = {
ECLKCResourcesUsed: [],
@@ -203,6 +204,7 @@ function ActivityReport({
const [creatorNameWithRole, updateCreatorRoleWithName] = useState('');
const reportId = useRef();
const { user } = useContext(UserContext);
+ // const { setErrorResponseCode } = useContext(SomethingWentWrongContext);
const {
socket,
From f7505c4bc7c82a40580c323d5983dce9e094477c Mon Sep 17 00:00:00 2001
From: Adam Levin
Date: Tue, 2 Jul 2024 13:43:29 -0400
Subject: [PATCH 09/26] cleanup and fixes
---
frontend/src/App.js | 2 +-
frontend/src/components/SomethingWentWrong.js | 4 ++--
frontend/src/pages/ActivityReport/index.js | 18 ++++++++----------
3 files changed, 11 insertions(+), 13 deletions(-)
diff --git a/frontend/src/App.js b/frontend/src/App.js
index adc57c50c0..efbf21c097 100644
--- a/frontend/src/App.js
+++ b/frontend/src/App.js
@@ -508,7 +508,7 @@ function App() {
)}
- {authenticated && renderAuthenticatedRoutes()}
+ {authenticated && !errorResponseCode && renderAuthenticatedRoutes()}
diff --git a/frontend/src/components/SomethingWentWrong.js b/frontend/src/components/SomethingWentWrong.js
index f8b41fa9ed..472550f233 100644
--- a/frontend/src/components/SomethingWentWrong.js
+++ b/frontend/src/components/SomethingWentWrong.js
@@ -1,6 +1,6 @@
import React, { useContext } from 'react';
import { Link, Button } from '@trussworks/react-uswds';
-import { Link as ReactLink, useHistory } from 'react-router-dom';
+import { useHistory } from 'react-router-dom';
import PropTypes from 'prop-types';
import SomethingWentWrongContext from '../SomethingWentWrongContext';
import './SomethingWentWrong.scss';
@@ -109,7 +109,7 @@ function SomethingWentWrong({ errorResponseCode }) {
Go back to
{' '}
- home
+ home
Contact
diff --git a/frontend/src/pages/ActivityReport/index.js b/frontend/src/pages/ActivityReport/index.js
index bd93b23531..6619a4e10d 100644
--- a/frontend/src/pages/ActivityReport/index.js
+++ b/frontend/src/pages/ActivityReport/index.js
@@ -45,8 +45,7 @@ import {
import useLocalStorage, { setConnectionActiveWithError } from '../../hooks/useLocalStorage';
import NetworkContext, { isOnlineMode } from '../../NetworkContext';
import UserContext from '../../UserContext';
-import { HTTPError } from '../../fetchers';
-// import SomethingWentWrongContext from '../../SomethingWentWrongContext';
+import SomethingWentWrongContext from '../../SomethingWentWrongContext';
const defaultValues = {
ECLKCResourcesUsed: [],
@@ -204,7 +203,7 @@ function ActivityReport({
const [creatorNameWithRole, updateCreatorRoleWithName] = useState('');
const reportId = useRef();
const { user } = useContext(UserContext);
- // const { setErrorResponseCode } = useContext(SomethingWentWrongContext);
+ const { setErrorResponseCode } = useContext(SomethingWentWrongContext);
const {
socket,
@@ -259,7 +258,12 @@ function ActivityReport({
reportId.current = activityReportId;
if (activityReportId !== 'new') {
- const fetchedReport = await getReport(activityReportId);
+ let fetchedReport;
+ try {
+ fetchedReport = await getReport(activityReportId);
+ } catch (e) {
+ setErrorResponseCode(e.status);
+ }
report = convertReportToFormData(fetchedReport);
} else {
report = {
@@ -386,12 +390,6 @@ function ActivityReport({
>
);
const errorMsg = !connection ? networkErrorMessage : <>Unable to load activity report>;
-
- if (e instanceof HTTPError && [403, 404].includes(e.status)) {
- // Redirect to the SomethingWentWrong component pass the response code as a param.
- history.push(`/something-went-wrong/${e.status}`);
- }
-
updateError(errorMsg);
// If the error was caused by an invalid region, we need a way to communicate that to the
// component so we can redirect the user. We can do this by updating the form data
From bc3b97cd58743d33aae4ac9e451ed2f016398ea9 Mon Sep 17 00:00:00 2001
From: Adam Levin
Date: Tue, 2 Jul 2024 15:11:55 -0400
Subject: [PATCH 10/26] updated on reports with tests
---
.../pages/ActivityReport/__tests__/index.js | 9 ++++
frontend/src/pages/ActivityReport/index.js | 1 +
.../src/pages/ActivityReport/testHelpers.js | 37 +++++++------
.../ApprovedActivityReport/__tests__/index.js | 38 ++++++++-----
.../src/pages/ApprovedActivityReport/index.js | 54 +++----------------
5 files changed, 63 insertions(+), 76 deletions(-)
diff --git a/frontend/src/pages/ActivityReport/__tests__/index.js b/frontend/src/pages/ActivityReport/__tests__/index.js
index 16f09e1912..017b0ca7f4 100644
--- a/frontend/src/pages/ActivityReport/__tests__/index.js
+++ b/frontend/src/pages/ActivityReport/__tests__/index.js
@@ -135,6 +135,15 @@ describe('ActivityReport', () => {
});
});
+ describe('something went wrong context', () => {
+ it('ensure we call set the response code on error', async () => {
+ fetchMock.get('/api/activity-reports/1', 500);
+ const setErrorResponseCode = jest.fn();
+ renderActivityReport('1', 'activity-summary', null, 1, setErrorResponseCode);
+ await waitFor(() => expect(setErrorResponseCode).toHaveBeenCalledWith(500));
+ });
+ });
+
describe('groups', () => {
it('recipients correctly update for groups', async () => {
const groupRecipients = {
diff --git a/frontend/src/pages/ActivityReport/index.js b/frontend/src/pages/ActivityReport/index.js
index 6619a4e10d..41bded708a 100644
--- a/frontend/src/pages/ActivityReport/index.js
+++ b/frontend/src/pages/ActivityReport/index.js
@@ -262,6 +262,7 @@ function ActivityReport({
try {
fetchedReport = await getReport(activityReportId);
} catch (e) {
+ // If error retrieving the report show the "something went wrong" page.
setErrorResponseCode(e.status);
}
report = convertReportToFormData(fetchedReport);
diff --git a/frontend/src/pages/ActivityReport/testHelpers.js b/frontend/src/pages/ActivityReport/testHelpers.js
index 13c8b2a889..60808ea50e 100644
--- a/frontend/src/pages/ActivityReport/testHelpers.js
+++ b/frontend/src/pages/ActivityReport/testHelpers.js
@@ -11,6 +11,7 @@ import moment from 'moment';
import ActivityReport from './index';
import UserContext from '../../UserContext';
import AppLoadingContext from '../../AppLoadingContext';
+import SomethingWentWrongContext from '../../SomethingWentWrongContext';
export const history = createMemoryHistory();
@@ -66,33 +67,37 @@ export const ReportComponent = ({
currentPage = 'activity-summary',
showLastUpdatedTime = null,
userId = 1,
+ setErrorResponseCode = jest.fn(),
}) => (
-
-
-
-
-
+
+
+
+
+
+
+
);
-export const renderActivityReport = (id, currentPage = 'activity-summary', showLastUpdatedTime = null, userId = 1) => {
+export const renderActivityReport = (id, currentPage = 'activity-summary', showLastUpdatedTime = null, userId = 1, setErrorResponseCode = jest.fn()) => {
render(
,
);
};
diff --git a/frontend/src/pages/ApprovedActivityReport/__tests__/index.js b/frontend/src/pages/ApprovedActivityReport/__tests__/index.js
index 1bb5e8e6ce..1150f212c8 100644
--- a/frontend/src/pages/ApprovedActivityReport/__tests__/index.js
+++ b/frontend/src/pages/ApprovedActivityReport/__tests__/index.js
@@ -10,6 +10,7 @@ import {
} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import fetchMock from 'fetch-mock';
+import SomethingWentWrongContext from '../../../SomethingWentWrongContext';
import ApprovedActivityReport from '../index';
@@ -104,7 +105,7 @@ describe('Activity report print and share view', () => {
],
};
- function renderApprovedActivityReport(id, passedUser = user) {
+ function renderApprovedActivityReport(id, passedUser = user, setErrorResponseCode = jest.fn()) {
const match = {
path: '',
url: '',
@@ -113,7 +114,11 @@ describe('Activity report print and share view', () => {
},
};
- render( );
+ render(
+
+
+ ,
+ );
}
afterEach(() => fetchMock.restore());
@@ -224,18 +229,22 @@ describe('Activity report print and share view', () => {
});
it('handles authorization errors', async () => {
- act(() => renderApprovedActivityReport(5007));
-
- await waitFor(() => {
- expect(screen.getByText(/sorry, you are not allowed to view this report/i)).toBeInTheDocument();
+ const setErrorResponseCode = jest.fn();
+ act(async () => {
+ renderApprovedActivityReport(5007, user, setErrorResponseCode);
+ await waitFor(() => {
+ expect(setErrorResponseCode).toHaveBeenCalledWith(401);
+ });
});
});
it('handles data errors', async () => {
- act(() => renderApprovedActivityReport(5002));
-
- await waitFor(() => {
- expect(screen.getByText(/sorry, something went wrong\./i)).toBeInTheDocument();
+ const setErrorResponseCode = jest.fn();
+ act(async () => {
+ renderApprovedActivityReport(5002, user, setErrorResponseCode);
+ await waitFor(() => {
+ expect(setErrorResponseCode).toHaveBeenCalled();
+ });
});
});
@@ -314,9 +323,12 @@ describe('Activity report print and share view', () => {
});
it('handles a malformed url', async () => {
- act(() => renderApprovedActivityReport('butter-lover'));
- await waitFor(() => {
- expect(screen.getByText(/sorry, something went wrong\./i)).toBeInTheDocument();
+ const setErrorResponseCode = jest.fn();
+ act(async () => {
+ renderApprovedActivityReport('butter-lover', user, setErrorResponseCode);
+ await waitFor(() => {
+ expect(setErrorResponseCode).toHaveBeenCalledWith(404);
+ });
});
});
diff --git a/frontend/src/pages/ApprovedActivityReport/index.js b/frontend/src/pages/ApprovedActivityReport/index.js
index 4028d78c25..c595242aaf 100644
--- a/frontend/src/pages/ApprovedActivityReport/index.js
+++ b/frontend/src/pages/ApprovedActivityReport/index.js
@@ -1,4 +1,6 @@
-import React, { useEffect, useState, useRef } from 'react';
+import React, {
+ useEffect, useState, useRef, useContext,
+} from 'react';
import PropTypes from 'prop-types';
import ReactRouterPropTypes from 'react-router-prop-types';
import { Redirect } from 'react-router-dom';
@@ -16,10 +18,10 @@ import './index.scss';
import ApprovedReportV1 from './components/ApprovedReportV1';
import ApprovedReportV2 from './components/ApprovedReportV2';
import ApprovedReportSpecialButtons from '../../components/ApprovedReportSpecialButtons';
+import SomethingWentWrongContext from '../../SomethingWentWrongContext';
export default function ApprovedActivityReport({ match, user }) {
- const [notAuthorized, setNotAuthorized] = useState(false);
- const [somethingWentWrong, setSomethingWentWrong] = useState(false);
+ const { setErrorResponseCode } = useContext(SomethingWentWrongContext);
const [justUnlocked, updatedJustUnlocked] = useState(false);
@@ -75,7 +77,6 @@ export default function ApprovedActivityReport({ match, user }) {
useEffect(() => {
if (!parseInt(match.params.activityReportId, 10)) {
- setSomethingWentWrong(true);
return;
}
@@ -85,54 +86,13 @@ export default function ApprovedActivityReport({ match, user }) {
// review and submit table
setReport(data);
} catch (err) {
- if (err && err.status && (err.status >= 400 && err.status < 500)) {
- setNotAuthorized(true);
- return;
- }
-
- // eslint-disable-next-line no-console
- console.log(err);
- setSomethingWentWrong(true);
+ setErrorResponseCode(err.status);
}
}
fetchReport();
- }, [match.params.activityReportId, user]);
-
- if (notAuthorized) {
- return (
- <>
-
- Not Authorized To View Activity Report
-
-
-
-
Unauthorized
-
- Sorry, you are not allowed to view this report
-
-
-
- >
- );
- }
+ }, [match.params.activityReportId, user, setErrorResponseCode]);
- if (somethingWentWrong) {
- return (
- <>
-
- Error Displaying Activity Report
-
-
-
-
- Sorry, something went wrong.
-
-
-
- >
- );
- }
const {
id: reportId,
displayId,
From c64be633f5d6bdf17e396a4c813ada0a1669e4bd Mon Sep 17 00:00:00 2001
From: Adam Levin
Date: Tue, 2 Jul 2024 15:18:53 -0400
Subject: [PATCH 11/26] make colors...
---
colorsjschecksum | 2 +-
frontend/src/colors.scss | 3 +--
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/colorsjschecksum b/colorsjschecksum
index d9761a45bb..ecf579b7f2 100644
--- a/colorsjschecksum
+++ b/colorsjschecksum
@@ -1 +1 @@
-69962956f5817a804f1a491395986eb3c612a6feb4d76315f58c5b273cdf25a7
\ No newline at end of file
+9d1caff32aaaea3109f14ce9fa740f7ef9c6ea6d55097a74abef1da773110c41
\ No newline at end of file
diff --git a/frontend/src/colors.scss b/frontend/src/colors.scss
index fac7c72316..80fc0e2643 100644
--- a/frontend/src/colors.scss
+++ b/frontend/src/colors.scss
@@ -39,5 +39,4 @@ $error-dark: #b50909;
$blue-vivid-focus: #2491FF;
$text-ink: #1b1b1b;
$text-link: #46789B;
-$text-visited: #8C39DB;
-$response-code: #71767A;
\ No newline at end of file
+$text-visited: #8C39DB;
\ No newline at end of file
From 32c83781c5c5037150c1fe1bb93e228eab2c732a Mon Sep 17 00:00:00 2001
From: Adam Levin
Date: Tue, 2 Jul 2024 15:26:07 -0400
Subject: [PATCH 12/26] add color
---
colorsjschecksum | 2 +-
colorsscsschecksum | 2 +-
frontend/src/colors.js | 1 +
frontend/src/colors.scss | 3 ++-
4 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/colorsjschecksum b/colorsjschecksum
index ecf579b7f2..ff45aef792 100644
--- a/colorsjschecksum
+++ b/colorsjschecksum
@@ -1 +1 @@
-9d1caff32aaaea3109f14ce9fa740f7ef9c6ea6d55097a74abef1da773110c41
\ No newline at end of file
+ebc7ad94231a4b6f7263c55eb114b48c1a9bcd927c6e829e71d24cf4184efc19
\ No newline at end of file
diff --git a/colorsscsschecksum b/colorsscsschecksum
index dd4f157735..5aa17e9d35 100644
--- a/colorsscsschecksum
+++ b/colorsscsschecksum
@@ -1 +1 @@
-45fe702aa79405030c90def8c4690064d0be4ca316fc297e6b1dbe1117ae95ff
\ No newline at end of file
+36906d289c12231e597eeb56423d83f37593429766f6d496f2db5f508c7d6ee8
\ No newline at end of file
diff --git a/frontend/src/colors.js b/frontend/src/colors.js
index 6d74aebfba..2196c2bd01 100644
--- a/frontend/src/colors.js
+++ b/frontend/src/colors.js
@@ -41,6 +41,7 @@ const colors = {
textInk: '#1b1b1b',
textLink: '#46789B',
textVisited: '#8C39DB',
+ responseCode: '#71767A',
};
module.exports = colors;
diff --git a/frontend/src/colors.scss b/frontend/src/colors.scss
index 80fc0e2643..fac7c72316 100644
--- a/frontend/src/colors.scss
+++ b/frontend/src/colors.scss
@@ -39,4 +39,5 @@ $error-dark: #b50909;
$blue-vivid-focus: #2491FF;
$text-ink: #1b1b1b;
$text-link: #46789B;
-$text-visited: #8C39DB;
\ No newline at end of file
+$text-visited: #8C39DB;
+$response-code: #71767A;
\ No newline at end of file
From 686772bbbe2fbeba551c6f40aaa5795b4c811de3 Mon Sep 17 00:00:00 2001
From: Adam Levin
Date: Tue, 2 Jul 2024 16:50:38 -0400
Subject: [PATCH 13/26] add to events
---
frontend/src/components/SomethingWentWrong.js | 5 +++
.../src/pages/SessionForm/__tests__/index.js | 37 ++++++++++--------
frontend/src/pages/SessionForm/index.js | 6 ++-
.../TrainingReportForm/__tests__/index.js | 39 +++++++++++--------
.../src/pages/TrainingReportForm/index.js | 11 +++++-
src/services/currentUser.js | 2 +
6 files changed, 63 insertions(+), 37 deletions(-)
diff --git a/frontend/src/components/SomethingWentWrong.js b/frontend/src/components/SomethingWentWrong.js
index 472550f233..d40c06c7e0 100644
--- a/frontend/src/components/SomethingWentWrong.js
+++ b/frontend/src/components/SomethingWentWrong.js
@@ -3,14 +3,19 @@ import { Link, Button } from '@trussworks/react-uswds';
import { useHistory } from 'react-router-dom';
import PropTypes from 'prop-types';
import SomethingWentWrongContext from '../SomethingWentWrongContext';
+import AppLoadingContext from '../AppLoadingContext';
import './SomethingWentWrong.scss';
/* eslint-disable max-len */
function SomethingWentWrong({ errorResponseCode }) {
const { setErrorResponseCode } = useContext(SomethingWentWrongContext);
+ const { setIsAppLoading, isAppLoading } = useContext(AppLoadingContext);
const history = useHistory();
+ // Make sure if something was loading when an error occurred, we stop the loading spinner.
+ if (isAppLoading) setIsAppLoading(false);
+
const supportLink = 'https://app.smartsheetgov.com/b/form/f0b4725683f04f349a939bd2e3f5425a';
const getSupportLink = () => (
support
diff --git a/frontend/src/pages/SessionForm/__tests__/index.js b/frontend/src/pages/SessionForm/__tests__/index.js
index 3100c15f04..257053deba 100644
--- a/frontend/src/pages/SessionForm/__tests__/index.js
+++ b/frontend/src/pages/SessionForm/__tests__/index.js
@@ -13,22 +13,30 @@ import UserContext from '../../../UserContext';
import AppLoadingContext from '../../../AppLoadingContext';
import { COMPLETE, IN_PROGRESS } from '../../../components/Navigator/constants';
import { mockRSSData } from '../../../testHelpers';
+import SomethingWentWrongContext from '../../../SomethingWentWrongContext';
describe('SessionReportForm', () => {
const sessionsUrl = join('/', 'api', 'session-reports');
const history = createMemoryHistory();
- const renderSessionForm = (trainingReportId, currentPage, sessionId) => render(
+ const renderSessionForm = (
+ trainingReportId,
+ currentPage,
+ sessionId,
+ setErrorResponseCode = jest.fn,
+ ) => render(
-
-
-
+
+
+
+
+
,
);
@@ -96,21 +104,18 @@ describe('SessionReportForm', () => {
expect(screen.getByText(/Training report - Session/i)).toBeInTheDocument();
});
- it('handles an error fetching a session', async () => {
+ it('sets response error', async () => {
const url = join(sessionsUrl, 'id', '1');
fetchMock.get(
url, 500,
);
-
+ const setErrorResponseCode = jest.fn();
act(() => {
- renderSessionForm('1', 'session-summary', '1');
+ renderSessionForm('1', 'session-summary', '1', setErrorResponseCode);
});
-
await waitFor(() => expect(fetchMock.called(url)).toBe(true));
-
- expect(screen.getByText(/Training report - Session/i)).toBeInTheDocument();
- expect(screen.getByText(/Error fetching session/i)).toBeInTheDocument();
+ expect(setErrorResponseCode).toHaveBeenCalledWith(500);
});
it('saves draft', async () => {
diff --git a/frontend/src/pages/SessionForm/index.js b/frontend/src/pages/SessionForm/index.js
index 52e322f395..ed0853765d 100644
--- a/frontend/src/pages/SessionForm/index.js
+++ b/frontend/src/pages/SessionForm/index.js
@@ -21,6 +21,7 @@ import Navigator from '../../components/Navigator';
import BackLink from '../../components/BackLink';
import pages from './pages';
import AppLoadingContext from '../../AppLoadingContext';
+import SomethingWentWrongContext from '../../SomethingWentWrongContext';
// websocket publish location interval
const INTERVAL_DELAY = 10000; // TEN SECONDS
@@ -96,6 +97,7 @@ export default function SessionForm({ match }) {
const { user } = useContext(UserContext);
const { setIsAppLoading } = useContext(AppLoadingContext);
+ const { setErrorResponseCode } = useContext(SomethingWentWrongContext);
const {
socket,
@@ -158,14 +160,14 @@ export default function SessionForm({ match }) {
resetFormData(hookForm.reset, session);
reportId.current = session.id;
} catch (e) {
- setError('Error fetching session');
+ setErrorResponseCode(e.status);
} finally {
setReportFetched(true);
setDatePickerKey(`f${Date.now().toString()}`);
}
}
fetchSession();
- }, [currentPage, hookForm.reset, reportFetched, sessionId]);
+ }, [currentPage, hookForm.reset, reportFetched, sessionId, setErrorResponseCode]);
// hook to update the page state in the sidebar
useHookFormPageState(hookForm, pages, currentPage);
diff --git a/frontend/src/pages/TrainingReportForm/__tests__/index.js b/frontend/src/pages/TrainingReportForm/__tests__/index.js
index 6e21bc51bd..b5638f4d53 100644
--- a/frontend/src/pages/TrainingReportForm/__tests__/index.js
+++ b/frontend/src/pages/TrainingReportForm/__tests__/index.js
@@ -11,21 +11,27 @@ import TrainingReportForm from '../index';
import UserContext from '../../../UserContext';
import AppLoadingContext from '../../../AppLoadingContext';
import { COMPLETE } from '../../../components/Navigator/constants';
+import SomethingWentWrong from '../../../SomethingWentWrongContext';
describe('TrainingReportForm', () => {
const history = createMemoryHistory();
const sessionsUrl = '/api/session-reports/eventId/1234';
- const renderTrainingReportForm = (trainingReportId, currentPage) => render(
+ const renderTrainingReportForm = (
+ trainingReportId, currentPage,
+ setErrorResponseCode = jest.fn,
+ ) => render(
-
+
+
+
,
@@ -65,6 +71,15 @@ describe('TrainingReportForm', () => {
expect(screen.getByText(/Training report - Event/i)).toBeInTheDocument();
});
+ it('calls setErrorResponseCode when an error occurs', async () => {
+ fetchMock.get('/api/events/id/1', 500);
+ const setErrorResponseCode = jest.fn();
+ act(() => {
+ renderTrainingReportForm('1', 'event-summary', setErrorResponseCode);
+ });
+ await waitFor(() => expect(setErrorResponseCode).toHaveBeenCalledWith(500));
+ });
+
it('redirects to event summary', async () => {
fetchMock.get('/api/events/id/1', {
id: 1,
@@ -145,16 +160,6 @@ describe('TrainingReportForm', () => {
expect(fetchMock.called('/api/events/id/123')).toBe(true);
});
- it('displays error when event report fails to load', async () => {
- fetchMock.get('/api/events/id/123', 500);
- act(() => {
- renderTrainingReportForm('123', 'event-summary');
- });
-
- expect(fetchMock.called('/api/events/id/123')).toBe(true);
- expect(await screen.findByText(/error fetching training report/i)).toBeInTheDocument();
- });
-
it('displays "no training report id provided" error', async () => {
fetchMock.get('/api/events/id/123', {
regionId: '1',
diff --git a/frontend/src/pages/TrainingReportForm/index.js b/frontend/src/pages/TrainingReportForm/index.js
index 763415daa2..9299bdf2df 100644
--- a/frontend/src/pages/TrainingReportForm/index.js
+++ b/frontend/src/pages/TrainingReportForm/index.js
@@ -25,6 +25,7 @@ import BackLink from '../../components/BackLink';
import pages from './pages';
import AppLoadingContext from '../../AppLoadingContext';
import useHookFormPageState from '../../hooks/useHookFormPageState';
+import SomethingWentWrongContext from '../../SomethingWentWrongContext';
// websocket publish location interval
const INTERVAL_DELAY = 10000; // TEN SECONDS
@@ -125,6 +126,7 @@ export default function TrainingReportForm({ match }) {
const { user } = useContext(UserContext);
const { setIsAppLoading, isAppLoading } = useContext(AppLoadingContext);
+ const { setErrorResponseCode } = useContext(SomethingWentWrongContext);
const {
socket,
@@ -179,14 +181,19 @@ export default function TrainingReportForm({ match }) {
resetFormData(hookForm.reset, event);
reportId.current = trainingReportId;
} catch (e) {
- setError('Error fetching training report');
+ setErrorResponseCode(e.status);
} finally {
setReportFetched(true);
setDatePickerKey(Date.now().toString());
}
}
fetchReport();
- }, [currentPage, hookForm.reset, isAppLoading, reportFetched, trainingReportId]);
+ }, [currentPage,
+ hookForm.reset,
+ isAppLoading,
+ reportFetched,
+ trainingReportId,
+ setErrorResponseCode]);
useEffect(() => {
// set error if no training report id
diff --git a/src/services/currentUser.js b/src/services/currentUser.js
index 5a2d0177ab..dfbd1cc0f9 100644
--- a/src/services/currentUser.js
+++ b/src/services/currentUser.js
@@ -26,6 +26,7 @@ import { validateUserAuthForAdmin } from './accessValidation';
*/
export async function currentUserId(req, res) {
function idFromSessionOrLocals() {
+ /*
if (req.session && req.session.userId) {
httpContext.set('impersonationUserId', Number(req.session.userId));
return Number(req.session.userId);
@@ -34,6 +35,7 @@ export async function currentUserId(req, res) {
httpContext.set('impersonationUserId', Number(res.locals.userId));
return Number(res.locals.userId);
}
+ */
// bypass authorization, used for cucumber UAT and axe accessibility testing
if (process.env.NODE_ENV !== 'production' && process.env.BYPASS_AUTH === 'true') {
From be1b0ef058799c3d78f6e81a7f728ce680b30dff Mon Sep 17 00:00:00 2001
From: Adam Levin
Date: Wed, 3 Jul 2024 12:10:54 -0400
Subject: [PATCH 14/26] add to goals with test
---
.../components/GoalForm/__tests__/index.js | 46 ++++++++++++-------
frontend/src/components/GoalForm/index.js | 14 ++++--
.../ApprovedActivityReport/__tests__/index.js | 16 +++----
.../pages/RecipientRecord/__tests__/index.js | 21 +++++----
src/services/currentUser.js | 2 -
5 files changed, 61 insertions(+), 38 deletions(-)
diff --git a/frontend/src/components/GoalForm/__tests__/index.js b/frontend/src/components/GoalForm/__tests__/index.js
index 00e7d7cd55..06808c15c7 100644
--- a/frontend/src/components/GoalForm/__tests__/index.js
+++ b/frontend/src/components/GoalForm/__tests__/index.js
@@ -6,6 +6,7 @@ import {
screen,
within,
waitFor,
+ act,
} from '@testing-library/react';
import { SCOPE_IDS } from '@ttahub/common';
import selectEvent from 'react-select-event';
@@ -18,6 +19,7 @@ import UserContext from '../../../UserContext';
import { OBJECTIVE_ERROR_MESSAGES } from '../constants';
import { BEFORE_OBJECTIVES_CREATE_GOAL, BEFORE_OBJECTIVES_SELECT_RECIPIENTS } from '../Form';
import AppLoadingContext from '../../../AppLoadingContext';
+import SomethingWentWrongContext from '../../../SomethingWentWrongContext';
const [objectiveTitleError] = OBJECTIVE_ERROR_MESSAGES;
@@ -101,31 +103,33 @@ describe('create goal', () => {
}],
}];
- function renderForm(recipient = defaultRecipient, goalId = 'new') {
+ function renderForm(recipient = defaultRecipient, goalId = 'new', setErrorResponseCode = jest.fn()) {
const history = createMemoryHistory();
render((
-
-
+
+
-
-
-
+ >
+
+
+
+
));
}
@@ -368,6 +372,16 @@ describe('create goal', () => {
expect(alert.textContent).toBe('There was an error saving your goal');
});
+ it('correctly calls the setErrorResponseCode function when there is an error', async () => {
+ const setErrorResponseCode = jest.fn();
+ fetchMock.restore();
+ fetchMock.get('/api/recipient/1/goals?goalIds=', 500);
+ await act(async () => {
+ renderForm(defaultRecipient, '48743', setErrorResponseCode);
+ await waitFor(() => expect(setErrorResponseCode).toHaveBeenCalledWith(500));
+ });
+ });
+
it('removes goals', async () => {
fetchMock.post('/api/goals', postResponse);
diff --git a/frontend/src/components/GoalForm/index.js b/frontend/src/components/GoalForm/index.js
index 5c5d010496..3f89df0267 100644
--- a/frontend/src/components/GoalForm/index.js
+++ b/frontend/src/components/GoalForm/index.js
@@ -36,6 +36,7 @@ import AppLoadingContext from '../../AppLoadingContext';
import useUrlParamState from '../../hooks/useUrlParamState';
import UserContext from '../../UserContext';
import VanillaModal from '../VanillaModal';
+import SomethingWentWrongContext from '../../SomethingWentWrongContext';
const [objectiveTextError] = OBJECTIVE_ERROR_MESSAGES;
@@ -112,6 +113,7 @@ export default function GoalForm({
const { isAppLoading, setIsAppLoading, setAppLoadingText } = useContext(AppLoadingContext);
const { user } = useContext(UserContext);
+ const { setErrorResponseCode } = useContext(SomethingWentWrongContext);
const canView = useMemo(() => user.permissions.filter(
(permission) => permission.regionId === parseInt(regionId, DECIMAL_BASE),
@@ -134,9 +136,14 @@ export default function GoalForm({
async function fetchGoal() {
setFetchAttempted(true); // as to only fetch once
try {
- const [goal] = await goalsByIdAndRecipient(
- ids, recipient.id.toString(),
- );
+ let goal = null;
+ try {
+ [goal] = await goalsByIdAndRecipient(
+ ids, recipient.id.toString(),
+ );
+ } catch (err) {
+ setErrorResponseCode(err.status);
+ }
const selectedGoalGrants = goal.grants ? goal.grants : [goal.grant];
@@ -200,6 +207,7 @@ export default function GoalForm({
ids,
setAppLoadingText,
setIsAppLoading,
+ setErrorResponseCode,
]);
const setObjectiveError = (objectiveIndex, errorText) => {
diff --git a/frontend/src/pages/ApprovedActivityReport/__tests__/index.js b/frontend/src/pages/ApprovedActivityReport/__tests__/index.js
index 1150f212c8..387db41d50 100644
--- a/frontend/src/pages/ApprovedActivityReport/__tests__/index.js
+++ b/frontend/src/pages/ApprovedActivityReport/__tests__/index.js
@@ -209,7 +209,7 @@ describe('Activity report print and share view', () => {
version: null,
});
- fetchMock.get('/api/activity-reports/5007', 401);
+ fetchMock.get('/api/activity-reports/5007', { status: 401 });
});
it('renders an activity report in clean view', async () => {
@@ -315,13 +315,6 @@ describe('Activity report print and share view', () => {
});
});
- it('renders a version 2 report with goals', async () => {
- act(() => renderApprovedActivityReport(5005));
- await waitFor(() => {
- expect(screen.getByText(report.author.fullName)).toBeInTheDocument();
- });
- });
-
it('handles a malformed url', async () => {
const setErrorResponseCode = jest.fn();
act(async () => {
@@ -350,4 +343,11 @@ describe('Activity report print and share view', () => {
global.localStorage = oldLocalStorage;
});
+
+ it('renders a version 2 report with goals', async () => {
+ act(() => renderApprovedActivityReport(5005));
+ await waitFor(() => {
+ expect(screen.getByText(report.author.fullName)).toBeInTheDocument();
+ });
+ });
});
diff --git a/frontend/src/pages/RecipientRecord/__tests__/index.js b/frontend/src/pages/RecipientRecord/__tests__/index.js
index 46fe31fe71..b27808c553 100644
--- a/frontend/src/pages/RecipientRecord/__tests__/index.js
+++ b/frontend/src/pages/RecipientRecord/__tests__/index.js
@@ -10,6 +10,7 @@ import { createMemoryHistory } from 'history';
import RecipientRecord, { PageWithHeading } from '../index';
import { formatDateRange } from '../../../utils';
import UserContext from '../../../UserContext';
+import SomethingWentWrongContext from '../../../SomethingWentWrongContext';
import AppLoadingContext from '../../../AppLoadingContext';
import { GrantDataProvider } from '../pages/GrantDataContext';
@@ -101,20 +102,22 @@ describe('recipient record page', () => {
render(
-
-
-
+
+
+
-
-
-
-
+ >
+
+
+
+
+
,
);
}
@@ -248,7 +251,7 @@ describe('recipient record page', () => {
fetchMock.get('/api/goals/12389/recipient/45', mockGoal);
fetchMock.get('/api/topic', []);
memoryHistory.push('/recipient-tta-records/45/region/1/goals/12389');
- act(() => renderRecipientRecord());
+ await act(() => renderRecipientRecord());
await waitFor(() => expect(screen.queryByText(/loading.../)).toBeNull());
await screen.findByText(/TTA Goals for the Mighty Recipient/i);
});
diff --git a/src/services/currentUser.js b/src/services/currentUser.js
index dfbd1cc0f9..5a2d0177ab 100644
--- a/src/services/currentUser.js
+++ b/src/services/currentUser.js
@@ -26,7 +26,6 @@ import { validateUserAuthForAdmin } from './accessValidation';
*/
export async function currentUserId(req, res) {
function idFromSessionOrLocals() {
- /*
if (req.session && req.session.userId) {
httpContext.set('impersonationUserId', Number(req.session.userId));
return Number(req.session.userId);
@@ -35,7 +34,6 @@ export async function currentUserId(req, res) {
httpContext.set('impersonationUserId', Number(res.locals.userId));
return Number(res.locals.userId);
}
- */
// bypass authorization, used for cucumber UAT and axe accessibility testing
if (process.env.NODE_ENV !== 'production' && process.env.BYPASS_AUTH === 'true') {
From 12315848fe34da2a1806e1b0ee0f2e1bcad352ab Mon Sep 17 00:00:00 2001
From: Adam Levin
Date: Wed, 3 Jul 2024 13:08:13 -0400
Subject: [PATCH 15/26] cleanup fe tests
---
.../ApprovedActivityReport/__tests__/index.js | 22 +++++++++----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/frontend/src/pages/ApprovedActivityReport/__tests__/index.js b/frontend/src/pages/ApprovedActivityReport/__tests__/index.js
index 387db41d50..4f3cadcd63 100644
--- a/frontend/src/pages/ApprovedActivityReport/__tests__/index.js
+++ b/frontend/src/pages/ApprovedActivityReport/__tests__/index.js
@@ -152,7 +152,7 @@ describe('Activity report print and share view', () => {
}],
requester: 'chud',
});
- fetchMock.get('/api/activity-reports/5002', 500);
+ fetchMock.get('/api/activity-reports/5002', { status: 500 });
fetchMock.get('/api/activity-reports/5003', {
...report,
@@ -230,21 +230,21 @@ describe('Activity report print and share view', () => {
it('handles authorization errors', async () => {
const setErrorResponseCode = jest.fn();
- act(async () => {
- renderApprovedActivityReport(5007, user, setErrorResponseCode);
- await waitFor(() => {
- expect(setErrorResponseCode).toHaveBeenCalledWith(401);
- });
+ act(() => renderApprovedActivityReport(5007, user, setErrorResponseCode));
+
+ await waitFor(() => {
+ expect(fetchMock.called('/api/activity-reports/5007')).toBeTruthy();
+ expect(setErrorResponseCode).toHaveBeenCalledWith(401);
});
});
it('handles data errors', async () => {
const setErrorResponseCode = jest.fn();
- act(async () => {
- renderApprovedActivityReport(5002, user, setErrorResponseCode);
- await waitFor(() => {
- expect(setErrorResponseCode).toHaveBeenCalled();
- });
+ act(() => renderApprovedActivityReport(5002, user, setErrorResponseCode));
+
+ await waitFor(() => {
+ expect(fetchMock.called('/api/activity-reports/5002')).toBeTruthy();
+ expect(setErrorResponseCode).toHaveBeenCalledWith(500);
});
});
From 2bad8354618764b1c8501eeb7c8f93b09cbe410a Mon Sep 17 00:00:00 2001
From: Matt Bevilacqua
Date: Wed, 3 Jul 2024 13:32:23 -0400
Subject: [PATCH 16/26] Update hash
---
colorsjschecksum | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/colorsjschecksum b/colorsjschecksum
index ff45aef792..15e52b0835 100644
--- a/colorsjschecksum
+++ b/colorsjschecksum
@@ -1 +1 @@
-ebc7ad94231a4b6f7263c55eb114b48c1a9bcd927c6e829e71d24cf4184efc19
\ No newline at end of file
+5dfc9c0a9f719af9ac72655dee86b64b9122ee7cda857e6ac68ae4a3dc76ade6
\ No newline at end of file
From 1e67b3e44a6e73807c6455b6afead10be17ab968 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 6 Jul 2024 00:57:55 +0000
Subject: [PATCH 17/26] Bump certifi from 2023.7.22 to 2024.7.4 in
/similarity_api/src
Bumps [certifi](https://github.com/certifi/python-certifi) from 2023.7.22 to 2024.7.4.
- [Commits](https://github.com/certifi/python-certifi/compare/2023.07.22...2024.07.04)
---
updated-dependencies:
- dependency-name: certifi
dependency-type: direct:production
...
Signed-off-by: dependabot[bot]
---
similarity_api/src/requirements.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/similarity_api/src/requirements.txt b/similarity_api/src/requirements.txt
index ec0b0315f2..df4b224127 100644
--- a/similarity_api/src/requirements.txt
+++ b/similarity_api/src/requirements.txt
@@ -2,7 +2,7 @@ annotated-types==0.5.0
blinker==1.6.2
blis==0.7.10
catalogue==2.0.9
-certifi==2023.7.22
+certifi==2024.7.4
charset-normalizer==3.2.0
click==8.1.6
confection==0.1.1
From 16f28b1fd02b646b4e65dd155c78b2118f99c7f8 Mon Sep 17 00:00:00 2001
From: Nathan Powell
Date: Mon, 8 Jul 2024 08:15:30 -0700
Subject: [PATCH 18/26] correct onAR type values and add missing link table
handling
---
...240702000000-remove_national_center_ars.js | 364 ++++++++++++++++++
1 file changed, 364 insertions(+)
diff --git a/src/migrations/20240702000000-remove_national_center_ars.js b/src/migrations/20240702000000-remove_national_center_ars.js
index dae0f8f6e2..c4dbc9863e 100644
--- a/src/migrations/20240702000000-remove_national_center_ars.js
+++ b/src/migrations/20240702000000-remove_national_center_ars.js
@@ -37,9 +37,12 @@ module.exports = {
-- ActivityReportObjectiveFiles
-- ActivityReportObjectiveResources
-- ActivityReportObjectiveTopics
+ -- ActivityReportObjectiveCourses
-- remove AROs -------------------
-- Create the orphaned Objective deletion list
+ -- Remove Objective link records: -------------
+ -- Delete ObjectiveCollaborators
-- remove Objectives -------------
-- Create the ARG deletion list
@@ -65,6 +68,11 @@ module.exports = {
-- Remove ARs -----------------------
+ -- Test query
+
+ -- Correct the onApprovedAR and onAR values for the goals
+ -- and objectives that were not deleted
+
-------------------------------------------------------------------------------------------------------------------
-------- Deleting unwanted ARs --------
-- Create the AR deletion list
@@ -222,6 +230,17 @@ module.exports = {
)
SELECT id FROM deletes
;
+ DROP TABLE IF EXISTS deleted_activityreportobjectivecourses;
+ CREATE TEMP TABLE deleted_activityreportobjectivecourses AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReportObjectiveCourses"
+ USING aros_to_delete
+ WHERE "activityReportObjectiveId" = aroid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
-- remove AROs -------------------
DROP TABLE IF EXISTS deleted_aros;
CREATE TEMP TABLE deleted_aros AS
@@ -246,6 +265,19 @@ module.exports = {
SELECT DISTINCT "objectiveId"
FROM "ActivityReportObjectives"
;
+ -- Remove Objective link records: -------------
+ -- Delete ObjectiveCollaborators
+ DROP TABLE IF EXISTS deleted_objectivecollaborators;
+ CREATE TEMP TABLE deleted_objectivecollaborators AS
+ WITH deletes AS (
+ DELETE FROM "ObjectiveCollaborators"
+ USING objectives_to_delete
+ WHERE "objectiveId" = oid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
-- remove Objectives -------------------
DROP TABLE IF EXISTS deleted_objectives;
@@ -504,10 +536,14 @@ module.exports = {
UNION
SELECT 12,'deleted_activityreportobjectivetopics', count(*) FROM deleted_activityreportobjectivetopics
UNION
+ SELECT 12,'deleted_activityreportobjectivecourses', count(*) FROM deleted_activityreportobjectivetopics
+ UNION
SELECT 13,'deleted_aros', count(*) FROM deleted_aros
UNION
SELECT 14,'objectives_to_delete', count(*) FROM objectives_to_delete
UNION
+ SELECT 14,'deleted_objectivecollaborators', count(*) FROM objectives_to_delete
+ UNION
SELECT 15,'deleted_objectives', count(*) FROM deleted_objectives
UNION
SELECT 16,'args_to_delete', count(*) FROM args_to_delete
@@ -544,6 +580,334 @@ module.exports = {
ORDER BY 1
;
+ -- Reset the onApprovedAR and onAR values for the goals and objectives that
+ -- were not deleted
+ -- 1. Calculate correct onApprovedAR values for objectives
+ DROP TABLE IF EXISTS objectives_on_ars;
+ CREATE TEMP TABLE objectives_on_ars
+ AS
+ WITH objectivelist AS (
+ SELECT DISTINCT oid FROM aros_to_delete
+ EXCEPT
+ SELECT id FROM deleted_objectives
+ )
+ SELECT
+ o.id oid,
+ BOOL_OR(ar.id IS NOT NULL AND ar."calculatedStatus" = 'approved') on_approved_ar,
+ BOOL_OR(ar.id IS NOT NULL) on_ar
+ FROM objectivelist ol
+ JOIN "Objectives" o
+ ON ol.oid = o.id
+ LEFT JOIN "ActivityReportObjectives" aro
+ ON o.id = aro."objectiveId"
+ LEFT JOIN "ActivityReports" ar
+ ON aro."activityReportId" = ar.id
+ AND ar."calculatedStatus" != 'deleted'
+ GROUP BY 1
+ ;
+ -- 2. Calculate correct onApprovedAR values for goals
+ DROP TABLE IF EXISTS goals_on_ars;
+ CREATE TEMP TABLE goals_on_ars
+ AS
+ WITH goallist AS (
+ SELECT DISTINCT gid FROM args_to_delete
+ EXCEPT
+ SELECT id FROM deleted_goals
+ )
+ SELECT
+ g.id gid,
+ BOOL_OR(
+ (ar.id IS NOT NULL AND ar."calculatedStatus" = 'approved')
+ OR
+ COALESCE(ooaa.on_approved_ar,FALSE)
+ ) on_approved_ar,
+ BOOL_OR(ar.id IS NOT NULL OR COALESCE(ooaa.on_ar,FALSE)) on_ar
+ FROM goallist gl
+ JOIN "Goals" g
+ ON g.id = gl.gid
+ LEFT JOIN "ActivityReportGoals" arg
+ ON g.id = arg."goalId"
+ LEFT JOIN "ActivityReports" ar
+ ON arg."activityReportId" = ar.id
+ AND ar."calculatedStatus" != 'deleted'
+ LEFT JOIN "Objectives" o
+ ON o."goalId" = g.id
+ LEFT JOIN objectives_on_ars ooaa
+ ON ooaa.oid = o.id
+ GROUP BY 1
+ ;
+ -- 3. Calculate onApprovedAR stats for objectives
+ DROP TABLE IF EXISTS initial_obj_approved_ar_stats;
+ CREATE TEMP TABLE initial_obj_approved_ar_stats
+ AS
+ SELECT
+ COUNT(*) FILTER (WHERE on_approved_ar = "onApprovedAR"
+ ) matching_values,
+ COUNT(*) FILTER (WHERE "onApprovedAR" IS NOT NULL AND on_approved_ar != "onApprovedAR"
+ ) incorrect_values,
+ COUNT(*) FILTER (WHERE on_approved_ar AND (NOT "onApprovedAR" OR "onApprovedAR" IS NULL)
+ ) should_be_marked_true_but_isnt,
+ COUNT(*) FILTER (WHERE NOT on_approved_ar AND ("onApprovedAR" OR "onApprovedAR" IS NULL)
+ ) marked_true_but_shouldnt_be,
+ COUNT(*) total_objectives
+ FROM "Objectives" o
+ JOIN objectives_on_ars
+ ON o.id = oid
+ ;
+ -- 4. Calculate onAR stats for objectives
+ DROP TABLE IF EXISTS initial_obj_onar_stats;
+ CREATE TEMP TABLE initial_obj_onar_stats
+ AS
+ SELECT
+ COUNT(*) FILTER (WHERE on_ar = "onAR"
+ ) matching_values,
+ COUNT(*) FILTER (WHERE "onAR" IS NOT NULL AND on_ar != "onAR"
+ ) incorrect_values,
+ COUNT(*) FILTER (WHERE on_ar AND (NOT "onAR" OR "onAR" IS NULL)
+ ) should_be_marked_true_but_isnt,
+ COUNT(*) FILTER (WHERE NOT on_ar AND ("onAR" OR "onAR" IS NULL)
+ ) marked_true_but_shouldnt_be,
+ COUNT(*) total_objectives
+ FROM "Objectives" o
+ JOIN objectives_on_ars
+ ON o.id = oid
+ ;
+ -- 5. Calculate onApprovedAR stats for goals
+ DROP TABLE IF EXISTS initial_goal_approved_ar_stats;
+ CREATE TEMP TABLE initial_goal_approved_ar_stats
+ AS
+ SELECT
+ COUNT(*) FILTER (WHERE on_approved_ar = "onApprovedAR"
+ ) matching_values,
+ COUNT(*) FILTER (WHERE "onApprovedAR" IS NOT NULL AND on_approved_ar != "onApprovedAR"
+ ) incorrect_values,
+ COUNT(*) FILTER (WHERE on_approved_ar AND (NOT "onApprovedAR" OR "onApprovedAR" IS NULL)
+ ) should_be_marked_true_but_isnt,
+ COUNT(*) FILTER (WHERE NOT on_approved_ar AND ("onApprovedAR" OR "onApprovedAR" IS NULL)
+ ) marked_true_but_shouldnt_be,
+ COUNT(*) total_goals
+ FROM "Goals" g
+ JOIN goals_on_ars
+ ON g.id = gid
+ ;
+ -- 6. Calculate onAR stats for goals
+ DROP TABLE IF EXISTS initial_goal_onar_stats;
+ CREATE TEMP TABLE initial_goal_onar_stats
+ AS
+ SELECT
+ COUNT(*) FILTER (WHERE on_ar = "onAR"
+ ) matching_values,
+ COUNT(*) FILTER (WHERE "onAR" IS NOT NULL AND on_ar != "onAR"
+ ) incorrect_values,
+ COUNT(*) FILTER (WHERE on_ar AND (NOT "onAR" OR "onAR" IS NULL)
+ ) should_be_marked_true_but_isnt,
+ COUNT(*) FILTER (WHERE NOT on_ar AND ("onAR" OR "onAR" IS NULL)
+ ) marked_true_but_shouldnt_be,
+ COUNT(*) total_goals
+ FROM "Goals" g
+ JOIN goals_on_ars
+ ON g.id = gid
+ ;
+ -- 7. Update onApprovedAR values for objectives and save the results
+ DROP TABLE IF EXISTS corrected_approved_objectives;
+ CREATE TEMP TABLE corrected_approved_objectives
+ AS
+ WITH updater AS (
+ UPDATE "Objectives" o
+ SET "onApprovedAR" = on_approved_ar
+ FROM objectives_on_ars
+ WHERE o.id = oid
+ AND ("onApprovedAR" != on_approved_ar OR "onApprovedAR" IS NULL)
+ RETURNING
+ oid,
+ on_approved_ar
+ ) SELECT * FROM updater
+ ;
+ -- 8. Update onAR values for objectives and save the results
+ DROP TABLE IF EXISTS corrected_onar_objectives;
+ CREATE TEMP TABLE corrected_onar_objectives
+ AS
+ WITH updater AS (
+ UPDATE "Objectives" o
+ SET "onAR" = on_ar
+ FROM objectives_on_ars
+ WHERE o.id = oid
+ AND ("onAR" != on_ar OR "onAR" IS NULL)
+ RETURNING
+ oid,
+ on_ar
+ ) SELECT * FROM updater
+ ;
+ -- 9. Update onApprovedAR values for goals and save the results
+ DROP TABLE IF EXISTS corrected_approved_goals;
+ CREATE TEMP TABLE corrected_approved_goals
+ AS
+ WITH updater AS (
+ UPDATE "Goals" g
+ SET "onApprovedAR" = on_approved_ar
+ FROM goals_on_ars
+ WHERE g.id = gid
+ AND ("onApprovedAR" != on_approved_ar OR "onApprovedAR" IS NULL)
+ RETURNING
+ gid,
+ on_approved_ar
+ ) SELECT * FROM updater
+ ;
+ -- 10. Update onAR values for goals and save the results
+ DROP TABLE IF EXISTS corrected_onar_goals;
+ CREATE TEMP TABLE corrected_onar_goals
+ AS
+ WITH updater AS (
+ UPDATE "Goals" g
+ SET "onAR" = on_ar
+ FROM goals_on_ars
+ WHERE g.id = gid
+ AND ("onAR" != on_ar OR "onAR" IS NULL)
+ RETURNING
+ gid,
+ on_ar
+ ) SELECT * FROM updater
+ ;
+ -- produce stats on what happened
+ -- 11. Final onApprovedAR stats for objectives
+ DROP TABLE IF EXISTS final_obj_approved_ar_stats;
+ CREATE TEMP TABLE final_obj_approved_ar_stats
+ AS
+ SELECT
+ COUNT(*) FILTER (WHERE on_approved_ar = "onApprovedAR"
+ ) matching_values,
+ COUNT(*) FILTER (WHERE "onApprovedAR" IS NOT NULL AND on_approved_ar != "onApprovedAR"
+ ) incorrect_values,
+ COUNT(*) FILTER (WHERE on_approved_ar AND (NOT "onApprovedAR" OR "onApprovedAR" IS NULL)
+ ) should_be_marked_true_but_isnt,
+ COUNT(*) FILTER (WHERE NOT on_approved_ar AND ("onApprovedAR" OR "onApprovedAR" IS NULL)
+ ) marked_true_but_shouldnt_be,
+ COUNT(*) total_objectives
+ FROM "Objectives" o
+ JOIN objectives_on_ars
+ ON o.id = oid
+ ;
+ -- 12. Final onAR stats for objectives
+ DROP TABLE IF EXISTS final_obj_onar_stats;
+ CREATE TEMP TABLE final_obj_onar_stats
+ AS
+ SELECT
+ COUNT(*) FILTER (WHERE on_ar = "onAR"
+ ) matching_values,
+ COUNT(*) FILTER (WHERE "onAR" IS NOT NULL AND on_ar != "onAR"
+ ) incorrect_values,
+ COUNT(*) FILTER (WHERE on_ar AND (NOT "onAR" OR "onAR" IS NULL)
+ ) should_be_marked_true_but_isnt,
+ COUNT(*) FILTER (WHERE NOT on_ar AND ("onAR" OR "onAR" IS NULL)
+ ) marked_true_but_shouldnt_be,
+ COUNT(*) total_objectives
+ FROM "Objectives" o
+ JOIN objectives_on_ars
+ ON o.id = oid
+ ;
+ -- 13. Final onApprovedAR stats for goals
+ DROP TABLE IF EXISTS final_goal_approved_ar_stats;
+ CREATE TEMP TABLE final_goal_approved_ar_stats
+ AS
+ SELECT
+ COUNT(*) FILTER (WHERE on_approved_ar = "onApprovedAR"
+ ) matching_values,
+ COUNT(*) FILTER (WHERE "onApprovedAR" IS NOT NULL AND on_approved_ar != "onApprovedAR"
+ ) incorrect_values,
+ COUNT(*) FILTER (WHERE on_approved_ar AND (NOT "onApprovedAR" OR "onApprovedAR" IS NULL)
+ ) should_be_marked_true_but_isnt,
+ COUNT(*) FILTER (WHERE NOT on_approved_ar AND ("onApprovedAR" OR "onApprovedAR" IS NULL)
+ ) marked_true_but_shouldnt_be,
+ COUNT(*) total_goals
+ FROM "Goals" g
+ JOIN goals_on_ars
+ ON g.id = gid
+ ;
+ -- 14. Final onAR stats for goals
+ DROP TABLE IF EXISTS final_goal_onar_stats;
+ CREATE TEMP TABLE final_goal_onar_stats
+ AS
+ SELECT
+ COUNT(*) FILTER (WHERE on_ar = "onAR"
+ ) matching_values,
+ COUNT(*) FILTER (WHERE "onAR" IS NOT NULL AND on_ar != "onAR"
+ ) incorrect_values,
+ COUNT(*) FILTER (WHERE on_ar AND (NOT "onAR" OR "onAR" IS NULL)
+ ) should_be_marked_true_but_isnt,
+ COUNT(*) FILTER (WHERE NOT on_ar AND ("onAR" OR "onAR" IS NULL)
+ ) marked_true_but_shouldnt_be,
+ COUNT(*) total_goals
+ FROM "Goals" g
+ JOIN goals_on_ars
+ ON g.id = gid
+ ;
+ -- make a nice little table to see the math
+ SELECT
+ 1 AS order,
+ 'objective onApprovedAR starting stats' description,
+ matching_values,
+ incorrect_values,
+ should_be_marked_true_but_isnt,
+ marked_true_but_shouldnt_be,
+ total_objectives total
+ FROM initial_obj_approved_ar_stats
+ UNION
+ SELECT
+ 2,
+ 'objective onApprovedAR values changed',
+ NULL,
+ NULL,
+ SUM(CASE WHEN on_approved_ar THEN 1 ELSE 0 END),
+ SUM(CASE WHEN NOT on_approved_ar THEN 1 ELSE 0 END),
+ COUNT(*)
+ FROM corrected_approved_objectives
+ UNION
+ SELECT 3,'objective onApprovedAR ending stats', * FROM final_obj_approved_ar_stats
+ UNION
+ SELECT 4,'objective onAR starting stats', * FROM initial_obj_onar_stats
+ UNION
+ SELECT
+ 5,
+ 'objective onAR values changed',
+ NULL,
+ NULL,
+ SUM(CASE WHEN on_ar THEN 1 ELSE 0 END),
+ SUM(CASE WHEN NOT on_ar THEN 1 ELSE 0 END),
+ COUNT(*)
+ FROM corrected_onar_objectives
+ UNION
+ SELECT 6,'objective onAR ending stats', * FROM final_obj_onar_stats
+ UNION
+ SELECT 7,'goal onApprovedAR starting stats', * FROM initial_goal_approved_ar_stats
+ UNION
+ SELECT
+ 8,
+ 'goal onApprovedAR values changed',
+ NULL,
+ NULL,
+ SUM(CASE WHEN on_approved_ar THEN 1 ELSE 0 END),
+ SUM(CASE WHEN NOT on_approved_ar THEN 1 ELSE 0 END),
+ COUNT(*)
+ FROM corrected_approved_goals
+ UNION
+ SELECT 9,'goal onApprovedAR ending stats', * FROM final_goal_approved_ar_stats
+ UNION
+ SELECT 10,'goal onAR starting stats', * FROM initial_goal_onar_stats
+ UNION
+ SELECT
+ 11,
+ 'goal onAR values changed',
+ NULL,
+ NULL,
+ SUM(CASE WHEN on_ar THEN 1 ELSE 0 END),
+ SUM(CASE WHEN NOT on_ar THEN 1 ELSE 0 END),
+ COUNT(*)
+ FROM corrected_onar_goals
+ UNION
+ SELECT 12,'goal onAR ending stats', * FROM final_goal_onar_stats
+ ORDER BY 1
+ ;
+
`, { transaction });
});
},
From c9fa7c5773c87194e79b9680a81ee4a8202bd58c Mon Sep 17 00:00:00 2001
From: Nathan Powell
Date: Mon, 8 Jul 2024 09:12:12 -0700
Subject: [PATCH 19/26] push migration date later
---
...240708000000-remove_national_center_ars.js | 917 ++++++++++++++++++
1 file changed, 917 insertions(+)
create mode 100644 src/migrations/20240708000000-remove_national_center_ars.js
diff --git a/src/migrations/20240708000000-remove_national_center_ars.js b/src/migrations/20240708000000-remove_national_center_ars.js
new file mode 100644
index 0000000000..c4dbc9863e
--- /dev/null
+++ b/src/migrations/20240708000000-remove_national_center_ars.js
@@ -0,0 +1,917 @@
+const {
+ prepMigration,
+} = require('../lib/migration');
+
+/** @type {import('sequelize-cli').Migration} */
+module.exports = {
+ async up(queryInterface) {
+ await queryInterface.sequelize.transaction(async (transaction) => {
+ const sessionSig = __filename;
+ await prepMigration(queryInterface, transaction, sessionSig);
+
+ await queryInterface.sequelize.query(`
+ ---------------------------------------------------
+ -- NOTE:
+ -- Files and Resources are most properly managed by
+ -- maintenance jobs, so this and similar migrations
+ -- won't delete them directly. Deleting the link
+ -- records will give the maintenance job the info
+ -- it needs to perform its housekeeping.
+ ---------------------------------------------------
+ -------- Deleting unwanted ARs --------
+ -- Create the AR deletion list
+ -- Remove AR link records: -------------
+ -- ActivityRecipients
+ -- ActivityReportApprovers
+ -- ActivityReportCollaborators
+ -- ActivityReportFiles (no need to remove Files)
+ -- ActivityReportResources (no need to remove Resources)
+
+ -- Create the NextSteps deletion list
+ -- Remove NextSteps link records: -------------
+ -- NextStepResources
+ -- remove NextSteps -------------
+
+ -- Create the ARO deletion list
+ -- Remove ARO link records: -------------
+ -- ActivityReportObjectiveFiles
+ -- ActivityReportObjectiveResources
+ -- ActivityReportObjectiveTopics
+ -- ActivityReportObjectiveCourses
+ -- remove AROs -------------------
+
+ -- Create the orphaned Objective deletion list
+ -- Remove Objective link records: -------------
+ -- Delete ObjectiveCollaborators
+ -- remove Objectives -------------
+
+ -- Create the ARG deletion list
+ -- Remove ARG link records: -------------
+ -- ActivityReportGoalFieldResponses
+ -- ActivityReportGoalResources
+ -- remove ARGs -------------------
+
+ -- Create the orphaned Goal deletions list
+ -- ( check if isFromSmartsheetTtaPlan, isRttapa)
+ -- Remove Goal link records: -------------
+ -- EventReportPilotGoals
+ -- GoalFieldResponses
+ -- GoalResources
+ -- remove Goals ------------------
+
+ -- Create the orphaned ObjectiveTemplate deletion list
+ -- Create the orphaned GoalTemplate deletion list
+ -- Remove GoalTemplate link records: -------------
+ -- GoalTemplateObjectiveTemplates
+ -- Remove ObjectiveTemplates --------
+ -- Remove GoalTemplates -------------
+
+ -- Remove ARs -----------------------
+
+ -- Test query
+
+ -- Correct the onApprovedAR and onAR values for the goals
+ -- and objectives that were not deleted
+
+ -------------------------------------------------------------------------------------------------------------------
+ -------- Deleting unwanted ARs --------
+ -- Create the AR deletion list
+ DROP TABLE IF EXISTS ars_to_delete;
+ CREATE TEMP TABLE ars_to_delete
+ AS
+ SELECT id arid
+ FROM "ActivityReports"
+ WHERE id IN (24998, 24645, 24297, 24122, 27517, 30829, 29864, 6442, 23057, 23718, 25205, 25792, 25577, 25573, 26478, 26210, 27117, 26918, 28451, 28117, 27669, 29542, 29101, 29024, 30137, 29762, 31201)
+ AND "regionId" = 10
+ ;
+
+ -- Remove AR link records: -------------
+ DROP TABLE IF EXISTS deleted_activityrecipients;
+ CREATE TEMP TABLE deleted_activityrecipients AS
+ WITH deletes AS (
+ DELETE FROM "ActivityRecipients"
+ USING ars_to_delete
+ WHERE "activityReportId" = arid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+ DROP TABLE IF EXISTS deleted_activityreportapprovers;
+ CREATE TEMP TABLE deleted_activityreportapprovers AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReportApprovers"
+ USING ars_to_delete
+ WHERE "activityReportId" = arid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+ DROP TABLE IF EXISTS deleted_activityreportcollaborators;
+ CREATE TEMP TABLE deleted_activityreportcollaborators AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReportCollaborators"
+ USING ars_to_delete
+ WHERE "activityReportId" = arid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+ DROP TABLE IF EXISTS deleted_activityreportfiles;
+ CREATE TEMP TABLE deleted_activityreportfiles AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReportFiles"
+ USING ars_to_delete
+ WHERE "activityReportId" = arid
+ RETURNING
+ id,
+ "fileId" fid
+ )
+ SELECT id, fid FROM deletes
+ ;
+ DROP TABLE IF EXISTS deleted_activityreportresources;
+ CREATE TEMP TABLE deleted_activityreportresources AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReportResources"
+ USING ars_to_delete
+ WHERE "activityReportId" = arid
+ RETURNING
+ id,
+ "resourceId" resourceid
+ )
+ SELECT id, resourceid FROM deletes
+ ;
+
+
+
+ -- Create the NextSteps deletion list
+ DROP TABLE IF EXISTS nextsteps_to_delete;
+ CREATE TEMP TABLE nextsteps_to_delete
+ AS
+ SELECT
+ id nsid
+ FROM "NextSteps"
+ JOIN ars_to_delete
+ ON "activityReportId" = arid
+ ;
+ -- Remove NextSteps link records: -------------
+ DROP TABLE IF EXISTS deleted_nextstepresources;
+ CREATE TEMP TABLE deleted_nextstepresources AS
+ WITH deletes AS (
+ DELETE FROM "NextStepResources"
+ USING nextsteps_to_delete
+ WHERE "nextStepId" = nsid
+ RETURNING
+ id,
+ "resourceId" resourceid
+ )
+ SELECT id, resourceid FROM deletes
+ ;
+ -- remove NextSteps -------------
+ DROP TABLE IF EXISTS deleted_nextsteps;
+ CREATE TEMP TABLE deleted_nextsteps AS
+ WITH deletes AS (
+ DELETE FROM "NextSteps"
+ USING nextsteps_to_delete
+ WHERE id = nsid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+
+
+ -- Create the ARO deletion list
+ DROP TABLE IF EXISTS aros_to_delete;
+ CREATE TEMP TABLE aros_to_delete
+ AS
+ SELECT
+ id aroid,
+ "objectiveId" oid
+ FROM "ActivityReportObjectives"
+ JOIN ars_to_delete
+ ON "activityReportId" = arid
+ ;
+ -- Remove ARO link records: -------------
+ DROP TABLE IF EXISTS deleted_activityreportobjectivefiles;
+ CREATE TEMP TABLE deleted_activityreportobjectivefiles AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReportObjectiveFiles"
+ USING aros_to_delete
+ WHERE "activityReportObjectiveId" = aroid
+ RETURNING
+ id,
+ "fileId" fid
+ )
+ SELECT id, fid FROM deletes
+ ;
+ DROP TABLE IF EXISTS deleted_activityreportobjectiveresources;
+ CREATE TEMP TABLE deleted_activityreportobjectiveresources AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReportObjectiveResources"
+ USING aros_to_delete
+ WHERE "activityReportObjectiveId" = aroid
+ RETURNING
+ id,
+ "resourceId" resourceid
+ )
+ SELECT id, resourceid FROM deletes
+ ;
+ DROP TABLE IF EXISTS deleted_activityreportobjectivetopics;
+ CREATE TEMP TABLE deleted_activityreportobjectivetopics AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReportObjectiveTopics"
+ USING aros_to_delete
+ WHERE "activityReportObjectiveId" = aroid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+ DROP TABLE IF EXISTS deleted_activityreportobjectivecourses;
+ CREATE TEMP TABLE deleted_activityreportobjectivecourses AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReportObjectiveCourses"
+ USING aros_to_delete
+ WHERE "activityReportObjectiveId" = aroid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+ -- remove AROs -------------------
+ DROP TABLE IF EXISTS deleted_aros;
+ CREATE TEMP TABLE deleted_aros AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReportObjectives"
+ USING aros_to_delete
+ WHERE id = aroid
+ RETURNING
+ id,
+ "objectiveId" oid
+ )
+ SELECT id, oid FROM deletes
+ ;
+
+ -- Create the orphaned Objective deletion list
+ DROP TABLE IF EXISTS objectives_to_delete;
+ CREATE TEMP TABLE objectives_to_delete
+ AS
+ SELECT DISTINCT oid
+ FROM deleted_aros
+ EXCEPT
+ SELECT DISTINCT "objectiveId"
+ FROM "ActivityReportObjectives"
+ ;
+ -- Remove Objective link records: -------------
+ -- Delete ObjectiveCollaborators
+ DROP TABLE IF EXISTS deleted_objectivecollaborators;
+ CREATE TEMP TABLE deleted_objectivecollaborators AS
+ WITH deletes AS (
+ DELETE FROM "ObjectiveCollaborators"
+ USING objectives_to_delete
+ WHERE "objectiveId" = oid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+
+ -- remove Objectives -------------------
+ DROP TABLE IF EXISTS deleted_objectives;
+ CREATE TEMP TABLE deleted_objectives AS
+ WITH deletes AS (
+ DELETE FROM "Objectives"
+ USING objectives_to_delete
+ WHERE id = oid
+ RETURNING
+ id,
+ "goalId" gid,
+ "objectiveTemplateId" otid
+ )
+ SELECT id, gid, otid FROM deletes
+ ;
+
+ -- Create the ARG deletion list
+ DROP TABLE IF EXISTS args_to_delete;
+ CREATE TEMP TABLE args_to_delete
+ AS
+ SELECT DISTINCT
+ id argid,
+ "goalId" gid
+ FROM "ActivityReportGoals"
+ JOIN ars_to_delete
+ ON "activityReportId" = arid
+ ;
+ -- Remove ARG link records: -------------
+ DROP TABLE IF EXISTS deleted_activityreportgoalfieldresponses;
+ CREATE TEMP TABLE deleted_activityreportgoalfieldresponses AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReportGoalFieldResponses"
+ USING args_to_delete
+ WHERE "activityReportGoalId" = argid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+ DROP TABLE IF EXISTS deleted_activityreportgoalresources;
+ CREATE TEMP TABLE deleted_activityreportgoalresources AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReportGoalResources"
+ USING args_to_delete
+ WHERE "activityReportGoalId" = argid
+ RETURNING
+ id,
+ "resourceId" resourceid
+ )
+ SELECT id, resourceid FROM deletes
+ ;
+ -- remove ARGs -------------------
+ DROP TABLE IF EXISTS deleted_args;
+ CREATE TEMP TABLE deleted_args AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReportGoals"
+ USING args_to_delete
+ WHERE id = argid
+ RETURNING
+ id,
+ "goalId" gid
+ )
+ SELECT id, gid FROM deletes
+ ;
+
+ -- Create the orphaned Goal deletions list
+ DROP TABLE IF EXISTS goals_to_delete;
+ CREATE TEMP TABLE goals_to_delete
+ AS
+ SELECT DISTINCT gid
+ FROM deleted_args dargs
+ JOIN "Goals" g
+ ON gid = g.id
+ WHERE (g."isRttapa" IS NULL OR g."isRttapa" != 'Yes')
+ AND g."isFromSmartsheetTtaPlan" != TRUE
+ AND g."createdVia" != 'merge'
+ EXCEPT
+ SELECT gid
+ FROM (
+ SELECT DISTINCT "goalId" gid
+ FROM "ActivityReportGoals"
+ UNION
+ SELECT DISTINCT "goalId"
+ FROM "Objectives"
+ UNION
+ SELECT DISTINCT "goalId"
+ FROM "EventReportPilotGoals"
+ ) keepers
+ ;
+ -- Remove Goal link records: -------------
+ DROP TABLE IF EXISTS deleted_goalcollaborators;
+ CREATE TEMP TABLE deleted_goalcollaborators AS
+ WITH deletes AS (
+ DELETE FROM "GoalCollaborators"
+ USING goals_to_delete
+ WHERE "goalId" = gid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+ DROP TABLE IF EXISTS deleted_goalfieldresponses;
+ CREATE TEMP TABLE deleted_goalfieldresponses AS
+ WITH deletes AS (
+ DELETE FROM "GoalFieldResponses"
+ USING goals_to_delete
+ WHERE "goalId" = gid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+ DROP TABLE IF EXISTS deleted_goalresources;
+ CREATE TEMP TABLE deleted_goalresources AS
+ WITH deletes AS (
+ DELETE FROM "GoalResources"
+ USING goals_to_delete
+ WHERE "goalId" = gid
+ RETURNING
+ id,
+ "resourceId" resourceid
+ )
+ SELECT id, resourceid FROM deletes
+ ;
+ DROP TABLE IF EXISTS deleted_goalstatuschanges;
+ CREATE TEMP TABLE deleted_goalstatuschanges AS
+ WITH deletes AS (
+ DELETE FROM "GoalStatusChanges"
+ USING goals_to_delete
+ WHERE "goalId" = gid
+ RETURNING
+ id,
+ "goalId" gid
+ )
+ SELECT id, gid FROM deletes
+ ;
+ -- remove Goals -------------------
+ DROP TABLE IF EXISTS deleted_goals;
+ CREATE TEMP TABLE deleted_goals AS
+ WITH deletes AS (
+ DELETE FROM "Goals"
+ USING goals_to_delete
+ WHERE id = gid
+ RETURNING
+ id,
+ "goalTemplateId" gtid
+ )
+ SELECT id, gtid FROM deletes
+ ;
+
+ -- Create the orphaned ObjectiveTemplate deletion list
+ DROP TABLE IF EXISTS ots_to_delete;
+ CREATE TEMP TABLE ots_to_delete
+ AS
+ SELECT DISTINCT otid
+ FROM deleted_objectives
+ EXCEPT
+ SELECT DISTINCT "objectiveTemplateId"
+ FROM "Objectives"
+ ;
+
+ -- Create the orphaned GoalTemplate deletion list
+ DROP TABLE IF EXISTS gts_to_delete;
+ CREATE TEMP TABLE gts_to_delete
+ AS
+ SELECT DISTINCT gtid
+ FROM deleted_goals
+ EXCEPT
+ SELECT DISTINCT "goalTemplateId"
+ FROM "Goals"
+ ;
+ -- Remove GoalTemplate link records: -------------
+ DROP TABLE IF EXISTS deleted_goaltemplateobjectivetemplates;
+ CREATE TEMP TABLE deleted_goaltemplateobjectivetemplates AS
+ WITH unified_deletes AS (
+ SELECT DISTINCT id gtotid
+ FROM "GoalTemplateObjectiveTemplates"
+ JOIN ots_to_delete
+ ON otid = "objectiveTemplateId"
+ UNION
+ SELECT DISTINCT id gtotid
+ FROM "GoalTemplateObjectiveTemplates"
+ JOIN gts_to_delete
+ ON gtid = "goalTemplateId"
+ ),
+ deletes AS (
+ DELETE FROM "GoalTemplateObjectiveTemplates"
+ USING unified_deletes
+ WHERE id = gtotid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+ -- Remove ObjectiveTemplates --------
+ DROP TABLE IF EXISTS deleted_objectivetemplates;
+ CREATE TEMP TABLE deleted_objectivetemplates AS
+ WITH deletes AS (
+ DELETE FROM "ObjectiveTemplates"
+ USING ots_to_delete
+ WHERE id = otid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+ -- Remove GoalTemplates -------------
+ DROP TABLE IF EXISTS deleted_goaltemplates;
+ CREATE TEMP TABLE deleted_goaltemplates AS
+ WITH deletes AS (
+ DELETE FROM "GoalTemplates"
+ USING gts_to_delete
+ WHERE id = gtid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+
+ -- Remove ARs -------------
+ DROP TABLE IF EXISTS deleted_ars;
+ CREATE TEMP TABLE deleted_ars AS
+ WITH deletes AS (
+ DELETE FROM "ActivityReports"
+ USING ars_to_delete
+ WHERE id = arid
+ RETURNING
+ id
+ )
+ SELECT id FROM deletes
+ ;
+
+
+ -- Stats ----------------------------
+ SELECT 1,'ars_to_delete', count(*) FROM ars_to_delete
+ UNION
+ SELECT 2,'deleted_activityreportapprovers', count(*) FROM deleted_activityreportapprovers
+ UNION
+ SELECT 3,'deleted_activityreportcollaborators', count(*) FROM deleted_activityreportcollaborators
+ UNION
+ SELECT 4,'deleted_activityreportfiles', count(*) FROM deleted_activityreportfiles
+ UNION
+ SELECT 5,'deleted_activityreportresources', count(*) FROM deleted_activityreportresources
+ UNION
+ SELECT 6,'nextsteps_to_delete', count(*) FROM nextsteps_to_delete
+ UNION
+ SELECT 7,'deleted_nextstepresources', count(*) FROM deleted_nextstepresources
+ UNION
+ SELECT 8,'deleted_nextsteps', count(*) FROM deleted_nextsteps
+ UNION
+ SELECT 9,'aros_to_delete', count(*) FROM aros_to_delete
+ UNION
+ SELECT 10,'deleted_activityreportobjectivefiles', count(*) FROM deleted_activityreportobjectivefiles
+ UNION
+ SELECT 11,'deleted_activityreportobjectiveresources', count(*) FROM deleted_activityreportobjectiveresources
+ UNION
+ SELECT 12,'deleted_activityreportobjectivetopics', count(*) FROM deleted_activityreportobjectivetopics
+ UNION
+ SELECT 12,'deleted_activityreportobjectivecourses', count(*) FROM deleted_activityreportobjectivetopics
+ UNION
+ SELECT 13,'deleted_aros', count(*) FROM deleted_aros
+ UNION
+ SELECT 14,'objectives_to_delete', count(*) FROM objectives_to_delete
+ UNION
+ SELECT 14,'deleted_objectivecollaborators', count(*) FROM objectives_to_delete
+ UNION
+ SELECT 15,'deleted_objectives', count(*) FROM deleted_objectives
+ UNION
+ SELECT 16,'args_to_delete', count(*) FROM args_to_delete
+ UNION
+ SELECT 17,'deleted_activityreportgoalfieldresponses', count(*) FROM deleted_activityreportgoalfieldresponses
+ UNION
+ SELECT 18,'deleted_activityreportgoalresources', count(*) FROM deleted_activityreportgoalresources
+ UNION
+ SELECT 19,'deleted_args', count(*) FROM deleted_args
+ UNION
+ SELECT 20,'goals_to_delete', count(*) FROM goals_to_delete
+ UNION
+ SELECT 21,'deleted_goalcollaborators', count(*) FROM deleted_goalcollaborators
+ UNION
+ SELECT 22,'deleted_goalfieldresponses', count(*) FROM deleted_goalfieldresponses
+ UNION
+ SELECT 23,'deleted_goalresources', count(*) FROM deleted_goalresources
+ UNION
+ SELECT 24,'deleted_goalstatuschanges', count(*) FROM deleted_goalstatuschanges
+ UNION
+ SELECT 25,'deleted_goals', count(*) FROM deleted_goals
+ UNION
+ SELECT 26,'ots_to_delete', count(*) FROM ots_to_delete
+ UNION
+ SELECT 27,'gts_to_delete', count(*) FROM gts_to_delete
+ UNION
+ SELECT 28,'deleted_goaltemplateobjectivetemplates', count(*) FROM deleted_goaltemplateobjectivetemplates
+ UNION
+ SELECT 29,'deleted_objectivetemplates', count(*) FROM deleted_objectivetemplates
+ UNION
+ SELECT 30,'deleted_goaltemplates', count(*) FROM deleted_goaltemplates
+ UNION
+ SELECT 31,'deleted_ars', count(*) FROM deleted_ars
+ ORDER BY 1
+ ;
+
+ -- Reset the onApprovedAR and onAR values for the goals and objectives that
+ -- were not deleted
+ -- 1. Calculate correct onApprovedAR values for objectives
+ DROP TABLE IF EXISTS objectives_on_ars;
+ CREATE TEMP TABLE objectives_on_ars
+ AS
+ WITH objectivelist AS (
+ SELECT DISTINCT oid FROM aros_to_delete
+ EXCEPT
+ SELECT id FROM deleted_objectives
+ )
+ SELECT
+ o.id oid,
+ BOOL_OR(ar.id IS NOT NULL AND ar."calculatedStatus" = 'approved') on_approved_ar,
+ BOOL_OR(ar.id IS NOT NULL) on_ar
+ FROM objectivelist ol
+ JOIN "Objectives" o
+ ON ol.oid = o.id
+ LEFT JOIN "ActivityReportObjectives" aro
+ ON o.id = aro."objectiveId"
+ LEFT JOIN "ActivityReports" ar
+ ON aro."activityReportId" = ar.id
+ AND ar."calculatedStatus" != 'deleted'
+ GROUP BY 1
+ ;
+ -- 2. Calculate correct onApprovedAR values for goals
+ DROP TABLE IF EXISTS goals_on_ars;
+ CREATE TEMP TABLE goals_on_ars
+ AS
+ WITH goallist AS (
+ SELECT DISTINCT gid FROM args_to_delete
+ EXCEPT
+ SELECT id FROM deleted_goals
+ )
+ SELECT
+ g.id gid,
+ BOOL_OR(
+ (ar.id IS NOT NULL AND ar."calculatedStatus" = 'approved')
+ OR
+ COALESCE(ooaa.on_approved_ar,FALSE)
+ ) on_approved_ar,
+ BOOL_OR(ar.id IS NOT NULL OR COALESCE(ooaa.on_ar,FALSE)) on_ar
+ FROM goallist gl
+ JOIN "Goals" g
+ ON g.id = gl.gid
+ LEFT JOIN "ActivityReportGoals" arg
+ ON g.id = arg."goalId"
+ LEFT JOIN "ActivityReports" ar
+ ON arg."activityReportId" = ar.id
+ AND ar."calculatedStatus" != 'deleted'
+ LEFT JOIN "Objectives" o
+ ON o."goalId" = g.id
+ LEFT JOIN objectives_on_ars ooaa
+ ON ooaa.oid = o.id
+ GROUP BY 1
+ ;
+ -- 3. Calculate onApprovedAR stats for objectives
+ DROP TABLE IF EXISTS initial_obj_approved_ar_stats;
+ CREATE TEMP TABLE initial_obj_approved_ar_stats
+ AS
+ SELECT
+ COUNT(*) FILTER (WHERE on_approved_ar = "onApprovedAR"
+ ) matching_values,
+ COUNT(*) FILTER (WHERE "onApprovedAR" IS NOT NULL AND on_approved_ar != "onApprovedAR"
+ ) incorrect_values,
+ COUNT(*) FILTER (WHERE on_approved_ar AND (NOT "onApprovedAR" OR "onApprovedAR" IS NULL)
+ ) should_be_marked_true_but_isnt,
+ COUNT(*) FILTER (WHERE NOT on_approved_ar AND ("onApprovedAR" OR "onApprovedAR" IS NULL)
+ ) marked_true_but_shouldnt_be,
+ COUNT(*) total_objectives
+ FROM "Objectives" o
+ JOIN objectives_on_ars
+ ON o.id = oid
+ ;
+ -- 4. Calculate onAR stats for objectives
+ DROP TABLE IF EXISTS initial_obj_onar_stats;
+ CREATE TEMP TABLE initial_obj_onar_stats
+ AS
+ SELECT
+ COUNT(*) FILTER (WHERE on_ar = "onAR"
+ ) matching_values,
+ COUNT(*) FILTER (WHERE "onAR" IS NOT NULL AND on_ar != "onAR"
+ ) incorrect_values,
+ COUNT(*) FILTER (WHERE on_ar AND (NOT "onAR" OR "onAR" IS NULL)
+ ) should_be_marked_true_but_isnt,
+ COUNT(*) FILTER (WHERE NOT on_ar AND ("onAR" OR "onAR" IS NULL)
+ ) marked_true_but_shouldnt_be,
+ COUNT(*) total_objectives
+ FROM "Objectives" o
+ JOIN objectives_on_ars
+ ON o.id = oid
+ ;
+ -- 5. Calculate onApprovedAR stats for goals
+ DROP TABLE IF EXISTS initial_goal_approved_ar_stats;
+ CREATE TEMP TABLE initial_goal_approved_ar_stats
+ AS
+ SELECT
+ COUNT(*) FILTER (WHERE on_approved_ar = "onApprovedAR"
+ ) matching_values,
+ COUNT(*) FILTER (WHERE "onApprovedAR" IS NOT NULL AND on_approved_ar != "onApprovedAR"
+ ) incorrect_values,
+ COUNT(*) FILTER (WHERE on_approved_ar AND (NOT "onApprovedAR" OR "onApprovedAR" IS NULL)
+ ) should_be_marked_true_but_isnt,
+ COUNT(*) FILTER (WHERE NOT on_approved_ar AND ("onApprovedAR" OR "onApprovedAR" IS NULL)
+ ) marked_true_but_shouldnt_be,
+ COUNT(*) total_goals
+ FROM "Goals" g
+ JOIN goals_on_ars
+ ON g.id = gid
+ ;
+ -- 6. Calculate onAR stats for goals
+ DROP TABLE IF EXISTS initial_goal_onar_stats;
+ CREATE TEMP TABLE initial_goal_onar_stats
+ AS
+ SELECT
+ COUNT(*) FILTER (WHERE on_ar = "onAR"
+ ) matching_values,
+ COUNT(*) FILTER (WHERE "onAR" IS NOT NULL AND on_ar != "onAR"
+ ) incorrect_values,
+ COUNT(*) FILTER (WHERE on_ar AND (NOT "onAR" OR "onAR" IS NULL)
+ ) should_be_marked_true_but_isnt,
+ COUNT(*) FILTER (WHERE NOT on_ar AND ("onAR" OR "onAR" IS NULL)
+ ) marked_true_but_shouldnt_be,
+ COUNT(*) total_goals
+ FROM "Goals" g
+ JOIN goals_on_ars
+ ON g.id = gid
+ ;
+ -- 7. Update onApprovedAR values for objectives and save the results
+ DROP TABLE IF EXISTS corrected_approved_objectives;
+ CREATE TEMP TABLE corrected_approved_objectives
+ AS
+ WITH updater AS (
+ UPDATE "Objectives" o
+ SET "onApprovedAR" = on_approved_ar
+ FROM objectives_on_ars
+ WHERE o.id = oid
+ AND ("onApprovedAR" != on_approved_ar OR "onApprovedAR" IS NULL)
+ RETURNING
+ oid,
+ on_approved_ar
+ ) SELECT * FROM updater
+ ;
+ -- 8. Update onAR values for objectives and save the results
+ DROP TABLE IF EXISTS corrected_onar_objectives;
+ CREATE TEMP TABLE corrected_onar_objectives
+ AS
+ WITH updater AS (
+ UPDATE "Objectives" o
+ SET "onAR" = on_ar
+ FROM objectives_on_ars
+ WHERE o.id = oid
+ AND ("onAR" != on_ar OR "onAR" IS NULL)
+ RETURNING
+ oid,
+ on_ar
+ ) SELECT * FROM updater
+ ;
+ -- 9. Update onApprovedAR values for goals and save the results
+ DROP TABLE IF EXISTS corrected_approved_goals;
+ CREATE TEMP TABLE corrected_approved_goals
+ AS
+ WITH updater AS (
+ UPDATE "Goals" g
+ SET "onApprovedAR" = on_approved_ar
+ FROM goals_on_ars
+ WHERE g.id = gid
+ AND ("onApprovedAR" != on_approved_ar OR "onApprovedAR" IS NULL)
+ RETURNING
+ gid,
+ on_approved_ar
+ ) SELECT * FROM updater
+ ;
+ -- 10. Update onAR values for goals and save the results
+ DROP TABLE IF EXISTS corrected_onar_goals;
+ CREATE TEMP TABLE corrected_onar_goals
+ AS
+ WITH updater AS (
+ UPDATE "Goals" g
+ SET "onAR" = on_ar
+ FROM goals_on_ars
+ WHERE g.id = gid
+ AND ("onAR" != on_ar OR "onAR" IS NULL)
+ RETURNING
+ gid,
+ on_ar
+ ) SELECT * FROM updater
+ ;
+ -- produce stats on what happened
+ -- 11. Final onApprovedAR stats for objectives
+ DROP TABLE IF EXISTS final_obj_approved_ar_stats;
+ CREATE TEMP TABLE final_obj_approved_ar_stats
+ AS
+ SELECT
+ COUNT(*) FILTER (WHERE on_approved_ar = "onApprovedAR"
+ ) matching_values,
+ COUNT(*) FILTER (WHERE "onApprovedAR" IS NOT NULL AND on_approved_ar != "onApprovedAR"
+ ) incorrect_values,
+ COUNT(*) FILTER (WHERE on_approved_ar AND (NOT "onApprovedAR" OR "onApprovedAR" IS NULL)
+ ) should_be_marked_true_but_isnt,
+ COUNT(*) FILTER (WHERE NOT on_approved_ar AND ("onApprovedAR" OR "onApprovedAR" IS NULL)
+ ) marked_true_but_shouldnt_be,
+ COUNT(*) total_objectives
+ FROM "Objectives" o
+ JOIN objectives_on_ars
+ ON o.id = oid
+ ;
+ -- 12. Final onAR stats for objectives
+ DROP TABLE IF EXISTS final_obj_onar_stats;
+ CREATE TEMP TABLE final_obj_onar_stats
+ AS
+ SELECT
+ COUNT(*) FILTER (WHERE on_ar = "onAR"
+ ) matching_values,
+ COUNT(*) FILTER (WHERE "onAR" IS NOT NULL AND on_ar != "onAR"
+ ) incorrect_values,
+ COUNT(*) FILTER (WHERE on_ar AND (NOT "onAR" OR "onAR" IS NULL)
+ ) should_be_marked_true_but_isnt,
+ COUNT(*) FILTER (WHERE NOT on_ar AND ("onAR" OR "onAR" IS NULL)
+ ) marked_true_but_shouldnt_be,
+ COUNT(*) total_objectives
+ FROM "Objectives" o
+ JOIN objectives_on_ars
+ ON o.id = oid
+ ;
+ -- 13. Final onApprovedAR stats for goals
+ DROP TABLE IF EXISTS final_goal_approved_ar_stats;
+ CREATE TEMP TABLE final_goal_approved_ar_stats
+ AS
+ SELECT
+ COUNT(*) FILTER (WHERE on_approved_ar = "onApprovedAR"
+ ) matching_values,
+ COUNT(*) FILTER (WHERE "onApprovedAR" IS NOT NULL AND on_approved_ar != "onApprovedAR"
+ ) incorrect_values,
+ COUNT(*) FILTER (WHERE on_approved_ar AND (NOT "onApprovedAR" OR "onApprovedAR" IS NULL)
+ ) should_be_marked_true_but_isnt,
+ COUNT(*) FILTER (WHERE NOT on_approved_ar AND ("onApprovedAR" OR "onApprovedAR" IS NULL)
+ ) marked_true_but_shouldnt_be,
+ COUNT(*) total_goals
+ FROM "Goals" g
+ JOIN goals_on_ars
+ ON g.id = gid
+ ;
+ -- 14. Final onAR stats for goals
+ DROP TABLE IF EXISTS final_goal_onar_stats;
+ CREATE TEMP TABLE final_goal_onar_stats
+ AS
+ SELECT
+ COUNT(*) FILTER (WHERE on_ar = "onAR"
+ ) matching_values,
+ COUNT(*) FILTER (WHERE "onAR" IS NOT NULL AND on_ar != "onAR"
+ ) incorrect_values,
+ COUNT(*) FILTER (WHERE on_ar AND (NOT "onAR" OR "onAR" IS NULL)
+ ) should_be_marked_true_but_isnt,
+ COUNT(*) FILTER (WHERE NOT on_ar AND ("onAR" OR "onAR" IS NULL)
+ ) marked_true_but_shouldnt_be,
+ COUNT(*) total_goals
+ FROM "Goals" g
+ JOIN goals_on_ars
+ ON g.id = gid
+ ;
+ -- make a nice little table to see the math
+ SELECT
+ 1 AS order,
+ 'objective onApprovedAR starting stats' description,
+ matching_values,
+ incorrect_values,
+ should_be_marked_true_but_isnt,
+ marked_true_but_shouldnt_be,
+ total_objectives total
+ FROM initial_obj_approved_ar_stats
+ UNION
+ SELECT
+ 2,
+ 'objective onApprovedAR values changed',
+ NULL,
+ NULL,
+ SUM(CASE WHEN on_approved_ar THEN 1 ELSE 0 END),
+ SUM(CASE WHEN NOT on_approved_ar THEN 1 ELSE 0 END),
+ COUNT(*)
+ FROM corrected_approved_objectives
+ UNION
+ SELECT 3,'objective onApprovedAR ending stats', * FROM final_obj_approved_ar_stats
+ UNION
+ SELECT 4,'objective onAR starting stats', * FROM initial_obj_onar_stats
+ UNION
+ SELECT
+ 5,
+ 'objective onAR values changed',
+ NULL,
+ NULL,
+ SUM(CASE WHEN on_ar THEN 1 ELSE 0 END),
+ SUM(CASE WHEN NOT on_ar THEN 1 ELSE 0 END),
+ COUNT(*)
+ FROM corrected_onar_objectives
+ UNION
+ SELECT 6,'objective onAR ending stats', * FROM final_obj_onar_stats
+ UNION
+ SELECT 7,'goal onApprovedAR starting stats', * FROM initial_goal_approved_ar_stats
+ UNION
+ SELECT
+ 8,
+ 'goal onApprovedAR values changed',
+ NULL,
+ NULL,
+ SUM(CASE WHEN on_approved_ar THEN 1 ELSE 0 END),
+ SUM(CASE WHEN NOT on_approved_ar THEN 1 ELSE 0 END),
+ COUNT(*)
+ FROM corrected_approved_goals
+ UNION
+ SELECT 9,'goal onApprovedAR ending stats', * FROM final_goal_approved_ar_stats
+ UNION
+ SELECT 10,'goal onAR starting stats', * FROM initial_goal_onar_stats
+ UNION
+ SELECT
+ 11,
+ 'goal onAR values changed',
+ NULL,
+ NULL,
+ SUM(CASE WHEN on_ar THEN 1 ELSE 0 END),
+ SUM(CASE WHEN NOT on_ar THEN 1 ELSE 0 END),
+ COUNT(*)
+ FROM corrected_onar_goals
+ UNION
+ SELECT 12,'goal onAR ending stats', * FROM final_goal_onar_stats
+ ORDER BY 1
+ ;
+
+ `, { transaction });
+ });
+ },
+
+ down: async () => {
+ },
+};
From 441d1f843c893e389c751af74c7b28804e72feb3 Mon Sep 17 00:00:00 2001
From: Nathan Powell
Date: Mon, 8 Jul 2024 09:43:11 -0700
Subject: [PATCH 20/26] push migration date later
---
...240702000000-remove_national_center_ars.js | 917 ------------------
1 file changed, 917 deletions(-)
delete mode 100644 src/migrations/20240702000000-remove_national_center_ars.js
diff --git a/src/migrations/20240702000000-remove_national_center_ars.js b/src/migrations/20240702000000-remove_national_center_ars.js
deleted file mode 100644
index c4dbc9863e..0000000000
--- a/src/migrations/20240702000000-remove_national_center_ars.js
+++ /dev/null
@@ -1,917 +0,0 @@
-const {
- prepMigration,
-} = require('../lib/migration');
-
-/** @type {import('sequelize-cli').Migration} */
-module.exports = {
- async up(queryInterface) {
- await queryInterface.sequelize.transaction(async (transaction) => {
- const sessionSig = __filename;
- await prepMigration(queryInterface, transaction, sessionSig);
-
- await queryInterface.sequelize.query(`
- ---------------------------------------------------
- -- NOTE:
- -- Files and Resources are most properly managed by
- -- maintenance jobs, so this and similar migrations
- -- won't delete them directly. Deleting the link
- -- records will give the maintenance job the info
- -- it needs to perform its housekeeping.
- ---------------------------------------------------
- -------- Deleting unwanted ARs --------
- -- Create the AR deletion list
- -- Remove AR link records: -------------
- -- ActivityRecipients
- -- ActivityReportApprovers
- -- ActivityReportCollaborators
- -- ActivityReportFiles (no need to remove Files)
- -- ActivityReportResources (no need to remove Resources)
-
- -- Create the NextSteps deletion list
- -- Remove NextSteps link records: -------------
- -- NextStepResources
- -- remove NextSteps -------------
-
- -- Create the ARO deletion list
- -- Remove ARO link records: -------------
- -- ActivityReportObjectiveFiles
- -- ActivityReportObjectiveResources
- -- ActivityReportObjectiveTopics
- -- ActivityReportObjectiveCourses
- -- remove AROs -------------------
-
- -- Create the orphaned Objective deletion list
- -- Remove Objective link records: -------------
- -- Delete ObjectiveCollaborators
- -- remove Objectives -------------
-
- -- Create the ARG deletion list
- -- Remove ARG link records: -------------
- -- ActivityReportGoalFieldResponses
- -- ActivityReportGoalResources
- -- remove ARGs -------------------
-
- -- Create the orphaned Goal deletions list
- -- ( check if isFromSmartsheetTtaPlan, isRttapa)
- -- Remove Goal link records: -------------
- -- EventReportPilotGoals
- -- GoalFieldResponses
- -- GoalResources
- -- remove Goals ------------------
-
- -- Create the orphaned ObjectiveTemplate deletion list
- -- Create the orphaned GoalTemplate deletion list
- -- Remove GoalTemplate link records: -------------
- -- GoalTemplateObjectiveTemplates
- -- Remove ObjectiveTemplates --------
- -- Remove GoalTemplates -------------
-
- -- Remove ARs -----------------------
-
- -- Test query
-
- -- Correct the onApprovedAR and onAR values for the goals
- -- and objectives that were not deleted
-
- -------------------------------------------------------------------------------------------------------------------
- -------- Deleting unwanted ARs --------
- -- Create the AR deletion list
- DROP TABLE IF EXISTS ars_to_delete;
- CREATE TEMP TABLE ars_to_delete
- AS
- SELECT id arid
- FROM "ActivityReports"
- WHERE id IN (24998, 24645, 24297, 24122, 27517, 30829, 29864, 6442, 23057, 23718, 25205, 25792, 25577, 25573, 26478, 26210, 27117, 26918, 28451, 28117, 27669, 29542, 29101, 29024, 30137, 29762, 31201)
- AND "regionId" = 10
- ;
-
- -- Remove AR link records: -------------
- DROP TABLE IF EXISTS deleted_activityrecipients;
- CREATE TEMP TABLE deleted_activityrecipients AS
- WITH deletes AS (
- DELETE FROM "ActivityRecipients"
- USING ars_to_delete
- WHERE "activityReportId" = arid
- RETURNING
- id
- )
- SELECT id FROM deletes
- ;
- DROP TABLE IF EXISTS deleted_activityreportapprovers;
- CREATE TEMP TABLE deleted_activityreportapprovers AS
- WITH deletes AS (
- DELETE FROM "ActivityReportApprovers"
- USING ars_to_delete
- WHERE "activityReportId" = arid
- RETURNING
- id
- )
- SELECT id FROM deletes
- ;
- DROP TABLE IF EXISTS deleted_activityreportcollaborators;
- CREATE TEMP TABLE deleted_activityreportcollaborators AS
- WITH deletes AS (
- DELETE FROM "ActivityReportCollaborators"
- USING ars_to_delete
- WHERE "activityReportId" = arid
- RETURNING
- id
- )
- SELECT id FROM deletes
- ;
- DROP TABLE IF EXISTS deleted_activityreportfiles;
- CREATE TEMP TABLE deleted_activityreportfiles AS
- WITH deletes AS (
- DELETE FROM "ActivityReportFiles"
- USING ars_to_delete
- WHERE "activityReportId" = arid
- RETURNING
- id,
- "fileId" fid
- )
- SELECT id, fid FROM deletes
- ;
- DROP TABLE IF EXISTS deleted_activityreportresources;
- CREATE TEMP TABLE deleted_activityreportresources AS
- WITH deletes AS (
- DELETE FROM "ActivityReportResources"
- USING ars_to_delete
- WHERE "activityReportId" = arid
- RETURNING
- id,
- "resourceId" resourceid
- )
- SELECT id, resourceid FROM deletes
- ;
-
-
-
- -- Create the NextSteps deletion list
- DROP TABLE IF EXISTS nextsteps_to_delete;
- CREATE TEMP TABLE nextsteps_to_delete
- AS
- SELECT
- id nsid
- FROM "NextSteps"
- JOIN ars_to_delete
- ON "activityReportId" = arid
- ;
- -- Remove NextSteps link records: -------------
- DROP TABLE IF EXISTS deleted_nextstepresources;
- CREATE TEMP TABLE deleted_nextstepresources AS
- WITH deletes AS (
- DELETE FROM "NextStepResources"
- USING nextsteps_to_delete
- WHERE "nextStepId" = nsid
- RETURNING
- id,
- "resourceId" resourceid
- )
- SELECT id, resourceid FROM deletes
- ;
- -- remove NextSteps -------------
- DROP TABLE IF EXISTS deleted_nextsteps;
- CREATE TEMP TABLE deleted_nextsteps AS
- WITH deletes AS (
- DELETE FROM "NextSteps"
- USING nextsteps_to_delete
- WHERE id = nsid
- RETURNING
- id
- )
- SELECT id FROM deletes
- ;
-
-
- -- Create the ARO deletion list
- DROP TABLE IF EXISTS aros_to_delete;
- CREATE TEMP TABLE aros_to_delete
- AS
- SELECT
- id aroid,
- "objectiveId" oid
- FROM "ActivityReportObjectives"
- JOIN ars_to_delete
- ON "activityReportId" = arid
- ;
- -- Remove ARO link records: -------------
- DROP TABLE IF EXISTS deleted_activityreportobjectivefiles;
- CREATE TEMP TABLE deleted_activityreportobjectivefiles AS
- WITH deletes AS (
- DELETE FROM "ActivityReportObjectiveFiles"
- USING aros_to_delete
- WHERE "activityReportObjectiveId" = aroid
- RETURNING
- id,
- "fileId" fid
- )
- SELECT id, fid FROM deletes
- ;
- DROP TABLE IF EXISTS deleted_activityreportobjectiveresources;
- CREATE TEMP TABLE deleted_activityreportobjectiveresources AS
- WITH deletes AS (
- DELETE FROM "ActivityReportObjectiveResources"
- USING aros_to_delete
- WHERE "activityReportObjectiveId" = aroid
- RETURNING
- id,
- "resourceId" resourceid
- )
- SELECT id, resourceid FROM deletes
- ;
- DROP TABLE IF EXISTS deleted_activityreportobjectivetopics;
- CREATE TEMP TABLE deleted_activityreportobjectivetopics AS
- WITH deletes AS (
- DELETE FROM "ActivityReportObjectiveTopics"
- USING aros_to_delete
- WHERE "activityReportObjectiveId" = aroid
- RETURNING
- id
- )
- SELECT id FROM deletes
- ;
- DROP TABLE IF EXISTS deleted_activityreportobjectivecourses;
- CREATE TEMP TABLE deleted_activityreportobjectivecourses AS
- WITH deletes AS (
- DELETE FROM "ActivityReportObjectiveCourses"
- USING aros_to_delete
- WHERE "activityReportObjectiveId" = aroid
- RETURNING
- id
- )
- SELECT id FROM deletes
- ;
- -- remove AROs -------------------
- DROP TABLE IF EXISTS deleted_aros;
- CREATE TEMP TABLE deleted_aros AS
- WITH deletes AS (
- DELETE FROM "ActivityReportObjectives"
- USING aros_to_delete
- WHERE id = aroid
- RETURNING
- id,
- "objectiveId" oid
- )
- SELECT id, oid FROM deletes
- ;
-
- -- Create the orphaned Objective deletion list
- DROP TABLE IF EXISTS objectives_to_delete;
- CREATE TEMP TABLE objectives_to_delete
- AS
- SELECT DISTINCT oid
- FROM deleted_aros
- EXCEPT
- SELECT DISTINCT "objectiveId"
- FROM "ActivityReportObjectives"
- ;
- -- Remove Objective link records: -------------
- -- Delete ObjectiveCollaborators
- DROP TABLE IF EXISTS deleted_objectivecollaborators;
- CREATE TEMP TABLE deleted_objectivecollaborators AS
- WITH deletes AS (
- DELETE FROM "ObjectiveCollaborators"
- USING objectives_to_delete
- WHERE "objectiveId" = oid
- RETURNING
- id
- )
- SELECT id FROM deletes
- ;
-
- -- remove Objectives -------------------
- DROP TABLE IF EXISTS deleted_objectives;
- CREATE TEMP TABLE deleted_objectives AS
- WITH deletes AS (
- DELETE FROM "Objectives"
- USING objectives_to_delete
- WHERE id = oid
- RETURNING
- id,
- "goalId" gid,
- "objectiveTemplateId" otid
- )
- SELECT id, gid, otid FROM deletes
- ;
-
- -- Create the ARG deletion list
- DROP TABLE IF EXISTS args_to_delete;
- CREATE TEMP TABLE args_to_delete
- AS
- SELECT DISTINCT
- id argid,
- "goalId" gid
- FROM "ActivityReportGoals"
- JOIN ars_to_delete
- ON "activityReportId" = arid
- ;
- -- Remove ARG link records: -------------
- DROP TABLE IF EXISTS deleted_activityreportgoalfieldresponses;
- CREATE TEMP TABLE deleted_activityreportgoalfieldresponses AS
- WITH deletes AS (
- DELETE FROM "ActivityReportGoalFieldResponses"
- USING args_to_delete
- WHERE "activityReportGoalId" = argid
- RETURNING
- id
- )
- SELECT id FROM deletes
- ;
- DROP TABLE IF EXISTS deleted_activityreportgoalresources;
- CREATE TEMP TABLE deleted_activityreportgoalresources AS
- WITH deletes AS (
- DELETE FROM "ActivityReportGoalResources"
- USING args_to_delete
- WHERE "activityReportGoalId" = argid
- RETURNING
- id,
- "resourceId" resourceid
- )
- SELECT id, resourceid FROM deletes
- ;
- -- remove ARGs -------------------
- DROP TABLE IF EXISTS deleted_args;
- CREATE TEMP TABLE deleted_args AS
- WITH deletes AS (
- DELETE FROM "ActivityReportGoals"
- USING args_to_delete
- WHERE id = argid
- RETURNING
- id,
- "goalId" gid
- )
- SELECT id, gid FROM deletes
- ;
-
- -- Create the orphaned Goal deletions list
- DROP TABLE IF EXISTS goals_to_delete;
- CREATE TEMP TABLE goals_to_delete
- AS
- SELECT DISTINCT gid
- FROM deleted_args dargs
- JOIN "Goals" g
- ON gid = g.id
- WHERE (g."isRttapa" IS NULL OR g."isRttapa" != 'Yes')
- AND g."isFromSmartsheetTtaPlan" != TRUE
- AND g."createdVia" != 'merge'
- EXCEPT
- SELECT gid
- FROM (
- SELECT DISTINCT "goalId" gid
- FROM "ActivityReportGoals"
- UNION
- SELECT DISTINCT "goalId"
- FROM "Objectives"
- UNION
- SELECT DISTINCT "goalId"
- FROM "EventReportPilotGoals"
- ) keepers
- ;
- -- Remove Goal link records: -------------
- DROP TABLE IF EXISTS deleted_goalcollaborators;
- CREATE TEMP TABLE deleted_goalcollaborators AS
- WITH deletes AS (
- DELETE FROM "GoalCollaborators"
- USING goals_to_delete
- WHERE "goalId" = gid
- RETURNING
- id
- )
- SELECT id FROM deletes
- ;
- DROP TABLE IF EXISTS deleted_goalfieldresponses;
- CREATE TEMP TABLE deleted_goalfieldresponses AS
- WITH deletes AS (
- DELETE FROM "GoalFieldResponses"
- USING goals_to_delete
- WHERE "goalId" = gid
- RETURNING
- id
- )
- SELECT id FROM deletes
- ;
- DROP TABLE IF EXISTS deleted_goalresources;
- CREATE TEMP TABLE deleted_goalresources AS
- WITH deletes AS (
- DELETE FROM "GoalResources"
- USING goals_to_delete
- WHERE "goalId" = gid
- RETURNING
- id,
- "resourceId" resourceid
- )
- SELECT id, resourceid FROM deletes
- ;
- DROP TABLE IF EXISTS deleted_goalstatuschanges;
- CREATE TEMP TABLE deleted_goalstatuschanges AS
- WITH deletes AS (
- DELETE FROM "GoalStatusChanges"
- USING goals_to_delete
- WHERE "goalId" = gid
- RETURNING
- id,
- "goalId" gid
- )
- SELECT id, gid FROM deletes
- ;
- -- remove Goals -------------------
- DROP TABLE IF EXISTS deleted_goals;
- CREATE TEMP TABLE deleted_goals AS
- WITH deletes AS (
- DELETE FROM "Goals"
- USING goals_to_delete
- WHERE id = gid
- RETURNING
- id,
- "goalTemplateId" gtid
- )
- SELECT id, gtid FROM deletes
- ;
-
- -- Create the orphaned ObjectiveTemplate deletion list
- DROP TABLE IF EXISTS ots_to_delete;
- CREATE TEMP TABLE ots_to_delete
- AS
- SELECT DISTINCT otid
- FROM deleted_objectives
- EXCEPT
- SELECT DISTINCT "objectiveTemplateId"
- FROM "Objectives"
- ;
-
- -- Create the orphaned GoalTemplate deletion list
- DROP TABLE IF EXISTS gts_to_delete;
- CREATE TEMP TABLE gts_to_delete
- AS
- SELECT DISTINCT gtid
- FROM deleted_goals
- EXCEPT
- SELECT DISTINCT "goalTemplateId"
- FROM "Goals"
- ;
- -- Remove GoalTemplate link records: -------------
- DROP TABLE IF EXISTS deleted_goaltemplateobjectivetemplates;
- CREATE TEMP TABLE deleted_goaltemplateobjectivetemplates AS
- WITH unified_deletes AS (
- SELECT DISTINCT id gtotid
- FROM "GoalTemplateObjectiveTemplates"
- JOIN ots_to_delete
- ON otid = "objectiveTemplateId"
- UNION
- SELECT DISTINCT id gtotid
- FROM "GoalTemplateObjectiveTemplates"
- JOIN gts_to_delete
- ON gtid = "goalTemplateId"
- ),
- deletes AS (
- DELETE FROM "GoalTemplateObjectiveTemplates"
- USING unified_deletes
- WHERE id = gtotid
- RETURNING
- id
- )
- SELECT id FROM deletes
- ;
- -- Remove ObjectiveTemplates --------
- DROP TABLE IF EXISTS deleted_objectivetemplates;
- CREATE TEMP TABLE deleted_objectivetemplates AS
- WITH deletes AS (
- DELETE FROM "ObjectiveTemplates"
- USING ots_to_delete
- WHERE id = otid
- RETURNING
- id
- )
- SELECT id FROM deletes
- ;
- -- Remove GoalTemplates -------------
- DROP TABLE IF EXISTS deleted_goaltemplates;
- CREATE TEMP TABLE deleted_goaltemplates AS
- WITH deletes AS (
- DELETE FROM "GoalTemplates"
- USING gts_to_delete
- WHERE id = gtid
- RETURNING
- id
- )
- SELECT id FROM deletes
- ;
-
- -- Remove ARs -------------
- DROP TABLE IF EXISTS deleted_ars;
- CREATE TEMP TABLE deleted_ars AS
- WITH deletes AS (
- DELETE FROM "ActivityReports"
- USING ars_to_delete
- WHERE id = arid
- RETURNING
- id
- )
- SELECT id FROM deletes
- ;
-
-
- -- Stats ----------------------------
- SELECT 1,'ars_to_delete', count(*) FROM ars_to_delete
- UNION
- SELECT 2,'deleted_activityreportapprovers', count(*) FROM deleted_activityreportapprovers
- UNION
- SELECT 3,'deleted_activityreportcollaborators', count(*) FROM deleted_activityreportcollaborators
- UNION
- SELECT 4,'deleted_activityreportfiles', count(*) FROM deleted_activityreportfiles
- UNION
- SELECT 5,'deleted_activityreportresources', count(*) FROM deleted_activityreportresources
- UNION
- SELECT 6,'nextsteps_to_delete', count(*) FROM nextsteps_to_delete
- UNION
- SELECT 7,'deleted_nextstepresources', count(*) FROM deleted_nextstepresources
- UNION
- SELECT 8,'deleted_nextsteps', count(*) FROM deleted_nextsteps
- UNION
- SELECT 9,'aros_to_delete', count(*) FROM aros_to_delete
- UNION
- SELECT 10,'deleted_activityreportobjectivefiles', count(*) FROM deleted_activityreportobjectivefiles
- UNION
- SELECT 11,'deleted_activityreportobjectiveresources', count(*) FROM deleted_activityreportobjectiveresources
- UNION
- SELECT 12,'deleted_activityreportobjectivetopics', count(*) FROM deleted_activityreportobjectivetopics
- UNION
- SELECT 12,'deleted_activityreportobjectivecourses', count(*) FROM deleted_activityreportobjectivetopics
- UNION
- SELECT 13,'deleted_aros', count(*) FROM deleted_aros
- UNION
- SELECT 14,'objectives_to_delete', count(*) FROM objectives_to_delete
- UNION
- SELECT 14,'deleted_objectivecollaborators', count(*) FROM objectives_to_delete
- UNION
- SELECT 15,'deleted_objectives', count(*) FROM deleted_objectives
- UNION
- SELECT 16,'args_to_delete', count(*) FROM args_to_delete
- UNION
- SELECT 17,'deleted_activityreportgoalfieldresponses', count(*) FROM deleted_activityreportgoalfieldresponses
- UNION
- SELECT 18,'deleted_activityreportgoalresources', count(*) FROM deleted_activityreportgoalresources
- UNION
- SELECT 19,'deleted_args', count(*) FROM deleted_args
- UNION
- SELECT 20,'goals_to_delete', count(*) FROM goals_to_delete
- UNION
- SELECT 21,'deleted_goalcollaborators', count(*) FROM deleted_goalcollaborators
- UNION
- SELECT 22,'deleted_goalfieldresponses', count(*) FROM deleted_goalfieldresponses
- UNION
- SELECT 23,'deleted_goalresources', count(*) FROM deleted_goalresources
- UNION
- SELECT 24,'deleted_goalstatuschanges', count(*) FROM deleted_goalstatuschanges
- UNION
- SELECT 25,'deleted_goals', count(*) FROM deleted_goals
- UNION
- SELECT 26,'ots_to_delete', count(*) FROM ots_to_delete
- UNION
- SELECT 27,'gts_to_delete', count(*) FROM gts_to_delete
- UNION
- SELECT 28,'deleted_goaltemplateobjectivetemplates', count(*) FROM deleted_goaltemplateobjectivetemplates
- UNION
- SELECT 29,'deleted_objectivetemplates', count(*) FROM deleted_objectivetemplates
- UNION
- SELECT 30,'deleted_goaltemplates', count(*) FROM deleted_goaltemplates
- UNION
- SELECT 31,'deleted_ars', count(*) FROM deleted_ars
- ORDER BY 1
- ;
-
- -- Reset the onApprovedAR and onAR values for the goals and objectives that
- -- were not deleted
- -- 1. Calculate correct onApprovedAR values for objectives
- DROP TABLE IF EXISTS objectives_on_ars;
- CREATE TEMP TABLE objectives_on_ars
- AS
- WITH objectivelist AS (
- SELECT DISTINCT oid FROM aros_to_delete
- EXCEPT
- SELECT id FROM deleted_objectives
- )
- SELECT
- o.id oid,
- BOOL_OR(ar.id IS NOT NULL AND ar."calculatedStatus" = 'approved') on_approved_ar,
- BOOL_OR(ar.id IS NOT NULL) on_ar
- FROM objectivelist ol
- JOIN "Objectives" o
- ON ol.oid = o.id
- LEFT JOIN "ActivityReportObjectives" aro
- ON o.id = aro."objectiveId"
- LEFT JOIN "ActivityReports" ar
- ON aro."activityReportId" = ar.id
- AND ar."calculatedStatus" != 'deleted'
- GROUP BY 1
- ;
- -- 2. Calculate correct onApprovedAR values for goals
- DROP TABLE IF EXISTS goals_on_ars;
- CREATE TEMP TABLE goals_on_ars
- AS
- WITH goallist AS (
- SELECT DISTINCT gid FROM args_to_delete
- EXCEPT
- SELECT id FROM deleted_goals
- )
- SELECT
- g.id gid,
- BOOL_OR(
- (ar.id IS NOT NULL AND ar."calculatedStatus" = 'approved')
- OR
- COALESCE(ooaa.on_approved_ar,FALSE)
- ) on_approved_ar,
- BOOL_OR(ar.id IS NOT NULL OR COALESCE(ooaa.on_ar,FALSE)) on_ar
- FROM goallist gl
- JOIN "Goals" g
- ON g.id = gl.gid
- LEFT JOIN "ActivityReportGoals" arg
- ON g.id = arg."goalId"
- LEFT JOIN "ActivityReports" ar
- ON arg."activityReportId" = ar.id
- AND ar."calculatedStatus" != 'deleted'
- LEFT JOIN "Objectives" o
- ON o."goalId" = g.id
- LEFT JOIN objectives_on_ars ooaa
- ON ooaa.oid = o.id
- GROUP BY 1
- ;
- -- 3. Calculate onApprovedAR stats for objectives
- DROP TABLE IF EXISTS initial_obj_approved_ar_stats;
- CREATE TEMP TABLE initial_obj_approved_ar_stats
- AS
- SELECT
- COUNT(*) FILTER (WHERE on_approved_ar = "onApprovedAR"
- ) matching_values,
- COUNT(*) FILTER (WHERE "onApprovedAR" IS NOT NULL AND on_approved_ar != "onApprovedAR"
- ) incorrect_values,
- COUNT(*) FILTER (WHERE on_approved_ar AND (NOT "onApprovedAR" OR "onApprovedAR" IS NULL)
- ) should_be_marked_true_but_isnt,
- COUNT(*) FILTER (WHERE NOT on_approved_ar AND ("onApprovedAR" OR "onApprovedAR" IS NULL)
- ) marked_true_but_shouldnt_be,
- COUNT(*) total_objectives
- FROM "Objectives" o
- JOIN objectives_on_ars
- ON o.id = oid
- ;
- -- 4. Calculate onAR stats for objectives
- DROP TABLE IF EXISTS initial_obj_onar_stats;
- CREATE TEMP TABLE initial_obj_onar_stats
- AS
- SELECT
- COUNT(*) FILTER (WHERE on_ar = "onAR"
- ) matching_values,
- COUNT(*) FILTER (WHERE "onAR" IS NOT NULL AND on_ar != "onAR"
- ) incorrect_values,
- COUNT(*) FILTER (WHERE on_ar AND (NOT "onAR" OR "onAR" IS NULL)
- ) should_be_marked_true_but_isnt,
- COUNT(*) FILTER (WHERE NOT on_ar AND ("onAR" OR "onAR" IS NULL)
- ) marked_true_but_shouldnt_be,
- COUNT(*) total_objectives
- FROM "Objectives" o
- JOIN objectives_on_ars
- ON o.id = oid
- ;
- -- 5. Calculate onApprovedAR stats for goals
- DROP TABLE IF EXISTS initial_goal_approved_ar_stats;
- CREATE TEMP TABLE initial_goal_approved_ar_stats
- AS
- SELECT
- COUNT(*) FILTER (WHERE on_approved_ar = "onApprovedAR"
- ) matching_values,
- COUNT(*) FILTER (WHERE "onApprovedAR" IS NOT NULL AND on_approved_ar != "onApprovedAR"
- ) incorrect_values,
- COUNT(*) FILTER (WHERE on_approved_ar AND (NOT "onApprovedAR" OR "onApprovedAR" IS NULL)
- ) should_be_marked_true_but_isnt,
- COUNT(*) FILTER (WHERE NOT on_approved_ar AND ("onApprovedAR" OR "onApprovedAR" IS NULL)
- ) marked_true_but_shouldnt_be,
- COUNT(*) total_goals
- FROM "Goals" g
- JOIN goals_on_ars
- ON g.id = gid
- ;
- -- 6. Calculate onAR stats for goals
- DROP TABLE IF EXISTS initial_goal_onar_stats;
- CREATE TEMP TABLE initial_goal_onar_stats
- AS
- SELECT
- COUNT(*) FILTER (WHERE on_ar = "onAR"
- ) matching_values,
- COUNT(*) FILTER (WHERE "onAR" IS NOT NULL AND on_ar != "onAR"
- ) incorrect_values,
- COUNT(*) FILTER (WHERE on_ar AND (NOT "onAR" OR "onAR" IS NULL)
- ) should_be_marked_true_but_isnt,
- COUNT(*) FILTER (WHERE NOT on_ar AND ("onAR" OR "onAR" IS NULL)
- ) marked_true_but_shouldnt_be,
- COUNT(*) total_goals
- FROM "Goals" g
- JOIN goals_on_ars
- ON g.id = gid
- ;
- -- 7. Update onApprovedAR values for objectives and save the results
- DROP TABLE IF EXISTS corrected_approved_objectives;
- CREATE TEMP TABLE corrected_approved_objectives
- AS
- WITH updater AS (
- UPDATE "Objectives" o
- SET "onApprovedAR" = on_approved_ar
- FROM objectives_on_ars
- WHERE o.id = oid
- AND ("onApprovedAR" != on_approved_ar OR "onApprovedAR" IS NULL)
- RETURNING
- oid,
- on_approved_ar
- ) SELECT * FROM updater
- ;
- -- 8. Update onAR values for objectives and save the results
- DROP TABLE IF EXISTS corrected_onar_objectives;
- CREATE TEMP TABLE corrected_onar_objectives
- AS
- WITH updater AS (
- UPDATE "Objectives" o
- SET "onAR" = on_ar
- FROM objectives_on_ars
- WHERE o.id = oid
- AND ("onAR" != on_ar OR "onAR" IS NULL)
- RETURNING
- oid,
- on_ar
- ) SELECT * FROM updater
- ;
- -- 9. Update onApprovedAR values for goals and save the results
- DROP TABLE IF EXISTS corrected_approved_goals;
- CREATE TEMP TABLE corrected_approved_goals
- AS
- WITH updater AS (
- UPDATE "Goals" g
- SET "onApprovedAR" = on_approved_ar
- FROM goals_on_ars
- WHERE g.id = gid
- AND ("onApprovedAR" != on_approved_ar OR "onApprovedAR" IS NULL)
- RETURNING
- gid,
- on_approved_ar
- ) SELECT * FROM updater
- ;
- -- 10. Update onAR values for goals and save the results
- DROP TABLE IF EXISTS corrected_onar_goals;
- CREATE TEMP TABLE corrected_onar_goals
- AS
- WITH updater AS (
- UPDATE "Goals" g
- SET "onAR" = on_ar
- FROM goals_on_ars
- WHERE g.id = gid
- AND ("onAR" != on_ar OR "onAR" IS NULL)
- RETURNING
- gid,
- on_ar
- ) SELECT * FROM updater
- ;
- -- produce stats on what happened
- -- 11. Final onApprovedAR stats for objectives
- DROP TABLE IF EXISTS final_obj_approved_ar_stats;
- CREATE TEMP TABLE final_obj_approved_ar_stats
- AS
- SELECT
- COUNT(*) FILTER (WHERE on_approved_ar = "onApprovedAR"
- ) matching_values,
- COUNT(*) FILTER (WHERE "onApprovedAR" IS NOT NULL AND on_approved_ar != "onApprovedAR"
- ) incorrect_values,
- COUNT(*) FILTER (WHERE on_approved_ar AND (NOT "onApprovedAR" OR "onApprovedAR" IS NULL)
- ) should_be_marked_true_but_isnt,
- COUNT(*) FILTER (WHERE NOT on_approved_ar AND ("onApprovedAR" OR "onApprovedAR" IS NULL)
- ) marked_true_but_shouldnt_be,
- COUNT(*) total_objectives
- FROM "Objectives" o
- JOIN objectives_on_ars
- ON o.id = oid
- ;
- -- 12. Final onAR stats for objectives
- DROP TABLE IF EXISTS final_obj_onar_stats;
- CREATE TEMP TABLE final_obj_onar_stats
- AS
- SELECT
- COUNT(*) FILTER (WHERE on_ar = "onAR"
- ) matching_values,
- COUNT(*) FILTER (WHERE "onAR" IS NOT NULL AND on_ar != "onAR"
- ) incorrect_values,
- COUNT(*) FILTER (WHERE on_ar AND (NOT "onAR" OR "onAR" IS NULL)
- ) should_be_marked_true_but_isnt,
- COUNT(*) FILTER (WHERE NOT on_ar AND ("onAR" OR "onAR" IS NULL)
- ) marked_true_but_shouldnt_be,
- COUNT(*) total_objectives
- FROM "Objectives" o
- JOIN objectives_on_ars
- ON o.id = oid
- ;
- -- 13. Final onApprovedAR stats for goals
- DROP TABLE IF EXISTS final_goal_approved_ar_stats;
- CREATE TEMP TABLE final_goal_approved_ar_stats
- AS
- SELECT
- COUNT(*) FILTER (WHERE on_approved_ar = "onApprovedAR"
- ) matching_values,
- COUNT(*) FILTER (WHERE "onApprovedAR" IS NOT NULL AND on_approved_ar != "onApprovedAR"
- ) incorrect_values,
- COUNT(*) FILTER (WHERE on_approved_ar AND (NOT "onApprovedAR" OR "onApprovedAR" IS NULL)
- ) should_be_marked_true_but_isnt,
- COUNT(*) FILTER (WHERE NOT on_approved_ar AND ("onApprovedAR" OR "onApprovedAR" IS NULL)
- ) marked_true_but_shouldnt_be,
- COUNT(*) total_goals
- FROM "Goals" g
- JOIN goals_on_ars
- ON g.id = gid
- ;
- -- 14. Final onAR stats for goals
- DROP TABLE IF EXISTS final_goal_onar_stats;
- CREATE TEMP TABLE final_goal_onar_stats
- AS
- SELECT
- COUNT(*) FILTER (WHERE on_ar = "onAR"
- ) matching_values,
- COUNT(*) FILTER (WHERE "onAR" IS NOT NULL AND on_ar != "onAR"
- ) incorrect_values,
- COUNT(*) FILTER (WHERE on_ar AND (NOT "onAR" OR "onAR" IS NULL)
- ) should_be_marked_true_but_isnt,
- COUNT(*) FILTER (WHERE NOT on_ar AND ("onAR" OR "onAR" IS NULL)
- ) marked_true_but_shouldnt_be,
- COUNT(*) total_goals
- FROM "Goals" g
- JOIN goals_on_ars
- ON g.id = gid
- ;
- -- make a nice little table to see the math
- SELECT
- 1 AS order,
- 'objective onApprovedAR starting stats' description,
- matching_values,
- incorrect_values,
- should_be_marked_true_but_isnt,
- marked_true_but_shouldnt_be,
- total_objectives total
- FROM initial_obj_approved_ar_stats
- UNION
- SELECT
- 2,
- 'objective onApprovedAR values changed',
- NULL,
- NULL,
- SUM(CASE WHEN on_approved_ar THEN 1 ELSE 0 END),
- SUM(CASE WHEN NOT on_approved_ar THEN 1 ELSE 0 END),
- COUNT(*)
- FROM corrected_approved_objectives
- UNION
- SELECT 3,'objective onApprovedAR ending stats', * FROM final_obj_approved_ar_stats
- UNION
- SELECT 4,'objective onAR starting stats', * FROM initial_obj_onar_stats
- UNION
- SELECT
- 5,
- 'objective onAR values changed',
- NULL,
- NULL,
- SUM(CASE WHEN on_ar THEN 1 ELSE 0 END),
- SUM(CASE WHEN NOT on_ar THEN 1 ELSE 0 END),
- COUNT(*)
- FROM corrected_onar_objectives
- UNION
- SELECT 6,'objective onAR ending stats', * FROM final_obj_onar_stats
- UNION
- SELECT 7,'goal onApprovedAR starting stats', * FROM initial_goal_approved_ar_stats
- UNION
- SELECT
- 8,
- 'goal onApprovedAR values changed',
- NULL,
- NULL,
- SUM(CASE WHEN on_approved_ar THEN 1 ELSE 0 END),
- SUM(CASE WHEN NOT on_approved_ar THEN 1 ELSE 0 END),
- COUNT(*)
- FROM corrected_approved_goals
- UNION
- SELECT 9,'goal onApprovedAR ending stats', * FROM final_goal_approved_ar_stats
- UNION
- SELECT 10,'goal onAR starting stats', * FROM initial_goal_onar_stats
- UNION
- SELECT
- 11,
- 'goal onAR values changed',
- NULL,
- NULL,
- SUM(CASE WHEN on_ar THEN 1 ELSE 0 END),
- SUM(CASE WHEN NOT on_ar THEN 1 ELSE 0 END),
- COUNT(*)
- FROM corrected_onar_goals
- UNION
- SELECT 12,'goal onAR ending stats', * FROM final_goal_onar_stats
- ORDER BY 1
- ;
-
- `, { transaction });
- });
- },
-
- down: async () => {
- },
-};
From f89fd6018a28baffb23852a7d5171b072006dd79 Mon Sep 17 00:00:00 2001
From: Adam Levin
Date: Tue, 9 Jul 2024 09:35:33 -0400
Subject: [PATCH 21/26] fixes per Matt
---
frontend/src/App.js | 3 +-
.../src/components/DisplayWithPermission.js | 4 +-
frontend/src/components/FeatureFlag.js | 4 +-
frontend/src/components/SomethingWentWrong.js | 6 ++-
.../src/components/SomethingWentWrong.scss | 3 +-
.../__tests__/DisplayWithPermission.js | 3 +-
.../src/components/__tests__/FeatureFlag.js | 3 +-
frontend/src/pages/AccountManagement/Group.js | 13 ++----
.../AccountManagement/__tests__/Group.js | 43 +++++++++++--------
.../pages/RecipientRecord/__tests__/index.js | 20 +++++----
frontend/src/pages/RecipientRecord/index.js | 19 ++------
.../RecipientRecord/pages/CommunicationLog.js | 4 +-
.../pages/RecipientRecord/pages/Profile.js | 2 +-
.../pages/__tests__/CommunicationLog.js | 26 ++++++++---
14 files changed, 84 insertions(+), 69 deletions(-)
diff --git a/frontend/src/App.js b/frontend/src/App.js
index efbf21c097..833bfea09b 100644
--- a/frontend/src/App.js
+++ b/frontend/src/App.js
@@ -22,7 +22,6 @@ import TrainingReports from './pages/TrainingReports';
import ResourcesDashboard from './pages/ResourcesDashboard';
import CourseDashboard from './pages/CourseDashboard';
import Unauthenticated from './pages/Unauthenticated';
-import NotFound from './pages/NotFound';
import Home from './pages/Home';
import Landing from './pages/Landing';
import ActivityReport from './pages/ActivityReport';
@@ -446,7 +445,7 @@ function App() {
(
-
+
)}
/>
diff --git a/frontend/src/components/DisplayWithPermission.js b/frontend/src/components/DisplayWithPermission.js
index a625ff5618..7fabca2e90 100644
--- a/frontend/src/components/DisplayWithPermission.js
+++ b/frontend/src/components/DisplayWithPermission.js
@@ -1,8 +1,8 @@
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
-import NotFound from '../pages/NotFound';
import UserContext from '../UserContext';
import isAdmin from '../permissions';
+import SomethingWentWrong from './SomethingWentWrong';
export default function DisplayWithPermission({
scopes, renderNotFound, children,
@@ -16,7 +16,7 @@ export default function DisplayWithPermission({
if (!admin && !userHasScope) {
if (renderNotFound) {
- return ;
+ return ;
}
return <>>;
}
diff --git a/frontend/src/components/FeatureFlag.js b/frontend/src/components/FeatureFlag.js
index 2a89054b4f..6a29671af4 100644
--- a/frontend/src/components/FeatureFlag.js
+++ b/frontend/src/components/FeatureFlag.js
@@ -1,8 +1,8 @@
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
-import NotFound from '../pages/NotFound';
import UserContext from '../UserContext';
import isAdmin from '../permissions';
+import SomethingWentWrong from './SomethingWentWrong';
export default function FeatureFlag({
flag, renderNotFound, children,
@@ -12,7 +12,7 @@ export default function FeatureFlag({
if (!admin && user.flags && !user.flags.includes(flag)) {
if (renderNotFound) {
- return ;
+ return ;
}
return <>>;
}
diff --git a/frontend/src/components/SomethingWentWrong.js b/frontend/src/components/SomethingWentWrong.js
index d40c06c7e0..3dcf1e1493 100644
--- a/frontend/src/components/SomethingWentWrong.js
+++ b/frontend/src/components/SomethingWentWrong.js
@@ -175,7 +175,11 @@ function SomethingWentWrong({ errorResponseCode }) {
}
SomethingWentWrong.propTypes = {
- errorResponseCode: PropTypes.number.isRequired,
+ errorResponseCode: PropTypes.number,
+};
+
+SomethingWentWrong.defaultProps = {
+ errorResponseCode: 404,
};
export default SomethingWentWrong;
diff --git a/frontend/src/components/SomethingWentWrong.scss b/frontend/src/components/SomethingWentWrong.scss
index 5f0e7691ce..89041ac9a0 100644
--- a/frontend/src/components/SomethingWentWrong.scss
+++ b/frontend/src/components/SomethingWentWrong.scss
@@ -11,7 +11,8 @@
font-weight: 700;
}
-.smart-hub--something-went-wrong p {
+.smart-hub--something-went-wrong p,
+.smart-hub--something-went-wrong ul li button {
color: $base-dark;
font-size: 1.25rem;
font-weight: 400;
diff --git a/frontend/src/components/__tests__/DisplayWithPermission.js b/frontend/src/components/__tests__/DisplayWithPermission.js
index c8588d03f9..9b1099af10 100644
--- a/frontend/src/components/__tests__/DisplayWithPermission.js
+++ b/frontend/src/components/__tests__/DisplayWithPermission.js
@@ -72,6 +72,7 @@ describe('display with permissions', () => {
};
const renderNotFound = true;
renderDisplayWithPermission([READ_WRITE_TRAINING_REPORTS], user, renderNotFound);
- expect(screen.getByRole('link', { name: /home page/i })).toBeVisible();
+ expect(screen.getByRole('heading', { name: /404 error/i })).toBeVisible();
+ expect(screen.getByRole('heading', { name: /page not found/i })).toBeVisible();
});
});
diff --git a/frontend/src/components/__tests__/FeatureFlag.js b/frontend/src/components/__tests__/FeatureFlag.js
index ed8fd84203..b4594a5910 100644
--- a/frontend/src/components/__tests__/FeatureFlag.js
+++ b/frontend/src/components/__tests__/FeatureFlag.js
@@ -71,6 +71,7 @@ describe('feature flag', () => {
};
const renderNotFound = true;
renderFeatureFlag(flag, user, renderNotFound);
- expect(screen.getByRole('link', { name: /home page/i })).toBeVisible();
+ expect(screen.getByRole('heading', { name: /404 error/i })).toBeVisible();
+ expect(screen.getByRole('heading', { name: /page not found/i })).toBeVisible();
});
});
diff --git a/frontend/src/pages/AccountManagement/Group.js b/frontend/src/pages/AccountManagement/Group.js
index 1bb94dbad6..fa38ba8413 100644
--- a/frontend/src/pages/AccountManagement/Group.js
+++ b/frontend/src/pages/AccountManagement/Group.js
@@ -4,16 +4,15 @@ import { Helmet } from 'react-helmet';
import { Link } from 'react-router-dom';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faArrowLeft } from '@fortawesome/free-solid-svg-icons';
-import { Alert } from '@trussworks/react-uswds';
import colors from '../../colors';
import { fetchGroup } from '../../fetchers/groups';
import AppLoadingContext from '../../AppLoadingContext';
import WidgetCard from '../../components/WidgetCard';
import ReadOnlyField from '../../components/ReadOnlyField';
+import SomethingWentWrongContext from '../../SomethingWentWrongContext';
export default function Group({ match }) {
const { groupId } = match.params;
- const [error, setError] = useState(null);
const [group, setGroup] = useState({
name: '',
@@ -21,6 +20,7 @@ export default function Group({ match }) {
});
const { setIsAppLoading } = useContext(AppLoadingContext);
+ const { setErrorResponseCode } = useContext(SomethingWentWrongContext);
useEffect(() => {
async function getGroup() {
@@ -29,7 +29,7 @@ export default function Group({ match }) {
const existingGroupData = await fetchGroup(groupId);
setGroup(existingGroupData);
} catch (err) {
- setError('There was an error fetching your group');
+ setErrorResponseCode(err.status);
} finally {
setIsAppLoading(false);
}
@@ -39,7 +39,7 @@ export default function Group({ match }) {
if (groupId) {
getGroup();
}
- }, [groupId, setIsAppLoading]);
+ }, [groupId, setIsAppLoading, setErrorResponseCode]);
if (!group) {
return null;
@@ -85,11 +85,6 @@ export default function Group({ match }) {
{group.name}}
>
- {error ? (
-
- {error}
-
- ) : null}
{group && group.creator ? group.creator.name : ''}
diff --git a/frontend/src/pages/AccountManagement/__tests__/Group.js b/frontend/src/pages/AccountManagement/__tests__/Group.js
index 5d1663e5ed..9ae5a29627 100644
--- a/frontend/src/pages/AccountManagement/__tests__/Group.js
+++ b/frontend/src/pages/AccountManagement/__tests__/Group.js
@@ -3,12 +3,14 @@ import {
act,
render,
screen,
+ waitFor,
} from '@testing-library/react';
import fetchMock from 'fetch-mock';
import join from 'url-join';
import { MemoryRouter } from 'react-router';
import Group from '../Group';
import AppLoadingContext from '../../../AppLoadingContext';
+import SomethingWentWrong from '../../../SomethingWentWrongContext';
const endpoint = join('/', 'api', 'groups');
@@ -17,11 +19,13 @@ describe('Group', () => {
fetchMock.restore();
});
- const renderGroup = (groupId) => {
+ const renderGroup = (groupId, setErrorResponseCode = jest.fn()) => {
render(
-
+
+
+
,
);
@@ -76,35 +80,36 @@ describe('Group', () => {
it('handles null response', async () => {
fetchMock.get(join(endpoint, '1'), null);
-
- act(() => {
- renderGroup(1);
+ const setErrorResponseCode = jest.fn();
+ act(async () => {
+ renderGroup(1, setErrorResponseCode);
+ await waitFor(() => {
+ expect(setErrorResponseCode).toHaveBeenCalledWith(null);
+ });
});
-
- const error = await screen.findByText('There was an error fetching your group');
- expect(error).toBeInTheDocument();
});
it('handles 404', async () => {
fetchMock.get(join(endpoint, '1'), 404);
-
- act(() => {
- renderGroup(1);
+ const setErrorResponseCode = jest.fn();
+ act(async () => {
+ renderGroup(1, setErrorResponseCode);
+ await waitFor(() => {
+ expect(setErrorResponseCode).toHaveBeenCalledWith(404);
+ });
});
-
- const error = await screen.findByText('There was an error fetching your group');
- expect(error).toBeInTheDocument();
});
it('handles 500', async () => {
fetchMock.get(join(endpoint, '1'), 500);
- act(() => {
- renderGroup(1);
+ const setErrorResponseCode = jest.fn();
+ await act(async () => {
+ renderGroup(1, setErrorResponseCode);
+ await waitFor(() => {
+ expect(setErrorResponseCode).toHaveBeenCalledWith(500);
+ });
});
-
- const error = await screen.findByText('There was an error fetching your group');
- expect(error).toBeInTheDocument();
});
it('handles no group id', async () => {
diff --git a/frontend/src/pages/RecipientRecord/__tests__/index.js b/frontend/src/pages/RecipientRecord/__tests__/index.js
index b27808c553..02e2d9d93e 100644
--- a/frontend/src/pages/RecipientRecord/__tests__/index.js
+++ b/frontend/src/pages/RecipientRecord/__tests__/index.js
@@ -90,7 +90,7 @@ describe('recipient record page', () => {
],
};
- function renderRecipientRecord(history = memoryHistory, regionId = '45') {
+ function renderRecipientRecord(history = memoryHistory, regionId = '45', setErrorResponseCode = jest.fn()) {
const match = {
path: '',
url: '',
@@ -102,7 +102,7 @@ describe('recipient record page', () => {
render(
-
+
{
it('handles recipient not found', async () => {
fetchMock.get('/api/recipient/1/region/45/merge-permissions', { canMergeGoalsForRecipient: false });
fetchMock.get('/api/recipient/1?region.in[]=45', 404);
- act(() => renderRecipientRecord());
- const error = await screen.findByText('Recipient record not found');
- expect(error).toBeInTheDocument();
+ const setErrorResponseCode = jest.fn();
+ await act(async () => renderRecipientRecord(memoryHistory, '45', setErrorResponseCode));
+ await waitFor(() => {
+ expect(setErrorResponseCode).toHaveBeenCalledWith(404);
+ });
});
it('handles fetch error', async () => {
fetchMock.get('/api/recipient/1/region/45/merge-permissions', { canMergeGoalsForRecipient: false });
fetchMock.get('/api/recipient/1?region.in[]=45', 500);
- act(() => renderRecipientRecord());
- const error = await screen.findByText('There was an error fetching recipient data');
- expect(error).toBeInTheDocument();
+ const setErrorResponseCode = jest.fn();
+ act(() => renderRecipientRecord(memoryHistory, '45', setErrorResponseCode));
+ await waitFor(() => {
+ expect(setErrorResponseCode).toHaveBeenCalledWith(500);
+ });
});
it('navigates to the profile page', async () => {
diff --git a/frontend/src/pages/RecipientRecord/index.js b/frontend/src/pages/RecipientRecord/index.js
index 4f29bc68ec..03a7f6ac4a 100644
--- a/frontend/src/pages/RecipientRecord/index.js
+++ b/frontend/src/pages/RecipientRecord/index.js
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import React, { useEffect, useState, useContext } from 'react';
import PropTypes from 'prop-types';
import ReactRouterPropTypes from 'react-router-prop-types';
import useDeepCompareEffect from 'use-deep-compare-effect';
@@ -8,7 +8,6 @@ import { Switch, Route } from 'react-router';
import { DECIMAL_BASE } from '@ttahub/common';
import { getMergeGoalPermissions, getRecipient } from '../../fetchers/recipient';
import RecipientTabs from './components/RecipientTabs';
-import { HTTPError } from '../../fetchers';
import './index.scss';
import Profile from './pages/Profile';
import TTAHistory from './pages/TTAHistory';
@@ -23,6 +22,7 @@ import CommunicationLogForm from './pages/CommunicationLogForm';
import ViewCommunicationLog from './pages/ViewCommunicationLog';
import { GrantDataProvider } from './pages/GrantDataContext';
import ViewGoals from './pages/ViewGoals';
+import SomethingWentWrongContext from '../../SomethingWentWrongContext';
export function PageWithHeading({
children,
@@ -34,7 +34,6 @@ export function PageWithHeading({
slug,
}) {
const headerMargin = backLink.props.children ? 'margin-top-0' : 'margin-top-5';
-
return (
@@ -77,6 +76,7 @@ PageWithHeading.defaultProps = {
};
export default function RecipientRecord({ match, hasAlerts }) {
+ const { setErrorResponseCode } = useContext(SomethingWentWrongContext);
const { recipientId, regionId } = match.params;
const [loading, setLoading] = useState(true);
@@ -92,7 +92,6 @@ export default function RecipientRecord({ match, hasAlerts }) {
recipientName: '',
});
- const [error, setError] = useState();
const [canMergeGoals, setCanMergeGoals] = useState(false);
useEffect(() => {
@@ -124,11 +123,7 @@ export default function RecipientRecord({ match, hasAlerts }) {
});
}
} catch (e) {
- if (e instanceof HTTPError && e.status === 404) {
- setError('Recipient record not found');
- } else {
- setError('There was an error fetching recipient data');
- }
+ setErrorResponseCode(e.status);
} finally {
setLoading(false);
}
@@ -162,7 +157,6 @@ export default function RecipientRecord({ match, hasAlerts }) {
@@ -202,7 +195,6 @@ export default function RecipientRecord({ match, hasAlerts }) {
@@ -327,7 +318,6 @@ export default function RecipientRecord({ match, hasAlerts }) {
@@ -345,7 +335,6 @@ export default function RecipientRecord({ match, hasAlerts }) {
diff --git a/frontend/src/pages/RecipientRecord/pages/CommunicationLog.js b/frontend/src/pages/RecipientRecord/pages/CommunicationLog.js
index 81c3532fd1..dc81637578 100644
--- a/frontend/src/pages/RecipientRecord/pages/CommunicationLog.js
+++ b/frontend/src/pages/RecipientRecord/pages/CommunicationLog.js
@@ -19,6 +19,7 @@ import {
methodFilter,
resultFilter,
} from '../../../components/filter/communicationLogFilters';
+import SomethingWentWrongContext from '../../../SomethingWentWrongContext';
const COMMUNICATION_LOG_PER_PAGE = 10;
const FILTER_KEY = 'communication-log-filters';
@@ -43,6 +44,7 @@ export default function CommunicationLog({ regionId, recipientId }) {
});
const { user } = useContext(UserContext);
+ const { setErrorResponseCode } = useContext(SomethingWentWrongContext);
const { setIsAppLoading } = useContext(AppLoadingContext);
const {
@@ -71,7 +73,7 @@ export default function CommunicationLog({ regionId, recipientId }) {
setLogs(response);
} catch (err) {
- setError('Error fetching communication logs');
+ setErrorResponseCode(err.status);
} finally {
setIsAppLoading(false);
}
diff --git a/frontend/src/pages/RecipientRecord/pages/Profile.js b/frontend/src/pages/RecipientRecord/pages/Profile.js
index 960c453bf8..c3211bcd92 100644
--- a/frontend/src/pages/RecipientRecord/pages/Profile.js
+++ b/frontend/src/pages/RecipientRecord/pages/Profile.js
@@ -15,7 +15,7 @@ export default function Profile({
regionId,
recipientId,
}) {
- const activeGrants = recipientSummary.grants.filter((grant) => grant.status === 'Active');
+ const activeGrants = (recipientSummary.grants || []).filter((grant) => grant.status === 'Active');
const { hasMonitoringData, hasClassData } = useGrantData();
return (
diff --git a/frontend/src/pages/RecipientRecord/pages/__tests__/CommunicationLog.js b/frontend/src/pages/RecipientRecord/pages/__tests__/CommunicationLog.js
index c59d88ec32..125d959167 100644
--- a/frontend/src/pages/RecipientRecord/pages/__tests__/CommunicationLog.js
+++ b/frontend/src/pages/RecipientRecord/pages/__tests__/CommunicationLog.js
@@ -12,18 +12,21 @@ import CommunicationLog from '../CommunicationLog';
import AppLoadingContext from '../../../../AppLoadingContext';
import UserContext from '../../../../UserContext';
import AriaLiveContext from '../../../../AriaLiveContext';
+import SomethingWentWrongContext from '../../../../SomethingWentWrongContext';
describe('CommunicationLog', () => {
const history = createMemoryHistory();
- const renderTest = () => {
+ const renderTest = (setErrorResponseCode = jest.fn) => {
render(
{} }}>
{} }}>
-
-
-
-
-
+
+
+
+
+
+
+
,
);
@@ -90,4 +93,15 @@ describe('CommunicationLog', () => {
await waitFor(() => expect(fetchMock.called(filteredUrl)).toBe(true));
});
+
+ it('correctly calls setErrorResponseCode when a 500 is returned', async () => {
+ fetchMock.get('/api/communication-logs/region/5/recipient/1?sortBy=communicationDate&direction=desc&offset=0&limit=10&format=json&result.in[]=RTTAPA%20declined', 500);
+ const setErrorResponseCode = jest.fn();
+ await act(async () => {
+ renderTest(setErrorResponseCode);
+ await waitFor(() => {
+ expect(setErrorResponseCode).toHaveBeenCalledWith(500);
+ });
+ });
+ });
});
From de264e9600a8bfeecff7bed3ad11f4a02cfacc27 Mon Sep 17 00:00:00 2001
From: Adam Levin
Date: Tue, 9 Jul 2024 11:37:06 -0400
Subject: [PATCH 22/26] cleanup and fixes
---
.../src/pages/AccountManagement/MyGroups.js | 6 ++-
.../AccountManagement/__tests__/MyGroups.js | 28 ++++++------
.../pages/RecipientRecord/__tests__/index.js | 5 ++-
.../RecipientRecord/pages/CommunicationLog.js | 4 +-
.../ViewCommunicationLog/__tests__/index.js | 45 ++++++++++---------
.../pages/ViewCommunicationLog/index.js | 20 +++------
.../pages/__tests__/CommunicationLog.js | 26 +++--------
7 files changed, 60 insertions(+), 74 deletions(-)
diff --git a/frontend/src/pages/AccountManagement/MyGroups.js b/frontend/src/pages/AccountManagement/MyGroups.js
index 73870a2194..a1dceb8fbc 100644
--- a/frontend/src/pages/AccountManagement/MyGroups.js
+++ b/frontend/src/pages/AccountManagement/MyGroups.js
@@ -21,6 +21,7 @@ import {
import { MyGroupsContext } from '../../components/MyGroupsProvider';
import AppLoadingContext from '../../AppLoadingContext';
import QuestionTooltip from '../../components/GoalForm/QuestionTooltip';
+import SomethingWentWrongContext from '../../SomethingWentWrongContext';
const mapSelectedRecipients = (grants) => grants.map((grant) => ({
value: grant.id,
@@ -73,6 +74,7 @@ export default function MyGroups({ match }) {
},
});
const { user } = useContext(UserContext);
+ const { setErrorResponseCode } = useContext(SomethingWentWrongContext);
const watchIsPrivate = watch(GROUP_FIELD_NAMES.IS_PRIVATE);
const watchShareWithEveryone = watch(GROUP_FIELD_NAMES.SHARE_WITH_EVERYONE);
const watchCoOwners = watch(GROUP_FIELD_NAMES.CO_OWNERS);
@@ -112,7 +114,7 @@ export default function MyGroups({ match }) {
});
}
} catch (err) {
- setError('There was an error fetching your group');
+ setErrorResponseCode(err.status);
} finally {
setIsAppLoading(false);
}
@@ -122,7 +124,7 @@ export default function MyGroups({ match }) {
if (groupId && usersFetched && recipientsFetched) {
getGroup();
}
- }, [groupId, setIsAppLoading, reset, usersFetched, recipientsFetched]);
+ }, [groupId, setIsAppLoading, reset, usersFetched, recipientsFetched, setErrorResponseCode]);
const isCreator = !groupId || (groupCreator && user.id === groupCreator.id);
diff --git a/frontend/src/pages/AccountManagement/__tests__/MyGroups.js b/frontend/src/pages/AccountManagement/__tests__/MyGroups.js
index c61ea5508c..9516cd8f71 100644
--- a/frontend/src/pages/AccountManagement/__tests__/MyGroups.js
+++ b/frontend/src/pages/AccountManagement/__tests__/MyGroups.js
@@ -14,6 +14,7 @@ import MyGroups, { GROUP_FIELD_NAMES } from '../MyGroups';
import MyGroupsProvider from '../../../components/MyGroupsProvider';
import AppLoadingContext from '../../../AppLoadingContext';
import UserContext from '../../../UserContext';
+import SomethingWentWrongContext from '../../../SomethingWentWrongContext';
const error = 'This group name already exists, please use a different name';
@@ -22,15 +23,17 @@ const user = {
};
describe('MyGroups', () => {
- const renderMyGroups = (groupId = null) => {
+ const renderMyGroups = (groupId = null, setErrorResponseCode = jest.fn()) => {
render(
-
-
-
-
-
+
+
+
+
+
+
+
,
);
@@ -214,13 +217,12 @@ describe('MyGroups', () => {
it('handles fetch errors', async () => {
fetchMock.get('/api/group/1', 500);
-
- act(() => {
- renderMyGroups(1);
- });
-
- await waitFor(() => {
- expect(screen.getByText(/There was an error fetching your group/i)).toBeInTheDocument();
+ const setErrorResponseCode = jest.fn();
+ await act(async () => {
+ renderMyGroups(1, setErrorResponseCode);
+ await waitFor(() => {
+ expect(setErrorResponseCode).toHaveBeenCalled();
+ });
});
});
diff --git a/frontend/src/pages/RecipientRecord/__tests__/index.js b/frontend/src/pages/RecipientRecord/__tests__/index.js
index 02e2d9d93e..f017adce5e 100644
--- a/frontend/src/pages/RecipientRecord/__tests__/index.js
+++ b/frontend/src/pages/RecipientRecord/__tests__/index.js
@@ -275,9 +275,10 @@ describe('recipient record page', () => {
fetchMock.get('/api/recipient/1?region.in[]=45', theMightyRecipient);
fetchMock.get('/api/communication-logs/region/1/log/1', 404);
memoryHistory.push('/recipient-tta-records/45/region/1/communication/1/view');
- act(() => renderRecipientRecord());
+ const setErrorResponseCode = jest.fn();
+ act(() => renderRecipientRecord(memoryHistory, '45', setErrorResponseCode));
await waitFor(() => expect(screen.queryByText(/loading.../)).toBeNull());
- await screen.findByText(/There was an error fetching the communication log/i);
+ await waitFor(() => expect(setErrorResponseCode).toHaveBeenCalledWith(404));
});
it('navigates to the communication log form', async () => {
diff --git a/frontend/src/pages/RecipientRecord/pages/CommunicationLog.js b/frontend/src/pages/RecipientRecord/pages/CommunicationLog.js
index dc81637578..81c3532fd1 100644
--- a/frontend/src/pages/RecipientRecord/pages/CommunicationLog.js
+++ b/frontend/src/pages/RecipientRecord/pages/CommunicationLog.js
@@ -19,7 +19,6 @@ import {
methodFilter,
resultFilter,
} from '../../../components/filter/communicationLogFilters';
-import SomethingWentWrongContext from '../../../SomethingWentWrongContext';
const COMMUNICATION_LOG_PER_PAGE = 10;
const FILTER_KEY = 'communication-log-filters';
@@ -44,7 +43,6 @@ export default function CommunicationLog({ regionId, recipientId }) {
});
const { user } = useContext(UserContext);
- const { setErrorResponseCode } = useContext(SomethingWentWrongContext);
const { setIsAppLoading } = useContext(AppLoadingContext);
const {
@@ -73,7 +71,7 @@ export default function CommunicationLog({ regionId, recipientId }) {
setLogs(response);
} catch (err) {
- setErrorResponseCode(err.status);
+ setError('Error fetching communication logs');
} finally {
setIsAppLoading(false);
}
diff --git a/frontend/src/pages/RecipientRecord/pages/ViewCommunicationLog/__tests__/index.js b/frontend/src/pages/RecipientRecord/pages/ViewCommunicationLog/__tests__/index.js
index 48fa850182..e91554ed39 100644
--- a/frontend/src/pages/RecipientRecord/pages/ViewCommunicationLog/__tests__/index.js
+++ b/frontend/src/pages/RecipientRecord/pages/ViewCommunicationLog/__tests__/index.js
@@ -10,6 +10,7 @@ import UserContext from '../../../../../UserContext';
import AppLoadingContext from '../../../../../AppLoadingContext';
import { NOT_STARTED, COMPLETE } from '../../../../../components/Navigator/constants';
import ViewCommunicationForm from '../index';
+import SomethingWentWrongContext from '../../../../../SomethingWentWrongContext';
const RECIPIENT_ID = 1;
const REGION_ID = 1;
@@ -26,23 +27,26 @@ describe('ViewCommunicationForm', () => {
const renderTest = (
communicationLogId = '1',
+ setErrorResponseCode = jest.fn(),
) => render(
-
-
-
+
+
+
+
+
,
);
@@ -103,13 +107,14 @@ describe('ViewCommunicationForm', () => {
it('shows error message', async () => {
const url = `${communicationLogUrl}/region/${REGION_ID}/log/1`;
+ const setErrorResponseCode = jest.fn();
fetchMock.get(url, 500);
-
- await act(() => waitFor(() => {
- renderTest();
- }));
-
- expect(await screen.findByText(/There was an error fetching the communication log/i)).toBeInTheDocument();
+ await act(async () => {
+ await waitFor(() => {
+ renderTest('1', setErrorResponseCode);
+ expect(setErrorResponseCode).toHaveBeenCalledWith(500);
+ });
+ });
});
it('should render the view without edit button', async () => {
diff --git a/frontend/src/pages/RecipientRecord/pages/ViewCommunicationLog/index.js b/frontend/src/pages/RecipientRecord/pages/ViewCommunicationLog/index.js
index a1a93cf2ff..65d972fad9 100644
--- a/frontend/src/pages/RecipientRecord/pages/ViewCommunicationLog/index.js
+++ b/frontend/src/pages/RecipientRecord/pages/ViewCommunicationLog/index.js
@@ -2,7 +2,6 @@ import React, { useEffect, useState, useContext } from 'react';
import moment from 'moment';
import PropTypes from 'prop-types';
import { Helmet } from 'react-helmet';
-import { Alert } from '@trussworks/react-uswds';
import ReactRouterPropTypes from 'react-router-prop-types';
import { Link } from 'react-router-dom';
import Container from '../../../../components/Container';
@@ -13,6 +12,7 @@ import BackLink from '../../../../components/BackLink';
import UserContext from '../../../../UserContext';
import DisplayNextSteps from './components/DisplayNextSteps';
import LogLine from './components/LogLine';
+import SomethingWentWrongContext from '../../../../SomethingWentWrongContext';
export default function ViewCommunicationLog({ match, recipientName }) {
const {
@@ -24,9 +24,9 @@ export default function ViewCommunicationLog({ match, recipientName }) {
} = match;
const { user } = useContext(UserContext);
+ const { setErrorResponseCode } = useContext(SomethingWentWrongContext);
const { setIsAppLoading } = useContext(AppLoadingContext);
const [log, setLog] = useState();
- const [error, setError] = useState();
const isAuthor = log && log.author && log.author.id === user.id;
@@ -37,29 +37,21 @@ export default function ViewCommunicationLog({ match, recipientName }) {
const response = await getCommunicationLogById(regionId, communicationLogId);
setLog(response);
} catch (err) {
- setError('There was an error fetching the communication log.');
+ setErrorResponseCode(err.status);
} finally {
setIsAppLoading(false);
}
}
- if (!log && !error) {
+ if (!log) {
fetchLog();
}
- }, [communicationLogId, error, log, regionId, setIsAppLoading]);
+ }, [communicationLogId, log, regionId, setIsAppLoading, setErrorResponseCode]);
- if (!log && !error) {
+ if (!log) {
return null;
}
- if (error) {
- return (
-
- {error}
-
- );
- }
-
return (
<>
diff --git a/frontend/src/pages/RecipientRecord/pages/__tests__/CommunicationLog.js b/frontend/src/pages/RecipientRecord/pages/__tests__/CommunicationLog.js
index 125d959167..c59d88ec32 100644
--- a/frontend/src/pages/RecipientRecord/pages/__tests__/CommunicationLog.js
+++ b/frontend/src/pages/RecipientRecord/pages/__tests__/CommunicationLog.js
@@ -12,21 +12,18 @@ import CommunicationLog from '../CommunicationLog';
import AppLoadingContext from '../../../../AppLoadingContext';
import UserContext from '../../../../UserContext';
import AriaLiveContext from '../../../../AriaLiveContext';
-import SomethingWentWrongContext from '../../../../SomethingWentWrongContext';
describe('CommunicationLog', () => {
const history = createMemoryHistory();
- const renderTest = (setErrorResponseCode = jest.fn) => {
+ const renderTest = () => {
render(
{} }}>
{} }}>
-
-
-
-
-
-
-
+
+
+
+
+
,
);
@@ -93,15 +90,4 @@ describe('CommunicationLog', () => {
await waitFor(() => expect(fetchMock.called(filteredUrl)).toBe(true));
});
-
- it('correctly calls setErrorResponseCode when a 500 is returned', async () => {
- fetchMock.get('/api/communication-logs/region/5/recipient/1?sortBy=communicationDate&direction=desc&offset=0&limit=10&format=json&result.in[]=RTTAPA%20declined', 500);
- const setErrorResponseCode = jest.fn();
- await act(async () => {
- renderTest(setErrorResponseCode);
- await waitFor(() => {
- expect(setErrorResponseCode).toHaveBeenCalledWith(500);
- });
- });
- });
});
From eaa0bed6dafd52d9a53e6925c548eb59a855b9e5 Mon Sep 17 00:00:00 2001
From: Adam Levin
Date: Tue, 9 Jul 2024 13:31:18 -0400
Subject: [PATCH 23/26] see if this fixes it
---
cucumber/features/notFound.feature | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cucumber/features/notFound.feature b/cucumber/features/notFound.feature
index 8db1b71901..c6eb900e0a 100644
--- a/cucumber/features/notFound.feature
+++ b/cucumber/features/notFound.feature
@@ -2,4 +2,4 @@ Feature: Not Found Page
Scenario: User is shown a 404 page if route is not found
Given I am logged in
And I go to an unknown page
- Then I see the "Not Found" alert message
+ Then I see the "404 error" alert message
From 5690da46c2cc66b7d1a8b3f1f9871e4566234b17 Mon Sep 17 00:00:00 2001
From: Adam Levin
Date: Tue, 9 Jul 2024 13:36:09 -0400
Subject: [PATCH 24/26] find class
---
cucumber/features/steps/notFoundSteps.js | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/cucumber/features/steps/notFoundSteps.js b/cucumber/features/steps/notFoundSteps.js
index 7bce974b2b..17976cb707 100644
--- a/cucumber/features/steps/notFoundSteps.js
+++ b/cucumber/features/steps/notFoundSteps.js
@@ -12,7 +12,10 @@ Given('I go to an unknown page', async () => {
Then('I see the {string} alert message', async (heading) => {
const page = scope.context.currentPage;
- const value = await page.$eval('.usa-alert__heading', (el) => el.textContent);
-
+ // find a div with the class 'smart-hub--something-went-wrong'..
+ const value = await page.evaluate(() => {
+ const element = document.querySelector('.smart-hub--something-went-wrong');
+ return element ? element.innerText : '';
+ });
assertTrue(value.includes(heading));
});
From ee860fb5013a5f876f302d31f67f387e7779cda2 Mon Sep 17 00:00:00 2001
From: Adam Levin
Date: Tue, 9 Jul 2024 15:44:38 -0400
Subject: [PATCH 25/26] fixes per ux review with Kelly
---
frontend/src/App.js | 9 ++-
frontend/src/components/SomethingWentWrong.js | 67 +++++--------------
.../src/components/SomethingWentWrong.scss | 7 +-
.../__tests__/DisplayWithPermission.js | 16 ++++-
.../src/components/__tests__/FeatureFlag.js | 15 ++++-
.../__tests__/SomethingWentWrong.js | 17 +++--
6 files changed, 68 insertions(+), 63 deletions(-)
diff --git a/frontend/src/App.js b/frontend/src/App.js
index 833bfea09b..a0c4bfb219 100644
--- a/frontend/src/App.js
+++ b/frontend/src/App.js
@@ -80,6 +80,7 @@ function App() {
const [areThereUnreadNotifications, setAreThereUnreadNotifications] = useState(false);
const [errorResponseCode, setErrorResponseCode] = useState(null);
+ const [showingNotFound, setShowingNotFound] = useState(false);
useGaUserData(user);
@@ -461,12 +462,14 @@ function App() {
- {authenticated && !errorResponseCode && (
+ {authenticated && !errorResponseCode && !showingNotFound && (
<>
Skip to main content
@@ -504,7 +507,7 @@ function App() {
{authenticated && errorResponseCode
&& (
-
+
)}
{authenticated && !errorResponseCode && renderAuthenticatedRoutes()}
diff --git a/frontend/src/components/SomethingWentWrong.js b/frontend/src/components/SomethingWentWrong.js
index 3dcf1e1493..d579905a6c 100644
--- a/frontend/src/components/SomethingWentWrong.js
+++ b/frontend/src/components/SomethingWentWrong.js
@@ -8,14 +8,19 @@ import './SomethingWentWrong.scss';
/* eslint-disable max-len */
-function SomethingWentWrong({ errorResponseCode }) {
- const { setErrorResponseCode } = useContext(SomethingWentWrongContext);
+function SomethingWentWrong({ passedErrorResponseCode }) {
+ const {
+ setErrorResponseCode, errorResponseCode, setShowingNotFound, showingNotFound,
+ } = useContext(SomethingWentWrongContext);
const { setIsAppLoading, isAppLoading } = useContext(AppLoadingContext);
const history = useHistory();
// Make sure if something was loading when an error occurred, we stop the loading spinner.
if (isAppLoading) setIsAppLoading(false);
+ // Make sure if we are showing not found we hide the NAV.
+ if (!errorResponseCode && (!showingNotFound && passedErrorResponseCode === 404)) setShowingNotFound(true);
+
const supportLink = 'https://app.smartsheetgov.com/b/form/f0b4725683f04f349a939bd2e3f5425a';
const getSupportLink = () => (
support
@@ -23,52 +28,15 @@ function SomethingWentWrong({ errorResponseCode }) {
const onHomeClick = () => {
setErrorResponseCode(null);
+ setShowingNotFound(false);
history.push('/');
};
const responseCodeMessages = [
{
- code: 401,
- message: '401 error - unauthorized',
- title: 'Unauthorized access',
- body: (
-
- Sorry, but it looks like you're trying to access a restricted area. Here's what you can do:
-
- If you believe this is an error or need further assistance, get in touch with
- {' '}
- {getSupportLink()}
- .
-
- ),
- },
- {
- code: 403,
+ codes: [401, 403],
message: '403 error - forbidden',
- title: 'Restricted access',
+ title: 'Restricted access.',
body: (
Sorry, but it looks like you're trying to access a restricted area. Here's what you can do:
@@ -104,9 +72,9 @@ function SomethingWentWrong({ errorResponseCode }) {
),
},
{
- code: 404,
+ codes: [404],
message: '404 error',
- title: 'Page not found',
+ title: 'Page not found.',
body: (
Well, this is awkward. It seems like the page you're looking for has taken a detour into the unknown. Here's what you can do:
@@ -129,9 +97,9 @@ function SomethingWentWrong({ errorResponseCode }) {
),
},
{
- code: 500,
+ codes: [500],
message: null,
- title: 'Something went wrong',
+ title: 'Something went wrong.',
body: (
Well, this is awkward. It seems like the page you're looking for has taken a detour into the unknown. Here's what you can do:
@@ -152,10 +120,11 @@ function SomethingWentWrong({ errorResponseCode }) {
Thanks for your understanding and patience!
),
+
},
];
- const messageToDisplay = responseCodeMessages.find((msg) => msg.code === errorResponseCode) || responseCodeMessages.find((msg) => msg.code === 500);
+ const messageToDisplay = responseCodeMessages.find((msg) => msg.codes.includes(passedErrorResponseCode)) || responseCodeMessages.find((msg) => msg.code === 500);
return (
@@ -175,11 +144,11 @@ function SomethingWentWrong({ errorResponseCode }) {
}
SomethingWentWrong.propTypes = {
- errorResponseCode: PropTypes.number,
+ passedErrorResponseCode: PropTypes.number,
};
SomethingWentWrong.defaultProps = {
- errorResponseCode: 404,
+ passedErrorResponseCode: 404,
};
export default SomethingWentWrong;
diff --git a/frontend/src/components/SomethingWentWrong.scss b/frontend/src/components/SomethingWentWrong.scss
index 89041ac9a0..3f7c0b2e61 100644
--- a/frontend/src/components/SomethingWentWrong.scss
+++ b/frontend/src/components/SomethingWentWrong.scss
@@ -9,11 +9,16 @@
.smart-hub--something-went-wrong h1 {
font-size: 2.5rem;
font-weight: 700;
+ font-family: Merriweather, serif;
+}
+
+.smart-hub--something-went-wrong-body {
+ max-width: 700px;
}
.smart-hub--something-went-wrong p,
.smart-hub--something-went-wrong ul li button {
- color: $base-dark;
+ color: $base-darkest;
font-size: 1.25rem;
font-weight: 400;
}
diff --git a/frontend/src/components/__tests__/DisplayWithPermission.js b/frontend/src/components/__tests__/DisplayWithPermission.js
index 9b1099af10..e3863ad3a8 100644
--- a/frontend/src/components/__tests__/DisplayWithPermission.js
+++ b/frontend/src/components/__tests__/DisplayWithPermission.js
@@ -8,6 +8,7 @@ import { Router } from 'react-router';
import { createMemoryHistory } from 'history';
import DisplayWithPermission from '../DisplayWithPermission';
import UserContext from '../../UserContext';
+import SomethingWentWrongContext from '../../SomethingWentWrongContext';
const { ADMIN, READ_WRITE_TRAINING_REPORTS, READ_ACTIVITY_REPORTS } = SCOPE_IDS;
@@ -18,9 +19,18 @@ describe('display with permissions', () => {
render(
-
- This is a test
-
+
+
+
+ This is a test
+
+
,
);
diff --git a/frontend/src/components/__tests__/FeatureFlag.js b/frontend/src/components/__tests__/FeatureFlag.js
index b4594a5910..44ec216763 100644
--- a/frontend/src/components/__tests__/FeatureFlag.js
+++ b/frontend/src/components/__tests__/FeatureFlag.js
@@ -8,6 +8,7 @@ import { Router } from 'react-router';
import { createMemoryHistory } from 'history';
import FeatureFlag from '../FeatureFlag';
import UserContext from '../../UserContext';
+import SomethingWentWrongContext from '../../SomethingWentWrongContext';
const { ADMIN } = SCOPE_IDS;
@@ -18,9 +19,17 @@ describe('feature flag', () => {
render(
-
- This is a test
-
+
+
+ This is a test
+
+
,
);
diff --git a/frontend/src/components/__tests__/SomethingWentWrong.js b/frontend/src/components/__tests__/SomethingWentWrong.js
index 3902eaf977..c3ed69b7ae 100644
--- a/frontend/src/components/__tests__/SomethingWentWrong.js
+++ b/frontend/src/components/__tests__/SomethingWentWrong.js
@@ -3,6 +3,7 @@ import { render, screen } from '@testing-library/react';
import { createMemoryHistory } from 'history';
import { Router } from 'react-router';
import SomethingWentWrong from '../SomethingWentWrong';
+import SomethingWentWrongContext from '../../SomethingWentWrongContext';
const history = createMemoryHistory();
@@ -10,7 +11,15 @@ const renderSomethingWentWrong = (
responseCode = 500,
) => render(
-
+
+
+
,
);
@@ -19,8 +28,8 @@ describe('SomethingWentWrong component', () => {
it('renders a 401 error message', async () => {
renderSomethingWentWrong(401);
- expect(screen.getByText('401 error - unauthorized')).toBeInTheDocument();
- expect(screen.getByRole('heading', { name: /unauthorized access/i })).toBeInTheDocument();
+ expect(screen.getByText('403 error - forbidden')).toBeInTheDocument();
+ expect(screen.getByRole('heading', { name: /restricted access/i })).toBeInTheDocument();
expect(screen.getByText(/Sorry, but it looks like you're trying to access a restricted area./i)).toBeInTheDocument();
expect(screen.getByText(/Double-check permissions:/i)).toBeInTheDocument();
expect(screen.getByText(/Ensure you have the proper clearance to access this page/i)).toBeInTheDocument();
@@ -52,7 +61,7 @@ describe('SomethingWentWrong component', () => {
renderSomethingWentWrong(404);
expect(screen.getByText('404 error')).toBeInTheDocument();
- expect(screen.getByText('Page not found')).toBeInTheDocument();
+ expect(screen.getByText('Page not found.')).toBeInTheDocument();
expect(screen.getByText(/Well, this is awkward. It seems like the page/i)).toBeInTheDocument();
expect(screen.getByText(/home/i)).toBeInTheDocument();
expect(screen.getByText(/support/i)).toBeInTheDocument();
From accb65e990f7017fa640817d4654f07a7e7fbb87 Mon Sep 17 00:00:00 2001
From: Adam Levin
Date: Wed, 10 Jul 2024 09:42:23 -0400
Subject: [PATCH 26/26] fix link colors
---
frontend/src/components/SomethingWentWrong.scss | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/frontend/src/components/SomethingWentWrong.scss b/frontend/src/components/SomethingWentWrong.scss
index 3f7c0b2e61..af1e4ae6f1 100644
--- a/frontend/src/components/SomethingWentWrong.scss
+++ b/frontend/src/components/SomethingWentWrong.scss
@@ -6,6 +6,16 @@
font-weight: 700;
}
+.smart-hub--something-went-wrong .smart-hub--something-went-wrong-body a,
+.smart-hub--something-went-wrong .smart-hub--something-went-wrong-body button
+ {
+ color: $text-link;
+}
+
+.smart-hub--something-went-wrong .smart-hub--something-went-wrong-body a:visited {
+ color: $text-visited;
+}
+
.smart-hub--something-went-wrong h1 {
font-size: 2.5rem;
font-weight: 700;