From faee22007ca81b2cbc701b74984ad58431e3c63b Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Wed, 10 Jun 2020 18:57:16 +0200 Subject: [PATCH 01/28] feat: accordion with state external --- .../__mocks__/loader.ts | 1 - .../indexpattern_datasource/datapanel.tsx | 417 ++++++++++-------- .../dimension_panel/dimension_panel.test.tsx | 1 - .../dimension_panel/field_select.tsx | 5 +- .../dimension_panel/popover_editor.tsx | 1 - .../public/indexpattern_datasource/loader.ts | 2 - .../public/indexpattern_datasource/types.ts | 1 - 7 files changed, 246 insertions(+), 182 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/__mocks__/loader.ts b/x-pack/plugins/lens/public/indexpattern_datasource/__mocks__/loader.ts index fe865edd629868..f2fedda1fa3530 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/__mocks__/loader.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/__mocks__/loader.ts @@ -19,7 +19,6 @@ export function loadInitialState() { [restricted.id]: restricted, }, layers: {}, - showEmptyFields: false, }; return result; } diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx index ae5632ddae84e2..24e328e04f144b 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx @@ -16,14 +16,13 @@ import { EuiContextMenuPanelProps, EuiPopover, EuiPopoverTitle, - EuiPopoverFooter, + EuiButton, EuiCallOut, EuiFormControlLayout, - EuiSwitch, - EuiFacetButton, - EuiIcon, + EuiNotificationBadge, EuiSpacer, EuiFormLabel, + EuiAccordion, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -93,17 +92,6 @@ export function IndexPatternDataPanel({ [state, setState] ); - const onToggleEmptyFields = useCallback( - (showEmptyFields?: boolean) => { - setState((prevState) => ({ - ...prevState, - showEmptyFields: - showEmptyFields === undefined ? !prevState.showEmptyFields : showEmptyFields, - })); - }, - [setState] - ); - const indexPatternList = uniq( Object.values(state.layers) .map((l) => l.indexPatternId) @@ -179,8 +167,6 @@ export function IndexPatternDataPanel({ dateRange={dateRange} filters={filters} dragDropContext={dragDropContext} - showEmptyFields={state.showEmptyFields} - onToggleEmptyFields={onToggleEmptyFields} core={core} data={data} onChangeIndexPattern={onChangeIndexPattern} @@ -206,8 +192,6 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ filters, dragDropContext, onChangeIndexPattern, - showEmptyFields, - onToggleEmptyFields, core, data, existingFields, @@ -217,8 +201,6 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ indexPatternRefs: IndexPatternRef[]; indexPatterns: Record; dragDropContext: DragContextState; - showEmptyFields: boolean; - onToggleEmptyFields: (showEmptyFields?: boolean) => void; onChangeIndexPattern: (newId: string) => void; existingFields: IndexPatternPrivateState['existingFields']; }) { @@ -226,6 +208,8 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ nameFilter: '', typeFilter: [], isTypeFilterOpen: false, + isAvailableFieldsAccordionOpen: true, + isEmptyFieldsAccordionOpen: false, }); const [pageSize, setPageSize] = useState(PAGINATION_SIZE); const [scrollContainer, setScrollContainer] = useState(undefined); @@ -252,7 +236,14 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ setPageSize(PAGINATION_SIZE); lazyScroll(); } - }, [localState.nameFilter, localState.typeFilter, currentIndexPatternId, showEmptyFields]); + if (localState.nameFilter.length || localState.typeFilter.length) { + setLocalState(() => ({ + ...localState, + isAvailableFieldsAccordionOpen: true, + isEmptyFieldsAccordionOpen: true, + })); + } + }, [localState.nameFilter, localState.typeFilter, currentIndexPatternId]); const availableFieldTypes = uniq(allFields.map(({ type }) => type)).filter( (type) => type in fieldTypeNames @@ -270,18 +261,6 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ return false; } - if (!showEmptyFields) { - const indexField = currentIndexPattern && fieldByName[field.name]; - const exists = - field.type === 'document' || - (indexField && fieldExists(existingFields, currentIndexPattern.title, indexField.name)); - if (localState.typeFilter.length > 0) { - return exists && localState.typeFilter.includes(field.type as DataType); - } - - return exists; - } - if (localState.typeFilter.length > 0) { return localState.typeFilter.includes(field.type as DataType); } @@ -296,8 +275,15 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ .slice(0, pageSize); const hilight = localState.nameFilter.toLowerCase(); - const filterByTypeLabel = i18n.translate('xpack.lens.indexPatterns.filterByTypeLabel', { - defaultMessage: 'Filter by type', + const fieldFiltersLabel = i18n.translate('xpack.lens.indexPatterns.fieldFiltersLabel', { + defaultMessage: 'Field filters', + }); + + const [availableFields, emptyFields] = _.partition(paginatedFields, (field) => { + const overallField = fieldByName[field.name]; + return ( + overallField && fieldExists(existingFields, currentIndexPattern.title, overallField.name) + ); }); return ( @@ -328,41 +314,6 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ -
- { - trackUiEvent('indexpattern_filters_cleared'); - clearLocalState(); - }, - }} - > - { - setLocalState({ ...localState, nameFilter: e.target.value }); - }} - aria-label={i18n.translate('xpack.lens.indexPatterns.filterByNameAriaLabel', { - defaultMessage: 'Search fields', - })} - /> - -
setLocalState(() => ({ ...localState, isTypeFilterOpen: false }))} button={ - } - isSelected={localState.typeFilter.length ? true : false} - onClick={() => { - setLocalState((s) => ({ - ...s, - isTypeFilterOpen: !localState.isTypeFilterOpen, - })); - }} - > - {filterByTypeLabel} - + + { + setLocalState((s) => ({ + ...s, + isTypeFilterOpen: !localState.isTypeFilterOpen, + })); + }} + > + {localState.typeFilter.length ? ( + <> + {fieldFiltersLabel}{' '} + + {localState.typeFilter.length} + + + ) : ( + fieldFiltersLabel + )} + + + } > - {filterByTypeLabel} + {fieldFiltersLabel} ))} /> - - { - trackUiEvent('indexpattern_existence_toggled'); - onToggleEmptyFields(); - }} - label={i18n.translate('xpack.lens.indexPatterns.toggleEmptyFieldsSwitch', { - defaultMessage: 'Only show fields with data', - })} - data-test-subj="lnsEmptyFilter" - /> -
+ +
+ { + trackUiEvent('indexpattern_filters_cleared'); + clearLocalState(); + }, + }} + > + { + setLocalState({ ...localState, nameFilter: e.target.value }); + }} + aria-label={i18n.translate('xpack.lens.indexPatterns.filterByNameAriaLabel', { + defaultMessage: 'Search fields', + })} + /> + +
{ @@ -458,83 +440,174 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ hideDetails={true} /> ))} - {specialFields.length > 0 && ( - <> - + + + + setLocalState({ + ...localState, + isAvailableFieldsAccordionOpen: !localState.isAvailableFieldsAccordionOpen, + }) + } + id="availableFieldsLabel" + buttonContent={ - {i18n.translate('xpack.lens.indexPattern.individualFieldsLabel', { - defaultMessage: 'Individual fields', + {i18n.translate('xpack.lens.indexPattern.availableFieldsLabel', { + defaultMessage: 'Available fields', })} - - - )} - {paginatedFields.map((field) => { - const overallField = fieldByName[field.name]; - return ( - - ); - })} + > + {availableFields.length} + + } + > + + {availableFields.map((field) => { + return ( + + ); + })} - {paginatedFields.length === 0 && ( - - {(!showEmptyFields || - localState.typeFilter.length || - localState.nameFilter.length) && ( - <> - - {i18n.translate('xpack.lens.indexPatterns.noFields.tryText', { - defaultMessage: 'Try:', - })} - -
    -
  • - {i18n.translate('xpack.lens.indexPatterns.noFields.extendTimeBullet', { - defaultMessage: 'Extending the time range', - })} -
  • -
  • - {i18n.translate('xpack.lens.indexPatterns.noFields.fieldFilterBullet', { - defaultMessage: - 'Using {filterByTypeLabel} {arrow} to show fields without data', - values: { filterByTypeLabel, arrow: '↑' }, + {availableFields.length === 0 && ( + + {(localState.typeFilter.length || + localState.nameFilter.length || + emptyFields.length) && ( + <> + + {i18n.translate('xpack.lens.indexPatterns.noFields.tryText', { + defaultMessage: 'Try:', })} -
  • -
- - )} -
- )} + +
    +
  • + {i18n.translate('xpack.lens.indexPatterns.noFields.extendTimeBullet', { + defaultMessage: 'Extending the time range', + })} +
  • + {localState.nameFilter.length ? ( +
  • + {i18n.translate( + 'xpack.lens.indexPatterns.noFields.fieldQueryFilterBullet', + { + defaultMessage: 'Changing the field query filter', + } + )} +
  • + ) : null} + {localState.typeFilter.length ? ( +
  • + {i18n.translate( + 'xpack.lens.indexPatterns.noFields.fieldTypeFilterBullet', + { + defaultMessage: 'Changing the field type filters', + } + )} +
  • + ) : null} + {filters.length ? ( +
  • + {i18n.translate( + 'xpack.lens.indexPatterns.noFields.globalFiltersBullet', + { + defaultMessage: 'Changing the global filters', + } + )} +
  • + ) : null} +
+ + )} + + )} +
+ + + setLocalState({ + ...localState, + isEmptyFieldsAccordionOpen: !localState.isEmptyFieldsAccordionOpen, + }) + } + id="emptyFieldsLabel" + buttonContent={ + + {i18n.translate('xpack.lens.indexPattern.emptyFieldsLabel', { + defaultMessage: 'Empty fields', + })} + + } + extraAction={ + + {emptyFields.length} + + } + > + + {emptyFields.map((field) => { + return ( + + ); + })} + + +
diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx index 4397ad65d63a5c..159c28473f020f 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx @@ -79,7 +79,6 @@ describe('IndexPatternDimensionEditorPanel', () => { indexPatternRefs: [], indexPatterns: expectedIndexPatterns, currentIndexPatternId: '1', - showEmptyFields: false, existingFields: { 'my-fake-index-pattern': { timestamp: true, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/field_select.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/field_select.tsx index 6544d703115118..d2044cbec131de 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/field_select.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/field_select.tsx @@ -26,7 +26,6 @@ export interface FieldChoice { export interface FieldSelectProps { currentIndexPattern: IndexPattern; - showEmptyFields: boolean; fieldMap: Record; incompatibleSelectedOperationType: OperationType | null; selectedColumnOperationType?: OperationType; @@ -39,7 +38,6 @@ export interface FieldSelectProps { export function FieldSelect({ currentIndexPattern, - showEmptyFields, fieldMap, incompatibleSelectedOperationType, selectedColumnOperationType, @@ -86,7 +84,7 @@ export function FieldSelect({ fieldExists(existingFields, currentIndexPattern.title, field), compatible: isCompatibleWithCurrentOperation(field), })) - .filter((field) => showEmptyFields || field.exists) + .filter((field) => field.exists) .sort((a, b) => { if (a.compatible && !b.compatible) { return -1; @@ -126,7 +124,6 @@ export function FieldSelect({ operationFieldSupportMatrix, currentIndexPattern, fieldMap, - showEmptyFields, ]); return ( diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/popover_editor.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/popover_editor.tsx index 7bed770e63fd23..57439751da4dc6 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/popover_editor.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/popover_editor.tsx @@ -188,7 +188,6 @@ export function PopoverEditor(props: PopoverEditorProps) { fieldName -> boolean */ existingFields: Record>; - showEmptyFields: boolean; }; export interface IndexPatternRef { From 3b3af95510928d815ef67f8183f53a0c89372c56 Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Wed, 10 Jun 2020 19:05:35 +0200 Subject: [PATCH 02/28] accordion with no external state --- .../indexpattern_datasource/datapanel.tsx | 25 ++----------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx index 24e328e04f144b..d4257866c023e9 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx @@ -208,8 +208,6 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ nameFilter: '', typeFilter: [], isTypeFilterOpen: false, - isAvailableFieldsAccordionOpen: true, - isEmptyFieldsAccordionOpen: false, }); const [pageSize, setPageSize] = useState(PAGINATION_SIZE); const [scrollContainer, setScrollContainer] = useState(undefined); @@ -236,13 +234,6 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ setPageSize(PAGINATION_SIZE); lazyScroll(); } - if (localState.nameFilter.length || localState.typeFilter.length) { - setLocalState(() => ({ - ...localState, - isAvailableFieldsAccordionOpen: true, - isEmptyFieldsAccordionOpen: true, - })); - } }, [localState.nameFilter, localState.typeFilter, currentIndexPatternId]); const availableFieldTypes = uniq(allFields.map(({ type }) => type)).filter( @@ -443,13 +434,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ - setLocalState({ - ...localState, - isAvailableFieldsAccordionOpen: !localState.isAvailableFieldsAccordionOpen, - }) - } + initialIsOpen={true} id="availableFieldsLabel" buttonContent={ @@ -560,13 +545,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ - setLocalState({ - ...localState, - isEmptyFieldsAccordionOpen: !localState.isEmptyFieldsAccordionOpen, - }) - } + initialIsOpen={false} id="emptyFieldsLabel" buttonContent={ From 88290a4f59d1a4818ee7f424bbfcc219d8e0f31e Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Thu, 11 Jun 2020 09:51:09 +0200 Subject: [PATCH 03/28] correct pagination --- .../indexpattern_datasource/datapanel.tsx | 50 +++++++++++-------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx index d4257866c023e9..9b83281e1142ce 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx @@ -183,6 +183,10 @@ interface DataPanelState { isTypeFilterOpen: boolean; } +const fieldFiltersLabel = i18n.translate('xpack.lens.indexPatterns.fieldFiltersLabel', { + defaultMessage: 'Field filters', +}); + export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ currentIndexPatternId, indexPatternRefs, @@ -213,7 +217,6 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ const [scrollContainer, setScrollContainer] = useState(undefined); const currentIndexPattern = indexPatterns[currentIndexPatternId]; const allFields = currentIndexPattern.fields; - const fieldByName = indexBy(allFields, 'name'); const clearLocalState = () => setLocalState((s) => ({ ...s, nameFilter: '', typeFilter: [] })); const lazyScroll = () => { @@ -240,7 +243,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ (type) => type in fieldTypeNames ); - const displayedFields = allFields.filter((field) => { + const filteredFields = allFields.filter((field) => { if (!supportedFieldTypes.has(field.type)) { return false; } @@ -255,27 +258,32 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ if (localState.typeFilter.length > 0) { return localState.typeFilter.includes(field.type as DataType); } - return true; }); - const specialFields = displayedFields.filter((f) => f.type === 'document'); - const paginatedFields = displayedFields - .filter((f) => f.type !== 'document') - .sort(sortFields) - .slice(0, pageSize); - const hilight = localState.nameFilter.toLowerCase(); - - const fieldFiltersLabel = i18n.translate('xpack.lens.indexPatterns.fieldFiltersLabel', { - defaultMessage: 'Field filters', - }); - - const [availableFields, emptyFields] = _.partition(paginatedFields, (field) => { + const containsData = (field: IndexPatternField) => { + const fieldByName = indexBy(allFields, 'name'); const overallField = fieldByName[field.name]; return ( overallField && fieldExists(existingFields, currentIndexPattern.title, overallField.name) ); - }); + }; + + const [specialFields, documentFields] = _.partition(filteredFields, (f) => f.type === 'document'); + + const [availableFields, emptyFields] = _.partition(documentFields, containsData); + + const paginatedFields = [ + ...availableFields.sort(sortFields), + ...emptyFields.sort(sortFields), + ].slice(0, pageSize); + + const [paginatedAvailableFields, paginatedEmptyFields] = _.partition( + paginatedFields, + containsData + ); + + const hilight = localState.nameFilter.toLowerCase(); return ( @@ -457,7 +465,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ } > - {availableFields.map((field) => { + {paginatedAvailableFields.map((field) => { return ( {(localState.typeFilter.length || localState.nameFilter.length || - emptyFields.length) && ( + paginatedEmptyFields.length) && ( <> {i18n.translate('xpack.lens.indexPatterns.noFields.tryText', { @@ -568,7 +576,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ } > - {emptyFields.map((field) => { + {paginatedEmptyFields.map((field) => { return ( Date: Thu, 11 Jun 2020 10:38:30 +0200 Subject: [PATCH 04/28] test removing --- .../datapanel.test.tsx | 32 ++++--------------- .../dimension_panel/dimension_panel.test.tsx | 1 - .../indexpattern.test.ts | 5 --- .../indexpattern_suggestions.test.tsx | 8 ----- .../layerpanel.test.tsx | 1 - .../indexpattern_datasource/loader.test.ts | 7 ---- .../definitions/date_histogram.test.tsx | 1 - .../operations/definitions/terms.test.tsx | 1 - .../operations/operations.test.ts | 1 - .../state_helpers.test.ts | 8 ----- 10 files changed, 7 insertions(+), 58 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx index 187ccb8c47563c..723ba5cd1845b2 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx @@ -21,7 +21,6 @@ const initialState: IndexPatternPrivateState = { indexPatternRefs: [], existingFields: {}, currentIndexPatternId: '1', - showEmptyFields: false, layers: { first: { indexPatternId: '1', @@ -229,8 +228,6 @@ describe('IndexPattern Data Panel', () => { }, query: { query: '', language: 'lucene' }, filters: [], - showEmptyFields: false, - onToggleEmptyFields: jest.fn(), }; }); @@ -303,7 +300,6 @@ describe('IndexPattern Data Panel', () => { state: { indexPatternRefs: [], existingFields: {}, - showEmptyFields: false, currentIndexPatternId: 'a', indexPatterns: { a: { id: 'a', title: 'aaa', timeFieldName: 'atime', fields: [] }, @@ -536,9 +532,7 @@ describe('IndexPattern Data Panel', () => { describe('while showing empty fields', () => { it('should list all supported fields in the pattern sorted alphabetically', async () => { - const wrapper = shallowWithIntl( - - ); + const wrapper = shallowWithIntl(); expect(wrapper.find(FieldItem).map((fieldItem) => fieldItem.prop('field').name)).toEqual([ 'Records', @@ -551,9 +545,7 @@ describe('IndexPattern Data Panel', () => { }); it('should filter down by name', () => { - const wrapper = shallowWithIntl( - - ); + const wrapper = shallowWithIntl(); act(() => { wrapper.find('[data-test-subj="lnsIndexPatternFieldSearch"]').prop('onChange')!({ @@ -567,9 +559,7 @@ describe('IndexPattern Data Panel', () => { }); it('should filter down by type', () => { - const wrapper = mountWithIntl( - - ); + const wrapper = mountWithIntl(); wrapper.find('[data-test-subj="lnsIndexPatternFiltersToggle"]').first().simulate('click'); @@ -582,9 +572,7 @@ describe('IndexPattern Data Panel', () => { }); it('should toggle type if clicked again', () => { - const wrapper = mountWithIntl( - - ); + const wrapper = mountWithIntl(); wrapper.find('[data-test-subj="lnsIndexPatternFiltersToggle"]').first().simulate('click'); @@ -602,9 +590,7 @@ describe('IndexPattern Data Panel', () => { }); it('should filter down by type and by name', () => { - const wrapper = mountWithIntl( - - ); + const wrapper = mountWithIntl(); act(() => { wrapper.find('[data-test-subj="lnsIndexPatternFieldSearch"]').prop('onChange')!({ @@ -638,7 +624,6 @@ describe('IndexPattern Data Panel', () => { })), }, }, - onToggleEmptyFields: jest.fn(), }; }); @@ -662,9 +647,7 @@ describe('IndexPattern Data Panel', () => { }); it('should filter down by name', () => { - const wrapper = shallowWithIntl( - - ); + const wrapper = shallowWithIntl(); act(() => { wrapper.find('[data-test-subj="lnsIndexPatternFieldSearch"]').prop('onChange')!({ @@ -685,8 +668,7 @@ describe('IndexPattern Data Panel', () => { wrapper.find('[data-test-subj="lnsEmptyFilter"]').first().prop('onChange')!( {} as ChangeEvent ); - - expect(emptyFieldsTestProps.onToggleEmptyFields).toHaveBeenCalled(); + // TO DO }); }); }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx index 159c28473f020f..e9a3b56a6f5bb3 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx @@ -1266,7 +1266,6 @@ describe('IndexPatternDimensionEditorPanel', () => { }, }, currentIndexPatternId: '1', - showEmptyFields: false, layers: { myLayer: { indexPatternId: 'foo', diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts index d8449143b569fe..a69d7c055eaa7a 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts @@ -127,7 +127,6 @@ function stateFromPersistedState( indexPatterns: expectedIndexPatterns, indexPatternRefs: [], existingFields: {}, - showEmptyFields: true, }; } @@ -402,7 +401,6 @@ describe('IndexPattern Data Source', () => { }, }, currentIndexPatternId: '1', - showEmptyFields: false, }; expect(indexPatternDatasource.insertLayer(state, 'newLayer')).toEqual({ ...state, @@ -423,7 +421,6 @@ describe('IndexPattern Data Source', () => { const state = { indexPatternRefs: [], existingFields: {}, - showEmptyFields: false, indexPatterns: expectedIndexPatterns, layers: { first: { @@ -458,7 +455,6 @@ describe('IndexPattern Data Source', () => { indexPatternDatasource.getLayers({ indexPatternRefs: [], existingFields: {}, - showEmptyFields: false, indexPatterns: expectedIndexPatterns, layers: { first: { @@ -484,7 +480,6 @@ describe('IndexPattern Data Source', () => { indexPatternDatasource.getMetaData({ indexPatternRefs: [], existingFields: {}, - showEmptyFields: false, indexPatterns: expectedIndexPatterns, layers: { first: { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx index 5eca55cbfcbdab..87d91b56d2a5cf 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx @@ -146,7 +146,6 @@ function testInitialState(): IndexPatternPrivateState { }, }, }, - showEmptyFields: false, }; } @@ -305,7 +304,6 @@ describe('IndexPattern Data Source suggestions', () => { indexPatternRefs: [], existingFields: {}, currentIndexPatternId: '1', - showEmptyFields: false, indexPatterns: { 1: { id: '1', @@ -510,7 +508,6 @@ describe('IndexPattern Data Source suggestions', () => { indexPatternRefs: [], existingFields: {}, currentIndexPatternId: '1', - showEmptyFields: false, indexPatterns: { 1: { id: '1', @@ -1049,7 +1046,6 @@ describe('IndexPattern Data Source suggestions', () => { it('returns no suggestions if there are no columns', () => { expect( getDatasourceSuggestionsFromCurrentState({ - showEmptyFields: false, indexPatternRefs: [], existingFields: {}, indexPatterns: expectedIndexPatterns, @@ -1355,7 +1351,6 @@ describe('IndexPattern Data Source suggestions', () => { ], }, }, - showEmptyFields: true, layers: { first: { ...initialState.layers.first, @@ -1475,7 +1470,6 @@ describe('IndexPattern Data Source suggestions', () => { ], }, }, - showEmptyFields: true, layers: { first: { ...initialState.layers.first, @@ -1529,7 +1523,6 @@ describe('IndexPattern Data Source suggestions', () => { ], }, }, - showEmptyFields: true, layers: { first: { ...initialState.layers.first, @@ -1560,7 +1553,6 @@ describe('IndexPattern Data Source suggestions', () => { existingFields: {}, currentIndexPatternId: '1', indexPatterns: expectedIndexPatterns, - showEmptyFields: true, layers: { first: { ...initialState.layers.first, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.test.tsx index 0d16e2d054a775..9cbd624b42d3e2 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.test.tsx @@ -22,7 +22,6 @@ const initialState: IndexPatternPrivateState = { ], existingFields: {}, currentIndexPatternId: '1', - showEmptyFields: false, layers: { first: { indexPatternId: '1', diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts index b54ad3651471d7..18ed0c112fa86c 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts @@ -283,7 +283,6 @@ describe('loader', () => { a: sampleIndexPatterns.a, }, layers: {}, - showEmptyFields: false, }); }); @@ -303,7 +302,6 @@ describe('loader', () => { b: sampleIndexPatterns.b, }, layers: {}, - showEmptyFields: false, }); }); @@ -351,7 +349,6 @@ describe('loader', () => { b: sampleIndexPatterns.b, }, layers: savedState.layers, - showEmptyFields: false, }); }); }); @@ -365,7 +362,6 @@ describe('loader', () => { indexPatterns: {}, existingFields: {}, layers: {}, - showEmptyFields: true, }; await changeIndexPattern({ @@ -395,7 +391,6 @@ describe('loader', () => { existingFields: {}, indexPatterns: {}, layers: {}, - showEmptyFields: true, }; await changeIndexPattern({ @@ -449,7 +444,6 @@ describe('loader', () => { indexPatternId: 'a', }, }, - showEmptyFields: true, }; await changeLayerIndexPattern({ @@ -512,7 +506,6 @@ describe('loader', () => { indexPatternId: 'a', }, }, - showEmptyFields: true, }; await changeLayerIndexPattern({ diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx index defc142d4976ea..d0c7af42114e35 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx @@ -51,7 +51,6 @@ describe('date_histogram', () => { indexPatternRefs: [], existingFields: {}, currentIndexPatternId: '1', - showEmptyFields: false, indexPatterns: { 1: { id: '1', diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms.test.tsx index 89d02708a900c7..1e1d83a0a5c4c2 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms.test.tsx @@ -34,7 +34,6 @@ describe('terms', () => { indexPatterns: {}, existingFields: {}, currentIndexPatternId: '1', - showEmptyFields: false, layers: { first: { indexPatternId: '1', diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.test.ts index e5d20839aae3d1..a73f6e13d94c59 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.test.ts @@ -147,7 +147,6 @@ describe('getOperationTypesForField', () => { indexPatternRefs: [], existingFields: {}, currentIndexPatternId: '1', - showEmptyFields: false, indexPatterns: expectedIndexPatterns, layers: { first: { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/state_helpers.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/state_helpers.test.ts index 074cb8f5bde17a..65a2401fd689a3 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/state_helpers.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/state_helpers.test.ts @@ -42,7 +42,6 @@ describe('state_helpers', () => { existingFields: {}, indexPatterns: {}, currentIndexPatternId: '1', - showEmptyFields: false, layers: { first: { indexPatternId: '1', @@ -96,7 +95,6 @@ describe('state_helpers', () => { existingFields: {}, indexPatterns: {}, currentIndexPatternId: '1', - showEmptyFields: false, layers: { first: { indexPatternId: '1', @@ -147,7 +145,6 @@ describe('state_helpers', () => { existingFields: {}, indexPatterns: {}, currentIndexPatternId: '1', - showEmptyFields: false, layers: { first: { indexPatternId: '1', @@ -188,7 +185,6 @@ describe('state_helpers', () => { existingFields: {}, indexPatterns: {}, currentIndexPatternId: '1', - showEmptyFields: false, layers: { first: { indexPatternId: '1', @@ -222,7 +218,6 @@ describe('state_helpers', () => { existingFields: {}, indexPatterns: {}, currentIndexPatternId: '1', - showEmptyFields: false, layers: { first: { indexPatternId: '1', @@ -284,7 +279,6 @@ describe('state_helpers', () => { existingFields: {}, indexPatterns: {}, currentIndexPatternId: '1', - showEmptyFields: false, layers: { first: { indexPatternId: '1', @@ -337,7 +331,6 @@ describe('state_helpers', () => { existingFields: {}, indexPatterns: {}, currentIndexPatternId: '1', - showEmptyFields: false, layers: { first: { indexPatternId: '1', @@ -417,7 +410,6 @@ describe('state_helpers', () => { existingFields: {}, indexPatterns: {}, currentIndexPatternId: '1', - showEmptyFields: false, layers: { first: { indexPatternId: '1', From d8e3ceca239a40a23eb4a63ba18fc5d9b1d887f5 Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Thu, 11 Jun 2020 14:13:51 +0200 Subject: [PATCH 05/28] fix i18n --- .../indexpattern_datasource/datapanel.tsx | 2 +- .../translations/translations/ja-JP.json | 120 +++++++++--------- .../translations/translations/zh-CN.json | 120 +++++++++--------- 3 files changed, 117 insertions(+), 125 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx index 9b83281e1142ce..98758aa441f1c0 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx @@ -492,7 +492,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ defaultMessage: 'No fields match the current filters.', }) : paginatedEmptyFields - ? i18n.translate('xpack.lens.indexPatterns.noFieldsLabel', { + ? i18n.translate('xpack.lens.indexPatterns.noDataLabel', { defaultMessage: `Looks like you don't have any fields with data`, }) : i18n.translate('xpack.lens.indexPatterns.noFieldsLabel', { diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 76636779001e78..f870485c230026 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -398,6 +398,9 @@ "core.ui.securityNavList.label": "セキュリティ", "core.ui.welcomeErrorMessage": "Elastic Kibana が正常に読み込まれませんでした。詳細はサーバーアウトプットを確認してください。", "core.ui.welcomeMessage": "Elastic Kibana の読み込み中", + "core.ui.errorUrlOverflow.bigUrlWarningNotificationMessage": "{advancedSettingsLink}で{storeInSessionStorageParam}オプションを有効にするか、オンスクリーンビジュアルを簡素化してください。", + "core.ui.errorUrlOverflow.bigUrlWarningNotificationMessage.advancedSettingsLinkText": "高度な設定", + "core.ui.errorUrlOverflow.bigUrlWarningNotificationTitle": "URLが大きく、Kibanaの動作が停止する可能性があります", "dashboard.actions.toggleExpandPanelMenuItem.expandedDisplayName": "最小化", "dashboard.actions.toggleExpandPanelMenuItem.notExpandedDisplayName": "全画面", "dashboard.addExistingVisualizationLinkText": "既存のユーザーを追加", @@ -2116,6 +2119,28 @@ "share.advancedSettings.csv.quoteValuesTitle": "CSV の値を引用", "share.advancedSettings.csv.separatorText": "エクスポートされた値をこの文字列で区切ります", "share.advancedSettings.csv.separatorTitle": "CSV セパレーター", + "share.contextMenu.embedCodeLabel": "埋め込みコード", + "share.contextMenu.embedCodePanelTitle": "埋め込みコード", + "share.contextMenu.permalinkPanelTitle": "パーマリンク", + "share.contextMenu.permalinksLabel": "パーマリンク", + "share.contextMenuTitle": "この {objectType} を共有", + "share.urlGenerators.error.createUrlFnProvided": "このジェネレーターは非推奨とマークされています。createUrl fn を付けないでください。", + "share.urlGenerators.error.migrateCalledNotDeprecated": "非推奨以外のジェネレーターで migrate を呼び出すことはできません。", + "share.urlGenerators.error.migrationFnGivenNotDeprecated": "移行機能を提供する場合、このジェネレーターに非推奨マークを付ける必要があります", + "share.urlGenerators.error.noCreateUrlFnProvided": "このジェネレーターには非推奨のマークがありません。createUrl fn を付けてください。", + "share.urlGenerators.error.noMigrationFnProvided": "アクセスリンクジェネレーターに非推奨マークが付いている場合、移行機能を提供する必要があります。", + "share.urlGenerators.errors.noGeneratorWithId": "{id} という ID のジェネレーターはありません", + "share.urlPanel.canNotShareAsSavedObjectHelpText": "{objectType} が保存されるまで保存されたオブジェクトを共有することはできません。", + "share.urlPanel.copyIframeCodeButtonLabel": "iFrame コードをコピー", + "share.urlPanel.copyLinkButtonLabel": "リンクをコピー", + "share.urlPanel.generateLinkAsLabel": "名前を付けてリンクを生成", + "share.urlPanel.savedObjectDescription": "この URL を共有することで、他のユーザーがこの {objectType} の最も最近保存されたバージョンを読み込めるようになります。", + "share.urlPanel.savedObjectLabel": "保存されたオブジェクト", + "share.urlPanel.shortUrlHelpText": "互換性が最も高くなるよう、短いスナップショット URL を共有することをお勧めします。Internet Explorer は URL の長さに制限があり、一部の wiki やマークアップパーサーは長い完全なスナップショット URL に対応していませんが、短い URL は正常に動作するはずです。", + "share.urlPanel.shortUrlLabel": "短い URL", + "share.urlPanel.snapshotDescription": "スナップショット URL には、{objectType} の現在の状態がエンコードされています。保存された {objectType} への編集内容はこの URL には反映されません。.", + "share.urlPanel.snapshotLabel": "スナップショット", + "share.urlPanel.unableCreateShortUrlErrorMessage": "短い URL を作成できません。エラー: {errorMessage}", "kbn.advancedSettings.darkModeText": "Kibana UI のダークモードを有効にします。この設定を適用するにはページの更新が必要です。", "kbn.advancedSettings.darkModeTitle": "ダークモード", "kbn.advancedSettings.dateFormat.dayOfWeekText": "週の初めの曜日を設定します", @@ -2167,9 +2192,37 @@ "kbn.advancedSettings.visualization.tileMap.wmsDefaultsTitle": "デフォルトの WMS プロパティ", "visualizations.advancedSettings.visualizeEnableLabsText": "ユーザーが実験的なビジュアライゼーションを作成、表示、編集できるようになります。無効の場合、\n ユーザーは本番準備が整ったビジュアライゼーションのみを利用できます。", "visualizations.advancedSettings.visualizeEnableLabsTitle": "実験的なビジュアライゼーションを有効にする", - "core.ui.errorUrlOverflow.bigUrlWarningNotificationMessage": "{advancedSettingsLink}で{storeInSessionStorageParam}オプションを有効にするか、オンスクリーンビジュアルを簡素化してください。", - "core.ui.errorUrlOverflow.bigUrlWarningNotificationMessage.advancedSettingsLinkText": "高度な設定", - "core.ui.errorUrlOverflow.bigUrlWarningNotificationTitle": "URLが大きく、Kibanaの動作が停止する可能性があります", + "visualizations.disabledLabVisualizationMessage": "ラボビジュアライゼーションを表示するには、高度な設定でラボモードをオンにしてください。", + "visualizations.disabledLabVisualizationTitle": "{title} はラボビジュアライゼーションです。", + "visualizations.displayName": "ビジュアライゼーション", + "visualizations.function.range.from.help": "範囲の開始", + "visualizations.function.range.help": "範囲オブジェクトを生成します", + "visualizations.function.range.to.help": "範囲の終了", + "visualizations.function.visDimension.accessor.help": "使用するデータセット内の列 (列インデックスまたは列名)", + "visualizations.function.visDimension.error.accessor": "入力された列名は無効です。", + "visualizations.function.visDimension.format.help": "フォーマット", + "visualizations.function.visDimension.formatParams.help": "フォーマットパラメーター", + "visualizations.function.visDimension.help": "visConfig ディメンションオブジェクトを生成します", + "visualizations.functions.visualization.help": "シンプルなビジュアライゼーションです", + "visualizations.newVisWizard.betaDescription": "このビジュアライゼーションはベータ段階で、変更される可能性があります。デザインとコードはオフィシャル GA 機能よりも完成度が低く、現状のまま保証なしで提供されています。ベータ機能にはオフィシャル GA 機能の SLA が適用されません", + "visualizations.newVisWizard.betaTitle": "ベータ", + "visualizations.newVisWizard.chooseSourceTitle": "ソースの選択", + "visualizations.newVisWizard.experimentalDescription": "このビジュアライゼーションは実験的なものです。デザインと導入は安定したビジュアライゼーションよりも完成度が低く、変更される可能性があります。", + "visualizations.newVisWizard.experimentalTitle": "実験的", + "visualizations.newVisWizard.experimentalTooltip": "このビジュアライゼーションは今後のリリースで変更または削除される可能性があり、SLA のサポート対象になりません。", + "visualizations.newVisWizard.filterVisTypeAriaLabel": "ビジュアライゼーションのタイプでフィルタリング", + "visualizations.newVisWizard.helpText": "タイプを選択してビジュアライゼーションの作成を始めましょう。", + "visualizations.newVisWizard.helpTextAriaLabel": "タイプを選択してビジュアライゼーションの作成を始めましょう。ESC を押してこのモーダルを閉じます。Tab キーを押して次に進みます。", + "visualizations.newVisWizard.newVisTypeTitle": "新規 {visTypeName}", + "visualizations.newVisWizard.resultsFound": "{resultCount} 個の{resultCount, plural, one {タイプ} other {タイプ} } が見つかりました", + "visualizations.newVisWizard.searchSelection.notFoundLabel": "一致インデックスまたは保存した検索が見つかりません。", + "visualizations.newVisWizard.searchSelection.savedObjectType.indexPattern": "インデックスパターン", + "visualizations.newVisWizard.searchSelection.savedObjectType.search": "保存検索", + "visualizations.newVisWizard.selectVisType": "ビジュアライゼーションのタイプを選択してください", + "visualizations.newVisWizard.title": "新規ビジュアライゼーション", + "visualizations.newVisWizard.visTypeAliasDescription": "Visualize 外で Kibana アプリケーションを開きます。", + "visualizations.newVisWizard.visTypeAliasTitle": "Kibana アプリケーション", + "visualizations.savedObjectName": "ビジュアライゼーション", "kibana_legacy.notify.fatalError.errorStatusMessage": "エラー {errStatus} {errStatusText}: {errMessage}", "kibana_legacy.notify.fatalError.unavailableServerErrorMessage": "HTTP リクエストで接続に失敗しました。Kibana サーバーが実行されていて、ご使用のブラウザの接続が正常に動作していることを確認するか、システム管理者にお問い合わせください。", "kibana_legacy.notify.toaster.errorMessage": "エラー: {errorMessage}\n {errorStack}", @@ -2421,28 +2474,6 @@ "server.status.redTitle": "赤", "server.status.uninitializedTitle": "アンインストールしました", "server.status.yellowTitle": "黄色", - "share.contextMenu.embedCodeLabel": "埋め込みコード", - "share.contextMenu.embedCodePanelTitle": "埋め込みコード", - "share.contextMenu.permalinkPanelTitle": "パーマリンク", - "share.contextMenu.permalinksLabel": "パーマリンク", - "share.contextMenuTitle": "この {objectType} を共有", - "share.urlGenerators.error.createUrlFnProvided": "このジェネレーターは非推奨とマークされています。createUrl fn を付けないでください。", - "share.urlGenerators.error.migrateCalledNotDeprecated": "非推奨以外のジェネレーターで migrate を呼び出すことはできません。", - "share.urlGenerators.error.migrationFnGivenNotDeprecated": "移行機能を提供する場合、このジェネレーターに非推奨マークを付ける必要があります", - "share.urlGenerators.error.noCreateUrlFnProvided": "このジェネレーターには非推奨のマークがありません。createUrl fn を付けてください。", - "share.urlGenerators.error.noMigrationFnProvided": "アクセスリンクジェネレーターに非推奨マークが付いている場合、移行機能を提供する必要があります。", - "share.urlGenerators.errors.noGeneratorWithId": "{id} という ID のジェネレーターはありません", - "share.urlPanel.canNotShareAsSavedObjectHelpText": "{objectType} が保存されるまで保存されたオブジェクトを共有することはできません。", - "share.urlPanel.copyIframeCodeButtonLabel": "iFrame コードをコピー", - "share.urlPanel.copyLinkButtonLabel": "リンクをコピー", - "share.urlPanel.generateLinkAsLabel": "名前を付けてリンクを生成", - "share.urlPanel.savedObjectDescription": "この URL を共有することで、他のユーザーがこの {objectType} の最も最近保存されたバージョンを読み込めるようになります。", - "share.urlPanel.savedObjectLabel": "保存されたオブジェクト", - "share.urlPanel.shortUrlHelpText": "互換性が最も高くなるよう、短いスナップショット URL を共有することをお勧めします。Internet Explorer は URL の長さに制限があり、一部の wiki やマークアップパーサーは長い完全なスナップショット URL に対応していませんが、短い URL は正常に動作するはずです。", - "share.urlPanel.shortUrlLabel": "短い URL", - "share.urlPanel.snapshotDescription": "スナップショット URL には、{objectType} の現在の状態がエンコードされています。保存された {objectType} への編集内容はこの URL には反映されません。.", - "share.urlPanel.snapshotLabel": "スナップショット", - "share.urlPanel.unableCreateShortUrlErrorMessage": "短い URL を作成できません。エラー: {errorMessage}", "statusPage.loadStatus.serverIsDownErrorMessage": "サーバーステータスのリクエストに失敗しました。サーバーがダウンしている可能性があります。", "statusPage.loadStatus.serverStatusCodeErrorMessage": "サーバーステータスのリクエストに失敗しました。ステータスコード: {responseStatus}", "statusPage.metricsTiles.columns.heapTotalHeader": "ヒープ合計", @@ -3839,37 +3870,6 @@ "visTypeVislib.vislib.legend.toggleOptionsButtonAriaLabel": "{legendDataLabel}、トグルオプション", "visTypeVislib.vislib.tooltip.fieldLabel": "フィールド", "visTypeVislib.vislib.tooltip.valueLabel": "値", - "visualizations.disabledLabVisualizationMessage": "ラボビジュアライゼーションを表示するには、高度な設定でラボモードをオンにしてください。", - "visualizations.disabledLabVisualizationTitle": "{title} はラボビジュアライゼーションです。", - "visualizations.displayName": "ビジュアライゼーション", - "visualizations.function.range.from.help": "範囲の開始", - "visualizations.function.range.help": "範囲オブジェクトを生成します", - "visualizations.function.range.to.help": "範囲の終了", - "visualizations.function.visDimension.accessor.help": "使用するデータセット内の列 (列インデックスまたは列名)", - "visualizations.function.visDimension.error.accessor": "入力された列名は無効です。", - "visualizations.function.visDimension.format.help": "フォーマット", - "visualizations.function.visDimension.formatParams.help": "フォーマットパラメーター", - "visualizations.function.visDimension.help": "visConfig ディメンションオブジェクトを生成します", - "visualizations.functions.visualization.help": "シンプルなビジュアライゼーションです", - "visualizations.newVisWizard.betaDescription": "このビジュアライゼーションはベータ段階で、変更される可能性があります。デザインとコードはオフィシャル GA 機能よりも完成度が低く、現状のまま保証なしで提供されています。ベータ機能にはオフィシャル GA 機能の SLA が適用されません", - "visualizations.newVisWizard.betaTitle": "ベータ", - "visualizations.newVisWizard.chooseSourceTitle": "ソースの選択", - "visualizations.newVisWizard.experimentalDescription": "このビジュアライゼーションは実験的なものです。デザインと導入は安定したビジュアライゼーションよりも完成度が低く、変更される可能性があります。", - "visualizations.newVisWizard.experimentalTitle": "実験的", - "visualizations.newVisWizard.experimentalTooltip": "このビジュアライゼーションは今後のリリースで変更または削除される可能性があり、SLA のサポート対象になりません。", - "visualizations.newVisWizard.filterVisTypeAriaLabel": "ビジュアライゼーションのタイプでフィルタリング", - "visualizations.newVisWizard.helpText": "タイプを選択してビジュアライゼーションの作成を始めましょう。", - "visualizations.newVisWizard.helpTextAriaLabel": "タイプを選択してビジュアライゼーションの作成を始めましょう。ESC を押してこのモーダルを閉じます。Tab キーを押して次に進みます。", - "visualizations.newVisWizard.newVisTypeTitle": "新規 {visTypeName}", - "visualizations.newVisWizard.resultsFound": "{resultCount} 個の{resultCount, plural, one {タイプ} other {タイプ} } が見つかりました", - "visualizations.newVisWizard.searchSelection.notFoundLabel": "一致インデックスまたは保存した検索が見つかりません。", - "visualizations.newVisWizard.searchSelection.savedObjectType.indexPattern": "インデックスパターン", - "visualizations.newVisWizard.searchSelection.savedObjectType.search": "保存検索", - "visualizations.newVisWizard.selectVisType": "ビジュアライゼーションのタイプを選択してください", - "visualizations.newVisWizard.title": "新規ビジュアライゼーション", - "visualizations.newVisWizard.visTypeAliasDescription": "Visualize 外で Kibana アプリケーションを開きます。", - "visualizations.newVisWizard.visTypeAliasTitle": "Kibana アプリケーション", - "visualizations.savedObjectName": "ビジュアライゼーション", "visualize.badge.readOnly.text": "読み取り専用", "visualize.badge.readOnly.tooltip": "ビジュアライゼーションを保存できません", "visualize.createVisualization.noIndexPatternOrSavedSearchIdErrorMessage": "indexPatternまたはsavedSearchIdが必要です", @@ -3969,6 +3969,8 @@ "xpack.uiActionsEnhanced.customizePanelTimeRange.modal.updatePanelTimeRangeButtonTitle": "更新", "xpack.uiActionsEnhanced.customizeTimeRange.modal.headerTitle": "パネルの時間範囲のカスタマイズ", "xpack.uiActionsEnhanced.customizeTimeRangeMenuItem.displayName": "時間範囲のカスタマイズ", + "xpack.uiActionsEnhanced.components.DiscoverDrilldownConfig.chooseIndexPattern": "対象インデックスパターンを選択", + "xpack.uiActionsEnhanced.drilldown.goToDiscover": "Discoverに移動(例)", "xpack.alerts.alertNavigationRegistry.get.missingNavigationError": "「{consumer}」内のアラートタイプ「{alertType}」のナビゲーションは登録されていません。", "xpack.alerts.alertNavigationRegistry.register.duplicateDefaultError": "「{consumer}」内のデフォルトナビゲーションは既に登録されています。", "xpack.alerts.alertNavigationRegistry.register.duplicateNavigationError": "「{consumer}」内のアラートタイプ「{alertType}」のナビゲーションは既に登録されています。", @@ -8727,16 +8729,12 @@ "xpack.lens.indexPattern.termsOf": "{name} のトップの値", "xpack.lens.indexPattern.uniqueLabel": "{label} [{num}]", "xpack.lens.indexPatterns.clearFiltersLabel": "名前とタイプフィルターを消去", - "xpack.lens.indexPatterns.emptyFieldsWithDataLabel": "データがないようです。", "xpack.lens.indexPatterns.filterByNameAriaLabel": "検索フィールド", "xpack.lens.indexPatterns.filterByNameLabel": "フィールドを検索", - "xpack.lens.indexPatterns.filterByTypeLabel": "タイプでフィルタリング", "xpack.lens.indexPatterns.noFields.extendTimeBullet": "時間範囲を拡張中", - "xpack.lens.indexPatterns.noFields.fieldFilterBullet": "{filterByTypeLabel} {arrow} を使用してデータなしのフィールドを表示", "xpack.lens.indexPatterns.noFields.tryText": "試行対象:", "xpack.lens.indexPatterns.noFieldsLabel": "このインデックスパターンにはフィールドがありません。", "xpack.lens.indexPatterns.noFilteredFieldsLabel": "現在のフィルターと一致するフィールドはありません。", - "xpack.lens.indexPatterns.toggleEmptyFieldsSwitch": "データがあるフィールドだけを表示", "xpack.lens.indexPatternSuggestion.removeLayerLabel": "{indexPatternTitle}のみを表示", "xpack.lens.indexPatternSuggestion.removeLayerPositionLabel": "レイヤー{layerNumber}のみを表示", "xpack.lens.lensSavedObjectLabel": "レンズビジュアライゼーション", @@ -16377,8 +16375,6 @@ "xpack.triggersActionsUI.timeUnits.secondLabel": "{timeValue, plural, one {秒} other {秒}}", "xpack.triggersActionsUI.typeRegistry.get.missingActionTypeErrorMessage": "オブジェクトタイプ「{id}」は登録されていません。", "xpack.triggersActionsUI.typeRegistry.register.duplicateObjectTypeErrorMessage": "オブジェクトタイプ「{id}」は既に登録されています。", - "xpack.uiActionsEnhanced.components.DiscoverDrilldownConfig.chooseIndexPattern": "対象インデックスパターンを選択", - "xpack.uiActionsEnhanced.drilldown.goToDiscover": "Discoverに移動(例)", "xpack.upgradeAssistant.appTitle": "{version} アップグレードアシスタント", "xpack.upgradeAssistant.checkupTab.backUpCallout.calloutBody.calloutDetail": "{snapshotRestoreDocsButton} でデータをバックアップします。", "xpack.upgradeAssistant.checkupTab.backUpCallout.calloutBody.snapshotRestoreDocsButtonLabel": "API のスナップショットと復元", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 331e9d67c38971..729cfd41985793 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -398,6 +398,9 @@ "core.ui.securityNavList.label": "安全", "core.ui.welcomeErrorMessage": "Elastic Kibana 未正确加载。检查服务器输出以了解详情。", "core.ui.welcomeMessage": "正在加载 Elastic Kibana", + "core.ui.errorUrlOverflow.bigUrlWarningNotificationMessage": "在{advancedSettingsLink}中启用“{storeInSessionStorageParam}”选项或简化屏幕视觉效果。", + "core.ui.errorUrlOverflow.bigUrlWarningNotificationMessage.advancedSettingsLinkText": "高级设置", + "core.ui.errorUrlOverflow.bigUrlWarningNotificationTitle": "URL 过长,Kibana 可能无法工作", "dashboard.actions.toggleExpandPanelMenuItem.expandedDisplayName": "最小化", "dashboard.actions.toggleExpandPanelMenuItem.notExpandedDisplayName": "全屏", "dashboard.addExistingVisualizationLinkText": "将现有", @@ -2119,6 +2122,28 @@ "share.advancedSettings.csv.quoteValuesTitle": "使用引号引起 CSV 值", "share.advancedSettings.csv.separatorText": "使用此字符串分隔导出的值", "share.advancedSettings.csv.separatorTitle": "CSV 分隔符", + "share.contextMenu.embedCodeLabel": "嵌入代码", + "share.contextMenu.embedCodePanelTitle": "嵌入代码", + "share.contextMenu.permalinkPanelTitle": "固定链接", + "share.contextMenu.permalinksLabel": "固定链接", + "share.contextMenuTitle": "共享此 {objectType}", + "share.urlGenerators.error.createUrlFnProvided": "此生成器标记为已过时。切勿提供 createUrl 函数。", + "share.urlGenerators.error.migrateCalledNotDeprecated": "无法在非过时的生成器上调用迁移。", + "share.urlGenerators.error.migrationFnGivenNotDeprecated": "如果提供了迁移函数,则必须将此生成器标记为已过时", + "share.urlGenerators.error.noCreateUrlFnProvided": "此生成器未标记为已过时。请提供 createUrl 函数。", + "share.urlGenerators.error.noMigrationFnProvided": "如果访问链接生成器标记为已过时,则必须提供迁移函数。", + "share.urlGenerators.errors.noGeneratorWithId": "未找到 ID 为 {id} 的生成器", + "share.urlPanel.canNotShareAsSavedObjectHelpText": "只有保存 {objectType} 后,才能共享为已保存对象。", + "share.urlPanel.copyIframeCodeButtonLabel": "复制 iFrame 代码", + "share.urlPanel.copyLinkButtonLabel": "复制链接", + "share.urlPanel.generateLinkAsLabel": "将链接生成为", + "share.urlPanel.savedObjectDescription": "您可以将此 URL 共享给相关人员,以便他们可以加载此 {objectType} 最新的已保存版本。", + "share.urlPanel.savedObjectLabel": "已保存对象", + "share.urlPanel.shortUrlHelpText": "建议共享缩短的快照 URL,以实现最大的兼容性。Internet Explorer 有 URL 长度限制,某些 wiki 和标记分析器无法很好地处理全长版本的快照 URL,但应能很好地处理短 URL。", + "share.urlPanel.shortUrlLabel": "短 URL", + "share.urlPanel.snapshotDescription": "快照 URL 将 {objectType} 的当前状态编入 URL 自身之中。通过此 URL 无法看到对已保存 {objectType} 的编辑。", + "share.urlPanel.snapshotLabel": "快照", + "share.urlPanel.unableCreateShortUrlErrorMessage": "无法创建短 URL。错误:{errorMessage}", "kbn.advancedSettings.darkModeText": "为 Kibana UI 启用深色模式需要刷新页面,才能应用设置。", "kbn.advancedSettings.darkModeTitle": "深色模式", "kbn.advancedSettings.dateFormat.dayOfWeekText": "一周从哪一日开始?", @@ -2170,9 +2195,37 @@ "kbn.advancedSettings.visualization.tileMap.wmsDefaultsTitle": "默认 WMS 属性", "visualizations.advancedSettings.visualizeEnableLabsText": "允许用户创建、查看和编辑实验性可视化。如果禁用,\n 仅被视为生产就绪的可视化可供用户使用。", "visualizations.advancedSettings.visualizeEnableLabsTitle": "启用实验性可视化", - "core.ui.errorUrlOverflow.bigUrlWarningNotificationMessage": "在{advancedSettingsLink}中启用“{storeInSessionStorageParam}”选项或简化屏幕视觉效果。", - "core.ui.errorUrlOverflow.bigUrlWarningNotificationMessage.advancedSettingsLinkText": "高级设置", - "core.ui.errorUrlOverflow.bigUrlWarningNotificationTitle": "URL 过长,Kibana 可能无法工作", + "visualizations.disabledLabVisualizationMessage": "请在高级设置中打开实验室模式,以查看实验室可视化。", + "visualizations.disabledLabVisualizationTitle": "{title} 为实验室可视化。", + "visualizations.displayName": "可视化", + "visualizations.function.range.from.help": "范围起始", + "visualizations.function.range.help": "生成范围对象", + "visualizations.function.range.to.help": "范围结束", + "visualizations.function.visDimension.accessor.help": "要使用的数据集列(列索引或列名称)", + "visualizations.function.visDimension.error.accessor": "提供的列名称无效", + "visualizations.function.visDimension.format.help": "格式", + "visualizations.function.visDimension.formatParams.help": "格式参数", + "visualizations.function.visDimension.help": "生成 visConfig 维度对象", + "visualizations.functions.visualization.help": "简单可视化", + "visualizations.newVisWizard.betaDescription": "此可视化为公测版,可能会进行更改。设计和代码相对于正式发行版功能还不够成熟,将按原样提供,且不提供任何保证。公测版功能不受正式发行版功能支持 SLA 的约束", + "visualizations.newVisWizard.betaTitle": "公测版", + "visualizations.newVisWizard.chooseSourceTitle": "选择源", + "visualizations.newVisWizard.experimentalDescription": "这是实验性可视化。与稳定的可视化相比,其设计和实现均不够成熟,可能会随时发生更改。", + "visualizations.newVisWizard.experimentalTitle": "实验性", + "visualizations.newVisWizard.experimentalTooltip": "未来版本可能会更改或删除此可视化,其不受支持 SLA 的约束。", + "visualizations.newVisWizard.filterVisTypeAriaLabel": "筛留可视化类型", + "visualizations.newVisWizard.helpText": "通过为该可视化选择类型,来开始创建您的可视化。", + "visualizations.newVisWizard.helpTextAriaLabel": "通过为该可视化选择类型,来开始创建您的可视化。按 Esc 键关闭此模式。按 Tab 键继续。", + "visualizations.newVisWizard.newVisTypeTitle": "新建{visTypeName}", + "visualizations.newVisWizard.resultsFound": "找到了 {resultCount} 个{resultCount, plural, one {类型} other {类型} }", + "visualizations.newVisWizard.searchSelection.notFoundLabel": "未找到匹配的索引或已保存搜索。", + "visualizations.newVisWizard.searchSelection.savedObjectType.indexPattern": "索引模式", + "visualizations.newVisWizard.searchSelection.savedObjectType.search": "已保存搜索", + "visualizations.newVisWizard.selectVisType": "选择可视化类型", + "visualizations.newVisWizard.title": "新建可视化", + "visualizations.newVisWizard.visTypeAliasDescription": "打开 Visualize 外部的 Kibana 应用程序。", + "visualizations.newVisWizard.visTypeAliasTitle": "Kibana 应用程序", + "visualizations.savedObjectName": "可视化", "kibana_legacy.notify.fatalError.errorStatusMessage": "错误 {errStatus} {errStatusText}:{errMessage}", "kibana_legacy.notify.fatalError.unavailableServerErrorMessage": "HTTP 请求无法连接。请检查 Kibana 服务器是否正在运行以及您的浏览器是否具有有效的连接,或请联系您的系统管理员。", "kibana_legacy.notify.toaster.errorMessage": "错误:{errorMessage}\n {errorStack}", @@ -2424,28 +2477,6 @@ "server.status.redTitle": "红", "server.status.uninitializedTitle": "未初始化", "server.status.yellowTitle": "黄", - "share.contextMenu.embedCodeLabel": "嵌入代码", - "share.contextMenu.embedCodePanelTitle": "嵌入代码", - "share.contextMenu.permalinkPanelTitle": "固定链接", - "share.contextMenu.permalinksLabel": "固定链接", - "share.contextMenuTitle": "共享此 {objectType}", - "share.urlGenerators.error.createUrlFnProvided": "此生成器标记为已过时。切勿提供 createUrl 函数。", - "share.urlGenerators.error.migrateCalledNotDeprecated": "无法在非过时的生成器上调用迁移。", - "share.urlGenerators.error.migrationFnGivenNotDeprecated": "如果提供了迁移函数,则必须将此生成器标记为已过时", - "share.urlGenerators.error.noCreateUrlFnProvided": "此生成器未标记为已过时。请提供 createUrl 函数。", - "share.urlGenerators.error.noMigrationFnProvided": "如果访问链接生成器标记为已过时,则必须提供迁移函数。", - "share.urlGenerators.errors.noGeneratorWithId": "未找到 ID 为 {id} 的生成器", - "share.urlPanel.canNotShareAsSavedObjectHelpText": "只有保存 {objectType} 后,才能共享为已保存对象。", - "share.urlPanel.copyIframeCodeButtonLabel": "复制 iFrame 代码", - "share.urlPanel.copyLinkButtonLabel": "复制链接", - "share.urlPanel.generateLinkAsLabel": "将链接生成为", - "share.urlPanel.savedObjectDescription": "您可以将此 URL 共享给相关人员,以便他们可以加载此 {objectType} 最新的已保存版本。", - "share.urlPanel.savedObjectLabel": "已保存对象", - "share.urlPanel.shortUrlHelpText": "建议共享缩短的快照 URL,以实现最大的兼容性。Internet Explorer 有 URL 长度限制,某些 wiki 和标记分析器无法很好地处理全长版本的快照 URL,但应能很好地处理短 URL。", - "share.urlPanel.shortUrlLabel": "短 URL", - "share.urlPanel.snapshotDescription": "快照 URL 将 {objectType} 的当前状态编入 URL 自身之中。通过此 URL 无法看到对已保存 {objectType} 的编辑。", - "share.urlPanel.snapshotLabel": "快照", - "share.urlPanel.unableCreateShortUrlErrorMessage": "无法创建短 URL。错误:{errorMessage}", "statusPage.loadStatus.serverIsDownErrorMessage": "无法请求服务器状态。也许您的服务器已关闭?", "statusPage.loadStatus.serverStatusCodeErrorMessage": "无法使用状态代码 {responseStatus} 请求服务器状态", "statusPage.metricsTiles.columns.heapTotalHeader": "堆总计", @@ -3842,37 +3873,6 @@ "visTypeVislib.vislib.legend.toggleOptionsButtonAriaLabel": "{legendDataLabel}, 切换选项", "visTypeVislib.vislib.tooltip.fieldLabel": "字段", "visTypeVislib.vislib.tooltip.valueLabel": "值", - "visualizations.disabledLabVisualizationMessage": "请在高级设置中打开实验室模式,以查看实验室可视化。", - "visualizations.disabledLabVisualizationTitle": "{title} 为实验室可视化。", - "visualizations.displayName": "可视化", - "visualizations.function.range.from.help": "范围起始", - "visualizations.function.range.help": "生成范围对象", - "visualizations.function.range.to.help": "范围结束", - "visualizations.function.visDimension.accessor.help": "要使用的数据集列(列索引或列名称)", - "visualizations.function.visDimension.error.accessor": "提供的列名称无效", - "visualizations.function.visDimension.format.help": "格式", - "visualizations.function.visDimension.formatParams.help": "格式参数", - "visualizations.function.visDimension.help": "生成 visConfig 维度对象", - "visualizations.functions.visualization.help": "简单可视化", - "visualizations.newVisWizard.betaDescription": "此可视化为公测版,可能会进行更改。设计和代码相对于正式发行版功能还不够成熟,将按原样提供,且不提供任何保证。公测版功能不受正式发行版功能支持 SLA 的约束", - "visualizations.newVisWizard.betaTitle": "公测版", - "visualizations.newVisWizard.chooseSourceTitle": "选择源", - "visualizations.newVisWizard.experimentalDescription": "这是实验性可视化。与稳定的可视化相比,其设计和实现均不够成熟,可能会随时发生更改。", - "visualizations.newVisWizard.experimentalTitle": "实验性", - "visualizations.newVisWizard.experimentalTooltip": "未来版本可能会更改或删除此可视化,其不受支持 SLA 的约束。", - "visualizations.newVisWizard.filterVisTypeAriaLabel": "筛留可视化类型", - "visualizations.newVisWizard.helpText": "通过为该可视化选择类型,来开始创建您的可视化。", - "visualizations.newVisWizard.helpTextAriaLabel": "通过为该可视化选择类型,来开始创建您的可视化。按 Esc 键关闭此模式。按 Tab 键继续。", - "visualizations.newVisWizard.newVisTypeTitle": "新建{visTypeName}", - "visualizations.newVisWizard.resultsFound": "找到了 {resultCount} 个{resultCount, plural, one {类型} other {类型} }", - "visualizations.newVisWizard.searchSelection.notFoundLabel": "未找到匹配的索引或已保存搜索。", - "visualizations.newVisWizard.searchSelection.savedObjectType.indexPattern": "索引模式", - "visualizations.newVisWizard.searchSelection.savedObjectType.search": "已保存搜索", - "visualizations.newVisWizard.selectVisType": "选择可视化类型", - "visualizations.newVisWizard.title": "新建可视化", - "visualizations.newVisWizard.visTypeAliasDescription": "打开 Visualize 外部的 Kibana 应用程序。", - "visualizations.newVisWizard.visTypeAliasTitle": "Kibana 应用程序", - "visualizations.savedObjectName": "可视化", "visualize.badge.readOnly.text": "只读", "visualize.badge.readOnly.tooltip": "无法保存可视化", "visualize.createVisualization.noIndexPatternOrSavedSearchIdErrorMessage": "必须提供 indexPattern 或 savedSearchId", @@ -3972,6 +3972,8 @@ "xpack.uiActionsEnhanced.customizePanelTimeRange.modal.updatePanelTimeRangeButtonTitle": "更新", "xpack.uiActionsEnhanced.customizeTimeRange.modal.headerTitle": "定制面板时间范围", "xpack.uiActionsEnhanced.customizeTimeRangeMenuItem.displayName": "定制时间范围", + "xpack.uiActionsEnhanced.components.DiscoverDrilldownConfig.chooseIndexPattern": "选择目标索引模式", + "xpack.uiActionsEnhanced.drilldown.goToDiscover": "前往 Discover(示例)", "xpack.alerts.alertNavigationRegistry.get.missingNavigationError": "在“{consumer}”内针对告警类型“{alertType}”的导航未注册。", "xpack.alerts.alertNavigationRegistry.register.duplicateDefaultError": "“{consumer}”内的默认导航已注册。", "xpack.alerts.alertNavigationRegistry.register.duplicateNavigationError": "在“{consumer}”内针对告警类型“{alertType}”的导航已注册。", @@ -8731,16 +8733,12 @@ "xpack.lens.indexPattern.termsOf": "{name} 的排名最前值", "xpack.lens.indexPattern.uniqueLabel": "{label} [{num}]", "xpack.lens.indexPatterns.clearFiltersLabel": "清除名称和类型筛选", - "xpack.lens.indexPatterns.emptyFieldsWithDataLabel": "似乎您没有任何数据。", "xpack.lens.indexPatterns.filterByNameAriaLabel": "搜索字段", "xpack.lens.indexPatterns.filterByNameLabel": "搜索字段", - "xpack.lens.indexPatterns.filterByTypeLabel": "按类型筛选", "xpack.lens.indexPatterns.noFields.extendTimeBullet": "延伸时间范围", - "xpack.lens.indexPatterns.noFields.fieldFilterBullet": "使用 {filterByTypeLabel} {arrow} 显示没有数据的字段", "xpack.lens.indexPatterns.noFields.tryText": "尝试:", "xpack.lens.indexPatterns.noFieldsLabel": "在此索引模式中不存在任何字段。", "xpack.lens.indexPatterns.noFilteredFieldsLabel": "没有任何字段匹配当前筛选。", - "xpack.lens.indexPatterns.toggleEmptyFieldsSwitch": "仅显示具有数据的字段", "xpack.lens.indexPatternSuggestion.removeLayerLabel": "仅显示 {indexPatternTitle}", "xpack.lens.indexPatternSuggestion.removeLayerPositionLabel": "仅显示图层 {layerNumber}", "xpack.lens.lensSavedObjectLabel": "Lens 可视化", @@ -16383,8 +16381,6 @@ "xpack.triggersActionsUI.timeUnits.secondLabel": "{timeValue, plural, one {秒} other {秒}}", "xpack.triggersActionsUI.typeRegistry.get.missingActionTypeErrorMessage": "未注册对象类型“{id}”。", "xpack.triggersActionsUI.typeRegistry.register.duplicateObjectTypeErrorMessage": "已注册对象类型“{id}”。", - "xpack.uiActionsEnhanced.components.DiscoverDrilldownConfig.chooseIndexPattern": "选择目标索引模式", - "xpack.uiActionsEnhanced.drilldown.goToDiscover": "前往 Discover(示例)", "xpack.upgradeAssistant.appTitle": "{version} 升级助手", "xpack.upgradeAssistant.checkupTab.backUpCallout.calloutBody.calloutDetail": "使用 {snapshotRestoreDocsButton} 备份您的数据。", "xpack.upgradeAssistant.checkupTab.backUpCallout.calloutBody.snapshotRestoreDocsButtonLabel": "快照和还原 API", From d13b2bccc907309b4ace073b2094b66cfe79f3bb Mon Sep 17 00:00:00 2001 From: cchaos Date: Thu, 11 Jun 2020 16:55:19 -0400 Subject: [PATCH 06/28] Design PR - Changed Field Filters component (once again) - Fixed some overflows of accordions --- .../indexpattern_datasource/_datapanel.scss | 17 +- .../indexpattern_datasource/datapanel.tsx | 159 +++++++++--------- 2 files changed, 82 insertions(+), 94 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/_datapanel.scss b/x-pack/plugins/lens/public/indexpattern_datasource/_datapanel.scss index 77d4b41a0413c1..e2341a1807bb13 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/_datapanel.scss +++ b/x-pack/plugins/lens/public/indexpattern_datasource/_datapanel.scss @@ -16,10 +16,6 @@ line-height: $euiSizeXXL; } -.lnsInnerIndexPatternDataPanel__filterWrapper { - flex-grow: 0; -} - /** * 1. Don't cut off the shadow of the field items */ @@ -39,13 +35,12 @@ top: 0; left: $euiSize; /* 1 */ right: $euiSizeXS; /* 1 */ -} -.lnsInnerIndexPatternDataPanel__filterButton { - width: 100%; - color: $euiColorPrimary; - padding-left: $euiSizeS; - padding-right: $euiSizeS; + /* EUI-TODO: Allow passing a classname to this component */ + .euiAccordion__childWrapper { + // Quick fix for making sure the shadow and focus rings are visible outside the accordion bounds + padding: $euiSizeXS; + } } .lnsInnerIndexPatternDataPanel__textField { @@ -54,7 +49,9 @@ } .lnsInnerIndexPatternDataPanel__filterType { + font-size: $euiFontSizeS; padding: $euiSizeS; + border-bottom: 1px solid $euiColorLightestShade; } .lnsInnerIndexPatternDataPanel__filterTypeInner { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx index 98758aa441f1c0..3466f61e4371ec 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx @@ -7,26 +7,23 @@ import { uniq, indexBy } from 'lodash'; import React, { useState, useEffect, memo, useCallback } from 'react'; import { - // @ts-ignore - EuiHighlight, EuiFlexGroup, EuiFlexItem, EuiContextMenuPanel, EuiContextMenuItem, EuiContextMenuPanelProps, EuiPopover, - EuiPopoverTitle, - EuiButton, + EuiText, EuiCallOut, EuiFormControlLayout, EuiNotificationBadge, EuiSpacer, - EuiFormLabel, EuiAccordion, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { DataPublicPluginStart } from 'src/plugins/data/public'; +import { EuiFilterGroup, EuiFilterButton } from '@elastic/eui'; import { DatasourceDataPanelProps, DataType, StateSetter } from '../types'; import { ChildDragDropProvider, DragContextState } from '../drag_drop'; import { FieldItem } from './field_item'; @@ -293,7 +290,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ direction="column" responsive={false} > - +
- -
+ + { + trackUiEvent('indexpattern_filters_cleared'); + clearLocalState(); + }, + }} + > + { + setLocalState({ ...localState, nameFilter: e.target.value }); + }} + aria-label={i18n.translate('xpack.lens.indexPatterns.filterByNameAriaLabel', { + defaultMessage: 'Search fields', + })} + /> + + + + + setLocalState(() => ({ ...localState, isTypeFilterOpen: false }))} button={ - - { - setLocalState((s) => ({ - ...s, - isTypeFilterOpen: !localState.isTypeFilterOpen, - })); - }} - > - {localState.typeFilter.length ? ( - <> - {fieldFiltersLabel}{' '} - - {localState.typeFilter.length} - - - ) : ( - fieldFiltersLabel - )} - - - + { + setLocalState((s) => ({ + ...s, + isTypeFilterOpen: !localState.isTypeFilterOpen, + })); + }} + > + {fieldFiltersLabel} + } > - {fieldFiltersLabel} -
- -
- { - trackUiEvent('indexpattern_filters_cleared'); - clearLocalState(); - }, - }} - > - { - setLocalState({ ...localState, nameFilter: e.target.value }); - }} - aria-label={i18n.translate('xpack.lens.indexPatterns.filterByNameAriaLabel', { - defaultMessage: 'Search fields', - })} - /> - -
+ +
+
{ @@ -445,11 +434,13 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ initialIsOpen={true} id="availableFieldsLabel" buttonContent={ - - {i18n.translate('xpack.lens.indexPattern.availableFieldsLabel', { - defaultMessage: 'Available fields', - })} - + + + {i18n.translate('xpack.lens.indexPattern.availableFieldsLabel', { + defaultMessage: 'Available fields', + })} + + } extraAction={ @@ -556,11 +547,13 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ initialIsOpen={false} id="emptyFieldsLabel" buttonContent={ - - {i18n.translate('xpack.lens.indexPattern.emptyFieldsLabel', { - defaultMessage: 'Empty fields', - })} - + + + {i18n.translate('xpack.lens.indexPattern.emptyFieldsLabel', { + defaultMessage: 'Empty fields', + })} + + } extraAction={ - -
From 9bff7c802520e7ef858402173d6a4e0017a0c7e7 Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Fri, 12 Jun 2020 11:02:56 +0200 Subject: [PATCH 07/28] fix: aligning the field-select --- .../indexpattern_datasource/datapanel.tsx | 3 +- .../dimension_panel/field_select.tsx | 44 +++++++++++++------ .../test/functional/page_objects/lens_page.ts | 9 ---- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx index 3466f61e4371ec..7ed5f4ab87a716 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx @@ -19,11 +19,12 @@ import { EuiNotificationBadge, EuiSpacer, EuiAccordion, + EuiFilterGroup, + EuiFilterButton, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { DataPublicPluginStart } from 'src/plugins/data/public'; -import { EuiFilterGroup, EuiFilterButton } from '@elastic/eui'; import { DatasourceDataPanelProps, DataType, StateSetter } from '../types'; import { ChildDragDropProvider, DragContextState } from '../drag_drop'; import { FieldItem } from './field_item'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/field_select.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/field_select.tsx index d2044cbec131de..0edf2a7ea7285d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/field_select.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/field_select.tsx @@ -66,6 +66,10 @@ export function FieldSelect({ (field) => fieldMap[field].type === 'document' ); + const containsData = (field: string) => + fieldMap[field].type === 'document' || + fieldExists(existingFields, currentIndexPattern.title, field); + function fieldNamesToOptions(items: string[]) { return items .map((field) => ({ @@ -79,12 +83,9 @@ export function FieldSelect({ ? selectedColumnOperationType : undefined, }, - exists: - fieldMap[field].type === 'document' || - fieldExists(existingFields, currentIndexPattern.title, field), + exists: containsData(field), compatible: isCompatibleWithCurrentOperation(field), })) - .filter((field) => field.exists) .sort((a, b) => { if (a.compatible && !b.compatible) { return -1; @@ -105,18 +106,33 @@ export function FieldSelect({ })); } - const fieldOptions: unknown[] = fieldNamesToOptions(specialFields); + const [availableFields, emptyFields] = _.partition(normalFields, containsData); - if (fields.length > 0) { - fieldOptions.push({ - label: i18n.translate('xpack.lens.indexPattern.individualFieldsLabel', { - defaultMessage: 'Individual fields', - }), - options: fieldNamesToOptions(normalFields), - }); - } + const constructFieldsOptions = (fieldsArr: string[], label: string) => + fieldsArr.length > 0 && { + label, + options: fieldNamesToOptions(fieldsArr), + }; + + const availableFieldsOptions = constructFieldsOptions( + availableFields, + i18n.translate('xpack.lens.indexPattern.availableFieldsLabel', { + defaultMessage: 'Available fields', + }) + ); + + const emptyFieldsOptions = constructFieldsOptions( + emptyFields, + i18n.translate('xpack.lens.indexPattern.emptyFieldsLabel', { + defaultMessage: 'Empty fields', + }) + ); - return fieldOptions; + return [ + ...fieldNamesToOptions(specialFields), + availableFieldsOptions, + emptyFieldsOptions, + ].filter(Boolean); }, [ incompatibleSelectedOperationType, selectedColumnOperationType, diff --git a/x-pack/test/functional/page_objects/lens_page.ts b/x-pack/test/functional/page_objects/lens_page.ts index 3f048a9ee2aaac..bae11e1ea8a900 100644 --- a/x-pack/test/functional/page_objects/lens_page.ts +++ b/x-pack/test/functional/page_objects/lens_page.ts @@ -30,15 +30,6 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont await testSubjects.click('lnsIndexPatternFiltersToggle'); }, - /** - * Toggles the field existence checkbox. - */ - async toggleExistenceFilter() { - await this.toggleIndexPatternFiltersPopover(); - await testSubjects.click('lnsEmptyFilter'); - await this.toggleIndexPatternFiltersPopover(); - }, - async findAllFields() { return await testSubjects.findAll('lnsFieldListPanelField'); }, From f4036c01622a1dc6021cb01e2556719d08a2aaf9 Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Fri, 12 Jun 2020 14:59:59 +0200 Subject: [PATCH 08/28] refactor: group fields & add proper selecting of filtered groups --- .../indexpattern_datasource/datapanel.tsx | 96 +++++++++++++------ 1 file changed, 65 insertions(+), 31 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx index 7ed5f4ab87a716..ee0d8eb862a854 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { uniq, indexBy } from 'lodash'; +import { uniq, indexBy, groupBy } from 'lodash'; import React, { useState, useEffect, memo, useCallback } from 'react'; import { EuiFlexGroup, @@ -181,6 +181,12 @@ interface DataPanelState { isTypeFilterOpen: boolean; } +export interface FieldsGroup { + specialFields: IndexPatternField[]; + availableFields: IndexPatternField[]; + emptyFields: IndexPatternField[]; +} + const fieldFiltersLabel = i18n.translate('xpack.lens.indexPatterns.fieldFiltersLabel', { defaultMessage: 'Field filters', }); @@ -241,24 +247,6 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ (type) => type in fieldTypeNames ); - const filteredFields = allFields.filter((field) => { - if (!supportedFieldTypes.has(field.type)) { - return false; - } - - if ( - localState.nameFilter.length && - !field.name.toLowerCase().includes(localState.nameFilter.toLowerCase()) - ) { - return false; - } - - if (localState.typeFilter.length > 0) { - return localState.typeFilter.includes(field.type as DataType); - } - return true; - }); - const containsData = (field: IndexPatternField) => { const fieldByName = indexBy(allFields, 'name'); const overallField = fieldByName[field.name]; @@ -267,13 +255,53 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ ); }; - const [specialFields, documentFields] = _.partition(filteredFields, (f) => f.type === 'document'); + const allSupportedTypesFields = allFields.filter((field) => supportedFieldTypes.has(field.type)); + + const fieldGroups: FieldsGroup = { + specialFields: [], + availableFields: [], + emptyFields: [], + ...groupBy(allSupportedTypesFields, (field) => { + if (field.type === 'document') { + return 'specialFields'; + } else if (containsData(field)) { + return 'availableFields'; + } else return 'emptyFields'; + }), + }; - const [availableFields, emptyFields] = _.partition(documentFields, containsData); + const filterFieldGroup = (fieldGroup: IndexPatternField[]) => + fieldGroup.filter((field) => { + if ( + localState.nameFilter.length && + !field.name.toLowerCase().includes(localState.nameFilter.toLowerCase()) + ) { + return false; + } + + if (localState.typeFilter.length > 0) { + return localState.typeFilter.includes(field.type as DataType); + } + return true; + }); + + const filteredFieldGroups: FieldsGroup = Object.entries(fieldGroups).reduce( + (acc, [name, fields]) => { + return { + ...acc, + [name]: filterFieldGroup(fields).sort(sortFields), + }; + }, + { + specialFields: [], + availableFields: [], + emptyFields: [], + } + ); const paginatedFields = [ - ...availableFields.sort(sortFields), - ...emptyFields.sort(sortFields), + ...filteredFieldGroups.availableFields, + ...filteredFieldGroups.emptyFields, ].slice(0, pageSize); const [paginatedAvailableFields, paginatedEmptyFields] = _.partition( @@ -414,7 +442,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ onScroll={lazyScroll} >
- {specialFields.map((field) => ( + {filteredFieldGroups.specialFields.map((field: IndexPatternField) => ( 0} + exists={!!fieldGroups.availableFields.length} dateRange={dateRange} query={query} filters={filters} @@ -447,17 +475,19 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ - {availableFields.length} + {filteredFieldGroups.availableFields.length} } > - {paginatedAvailableFields.map((field) => { + {paginatedAvailableFields.map((field: IndexPatternField) => { return ( )} + - {emptyFields.length} + {filteredFieldGroups.emptyFields.length} } > - {paginatedEmptyFields.map((field) => { + {paginatedEmptyFields.map((field: IndexPatternField) => { return ( ); })} + +
From 651d412dc1f6e9fc73fbaf31831b2f7077ca1c07 Mon Sep 17 00:00:00 2001 From: cchaos Date: Fri, 12 Jun 2020 11:35:47 -0400 Subject: [PATCH 09/28] More spacing fixes --- .../indexpattern_datasource/_index.scss | 1 - .../{_datapanel.scss => datapanel.scss} | 9 +-- .../indexpattern_datasource/datapanel.tsx | 75 ++++++++++--------- 3 files changed, 43 insertions(+), 42 deletions(-) rename x-pack/plugins/lens/public/indexpattern_datasource/{_datapanel.scss => datapanel.scss} (84%) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/_index.scss b/x-pack/plugins/lens/public/indexpattern_datasource/_index.scss index e5d8b408e33e53..408ba057262df3 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/_index.scss +++ b/x-pack/plugins/lens/public/indexpattern_datasource/_index.scss @@ -1,4 +1,3 @@ -@import 'datapanel'; @import 'field_item'; @import 'dimension_panel/index'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/_datapanel.scss b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.scss similarity index 84% rename from x-pack/plugins/lens/public/indexpattern_datasource/_datapanel.scss rename to x-pack/plugins/lens/public/indexpattern_datasource/datapanel.scss index e2341a1807bb13..3e767502fae3b5 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/_datapanel.scss +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.scss @@ -35,12 +35,11 @@ top: 0; left: $euiSize; /* 1 */ right: $euiSizeXS; /* 1 */ +} - /* EUI-TODO: Allow passing a classname to this component */ - .euiAccordion__childWrapper { - // Quick fix for making sure the shadow and focus rings are visible outside the accordion bounds - padding: $euiSizeXS; - } +.lnsInnerIndexPatternDataPanel__fieldItems { + // Quick fix for making sure the shadow and focus rings are visible outside the accordion bounds + padding: $euiSizeXS $euiSizeXS 0; } .lnsInnerIndexPatternDataPanel__textField { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx index ee0d8eb862a854..23ce76632ed949 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import './datapanel.scss'; import { uniq, indexBy, groupBy } from 'lodash'; import React, { useState, useEffect, memo, useCallback } from 'react'; import { @@ -487,22 +488,24 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ } > - {paginatedAvailableFields.map((field: IndexPatternField) => { - return ( - - ); - })} +
+ {paginatedAvailableFields.map((field: IndexPatternField) => { + return ( + + ); + })} +
{paginatedAvailableFields.length === 0 && ( )} -
- + - {paginatedEmptyFields.map((field: IndexPatternField) => { - return ( - - ); - })} - +
+ {paginatedEmptyFields.map((field: IndexPatternField) => { + return ( + + ); + })} +
- + From 6b56c09f38131c89ceb9ec3b55230219ebcddb4e Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Mon, 15 Jun 2020 10:34:19 +0200 Subject: [PATCH 10/28] refactor: extract NoFieldsCallout --- .../indexpattern_datasource/datapanel.tsx | 91 ++++--------------- .../no_fields_callout.tsx | 75 +++++++++++++++ .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 4 files changed, 93 insertions(+), 75 deletions(-) create mode 100644 x-pack/plugins/lens/public/indexpattern_datasource/no_fields_callout.tsx diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx index 23ce76632ed949..5b25d3b1668b1f 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx @@ -29,6 +29,7 @@ import { DataPublicPluginStart } from 'src/plugins/data/public'; import { DatasourceDataPanelProps, DataType, StateSetter } from '../types'; import { ChildDragDropProvider, DragContextState } from '../drag_drop'; import { FieldItem } from './field_item'; +import { NoFieldsCallout } from './no_fields_callout'; import { IndexPattern, IndexPatternPrivateState, @@ -311,6 +312,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ ); const hilight = localState.nameFilter.toLowerCase(); + const hasFieldFilter = !!(localState.typeFilter.length || localState.nameFilter.length); return ( @@ -389,7 +391,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ iconType="arrowDown" isSelected={localState.isTypeFilterOpen} numFilters={localState.typeFilter.length} - hasActiveFilters={localState.typeFilter.length ? true : false} + hasActiveFilters={!!localState.typeFilter.length} numActiveFilters={localState.typeFilter.length} data-test-subj="lnsIndexPatternFiltersToggle" onClick={() => { @@ -476,9 +478,8 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ - - {paginatedAvailableFields.length === 0 && ( - - {(localState.typeFilter.length || - localState.nameFilter.length || - paginatedEmptyFields.length) && ( - <> - - {i18n.translate('xpack.lens.indexPatterns.noFields.tryText', { - defaultMessage: 'Try:', - })} - -
    -
  • - {i18n.translate('xpack.lens.indexPatterns.noFields.extendTimeBullet', { - defaultMessage: 'Extending the time range', - })} -
  • - {localState.nameFilter.length ? ( -
  • - {i18n.translate( - 'xpack.lens.indexPatterns.noFields.fieldQueryFilterBullet', - { - defaultMessage: 'Changing the field query filter', - } - )} -
  • - ) : null} - {localState.typeFilter.length ? ( -
  • - {i18n.translate( - 'xpack.lens.indexPatterns.noFields.fieldTypeFilterBullet', - { - defaultMessage: 'Changing the field filters', - } - )} -
  • - ) : null} - {filters.length ? ( -
  • - {i18n.translate( - 'xpack.lens.indexPatterns.noFields.globalFiltersBullet', - { - defaultMessage: 'Changing the global filters', - } - )} -
  • - ) : null} -
- - )} -
- )} + {paginatedAvailableFields.length === 0 && ( + + )} + {paginatedEmptyFields.length === 0 && ( + + )} diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/no_fields_callout.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/no_fields_callout.tsx new file mode 100644 index 00000000000000..d6b089f63669ff --- /dev/null +++ b/x-pack/plugins/lens/public/indexpattern_datasource/no_fields_callout.tsx @@ -0,0 +1,75 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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 { EuiCallOut } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +export const NoFieldsCallout = ({ + isAffectedByFieldFilter, + existFieldsInIndex, + isAffectedByTimerange = false, + isAffectedByGlobalFilter = false, +}: { + isAffectedByFieldFilter: boolean; + existFieldsInIndex: boolean; + isAffectedByTimerange?: boolean; + isAffectedByGlobalFilter?: boolean; +}) => { + return ( + + {existFieldsInIndex && ( + <> + + {i18n.translate('xpack.lens.indexPatterns.noFields.tryText', { + defaultMessage: 'Try:', + })} + +
    + {isAffectedByTimerange && ( + <> +
  • + {i18n.translate('xpack.lens.indexPatterns.noFields.extendTimeBullet', { + defaultMessage: 'Extending the time range', + })} +
  • + + )} + {isAffectedByFieldFilter ? ( +
  • + {i18n.translate('xpack.lens.indexPatterns.noFields.fieldTypeFilterBullet', { + defaultMessage: 'Changing the field filters', + })} +
  • + ) : null} + {isAffectedByGlobalFilter ? ( +
  • + {i18n.translate('xpack.lens.indexPatterns.noFields.globalFiltersBullet', { + defaultMessage: 'Changing the global filters', + })} +
  • + ) : null} +
+ + )} +
+ ); +}; diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index f870485c230026..fd0cc8a924a103 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -8698,7 +8698,6 @@ "xpack.lens.indexPattern.groupingSecondDateHistogram": "各 {target} の日付", "xpack.lens.indexPattern.groupingSecondTerms": "各 {target} のトップの値", "xpack.lens.indexPattern.indexPatternLoadError": "インデックスパターンの読み込み中にエラーが発生", - "xpack.lens.indexPattern.individualFieldsLabel": "個々のフィールド", "xpack.lens.indexPattern.invalidInterval": "無効な間隔値", "xpack.lens.indexPattern.invalidOperationLabel": "この関数を使用するには、別のフィールドを選択してください。", "xpack.lens.indexPattern.max": "最高", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 729cfd41985793..e1a442cea5a9d4 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -8702,7 +8702,6 @@ "xpack.lens.indexPattern.groupingSecondDateHistogram": "每个 {target} 的日期", "xpack.lens.indexPattern.groupingSecondTerms": "每个 {target} 的排名最前值", "xpack.lens.indexPattern.indexPatternLoadError": "加载索引模式时出错", - "xpack.lens.indexPattern.individualFieldsLabel": "各个字段", "xpack.lens.indexPattern.invalidInterval": "时间间隔值无效", "xpack.lens.indexPattern.invalidOperationLabel": "要使用此函数,请选择不同的字段。", "xpack.lens.indexPattern.max": "最大值", From 4277633aad75ada5f9602a52434c83481efa4d6e Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Mon, 15 Jun 2020 14:26:06 +0200 Subject: [PATCH 11/28] test added to no fields callout --- .../no_fields_callout.test.tsx.snap | 49 +++++++ .../indexpattern_datasource/datapanel.tsx | 126 ++++++++++-------- .../no_fields_callout.test.tsx | 36 +++++ 3 files changed, 155 insertions(+), 56 deletions(-) create mode 100644 x-pack/plugins/lens/public/indexpattern_datasource/__snapshots__/no_fields_callout.test.tsx.snap create mode 100644 x-pack/plugins/lens/public/indexpattern_datasource/no_fields_callout.test.tsx diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/__snapshots__/no_fields_callout.test.tsx.snap b/x-pack/plugins/lens/public/indexpattern_datasource/__snapshots__/no_fields_callout.test.tsx.snap new file mode 100644 index 00000000000000..35ccb65976bbf8 --- /dev/null +++ b/x-pack/plugins/lens/public/indexpattern_datasource/__snapshots__/no_fields_callout.test.tsx.snap @@ -0,0 +1,49 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`NoFieldCallout renders properly for index with no fields 1`] = ` + +`; + +exports[`NoFieldCallout renders properly when affected by field filter 1`] = ` + + + Try: + +
    +
  • + Changing the field filters +
  • +
+
+`; + +exports[`NoFieldCallout renders properly when affected by field filters, global filter and timerange 1`] = ` + + + Try: + +
    +
  • + Extending the time range +
  • +
  • + Changing the field filters +
  • +
  • + Changing the global filters +
  • +
+
+`; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx index 5b25d3b1668b1f..5b454fc010fd34 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx @@ -189,6 +189,12 @@ export interface FieldsGroup { emptyFields: IndexPatternField[]; } +const defaultFieldGroups = { + specialFields: [], + availableFields: [], + emptyFields: [], +}; + const fieldFiltersLabel = i18n.translate('xpack.lens.indexPatterns.fieldFiltersLabel', { defaultMessage: 'Field filters', }); @@ -260,9 +266,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ const allSupportedTypesFields = allFields.filter((field) => supportedFieldTypes.has(field.type)); const fieldGroups: FieldsGroup = { - specialFields: [], - availableFields: [], - emptyFields: [], + ...defaultFieldGroups, ...groupBy(allSupportedTypesFields, (field) => { if (field.type === 'document') { return 'specialFields'; @@ -294,11 +298,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ [name]: filterFieldGroup(fields).sort(sortFields), }; }, - { - specialFields: [], - availableFields: [], - emptyFields: [], - } + defaultFieldGroups ); const paginatedFields = [ @@ -488,33 +488,40 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({
} > - -
- {paginatedAvailableFields.map((field: IndexPatternField) => { - return ( - - ); - })} -
+ {!!filteredFieldGroups.availableFields.length && ( + <> + +
+ {paginatedAvailableFields.map((field: IndexPatternField) => { + return ( + + ); + })} +
+ + )} {paginatedAvailableFields.length === 0 && ( - + <> + + + )} } > - -
- {paginatedEmptyFields.map((field: IndexPatternField) => { - return ( - - ); - })} -
+ {!!paginatedEmptyFields.length && ( + <> + +
+ {paginatedEmptyFields.map((field: IndexPatternField) => { + return ( + + ); + })} +
+ + )}
{paginatedEmptyFields.length === 0 && ( - + <> + + + )} diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/no_fields_callout.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/no_fields_callout.test.tsx new file mode 100644 index 00000000000000..f32bf52339e1c0 --- /dev/null +++ b/x-pack/plugins/lens/public/indexpattern_datasource/no_fields_callout.test.tsx @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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 { shallow } from 'enzyme'; +import { NoFieldsCallout } from './no_fields_callout'; + +describe('NoFieldCallout', () => { + it('renders properly for index with no fields', () => { + const component = shallow( + + ); + expect(component).toMatchSnapshot(); + }); + + it('renders properly when affected by field filters, global filter and timerange', () => { + const component = shallow( + + ); + expect(component).toMatchSnapshot(); + }); + + it('renders properly when affected by field filter', () => { + const component = shallow( + + ); + expect(component).toMatchSnapshot(); + }); +}); From 563f82153dd1ac9efc5fab410349652a54a0528d Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Mon, 15 Jun 2020 15:32:05 +0200 Subject: [PATCH 12/28] tests updated --- .../datapanel.test.tsx | 122 ++++++++++-------- .../indexpattern_datasource/datapanel.tsx | 7 +- 2 files changed, 70 insertions(+), 59 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx index 723ba5cd1845b2..6f436f367bc0aa 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx @@ -9,6 +9,7 @@ import { createMockedDragDropContext } from './mocks'; import { dataPluginMock } from '../../../../../src/plugins/data/public/mocks'; import { InnerIndexPatternDataPanel, IndexPatternDataPanel, MemoizedDataPanel } from './datapanel'; import { FieldItem } from './field_item'; +import { NoFieldsCallout } from './no_fields_callout'; import { act } from 'react-dom/test-utils'; import { coreMock } from 'src/core/public/mocks'; import { IndexPatternPrivateState } from './types'; @@ -530,18 +531,47 @@ describe('IndexPattern Data Panel', () => { }); }); - describe('while showing empty fields', () => { - it('should list all supported fields in the pattern sorted alphabetically', async () => { - const wrapper = shallowWithIntl(); + describe('displaying field list', () => { + it('should list all supported fields in the pattern sorted alphabetically in groups', async () => { + const existingFields = { + idx1: { + bytes: true, + memory: true, + }, + }; + const wrapper = shallowWithIntl( + + ); + expect(wrapper.find(FieldItem).first().prop('field').name).toEqual('Records'); + expect( + wrapper + .find('[data-test-subj="lnsIndexPatternAvailableFields"]') + .find(FieldItem) + .map((fieldItem) => fieldItem.prop('field').name) + ).toEqual(['bytes', 'memory']); + expect( + wrapper + .find('[data-test-subj="lnsIndexPatternEmptyFields"]') + .find(FieldItem) + .map((fieldItem) => fieldItem.prop('field').name) + ).toEqual(['client', 'source', 'timestamp']); + }); - expect(wrapper.find(FieldItem).map((fieldItem) => fieldItem.prop('field').name)).toEqual([ - 'Records', - 'bytes', - 'client', - 'memory', - 'source', - 'timestamp', - ]); + it('should display NoFieldsCallout when all fields are empty', async () => { + const wrapper = shallowWithIntl(); + expect(wrapper.find(NoFieldsCallout).first().prop('isAffectedByTimerange')).toEqual(true); + expect( + wrapper + .find('[data-test-subj="lnsIndexPatternAvailableFields"]') + .find(FieldItem) + .map((fieldItem) => fieldItem.prop('field').name) + ).toEqual([]); + expect( + wrapper + .find('[data-test-subj="lnsIndexPatternEmptyFields"]') + .find(FieldItem) + .map((fieldItem) => fieldItem.prop('field').name) + ).toEqual(['bytes', 'client', 'memory', 'source', 'timestamp']); }); it('should filter down by name', () => { @@ -549,12 +579,13 @@ describe('IndexPattern Data Panel', () => { act(() => { wrapper.find('[data-test-subj="lnsIndexPatternFieldSearch"]').prop('onChange')!({ - target: { value: 'mem' }, + target: { value: 'me' }, } as ChangeEvent); }); expect(wrapper.find(FieldItem).map((fieldItem) => fieldItem.prop('field').name)).toEqual([ 'memory', + 'timestamp', ]); }); @@ -571,6 +602,27 @@ describe('IndexPattern Data Panel', () => { ]); }); + it('should display no fields in groups when filtered by type Record', () => { + const existingFields = { + idx1: { + bytes: true, + memory: true, + }, + }; + const wrapper = mountWithIntl( + + ); + + wrapper.find('[data-test-subj="lnsIndexPatternFiltersToggle"]').first().simulate('click'); + + wrapper.find('[data-test-subj="typeFilter-document"]').first().simulate('click'); + + expect(wrapper.find(FieldItem).map((fieldItem) => fieldItem.prop('field').name)).toEqual([ + 'Records', + ]); + expect(wrapper.find(NoFieldsCallout).length).toEqual(2); + }); + it('should toggle type if clicked again', () => { const wrapper = mountWithIntl(); @@ -594,7 +646,7 @@ describe('IndexPattern Data Panel', () => { act(() => { wrapper.find('[data-test-subj="lnsIndexPatternFieldSearch"]').prop('onChange')!({ - target: { value: 'mem' }, + target: { value: 'me' }, } as ChangeEvent); }); @@ -626,49 +678,5 @@ describe('IndexPattern Data Panel', () => { }, }; }); - - it('should list all supported fields in the pattern sorted alphabetically', async () => { - const props = { - ...emptyFieldsTestProps, - existingFields: { - idx1: { - bytes: true, - memory: true, - }, - }, - }; - const wrapper = shallowWithIntl(); - - expect(wrapper.find(FieldItem).map((fieldItem) => fieldItem.prop('field').name)).toEqual([ - 'Records', - 'bytes', - 'memory', - ]); - }); - - it('should filter down by name', () => { - const wrapper = shallowWithIntl(); - - act(() => { - wrapper.find('[data-test-subj="lnsIndexPatternFieldSearch"]').prop('onChange')!({ - target: { value: 'mem' }, - } as ChangeEvent); - }); - - expect(wrapper.find(FieldItem).map((fieldItem) => fieldItem.prop('field').name)).toEqual([ - 'memory', - ]); - }); - - it('should allow removing the filter for data', () => { - const wrapper = mountWithIntl(); - - wrapper.find('[data-test-subj="lnsIndexPatternFiltersToggle"]').first().simulate('click'); - - wrapper.find('[data-test-subj="lnsEmptyFilter"]').first().prop('onChange')!( - {} as ChangeEvent - ); - // TO DO - }); }); }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx index 5b454fc010fd34..54e23d538a2110 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx @@ -258,6 +258,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ const containsData = (field: IndexPatternField) => { const fieldByName = indexBy(allFields, 'name'); const overallField = fieldByName[field.name]; + return ( overallField && fieldExists(existingFields, currentIndexPattern.title, overallField.name) ); @@ -464,7 +465,8 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ @@ -526,7 +528,8 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ From 09cb8b511dade0c7f633a84c655765e677e8ee2a Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Mon, 15 Jun 2020 16:26:52 +0200 Subject: [PATCH 13/28] test: remove not needed --- .../datapanel.test.tsx | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx index 6f436f367bc0aa..7e67a0d229d5ec 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx @@ -659,24 +659,4 @@ describe('IndexPattern Data Panel', () => { ]); }); }); - - describe('filtering out empty fields', () => { - let emptyFieldsTestProps: typeof defaultProps; - - beforeEach(() => { - emptyFieldsTestProps = { - ...defaultProps, - indexPatterns: { - ...defaultProps.indexPatterns, - '1': { - ...defaultProps.indexPatterns['1'], - fields: defaultProps.indexPatterns['1'].fields.map((field) => ({ - ...field, - exists: field.type === 'number', - })), - }, - }, - }; - }); - }); }); From 157c7d4021f103540cbb9ff3803e08bd04368fbc Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Wed, 17 Jun 2020 11:34:15 +0200 Subject: [PATCH 14/28] copy --- .../public/indexpattern_datasource/no_fields_callout.tsx | 6 +++--- x-pack/plugins/translations/translations/ja-JP.json | 1 - x-pack/plugins/translations/translations/zh-CN.json | 1 - 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/no_fields_callout.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/no_fields_callout.tsx index d6b089f63669ff..066d60f0062073 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/no_fields_callout.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/no_fields_callout.tsx @@ -25,11 +25,11 @@ export const NoFieldsCallout = ({ title={ isAffectedByFieldFilter ? i18n.translate('xpack.lens.indexPatterns.noFilteredFieldsLabel', { - defaultMessage: 'No fields match the current filters.', + defaultMessage: 'No fields match the selected filters.', }) : existFieldsInIndex ? i18n.translate('xpack.lens.indexPatterns.noDataLabel', { - defaultMessage: `Looks like you don't have any fields with data`, + defaultMessage: `There are no available fields that contain data.`, }) : i18n.translate('xpack.lens.indexPatterns.noFieldsLabel', { defaultMessage: 'No fields exist in this index pattern.', @@ -56,7 +56,7 @@ export const NoFieldsCallout = ({ {isAffectedByFieldFilter ? (
  • {i18n.translate('xpack.lens.indexPatterns.noFields.fieldTypeFilterBullet', { - defaultMessage: 'Changing the field filters', + defaultMessage: 'Using different field filters', })}
  • ) : null} diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 75cbe02657b8bd..16ffad3ea2c14a 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -8722,7 +8722,6 @@ "xpack.lens.indexPatterns.noFields.extendTimeBullet": "時間範囲を拡張中", "xpack.lens.indexPatterns.noFields.tryText": "試行対象:", "xpack.lens.indexPatterns.noFieldsLabel": "このインデックスパターンにはフィールドがありません。", - "xpack.lens.indexPatterns.noFilteredFieldsLabel": "現在のフィルターと一致するフィールドはありません。", "xpack.lens.indexPatternSuggestion.removeLayerLabel": "{indexPatternTitle}のみを表示", "xpack.lens.indexPatternSuggestion.removeLayerPositionLabel": "レイヤー{layerNumber}のみを表示", "xpack.lens.lensSavedObjectLabel": "レンズビジュアライゼーション", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 51e02383686f45..955d3ca4b422f8 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -8726,7 +8726,6 @@ "xpack.lens.indexPatterns.noFields.extendTimeBullet": "延伸时间范围", "xpack.lens.indexPatterns.noFields.tryText": "尝试:", "xpack.lens.indexPatterns.noFieldsLabel": "在此索引模式中不存在任何字段。", - "xpack.lens.indexPatterns.noFilteredFieldsLabel": "没有任何字段匹配当前筛选。", "xpack.lens.indexPatternSuggestion.removeLayerLabel": "仅显示 {indexPatternTitle}", "xpack.lens.indexPatternSuggestion.removeLayerPositionLabel": "仅显示图层 {layerNumber}", "xpack.lens.lensSavedObjectLabel": "Lens 可视化", From 5cb1b3b390275f5e997e32d7692edabf392d812d Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Wed, 17 Jun 2020 11:39:34 +0200 Subject: [PATCH 15/28] fix: correct pagination bug --- .../indexpattern_datasource/datapanel.tsx | 166 ++++++++++-------- 1 file changed, 92 insertions(+), 74 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx index 54e23d538a2110..959136f39b40c4 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx @@ -63,7 +63,7 @@ function sortFields(fieldA: IndexPatternField, fieldB: IndexPatternField) { } const supportedFieldTypes = new Set(['string', 'number', 'boolean', 'date', 'ip', 'document']); -const PAGINATION_SIZE = 50; +const PAGINATION_SIZE = 10; const fieldTypeNames: Record = { document: i18n.translate('xpack.lens.datatypes.record', { defaultMessage: 'record' }), @@ -224,6 +224,8 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ nameFilter: '', typeFilter: [], isTypeFilterOpen: false, + isAvailableAccordionOpen: true, + isEmptyAccordionOpen: false, }); const [pageSize, setPageSize] = useState(PAGINATION_SIZE); const [scrollContainer, setScrollContainer] = useState(undefined); @@ -231,17 +233,6 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ const allFields = currentIndexPattern.fields; const clearLocalState = () => setLocalState((s) => ({ ...s, nameFilter: '', typeFilter: [] })); - const lazyScroll = () => { - if (scrollContainer) { - const nearBottom = - scrollContainer.scrollTop + scrollContainer.clientHeight > - scrollContainer.scrollHeight * 0.9; - if (nearBottom) { - setPageSize(Math.max(PAGINATION_SIZE, Math.min(pageSize * 1.5, allFields.length))); - } - } - }; - useEffect(() => { // Reset the scroll if we have made material changes to the field list if (scrollContainer) { @@ -303,10 +294,24 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ ); const paginatedFields = [ - ...filteredFieldGroups.availableFields, - ...filteredFieldGroups.emptyFields, + ...(localState.isAvailableAccordionOpen ? filteredFieldGroups.availableFields : []), + ...(localState.isEmptyAccordionOpen ? filteredFieldGroups.emptyFields : []), ].slice(0, pageSize); + const lazyScroll = () => { + if (scrollContainer) { + const nearBottom = + scrollContainer.scrollTop + scrollContainer.clientHeight > + scrollContainer.scrollHeight * 0.9; + if (nearBottom) { + const displayedFieldLength = + (localState.isAvailableAccordionOpen ? filteredFieldGroups.availableFields.length : 0) + + (localState.isEmptyAccordionOpen ? filteredFieldGroups.emptyFields.length : 0); + setPageSize(Math.max(PAGINATION_SIZE, Math.min(pageSize * 1.5, displayedFieldLength))); + } + } + }; + const [paginatedAvailableFields, paginatedEmptyFields] = _.partition( paginatedFields, containsData @@ -464,7 +469,19 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ { + setLocalState((s) => ({ + ...s, + isAvailableAccordionOpen: open, + })); + const displayedFieldLength = + (open ? filteredFieldGroups.availableFields.length : 0) + + (localState.isEmptyAccordionOpen ? filteredFieldGroups.emptyFields.length : 0); + setPageSize( + Math.max(PAGINATION_SIZE, Math.min(pageSize * 1.5, displayedFieldLength)) + ); + }} data-test-subj="lnsIndexPatternAvailableFields" id="lnsIndexPatternAvailableFields" buttonContent={ @@ -490,44 +507,51 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ } > - {!!filteredFieldGroups.availableFields.length && ( - <> - -
    - {paginatedAvailableFields.map((field: IndexPatternField) => { - return ( - - ); - })} -
    - - )} -
    - {paginatedAvailableFields.length === 0 && ( - <> - + + {!!filteredFieldGroups.availableFields.length ? ( +
    + {paginatedAvailableFields.map((field: IndexPatternField) => { + return ( + + ); + })} +
    + ) : ( - - )} + )} +
    { + setLocalState((s) => ({ + ...s, + isEmptyAccordionOpen: open, + })); + const displayedFieldLength = + (localState.isAvailableAccordionOpen + ? filteredFieldGroups.availableFields.length + : 0) + (open ? filteredFieldGroups.emptyFields.length : 0); + setPageSize( + Math.max(PAGINATION_SIZE, Math.min(pageSize * 1.5, displayedFieldLength)) + ); + }} data-test-subj="lnsIndexPatternEmptyFields" id="lnsIndexPatternEmptyFields" buttonContent={ @@ -552,39 +576,33 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ } > - {!!paginatedEmptyFields.length && ( - <> - -
    - {paginatedEmptyFields.map((field: IndexPatternField) => { - return ( - - ); - })} -
    - - )} -
    - {paginatedEmptyFields.length === 0 && ( - <> - + + {!!filteredFieldGroups.emptyFields.length ? ( +
    + {paginatedEmptyFields.map((field: IndexPatternField) => { + return ( + + ); + })} +
    + ) : ( - - )} + )} +
    From c19c0e85476aa8b90b960a799b7b36c98c21470c Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Wed, 17 Jun 2020 13:24:04 +0200 Subject: [PATCH 16/28] fixes pagination_size and always displays affectedbyTimerange --- .../plugins/lens/public/indexpattern_datasource/datapanel.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx index 959136f39b40c4..0b7ec90e2ec008 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx @@ -63,7 +63,7 @@ function sortFields(fieldA: IndexPatternField, fieldB: IndexPatternField) { } const supportedFieldTypes = new Set(['string', 'number', 'boolean', 'date', 'ip', 'document']); -const PAGINATION_SIZE = 10; +const PAGINATION_SIZE = 50; const fieldTypeNames: Record = { document: i18n.translate('xpack.lens.datatypes.record', { defaultMessage: 'record' }), @@ -531,7 +531,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ )} From 683a0e39ba0b57401e56d3aac1dde63ae180ea47 Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Wed, 17 Jun 2020 14:15:44 +0200 Subject: [PATCH 17/28] updating tests --- .../datapanel.test.tsx | 67 +++++++++++-------- .../indexpattern_datasource/datapanel.tsx | 2 + 2 files changed, 42 insertions(+), 27 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx index 7e67a0d229d5ec..55ea508c32782b 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx @@ -532,16 +532,20 @@ describe('IndexPattern Data Panel', () => { }); describe('displaying field list', () => { - it('should list all supported fields in the pattern sorted alphabetically in groups', async () => { - const existingFields = { - idx1: { - bytes: true, - memory: true, + let props: Parameters[0]; + beforeEach(() => { + props = { + ...defaultProps, + existingFields: { + idx1: { + bytes: true, + memory: true, + }, }, }; - const wrapper = shallowWithIntl( - - ); + }); + it('should list all supported fields in the pattern sorted alphabetically in groups', async () => { + const wrapper = mountWithIntl(); expect(wrapper.find(FieldItem).first().prop('field').name).toEqual('Records'); expect( wrapper @@ -549,6 +553,11 @@ describe('IndexPattern Data Panel', () => { .find(FieldItem) .map((fieldItem) => fieldItem.prop('field').name) ).toEqual(['bytes', 'memory']); + wrapper + .find('[data-test-subj="lnsIndexPatternEmptyFields"]') + .find('button') + .first() + .simulate('click'); expect( wrapper .find('[data-test-subj="lnsIndexPatternEmptyFields"]') @@ -558,7 +567,7 @@ describe('IndexPattern Data Panel', () => { }); it('should display NoFieldsCallout when all fields are empty', async () => { - const wrapper = shallowWithIntl(); + const wrapper = mountWithIntl(); expect(wrapper.find(NoFieldsCallout).first().prop('isAffectedByTimerange')).toEqual(true); expect( wrapper @@ -566,6 +575,11 @@ describe('IndexPattern Data Panel', () => { .find(FieldItem) .map((fieldItem) => fieldItem.prop('field').name) ).toEqual([]); + wrapper + .find('[data-test-subj="lnsIndexPatternEmptyFields"]') + .find('button') + .first() + .simulate('click'); expect( wrapper .find('[data-test-subj="lnsIndexPatternEmptyFields"]') @@ -575,14 +589,19 @@ describe('IndexPattern Data Panel', () => { }); it('should filter down by name', () => { - const wrapper = shallowWithIntl(); - + const wrapper = mountWithIntl(); act(() => { wrapper.find('[data-test-subj="lnsIndexPatternFieldSearch"]').prop('onChange')!({ target: { value: 'me' }, } as ChangeEvent); }); + wrapper + .find('[data-test-subj="lnsIndexPatternEmptyFields"]') + .find('button') + .first() + .simulate('click'); + expect(wrapper.find(FieldItem).map((fieldItem) => fieldItem.prop('field').name)).toEqual([ 'memory', 'timestamp', @@ -590,7 +609,7 @@ describe('IndexPattern Data Panel', () => { }); it('should filter down by type', () => { - const wrapper = mountWithIntl(); + const wrapper = mountWithIntl(); wrapper.find('[data-test-subj="lnsIndexPatternFiltersToggle"]').first().simulate('click'); @@ -603,15 +622,7 @@ describe('IndexPattern Data Panel', () => { }); it('should display no fields in groups when filtered by type Record', () => { - const existingFields = { - idx1: { - bytes: true, - memory: true, - }, - }; - const wrapper = mountWithIntl( - - ); + const wrapper = mountWithIntl(); wrapper.find('[data-test-subj="lnsIndexPatternFiltersToggle"]').first().simulate('click'); @@ -624,26 +635,28 @@ describe('IndexPattern Data Panel', () => { }); it('should toggle type if clicked again', () => { - const wrapper = mountWithIntl(); - + const wrapper = mountWithIntl(); wrapper.find('[data-test-subj="lnsIndexPatternFiltersToggle"]').first().simulate('click'); wrapper.find('[data-test-subj="typeFilter-number"]').first().simulate('click'); wrapper.find('[data-test-subj="typeFilter-number"]').first().simulate('click'); - + wrapper + .find('[data-test-subj="lnsIndexPatternEmptyFields"]') + .find('button') + .first() + .simulate('click'); expect(wrapper.find(FieldItem).map((fieldItem) => fieldItem.prop('field').name)).toEqual([ 'Records', 'bytes', - 'client', 'memory', + 'client', 'source', 'timestamp', ]); }); it('should filter down by type and by name', () => { - const wrapper = mountWithIntl(); - + const wrapper = mountWithIntl(); act(() => { wrapper.find('[data-test-subj="lnsIndexPatternFieldSearch"]').prop('onChange')!({ target: { value: 'me' }, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx index 0b7ec90e2ec008..2c3e2c7986597d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx @@ -181,6 +181,8 @@ interface DataPanelState { nameFilter: string; typeFilter: DataType[]; isTypeFilterOpen: boolean; + isAvailableAccordionOpen: boolean; + isEmptyAccordionOpen: boolean; } export interface FieldsGroup { From 6a64c642ab30e44a5c3d2bef123d63c3550c7be8 Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Wed, 17 Jun 2020 16:35:52 +0200 Subject: [PATCH 18/28] update copy in snapshots --- .../__snapshots__/no_fields_callout.test.tsx.snap | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/__snapshots__/no_fields_callout.test.tsx.snap b/x-pack/plugins/lens/public/indexpattern_datasource/__snapshots__/no_fields_callout.test.tsx.snap index 35ccb65976bbf8..607f968d86faa0 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/__snapshots__/no_fields_callout.test.tsx.snap +++ b/x-pack/plugins/lens/public/indexpattern_datasource/__snapshots__/no_fields_callout.test.tsx.snap @@ -12,14 +12,14 @@ exports[`NoFieldCallout renders properly when affected by field filter 1`] = ` Try:
    • - Changing the field filters + Using different field filters
    @@ -29,7 +29,7 @@ exports[`NoFieldCallout renders properly when affected by field filters, global Try: @@ -39,7 +39,7 @@ exports[`NoFieldCallout renders properly when affected by field filters, global Extending the time range
  • - Changing the field filters + Using different field filters
  • Changing the global filters From 1f6908bdafb87fc6fa4c9a37866ae8845e0dc00f Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Thu, 18 Jun 2020 12:25:21 +0200 Subject: [PATCH 19/28] perf improvements --- .../indexpattern_datasource/datapanel.tsx | 123 +++++++++++------- .../indexpattern_datasource/field_item.tsx | 8 +- 2 files changed, 85 insertions(+), 46 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx index 2c3e2c7986597d..0ad72ee68da4b7 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx @@ -6,7 +6,7 @@ import './datapanel.scss'; import { uniq, indexBy, groupBy } from 'lodash'; -import React, { useState, useEffect, memo, useCallback } from 'react'; +import React, { useState, useEffect, memo, useCallback, useMemo } from 'react'; import { EuiFlexGroup, EuiFlexItem, @@ -86,7 +86,6 @@ export function IndexPatternDataPanel({ changeIndexPattern, }: Props) { const { indexPatternRefs, indexPatterns, currentIndexPatternId } = state; - const onChangeIndexPattern = useCallback( (id: string) => changeIndexPattern(id, state, setState), [state, setState] @@ -234,7 +233,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ const currentIndexPattern = indexPatterns[currentIndexPatternId]; const allFields = currentIndexPattern.fields; const clearLocalState = () => setLocalState((s) => ({ ...s, nameFilter: '', typeFilter: [] })); - + const hasSyncedExistingFields = existingFields[currentIndexPattern.title]; useEffect(() => { // Reset the scroll if we have made material changes to the field list if (scrollContainer) { @@ -257,48 +256,59 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ ); }; - const allSupportedTypesFields = allFields.filter((field) => supportedFieldTypes.has(field.type)); - - const fieldGroups: FieldsGroup = { - ...defaultFieldGroups, - ...groupBy(allSupportedTypesFields, (field) => { - if (field.type === 'document') { - return 'specialFields'; - } else if (containsData(field)) { - return 'availableFields'; - } else return 'emptyFields'; - }), - }; - - const filterFieldGroup = (fieldGroup: IndexPatternField[]) => - fieldGroup.filter((field) => { - if ( - localState.nameFilter.length && - !field.name.toLowerCase().includes(localState.nameFilter.toLowerCase()) - ) { - return false; - } + const fieldGroups: FieldsGroup = useMemo(() => { + const allSupportedTypesFields = allFields.filter((field) => + supportedFieldTypes.has(field.type) + ); + const sorted = allSupportedTypesFields.sort(sortFields); + // optimization before existingFields are synced + if (!hasSyncedExistingFields) { + return { + ...defaultFieldGroups, + ...groupBy(sorted, (field) => { + if (field.type === 'document') { + return 'specialFields'; + } else { + return 'emptyFields'; + } + }), + }; + } + return { + ...defaultFieldGroups, + ...groupBy(sorted, (field) => { + if (field.type === 'document') { + return 'specialFields'; + } else if (containsData(field)) { + return 'availableFields'; + } else return 'emptyFields'; + }), + }; + }, [allFields, existingFields[currentIndexPattern.title], currentIndexPattern]); + + const filteredFieldGroups: FieldsGroup = useMemo(() => { + const filterFieldGroup = (fieldGroup: IndexPatternField[]) => + fieldGroup.filter((field) => { + if ( + localState.nameFilter.length && + !field.name.toLowerCase().includes(localState.nameFilter.toLowerCase()) + ) { + return false; + } - if (localState.typeFilter.length > 0) { - return localState.typeFilter.includes(field.type as DataType); - } - return true; - }); + if (localState.typeFilter.length > 0) { + return localState.typeFilter.includes(field.type as DataType); + } + return true; + }); - const filteredFieldGroups: FieldsGroup = Object.entries(fieldGroups).reduce( - (acc, [name, fields]) => { + return Object.entries(fieldGroups).reduce((acc, [name, fields]) => { return { ...acc, - [name]: filterFieldGroup(fields).sort(sortFields), + [name]: filterFieldGroup(fields), }; - }, - defaultFieldGroups - ); - - const paginatedFields = [ - ...(localState.isAvailableAccordionOpen ? filteredFieldGroups.availableFields : []), - ...(localState.isEmptyAccordionOpen ? filteredFieldGroups.emptyFields : []), - ].slice(0, pageSize); + }, defaultFieldGroups); + }, [fieldGroups, localState.nameFilter, localState.typeFilter]); const lazyScroll = () => { if (scrollContainer) { @@ -314,10 +324,35 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ } }; - const [paginatedAvailableFields, paginatedEmptyFields] = _.partition( - paginatedFields, - containsData - ); + // to test + const [paginatedAvailableFields, paginatedEmptyFields]: [ + IndexPatternField[], + IndexPatternField[] + ] = useMemo(() => { + const { availableFields, emptyFields } = filteredFieldGroups; + const { isAvailableAccordionOpen, isEmptyAccordionOpen } = localState; + + if (isAvailableAccordionOpen && isEmptyAccordionOpen) { + if (availableFields.length > pageSize) { + return [availableFields.slice(0, pageSize), []]; + } else { + return [availableFields, emptyFields.slice(0, pageSize - availableFields.length)]; + } + } + if (isAvailableAccordionOpen && !isEmptyAccordionOpen) { + return [availableFields.slice(0, pageSize), []]; + } + + if (!isAvailableAccordionOpen && isEmptyAccordionOpen) { + return [[], emptyFields.slice(0, pageSize)]; + } + return [[], []]; + }, [ + localState.isAvailableAccordionOpen, + localState.isEmptyAccordionOpen, + filteredFieldGroups, + pageSize, + ]); const hilight = localState.nameFilter.toLowerCase(); const hasFieldFilter = !!(localState.typeFilter.length || localState.nameFilter.length); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx index 6c00706cc86091..6d1106e8a733ff 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx @@ -49,6 +49,8 @@ import { IndexPattern, IndexPatternField } from './types'; import { LensFieldIcon } from './lens_field_icon'; import { trackUiEvent } from '../lens_ui_telemetry'; +import { debouncedComponent } from '../debounced_component'; + export interface FieldItemProps { core: DatasourceDataPanelProps['core']; data: DataPublicPluginStart; @@ -78,7 +80,7 @@ function wrapOnDot(str?: string) { return str ? str.replace(/\./g, '.\u200B') : ''; } -export const FieldItem = React.memo(function FieldItem(props: FieldItemProps) { +export const InnerFieldItem = function InnerFieldItem(props: FieldItemProps) { const { core, field, @@ -239,7 +241,9 @@ export const FieldItem = React.memo(function FieldItem(props: FieldItemProps) { ); -}); +}; + +export const FieldItem = React.memo(debouncedComponent(InnerFieldItem)); function FieldItemPopoverContents(props: State & FieldItemProps) { const { From 84647fedbd2e3056e22ef9fd5cece7e463b6eee7 Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Thu, 18 Jun 2020 12:25:42 +0200 Subject: [PATCH 20/28] controversial spinner? --- .../indexpattern_datasource/datapanel.tsx | 120 +++++++++++------- 1 file changed, 72 insertions(+), 48 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx index 0ad72ee68da4b7..dbc62d395fc1ae 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx @@ -22,6 +22,7 @@ import { EuiAccordion, EuiFilterGroup, EuiFilterButton, + EuiLoadingSpinner, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -545,32 +546,43 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ } > - {!!filteredFieldGroups.availableFields.length ? ( -
    - {paginatedAvailableFields.map((field: IndexPatternField) => { - return ( - - ); - })} -
    + {hasSyncedExistingFields ? ( + !!filteredFieldGroups.availableFields.length ? ( +
    + {paginatedAvailableFields.map((field: IndexPatternField) => { + return ( + + ); + })} +
    + ) : ( + + ) ) : ( - + <> + + + + + + + )} @@ -614,30 +626,42 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ } > - {!!filteredFieldGroups.emptyFields.length ? ( -
    - {paginatedEmptyFields.map((field: IndexPatternField) => { - return ( - - ); - })} -
    + + {hasSyncedExistingFields ? ( + !!filteredFieldGroups.emptyFields.length ? ( +
    + {paginatedEmptyFields.map((field: IndexPatternField) => { + return ( + + ); + })} +
    + ) : ( + + ) ) : ( - + <> + + + + + + + )} From 78d05820aab0f94e3f679a62740eed0b7707425c Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Thu, 18 Jun 2020 13:51:29 +0200 Subject: [PATCH 21/28] spinner tests --- .../datapanel.test.tsx | 18 +++++- .../indexpattern_datasource/datapanel.tsx | 59 ++++++++----------- 2 files changed, 38 insertions(+), 39 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx index 55ea508c32782b..7653dab2c9b846 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx @@ -15,7 +15,7 @@ import { coreMock } from 'src/core/public/mocks'; import { IndexPatternPrivateState } from './types'; import { mountWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers'; import { ChangeIndexPattern } from './change_indexpattern'; -import { EuiProgress } from '@elastic/eui'; +import { EuiProgress, EuiLoadingSpinner } from '@elastic/eui'; import { documentField } from './document_field'; const initialState: IndexPatternPrivateState = { @@ -567,8 +567,10 @@ describe('IndexPattern Data Panel', () => { }); it('should display NoFieldsCallout when all fields are empty', async () => { - const wrapper = mountWithIntl(); - expect(wrapper.find(NoFieldsCallout).first().prop('isAffectedByTimerange')).toEqual(true); + const wrapper = mountWithIntl( + + ); + expect(wrapper.find(NoFieldsCallout).length).toEqual(1); expect( wrapper .find('[data-test-subj="lnsIndexPatternAvailableFields"]') @@ -588,6 +590,16 @@ describe('IndexPattern Data Panel', () => { ).toEqual(['bytes', 'client', 'memory', 'source', 'timestamp']); }); + it('should display spinner for available fields accordion if existing fields are not loaded yet', async () => { + const wrapper = mountWithIntl(); + expect( + wrapper.find('[data-test-subj="lnsIndexPatternAvailableFields"]').find(EuiLoadingSpinner) + .length + ).toEqual(1); + wrapper.setProps({ existingFields: { idx1: {} } }); + expect(wrapper.find(NoFieldsCallout).length).toEqual(1); + }); + it('should filter down by name', () => { const wrapper = mountWithIntl(); act(() => { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx index dbc62d395fc1ae..9337cbc9ef7ebb 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx @@ -325,7 +325,6 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ } }; - // to test const [paginatedAvailableFields, paginatedEmptyFields]: [ IndexPatternField[], IndexPatternField[] @@ -626,42 +625,30 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ } > - - {hasSyncedExistingFields ? ( - !!filteredFieldGroups.emptyFields.length ? ( -
    - {paginatedEmptyFields.map((field: IndexPatternField) => { - return ( - - ); - })} -
    - ) : ( - - ) + {!!filteredFieldGroups.emptyFields.length ? ( +
    + {paginatedEmptyFields.map((field: IndexPatternField) => { + return ( + + ); + })} +
    ) : ( - <> - - - - - - - + )} From 6112e7ac55dbb20d12180469de293f2b42309ff6 Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Thu, 18 Jun 2020 15:29:02 +0200 Subject: [PATCH 22/28] feat: test of FieldItem without debounced hoc --- .../lens/public/indexpattern_datasource/field_item.test.tsx | 6 +++--- .../lens/public/indexpattern_datasource/field_item.tsx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.test.tsx index 511ba3c0442c7a..500133fb0ca2cc 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { act } from 'react-dom/test-utils'; import { EuiLoadingSpinner, EuiPopover } from '@elastic/eui'; -import { FieldItem, FieldItemProps } from './field_item'; +import { FieldItem, InnerFieldItem, FieldItemProps } from './field_item'; import { coreMock } from 'src/core/public/mocks'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; @@ -94,7 +94,7 @@ describe('IndexPattern Field Item', () => { core.http.post.mockImplementationOnce(() => { return Promise.resolve({}); }); - const wrapper = mountWithIntl(); + const wrapper = mountWithIntl(); await act(async () => { wrapper.find('[data-test-subj="lnsFieldListPanelField-bytes"]').simulate('click'); @@ -119,7 +119,7 @@ describe('IndexPattern Field Item', () => { }); }); - const wrapper = mountWithIntl(); + const wrapper = mountWithIntl(); wrapper.find('[data-test-subj="lnsFieldListPanelField-bytes"]').simulate('click'); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx index 6d1106e8a733ff..1a1a34d30f8a8e 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx @@ -243,7 +243,7 @@ export const InnerFieldItem = function InnerFieldItem(props: FieldItemProps) { ); }; -export const FieldItem = React.memo(debouncedComponent(InnerFieldItem)); +export const FieldItem = debouncedComponent(InnerFieldItem); function FieldItemPopoverContents(props: State & FieldItemProps) { const { From 0063dbd2d9ad2571f5b7df3de893abf3dbf6a8c0 Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Thu, 18 Jun 2020 17:05:43 +0200 Subject: [PATCH 23/28] types --- .../lens/public/indexpattern_datasource/field_item.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.test.tsx index 500133fb0ca2cc..e8dfbc250c539a 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { act } from 'react-dom/test-utils'; import { EuiLoadingSpinner, EuiPopover } from '@elastic/eui'; -import { FieldItem, InnerFieldItem, FieldItemProps } from './field_item'; +import { InnerFieldItem, FieldItemProps } from './field_item'; import { coreMock } from 'src/core/public/mocks'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; From c2d8c164e1d3919f13a1f4348365dc82d0432789 Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Thu, 25 Jun 2020 10:22:50 +0200 Subject: [PATCH 24/28] fix: spinner in right place, hooks rules --- .../indexpattern_datasource/datapanel.tsx | 109 +++++++++--------- 1 file changed, 53 insertions(+), 56 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx index 9337cbc9ef7ebb..3b56eeb97fe598 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx @@ -89,7 +89,7 @@ export function IndexPatternDataPanel({ const { indexPatternRefs, indexPatterns, currentIndexPatternId } = state; const onChangeIndexPattern = useCallback( (id: string) => changeIndexPattern(id, state, setState), - [state, setState] + [state, setState, changeIndexPattern] ); const indexPatternList = uniq( @@ -242,22 +242,22 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ setPageSize(PAGINATION_SIZE); lazyScroll(); } - }, [localState.nameFilter, localState.typeFilter, currentIndexPatternId]); + }, [localState.nameFilter, localState.typeFilter, currentIndexPatternId, scrollContainer]); const availableFieldTypes = uniq(allFields.map(({ type }) => type)).filter( (type) => type in fieldTypeNames ); - const containsData = (field: IndexPatternField) => { - const fieldByName = indexBy(allFields, 'name'); - const overallField = fieldByName[field.name]; + const fieldGroups: FieldsGroup = useMemo(() => { + const containsData = (field: IndexPatternField) => { + const fieldByName = indexBy(allFields, 'name'); + const overallField = fieldByName[field.name]; - return ( - overallField && fieldExists(existingFields, currentIndexPattern.title, overallField.name) - ); - }; + return ( + overallField && fieldExists(existingFields, currentIndexPattern.title, overallField.name) + ); + }; - const fieldGroups: FieldsGroup = useMemo(() => { const allSupportedTypesFields = allFields.filter((field) => supportedFieldTypes.has(field.type) ); @@ -285,7 +285,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ } else return 'emptyFields'; }), }; - }, [allFields, existingFields[currentIndexPattern.title], currentIndexPattern]); + }, [allFields, existingFields, currentIndexPattern, hasSyncedExistingFields]); const filteredFieldGroups: FieldsGroup = useMemo(() => { const filterFieldGroup = (fieldGroup: IndexPatternField[]) => @@ -531,57 +531,54 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ } extraAction={ - - {filteredFieldGroups.availableFields.length} - - } - > - - {hasSyncedExistingFields ? ( - !!filteredFieldGroups.availableFields.length ? ( -
    - {paginatedAvailableFields.map((field: IndexPatternField) => { - return ( - - ); - })} -
    + hasSyncedExistingFields ? ( + + {filteredFieldGroups.availableFields.length} + ) : ( - - ) - ) : ( - <> - - + ) + } + > + + {!!filteredFieldGroups.availableFields.length ? ( +
    + {paginatedAvailableFields.map((field: IndexPatternField) => { + return ( + + ); + })} +
    + ) : ( + )} From 0ad477292b301876220dc68e6848f4ab7c986a31 Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Thu, 25 Jun 2020 14:18:03 +0200 Subject: [PATCH 25/28] perf: extracting fields_accordion & speeding up datapanel --- .../indexpattern_datasource/datapanel.tsx | 212 +++++++----------- .../fields_accordion.tsx | 106 +++++++++ 2 files changed, 184 insertions(+), 134 deletions(-) create mode 100644 x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.tsx diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx index 3b56eeb97fe598..b72f87e243dcd2 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx @@ -5,7 +5,7 @@ */ import './datapanel.scss'; -import { uniq, indexBy, groupBy } from 'lodash'; +import { uniq, indexBy, groupBy, throttle } from 'lodash'; import React, { useState, useEffect, memo, useCallback, useMemo } from 'react'; import { EuiFlexGroup, @@ -14,15 +14,11 @@ import { EuiContextMenuItem, EuiContextMenuPanelProps, EuiPopover, - EuiText, EuiCallOut, EuiFormControlLayout, - EuiNotificationBadge, EuiSpacer, - EuiAccordion, EuiFilterGroup, EuiFilterButton, - EuiLoadingSpinner, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -41,6 +37,7 @@ import { trackUiEvent } from '../lens_ui_telemetry'; import { syncExistingFields } from './loader'; import { fieldExists } from './pure_helpers'; import { Loader } from '../loader'; +import { FieldsAccordion } from './fields_accordion'; import { esQuery, IIndexPattern } from '../../../../../src/plugins/data/public'; export type Props = DatasourceDataPanelProps & { @@ -235,19 +232,18 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ const allFields = currentIndexPattern.fields; const clearLocalState = () => setLocalState((s) => ({ ...s, nameFilter: '', typeFilter: [] })); const hasSyncedExistingFields = existingFields[currentIndexPattern.title]; + const availableFieldTypes = uniq(allFields.map(({ type }) => type)).filter( + (type) => type in fieldTypeNames + ); + useEffect(() => { // Reset the scroll if we have made material changes to the field list if (scrollContainer) { scrollContainer.scrollTop = 0; setPageSize(PAGINATION_SIZE); - lazyScroll(); } }, [localState.nameFilter, localState.typeFilter, currentIndexPatternId, scrollContainer]); - const availableFieldTypes = uniq(allFields.map(({ type }) => type)).filter( - (type) => type in fieldTypeNames - ); - const fieldGroups: FieldsGroup = useMemo(() => { const containsData = (field: IndexPatternField) => { const fieldByName = indexBy(allFields, 'name'); @@ -311,26 +307,39 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ }, defaultFieldGroups); }, [fieldGroups, localState.nameFilter, localState.typeFilter]); - const lazyScroll = () => { + const lazyScroll = useCallback(() => { if (scrollContainer) { const nearBottom = scrollContainer.scrollTop + scrollContainer.clientHeight > scrollContainer.scrollHeight * 0.9; if (nearBottom) { - const displayedFieldLength = + const displayedFieldsLength = (localState.isAvailableAccordionOpen ? filteredFieldGroups.availableFields.length : 0) + (localState.isEmptyAccordionOpen ? filteredFieldGroups.emptyFields.length : 0); - setPageSize(Math.max(PAGINATION_SIZE, Math.min(pageSize * 1.5, displayedFieldLength))); + setPageSize( + Math.max( + PAGINATION_SIZE, + Math.min(pageSize + PAGINATION_SIZE * 0.5, displayedFieldsLength) + ) + ); } } - }; + }, [ + scrollContainer, + localState.isAvailableAccordionOpen, + localState.isEmptyAccordionOpen, + filteredFieldGroups, + pageSize, + setPageSize, + ]); const [paginatedAvailableFields, paginatedEmptyFields]: [ IndexPatternField[], IndexPatternField[] ] = useMemo(() => { const { availableFields, emptyFields } = filteredFieldGroups; - const { isAvailableAccordionOpen, isEmptyAccordionOpen } = localState; + const isAvailableAccordionOpen = localState.isAvailableAccordionOpen; + const isEmptyAccordionOpen = localState.isEmptyAccordionOpen; if (isAvailableAccordionOpen && isEmptyAccordionOpen) { if (availableFields.length > pageSize) { @@ -354,8 +363,18 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ pageSize, ]); - const hilight = localState.nameFilter.toLowerCase(); - const hasFieldFilter = !!(localState.typeFilter.length || localState.nameFilter.length); + const fieldProps = useMemo( + () => ({ + core, + data, + indexPattern: currentIndexPattern, + highlight: localState.nameFilter.toLowerCase(), + dateRange, + query, + filters, + }), + [core, data, currentIndexPattern, dateRange, query, filters, localState.nameFilter] + ); return ( @@ -485,28 +504,34 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ setScrollContainer(el); } }} - onScroll={lazyScroll} + onScroll={throttle(lazyScroll, 100)} >
    {filteredFieldGroups.specialFields.map((field: IndexPatternField) => ( ))} - { setLocalState((s) => ({ ...s, @@ -519,71 +544,32 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ Math.max(PAGINATION_SIZE, Math.min(pageSize * 1.5, displayedFieldLength)) ); }} - data-test-subj="lnsIndexPatternAvailableFields" - id="lnsIndexPatternAvailableFields" - buttonContent={ - - - {i18n.translate('xpack.lens.indexPattern.availableFieldsLabel', { - defaultMessage: 'Available fields', - })} - - - } - extraAction={ - hasSyncedExistingFields ? ( - - {filteredFieldGroups.availableFields.length} - - ) : ( - - - - - - ) - } - > - - {!!filteredFieldGroups.availableFields.length ? ( -
    - {paginatedAvailableFields.map((field: IndexPatternField) => { - return ( - - ); - })} -
    - ) : ( + renderCallout={ - )} -
    + } + /> - { setLocalState((s) => ({ ...s, @@ -597,57 +583,15 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ Math.max(PAGINATION_SIZE, Math.min(pageSize * 1.5, displayedFieldLength)) ); }} - data-test-subj="lnsIndexPatternEmptyFields" - id="lnsIndexPatternEmptyFields" - buttonContent={ - - - {i18n.translate('xpack.lens.indexPattern.emptyFieldsLabel', { - defaultMessage: 'Empty fields', - })} - - - } - extraAction={ - - {filteredFieldGroups.emptyFields.length} - - } - > - - {!!filteredFieldGroups.emptyFields.length ? ( -
    - {paginatedEmptyFields.map((field: IndexPatternField) => { - return ( - - ); - })} -
    - ) : ( + renderCallout={ - )} -
    + } + />
    diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.tsx new file mode 100644 index 00000000000000..8395bdec688bf7 --- /dev/null +++ b/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.tsx @@ -0,0 +1,106 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import './datapanel.scss'; +import React, { memo, useCallback } from 'react'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiText, + EuiNotificationBadge, + EuiSpacer, + EuiAccordion, + EuiLoadingSpinner, +} from '@elastic/eui'; +import { DataPublicPluginStart } from 'src/plugins/data/public'; +import { IndexPatternField } from './types'; +import { FieldItem } from './field_item'; +import { Query, Filter } from '../../../../../src/plugins/data/public'; +import { DatasourceDataPanelProps } from '../types'; +import { IndexPattern } from './types'; + +export interface FieldProps { + core: DatasourceDataPanelProps['core']; + data: DataPublicPluginStart; + indexPattern: IndexPattern; + highlight?: string; + query: Query; + dateRange: DatasourceDataPanelProps['dateRange']; + filters: Filter[]; +} + +export const InnerFieldsAccordion = function InnerFieldsAccordion({ + initialIsOpen, + onToggle, + id, + label, + hasLoaded, + fieldsCount, + isFiltered, + paginatedFields, + fieldProps, + renderCallout, + exists, +}: { + initialIsOpen: boolean; + onToggle: (open: boolean) => void; + id: string; + label: string; + hasLoaded: boolean; + fieldsCount: number; + isFiltered: boolean; + paginatedFields: IndexPatternField[]; + fieldProps: FieldProps; + renderCallout: JSX.Element; + exists: boolean; +}) { + const renderField = useCallback( + (field: IndexPatternField) => { + return ( + + ); + }, + [fieldProps] + ); + + return ( + + {label} + + } + extraAction={ + hasLoaded ? ( + + {fieldsCount} + + ) : ( + + + + + + ) + } + > + + {!!fieldsCount ? ( +
    + {paginatedFields && paginatedFields.map(renderField)} +
    + ) : ( + renderCallout + )} +
    + ); +}; + +export const FieldsAccordion = memo(InnerFieldsAccordion); From 65451f05bfe09c8cd2154babc884f4958b470ba6 Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Thu, 25 Jun 2020 15:35:25 +0200 Subject: [PATCH 26/28] tests added --- .../fields_accordion.test.tsx | 97 +++++++++++++++++++ .../fields_accordion.tsx | 36 +++---- 2 files changed, 115 insertions(+), 18 deletions(-) create mode 100644 x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.test.tsx diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.test.tsx new file mode 100644 index 00000000000000..41d90a4f8870ff --- /dev/null +++ b/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.test.tsx @@ -0,0 +1,97 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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 { EuiLoadingSpinner, EuiNotificationBadge } from '@elastic/eui'; +import { coreMock } from 'src/core/public/mocks'; +import { mountWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers'; +import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; +import { dataPluginMock } from '../../../../../src/plugins/data/public/mocks'; +import { IndexPattern } from './types'; +import { FieldItem } from './field_item'; +import { FieldsAccordion, FieldsAccordionProps, FieldItemSharedProps } from './fields_accordion'; + +describe('Fields Accordion', () => { + let defaultProps: FieldsAccordionProps; + let indexPattern: IndexPattern; + let core: ReturnType; + let data: DataPublicPluginStart; + let fieldProps: FieldItemSharedProps; + + beforeEach(() => { + indexPattern = { + id: '1', + title: 'my-fake-index-pattern', + timeFieldName: 'timestamp', + fields: [ + { + name: 'timestamp', + type: 'date', + aggregatable: true, + searchable: true, + }, + { + name: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + ], + } as IndexPattern; + core = coreMock.createSetup(); + data = dataPluginMock.createStartContract(); + core.http.post.mockClear(); + + fieldProps = { + indexPattern, + data, + core, + highlight: '', + dateRange: { + fromDate: 'now-7d', + toDate: 'now', + }, + query: { query: '', language: 'lucene' }, + filters: [], + }; + + defaultProps = { + initialIsOpen: true, + onToggle: jest.fn(), + id: 'id', + label: 'label', + hasLoaded: true, + fieldsCount: 2, + isFiltered: false, + paginatedFields: indexPattern.fields, + fieldProps, + renderCallout:
    Callout
    , + exists: true, + }; + }); + + it('renders correct number of Field Items', () => { + const wrapper = mountWithIntl(); + expect(wrapper.find(FieldItem).length).toEqual(2); + }); + + it('renders callout if no fields', () => { + const wrapper = shallowWithIntl( + + ); + expect(wrapper.find('#lens-test-callout').length).toEqual(1); + }); + + it('renders accented notificationBadge state if isFiltered', () => { + const wrapper = mountWithIntl(); + expect(wrapper.find(EuiNotificationBadge).prop('color')).toEqual('accent'); + }); + + it('renders spinner if has not loaded', () => { + const wrapper = mountWithIntl(); + expect(wrapper.find(EuiLoadingSpinner).length).toEqual(1); + }); +}); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.tsx index 8395bdec688bf7..e86639343d938d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.tsx @@ -22,7 +22,7 @@ import { Query, Filter } from '../../../../../src/plugins/data/public'; import { DatasourceDataPanelProps } from '../types'; import { IndexPattern } from './types'; -export interface FieldProps { +export interface FieldItemSharedProps { core: DatasourceDataPanelProps['core']; data: DataPublicPluginStart; indexPattern: IndexPattern; @@ -32,6 +32,20 @@ export interface FieldProps { filters: Filter[]; } +export interface FieldsAccordionProps { + initialIsOpen: boolean; + onToggle: (open: boolean) => void; + id: string; + label: string; + hasLoaded: boolean; + fieldsCount: number; + isFiltered: boolean; + paginatedFields: IndexPatternField[]; + fieldProps: FieldItemSharedProps; + renderCallout: JSX.Element; + exists: boolean; +} + export const InnerFieldsAccordion = function InnerFieldsAccordion({ initialIsOpen, onToggle, @@ -44,26 +58,12 @@ export const InnerFieldsAccordion = function InnerFieldsAccordion({ fieldProps, renderCallout, exists, -}: { - initialIsOpen: boolean; - onToggle: (open: boolean) => void; - id: string; - label: string; - hasLoaded: boolean; - fieldsCount: number; - isFiltered: boolean; - paginatedFields: IndexPatternField[]; - fieldProps: FieldProps; - renderCallout: JSX.Element; - exists: boolean; -}) { +}: FieldsAccordionProps) { const renderField = useCallback( (field: IndexPatternField) => { - return ( - - ); + return ; }, - [fieldProps] + [fieldProps, exists] ); return ( From 572d9a15d41169290fcf6704002e34119d79981f Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Fri, 26 Jun 2020 16:45:39 +0200 Subject: [PATCH 27/28] don't show callout if not loaded --- .../indexpattern_datasource/fields_accordion.tsx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.tsx index e86639343d938d..0d2c016351f6d6 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.tsx @@ -92,13 +92,14 @@ export const InnerFieldsAccordion = function InnerFieldsAccordion({ } > - {!!fieldsCount ? ( -
    - {paginatedFields && paginatedFields.map(renderField)} -
    - ) : ( - renderCallout - )} + {hasLoaded && + (!!fieldsCount ? ( +
    + {paginatedFields && paginatedFields.map(renderField)} +
    + ) : ( + renderCallout + ))} ); }; From d609e6a9241173aea88766d6c1307b8a82473d0a Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Fri, 26 Jun 2020 16:53:41 +0200 Subject: [PATCH 28/28] removing flexgroup --- .../public/indexpattern_datasource/fields_accordion.tsx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.tsx index 0d2c016351f6d6..b756cf81a90739 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.tsx @@ -7,8 +7,6 @@ import './datapanel.scss'; import React, { memo, useCallback } from 'react'; import { - EuiFlexGroup, - EuiFlexItem, EuiText, EuiNotificationBadge, EuiSpacer, @@ -83,11 +81,7 @@ export const InnerFieldsAccordion = function InnerFieldsAccordion({ {fieldsCount} ) : ( - - - - - + ) } >