This is an automated email from the ASF dual-hosted git repository.
vogievetsky pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git
The following commit(s) were added to refs/heads/master by this push:
new 375dfd128cd minor: Web console: improve and fix supervisor view
(#19475)
375dfd128cd is described below
commit 375dfd128cdc613e8385e71bfefd63df0a932ee0
Author: Vadim Ogievetsky <[email protected]>
AuthorDate: Mon May 18 13:17:37 2026 -0700
minor: Web console: improve and fix supervisor view (#19475)
* improve and fix supervisor view
* update test
* add aggregate lag label
---
.../__snapshots__/supervisors-view.spec.tsx.snap | 58 +++++++++++----
.../views/supervisors-view/supervisors-view.tsx | 84 ++++++++++++++--------
2 files changed, 100 insertions(+), 42 deletions(-)
diff --git
a/web-console/src/views/supervisors-view/__snapshots__/supervisors-view.spec.tsx.snap
b/web-console/src/views/supervisors-view/__snapshots__/supervisors-view.spec.tsx.snap
index fd8462b8647..44708aab819 100644
---
a/web-console/src/views/supervisors-view/__snapshots__/supervisors-view.spec.tsx.snap
+++
b/web-console/src/views/supervisors-view/__snapshots__/supervisors-view.spec.tsx.snap
@@ -11,6 +11,46 @@ exports[`SupervisorsView matches snapshot 1`] = `
localStorageKey="supervisors-refresh-rate"
onRefresh={[Function]}
/>
+ <Blueprint5.Popover
+ boundary="clippingParents"
+ captureDismiss={false}
+ content={
+ <Blueprint5.Menu>
+ <Blueprint5.MenuItem
+ active={false}
+ disabled={false}
+ icon="manually-entered-data"
+ multiline={false}
+ onClick={[Function]}
+ popoverProps={{}}
+ shouldDismissPopover={true}
+ text="Submit JSON supervisor"
+ />
+ </Blueprint5.Menu>
+ }
+ defaultIsOpen={false}
+ disabled={false}
+ fill={false}
+ hasBackdrop={false}
+ hoverCloseDelay={300}
+ hoverOpenDelay={150}
+ inheritDarkTheme={true}
+ interactionKind="click"
+ matchTargetWidth={false}
+ minimal={false}
+ openOnTargetFocus={true}
+ position="bottom-left"
+ positioningStrategy="absolute"
+ shouldReturnFocusOnClose={false}
+ targetTagName="span"
+ transitionDuration={300}
+ usePortal={true}
+ >
+ <Blueprint5.Button
+ icon="plus"
+ text="Create"
+ />
+ </Blueprint5.Popover>
<React.Fragment>
<Memo(MoreButton)>
<Blueprint5.MenuItem
@@ -23,16 +63,6 @@ exports[`SupervisorsView matches snapshot 1`] = `
shouldDismissPopover={true}
text="View SQL query for table"
/>
- <Blueprint5.MenuItem
- active={false}
- disabled={false}
- icon="manually-entered-data"
- multiline={false}
- onClick={[Function]}
- popoverProps={{}}
- shouldDismissPopover={true}
- text="Submit JSON supervisor"
- />
<Blueprint5.MenuItem
active={false}
disabled={false}
@@ -81,7 +111,7 @@ exports[`SupervisorsView matches snapshot 1`] = `
},
{
"label": "status API",
- "text": "Aggregate lag",
+ "text": "Details",
},
{
"label": "stats API",
@@ -227,13 +257,14 @@ exports[`SupervisorsView matches snapshot 1`] = `
},
{
"Cell": [Function],
- "Header": "Aggregate lag",
+ "Header": "Details",
"accessor": "supervisor_id",
"className": "padded",
"filterable": false,
+ "id": "details",
"show": true,
"sortable": false,
- "width": 200,
+ "width": 250,
},
{
"Cell": [Function],
@@ -257,6 +288,7 @@ exports[`SupervisorsView matches snapshot 1`] = `
"Header": "Recent errors",
"accessor": "supervisor_id",
"filterable": false,
+ "id": "recent_errors",
"show": true,
"sortable": false,
"width": 150,
diff --git a/web-console/src/views/supervisors-view/supervisors-view.tsx
b/web-console/src/views/supervisors-view/supervisors-view.tsx
index 294e86d81e9..9aa090947fe 100644
--- a/web-console/src/views/supervisors-view/supervisors-view.tsx
+++ b/web-console/src/views/supervisors-view/supervisors-view.tsx
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-import { Icon, Intent, Menu, MenuItem, Popover, Position, Tag } from
'@blueprintjs/core';
+import { Button, Icon, Intent, Menu, MenuItem, Popover, Position, Tag } from
'@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import * as JSONBig from 'json-bigint-native';
import memoize from 'memoize-one';
@@ -102,7 +102,7 @@ const SUPERVISOR_TABLE_COLUMNS: TableColumnSelectorColumn[]
= [
'Status',
'Configured tasks',
{ text: 'Running tasks', label: 'status API' },
- { text: 'Aggregate lag', label: 'status API' },
+ { text: 'Details', label: 'status API' },
{ text: 'Stats', label: 'stats API' },
{ text: 'Recent errors', label: 'status API' },
];
@@ -302,7 +302,9 @@ export class SupervisorsView extends React.PureComponent<
' "type",',
' "source",',
` CASE WHEN "suspended" = 0 THEN "detailed_state" ELSE
'SUSPENDED' END AS "detailed_state",`,
- visibleColumns.shown('Configured tasks') ? ' "spec",' : undefined,
+ visibleColumns.shown('Configured tasks') ||
visibleColumns.shown('Details')
+ ? ' "spec",'
+ : undefined,
' "suspended" = 1 AS "suspended"',
'FROM "sys"."supervisors")',
'SELECT *',
@@ -382,7 +384,7 @@ export class SupervisorsView extends React.PureComponent<
}
if (capabilities.hasOverlordAccess()) {
- if (visibleColumns.shown('Running tasks', 'Aggregate lag', 'Recent
errors')) {
+ if (visibleColumns.shown('Running tasks', 'Details', 'Recent
errors')) {
auxiliaryQueries.push(
...supervisors.map(
(supervisor): AuxiliaryQueryFn<SupervisorsWithAuxiliaryInfo> =>
@@ -526,7 +528,7 @@ export class SupervisorsView extends React.PureComponent<
const { goToView, goToStreamingDataLoader } = this.props;
const actions: BasicAction[] = [];
- if (oneOf(type, 'kafka', 'kinesis')) {
+ if (oneOf(type, 'kafka', 'kinesis', 'rabbit')) {
actions.push(
{
icon: IconNames.MULTI_SELECT,
@@ -955,20 +957,23 @@ export class SupervisorsView extends React.PureComponent<
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 className="detail-line">
- {replicas === 1
- ? '(no replication)'
- : `(${pluralIfNeeded(taskCount, 'task')} ×
${pluralIfNeeded(
- replicas,
- 'replica',
- )})`}
+ if (typeof taskCount === 'number' && typeof replicas === 'number')
{
+ return (
+ <div>
+ <div>{formatInteger(taskCount * replicas)}</div>
+ <div className="detail-line">
+ {replicas === 1
+ ? '(no replication)'
+ : `(${pluralIfNeeded(taskCount, 'task')} ×
${pluralIfNeeded(
+ replicas,
+ 'replica',
+ )})`}
+ </div>
</div>
- </div>
- );
+ );
+ }
+
+ return null;
},
show: visibleColumns.shown('Configured tasks'),
},
@@ -1011,17 +1016,28 @@ export class SupervisorsView extends
React.PureComponent<
show: visibleColumns.shown('Running tasks'),
},
{
- Header: 'Aggregate lag',
+ Header: 'Details',
+ id: 'details',
accessor: 'supervisor_id',
- width: 200,
+ width: 250,
filterable: false,
sortable: false,
className: 'padded',
- show: visibleColumns.shown('Aggregate lag'),
- Cell: ({ value }) => {
+ show: visibleColumns.shown('Details'),
+ Cell: ({ value, original }) => {
const status = useContext(StatusContext);
- const aggregateLag = status[value]?.payload?.aggregateLag;
- return isNumberLike(aggregateLag) ? formatInteger(aggregateLag) :
null;
+ const supervisorStatusPayload: SupervisorStatus['payload'] |
undefined =
+ status[value]?.payload;
+ if (oneOf(original.type, 'kafka', 'kinesis', 'rabbit')) {
+ const aggregateLag = supervisorStatusPayload?.aggregateLag;
+ return isNumberLike(aggregateLag) ? (
+ <span data-tooltip="Aggregate lag across all tasks">{`Lag:
${formatInteger(
+ aggregateLag,
+ )}`}</span>
+ ) : null;
+ } else {
+ return null;
+ }
},
},
{
@@ -1102,6 +1118,7 @@ export class SupervisorsView extends React.PureComponent<
},
{
Header: 'Recent errors',
+ id: 'recent_errors',
accessor: 'supervisor_id',
width: 150,
filterable: false,
@@ -1162,11 +1179,6 @@ export class SupervisorsView extends React.PureComponent<
}}
/>
)}
- <MenuItem
- icon={IconNames.MANUALLY_ENTERED_DATA}
- text="Submit JSON supervisor"
- onClick={() => this.setState({ supervisorSpecDialogOpen: true })}
- />
<MenuItem
icon={IconNames.PLAY}
text="Resume all supervisors"
@@ -1288,6 +1300,20 @@ export class SupervisorsView extends React.PureComponent<
this.supervisorQueryManager.rerunLastQuery(auto);
}}
/>
+ <Popover
+ position={Position.BOTTOM_LEFT}
+ content={
+ <Menu>
+ <MenuItem
+ icon={IconNames.MANUALLY_ENTERED_DATA}
+ text="Submit JSON supervisor"
+ onClick={() => this.setState({ supervisorSpecDialogOpen:
true })}
+ />
+ </Menu>
+ }
+ >
+ <Button icon={IconNames.PLUS} text="Create" />
+ </Popover>
{this.renderBulkSupervisorActions()}
<TableColumnSelector
columns={SUPERVISOR_TABLE_COLUMNS}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]