diff --git a/src/pages/workspace/utils/web_scraping/web_page_content_tracker_revision.tsx b/src/pages/workspace/utils/web_scraping/web_page_content_tracker_revision.tsx index a2a03be..ffd4430 100644 --- a/src/pages/workspace/utils/web_scraping/web_page_content_tracker_revision.tsx +++ b/src/pages/workspace/utils/web_scraping/web_page_content_tracker_revision.tsx @@ -1,23 +1,34 @@ -import { EuiCodeBlock } from '@elastic/eui'; +import { EuiCodeBlock, useEuiTextDiff } from '@elastic/eui'; import type { WebPageContentRevision } from './web_page_data_revision'; export interface WebPageContentTrackerRevisionProps { revision: WebPageContentRevision; + previousRevision?: WebPageContentRevision; + showDiff?: boolean; } -export function WebPageContentTrackerRevision({ revision }: WebPageContentTrackerRevisionProps) { - const parsedData = JSON.parse(revision.data) as string | number | object; +function getTextToRender(text: string): [string, string | undefined] { + const parsedData = JSON.parse(text) as string | object; if (parsedData && typeof parsedData === 'object') { - return ( - - {JSON.stringify(parsedData, null, 2)} - - ); + return [JSON.stringify(parsedData, null, 2), 'json']; } + + return [parsedData, undefined]; +} + +export function WebPageContentTrackerRevision({ + revision, + previousRevision, + showDiff, +}: WebPageContentTrackerRevisionProps) { + const [afterText, language] = getTextToRender(revision.data); + const [beforeText] = previousRevision && showDiff ? getTextToRender(previousRevision.data) : [afterText]; + + const [textToRender] = useEuiTextDiff({ beforeText, afterText }); return ( - - {parsedData} + + {!showDiff || afterText === beforeText ? afterText : textToRender} ); } diff --git a/src/pages/workspace/utils/web_scraping/web_page_content_trackers.tsx b/src/pages/workspace/utils/web_scraping/web_page_content_trackers.tsx index 2650c6c..2b7a15a 100644 --- a/src/pages/workspace/utils/web_scraping/web_page_content_trackers.tsx +++ b/src/pages/workspace/utils/web_scraping/web_page_content_trackers.tsx @@ -154,7 +154,13 @@ export default function WebPageContentTrackers() { } else { itemIdToExpandedRowMapValues[tracker.name] = ( - {(revision) => } + {(revision, previousRevision, showDiff) => ( + + )} ); } diff --git a/src/pages/workspace/utils/web_scraping/web_page_resources_tracker_revision.tsx b/src/pages/workspace/utils/web_scraping/web_page_resources_tracker_revision.tsx index 6dd91af..436f924 100644 --- a/src/pages/workspace/utils/web_scraping/web_page_resources_tracker_revision.tsx +++ b/src/pages/workspace/utils/web_scraping/web_page_resources_tracker_revision.tsx @@ -155,7 +155,7 @@ export function WebPageResourcesTrackerRevision({ revision }: WebPageResourcesTr {unix(revision.createdAt).format('LL HH:mm:ss')}} + title={{unix(revision.createdAt).format('ll HH:mm:ss')}} titleSize={'xs'} description={'Last updated'} /> diff --git a/src/pages/workspace/utils/web_scraping/web_page_tracker_history.tsx b/src/pages/workspace/utils/web_scraping/web_page_tracker_history.tsx index ea0b711..d25ee09 100644 --- a/src/pages/workspace/utils/web_scraping/web_page_tracker_history.tsx +++ b/src/pages/workspace/utils/web_scraping/web_page_tracker_history.tsx @@ -7,12 +7,12 @@ import { EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, - EuiFormRow, EuiIcon, EuiPanel, EuiSelect, - EuiSpacer, + EuiSwitch, } from '@elastic/eui'; +import { css } from '@emotion/react'; import axios from 'axios'; import { unix } from 'moment'; @@ -25,17 +25,22 @@ import { useWorkspaceContext } from '../../hooks'; export interface WebPageTrackerHistoryProps { tracker: WebPageTracker; kind: 'content' | 'resources'; - children: (revision: WebPageDataRevision) => ReactNode; + children: ( + revision: WebPageDataRevision, + previousRevision: WebPageDataRevision | undefined, + showDiff: boolean, + ) => ReactNode; } export function WebPageTrackerHistory({ kind, tracker, children }: WebPageTrackerHistoryProps) { const { uiState, addToast } = useWorkspaceContext(); + const [showDiff, setShowDiff] = useState(true); const [revisions, setRevisions] = useState>({ status: 'pending', state: null, }); - const [revision, setRevision] = useState(null); + const [revisionIndex, setRevisionIndex] = useState(null); const fetchHistory = useCallback( ({ refresh }: { refresh: boolean } = { refresh: false }) => { setRevisions((currentRevisions) => @@ -46,13 +51,17 @@ export function WebPageTrackerHistory({ kind, tracker, children }: WebPageTracke axios .post( getApiUrl(`/api/utils/web_scraping/${kind}/${encodeURIComponent(tracker.id)}/history`), - { refresh, calculateDiff: true }, + { refresh, calculateDiff: showDiff }, getApiRequestConfig(), ) .then( (response) => { setRevisions({ status: 'succeeded', data: response.data }); - setRevision(response.data.length > 0 ? response.data[response.data.length - 1] : null); + + // Reset revision index only if it's not set or doesn't exist in the new data. + if (revisionIndex === null || revisionIndex >= response.data.length) { + setRevisionIndex(response.data.length > 0 ? response.data.length - 1 : null); + } }, (err: Error) => { setRevisions((currentRevisions) => ({ @@ -60,11 +69,11 @@ export function WebPageTrackerHistory({ kind, tracker, children }: WebPageTracke error: getErrorMessage(err), state: currentRevisions.state, })); - setRevision(null); + setRevisionIndex(null); }, ); }, - [getApiUrl], + [getApiUrl, revisionIndex, showDiff], ); useEffect(() => { @@ -73,12 +82,12 @@ export function WebPageTrackerHistory({ kind, tracker, children }: WebPageTracke } fetchHistory(); - }, [uiState, tracker]); + }, [uiState, tracker, showDiff]); const onRevisionChange = useCallback( (revisionId: string) => { if (revisions.status === 'succeeded') { - setRevision(revisions.data?.find((revision) => revision.id === revisionId) ?? null); + setRevisionIndex(revisions.data?.findIndex((revision) => revision.id === revisionId) ?? null); } }, [revisions], @@ -106,7 +115,7 @@ export function WebPageTrackerHistory({ kind, tracker, children }: WebPageTracke .then( () => { setRevisions({ status: 'succeeded', data: [] }); - setRevision(null); + setRevisionIndex(null); addToast({ id: `success-clear-tracker-history-${tracker.name}`, @@ -157,8 +166,12 @@ export function WebPageTrackerHistory({ kind, tracker, children }: WebPageTracke } /> ); - } else if (revision) { - history = children(revision); + } else if (revisionIndex !== null) { + history = children( + revisions.data[revisionIndex], + revisionIndex > 0 ? revisions.data[revisionIndex - 1] : undefined, + showDiff, + ); } else { const updateButton = ( 0) || (revisions.state?.length ?? 0 > 0); const controlPanel = shouldDisplayControlPanel ? ( - - - - - ({ - value: rev.id, - text: unix(rev.createdAt).format('LL HH:mm:ss'), - }))} - disabled={revisions.status === 'pending'} - value={revision?.id} - onChange={(e) => onRevisionChange(e.target.value)} - /> - + + + ({ + value: rev.id, + text: unix(rev.createdAt).format('ll HH:mm:ss'), + }))} + disabled={revisions.status === 'pending'} + value={ + revisionsToSelect.length > 0 && revisionIndex !== null ? revisionsToSelect[revisionIndex].id : undefined + } + onChange={(e) => onRevisionChange(e.target.value)} + /> + + + setShowDiff(e.target.checked)} + /> - - fetchHistory({ refresh: true })}> - Update - - + fetchHistory({ refresh: true })} + > + Update + - - setClearHistoryStatus({ isModalVisible: true, isInProgress: false })} - > - Clear - - + setClearHistoryStatus({ isModalVisible: true, isInProgress: false })} + > + Clear + ) : null; return ( - + {controlPanel} diff --git a/src/pages/workspace/utils/webhooks/responder_requests_table.tsx b/src/pages/workspace/utils/webhooks/responder_requests_table.tsx index 10533c3..7857565 100644 --- a/src/pages/workspace/utils/webhooks/responder_requests_table.tsx +++ b/src/pages/workspace/utils/webhooks/responder_requests_table.tsx @@ -12,7 +12,6 @@ import { EuiFormRow, EuiIcon, EuiPanel, - EuiSpacer, } from '@elastic/eui'; import axios from 'axios'; import { unix } from 'moment'; @@ -280,7 +279,6 @@ export function ResponderRequestsTable({ responder }: ResponderRequestsTableProp const shouldDisplayControlPanel = requests.status === 'succeeded' && requests.data.length > 0; const controlPanel = shouldDisplayControlPanel ? ( - @@ -298,7 +296,7 @@ export function ResponderRequestsTable({ responder }: ResponderRequestsTableProp ) : null; return ( - + {controlPanel}