Skip to content

Commit

Permalink
🌊 Streams: Management base page (elastic#201649)
Browse files Browse the repository at this point in the history
<img width="659" alt="Screenshot 2024-11-25 at 17 50 18"
src="https://github.com/user-attachments/assets/1f623207-a5cb-4a76-9d0e-c4ff811ab854">

This PR adds an empty placeholder for the different parts of the
management tab which will be filled later on by follow-up PRs like
elastic#201427

Changes:
* Make the whole tree of wrapper elements flex so eventual page content
can easily grow to the full height of the viewport. This is important
for the preview view for routing and parsing. Doing this required some
changes to existing listing and detail pages which just took the part of
the page they actually needed. The changes come down to setting `grow:
false` on the header wrapper and `grow: true` on the content wrapper
* Introduce another routing layer: `{key}/{tab}/{subtab}` to support the
two-leveled tabs of management. As our routing helpers don't support
optional path variables, I slightly extended them to pass through the
`optional` flag so the stream detail component can try to parse the path
for both key/tab and key/tab/subtab and go with whatever works.
* Add the second tabbing layer for the management view component and add
placeholders for the three subtabs we are going to need.
* Pass through a callback to refresh the stream definition that's passed
down - this will come in handy in the various management views because
the user can make changes and we want to update the stream definition
once the change is submitted

---------

Co-authored-by: Dario Gieselaar <[email protected]>
  • Loading branch information
flash1293 and dgieselaar authored Nov 27, 2024
1 parent 01c18c2 commit 40411b4
Show file tree
Hide file tree
Showing 12 changed files with 287 additions and 99 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { EuiFlexGroup, EuiIcon, EuiLink, EuiPanel } from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiLink, EuiPanel } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { useStreamsAppBreadcrumbs } from '../../hooks/use_streams_app_breadcrumbs';
Expand Down Expand Up @@ -71,31 +71,35 @@ export function EntityDetailViewWithoutParams({

return (
<EuiFlexGroup direction="column" gutterSize="none">
<EuiPanel color="transparent">
<EuiLink data-test-subj="streamsEntityDetailViewGoBackHref" href={router.link('/')}>
<EuiFlexGroup direction="row" alignItems="center" gutterSize="s">
<EuiIcon type="arrowLeft" />
{i18n.translate('xpack.streams.entityDetailView.goBackLinkLabel', {
defaultMessage: 'Back',
<EuiFlexItem grow={false}>
<EuiPanel color="transparent">
<EuiLink data-test-subj="streamsEntityDetailViewGoBackHref" href={router.link('/')}>
<EuiFlexGroup direction="row" alignItems="center" gutterSize="s">
<EuiIcon type="arrowLeft" />
{i18n.translate('xpack.streams.entityDetailView.goBackLinkLabel', {
defaultMessage: 'Back',
})}
</EuiFlexGroup>
</EuiLink>
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<StreamsAppPageHeader
verticalPaddingSize="none"
title={<StreamsAppPageHeaderTitle title={entity.displayName} />}
>
<EntityOverviewTabList
tabs={Object.entries(tabMap).map(([tabKey, { label, href }]) => {
return {
name: tabKey,
label,
href,
selected: selectedTab === tabKey,
};
})}
</EuiFlexGroup>
</EuiLink>
</EuiPanel>
<StreamsAppPageHeader
verticalPaddingSize="none"
title={<StreamsAppPageHeaderTitle title={entity.displayName} />}
>
<EntityOverviewTabList
tabs={Object.entries(tabMap).map(([tabKey, { label, href }]) => {
return {
name: tabKey,
label,
href,
selected: selectedTab === tabKey,
};
})}
/>
</StreamsAppPageHeader>
/>
</StreamsAppPageHeader>
</EuiFlexItem>
<StreamsAppPageBody>{selectedTabObject.content}</StreamsAppPageBody>
</EuiFlexGroup>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { StreamDefinition } from '@kbn/streams-plugin/common';
import React from 'react';

export function StreamDetailEnriching({
definition: _definition,
refreshDefinition: _refreshDefinition,
}: {
definition?: StreamDefinition;
refreshDefinition: () => void;
}) {
return <>{'TODO'}</>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React from 'react';
import { i18n } from '@kbn/i18n';
import { StreamDefinition } from '@kbn/streams-plugin/common';
import { EuiButtonGroup, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { useStreamsAppParams } from '../../hooks/use_streams_app_params';
import { RedirectTo } from '../redirect_to';
import { useStreamsAppRouter } from '../../hooks/use_streams_app_router';
import { StreamDetailRouting } from '../stream_detail_routing';
import { StreamDetailEnriching } from '../stream_detail_enriching';
import { StreamDetailSchemaEditor } from '../stream_detail_schema_editor';

type ManagementSubTabs = 'route' | 'enrich' | 'schemaEditor';

function isValidManagementSubTab(value: string): value is ManagementSubTabs {
return ['route', 'enrich', 'schemaEditor'].includes(value);
}

export function StreamDetailManagement({
definition,
refreshDefinition,
}: {
definition?: StreamDefinition;
refreshDefinition: () => void;
}) {
const {
path: { key, subtab },
} = useStreamsAppParams('/{key}/management/{subtab}');
const router = useStreamsAppRouter();

const tabs = {
route: {
content: (
<StreamDetailRouting definition={definition} refreshDefinition={refreshDefinition} />
),
label: i18n.translate('xpack.streams.streamDetailView.routingTab', {
defaultMessage: 'Streams Partitioning',
}),
},
enrich: {
content: (
<StreamDetailEnriching definition={definition} refreshDefinition={refreshDefinition} />
),
label: i18n.translate('xpack.streams.streamDetailView.enrichingTab', {
defaultMessage: 'Extract field',
}),
},
schemaEditor: {
content: (
<StreamDetailSchemaEditor definition={definition} refreshDefinition={refreshDefinition} />
),
label: i18n.translate('xpack.streams.streamDetailView.schemaEditorTab', {
defaultMessage: 'Schema editor',
}),
},
};

if (!isValidManagementSubTab(subtab)) {
return (
<RedirectTo path="/{key}/management/{subtab}" params={{ path: { key, subtab: 'route' } }} />
);
}

const selectedTabObject = tabs[subtab];

return (
<EuiFlexGroup direction="column" gutterSize="none">
<EuiFlexItem grow={false}>
<EuiButtonGroup
legend="Management tabs"
idSelected={subtab}
onChange={(optionId) => {
router.push('/{key}/management/{subtab}', {
path: { key, subtab: optionId },
query: {},
});
}}
options={Object.keys(tabs).map((id) => ({
id,
label: tabs[id as ManagementSubTabs].label,
}))}
/>
</EuiFlexItem>
<EuiFlexItem grow>{selectedTabObject.content}</EuiFlexItem>
</EuiFlexGroup>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,54 +114,58 @@ export function StreamDetailOverview({ definition }: { definition?: StreamDefini
return (
<>
<EuiFlexGroup direction="column">
<EuiFlexGroup direction="row" gutterSize="s">
<EuiFlexItem grow>
<StreamsAppSearchBar
onQuerySubmit={({ dateRange }, isUpdate) => {
if (!isUpdate) {
<EuiFlexItem grow={false}>
<EuiFlexGroup direction="row" gutterSize="s">
<EuiFlexItem grow>
<StreamsAppSearchBar
onQuerySubmit={({ dateRange }, isUpdate) => {
if (!isUpdate) {
histogramQueryFetch.refresh();
return;
}

if (dateRange) {
setTimeRange({ from: dateRange.from, to: dateRange?.to, mode: dateRange.mode });
}
}}
onRefresh={() => {
histogramQueryFetch.refresh();
return;
}

if (dateRange) {
setTimeRange({ from: dateRange.from, to: dateRange?.to, mode: dateRange.mode });
}
}}
onRefresh={() => {
histogramQueryFetch.refresh();
}}
placeholder={i18n.translate(
'xpack.streams.entityDetailOverview.searchBarPlaceholder',
{
defaultMessage: 'Filter data by using KQL',
}
)}
dateRangeFrom={timeRange.from}
dateRangeTo={timeRange.to}
/>
</EuiFlexItem>
<EuiButton
data-test-subj="streamsDetailOverviewOpenInDiscoverButton"
iconType="discoverApp"
href={discoverLink}
color="text"
>
{i18n.translate('xpack.streams.streamDetailOverview.openInDiscoverButtonLabel', {
defaultMessage: 'Open in Discover',
})}
</EuiButton>
</EuiFlexGroup>
<EuiPanel hasShadow={false} hasBorder>
<EuiFlexGroup direction="column">
<ControlledEsqlChart
result={histogramQueryFetch}
id="entity_log_rate"
metricNames={['metric']}
height={200}
chartType={'bar'}
/>
}}
placeholder={i18n.translate(
'xpack.streams.entityDetailOverview.searchBarPlaceholder',
{
defaultMessage: 'Filter data by using KQL',
}
)}
dateRangeFrom={timeRange.from}
dateRangeTo={timeRange.to}
/>
</EuiFlexItem>
<EuiButton
data-test-subj="streamsDetailOverviewOpenInDiscoverButton"
iconType="discoverApp"
href={discoverLink}
color="text"
>
{i18n.translate('xpack.streams.streamDetailOverview.openInDiscoverButtonLabel', {
defaultMessage: 'Open in Discover',
})}
</EuiButton>
</EuiFlexGroup>
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiPanel hasShadow={false} hasBorder>
<EuiFlexGroup direction="column">
<ControlledEsqlChart
result={histogramQueryFetch}
id="entity_log_rate"
metricNames={['metric']}
height={200}
chartType={'bar'}
/>
</EuiFlexGroup>
</EuiPanel>
</EuiFlexItem>
</EuiFlexGroup>
</>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { StreamDefinition } from '@kbn/streams-plugin/common';
import React from 'react';

export function StreamDetailRouting({
definition: _definition,
refreshDefinition: _refreshDefinition,
}: {
definition?: StreamDefinition;
refreshDefinition: () => void;
}) {
return <>{'TODO'}</>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { StreamDefinition } from '@kbn/streams-plugin/common';
import React from 'react';

export function StreamDetailSchemaEditor({
definition: _definition,
refreshDefinition: _refreshDefinition,
}: {
definition?: StreamDefinition;
refreshDefinition: () => void;
}) {
return <>{'TODO'}</>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ import { useStreamsAppParams } from '../../hooks/use_streams_app_params';
import { useStreamsAppFetch } from '../../hooks/use_streams_app_fetch';
import { useKibana } from '../../hooks/use_kibana';
import { StreamDetailOverview } from '../stream_detail_overview';
import { StreamDetailManagement } from '../stream_detail_management';

export function StreamDetailView() {
const {
path: { key, tab },
} = useStreamsAppParams('/{key}/{tab}');
const { path } = useStreamsAppParams('/{key}/*');

const key = path.key;
const tab = 'tab' in path ? path.tab : 'management';

const {
dependencies: {
Expand All @@ -25,7 +27,7 @@ export function StreamDetailView() {
},
} = useKibana();

const { value: streamEntity } = useStreamsAppFetch(
const { value: streamEntity, refresh } = useStreamsAppFetch(
({ signal }) => {
return streamsRepositoryClient.fetch('GET /api/streams/{id}', {
signal,
Expand Down Expand Up @@ -54,7 +56,7 @@ export function StreamDetailView() {
},
{
name: 'management',
content: <></>,
content: <StreamDetailManagement definition={streamEntity} refreshDefinition={refresh} />,
label: i18n.translate('xpack.streams.streamDetailView.managementTab', {
defaultMessage: 'Management',
}),
Expand Down
Loading

0 comments on commit 40411b4

Please sign in to comment.