Skip to content

Commit 443f21b

Browse files
[Data Quality] Integrate failure store modal (#231846)
Closes #231429 ## Summary This PR integrates the Failure Store Modal in the Dataset Quality page. https://github.com/user-attachments/assets/c41d7b6e-a40b-4e5e-9a94-ec3a606012f9 Note: I'm not sure if there is a better way of refreshing the card after saving the failure store configs using the State Machine --------- Co-authored-by: kibanamachine <[email protected]>
1 parent 0365083 commit 443f21b

File tree

25 files changed

+838
-49
lines changed

25 files changed

+838
-49
lines changed

x-pack/platform/plugins/shared/dataset_quality/common/api_types.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,8 @@ export const dataStreamDetailsRt = rt.partial({
260260
services: rt.record(rt.string, rt.array(rt.string)),
261261
hosts: rt.record(rt.string, rt.array(rt.string)),
262262
userPrivileges: userPrivilegesRt,
263+
defaultRetentionPeriod: rt.string,
264+
customRetentionPeriod: rt.string,
263265
});
264266

265267
export type DataStreamDetails = rt.TypeOf<typeof dataStreamDetailsRt>;
@@ -308,3 +310,9 @@ export const getPreviewChartResponseRt = rt.type({
308310
});
309311

310312
export type PreviewChartResponse = rt.TypeOf<typeof getPreviewChartResponseRt>;
313+
314+
export const updateFailureStoreResponseRt = rt.type({
315+
headers: rt.record(rt.string, rt.unknown),
316+
});
317+
318+
export type UpdateFailureStoreResponse = rt.TypeOf<typeof updateFailureStoreResponseRt>;

x-pack/platform/plugins/shared/dataset_quality/common/data_stream_details/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,9 @@ export interface IntegrationType {
2727
areAssetsAvailable: boolean;
2828
integration?: Integration;
2929
}
30+
31+
export interface UpdateFailureStoreParams {
32+
dataStream: string;
33+
failureStoreEnabled: boolean;
34+
customRetentionPeriod?: string;
35+
}

x-pack/platform/plugins/shared/dataset_quality/common/translations.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,13 @@ export const overviewPanelDatasetQualityIndicatorFailedDocs = i18n.translate(
331331
}
332332
);
333333

334+
export const overviewPanelDatasetQualityIndicatorNoFailureStore = i18n.translate(
335+
'xpack.datasetQuality.details.overviewPanel.datasetQuality.noFailureStore',
336+
{
337+
defaultMessage: 'No failure store',
338+
}
339+
);
340+
334341
export const overviewDegradedFieldsTableLoadingText = i18n.translate(
335342
'xpack.datasetQuality.details.degradedFieldsTableLoadingText',
336343
{

x-pack/platform/plugins/shared/dataset_quality/kibana.jsonc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"requiredBundles": [
4040
"charts",
4141
"discover",
42+
"esUiShared",
4243
"stackAlerts",
4344
],
4445
"extraPublicDirs": [

x-pack/platform/plugins/shared/dataset_quality/public/components/dataset_quality_details/overview/quality_summary_cards/card.tsx

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,32 +26,46 @@ export function Card({
2626
}) {
2727
const { euiTheme } = useEuiTheme();
2828

29-
return (
29+
const style = css`
30+
height: 100%;
31+
min-width: 300px;
32+
border: ${isSelected
33+
? `${euiTheme.border.width.thick} solid ${euiTheme.colors.borderStrongPrimary}`
34+
: 'none'};
35+
background-color: ${isSelected ? euiTheme.colors.backgroundLightPrimary : 'inherit'};
36+
`;
37+
38+
const dataTestSubject = `datasetQualityDetailsSummaryKpiCard-${title}`;
39+
40+
const content = (
41+
<>
42+
<EuiText textAlign="left">{title}</EuiText>
43+
<EuiSpacer size="xs" />
44+
<EuiText textAlign="left" data-test-subj={`datasetQualityDetailsSummaryKpiValue-${title}`}>
45+
<h2>{kpiValue}</h2>
46+
</EuiText>
47+
<EuiSpacer size="xs" />
48+
<EuiText textAlign="left">{footer}</EuiText>
49+
</>
50+
);
51+
52+
return onClick ? (
3053
<EuiButtonEmpty
3154
isDisabled={isDisabled}
3255
onClick={onClick}
33-
css={css`
34-
height: 100%;
35-
min-width: 300px;
36-
border: ${isSelected
37-
? `${euiTheme.border.width.thick} solid ${euiTheme.colors.borderStrongPrimary}`
38-
: 'none'};
39-
background-color: ${isSelected ? euiTheme.colors.backgroundLightPrimary : 'inherit'};
40-
`}
56+
css={style}
4157
contentProps={{
4258
css: css`
4359
justify-content: flex-start;
4460
`,
4561
}}
46-
data-test-subj={`datasetQualityDetailsSummaryKpiCard-${title}`}
62+
data-test-subj={dataTestSubject}
4763
>
48-
<EuiText textAlign="left">{title}</EuiText>
49-
<EuiSpacer size="xs" />
50-
<EuiText textAlign="left" data-test-subj={`datasetQualityDetailsSummaryKpiValue-${title}`}>
51-
<h2>{kpiValue}</h2>
52-
</EuiText>
53-
<EuiSpacer size="xs" />
54-
<EuiText textAlign="left">{footer}</EuiText>
64+
{content}
5565
</EuiButtonEmpty>
66+
) : (
67+
<div css={style} data-test-subj={dataTestSubject}>
68+
{content}
69+
</div>
5670
);
5771
}

x-pack/platform/plugins/shared/dataset_quality/public/components/dataset_quality_details/overview/quality_summary_cards/index.tsx

Lines changed: 58 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,19 @@
55
* 2.0.
66
*/
77

8-
import { EuiFlexGroup, EuiFlexItem, EuiLink } from '@elastic/eui';
9-
import React from 'react';
8+
import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
9+
import React, { useState } from 'react';
1010
import { i18n } from '@kbn/i18n';
11+
import { FailureStoreModal } from '@kbn/failure-store-modal';
1112
import {
1213
overviewPanelDatasetQualityIndicatorDegradedDocs,
1314
overviewPanelDatasetQualityIndicatorFailedDocs,
15+
overviewPanelDatasetQualityIndicatorNoFailureStore,
1416
} from '../../../../../common/translations';
1517
import { useOverviewSummaryPanel } from '../../../../hooks/use_overview_summary_panel';
1618
import { useQualityIssuesDocsChart } from '../../../../hooks/use_quality_issues_docs_chart';
1719
import { useDatasetQualityDetailsState } from '../../../../hooks/use_dataset_quality_details_state';
1820
import { DatasetQualityIndicator, QualityPercentageIndicator } from '../../../quality_indicator';
19-
import { useKibanaContextForPlugin } from '../../../../utils/use_kibana';
2021
import { Card } from './card';
2122

2223
// Allow for lazy loading
@@ -40,20 +41,34 @@ export default function QualitySummaryCards({
4041
} = useOverviewSummaryPanel();
4142
const { handleDocsTrendChartChange } = useQualityIssuesDocsChart();
4243
const {
43-
dataStream,
4444
canUserReadFailureStore,
4545
hasFailureStore,
4646
loadingState: { dataStreamSettingsLoading },
47+
defaultRetentionPeriod,
48+
customRetentionPeriod,
49+
updateFailureStore,
4750
} = useDatasetQualityDetailsState();
4851

49-
const {
50-
services: {
51-
share: { url: urlService },
52-
},
53-
} = useKibanaContextForPlugin();
52+
const [isFailureStoreModalOpen, setIsFailureStoreModalOpen] = useState(false);
53+
54+
const closeModal = () => {
55+
setIsFailureStoreModalOpen(false);
56+
};
5457

55-
const locator = urlService.locators.get('INDEX_MANAGEMENT_LOCATOR_ID');
56-
const locatorParams = { page: 'data_streams_details', dataStreamName: dataStream } as const;
58+
const handleSaveModal = async (data: {
59+
failureStoreEnabled: boolean;
60+
customRetentionPeriod?: string;
61+
}) => {
62+
updateFailureStore({
63+
failureStoreEnabled: data.failureStoreEnabled,
64+
customRetentionPeriod: data.customRetentionPeriod,
65+
});
66+
closeModal();
67+
};
68+
69+
const onClick = () => {
70+
setIsFailureStoreModalOpen(true);
71+
};
5772

5873
return (
5974
<EuiFlexGroup gutterSize="m" direction="column" style={{ height: '100%' }}>
@@ -95,26 +110,38 @@ export default function QualitySummaryCards({
95110
</EuiFlexItem>
96111
<EuiFlexItem grow={true}>
97112
{!dataStreamSettingsLoading && !(hasFailureStore && canUserReadFailureStore) ? (
98-
<Card
99-
isDisabled={true}
100-
title={overviewPanelDatasetQualityIndicatorFailedDocs}
101-
kpiValue={i18n.translate('xpack.datasetQuality.noFailureStoreTitle', {
102-
defaultMessage: 'No failure store',
103-
})}
104-
footer={
105-
canUserReadFailureStore && (
106-
<EuiLink
107-
href={locator?.getRedirectUrl(locatorParams)}
108-
target="_blank"
109-
external={false}
110-
>
111-
{i18n.translate('xpack.datasetQuality.enableFailureStore', {
112-
defaultMessage: 'Enable failure store',
113-
})}
114-
</EuiLink>
115-
)
116-
}
117-
/>
113+
<>
114+
<Card
115+
isDisabled={true}
116+
title={overviewPanelDatasetQualityIndicatorNoFailureStore}
117+
kpiValue={i18n.translate('xpack.datasetQuality.noFailureStoreTitle', {
118+
defaultMessage: 'No failure store',
119+
})}
120+
footer={
121+
canUserReadFailureStore && (
122+
<EuiButtonEmpty
123+
onClick={onClick}
124+
data-test-subj="datasetQualityDetailsEnableFailureStoreButton"
125+
>
126+
{i18n.translate('xpack.datasetQuality.enableFailureStore', {
127+
defaultMessage: 'Enable failure store',
128+
})}
129+
</EuiButtonEmpty>
130+
)
131+
}
132+
/>
133+
{canUserReadFailureStore && isFailureStoreModalOpen && defaultRetentionPeriod && (
134+
<FailureStoreModal
135+
onCloseModal={closeModal}
136+
onSaveModal={handleSaveModal}
137+
failureStoreProps={{
138+
failureStoreEnabled: hasFailureStore,
139+
defaultRetentionPeriod,
140+
customRetentionPeriod,
141+
}}
142+
/>
143+
)}
144+
</>
118145
) : (
119146
<Card
120147
isDisabled={false}

x-pack/platform/plugins/shared/dataset_quality/public/hooks/use_dataset_quality_details_state.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,30 @@ export const useDatasetQualityDetailsState = () => {
160160
[service]
161161
);
162162

163+
const updateFailureStore = useCallback(
164+
({
165+
failureStoreEnabled,
166+
customRetentionPeriod,
167+
}: {
168+
failureStoreEnabled: boolean;
169+
customRetentionPeriod?: string;
170+
}) => {
171+
service.send({
172+
type: 'UPDATE_FAILURE_STORE',
173+
data: {
174+
...dataStreamDetails,
175+
hasFailureStore: failureStoreEnabled,
176+
customRetentionPeriod,
177+
},
178+
});
179+
},
180+
[dataStreamDetails, service]
181+
);
182+
163183
const hasFailureStore = Boolean(dataStreamDetails?.hasFailureStore);
164184
const canShowFailureStoreInfo = canUserReadFailureStore && hasFailureStore;
185+
const defaultRetentionPeriod = dataStreamDetails?.defaultRetentionPeriod;
186+
const customRetentionPeriod = dataStreamDetails?.customRetentionPeriod;
165187

166188
return {
167189
service,
@@ -180,6 +202,7 @@ export const useDatasetQualityDetailsState = () => {
180202
timeRange,
181203
loadingState,
182204
updateTimeRange,
205+
updateFailureStore,
183206
dataStreamSettings,
184207
integrationDetails,
185208
canUserAccessDashboards,
@@ -189,5 +212,7 @@ export const useDatasetQualityDetailsState = () => {
189212
canShowFailureStoreInfo,
190213
expandedQualityIssue,
191214
isQualityIssueFlyoutOpen,
215+
defaultRetentionPeriod,
216+
customRetentionPeriod,
192217
};
193218
};

x-pack/platform/plugins/shared/dataset_quality/public/services/data_stream_details/data_stream_details_client.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import type {
1616
FailedDocsErrorsResponse,
1717
IntegrationDashboardsResponse,
1818
UpdateFieldLimitResponse,
19+
UpdateFailureStoreResponse,
1920
} from '../../../common/api_types';
2021
import {
2122
checkAndLoadIntegrationResponseRt,
@@ -29,6 +30,7 @@ import {
2930
integrationDashboardsRT,
3031
qualityIssueBaseRT,
3132
updateFieldLimitResponseRt,
33+
updateFailureStoreResponseRt,
3234
} from '../../../common/api_types';
3335
import type {
3436
DataStreamDetails,
@@ -309,4 +311,34 @@ export class DataStreamDetailsClient implements IDataStreamDetailsClient {
309311
new DatasetQualityError(`Failed to decode rollover response: ${message}"`)
310312
)(response);
311313
}
314+
315+
public async updateFailureStore({
316+
dataStream,
317+
failureStoreEnabled,
318+
customRetentionPeriod,
319+
}: {
320+
dataStream: string;
321+
failureStoreEnabled: boolean;
322+
customRetentionPeriod?: string;
323+
}): Promise<UpdateFailureStoreResponse> {
324+
const response = await this.http
325+
.put<UpdateFailureStoreResponse>(
326+
`/internal/dataset_quality/data_streams/${dataStream}/update_failure_store`,
327+
{
328+
body: JSON.stringify({
329+
failureStoreEnabled,
330+
customRetentionPeriod,
331+
}),
332+
}
333+
)
334+
.catch((error) => {
335+
throw new DatasetQualityError(`Failed to update failure store": ${error}`, error);
336+
});
337+
338+
return decodeOrThrow(
339+
updateFailureStoreResponseRt,
340+
(message: string) =>
341+
new DatasetQualityError(`Failed to decode update failure store response: ${message}"`)
342+
)(response);
343+
}
312344
}

x-pack/platform/plugins/shared/dataset_quality/public/services/data_stream_details/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import type {
2323
IntegrationType,
2424
CheckAndLoadIntegrationParams,
2525
UpdateFieldLimitParams,
26+
UpdateFailureStoreParams,
2627
} from '../../../common/data_stream_details/types';
2728
import type {
2829
Dashboard,
@@ -32,6 +33,7 @@ import type {
3233
FailedDocsDetails,
3334
FailedDocsErrorsResponse,
3435
UpdateFieldLimitResponse,
36+
UpdateFailureStoreResponse,
3537
} from '../../../common/api_types';
3638

3739
export type DataStreamDetailsServiceSetup = void;
@@ -62,4 +64,5 @@ export interface IDataStreamDetailsClient {
6264
analyzeDegradedField(params: AnalyzeDegradedFieldsParams): Promise<DegradedFieldAnalysis>;
6365
setNewFieldLimit(params: UpdateFieldLimitParams): Promise<UpdateFieldLimitResponse>;
6466
rolloverDataStream(params: { dataStream: string }): Promise<DataStreamRolloverResponse>;
67+
updateFailureStore(params: UpdateFailureStoreParams): Promise<UpdateFailureStoreResponse>;
6568
}

x-pack/platform/plugins/shared/dataset_quality/public/state_machines/dataset_quality_details_controller/notifications.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,20 @@ export const rolloverDataStreamFailedNotifier = (
7777
text: error.message,
7878
});
7979
};
80+
81+
export const updateFailureStoreFailedNotifier = (toasts: IToasts, error: Error) => {
82+
toasts.addDanger({
83+
title: i18n.translate('xpack.datasetQuality.details.updateFailureStoreFailed', {
84+
defaultMessage: "We couldn't update the failure store settings.",
85+
}),
86+
text: error.message,
87+
});
88+
};
89+
90+
export const updateFailureStoreSuccessNotifier = (toasts: IToasts) => {
91+
toasts.addSuccess({
92+
title: i18n.translate('xpack.datasetQuality.details.updateFailureStoreSuccess', {
93+
defaultMessage: 'Failure store settings saved',
94+
}),
95+
});
96+
};

0 commit comments

Comments
 (0)