From 5e932ec07f1ffb8455c562b2f7402e1912e5fe12 Mon Sep 17 00:00:00 2001 From: Sparkle <1284531+baurine@users.noreply.github.com> Date: Tue, 2 Apr 2024 11:01:46 +0800 Subject: [PATCH] feat(top_slowquery): support select time range on the chart (#1665) * feat(top_slowquery): support select time range on the chart * comment test code --- .../public/ngm.html | 32 +++++---- .../apps/TopSlowQuery/context-provider.tsx | 6 +- .../src/apps/TopSlowQuery/context.ts | 2 +- .../apps/TopSlowQuery/pages/CountChart.tsx | 33 +++++---- .../src/apps/TopSlowQuery/pages/List.tsx | 70 ++++++++++--------- .../src/apps/TopSlowQuery/uilts/helpers.ts | 2 +- .../src/apps/TopSlowQuery/uilts/url-state.ts | 41 +++++++---- 7 files changed, 104 insertions(+), 82 deletions(-) diff --git a/ui/packages/tidb-dashboard-for-clinic-cloud/public/ngm.html b/ui/packages/tidb-dashboard-for-clinic-cloud/public/ngm.html index a06c0270c..e36803b14 100644 --- a/ui/packages/tidb-dashboard-for-clinic-cloud/public/ngm.html +++ b/ui/packages/tidb-dashboard-for-clinic-cloud/public/ngm.html @@ -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({ @@ -162,14 +173,7 @@ apiPathBase, apiToken }, - clusterInfo: { - provider, - region, - orgId, - projectId, - clusterId, - deployType - }, + clusterInfo, appsConfig: { slowQuery: { enableExport: false, diff --git a/ui/packages/tidb-dashboard-for-clinic-cloud/src/apps/TopSlowQuery/context-provider.tsx b/ui/packages/tidb-dashboard-for-clinic-cloud/src/apps/TopSlowQuery/context-provider.tsx index a45c1f77a..dd71fc2ee 100644 --- a/ui/packages/tidb-dashboard-for-clinic-cloud/src/apps/TopSlowQuery/context-provider.tsx +++ b/ui/packages/tidb-dashboard-for-clinic-cloud/src/apps/TopSlowQuery/context-provider.tsx @@ -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( diff --git a/ui/packages/tidb-dashboard-lib/src/apps/TopSlowQuery/context.ts b/ui/packages/tidb-dashboard-lib/src/apps/TopSlowQuery/context.ts index 8a6706371..fe28697dd 100644 --- a/ui/packages/tidb-dashboard-lib/src/apps/TopSlowQuery/context.ts +++ b/ui/packages/tidb-dashboard-lib/src/apps/TopSlowQuery/context.ts @@ -20,7 +20,7 @@ export type TopSlowQueryCtxValue = { getAvailableTimeWindows(params: { from: number to: number - tws: number + duration: number }): Promise getMetrics: (params: { diff --git a/ui/packages/tidb-dashboard-lib/src/apps/TopSlowQuery/pages/CountChart.tsx b/ui/packages/tidb-dashboard-lib/src/apps/TopSlowQuery/pages/CountChart.tsx index b013b5730..80af96847 100644 --- a/ui/packages/tidb-dashboard-lib/src/apps/TopSlowQuery/pages/CountChart.tsx +++ b/ui/packages/tidb-dashboard-lib/src/apps/TopSlowQuery/pages/CountChart.tsx @@ -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 ( Duration: - setDurationAndTimeRange(v, DEFAULT_TIME_RANGE)} + > + {DURATIONS.map((item) => ( {item.label} @@ -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 (
@@ -256,7 +262,7 @@ function SlowQueryCountChart() {
diff --git a/ui/packages/tidb-dashboard-lib/src/apps/TopSlowQuery/uilts/helpers.ts b/ui/packages/tidb-dashboard-lib/src/apps/TopSlowQuery/uilts/helpers.ts index 8e6ff08bf..6ca71537c 100644 --- a/ui/packages/tidb-dashboard-lib/src/apps/TopSlowQuery/uilts/helpers.ts +++ b/ui/packages/tidb-dashboard-lib/src/apps/TopSlowQuery/uilts/helpers.ts @@ -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 }, diff --git a/ui/packages/tidb-dashboard-lib/src/apps/TopSlowQuery/uilts/url-state.ts b/ui/packages/tidb-dashboard-lib/src/apps/TopSlowQuery/uilts/url-state.ts index 95cf5459d..a0b959665 100644 --- a/ui/packages/tidb-dashboard-lib/src/apps/TopSlowQuery/uilts/url-state.ts +++ b/ui/packages/tidb-dashboard-lib/src/apps/TopSlowQuery/uilts/url-state.ts @@ -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() { @@ -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] ) @@ -59,7 +71,6 @@ export function useTopSlowQueryUrlState() { } return [0, 0] }, [queryParams.tw]) - const setTw = useCallback( (v: string) => { // v format: "from-to" @@ -90,8 +101,10 @@ export function useTopSlowQueryUrlState() { timeRange, setTimeRange, - tws, - setTws, + duration, + setDuration, + + setDurationAndTimeRange, tw, setTw,