Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Commit

Permalink
support remote cluster indices (#244)
Browse files Browse the repository at this point in the history
* support remote cluster indices

* add callout in detector filter panel; set callout message as tech writer suggested
  • Loading branch information
ylwu-amzn authored Jun 25, 2020
1 parent 28c5924 commit 118dad2
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ export const AggregationSelector = (props: AggregationSelectorProps) => {
name={`featureList.${props.index}.aggregationBy`}
options={AGGREGATION_TYPES}
onChange={e => {
debugger;
const currentValue = field.value;
const aggregationOf = get(
form,
Expand Down Expand Up @@ -95,6 +94,15 @@ export const AggregationSelector = (props: AggregationSelectorProps) => {
placeholder="Select field"
singleSelection
selectedOptions={field.value}
onCreateOption={(createdOption: string) => {
const normalizedOptions = createdOption.trim();
if (!normalizedOptions) return;
const customOption = [{ label: normalizedOptions }];
form.setFieldValue(
`featureList.${props.index}.aggregationOf`,
customOption
);
}}
//@ts-ignore
options={
get(form, `values.featureList.${props.index}.aggregationBy`) ===
Expand Down
13 changes: 13 additions & 0 deletions public/pages/EditFeatures/containers/EditFeatures.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import {
EuiOverlayMask,
EuiButtonEmpty,
EuiIcon,
EuiCallOut,
EuiSpacer,
} from '@elastic/eui';
import { FieldArray, FieldArrayRenderProps, Form, Formik } from 'formik';
import { get, isEmpty, forOwn } from 'lodash';
Expand Down Expand Up @@ -121,6 +123,17 @@ export function EditFeatures(props: EditFeaturesProps) {
setFirstLoad(false);
return (
<Fragment>
{get(detector, 'indices.0', '').includes(':') ? (
<div>
<EuiCallOut
title="This detector is using a remote cluster index, so you need to manually input the field."
color="warning"
iconType="alert"
/>
<EuiSpacer size="m" />
</div>
) : null}

{values.featureList.map((feature: any, index: number) => (
<FeatureAccordion
onDelete={() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
EuiPanel,
EuiText,
EuiSpacer,
EuiCallOut,
} from '@elastic/eui';
import {
Field,
Expand Down Expand Up @@ -99,6 +100,17 @@ export const SimpleFilter = (props: DataFilterProps) => {
{values.filters.map((filter: UIFilter, index: number) => {
return (
<EuiPanel key={index} className="filter-container">
{get(props, 'formikProps.values.index.0.label', '').includes(':') ? (
<div>
<EuiCallOut
title="This detector is using a remote cluster index, so you need to manually input the filter field."
color="warning"
iconType="alert"
/>
<EuiSpacer size="m" />
</div>
) : null}

<EuiAccordion
id={'name'}
initialIsOpen={true}
Expand Down Expand Up @@ -141,9 +153,20 @@ export const SimpleFilter = (props: DataFilterProps) => {
isClearable
//@ts-ignore
options={indexFields}
onCreateOption={(createdOption: string) => {
const normalizedOptions = createdOption.trim();
if (!normalizedOptions) return;
const customOption = [
{ label: normalizedOptions },
];
form.setFieldValue(
`filters.${index}.fieldInfo`,
customOption
);
}}
selectedOptions={field.value}
{...field}
onChange={options => {
onChange={(options) => {
//Reset operator and values
replace(
index,
Expand Down
70 changes: 54 additions & 16 deletions public/pages/createDetector/containers/DataSource/DataSource.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
* permissions and limitations under the License.
*/

import { EuiComboBox, EuiSelect } from '@elastic/eui';
import { EuiComboBox, EuiCallOut, EuiSpacer } from '@elastic/eui';
import { Field, FieldProps } from 'formik';
import { debounce, get } from 'lodash';
import { debounce, get, isEmpty } from 'lodash';
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { CatIndex, IndexAlias } from '../../../../../server/models/types';
Expand All @@ -39,6 +39,7 @@ import { FormattedFormRow } from '../../components/FormattedFormRow/FormattedFor
function DataSource(props: DataFilterProps) {
const dispatch = useDispatch();
const [queryText, setQueryText] = useState('');
const [indexName, setIndexName] = useState(undefined);
const elasticsearchState = useSelector(
(state: AppState) => state.elasticsearch
);
Expand All @@ -57,26 +58,48 @@ function DataSource(props: DataFilterProps) {
}
}, 300);

const handleChange = (selectedOptions: any) => {
const handleIndexNameChange = (selectedOptions: any) => {
const indexName = get(selectedOptions, '0.label', '');
setIndexName(indexName);
if (indexName !== '') {
dispatch(getMappings(indexName));
}
};

const dateFields = Array.from(get(
elasticsearchState,
'dataTypes.date',
[]
) as string[]);
const timeStampFieldOptions = ['']
.concat(dateFields)
.map(dateField => ({ value: dateField, text: dateField }));
const dateFields = Array.from(
get(elasticsearchState, 'dataTypes.date', []) as string[]
);

const timeStampFieldOptions = isEmpty(dateFields)
? []
: dateFields.map(dateField => ({ label: dateField }));

const visibleIndices = get(elasticsearchState, 'indices', []) as CatIndex[];
const visibleAliases = get(elasticsearchState, 'aliases', []) as IndexAlias[];

const isRemoteIndex = () => {
const initialIndex = get(
props.formikProps,
'initialValues.index.0.label',
''
);
return indexName !== undefined
? indexName.includes(':')
: initialIndex.includes(':');
};

return (
<ContentPanel title="Data Source" titleSize="s">
{isRemoteIndex() ? (
<div>
<EuiCallOut
title="This detector is using a remote cluster index, so you need to manually input the time field."
color="warning"
iconType="alert"
/>
<EuiSpacer size="m" />
</div>
) : null}
<Field name="index" validate={validateIndex}>
{({ field, form }: FieldProps) => {
return (
Expand All @@ -95,18 +118,19 @@ function DataSource(props: DataFilterProps) {
options={getVisibleOptions(visibleIndices, visibleAliases)}
onSearchChange={handleSearchChange}
onCreateOption={(createdOption: string) => {
const normalizedOptions = createdOption.trim().toLowerCase();
const normalizedOptions = createdOption.trim();
if (!normalizedOptions) return;
const customOption = [{ label: normalizedOptions }];
form.setFieldValue('index', customOption);
handleChange(customOption);
handleIndexNameChange(customOption);
}}
onBlur={() => {
form.setFieldTouched('index', true);
}}
onChange={options => {
form.setFieldValue('index', options);
handleChange(options);
form.setFieldValue('timeField', undefined);
handleIndexNameChange(options);
}}
selectedOptions={field.value}
singleSelection={true}
Expand All @@ -131,11 +155,25 @@ function DataSource(props: DataFilterProps) {
isInvalid={isInvalid(field.name, form)}
error={getError(field.name, form)}
>
<EuiSelect
{...field}
<EuiComboBox
id="timeField"
placeholder="Find timestamp"
options={timeStampFieldOptions}
onSearchChange={handleSearchChange}
onCreateOption={(createdOption: string) => {
const normalizedOptions = createdOption.trim();
if (!normalizedOptions) return;
form.setFieldValue('timeField', normalizedOptions);
}}
onBlur={() => {
form.setFieldTouched('timeField', true);
}}
onChange={options => {
form.setFieldValue('timeField', get(options, '0.label'));
}}
selectedOptions={(field.value && [{ label: field.value }]) || []}
singleSelection={true}
isClearable={false}
/>
</FormattedFormRow>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -342,38 +342,65 @@ exports[`<CreateDetector /> spec create detector renders the component 1`] = `
class="euiFormRow__fieldWrapper"
>
<div
class="euiFormControlLayout"
aria-expanded="false"
aria-haspopup="listbox"
class="euiComboBox"
role="combobox"
>
<div
class="euiFormControlLayout__childrenWrapper"
class="euiFormControlLayout"
>
<select
class="euiSelect"
id="random_id"
name="timeField"
placeholder="Find timestamp"
>
<option
value=""
/>
</select>
<div
class="euiFormControlLayoutIcons euiFormControlLayoutIcons--right"
class="euiFormControlLayout__childrenWrapper"
>
<span
class="euiFormControlLayoutCustomIcon"
<div
class="euiComboBox__inputWrap euiComboBox__inputWrap--noWrap"
data-test-subj="comboBoxInput"
tabindex="-1"
>
<svg
aria-hidden="true"
class="euiIcon euiIcon--medium euiIcon-isLoading euiFormControlLayoutCustomIcon__icon"
focusable="false"
height="16"
role="img"
viewBox="0 0 16 16"
width="16"
xmlns="http://www.w3.org/2000/svg"
/>
</span>
<p
class="euiComboBoxPlaceholder"
>
Find timestamp
</p>
<div
class="euiComboBox__input"
style="font-size: 14px; display: inline-block;"
>
<input
aria-controls=""
data-test-subj="comboBoxSearchInput"
id="random_id"
role="textbox"
style="box-sizing: content-box; width: 2px;"
value=""
/>
<div
style="position: absolute; top: 0px; left: 0px; visibility: hidden; height: 0px; overflow: scroll; white-space: pre; font-family: -webkit-small-control; letter-spacing: normal; text-transform: none;"
/>
</div>
</div>
<div
class="euiFormControlLayoutIcons euiFormControlLayoutIcons--right"
>
<button
aria-label="Open list of options"
class="euiFormControlLayoutCustomIcon euiFormControlLayoutCustomIcon--clickable"
data-test-subj="comboBoxToggleListButton"
type="button"
>
<svg
aria-hidden="true"
class="euiIcon euiIcon--medium euiIcon-isLoading euiFormControlLayoutCustomIcon__icon"
focusable="false"
height="16"
role="img"
viewBox="0 0 16 16"
width="16"
xmlns="http://www.w3.org/2000/svg"
/>
</button>
</div>
</div>
</div>
</div>
Expand Down
11 changes: 6 additions & 5 deletions public/redux/reducers/elasticsearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import handleActions from '../utils/handleActions';
import { getPathsPerDataType } from './mapper';
import { CatIndex, IndexAlias } from '../../../server/models/types';
import { AD_NODE_API } from '../../../utils/constants';
import { get } from 'lodash';

const GET_INDICES = 'elasticsearch/GET_INDICES';
const GET_ALIASES = 'elasticsearch/GET_ALIASES';
Expand Down Expand Up @@ -93,7 +94,7 @@ const reducer = handleActions<ElasticsearchState>(
): ElasticsearchState => ({
...state,
requesting: false,
errorMessage: action.error.data.error,
errorMessage: get(action, 'error.data.error', action.error),
}),
},
[GET_ALIASES]: {
Expand All @@ -118,7 +119,7 @@ const reducer = handleActions<ElasticsearchState>(
): ElasticsearchState => ({
...state,
requesting: false,
errorMessage: action.error.data.error,
errorMessage: get(action, 'error.data.error', action.error),
}),
},
[SEARCH_ES]: {
Expand All @@ -143,8 +144,7 @@ const reducer = handleActions<ElasticsearchState>(
): ElasticsearchState => ({
...state,
requesting: false,

errorMessage: action.error.data.error,
errorMessage: get(action, 'error.data.error', action.error),
}),
},
[GET_MAPPINGS]: {
Expand All @@ -169,7 +169,8 @@ const reducer = handleActions<ElasticsearchState>(
): ElasticsearchState => ({
...state,
requesting: false,
errorMessage: action.error.data.error,
errorMessage: get(action, 'error.data.error', action.error),
dataTypes: {}
}),
},
},
Expand Down
2 changes: 1 addition & 1 deletion server/routes/elasticsearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,6 @@ const getMapping = async (
return { ok: true, response: { mappings: response } };
} catch (err) {
console.log('Anomaly detector - Unable to get mappings', err);
return { ok: false, error: err.message };
return { ok: false, error: err };
}
};

0 comments on commit 118dad2

Please sign in to comment.