Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[infra UI] Add overview tab with the first section to asset details view #160924

Conversation

jennypavlova
Copy link
Member

@jennypavlova jennypavlova commented Jun 29, 2023

Closes #160376

Summary

This PR adds the initial version of the Overview tab including KPI tiles and metadata summary.
image

The storybook is not showing the lens charts as it will be hard because of the dependencies (we should consider if it is worth the effort to add them there in the future) The other parts look Ok:
image

Next steps 👣

There are still some parts that can be addressed separately when other parts are ready:

  • The date is currently relying on the host date picker (passed as an override) which can be fixed once the date picker is added to the page

Testing

  • Go to host view and open the flyout - the default tab is now overview tab
    • Hint: to see the chart movements better pick a wider time range (5 days for example)
image
  • Show all button in the metadata section should open the metadata tab
  • Storybook: Use yarn storybook infra to run the storybook and check both Page and Flyout

@jennypavlova jennypavlova self-assigned this Jun 29, 2023
@apmmachine
Copy link
Contributor

🤖 GitHub comments

Expand to view the GitHub comments

Just comment with:

  • /oblt-deploy : Deploy a Kibana instance using the Observability test environments.
  • run elasticsearch-ci/docs : Re-trigger the docs validation. (use unformatted text in the comment!)

@jennypavlova jennypavlova force-pushed the 160376-infra-ui-add-overview-tab-with-the-first-section-to-asset-details-view branch from f83abca to 96257f8 Compare June 29, 2023 16:55
@@ -98,6 +107,16 @@ const stories: Meta<AssetDetailsProps> = {
memoryFree: 34359738368,
},
overrides: {
overview: {
dataView: {
Copy link
Member Author

Choose a reason for hiding this comment

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

I couldn't find a good way to add the types here as I wanted to add this just to mock the data view in order to load the overview tab

@@ -38,6 +41,10 @@ export enum FlyoutTabIds {
export type TabIds = `${FlyoutTabIds}`;

export interface TabState {
overview?: {
dateRange: StringDateRange;
Copy link
Member Author

Choose a reason for hiding this comment

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

This will change once we have the date picker for now the consumer of the component will set the time range

@jennypavlova jennypavlova added Team:Infra Monitoring UI - DEPRECATED DEPRECATED - Label for the Infra Monitoring UI team. Use Team:obs-ux-infra_services release_note:skip Skip the PR/issue when compiling release notes labels Jul 3, 2023
@jennypavlova jennypavlova marked this pull request as ready for review July 3, 2023 07:31
@jennypavlova jennypavlova requested a review from a team as a code owner July 3, 2023 07:31
@elasticmachine
Copy link
Contributor

Pinging @elastic/infra-monitoring-ui (Team:Infra Monitoring UI)

@crespocarlos crespocarlos self-requested a review July 3, 2023 14:48

return (
<>
<EuiFlexGroup gutterSize="m" responsive={false} wrap={true} justifyContent="spaceBetween">
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
<EuiFlexGroup gutterSize="m" responsive={false} wrap={true} justifyContent="spaceBetween">
<EuiFlexGroup gutterSize="m" responsive={false} wrap justifyContent="spaceBetween">

@@ -0,0 +1,144 @@
/*
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm wondering what we could do to avoid duplicating this component. We should probably have a common folder. Not sure if that would work once we move the asset details to another plugin. But might be worth exploring the possibilities.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, there are other dependencies still (LensWrapper, buildCombinedHostsFilter, TooltipContent) and they are reused in other places. The host filter build helper is not really asset details specific and we can't move it because it should also live in infra in the future (so when the component lives outside of infra because we also don't want to get it from infra once we move the asset details).
I will first pull the latest main here and I will think about how to move more of the shared parts ( and at least for now we can reuse them from a common folder)

Copy link
Member Author

Choose a reason for hiding this comment

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

I moved the dependencies and checked the component and there are still some differences in the filters, also the host component is connected to the host state while in asset view I changed it to accept props for the nodeName, dateRange, and dataView. We can also have a common component and 2 wrappers to pass the data but then it's still something we need to rework when we move it, should we do that and have 3 components - one with the common parts and 2 wrappers (1 in asset details and 1 in host page)?
If we keep it in the asset details as a separate one we are also flexible to change it without affecting the host page. wdyt?

Copy link
Contributor

Choose a reason for hiding this comment

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

I like the way you did it. You moved the lens_wrapper and other common components to common/visualizations. For now, it looks great. In the future, if we realize these components are doing the same thing we can move them too

Comment on lines 248 to 249
// FLAKY: https://github.com/elastic/kibana/issues/159368
// FLAKY: https://github.com/elastic/kibana/issues/159369
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we remove these comments too?

currentTimeRange={currentTimeRange}
nodeName={node.name}
nodeType={nodeType}
onTabsStateChange={(tabId: TabIds) => onChange({ activeTabId: tabId })}
Copy link
Contributor

@crespocarlos crespocarlos Jul 4, 2023

Choose a reason for hiding this comment

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

We could remove this prop, if we make the useTabSwitcher fire the onTabsStateChange event. In consequence we could remove the onChange event handler

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok, I added the suggestion and used showTab here instead, but we are not getting rid of the onChange function because it's used to handle the other state updates. I added this commit to apply the changes, I am not sure if I understood the idea correctly so we can discuss the changes there to make sure that it's correct.

if (onShowAllClick) {
onShowAllClick(FlyoutTabIds.METADATA);
}
showTab(FlyoutTabIds.METADATA);
Copy link
Contributor

Choose a reason for hiding this comment

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

onShowAllClick will in the end call the onTabsStateChange. We could make the useTabSwitcher do that:

export function useTabSwitcher({
  initialActiveTabId,
  onTabsStateChange,
}: {
  initialActiveTabId?: TabIds;
  onTabsStateChange?: TabsStateChangeFn;
}) {
  const [activeTabId, setActiveTabId] = useState<TabIds | undefined>(initialActiveTabId);

  // This set keeps track of which tabs content have been rendered the first time.
  // We need it in order to load a tab content only if it gets clicked, and then keep it in the DOM for performance improvement.
  const renderedTabsSet = useLazyRef(() => new Set([initialActiveTabId]));

  const showTab = (tabId: TabIds) => {
    renderedTabsSet.current.add(tabId); // On a tab click, mark the tab content as allowed to be rendered
    setActiveTabId(tabId);

    if (onTabsStateChange) {
      onTabsStateChange({ activeTabId: tabId });
    }
  };

  return {
    activeTabId,
    renderedTabsSet,
    showTab,
  };
}

We'd have to change the header.tsx too, but might be a good idea to centralize this event in the context

reload: (
<EuiLink
data-test-subj="infraMetadataReloadPageLink"
onClick={() => window.location.reload()}
Copy link
Contributor

Choose a reason for hiding this comment

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

This will reload the whole page. Perhaps it's better to load only the flyout content instead

Copy link
Member Author

Choose a reason for hiding this comment

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

That was added when we implemented the metadata fetching. The idea is to reload everything if this host for example doesn't exist anymore you can't get the metadata of the same host if you reload only the tab and it will go in circles - if we reload the page we can see that the host is not in the table.
We can think about some metadata improvements and do it both here and in the metadata component separately so it's not confusing.

Copy link
Contributor

Choose a reason for hiding this comment

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

I've forced the error here, and because we store in the URL the flyout state, which contains the active host.name, I guess the user will continue in a loop if they reload the page

overview.mov

I'm wondering if just showing a message here would be enough. wdyt? Besides, window.location.reload() forces a full page refresh

Copy link
Contributor

Choose a reason for hiding this comment

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

Just realized that the Metadata tab does the same. 🤔

Copy link
Member Author

Choose a reason for hiding this comment

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

Just realized that the Metadata tab does the same. 🤔

Yes, that's why I mentioned that is better to change both places and we can do it in a separate issue and implement there only a partial reload of the flyout ( so doing the call to get the metadata ).

I'm wondering if just showing a message here would be enough.

I briefly remember when we did it for the metadata tab and also other places - the UX idea behind it was to have an action together with the errors/warnings but in general, the idea was to be a link to reload the page instead of just a text to have something the user can click directly, I think this should not be shown very often though.

Also maybe in this case of the overview tab maybe we can customize it a bit so it's not so generic - showing the charts still (even if the metadata is not available) and then having a message that the metadata couldn't load (with try again later instead of reload link for example because we will still show something and it's not really only an error to force an action 🤔 ) wdyt?

Copy link
Contributor

Choose a reason for hiding this comment

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

I briefly remember when we did it for the metadata tab and also other places - the UX idea behind it was to have an action together with the errors/warnings but in general, the idea was to be a link to reload the page instead of just a text to have something the user can click directly, I think this should not be shown very often though.

Yeah. providing users an option to recover from a failed state is good. Loading only the metadata and not reloading the whole page might be more effective.

Also maybe in this case of the overview tab maybe we can customize it a bit so it's not so generic - showing the charts still (even if the metadata is not available) and then having a message that the metadata couldn't load (with try again later instead of reload link for example because we will still show something and it's not really only an error to force an action 🤔 ) wdyt?

Agree! Blocking charts from loading if metadata fails to load seems weird. I like it.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok, so I changed it to load the charts in the overview tab and kept the same message:
image

When we change the metadata reload behavior we can extract it and reuse it here ( even have a shared component for the error state ) but for now, this should be Ok.

Copy link
Member Author

Choose a reason for hiding this comment

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

The new issue for the refactoring added: #161367

hostOsVersion: i18n.translate(
'xpack.infra.assetDetailsEmbeddable.overview.metadataHostOsVersionHeading',
{
defaultMessage: 'Host os version',
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't it be OS? (I know it's os in the mockup)

Suggested change
defaultMessage: 'Host os version',
defaultMessage: 'Host OS version',

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, probably, changed 👍

Comment on lines 98 to 111
<EuiFlexItem grow={false} key="metadata-link">
<EuiButtonEmpty
data-test-subj="infraMetadataSummaryShowAllMetadataButton"
onClick={onClick}
size="s"
flush="both"
iconSide="right"
iconType="sortRight"
>
<FormattedMessage
id="xpack.infra.assetDetailsEmbeddable.metadataSummary.showAllMetadataButton"
defaultMessage="Show all"
/>
</EuiButtonEmpty>
Copy link
Contributor

Choose a reason for hiding this comment

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

This is slightly misaligned according to the mockup. Show All has extra padding and height. Nothing major though.

mockup
image

implementation
image

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm I see the button is also smaller there, it's hard to align it as the empty button has this blue background on click. With a smaller size looks a bit better and closer to the mockup I think (I made it larger as I thought it will be more visible but most of the links are smaller so I will keep it consistent):
image

type: 'normalizedLoad1m',
trendLine: true,
backgroundColor: '#79AAD9',
title: i18n.translate('xpack.infra.hostsViewPage.metricTrend.normalizedLoad1m.title', {
Copy link
Contributor

Choose a reason for hiding this comment

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

is xpack.infra.hostsViewPage still correct in the flyout context? 🤔 . We'll need to change it for sure when we move these components to a new plugin

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch, thanks, I renamed the ones in the translation folder but forget the others, I think now I renamed them everywhere in the overview folder

nodeType={nodeType}
onTabsStateChange={(tabId: TabIds) => onChange({ activeTabId: tabId })}
dataView={overrides?.overview?.dataView}
dateRange={overrides?.overview?.dateRange!}
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's pass the dateRange as is and define a default date range in the Overview component

Suggested change
dateRange={overrides?.overview?.dateRange!}
dateRange={overrides?.overview?.dateRange}

Perhaps 15m range as default would work. wdyt?

Copy link
Member Author

Choose a reason for hiding this comment

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

Sounds good, this is temporary as I already mentioned - until we have the date picker in the tab so for the time until that this is fine (then we will remove that from the tab and prefill the date picker and rely on it - also we can have the same concept with the default there as well)

@@ -168,7 +168,7 @@ export const Table = ({ loading, rows, onSearchChange, search, showActionsColumn
interface ExpandableContentProps {
values: string | string[] | undefined;
}
const ExpandableContent = (props: ExpandableContentProps) => {
export const ExpandableContent = (props: ExpandableContentProps) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a good candidate to be moved to its own folder within asset_details. Seems like a generic component

Copy link
Member Author

Choose a reason for hiding this comment

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

Good idea, I added a new folder for generic components and moved it.

import type { HostsLensMetricChartFormulas } from '../../../../common/visualizations';
import { LensWrapper } from '../../../../pages/metrics/hosts/components/chart/lens_wrapper';
import { buildCombinedHostsFilter } from '../../../../pages/metrics/hosts/utils';
import { TooltipContent } from '../../../../pages/metrics/hosts/components/metric_explanation/tooltip_content';
Copy link
Contributor

Choose a reason for hiding this comment

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

We're importing this from ../../../../pages/metrics/hosts. Perhaps this should be moved to a common folder

Copy link
Contributor

@crespocarlos crespocarlos left a comment

Choose a reason for hiding this comment

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

Great job, Jenny! 🚀 Overview tab looks great. I've tested it and it works perfectly. Left some comments here. Let me know if you have any questions

nodeName: string;
}

export const KPIGrid = ({ nodeName, dataView, dateRange }: KPIGridProps) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

I've noticed that the KPIGrid re-renders when switching tabs. Charts are heavy and can degrade performance. Let's wrap this in a React.memo

image

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch, thanks. Added 🙂

@jennypavlova jennypavlova force-pushed the 160376-infra-ui-add-overview-tab-with-the-first-section-to-asset-details-view branch from 044ac0b to ee3c1c2 Compare July 4, 2023 16:25
Copy link
Contributor

@crespocarlos crespocarlos left a comment

Choose a reason for hiding this comment

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

Thanks for the changes! Left some follow up comments. I'm not quite sure about the reload button, we could revisit this topic later if you feel like it's not for this PR.

currentTimeRange: MetricsTimeInput;
nodeName: string;
nodeType: InventoryItemType;
onTabsStateChange?: (tabId: TabIds) => void;
Copy link
Contributor

Choose a reason for hiding this comment

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

This isn't used anymore. We can remove it now :)

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch! Removed, thanks!

@@ -0,0 +1,144 @@
/*
Copy link
Contributor

Choose a reason for hiding this comment

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

I like the way you did it. You moved the lens_wrapper and other common components to common/visualizations. For now, it looks great. In the future, if we realize these components are doing the same thing we can move them too

reload: (
<EuiLink
data-test-subj="infraMetadataReloadPageLink"
onClick={() => window.location.reload()}
Copy link
Contributor

Choose a reason for hiding this comment

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

I've forced the error here, and because we store in the URL the flyout state, which contains the active host.name, I guess the user will continue in a loop if they reload the page

overview.mov

I'm wondering if just showing a message here would be enough. wdyt? Besides, window.location.reload() forces a full page refresh

Comment on lines 29 to 32
gutterSize={'xs'}
responsive={false}
alignItems={'baseline'}
wrap={true}
Copy link
Contributor

Choose a reason for hiding this comment

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

nit:

Suggested change
gutterSize={'xs'}
responsive={false}
alignItems={'baseline'}
wrap={true}
gutterSize="xs"
responsive={false}
alignItems="baseline"
wrap

Comment on lines 12 to 13
import type { DataViewField } from '@kbn/data-views-plugin/common';
import type { DataView } from '@kbn/data-views-plugin/public';
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we import both types from /public?

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh yeah, DataViewField is also available in public, I guess the import helper got it from common. Fixed 👍

reload: (
<EuiLink
data-test-subj="infraMetadataReloadPageLink"
onClick={() => window.location.reload()}
Copy link
Contributor

Choose a reason for hiding this comment

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

Just realized that the Metadata tab does the same. 🤔

@jennypavlova jennypavlova requested a review from crespocarlos July 6, 2023 11:56
Copy link
Contributor

@crespocarlos crespocarlos left a comment

Choose a reason for hiding this comment

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

LGTM! 🚀

…-add-overview-tab-with-the-first-section-to-asset-details-view
import type { KPIProps } from './overview';
import type { StringDateRange } from '../../types';

const KPI_CHARTS: Array<Omit<KPIChartProps, 'loading' | 'subtitle'>> = [
Copy link
Contributor

@neptunian neptunian Jul 6, 2023

Choose a reason for hiding this comment

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

Would it be possible to reuse the config we have for the Hosts page for these KPIs? https://github.com/elastic/kibana/blob/main/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/kpi_grid.tsx

Copy link
Member Author

Choose a reason for hiding this comment

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

I moved the config to a common folder and now I use the same in both places 👍

Comment on lines 28 to 50
export interface KPIChartProps {
title: string;
subtitle?: string;
trendLine?: boolean;
backgroundColor: string;
type: HostsLensMetricChartFormulas;
decimals?: number;
toolTip: string;
}

const MIN_HEIGHT = 150;

export const Tile = ({
title,
type,
backgroundColor,
toolTip,
decimals = 1,
trendLine = false,
nodeName,
dateRange,
dataView,
}: KPIChartProps & KPIGridProps) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit:

Suggested change
export interface KPIChartProps {
title: string;
subtitle?: string;
trendLine?: boolean;
backgroundColor: string;
type: HostsLensMetricChartFormulas;
decimals?: number;
toolTip: string;
}
const MIN_HEIGHT = 150;
export const Tile = ({
title,
type,
backgroundColor,
toolTip,
decimals = 1,
trendLine = false,
nodeName,
dateRange,
dataView,
}: KPIChartProps & KPIGridProps) => {
export interface KPIChartProps, KPIGridProps {
title: string;
subtitle?: string;
trendLine?: boolean;
backgroundColor: string;
type: HostsLensMetricChartFormulas;
decimals?: number;
toolTip: string;
}
const MIN_HEIGHT = 150;
export const Tile = ({
title,
type,
backgroundColor,
toolTip,
decimals = 1,
trendLine = false,
nodeName,
dateRange,
dataView,
}: KPIChartProps) => {

Copy link
Member Author

Choose a reason for hiding this comment

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

I moved the config and the type to a common folder so I now import both interfaces and still have KPIChartProps & KPIGridProps is that fine?

@jennypavlova jennypavlova requested a review from neptunian July 7, 2023 11:11
@kibana-ci
Copy link
Collaborator

💚 Build Succeeded

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
infra 1381 1389 +8

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
infra 1.9MB 2.0MB +7.1KB
Unknown metric groups

ESLint disabled line counts

id before after diff
enterpriseSearch 14 16 +2
securitySolution 408 412 +4
total +6

Total ESLint disabled count

id before after diff
enterpriseSearch 15 17 +2
securitySolution 487 491 +4
total +6

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

cc @jennypavlova

@jennypavlova jennypavlova merged commit 74a7860 into elastic:main Jul 7, 2023
@jennypavlova jennypavlova deleted the 160376-infra-ui-add-overview-tab-with-the-first-section-to-asset-details-view branch July 7, 2023 15:14
@kibanamachine kibanamachine added v8.10.0 backport:skip This commit does not require backporting labels Jul 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport:skip This commit does not require backporting release_note:skip Skip the PR/issue when compiling release notes Team:Infra Monitoring UI - DEPRECATED DEPRECATED - Label for the Infra Monitoring UI team. Use Team:obs-ux-infra_services v8.10.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Infra UI] Add overview tab with the first section to asset details view
7 participants