diff --git a/Src/WitsmlExplorer.Api/Services/LogObjectService.cs b/Src/WitsmlExplorer.Api/Services/LogObjectService.cs index 71fd31b57..12497f1e4 100644 --- a/Src/WitsmlExplorer.Api/Services/LogObjectService.cs +++ b/Src/WitsmlExplorer.Api/Services/LogObjectService.cs @@ -367,13 +367,12 @@ 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); - var allLogData = logData; while (logData != null) { if (progressReporter != null) { - double progress = LogWorkerTools.CalculateProgressBasedOnIndex(log, logData); + double progress = LogWorkerTools.CalculateProgressBasedOnIndex(log, logData, startIndex, endIndex); progressReporter.Report(progress); } logData = await logDataReader.GetNextBatch(cancellationToken); diff --git a/Src/WitsmlExplorer.Api/Workers/DownloadLogDataWorker.cs b/Src/WitsmlExplorer.Api/Workers/DownloadLogDataWorker.cs index 43258b323..168c50a59 100644 --- a/Src/WitsmlExplorer.Api/Workers/DownloadLogDataWorker.cs +++ b/Src/WitsmlExplorer.Api/Workers/DownloadLogDataWorker.cs @@ -66,6 +66,13 @@ public DownloadLogDataWorker( } var logData = await _logObjectService.ReadLogData(job.LogReference.WellUid, job.LogReference.WellboreUid, job.LogReference.Uid, job.Mnemonics.ToList(), job.StartIndexIsInclusive, job.LogReference.StartIndex, job.LogReference.EndIndex, true, cancellationToken, progressReporter); + if (logData.CurveSpecifications == null) + { + var message = "DownloadLogDataJob failed. No data found in the given range."; + Logger.LogError(message); + return (new WorkerResult(GetTargetWitsmlClientOrThrow().GetServerHostname(), false, message, message, jobId: job.JobInfo.Id), null); + } + return (job.ExportToLas) ? await DownloadLogDataResultLasFile(job, logData.Data, logData.CurveSpecifications) diff --git a/Src/WitsmlExplorer.Api/Workers/Tools/LogWorkerTools.cs b/Src/WitsmlExplorer.Api/Workers/Tools/LogWorkerTools.cs index 6412a33fd..aa574959d 100644 --- a/Src/WitsmlExplorer.Api/Workers/Tools/LogWorkerTools.cs +++ b/Src/WitsmlExplorer.Api/Workers/Tools/LogWorkerTools.cs @@ -63,7 +63,7 @@ public static async Task GetLogDataForCurve(IWitsmlClient witsmlC }; } - public static double CalculateProgressBasedOnIndex(WitsmlLog log, WitsmlLogData currentData) + public static double CalculateProgressBasedOnIndex(WitsmlLog log, WitsmlLogData currentData, CurveIndex start = null, CurveIndex end = null) { string index = currentData.Data.LastOrDefault()?.Data.Split(CommonConstants.DataSeparator).FirstOrDefault(); if (index == null) return 0; @@ -77,6 +77,15 @@ public static double CalculateProgressBasedOnIndex(WitsmlLog log, WitsmlLogData { string startIndex = log.StartDateTimeIndex; string endIndex = log.EndDateTimeIndex; + if (start != null && !start.GetValueAsString().Equals(log.StartDateTimeIndex)) + { + startIndex = start.GetValueAsString(); + } + if (end != null && !end.GetValueAsString().Equals(log.EndDateTimeIndex)) + { + endIndex = end.GetValueAsString(); + } + return (DateTime.Parse(index) - DateTime.Parse(startIndex)).TotalMilliseconds / (DateTime.Parse(endIndex) - DateTime.Parse(startIndex)).TotalMilliseconds; } } diff --git a/Src/WitsmlExplorer.Frontend/components/ContentViews/CurveValuesView.tsx b/Src/WitsmlExplorer.Frontend/components/ContentViews/CurveValuesView.tsx index 26e2deabd..994abed54 100644 --- a/Src/WitsmlExplorer.Frontend/components/ContentViews/CurveValuesView.tsx +++ b/Src/WitsmlExplorer.Frontend/components/ContentViews/CurveValuesView.tsx @@ -380,6 +380,7 @@ export const CurveValuesView = (): React.ReactElement => { startIndex: startIndex, endIndex: endIndex, columns: columns, + 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..a65164777 100644 --- a/Src/WitsmlExplorer.Frontend/components/Modals/DownloadOptionsSelectionModal.tsx +++ b/Src/WitsmlExplorer.Frontend/components/Modals/DownloadOptionsSelectionModal.tsx @@ -17,6 +17,14 @@ import React, { CSSProperties, useCallback, 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 { + WITSML_INDEX_TYPE_DATE_TIME, + WITSML_LOG_ORDERTYPE_DECREASING +} from "components/Constants"; +import AdjustDateTimeModal from "./TrimLogObject/AdjustDateTimeModal"; +import WarningBar from "components/WarningBar"; export interface DownloadOptionsSelectionModalProps { mnemonics: string[]; @@ -25,6 +33,7 @@ export interface DownloadOptionsSelectionModalProps { startIndex: string; endIndex: string; columns: ExportableContentTableColumn[]; + curveValueRows: CurveValueRow[]; autoRefresh: boolean; } @@ -48,9 +57,41 @@ const DownloadOptionsSelectionModal = ( const [selectedDownloadFormat, setSelectedDownloadFormat] = useState(DownloadFormat.Csv); - const { exportData, exportOptions } = useExport(); + const { logType } = useParams(); + + const { log, curveValueRows } = props; + + const getStartIndex = (log: LogObject): string | number => { + const isTimeIndexed = log.indexType === WITSML_INDEX_TYPE_DATE_TIME; + if (selectedDownloadOption === DownloadOptions.All) { + return isTimeIndexed ? log.startIndex : indexToNumber(log.startIndex); + } + if (selectedDownloadOption === DownloadOptions.SelectedRange) { + return isTimeIndexed ? props.startIndex : indexToNumber(props.startIndex); + } + }; + + const getEndIndex = (log: LogObject): string | number => { + const isTimeIndexed = log.indexType === WITSML_INDEX_TYPE_DATE_TIME; + if (selectedDownloadOption === DownloadOptions.All) { + return isTimeIndexed ? log.endIndex : indexToNumber(log.endIndex); + } + if (selectedDownloadOption === DownloadOptions.SelectedRange) { + return isTimeIndexed ? props.endIndex : indexToNumber(props.endIndex); + } + }; + + const isTimeLog = logType === RouterLogType.TIME; + + const [startIndex, setStartIndex] = useState( + getStartIndex(log) + ); + const [endIndex, setEndIndex] = useState(getEndIndex(log)); + + const [isValidInterval, setIsValidInterval] = useState(true); + const exportSelectedRange = async () => { const logReference: LogObject = props.log; const startIndexIsInclusive = !props.autoRefresh; @@ -60,8 +101,8 @@ const DownloadOptionsSelectionModal = ( mnemonics: props.mnemonics, startIndexIsInclusive, exportToLas, - startIndex: props.startIndex, - endIndex: props.endIndex + startIndex: startIndex.toString(), + endIndex: endIndex.toString() }; callExportJob(downloadLogDataJob); }; @@ -70,13 +111,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 +198,31 @@ const DownloadOptionsSelectionModal = ( } }; + const step = + curveValueRows?.length > 1 + ? new Date(curveValueRows[1].id.toString()).getTime() - + new Date(curveValueRows[0].id.toString()).getTime() + : null; + const actualSize = + (new Date(endIndex).getTime() - new Date(startIndex).getTime()) / + 60 / + 60 / + 24; + const maxSpan = (1290 * step) / props.mnemonics.length; + const tooBigInterval = actualSize > maxSpan; + + const outOfRange = + new Date(startIndex).getTime() - new Date(log.startIndex).getTime() < 0 || + new Date(endIndex).getTime() - new Date(log.endIndex).getTime() > 0; + return ( @@ -210,6 +286,49 @@ const DownloadOptionsSelectionModal = ( /> Las file + {isTimeLog && + tooBigInterval && + (selectedDownloadOption === DownloadOptions.All || + selectedDownloadOption === DownloadOptions.SelectedRange) && ( + + )} + {isTimeLog && + outOfRange && + (selectedDownloadOption === DownloadOptions.All || + selectedDownloadOption === DownloadOptions.SelectedRange) && ( + + )} + {isTimeLog && selectedDownloadOption === DownloadOptions.All && ( + setIsValidInterval(isValid)} + /> + )} + {isTimeLog && + selectedDownloadOption === DownloadOptions.SelectedRange && ( + + 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 && ( + + ) + ); + })}