diff --git a/ui/lib/apps/SlowQuery/pages/Detail/index.tsx b/ui/lib/apps/SlowQuery/pages/Detail/index.tsx
index 5ffe5a5650..1f47b2e777 100644
--- a/ui/lib/apps/SlowQuery/pages/Detail/index.tsx
+++ b/ui/lib/apps/SlowQuery/pages/Detail/index.tsx
@@ -1,25 +1,25 @@
import React from 'react'
import { Space } from 'antd'
import { useTranslation } from 'react-i18next'
-import { useLocation, Link } from 'react-router-dom'
+import { Link, useLocation } from 'react-router-dom'
import { ArrowLeftOutlined } from '@ant-design/icons'
-import { useToggle } from '@umijs/hooks'
+import { useLocalStorageState } from '@umijs/hooks'
import client from '@lib/client'
import { useClientRequest } from '@lib/utils/useClientRequest'
-import { parseQueryFn, buildQueryFn } from '@lib/utils/query'
+import { buildQueryFn, parseQueryFn } from '@lib/utils/query'
import formatSql from '@lib/utils/formatSql'
import {
- Head,
- Descriptions,
- TextWithInfo,
- Pre,
- HighlightSQL,
- Expand,
- CopyLink,
- CardTabs,
AnimatedSkeleton,
+ CardTabs,
+ CopyLink,
+ Descriptions,
ErrorBar,
+ Expand,
+ Head,
+ HighlightSQL,
+ Pre,
+ TextWithInfo,
} from '@lib/components'
import TabBasic from './DetailTabBasic'
import TabTime from './DetailTabTime'
@@ -32,6 +32,8 @@ export interface IPageQuery {
timestamp?: number
}
+const SLOW_QUERY_DETAIL_EXPAND = 'slow_query.detail_expand'
+
function DetailPage() {
const query = DetailPage.parseQuery(useLocation().search)
@@ -48,11 +50,21 @@ function DetailPage() {
)
)
- const { state: sqlExpanded, toggle: toggleSqlExpanded } = useToggle(false)
- const { state: prevSqlExpanded, toggle: togglePrevSqlExpanded } = useToggle(
- false
+ const [detailExpand, setDetailExpand] = useLocalStorageState(
+ SLOW_QUERY_DETAIL_EXPAND,
+ {
+ prev_query: false,
+ query: false,
+ plan: false,
+ }
)
- const { state: planExpanded, toggle: togglePlanExpanded } = useToggle(false)
+
+ const togglePrevQuery = () =>
+ setDetailExpand((prev) => ({ ...prev, prev_query: !prev.prev_query }))
+ const toggleQuery = () =>
+ setDetailExpand((prev) => ({ ...prev, query: !prev.query }))
+ const togglePlan = () =>
+ setDetailExpand((prev) => ({ ...prev, plan: !prev.plan }))
return (
@@ -71,20 +83,20 @@ function DetailPage() {
toggleSqlExpanded()}
+ expanded={detailExpand.query}
+ onClick={toggleQuery}
/>
}
>
}
@@ -97,20 +109,20 @@ function DetailPage() {
return (
togglePrevSqlExpanded()}
+ expanded={detailExpand.prev_query}
+ onClick={togglePrevQuery}
/>
}
>
}
@@ -122,19 +134,19 @@ function DetailPage() {
})()}
togglePlanExpanded()}
+ expanded={detailExpand.plan}
+ onClick={togglePlan}
/>
}
>
-
+
{data.plan}
diff --git a/ui/lib/apps/SlowQuery/utils/tableColumns.tsx b/ui/lib/apps/SlowQuery/utils/tableColumns.tsx
index d3ca0e48bc..72e11399b3 100644
--- a/ui/lib/apps/SlowQuery/utils/tableColumns.tsx
+++ b/ui/lib/apps/SlowQuery/utils/tableColumns.tsx
@@ -18,6 +18,21 @@ function ResultStatusBadge({ status }: { status: 'success' | 'error' }) {
//////////////////////////////////////////
const TRANS_KEY_PREFIX = 'slow_query.fields'
+export const derivedFields = {
+ cop_proc_avg: [
+ { tooltipPrefix: 'mean', fieldName: 'cop_proc_avg' },
+ { tooltipPrefix: 'max', fieldName: 'cop_proc_max' },
+ { tooltipPrefix: 'p90', fieldName: 'cop_proc_p90' },
+ ],
+ cop_wait_avg: [
+ { tooltipPrefix: 'mean', fieldName: 'cop_wait_avg' },
+ { tooltipPrefix: 'max', fieldName: 'cop_wait_max' },
+ { tooltipPrefix: 'p90', fieldName: 'cop_wait_p90' },
+ ],
+}
+
+//////////////////////////////////////////
+
export function slowQueryColumns(
rows: SlowquerySlowQuery[],
showFullSQL?: boolean
@@ -73,28 +88,8 @@ export function slowQueryColumns(
tcf.bar.single('commit_backoff_time', 'ns', rows),
tcf.bar.single('resolve_lock_time', 'ns', rows),
// cop
- tcf.bar.multiple(
- {
- bars: [
- { mean: 'cop_proc_avg' },
- { max: 'cop_proc_max' },
- { p90: 'cop_proc_p90' },
- ],
- },
- 'ns',
- rows
- ),
- tcf.bar.multiple(
- {
- bars: [
- { mean: 'cop_wait_avg' },
- { max: 'cop_wait_avg' },
- { p90: 'cop_wait_avg' },
- ],
- },
- 'ns',
- rows
- ),
+ tcf.bar.multiple({ sources: derivedFields.cop_proc_avg }, 'ns', rows),
+ tcf.bar.multiple({ sources: derivedFields.cop_wait_avg }, 'ns', rows),
// transaction
tcf.bar.single('write_keys', 'short', rows),
tcf.bar.single('write_size', 'bytes', rows),
diff --git a/ui/lib/apps/SlowQuery/utils/useSlowQueryTableController.ts b/ui/lib/apps/SlowQuery/utils/useSlowQueryTableController.ts
index 9e35fdc9f2..dcb4370bc7 100644
--- a/ui/lib/apps/SlowQuery/utils/useSlowQueryTableController.ts
+++ b/ui/lib/apps/SlowQuery/utils/useSlowQueryTableController.ts
@@ -6,7 +6,7 @@ import client, { ErrorStrategy, SlowquerySlowQuery } from '@lib/client'
import { calcTimeRange, TimeRange, IColumnKeys } from '@lib/components'
import useOrderState, { IOrderOptions } from '@lib/utils/useOrderState'
-import { slowQueryColumns } from './tableColumns'
+import { derivedFields, slowQueryColumns } from './tableColumns'
import { getSelectedFields } from '@lib/utils/tableColumnFactory'
export const DEF_SLOW_QUERY_COLUMN_KEYS: IColumnKeys = {
@@ -123,18 +123,16 @@ export default function useSlowQueryTableController(
querySchemas()
}, [])
- // Notice: slowQueries, tableColumns, selectedFields make loop dependencies
+ const selectedFields = useMemo(
+ () => getSelectedFields(visibleColumnKeys, derivedFields).join(','),
+ [visibleColumnKeys]
+ )
+
const tableColumns = useMemo(
() => slowQueryColumns(slowQueries, showFullSQL),
[slowQueries, showFullSQL]
)
- // make selectedFields as a string instead of an array to avoid infinite loop
- // I have verified that it will cause infinite loop if we return selectedFields as an array
- // so it is better to use the basic type (string, number...) instead of object as the dependency
- const selectedFields = useMemo(
- () => getSelectedFields(visibleColumnKeys, tableColumns).join(','),
- [visibleColumnKeys, tableColumns]
- )
+
useEffect(() => {
async function getSlowQueryList() {
setLoadingSlowQueries(true)
diff --git a/ui/lib/apps/Statement/pages/Detail/PlanDetail.tsx b/ui/lib/apps/Statement/pages/Detail/PlanDetail.tsx
index ef16819a97..b686c63345 100644
--- a/ui/lib/apps/Statement/pages/Detail/PlanDetail.tsx
+++ b/ui/lib/apps/Statement/pages/Detail/PlanDetail.tsx
@@ -1,18 +1,18 @@
import React from 'react'
import { Space } from 'antd'
-import { useToggle } from '@umijs/hooks'
+import { useLocalStorageState } from '@umijs/hooks'
import { useTranslation } from 'react-i18next'
import {
+ AnimatedSkeleton,
Card,
- Descriptions,
- HighlightSQL,
- TextWithInfo,
- Pre,
CardTabs,
- Expand,
CopyLink,
- AnimatedSkeleton,
+ Descriptions,
ErrorBar,
+ Expand,
+ HighlightSQL,
+ Pre,
+ TextWithInfo,
} from '@lib/components'
import { useClientRequest } from '@lib/utils/useClientRequest'
import client from '@lib/client'
@@ -34,6 +34,8 @@ export interface IPlanDetailProps {
query: IQuery
}
+const STMT_DETAIL_PLAN_EXPAND = 'statement.detail_plan_expand'
+
function PlanDetail({ query }: IPlanDetailProps) {
const { t } = useTranslation()
const { data, isLoading, error } = useClientRequest((reqConfig) =>
@@ -48,11 +50,22 @@ function PlanDetail({ query }: IPlanDetailProps) {
reqConfig
)
)
- const { state: sqlExpanded, toggle: toggleSqlExpanded } = useToggle(false)
- const { state: prevSqlExpanded, toggle: togglePrevSqlExpanded } = useToggle(
- false
+
+ const [detailExpand, setDetailExpand] = useLocalStorageState(
+ STMT_DETAIL_PLAN_EXPAND,
+ {
+ prev_query: false,
+ query: false,
+ plan: false,
+ }
)
- const { state: planExpanded, toggle: togglePlanExpanded } = useToggle(false)
+
+ const togglePrevQuery = () =>
+ setDetailExpand((prev) => ({ ...prev, prev_query: !prev.prev_query }))
+ const toggleQuery = () =>
+ setDetailExpand((prev) => ({ ...prev, query: !prev.query }))
+ const togglePlan = () =>
+ setDetailExpand((prev) => ({ ...prev, plan: !prev.plan }))
let title_key
if (query.allPlans === 1) {
@@ -62,7 +75,6 @@ function PlanDetail({ query }: IPlanDetailProps) {
} else {
title_key = 'some'
}
-
return (
toggleSqlExpanded()}
+ expanded={detailExpand.query}
+ onClick={toggleQuery}
/>
}
>
}
@@ -100,20 +112,20 @@ function PlanDetail({ query }: IPlanDetailProps) {
{data.prev_sample_text ? (
togglePrevSqlExpanded()}
+ expanded={detailExpand.prev_query}
+ onClick={togglePrevQuery}
/>
}
>
}
@@ -124,19 +136,19 @@ function PlanDetail({ query }: IPlanDetailProps) {
) : null}
togglePlanExpanded()}
+ expanded={detailExpand.plan}
+ onClick={togglePlan}
/>
}
>
-
+
{data.plan}
diff --git a/ui/lib/apps/Statement/pages/Detail/index.tsx b/ui/lib/apps/Statement/pages/Detail/index.tsx
index 858747e8b0..8f97175764 100644
--- a/ui/lib/apps/Statement/pages/Detail/index.tsx
+++ b/ui/lib/apps/Statement/pages/Detail/index.tsx
@@ -5,7 +5,7 @@ import React, { useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Link, useLocation } from 'react-router-dom'
import { ArrowLeftOutlined } from '@ant-design/icons'
-import { useToggle } from '@umijs/hooks'
+import { useLocalStorageState } from '@umijs/hooks'
import client, { StatementModel } from '@lib/client'
import {
@@ -13,11 +13,11 @@ import {
CardTable,
DateTime,
Descriptions,
+ ErrorBar,
Expand,
Head,
HighlightSQL,
TextWithInfo,
- ErrorBar,
} from '@lib/components'
import CopyLink from '@lib/components/CopyLink'
import formatSql from '@lib/utils/formatSql'
@@ -34,6 +34,8 @@ export interface IPageQuery {
endTime?: number
}
+const STMT_DETAIL_EXPAND = 'statement.detail_expand'
+
function DetailPage() {
const query = DetailPage.parseQuery(useLocation().search)
const { data: plans, isLoading, error } = useClientRequest((reqConfig) =>
@@ -60,7 +62,11 @@ function DetailPage() {
})
)
- const { state: sqlExpanded, toggle: toggleSqlExpanded } = useToggle(false)
+ const [sqlExpanded, setSqlExpanded] = useLocalStorageState(
+ STMT_DETAIL_EXPAND,
+ false
+ )
+ const toggleSqlExpanded = () => setSqlExpanded((prev) => !prev)
useEffect(() => {
if (plans && plans.length > 0) {
@@ -91,7 +97,7 @@ function DetailPage() {
toggleSqlExpanded()}
+ onClick={toggleSqlExpanded}
/>
diff --git a/ui/lib/apps/Statement/utils/tableColumns.tsx b/ui/lib/apps/Statement/utils/tableColumns.tsx
index ea901ead38..94bdab4875 100644
--- a/ui/lib/apps/Statement/utils/tableColumns.tsx
+++ b/ui/lib/apps/Statement/utils/tableColumns.tsx
@@ -10,9 +10,9 @@ import { orange, red } from '@ant-design/colors'
import { StatementModel } from '@lib/client'
import { Bar, Pre } from '@lib/components'
import {
- TableColumnFactory,
formatVal,
- IColumnWithSourceFields,
+ genDerivedBarSources,
+ TableColumnFactory,
} from '@lib/utils/tableColumnFactory'
///////////////////////////////////////
@@ -20,27 +20,76 @@ import {
// slow query order list in backend by key of IColumn
const TRANS_KEY_PREFIX = 'statement.fields'
+export const derivedFields = {
+ avg_latency: genDerivedBarSources(
+ 'avg_latency',
+ 'max_latency',
+ 'min_latency'
+ ),
+ parse_latency: genDerivedBarSources('avg_parse_latency', 'max_parse_latency'),
+ compile_latency: genDerivedBarSources(
+ 'avg_compile_latency',
+ 'max_compile_latency'
+ ),
+ process_time: genDerivedBarSources(
+ 'avg_cop_process_time',
+ 'max_cop_process_time'
+ ),
+ wait_time: genDerivedBarSources('avg_cop_wait_time', 'max_cop_wait_time'),
+ total_process_time: genDerivedBarSources(
+ 'avg_process_time',
+ 'max_process_time'
+ ),
+ total_wait_time: genDerivedBarSources('avg_wait_time', 'max_wait_time'),
+ backoff_time: genDerivedBarSources('avg_backoff_time', 'max_backoff_time'),
+ avg_write_keys: genDerivedBarSources('avg_write_keys', 'max_write_keys'),
+ avg_processed_keys: genDerivedBarSources(
+ 'avg_processed_keys',
+ 'max_processed_keys'
+ ),
+ avg_total_keys: genDerivedBarSources('avg_total_keys', 'max_total_keys'),
+ prewrite_time: genDerivedBarSources('avg_prewrite_time', 'max_prewrite_time'),
+ commit_time: genDerivedBarSources('avg_commit_time', 'max_commit_time'),
+ get_commit_ts_time: genDerivedBarSources(
+ 'avg_get_commit_ts_time',
+ 'max_get_commit_ts_time'
+ ),
+ commit_backoff_time: genDerivedBarSources(
+ 'avg_commit_backoff_time',
+ 'max_commit_backoff_time'
+ ),
+ resolve_lock_time: genDerivedBarSources(
+ 'avg_resolve_lock_time',
+ 'max_resolve_lock_time'
+ ),
+ local_latch_wait_time: genDerivedBarSources(
+ 'avg_local_latch_wait_time',
+ 'max_local_latch_wait_time'
+ ),
+ avg_write_size: genDerivedBarSources('avg_write_size', 'max_write_size'),
+ avg_prewrite_regions: genDerivedBarSources(
+ 'avg_prewrite_regions',
+ 'max_prewrite_regions'
+ ),
+ avg_txn_retry: genDerivedBarSources('avg_txn_retry', 'max_txn_retry'),
+ avg_mem: genDerivedBarSources('avg_mem', 'max_mem'),
+ sum_errors: ['sum_errors', 'sum_warnings'],
+ related_schemas: ['table_names'],
+}
+
+//////////////////////////////////////////
+
function avgMinMaxLatencyColumn(
tcf: TableColumnFactory,
rows?: { max_latency?: number; min_latency?: number; avg_latency?: number }[]
): IColumn {
- return tcf.bar.multiple(
- {
- bars: [
- { mean: 'avg_latency' },
- { max: 'max_latency' },
- { min: 'min_latency' },
- ],
- },
- 'ns',
- rows
- )
+ return tcf.bar.multiple({ sources: derivedFields.avg_latency }, 'ns', rows)
}
function errorsWarningsColumn(
tcf: TableColumnFactory,
rows?: { sum_errors?: number; sum_warnings?: number }[]
-): IColumnWithSourceFields {
+): IColumn {
const capacity = rows
? max(rows.map((v) => v.sum_errors! + v.sum_warnings!)) ?? 0
: 0
@@ -49,7 +98,6 @@ function errorsWarningsColumn(
name: tcf.columnName('errors_warnings'),
key,
fieldName: key,
- sourceFields: ['sum_errors', 'sum_warnings'],
minWidth: 140,
maxWidth: 200,
columnActionsMode: ColumnActionsMode.clickable,
@@ -80,8 +128,6 @@ Warnings: ${warningsFmtVal}`
function avgMaxColumn(
tcf: TableColumnFactory,
- avgKey: keyof T,
- maxKey: keyof T,
displayTransKey: string,
unit: string,
rows?: T[]
@@ -89,7 +135,7 @@ function avgMaxColumn(
return tcf.bar.multiple(
{
displayTransKey,
- bars: [{ mean: avgKey }, { max: maxKey }],
+ sources: derivedFields[displayTransKey],
},
unit,
rows
@@ -101,7 +147,7 @@ function avgMaxColumn(
export function statementColumns(
rows: StatementModel[],
showFullSQL?: boolean
-): IColumnWithSourceFields[] {
+): IColumn[] {
const tcf = new TableColumnFactory(TRANS_KEY_PREFIX)
return [
@@ -116,161 +162,28 @@ export function statementColumns(
maxWidth: 300,
columnActionsMode: ColumnActionsMode.clickable,
},
- avgMaxColumn(tcf, 'avg_mem', 'max_mem', 'avg_mem', 'bytes', rows),
+ avgMaxColumn(tcf, 'avg_mem', 'bytes', rows),
errorsWarningsColumn(tcf, rows),
- avgMaxColumn(
- tcf,
- 'avg_parse_latency',
- 'max_parse_latency',
- 'parse_latency',
- 'ns',
- rows
- ),
- avgMaxColumn(
- tcf,
- 'avg_compile_latency',
- 'max_compile_latency',
- 'compile_latency',
- 'ns',
- rows
- ),
+ avgMaxColumn(tcf, 'parse_latency', 'ns', rows),
+ avgMaxColumn(tcf, 'compile_latency', 'ns', rows),
tcf.bar.single('sum_cop_task_num', 'short', rows),
- avgMaxColumn(
- tcf,
- 'avg_cop_process_time',
- 'max_cop_process_time',
- 'process_time',
- 'ns',
- rows
- ),
- avgMaxColumn(
- tcf,
- 'avg_cop_wait_time',
- 'max_cop_wait_time',
- 'wait_time',
- 'ns',
- rows
- ),
- avgMaxColumn(
- tcf,
- 'avg_process_time',
- 'max_process_time',
- 'total_process_time',
- 'ns',
- rows
- ),
- avgMaxColumn(
- tcf,
- 'avg_wait_time',
- 'max_wait_time',
- 'total_wait_time',
- 'ns',
- rows
- ),
- avgMaxColumn(
- tcf,
- 'avg_backoff_time',
- 'max_backoff_time',
- 'backoff_time',
- 'ns',
- rows
- ),
- avgMaxColumn(
- tcf,
- 'avg_write_keys',
- 'max_write_keys',
- 'avg_write_keys',
- 'short',
- rows
- ),
- avgMaxColumn(
- tcf,
- 'avg_processed_keys',
- 'max_processed_keys',
- 'avg_processed_keys',
- 'short',
- rows
- ),
- avgMaxColumn(
- tcf,
- 'avg_total_keys',
- 'max_total_keys',
- 'avg_total_keys',
- 'short',
- rows
- ),
- avgMaxColumn(
- tcf,
- 'avg_prewrite_time',
- 'max_prewrite_time',
- 'prewrite_time',
- 'ns',
- rows
- ),
- avgMaxColumn(
- tcf,
- 'avg_commit_time',
- 'max_commit_time',
- 'commit_time',
- 'ns',
- rows
- ),
- avgMaxColumn(
- tcf,
- 'avg_get_commit_ts_time',
- 'max_get_commit_ts_time',
- 'get_commit_ts_time',
- 'ns',
- rows
- ),
- avgMaxColumn(
- tcf,
- 'avg_commit_backoff_time',
- 'max_commit_backoff_time',
- 'commit_backoff_time',
- 'ns',
- rows
- ),
- avgMaxColumn(
- tcf,
- 'avg_resolve_lock_time',
- 'max_resolve_lock_time',
- 'resolve_lock_time',
- 'ns',
- rows
- ),
- avgMaxColumn(
- tcf,
- 'avg_local_latch_wait_time',
- 'max_local_latch_wait_time',
- 'local_latch_wait_time',
- 'ns',
- rows
- ),
- avgMaxColumn(
- tcf,
- 'avg_write_size',
- 'max_write_size',
- 'avg_write_size',
- 'bytes',
- rows
- ),
- avgMaxColumn(
- tcf,
- 'avg_prewrite_regions',
- 'max_prewrite_regions',
- 'avg_prewrite_regions',
- 'short',
- rows
- ),
- avgMaxColumn(
- tcf,
- 'avg_txn_retry',
- 'max_txn_retry',
- 'avg_txn_retry',
- 'short',
- rows
- ),
+ avgMaxColumn(tcf, 'process_time', 'ns', rows),
+ avgMaxColumn(tcf, 'wait_time', 'ns', rows),
+ avgMaxColumn(tcf, 'total_process_time', 'ns', rows),
+ avgMaxColumn(tcf, 'total_wait_time', 'ns', rows),
+ avgMaxColumn(tcf, 'backoff_time', 'ns', rows),
+ avgMaxColumn(tcf, 'avg_write_keys', 'short', rows),
+ avgMaxColumn(tcf, 'avg_processed_keys', 'short', rows),
+ avgMaxColumn(tcf, 'avg_total_keys', 'short', rows),
+ avgMaxColumn(tcf, 'prewrite_time', 'ns', rows),
+ avgMaxColumn(tcf, 'commit_time', 'ns', rows),
+ avgMaxColumn(tcf, 'get_commit_ts_time', 'ns', rows),
+ avgMaxColumn(tcf, 'commit_backoff_time', 'ns', rows),
+ avgMaxColumn(tcf, 'resolve_lock_time', 'ns', rows),
+ avgMaxColumn(tcf, 'local_latch_wait_time', 'ns', rows),
+ avgMaxColumn(tcf, 'avg_write_size', 'bytes', rows),
+ avgMaxColumn(tcf, 'avg_prewrite_regions', 'short', rows),
+ avgMaxColumn(tcf, 'avg_txn_retry', 'short', rows),
tcf.bar.single('sum_backoff_times', 'short', rows),
tcf.bar.single('avg_affected_rows', 'short', rows),
@@ -292,7 +205,6 @@ export function statementColumns(
...tcf.textWithTooltip('related_schemas', rows),
minWidth: 160,
maxWidth: 240,
- sourceFields: ['table_names'],
},
]
}
@@ -309,6 +221,6 @@ export function planColumns(rows: StatementModel[]): IColumn[] {
tcf.bar.single('sum_latency', 'ns', rows),
avgMinMaxLatencyColumn(tcf, rows),
tcf.bar.single('exec_count', 'short', rows),
- avgMaxColumn(tcf, 'avg_mem', 'max_mem', 'avg_mem', 'bytes', rows),
+ avgMaxColumn(tcf, 'avg_mem', 'bytes', rows),
]
}
diff --git a/ui/lib/apps/Statement/utils/useStatementTableController.ts b/ui/lib/apps/Statement/utils/useStatementTableController.ts
index 876549dc02..ddfbf41b0d 100644
--- a/ui/lib/apps/Statement/utils/useStatementTableController.ts
+++ b/ui/lib/apps/Statement/utils/useStatementTableController.ts
@@ -15,7 +15,7 @@ import {
DEFAULT_TIME_RANGE,
TimeRange,
} from '../pages/List/TimeRangeSelector'
-import { statementColumns } from './tableColumns'
+import { derivedFields, statementColumns } from './tableColumns'
import { getSelectedFields } from '@lib/utils/tableColumnFactory'
export const DEF_STMT_COLUMN_KEYS: IColumnKeys = {
@@ -174,18 +174,16 @@ export default function useStatementTableController(
queryStmtTypes()
}, [refreshTimes])
- // Notice: statements, tableColumns, selectedFields make loop dependencies
+ const selectedFields = useMemo(
+ () => getSelectedFields(visibleColumnKeys, derivedFields).join(','),
+ [visibleColumnKeys]
+ )
+
const tableColumns = useMemo(
() => statementColumns(statements, showFullSQL),
[statements, showFullSQL]
)
- // make selectedFields as a string instead of an array to avoid infinite loop
- // I have verified that it will cause infinite loop if we return selectedFields as an array
- // so it is better to use the basic type (string, number...) instead of object as the dependency
- const selectedFields = useMemo(
- () => getSelectedFields(visibleColumnKeys, tableColumns).join(','),
- [visibleColumnKeys, tableColumns]
- )
+
useEffect(() => {
async function queryStatementList() {
if (allTimeRanges.length === 0) {
diff --git a/ui/lib/utils/tableColumnFactory.tsx b/ui/lib/utils/tableColumnFactory.tsx
index ba43d41ba7..9abb88f56a 100644
--- a/ui/lib/utils/tableColumnFactory.tsx
+++ b/ui/lib/utils/tableColumnFactory.tsx
@@ -17,15 +17,17 @@ import {
IColumnKeys,
} from '@lib/components'
-type Bar = { [key: string]: keyof T }
-type BarsConfig = {
+export type DerivedField = {
displayTransKey?: string // it is same as avg field name default
- bars: [Bar, Bar, Bar?] // [avg, max, min?]
+ sources: T[]
}
-export type IColumnWithSourceFields = IColumn & {
- sourceFields?: string[]
-}
+export type DerivedBar = DerivedField<{
+ tooltipPrefix: string
+ fieldName: string
+}>
+
+export type DerivedCol = DerivedField
export function formatVal(val: number, unit: string, decimals: number = 1) {
const formatFn = getValueFormat(unit)
@@ -61,7 +63,7 @@ export class TableColumnFactory {
textWithTooltip(
fieldName: T,
_rows?: U[]
- ): IColumnWithSourceFields {
+ ): IColumn {
return {
...this.columnFromField(fieldName),
minWidth: 100,
@@ -78,7 +80,7 @@ export class TableColumnFactory {
fieldName: T,
unit: string,
rows?: U[]
- ): IColumnWithSourceFields {
+ ): IColumn {
const capacity = rows ? _max(rows.map((v) => v[fieldName])) ?? 0 : 0
return {
...this.columnFromField(fieldName),
@@ -96,48 +98,27 @@ export class TableColumnFactory {
}
}
- multipleBar(
- barsConfig: BarsConfig,
- unit: string,
- rows?: T[]
- ): IColumnWithSourceFields {
+ multipleBar(barsConfig: DerivedBar, unit: string, rows?: T[]): IColumn {
const {
displayTransKey,
- bars: [avg_, max_, min_],
+ sources: [avg, max, min],
} = barsConfig
- const tooltioPrefixLens: number[] = []
- const avg = {
- fieldName: Object.values(avg_)[0],
- tooltipPrefix: Object.keys(avg_)[0],
- }
- tooltioPrefixLens.push(avg.tooltipPrefix.length)
- const max = {
- fieldName: Object.values(max_)[0],
- tooltipPrefix: Object.keys(max_)[0],
- }
- tooltioPrefixLens.push(max.tooltipPrefix.length)
- let min
- if (min_) {
- min = {
- fieldName: Object.values(min_)[0],
- tooltipPrefix: Object.keys(min_)[0],
- }
- tooltioPrefixLens.push(min.tooltipPrefix.length)
- } else {
- min = undefined
- }
- const maxTooltipPrefixLen = _max(tooltioPrefixLens) || 0
+ const tooltipPrefixLens: number[] = []
- const capacity = rows ? _max(rows.map((v) => v[max.fieldName])) ?? 0 : 0
- let sourceFields = [avg.fieldName, max.fieldName] as string[]
+ tooltipPrefixLens.push(avg.tooltipPrefix.length)
+ tooltipPrefixLens.push(max.tooltipPrefix.length)
if (min) {
- sourceFields.push(min.fieldName)
+ tooltipPrefixLens.push(min.tooltipPrefix.length)
}
+
+ const maxTooltipPrefixLen = _max(tooltipPrefixLens) || 0
+
+ const capacity = rows ? _max(rows.map((v) => v[max.fieldName])) ?? 0 : 0
+
return {
- ...this.columnFromField(avg.fieldName as string),
- name: this.columnName((displayTransKey || avg.fieldName) as string),
- sourceFields,
+ ...this.columnFromField(avg.fieldName),
+ name: this.columnName(displayTransKey || avg.fieldName),
minWidth: 140,
maxWidth: 200,
columnActionsMode: ColumnActionsMode.clickable,
@@ -175,7 +156,7 @@ export class TableColumnFactory {
timestamp(
fieldName: T,
_rows?: U[]
- ): IColumnWithSourceFields {
+ ): IColumn {
return {
...this.columnFromField(fieldName),
minWidth: 100,
@@ -193,7 +174,7 @@ export class TableColumnFactory {
fieldName: T,
showFullSQL?: boolean,
_rows?: U[]
- ): IColumnWithSourceFields {
+ ): IColumn {
return {
...this.columnFromField(fieldName),
minWidth: 100,
@@ -229,26 +210,64 @@ export class BarColumn {
return this.factory.singleBar(fieldName, unit, rows)
}
- multiple(bars: BarsConfig, unit: string, rows?: T[]) {
+ multiple(bars: DerivedBar, unit: string, rows?: T[]) {
return this.factory.multipleBar(bars, unit, rows)
}
}
////////////////////////////////////////////
+export type DerivedFields = Record<
+ string,
+ DerivedBar['sources'] | DerivedCol['sources']
+>
+
+export function genDerivedBarSources(
+ avg: string,
+ max: string,
+ min?: string
+): DerivedBar['sources'] {
+ const res = [
+ {
+ tooltipPrefix: 'mean',
+ fieldName: avg,
+ },
+ {
+ tooltipPrefix: 'max',
+ fieldName: max,
+ },
+ ]
+ if (min) {
+ res.push({
+ tooltipPrefix: 'min',
+ fieldName: min,
+ })
+ }
+ return res
+}
+
+function isDerivedBarSources(v: any): v is DerivedBar['sources'] {
+ return !!v[0].fieldName
+}
+
export function getSelectedFields(
visibleColumnKeys: IColumnKeys,
- columns: IColumnWithSourceFields[]
+ derivedFields: DerivedFields
) {
let fields: string[] = []
- columns.forEach((c) => {
- if (visibleColumnKeys[c.key] === true) {
- if (c.sourceFields !== undefined) {
- fields = fields.concat(c.sourceFields)
+ let sources: DerivedFields[keyof DerivedFields]
+ for (const columnKey in visibleColumnKeys) {
+ if (visibleColumnKeys[columnKey]) {
+ if ((sources = derivedFields[columnKey])) {
+ if (isDerivedBarSources(sources)) {
+ fields.push(...sources.map((b) => b.fieldName))
+ } else {
+ fields.push(...sources)
+ }
} else {
- fields.push(c.key)
+ fields.push(columnKey)
}
}
- })
+ }
return fields
}