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 f320470b244a5e4008c9c7cbd4db8bf58d608c0e
Author: Vadim Ogievetsky <[email protected]>
AuthorDate: Fri Nov 1 00:10:18 2024 -0700

    fix supervisor view
---
 .../segment-timeline/segment-bar-chart-render.tsx  | 34 +----------
 .../datasource/datasource.ts}                      | 57 +++++++++----------
 web-console/src/druid-models/index.ts              |  1 +
 web-console/src/react-table/react-table-utils.ts   |  7 ++-
 .../views/datasources-view/datasources-view.scss   |  7 +++
 .../views/datasources-view/datasources-view.tsx    | 16 ++++--
 .../src/views/segments-view/segments-view.tsx      | 42 ++++++++++----
 .../views/supervisors-view/supervisors-view.tsx    | 65 ++++++++++++++--------
 8 files changed, 128 insertions(+), 101 deletions(-)

diff --git 
a/web-console/src/components/segment-timeline/segment-bar-chart-render.tsx 
b/web-console/src/components/segment-timeline/segment-bar-chart-render.tsx
index 44407e22233..026b6e7d0d8 100644
--- a/web-console/src/components/segment-timeline/segment-bar-chart-render.tsx
+++ b/web-console/src/components/segment-timeline/segment-bar-chart-render.tsx
@@ -25,6 +25,7 @@ import { scaleLinear, scaleUtc } from 'd3-scale';
 import type React from 'react';
 import { useMemo, useRef, useState } from 'react';
 
+import { getDatasourceColor } from '../../druid-models';
 import { useGlobalEventListener } from '../../hooks';
 import {
   capitalizeFirst,
@@ -36,7 +37,6 @@ import {
   formatInteger,
   formatNumber,
   groupBy,
-  hashJoaat,
   prettyFormatIsoDate,
   TZ_UTC,
 } from '../../utils';
@@ -63,30 +63,6 @@ const POSSIBLE_GRANULARITIES = [
 const EXTEND_DATE_RANGE_BY = 0;
 const EXTEND_X_SCALE_DOMAIN_BY = 10;
 
-const COLORS = [
-  '#b33040',
-  '#d25c4d',
-  '#f2b447',
-  '#d9d574',
-  '#4FAA7E',
-  '#57ceff',
-  '#789113',
-  '#098777',
-  '#b33040',
-  '#d2757b',
-  '#f29063',
-  '#d9a241',
-  '#80aa61',
-  '#c4ff9e',
-  '#915412',
-  '#87606c',
-];
-
-const COLORIZER = ({ datasource }: IntervalBar) => {
-  const hash = hashJoaat(datasource);
-  return COLORS[hash % COLORS.length];
-};
-
 function offsetDateRange(dateRange: NonNullDateRange, offset: number): 
NonNullDateRange {
   return [new Date(dateRange[0].valueOf() + offset), new 
Date(dateRange[1].valueOf() + offset)];
 }
@@ -390,12 +366,8 @@ export const SegmentBarChartRender = function 
SegmentBarChartRender(
                   key={i}
                   className="bar-unit"
                   {...segmentBarToRect(intervalBar)}
-                  style={{ fill: COLORIZER(intervalBar) }}
-                  onClick={
-                    intervalBar.datasource
-                      ? () => changeFocusDatasource(intervalBar.datasource)
-                      : undefined
-                  }
+                  style={{ fill: getDatasourceColor(intervalBar.datasource) }}
+                  onClick={() => changeFocusDatasource(intervalBar.datasource)}
                   onMouseOver={() => {
                     if (mouseDownAt) return;
                     setHoverOn(intervalBar);
diff --git a/web-console/src/views/datasources-view/datasources-view.scss 
b/web-console/src/druid-models/datasource/datasource.ts
similarity index 59%
copy from web-console/src/views/datasources-view/datasources-view.scss
copy to web-console/src/druid-models/datasource/datasource.ts
index 1f9d9df328e..313d711b35c 100644
--- a/web-console/src/views/datasources-view/datasources-view.scss
+++ b/web-console/src/druid-models/datasource/datasource.ts
@@ -16,37 +16,32 @@
  * limitations under the License.
  */
 
-@import '../../variables';
+import { hashJoaat } from '../../utils';
 
-.datasources-view {
-  height: 100%;
-  width: 100%;
-  overflow: auto;
+const COLORS = [
+  '#1f77b4',
+  '#aec7e8',
+  '#ff7f0e',
+  '#ffbb78',
+  '#2ca02c',
+  '#98df8a',
+  '#d62728',
+  '#ff9896',
+  '#9467bd',
+  '#c5b0d5',
+  '#8c564b',
+  '#c49c94',
+  '#e377c2',
+  '#f7b6d2',
+  '#7f7f7f',
+  '#c7c7c7',
+  '#bcbd22',
+  '#dbdb8d',
+  '#17becf',
+  '#9edae5',
+];
 
-  .splitter-layout.timeline-datasources-splitter {
-    position: absolute;
-    top: $view-control-bar-height + $standard-padding;
-    bottom: 0;
-    width: 100%;
-
-    & > .layout-splitter:hover {
-      background: black;
-      opacity: 0.1;
-      border-radius: 2px;
-    }
-  }
-
-  .segment-timeline {
-    position: absolute;
-    width: 100%;
-    height: 100%;
-  }
-
-  .ReactTable {
-    @include pin-full;
-
-    .clickable-cell {
-      cursor: pointer;
-    }
-  }
+export function getDatasourceColor(datasource: string) {
+  const hash = hashJoaat(datasource);
+  return COLORS[hash % COLORS.length];
 }
diff --git a/web-console/src/druid-models/index.ts 
b/web-console/src/druid-models/index.ts
index 3e5c7062232..e31eedeea73 100644
--- a/web-console/src/druid-models/index.ts
+++ b/web-console/src/druid-models/index.ts
@@ -21,6 +21,7 @@ export * from './compaction-config/compaction-config';
 export * from './compaction-status/compaction-status';
 export * from './coordinator-dynamic-config/coordinator-dynamic-config';
 export * from './dart/dart-query-entry';
+export * from './datasource/datasource';
 export * from './dimension-spec/dimension-spec';
 export * from './druid-engine/druid-engine';
 export * from './execution/execution';
diff --git a/web-console/src/react-table/react-table-utils.ts 
b/web-console/src/react-table/react-table-utils.ts
index ce9497a1209..dc3debdf32c 100644
--- a/web-console/src/react-table/react-table-utils.ts
+++ b/web-console/src/react-table/react-table-utils.ts
@@ -18,8 +18,7 @@
 
 import type { IconName } from '@blueprintjs/core';
 import { IconNames } from '@blueprintjs/icons';
-import type { SqlExpression } from '@druid-toolkit/query';
-import { C, F } from '@druid-toolkit/query';
+import { C, F, SqlExpression } from '@druid-toolkit/query';
 import type { Filter } from 'react-table';
 
 import { addOrUpdate, caseInsensitiveContains, filterMap } from '../utils';
@@ -153,6 +152,10 @@ export function sqlQueryCustomTableFilter(filter: Filter): 
SqlExpression | undef
   }
 }
 
+export function sqlQueryCustomTableFilters(filters: Filter[]): SqlExpression {
+  return SqlExpression.and(...filterMap(filters, sqlQueryCustomTableFilter));
+}
+
 export function tableFiltersToString(tableFilters: Filter[]): string {
   return tableFilters
     .map(({ id, value }) => `${id}${value.replace(/[&%]/g, 
encodeURIComponent)}`)
diff --git a/web-console/src/views/datasources-view/datasources-view.scss 
b/web-console/src/views/datasources-view/datasources-view.scss
index 1f9d9df328e..91a95bc32a0 100644
--- a/web-console/src/views/datasources-view/datasources-view.scss
+++ b/web-console/src/views/datasources-view/datasources-view.scss
@@ -45,6 +45,13 @@
   .ReactTable {
     @include pin-full;
 
+    .datasource-color-tab {
+      display: inline-block;
+      width: 10px;
+      height: 20px;
+      border-radius: 3px;
+    }
+
     .clickable-cell {
       cursor: pointer;
     }
diff --git a/web-console/src/views/datasources-view/datasources-view.tsx 
b/web-console/src/views/datasources-view/datasources-view.tsx
index 4477540af66..f58caee1ae8 100644
--- a/web-console/src/views/datasources-view/datasources-view.tsx
+++ b/web-console/src/views/datasources-view/datasources-view.tsx
@@ -56,6 +56,7 @@ import type {
 import {
   END_OF_TIME_DATE,
   formatCompactionInfo,
+  getDatasourceColor,
   RuleUtil,
   START_OF_TIME_DATE,
   zeroCompactionStatus,
@@ -1145,7 +1146,8 @@ GROUP BY 1, 2`;
 
   private renderDatasourcesTable() {
     const { goToSegments, goToTasks, capabilities, filters, onFiltersChange } 
= this.props;
-    const { datasourcesAndDefaultRulesState, showUnused, visibleColumns } = 
this.state;
+    const { datasourcesAndDefaultRulesState, showUnused, visibleColumns, 
showSegmentTimeline } =
+      this.state;
 
     let { datasources, defaultRules } = datasourcesAndDefaultRulesState.data 
|| { datasources: [] };
 
@@ -1199,12 +1201,18 @@ GROUP BY 1, 2`;
             show: visibleColumns.shown('Datasource name'),
             accessor: 'datasource',
             width: 150,
-            Cell: row => (
+            Cell: ({ value, original }) => (
               <TableClickableCell
-                onClick={() => this.onDetail(row.original)}
+                onClick={() => this.onDetail(original)}
                 hoverIcon={IconNames.SEARCH_TEMPLATE}
               >
-                {row.value}
+                {showSegmentTimeline ? (
+                  <>
+                    <span style={{ color: getDatasourceColor(value) 
}}>&#9632;</span> {value}
+                  </>
+                ) : (
+                  value
+                )}
               </TableClickableCell>
             ),
           },
diff --git a/web-console/src/views/segments-view/segments-view.tsx 
b/web-console/src/views/segments-view/segments-view.tsx
index 18dcc4c4cc3..0f7751bf76c 100644
--- a/web-console/src/views/segments-view/segments-view.tsx
+++ b/web-console/src/views/segments-view/segments-view.tsx
@@ -20,6 +20,7 @@ import { Button, ButtonGroup, Intent, Label, MenuItem, 
Switch, Tag } from '@blue
 import { IconNames } from '@blueprintjs/icons';
 import { C, L, SqlComparison, SqlExpression } from '@druid-toolkit/query';
 import * as JSONBig from 'json-bigint-native';
+import type { ReactNode } from 'react';
 import React from 'react';
 import type { Filter, SortingRule } from 'react-table';
 import ReactTable from 'react-table';
@@ -44,7 +45,7 @@ import { AsyncActionDialog } from '../../dialogs';
 import { SegmentTableActionDialog } from 
'../../dialogs/segments-table-action-dialog/segment-table-action-dialog';
 import { ShowValueDialog } from 
'../../dialogs/show-value-dialog/show-value-dialog';
 import type { QueryWithContext } from '../../druid-models';
-import { computeSegmentTimeSpan } from '../../druid-models';
+import { computeSegmentTimeSpan, getDatasourceColor } from 
'../../druid-models';
 import type { Capabilities, CapabilitiesMode } from '../../helpers';
 import {
   booleanCustomTableFilter,
@@ -275,8 +276,6 @@ export class SegmentsView extends 
React.PureComponent<SegmentsViewProps, Segment
         if (capabilities.hasSql()) {
           const whereExpression = segmentFiltersToExpression(filtered);
 
-          let queryParts: string[];
-
           let filterClause = '';
           if (whereExpression.toString() !== 'TRUE') {
             filterClause = whereExpression.toString();
@@ -296,6 +295,7 @@ export class SegmentsView extends 
React.PureComponent<SegmentsViewProps, Segment
           const base = SegmentsView.baseQuery(visibleColumns);
           const orderByClause = sortedToOrderByClause(effectiveSorted);
 
+          let queryParts: string[];
           if (groupByInterval) {
             const innerQuery = compact([
               `SELECT "start", "end"`,
@@ -476,7 +476,11 @@ export class SegmentsView extends 
React.PureComponent<SegmentsViewProps, Segment
     });
   }
 
-  private renderFilterableCell(field: string, enableComparisons = false) {
+  private renderFilterableCell(
+    field: string,
+    enableComparisons = false,
+    valueFn: (value: string) => ReactNode = String,
+  ) {
     const { filters, onFiltersChange } = this.props;
 
     // eslint-disable-next-line react/display-name
@@ -488,14 +492,22 @@ export class SegmentsView extends 
React.PureComponent<SegmentsViewProps, Segment
         onFiltersChange={onFiltersChange}
         enableComparisons={enableComparisons}
       >
-        {row.value}
+        {valueFn(row.value)}
       </TableFilterableCell>
     );
   }
 
   renderSegmentsTable() {
     const { capabilities, filters, onFiltersChange } = this.props;
-    const { segmentsState, visibleColumns, groupByInterval, page, pageSize, 
sorted } = this.state;
+    const {
+      segmentsState,
+      visibleColumns,
+      groupByInterval,
+      page,
+      pageSize,
+      sorted,
+      showSegmentTimeline,
+    } = this.state;
 
     const segments = segmentsState.data || [];
 
@@ -530,15 +542,15 @@ export class SegmentsView extends 
React.PureComponent<SegmentsViewProps, Segment
         onFilteredChange={onFiltersChange}
         sorted={sorted}
         onSortedChange={sorted => this.setState({ sorted })}
-        showPageJump={false}
-        ofText=""
-        pivotBy={groupByInterval ? ['interval'] : []}
         page={page}
         onPageChange={page => this.setState({ page })}
         pageSize={pageSize}
         onPageSizeChange={pageSize => this.setState({ pageSize })}
         pageSizeOptions={STANDARD_TABLE_PAGE_SIZE_OPTIONS}
         showPagination
+        showPageJump={false}
+        ofText=""
+        pivotBy={groupByInterval ? ['interval'] : []}
         columns={[
           {
             Header: 'Segment ID',
@@ -561,7 +573,17 @@ export class SegmentsView extends 
React.PureComponent<SegmentsViewProps, Segment
             show: visibleColumns.shown('Datasource'),
             accessor: 'datasource',
             width: 140,
-            Cell: this.renderFilterableCell('datasource'),
+            Cell: this.renderFilterableCell(
+              'datasource',
+              false,
+              showSegmentTimeline
+                ? value => (
+                    <>
+                      <span style={{ color: getDatasourceColor(value) 
}}>&#9632;</span> {value}
+                    </>
+                  )
+                : String,
+            ),
           },
           {
             Header: 'Interval',
diff --git a/web-console/src/views/supervisors-view/supervisors-view.tsx 
b/web-console/src/views/supervisors-view/supervisors-view.tsx
index 2474782e0ae..8c557fe3c54 100644
--- a/web-console/src/views/supervisors-view/supervisors-view.tsx
+++ b/web-console/src/views/supervisors-view/supervisors-view.tsx
@@ -18,11 +18,10 @@
 
 import { Icon, Intent, Menu, MenuItem, Popover, Position, Tag } from 
'@blueprintjs/core';
 import { IconNames } from '@blueprintjs/icons';
-import { SqlExpression } from '@druid-toolkit/query';
 import * as JSONBig from 'json-bigint-native';
 import type { JSX } from 'react';
 import React from 'react';
-import type { Filter } from 'react-table';
+import type { Filter, SortingRule } from 'react-table';
 import ReactTable from 'react-table';
 
 import type { TableColumnSelectorColumn } from '../../components';
@@ -58,7 +57,7 @@ import type { Capabilities } from '../../helpers';
 import {
   SMALL_TABLE_PAGE_SIZE,
   SMALL_TABLE_PAGE_SIZE_OPTIONS,
-  sqlQueryCustomTableFilter,
+  sqlQueryCustomTableFilters,
 } from '../../react-table';
 import { Api, AppToaster } from '../../singletons';
 import type { AuxiliaryQueryFn, TableState } from '../../utils';
@@ -67,7 +66,6 @@ import {
   changeByIndex,
   checkedCircleIcon,
   deepGet,
-  filterMap,
   formatByteRate,
   formatBytes,
   formatInteger,
@@ -162,7 +160,11 @@ export interface SupervisorsViewState {
 
   supervisorTableActionDialogId?: string;
   supervisorTableActionDialogActions: BasicAction[];
+
   visibleColumns: LocalStorageBackedVisibility;
+  page: number;
+  pageSize: number;
+  sorted: SortingRule[];
 }
 
 function detailedStateToColor(detailedState: string): string {
@@ -223,6 +225,9 @@ export class SupervisorsView extends React.PureComponent<
       visibleColumns: new LocalStorageBackedVisibility(
         LocalStorageKeys.SUPERVISOR_TABLE_COLUMN_SELECTION,
       ),
+      page: 0,
+      pageSize: SMALL_TABLE_PAGE_SIZE,
+      sorted: [],
     };
 
     this.supervisorQueryManager = new QueryManager({
@@ -233,10 +238,11 @@ export class SupervisorsView extends React.PureComponent<
       ) => {
         let supervisors: SupervisorQueryResultRow[];
         if (capabilities.hasSql()) {
+          const whereExpression = sqlQueryCustomTableFilters(filtered);
+
           let filterClause = '';
-          const whereParts = filterMap(filtered, sqlQueryCustomTableFilter);
-          if (whereParts.length) {
-            filterClause = SqlExpression.and(...whereParts).toString();
+          if (whereExpression.toString() !== 'TRUE') {
+            filterClause = whereExpression.toString();
           }
 
           const sqlQuery = assemble(
@@ -355,22 +361,33 @@ export class SupervisorsView extends React.PureComponent<
     });
   }
 
-  private lastTableState: TableState | undefined;
-
   componentWillUnmount(): void {
     this.supervisorQueryManager.terminate();
   }
 
-  private readonly fetchData = (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<SupervisorsViewProps>,
+    prevState: Readonly<SupervisorsViewState>,
+  ) {
+    const { filters } = this.props;
+    const { page, pageSize, sorted } = this.state;
+    if (
+      
!sqlQueryCustomTableFilters(filters).equals(sqlQueryCustomTableFilters(prevProps.filters))
 ||
+      page !== prevState.page ||
+      pageSize !== prevState.pageSize ||
+      sortedToOrderByClause(sorted) !== sortedToOrderByClause(prevState.sorted)
+    ) {
+      this.fetchData();
+    }
+  }
+
+  private readonly fetchData = () => {
+    const { capabilities, filters } = this.props;
+    const { visibleColumns, page, pageSize, sorted } = this.state;
     this.supervisorQueryManager.runQuery({
       page,
       pageSize,
-      filtered,
+      filtered: filters,
       sorted,
       visibleColumns,
       capabilities,
@@ -663,7 +680,7 @@ export class SupervisorsView extends React.PureComponent<
 
   private renderSupervisorTable() {
     const { goToTasks, filters, onFiltersChange } = this.props;
-    const { supervisorsState, statsKey, visibleColumns } = this.state;
+    const { supervisorsState, statsKey, visibleColumns, page, pageSize, sorted 
} = this.state;
 
     const supervisors = supervisorsState.data || [];
     return (
@@ -678,14 +695,16 @@ export class SupervisorsView extends React.PureComponent<
         filterable
         filtered={filters}
         onFilteredChange={onFiltersChange}
-        onFetchData={tableState => {
-          this.fetchData(tableState);
-        }}
-        showPageJump={false}
-        ofText=""
-        defaultPageSize={SMALL_TABLE_PAGE_SIZE}
+        sorted={sorted}
+        onSortedChange={sorted => this.setState({ sorted })}
+        page={page}
+        onPageChange={page => this.setState({ page })}
+        pageSize={pageSize}
+        onPageSizeChange={pageSize => this.setState({ pageSize })}
         pageSizeOptions={SMALL_TABLE_PAGE_SIZE_OPTIONS}
         showPagination={supervisors.length > SMALL_TABLE_PAGE_SIZE}
+        showPageJump={false}
+        ofText=""
         columns={[
           {
             Header: twoLines('Supervisor ID', <i>(datasource)</i>),


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to