Skip to content

Commit

Permalink
[UnifiedFieldList] Persist field list sections state in local storage
Browse files Browse the repository at this point in the history
  • Loading branch information
jughosta committed Jan 4, 2023
1 parent b4f7aae commit 68f8805
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ export function DiscoverSidebarComponent({
{...fieldListGroupedProps}
renderFieldItem={renderFieldItem}
screenReaderDescriptionId={fieldSearchDescriptionId}
localStorageKeyPrefix="discover"
/>
)}
</EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -431,4 +431,54 @@ describe('UnifiedFieldList <FieldListGrouped /> + useGroupedFields()', () => {
'2 selected fields. 10 popular fields. 25 available fields. 112 unmapped fields. 0 empty fields. 3 meta fields.'
);
});

it('persists sections state in local storage', async () => {
const wrapper = await mountGroupedList({
listProps: {
...defaultProps,
fieldsExistenceStatus: ExistenceFetchStatus.succeeded,
localStorageKeyPrefix: 'test',
},
hookParams: {
dataViewId: dataView.id!,
allFields: manyFields,
},
});

// only Available is open
expect(
wrapper.find(FieldsAccordion).map((accordion) => accordion.prop('initialIsOpen'))
).toStrictEqual([true, false, false, false]);

await act(async () => {
await wrapper
.find('[data-test-subj="fieldListGroupedEmptyFields"]')
.find('button')
.first()
.simulate('click');
await wrapper.update();
});

// now Empty is open too
expect(
wrapper.find(FieldsAccordion).map((accordion) => accordion.prop('initialIsOpen'))
).toStrictEqual([true, false, true, false]);

const wrapper2 = await mountGroupedList({
listProps: {
...defaultProps,
fieldsExistenceStatus: ExistenceFetchStatus.succeeded,
localStorageKeyPrefix: 'test',
},
hookParams: {
dataViewId: dataView.id!,
allFields: manyFields,
},
});

// both Available and Empty are open for the second instance
expect(
wrapper2.find(FieldsAccordion).map((accordion) => accordion.prop('initialIsOpen'))
).toStrictEqual([true, false, true, false]);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import { partition, throttle } from 'lodash';
import React, { Fragment, useCallback, useEffect, useMemo, useState } from 'react';
import useLocalStorage from 'react-use/lib/useLocalStorage';
import { i18n } from '@kbn/i18n';
import { EuiScreenReaderOnly, EuiSpacer } from '@elastic/eui';
import { type DataViewField } from '@kbn/data-views-plugin/common';
Expand All @@ -18,10 +19,13 @@ import { ExistenceFetchStatus, FieldsGroup, FieldsGroupNames } from '../../types
import './field_list_grouped.scss';

const PAGINATION_SIZE = 50;
export const LOCAL_STORAGE_KEY_SECTIONS = 'unifiedFieldList.initiallyOpenSections';

type InitiallyOpenSections = Record<string, boolean>;

function getDisplayedFieldsLength<T extends FieldListItem>(
fieldGroups: FieldListGroups<T>,
accordionState: Partial<Record<string, boolean>>
accordionState: InitiallyOpenSections
) {
return Object.entries(fieldGroups)
.filter(([key]) => accordionState[key])
Expand All @@ -35,6 +39,7 @@ export interface FieldListGroupedProps<T extends FieldListItem> {
renderFieldItem: FieldsAccordionProps<T>['renderFieldItem'];
scrollToTopResetCounter: number;
screenReaderDescriptionId?: string;
localStorageKeyPrefix?: string; // Your app name: "discover", "lens", etc. If not provided, sections state would not be persisted.
'data-test-subj'?: string;
}

Expand All @@ -45,6 +50,7 @@ function InnerFieldListGrouped<T extends FieldListItem = DataViewField>({
renderFieldItem,
scrollToTopResetCounter,
screenReaderDescriptionId,
localStorageKeyPrefix,
'data-test-subj': dataTestSubject = 'fieldListGrouped',
}: FieldListGroupedProps<T>) {
const hasSyncedExistingFields =
Expand All @@ -56,9 +62,22 @@ function InnerFieldListGrouped<T extends FieldListItem = DataViewField>({
);
const [pageSize, setPageSize] = useState(PAGINATION_SIZE);
const [scrollContainer, setScrollContainer] = useState<Element | undefined>(undefined);
const [accordionState, setAccordionState] = useState<Partial<Record<string, boolean>>>(() =>
const [storedInitiallyOpenSections, storeInitiallyOpenSections] =
useLocalStorage<InitiallyOpenSections>(
`${localStorageKeyPrefix ? localStorageKeyPrefix + '.' : ''}${LOCAL_STORAGE_KEY_SECTIONS}`,
{}
);
const [accordionState, setAccordionState] = useState<InitiallyOpenSections>(() =>
Object.fromEntries(
fieldGroupsToShow.map(([key, { isInitiallyOpen }]) => [key, isInitiallyOpen])
fieldGroupsToShow.map(([key, { isInitiallyOpen }]) => {
const storedInitiallyOpen = localStorageKeyPrefix
? storedInitiallyOpenSections?.[key]
: null; // from localStorage
return [
key,
typeof storedInitiallyOpen === 'boolean' ? storedInitiallyOpen : isInitiallyOpen,
];
})
)
);

Expand Down Expand Up @@ -256,6 +275,12 @@ function InnerFieldListGrouped<T extends FieldListItem = DataViewField>({
Math.min(Math.ceil(pageSize * 1.5), displayedFieldLength)
)
);
if (localStorageKeyPrefix) {
storeInitiallyOpenSections({
...storedInitiallyOpenSections,
[key]: open,
});
}
}}
showExistenceFetchError={fieldsExistenceStatus === ExistenceFetchStatus.failed}
showExistenceFetchTimeout={fieldsExistenceStatus === ExistenceFetchStatus.failed} // TODO: deprecate timeout logic?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@ export const InnerFormBasedDataPanel = function InnerFormBasedDataPanel({
{...fieldListGroupedProps}
renderFieldItem={renderFieldItem}
data-test-subj="lnsIndexPattern"
localStorageKeyPrefix="lens"
/>
</FieldList>
</ChildDragDropProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ export function TextBasedDataPanel({
{...fieldListGroupedProps}
renderFieldItem={renderFieldItem}
data-test-subj="lnsTextBasedLanguages"
localStorageKeyPrefix="lens"
/>
</FieldList>
</ChildDragDropProvider>
Expand Down

0 comments on commit 68f8805

Please sign in to comment.