Skip to content

Commit

Permalink
feat(top_slowquery): support select time range on the chart (#1665)
Browse files Browse the repository at this point in the history
* feat(top_slowquery): support select time range on the chart

* comment test code
  • Loading branch information
baurine authored Apr 2, 2024
1 parent e44a58d commit 5e932ec
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 82 deletions.
32 changes: 18 additions & 14 deletions ui/packages/tidb-dashboard-for-clinic-cloud/public/ngm.html
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,23 @@
window.location.assign('/')
}

// const topslowQueryBlockOrgIds = ['1372813089209061633']
// const topslowQueryBlockOrgIds = [
// '1372813089209061633',
// '1369847559691367400'
// ]
// const enableTopSlowquery = !topslowQueryBlockOrgIds.includes(orgId)
let clusterInfo = {
provider,
region,
orgId,
projectId,
clusterId,
deployType
}
// test
// clusterInfo = {
// provider: 'aws',
// region: 'us-east-1',
// orgId: '1372813089209061633',
// projectId: '1372813089454525346',
// clusterId: '1379661944646413143',
// deployType
// }

const apiPathBase = `/ngm/api/v1`
startDashboard({
Expand All @@ -162,14 +173,7 @@
apiPathBase,
apiToken
},
clusterInfo: {
provider,
region,
orgId,
projectId,
clusterId,
deployType
},
clusterInfo,
appsConfig: {
slowQuery: {
enableExport: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ export function TopSlowQueryProvider(props: { children: React.ReactNode }) {
getAvailableTimeWindows: async ({
from,
to,
tws
duration
}: {
from: number
to: number
tws: number
duration: number
}) => {
const hours = tws / 3600
const hours = duration / 3600
return client
.getAxiosInstance()
.get(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export type TopSlowQueryCtxValue = {
getAvailableTimeWindows(params: {
from: number
to: number
tws: number
duration: number
}): Promise<ITimeWindow[]>

getMetrics: (params: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,30 +26,29 @@ export function CountChart({
return (data ?? []).map(([time, count]) => [time * 1000, count])
}, [data])

// TODO: next pr
// function onBrushEnd(e: BrushEvent) {
// if (!e.x) {
// return
// }
function onBrushEnd(e: BrushEvent) {
if (!e.x) {
return
}

// let value: [number, number]
// const tr = e.x.map((d) => d / 1000)
// const delta = tr[1] - tr[0]
// if (delta < 60) {
// const offset = Math.floor(delta / 2)
// value = [Math.ceil(tr[0] + offset - 30), Math.floor(tr[1] - offset + 30)]
// } else {
// value = [Math.ceil(tr[0]), Math.floor(tr[1])]
// }
// onSelectTimeRange?.(value)
// }
let value: [number, number]
const tr = e.x.map((d) => d / 1000)
const delta = tr[1] - tr[0]
if (delta < 60) {
const offset = Math.floor(delta / 2)
value = [Math.ceil(tr[0] + offset - 30), Math.floor(tr[1] - offset + 30)]
} else {
value = [Math.ceil(tr[0]), Math.floor(tr[1])]
}
onSelectTimeRange?.(value)
}

return (
<Chart>
<Settings
{...DEFAULT_CHART_SETTINGS}
showLegend={false}
// onBrushEnd={onBrushEnd}
onBrushEnd={onSelectTimeRange ? onBrushEnd : undefined}
xDomain={{
min: timeRange[0] * 1000,
max: timeRange[1] * 1000
Expand Down
70 changes: 38 additions & 32 deletions ui/packages/tidb-dashboard-lib/src/apps/TopSlowQuery/pages/List.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import React, { useRef, useMemo } from 'react'
import { Space, Select, Typography, Button, Tag, Skeleton } from 'antd'
import { CaretLeftOutlined, CaretRightOutlined } from '@ant-design/icons'
import { Card, TimeRangeValue, toTimeRangeValue } from '@lib/components'
import {
Card,
TimeRangeValue,
fromTimeRangeValue,
toTimeRangeValue
} from '@lib/components'

import styles from './List.module.less'
import { useTopSlowQueryContext } from '../context'
import { Link } from 'react-router-dom'
import { useTopSlowQueryUrlState } from '../uilts/url-state'
import { TIME_WINDOW_SIZES, ORDER_BY } from '../uilts/helpers'
import { DEFAULT_TIME_RANGE, DURATIONS, ORDER_BY } from '../uilts/helpers'
import { useQuery } from '@tanstack/react-query'
import dayjs from 'dayjs'
import { TopSlowQueryListTable } from './ListTable'
Expand Down Expand Up @@ -74,12 +79,12 @@ function ClusterInfoHeader() {

function useTimeWindows() {
const ctx = useTopSlowQueryContext()
const { tws, tw, setTw, timeRange } = useTopSlowQueryUrlState()
const { duration, tw, setTw, timeRange } = useTopSlowQueryUrlState()

const query = useQuery({
queryKey: [
'top_slowquery_time_windows',
tws,
duration,
timeRange,
ctx.cfg.orgName,
ctx.cfg.clusterName
Expand All @@ -89,7 +94,7 @@ function useTimeWindows() {
return ctx.api.getAvailableTimeWindows({
from: timeVal[0],
to: timeVal[1],
tws
duration
})
},
onSuccess(data) {
Expand All @@ -107,7 +112,8 @@ function useTimeWindows() {

const timezone = dayjs().format('UTCZ')
function TimeWindowSelect() {
const { tws, setTws, tw, setTw } = useTopSlowQueryUrlState()
const { duration, setDurationAndTimeRange, tw, setTw } =
useTopSlowQueryUrlState()
const { data: availableTimeWindows } = useTimeWindows()

function newerTw() {
Expand Down Expand Up @@ -153,8 +159,12 @@ function TimeWindowSelect() {

<div>
<span>Duration: </span>
<Select style={{ width: 128 }} value={tws} onChange={setTws}>
{TIME_WINDOW_SIZES.map((item) => (
<Select
style={{ width: 128 }}
value={duration}
onChange={(v) => setDurationAndTimeRange(v, DEFAULT_TIME_RANGE)}
>
{DURATIONS.map((item) => (
<Select.Option value={item.value} key={item.label}>
{item.label}
</Select.Option>
Expand Down Expand Up @@ -223,30 +233,26 @@ function useChartData() {

function SlowQueryCountChart() {
const { data: chartData, isLoading } = useChartData()
const { tw } = useTopSlowQueryUrlState()
const { tw, setDurationAndTimeRange } = useTopSlowQueryUrlState()

// TODO: next pr
// function onSelectTimeRange(timeRange: TimeRangeValue) {
// const delta = timeRange[1] - timeRange[0]
// let tws = 60 * 60
// if (delta < 60 * 60) {
// tws = 60 * 60
// } else if (delta < 3 * 60 * 60) {
// tws = 3 * 60 * 60
// } else if (delta < 6 * 60 * 60) {
// tws = 6 * 60 * 60
// } else if (delta < 12 * 60 * 60) {
// tws = 12 * 60 * 60
// } else if (delta < 24 * 60 * 60) {
// tws = 24 * 60 * 60
// } else if (delta < 7 * 24 * 60 * 60) {
// tws = 7 * 24 * 60 * 60
// }
// // console.log('onSelectTimeRange', timeRange, tws)
// // useUrlState has a bug: can not set 2 keys at the same time
// // setTws(tws)
// // setTimeRange(fromTimeRangeValue(timeRange))
// }
function onSelectTimeRange(timeRange: TimeRangeValue) {
const delta = timeRange[1] - timeRange[0]
let duration = 60 * 60
if (delta < 60 * 60) {
duration = 60 * 60
} else if (delta < 3 * 60 * 60) {
duration = 3 * 60 * 60
} else if (delta < 6 * 60 * 60) {
duration = 6 * 60 * 60
} else if (delta < 12 * 60 * 60) {
duration = 12 * 60 * 60
} else if (delta < 24 * 60 * 60) {
duration = 24 * 60 * 60
} else if (delta < 7 * 24 * 60 * 60) {
duration = 7 * 24 * 60 * 60
}
setDurationAndTimeRange(duration, fromTimeRangeValue(timeRange))
}

return (
<div style={{ marginTop: 16, marginBottom: 24 }}>
Expand All @@ -256,7 +262,7 @@ function SlowQueryCountChart() {
<CountChart
data={chartData ?? []}
timeRange={tw as TimeRangeValue}
// onSelectTimeRange={onSelectTimeRange}
onSelectTimeRange={onSelectTimeRange}
/>
</Skeleton>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const DEFAULT_TIME_RANGE: TimeRange = {
value: TIME_RANGE_RECENT_SECONDS[6]
}

export const TIME_WINDOW_SIZES = [
export const DURATIONS = [
{ label: '1 hour', value: 60 * 60 },
{ label: '3 hours', value: 3 * 60 * 60 },
{ label: '6 hours', value: 6 * 60 * 60 },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import {
urlToTimeRange
} from '@lib/components/TimeRangeSelector'
import { useCallback, useMemo } from 'react'
import { DEFAULT_TIME_RANGE, TIME_WINDOW_SIZES, ORDER_BY } from './helpers'
import { DEFAULT_TIME_RANGE, DURATIONS, ORDER_BY } from './helpers'

// tws: time window size (1 hour, 2 hours ...)
// tw: time window (start-end)
type UrlState = Partial<
Record<'from' | 'to' | 'tws' | 'tw' | 'order' | 'db' | 'internal', string>
Record<
'from' | 'to' | 'duration' | 'tw' | 'order' | 'db' | 'internal',
string
>
>

export function useTopSlowQueryUrlState() {
Expand All @@ -31,19 +33,29 @@ export function useTopSlowQueryUrlState() {
[setQueryParams]
)

const tws: number = useMemo(() => {
const v = parseInt(queryParams.tws)
const duration: number = useMemo(() => {
const v = parseInt(queryParams.duration)
if (isNaN(v)) {
return TIME_WINDOW_SIZES[0].value
return DURATIONS[0].value
}
if (TIME_WINDOW_SIZES.some((s) => s.value === v)) {
if (DURATIONS.some((s) => s.value === v)) {
return v
}
return TIME_WINDOW_SIZES[0].value
}, [queryParams.tws])
const setTws = useCallback(
return DURATIONS[0].value
}, [queryParams.duration])
const setDuration = useCallback(
(v: number) => {
setQueryParams({ tws: v + '' })
setQueryParams({ duration: v + '' })
},
[setQueryParams]
)

// Note: when calling `setDuration(); setTimeRange();` at the same time, only the last one will take effect
// the latter one will overwrite the former one
// TODO: do we have a better solution? expose the `setQueryParams` as well?
const setDurationAndTimeRange = useCallback(
(v: number, tr: TimeRange) => {
setQueryParams({ duration: v + '', ...toURLTimeRange(tr) })
},
[setQueryParams]
)
Expand All @@ -59,7 +71,6 @@ export function useTopSlowQueryUrlState() {
}
return [0, 0]
}, [queryParams.tw])

const setTw = useCallback(
(v: string) => {
// v format: "from-to"
Expand Down Expand Up @@ -90,8 +101,10 @@ export function useTopSlowQueryUrlState() {
timeRange,
setTimeRange,

tws,
setTws,
duration,
setDuration,

setDurationAndTimeRange,

tw,
setTw,
Expand Down

0 comments on commit 5e932ec

Please sign in to comment.