From 8dc577eb2b854e71a66bb32ce562e05cc3ab1019 Mon Sep 17 00:00:00 2001 From: Yota Hamada Date: Sat, 9 Nov 2024 20:41:04 +0900 Subject: [PATCH] ui: Adjust timezone handling (#705) --- ui/src/App.tsx | 42 +++++++++---------- ui/src/components/molecules/DAGTable.tsx | 6 +-- .../molecules/DashboardTimechart.tsx | 15 +++---- ui/src/contexts/ConfigContext.tsx | 15 +++++++ ui/src/index.tsx | 3 +- ui/src/models/index.ts | 3 +- ui/src/pages/index.tsx | 4 +- 7 files changed, 50 insertions(+), 38 deletions(-) create mode 100644 ui/src/contexts/ConfigContext.tsx diff --git a/ui/src/App.tsx b/ui/src/App.tsx index 56084e69..e70afb45 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -9,14 +9,8 @@ import { SWRConfig } from 'swr'; import fetchJson from './lib/fetchJson'; import Search from './pages/search'; import { UserPreferencesProvider } from './contexts/UserPreference'; - -export type Config = { - apiURL: string; - title: string; - navbarColor: string; - tz: string; - version: string; -}; +import { Config, ConfigContext } from './contexts/ConfigContext'; +import moment from 'moment-timezone'; type Props = { config: Config; @@ -24,6 +18,8 @@ type Props = { function App({ config }: Props) { const [title, setTitle] = React.useState(''); + config.tz ||= moment.tz.guess(); + return ( - - - - - } /> - } /> - } /> - } /> - } /> - } /> - - - - + + + + + + } /> + } /> + } /> + } /> + } /> + } /> + + + + + ); diff --git a/ui/src/components/molecules/DAGTable.tsx b/ui/src/components/molecules/DAGTable.tsx index 4e76657f..041fd570 100644 --- a/ui/src/components/molecules/DAGTable.tsx +++ b/ui/src/components/molecules/DAGTable.tsx @@ -44,10 +44,10 @@ import { KeyboardArrowUp, } from '@mui/icons-material'; import LiveSwitch from './LiveSwitch'; -import moment from 'moment'; import 'moment-duration-format'; import Ticker from '../atoms/Ticker'; import VisuallyHidden from '../atoms/VisuallyHidden'; +import moment from 'moment-timezone'; type Props = { DAGs: DAGItem[]; @@ -251,9 +251,7 @@ const defaultColumns = [ }), columnHelper.accessor('Type', { id: 'Schedule', - header: getConfig().tz - ? `Schedule in ${getConfig().tz}` - : 'Schedule', + header: `Schedule in ${getConfig().tz || moment.tz.guess()}`, enableSorting: true, cell: (props) => { const data = props.row.original!; diff --git a/ui/src/components/molecules/DashboardTimechart.tsx b/ui/src/components/molecules/DashboardTimechart.tsx index 1cbc55e0..684dbf99 100644 --- a/ui/src/components/molecules/DashboardTimechart.tsx +++ b/ui/src/components/molecules/DashboardTimechart.tsx @@ -6,6 +6,7 @@ import 'vis-timeline/styles/vis-timeline-graph2d.css'; import { statusColorMapping } from '../../consts'; import { DAGStatus } from '../../models'; import { WorkflowListItem } from '../../models/api'; +import { useConfig } from '../../contexts/ConfigContext'; type Props = { data: DAGStatus[] | WorkflowListItem[] }; @@ -21,15 +22,11 @@ type TimelineItem = { function DashboardTimechart({ data: input }: Props) { const timelineRef = useRef(null); const timelineInstance = useRef(null); + const config = useConfig(); useEffect(() => { if (!timelineRef.current) return; - let timezone = getConfig().tz; - if (!timezone) { - timezone = moment.tz.guess(); - } - const items: TimelineItem[] = []; const now = moment(); const startOfDay = moment().startOf('day'); @@ -47,8 +44,8 @@ function DashboardTimechart({ data: input }: Props) { items.push({ id: status.Name + `_${status.RequestId}`, content: status.Name, - start: startMoment.tz(timezone).toDate(), - end: end.tz(timezone).toDate(), + start: startMoment.tz(config.tz).toDate(), + end: end.tz(config.tz).toDate(), group: 'main', className: `status-${status.Status}`, }); @@ -59,7 +56,7 @@ function DashboardTimechart({ data: input }: Props) { if (!timelineInstance.current) { timelineInstance.current = new Timeline(timelineRef.current, dataset, { - moment: (date: MomentInput) => moment(date).tz(timezone), + moment: (date: MomentInput) => moment(date).tz(config.tz), start: startOfDay.toDate(), end: now.endOf('day').toDate(), orientation: 'top', @@ -76,7 +73,7 @@ function DashboardTimechart({ data: input }: Props) { hour: 'HH:mm', }, majorLabels: { - hour: 'HH:mm', + hour: 'ddd D MMMM', day: 'ddd D MMMM', }, }, diff --git a/ui/src/contexts/ConfigContext.tsx b/ui/src/contexts/ConfigContext.tsx new file mode 100644 index 00000000..e1b360ef --- /dev/null +++ b/ui/src/contexts/ConfigContext.tsx @@ -0,0 +1,15 @@ +import { createContext, useContext } from 'react'; + +export type Config = { + apiURL: string; + title: string; + navbarColor: string; + tz: string; + version: string; +}; + +export const ConfigContext = createContext(null!); + +export function useConfig() { + return useContext(ConfigContext); +} diff --git a/ui/src/index.tsx b/ui/src/index.tsx index 1e42b2fb..f2d8f3cf 100644 --- a/ui/src/index.tsx +++ b/ui/src/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { createRoot } from 'react-dom/client'; -import App, { Config } from './App'; +import App from './App'; import './styles/styles.css'; import './styles/prism.css'; @@ -14,6 +14,7 @@ import '@fontsource/roboto/300.css'; import '@fontsource/roboto/400.css'; import '@fontsource/roboto/500.css'; import '@fontsource/roboto/700.css'; +import { Config } from './contexts/ConfigContext'; declare global { const getConfig: () => Config; diff --git a/ui/src/models/index.ts b/ui/src/models/index.ts index a1174d53..ff40a6c2 100644 --- a/ui/src/models/index.ts +++ b/ui/src/models/index.ts @@ -1,4 +1,5 @@ import cronParser from 'cron-parser'; +import moment from 'moment-timezone'; import { WorkflowListItem } from './api'; export enum SchedulerStatus { @@ -150,7 +151,7 @@ export function getNextSchedule(data: WorkflowListItem): number { if (!schedules || schedules.length == 0 || data.Suspended) { return Number.MAX_SAFE_INTEGER; } - const tz = getConfig().tz; + const tz = getConfig().tz || moment.tz.guess(); const datesToRun = schedules.map((s) => { const expression = tz ? cronParser.parseExpression(s.Expression, { diff --git a/ui/src/pages/index.tsx b/ui/src/pages/index.tsx index f441f435..7de34d50 100644 --- a/ui/src/pages/index.tsx +++ b/ui/src/pages/index.tsx @@ -8,6 +8,7 @@ import DashboardTimechart from '../components/molecules/DashboardTimechart'; import Title from '../components/atoms/Title'; import { AppBarContext } from '../contexts/AppBarContext'; import useSWR from 'swr'; +import { useConfig } from '../contexts/ConfigContext'; type metrics = Record; @@ -25,6 +26,7 @@ function Dashboard() { const { data } = useSWR(`/dags`, null, { refreshInterval: 10000, }); + const config = useConfig(); React.useEffect(() => { if (!data) { @@ -79,7 +81,7 @@ function Dashboard() { height: '100%', }} > - {getConfig().tz ? `Timeline in ${getConfig().tz}` : "Timeline"} + {`Timeline in ${config.tz}`}