Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
86ae41e
MPDX-9771 - Plumb MPD supervisor admin flag and impersonation scope i…
wjames111 Jul 14, 2026
07f5eed
MPDX-9771 - Block contacts, tasks, and tools routes during restricted…
wjames111 Jul 14, 2026
229ab99
MPDX-9771 - Hide contacts, tasks, and tools nav and expose Admin Cons…
wjames111 Jul 14, 2026
c3b232d
MPDX-9771 - Add impersonate action to MPD Goal Admin rows
wjames111 Jul 14, 2026
065d159
MPDX-9771 - Render non-editable HR forms read-only during restricted …
wjames111 Jul 14, 2026
51dce70
fix: address review comment on AdditionalSalaryRequestContext.tsx:220
wjames111 Jul 15, 2026
3ba67c1
fix: address review comment on useAdditionalSalaryRequestForm.ts:209
wjames111 Jul 15, 2026
407f1c1
fix: address review comment on pagePropsHelpers.ts:64
wjames111 Jul 15, 2026
6e9b5ac
fix: address review comment on useNavPages.tsx:66
wjames111 Jul 15, 2026
b9e9377
fix: address review comment on TransfersTable.tsx:191
wjames111 Jul 15, 2026
e7d9a96
fix: address review comment on [...nextauth].page.ts:291
wjames111 Jul 15, 2026
1b497d0
fix: address review comment on HoursPerWeekGrid.tsx:135
wjames111 Jul 15, 2026
5f9a946
fix: address review comment on GoalCard.tsx:66
wjames111 Jul 15, 2026
3f607eb
fix: address review comment on GoalsTable.tsx:57
wjames111 Jul 15, 2026
ff99d0c
fix: address review comment on useSettingsNavItems.ts:62
wjames111 Jul 15, 2026
4010f64
fix: address review comment on DirectionButtons.tsx:149
wjames111 Jul 15, 2026
b499a65
fix: block restricted impersonation on tools landing page
wjames111 Jul 15, 2026
2a1caf4
test: move restricted-impersonation submit test to end of onSubmit block
wjames111 Jul 15, 2026
8e1d03c
Merge remote-tracking branch 'origin/main' into MPDX-9771
wjames111 Jul 15, 2026
42dd3bf
fix: address review comment on useAdditionalSalaryRequestForm.test.ts…
wjames111 Jul 16, 2026
be640d5
fix: address review comment on restrictedImpersonation.ts:13
wjames111 Jul 16, 2026
a416268
fix: address review comment on GoalsTable.test.tsx:207
wjames111 Jul 16, 2026
5a88882
Rely on API mutation blocking instead of frontend read-only guards
wjames111 Jul 17, 2026
9ac10be
Restore developer access to the Admin Console
wjames111 Jul 17, 2026
2762f25
MPDX-9771 - Base impersonation access on coaching, not a flag
wjames111 Jul 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions __tests__/fixtures/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const session: Session = {
userID: 'user-1',
admin: false,
developer: false,
coach: false,
impersonating: false,
},
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Head from 'next/head';
import React, { useContext } from 'react';
import { useTranslation } from 'react-i18next';
import { ensureSessionAndAccountList } from 'pages/api/utils/pagePropsHelpers';
import { blockRestrictedImpersonation } from 'pages/api/utils/pagePropsHelpers';
import {
ContactsContext,
ContactsType,
Expand Down Expand Up @@ -66,4 +66,4 @@ const ContactsPage: React.FC = () => (

export default ContactsPage;

export const getServerSideProps = ensureSessionAndAccountList;
export const getServerSideProps = blockRestrictedImpersonation;
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useSnackbar } from 'notistack';
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import { useTranslation } from 'react-i18next';
import { ensureSessionAndAccountList } from 'pages/api/utils/pagePropsHelpers';
import { blockRestrictedImpersonation } from 'pages/api/utils/pagePropsHelpers';
import { colorMap } from 'src/components/Contacts/ContactFlow/ContactFlow';
import { ContactFlowSetupColumn } from 'src/components/Contacts/ContactFlow/ContactFlowSetup/Column/ContactFlowSetupColumn';
import { UnusedStatusesColumn } from 'src/components/Contacts/ContactFlow/ContactFlowSetup/Column/UnusedStatusesColumn';
Expand Down Expand Up @@ -227,6 +227,6 @@ const ContactFlowSetupPage: React.FC = () => {
);
};

export const getServerSideProps = ensureSessionAndAccountList;
export const getServerSideProps = blockRestrictedImpersonation;

export default ContactFlowSetupPage;
14 changes: 14 additions & 0 deletions pages/accountLists/[accountListId]/settings/admin.page.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { render, waitFor } from '@testing-library/react';
import { SnackbarProvider } from 'notistack';
import TestRouter from '__tests__/util/TestRouter';
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
import { mockSession } from '__tests__/util/mockSession';
import { AdminAccordion } from 'src/components/Shared/Forms/Accordions/AccordionEnum';
import theme from 'src/theme';
import Admin from './admin.page';
Expand Down Expand Up @@ -36,6 +37,8 @@ const Components: React.FC<ComponentsProps> = ({ selectedTab }) => (

describe('Admin', () => {
it('should keep impersonate user accordion close', async () => {
mockSession({ admin: true });

const { getAllByText } = render(<Components />);
await waitFor(() => {
expect(getAllByText('Impersonate User')).toHaveLength(3);
Expand All @@ -44,6 +47,8 @@ describe('Admin', () => {
});

it('should open impersonate user accordion', async () => {
mockSession({ admin: true });

const { getAllByText } = render(
<Components selectedTab={AdminAccordion.ResetAccount} />,
);
Expand All @@ -52,4 +57,13 @@ describe('Admin', () => {
expect(getAllByText('Reset Account').length).toEqual(3);
});
});

it('should hide the reset account accordion from MPD supervisor admins who are not admins', async () => {
mockSession({ admin: false, coach: true });

const { findAllByText, queryByText } = render(<Components />);

expect(await findAllByText('Impersonate User')).toHaveLength(3);
expect(queryByText('Reset Account')).not.toBeInTheDocument();
});
});
16 changes: 10 additions & 6 deletions pages/accountLists/[accountListId]/settings/admin.page.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import { useRouter } from 'next/router';
import React, { ReactElement, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { enforceAdmin } from 'pages/api/utils/pagePropsHelpers';
import { enforceAdminOrCoach } from 'pages/api/utils/pagePropsHelpers';
import { ImpersonateUserAccordion } from 'src/components/Settings/Admin/ImpersonateUser/ImpersonateUserAccordion';
import { ResetAccountAccordion } from 'src/components/Settings/Admin/ResetAccount/ResetAccountAccordion';
import { AdminAccordion } from 'src/components/Shared/Forms/Accordions/AccordionEnum';
import { AccordionGroup } from 'src/components/Shared/Forms/Accordions/AccordionGroup';
import { useRequiredSession } from 'src/hooks/useRequiredSession';
import { SettingsWrapper } from './Wrapper';

export const suggestedArticles = 'HS_SETTINGS_SERVICES_SUGGESTIONS';

const Admin = (): ReactElement => {
const { t } = useTranslation();
const { query } = useRouter();
const user = useRequiredSession();
const [expandedAccordion, setExpandedAccordion] =
useState<AdminAccordion | null>(
typeof query.selectedTab === 'string'
Expand All @@ -32,15 +34,17 @@ const Admin = (): ReactElement => {
expandedAccordion={expandedAccordion}
/>

<ResetAccountAccordion
handleAccordionChange={setExpandedAccordion}
expandedAccordion={expandedAccordion}
/>
{user.admin && (
<ResetAccountAccordion
handleAccordionChange={setExpandedAccordion}
expandedAccordion={expandedAccordion}
/>
)}
</AccordionGroup>
</SettingsWrapper>
);
};

export const getServerSideProps = enforceAdmin;
export const getServerSideProps = enforceAdminOrCoach;

export default Admin;
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Box, Button, ButtonGroup } from '@mui/material';
import { styled } from '@mui/material/styles';
import { DateTime } from 'luxon';
import { useTranslation } from 'react-i18next';
import { ensureSessionAndAccountList } from 'pages/api/utils/pagePropsHelpers';
import { blockRestrictedImpersonation } from 'pages/api/utils/pagePropsHelpers';
import { DynamicContactsRightPanel } from 'src/components/Contacts/ContactsRightPanel/DynamicContactsRightPanel';
import { InfiniteList } from 'src/components/InfiniteList/InfiniteList';
import { navBarHeight } from 'src/components/Layouts/Primary/Primary';
Expand Down Expand Up @@ -382,6 +382,6 @@ const TasksPage: React.FC = () => (
</UrlFiltersProvider>
);

export const getServerSideProps = ensureSessionAndAccountList;
export const getServerSideProps = blockRestrictedImpersonation;

export default TasksPage;
7 changes: 6 additions & 1 deletion pages/accountLists/[accountListId]/tools.page.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import { render, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import TestRouter from '__tests__/util/TestRouter';
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
import { blockRestrictedImpersonation } from 'pages/api/utils/pagePropsHelpers';
import theme from 'src/theme';
import ToolsPage from './tools.page';
import ToolsPage, { getServerSideProps } from './tools.page';

const accountListId = 'account-list-1';

Expand Down Expand Up @@ -34,6 +35,10 @@ const MocksProviders: React.FC<MocksProvidersProps> = ({ children, setup }) => (
);

describe('Tools Page', () => {
it('blocks restricted impersonation in getServerSideProps', () => {
expect(getServerSideProps).toBe(blockRestrictedImpersonation);
});

it('should render page', async () => {
const { findByText } = render(
<MocksProviders>
Expand Down
4 changes: 2 additions & 2 deletions pages/accountLists/[accountListId]/tools.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useRouter } from 'next/router';
import React, { ReactElement } from 'react';
import { Button } from '@mui/material';
import { useTranslation } from 'react-i18next';
import { ensureSessionAndAccountList } from 'pages/api/utils/pagePropsHelpers';
import { blockRestrictedImpersonation } from 'pages/api/utils/pagePropsHelpers';
import { SetupBanner } from 'src/components/Settings/preferences/SetupBanner';
import { StickyBox } from 'src/components/Shared/Header/styledComponents';
import ToolsHome from 'src/components/Tool/Home/ToolsHome';
Expand Down Expand Up @@ -43,6 +43,6 @@ const ToolsPage = (): ReactElement => {
);
};

export const getServerSideProps = ensureSessionAndAccountList;
export const getServerSideProps = blockRestrictedImpersonation;

export default ToolsPage;
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Head from 'next/head';
import React, { ReactElement } from 'react';
import { useTranslation } from 'react-i18next';
import { ensureSessionAndAccountList } from 'pages/api/utils/pagePropsHelpers';
import { blockRestrictedImpersonation } from 'pages/api/utils/pagePropsHelpers';
import AppealsDetailsPage from 'src/components/Tool/Appeal/AppealDetails/AppealsDetailsPage';
import { getAppName } from 'src/lib/getAppName';
import { AppealsWrapper } from '../AppealsWrapper';
Expand Down Expand Up @@ -29,4 +29,4 @@ const AppealsPage: React.FC = () => (

export default AppealsPage;

export const getServerSideProps = ensureSessionAndAccountList;
export const getServerSideProps = blockRestrictedImpersonation;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { ReactElement } from 'react';
import { useTranslation } from 'react-i18next';
import { ensureSessionAndAccountList } from 'pages/api/utils/pagePropsHelpers';
import { blockRestrictedImpersonation } from 'pages/api/utils/pagePropsHelpers';
import AppealsInitialPage from 'src/components/Tool/Appeal/InitialPage/AppealsInitialPage';
import { ToolsWrapper } from '../ToolsWrapper';

Expand All @@ -16,4 +16,4 @@ const AppealsPage = (): ReactElement => {

export default AppealsPage;

export const getServerSideProps = ensureSessionAndAccountList;
export const getServerSideProps = blockRestrictedImpersonation;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { ensureSessionAndAccountList } from 'pages/api/utils/pagePropsHelpers';
import { blockRestrictedImpersonation } from 'pages/api/utils/pagePropsHelpers';
import FixCommitmentInfo from 'src/components/Tool/FixCommitmentInfo/FixCommitmentInfo';
import { useAccountListId } from 'src/hooks/useAccountListId';
import { ToolsWrapper } from '../../ToolsWrapper';
Expand All @@ -19,6 +19,6 @@ const FixCommitmentInfoPage: React.FC = () => {
);
};

export const getServerSideProps = ensureSessionAndAccountList;
export const getServerSideProps = blockRestrictedImpersonation;

export default FixCommitmentInfoPage;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { ensureSessionAndAccountList } from 'pages/api/utils/pagePropsHelpers';
import { blockRestrictedImpersonation } from 'pages/api/utils/pagePropsHelpers';
import { FixEmailAddresses } from 'src/components/Tool/FixEmailAddresses/FixEmailAddresses';
import { useAccountListId } from 'src/hooks/useAccountListId';
import { ToolsWrapper } from '../../ToolsWrapper';
Expand All @@ -19,6 +19,6 @@ const FixEmailAddressesPage: React.FC = () => {
);
};

export const getServerSideProps = ensureSessionAndAccountList;
export const getServerSideProps = blockRestrictedImpersonation;

export default FixEmailAddressesPage;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { ensureSessionAndAccountList } from 'pages/api/utils/pagePropsHelpers';
import { blockRestrictedImpersonation } from 'pages/api/utils/pagePropsHelpers';
import FixMailingAddresses from 'src/components/Tool/FixMailingAddresses/FixMailingAddresses';
import { useAccountListId } from 'src/hooks/useAccountListId';
import { ToolsWrapper } from '../../ToolsWrapper';
Expand All @@ -19,6 +19,6 @@ const FixMailingAddressesPage: React.FC = () => {
);
};

export const getServerSideProps = ensureSessionAndAccountList;
export const getServerSideProps = blockRestrictedImpersonation;

export default FixMailingAddressesPage;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { ensureSessionAndAccountList } from 'pages/api/utils/pagePropsHelpers';
import { blockRestrictedImpersonation } from 'pages/api/utils/pagePropsHelpers';
import FixPhoneNumbers from 'src/components/Tool/FixPhoneNumbers/FixPhoneNumbers';
import { useAccountListId } from 'src/hooks/useAccountListId';
import { ToolsWrapper } from '../../ToolsWrapper';
Expand All @@ -19,6 +19,6 @@ const FixPhoneNumbersPage: React.FC = () => {
);
};

export const getServerSideProps = ensureSessionAndAccountList;
export const getServerSideProps = blockRestrictedImpersonation;

export default FixPhoneNumbersPage;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { ensureSessionAndAccountList } from 'pages/api/utils/pagePropsHelpers';
import { blockRestrictedImpersonation } from 'pages/api/utils/pagePropsHelpers';
import FixSendNewsletter from 'src/components/Tool/FixSendNewsletter/FixSendNewsletter';
import { useAccountListId } from 'src/hooks/useAccountListId';
import { ToolsWrapper } from '../../ToolsWrapper';
Expand All @@ -19,6 +19,6 @@ const FixSendNewsletterPage: React.FC = () => {
);
};

export const getServerSideProps = ensureSessionAndAccountList;
export const getServerSideProps = blockRestrictedImpersonation;

export default FixSendNewsletterPage;
4 changes: 2 additions & 2 deletions pages/accountLists/[accountListId]/tools/import/csv.page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useRouter } from 'next/router';
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { ensureSessionAndAccountList } from 'pages/api/utils/pagePropsHelpers';
import { blockRestrictedImpersonation } from 'pages/api/utils/pagePropsHelpers';
import {
CsvImportProvider,
CsvImportViewStepEnum,
Expand Down Expand Up @@ -73,6 +73,6 @@ const CsvHome: React.FC = () => {
);
};

export const getServerSideProps = ensureSessionAndAccountList;
export const getServerSideProps = blockRestrictedImpersonation;

export default CsvHome;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { ensureSessionAndAccountList } from 'pages/api/utils/pagePropsHelpers';
import { blockRestrictedImpersonation } from 'pages/api/utils/pagePropsHelpers';
import Loading from 'src/components/Loading';
import GoogleImport from 'src/components/Tool/GoogleImport/GoogleImport';
import { useAccountListId } from 'src/hooks/useAccountListId';
Expand All @@ -24,6 +24,6 @@ const GoogleImportPage: React.FC = () => {
);
};

export const getServerSideProps = ensureSessionAndAccountList;
export const getServerSideProps = blockRestrictedImpersonation;

export default GoogleImportPage;
4 changes: 2 additions & 2 deletions pages/accountLists/[accountListId]/tools/import/tnt.page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { ensureSessionAndAccountList } from 'pages/api/utils/pagePropsHelpers';
import { blockRestrictedImpersonation } from 'pages/api/utils/pagePropsHelpers';
import Loading from 'src/components/Loading';
import TntConnect from 'src/components/Tool/TntConnect/TntConnect';
import { useAccountListId } from 'src/hooks/useAccountListId';
Expand All @@ -24,6 +24,6 @@ const TntConnectPage: React.FC = () => {
);
};

export const getServerSideProps = ensureSessionAndAccountList;
export const getServerSideProps = blockRestrictedImpersonation;

export default TntConnectPage;
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useRouter } from 'next/router';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { ensureSessionAndAccountList } from 'pages/api/utils/pagePropsHelpers';
import { blockRestrictedImpersonation } from 'pages/api/utils/pagePropsHelpers';
import MergeContacts from 'src/components/Tool/MergeContacts/MergeContacts';
import { useAccountListId } from 'src/hooks/useAccountListId';
import { ToolsWrapper } from '../../ToolsWrapper';
Expand All @@ -26,6 +26,6 @@ const MergeContactsPage: React.FC = () => {
);
};

export const getServerSideProps = ensureSessionAndAccountList;
export const getServerSideProps = blockRestrictedImpersonation;

export default MergeContactsPage;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { ensureSessionAndAccountList } from 'pages/api/utils/pagePropsHelpers';
import { blockRestrictedImpersonation } from 'pages/api/utils/pagePropsHelpers';
import MergePeople from 'src/components/Tool/MergePeople/MergePeople';
import { useAccountListId } from 'src/hooks/useAccountListId';
import { ToolsWrapper } from '../../ToolsWrapper';
Expand All @@ -16,6 +16,6 @@ const MergePeoplePage: React.FC = () => {
);
};

export const getServerSideProps = ensureSessionAndAccountList;
export const getServerSideProps = blockRestrictedImpersonation;

export default MergePeoplePage;
Loading
Loading