-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create index pattern - modal popup (opensearch-project#366) (opensear…
…ch-project#397) * create index pattern modal Signed-off-by: Aleksandar Djindjic <[email protected]> * validate index pattern name and fill timeFields Signed-off-by: Aleksandar Djindjic <[email protected]> * reuse SavedObjectsService from dashboards core Signed-off-by: Aleksandar Djindjic <[email protected]> * take title and time field from the form Signed-off-by: Aleksandar Djindjic <[email protected]> * reuse index patterns service from core dashboards Signed-off-by: Aleksandar Djindjic <[email protected]> * improve ux for create index pattern Signed-off-by: Aleksandar Djindjic <[email protected]> * rename props Signed-off-by: Aleksandar Djindjic <[email protected]> * submit button loading state from formik submiting Signed-off-by: Aleksandar Djindjic <[email protected]> * typos and minor changes Signed-off-by: Aleksandar Djindjic <[email protected]> * indexPatternsService marked as mandatory dep Signed-off-by: Aleksandar Djindjic <[email protected]> * better typing on injected dependencies Signed-off-by: Aleksandar Djindjic <[email protected]> * cypress test for create index pattern Signed-off-by: Aleksandar Djindjic <[email protected]> * align cypress test with new convention Signed-off-by: Aleksandar Djindjic <[email protected]> * useCallback event handler wrapper Signed-off-by: Aleksandar Djindjic <[email protected]> --------- Signed-off-by: Aleksandar Djindjic <[email protected]> (cherry picked from commit 2f08f22) Co-authored-by: Aleksandar Djindjic <[email protected]> Signed-off-by: AWSHurneyt <[email protected]>
- Loading branch information
1 parent
d120d59
commit 21140df
Showing
12 changed files
with
370 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
210 changes: 210 additions & 0 deletions
210
public/pages/Findings/components/CreateIndexPatternForm.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import React, { useEffect, useState, useCallback } from 'react'; | ||
import { Formik, Form, FormikErrors } from 'formik'; | ||
import { | ||
EuiFlexGroup, | ||
EuiFlexItem, | ||
EuiFormRow, | ||
EuiFieldText, | ||
EuiButton, | ||
EuiSpacer, | ||
EuiComboBox, | ||
EuiText, | ||
EuiCallOut, | ||
} from '@elastic/eui'; | ||
import { IndexPatternsService } from '../../../services'; | ||
|
||
const ILLEGAL_CHARACTERS = [' ', '\\', '/', '?', '"', '<', '>', '|']; | ||
|
||
const containsIllegalCharacters = (pattern: string) => { | ||
return ILLEGAL_CHARACTERS.some((char) => pattern.includes(char)); | ||
}; | ||
|
||
export interface CreateIndexPatternFormModel { | ||
name: string; | ||
timeField: string; | ||
} | ||
|
||
export interface CreateIndexPatternFormProps { | ||
initialValue: { | ||
name: string; | ||
}; | ||
created: (values: string) => void; | ||
close: () => void; | ||
indexPatternsService: IndexPatternsService; | ||
} | ||
|
||
export const CreateIndexPatternForm: React.FC<CreateIndexPatternFormProps> = ({ | ||
initialValue, | ||
created, | ||
close, | ||
indexPatternsService, | ||
}) => { | ||
const [timeFields, setTimeFields] = useState<string[]>([]); | ||
const [createdIndex, setCreatedIndex] = useState<{ id?: string; title: string }>(); | ||
|
||
const getTimeFields = useCallback( | ||
async (name: string): Promise<string[]> => { | ||
if (!indexPatternsService) { | ||
return []; | ||
} | ||
|
||
return indexPatternsService | ||
.getFieldsForWildcard({ | ||
pattern: `${name}`, | ||
metaFields: ['_source', '_id', '_type', '_index', '_score'], | ||
params: {}, | ||
}) | ||
.then((res) => { | ||
return res.filter((f) => f.type === 'date').map((f) => f.name); | ||
}) | ||
.catch(() => { | ||
return []; | ||
}); | ||
}, | ||
[initialValue] | ||
); | ||
|
||
useEffect(() => { | ||
getTimeFields(initialValue.name).then((fields) => { | ||
setTimeFields(fields); | ||
}); | ||
}, [initialValue.name]); | ||
|
||
return createdIndex ? ( | ||
<> | ||
<EuiCallOut title={`${createdIndex?.title} has been successfully created`} color="success"> | ||
<p>You may now view surrounding documents within the index</p> | ||
</EuiCallOut> | ||
<EuiSpacer /> | ||
<EuiFlexGroup justifyContent="flexEnd"> | ||
<EuiFlexItem grow={false}> | ||
<EuiButton | ||
fill | ||
onClick={() => { | ||
created(createdIndex?.id || ''); | ||
}} | ||
> | ||
View surrounding documents | ||
</EuiButton> | ||
</EuiFlexItem> | ||
</EuiFlexGroup> | ||
</> | ||
) : ( | ||
<Formik | ||
initialValues={{ ...initialValue, timeField: '' }} | ||
validate={(values) => { | ||
const errors: FormikErrors<CreateIndexPatternFormModel> = {}; | ||
|
||
if (!values.name) { | ||
errors.name = 'Index patter name is required'; | ||
} | ||
|
||
if (!values.timeField) { | ||
errors.timeField = 'Time field is required'; | ||
} | ||
|
||
if (containsIllegalCharacters(values.name)) { | ||
errors.name = | ||
'A index pattern cannot contain spaces or the characters: , /, ?, ", <, >, |'; | ||
} | ||
|
||
return errors; | ||
}} | ||
onSubmit={async (values, { setSubmitting }) => { | ||
try { | ||
const newIndex = await indexPatternsService.createAndSave({ | ||
title: values.name, | ||
timeFieldName: values.timeField, | ||
}); | ||
setCreatedIndex({ id: newIndex.id, title: newIndex.title }); | ||
} catch (e) { | ||
console.warn(e); | ||
} | ||
setSubmitting(false); | ||
}} | ||
> | ||
{(props) => ( | ||
<Form> | ||
<EuiText> | ||
An index pattern is required to view all surrounding documents within the index. Create | ||
an index pattern to continue. | ||
</EuiText> | ||
<EuiSpacer /> | ||
<EuiFormRow | ||
label={ | ||
<EuiText size={'s'}> | ||
<strong>Specify index pattern name</strong> | ||
</EuiText> | ||
} | ||
isInvalid={props.touched.name && !!props.errors?.name} | ||
error={props.errors.name} | ||
> | ||
<EuiFieldText | ||
isInvalid={props.touched.name && !!props.errors.name} | ||
placeholder="Enter index pattern name" | ||
data-test-subj={'index_pattern_name_field'} | ||
onChange={async (e) => { | ||
props.handleChange('name')(e); | ||
const fields = await getTimeFields(e.target.value); | ||
setTimeFields(fields); | ||
props.setFieldValue('timeField', ''); | ||
}} | ||
onBlur={props.handleBlur('name')} | ||
value={props.values.name} | ||
/> | ||
</EuiFormRow> | ||
|
||
<EuiFormRow | ||
label={ | ||
<EuiText size={'s'}> | ||
<strong>Time filed</strong> | ||
</EuiText> | ||
} | ||
isInvalid={props.touched.timeField && !!props.errors?.timeField} | ||
error={props.errors.timeField} | ||
> | ||
<EuiComboBox | ||
isInvalid={props.touched.timeField && !!props.errors.timeField} | ||
placeholder="Select a time field" | ||
data-test-subj={'index_pattern_time_field_dropdown'} | ||
options={timeFields.map((field: string) => ({ value: field, label: field }))} | ||
singleSelection={{ asPlainText: true }} | ||
onChange={(e) => { | ||
props.handleChange('timeField')(e[0]?.value ? e[0].value : ''); | ||
}} | ||
onBlur={props.handleBlur('timeField')} | ||
selectedOptions={ | ||
props.values.timeField | ||
? [{ value: props.values.timeField, label: props.values.timeField }] | ||
: [] | ||
} | ||
/> | ||
</EuiFormRow> | ||
|
||
<EuiSpacer /> | ||
|
||
<EuiFlexGroup justifyContent="flexEnd"> | ||
<EuiFlexItem grow={false}> | ||
<EuiButton onClick={() => close()}>Cancel</EuiButton> | ||
</EuiFlexItem> | ||
<EuiFlexItem grow={false}> | ||
<EuiButton | ||
data-test-subj={'index_pattern_form_submit_button'} | ||
isLoading={props.isSubmitting} | ||
fill | ||
onClick={() => props.handleSubmit()} | ||
> | ||
Create index pattern | ||
</EuiButton> | ||
</EuiFlexItem> | ||
</EuiFlexGroup> | ||
</Form> | ||
)} | ||
</Formik> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.