Skip to content

BGDIINF_SB-2472 : better handling of empty profile#285

Merged
pakb merged 8 commits intodevelopfrom
feat_BGDIINF_SB-2472_empty_profile_handling
Nov 16, 2022
Merged

BGDIINF_SB-2472 : better handling of empty profile#285
pakb merged 8 commits intodevelopfrom
feat_BGDIINF_SB-2472_empty_profile_handling

Conversation

@pakb
Copy link
Contributor

@pakb pakb commented Nov 8, 2022

As we still need to be able to delete a profile, even if empty, I've left the info container and the trash button. Otherwise, if the whole popup was hidden, the user was not able to delete an empty profile anymore.

In E2E test : adding a profile mockup function as it is used in 2 different files, and harmonisation of profile mockup usage. Reactivation of tests that now works as intended.

Test link

@pakb pakb requested review from jedef and ltshb November 8, 2022 10:01
Comment on lines 257 to 261
// checking if profile has data, if not (outside CH) we hide the profile
this.profileHasData = data.length > 0
this.profileChart.create(data)
const areaChartPath = this.profileChart.group.select('.profile-area')
const glass = this.profileChart.glass
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we don't show the create why create the profile chart ?

@ltshb
Copy link
Contributor

ltshb commented Nov 8, 2022

When drawing a line outside of swiss, then dragging a point inside switzerland we have the following result
image

Copy link
Contributor

@jedef jedef left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you draw a line, the whole info container theoretically could the hidden, as the delete button is not in the profile in this case. But I don't now if it's too complex to make a distinction between measure and line here.
Also, when you select a measure drawn outside of switzerland, the whole info box is first shown before the graph part is hidden. But as you have to wait for the response from the backend to know if the profile is displayed or not, this probably can't be fixed easily.

cy.get('[data-cy="profile-popup-area"]').should('not.have.attr', 'd')
})
it('has a functioning delete button', () => {
// Delete is currently not implemented. Will be added in a later commit.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment should probably be deleted

}
return `${format(Math.round(value), 3)}m`
},
checkIfProfileDataPresent(data) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function seems to be called nowhere

pakb added 4 commits November 15, 2022 15:56
As we still need to be able to delete a profile, even if empty, I've left the info container and the trash button. Otherwise, if the whole popup was hidden, the user was not able to delete an empty profile anymore.

In E2E test : adding a profile mockup function as it is used in 2 different files, and harmonisation of profile mockup usage.
Reactivation of tests that now works as intended.
Removing unnecessary event, fix typo
Overhaul of the d3 chart generation made by the profile popup.
- Simplification of many aspects of this generation
- Regrouping of (mostly) all d3 related functions in a dedicated file
- Removal of artifact code from mf-geoadmin3, or simplification of it
- All business calculation related to profile are now made in a API class, as other API files are doing

There is still some UI glitches to fix with scrollbar appearing on the side on mobile, or sometimes when the profile is updated as empty.
This way, it's way easier to debug them, and change the app code without having to reload the whole test suite (but it requires a little bit of pre-loading for the first test)
@pakb pakb force-pushed the feat_BGDIINF_SB-2472_empty_profile_handling branch from 57adb7f to 8679670 Compare November 15, 2022 16:15
@pakb
Copy link
Contributor Author

pakb commented Nov 15, 2022

Here it comes, big profile rewrite in order to extract most d3 logic in a file, and move all "wiring" with vue in the component.
This should greatly enhance our reading of this part of the app, and our understanding of it.
Enjoy reviewing it 😉

@pakb pakb requested review from jedef and ltshb November 15, 2022 16:17
@pakb
Copy link
Contributor Author

pakb commented Nov 15, 2022

There is still some scrollbar issue appearing sometimes, I've decided that I've spent enough time on this for the time being, we can open a ticket to fix this later on if you guys find it is unsettling.

Comment on lines +108 to +133
get highestElevation() {
if (this.hasData) {
const highestPoint = this.points.reduce((previousPoint, currentPoint) => {
if (currentPoint.elevation > previousPoint.elevation) {
return currentPoint
}
return previousPoint
})
return highestPoint.elevation
}
return 0
}

/** @returns {Number} The lowest elevation in this profile */
get lowestElevation() {
if (this.hasData) {
const lowestPoint = this.points.reduce((previousPoint, currentPoint) => {
if (currentPoint.elevation < previousPoint.elevation) {
return currentPoint
}
return previousPoint
})
return lowestPoint.elevation
}
return 0
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get the difference between highestElevation and maxElevation ? Same for lowestElevation and minElevation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

more simplification can be made, I didn't see that I had two time the kind of same extraction of value

* @returns {number} Estimation of hiking time for this profile
*/
get hikingTime() {
if (!this.hasData) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above check that we have at least two points

return Math.round(
this.points
.map((currentPoint, index, points) => {
if (index < points.length - 2) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we have only two points, then we don't enter the if and the result will be 0 ! I think it should be if (index < points.length - 1) here or if (index <= points.length - 2)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be fixed if hasData is only true when there is two or more points

// no setter
}

export class GeoAdminProfile {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why calling this GeoAdminProfile ? It seems to me to be a general profile why not AltiProfile ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like naming things with only one word, like Profile as it is too generic. And I don't really like Alti too, because it doesn't mean anything in English... So I thought of this name as a "good enough" but am open to suggestions

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I totally agree with you Profile is a bad name as it is too general. To be honest I find AltiProfile a good choice as Alti is a shorthand for Altitude and it is an altitude profile. But here other ideas

  • ElevationProfile
  • GeoProfile

},
computed: {
profileHasData() {
return this.profileData && this.profileData.length > 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly, a valid Profile should have at least two point ? Why not either use the GeoadminProfile.hasData method here (would need to modify this method to check for > 1) or even better rename the hasData to isValid. This method could also be used above in the GeoadminProfile class .

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should be using .hasData here, good catch

)
lowerIndex = Math.min(lowerIndex, this.profileData.length - 1)
// As it is not perfectly regular (maybe as a result of trunking the decimals in the backend?) we still need to correct our first guess with these two while loops. */
while (distToSearch < this.profileData.points[lowerIndex].dist) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add guard here to avoid negative index due to bad data

while (lowerIndex > 0 && distToSearch < this.profileData.points[lowerIndex].dist)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's also some relic of mf-geoadmin3, I don't mind that we enhance this piece of code in the future, but right now it's really low on our priority list. So if you don't mind, we can write a ticket for post MVP task to have a look into optimizing / fixing this part of the code, but for now we can live with it

Copy link
Contributor

@ltshb ltshb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also had some exceptions while testing

index.33f0af09.js:93 Uncaught (in promise) TypeError: Cannot read properties of null (reading 'clientWidth')
    at p_t (index.33f0af09.js:93:63583)
    at Proxy.updateProfileChart (index.33f0af09.js:93:65865)
p_t @ index.33f0af09.js:93
updateProfileChart @ index.33f0af09.js:93
Promise.then (async)
vN @ index.33f0af09.js:24
onResize @ index.33f0af09.js:93

export default {
props: {
profile: {
type: GeoAdminProfile,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a Vue warning here because the profile is required but it can be null ! Either remove the required or allow for null value or when instanciating the FeatureProfile create an empty GeoadminProfile instead of null.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch, thanks

pakb added 2 commits November 16, 2022 10:52
Remove unused/doubled min/max elevation
Profile is considered having data if it contains at least 2 points (1 was enough before)
Adding unit test coverage for basic profile calculation (hiking time is excluded for now...)
Switching from old style for loops to filter/map/reduce equivalent in profile calculations
Adding a npm target to run unit test in watch mode, easier to debug this way
When the total distance of the profile exceeds 10km, the chart now switches back to display km as values on the X axis instead of flooding the user with big meter numbers
@pakb pakb requested a review from ltshb November 16, 2022 10:05
Copy link
Contributor

@ltshb ltshb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good, but I would change the name GeoadminProfile, see comment. Also a possible minor improvement in the unit test.
Overall very good job and clean code 💯

Comment on lines +6 to +9
new ProfilePoint(0, [0, 0], 100),
new ProfilePoint(50, [0, 50], 200),
new ProfilePoint(150, [0, 150], 90),
new ProfilePoint(200, [50, 150], 210),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To better test the maxElevation on line 31, I would suggest to change the elevation order here to put the highest in the middle of the array.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point, I've added the last point so that I could compute a descent/ascent better but didn't think about the maxElevation, I'll switch it with second place.

@pakb
Copy link
Contributor Author

pakb commented Nov 16, 2022

Let's settle on ElevationProfile, I'll also change some component's name to reflect this

pakb added 2 commits November 16, 2022 13:00
Rename also related components and some variable to reflect this change.
So that we thoroughly test that the max elevation is not necessarily the last point.
@pakb pakb merged commit 3539223 into develop Nov 16, 2022
@pakb pakb deleted the feat_BGDIINF_SB-2472_empty_profile_handling branch November 16, 2022 12:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants