diff --git a/source/frontend/src/features/mapSideBar/research/tabs/ResearchTabsContainer.tsx b/source/frontend/src/features/mapSideBar/research/tabs/ResearchTabsContainer.tsx index 9599b4500f..d70fdb5d18 100644 --- a/source/frontend/src/features/mapSideBar/research/tabs/ResearchTabsContainer.tsx +++ b/source/frontend/src/features/mapSideBar/research/tabs/ResearchTabsContainer.tsx @@ -13,6 +13,7 @@ import { SideBarContext } from '../../context/sidebarContext'; import { FileTabs, FileTabType, TabFileView } from '../../shared/detail/FileTabs'; import DocumentsTab from '../../shared/tabs/DocumentsTab'; import ResearchSummaryView from './fileDetails/details/ResearchSummaryView'; +import ResearchStatusUpdateSolver from './fileDetails/ResearchStatusUpdateSolver'; export interface IResearchTabsContainerProps { researchFile?: ApiGen_Concepts_ResearchFile; @@ -35,6 +36,7 @@ export const ResearchTabsContainer: React.FunctionComponent< const defaultTab = FileTabType.FILE_DETAILS; const { tab } = useParams<{ tab?: string }>(); const activeTab = Object.values(FileTabType).find(value => value === tab) ?? defaultTab; + const statusSolver = new ResearchStatusUpdateSolver(researchFile); const setActiveTab = (tab: FileTabType) => { if (activeTab !== tab) { @@ -47,7 +49,13 @@ export const ResearchTabsContainer: React.FunctionComponent< }; tabViews.push({ - content: , + content: ( + + ), key: FileTabType.FILE_DETAILS, name: 'File Details', }); diff --git a/source/frontend/src/features/mapSideBar/research/tabs/fileDetails/details/ResearchSummaryView.test.tsx b/source/frontend/src/features/mapSideBar/research/tabs/fileDetails/details/ResearchSummaryView.test.tsx index 260447239a..479ba73073 100644 --- a/source/frontend/src/features/mapSideBar/research/tabs/fileDetails/details/ResearchSummaryView.test.tsx +++ b/source/frontend/src/features/mapSideBar/research/tabs/fileDetails/details/ResearchSummaryView.test.tsx @@ -3,6 +3,7 @@ import { getMockResearchFile } from '@/mocks/researchFile.mock'; import { act, render, RenderOptions, userEvent } from '@/utils/test-utils'; import ResearchSummaryView, { IResearchSummaryViewProps } from './ResearchSummaryView'; +import Roles from '@/constants/roles'; const setEditMode = vi.fn(); @@ -13,6 +14,7 @@ describe('ResearchSummaryView component', () => { , { ...renderOptions, @@ -28,7 +30,11 @@ describe('ResearchSummaryView component', () => { }); it('renders as expected when research file is provided', () => { - const { asFragment } = setup({ researchFile: getMockResearchFile(), setEditMode }); + const { asFragment } = setup({ + researchFile: getMockResearchFile(), + setEditMode, + isFileFinalStatus: false, + }); expect(asFragment()).toMatchSnapshot(); }); @@ -37,6 +43,7 @@ describe('ResearchSummaryView component', () => { researchFile: getMockResearchFile(), setEditMode, claims: [], + isFileFinalStatus: false, }); const editResearchFile = queryByTitle('Edit research file'); expect(editResearchFile).toBeNull(); @@ -47,6 +54,7 @@ describe('ResearchSummaryView component', () => { researchFile: getMockResearchFile(), setEditMode, claims: [Claims.RESEARCH_EDIT], + isFileFinalStatus: false, }); const editResearchFile = getByTitle('Edit research file'); expect(editResearchFile).toBeVisible(); @@ -57,9 +65,33 @@ describe('ResearchSummaryView component', () => { researchFile: getMockResearchFile(), setEditMode, claims: [Claims.RESEARCH_EDIT], + isFileFinalStatus: false, }); const editResearchFile = getByTitle('Edit research file'); await act(async () => userEvent.click(editResearchFile)); expect(setEditMode).toHaveBeenCalledWith(true); }); + + it('displays a warning tooltip when the user cannot edit', async () => { + const { getByTestId } = setup({ + researchFile: getMockResearchFile(), + setEditMode, + claims: [Claims.RESEARCH_EDIT], + isFileFinalStatus: true, + }); + const editResearchFile = getByTestId('tooltip-icon-research-cannot-edit-tooltip'); + expect(editResearchFile).toBeVisible(); + }); + + it('ignores final file status and is editable when user is an admin', async () => { + const { queryByTestId } = setup({ + researchFile: getMockResearchFile(), + setEditMode, + claims: [Claims.RESEARCH_EDIT], + roles: [Roles.SYSTEM_ADMINISTRATOR], + isFileFinalStatus: true, + }); + const editResearchFile = queryByTestId('tooltip-icon-research-cannot-edit-tooltip'); + expect(editResearchFile).toBeNull(); + }); }); diff --git a/source/frontend/src/features/mapSideBar/research/tabs/fileDetails/details/ResearchSummaryView.tsx b/source/frontend/src/features/mapSideBar/research/tabs/fileDetails/details/ResearchSummaryView.tsx index 0587ef2473..8f54fbea6f 100644 --- a/source/frontend/src/features/mapSideBar/research/tabs/fileDetails/details/ResearchSummaryView.tsx +++ b/source/frontend/src/features/mapSideBar/research/tabs/fileDetails/details/ResearchSummaryView.tsx @@ -2,7 +2,10 @@ import EditButton from '@/components/common/buttons/EditButton'; import { Section } from '@/components/common/Section/Section'; import { SectionField } from '@/components/common/Section/SectionField'; import { StyledEditWrapper, StyledSummarySection } from '@/components/common/Section/SectionStyles'; +import TooltipIcon from '@/components/common/TooltipIcon'; import Claims from '@/constants/claims'; +import Roles from '@/constants/roles'; +import { cannotEditMessage } from '@/features/mapSideBar/acquisition/common/constants'; import useKeycloakWrapper from '@/hooks/useKeycloakWrapper'; import { ApiGen_Concepts_ResearchFile } from '@/models/api/generated/ApiGen_Concepts_ResearchFile'; import { exists, formatApiProjectName, prettyFormatDate } from '@/utils'; @@ -32,6 +35,7 @@ interface DetailResearchFile { export interface IResearchSummaryViewProps { researchFile?: ApiGen_Concepts_ResearchFile; setEditMode: (editable: boolean) => void; + isFileFinalStatus: boolean; } const ResearchSummaryView: React.FunctionComponent = props => { @@ -80,7 +84,9 @@ const ResearchSummaryView: React.FunctionComponent = return ( - {keycloak.hasClaim(Claims.RESEARCH_EDIT) && props.researchFile !== undefined ? ( + {keycloak.hasClaim(Claims.RESEARCH_EDIT) && + (!props.isFileFinalStatus || keycloak.hasRole(Roles.SYSTEM_ADMINISTRATOR)) && + props.researchFile !== undefined ? ( { @@ -89,6 +95,11 @@ const ResearchSummaryView: React.FunctionComponent = style={{ float: 'right' }} /> ) : null} + {keycloak.hasClaim(Claims.RESEARCH_EDIT) && + props.isFileFinalStatus && + !keycloak.hasRole(Roles.SYSTEM_ADMINISTRATOR) && ( + + )}