-
Notifications
You must be signed in to change notification settings - Fork 0
ERA-11239: track styles: patrol tracks #1244
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…SubjectTrackLegend and PatrolTrackLegend
@@ -369,12 +369,6 @@ const Map = ({ | |||
); | |||
}, [dispatch]); | |||
|
|||
const onPatrolTrackLegendClose = useCallback(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This dispatch is now handled directly by PatrolTrackLegend
.
@@ -1,110 +1,65 @@ | |||
import React, { memo, useCallback } from 'react'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
patrolData={patrolData} | ||
/>} | ||
/> : null; | ||
const patrolTrackState = useSelector((state) => state.view.patrolTrackState); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extremely simple component, we just need to select the patrolTrackState
and patrolsWithTrackData
values from Redux to calculate the description and the items array (patrols being tracked).
@@ -1,125 +1,65 @@ | |||
import React, { useCallback, useEffect, useMemo, useState } from 'react'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const dispatch = useDispatch(); | ||
const { t } = useTranslation('tracks', { keyPrefix: 'subjectTrackLegend' }); | ||
|
||
const timeOfDayTrackingEnabled = useFeatureFlag(FEATURE_FLAG_LABELS.TIME_OF_DAY_TRACKING); | ||
|
||
const isTimeOfDayColoringActive = useSelector((state) => state.view.trackSettings.isTimeOfDayColoringActive); | ||
const subjectStore = useSelector((state) => state.data.subjectStore); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The implementation is very similar to the PatrolTrackLegend
. Here we select subjectStore
, subjectTrackState
, subjectTracksTrimmedToTrackTimeEnvelope
and trackTimeEnvelope
to build the description and items (tracked subjects).
@@ -0,0 +1,57 @@ | |||
import React from 'react'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not really a new component, it's just the abstraction of what used to be SubjectTrackList
so now it's agnostic of the items that are listed. They could either be subjects or patrols.
@@ -0,0 +1,204 @@ | |||
import React, { useCallback, useEffect, useState } from 'react'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the new abstraction that renders track legends. It needs to be implemented and provided with the items, description, callbacks and the flags to render or not certain buttons. SubjectTrackLegend
and PatrolTrackLegend
use this component to render their legends, they provide subjects and patrols as items respectevely.
The code is very similar to what used to be SubjectTrackLegend
, but I removed all the logic related to subjects so now the "items" are injected as dependencies (props) and the component stays agnostic.
results: [], | ||
}; | ||
|
||
const patrolsReducer = (state = INITIAL_PATROLS_STATE, action) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This reducer wasn't needed anymore. We can rely entirely on the patrolStore
. And honestly, it was old nasty code, we were basically storing an Axios response object in our store and barely using it (nothing we couldn't achieve using the patrolStore
directly).
@@ -1,155 +1,143 @@ | |||
import uniq from 'lodash/uniq'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Total refactor and optimization of our patrol selectors.
@@ -228,15 +228,6 @@ export const actualEndTimeForPatrol = (patrol) => { | |||
: null; | |||
}; | |||
|
|||
export const getLeaderForPatrol = (patrol, subjectStore) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused code.
@@ -64,68 +62,45 @@ export const selectHeatmapSubjectTracksTrimmedToTrackTimeEnvelope = createSelect | |||
) | |||
); | |||
|
|||
const selectPatrolTracksLeaderIds = createSelector( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This selector is no longer needed since the logic to show / hide the subjects tracks when a patrol is being tracked and the subject is the leader of the patrol was a little bit cleaned (lots could be done to improve this flow still, it's buggy, but this is a start).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just left a couple of minor comments, the only reason I'm not approving is that I don't see test coverage for TrackLegend
implementation in PatrolTrackLegend
and SubjectTrackLegend
is there a reason for that?
} else { | ||
// If there is a menu expanded, we first collapse it and then expand the new one. | ||
onCollapseMenu(); | ||
setTimeout(() => setExpandedMenu(menu), BOOTSTRAP_DEFAULTS.COLLAPSE_TRANSITION_TIME); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be worth it to clear this timeout on unmount?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, it's impossible to unmount the component without first finishing the timeout. If you go to the last few lines of this component, it is wrapped by DelayedUnmount
by the same amount of time of this timeout: BOOTSTRAP_DEFAULTS.COLLAPSE_TRANSITION_TIME
. This means that even if the component is about to be unmounted, it will at least wait for this time to elapse, making the cleaning task unnecessary 😄
src/TrackLegend/index.js
Outdated
onExpandMenu(MENUS.TIME_OF_DAY_SETTINGS); | ||
}; | ||
|
||
const onDectivateTimeOfDayColoring = useCallback(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
little type in here, it should be onDeactivateTimeOfDayColoring
src/TrackLegend/index.js
Outdated
dispatch(setIsTimeOfDayColoringActive(false)); | ||
|
||
// When deactivating the time of day coloring, we collapse its menu if it was expanded. | ||
if (expandedMenu === MENUS.TIME_OF_DAY_SETTINGS) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Several ifs statements are repeating the same comparisons of the const at the beginning of the component isTimeOfDaySettingsExpanded
isTrackSettingsExpanded
isTracksListExpanded
Why are we using those here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duh, didn't think of it 🤓 Updating them!
src/SubjectTrackLegend/index.js
Outdated
}; | ||
// Build the items array with the description, icon, id and title of each tracked subject. | ||
const items = useMemo(() => subjectTracksTrimmedToTrackTimeEnvelope.map((subjectTracks) => { | ||
const id = subjectTracks.track.features[0].properties.id; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here seems like a good place to use:
const [firstFeature] = subjectTracks.track.features;
instead of repeating subjectTracks.track.features[0]
just to make the code more readable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, is it possible to subjectTracks.track.features[0]
to does not exist? If yes, We should add some default values or validations
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the first comment: agreed, I'll update it.
On the second one: it shouldn't, that data comes from a selector that is already running validations and filtering just the valid data. If we ever hit that issue, I wouldn't say the solution is adding a check here but fixing the selector.
@gaboDev Nice observation! Actually I forgot to add a comment regarding this myself. I decided not to add tests to those. I tried, but the necessary mocked data in the store for the selectors to build the right scenarios is so complex and big, that the tests would be extremely fragile and hard to comprehend. I know this is not orthodox, we should try to add tests anyway, but for real, the amount of data was insane, and in every scenario it changes considerably. In my opinion, components shouldn't rely on these super complex data selection. Our selectors are doing too much. I would say that the right fix is to update our reducers to actually do some pre-processing before storing the data and avoid having to do all that processing in our selectors. That would optimize time and memory, while also simplifying the data mocking in the tests. But that was definitely out of the scope. This PR was big enough. |
What does this PR do?
Re-do the
PatrolTrackLegend
component so it has the look and feel like the newSubjectTrackLegend
.How does it look
Desktop:

Mobile:

Relevant link(s)
Where / how to start reviewing (optional)
1- Start by reviewing the new component
src/TrackLegend/index.js
. It's code is around 80% of whatSubjectTrackLegend
used to be. I just removed the subject internal details so new abstraction is not tied to subjects, and we can also use it to render patrol tracks.2- After understanding the code of
TrackLegend
, reviewingPatrolTrackLegend
andSubjectTrackLegend
will be trivial.3- The "last" important thing to review is the refactoring and optimization of patrols related selectors in
src/selectors/patrols.js
.4- The rest of the files are translations and selector naming updates.