From da6a026763326d1279e6d616a666bd232fb07f51 Mon Sep 17 00:00:00 2001 From: Saloni Gupta Date: Fri, 10 May 2024 10:33:56 -0700 Subject: [PATCH] changes based on comments --- master/internal/api_trials.go | 4 +- master/internal/api_trials_intg_test.go | 25 +- .../RemainingRetentionDaysLabelComponent.tsx | 37 +++ .../ExperimentSingleTrialTabs.tsx | 70 ++---- webui/react/src/pages/TrialDetails.tsx | 69 ++--- .../pages/TrialDetails/TrialInfoBox.test.tsx | 237 ++++++++++++++++++ .../src/pages/TrialDetails/TrialInfoBox.tsx | 7 +- 7 files changed, 331 insertions(+), 118 deletions(-) create mode 100644 webui/react/src/components/RemainingRetentionDaysLabelComponent.tsx create mode 100644 webui/react/src/pages/TrialDetails/TrialInfoBox.test.tsx diff --git a/master/internal/api_trials.go b/master/internal/api_trials.go index de8380fc303..34e28c2d0bb 100644 --- a/master/internal/api_trials.go +++ b/master/internal/api_trials.go @@ -656,7 +656,7 @@ func (a *apiServer) GetTrialRemainingLogRetentionDays( q := ` SELECT CASE - WHEN MIN(t.end_time) <= ( retention_timestamp() - make_interval(days => ?) ) THEN 0 + WHEN MIN(t.end_time) <= ( NOW() - make_interval(days => ?) ) THEN 0 ELSE extract(day from MIN(end_time) + make_interval(days => ?) - NOW())::int END remaining_log_retention_days FROM tasks t @@ -1568,6 +1568,8 @@ func (a *apiServer) PostTrialRunnerMetadata( func (a *apiServer) isTrialTerminalFunc(trialID int, buffer time.Duration) api.TerminationCheckFn { return func() (bool, error) { state, endTime, err := a.m.db.TrialStatus(trialID) + log.Print("state, ", state) + log.Print("endTime", endTime) if err != nil || (model.TerminalStates[state] && endTime.Add(buffer).Before(time.Now().UTC())) { return true, err diff --git a/master/internal/api_trials_intg_test.go b/master/internal/api_trials_intg_test.go index 308a53f260c..cfe01ef9e80 100644 --- a/master/internal/api_trials_intg_test.go +++ b/master/internal/api_trials_intg_test.go @@ -1450,18 +1450,29 @@ func TestPutTrialRetainLogs(t *testing.T) { } func completeTrialsandTasks(ctx context.Context, trialID int, endTimeDays int) error { - _, err := db.Bun().NewUpdate().Table("runs"). + _, err := db.Bun().NewUpdate(). + Table("tasks", "run_id_task_id"). + Set("end_time = (NOW() - make_interval(days => ?))", endTimeDays). + Where("run_id_task_id.run_id = ? and tasks.task_id = run_id_task_id.task_id", trialID). + Exec(ctx) + if err != nil { + return err + } + _, err = db.Bun().NewUpdate().Table("runs", "run_id_task_id", "tasks"). Set("state = ?", model.CompletedState). + Set("end_time = (NOW() - make_interval(days => ?))", endTimeDays). Where("id = ?", trialID). Exec(ctx) if err != nil { return err } + return nil +} - _, err = db.Bun().NewUpdate(). - Table("tasks", "run_id_task_id"). - Set("end_time = (NOW() - make_interval(days => ?))", endTimeDays). - Where("run_id_task_id.run_id = ? and tasks.task_id = run_id_task_id.task_id", trialID). +func completeExp(ctx context.Context, expID int32) error { + _, err := db.Bun().NewUpdate().Table("experiments"). + Set("state = ?", model.CompletedState). + Where("id = ?", expID). Exec(ctx) if err != nil { return err @@ -1491,7 +1502,7 @@ retention_policy: for _, tt := range tests { log.Printf("Starting %v", tt.name) testEndTimes := []int{15, 10, 5, 0} - _, trialIDs, _ := CreateTestRetentionExperiment(ctx, t, api, tt.logRetentionDays, len(testEndTimes)) + exp, trialIDs, _ := CreateTestRetentionExperiment(ctx, t, api, tt.logRetentionDays, len(testEndTimes)) for i, v := range testEndTimes { err := completeTrialsandTasks(ctx, trialIDs[i], v) @@ -1503,5 +1514,7 @@ retention_policy: require.NoError(t, err) require.Equal(t, tt.expRemainingDays[i], *d.RemainingDays) } + err := completeExp(ctx, exp.Id) + require.NoError(t, err) } } diff --git a/webui/react/src/components/RemainingRetentionDaysLabelComponent.tsx b/webui/react/src/components/RemainingRetentionDaysLabelComponent.tsx new file mode 100644 index 00000000000..8d518a5a986 --- /dev/null +++ b/webui/react/src/components/RemainingRetentionDaysLabelComponent.tsx @@ -0,0 +1,37 @@ +import { Loadable } from 'hew/utils/loadable'; +import React from 'react'; + +import { pluralizer } from 'utils/string'; + +import Badge from './Badge'; + +interface Props { + remainingLogDays: Loadable; +} + +const RemainingRetentionDaysLabelComponent: React.FC = ({ remainingLogDays }: Props) => { + let toolTipText = ''; + let badgeText = ''; + const days = Loadable.getOrElse(undefined, remainingLogDays); + if (days === undefined) { + toolTipText = 'Days remaining to retention are not available yet.'; + badgeText = '-'; + } else if (days === -1) { + toolTipText = 'Logs will be retained forever.'; + badgeText = 'Frvr'; + } else if (days === 0) { + toolTipText = 'Some logs have begun to be deleted for this trial.'; + badgeText = '0'; + } else { + toolTipText = `${days} ${pluralizer(days, 'day')} left to retain logs`; + badgeText = `${days}`; + } + return ( +
+ Logs + {badgeText} +
+ ); +}; + +export default RemainingRetentionDaysLabelComponent; diff --git a/webui/react/src/pages/ExperimentDetails/ExperimentSingleTrialTabs.tsx b/webui/react/src/pages/ExperimentDetails/ExperimentSingleTrialTabs.tsx index d5a4673f393..b094c49dd84 100644 --- a/webui/react/src/pages/ExperimentDetails/ExperimentSingleTrialTabs.tsx +++ b/webui/react/src/pages/ExperimentDetails/ExperimentSingleTrialTabs.tsx @@ -10,8 +10,8 @@ import { string } from 'io-ts'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { unstable_useBlocker, useLocation, useNavigate, useParams } from 'react-router-dom'; -import Badge from 'components/Badge'; import HyperparameterSearchModalComponent from 'components/HyperparameterSearchModal'; +import RemainingRetentionDaysLabelComponent from 'components/RemainingRetentionDaysLabelComponent'; import TrialLogPreview from 'components/TrialLogPreview'; import { UNMANAGED_MESSAGE } from 'constant'; import { terminalRunStates } from 'constants/states'; @@ -33,7 +33,6 @@ import { } from 'services/api'; import { ExperimentBase, Note, TrialDetails, TrialItem, ValueOf } from 'types'; import handleError, { ErrorLevel, ErrorType } from 'utils/error'; -import { pluralizer } from 'utils/string'; import ExperimentCheckpoints from './ExperimentCheckpoints'; import ExperimentCodeViewer from './ExperimentCodeViewer'; @@ -84,7 +83,7 @@ const ExperimentSingleTrialTabs: React.FC = ({ const [canceler] = useState(new AbortController()); const [trialDetails, setTrialDetails] = useState(); const [tabKey, setTabKey] = useState(tab && TAB_KEYS.includes(tab) ? tab : DEFAULT_TAB_KEY); - const [remainingLogDays, setRemainingLogDays] = useState>(NotLoaded); + const [remainingLogDays, setRemainingLogDays] = useState>(NotLoaded); const waitingForTrials = !trialId && !wontHaveTrials; @@ -139,12 +138,16 @@ const ExperimentSingleTrialTabs: React.FC = ({ } }, [canceler, experiment.id, experiment.state, onTrialUpdate]); - const fetchTrialDetails = useCallback(async () => { + const fetchTrialData = useCallback(async () => { if (!trialId) return; try { - const response = await getTrialDetails({ id: trialId }, { signal: canceler.signal }); - onTrialUpdate?.(response); - setTrialDetails(response); + const [trialDetailResponse, logRemainingResponse] = await Promise.all([ + getTrialDetails({ id: trialId }, { signal: canceler.signal }), + getTrialRemainingLogRetentionDays({ id: trialId }), + ]); + onTrialUpdate?.(trialDetailResponse); + setTrialDetails(trialDetailResponse); + setRemainingLogDays(Loaded(logRemainingResponse.remainingLogRetentionDays)); } catch (e) { handleError(e, { level: ErrorLevel.Error, @@ -155,50 +158,7 @@ const ExperimentSingleTrialTabs: React.FC = ({ } }, [canceler.signal, onTrialUpdate, trialId]); - const fetchRemainingLogDays = useCallback(async () => { - if (!trialId) return; - try { - const remainingDays = await getTrialRemainingLogRetentionDays({ id: trialId }); - setRemainingLogDays( - remainingDays.remainingLogRetentionDays !== undefined - ? Loaded(remainingDays.remainingLogRetentionDays) - : NotLoaded, - ); - } catch (e) { - setRemainingLogDays(NotLoaded); - } - }, [trialId]); - - const fetchAllTrialDetails = useCallback(async () => { - await Promise.allSettled([fetchTrialDetails(), fetchRemainingLogDays()]); - }, [fetchRemainingLogDays, fetchTrialDetails]); - - const getRemainingLogsLabel = useMemo(() => { - let toolTipText = ''; - let badgeText = ''; - const days = Loadable.getOrElse(null, remainingLogDays); - if (days === null) { - toolTipText = 'Days remaining to retention are not available yet.'; - badgeText = '-'; - } else if (days === -1) { - toolTipText = 'Logs will be retained forever.'; - badgeText = 'Frvr'; - } else if (days === 0) { - toolTipText = 'Some logs have begun to be deleted for this trial.'; - badgeText = '0'; - } else { - toolTipText = `${pluralizer(days, 'day')} left to retain logs`; - badgeText = `${remainingLogDays}`; - } - return ( -
- <>Logs - {badgeText} -
- ); - }, [remainingLogDays]); - - const { stopPolling } = usePolling(fetchAllTrialDetails, { rerunOnNewFn: true }); + const { stopPolling } = usePolling(fetchTrialData, { rerunOnNewFn: true }); const { stopPolling: stopPollingFirstTrialId } = usePolling(fetchFirstTrialId, { rerunOnNewFn: true, }); @@ -250,8 +210,8 @@ const ExperimentSingleTrialTabs: React.FC = ({ * next polling cycle when trial Id goes from undefined to defined. */ useEffect(() => { - if (prevTrialId === undefined && prevTrialId !== trialId) fetchAllTrialDetails(); - }, [fetchAllTrialDetails, prevTrialId, trialId]); + if (prevTrialId === undefined && prevTrialId !== trialId) fetchTrialData(); + }, [fetchTrialData, prevTrialId, trialId]); const handleNotesUpdate = useCallback( async (notes: Note) => { @@ -371,7 +331,7 @@ const ExperimentSingleTrialTabs: React.FC = ({ ), key: TabType.Logs, - label: getRemainingLogsLabel, + label: RemainingRetentionDaysLabelComponent({ remainingLogDays }), }); } @@ -379,10 +339,10 @@ const ExperimentSingleTrialTabs: React.FC = ({ }, [ editableNotes, experiment, - getRemainingLogsLabel, handleNotesUpdate, handleSelectFile, pageRef, + remainingLogDays, settings.filePath, showExperimentArtifacts, trialDetails, diff --git a/webui/react/src/pages/TrialDetails.tsx b/webui/react/src/pages/TrialDetails.tsx index e145848db16..ce0c4e897e1 100644 --- a/webui/react/src/pages/TrialDetails.tsx +++ b/webui/react/src/pages/TrialDetails.tsx @@ -5,8 +5,8 @@ import { Loadable, Loaded, NotLoaded } from 'hew/utils/loadable'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; -import Badge from 'components/Badge'; import Page from 'components/Page'; +import RemainingRetentionDaysLabelComponent from 'components/RemainingRetentionDaysLabelComponent'; import RoutePagination from 'components/RoutePagination'; import TrialLogPreview from 'components/TrialLogPreview'; import { terminalRunStates } from 'constants/states'; @@ -30,7 +30,6 @@ import handleError, { ErrorType } from 'utils/error'; import { isSingleTrialExperiment } from 'utils/experiment'; import { useObservable } from 'utils/observable'; import { isAborted, isNotFound } from 'utils/service'; -import { pluralizer } from 'utils/string'; import MultiTrialDetailsHyperparameters from './TrialDetails/MultiTrialDetailsHyperparameters'; @@ -71,7 +70,7 @@ const TrialDetailsComp: React.FC = () => { const workspaces = Loadable.getOrElse([], useObservable(workspaceStore.workspaces)); const basePath = paths.trialDetails(trialId, experimentId); const trial = trialDetails.data; - const [remainingLogDays, setRemainingLogDays] = useState>(NotLoaded); + const [remainingLogDays, setRemainingLogDays] = useState>(NotLoaded); const showExperimentArtifacts = usePermissions().canViewExperimentArtifacts({ workspace: { id: experiment?.workspaceId ?? 0 }, @@ -104,10 +103,14 @@ const TrialDetailsComp: React.FC = () => { } }, [canceler, navigate, experimentId, trial]); - const fetchTrialDetails = useCallback(async () => { + const fetchTrialData = useCallback(async () => { try { - const response = await getTrialDetails({ id: trialId }, { signal: canceler.signal }); - setTrialDetails((prev) => ({ ...prev, data: response })); + const [trialDetailResponse, logRemainingResponse] = await Promise.all([ + getTrialDetails({ id: trialId }, { signal: canceler.signal }), + getTrialRemainingLogRetentionDays({ id: trialId }), + ]); + setTrialDetails((prev) => ({ ...prev, data: trialDetailResponse })); + setRemainingLogDays(Loaded(logRemainingResponse.remainingLogRetentionDays)); } catch (e) { if (!trialDetails.error && !isAborted(e)) { setTrialDetails((prev) => ({ ...prev, error: e as Error })); @@ -115,48 +118,6 @@ const TrialDetailsComp: React.FC = () => { } }, [canceler, trialDetails.error, trialId]); - const fetchRemainingLogDays = useCallback(async () => { - try { - const remainingDays = await getTrialRemainingLogRetentionDays({ id: trialId }); - setRemainingLogDays( - remainingDays.remainingLogRetentionDays !== undefined - ? Loaded(remainingDays.remainingLogRetentionDays) - : NotLoaded, - ); - } catch (e) { - setRemainingLogDays(NotLoaded); - } - }, [trialId]); - - const fetchAllTrialDetails = useCallback(async () => { - await Promise.allSettled([fetchTrialDetails(), fetchRemainingLogDays()]); - }, [fetchRemainingLogDays, fetchTrialDetails]); - - const getRemainingLogsLabel = useMemo(() => { - let toolTipText = ''; - let badgeText = ''; - const days = Loadable.getOrElse(null, remainingLogDays); - if (days === null) { - toolTipText = 'Days remaining to retention are not available yet.'; - badgeText = '-'; - } else if (days === -1) { - toolTipText = 'Logs will be retained forever.'; - badgeText = 'Frvr'; - } else if (days === 0) { - toolTipText = 'Some logs have begun to be deleted for this trial.'; - badgeText = '0'; - } else { - toolTipText = `${pluralizer(days, 'day')} left to retain logs`; - badgeText = `${remainingLogDays}`; - } - return ( -
- <>Logs - {badgeText} -
- ); - }, [remainingLogDays]); - const handleTabChange = useCallback( (key: string) => { setTabKey(key as TabType); @@ -210,7 +171,7 @@ const TrialDetailsComp: React.FC = () => { { children: , key: TabType.Logs, - label: getRemainingLogsLabel, + label: RemainingRetentionDaysLabelComponent({ remainingLogDays }), }, ]; @@ -223,9 +184,9 @@ const TrialDetailsComp: React.FC = () => { } return tabs; - }, [experiment, trial, getRemainingLogsLabel, showExperimentArtifacts]); + }, [experiment, trial, remainingLogDays, showExperimentArtifacts]); - const { stopPolling } = usePolling(fetchAllTrialDetails); + const { stopPolling } = usePolling(fetchTrialData); useEffect(() => { setTrialId(Number(trialID)); @@ -233,8 +194,8 @@ const TrialDetailsComp: React.FC = () => { useEffect(() => { setIsFetching(true); - fetchAllTrialDetails(); - }, [fetchAllTrialDetails, trialId]); + fetchTrialData(); + }, [fetchTrialData, trialId]); useEffect(() => { fetchExperimentDetails(); @@ -290,7 +251,7 @@ const TrialDetailsComp: React.FC = () => { headerComponent={ } diff --git a/webui/react/src/pages/TrialDetails/TrialInfoBox.test.tsx b/webui/react/src/pages/TrialDetails/TrialInfoBox.test.tsx new file mode 100644 index 00000000000..931e95fba06 --- /dev/null +++ b/webui/react/src/pages/TrialDetails/TrialInfoBox.test.tsx @@ -0,0 +1,237 @@ +import { render, screen } from '@testing-library/react'; +import UIProvider, { DefaultTheme } from 'hew/Theme'; +import { ConfirmationProvider } from 'hew/useConfirm'; + +import {} from 'stores/cluster'; + +import { ExperimentBase, TrialDetails } from 'types'; + +import TrialInfoBox from './TrialInfoBox'; + +vi.useFakeTimers(); + +vi.mock('routes/utils', async (importOriginal) => ({ + ...(await importOriginal()), + serverAddress: () => 'http://localhost', +})); + +const setup = (trial: TrialDetails, experiment: ExperimentBase) => { + const view = render( + + + + + , + ); + return { view }; +}; + +const mockExperiment: ExperimentBase = { + archived: false, + config: { + checkpointPolicy: 'best', + checkpointStorage: { + bucket: 'det-determined-master-us-west-2-573932760021', + saveExperimentBest: 0, + saveTrialBest: 1, + saveTrialLatest: 1, + type: 's3' as const, + }, + hyperparameters: { + global_batch_size: { type: 'const' as const, val: 64 }, + hidden_size: { type: 'const' as const, val: 64 }, + learning_rate: { maxval: 0.1, minval: 0.0001, type: 'double' as const }, + }, + labels: [], + maxRestarts: 5, + name: 'mnist_pytorch_lightning_adaptive', + profiling: { enabled: false }, + resources: {}, + searcher: { + max_length: { batches: 937, epochs: 1, records: 1 }, + max_trials: 16, + metric: 'val_loss', + name: 'adaptive_asha' as const, + smallerIsBetter: true, + }, + }, + configRaw: {}, + hyperparameters: {}, + id: 1, + jobId: '', + labels: [], + name: '', + numTrials: 3, + originalConfig: '', + parentArchived: false, + projectId: 0, + projectName: '', + projectOwnerId: 0, + resourcePool: '', + searcherType: '', + startTime: '', + state: 'ACTIVE', + trialIds: [1, 2, 3], + userId: 0, + workspaceId: 0, + workspaceName: '', +}; + +const mockTrial1: TrialDetails = { + autoRestarts: 0, + bestAvailableCheckpoint: { + endTime: '2022-08-05T05:56:47.998811Z', + resources: { + 'code/': 0, + 'code/adaptive.yaml': 418, + 'code/const.yaml': 349, + 'code/data.py': 3254, + 'code/mnist.py': 2996, + 'code/model_def.py': 1445, + 'code/README.md': 1492, + 'code/startup-hook.sh': 59, + 'load_data.json': 2665, + 'state_dict.pth': 680041, + 'workload_sequencer.pkl': 89, + }, + state: 'COMPLETED' as const, + totalBatches: 58, + uuid: 'b01dfffc-ad3e-4398-b205-b66d920d7b0b', + }, + bestValidationMetric: { + endTime: '2022-08-05T05:56:49.692523Z', + metrics: { accuracy: 0.17780853807926178, val_loss: 2.141766309738159 }, + totalBatches: 58, + }, + endTime: '2022-08-05T05:56:51.432745Z', + experimentId: 1, + hyperparameters: { + global_batch_size: 64, + hidden_size: 64, + learning_rate: 0.08311236560675993, + }, + id: 3, + latestValidationMetric: { + endTime: '2022-08-05T05:56:49.692523Z', + metrics: { accuracy: 0.17780853807926178, val_loss: 2.141766309738159 }, + totalBatches: 58, + }, + startTime: '2022-08-05T05:56:23.400221Z', + state: 'COMPLETED' as const, + totalBatchesProcessed: 58, + totalCheckpointSize: 58, +}; + +const mockTrial2: TrialDetails = { + autoRestarts: 0, + bestAvailableCheckpoint: { + endTime: '2022-08-05T05:56:19.781968Z', + resources: { + 'code/': 0, + 'code/adaptive.yaml': 418, + 'code/const.yaml': 349, + 'code/data.py': 3254, + 'code/mnist.py': 2996, + 'code/model_def.py': 1445, + 'code/README.md': 1492, + 'code/startup-hook.sh': 59, + 'load_data.json': 2664, + 'state_dict.pth': 680105, + 'workload_sequencer.pkl': 89, + }, + state: 'COMPLETED' as const, + totalBatches: 58, + uuid: '3b780651-0250-4307-8ec0-fac09a688970', + }, + bestValidationMetric: { + endTime: '2022-08-05T05:56:21.150552Z', + metrics: { accuracy: 0.1809730976819992, val_loss: 2.1605682373046875 }, + totalBatches: 58, + }, + endTime: '2022-08-05T05:56:49.524883Z', + experimentId: 1, + hyperparameters: { + global_batch_size: 64, + hidden_size: 64, + learning_rate: 0.0951845051299588, + }, + id: 2, + latestValidationMetric: { + endTime: '2022-08-05T05:56:21.150552Z', + metrics: { accuracy: 0.1809730976819992, val_loss: 2.1605682373046875 }, + totalBatches: 58, + }, + logRetentionDays: 12, + startTime: '2022-08-05T05:55:55.152888Z', + state: 'COMPLETED' as const, + totalBatchesProcessed: 58, + totalCheckpointSize: 58, +}; + +const mockTrial3: TrialDetails = { + autoRestarts: 0, + bestAvailableCheckpoint: { + endTime: '2022-08-05T05:56:41.515152Z', + resources: { + 'code/': 0, + 'code/adaptive.yaml': 418, + 'code/const.yaml': 349, + 'code/data.py': 3254, + 'code/mnist.py': 2996, + 'code/model_def.py': 1445, + 'code/README.md': 1492, + 'code/startup-hook.sh': 59, + 'load_data.json': 2665, + 'state_dict.pth': 680105, + 'workload_sequencer.pkl': 89, + }, + state: 'COMPLETED' as const, + totalBatches: 58, + uuid: 'b3d4ed7e-625c-4083-9e6c-ffba4ac03729', + }, + bestValidationMetric: { + endTime: '2022-08-05T05:56:42.958782Z', + metrics: { accuracy: 0.3433544337749481, val_loss: 1.7270305156707764 }, + totalBatches: 58, + }, + endTime: '2022-08-05T05:56:49.345991Z', + experimentId: 1249, + hyperparameters: { + global_batch_size: 64, + hidden_size: 64, + learning_rate: 0.06607116139078467, + }, + id: 3567, + latestValidationMetric: { + endTime: '2022-08-05T05:56:42.958782Z', + metrics: { accuracy: 0.3433544337749481, val_loss: 1.7270305156707764 }, + totalBatches: 58, + }, + logRetentionDays: -1, + startTime: '2022-08-05T05:56:16.181755Z', + state: 'COMPLETED' as const, + totalBatchesProcessed: 58, + totalCheckpointSize: 58, +}; + +describe('Trial Info Box', () => { + describe('should show log retention days box', () => { + it('should show Log Retention box with "-" for days', async () => { + setup(mockTrial1, mockExperiment); + await screen.findByText('Log Retention Days'); + await screen.findByText('-'); + }); + + it('should show Log Retention box with given number of days', async () => { + setup(mockTrial2, mockExperiment); + await screen.findByText('Log Retention Days'); + await screen.findByText(`${mockTrial2.logRetentionDays} days`); + }); + + it('should show Log Retention box with "Forever" for days', async () => { + setup(mockTrial3, mockExperiment); + await screen.findByText('Log Retention Days'); + await screen.findByText('Forever'); + }); + }); +}); diff --git a/webui/react/src/pages/TrialDetails/TrialInfoBox.tsx b/webui/react/src/pages/TrialDetails/TrialInfoBox.tsx index 1f993e0b2fd..5f7a2191031 100644 --- a/webui/react/src/pages/TrialDetails/TrialInfoBox.tsx +++ b/webui/react/src/pages/TrialDetails/TrialInfoBox.tsx @@ -39,7 +39,6 @@ const TrialInfoBox: React.FC = ({ trial, experiment }: Props) => { }, [trial?.totalCheckpointSize]); const logRetentionDays = useMemo(() => { - //const days = trial?.logRetentionDays; switch (trial?.logRetentionDays) { case undefined: return '-'; @@ -72,7 +71,11 @@ const TrialInfoBox: React.FC = ({ trial, experiment }: Props) => { {checkpointModalComponents} )} - {{logRetentionDays}} + { + + {logRetentionDays} + + } );