You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@druid.apache.org by vo...@apache.org on 2024/04/22 22:24:52 UTC
(druid) 02/04: better tabs
This is an automated email from the ASF dual-hosted git repository.
vogievetsky pushed a commit to branch better_supervisor_view
in repository https://gitbox.apache.org/repos/asf/druid.git
commit 78ad36ba85028d12372fe684e178593c00235d6a
Author: Vadim Ogievetsky <va...@ogievetsky.com>
AuthorDate: Fri Apr 19 12:52:06 2024 -0700
better tabs
---
.../compaction-history-dialog.tsx | 4 +-
.../kill-datasource-dialog.tsx | 7 +-
.../supervisor-table-action-dialog.tsx | 14 +-
.../task-table-action-dialog.tsx | 40 ++---
.../supervisor-status/supervisor-status.ts | 11 +-
.../src/views/load-data-view/info-messages.tsx | 6 +-
.../src/views/load-data-view/load-data-view.tsx | 10 +-
.../src/views/segments-view/segments-view.tsx | 6 +-
.../views/supervisors-view/supervisors-view.scss | 4 +
.../views/supervisors-view/supervisors-view.tsx | 171 ++++++++++++++-------
web-console/src/views/tasks-view/tasks-view.tsx | 6 +-
11 files changed, 179 insertions(+), 100 deletions(-)
diff --git a/web-console/src/dialogs/compaction-history-dialog/compaction-history-dialog.tsx b/web-console/src/dialogs/compaction-history-dialog/compaction-history-dialog.tsx
index 4cdc916ee74..cb886d0483d 100644
--- a/web-console/src/dialogs/compaction-history-dialog/compaction-history-dialog.tsx
+++ b/web-console/src/dialogs/compaction-history-dialog/compaction-history-dialog.tsx
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-import { Button, Callout, Classes, Code, Dialog, Tab, Tabs } from '@blueprintjs/core';
+import { Button, Callout, Classes, Dialog, Tab, Tabs, Tag } from '@blueprintjs/core';
import * as JSONBig from 'json-bigint-native';
import React, { useState } from 'react';
@@ -117,7 +117,7 @@ export const CompactionHistoryDialog = React.memo(function CompactionHistoryDial
</Tabs>
) : (
<div>
- There is no compaction history for <Code>{datasource}</Code>.
+ There is no compaction history for <Tag minimal>{datasource}</Tag>.
</div>
)
) : historyState.loading ? (
diff --git a/web-console/src/dialogs/kill-datasource-dialog/kill-datasource-dialog.tsx b/web-console/src/dialogs/kill-datasource-dialog/kill-datasource-dialog.tsx
index f95a5a5d3b8..dba85268d00 100644
--- a/web-console/src/dialogs/kill-datasource-dialog/kill-datasource-dialog.tsx
+++ b/web-console/src/dialogs/kill-datasource-dialog/kill-datasource-dialog.tsx
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-import { Code, Intent } from '@blueprintjs/core';
+import { Intent, Tag } from '@blueprintjs/core';
import React, { useState } from 'react';
import { FormGroupWithInfo, PopoverText } from '../../components';
@@ -74,13 +74,14 @@ export const KillDatasourceDialog = function KillDatasourceDialog(
warningChecks={[
<>
I understand that this operation will delete all metadata about the unused segments of{' '}
- <Code>{datasource}</Code> and removes them from deep storage.
+ <Tag minimal>{datasource}</Tag> and removes them from deep storage.
</>,
'I understand that this operation cannot be undone.',
]}
>
<p>
- Are you sure you want to permanently delete unused segments in <Code>{datasource}</Code>?
+ Are you sure you want to permanently delete unused segments in{' '}
+ <Tag minimal>{datasource}</Tag>?
</p>
<p>This action is not reversible and the data deleted will be lost.</p>
<FormGroupWithInfo
diff --git a/web-console/src/dialogs/supervisor-table-action-dialog/supervisor-table-action-dialog.tsx b/web-console/src/dialogs/supervisor-table-action-dialog/supervisor-table-action-dialog.tsx
index 02d9e3c28b8..5e3d9e50028 100644
--- a/web-console/src/dialogs/supervisor-table-action-dialog/supervisor-table-action-dialog.tsx
+++ b/web-console/src/dialogs/supervisor-table-action-dialog/supervisor-table-action-dialog.tsx
@@ -28,6 +28,8 @@ import { TableActionDialog } from '../table-action-dialog/table-action-dialog';
import { SupervisorStatisticsTable } from './supervisor-statistics-table/supervisor-statistics-table';
+type SupervisorTableActionDialogTab = 'status' | 'stats' | 'spec' | 'history';
+
interface SupervisorTableActionDialogProps {
supervisorId: string;
actions: BasicAction[];
@@ -38,7 +40,7 @@ export const SupervisorTableActionDialog = React.memo(function SupervisorTableAc
props: SupervisorTableActionDialogProps,
) {
const { supervisorId, actions, onClose } = props;
- const [activeTab, setActiveTab] = useState('status');
+ const [activeTab, setActiveTab] = useState<SupervisorTableActionDialogTab>('status');
const supervisorTableSideButtonMetadata: SideButtonMetaData[] = [
{
@@ -49,15 +51,15 @@ export const SupervisorTableActionDialog = React.memo(function SupervisorTableAc
},
{
icon: 'chart',
- text: 'Statistics',
+ text: 'Task stats',
active: activeTab === 'stats',
onClick: () => setActiveTab('stats'),
},
{
icon: 'align-left',
- text: 'Payload',
- active: activeTab === 'payload',
- onClick: () => setActiveTab('payload'),
+ text: 'Spec',
+ active: activeTab === 'spec',
+ onClick: () => setActiveTab('spec'),
},
{
icon: 'history',
@@ -88,7 +90,7 @@ export const SupervisorTableActionDialog = React.memo(function SupervisorTableAc
downloadFilename={`supervisor-stats-${supervisorId}.json`}
/>
)}
- {activeTab === 'payload' && (
+ {activeTab === 'spec' && (
<ShowJson
endpoint={supervisorEndpointBase}
transform={x => cleanSpec(x, true)}
diff --git a/web-console/src/dialogs/task-table-action-dialog/task-table-action-dialog.tsx b/web-console/src/dialogs/task-table-action-dialog/task-table-action-dialog.tsx
index a0a5dbbf13f..9edc5d996f4 100644
--- a/web-console/src/dialogs/task-table-action-dialog/task-table-action-dialog.tsx
+++ b/web-console/src/dialogs/task-table-action-dialog/task-table-action-dialog.tsx
@@ -25,18 +25,20 @@ import type { BasicAction } from '../../utils/basic-action';
import type { SideButtonMetaData } from '../table-action-dialog/table-action-dialog';
import { TableActionDialog } from '../table-action-dialog/table-action-dialog';
+type TaskTableActionDialogTab = 'status' | 'report' | 'spec' | 'log';
+
interface TaskTableActionDialogProps {
taskId: string;
actions: BasicAction[];
- onClose: () => void;
status: string;
+ onClose(): void;
}
export const TaskTableActionDialog = React.memo(function TaskTableActionDialog(
props: TaskTableActionDialogProps,
) {
const { taskId, actions, onClose, status } = props;
- const [activeTab, setActiveTab] = useState('status');
+ const [activeTab, setActiveTab] = useState<TaskTableActionDialogTab>('status');
const taskTableSideButtonMetadata: SideButtonMetaData[] = [
{
@@ -45,21 +47,21 @@ export const TaskTableActionDialog = React.memo(function TaskTableActionDialog(
active: activeTab === 'status',
onClick: () => setActiveTab('status'),
},
- {
- icon: 'align-left',
- text: 'Payload',
- active: activeTab === 'payload',
- onClick: () => setActiveTab('payload'),
- },
{
icon: 'comparison',
text: 'Reports',
- active: activeTab === 'reports',
- onClick: () => setActiveTab('reports'),
+ active: activeTab === 'report',
+ onClick: () => setActiveTab('report'),
+ },
+ {
+ icon: 'align-left',
+ text: 'Spec',
+ active: activeTab === 'spec',
+ onClick: () => setActiveTab('spec'),
},
{
icon: 'align-justify',
- text: 'Logs',
+ text: 'Log',
active: activeTab === 'log',
onClick: () => setActiveTab('log'),
},
@@ -80,20 +82,20 @@ export const TaskTableActionDialog = React.memo(function TaskTableActionDialog(
downloadFilename={`task-status-${taskId}.json`}
/>
)}
- {activeTab === 'payload' && (
- <ShowJson
- endpoint={taskEndpointBase}
- transform={x => deepGet(x, 'payload') || x}
- downloadFilename={`task-payload-${taskId}.json`}
- />
- )}
- {activeTab === 'reports' && (
+ {activeTab === 'report' && (
<ShowJson
endpoint={`${taskEndpointBase}/reports`}
transform={x => deepGet(x, 'ingestionStatsAndErrors.payload') || x}
downloadFilename={`task-reports-${taskId}.json`}
/>
)}
+ {activeTab === 'spec' && (
+ <ShowJson
+ endpoint={taskEndpointBase}
+ transform={x => deepGet(x, 'payload') || x}
+ downloadFilename={`task-payload-${taskId}.json`}
+ />
+ )}
{activeTab === 'log' && (
<ShowLog
tail={status === 'RUNNING'}
diff --git a/web-console/src/druid-models/supervisor-status/supervisor-status.ts b/web-console/src/druid-models/supervisor-status/supervisor-status.ts
index bdbc3187736..d76ad19cc14 100644
--- a/web-console/src/druid-models/supervisor-status/supervisor-status.ts
+++ b/web-console/src/druid-models/supervisor-status/supervisor-status.ts
@@ -42,20 +42,27 @@ export interface SupervisorStatus {
healthy: boolean;
state: string;
detailedState: string;
- recentErrors: any[];
+ recentErrors: SupervisorError[];
};
}
export interface SupervisorStatusTask {
id: string;
startingOffsets: SupervisorOffsetMap;
- startTime: '2024-04-12T21:35:34.834Z';
+ startTime: string;
remainingSeconds: number;
type: string;
currentOffsets: SupervisorOffsetMap;
lag: SupervisorOffsetMap;
}
+export interface SupervisorError {
+ timestamp: string;
+ exceptionClass: string;
+ message: string;
+ streamException: boolean;
+}
+
export type SupervisorStats = Record<string, Record<string, RowStats>>;
export type RowStatsKey = 'totals' | '1m' | '5m' | '15m';
diff --git a/web-console/src/views/load-data-view/info-messages.tsx b/web-console/src/views/load-data-view/info-messages.tsx
index b88cf8a70c2..ad9e96667db 100644
--- a/web-console/src/views/load-data-view/info-messages.tsx
+++ b/web-console/src/views/load-data-view/info-messages.tsx
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-import { Button, Callout, Code, FormGroup, Intent } from '@blueprintjs/core';
+import { Button, Callout, Code, FormGroup, Intent, Tag } from '@blueprintjs/core';
import React from 'react';
import { ExternalLink, LearnMore } from '../../components';
@@ -236,8 +236,8 @@ export const AppendToExistingIssue = React.memo(function AppendToExistingIssue(
<FormGroup>
<Callout intent={Intent.DANGER}>
<p>
- Only <Code>dynamic</Code> partitioning supports <Code>appendToExisting: true</Code>. You
- have currently selected <Code>{partitionsSpecType}</Code> partitioning.
+ Only <Tag minimal>dynamic</Tag> partitioning supports <Code>appendToExisting: true</Code>.
+ You have currently selected <Tag minimal>{partitionsSpecType}</Tag> partitioning.
</p>
<Button
intent={Intent.SUCCESS}
diff --git a/web-console/src/views/load-data-view/load-data-view.tsx b/web-console/src/views/load-data-view/load-data-view.tsx
index fdb45420e0a..d95943b4f1c 100644
--- a/web-console/src/views/load-data-view/load-data-view.tsx
+++ b/web-console/src/views/load-data-view/load-data-view.tsx
@@ -34,6 +34,7 @@ import {
Radio,
RadioGroup,
Switch,
+ Tag,
TextArea,
} from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
@@ -3073,8 +3074,9 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
<p>Your partitioning and sorting configuration is uncommon.</p>
<p>
For best performance the first dimension in your schema (
- <Code>{firstDimensionName}</Code>), which is what the data will be primarily sorted
- on, commonly matches the partitioning dimension (<Code>{partitionDimension}</Code>).
+ <Tag minimal>{firstDimensionName}</Tag>), which is what the data will be primarily
+ sorted on, commonly matches the partitioning dimension (
+ <Tag minimal>{partitionDimension}</Tag>).
</p>
<p>
<Button
@@ -3452,11 +3454,11 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
<p>
You have enabled type-aware schema discovery (
<Code>useSchemaDiscovery: true</Code>) to ingest data into the existing
- datasource <Code>{datasource}</Code>.
+ datasource <Tag minimal>{datasource}</Tag>.
</p>
<p>
If you used string-based schema discovery when first ingesting data to{' '}
- <Code>{datasource}</Code>, using type-aware schema discovery now can cause
+ <Tag minimal>{datasource}</Tag>, using type-aware schema discovery now can cause
problems with the values multi-value string dimensions.
</p>
<p>
diff --git a/web-console/src/views/segments-view/segments-view.tsx b/web-console/src/views/segments-view/segments-view.tsx
index 44d59f6fa95..ba4b84b76c4 100644
--- a/web-console/src/views/segments-view/segments-view.tsx
+++ b/web-console/src/views/segments-view/segments-view.tsx
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-import { Button, ButtonGroup, Code, Intent, Label, MenuItem, Switch } from '@blueprintjs/core';
+import { Button, ButtonGroup, Intent, Label, MenuItem, Switch, Tag } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import { C, L, SqlComparison, SqlExpression } from '@druid-toolkit/query';
import classNames from 'classnames';
@@ -919,7 +919,7 @@ END AS "time_span"`,
);
return resp.data;
}}
- confirmButtonText="Drop Segment"
+ confirmButtonText="Drop segment"
successText="Segment drop request acknowledged, next time the coordinator runs segment will be dropped"
failText="Could not drop segment"
intent={Intent.DANGER}
@@ -931,7 +931,7 @@ END AS "time_span"`,
}}
>
<p>
- Are you sure you want to drop segment <Code>{terminateSegmentId}</Code>?
+ Are you sure you want to drop segment <Tag minimal>{terminateSegmentId}</Tag>?
</p>
<p>This action is not reversible.</p>
</AsyncActionDialog>
diff --git a/web-console/src/views/supervisors-view/supervisors-view.scss b/web-console/src/views/supervisors-view/supervisors-view.scss
index edf04bc4e0d..6db2b646d95 100644
--- a/web-console/src/views/supervisors-view/supervisors-view.scss
+++ b/web-console/src/views/supervisors-view/supervisors-view.scss
@@ -28,5 +28,9 @@
top: $view-control-bar-height + $standard-padding;
bottom: 0;
width: 100%;
+
+ .title-button {
+ cursor: pointer;
+ }
}
}
diff --git a/web-console/src/views/supervisors-view/supervisors-view.tsx b/web-console/src/views/supervisors-view/supervisors-view.tsx
index 6e872792220..0483cbd2184 100644
--- a/web-console/src/views/supervisors-view/supervisors-view.tsx
+++ b/web-console/src/views/supervisors-view/supervisors-view.tsx
@@ -16,9 +16,11 @@
* limitations under the License.
*/
-import { Button, Code, Intent, Menu, MenuItem, Position } from '@blueprintjs/core';
+import { Icon, Intent, Menu, MenuItem, Position, Tag } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import { Popover2 } from '@blueprintjs/popover2';
+import * as JSONBig from 'json-bigint-native';
+import type { JSX } from 'react';
import React from 'react';
import type { Filter } from 'react-table';
import ReactTable from 'react-table';
@@ -42,7 +44,12 @@ import {
SupervisorTableActionDialog,
} from '../../dialogs';
import { SupervisorResetOffsetsDialog } from '../../dialogs/supervisor-reset-offsets-dialog/supervisor-reset-offsets-dialog';
-import type { QueryWithContext, RowStatsKey, SupervisorStatus } from '../../druid-models';
+import type {
+ IngestionSpec,
+ QueryWithContext,
+ RowStatsKey,
+ SupervisorStatus,
+} from '../../druid-models';
import { getTotalSupervisorStats } from '../../druid-models';
import type { Capabilities } from '../../helpers';
import {
@@ -64,6 +71,7 @@ import {
hasPopoverOpen,
LocalStorageBackedVisibility,
LocalStorageKeys,
+ nonEmptyArray,
oneOf,
pluralIfNeeded,
queryDruidSql,
@@ -81,16 +89,16 @@ const supervisorTableColumns: string[] = [
'Type',
'Topic/Stream',
'Status',
- 'Active tasks',
+ 'Configured tasks',
+ 'Running tasks',
'Aggregate lag',
'Stats',
ACTION_COLUMN_LABEL,
];
-const ROW_STATS_KEYS: RowStatsKey[] = ['totals', '1m', '5m', '15m'];
+const ROW_STATS_KEYS: RowStatsKey[] = ['1m', '5m', '15m'];
function getRowStatsKeyTitle(key: RowStatsKey) {
- if (key === 'totals') return 'Total';
return `Rate over past ${pluralIfNeeded(parseInt(key, 10), 'minute')}`;
}
@@ -104,6 +112,7 @@ interface SupervisorQueryResultRow {
type: string;
source: string;
detailed_state: string;
+ spec?: IngestionSpec;
suspended: boolean;
status?: SupervisorStatus;
stats?: any;
@@ -182,14 +191,6 @@ export class SupervisorsView extends React.PureComponent<
SupervisorQueryResultRow[]
>;
- static SUPERVISOR_SQL_BASE = `WITH s AS (SELECT
- "supervisor_id",
- "type",
- "source",
- CASE WHEN "suspended" = 0 THEN "detailed_state" ELSE 'SUSPENDED' END AS "detailed_state",
- "suspended" = 1 AS "suspended"
-FROM "sys"."supervisors")`;
-
constructor(props: SupervisorsViewProps) {
super(props);
@@ -219,7 +220,14 @@ FROM "sys"."supervisors")`;
let supervisors: SupervisorQueryResultRow[];
if (capabilities.hasSql()) {
const sqlQuery = assemble(
- SupervisorsView.SUPERVISOR_SQL_BASE,
+ 'WITH s AS (SELECT',
+ ' "supervisor_id",',
+ ' "type",',
+ ' "source",',
+ ` CASE WHEN "suspended" = 0 THEN "detailed_state" ELSE 'SUSPENDED' END AS "detailed_state",`,
+ visibleColumns.shown('Configured tasks') ? ' "spec",' : undefined,
+ ' "suspended" = 1 AS "suspended"',
+ 'FROM "sys"."supervisors")',
'SELECT *',
'FROM s',
filtered.length
@@ -236,6 +244,13 @@ FROM "sys"."supervisors")`;
},
cancelToken,
);
+
+ for (const supervisor of supervisors) {
+ const spec: any = supervisor.spec;
+ if (typeof spec === 'string') {
+ supervisor.spec = JSONBig.parse(spec);
+ }
+ }
} else if (capabilities.hasOverlordAccess()) {
const supervisorList = (
await Api.instance.get('/druid/indexer/v1/supervisor?full', { cancelToken })
@@ -253,6 +268,7 @@ FROM "sys"."supervisors")`;
'n/a',
state: deepGet(sup, 'state'),
detailed_state: deepGet(sup, 'detailedState'),
+ spec: sup.spec,
suspended: Boolean(deepGet(sup, 'suspended')),
};
});
@@ -272,7 +288,7 @@ FROM "sys"."supervisors")`;
}
if (capabilities.hasOverlordAccess()) {
- if (visibleColumns.shown('Active tasks') || visibleColumns.shown('Aggregate lag')) {
+ if (visibleColumns.shown('Running tasks') || visibleColumns.shown('Aggregate lag')) {
try {
for (const supervisor of supervisors) {
cancelToken.throwIfRequested();
@@ -451,7 +467,7 @@ FROM "sys"."supervisors")`;
}}
>
<p>
- Are you sure you want to resume supervisor <Code>{resumeSupervisorId}</Code>?
+ Are you sure you want to resume supervisor <Tag minimal>{resumeSupervisorId}</Tag>?
</p>
</AsyncActionDialog>
);
@@ -482,7 +498,7 @@ FROM "sys"."supervisors")`;
}}
>
<p>
- Are you sure you want to suspend supervisor <Code>{suspendSupervisorId}</Code>?
+ Are you sure you want to suspend supervisor <Tag minimal>{suspendSupervisorId}</Tag>?
</p>
</AsyncActionDialog>
);
@@ -527,17 +543,20 @@ FROM "sys"."supervisors")`;
this.supervisorQueryManager.rerunLastQuery();
}}
warningChecks={[
- `I understand that resetting ${resetSupervisorId} will clear checkpoints and therefore lead to data loss or duplication.`,
+ <>
+ I understand that resetting <Tag minimal>{resetSupervisorId}</Tag> will clear
+ checkpoints and may lead to data loss or duplication.
+ </>,
'I understand that this operation cannot be undone.',
]}
>
<p>
- Are you sure you want to hard reset supervisor <Code>{resetSupervisorId}</Code>?
+ Are you sure you want to hard reset supervisor <Tag minimal>{resetSupervisorId}</Tag>?
</p>
- <p>Hard resetting a supervisor will lead to data loss or data duplication.</p>
+ <p>Hard resetting a supervisor may lead to data loss or data duplication.</p>
<p>
- The reason for using this operation is to recover from a state in which the supervisor
- ceases operating due to missing offsets.
+ Use this operation to restore functionality when the supervisor stops operating due to
+ missing offsets.
</p>
</AsyncActionDialog>
);
@@ -568,7 +587,7 @@ FROM "sys"."supervisors")`;
}}
>
<p>
- Are you sure you want to terminate supervisor <Code>{terminateSupervisorId}</Code>?
+ Are you sure you want to terminate supervisor <Tag minimal>{terminateSupervisorId}</Tag>?
</p>
<p>This action is not reversible.</p>
</AsyncActionDialog>
@@ -673,29 +692,69 @@ FROM "sys"."supervisors")`;
show: visibleColumns.shown('Status'),
},
{
- Header: 'Active tasks',
- id: 'active_tasks',
+ Header: 'Configured tasks',
+ id: 'configured_tasks',
width: 150,
- accessor: 'status.payload.activeTasks',
+ accessor: 'spec',
+ filterable: false,
+ sortable: false,
+ className: 'padded',
+ Cell: ({ value }) => {
+ if (!value) return null;
+ const taskCount = deepGet(value, 'spec.ioConfig.taskCount');
+ const replicas = deepGet(value, 'spec.ioConfig.replicas');
+ if (typeof taskCount !== 'number' || typeof replicas !== 'number') return null;
+ return (
+ <div>
+ <div>{formatInteger(taskCount * replicas)}</div>
+ <div>
+ {replicas === 1
+ ? '(no replication)'
+ : `(${pluralIfNeeded(taskCount, 'task')} × ${pluralIfNeeded(
+ replicas,
+ 'replica',
+ )})`}
+ </div>
+ </div>
+ );
+ },
+ show: visibleColumns.shown('Configured tasks'),
+ },
+ {
+ Header: 'Running tasks',
+ id: 'running_tasks',
+ width: 150,
+ accessor: 'status.payload',
filterable: false,
sortable: false,
Cell: ({ value, original }) => {
if (original.suspended) return;
+ let label: string | JSX.Element;
+ const { activeTasks, publishingTasks } = value || {};
+ if (Array.isArray(activeTasks)) {
+ label = pluralIfNeeded(activeTasks.length, 'active task');
+ if (nonEmptyArray(publishingTasks)) {
+ label = (
+ <>
+ <div>{label}</div>
+ <div>{pluralIfNeeded(publishingTasks.length, 'publishing task')}</div>
+ </>
+ );
+ }
+ } else {
+ label = 'n/a';
+ }
return (
<TableClickableCell
onClick={() => goToTasks(original.supervisor_id, `index_${original.type}`)}
hoverIcon={IconNames.ARROW_TOP_RIGHT}
title="Go to tasks"
>
- {typeof value === 'undefined'
- ? 'n/a'
- : value.length > 0
- ? pluralIfNeeded(value.length, 'running task')
- : `No running tasks`}
+ {label}
</TableClickableCell>
);
},
- show: visibleColumns.shown('Active tasks'),
+ show: visibleColumns.shown('Running tasks'),
},
{
Header: 'Aggregate lag',
@@ -708,7 +767,30 @@ FROM "sys"."supervisors")`;
Cell: ({ value }) => formatInteger(value),
},
{
- Header: twoLines('Stats', <i>{getRowStatsKeyTitle(statsKey)}</i>),
+ Header: twoLines(
+ 'Stats',
+ <Popover2
+ position={Position.BOTTOM}
+ content={
+ <Menu>
+ {ROW_STATS_KEYS.map(k => (
+ <MenuItem
+ key={k}
+ icon={checkedCircleIcon(k === statsKey)}
+ text={getRowStatsKeyTitle(k)}
+ onClick={() => {
+ this.setState({ statsKey: k });
+ }}
+ />
+ ))}
+ </Menu>
+ }
+ >
+ <i className="title-button">
+ {getRowStatsKeyTitle(statsKey)} <Icon icon={IconNames.CARET_DOWN} />
+ </i>
+ </Popover2>,
+ ),
id: 'stats',
width: 220,
filterable: false,
@@ -889,7 +971,6 @@ FROM "sys"."supervisors")`;
supervisorTableActionDialogId,
supervisorTableActionDialogActions,
visibleColumns,
- statsKey,
} = this.state;
return (
@@ -902,28 +983,6 @@ FROM "sys"."supervisors")`;
this.supervisorQueryManager.rerunLastQuery(auto);
}}
/>
- <Popover2
- position={Position.BOTTOM}
- content={
- <Menu>
- {ROW_STATS_KEYS.map(k => (
- <MenuItem
- key={k}
- icon={checkedCircleIcon(k === statsKey)}
- text={getRowStatsKeyTitle(k)}
- onClick={() => {
- this.setState({ statsKey: k });
- }}
- />
- ))}
- </Menu>
- }
- >
- <Button
- text={`Stats: ${getRowStatsKeyTitle(statsKey)}`}
- rightIcon={IconNames.CARET_DOWN}
- />
- </Popover2>
{this.renderBulkSupervisorActions()}
<TableColumnSelector
columns={supervisorTableColumns}
diff --git a/web-console/src/views/tasks-view/tasks-view.tsx b/web-console/src/views/tasks-view/tasks-view.tsx
index 795c9908412..2be3575b9e1 100644
--- a/web-console/src/views/tasks-view/tasks-view.tsx
+++ b/web-console/src/views/tasks-view/tasks-view.tsx
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-import { Button, ButtonGroup, Intent, Label, MenuItem } from '@blueprintjs/core';
+import { Button, ButtonGroup, Intent, Label, MenuItem, Tag } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import React from 'react';
import type { Filter } from 'react-table';
@@ -310,7 +310,9 @@ ORDER BY
this.taskQueryManager.rerunLastQuery();
}}
>
- <p>{`Are you sure you want to kill task '${killTaskId}'?`}</p>
+ <p>
+ Are you sure you want to kill task <Tag minimal>{killTaskId}</Tag>?
+ </p>
</AsyncActionDialog>
);
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org