This is an automated email from the ASF dual-hosted git repository. vogievetsky pushed a commit to branch segment_timeline2 in repository https://gitbox.apache.org/repos/asf/druid.git
commit c89e0588747ec95eeda5ef64eac2242ef4ac075e Author: Vadim Ogievetsky <[email protected]> AuthorDate: Mon Oct 28 14:04:44 2024 -0700 improve segment view --- web-console/src/utils/table-helpers.ts | 11 +- .../src/views/segments-view/segments-view.tsx | 148 +++++++++++++-------- 2 files changed, 93 insertions(+), 66 deletions(-) diff --git a/web-console/src/utils/table-helpers.ts b/web-console/src/utils/table-helpers.ts index 45e8758bf6f..117b34f2d1a 100644 --- a/web-console/src/utils/table-helpers.ts +++ b/web-console/src/utils/table-helpers.ts @@ -18,7 +18,7 @@ import type { QueryResult, SqlExpression } from '@druid-toolkit/query'; import { C } from '@druid-toolkit/query'; -import type { Filter } from 'react-table'; +import type { Filter, SortingRule } from 'react-table'; import { filterMap, formatNumber, isNumberLike, oneOf } from './general'; import { deepSet } from './object-change'; @@ -67,19 +67,14 @@ export function getNumericColumnBraces( return numericColumnBraces; } -export interface Sorted { - id: string; - desc: boolean; -} - export interface TableState { page: number; pageSize: number; filtered: Filter[]; - sorted: Sorted[]; + sorted: SortingRule[]; } -export function sortedToOrderByClause(sorted: Sorted[]): string | undefined { +export function sortedToOrderByClause(sorted: SortingRule[]): string | undefined { if (!sorted.length) return; return 'ORDER BY ' + sorted.map(sort => `${C(sort.id)} ${sort.desc ? 'DESC' : 'ASC'}`).join(', '); } diff --git a/web-console/src/views/segments-view/segments-view.tsx b/web-console/src/views/segments-view/segments-view.tsx index 74373e097a7..18a44e66180 100644 --- a/web-console/src/views/segments-view/segments-view.tsx +++ b/web-console/src/views/segments-view/segments-view.tsx @@ -21,7 +21,7 @@ import { IconNames } from '@blueprintjs/icons'; import { C, L, SqlComparison, SqlExpression } from '@druid-toolkit/query'; import * as JSONBig from 'json-bigint-native'; import React from 'react'; -import type { Filter } from 'react-table'; +import type { Filter, SortingRule } from 'react-table'; import ReactTable from 'react-table'; import { @@ -127,6 +127,43 @@ function formatRangeDimensionValue(dimension: any, value: any): string { return `${C(String(dimension))}=${L(String(value))}`; } +function segmentFiltersToExpression(filters: Filter[]): SqlExpression { + return SqlExpression.and( + ...filterMap(filters, filter => { + if (filter.id === 'shard_type') { + // Special handling for shard_type that needs to be searched for in the shard_spec + // Creates filters like `shard_spec LIKE '%"type":"numbered"%'` + const modeAndNeedle = parseFilterModeAndNeedle(filter); + if (!modeAndNeedle) return; + const shardSpecColumn = C('shard_spec'); + switch (modeAndNeedle.mode) { + case '=': + return SqlComparison.like(shardSpecColumn, `%"type":"${modeAndNeedle.needle}"%`); + + case '!=': + return SqlComparison.notLike(shardSpecColumn, `%"type":"${modeAndNeedle.needle}"%`); + + default: + return SqlComparison.like(shardSpecColumn, `%"type":"${modeAndNeedle.needle}%`); + } + } else if (filter.id.startsWith('is_')) { + switch (filter.value) { + case '=false': + return C(filter.id).equal(0); + + case '=true': + return C(filter.id).equal(1); + + default: + return; + } + } else { + return sqlQueryCustomTableFilter(filter); + } + }), + ); +} + interface SegmentsQuery extends TableState { visibleColumns: LocalStorageBackedVisibility; capabilities: Capabilities; @@ -167,11 +204,16 @@ export interface SegmentsViewState { segmentTableActionDialogId?: string; datasourceTableActionDialogId?: string; actions: BasicAction[]; - terminateSegmentId?: string; - terminateDatasourceId?: string; + visibleColumns: LocalStorageBackedVisibility; groupByInterval: boolean; showSegmentTimeline: boolean; + page: number; + pageSize: number; + sorted: SortingRule[]; + + terminateSegmentId?: string; + terminateDatasourceId?: string; showFullShardSpec?: string; } @@ -237,8 +279,6 @@ END AS "time_span"`, private readonly segmentsQueryManager: QueryManager<SegmentsQuery, SegmentQueryResultRow[]>; - private lastTableState: TableState | undefined; - constructor(props: SegmentsViewProps) { super(props); @@ -251,6 +291,13 @@ END AS "time_span"`, ), groupByInterval: false, showSegmentTimeline: false, + page: 0, + pageSize: STANDARD_TABLE_PAGE_SIZE, + sorted: [ + props.capabilities.hasSql() + ? { id: 'start', desc: true } + : { id: 'datasource', desc: false }, + ], }; this.segmentsQueryManager = new QueryManager({ @@ -259,48 +306,16 @@ END AS "time_span"`, const { page, pageSize, filtered, sorted, visibleColumns, capabilities, groupByInterval } = query; - if (capabilities.hasSql()) { - const whereParts = filterMap(filtered, (f: Filter) => { - if (f.id === 'shard_type') { - // Special handling for shard_type that needs to be searched for in the shard_spec - // Creates filters like `shard_spec LIKE '%"type":"numbered"%'` - const modeAndNeedle = parseFilterModeAndNeedle(f); - if (!modeAndNeedle) return; - const shardSpecColumn = C('shard_spec'); - switch (modeAndNeedle.mode) { - case '=': - return SqlComparison.like(shardSpecColumn, `%"type":"${modeAndNeedle.needle}"%`); - - case '!=': - return SqlComparison.notLike( - shardSpecColumn, - `%"type":"${modeAndNeedle.needle}"%`, - ); - - default: - return SqlComparison.like(shardSpecColumn, `%"type":"${modeAndNeedle.needle}%`); - } - } else if (f.id.startsWith('is_')) { - switch (f.value) { - case '=false': - return C(f.id).equal(0); - - case '=true': - return C(f.id).equal(1); + console.log('run', filtered); - default: - return; - } - } else { - return sqlQueryCustomTableFilter(f); - } - }); + if (capabilities.hasSql()) { + const whereExpression = segmentFiltersToExpression(filtered); let queryParts: string[]; let filterClause = ''; - if (whereParts.length) { - filterClause = SqlExpression.and(...whereParts).toString(); + if (whereExpression.toString() !== 'TRUE') { + filterClause = whereExpression.toString(); } let effectiveSorted = sorted; @@ -440,20 +455,38 @@ END AS "time_span"`, }); } + componentDidMount() { + this.fetchData(); + } + componentWillUnmount(): void { this.segmentsQueryManager.terminate(); } - private readonly fetchData = (groupByInterval: boolean, tableState?: TableState) => { - const { capabilities } = this.props; - const { visibleColumns } = this.state; - if (tableState) this.lastTableState = tableState; - if (!this.lastTableState) return; - const { page, pageSize, filtered, sorted } = this.lastTableState; + componentDidUpdate( + prevProps: Readonly<SegmentsViewProps>, + prevState: Readonly<SegmentsViewState>, + ) { + const { filters } = this.props; + const { groupByInterval, page, pageSize, sorted } = this.state; + if ( + !segmentFiltersToExpression(filters).equals(segmentFiltersToExpression(prevProps.filters)) || + groupByInterval !== prevState.groupByInterval || + page !== prevState.page || + pageSize !== prevState.pageSize || + sortedToOrderByClause(sorted) !== sortedToOrderByClause(prevState.sorted) + ) { + this.fetchData(); + } + } + + private readonly fetchData = () => { + const { capabilities, filters } = this.props; + const { visibleColumns, groupByInterval, page, pageSize, sorted } = this.state; this.segmentsQueryManager.runQuery({ page, pageSize, - filtered, + filtered: filters, sorted, visibleColumns, capabilities, @@ -499,7 +532,7 @@ END AS "time_span"`, renderSegmentsTable() { const { capabilities, filters, onFiltersChange } = this.props; - const { segmentsState, visibleColumns, groupByInterval } = this.state; + const { segmentsState, visibleColumns, groupByInterval, page, pageSize, sorted } = this.state; const segments = segmentsState.data || []; @@ -532,14 +565,15 @@ END AS "time_span"`, filterable filtered={filters} onFilteredChange={onFiltersChange} - defaultSorted={[hasSql ? { id: 'start', desc: true } : { id: 'datasource', desc: false }]} - onFetchData={tableState => { - this.fetchData(groupByInterval, tableState); - }} + sorted={sorted} + onSortedChange={sorted => this.setState({ sorted })} showPageJump={false} ofText="" pivotBy={groupByInterval ? ['interval'] : []} - defaultPageSize={STANDARD_TABLE_PAGE_SIZE} + page={page} + onPageChange={page => this.setState({ page })} + pageSize={pageSize} + onPageSizeChange={pageSize => this.setState({ pageSize })} pageSizeOptions={STANDARD_TABLE_PAGE_SIZE_OPTIONS} showPagination columns={[ @@ -984,7 +1018,6 @@ END AS "time_span"`, active={!groupByInterval} onClick={() => { this.setState({ groupByInterval: false }); - this.fetchData(false); }} > None @@ -993,7 +1026,6 @@ END AS "time_span"`, active={groupByInterval} onClick={() => { this.setState({ groupByInterval: true }); - this.fetchData(true); }} > Interval @@ -1015,7 +1047,7 @@ END AS "time_span"`, } onClose={added => { if (!added) return; - this.fetchData(groupByInterval); + this.fetchData(); }} tableColumnsHidden={visibleColumns.getHiddenColumns()} /> --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
