Skip to content

Frontend for the pluggable entity metrics endpoint (Inputs page) - #26094

Merged
ousmaneo merged 12 commits into
masterfrom
feat/input-performances-fields-ui
Jun 3, 2026
Merged

Frontend for the pluggable entity metrics endpoint (Inputs page)#26094
ousmaneo merged 12 commits into
masterfrom
feat/input-performances-fields-ui

Conversation

@ousmaneo

@ousmaneo ousmaneo commented May 21, 2026

Copy link
Copy Markdown
Contributor

Wires the new GET /system/inputs/metrics endpoint into the Inputs overview as three opt-in, hidden-by-default columns. No metrics request fires unless the user enables one of them via the column picker.

New columns

Column Source Expanded section
Message Count (Last 24H) messages_per_stream (sum of values) per-stream breakdown — stream titles resolved via POST /system/catalog/entities/titles, deleted streams shown as <id> (deleted)
Extractors extractor_count lazy-loaded list from GET /system/inputs/{inputId}/extractors; "Manage extractors" lives in the section's actions slot
Associated Streams (Last 24H) derived from messages_per_stream keys linked list of stream titles

Each cell renders as a CountBadge with a chevron that flips when the matching section is open. While metrics are loading the cell shows a spinner; on error or missing data it falls back to — the table itself never blocks on the metrics fetch (two-phase render).

Scope

Inputs page only. Streams, Forwarder Inputs, and Event Definitions columns from the broader project PRD are out of scope for this PR and will land with their own backend endpoints.
/nocl
associated to #25997
part of #25928

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Refactoring (non-breaking change)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have requested a documentation update.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.

@ousmaneo
ousmaneo requested a review from a team May 22, 2026 07:12
Base automatically changed from input_columns to master May 27, 2026 11:08
@ousmaneo
ousmaneo force-pushed the feat/input-performances-fields-ui branch from 9915b9f to e75ca80 Compare May 28, 2026 06:42

@laura-b-g laura-b-g left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested and looking good in general. I have some comments in the code (nitpicks though). And I found one minor issue: For some reasons the columns in the message count table are not aligned in all cases, see screenshot:

Image

): Promise<InputMetricsResponse> => {
const query = Qs.stringify({ input_ids: inputIds, fields }, { indices: false });

return fetch('GET', qualifyUrl(`/system/inputs/metrics?${query}`));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there an API stub that we can use instead?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have the API stub yet because the backend is not ready for it.

isInitialLoading: boolean;
isError: boolean;
} => {
const stableEntities = useMemo(() => [...entities].sort((a, b) => a.id.localeCompare(b.id)), [entities]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With react compiler I think we might not need this.

placeholderData: keepPreviousData,
});

const titlesById = useMemo(() => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With react compiler I think we might not need this.

return result;
}, [data]);

const notPermittedIds = useMemo(() => new Set(data?.not_permitted_to_view ?? []), [data]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With react compiler I think we might not need this.

Comment on lines +59 to +60
const stableIds = useMemo(() => sortedUnique(inputIds), [inputIds]);
const stableFields = useMemo(() => sortedUnique(fields), [fields]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With react compiler I think we might not need useMemo

};

const [visibleInputIds, setVisibleInputIds] = useState<Array<string>>([]);
const onDataLoaded = useCallback((data: PaginatedResponse<Input>) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With React Compiler we might not need useCallback

}, []);

const { data: layoutPreferences } = useUserLayoutPreferences(resolvedTableLayout.entityTableId);
const requestedFields = useMemo(() => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With React Compiler we might not need useMemo

Comment on lines +35 to +36
const streamIds = useMemo(() => (messagesPerStream ? Object.keys(messagesPerStream) : []), [messagesPerStream]);
const titleEntities = useMemo(() => streamIds.map((id) => ({ id, type: 'streams' })), [streamIds]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here: useMemo should not be needed?


import ExtractorsSection from './ExtractorsSection';

jest.mock('logic/rest/FetchProvider', () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are using api stubs to fetch this data, we could simply mock the function for that stub. I think mocking the whole fetch provider is not ideal.

Comment on lines +36 to +37
const streamIds = useMemo(() => (messagesPerStream ? Object.keys(messagesPerStream) : []), [messagesPerStream]);
const titleEntities = useMemo(() => streamIds.map((id) => ({ id, type: 'streams' })), [streamIds]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, do we need useMemo?

@ousmaneo
ousmaneo requested a review from laura-b-g June 2, 2026 12:31
@ousmaneo
ousmaneo merged commit 50b01d6 into master Jun 3, 2026
24 checks passed
@ousmaneo
ousmaneo deleted the feat/input-performances-fields-ui branch June 3, 2026 07:58
dennisoelkers pushed a commit that referenced this pull request Jun 4, 2026
)

* Add useEntityTitles hook for bulk id -> title resolution

* Add useInputMetrics hook and per-page metrics context for Inputs

* Add Message Count, Extractors, Associated Streams columns to Inputs

* adjust extractors permissions

* fix review

---------

Co-authored-by: Laura Bergenthal-Grotlüschen <197286649+laura-b-g@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants