Skip to content

Commit 64e1da0

Browse files
authored
Merge branch 'google-docs-document-outline' into feat/cell-level-mappings
2 parents afd70da + 1238860 commit 64e1da0

84 files changed

Lines changed: 24095 additions & 381 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/google-docs/src/hooks/useWorkflowAgent.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ import { useState, useCallback } from 'react';
22
import { PageAppSDK } from '@contentful/app-sdk';
33
import { POLL_INTERVAL_MS, MAX_POLL_ATTEMPTS, WORKFLOW_AGENT_ID } from '../utils/constants/agent';
44
import {
5+
MappingReviewSuspendPayload,
56
ResumePayload,
6-
SuspendPayload,
7+
TabsImagesSuspendPayload,
78
PreviewPayload,
89
WorkflowRunResult,
910
RunStatus,
@@ -79,8 +80,11 @@ const getRunErrorMessage = (runData: AgentRunData): string => {
7980
return 'Workflow failed';
8081
};
8182

82-
const getSuspendPayload = (runData: AgentRunData): SuspendPayload | undefined =>
83-
runData.metadata?.suspendPayload as SuspendPayload | undefined;
83+
const getSuspendPayload = (
84+
runData: AgentRunData
85+
): TabsImagesSuspendPayload | MappingReviewSuspendPayload | undefined => {
86+
return runData.metadata?.suspendPayload;
87+
};
8488

8589
const getWorkflowRunResult = (
8690
runData: AgentRunData,

apps/google-docs/src/locations/Page/Page.tsx

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,18 @@ import {
88
} from './components/mainpage/ModalOrchestrator';
99
import { MainPageView } from './components/mainpage/MainPageView';
1010
import { PreviewPageView } from './components/mainpage/PreviewPageView';
11-
import { MappingReviewSuspendPayload, PreviewPayload, ResumePayload } from '@types';
11+
import { MappingReviewSuspendPayload, PreviewPayload } from '@types';
12+
import { isMappingReviewSuspendPayload } from '../../utils/utils';
1213

1314
const Page = () => {
1415
const sdk = useSDK<PageAppSDK>();
1516
const modalOrchestratorRef = useRef<ModalOrchestratorHandle>(null);
1617
const [oauthToken, setOauthToken] = useState<string>('');
1718
const [isOAuthConnected, setIsOAuthConnected] = useState(false);
1819
const [isOAuthLoading, setIsOAuthLoading] = useState(true);
19-
const [isMappingPrototypeVisible, setIsMappingPrototypeVisible] = useState(false);
20-
const [mappingReviewPayload, setMappingReviewPayload] =
21-
useState<MappingReviewSuspendPayload | null>(null);
22-
const [previewPayload, setPreviewPayload] = useState<PreviewPayload | null>(null);
20+
const [previewPayload, setPreviewPayload] = useState<
21+
PreviewPayload | MappingReviewSuspendPayload | null
22+
>(null);
2323

2424
const handleOauthTokenChange = (token: string) => {
2525
setOauthToken(token);
@@ -44,9 +44,7 @@ const Page = () => {
4444
};
4545

4646
const handleMappingReviewReady = (payload: MappingReviewSuspendPayload) => {
47-
setIsMappingPrototypeVisible(false);
48-
setPreviewPayload(null);
49-
setMappingReviewPayload(payload);
47+
setPreviewPayload(payload);
5048
};
5149

5250
const handleReturnToMainPage = () => {
@@ -55,18 +53,20 @@ const Page = () => {
5553
setPreviewPayload(null);
5654
};
5755

58-
const handlePreviewCancel = () => {
59-
if (isMappingPrototypeVisible) {
60-
handleReturnToMainPage();
56+
const handleResumeMappingReview = async () => {
57+
if (!previewPayload || !isMappingReviewSuspendPayload(previewPayload)) {
6158
return;
6259
}
6360

64-
modalOrchestratorRef.current?.resetFlowFromPreviewCancel();
61+
try {
62+
await modalOrchestratorRef.current?.resumeMappingReview(previewPayload);
63+
} catch (error) {
64+
console.error('Failed to resume mapping review:', error);
65+
sdk.notifier.error('Unable to resume preview. Please try again.');
66+
}
6567
};
6668

67-
const handleMappingReviewContinue = async (resumePayload: ResumePayload) => {
68-
await modalOrchestratorRef.current?.resumeMappingReview(resumePayload);
69-
};
69+
console.log('previewPayload', previewPayload);
7070

7171
return (
7272
<>
@@ -76,6 +76,7 @@ const Page = () => {
7676
payload={previewPayload}
7777
oauthToken={oauthToken}
7878
onLeavePreview={handleReturnToMainPage}
79+
onResumeMappingReview={handleResumeMappingReview}
7980
/>
8081
) : (
8182
<MainPageView

apps/google-docs/src/locations/Page/components/mainpage/ModalOrchestrator.tsx

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ import { CONTENT_TYPE_SUBMIT_LOADING_DELAY_MS } from '@constants/agent';
1111
import { SelectTabsModal } from '../modals/step_3/SelectTabsModal';
1212
import {
1313
DocumentTabProps,
14-
DocumentScopeSuspendPayload,
1514
MappingReviewSuspendPayload,
1615
ResumePayload,
16+
TabsImagesSuspendPayload,
1717
PreviewPayload,
1818
RunStatus,
1919
WorkflowRunResult,
@@ -24,8 +24,9 @@ import { useWorkflowAgent } from '@hooks/useWorkflowAgent';
2424

2525
export interface ModalOrchestratorHandle {
2626
startFlow: () => void;
27-
resetFlowFromPreviewCancel: () => void;
28-
resumeMappingReview: (resumePayload: ResumePayload) => Promise<void>;
27+
/** Clears in-progress flow state without calling `onResetToMain` (parent clears preview separately). */
28+
resetFlowState: () => void;
29+
resumeMappingReview: (payload: MappingReviewSuspendPayload) => Promise<void>;
2930
}
3031

3132
enum FlowStep {
@@ -41,6 +42,7 @@ interface ModalOrchestratorProps {
4142
onPreviewReady: (payload: PreviewPayload) => void;
4243
onMappingReviewReady: (payload: MappingReviewSuspendPayload) => void;
4344
onResetToMain: () => void;
45+
onMappingReviewReady: (payload: MappingReviewSuspendPayload) => void;
4446
}
4547

4648
export const ModalOrchestrator = forwardRef<ModalOrchestratorHandle, ModalOrchestratorProps>(
@@ -83,6 +85,19 @@ export const ModalOrchestrator = forwardRef<ModalOrchestratorHandle, ModalOrches
8385
showWorkflowError();
8486
}
8587
},
88+
resumeMappingReview: async (payload: MappingReviewSuspendPayload) => {
89+
if (!activeRunId) {
90+
throw new Error('Workflow run id is missing for resume.');
91+
}
92+
93+
// TODO : modify the normalized document and entry block graph with the edited values
94+
const workflowRun = await resumeWorkflow(activeRunId, {
95+
editedNormalizedDocument: payload.normalizedDocument,
96+
entryBlockGraph: payload.entryBlockGraph,
97+
});
98+
99+
handleWorkflowResult(workflowRun);
100+
},
86101
}));
87102

88103
const resetDocumentScopeReview = () => {
@@ -130,7 +145,7 @@ export const ModalOrchestrator = forwardRef<ModalOrchestratorHandle, ModalOrches
130145
showDiscardConfirmation();
131146
};
132147

133-
const showDocumentScopeReview = (suspendPayload?: DocumentScopeSuspendPayload) => {
148+
const showDocumentScopeReview = (suspendPayload?: TabsImagesSuspendPayload) => {
134149
setAvailableTabs(
135150
(suspendPayload?.tabs ?? []).map((tab) => ({
136151
tabId: tab.id ?? '',

apps/google-docs/src/locations/Page/components/mainpage/PreviewPageView.tsx

Lines changed: 17 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -2,88 +2,34 @@ import { useEffect, useMemo, useState } from 'react';
22
import { PageAppSDK } from '@contentful/app-sdk';
33
import { Button, Flex, Heading, Layout, Note, Paragraph } from '@contentful/f36-components';
44
import Splitter from './Splitter';
5-
import { MappingReviewSuspendPayload, PreviewPayload, ResumePayload } from '@types';
5+
import { MappingReviewSuspendPayload, PreviewPayload } from '@types';
66
import { ConfirmCancelModal } from '../modals/ConfirmCancelModal';
77
import { loadGoogleDocsReviewData } from '../../../../fixtures/googleDocsReview';
88
import { GoogleDocsMappingReviewScreen } from '../review-prototype/GoogleDocsMappingReviewScreen';
99
import OverviewSection from '../overview/OverviewSection';
10+
import { useSDK } from '@contentful/react-apps-toolkit';
11+
import { PageAppSDK } from '@contentful/app-sdk';
12+
import { isMappingReviewSuspendPayload } from '../../../../utils/utils';
1013

1114
interface PreviewPageViewProps {
12-
payload: PreviewPayload;
15+
payload: PreviewPayload | MappingReviewSuspendPayload;
1316
oauthToken: string;
1417
onLeavePreview: () => void;
18+
onResumeMappingReview?: () => Promise<void>;
1519
}
1620

17-
export const PreviewPageView = ({ payload, oauthToken, onLeavePreview }: PreviewPageViewProps) => {
21+
export const PreviewPageView = ({
22+
payload,
23+
oauthToken,
24+
onLeavePreview,
25+
onResumeMappingReview,
26+
}: PreviewPageViewProps) => {
1827
const sdk = useSDK<PageAppSDK>();
1928
const [isConfirmCancelModalOpen, setIsConfirmCancelModalOpen] = useState(false);
20-
const [isContinuing, setIsContinuing] = useState(false);
21-
const fixture = isFixtureMode ? loadGoogleDocsReviewData() : null;
22-
const reviewFixture = useMemo(() => {
23-
if (isFixtureMode) {
24-
return fixture;
25-
}
26-
27-
if (props.mode === 'workflow') {
28-
return buildFixtureFromCompletedPayload(props.payload);
29-
}
30-
31-
return buildFixtureFromMappingReviewPayload(props.payload);
32-
}, [fixture, isFixtureMode, props]);
33-
34-
useEffect(() => {
35-
if (!reviewFixture) {
36-
console.warn(
37-
'[google-docs][preview]',
38-
'Fixture review screen could not be rendered because no valid fixture was loaded.'
39-
);
40-
return;
41-
}
42-
43-
console.log('[google-docs][preview]', 'Resolved preview fixture state...', {
44-
mode: props.mode,
45-
entryCount: reviewFixture.entries.length,
46-
assetCount: reviewFixture.assets.length,
47-
contentBlockCount: reviewFixture.originalNormalizedDocument.contentBlocks.length,
48-
tableCount: reviewFixture.originalNormalizedDocument.tables.length,
49-
graphEntryCount: reviewFixture.entryBlockGraph.entries.length,
50-
});
51-
}, [props.mode, reviewFixture]);
52-
53-
const title = isFixtureMode
54-
? 'Create from fixture preview'
55-
: isMappingReviewMode
56-
? `Review document "${
57-
props.payload.documentTitle ??
58-
props.payload.normalizedDocument.title ??
59-
props.payload.documentId
60-
}"`
61-
: `Create from document "${props.payload.normalizedDocument?.title ?? 'Selected document'}"`;
62-
63-
const handleContinue = async () => {
64-
if (props.mode !== 'mappingReview' || isContinuing) {
65-
return;
66-
}
67-
68-
const resumePayload = {
69-
editedNormalizedDocument:
70-
reviewFixture?.editableNormalizedDocument ?? props.payload.normalizedDocument,
71-
entryBlockGraph: reviewFixture?.entryBlockGraph ?? props.payload.entryBlockGraph,
72-
};
73-
74-
console.log('[google-docs][preview]', 'Continuing mapping review with current graph state.', {
75-
contentBlockCount: resumePayload.editedNormalizedDocument.contentBlocks.length,
76-
tableCount: resumePayload.editedNormalizedDocument.tables.length,
77-
graphEntryCount: resumePayload.entryBlockGraph.entries.length,
78-
});
79-
80-
setIsContinuing(true);
81-
try {
82-
await props.onContinue(resumePayload);
83-
} finally {
84-
setIsContinuing(false);
85-
}
86-
};
29+
const mappingReviewPayload = isMappingReviewSuspendPayload(payload) ? payload : null;
30+
const rawTitle = payload.normalizedDocument?.title;
31+
const docTitle = typeof rawTitle === 'string' ? rawTitle : undefined;
32+
const title = docTitle && docTitle.trim().length > 0 ? docTitle : 'Selected document';
8733

8834
return (
8935
<>
@@ -109,6 +55,7 @@ export const PreviewPageView = ({ payload, oauthToken, onLeavePreview }: Preview
10955
payload={payload}
11056
oauthToken={oauthToken}
11157
onReturnToMainPage={onLeavePreview}
58+
onCreateSelected={mappingReviewPayload ? onResumeMappingReview : undefined}
11259
/>
11360
<Heading as="h2" marginBottom="none">
11461
Document outline

0 commit comments

Comments
 (0)