From 1f6da7429083de08e2277f3c0bb16055c47fb77c Mon Sep 17 00:00:00 2001 From: barshathakuri Date: Thu, 18 Jul 2024 15:09:43 +0545 Subject: [PATCH] Add query for edit analysis dashboard --- app/types/analysisModule.tsx | 2 - app/types/user.tsx | 2 +- .../Analysis/AnalysisCloneModal/index.tsx | 16 -- .../Analysis/AnalysisPillar/index.tsx | 11 +- .../Analysis/PillarAssignment/index.tsx | 8 +- .../Analysis/PillarList/index.tsx | 7 +- .../AnalysisDashboard/Analysis/index.tsx | 37 +-- .../PillarAnalysisRow/index.tsx | 19 +- .../AnalysisEditModal/index.tsx | 142 +++++------ app/views/AnalysisDashboard/index.tsx | 232 +++++++++--------- 10 files changed, 227 insertions(+), 249 deletions(-) diff --git a/app/types/analysisModule.tsx b/app/types/analysisModule.tsx index 3169fea9de..5ad988e431 100644 --- a/app/types/analysisModule.tsx +++ b/app/types/analysisModule.tsx @@ -48,8 +48,6 @@ export interface PillarSummary { totalCount?: number | null | undefined; } | null | undefined; analyticalStatementCount: number; - analyticalStatements: any[]; - assigneeDetails: any; } export interface AnalysisElement { diff --git a/app/types/user.tsx b/app/types/user.tsx index f8ccd9af36..d494eaf337 100644 --- a/app/types/user.tsx +++ b/app/types/user.tsx @@ -16,7 +16,7 @@ export interface User { } export interface UserMini { - id: number; + id: string; email: string; displayName: string; } diff --git a/app/views/AnalysisDashboard/Analysis/AnalysisCloneModal/index.tsx b/app/views/AnalysisDashboard/Analysis/AnalysisCloneModal/index.tsx index 1beaa8e772..8c5d409664 100644 --- a/app/views/AnalysisDashboard/Analysis/AnalysisCloneModal/index.tsx +++ b/app/views/AnalysisDashboard/Analysis/AnalysisCloneModal/index.tsx @@ -88,22 +88,6 @@ function AnalysisCloneModal(props: Props) { const error = getErrorObject(riskyError); - /* - const { - pending: pendingAnalysisGet, - } = useRequest({ - url: `server://projects/${projectId}/analysis/${analysisId}/`, - method: 'GET', - onSuccess: (response) => { - setValue({ - title: response.title, - startDate: response.startDate, - endDate: response.endDate, - }); - }, - }); - */ - const { pending: pendingAnalysisClone, trigger: triggerAnalysisClone, diff --git a/app/views/AnalysisDashboard/Analysis/AnalysisPillar/index.tsx b/app/views/AnalysisDashboard/Analysis/AnalysisPillar/index.tsx index 7db7fb6249..235642af0b 100644 --- a/app/views/AnalysisDashboard/Analysis/AnalysisPillar/index.tsx +++ b/app/views/AnalysisDashboard/Analysis/AnalysisPillar/index.tsx @@ -35,10 +35,11 @@ export interface Props { title: string; createdAt: string; onDelete: (value: number) => void; + pendingPillarDelete: boolean; pillarId: PillarSummary['id']; projectId: string; className?: string; totalEntries: number; - analyzedEntries?: number; + analyzedEntries?: number | undefined; } function AnalysisPillar(props: Props) { @@ -53,6 +54,7 @@ function AnalysisPillar(props: Props) { statements, className, totalEntries, + pendingPillarDelete, analyzedEntries = 0, } = props; @@ -72,6 +74,7 @@ function AnalysisPillar(props: Props) { } const onDeleteConfirmClick = useCallback(() => { + // TODO: Remove Number in pillarId onDelete(Number(pillarId)); }, [onDelete, pillarId]); @@ -89,6 +92,8 @@ function AnalysisPillar(props: Props) { value: data.statement, }), []); + const disabled = pendingPillarDelete; + return ( @@ -123,7 +128,7 @@ function AnalysisPillar(props: Props) { onConfirm={onDeleteConfirmClick} title={_ts('analysis', 'deletePillarButtonTitle')} message={_ts('analysis', 'deletePillarConfirmMessage')} - disabled={undefined} + disabled={disabled} showConfirmationInitially={false} variant="secondary" > diff --git a/app/views/AnalysisDashboard/Analysis/PillarAssignment/index.tsx b/app/views/AnalysisDashboard/Analysis/PillarAssignment/index.tsx index 7afd92ec20..08b5ae0e5c 100644 --- a/app/views/AnalysisDashboard/Analysis/PillarAssignment/index.tsx +++ b/app/views/AnalysisDashboard/Analysis/PillarAssignment/index.tsx @@ -5,7 +5,7 @@ import _ts from '#ts'; import styles from './styles.css'; -interface Props { +export interface Props { className?: string; assigneeName: string | null | undefined; pillarTitle: string; @@ -36,13 +36,13 @@ function PillarAssignment(props: Props) { className={styles.assigneeName} title={isDefined(assigneeName) ? assigneeName : undefined} > - {assigneeName} + { assigneeName }
- {pillarTitle} + { pillarTitle }
- {statusLabel} + { statusLabel }
); diff --git a/app/views/AnalysisDashboard/Analysis/PillarList/index.tsx b/app/views/AnalysisDashboard/Analysis/PillarList/index.tsx index 784aadcfeb..da394f80fd 100644 --- a/app/views/AnalysisDashboard/Analysis/PillarList/index.tsx +++ b/app/views/AnalysisDashboard/Analysis/PillarList/index.tsx @@ -7,8 +7,6 @@ import { Kraken, } from '@the-deep/deep-ui'; -import _ts from '#ts'; - import { AnalysisSummaryQuery } from '#generated/types'; import AnalysisPillar, { Props as PillarComponentProps } from '../AnalysisPillar'; @@ -26,7 +24,7 @@ interface Props { activeProject: string; onAnalysisPillarDelete: () => void; analysisId: string; - totalEntries: number; + totalEntries: number | undefined; pillars: PillarSummary[] | null | undefined; pillarsPending: boolean; } @@ -59,6 +57,7 @@ function AnalysisDetails(props: Props) { title: data.title, totalEntries, }), [ + onAnalysisPillarDelete, totalEntries, createdAt, analysisId, @@ -71,7 +70,7 @@ function AnalysisDetails(props: Props) { className={_cs(className, styles.container)} spacing="none" contentClassName={styles.content} - footerActions={((totalEntries ?? 0) / MAX_ITEMS_PER_PAGE) > 1 ? ( + footerActions={((pillars?.length ?? 0) / MAX_ITEMS_PER_PAGE) > 1 ? ( (item.id); -function Analysis(props: ComponentProps) { +function Analysis(props: Props) { const { title, className, @@ -167,7 +167,7 @@ function Analysis(props: ComponentProps) { const alert = useAlert(); const pillarAssignmentRendererParams = useCallback( - (_: string, data: PillarSummary) => ({ + (_: string, data: PillarSummary): PillarAssignmentItemProps => ({ assigneeName: data.assignee?.displayName, pillarTitle: data.title, analyzedEntries: data.analyzedEntriesCount, @@ -230,14 +230,16 @@ function Analysis(props: ComponentProps) { onDelete(analysisId); }, [analysisId, onDelete]); - const barChartData = useMemo(() => ( - pillars?.map((o) => ({ + const barChartData = useMemo(() => { + if (!pillars || totalEntries === undefined) return []; + + return pillars.map((o) => ({ ...o, percent: Math.round( ((o.analyzedEntriesCount ?? 0) / (totalEntries === 0 ? 1 : totalEntries)) * 10000, ) / 100, - })) - ), [pillars, totalEntries]); + })); + }, [pillars, totalEntries]); const disabled = pendingAnalysisDelete; @@ -249,6 +251,11 @@ function Analysis(props: ComponentProps) { const canTagEntry = project?.analysisFramework?.id && project?.allowedPermissions?.includes('UPDATE_ENTRY'); + const safeAnalyzedLeads = analyzedLeads ?? 0; + const safeTotalSource = totalSources ?? 1; + const safeAnalyzedEntries = analyzedEntries ?? 0; + const safeTotalEntries = totalEntries ?? 1; + return ( @@ -427,7 +434,7 @@ function Analysis(props: ComponentProps) { ['userMembers']>['results']>>[number]; - export interface PillarAnalysisFields { title: string; - emailDisplay: UserMemberType; + assignee: string; filters: MatrixPillar['uniqueId'][]; } const idSelector = (d: MatrixPillar) => d.uniqueId; const labelSelector = (d: MatrixPillar) => d.altTitle ?? d.title; -const userKeySelector = (u: UserMemberType) => u.id; -const userLabelSelector = (u: UserMemberType) => u.member.emailDisplay; +const userKeySelector = (u: UserMini) => u.id; +const userLabelSelector = (u: UserMini) => u.displayName; type Value = PartialForm const defaultValue: Value = { @@ -50,7 +48,7 @@ export interface Props { matrixPillars?: MatrixPillar[]; onChange: (value: SetValueArg, index: number) => void; onRemove: (index: number) => void; - usersList: UserMemberType[]; + usersList: UserMini[]; value: Value; pending: boolean; } @@ -70,7 +68,6 @@ function PillarAnalysisRow(props: Props) { const error = getErrorObject(riskyError); - console.info('value', value); const onFieldChange = useFormObject(index, onChange, defaultValue); return ( @@ -87,15 +84,15 @@ function PillarAnalysisRow(props: Props) { /> = RawPartialForm; -type AnalysisPillar = Partial & { key: string; id?: number }; - -type UserMemberType = NonNullable['userMembers']>['results']>>[number]; +type AnalysisPillar = Partial & { key: string; id?: string }; type FormType = { title?: string; - teamLead?: UserMemberType['id']; + teamLead?: UserMini['id']; startDate?: string; endDate: string; analysisPillar?: AnalysisPillar[]; @@ -156,7 +136,7 @@ const defaultAnalysisFormValues: PartialForm = { analysisPillar: [{ key: randomString(16) }], }; -const userKeySelector = (u: UserMini) => String(u.id); +const userKeySelector = (u: UserMini) => u.id; const userLabelSelector = (u: UserMini) => u.displayName; const childrenSelector = (d: MatrixPillar) => d.children; @@ -167,7 +147,6 @@ interface AnalysisEditModalProps { onSuccess: (value: AnalysisElement, isEditMode: boolean) => void; onModalClose: () => void; analysisToEdit?: string; - projectId: number; } function AnalysisEditModal(props: AnalysisEditModalProps) { @@ -176,7 +155,6 @@ function AnalysisEditModal(props: AnalysisEditModalProps) { onSuccess, onModalClose, analysisToEdit, - projectId, } = props; const { @@ -186,57 +164,63 @@ function AnalysisEditModal(props: AnalysisEditModalProps) { setFieldValue, validate, setError, - setValue, } = useForm(analysisFormSchema, defaultAnalysisFormValues); const error = getErrorObject(riskyError); const arrayError = getErrorObject(error?.analysisPillar); const { - pending: analysisGetPending, - } = useRequest({ - skip: !analysisToEdit, - url: `server://projects/${projectId}/analysis/${analysisToEdit}/`, - onSuccess: (response) => { - setValue({ - teamLead: String(response.teamLead), - title: response.title, - startDate: response.startDate, - endDate: response.endDate, - analysisPillar: response.analysisPillar.map((ap) => ({ - id: ap.id, - key: String(ap.id), - assignee: String(ap.assignee), - filters: ap.filters?.map((f) => f.uniqueId), - title: ap.title, - })), - }); - }, - }); - - const userMembersVariables = useMemo( - (): ProjectUserMembersQueryVariables => ({ - projectId: String(projectId), - analysisId: '', - }), - [projectId], - ); - - const { - loading: pendingProjectUserMembers, - data: projectUserMembers, - } = useQuery( - PROJECT_USER_MEMBERS, + project, + } = useContext(ProjectContext); + + /* + const [ + updateAnalysis, + { loading: updateAnalysisPending }, + ] = useMutation( + PROJECT_UPDATE, { - variables: userMembersVariables, + onCompleted: (gqlResponse) => { + const response = gqlResponse?.project?.projectUpdate; + if (!response) { + return; + } + + if (response.ok) { + alert.show( + 'Successfully Update Analysis', + { variant: 'success' }, + ); + } else { + const formError = transformToFormError( + removeNull(response.errors) as ObjectError[], + ); + setError(formError); + + alert.show( + 'Failed to update analysis!', + { variant: 'error' }, + ); + } + }, + onError: (gqlError) => { + alert.show( + 'Failed to update analysis!', + { variant: 'error' }, + ); + + console.error(gqlError); + }, }, ); + */ const frameworkVariables = useMemo( - (): FrameworkDetailsForAnalysisQueryVariables => ({ - projectId: String(projectId), - }), - [projectId], + (): FrameworkDetailsForAnalysisQueryVariables | undefined => ( + (project) ? ({ + projectId: project.id, + }) : undefined), + [project], ); const { @@ -270,7 +254,7 @@ function AnalysisEditModal(props: AnalysisEditModalProps) { pending: pendingUsersList, response: usersListResponse, } = useRequest>({ - url: `server://projects/${projectId}/members/`, + url: `server://projects/${project?.id}/members/`, query: usersQueryFields, method: 'GET', }); @@ -280,8 +264,8 @@ function AnalysisEditModal(props: AnalysisEditModalProps) { trigger: triggerAnalysisEdit, } = useLazyRequest({ url: isDefined(analysisToEdit) - ? `server://projects/${projectId}/analysis/${analysisToEdit}/` - : `server://projects/${projectId}/analysis/`, + ? `server://projects/${project?.id}/analysis/${analysisToEdit}/` + : `server://projects/${project?.id}/analysis/`, method: isDefined(analysisToEdit) ? 'PATCH' : 'POST', body: (ctx) => ctx, onSuccess: (response) => { @@ -303,9 +287,7 @@ function AnalysisEditModal(props: AnalysisEditModalProps) { : 'Failed to create new analysis', }); - const pending = pendingFramework || pendingProjectUserMembers || pendingAnalysisEdit; - - console.log('user', usersListResponse, 'graphql', projectUserMembers); + const pending = pendingFramework || pendingAnalysisEdit; const { setValue: onRowChange, @@ -324,10 +306,17 @@ function AnalysisEditModal(props: AnalysisEditModalProps) { onChange: onRowChange as PillarAnalysisProps['onChange'], onRemove: onRowRemove, pending, - usersList: projectUserMembers?.project?.userMembers?.results ?? [], + usersList: usersListResponse?.results ?? [], value: data, }), - [projectUserMembers, matrixPillars, arrayError, onRowChange, onRowRemove, pending], + [ + usersListResponse, + matrixPillars, + arrayError, + onRowChange, + onRowRemove, + pending, + ], ); type AnalysisPillarList = typeof value.analysisPillar; @@ -395,7 +384,6 @@ function AnalysisEditModal(props: AnalysisEditModalProps) { {/* NOTE: Set delay to 0 as it needs to be blocked */} - {analysisGetPending && } diff --git a/app/views/AnalysisDashboard/index.tsx b/app/views/AnalysisDashboard/index.tsx index 5ac7e8549b..205b489022 100644 --- a/app/views/AnalysisDashboard/index.tsx +++ b/app/views/AnalysisDashboard/index.tsx @@ -10,6 +10,7 @@ import { _cs, isDefined, } from '@togglecorp/fujs'; +import { getOperationName } from 'apollo-link'; import { IoDocumentOutline, IoCheckmarkCircle, @@ -60,7 +61,7 @@ import { DeleteAnalysisMutationVariables, } from '#generated/types'; -import Analysis from './Analysis'; +import Analysis, { type Props as AnalysisItemProps } from './Analysis'; import AnalysisEditModal from './AnalysisEditModal'; import styles from './styles.css'; @@ -70,107 +71,90 @@ const ANALYSIS_SUMMARY = gql` $createdAtGte: DateTime, $modifiedAt: DateTime, $createdAtLte: DateTime, - $analysisId: ID!, $page: Int, $pageSize: Int, ) { project(id: $projectId) { - analyses( - createdAtGte: $createdAtGte, - createdAtLte: $createdAtLte, - modifiedAt: $modifiedAt, - page: $page, - pageSize: $pageSize, - ) - { - results { - id - analyzedEntriesCount - analyzedLeadsCount - modifiedAt - createdAt - startDate - endDate - title - teamLead { - id - displayName - } - pillars { + analyses( + createdAtGte: $createdAtGte, + createdAtLte: $createdAtLte, + modifiedAt: $modifiedAt, + page: $page, + pageSize: $pageSize, + ) { + results { id - title - createdAt - analysis analyzedEntriesCount - assignee { + analyzedLeadsCount + modifiedAt + createdAt + startDate + endDate + title + teamLead { + id displayName + } + pillars { id + title + createdAt + analysisId + analyzedEntriesCount + assignee { + displayName + id + } } } + totalCount } - totalCount - } - analysis(id: $analysisId) { - title - teamLead { - id - displayName - } - pillars { - id - } - startDate - endDate - id - createdAt - modifiedAt - } - analysisOverview { - analyzedEntriesCount - analyzedLeadsCount - totalEntriesCount - totalLeadsCount - authoringOrganizations { - count - id - title - } - } - analyticalStatements { - results { - id - entriesCount - statement - } - } - analysisPillars { - results { - assignee { - displayName + analysisOverview { + analyzedEntriesCount + analyzedLeadsCount + totalEntriesCount + totalLeadsCount + authoringOrganizations { id - } + count title - analyzedEntriesCount - analysis + } + } + analyticalStatements { + results { id - createdAt - statements { + entriesCount + statement + } + } + analysisPillars { + results { + assignee { + displayName id - statement - entriesCount } - } + title + analyzedEntriesCount + analysisId + id + createdAt + statements { + id + statement + entriesCount + } + } } } } `; - const DELETE_ANALYSIS = gql` mutation DeleteAnalysis( $projectId: ID!, $analysisId: ID!, ) { project(id: $projectId) { + id analysisReportDelete(id: $analysisId) { errors ok @@ -207,18 +191,18 @@ type TimelineData = { label: string; }; -const analysisSummaryKeySelector = (d: AnalysisSummaryType) => d.id; +const analysisSummaryKeySelector = (item: AnalysisSummaryType) => item.id; const labelSelector = (item: AuthoringOrganizations) => item.title; const valueSelector = (item: AuthoringOrganizations) => item.count; const tickFormatter = (title: string) => title; -const timelineLabelSelector = (d: TimelineData): string => d.label; -const timelineValueSelector = (d: TimelineData): number => d.value; -const timelineKeySelector = (d: TimelineData): string => d.key; +const timelineLabelSelector = (item: TimelineData): string => item.label; +const timelineValueSelector = (item: TimelineData): number => item.value; +const timelineKeySelector = (item: TimelineData): string => item.key; -const timelineTickSelector = (d: number) => { - const date = new Date(d); +const timelineTickSelector = (item: number) => { + const date = new Date(item); const year = date.getFullYear(); const month = date.getMonth(); @@ -260,7 +244,6 @@ function AnalysisDashboard(props: AnalysisDashboardProps) { projectId: project.id, page: activePage, pageSize: maxItemsPerPage, - analysisId, createdAtGte: convertDateToIsoDateTime(dateRangeFilter?.startDate), createdAtLte: convertDateToIsoDateTime( dateRangeFilter?.endDate, { endOfDay: true }, @@ -268,7 +251,6 @@ function AnalysisDashboard(props: AnalysisDashboardProps) { }) : undefined), [ project, - analysisId, activePage, dateRangeFilter?.startDate, dateRangeFilter?.endDate, @@ -294,10 +276,11 @@ function AnalysisDashboard(props: AnalysisDashboardProps) { ] = useMutation( DELETE_ANALYSIS, { + refetchQueries: [getOperationName(ANALYSIS_SUMMARY)].filter(isDefined), onCompleted: (response) => { if (response?.project?.analysisReportDelete?.ok) { alert.show( - _ts('analysis', 'analysisDeleteSuccessful'), + 'Successfully deleted analysis.', { variant: 'success' }, ); getProjectAnalysis(); @@ -366,7 +349,7 @@ function AnalysisDashboard(props: AnalysisDashboardProps) { const handleAnalysisEditClick = useCallback(() => { setAnalysisToEdit(analysisId); setModalVisible(); - }, [setModalVisible]); + }, [setModalVisible, analysisId]); const handleNewAnalysisCreateClick = useCallback(() => { setAnalysisToEdit(undefined); @@ -383,37 +366,54 @@ function AnalysisDashboard(props: AnalysisDashboardProps) { }, }); } - }, [deleteAnalysis, project], + }, [ + deleteAnalysis, + project, + analysisId, + ], + ); + + const analyzedEntriesCount = analysisSummaryData + ?.project?.analysisOverview?.analyzedEntriesCount; + const analyzedLeadsCount = analysisSummaryData + ?.project?.analysisOverview?.analyzedLeadsCount; + const totalEntriesCount = analysisSummaryData + ?.project?.analysisOverview?.totalEntriesCount; + const totalLeadsCount = analysisSummaryData + ?.project?.analysisOverview?.totalLeadsCount; + + const analysisRendererParams = useCallback( + (id: string, data: AnalysisSummaryType): AnalysisItemProps => ({ + analysisId: id, + onEdit: handleAnalysisEditClick, + onDelete: handleAnalysisDeleteClick, + title: data.title, + startDate: data.startDate, + endDate: data.endDate, + teamLeadName: data.teamLead?.displayName, + createdAt: data.createdAt, + pillars: data.pillars, + pillarsPending: analysisSummaryLoading, + analyzedLeads: analyzedLeadsCount, + analyzedEntries: analyzedEntriesCount, + totalSources: totalLeadsCount, + totalEntries: totalEntriesCount, + onAnalysisCloseSuccess: getProjectAnalysis, + onAnalysisPillarDelete: getProjectAnalysis, + pendingAnalysisDelete: deleteAnalysisPending && data.id === id, + }), [ + analyzedEntriesCount, + analyzedLeadsCount, + totalLeadsCount, + totalEntriesCount, + getProjectAnalysis, + handleAnalysisEditClick, + handleAnalysisDeleteClick, + deleteAnalysisPending, + analysisSummaryLoading, + ], ); - const analysisRendererParams = useCallback((id: string, data: AnalysisSummaryType) => ({ - analysisId: id, - onEdit: handleAnalysisEditClick, - onDelete: handleAnalysisDeleteClick, - title: data.title, - startDate: data.startDate, - endDate: data.endDate, - teamLeadName: data.teamLead?.displayName, - createdAt: data.createdAt, - modifiedAt: data.modifiedAt, - pillars: data.pillars, - pillarsPending: analysisSummaryLoading, - analyzedLeads: data.analyzedLeadsCount, - analyzedEntries: data.analyzedEntriesCount, - // FIX ME: Add `Total Lead count` - totalSources: data?.analyzedLeadsCount, - // FIX ME: Add `Total Entries count` - totalEntries: data?.analyzedEntriesCount, - onAnalysisCloseSuccess: getProjectAnalysis, - onAnalysisPillarDelete: getProjectAnalysis, - pendingAnalysisDelete: deleteAnalysisPending && data?.id === id, - }), [ - getProjectAnalysis, - handleAnalysisEditClick, - handleAnalysisDeleteClick, - deleteAnalysisPending, - analysisSummaryLoading, - ]); const canTagEntry = project?.allowedPermissions?.includes('UPDATE_ENTRY'); return ( @@ -589,7 +589,7 @@ function AnalysisDashboard(props: AnalysisDashboardProps) { )}