-
Notifications
You must be signed in to change notification settings - Fork 929
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
Add user profile heatmap visualization for contributions #5402
base: master
Are you sure you want to change the base?
Conversation
b27b7a6
to
b134a0a
Compare
Oh, I forgot about this. |
It is a very minor nitpick, but is it possible to dynamically determine what's the first weekday based on the user's locale and adjust the heatmap accordingly? Intl.Locale.prototype.getWeekInfo() could be used. It isn't currently available in Firefox but all other browsers have it. P.S. Added bug 1937867 to Firefox's bug tracker. |
What's the source(s) of all the javascript in Also, how does the inclusion of popper interact with the popper already included? We end up with |
OK, I found the answer for the cal-heatmap part of the code, which is available as an npm module. In which case, using package.json will allow us to upgrade to new versions automatically, and would be the preferred option. |
UX thoughts:
Code comments:
|
I've tested the performance of the underlying query and using the user with the most changesets in the last year (just over 50 thousand) it took a fraction over one second which is probably acceptable. That result (which was a full 365 days of data) serialised to just under 10Kb which is a fair chunk to be caching but hopefully most entries will be smaller than that. |
Thank you for the suggestion. I’ll refactor accordingly to ensure alignment with the preferred color scheme setting.
I tried dynamically adjusting the start and end weekdays using ghDay as the subdomain, but it rounds to the first and last weeks of the month, making implementation tricky. Accommodating this would require significant effort, which may not be worth it for such a minor adjustment.
To be honest I wasn’t too familiar with how our assets pipeline works,so I just added the Thank you for pointing out the existing |
0a8fc14
to
af02b6a
Compare
I've updated the code to account for the "Preferred Website Color Scheme." Theme settings should now be working correctly. UX Thoughts:
Code Comments:
Also a big thank you to @tomhughes for testing the performance here. |
How is it included in |
It's not going to work correctly because our Auto option follows Looks like cal-heatmap doesn't have a proper auto scheme "as not all websites support dark/light mode". You'd have to then setup a listener like this but without using Leaflet of course and redraw the heatmap. Same is true for #5426 by the way. |
Any other change to the theme of the page without reloading will break most of the CSS theming anyway since the stylesheets were split in #5362 by the way. It would be great to have a global leaflet-independent watcher where clients can add themselves to a callback list. |
You don't need to change the theme of the page, neither here, nor in #5426. Or do you say that you haven't tried switching
Leaflet code is just a wrapper for |
I did that for testing, but since listening increased the complexity unnecessarily, I left that for a second pass. But suppose the site needs a theme watcher anyway because the cal-heatmap doesn't want to let CSS do the color mixing theme-agnostically. In that case, instead of having two listeners, a common solution that includes MutationObservers outside of jQuery would be the one with the least overhead. |
Why MutationObservers? |
The MutationObserver thought came from my tinkering with the site locally wanting to reduce the reloads, forgetting that a toggle if added would already have onchange events.
Yeah, I kinda missed that... Still, having a similar style on such similar functions and having them moved to some unified location would be a nice thing to have, currently, they could be much more different. But that's more of a refactor thing if both are merged. |
940feb9
to
8028378
Compare
I've moved the import to
Added the logic to handle the auto prefered-color-changes. Should be resolved now as well.
I'm working on resolving this CSP violations. Right now I'm trying to generate nonce for the .js file and use that to validate and transpass the CSP violation. I'm not sure if it is the right approach for this since I never had experience dealing with similar stuff before. If there is a more elegant and compact solution, please feel free to point it out. Thank you. |
For the wrong one though. Another copy of the html's bs-theme attribute isn't necessarily helpful, and the media query is still not being listened to. |
app/assets/javascripts/heatmap.js
Outdated
function getThemeFromColorScheme(colorScheme) { | ||
if (colorScheme === "auto") { | ||
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"; | ||
} | ||
return colorScheme; // Return "light" or "dark" directly if specified | ||
} |
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.
I'm sorry, but I don't see where a re-draw would be triggered.
|
I need to test this once again and get back to you. I guess you are right since there is some strange behaviour right now that I'm currently looking into. |
@hlfan This deprecates |
8028378
to
81f13d7
Compare
81f13d7
to
904951e
Compare
Nice ....... but, sorry to be a spoil sport here, this changes the information available on the user page significantly, the likely solution would be to make it available only to logged in users. Both the LWG and EWG should be informed and https://wiki.openstreetmap.org/wiki/GDPR/Affected_Services#User_page_(done) updated to reflect the additional feature. PS: I'm not quite sure why the user page item is marked as done, when it obviously isn't, but that is OT. |
@simonpoole This is not something you should worry about because it will take one |
//= require d3 | ||
//= require cal-heatmap | ||
//= require calendar-label | ||
//= require popper | ||
//= require tooltip |
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.
You don't need to put these scripts here because you remove them later.
Is it the intended effect that nothing gets rendered in case the user made no edits in the span of one year? |
@@ -53,6 +53,23 @@ def show | |||
if @user && | |||
(@user.visible? || current_user&.administrator?) | |||
@title = @user.display_name | |||
|
|||
one_year_ago = 1.year.ago |
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.
Is this done to freeze the starting point because we're not sure when the block below runs? Then why is the same not done with the ending point? And shouldn't it be truncated to a day?
scale: { | ||
color: { | ||
type: "threshold", | ||
range: currentTheme === "dark" ? rangeColors : rangeColors.reverse(), |
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.
rangeColors.reverse()
reverses the array in place, probably not what you want.
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.
range: currentTheme === "dark" ? rangeColors : rangeColors.reverse(), | |
range: currentTheme === "dark" ? rangeColors : Array.from(rangeColors).reverse(), |
would solve that.
const jsDate = new Date(date); | ||
const translations = I18n.translations[locale] || I18n.translations.en; | ||
const dateTranslations = translations && translations.date; | ||
const monthNames = dateTranslations && dateTranslations.month_names; | ||
|
||
const months = monthNames || []; | ||
const monthName = months[jsDate.getMonth() + 1] || `${jsDate.getMonth + 1}.`; | ||
const day = jsDate.getDate(); | ||
const year = jsDate.getFullYear(); | ||
|
||
const localizedDate = `${day}. ${monthName} ${year}.`; |
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 jsDate = new Date(date); | |
const translations = I18n.translations[locale] || I18n.translations.en; | |
const dateTranslations = translations && translations.date; | |
const monthNames = dateTranslations && dateTranslations.month_names; | |
const months = monthNames || []; | |
const monthName = months[jsDate.getMonth() + 1] || `${jsDate.getMonth + 1}.`; | |
const day = jsDate.getDate(); | |
const year = jsDate.getFullYear(); | |
const localizedDate = `${day}. ${monthName} ${year}.`; | |
const localizedDate = I18n.l("date.formats.long", date); |
|
||
const heatmapData = heatmapElement.dataset.heatmap ? JSON.parse(heatmapElement.dataset.heatmap) : []; | ||
const colorScheme = heatmapElement.dataset.siteColorScheme || "auto"; | ||
const locale = $("head").data().locale; |
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.
If application.js
is initialized, the locale is available in I18n.locale
. But looks like it's not necessarily initialized...
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.
I think the entire heatmap can be delayed by putting it in turbo frame or maybe some collapsible section (maybe for performance reasons). You need I18n
initialized before anyway, I don't know how you're going to translate dates correctly otherwise. Although popup dates seem to work even if I18n
is not initialized before the heatmap because they are constructed later.
Oh, I'm not concerned at all. I was just pointing this out for good form, aka I saw something that I know is wrong, and I'm giving the people here a fighting chance to do the right thing. |
Description
This PR addresses #5373 by adding a heatmap visualization on user profile pages to display daily contribution activity over the past year.
Key changes include:
users/show.html.erb
).heatmap.js
) using CalHeatmap to render the heatmap dynamically based on contribution data.config/locales/en.yml
) to include tooltips and month/weekday labels for the heatmap.users_controller_test.rb
to validate heatmap data handling.Screenshots:
How has this been tested?
Let me know if you need further tweaks or enhancements!