Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
a22bf94
Fix issue when no changes made in JSON modal
Jan 2, 2020
1a6657f
Create flat field list item
Jan 2, 2020
441c891
Move search term to reducer
Jan 2, 2020
bdd9383
Define min width for search box
Jan 2, 2020
3c74989
Make code review suggestion
Jan 2, 2020
70be044
Add dummy data to test performance
Jan 3, 2020
9c26db9
Use react-tiny-virtual-list to render results
Jan 3, 2020
7088d12
Refactor: move search fields to its own folder
Jan 3, 2020
23a6c6e
Search algorithm (wip)
Jan 3, 2020
b813e96
Add search fields call in reducer
Jan 3, 2020
693943c
Move react-tiny-virtual-list dep to x-pack package.json
Jan 7, 2020
e508529
Remove dummy content generator
Jan 7, 2020
2911c28
Improve search algorithm
Jan 7, 2020
a7c333c
Improve search algorithm
Jan 7, 2020
83fccf3
Cherry pick PR changes to field "path" array format
Jan 8, 2020
7680ea3
Refactor: move tree editor in its own component
Jan 8, 2020
f8a1877
Add "edit" handler to search item
Jan 8, 2020
5b18037
Update search result after "removing" or "updating" a field
Jan 8, 2020
714b4c5
Add select styling when editing a field from search
Jan 8, 2020
08f9fe3
Merge remote-tracking branch 'upstream/feature/mappings-editor' into …
Jan 8, 2020
ec32fc1
Refactor func name: getRegexArrayFromSearchTerms()
Jan 9, 2020
f2d1e52
Merge remote-tracking branch 'upstream/feature/mappings-editor' into …
Jan 9, 2020
aac6291
Use EuiButton instead of EuiButtonEmpty in prompt
Jan 9, 2020
a066cf9
Add missing i18n
Jan 9, 2020
34ec07e
Address CR + fix tests
Jan 9, 2020
f829f45
Merge remote-tracking branch 'upstream/feature/mappings-editor' into …
Jan 9, 2020
4ff65bd
Sort first field name before descendants
Jan 10, 2020
92d4202
Sort fully name match before partial match
Jan 10, 2020
8915d4c
Hide horizontal scrollbar in search result
Jan 10, 2020
a9a029f
Ignore searching for ">" char
Jan 10, 2020
519735b
Highlight latest instance of string in search result
Jan 11, 2020
727bb6d
Only convert toLowercase() once per search
Jan 11, 2020
124a251
Allow up to 3 fuzzy words
Jan 11, 2020
bf3e9bd
Add reveal in editor button to search result
Jan 13, 2020
e771da1
Make the searchBox "sticky"
Jan 13, 2020
19d4fbc
Move SearchBox to its own component
Jan 13, 2020
4f9b395
Add "Back to search results" button in SearchBox
Jan 13, 2020
ec7a047
Reset search selection when creating new field or edit other field
Jan 13, 2020
983a269
Fix sticky position for large screens
Jan 13, 2020
f1c8598
Increase line height in search result path
Jan 13, 2020
b1bd152
Fix TS issue
Jan 13, 2020
ff6bb4f
Merge remote-tracking branch 'upstream/feature/mappings-editor' into …
Jan 13, 2020
a0f7d04
Escape strings passed to new RegExp (#14)
jloleysens Jan 14, 2020
b02591c
Revert sticky behaviour on searchBox
Jan 14, 2020
c8d0ec2
Revert "Reveal in editor" from search results
Jan 14, 2020
bcbe407
Merge branch 'mappings-editor/search-fields' of github.com:sebelga/ki…
Jan 14, 2020
c84889b
Address copy review changes
Jan 14, 2020
f91fc86
Merge remote-tracking branch 'upstream/feature/mappings-editor' into …
Jan 14, 2020
052f1b7
Improve search algorithm
Jan 14, 2020
e7c4edf
Fix test
Jan 14, 2020
63eb21b
Clear search result when loading JSON
Jan 14, 2020
f04f9a0
Revert "isSelected" and scroll to item on selected item
Jan 14, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,16 @@ export const ConfigurationForm = React.memo(({ defaultValue }: Props) => {
const dispatch = useDispatch();

useEffect(() => {
const subscription = form.subscribe(updatedConfiguration => {
dispatch({ type: 'configuration.update', value: { ...updatedConfiguration, form } });
const subscription = form.subscribe(({ data, isValid, validate }) => {
dispatch({
type: 'configuration.update',
value: {
data,
isValid,
validate,
submitForm: form.submit,
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I appreciate the improved clarity of being explicit here!

});
});
return subscription.unsubscribe;
}, [form]);
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@

@import './document_fields';
@import './fields/index';
Original file line number Diff line number Diff line change
Expand Up @@ -3,81 +3,60 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React, { useEffect, useMemo } from 'react';
import { EuiButtonEmpty, EuiSpacer } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React, { useMemo, useCallback } from 'react';
import { EuiSpacer } from '@elastic/eui';

import { useMappingsState, useDispatch } from '../../mappings_state';
import { FieldsList, CreateField, EditFieldContainer } from './fields';

export const DocumentFields = () => {
import { deNormalize } from '../../lib';
import { EditFieldContainer } from './fields';
import { DocumentFieldsHeader } from './document_fields_header';
import { DocumentFieldsJsonEditor } from './fields_json_editor';
import { DocumentFieldsTreeEditor } from './fields_tree_editor';
import { SearchResult } from './search_fields';

export const DocumentFields = React.memo(() => {
const { fields, search, documentFields } = useMappingsState();
const dispatch = useDispatch();
const {
fields: { byId, rootLevelFields },
documentFields: { status, fieldToAddFieldTo, fieldToEdit },
} = useMappingsState();

const getField = (fieldId: string) => byId[fieldId];
const fields = useMemo(() => rootLevelFields.map(getField), [rootLevelFields]);

const addField = () => {
dispatch({ type: 'documentField.createField' });
};
const { status, fieldToEdit, editor: editorType } = documentFields;

useEffect(() => {
/**
* If there aren't any fields yet, we display the create field form
*/
if (status === 'idle' && fields.length === 0) {
addField();
const jsonEditorDefaultValue = useMemo(() => {
if (editorType === 'json') {
return deNormalize(fields);
}
}, [fields, status]);
}, [editorType]);

const renderCreateField = () => {
// The "fieldToAddFieldTo" is undefined when adding to the top level "properties" object.
const isCreateFieldFormVisible = status === 'creatingField' && fieldToAddFieldTo === undefined;

if (!isCreateFieldFormVisible) {
return null;
}

return <CreateField isCancelable={fields.length > 0} allFields={byId} isRootLevelField />;
};

const renderAddFieldButton = () => {
const isDisabled = status !== 'idle';
return (
<>
<EuiSpacer />
<EuiButtonEmpty
disabled={isDisabled}
onClick={addField}
iconType="plusInCircleFilled"
data-test-subj="addFieldButton"
>
{i18n.translate('xpack.idxMgmt.mappingsEditor.addFieldButtonLabel', {
defaultMessage: 'Add field',
})}
</EuiButtonEmpty>
</>
const editor =
editorType === 'json' ? (
<DocumentFieldsJsonEditor defaultValue={jsonEditorDefaultValue!} />
) : (
<DocumentFieldsTreeEditor />
);
};

const renderEditField = () => {
if (status !== 'editingField') {
return null;
}
const field = byId[fieldToEdit!];
return <EditFieldContainer field={field} allFields={byId} />;
const field = fields.byId[fieldToEdit!];
return <EditFieldContainer field={field} allFields={fields.byId} />;
};

const onSearchChange = useCallback((value: string) => {
dispatch({ type: 'search:update', value });
}, []);

const searchTerm = search.term.trim();

return (
<>
<FieldsList fields={fields} />
{renderCreateField()}
{renderAddFieldButton()}
<DocumentFieldsHeader searchValue={search.term} onSearchChange={onSearchChange} />
<EuiSpacer size="m" />
{searchTerm !== '' ? (
<SearchResult result={search.result} documentFieldsState={documentFields} />
) : (
editor
)}
{renderEditField()}
</>
);
};
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,57 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React from 'react';
import { EuiText, EuiLink } from '@elastic/eui';

import { EuiText, EuiLink, EuiFlexGroup, EuiFlexItem, EuiFieldSearch } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { documentationService } from '../../../../services/documentation';

export const DocumentFieldsHeader = () => {
interface Props {
searchValue: string;
onSearchChange(value: string): void;
}

export const DocumentFieldsHeader = React.memo(({ searchValue, onSearchChange }: Props) => {
return (
<EuiText size="s" color="subdued">
<FormattedMessage
id="xpack.idxMgmt.mappingsEditor.documentFieldsDescription"
defaultMessage="Define the fields for your indexed documents. {docsLink}"
values={{
docsLink: (
<EuiLink href={documentationService.getMappingTypesLink()} target="_blank">
{i18n.translate('xpack.idxMgmt.mappingsEditor.documentFieldsDocumentationLink', {
defaultMessage: 'Learn more.',
})}
</EuiLink>
),
}}
/>
</EuiText>
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexItem>
<EuiText size="s" color="subdued">
<FormattedMessage
id="xpack.idxMgmt.mappingsEditor.documentFieldsDescription"
defaultMessage="Define the fields for your indexed documents. {docsLink}"
values={{
docsLink: (
<EuiLink href={documentationService.getMappingTypesLink()} target="_blank">
{i18n.translate('xpack.idxMgmt.mappingsEditor.documentFieldsDocumentationLink', {
defaultMessage: 'Learn more.',
})}
</EuiLink>
),
}}
/>
</EuiText>
</EuiFlexItem>

<EuiFlexItem grow={false}>
<EuiFieldSearch
style={{ minWidth: '350px' }}
placeholder={i18n.translate(
'xpack.idxMgmt.mappingsEditor.documentFields.searchFieldsPlaceholder',
{
defaultMessage: 'Search fields',
}
)}
value={searchValue}
onChange={e => onSearchChange(e.target.value)}
aria-label={i18n.translate(
'xpack.idxMgmt.mappingsEditor.documentFields.searchFieldsAriaLabel',
{
defaultMessage: 'Search mapped fields',
}
)}
/>
</EuiFlexItem>
</EuiFlexGroup>
);
};
});
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,10 @@ export const FieldDataParameter = ({ field, defaultToggleValue }: Props) => {
const nextMaxConfig = getConfig('max', nextValueType);

min.setValue(
nextMinConfig.deserializer
? nextMinConfig.deserializer(nextMinConfig.defaultValue)
: nextMinConfig.defaultValue
nextMinConfig.deserializer?.(nextMinConfig.defaultValue) ?? nextMinConfig.defaultValue
);
max.setValue(
nextMaxConfig.deserializer
? nextMaxConfig.deserializer(nextMaxConfig.defaultValue)
: nextMaxConfig.defaultValue
nextMaxConfig.deserializer?.(nextMaxConfig.defaultValue) ?? nextMaxConfig.defaultValue
);

setValueType(nextValueType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

.mappingsEditor__fieldsListItem__field {
border-bottom: $euiBorderThin;
height: $euiSizeXL * 2;
margin-top: $euiSizeXS; // [1]
}

Expand All @@ -24,7 +25,7 @@
}
}

.mappingsEditor__fieldsListItem__field--selected {
.mappingsEditor__fieldsListItem__field--highlighted {
background-color: $euiColorLightestShade;
&:hover {
background-color: $euiColorLightestShade;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import React from 'react';
import React, { forwardRef } from 'react';
import classNames from 'classnames';
import {
EuiFlexGroup,
Expand Down Expand Up @@ -41,21 +41,24 @@ interface Props {
treeDepth: number;
}

export const FieldsListItem = React.memo(function FieldListItemComponent({
field,
allFields,
isHighlighted,
isDimmed,
isCreateFieldFormVisible,
areActionButtonsVisible,
isLastItem,
childFieldsArray,
maxNestedDepth,
addField,
editField,
toggleExpand,
treeDepth,
}: Props) {
function FieldListItemComponent(
{
field,
allFields,
isHighlighted,
isDimmed,
isCreateFieldFormVisible,
areActionButtonsVisible,
isLastItem,
childFieldsArray,
maxNestedDepth,
addField,
editField,
toggleExpand,
treeDepth,
}: Props,
ref: React.Ref<HTMLLIElement>
) {
const {
source,
isMultiField,
Expand Down Expand Up @@ -149,12 +152,13 @@ export const FieldsListItem = React.memo(function FieldListItemComponent({
'mappingsEditor__fieldsListItem--dottedLine': hasDottedLine,
})}
data-test-subj="fieldsListItem"
ref={ref}
>
<div
style={{ paddingLeft: `${indent}px` }}
className={classNames('mappingsEditor__fieldsListItem__field', {
'mappingsEditor__fieldsListItem__field--enabled': areActionButtonsVisible,
'mappingsEditor__fieldsListItem__field--selected': isHighlighted,
'mappingsEditor__fieldsListItem__field--highlighted': isHighlighted,
'mappingsEditor__fieldsListItem__field--dim': isDimmed,
})}
>
Expand Down Expand Up @@ -248,4 +252,6 @@ export const FieldsListItem = React.memo(function FieldListItemComponent({
{renderCreateField()}
</li>
);
});
}

export const FieldsListItem = React.memo(forwardRef<HTMLLIElement, Props>(FieldListItemComponent));
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import React, { useMemo, useCallback } from 'react';
import React, { useMemo, useCallback, useRef } from 'react';

import { useMappingsState, useDispatch } from '../../../mappings_state';
import { NormalizedField } from '../../../types';
Expand All @@ -17,6 +17,7 @@ interface Props {

export const FieldsListItemContainer = ({ fieldId, treeDepth, isLastItem }: Props) => {
const dispatch = useDispatch();
const listElement = useRef<HTMLLIElement | null>(null);
const {
documentFields: { status, fieldToAddFieldTo, fieldToEdit },
fields: { byId, maxNestedDepth },
Expand Down Expand Up @@ -55,6 +56,7 @@ export const FieldsListItemContainer = ({ fieldId, treeDepth, isLastItem }: Prop

return (
<FieldsListItem
ref={listElement}
field={field}
allFields={byId}
treeDepth={treeDepth}
Expand Down
Loading