mirror of https://github.com/langgenius/dify.git
feat: new time range picker outline
This commit is contained in:
parent
8254a40e75
commit
1205960c59
|
|
@ -5,16 +5,19 @@ import quarterOfYear from 'dayjs/plugin/quarterOfYear'
|
|||
import { useTranslation } from 'react-i18next'
|
||||
import type { PeriodParams } from '@/app/components/app/overview/app-chart'
|
||||
import { AvgResponseTime, AvgSessionInteractions, AvgUserInteractions, ConversationsChart, CostChart, EndUsersChart, MessagesChart, TokenPerSecond, UserSatisfactionRate, WorkflowCostChart, WorkflowDailyTerminalsChart, WorkflowMessagesChart } from '@/app/components/app/overview/app-chart'
|
||||
import type { Item } from '@/app/components/base/select'
|
||||
import { SimpleSelect } from '@/app/components/base/select'
|
||||
import { TIME_PERIOD_MAPPING } from '@/app/components/app/log/filter'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
import { sendGAEvent } from '@/utils/gtag'
|
||||
import TimeRangePicker from './time-range-picker'
|
||||
|
||||
dayjs.extend(quarterOfYear)
|
||||
|
||||
const today = dayjs()
|
||||
|
||||
const TIME_PERIOD_MAPPING = [
|
||||
{ value: 0, name: 'today' },
|
||||
{ value: 7, name: 'last7days' },
|
||||
{ value: 30, name: 'last30days' },
|
||||
]
|
||||
|
||||
const queryDateFormat = 'YYYY-MM-DD HH:mm'
|
||||
|
||||
export type IChartViewProps = {
|
||||
|
|
@ -27,21 +30,7 @@ export default function ChartView({ appId, headerRight }: IChartViewProps) {
|
|||
const appDetail = useAppStore(state => state.appDetail)
|
||||
const isChatApp = appDetail?.mode !== 'completion' && appDetail?.mode !== 'workflow'
|
||||
const isWorkflow = appDetail?.mode === 'workflow'
|
||||
const [period, setPeriod] = useState<PeriodParams>({ name: t('appLog.filter.period.last7days'), query: { start: today.subtract(7, 'day').startOf('day').format(queryDateFormat), end: today.endOf('day').format(queryDateFormat) } })
|
||||
|
||||
const onSelect = (item: Item) => {
|
||||
if (item.value === -1) {
|
||||
setPeriod({ name: item.name, query: undefined })
|
||||
}
|
||||
else if (item.value === 0) {
|
||||
const startOfToday = today.startOf('day').format(queryDateFormat)
|
||||
const endOfToday = today.endOf('day').format(queryDateFormat)
|
||||
setPeriod({ name: item.name, query: { start: startOfToday, end: endOfToday } })
|
||||
}
|
||||
else {
|
||||
setPeriod({ name: item.name, query: { start: today.subtract(item.value as number, 'day').startOf('day').format(queryDateFormat), end: today.endOf('day').format(queryDateFormat) } })
|
||||
}
|
||||
}
|
||||
const [period, setPeriod] = useState<PeriodParams>({ name: t('appLog.filter.period.today'), query: { start: today.startOf('day').format(queryDateFormat), end: today.endOf('day').format(queryDateFormat) } })
|
||||
|
||||
if (!appDetail)
|
||||
return null
|
||||
|
|
@ -52,21 +41,10 @@ export default function ChartView({ appId, headerRight }: IChartViewProps) {
|
|||
<div className='system-xl-semibold mb-2 text-text-primary'>{t('common.appMenus.overview')}</div>
|
||||
<div className='flex items-center justify-between'>
|
||||
<div className='flex flex-row items-center'>
|
||||
<SimpleSelect
|
||||
items={Object.entries(TIME_PERIOD_MAPPING).map(([k, v]) => ({ value: k, name: t(`appLog.filter.period.${v.name}`) }))}
|
||||
className='mt-0 !w-40'
|
||||
notClearable={true}
|
||||
onSelect={(item) => {
|
||||
sendGAEvent(isWorkflow ? 'filter_workflow_overview_period' : 'filter_chat_conversation_overview_period', {
|
||||
period: item.value,
|
||||
period_name: item.name,
|
||||
})
|
||||
const id = item.value
|
||||
const value = TIME_PERIOD_MAPPING[id]?.value ?? '-1'
|
||||
const name = item.name || t('appLog.filter.period.allTime')
|
||||
onSelect({ value, name })
|
||||
}}
|
||||
defaultValue={'2'}
|
||||
<TimeRangePicker
|
||||
ranges={TIME_PERIOD_MAPPING}
|
||||
onSelect={setPeriod}
|
||||
queryDateFormat={queryDateFormat}
|
||||
/>
|
||||
</div>
|
||||
{headerRight}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
'use client'
|
||||
import type { PeriodParams } from '@/app/components/app/overview/app-chart'
|
||||
import type { FC } from 'react'
|
||||
import React, { useCallback } from 'react'
|
||||
import { SimpleSelect } from '@/app/components/base/select'
|
||||
import type { Item } from '@/app/components/base/select'
|
||||
import dayjs from 'dayjs'
|
||||
import { HourglassShape } from '@/app/components/base/icons/src/vender/other'
|
||||
import TimePicker from '@/app/components/base/date-and-time-picker/time-picker'
|
||||
import { noop } from 'lodash-es'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
const today = dayjs()
|
||||
|
||||
type Props = {
|
||||
ranges: { value: number; name: string }[]
|
||||
onSelect: (payload: PeriodParams) => void
|
||||
queryDateFormat: string
|
||||
}
|
||||
|
||||
const TimeRangePicker: FC<Props> = ({
|
||||
ranges,
|
||||
onSelect,
|
||||
queryDateFormat,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
console.log(Object.entries(ranges).map(([k, v]) => ({ value: k, name: t(`appLog.filter.period.${v.name}`) })))
|
||||
|
||||
const handleSelectRange = useCallback((item: Item) => {
|
||||
const { name, value } = item
|
||||
let period: PeriodParams['query'] | null = null
|
||||
if (value === 0) {
|
||||
const startOfToday = today.startOf('day').format(queryDateFormat)
|
||||
const endOfToday = today.endOf('day').format(queryDateFormat)
|
||||
period = { start: startOfToday, end: endOfToday }
|
||||
}
|
||||
else {
|
||||
period = { start: today.subtract(item.value as number, 'day').startOf('day').format(queryDateFormat), end: today.endOf('day').format(queryDateFormat) }
|
||||
}
|
||||
onSelect({ query: period!, name })
|
||||
}, [onSelect])
|
||||
return (
|
||||
<div className='flex items-center'>
|
||||
<SimpleSelect
|
||||
items={ranges.map(v => ({ ...v, name: t(`appLog.filter.period.${v.name}`) }))}
|
||||
className='mt-0 !w-40'
|
||||
notClearable={true}
|
||||
onSelect={handleSelectRange}
|
||||
defaultValue={0}
|
||||
/>
|
||||
<HourglassShape className='h-3.5 w-2 text-components-input-bg-normal' />
|
||||
<TimePicker
|
||||
value={today}
|
||||
onChange={noop}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default React.memo(TimeRangePicker)
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="8" height="14" viewBox="0 0 8 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 14C8 11.7909 6.20914 10 4 10C1.79086 10 0 11.7909 0 14V0C8.05332e-08 2.20914 1.79086 4 4 4C6.20914 4 8 2.20914 8 0V14Z" fill="#C8CEDA" fill-opacity="0.25"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 270 B |
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"icon": {
|
||||
"type": "element",
|
||||
"isRootNode": true,
|
||||
"name": "svg",
|
||||
"attributes": {
|
||||
"width": "8",
|
||||
"height": "14",
|
||||
"viewBox": "0 0 8 14",
|
||||
"fill": "none",
|
||||
"xmlns": "http://www.w3.org/2000/svg"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"d": "M8 14C8 11.7909 6.20914 10 4 10C1.79086 10 0 11.7909 0 14V0C8.05332e-08 2.20914 1.79086 4 4 4C6.20914 4 8 2.20914 8 0V14Z",
|
||||
"fill": "currentColor",
|
||||
"fill-opacity": "0.25"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "HourglassShape"
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// GENERATE BY script
|
||||
// DON NOT EDIT IT MANUALLY
|
||||
|
||||
import * as React from 'react'
|
||||
import data from './HourglassShape.json'
|
||||
import IconBase from '@/app/components/base/icons/IconBase'
|
||||
import type { IconData } from '@/app/components/base/icons/IconBase'
|
||||
|
||||
const Icon = (
|
||||
{
|
||||
ref,
|
||||
...props
|
||||
}: React.SVGProps<SVGSVGElement> & {
|
||||
ref?: React.RefObject<React.RefObject<HTMLOrSVGElement>>;
|
||||
},
|
||||
) => <IconBase {...props} ref={ref} data={data as IconData} />
|
||||
|
||||
Icon.displayName = 'HourglassShape'
|
||||
|
||||
export default Icon
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
export { default as AnthropicText } from './AnthropicText'
|
||||
export { default as Generator } from './Generator'
|
||||
export { default as Group } from './Group'
|
||||
export { default as HourglassShape } from './HourglassShape'
|
||||
export { default as Mcp } from './Mcp'
|
||||
export { default as NoToolPlaceholder } from './NoToolPlaceholder'
|
||||
export { default as Openai } from './Openai'
|
||||
|
|
|
|||
Loading…
Reference in New Issue