Skip to content

Commit 8392660

Browse files
authored
Enable Fetching of Logs from Timekeeper (#99)
* Initial refactoring * Adding subscription for Cars * Trigger the state function if it has not run the last minute * Add API calls into main API file for cars * Track if car is logging capable * Button dropdown in devices list * Allow filter on racer * Column fixes * Clean car option - with or without ROS logs * Make notifications time out * Embed fetching of logs in time-keeper * Fix fetch logs button
1 parent a941728 commit 8392660

File tree

7 files changed

+389
-235
lines changed

7 files changed

+389
-235
lines changed

website/public/locales/en/translation.json

+1
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,7 @@
653653
"end-session.warning-message": "Discarding the race will delete the race without saving it!",
654654
"end-session.page-header": "Timekeeper: Submit race",
655655
"end-session.page-description": "Check lap information and racer details before submitting a race to the leaderboard.",
656+
"end-session.fetch-logs": "Fetch logs",
656657
"fastest-lap": "Fastest lap",
657658
"lap-table.valid-header": "Valid",
658659
"lap-table.valid": "Yes",

website/src/pages/timekeeper/pages/raceFinishPage.jsx

+38-2
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@ import {
66
Header,
77
Modal,
88
SpaceBetween,
9+
ToggleButton,
910
} from '@cloudscape-design/components';
1011
import React, { useEffect, useState } from 'react';
1112
import { useTranslation } from 'react-i18next';
1213
import { RaceTypeEnum } from '../../../admin/events/support-functions/raceConfig';
1314
import { SimpleHelpPanelLayout } from '../../../components/help-panels/simple-help-panel';
1415
import { PageLayout } from '../../../components/pageLayout';
16+
import { useCarCmdApi } from '../../../hooks/useCarsApi';
1517
import useMutation from '../../../hooks/useMutation';
1618
import { useStore } from '../../../store/store';
1719
import { FastestAverageLapTable } from '../components/fastesAverageLapTable';
@@ -26,12 +28,16 @@ export const RaceFinishPage = ({
2628
raceConfig,
2729
onAction,
2830
onNext,
31+
startTime,
32+
fetchLogsEnable,
2933
}) => {
3034
const { t } = useTranslation(['translation', 'help-admin-timekeeper-race-finish']);
35+
const { carFetchLogs } = useCarCmdApi();
3136
const [buttonsIsDisabled, SetButtonsIsDisabled] = useState(false);
3237
const [sendMutation, loading, errorMessage, data] = useMutation();
3338
const [warningModalVisible, setWarningModalVisible] = useState(false);
34-
const [, dispatch] = useStore();
39+
const [state, dispatch] = useStore();
40+
const [fetchLogs, setFetchLogs] = React.useState(fetchLogsEnable);
3541
const messageDisplayTime = 4000;
3642
const notificationId = '';
3743

@@ -44,7 +50,7 @@ export const RaceFinishPage = ({
4450
onNext();
4551
}, messageDisplayTime);
4652
}
47-
}, [errorMessage, loading]);
53+
}, [errorMessage, loading, data, dispatch, notificationId, onNext]);
4854

4955
const submitRaceHandler = async () => {
5056
SetButtonsIsDisabled(true);
@@ -62,6 +68,27 @@ export const RaceFinishPage = ({
6268
raceStatus: 'RACE_SUBMITTED',
6369
});
6470
sendMutation('addRace', { ...raceInfo });
71+
72+
if (fetchLogs) {
73+
const uniqueCars = new Set();
74+
raceInfo.laps.forEach((lap) => {
75+
const car = state.cars.cars.find((car) => {
76+
return car.ComputerName === lap.carName && car.LoggingCapable;
77+
});
78+
if (car) {
79+
uniqueCars.add(car);
80+
}
81+
});
82+
83+
console.debug(Array.from(uniqueCars));
84+
85+
carFetchLogs(
86+
uniqueCars,
87+
{ eventId: raceInfo.eventId, eventName: raceConfig.eventName },
88+
new Date(startTime.getTime()).toISOString(),
89+
raceInfo.username
90+
);
91+
}
6592
};
6693

6794
const discardRaceHandler = () => {
@@ -137,6 +164,15 @@ export const RaceFinishPage = ({
137164
const actionButtons = (
138165
<Box float="right">
139166
<SpaceBetween direction="horizontal" size="xs">
167+
<ToggleButton
168+
onChange={({ detail }) => setFetchLogs(detail.pressed)}
169+
pressed={fetchLogs}
170+
disabled={!fetchLogsEnable}
171+
iconName="upload"
172+
pressedIconName="upload"
173+
>
174+
{t('timekeeper.end-session.fetch-logs')}
175+
</ToggleButton>
140176
<Button
141177
variant="link"
142178
disabled={buttonsIsDisabled}

website/src/pages/timekeeper/pages/raceFinishPageLite.jsx

+14-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
Header,
77
Modal,
88
SpaceBetween,
9+
Toggle,
910
} from '@cloudscape-design/components';
1011
import React, { useState } from 'react';
1112
import { useTranslation } from 'react-i18next';
@@ -20,12 +21,13 @@ export const RaceFinishPage = ({
2021
fastestAverageLap = [],
2122
raceConfig,
2223
onAction,
23-
onNext,
24-
submitRaceHandler,
25-
discardRaceHandler
24+
discardRaceHandler,
25+
fetchLogsEnable,
26+
fetchLogs,
27+
setFetchLogs,
2628
}) => {
2729
const { t } = useTranslation(['translation', 'help-admin-timekeeper-race-finish']);
28-
const [buttonsIsDisabled, SetButtonsIsDisabled] = useState(false);
30+
const [buttonsIsDisabled] = useState(false);
2931
const [warningModalVisible, setWarningModalVisible] = useState(false);
3032

3133
const raceInfoPanel = (
@@ -47,6 +49,14 @@ export const RaceFinishPage = ({
4749
<Header variant="h3">{t('timekeeper.end-session.raced-by-proxy')}</Header>
4850
{raceInfo.racedByProxy ? t('common.yes') : t('common.no')}
4951
</Box>
52+
<Box>
53+
<Header variant="h3">{t('timekeeper.end-session.fetch-logs')}</Header>
54+
<Toggle
55+
onChange={({ detail }) => setFetchLogs(detail.checked)}
56+
checked={fetchLogs}
57+
disabled={!fetchLogsEnable}
58+
/>
59+
</Box>
5060
</SpaceBetween>
5161
</Container>
5262
);

website/src/pages/timekeeper/pages/racePage.jsx

+11-6
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
Header,
88
Modal,
99
Select,
10-
SpaceBetween
10+
SpaceBetween,
1111
} from '@cloudscape-design/components';
1212
import { useMachine } from '@xstate/react';
1313
import React, { useEffect, useRef, useState } from 'react';
@@ -37,6 +37,7 @@ import styles from './racePage.module.css';
3737
export const RacePage = ({
3838
raceInfo,
3939
setRaceInfo,
40+
setStartTime,
4041
fastestLap,
4142
fastestAverageLap,
4243
raceConfig,
@@ -59,7 +60,7 @@ export const RacePage = ({
5960
const [btnUndoFalseFinish, setBtnUndoFalseFinish] = useState(true);
6061
const [btnEndRace, setBtnEndRace] = useState(false);
6162
const [btnStartRace, setBtnStartRace] = useState(false);
62-
const [currentCar, setCurrentCar] = useState(defaultCar)
63+
const [currentCar, setCurrentCar] = useState(defaultCar);
6364

6465
const [
6566
carResetCounter,
@@ -91,6 +92,7 @@ export const RacePage = ({
9192
setBtnStartRace(true);
9293
},
9394
startTimer: () => {
95+
setStartTime(new Date());
9496
setStartButtonText(t('timekeeper.pause-race'));
9597
startTimers();
9698
// Buttons
@@ -317,12 +319,15 @@ export const RacePage = ({
317319
<span>
318320
<Header variant="h5">{t('timekeeper.current-car')}:</Header>
319321
<Select
320-
selectedOption={{ label: currentCar.ComputerName, value: currentCar.Computername }}
322+
selectedOption={{
323+
label: currentCar.ComputerName,
324+
value: currentCar.Computername,
325+
}}
321326
onChange={({ detail }) => {
322-
setCurrentCar(detail.selectedOption.value)
327+
setCurrentCar(detail.selectedOption.value);
323328
}}
324-
options={cars.map(car => {
325-
return { label: car['ComputerName'], value: car }
329+
options={cars.map((car) => {
330+
return { label: car['ComputerName'], value: car };
326331
})}
327332
/>
328333
</span>

website/src/pages/timekeeper/pages/racePageLite.jsx

+10-5
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export const RacePage = ({
3939
raceConfig,
4040
onNext,
4141
selectedCar,
42+
setStartTime,
4243
}) => {
4344
const { t } = useTranslation(['translation', 'help-admin-timekeeper-race-page']);
4445
const [state] = useStore();
@@ -57,7 +58,7 @@ export const RacePage = ({
5758
const [btnUndoFalseFinish, setBtnUndoFalseFinish] = useState(true);
5859
const [btnEndRace, setBtnEndRace] = useState(false);
5960
const [btnStartRace, setBtnStartRace] = useState(false);
60-
const [currentCar, setCurrentCar] = useState(selectedCar || defaultCar)
61+
const [currentCar, setCurrentCar] = useState(selectedCar || defaultCar);
6162

6263
const [
6364
carResetCounter,
@@ -90,6 +91,7 @@ export const RacePage = ({
9091
},
9192
startTimer: () => {
9293
setStartButtonText(t('timekeeper.pause-race'));
94+
setStartTime(new Date());
9395
startTimers();
9496
// Buttons
9597
toggleBtnState(false);
@@ -302,12 +304,15 @@ export const RacePage = ({
302304
<span>
303305
<Header variant="h5">{t('timekeeper.current-car')}:</Header>
304306
<Select
305-
selectedOption={{ label: currentCar.ComputerName, value: currentCar.Computername }}
307+
selectedOption={{
308+
label: currentCar.ComputerName,
309+
value: currentCar.Computername,
310+
}}
306311
onChange={({ detail }) => {
307-
setCurrentCar(detail.selectedOption.value)
312+
setCurrentCar(detail.selectedOption.value);
308313
}}
309-
options={cars.map(car => {
310-
return { label: car['ComputerName'], value: car }
314+
options={cars.map((car) => {
315+
return { label: car['ComputerName'], value: car };
311316
})}
312317
/>
313318
</span>

website/src/pages/timekeeper/timeKeeper.jsx

+31-7
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,16 @@ export const Timekeeper = () => {
1515
const [activeStepIndex, setActiveStepIndex] = useLocalStorage('DREM-timekeeper-state', 0);
1616
const [raceConfig, setRaceConfig] = useLocalStorage('DREM-timekeeper-race-config', {});
1717
const [race, setRace] = useLocalStorage('DREM-timekeeper-current-race', defaultRace);
18-
const [fastestLap, SetFastestLap] = useState([]);
18+
const [fetchLogsEnable, setFetchLogsEnable] = useState(false);
19+
const [fastestLap, setFastestLap] = useState([]);
1920
const [fastestAverageLap, setFastestAverageLap] = useState([]);
21+
const [startTime, setStartTime] = useState(() => {
22+
new Date();
23+
});
2024
const selectedEvent = useSelectedEventContext();
2125
const selectedTrack = useSelectedTrackContext();
2226

23-
const [, dispatch] = useStore();
27+
const [state, dispatch] = useStore();
2428
// change event info and race config when a user select another event
2529
useEffect(() => {
2630
if (selectedEvent.eventId !== race.eventId) {
@@ -31,7 +35,8 @@ export const Timekeeper = () => {
3135
const modifiedRace = { ...race, eventId: selectedEvent.eventId };
3236
setRace(modifiedRace);
3337
}
34-
}, [selectedEvent, selectedTrack, race, setRace, setRaceConfig]);
38+
// eslint-disable-next-line react-hooks/exhaustive-deps
39+
}, [selectedEvent, selectedTrack]);
3540

3641
// Reset the timekeeper when navigating away from the timekeeper
3742
useEffect(() => {
@@ -40,6 +45,7 @@ export const Timekeeper = () => {
4045
setActiveStepIndex(0);
4146
setRace(defaultRace);
4247
};
48+
// eslint-disable-next-line react-hooks/exhaustive-deps
4349
}, []);
4450

4551
useEffect(() => {
@@ -65,12 +71,26 @@ export const Timekeeper = () => {
6571
const obj = validLaps.find((o) => {
6672
return o.time === res;
6773
});
68-
SetFastestLap([obj]);
74+
setFastestLap([obj]);
75+
// Find if any car is able to log
76+
if (!fetchLogsEnable) {
77+
validLaps.some((lap) => {
78+
const car = state.cars.cars.find((car) => {
79+
return car.ComputerName === lap.carName && car.LoggingCapable;
80+
});
81+
if (car) {
82+
setFetchLogsEnable(true);
83+
return true;
84+
} else {
85+
return false;
86+
}
87+
});
88+
}
6989
} else {
70-
SetFastestLap([]);
90+
setFastestLap([]);
7191
}
7292
} else {
73-
SetFastestLap([]);
93+
setFastestLap([]);
7494
}
7595

7696
race.averageLaps = getAverageWindows(race.laps, raceConfig.averageLapsWindow);
@@ -82,6 +102,7 @@ export const Timekeeper = () => {
82102
} else {
83103
setFastestAverageLap([]);
84104
}
105+
// eslint-disable-next-line react-hooks/exhaustive-deps
85106
}, [race.laps]);
86107

87108
// handlers functions
@@ -115,7 +136,7 @@ export const Timekeeper = () => {
115136
const resetRacehandler = () => {
116137
setRace(defaultRace);
117138
setRaceConfig({});
118-
SetFastestLap([]);
139+
setFastestLap([]);
119140
setFastestAverageLap([]);
120141

121142
setActiveStepIndex(0);
@@ -135,6 +156,7 @@ export const Timekeeper = () => {
135156
fastestLap={fastestLap}
136157
fastestAverageLap={fastestAverageLap}
137158
raceConfig={raceConfig}
159+
setStartTime={setStartTime}
138160
onNext={raceIsDoneHandler}
139161
/>
140162
);
@@ -149,6 +171,8 @@ export const Timekeeper = () => {
149171
raceConfig={raceConfig}
150172
onAction={actionHandler}
151173
onNext={resetRacehandler}
174+
startTime={startTime}
175+
fetchLogsEnable={fetchLogsEnable}
152176
/>
153177
);
154178
break;

0 commit comments

Comments
 (0)