Skip to content

Commit

Permalink
Merge pull request #554 from CBIIT/CRDCDH-1993
Browse files Browse the repository at this point in the history
CRDCDH-1993 Submitter Study Assignment (1/2) – User Mgmt
  • Loading branch information
amattu2 authored Dec 11, 2024
2 parents 503920f + ab4f623 commit 432ce48
Show file tree
Hide file tree
Showing 31 changed files with 282 additions and 576 deletions.
1 change: 0 additions & 1 deletion src/components/APITokenDialog/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ const baseUser: User = {
role: null,
IDP: "nih",
email: "",
organization: null,
studies: null,
dataCommons: [],
createdAt: "",
Expand Down
8 changes: 1 addition & 7 deletions src/components/Contexts/AuthContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,7 @@ export const AuthProvider: FC<ProviderProps> = ({ children }: ProviderProps) =>
const setData = (data: Partial<User>): void => {
if (!state.isLoggedIn) return;

// Remove any nested objects that are null
const newUser = { ...state.user, ...data };
if (!data?.organization) {
delete newUser.organization;
}

setState((prev) => ({ ...prev, user: newUser }));
setState((prev) => ({ ...prev, user: { ...state.user, ...data } }));
};

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { FC } from "react";
import { MemoryRouter } from "react-router-dom";
import { fireEvent, render, waitFor, within } from "@testing-library/react";
import { render, waitFor, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { MockedProvider, MockedResponse } from "@apollo/client/testing";
import { GraphQLError } from "graphql";
Expand Down Expand Up @@ -119,13 +119,6 @@ const baseUser: Omit<User, "role"> = {
userStatus: "Active",
IDP: "nih",
email: "",
organization: {
orgID: "some-org-1",
orgName: "org1",
status: "Active",
createdAt: "2023-10-06T19:19:04.183Z",
updateAt: "2024-07-03T19:09:29.513Z",
},
studies: null,
dataCommons: [],
createdAt: "",
Expand Down Expand Up @@ -250,77 +243,6 @@ describe("Basic Functionality", () => {
expect(handleCreate).toHaveBeenCalledTimes(1);
});

it("should disable open dialog button and show tooltip if user has 'Inactive' org", async () => {
const { getByTestId, getByRole } = render(
<TestParent
authCtxState={{
...baseAuthCtx,
user: {
...baseUser,
role: "Submitter",
organization: { ...baseUser.organization, status: "Inactive" },
},
}}
>
<CreateDataSubmissionDialog onCreate={handleCreate} />
</TestParent>
);

const openDialogButton = getByRole("button", { name: "Create a Data Submission" });
expect(openDialogButton).toBeInTheDocument();
expect(openDialogButton).toBeDisabled();

userEvent.click(openDialogButton);

await waitFor(() => {
expect(() => getByTestId("create-submission-dialog")).toThrow();
});

fireEvent.mouseOver(openDialogButton);

await waitFor(() => {
const tooltip = getByRole("tooltip");
expect(tooltip).toBeInTheDocument();
expect(tooltip).toHaveTextContent(
"Your associated organization is inactive. You cannot create a data submission at this time."
);
});
});

it("should not disable open dialog button or show tooltip if user has 'Active' org", async () => {
const { getByTestId, getByRole } = render(
<TestParent
authCtxState={{
...baseAuthCtx,
user: {
...baseUser,
role: "Submitter",
organization: { ...baseUser.organization, status: "Active" },
},
}}
>
<CreateDataSubmissionDialog onCreate={handleCreate} />
</TestParent>
);

const openDialogButton = getByRole("button", { name: "Create a Data Submission" });
expect(openDialogButton).toBeInTheDocument();

await waitFor(() => expect(openDialogButton).toBeEnabled());

fireEvent.mouseOver(openDialogButton);

await waitFor(() => {
expect(() => getByRole("tooltip")).toThrow();
});

userEvent.click(openDialogButton);

await waitFor(() => {
expect(getByTestId("create-submission-dialog")).toBeInTheDocument();
});
});

it("should only show the dbGaP ID if study is controlled access", async () => {
const { getByText, getByRole, getByTestId } = render(
<TestParent authCtxState={{ ...baseAuthCtx, user: { ...baseUser, role: "Submitter" } }}>
Expand Down
36 changes: 8 additions & 28 deletions src/components/DataSubmissions/CreateDataSubmissionDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FC, useEffect, useMemo, useState } from "react";
import { FC, useEffect, useState } from "react";
import {
Button,
Dialog,
Expand Down Expand Up @@ -236,13 +236,7 @@ const CreateDataSubmissionDialog: FC<Props> = ({ onCreate }) => {
});

const orgOwnerOrSubmitter = user?.role === "Organization Owner" || user?.role === "Submitter";
const hasOrganizationAssigned = user?.organization !== null && user?.organization?.orgID !== null;
const intention = watch("intention");
const userHasInactiveOrg = useMemo(
() => user?.organization?.status === "Inactive",
[user?.organization?.status]
);

const submissionTypeOptions: RadioOption[] = [
{
label: "New/Update",
Expand Down Expand Up @@ -559,28 +553,14 @@ const CreateDataSubmissionDialog: FC<Props> = ({ onCreate }) => {

{orgOwnerOrSubmitter && (
<StyledTooltipWrapper alignItems="center" justifyContent="flex-end">
<Tooltip
placement="top"
title="Your associated organization is inactive. You cannot create a data submission at this time."
open={undefined}
disableHoverListener={!userHasInactiveOrg}
<StyledButton
type="button"
variant="contained"
onClick={handleOpenDialog}
disabled={authStatus === AuthStatus.LOADING || approvedStudiesLoading}
>
<span>
<StyledButton
type="button"
variant="contained"
onClick={handleOpenDialog}
disabled={
!hasOrganizationAssigned ||
userHasInactiveOrg ||
authStatus === AuthStatus.LOADING ||
approvedStudiesLoading
}
>
Create a Data Submission
</StyledButton>
</span>
</Tooltip>
Create a Data Submission
</StyledButton>
</StyledTooltipWrapper>
)}
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ const baseUser: Omit<User, "role"> = {
userStatus: "Active",
IDP: "nih",
email: "",
organization: null,
studies: null,
dataCommons: [],
createdAt: "",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ const baseUser: User = {
role: null,
IDP: "nih",
email: "",
organization: null,
studies: null,
dataCommons: [],
createdAt: "",
Expand Down
1 change: 0 additions & 1 deletion src/components/DataSubmissions/DataUpload.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ const baseUser: User = {
role: "Submitter", // NOTE: This base role allows for all actions
IDP: "nih",
email: "",
organization: null,
studies: null,
dataCommons: null,
createdAt: "",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ const baseUser: User = {
role: "Submitter", // NOTE: This role has access to the delete button by default
IDP: "nih",
email: "",
organization: null,
studies: null,
dataCommons: [],
createdAt: "",
Expand Down
1 change: 0 additions & 1 deletion src/components/DataSubmissions/MetadataUpload.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ const baseUser: Omit<User, "role"> = {
userStatus: "Active",
IDP: "nih",
email: "",
organization: null,
studies: null,
dataCommons: [],
createdAt: "",
Expand Down
1 change: 0 additions & 1 deletion src/components/DataSubmissions/ValidationControls.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ const baseUser: Omit<User, "role"> = {
userStatus: "Active",
IDP: "nih",
email: "",
organization: null,
studies: null,
dataCommons: [],
createdAt: "",
Expand Down
19 changes: 0 additions & 19 deletions src/config/AuthRoles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,6 @@ export const Roles: UserRole[] = [
"Admin",
];

/**
* Defines a list of roles that are required to have an
* organization assigned to them. This unlocks the Organization assignment dropdown.
*/
export const OrgRequiredRoles: UserRole[] = ["Submitter", "Organization Owner", "Data Commons POC"];

/**
* A map of the roles that are required to be pre-assigned
* to a specific organization in the database. This locks the Organization assignment dropdown.
*
* @note This requires that an organization with the specified name exists in the database.
*/
type RoleSubset = Extends<UserRole, "Admin" | "Federal Lead" | "Federal Monitor">;
export const OrgAssignmentMap: Record<RoleSubset, string> = {
Admin: "FNL",
"Federal Lead": "NCI",
"Federal Monitor": "NCI",
};

/**
* Defines a list of roles that are allowed to interact with regular Validation.
*/
Expand Down
1 change: 0 additions & 1 deletion src/content/OperationDashboard/Controller.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ const baseUser: Omit<User, "role"> = {
userStatus: "Active",
IDP: "nih",
email: "",
organization: null,
dataCommons: [],
createdAt: "",
updateAt: "",
Expand Down
1 change: 0 additions & 1 deletion src/content/OperationDashboard/DashboardView.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ const baseUser: Omit<User, "role"> = {
userStatus: "Active",
IDP: "nih",
email: "",
organization: null,
dataCommons: [],
createdAt: "",
updateAt: "",
Expand Down
5 changes: 4 additions & 1 deletion src/content/OperationDashboard/DashboardView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,10 @@ const DashboardView: FC<DashboardViewProps> = ({
const params: DashboardContentOptions["parameters"] = [];

if (role === "Federal Monitor" && Array.isArray(studies) && studies.length > 0) {
params.push({ Name: "studiesParameter", Values: studies });
params.push({
Name: "studiesParameter",
Values: studies?.map((study: ApprovedStudy) => study?._id),
});
} else if (role === "Federal Monitor") {
Logger.error("This role requires studies to be set but none were found.", studies);
params.push({ Name: "studiesParameter", Values: ["NO-CONTENT"] });
Expand Down
1 change: 0 additions & 1 deletion src/content/dataSubmissions/SubmittedData.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ const baseUser: User = {
role: "Submitter", // NOTE: This role has access to everything nested here by default
IDP: "nih",
email: "",
organization: null,
studies: null,
dataCommons: [],
createdAt: "",
Expand Down
1 change: 0 additions & 1 deletion src/content/questionnaire/ListView.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ const baseUser: Omit<User, "role"> = {
userStatus: "Active",
IDP: "nih",
email: "",
organization: null,
dataCommons: [],
createdAt: "",
updateAt: "",
Expand Down
1 change: 0 additions & 1 deletion src/content/studies/Controller.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ const baseUser: Omit<User, "role"> = {
userStatus: "Active",
IDP: "nih",
email: "",
organization: null,
dataCommons: [],
createdAt: "",
updateAt: "",
Expand Down
23 changes: 3 additions & 20 deletions src/content/users/Controller.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { memo } from "react";
import React from "react";
import { Navigate, useParams } from "react-router-dom";
import { useAuthContext } from "../../components/Contexts/AuthContext";
import { OrganizationProvider } from "../../components/Contexts/OrganizationListContext";
import ListView from "./ListView";
import ProfileView from "./ProfileView";
import { CanManageUsers } from "../../config/AuthRoles";
Expand All @@ -10,14 +9,6 @@ type Props = {
type: "users" | "profile";
};

/**
* A memoized version of OrganizationProvider
* which caches data between ListView and ProfileView
*
* @see OrganizationProvider
*/
const MemorizedProvider = memo(OrganizationProvider);

/**
* Renders the correct view based on the URL and permissions-tier
*
Expand Down Expand Up @@ -54,19 +45,11 @@ const UserController = ({ type }: Props) => {

// Show list of users to Admin or Org Owner
if (!userId && isAdministrative) {
return (
<MemorizedProvider preload>
<ListView />
</MemorizedProvider>
);
return <ListView />;
}

// Admin or Org Owner viewing a user's "Edit User" page or their own "Edit User" page
return (
<MemorizedProvider preload={isAdministrative && type === "users"}>
<ProfileView _id={userId} viewType={type} />
</MemorizedProvider>
);
return <ProfileView _id={userId} viewType={type} />;
};

export default UserController;
Loading

0 comments on commit 432ce48

Please sign in to comment.