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] Add collapsible sections #176048

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,13 @@ export const Popover = ({
<EuiPopover
panelPaddingSize="s"
button={
<button onClick={togglePopover} data-test-subj={props['data-test-subj']}>
<button
onClick={(e) => {
e.stopPropagation();
togglePopover();
}}
cauemarcondes marked this conversation as resolved.
Show resolved Hide resolved
data-test-subj={props['data-test-subj']}
>
<EuiIcon
type="questionInCircle"
color={iconColor ?? 'text'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/
import React, { useMemo } from 'react';

import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { useSummaryTimeRange } from '@kbn/observability-plugin/public';
import type { TimeRange } from '@kbn/es-query';
import type { InventoryItemType } from '@kbn/metrics-data-access-plugin/common';
Expand All @@ -23,6 +23,7 @@ import { useBoolean } from '../../../../hooks/use_boolean';
import { ALERT_STATUS_ALL } from '../../../../common/alerts/constants';
import { AlertsSectionTitle } from '../../components/section_titles';
import { useAssetDetailsRenderPropsContext } from '../../hooks/use_asset_details_render_props';
import { CollapsibleSection } from './section/collapsible_section';

export const AlertsSummaryContent = ({
assetName,
Expand All @@ -49,25 +50,30 @@ export const AlertsSummaryContent = ({

return (
<>
<EuiFlexGroup justifyContent="spaceBetween" alignItems="center" responsive={false}>
<EuiFlexItem>
<AlertsSectionTitle />
</EuiFlexItem>
{featureFlags.inventoryThresholdAlertRuleEnabled && (
<EuiFlexItem grow={false}>
<LinkToAlertsRule onClick={toggleAlertFlyout} />
</EuiFlexItem>
)}
<EuiFlexItem grow={false}>
<LinkToAlertsPage
assetName={assetName}
queryField={`${assetType}.name`}
dateRange={dateRange}
/>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="s" />
<MemoAlertSummaryWidget alertsQuery={alertsEsQueryByStatus} dateRange={dateRange} />
<CollapsibleSection
title={AlertsSectionTitle}
collapsible
data-test-subj="infraAssetDetailsAlertsCollapsible"
id="alerts"
extraAction={
<EuiFlexGroup alignItems="center" responsive={false}>
{featureFlags.inventoryThresholdAlertRuleEnabled && (
<EuiFlexItem grow={false}>
<LinkToAlertsRule onClick={toggleAlertFlyout} />
</EuiFlexItem>
)}
<EuiFlexItem grow={false}>
<LinkToAlertsPage
assetName={assetName}
queryField={`${assetType}.name`}
dateRange={dateRange}
/>
</EuiFlexItem>
</EuiFlexGroup>
}
>
<MemoAlertSummaryWidget alertsQuery={alertsEsQueryByStatus} dateRange={dateRange} />
</CollapsibleSection>

{featureFlags.inventoryThresholdAlertRuleEnabled && (
<AlertFlyout
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
EuiDescriptionList,
EuiDescriptionListDescription,
EuiLoadingSpinner,
EuiSpacer,
} from '@elastic/eui';
import type { InfraMetadata } from '../../../../../../common/http_api';
import { NOT_AVAILABLE_LABEL } from '../../../translations';
Expand All @@ -23,6 +24,7 @@ import { ExpandableContent } from '../../../components/expandable_content';
import { MetadataHeader } from './metadata_header';
import { MetadataExplanationMessage } from '../../../components/metadata_explanation';
import { MetadataSectionTitle } from '../../../components/section_titles';
import { CollapsibleSection } from '../section/collapsible_section';

interface MetadataSummaryProps {
metadata: InfraMetadata | null;
Expand Down Expand Up @@ -80,52 +82,51 @@ const MetadataSummaryListWrapper = ({

return (
<EuiFlexGroup gutterSize="s" justifyContent="spaceBetween" direction="column" wrap>
<EuiFlexGroup direction="column" gutterSize="xs">
<EuiFlexGroup justifyContent="spaceBetween" responsive={false}>
<EuiFlexItem grow={false}>
<MetadataSectionTitle />
</EuiFlexItem>
<EuiFlexItem grow={false} key="metadata-link">
<EuiButtonEmpty
data-test-subj="infraAssetDetailsMetadataShowAllButton"
onClick={onClick}
size="xs"
flush="both"
iconSide="right"
iconType="sortRight"
>
<FormattedMessage
id="xpack.infra.assetDetailsEmbeddable.metadataSummary.showAllMetadataButton"
defaultMessage="Show all"
/>
</EuiButtonEmpty>
</EuiFlexItem>
</EuiFlexGroup>
<EuiFlexGroup>
<EuiFlexItem>
<MetadataExplanationMessage />
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexGroup>
<EuiFlexGroup>
{visibleMetadata.map(
(metadataValue) =>
metadataValue && (
<EuiFlexItem key={metadataValue.field} grow={false}>
<EuiDescriptionList data-test-subj="infraMetadataSummaryItem" compressed>
<MetadataHeader metadataValue={metadataValue} />
<EuiDescriptionListDescription>
{metadataLoading && !metadataValue.value ? (
<EuiLoadingSpinner />
) : (
<ExpandableContent values={metadataValue.value ?? NOT_AVAILABLE_LABEL} />
)}
</EuiDescriptionListDescription>
</EuiDescriptionList>
</EuiFlexItem>
)
)}
</EuiFlexGroup>
<CollapsibleSection
title={MetadataSectionTitle}
collapsible
data-test-subj="infraAssetDetailsMetadataCollapsible"
id="metadata"
extraAction={
<EuiButtonEmpty
data-test-subj="infraAssetDetailsMetadataShowAllButton"
onClick={onClick}
size="xs"
flush="both"
iconSide="right"
iconType="sortRight"
key="metadata-link"
>
<FormattedMessage
id="xpack.infra.assetDetailsEmbeddable.metadataSummary.showAllMetadataButton"
defaultMessage="Show all"
/>
</EuiButtonEmpty>
}
>
<>
<MetadataExplanationMessage />
<EuiSpacer size="s" />
<EuiFlexGroup>
{visibleMetadata
.filter((metadataValue) => metadataValue)
.map((metadataValue) => (
<EuiFlexItem key={metadataValue.field} grow={false}>
<EuiDescriptionList data-test-subj="infraMetadataSummaryItem" compressed>
<MetadataHeader metadataValue={metadataValue} />
<EuiDescriptionListDescription>
{metadataLoading && !metadataValue.value ? (
<EuiLoadingSpinner />
) : (
<ExpandableContent values={metadataValue.value ?? NOT_AVAILABLE_LABEL} />
)}
</EuiDescriptionListDescription>
</EuiDescriptionList>
</EuiFlexItem>
))}
</EuiFlexGroup>
</>
</CollapsibleSection>
</EuiFlexGroup>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
*/
import React, { useMemo } from 'react';

import { EuiFlexItem } from '@elastic/eui';
import type { DataView } from '@kbn/data-views-plugin/public';
import type { TimeRange } from '@kbn/es-query';
import { EuiFlexGroup } from '@elastic/eui';
Expand All @@ -18,6 +17,7 @@ import {
} from '../../../components/section_titles';
import { useMetadataStateContext } from '../../../hooks/use_metadata_state';
import { MetricsGrid } from './metrics_grid';
import { CollapsibleSection } from '../section/collapsible_section';

interface Props {
assetName: string;
Expand Down Expand Up @@ -49,7 +49,7 @@ export const MetricsSection = ({ assetName, metricsDataView, logsDataView, dateR

return (
<EuiFlexGroup direction="column" gutterSize="s">
<Section title={MetricsSectionTitle}>
<Section title={MetricsSectionTitle} collapsible>
<MetricsGrid
assetName={assetName}
dateRange={dateRange}
Expand Down Expand Up @@ -92,7 +92,7 @@ export const MetricsSectionCompact = ({
);

return (
<Section title={MetricsSectionTitle}>
<Section title={MetricsSectionTitle} collapsible>
<MetricsGrid
assetName={assetName}
dateRange={dateRange}
Expand All @@ -107,13 +107,14 @@ export const MetricsSectionCompact = ({
const Section = ({
title,
dependsOn = [],
collapsible = false,
children,
}: {
title: React.FunctionComponent;
dependsOn?: string[];
collapsible?: boolean;
children: React.ReactNode;
}) => {
const Title = title;
const { metadata } = useMetadataStateContext();

const shouldRender = useMemo(
Expand All @@ -124,11 +125,13 @@ const Section = ({
);

return shouldRender ? (
<EuiFlexGroup gutterSize="m" direction="column">
<EuiFlexItem grow={false}>
<Title />
</EuiFlexItem>
<EuiFlexItem grow={false}>{children}</EuiFlexItem>
</EuiFlexGroup>
<CollapsibleSection
title={title}
collapsible={collapsible}
data-test-subj={`infraAssetDetailsMetrics${collapsible ? 'Collapsible' : 'Section'}`}
id="metrics"
>
{children}
</CollapsibleSection>
) : null;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* 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 {
EuiAccordion,
EuiFlexGroup,
EuiFlexItem,
useGeneratedHtmlId,
type EuiAccordionProps,
} from '@elastic/eui';
import React, { useState } from 'react';

export const CollapsibleSection = ({
title,
closedSectionContent,
extraAction,
children,
collapsible,
['data-test-subj']: dataTestSubj,
id,
}: {
title: React.FunctionComponent;
closedSectionContent?: React.ReactNode;
extraAction?: React.ReactNode;
dependsOn?: string[];
children: React.ReactNode;
collapsible: boolean;
['data-test-subj']: string;
id: string;
}) => {
const [trigger, setTrigger] = useState<EuiAccordionProps['forceState']>('open');

const Title = title;
const ButtonContent = () =>
closedSectionContent && trigger === 'closed' ? (
<EuiFlexGroup gutterSize="m">
<EuiFlexItem grow={false}>
<Title />
</EuiFlexItem>
<EuiFlexItem grow={false}>{closedSectionContent}</EuiFlexItem>
</EuiFlexGroup>
) : (
<Title />
);
const collapsibleSectionAccordionId = useGeneratedHtmlId({
prefix: id,
});

const onToggle = (isOpen: boolean) => {
const newState = isOpen ? 'open' : 'closed';
setTrigger(newState);
};

return collapsible ? (
<EuiAccordion
id={collapsibleSectionAccordionId}
data-section-id={id}
buttonElement="div"
element="fieldset"
buttonContent={<ButtonContent />}
buttonProps={{ 'data-test-subj': dataTestSubj }}
paddingSize="s"
initialIsOpen={true}
extraAction={extraAction ?? undefined}
forceState={trigger}
onToggle={onToggle}
data-section-state={trigger}
data-test-subj="infraAssetDetailsCollapseExpandSection"
>
{children}
</EuiAccordion>
) : (
<EuiFlexGroup gutterSize="m" direction="column">
<EuiFlexItem grow={false}>
<Title />
</EuiFlexItem>
<EuiFlexItem grow={false}>{children}</EuiFlexItem>
</EuiFlexGroup>
);
};
6 changes: 6 additions & 0 deletions x-pack/test/functional/apps/infra/hosts_view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
expect(hosts.length).to.equal(9);
});

it('should show all section as collapsable', async () => {
await pageObjects.assetDetails.metadataSectionCollapsibleExist();
await pageObjects.assetDetails.alertsSectionCollapsibleExist();
await pageObjects.assetDetails.metricsSectionCollapsibleExist();
});

it('should show alerts', async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
await pageObjects.assetDetails.overviewAlertsTitleExists();
Expand Down
6 changes: 6 additions & 0 deletions x-pack/test/functional/apps/infra/node_details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
expect(hosts.length).to.equal(12);
});

it('should show all section as collapsable', async () => {
await pageObjects.assetDetails.metadataSectionCollapsibleExist();
await pageObjects.assetDetails.alertsSectionCollapsibleExist();
await pageObjects.assetDetails.metricsSectionCollapsibleExist();
});

it('should show alerts', async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
await pageObjects.assetDetails.overviewAlertsTitleExists();
Expand Down
11 changes: 11 additions & 0 deletions x-pack/test/functional/page_objects/asset_details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,17 @@ export function AssetDetailsProvider({ getService }: FtrProviderContext) {
return await testSubjects.missingOrFail('infraAssetDetailsProfilingTab');
},

// Collapsable sections
async metadataSectionCollapsibleExist() {
return await testSubjects.existOrFail('infraAssetDetailsMetadataCollapsible');
},
async alertsSectionCollapsibleExist() {
return await testSubjects.existOrFail('infraAssetDetailsAlertsCollapsible');
},
async metricsSectionCollapsibleExist() {
return await testSubjects.existOrFail('infraAssetDetailsMetricsCollapsible');
},

// Metadata
async clickMetadataTab() {
return testSubjects.click('infraAssetDetailsMetadataTab');
Expand Down