diff --git a/app/views/PillarAnalysis/AnalyticalStatementInput/StoryAnalysisModal/Summary/index.tsx b/app/views/PillarAnalysis/AnalyticalStatementInput/StoryAnalysisModal/Summary/index.tsx index 93f3aed02a..3d3558a01d 100644 --- a/app/views/PillarAnalysis/AnalyticalStatementInput/StoryAnalysisModal/Summary/index.tsx +++ b/app/views/PillarAnalysis/AnalyticalStatementInput/StoryAnalysisModal/Summary/index.tsx @@ -1,81 +1,31 @@ -import React, { useEffect } from 'react'; +import React from 'react'; import { isDefined } from '@togglecorp/fujs'; -import { gql, useQuery } from '@apollo/client'; import { Kraken, Message, PendingMessage, } from '@the-deep/deep-ui'; import { - AutomaticSummaryQuery, - AutomaticSummaryQueryVariables, + type ApolloError, +} from '@apollo/client'; +import { + AnalyticalInformationSummaryQuery, } from '#generated/types'; import styles from './styles.css'; -const AUTOMATIC_SUMMARY = gql` -query AutomaticSummary($projectId: ID!, $summaryId: ID!) { - project(id: $projectId) { - id - analysisAutomaticSummary(id: $summaryId) { - id - status - summary - } - } -} -`; - interface Props { - projectId: string; - summaryId: string | undefined; + summaryData: AnalyticalInformationSummaryQuery | undefined; + error: ApolloError | undefined; } function Summary(props: Props) { const { - projectId, - summaryId, - } = props; - - const { - data, - loading, - startPolling, - stopPolling, + summaryData, error, - } = useQuery( - AUTOMATIC_SUMMARY, - { - skip: !summaryId, - variables: summaryId ? { - projectId, - summaryId, - } : undefined, - }, - ); - - useEffect( - () => { - const shouldPoll = data?.project?.analysisAutomaticSummary?.status === 'PENDING' - || data?.project?.analysisAutomaticSummary?.status === 'STARTED'; - - if (shouldPoll) { - startPolling(5000); - } else { - stopPolling(); - } - return (() => { - stopPolling(); - }); - }, - [ - data?.project?.analysisAutomaticSummary?.status, - startPolling, - stopPolling, - ], - ); + } = props; - if (data?.project?.analysisAutomaticSummary?.status === 'SEND_FAILED') { + if (summaryData?.project?.analysisAutomaticSummary?.status === 'SEND_FAILED') { return (
- {(data?.project?.analysisAutomaticSummary?.summary?.length ?? 0) > 0 ? ( + {(summaryData?.project?.analysisAutomaticSummary?.summary?.length ?? 0) > 0 ? (

- {data?.project?.analysisAutomaticSummary?.summary} + {summaryData?.project?.analysisAutomaticSummary?.summary}

) : (
diff --git a/app/views/PillarAnalysis/AnalyticalStatementInput/StoryAnalysisModal/index.tsx b/app/views/PillarAnalysis/AnalyticalStatementInput/StoryAnalysisModal/index.tsx index 8ff4011e35..acef08e948 100644 --- a/app/views/PillarAnalysis/AnalyticalStatementInput/StoryAnalysisModal/index.tsx +++ b/app/views/PillarAnalysis/AnalyticalStatementInput/StoryAnalysisModal/index.tsx @@ -3,7 +3,12 @@ import React, { useCallback, useContext, useMemo, + useEffect, } from 'react'; +import { + gql, + useQuery, +} from '@apollo/client'; import { Button, CollapsibleContainer, @@ -11,7 +16,9 @@ import { ListView, Modal, QuickActionButton, + QuickActionConfirmButton, SegmentInput, + Svg, Tab, TabList, TabPanel, @@ -33,7 +40,6 @@ import { IoInformation, } from 'react-icons/io5'; import { VscServerProcess } from 'react-icons/vsc'; - import WordTree from '#components/WordTree'; import MarkdownEditor from '#components/MarkdownEditor'; import { organizationTitleSelector } from '#components/selections/NewOrganizationSelectInput'; @@ -41,6 +47,11 @@ import { GeoArea } from '#components/GeoMultiSelectInput'; import SourcesFilterContext from '#components/leadFilters/SourcesFilterContext'; import ProjectContext from '#base/context/ProjectContext'; +import { + AnalyticalInformationSummaryQuery, + AnalyticalInformationSummaryQueryVariables, +} from '#generated/types'; +import brainIcon from '#resources/img/brain.svg'; import EntryCard from './EntryCard'; import EntryContext from '../../context'; import Summary from './Summary'; @@ -75,6 +86,21 @@ const sourceOptions: KeyLabel[] = [ }, ]; +const ANALYTICAL_INFORMATION_SUMMARY = gql` +query AnalyticalInformationSummary($projectId: ID!, $summaryId: ID!) { + project(id: $projectId) { + id + analysisAutomaticSummary(id: $summaryId) { + id + status + informationGap + analyticalStatement + summary + } + } +} +`; + const keySelector = (d: KeyLabel) => d.key; const labelSelector = (d: KeyLabel) => d.label; @@ -315,6 +341,100 @@ function StoryAnalysisModal(props: Props) { message: 'Looks like there are some changes that have not been saved yet. Are you sure you want to close?', }); + const variables = useMemo(() => ( + isDefined(automaticSummaryId) + ? { + projectId, + summaryId: automaticSummaryId, + } + : undefined + ), [projectId, automaticSummaryId]); + + const { + data, + loading, + startPolling, + stopPolling, + error, + } = useQuery( + ANALYTICAL_INFORMATION_SUMMARY, + { + skip: !automaticSummaryId, + variables, + }, + ); + + const informationGapOnClick = useCallback(() => { + setPristine(false); + const informationGapResponse = data?.project?.analysisAutomaticSummary?.informationGap; + setInformationGaps(informationGapResponse); + }, [data?.project?.analysisAutomaticSummary]); + + const onStatementGenerateClick = useCallback(() => { + setPristine(false); + const analyticalStatementResponse = data + ?.project?.analysisAutomaticSummary?.analyticalStatement; + setAnalyticalStatement(analyticalStatementResponse); + }, [data?.project?.analysisAutomaticSummary]); + + const onAnalysisGenerateClick = useCallback(() => { + setPristine(false); + const generatedReportText = originalEntries.map((entry) => generateReportText(entry)).join('\n\n'); + + const summaryResponse = data?.project?.analysisAutomaticSummary?.summary; + + const myAnalysisHeading = '**My Analysis** \n \n'; + + const summaryText = summaryResponse + ? `**Summary** \n \n ${summaryResponse} \n \n` + : ''; + + const informationGapText = informationGaps + ? `**Information Gaps** \n \n ${informationGaps} \n \n` + : ''; + + const analyticalStatementText = analyticalStatement + ? `**Analytical Statement** \n \n ${analyticalStatement} \n \n` + : ''; + const entriesText = generatedReportText + ? `**Evidences** \n \n ${generatedReportText} \n \n` + : ''; + + const myAnalysis = myAnalysisHeading + + analyticalStatementText + + summaryText + + informationGapText + + entriesText; + + setReportText(myAnalysis); + }, [informationGaps, analyticalStatement, originalEntries, + data?.project?.analysisAutomaticSummary]); + + useEffect( + () => { + const shouldPoll = data?.project?.analysisAutomaticSummary?.status === 'PENDING' + || data?.project?.analysisAutomaticSummary?.status === 'STARTED'; + + if (shouldPoll) { + startPolling(5000); + } else { + stopPolling(); + } + return (() => { + stopPolling(); + }); + }, + [ + data?.project?.analysisAutomaticSummary, + startPolling, + stopPolling, + ], + ); + + const pending = loading + || data?.project?.analysisAutomaticSummary?.status === 'STARTED' + || data?.project?.analysisAutomaticSummary?.status === 'PENDING'; + return ( <> - Auto summary is not available + Automatic summary is not available for private projects to maintain document privacy. @@ -460,8 +580,8 @@ function StoryAnalysisModal(props: Props) { className={styles.tabPanel} > @@ -473,7 +593,38 @@ function StoryAnalysisModal(props: Props) { +
+ Information Gaps +
+
+ + + + {project?.isPrivate && ( +
+ + + Auto generate is not available + for private projects to + maintain document privacy. + +
+ )} +
+ + )} name="informationGap" value={informationGaps} onChange={handleInformationGapChange} @@ -510,7 +661,38 @@ function StoryAnalysisModal(props: Props) { +
+ Analytical Statament +
+
+ + + + {project?.isPrivate && ( +
+ + + Auto generate is not available + for private projects to + maintain document privacy. + +
+ )} +
+ + )} name="analyticalStatement" value={analyticalStatement} onChange={handleAnalyticalStatementChange} @@ -521,7 +703,38 @@ function StoryAnalysisModal(props: Props) { className={styles.editor} labelContainerClassName={styles.labelContainer} inputSectionClassName={styles.inputSection} - label="My Analysis" + label={( + <> +
+ My Analysis +
+
+ + + + {project?.isPrivate && ( +
+ + + Auto generate is not available + for private projects to + maintain document privacy. + +
+ )} +
+ + )} name="reportText" value={reportText} onChange={handleReportTextChange} diff --git a/app/views/PillarAnalysis/AnalyticalStatementInput/StoryAnalysisModal/styles.css b/app/views/PillarAnalysis/AnalyticalStatementInput/StoryAnalysisModal/styles.css index cd5fcd0e3f..f7f3369a04 100644 --- a/app/views/PillarAnalysis/AnalyticalStatementInput/StoryAnalysisModal/styles.css +++ b/app/views/PillarAnalysis/AnalyticalStatementInput/StoryAnalysisModal/styles.css @@ -45,15 +45,6 @@ font-size: var(--dui-font-size-large); font-weight: var(--dui-font-weight-regular); } - .info { - display: flex; - align-self: center; - border: var(--dui-width-separator-thin) solid var(--dui-color-separator); - border-radius: 50%; - padding: var(--dui-spacing-extra-small); - font-size: var(--dui-font-size-medium); - } - .brain-icon { align-self: center; } @@ -140,11 +131,22 @@ gap: var(--dui-width-separator-thin); .label-container { + display: flex; + justify-content: space-between; padding-bottom: var(--dui-spacing-small); color: var(--dui-color-text); font-size: var(--dui-font-size-large); font-weight: var(--dui-font-weight-bold); } + + .label-container-action { + display: flex; + + .brain-icon { + width: auto; + height: var(--dui-font-size-extra-large); + } + } } } @@ -207,4 +209,12 @@ } } } + .info { + display: flex; + align-self: center; + border: var(--dui-width-separator-thin) solid var(--dui-color-separator); + border-radius: 50%; + padding: var(--dui-spacing-extra-small); + font-size: var(--dui-font-size-medium); + } }