Skip to content

Commit b26f8c3

Browse files
authored
Adding remote indices and multi index functionality (opensearch-project#854)
* Adding remote indices and multi index functionality Signed-off-by: Amit Galitzky <amgalitz@amazon.com> * changing removed index check Signed-off-by: Amit Galitzky <amgalitz@amazon.com> --------- Signed-off-by: Amit Galitzky <amgalitz@amazon.com>
1 parent 9874c48 commit b26f8c3

File tree

33 files changed

+2497
-362
lines changed

33 files changed

+2497
-362
lines changed

public/components/FeatureAnywhereContextMenu/CreateAnomalyDetector/AddAnomalyDetector.tsx

+20-9
Original file line numberDiff line numberDiff line change
@@ -134,16 +134,23 @@ function AddAnomalyDetector({
134134
>();
135135

136136
const indexPatternId = embeddable.vis.data.aggs.indexPattern.id;
137-
const [dataSourceId, setDataSourceId] = useState<string | undefined>(undefined);
137+
const [dataSourceId, setDataSourceId] = useState<string | undefined>(
138+
undefined
139+
);
138140

139141
async function getDataSourceId() {
140142
try {
141-
const indexPattern = await getSavedObjectsClient().get('index-pattern', indexPatternId);
143+
const indexPattern = await getSavedObjectsClient().get(
144+
'index-pattern',
145+
indexPatternId
146+
);
142147
const refs = indexPattern.references as References[];
143-
const foundDataSourceId = refs.find(ref => ref.type === 'data-source')?.id;
144-
setDataSourceId(foundDataSourceId);
148+
const foundDataSourceId = refs.find(
149+
(ref) => ref.type === 'data-source'
150+
)?.id;
151+
setDataSourceId(foundDataSourceId);
145152
} catch (error) {
146-
console.error("Error fetching index pattern:", error);
153+
console.error('Error fetching index pattern:', error);
147154
}
148155
}
149156

@@ -152,8 +159,12 @@ function AddAnomalyDetector({
152159
async function fetchData() {
153160
await getDataSourceId();
154161

155-
const getIndicesDispatchCall = dispatch(getIndices(queryText, dataSourceId));
156-
const getMappingDispatchCall = dispatch(getMappings(embeddable.vis.data.aggs.indexPattern.title, dataSourceId));
162+
const getIndicesDispatchCall = dispatch(
163+
getIndices(queryText, dataSourceId)
164+
);
165+
const getMappingDispatchCall = dispatch(
166+
getMappings([embeddable.vis.data.aggs.indexPattern.title], dataSourceId)
167+
);
157168
await Promise.all([getIndicesDispatchCall, getMappingDispatchCall]);
158169
}
159170

@@ -167,7 +178,7 @@ function AddAnomalyDetector({
167178
}
168179
fetchData();
169180
createEmbeddable();
170-
}, [dataSourceId]);
181+
}, [dataSourceId]);
171182

172183
const [isShowVis, setIsShowVis] = useState(false);
173184
const [accordionsOpen, setAccordionsOpen] = useState({ modelFeatures: true });
@@ -335,7 +346,7 @@ function AddAnomalyDetector({
335346
name: OVERLAY_ANOMALIES,
336347
args: {
337348
detectorId: detectorId,
338-
dataSourceId: dataSourceId
349+
dataSourceId: dataSourceId,
339350
},
340351
} as VisLayerExpressionFn;
341352

public/pages/ConfigureModel/components/Features/Features.tsx

-10
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,6 @@ export function Features(props: FeaturesProps) {
6565
{({ push, remove, form: { values } }: FieldArrayRenderProps) => {
6666
return (
6767
<Fragment>
68-
{get(props.detector, 'indices.0', '').includes(':') ? (
69-
<div>
70-
<EuiCallOut
71-
title="This detector is using a remote cluster index, so you need to manually input the field."
72-
color="warning"
73-
iconType="alert"
74-
/>
75-
<EuiSpacer size="m" />
76-
</div>
77-
) : null}
7868
{values.featureList.map((feature: any, index: number) => (
7969
<FeatureAccordion
8070
onDelete={() => {

public/pages/ConfigureModel/containers/ConfigureModel.tsx

+13-6
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,11 @@ import { RouteComponentProps, useLocation } from 'react-router-dom';
3030
import { AppState } from '../../../redux/reducers';
3131
import { getMappings } from '../../../redux/reducers/opensearch';
3232
import { useFetchDetectorInfo } from '../../CreateDetectorSteps/hooks/useFetchDetectorInfo';
33-
import { BREADCRUMBS, BASE_DOCS_LINK, MDS_BREADCRUMBS } from '../../../utils/constants';
33+
import {
34+
BREADCRUMBS,
35+
BASE_DOCS_LINK,
36+
MDS_BREADCRUMBS,
37+
} from '../../../utils/constants';
3438
import { useHideSideNavBar } from '../../main/hooks/useHideSideNavBar';
3539
import { updateDetector } from '../../../redux/reducers/ad';
3640
import {
@@ -121,7 +125,7 @@ export function ConfigureModel(props: ConfigureModelProps) {
121125
setIsHCDetector(true);
122126
}
123127
if (detector?.indices) {
124-
dispatch(getMappings(detector.indices[0], dataSourceId));
128+
dispatch(getMappings(detector.indices, dataSourceId));
125129
}
126130
}, [detector]);
127131

@@ -133,7 +137,11 @@ export function ConfigureModel(props: ConfigureModelProps) {
133137
MDS_BREADCRUMBS.DETECTORS(dataSourceId),
134138
{
135139
text: detector && detector.name ? detector.name : '',
136-
href: constructHrefWithDataSourceId(`#/detectors/${detectorId}`, dataSourceId, false)
140+
href: constructHrefWithDataSourceId(
141+
`#/detectors/${detectorId}`,
142+
dataSourceId,
143+
false
144+
),
137145
},
138146
MDS_BREADCRUMBS.EDIT_MODEL_CONFIGURATION,
139147
]);
@@ -167,12 +175,11 @@ export function ConfigureModel(props: ConfigureModelProps) {
167175

168176
useEffect(() => {
169177
if (hasError) {
170-
if(dataSourceEnabled) {
178+
if (dataSourceEnabled) {
171179
props.history.push(
172180
constructHrefWithDataSourceId('/detectors', dataSourceId, false)
173181
);
174-
}
175-
else {
182+
} else {
176183
props.history.push('/detectors');
177184
}
178185
}

public/pages/CreateDetectorSteps/hooks/useFetchDetectorInfo.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*/
1111

1212
import { get, isEmpty } from 'lodash';
13-
import { useEffect } from 'react';
13+
import { useEffect, useMemo } from 'react';
1414
import { useDispatch, useSelector } from 'react-redux';
1515
import { Detector } from '../../../models/interfaces';
1616
import { AppState } from '../../../redux/reducers';
@@ -40,13 +40,13 @@ export const useFetchDetectorInfo = (
4040
const isIndicesRequesting = useSelector(
4141
(state: AppState) => state.opensearch.requesting
4242
);
43-
const selectedIndices = get(detector, 'indices.0', '');
43+
const selectedIndices = useMemo(() => get(detector, 'indices', []), [detector]);
4444
useEffect(() => {
4545
const fetchDetector = async () => {
4646
if (!detector) {
4747
await dispatch(getDetector(detectorId, dataSourceId));
4848
}
49-
if (selectedIndices) {
49+
if (selectedIndices && selectedIndices.length > 0) {
5050
await dispatch(getMappings(selectedIndices, dataSourceId));
5151
}
5252
};

public/pages/DefineDetector/components/DataFilterList/DataFilterList.tsx

-16
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import {
1515
EuiSpacer,
1616
EuiIcon,
1717
EuiButtonEmpty,
18-
EuiCallOut,
1918
} from '@elastic/eui';
2019
import { FieldArray, FieldArrayRenderProps, FormikProps } from 'formik';
2120
import React, { useState, Fragment } from 'react';
@@ -38,9 +37,6 @@ export const DataFilterList = (props: DataFilterListProps) => {
3837
const [isCreatingNewFilter, setIsCreatingNewFilter] =
3938
useState<boolean>(false);
4039

41-
const selectedIndex = get(props, 'formikProps.values.index.0.label', '');
42-
const isRemoteIndex = selectedIndex.includes(':');
43-
4440
return (
4541
<FieldArray name="filters" validateOnChange={true}>
4642
{({ push, remove, replace, form: { values } }: FieldArrayRenderProps) => {
@@ -66,18 +62,6 @@ export const DataFilterList = (props: DataFilterListProps) => {
6662
>
6763
<Fragment>
6864
<EuiSpacer size="m" />
69-
{isRemoteIndex ? (
70-
<div>
71-
<EuiCallOut
72-
title="A remote index is selected, so you need to manually input the filter fields."
73-
color="warning"
74-
iconType="alert"
75-
size="s"
76-
style={{ marginTop: '-4px' }}
77-
/>
78-
<EuiSpacer size="m" />
79-
</div>
80-
) : null}
8165
<EuiFlexGroup direction="row" gutterSize="xs">
8266
<EuiFlexItem grow={false}>
8367
{values.filters?.length === 0 ||

public/pages/DefineDetector/components/DataFilterList/components/SimpleFilter.tsx

+14-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import { getIndexFields, getOperators, isNullOperator } from '../utils/helpers';
3232
import FilterValue from './FilterValue';
3333
import { DetectorDefinitionFormikValues } from '../../../models/interfaces';
3434
import { EMPTY_UI_FILTER } from '../../../utils/constants';
35+
import _ from 'lodash';
3536

3637
interface SimpleFilterProps {
3738
filter: UIFilter;
@@ -40,8 +41,20 @@ interface SimpleFilterProps {
4041
replace(index: number, value: any): void;
4142
}
4243

44+
// This sorting is needed because we utilize two different ways to get index fields,
45+
// through get mapping call and through field_caps API for remote indices
46+
const sortByLabel = (indexFields) => {
47+
//sort the `options` array inside each object by the `label` field
48+
indexFields.forEach(item => {
49+
item.options = _.sortBy(item.options, 'label');
50+
});
51+
//sort the outer array by the `label` field
52+
return _.sortBy(indexFields, 'label');
53+
};
54+
4355
export const SimpleFilter = (props: SimpleFilterProps) => {
44-
const indexFields = getIndexFields(useSelector(getAllFields));
56+
let indexFields = getIndexFields(useSelector(getAllFields));
57+
indexFields = sortByLabel(indexFields)
4558
const [searchedIndexFields, setSearchedIndexFields] = useState<
4659
({
4760
label: DATA_TYPES;

0 commit comments

Comments
 (0)