Skip to content

Commit 4f63726

Browse files
kaituogithub-actions[bot]
authored andcommitted
Update Frontend for Custom Result Index Query and Fix Issues (#772)
* Update Frontend for Custom Result Index Query and Fix Issues This PR finalizes the frontend changes related to PR #1225. The custom result index query now uses an index pattern instead of a single index. Additionally, this PR addresses an issue where missing custom result indices would appear because the original code checked for the existence of an index name, but now we use it as a prefix. We have updated the logic to perform a prefix search instead of checking for index name equality. This PR also resolves issue #765 by downgrading the version of jest-canvas-mock. Testing Done: * Added unit tests. * Verified that the custom result index missing callout is not shown. * Confirmed that the frontend can still display old and new results after a rollover. Signed-off-by: Kaituo Li <kaituo@amazon.com> * change to check alias Signed-off-by: Kaituo Li <kaituo@amazon.com> * fix warning msg Signed-off-by: Kaituo Li <kaituo@amazon.com> --------- Signed-off-by: Kaituo Li <kaituo@amazon.com> (cherry picked from commit 6513e1b)
1 parent 14ebd03 commit 4f63726

File tree

11 files changed

+449
-26
lines changed

11 files changed

+449
-26
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"babel-polyfill": "^6.26.0",
3030
"eslint-plugin-no-unsanitized": "^3.0.2",
3131
"eslint-plugin-prefer-object-spread": "^1.2.1",
32-
"jest-canvas-mock": "^2.5.2",
32+
"jest-canvas-mock": "^2.5.1",
3333
"lint-staged": "^9.2.0",
3434
"moment": "^2.24.0",
3535
"redux-mock-store": "^1.5.4",

public/pages/DefineDetector/components/CustomResultIndex/CustomResultIndex.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ function CustomResultIndex(props: CustomResultIndexProps) {
8989
<EuiFlexItem>
9090
<EuiCallOut
9191
data-test-subj="cannotEditResultIndexCallout"
92-
title="You can't change the custom result index after creating the detector. You can manage the result index using the following three settings inside Anomaly Detection plugin or with the Index Management plugin."
92+
title="You can't change the custom result index after creating the detector. You can manage the result index using the following three settings."
9393
color="warning"
9494
iconType="alert"
9595
size="s"

public/pages/DetectorDetail/containers/DetectorDetail.tsx

+17-11
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ import {
4545
getDetector,
4646
stopHistoricalDetector,
4747
} from '../../../redux/reducers/ad';
48-
import { getIndices } from '../../../redux/reducers/opensearch';
48+
import { getAliases, getIndices } from '../../../redux/reducers/opensearch';
4949
import { getErrorMessage, Listener } from '../../../utils/utils';
5050
import { darkModeEnabled } from '../../../utils/opensearchDashboardsUtils';
5151
import { BREADCRUMBS, MDS_BREADCRUMBS } from '../../../utils/constants';
@@ -62,8 +62,8 @@ import {
6262
prettifyErrorMessage,
6363
} from '../../../../server/utils/helpers';
6464
import { DETECTOR_STATE } from '../../../../server/utils/constants';
65-
import { CatIndex } from '../../../../server/models/types';
66-
import { containsIndex } from '../utils/helpers';
65+
import { CatIndex, IndexAlias } from '../../../../server/models/types';
66+
import { containsIndex, containsAlias } from '../utils/helpers';
6767
import { DataSourceViewConfig } from '../../../../../../src/plugins/data_source_management/public';
6868
import {
6969
getDataSourceManagementPlugin,
@@ -136,29 +136,34 @@ export const DetectorDetail = (props: DetectorDetailProps) => {
136136
const isCatIndicesRequesting = useSelector(
137137
(state: AppState) => state.opensearch.requesting
138138
) as boolean;
139+
const visibleAliases = useSelector(
140+
(state: AppState) => state.opensearch.aliases
141+
) as IndexAlias[];
139142

140143
/*
141144
Determine if the result index is missing based on several conditions:
142145
- If the detector is still loading, the result index is not missing.
143146
- If the result index retrieved from the detector is empty, it is not missing.
144147
- If cat indices are being requested, the result index is not missing.
145-
- If visible indices are empty, it is likely there is an issue retrieving existing indices.
148+
- If visible indices/aliaes are empty, it is likely there is an issue retrieving existing indices.
146149
To be safe, we'd rather not show the error message and consider the result index not missing.
147150
- If the result index is not found in the visible indices, then it is missing.
148151
*/
152+
const resultIndexOrAlias = get(detector, 'resultIndex', '')
149153
const isResultIndexMissing = isLoadingDetector
150154
? false
151155
: isEmpty(get(detector, 'resultIndex', ''))
152156
? false
153157
: isCatIndicesRequesting
154158
? false
155-
: isEmpty(visibleIndices)
159+
: isEmpty(visibleIndices) || isEmpty(visibleAliases)
156160
? false
157-
: !containsIndex(get(detector, 'resultIndex', ''), visibleIndices);
161+
: !containsIndex(resultIndexOrAlias, visibleIndices) && !containsAlias(resultIndexOrAlias, visibleAliases);
158162

159163
// debug message: prints visibleIndices if isResultIndexMissing is true
160164
if (isResultIndexMissing) {
161-
console.log(`isResultIndexMissing is true, visibleIndices: ${visibleIndices}, detector result index: ${get(detector, 'resultIndex', '')}`);
165+
// The JSON.stringify method converts a JavaScript object or value to a JSON string. The optional null parameter is for the replacer function (not used here), and 2 specifies the indentation level for pretty-printing the JSON.
166+
console.log(`isResultIndexMissing is true, visibleIndices: ${JSON.stringify(visibleIndices, null, 2)}, visibleAliases: ${JSON.stringify(visibleAliases, null, 2)}, detector result index: ${resultIndexOrAlias}`);
162167
}
163168

164169
// String to set in the modal if the realtime detector and/or historical analysis
@@ -197,20 +202,21 @@ export const DetectorDetail = (props: DetectorDetailProps) => {
197202
scroll(0, 0);
198203
}, []);
199204

200-
// Getting all visible indices. Will re-fetch if changes to the detector (e.g.,
205+
// Getting all visible indices & aliases. Will re-fetch if changes to the detector (e.g.,
201206
// detector starts, result index recreated or user switches tabs to re-fetch detector)
202207
useEffect(() => {
203-
const getInitialIndices = async () => {
208+
const getInitialIndicesAliases = async () => {
204209
try {
205210
await dispatch(getIndices('', dataSourceId));
211+
await dispatch(getAliases('', dataSourceId));
206212
} catch (error) {
207213
console.error(error);
208-
core.notifications.toasts.addDanger('Error getting all indices');
214+
core.notifications.toasts.addDanger('Error getting all indices or aliases');
209215
}
210216
};
211217
// only need to check if indices exist after detector finishes loading
212218
if (!isLoadingDetector) {
213-
getInitialIndices();
219+
getInitialIndicesAliases();
214220
}
215221
}, [detector]);
216222

public/pages/DetectorDetail/containers/__tests__/CustomIndexErrorMsg.test.tsx

+79-2
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ describe('detector detail', () => {
209209
expect(element).toBeNull();
210210
});
211211

212-
test('the result index is not found in the visible indices', () => {
212+
test('the result index is not found in the visible indices but alias is empty', () => {
213213
const detectorInfo = {
214214
detector: getRandomDetector(true, resultIndex),
215215
hasError: false,
@@ -236,7 +236,7 @@ describe('detector detail', () => {
236236
const element = screen.queryByTestId('missingResultIndexCallOut');
237237

238238
// Assert that the element is in the document
239-
expect(element).not.toBeNull();
239+
expect(element).toBeNull();
240240
});
241241

242242
test('the result index is found in the visible indices', () => {
@@ -272,4 +272,81 @@ describe('detector detail', () => {
272272
// Assert that the element is not in the document
273273
expect(element).toBeNull();
274274
});
275+
276+
test('the result index prefix is found in the visible aliaes', () => {
277+
const detector = getRandomDetector(true, resultIndex);
278+
const resultIndexFull = resultIndex + '-history-2024.06.05-1';
279+
280+
// Set up the mock implementation for useFetchDetectorInfo
281+
(useFetchDetectorInfo as jest.Mock).mockImplementation(() => ({
282+
detector: detector,
283+
hasError: false,
284+
isLoadingDetector: false,
285+
errorMessage: undefined,
286+
}));
287+
288+
const initialState = {
289+
opensearch: {
290+
indices: [
291+
{ health: 'green', index: '.kibana_-962704462_v992471_1' },
292+
{ health: 'green', index: resultIndexFull},
293+
],
294+
aliases : [
295+
{index: '.opendistro-anomaly-results-history-2024.06.08-1', alias: '.opendistro-anomaly-results'},
296+
{index: resultIndexFull, alias: resultIndex},
297+
{index: '.kibana_1', alias: '.kibana'},
298+
],
299+
requesting: false,
300+
},
301+
ad: {
302+
detectors: {},
303+
},
304+
alerting: {
305+
monitors: {},
306+
},
307+
};
308+
309+
renderWithRouter(detectorId, initialState);
310+
const element = screen.queryByTestId('missingResultIndexCallOut');
311+
312+
// Assert that the element is not in the document
313+
expect(element).toBeNull();
314+
});
315+
316+
test('the result index prefix is not found in both visible aliaes and indices', () => {
317+
const detector = getRandomDetector(true, resultIndex);
318+
319+
// Set up the mock implementation for useFetchDetectorInfo
320+
(useFetchDetectorInfo as jest.Mock).mockImplementation(() => ({
321+
detector: detector,
322+
hasError: false,
323+
isLoadingDetector: false,
324+
errorMessage: undefined,
325+
}));
326+
327+
const initialState = {
328+
opensearch: {
329+
indices: [
330+
{ health: 'green', index: '.kibana_-962704462_v992471_1' },
331+
],
332+
aliases : [
333+
{index: '.opendistro-anomaly-results-history-2024.06.08-1', alias: '.opendistro-anomaly-results'},
334+
{index: '.kibana_1', alias: '.kibana'},
335+
],
336+
requesting: false,
337+
},
338+
ad: {
339+
detectors: {},
340+
},
341+
alerting: {
342+
monitors: {},
343+
},
344+
};
345+
346+
renderWithRouter(detectorId, initialState);
347+
const element = screen.queryByTestId('missingResultIndexCallOut');
348+
349+
// Assert that the element is not in the document
350+
expect(element).not.toBeNull();
351+
});
275352
});

public/pages/DetectorDetail/utils/helpers.tsx

+24-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { DETECTOR_STATE } from '../../../../server/utils/constants';
1717
import { Detector } from '../../../models/interfaces';
1818
import { EuiHealth } from '@elastic/eui';
1919
import moment from 'moment';
20-
import { CatIndex } from '../../../../server/models/types';
20+
import { CatIndex, IndexAlias } from '../../../../server/models/types';
2121

2222
export const getInitFailureMessageAndActionItem = (error: string): object => {
2323
const failureDetails = Object.values(DETECTOR_INIT_FAILURES);
@@ -142,6 +142,17 @@ export const getDetectorStateDetails = (
142142
);
143143
};
144144

145+
/**
146+
* Checks if any of the given indices contain the specified index.
147+
*
148+
* This function iterates through an array of `CatIndex` objects and checks if the `index` property of any
149+
* `CatIndex` object equals to the specified `index` string. It returns `true` if such an `index` is found,
150+
* otherwise it returns `false`.
151+
*
152+
* @param index - The string to check against the `index` properties of the `CatIndex` objects.
153+
* @param indices - An array of `CatIndex` objects to search through.
154+
* @returns A boolean value indicating whether any `CatIndex` object's `index` property equals to the specified prefix.
155+
*/
145156
export const containsIndex = (index: string, indices: CatIndex[]) => {
146157
let containsIndex = false;
147158
if (!isEmpty(indices)) {
@@ -153,3 +164,15 @@ export const containsIndex = (index: string, indices: CatIndex[]) => {
153164
}
154165
return containsIndex;
155166
};
167+
168+
export const containsAlias = (alias: string, aliases: IndexAlias[]) => {
169+
let containsAlias = false;
170+
if (!isEmpty(aliases)) {
171+
aliases.forEach((catAlias: IndexAlias) => {
172+
if (get(catAlias, 'alias', '') == alias) {
173+
containsAlias = true;
174+
}
175+
});
176+
}
177+
return containsAlias;
178+
};

public/pages/ReviewAndCreate/components/DetectorDefinitionFields/DetectorDefinitionFields.tsx

+7-3
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,10 @@ export const DetectorDefinitionFields = (
131131
}
132132
};
133133

134+
const minAge = get(props, 'detector.resultIndexMinAge', '-');
135+
const minSize = get(props, 'detector.resultIndexMinSize', '-');
136+
const ttl = get(props, 'detector.resultIndexTtl', '-');
137+
134138
return (
135139
<ContentPanel
136140
title="Detector settings"
@@ -220,19 +224,19 @@ export const DetectorDefinitionFields = (
220224
<EuiFlexItem>
221225
<ConfigCell
222226
title="Custom result index min age"
223-
description={get(props, 'detector.resultIndexMinAge', '-') + ' Days'}
227+
description={minAge === '-' ? minAge : `${minAge} Days`}
224228
/>
225229
</EuiFlexItem>
226230
<EuiFlexItem>
227231
<ConfigCell
228232
title="Custom result index min size"
229-
description={get(props, 'detector.resultIndexMinSize', '-') + ' MB'}
233+
description={minSize == '-' ? minSize : `${minSize} MB`}
230234
/>
231235
</EuiFlexItem>
232236
<EuiFlexItem>
233237
<ConfigCell
234238
title="Custom result index TTL"
235-
description={get(props, 'detector.resultIndexTtl', '-') + ' Days'}
239+
description={ttl == '-' ? ttl : `${ttl} Days`}
236240
/>
237241
</EuiFlexItem>
238242
</EuiFlexGrid>

public/pages/ReviewAndCreate/containers/__tests__/__snapshots__/ReviewAndCreate.test.tsx.snap

+6-6
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,7 @@ exports[`<ReviewAndCreate /> spec renders the component, validation loading 1`]
424424
<p
425425
class="enabled"
426426
>
427-
- Days
427+
-
428428
</p>
429429
</div>
430430
</div>
@@ -458,7 +458,7 @@ exports[`<ReviewAndCreate /> spec renders the component, validation loading 1`]
458458
<p
459459
class="enabled"
460460
>
461-
- MB
461+
-
462462
</p>
463463
</div>
464464
</div>
@@ -492,7 +492,7 @@ exports[`<ReviewAndCreate /> spec renders the component, validation loading 1`]
492492
<p
493493
class="enabled"
494494
>
495-
- Days
495+
-
496496
</p>
497497
</div>
498498
</div>
@@ -1518,7 +1518,7 @@ exports[`issue in detector validation issues in feature query 1`] = `
15181518
<p
15191519
class="enabled"
15201520
>
1521-
- Days
1521+
-
15221522
</p>
15231523
</div>
15241524
</div>
@@ -1552,7 +1552,7 @@ exports[`issue in detector validation issues in feature query 1`] = `
15521552
<p
15531553
class="enabled"
15541554
>
1555-
- MB
1555+
-
15561556
</p>
15571557
</div>
15581558
</div>
@@ -1586,7 +1586,7 @@ exports[`issue in detector validation issues in feature query 1`] = `
15861586
<p
15871587
class="enabled"
15881588
>
1589-
- Days
1589+
-
15901590
</p>
15911591
</div>
15921592
</div>

0 commit comments

Comments
 (0)