From 6cc8cb8762403cf661f599e72cfc5344c16ca566 Mon Sep 17 00:00:00 2001 From: Robert Basti Date: Tue, 14 Jan 2025 19:16:53 +0100 Subject: [PATCH 01/22] rr --- .../components/Modals/OffsetLogCurveModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/WitsmlExplorer.Frontend/components/Modals/OffsetLogCurveModal.tsx b/Src/WitsmlExplorer.Frontend/components/Modals/OffsetLogCurveModal.tsx index 668eb5ef7..639dad207 100644 --- a/Src/WitsmlExplorer.Frontend/components/Modals/OffsetLogCurveModal.tsx +++ b/Src/WitsmlExplorer.Frontend/components/Modals/OffsetLogCurveModal.tsx @@ -189,7 +189,7 @@ export const OffsetLogCurveModal = ( onSubmit={onSubmit} isLoading={false} confirmText={"Save"} - confirmDisabled={!isValidOffset || !isValidInterval} + confirmDisabled={!isValidOffset || !isValidInterval} /> ); }; From 6e47b3b81de9eb0f198dbfa7ced4991a314fed22 Mon Sep 17 00:00:00 2001 From: Robert Basti Date: Tue, 21 Jan 2025 12:20:36 +0100 Subject: [PATCH 02/22] =?UTF-8?q?Large=20log=20data=20download=20-=20Memor?= =?UTF-8?q?y=20issue=F0=9F=90=9B=20#2617?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/LogObjectService.cs | 9 +- .../ContentViews/CurveValuesView.tsx | 2 + .../components/Modals/ConfirmModal.tsx | 2 + .../Modals/DownloadOptionsSelectionModal.tsx | 162 +++++++++++++++++- .../TrimLogObject/AdjustDateTimeModal.tsx | 41 +++-- 5 files changed, 187 insertions(+), 29 deletions(-) diff --git a/Src/WitsmlExplorer.Api/Services/LogObjectService.cs b/Src/WitsmlExplorer.Api/Services/LogObjectService.cs index 71fd31b57..636dfba90 100644 --- a/Src/WitsmlExplorer.Api/Services/LogObjectService.cs +++ b/Src/WitsmlExplorer.Api/Services/LogObjectService.cs @@ -367,7 +367,14 @@ private async Task LoadDataRecursive(List mnemonics, WitsmlLo { await using LogDataReader logDataReader = new(_witsmlClient, log, new List(mnemonics), null, startIndex, endIndex); WitsmlLogData logData = await logDataReader.GetNextBatch(cancellationToken); - + if (!startIndex.GetValueAsString().Equals(log.StartDateTimeIndex)) + { + log.StartDateTimeIndex = startIndex.GetValueAsString(); + } + if (!endIndex.GetValueAsString().Equals(log.EndDateTimeIndex)) + { + log.EndDateTimeIndex = endIndex.GetValueAsString(); + } var allLogData = logData; while (logData != null) { diff --git a/Src/WitsmlExplorer.Frontend/components/ContentViews/CurveValuesView.tsx b/Src/WitsmlExplorer.Frontend/components/ContentViews/CurveValuesView.tsx index 26e2deabd..a7e840ec8 100644 --- a/Src/WitsmlExplorer.Frontend/components/ContentViews/CurveValuesView.tsx +++ b/Src/WitsmlExplorer.Frontend/components/ContentViews/CurveValuesView.tsx @@ -380,6 +380,8 @@ export const CurveValuesView = (): React.ReactElement => { startIndex: startIndex, endIndex: endIndex, columns: columns, + logCurveInfoRows: null, + curveValueRows: tableData, autoRefresh: autoRefresh }; const action: DisplayModalAction = { diff --git a/Src/WitsmlExplorer.Frontend/components/Modals/ConfirmModal.tsx b/Src/WitsmlExplorer.Frontend/components/Modals/ConfirmModal.tsx index 3531afb24..f3dfee114 100644 --- a/Src/WitsmlExplorer.Frontend/components/Modals/ConfirmModal.tsx +++ b/Src/WitsmlExplorer.Frontend/components/Modals/ConfirmModal.tsx @@ -10,6 +10,7 @@ interface ConfirmProps { switchButtonPlaces?: boolean; showCancelButton?: boolean; cancelText?: string; + confirmDisabled?: boolean; } const ConfirmModal = (props: ConfirmProps): React.ReactElement => { @@ -24,6 +25,7 @@ const ConfirmModal = (props: ConfirmProps): React.ReactElement => { confirmColor={props.confirmColor} switchButtonPlaces={props.switchButtonPlaces} showCancelButton={props.showCancelButton} + confirmDisabled={props.confirmDisabled} /> ); }; diff --git a/Src/WitsmlExplorer.Frontend/components/Modals/DownloadOptionsSelectionModal.tsx b/Src/WitsmlExplorer.Frontend/components/Modals/DownloadOptionsSelectionModal.tsx index 3cbdc8b24..4cb883bc1 100644 --- a/Src/WitsmlExplorer.Frontend/components/Modals/DownloadOptionsSelectionModal.tsx +++ b/Src/WitsmlExplorer.Frontend/components/Modals/DownloadOptionsSelectionModal.tsx @@ -13,10 +13,20 @@ import orderBy from "lodash/orderBy"; import DownloadLogDataJob from "models/jobs/downloadLogDataJob"; import { CurveSpecification } from "models/logData"; import LogObject, { indexToNumber } from "models/logObject"; -import React, { CSSProperties, useCallback, useState } from "react"; +import React, { CSSProperties, useCallback, useMemo, useState } from "react"; import JobService, { JobType } from "services/jobService"; import ConfirmModal from "./ConfirmModal"; import { ReportModal } from "./ReportModal"; +import { RouterLogType } from "routes/routerConstants"; +import { useParams } from "react-router-dom"; +import { LogCurveInfoRow } from "components/ContentViews/LogCurveInfoListViewUtils"; +import { + WITSML_INDEX_TYPE_DATE_TIME, + WITSML_LOG_ORDERTYPE_DECREASING +} from "components/Constants"; +import AdjustDateTimeModal from "./TrimLogObject/AdjustDateTimeModal"; +import { useGetActiveRoute } from "hooks/useGetActiveRoute"; +import WarningBar from "components/WarningBar"; export interface DownloadOptionsSelectionModalProps { mnemonics: string[]; @@ -25,6 +35,8 @@ export interface DownloadOptionsSelectionModalProps { startIndex: string; endIndex: string; columns: ExportableContentTableColumn[]; + logCurveInfoRows: LogCurveInfoRow[]; + curveValueRows: CurveValueRow[]; autoRefresh: boolean; } @@ -48,9 +60,86 @@ const DownloadOptionsSelectionModal = ( const [selectedDownloadFormat, setSelectedDownloadFormat] = useState(DownloadFormat.Csv); - const { exportData, exportOptions } = useExport(); + const { logType } = useParams(); + + const { logCurveInfoRows, log, curveValueRows } = props; + + const getStartIndex = ( + log: LogObject, + logCurveInfoRows: LogCurveInfoRow[], + isMultiLog: boolean + ): string | number => { + const isTimeIndexed = log.indexType === WITSML_INDEX_TYPE_DATE_TIME; + + if (isMultiLog) { + if (isTimeIndexed) { + return ( + logCurveInfoRows + .reduce((minRow, currentRow) => { + if (minRow.minIndex === null) return currentRow; + if (currentRow.minIndex === null) return minRow; + return new Date(currentRow.minIndex) < new Date(minRow.minIndex) + ? currentRow + : minRow; + }) + .minIndex?.toString() ?? "" + ); + } else { + const min = Math.min( + ...logCurveInfoRows.map((lci) => + lci.minIndex === null ? Infinity : (lci.minIndex as number) + ) + ); + return min === Infinity ? 0 : min; + } + } else { + return isTimeIndexed ? log.startIndex : indexToNumber(log.startIndex); + } + }; + + const getEndIndex = ( + log: LogObject, + logCurveInfoRows: LogCurveInfoRow[], + isMultiLog: boolean + ): string | number => { + const isTimeIndexed = log.indexType === WITSML_INDEX_TYPE_DATE_TIME; + + if (isMultiLog) { + if (isTimeIndexed) { + return ( + logCurveInfoRows + .reduce((maxRow, currentRow) => + new Date(currentRow.maxIndex) > new Date(maxRow.maxIndex) + ? currentRow + : maxRow + ) + .maxIndex?.toString() ?? "" + ); + } else { + return Math.max( + ...logCurveInfoRows.map((lci) => lci.maxIndex as number) + ); + } + } else { + return isTimeIndexed ? log.endIndex : indexToNumber(log.endIndex); + } + }; + + const isTimeLog = logType === RouterLogType.TIME; + + const { isMultiLogsCurveInfoListView: isMultiLog } = useGetActiveRoute(); + const [startIndex, setStartIndex] = useState( + getStartIndex(log, logCurveInfoRows, isMultiLog) + ); + const [endIndex, setEndIndex] = useState( + getEndIndex(log, logCurveInfoRows, isMultiLog) + ); + const [maxSpan, setMaxSpan] = useState(); + + const [isValidInterval, setIsValidInterval] = useState(true); + const exportSelectedRange = async () => { const logReference: LogObject = props.log; const startIndexIsInclusive = !props.autoRefresh; @@ -70,13 +159,26 @@ const DownloadOptionsSelectionModal = ( const logReference: LogObject = props.log; const startIndexIsInclusive = !props.autoRefresh; const exportToLas = selectedDownloadFormat === DownloadFormat.Las; - const downloadLogDataJob: DownloadLogDataJob = { - logReference, - mnemonics: props.mnemonics, - startIndexIsInclusive, - exportToLas - }; - callExportJob(downloadLogDataJob); + const isTimeIndexed = log.indexType === WITSML_INDEX_TYPE_DATE_TIME; + if (isTimeIndexed) { + const downloadLogDataJob: DownloadLogDataJob = { + logReference, + mnemonics: props.mnemonics, + startIndexIsInclusive, + exportToLas, + startIndex: startIndex.toString(), + endIndex: endIndex.toString() + }; + callExportJob(downloadLogDataJob); + } else { + const downloadLogDataJob: DownloadLogDataJob = { + logReference, + mnemonics: props.mnemonics, + startIndexIsInclusive, + exportToLas + }; + callExportJob(downloadLogDataJob); + } }; const callExportJob = async (downloadLogDataJob: DownloadLogDataJob) => { @@ -144,9 +246,29 @@ const DownloadOptionsSelectionModal = ( } }; + const tooBigInterval = useMemo(() => { + if (curveValueRows !== null && curveValueRows.length > 1) { + var step = + new Date(curveValueRows[1].id.toString()).getTime() - + new Date(curveValueRows[0].id.toString()).getTime(); + var actualSize = + (new Date(endIndex).getTime() - new Date(startIndex).getTime()) / + 60 / + 60 / + 24; + var maxAvaivableSize = (1300 * step) / props.mnemonics.length; + setMaxSpan(maxAvaivableSize); + if (actualSize < maxAvaivableSize) { + return false; + } + return true; + } + }, [endIndex, startIndex]); + return ( @@ -210,6 +332,28 @@ const DownloadOptionsSelectionModal = ( /> Las file + {isTimeLog && + tooBigInterval && + selectedDownloadOption === DownloadOptions.All && ( + + )} + {isTimeLog && selectedDownloadOption === DownloadOptions.All && ( + setIsValidInterval(isValid)} + /> + )} } onConfirm={() => { diff --git a/Src/WitsmlExplorer.Frontend/components/Modals/TrimLogObject/AdjustDateTimeModal.tsx b/Src/WitsmlExplorer.Frontend/components/Modals/TrimLogObject/AdjustDateTimeModal.tsx index 7603455da..5b66fb1d1 100644 --- a/Src/WitsmlExplorer.Frontend/components/Modals/TrimLogObject/AdjustDateTimeModal.tsx +++ b/Src/WitsmlExplorer.Frontend/components/Modals/TrimLogObject/AdjustDateTimeModal.tsx @@ -8,6 +8,7 @@ export interface AdjustDateTimeModelProps { minDate: string; maxDate: string; isDescending?: boolean; + hideSetButtons?: boolean; onStartDateChanged: (value: string) => void; onEndDateChanged: (value: string) => void; onValidChange: (isValid: boolean) => void; @@ -25,6 +26,7 @@ const AdjustDateTimeModal = ( minDate, maxDate, isDescending, + hideSetButtons, onStartDateChanged, onEndDateChanged, onValidChange @@ -93,25 +95,26 @@ const AdjustDateTimeModal = ( aria-label="set time range button group" style={{ margin: ".5rem" }} > - {setRangeButtons.map((buttonValue) => { - return ( - totalTimeSpan > buttonValue.timeInMilliseconds && ( - - ) - ); - })} + {!hideSetButtons && + setRangeButtons.map((buttonValue) => { + return ( + totalTimeSpan > buttonValue.timeInMilliseconds && ( + + ) + ); + })}