Skip to content

Commit 33d5c8c

Browse files
authored
[8.19] [Synthetics] Added compact view in monitors overview page (#219060) (#219710)
# Backport This will backport the following commits from `main` to `8.19`: - [[Synthetics] Added compact view in monitors overview page (#219060)](#219060) <!--- Backport version: 9.6.6 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Francesco Fagnani","email":"[email protected]"},"sourceCommit":{"committedDate":"2025-04-30T10:36:46Z","message":"[Synthetics] Added compact view in monitors overview page (#219060)\n\nThis PR contains the first version of the new compact view for monitors\noverview in Synthetics, see issue #217579.\n\n\n\nhttps://github.com/user-attachments/assets/b096d5c3-c8c2-4e27-a889-8dee6ef52481\n\nAdditional points:\n- When selecting a different view the value is saved in local storage.\n- All the actions available in the card view are available in the\ncompact view.\n- When adding an embeddable to a dashboard the current view is saved in\nthe dashboard state.\n\n---------\n\nCo-authored-by: Shahzad <[email protected]>","sha":"543503761693f087156518a81e103422db1bd7a7","branchLabelMapping":{"^v9.1.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:feature","Team:obs-ux-management","backport:version","v9.1.0","v8.19.0"],"title":"[Synthetics] Added compact view in monitors overview page","number":219060,"url":"https://github.com/elastic/kibana/pull/219060","mergeCommit":{"message":"[Synthetics] Added compact view in monitors overview page (#219060)\n\nThis PR contains the first version of the new compact view for monitors\noverview in Synthetics, see issue #217579.\n\n\n\nhttps://github.com/user-attachments/assets/b096d5c3-c8c2-4e27-a889-8dee6ef52481\n\nAdditional points:\n- When selecting a different view the value is saved in local storage.\n- All the actions available in the card view are available in the\ncompact view.\n- When adding an embeddable to a dashboard the current view is saved in\nthe dashboard state.\n\n---------\n\nCo-authored-by: Shahzad <[email protected]>","sha":"543503761693f087156518a81e103422db1bd7a7"}},"sourceBranch":"main","suggestedTargetBranches":["8.19"],"targetPullRequestStates":[{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/219060","number":219060,"mergeCommit":{"message":"[Synthetics] Added compact view in monitors overview page (#219060)\n\nThis PR contains the first version of the new compact view for monitors\noverview in Synthetics, see issue #217579.\n\n\n\nhttps://github.com/user-attachments/assets/b096d5c3-c8c2-4e27-a889-8dee6ef52481\n\nAdditional points:\n- When selecting a different view the value is saved in local storage.\n- All the actions available in the card view are available in the\ncompact view.\n- When adding an embeddable to a dashboard the current view is saved in\nthe dashboard state.\n\n---------\n\nCo-authored-by: Shahzad <[email protected]>","sha":"543503761693f087156518a81e103422db1bd7a7"}},{"branch":"8.19","label":"v8.19.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT-->
1 parent c2a3e2a commit 33d5c8c

40 files changed

+1505
-313
lines changed

x-pack/solutions/observability/plugins/synthetics/common/runtime_types/monitor_management/synthetics_overview_status.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export const OverviewStatusMetaDataCodec = t.intersection([
5353
updated_at: t.string,
5454
timestamp: t.string,
5555
spaceId: t.string,
56+
urls: t.string,
5657
}),
5758
]);
5859

x-pack/solutions/observability/plugins/synthetics/e2e/synthetics/journeys/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,4 @@ export * from './step_details.journey';
2828
export * from './project_monitor_read_only.journey';
2929
export * from './overview_save_lens_visualization.journey';
3030
export * from './filter_monitors.journey';
31+
export * from './overview_compact_view.journey';
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
import { before, expect, journey, step, after } from '@elastic/synthetics';
9+
import { syntheticsAppPageProvider } from '../page_objects/synthetics_app';
10+
import { SyntheticsServices } from './services/synthetics_services';
11+
12+
journey('OverviewCompactView', async ({ page, params }) => {
13+
const syntheticsApp = syntheticsAppPageProvider({ page, kibanaUrl: params.kibanaUrl, params });
14+
const syntheticsService = new SyntheticsServices(params);
15+
16+
before(async () => {
17+
await syntheticsService.cleanUp();
18+
});
19+
20+
after(async () => {
21+
await syntheticsService.cleanUp();
22+
});
23+
24+
step('Go to Monitors overview page', async () => {
25+
await syntheticsApp.navigateToOverview(true, 15);
26+
});
27+
28+
step('Create test monitor', async () => {
29+
await syntheticsService.addTestMonitor('Test Overview Compact View Monitor', {
30+
type: 'http',
31+
urls: 'https://www.google.com',
32+
locations: ['us_central'],
33+
});
34+
await page.getByTestId('syntheticsRefreshButtonButton').click();
35+
});
36+
37+
step('Change to compact view', async () => {
38+
await expect(page.getByTestId('compactView')).toBeEnabled();
39+
await page.getByTestId('compactView').click();
40+
await expect(page.getByTestId('syntheticsCompactViewTable')).toBeVisible();
41+
});
42+
43+
step('The selected view for the overview page is saved in local storage', async () => {
44+
await syntheticsApp.navigateToOverview();
45+
await expect(page.getByTestId('syntheticsCompactViewTable')).toBeVisible();
46+
});
47+
});

x-pack/solutions/observability/plugins/synthetics/public/apps/embeddables/common/monitor_configuration.tsx

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
* 2.0.
66
*/
77

8-
import React from 'react';
8+
import React, { useState } from 'react';
9+
import { i18n } from '@kbn/i18n';
910
import {
1011
EuiButton,
1112
EuiButtonEmpty,
@@ -16,17 +17,31 @@ import {
1617
EuiFlyoutBody,
1718
EuiFlyoutFooter,
1819
EuiTitle,
20+
EuiSwitch,
21+
EuiSwitchEvent,
1922
} from '@elastic/eui';
2023
import { FormattedMessage } from '@kbn/i18n-react';
2124
import { FormProvider, useForm } from 'react-hook-form';
2225
import { MonitorFilters } from '../monitors_overview/types';
2326
import { MonitorFiltersForm } from './monitor_filters_form';
27+
import { DEFAULT_OVERVIEW_VIEW, OverviewView } from '../../synthetics/state';
28+
29+
const MonitorConfigurationContext = React.createContext<{
30+
overviewView: OverviewView;
31+
onChangeCompactViewSwitch: (e: EuiSwitchEvent) => void;
32+
}>({ overviewView: DEFAULT_OVERVIEW_VIEW, onChangeCompactViewSwitch: () => {} });
33+
34+
const COMPACT_VIEW_LABEL = i18n.translate(
35+
'xpack.synthetics.embeddables.monitorsOverview.compactViewLabel',
36+
{ defaultMessage: 'Compact view' }
37+
);
2438

2539
interface MonitorConfigurationProps {
2640
initialInput?: {
2741
filters: MonitorFilters;
42+
view?: OverviewView;
2843
};
29-
onCreate: (props: { filters: MonitorFilters }) => void;
44+
onCreate: (props: { filters: MonitorFilters; view: OverviewView }) => void;
3045
onCancel: () => void;
3146
title: string;
3247
}
@@ -36,7 +51,16 @@ export function MonitorConfiguration({
3651
onCreate,
3752
onCancel,
3853
title,
39-
}: MonitorConfigurationProps) {
54+
children,
55+
}: React.PropsWithChildren<MonitorConfigurationProps>) {
56+
const [overviewView, setOverviewView] = useState<OverviewView>(
57+
initialInput?.view || DEFAULT_OVERVIEW_VIEW
58+
);
59+
60+
const onChangeCompactViewSwitch = (e: EuiSwitchEvent) => {
61+
setOverviewView(e.target.checked ? 'compactView' : 'cardView');
62+
};
63+
4064
const methods = useForm<MonitorFilters>({
4165
defaultValues: {
4266
monitorIds: [],
@@ -54,9 +78,12 @@ export function MonitorConfiguration({
5478
const newFilters = getValues();
5579
onCreate({
5680
filters: newFilters,
81+
view: overviewView,
5782
});
5883
};
5984

85+
const hasViewChanged = initialInput?.view && overviewView !== initialInput.view;
86+
6087
return (
6188
<EuiFlyout onClose={onCancel}>
6289
<EuiFlyoutHeader>
@@ -67,12 +94,20 @@ export function MonitorConfiguration({
6794
<EuiFlyoutBody>
6895
<EuiFlexGroup>
6996
<EuiFlexItem>
70-
<EuiFlexGroup>
97+
<EuiFlexGroup direction="column">
7198
<EuiFlexItem grow>
7299
<FormProvider {...methods}>
73100
<MonitorFiltersForm />
74101
</FormProvider>
75102
</EuiFlexItem>
103+
<MonitorConfigurationContext.Provider
104+
value={{
105+
overviewView,
106+
onChangeCompactViewSwitch,
107+
}}
108+
>
109+
{children}
110+
</MonitorConfigurationContext.Provider>
76111
</EuiFlexGroup>
77112
</EuiFlexItem>
78113
</EuiFlexGroup>
@@ -91,7 +126,7 @@ export function MonitorConfiguration({
91126

92127
<EuiButton
93128
data-test-subj="syntheticsMonitorConfigurationSaveButton"
94-
isDisabled={!(formState.isDirty || !initialInput)}
129+
isDisabled={!(formState.isDirty || !initialInput || hasViewChanged)}
95130
onClick={onConfirmClick}
96131
fill
97132
>
@@ -105,3 +140,17 @@ export function MonitorConfiguration({
105140
</EuiFlyout>
106141
);
107142
}
143+
144+
function ViewSwitch() {
145+
const { onChangeCompactViewSwitch, overviewView } = React.useContext(MonitorConfigurationContext);
146+
return (
147+
<EuiSwitch
148+
compressed
149+
checked={overviewView === 'compactView'}
150+
label={COMPACT_VIEW_LABEL}
151+
onChange={onChangeCompactViewSwitch}
152+
/>
153+
);
154+
}
155+
156+
MonitorConfiguration.ViewSwitch = ViewSwitch;

x-pack/solutions/observability/plugins/synthetics/public/apps/embeddables/common/monitors_open_configuration.tsx

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,36 +5,55 @@
55
* 2.0.
66
*/
77

8-
import React, { Suspense, lazy } from 'react';
8+
import React from 'react';
99
import type { CoreStart } from '@kbn/core/public';
1010
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
1111
import { toMountPoint } from '@kbn/react-kibana-mount';
1212
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
13-
import { EuiSkeletonText } from '@elastic/eui';
14-
import { MonitorFilters } from '../monitors_overview/types';
1513
import { ClientPluginsStart } from '../../../plugin';
14+
import { MonitorConfiguration } from './monitor_configuration';
15+
import { SYNTHETICS_MONITORS_EMBEDDABLE, SYNTHETICS_STATS_OVERVIEW_EMBEDDABLE } from '../constants';
16+
import { OverviewMonitorsEmbeddableCustomState } from '../monitors_overview/monitors_embeddable_factory';
17+
import { OverviewStatsEmbeddableCustomState } from '../stats_overview/stats_overview_embeddable_factory';
1618

19+
interface CommonParams {
20+
title: string;
21+
coreStart: CoreStart;
22+
pluginStart: ClientPluginsStart;
23+
}
24+
25+
type OverviewMonitorsInput = Required<OverviewMonitorsEmbeddableCustomState>;
26+
type OverviewStatsInput = Required<OverviewStatsEmbeddableCustomState>;
27+
28+
// Function overloads to provide type safety without casting
29+
export async function openMonitorConfiguration(
30+
params: CommonParams & {
31+
initialState?: OverviewMonitorsInput;
32+
type: typeof SYNTHETICS_MONITORS_EMBEDDABLE;
33+
}
34+
): Promise<OverviewMonitorsInput>;
35+
export async function openMonitorConfiguration(
36+
params: CommonParams & {
37+
initialState?: OverviewStatsInput;
38+
type: typeof SYNTHETICS_STATS_OVERVIEW_EMBEDDABLE;
39+
}
40+
): Promise<OverviewStatsInput>;
41+
42+
// Implementation
1743
export async function openMonitorConfiguration({
1844
coreStart,
1945
pluginStart,
2046
initialState,
2147
title,
22-
}: {
23-
title: string;
24-
coreStart: CoreStart;
25-
pluginStart: ClientPluginsStart;
26-
initialState?: { filters: MonitorFilters };
27-
}): Promise<{ filters: MonitorFilters }> {
48+
type,
49+
}: CommonParams & {
50+
initialState?: OverviewMonitorsInput | OverviewStatsInput;
51+
type: typeof SYNTHETICS_MONITORS_EMBEDDABLE | typeof SYNTHETICS_STATS_OVERVIEW_EMBEDDABLE;
52+
}): Promise<OverviewMonitorsInput | OverviewStatsInput> {
2853
const { overlays } = coreStart;
2954
const queryClient = new QueryClient();
3055
return new Promise(async (resolve, reject) => {
3156
try {
32-
const LazyMonitorConfiguration = lazy(async () => {
33-
const { MonitorConfiguration } = await import('./monitor_configuration');
34-
return {
35-
default: MonitorConfiguration,
36-
};
37-
});
3857
const flyoutSession = overlays.openFlyout(
3958
toMountPoint(
4059
<KibanaContextProvider
@@ -44,20 +63,22 @@ export async function openMonitorConfiguration({
4463
}}
4564
>
4665
<QueryClientProvider client={queryClient}>
47-
<Suspense fallback={<EuiSkeletonText />}>
48-
<LazyMonitorConfiguration
49-
title={title}
50-
initialInput={initialState}
51-
onCreate={(update: { filters: MonitorFilters }) => {
52-
flyoutSession.close();
53-
resolve(update);
54-
}}
55-
onCancel={() => {
56-
flyoutSession.close();
57-
reject();
58-
}}
59-
/>
60-
</Suspense>
66+
<MonitorConfiguration
67+
title={title}
68+
initialInput={initialState}
69+
onCreate={(update) => {
70+
flyoutSession.close();
71+
resolve(update);
72+
}}
73+
onCancel={() => {
74+
flyoutSession.close();
75+
reject();
76+
}}
77+
>
78+
{type === SYNTHETICS_MONITORS_EMBEDDABLE ? (
79+
<MonitorConfiguration.ViewSwitch />
80+
) : null}
81+
</MonitorConfiguration>
6182
</QueryClientProvider>
6283
</KibanaContextProvider>,
6384
coreStart

0 commit comments

Comments
 (0)