-
Notifications
You must be signed in to change notification settings - Fork 5.9k
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
[Feat][Dashboard] Add global UTC timezone button in navbar with local storage #48510
Conversation
… storage Signed-off-by: Dongjun Na <kmu5544616@gmail.com>
0431e38
to
33d4f80
Compare
Signed-off-by: Dongjun Na <kmu5544616@gmail.com>
@alanwguo Could you take a look at this when you have a moment? |
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.
Thanks!
Can we add a description or tooltip near the timezone selector that explains that timezone of logs may not respect this value?
window.location.reload(); | ||
}; | ||
|
||
const timezones = [ |
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.
where did this list come from? Does this cover most common time zones?
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.
Signed-off-by: Dongjun Na <kmu5544616@gmail.com>
@alanwguo I added a tooltip with the message "The timezone of logs may not match this selection." Thanks for the review! |
@scottsun94, plz review as well. A couple of suggestions. When the dropdown is collapsed, can we make the contents of the dropdown slimmer. Like "GMT-8" instead of the full name. Second. Can we detect the timezone used by the head node and set that as the default for the UI? I think in many cases, the user's time zone won't match the system's time zone which is often UTC for cloud-based instances. By setting the default to the head node, at least the logs and the UI will match timezones. |
@alanwguo Thanks for the review, The first suggestion sounds doable. For the second, would it work to set the default timezone to the timezone where the dashboard server (React server) is running? Also, is there a separate API to fetch the UTC timezone of the head node? |
Here is a great article about the timezone UX: https://www.linkedin.com/pulse/designers-guide-time-zone-selection-ux-vitaly-friedman/. Grafana seems a great example to learn from:
|
@scottsun94 Thank you for sharing the great article. I will refer to it and incorporate the suggestions accordingly. |
There is no API for this for now, but you can add a new API to |
Thank you for the guidance! Here's how I plan to proceed with the additional changes:
Please let me know if you have any additional feedback. |
@nadongjun after the UI change is done, can you share a short walkthrough video or screenshots? Would love to take another look. |
@scottsun94 Sure, I am currently working on the UI changes first. Once the updates are complete, I will share a video walkthrough and tag you. |
I've implemented the changes using the react-select library. Screen.Recording.2024-11-09.at.1.41.04.AM.mov |
@nadongjun have you tried implementing with https://mui.com/material-ui/react-autocomplete/ ? Then we can use the existing MUI library and don't have to take on a new dependency |
Screen.Recording.2024-11-09.at.10.09.23.AM.mov
@alanwguo Thank you for the suggestion to use Autocomplete from MUI. I've updated the implementation to use the existing MUI library, so no new dependencies are added. @scottsun94
Please let me know if you think any changes are needed. Thanks again for the helpful input! |
…ection Signed-off-by: Dongjun Na <kmu5544616@gmail.com>
Signed-off-by: Dongjun Na <kmu5544616@gmail.com>
I’ll address your comments and let you know once the changes are committed. Appreciate your help with the CSS issues. |
…aving button state directly to local storage Signed-off-by: Dongjun Na <kmu5544616@gmail.com>
…ndle timezone conversion Signed-off-by: Dongjun Na <kmu5544616@gmail.com>
Screen.Recording.2024-11-16.at.12.52.50.AM.movAs per your review, I have made changes to avoid using external libraries. The dashboard server now maintains a single list of timezone names corresponding to each offset and returns the appropriate timezone name for a given offset via the /timezone API. Additionally, instead of using useEffect, the data is now directly saved to localStorage, and the timezone name retrieved from the /timezone API is not stored in localStorage. For UI adjustments, the Dashboard Server Timezone will display Asia/Irkutsk, which is the representative timezone for +09:00 on the server side, as seen in the demo video. It might be better to hide the value for the system timezone in this case. Please feel free to share any additional feedback regarding the changes. |
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.
Thanks! This is looking close. Just some minor stylistic changes.
Please just address my comments, I'll work on any follow-up UI changes including the banner @scottsun94 suggested.
python/requirements.txt
Outdated
@@ -60,4 +60,4 @@ pandas>=1.3 | |||
pydantic!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.*,<3 # Serve users can use pydantic<2 | |||
py-spy>=0.2.0 | |||
memray; sys_platform != "win32" # memray is not supported on Windows | |||
pyOpenSSL | |||
pyOpenSSL |
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.
revert the changes to this file plz.
@@ -77,3 +83,910 @@ export const SearchSelect = ({ | |||
</TextField> | |||
); | |||
}; | |||
|
|||
export const SearchTimezone = ({ |
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.
Let's move this to a separate file SearchTimezone.tsx
/** | ||
* The name of the current server-side timezone. | ||
*/ | ||
serverTimeZone: string | undefined; | ||
|
||
serverTimeZoneLoaded: boolean | undefined; |
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.
let's combine these into a single variable.
serverTimeZone
will either be undefined if it's unloaded. null, if we couldn't fetch it, or the value from the server.
def get_gmt_offset(self): | ||
current_tz = datetime.now().astimezone().tzinfo | ||
offset = current_tz.utcoffset(None) | ||
hours, remainder = divmod(offset.total_seconds(), 3600) | ||
minutes = remainder // 60 | ||
sign = "+" if hours >= 0 else "-" | ||
return f"GMT{sign}{abs(int(hours)):02d}:{abs(int(minutes)):02d}" |
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.
let's move this and most of the implementation of get_timezone
into a separate file. SOmething like timezone_utils.py
|
||
@routes.get("/timezone") | ||
async def get_timezone(self, req) -> aiohttp.web.Response: | ||
timezones = [ |
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.
after moving this to a new file, let's up-level this to be a file-level const.
@routes.get("/timezone") | ||
async def get_timezone(self, req) -> aiohttp.web.Response: | ||
timezones = [ | ||
{"utc": "GMT-12:00", "value": "Etc/GMT+12"}, |
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.
instead of utc
the key should be offset
) | ||
|
||
if current_timezone: | ||
return aiohttp.web.Response(text=str(current_timezone)) |
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.
instead of returning raw text, let's return a simple json dictionary so we may add additional fields in the future.
Signed-off-by: Dongjun Na <kmu5544616@gmail.com>
Signed-off-by: Dongjun Na <kmu5544616@gmail.com>
…t, value) Signed-off-by: Dongjun Na <kmu5544616@gmail.com>
Signed-off-by: Dongjun Na <kmu5544616@gmail.com>
Thank you for your feedback. I’ve incorporated your suggestions.
Let me know if there’s anything else to improve! |
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.
a couple more comments for a bit cleaner code.
const [timezone, setTimezone] = useState<string>(""); | ||
|
||
useEffect(() => { | ||
if (serverTimeZoneLoaded) { |
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.
can we delete serverTimeZoneLoaded
now that serverTimeZone
has the null
and undefined
case?
@@ -26,6 +27,11 @@ type PrometheusHealthcheckRsp = { | |||
msg: string; | |||
}; | |||
|
|||
type TimezonekRsp = { |
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.
type TimezonekRsp = { | |
type TimezoneRsp = { |
offset?: string | null; | ||
value?: string | null; |
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.
do these have to be nullable or undefined? Seems like the entire TimeZoneInfo can be possibly undefined, but if we do get the TimezoneInfo, the fields inside should both have a value.
Signed-off-by: Dongjun Na <kmu5544616@gmail.com>
Thank you for your feedback. I've addressed the review comments and made the following changes:
|
Move current timezone logic into the global context since its used by multiple places Signed-off-by: Alan Guo <aguo@anyscale.com>
Okay I pushed a commit that updates the styling. I wasn't able to get a banner to show up in the Autocomplete options list but I think i covered the other style changes. I also refactored the code slightly to move the currentTimeZone logic into the GlobalContext since it is re-used in multiple places. I updated the default time for the Overview page for now-1h instead of now-30m. For some really weird reason, the timezone query param doesn't work when the its 30 minutes, but works with every other value? |
Could anyone merge this PR? |
… storage (ray-project#48510) Signed-off-by: Dongjun Na <kmu5544616@gmail.com> Signed-off-by: Connor Sanders <connor@elastiflow.com>
… storage (ray-project#48510) Signed-off-by: Dongjun Na <kmu5544616@gmail.com> Signed-off-by: hjiang <dentinyhao@gmail.com>
Why are these changes needed?
Changes Included
Timezone Selection Button: Added a button at the top of the UI that lets users choose their preferred timezone (UTC). This selection will update displayed dates accordingly in supported sections.
Persistent Settings: The selected timezone is saved to the browser’s local storage, ensuring that the setting remains consistent upon page reloads.
Supported Sections:
Three main areas were considered for timezone adjustments:
Scope: Given current limitations, only the Log Data section (Point 3 above) does not support timezone adjustments, while Grafana-Related Data and the Jobs, Nodes, Actors, and Workers sections are fully updated to reflect the timezone selection.
Result:
Related issue number
Closes #47762
Checks
git commit -s
) in this PR.scripts/format.sh
to lint the changes in this PR.method in Tune, I've added it in
doc/source/tune/api/
under thecorresponding
.rst
file.