feat: add time zone

pull/19758/head
Joel 7 months ago committed by Junyan Qin
parent c7f485123c
commit f6da7a03db
No known key found for this signature in database
GPG Key ID: 22FE3AFADC710CEB

@ -111,6 +111,15 @@ const TimePicker = ({
const displayValue = value?.format(timeFormat) || '' const displayValue = value?.format(timeFormat) || ''
const placeholderDate = isOpen && selectedTime ? selectedTime.format(timeFormat) : (placeholder || t('time.defaultPlaceholder')) const placeholderDate = isOpen && selectedTime ? selectedTime.format(timeFormat) : (placeholder || t('time.defaultPlaceholder'))
const inputElem = (
<input
className='system-xs-regular flex-1 cursor-pointer appearance-none truncate bg-transparent p-1
text-components-input-text-filled outline-none placeholder:text-components-input-text-placeholder'
readOnly
value={isOpen ? '' : displayValue}
placeholder={placeholderDate}
/>
)
return ( return (
<PortalToFollowElem <PortalToFollowElem
open={isOpen} open={isOpen}
@ -118,18 +127,16 @@ const TimePicker = ({
placement='bottom-end' placement='bottom-end'
> >
<PortalToFollowElemTrigger> <PortalToFollowElemTrigger>
{renderTrigger ? (renderTrigger()) : ( {renderTrigger ? (renderTrigger({
inputElem,
onClick: handleClickTrigger,
isOpen,
})) : (
<div <div
className='group flex w-[252px] cursor-pointer items-center gap-x-0.5 rounded-lg bg-components-input-bg-normal px-2 py-1 hover:bg-state-base-hover-alt' className='group flex w-[252px] cursor-pointer items-center gap-x-0.5 rounded-lg bg-components-input-bg-normal px-2 py-1 hover:bg-state-base-hover-alt'
onClick={handleClickTrigger} onClick={handleClickTrigger}
> >
<input {inputElem}
className='system-xs-regular flex-1 cursor-pointer appearance-none truncate bg-transparent p-1
text-components-input-text-filled outline-none placeholder:text-components-input-text-placeholder'
readOnly
value={isOpen ? '' : displayValue}
placeholder={placeholderDate}
/>
<RiTimeLine className={cn( <RiTimeLine className={cn(
'h-4 w-4 shrink-0 text-text-quaternary', 'h-4 w-4 shrink-0 text-text-quaternary',
isOpen ? 'text-text-secondary' : 'group-hover:text-text-secondary', isOpen ? 'text-text-secondary' : 'group-hover:text-text-secondary',

@ -48,13 +48,18 @@ export type DatePickerFooterProps = {
handleConfirmDate: () => void handleConfirmDate: () => void
} }
export type TriggerParams = {
isOpen: boolean
inputElem: React.ReactNode
onClick: (e: React.MouseEvent) => void
}
export type TimePickerProps = { export type TimePickerProps = {
value: Dayjs | undefined value: Dayjs | undefined
timezone?: string timezone?: string
placeholder?: string placeholder?: string
onChange: (date: Dayjs | undefined) => void onChange: (date: Dayjs | undefined) => void
onClear: () => void onClear: () => void
renderTrigger?: () => React.ReactNode renderTrigger?: (props: TriggerParams) => React.ReactNode
title?: string title?: string
minuteFilter?: (minutes: string[]) => string[] minuteFilter?: (minutes: string[]) => string[]
popupClassName?: string popupClassName?: string

@ -2,6 +2,7 @@ import dayjs, { type Dayjs } from 'dayjs'
import type { Day } from '../types' import type { Day } from '../types'
import utc from 'dayjs/plugin/utc' import utc from 'dayjs/plugin/utc'
import timezone from 'dayjs/plugin/timezone' import timezone from 'dayjs/plugin/timezone'
import tz from '@/utils/timezone.json'
dayjs.extend(utc) dayjs.extend(utc)
dayjs.extend(timezone) dayjs.extend(timezone)
@ -78,3 +79,14 @@ export const getHourIn12Hour = (date: Dayjs) => {
export const getDateWithTimezone = (props: { date?: Dayjs, timezone?: string }) => { export const getDateWithTimezone = (props: { date?: Dayjs, timezone?: string }) => {
return props.date ? dayjs.tz(props.date, props.timezone) : dayjs().tz(props.timezone) return props.date ? dayjs.tz(props.date, props.timezone) : dayjs().tz(props.timezone)
} }
// Asia/Shanghai -> UTC+8
const DEFAULT_OFFSET_STR = 'UTC+0'
export const convertTimezoneToOffsetStr = (timezone?: string) => {
if(!timezone)
return DEFAULT_OFFSET_STR
const tzItem = tz.find(item => item.value === timezone)
if(!tzItem)
return DEFAULT_OFFSET_STR
return `UTC${tzItem.name.charAt(0)}${tzItem.name.charAt(2)}`
}

@ -4,12 +4,17 @@ import React, { useCallback, useMemo } from 'react'
import { AUTO_UPDATE_MODE, AUTO_UPDATE_STRATEGY, type AutoUpdateConfig } from './types' import { AUTO_UPDATE_MODE, AUTO_UPDATE_STRATEGY, type AutoUpdateConfig } from './types'
import Label from '../label' import Label from '../label'
import StrategyPicker from './strategy-picker' import StrategyPicker from './strategy-picker'
import { useTranslation } from 'react-i18next' import { Trans, useTranslation } from 'react-i18next'
import TimePicker from '@/app/components/base/date-and-time-picker/time-picker' import TimePicker from '@/app/components/base/date-and-time-picker/time-picker'
import OptionCard from '@/app/components/workflow/nodes/_base/components/option-card' import OptionCard from '@/app/components/workflow/nodes/_base/components/option-card'
import PluginsPicker from './plugins-picker' import PluginsPicker from './plugins-picker'
import { convertLocalSecondsToUTCDaySeconds, convertUTCDaySecondsToLocalSeconds, dayjsToTimeOfDay, timeOfDayToDayjs } from './utils' import { convertLocalSecondsToUTCDaySeconds, convertUTCDaySecondsToLocalSeconds, dayjsToTimeOfDay, timeOfDayToDayjs } from './utils'
import { useAppContext } from '@/context/app-context' import { useAppContext } from '@/context/app-context'
import type { TriggerParams } from '@/app/components/base/date-and-time-picker/types'
import { RiTimeLine } from '@remixicon/react'
import cn from '@/utils/classnames'
import { convertTimezoneToOffsetStr } from '@/app/components/base/date-and-time-picker/utils/dayjs'
import { useModalContextSelector } from '@/context/modal-context'
const i18nPrefix = 'plugin.autoUpdate' const i18nPrefix = 'plugin.autoUpdate'
@ -18,6 +23,16 @@ type Props = {
onChange: (payload: AutoUpdateConfig) => void onChange: (payload: AutoUpdateConfig) => void
} }
const SettingTimeZone: FC<{
children?: React.ReactNode
}> = ({
children,
}) => {
const setShowAccountSettingModal = useModalContextSelector(s => s.setShowAccountSettingModal)
return (
<span className='body-xs-regular cursor-pointer text-text-accent' onClick={() => setShowAccountSettingModal({ payload: 'language' })} >{children}</span>
)
}
const AutoUpdateSetting: FC<Props> = ({ const AutoUpdateSetting: FC<Props> = ({
payload, payload,
onChange, onChange,
@ -83,10 +98,29 @@ const AutoUpdateSetting: FC<Props> = ({
}) })
} }
}, [payload, onChange]) }, [payload, onChange])
const renderTimePickerTrigger = useCallback(({ inputElem, onClick, isOpen }: TriggerParams) => {
return (
<div
className='group float-right flex h-8 w-[160px] cursor-pointer items-center justify-between rounded-lg bg-components-input-bg-normal px-2 hover:bg-state-base-hover-alt'
onClick={onClick}
>
<div className='flex w-0 grow items-center gap-x-1'>
<RiTimeLine className={cn(
'h-4 w-4 shrink-0 text-text-tertiary',
isOpen ? 'text-text-secondary' : 'group-hover:text-text-secondary',
)} />
{inputElem}
</div>
<div className='system-sm-regular text-text-tertiary'>{convertTimezoneToOffsetStr(timezone)}</div>
</div>
)
}, [timezone])
return ( return (
<div className='self-stretch px-6'> <div className='self-stretch px-6'>
<div className='my-3 flex items-center'> <div className='my-3 flex items-center'>
<div className='system-xs-medium-uppercase text-text-tertiary'>Updates Settings</div> <div className='system-xs-medium-uppercase text-text-tertiary'>{t(`${i18nPrefix}.updateSettings`)}</div>
<div className='ml-2 h-px grow bg-divider-subtle'></div> <div className='ml-2 h-px grow bg-divider-subtle'></div>
</div> </div>
@ -99,15 +133,26 @@ const AutoUpdateSetting: FC<Props> = ({
<> <>
<div className='flex items-center justify-between'> <div className='flex items-center justify-between'>
<Label label={t(`${i18nPrefix}.updateTime`)} /> <Label label={t(`${i18nPrefix}.updateTime`)} />
<TimePicker <div className='flex flex-col justify-start'>
value={timeOfDayToDayjs(convertUTCDaySecondsToLocalSeconds(upgrade_time_of_day, timezone!))} <TimePicker
timezone={timezone} value={timeOfDayToDayjs(convertUTCDaySecondsToLocalSeconds(upgrade_time_of_day, timezone!))}
onChange={v => handleChange('upgrade_time_of_day')(convertLocalSecondsToUTCDaySeconds(dayjsToTimeOfDay(v), timezone!))} timezone={timezone}
onClear={() => handleChange('upgrade_time_of_day')(convertLocalSecondsToUTCDaySeconds(0, timezone!))} onChange={v => handleChange('upgrade_time_of_day')(convertLocalSecondsToUTCDaySeconds(dayjsToTimeOfDay(v), timezone!))}
popupClassName='z-[99]' onClear={() => handleChange('upgrade_time_of_day')(convertLocalSecondsToUTCDaySeconds(0, timezone!))}
title={t(`${i18nPrefix}.updateTime`)} popupClassName='z-[99]'
minuteFilter={minuteFilter} title={t(`${i18nPrefix}.updateTime`)}
/> minuteFilter={minuteFilter}
renderTrigger={renderTimePickerTrigger}
/>
<div className='body-xs-regular mt-1 text-right text-text-tertiary'>
<Trans
i18nKey={`${i18nPrefix}.changeTimezone`}
components={{
setTimezone: <SettingTimeZone />,
}}
/>
</div>
</div>
</div> </div>
<div> <div>
<Label label={t(`${i18nPrefix}.specifyPluginsToUpdate`)} /> <Label label={t(`${i18nPrefix}.specifyPluginsToUpdate`)} />

@ -172,6 +172,8 @@ const translation = {
noFound: 'No plugins were found', noFound: 'No plugins were found',
noInstalled: 'No plugins installed', noInstalled: 'No plugins installed',
}, },
updateSettings: 'Update Settings',
changeTimezone: 'To change time zone, go to <setTimezone>Settings</setTimezone>',
}, },
pluginInfoModal: { pluginInfoModal: {
title: 'Plugin info', title: 'Plugin info',

@ -172,6 +172,8 @@ const translation = {
noFound: '未找到插件', noFound: '未找到插件',
noInstalled: '未安装插件', noInstalled: '未安装插件',
}, },
updateSettings: '更新设置',
changeTimezone: '要更改时区,请前往<setTimezone>设置</setTimezone>',
}, },
pluginInfoModal: { pluginInfoModal: {
title: '插件信息', title: '插件信息',

Loading…
Cancel
Save