From 3c69908f547082c7b9e0d0822c3a59add90cf157 Mon Sep 17 00:00:00 2001 From: Duyet Le Date: Sun, 24 Nov 2024 22:02:49 +0700 Subject: [PATCH] feat: query detail page --- app/[host]/[query]/queries/history-queries.ts | 3 + app/[host]/[query]/queries/running-queries.ts | 9 + .../[cluster]/count-across-replicas/page.tsx | 4 +- .../[cluster]/parts-across-replicas/page.tsx | 1 + .../[cluster]/replicas-status/page.tsx | 1 + app/[host]/clusters/config.ts | 4 +- app/[host]/clusters/page.tsx | 9 +- .../[database]/[table]/@mergetree/page.tsx | 3 +- .../[database]/[table]/extras/extras.tsx | 4 +- .../top-usage-columns-button.tsx} | 3 +- app/[host]/database/[database]/default.tsx | 5 +- app/[host]/database/[database]/page.tsx | 1 + app/[host]/query/[query_id]/config.ts | 186 ++++++++++ app/[host]/query/[query_id]/page.tsx | 43 +++ app/[host]/query/[query_id]/query-detail.tsx | 351 ++++++++++++++++++ app/[host]/query/[query_id]/types.ts | 6 + app/[host]/replica/[replica]/tables/page.tsx | 1 + app/globals.css | 1 - .../data-table/cells/link-format.cy.tsx | 135 ++++++- components/data-table/cells/link-format.tsx | 17 +- components/data-table/column-defs.tsx | 6 +- components/data-table/data-table-toolbar.tsx | 2 +- components/data-table/data-table.cy.tsx | 43 ++- components/data-table/data-table.tsx | 16 +- components/data-table/format-cell.tsx | 7 +- components/table.tsx | 2 + components/truncated-list.cy.tsx | 62 ++++ components/truncated-list.tsx | 34 ++ components/truncated-paragraph.cy.tsx | 49 +++ components/truncated-paragraph.tsx | 65 ++++ lib/format-readable.ts | 1 - types/column-format.ts | 7 +- 32 files changed, 1041 insertions(+), 40 deletions(-) rename app/[host]/database/[database]/[table]/{@mergetree/toolbar.tsx => extras/top-usage-columns-button.tsx} (90%) create mode 100644 app/[host]/query/[query_id]/config.ts create mode 100644 app/[host]/query/[query_id]/page.tsx create mode 100644 app/[host]/query/[query_id]/query-detail.tsx create mode 100644 app/[host]/query/[query_id]/types.ts create mode 100644 components/truncated-list.cy.tsx create mode 100644 components/truncated-list.tsx create mode 100644 components/truncated-paragraph.cy.tsx create mode 100644 components/truncated-paragraph.tsx diff --git a/app/[host]/[query]/queries/history-queries.ts b/app/[host]/[query]/queries/history-queries.ts index 1580a970..6a239df9 100644 --- a/app/[host]/[query]/queries/history-queries.ts +++ b/app/[host]/[query]/queries/history-queries.ts @@ -36,6 +36,7 @@ export const historyQueriesConfig: QueryConfig = { AND if ({duration_1m: String} = '1', query_duration >= 60, true) AND if (notEmpty({event_time: String}), toDate(event_time) = {event_time: String}, true) AND if ({database: String} != '' AND {table: String} != '', has(tables, format('{}.{}', {database: String}, {table: String})), true) + AND if ({user: String} != '', user = {user: String}, true) ORDER BY event_time DESC LIMIT 1000 `, @@ -68,6 +69,7 @@ export const historyQueriesConfig: QueryConfig = { readable_read_rows: ColumnFormat.BackgroundBar, readable_written_rows: ColumnFormat.BackgroundBar, readable_memory_usage: ColumnFormat.BackgroundBar, + query_id: [ColumnFormat.Link, { href: '/[ctx.hostId]/query/[query_id]' }], }, defaultParams: { @@ -76,6 +78,7 @@ export const historyQueriesConfig: QueryConfig = { event_time: '', database: '', table: '', + user: '', }, filterParamPresets: [ diff --git a/app/[host]/[query]/queries/running-queries.ts b/app/[host]/[query]/queries/running-queries.ts index 726209c5..e8900353 100644 --- a/app/[host]/[query]/queries/running-queries.ts +++ b/app/[host]/[query]/queries/running-queries.ts @@ -5,6 +5,7 @@ export const runningQueriesConfig: QueryConfig = { name: 'running-queries', sql: ` SELECT *, + query_id as query_detail, multiIf (elapsed < 30, format('{} seconds', round(elapsed, 1)), elapsed < 90, 'a minute', formatReadableTimeDelta(elapsed, 'days', 'minutes')) as readable_elapsed, @@ -38,6 +39,7 @@ export const runningQueriesConfig: QueryConfig = { `, columns: [ 'query', + 'query_detail', 'user', 'readable_memory_usage', 'readable_elapsed', @@ -66,6 +68,13 @@ export const runningQueriesConfig: QueryConfig = { ], user: ColumnFormat.ColoredBadge, estimated_remaining_time: ColumnFormat.Duration, + query_detail: [ + ColumnFormat.Link, + { + href: '/[ctx.hostId]/query/[query_id]', + className: 'truncate max-w-48 text-wrap', + }, + ], query_id: [ ColumnFormat.Action, ['kill-query', 'explain-query', 'query-settings'], diff --git a/app/[host]/clusters/[cluster]/count-across-replicas/page.tsx b/app/[host]/clusters/[cluster]/count-across-replicas/page.tsx index cd59d9f2..eb79a184 100644 --- a/app/[host]/clusters/[cluster]/count-across-replicas/page.tsx +++ b/app/[host]/clusters/[cluster]/count-across-replicas/page.tsx @@ -1,5 +1,6 @@ import { DataTable } from '@/components/data-table/data-table' import { fetchData } from '@/lib/clickhouse' +import { getHostIdCookie } from '@/lib/scoped-link' import { ColumnFormat } from '@/types/column-format' import { type QueryConfig } from '@/types/query-config' @@ -45,7 +46,7 @@ export default async function Page({ params }: PageProps) { columnFormats: { database_table: [ ColumnFormat.Link, - { href: `/database/[database]/[table]` }, + { href: `/[ctx.hostId]/database/[database]/[table]` }, ], ...replicas .map(({ replica }) => ({ @@ -70,6 +71,7 @@ export default async function Page({ params }: PageProps) { title={`Total rows of active parts across replicas in the '${cluster}' cluster`} queryConfig={queryConfig} data={data} + context={{ hostId: '' + (await getHostIdCookie()) }} /> ) } diff --git a/app/[host]/clusters/[cluster]/parts-across-replicas/page.tsx b/app/[host]/clusters/[cluster]/parts-across-replicas/page.tsx index 04f80f6c..24114977 100644 --- a/app/[host]/clusters/[cluster]/parts-across-replicas/page.tsx +++ b/app/[host]/clusters/[cluster]/parts-across-replicas/page.tsx @@ -62,6 +62,7 @@ export default async function Page({ params }: PageProps) { title={`Count of active parts across replicas in the '${cluster}' cluster`} queryConfig={queryConfig} data={data} + context={{}} /> ) } diff --git a/app/[host]/clusters/[cluster]/replicas-status/page.tsx b/app/[host]/clusters/[cluster]/replicas-status/page.tsx index 456dea21..3c9aab09 100644 --- a/app/[host]/clusters/[cluster]/replicas-status/page.tsx +++ b/app/[host]/clusters/[cluster]/replicas-status/page.tsx @@ -25,6 +25,7 @@ export default async function Page({ params }: PageProps) { title={`Row counts across '${cluster}' cluster`} queryConfig={queryConfig} data={data} + context={{ cluster }} topRightToolbarExtras={} /> ) diff --git a/app/[host]/clusters/config.ts b/app/[host]/clusters/config.ts index c99bb70b..e61e9070 100644 --- a/app/[host]/clusters/config.ts +++ b/app/[host]/clusters/config.ts @@ -23,10 +23,10 @@ export const queryConfig: QueryConfig = { `, columns: ['cluster', 'shard_count', 'replica_count', 'replica_status'], columnFormats: { - cluster: [ColumnFormat.Link, { href: `/clusters/[cluster]` }], + cluster: [ColumnFormat.Link, { href: `/[ctx.hostId]/clusters/[cluster]` }], replica_status: [ ColumnFormat.Link, - { href: `/clusters/[cluster]/replicas-status` }, + { href: `/[ctx.hostId]/clusters/[cluster]/replicas-status` }, ], }, } diff --git a/app/[host]/clusters/page.tsx b/app/[host]/clusters/page.tsx index caec5efd..ba200e2b 100644 --- a/app/[host]/clusters/page.tsx +++ b/app/[host]/clusters/page.tsx @@ -1,6 +1,7 @@ import { DataTable } from '@/components/data-table/data-table' import { fetchData } from '@/lib/clickhouse' +import { getHostIdCookie } from '@/lib/scoped-link' import { queryConfig, type Row } from './config' export const dynamic = 'force-dynamic' @@ -8,5 +9,11 @@ export const dynamic = 'force-dynamic' export default async function ClustersPage() { const { data } = await fetchData({ query: queryConfig.sql }) - return + return ( + + ) } diff --git a/app/[host]/database/[database]/[table]/@mergetree/page.tsx b/app/[host]/database/[database]/[table]/@mergetree/page.tsx index 7d09e458..ae053707 100644 --- a/app/[host]/database/[database]/[table]/@mergetree/page.tsx +++ b/app/[host]/database/[database]/[table]/@mergetree/page.tsx @@ -5,7 +5,6 @@ import { fetchData } from '@/lib/clickhouse' import { queryConfig, type Row } from '../config' import { engineType } from '../engine-type' import { TableComment } from './table-comment' -import { Toolbar } from './toolbar' interface Props { params: Promise<{ @@ -34,9 +33,9 @@ export default async function MergeTree({ params }: Props) { title={`Table: ${database}.${table}`} description={} toolbarExtras={} - topRightToolbarExtras={} queryConfig={queryConfig} data={columns} + context={{ host: `${host}`, database, table }} /> ) } diff --git a/app/[host]/database/[database]/[table]/extras/extras.tsx b/app/[host]/database/[database]/[table]/extras/extras.tsx index b7bab363..acb1aa92 100644 --- a/app/[host]/database/[database]/[table]/extras/extras.tsx +++ b/app/[host]/database/[database]/[table]/extras/extras.tsx @@ -10,6 +10,7 @@ import { SampleDataButton } from './sample-data-button' import { ShowDDL } from './show-ddl-button' import { TableInfo } from './table-info' import { TableSelector } from './table-selector' +import { TopUsageColumnsButton } from './top-usage-columns-button' export const Extras = ({ host, @@ -20,7 +21,7 @@ export const Extras = ({ database: string table: string }) => ( -
+
) diff --git a/app/[host]/database/[database]/[table]/@mergetree/toolbar.tsx b/app/[host]/database/[database]/[table]/extras/top-usage-columns-button.tsx similarity index 90% rename from app/[host]/database/[database]/[table]/@mergetree/toolbar.tsx rename to app/[host]/database/[database]/[table]/extras/top-usage-columns-button.tsx index a9c60480..229e8ee2 100644 --- a/app/[host]/database/[database]/[table]/@mergetree/toolbar.tsx +++ b/app/[host]/database/[database]/[table]/extras/top-usage-columns-button.tsx @@ -4,7 +4,7 @@ import Link from 'next/link' import { Button } from '@/components/ui/button' import { getScopedLink } from '@/lib/scoped-link' -export async function Toolbar({ +export async function TopUsageColumnsButton({ database, table, }: { @@ -20,6 +20,7 @@ export async function Toolbar({