diff --git a/app/views/AnalysisDashboard/Analysis/AnalysisPillar/index.tsx b/app/views/AnalysisDashboard/Analysis/AnalysisPillar/index.tsx index f40f07f31..dd4a90bba 100644 --- a/app/views/AnalysisDashboard/Analysis/AnalysisPillar/index.tsx +++ b/app/views/AnalysisDashboard/Analysis/AnalysisPillar/index.tsx @@ -24,7 +24,6 @@ import { calcPercent } from '#utils/common'; import _ts from '#ts'; import styles from './styles.css'; -type PillarSummary = NonNullable['analysisPillars']>['results']>[number]; type AnalyticalStatement = NonNullable['analyticalStatements']>['results']>[number]; const statementKeySelector = (item: AnalyticalStatement) => Number(item.id); @@ -37,7 +36,8 @@ export interface Props { createdAt: string; onDelete: (value: number) => void; pendingPillarDelete: boolean; - pillarId: PillarSummary['id']; projectId: string; + pillarId: string; + projectId: string; className?: string; totalEntries: number | undefined; analyzedEntries?: number | undefined; diff --git a/app/views/AnalysisDashboard/Analysis/PillarList/index.tsx b/app/views/AnalysisDashboard/Analysis/PillarList/index.tsx index bb08c7e17..9c6ccbdf9 100644 --- a/app/views/AnalysisDashboard/Analysis/PillarList/index.tsx +++ b/app/views/AnalysisDashboard/Analysis/PillarList/index.tsx @@ -6,76 +6,130 @@ import { ListView, Kraken, } from '@the-deep/deep-ui'; +import { gql, useQuery } from '@apollo/client'; -import { AnalysisSummaryQuery } from '#generated/types'; +import { + AnalysisPillarsQuery, + AnalysisPillarsQueryVariables, +} from '#generated/types'; import AnalysisPillar, { Props as PillarComponentProps } from '../AnalysisPillar'; import styles from './styles.css'; -type PillarSummary = NonNullable['analysisPillars']>['results']>[number]; +type PillarItem = NonNullable['analysisPillars']>['results']>[number]; + +export const ANALYSIS_PILLARS = gql` + query AnalysisPillars( + $projectId: ID!, + $page: Int, + $analysisId: ID!, + $pageSize: Int, + ) { + project(id: $projectId) { + analysisPillars( + page: $page, + analyses: [$analysisId], + pageSize: $pageSize, + ) { + results { + id + title + createdAt + analysisId + analyzedEntriesCount + assignee { + displayName + id + } + statements { + id + statement + entriesCount + } + } + totalCount + } + } + } +`; const MAX_ITEMS_PER_PAGE = 5; -const keySelector = (item: PillarSummary) => item.id; +const keySelector = (item: PillarItem) => item.id; interface Props { className?: string; createdAt: string; - activeProject: string; - onAnalysisPillarDelete: () => void; + projectId: string; analysisId: string; totalEntries: number | undefined; - pillars: PillarSummary[] | null | undefined; - pillarsPending: boolean; } function AnalysisDetails(props: Props) { const { className, createdAt, - activeProject, - onAnalysisPillarDelete, + projectId, analysisId, totalEntries, - pillars, - pillarsPending, } = props; const [activePage, setActivePage] = useState(1); + const handleAnalysisPillarDelete = useCallback(() => { + console.log('here'); + }, []); + + const { + data: analysisPillarsData, + loading: pillarsPending, + } = useQuery( + ANALYSIS_PILLARS, + { + variables: { + page: activePage, + analysisId, + projectId, + pageSize: MAX_ITEMS_PER_PAGE, + }, + }, + ); + const analysisPillarRendererParams = useCallback( - (_: string, data: PillarSummary): PillarComponentProps => ({ + (_: string, data: PillarItem): PillarComponentProps => ({ className: styles.pillar, analysisId, assigneeName: data.assignee?.displayName, createdAt, - onDelete: onAnalysisPillarDelete, + onDelete: handleAnalysisPillarDelete, statements: data.statements, pillarId: data.id, analyzedEntries: data.analyzedEntriesCount, - projectId: activeProject, + projectId, title: data.title, totalEntries, pendingPillarDelete: pillarsPending, }), [ - onAnalysisPillarDelete, + handleAnalysisPillarDelete, totalEntries, createdAt, analysisId, - activeProject, + projectId, pillarsPending, ], ); + const pillars = analysisPillarsData?.project?.analysisPillars; + return ( 1 ? ( + footerActions={((pillars?.totalCount ?? 0) / MAX_ITEMS_PER_PAGE) > 1 ? ( ['analysisPillars']>['results']>[number]; +type PillarSummary = NonNullable['analyses']>['results']>[number]['pillars']>[number]; // eslint-disable-next-line @typescript-eslint/no-explicit-any const renderCustomizedLabel = (props: any) => { @@ -108,7 +110,6 @@ export interface Props { startDate?: string | null; endDate: string; onEdit: (analysisId: string) => void; - onAnalysisPillarDelete: () => void; onAnalysisCloseSuccess: () => void; teamLeadName?: string | null; createdAt: string; @@ -132,7 +133,6 @@ function Analysis(props: Props) { endDate, analysisId, teamLeadName, - onAnalysisPillarDelete, onAnalysisCloseSuccess, pillars, pillarsPending, @@ -443,11 +443,8 @@ function Analysis(props: Props) { )} diff --git a/app/views/AnalysisDashboard/AnalysisEditModal/PillarAnalysisRow/index.tsx b/app/views/AnalysisDashboard/AnalysisEditModal/PillarAnalysisRow/index.tsx index 2cd2ab648..617f3cdc1 100644 --- a/app/views/AnalysisDashboard/AnalysisEditModal/PillarAnalysisRow/index.tsx +++ b/app/views/AnalysisDashboard/AnalysisEditModal/PillarAnalysisRow/index.tsx @@ -1,5 +1,8 @@ import React from 'react'; -import { _cs } from '@togglecorp/fujs'; +import { + _cs, + isDefined, +} from '@togglecorp/fujs'; import { IoClose } from 'react-icons/io5'; import { QuickActionButton, @@ -110,8 +113,8 @@ function PillarAnalysisRow(props: Props) { className={styles.button} name={index} onClick={onRemove} - title="Remove" - disabled={pending} + title={isDefined(value.id) ? 'This cannot be removed from here. Please delete is individually from the list.' : 'Remove'} + disabled={pending || isDefined(value.id)} > diff --git a/app/views/AnalysisDashboard/AnalysisEditModal/index.tsx b/app/views/AnalysisDashboard/AnalysisEditModal/index.tsx index b4e09b347..e9fa752ca 100644 --- a/app/views/AnalysisDashboard/AnalysisEditModal/index.tsx +++ b/app/views/AnalysisDashboard/AnalysisEditModal/index.tsx @@ -6,6 +6,7 @@ import React, { import { _cs, randomString, + listToMap, isDefined, compareDate, } from '@togglecorp/fujs'; @@ -47,6 +48,8 @@ import { AnalysisInputType, FrameworkDetailsForAnalysisQuery, FrameworkDetailsForAnalysisQueryVariables, + CreateAnalysisMutation, + CreateAnalysisMutationVariables, UpdateAnalysisMutation, UpdateAnalysisMutationVariables, UserMembersQuery, @@ -77,6 +80,49 @@ const FRAMEWORK_DETAILS_FOR_ANALYSIS = gql` } `; +const CREATE_ANALYSIS = gql` + mutation CreateAnalysis( + $projectId: ID!, + $data: AnalysisInputType!, + ) { + project(id: $projectId) { + analysisCreate( + data: $data, + ) { + ok + errors + result { + id + title + endDate + startDate + pillars { + id + assignee { + id + displayName + emailDisplay + } + analysisId + clientId + title + filters { + id + key + uniqueId + } + } + teamLead { + id + displayName + emailDisplay + } + } + } + } + } +`; + const UPDATE_ANALYSIS = gql` mutation UpdateAnalysis( $projectId: ID!, @@ -96,6 +142,7 @@ const UPDATE_ANALYSIS = gql` endDate startDate pillars { + id assignee { id displayName @@ -138,6 +185,7 @@ const ANALYSIS_DETAIL = gql` startDate endDate pillars { + id title analysisId clientId @@ -203,6 +251,7 @@ type AnalysisPillarSchema = ObjectSchema, Partia type AnalysisPillarSchemaFields = ReturnType; const analysisPillarSchema: AnalysisPillarSchema = { fields: (): AnalysisPillarSchemaFields => ({ + id: [defaultUndefinedType], clientId: [defaultUndefinedType], title: [requiredStringCondition], assignee: [requiredCondition], @@ -254,7 +303,7 @@ interface AnalysisEditModalProps { className?: string; onSuccess: () => void; onModalClose: () => void; - analysisToEdit: string; + analysisToEdit: string | undefined; projectId: string; } @@ -319,15 +368,21 @@ function AnalysisEditModal(props: AnalysisEditModalProps) { const alert = useAlert(); + const analysisDetailVariables = useMemo(() => (analysisToEdit ? ({ + projectId, + analysisId: analysisToEdit, + }) : undefined), [ + projectId, + analysisToEdit, + ]); + const { loading: analysisDetailLoading, } = useQuery( ANALYSIS_DETAIL, { - variables: { - projectId, - analysisId: analysisToEdit, - }, + skip: !analysisDetailVariables, + variables: analysisDetailVariables, onCompleted: (response) => { const { analysis, @@ -342,6 +397,7 @@ function AnalysisEditModal(props: AnalysisEditModalProps) { endDate: analysis?.endDate, teamLead: analysis.teamLead.id, analysisPillar: analysis.pillars?.map((pillar: AnalysisPillar) => ({ + id: pillar.id, analysisId: pillar.analysisId, clientId: pillar.clientId, title: pillar.title, @@ -372,9 +428,56 @@ function AnalysisEditModal(props: AnalysisEditModalProps) { }, ); + const [ + triggerAnalysisCreate, + { loading: createAnalysisPending }, + ] = useMutation( + CREATE_ANALYSIS, + { + refetchQueries: [ + { + query: ANALYSIS_DETAIL, + variables: { + projectId, + analysisId: analysisToEdit, + }, + }], + onCompleted: (response) => { + const updateDraftAnalysisResponse = response?.project?.analysisCreate; + if (!response) { + return; + } + if (updateDraftAnalysisResponse?.ok) { + onSuccess(); + alert.show( + 'Successfully created new analysis.', + { + variant: 'success', + }, + ); + } else { + alert.show( + 'Failed to create the analysis.', + { + variant: 'error', + }, + ); + } + }, + onError: () => { + alert.show( + 'Failed to change the analysis.', + { + variant: 'error', + }, + ); + }, + }, + ); + const [ triggerAnalysisEdit, - { loading: UpdateAnalysisPending }, + { loading: updateAnalysisPending }, ] = useMutation( UPDATE_ANALYSIS, { @@ -420,7 +523,7 @@ function AnalysisEditModal(props: AnalysisEditModalProps) { ); const pending = pendingFramework || pendingUsersList - || UpdateAnalysisPending || analysisDetailLoading; + || updateAnalysisPending || analysisDetailLoading || createAnalysisPending; const { setValue: onRowChange, @@ -457,27 +560,47 @@ function AnalysisEditModal(props: AnalysisEditModalProps) { validate, setError, (val) => { + const matrixMap = listToMap( + matrixPillars, + (d) => d.uniqueId, + (d) => ({ + id: d.id, + key: d.key, + uniqueId: d.uniqueId, + }), + ); const cleanedData = { ...val, analysisPillar: val.analysisPillar?.map((pillar) => ({ ...pillar, - assignee: pillar.assignee, - clientId: pillar.clientId, + filters: pillar.filters?.map((f) => matrixMap[f]), })), - } as unknown as AnalysisInputType; - triggerAnalysisEdit({ - variables: { - data: cleanedData, - projectId, - analysisId: analysisToEdit, - }, - }); + } as AnalysisInputType; + + if (isDefined(analysisToEdit)) { + triggerAnalysisEdit({ + variables: { + data: cleanedData, + projectId, + analysisId: analysisToEdit, + }, + }); + } else { + triggerAnalysisCreate({ + variables: { + data: cleanedData, + projectId, + }, + }); + } }, ); submit(); }, [ + matrixPillars, validate, setError, + triggerAnalysisCreate, triggerAnalysisEdit, projectId, analysisToEdit, diff --git a/app/views/AnalysisDashboard/index.tsx b/app/views/AnalysisDashboard/index.tsx index 932a3f77a..6bbd0232c 100644 --- a/app/views/AnalysisDashboard/index.tsx +++ b/app/views/AnalysisDashboard/index.tsx @@ -127,24 +127,6 @@ export const ANALYSIS_SUMMARY = gql` statement } } - analysisPillars { - results { - assignee { - displayName - id - } - title - analyzedEntriesCount - analysisId - id - createdAt - statements { - id - statement - entriesCount - } - } - } } } `; @@ -374,7 +356,6 @@ function AnalysisDashboard(props: AnalysisDashboardProps) { totalSources: totalLeadsCount, totalEntries: totalEntriesCount, onAnalysisCloseSuccess: getProjectAnalysis, - onAnalysisPillarDelete: getProjectAnalysis, pendingAnalysisDelete: deleteAnalysisPending && data.id === id, }), [ analyzedEntriesCount, @@ -403,7 +384,7 @@ function AnalysisDashboard(props: AnalysisDashboardProps) { )} > - {_ts('analysis', 'setupNewAnalysisButtonLabel')} + Setup a new analysis )} @@ -560,7 +541,7 @@ function AnalysisDashboard(props: AnalysisDashboardProps) { messageShown /> - {showAnalysisAddModal && activeProject && analysisToEdit && ( + {showAnalysisAddModal && activeProject && (