From aff9a57f21962cf4b99759e680d45869f55a4f54 Mon Sep 17 00:00:00 2001 From: Dave Falke Date: Wed, 20 Nov 2024 13:32:45 -0500 Subject: [PATCH] Move record page perisistence to wdk-client package (#1270) --- .../wdk-client/src/Actions/RecordActions.ts | 46 +++- .../src/Controllers/RecordController.tsx | 12 +- .../src/StoreModules/RecordStoreModule.ts | 222 +++++++++++++++++- .../RecordMain/RecordMainCategorySection.jsx | 6 + .../Records/RecordMain/RecordMainSection.jsx | 7 + .../RecordTable/RecordTableSection.tsx | 16 ++ .../wdk-client/src/Views/Records/RecordUI.jsx | 2 + .../RecordViewActionCreators.ts | 6 - .../js/client/componentWrappers.jsx | 9 +- .../js/client/storeModules/Record.js | 191 +-------------- 10 files changed, 316 insertions(+), 201 deletions(-) diff --git a/packages/libs/wdk-client/src/Actions/RecordActions.ts b/packages/libs/wdk-client/src/Actions/RecordActions.ts index efec321c3a..48bcb8eaa3 100644 --- a/packages/libs/wdk-client/src/Actions/RecordActions.ts +++ b/packages/libs/wdk-client/src/Actions/RecordActions.ts @@ -26,6 +26,7 @@ export type Action = | RecordLoadingAction | RecordErrorAction | SectionVisibilityAction + | UpdateTableStateAction | SetCollapsedSectionsAction | AllFieldVisibilityAction | NavigationVisibilityAction @@ -43,6 +44,7 @@ export type RecordReceivedAction = { record: RecordInstance; recordClass: RecordClass; categoryTree: CategoryTreeNode; + defaultExpandedSections?: string[]; }; }; @@ -209,6 +211,30 @@ export function setCollapsedSections( //============================================================================== +export const TABLE_STATE_UPDATED = 'record-view/table-state-updated'; + +export type UpdateTableStateAction = { + type: typeof TABLE_STATE_UPDATED; + payload: { + tableName: string; + tableState: { + searchTerm: string; + selectedRow?: number; + expandedRows: number[]; + }; + }; +}; + +export const updateTableState = ( + tableName: string, + tableState: UpdateTableStateAction['payload']['tableState'] +): UpdateTableStateAction => ({ + type: TABLE_STATE_UPDATED, + payload: { tableName, tableState }, +}); + +//============================================================================== + export const ALL_FIELD_VISIBILITY = 'record-view/all-field-visibility-changed'; export type AllFieldVisibilityAction = { @@ -325,6 +351,12 @@ interface RequestRequestOptionsGetter { ): RecordRequestOptions[]; } +interface DefaultExpandedSectionsGetter { + (recordClass: RecordClass, categoryTree: CategoryTreeNode): + | string[] + | undefined; +} + interface CategoryTreePruner { (recordClass: RecordClass, categoryTree: CategoryTreeNode): CategoryTreeNode; } @@ -334,14 +366,16 @@ export function loadRecordData( recordClass: string, primaryKeyValues: string[], getRecordRequestOptions: RequestRequestOptionsGetter, - pruneCategoryTree: CategoryTreePruner + pruneCategoryTree: CategoryTreePruner, + getDefaultExpandedSections: DefaultExpandedSectionsGetter ): ActionThunk { return function run({ wdkService }) { return setActiveRecord( recordClass, primaryKeyValues, getRecordRequestOptions, - pruneCategoryTree + pruneCategoryTree, + getDefaultExpandedSections ); }; } @@ -357,7 +391,8 @@ function setActiveRecord( recordClassUrlSegment: string, primaryKeyValues: string[], getRecordRequestOptions: RequestRequestOptionsGetter, - pruneCategoryTree: CategoryTreePruner + pruneCategoryTree: CategoryTreePruner, + getDefaultExpandedSections: DefaultExpandedSectionsGetter ): ActionThunk { return ({ wdkService }) => { const id = uniqueId('recordViewId'); @@ -381,6 +416,10 @@ function setActiveRecord( { name: '__', tree: prunedCategoryTree }, isNotInternalNode ); + const defaultExpandedSections = getDefaultExpandedSections( + recordClass, + categoryTree + ); const initialAction$ = wdkService .getRecord(recordClass.urlSegment, primaryKey, initialOptions) .then((record) => @@ -388,6 +427,7 @@ function setActiveRecord( record, recordClass, categoryTree, + defaultExpandedSections, }) ); const additionalActions = additionalOptions.map((options) => diff --git a/packages/libs/wdk-client/src/Controllers/RecordController.tsx b/packages/libs/wdk-client/src/Controllers/RecordController.tsx index a2535021d9..3d5d169bb5 100644 --- a/packages/libs/wdk-client/src/Controllers/RecordController.tsx +++ b/packages/libs/wdk-client/src/Controllers/RecordController.tsx @@ -17,6 +17,7 @@ import { updateNavigationVisibility, updateSectionVisibility, requestPartialRecord, + updateTableState, } from '../Actions/RecordActions'; import { @@ -42,6 +43,7 @@ const ActionCreators = { loadRecordData, updateSectionVisibility, updateNavigationQuery, + updateTableState, updateAllFieldVisibility, updateNavigationCategoryExpansion, updateNavigationVisibility, @@ -96,6 +98,13 @@ class RecordController extends PageController { ]; } + getDefaultExpandedSections( + recordClass: RecordClass, + categoryTree: CategoryTreeNode + ): string[] | undefined { + return undefined; + } + pruneCategoryTree( recordClass: RecordClass, categoryTree: CategoryTreeNode @@ -176,7 +185,8 @@ class RecordController extends PageController { recordClass, pkValues, this.getRecordRequestOptions.bind(this), - this.pruneCategoryTree.bind(this) + this.pruneCategoryTree.bind(this), + this.getDefaultExpandedSections.bind(this) ); } } diff --git a/packages/libs/wdk-client/src/StoreModules/RecordStoreModule.ts b/packages/libs/wdk-client/src/StoreModules/RecordStoreModule.ts index 7f16fd6fa7..8053cc7cc5 100644 --- a/packages/libs/wdk-client/src/StoreModules/RecordStoreModule.ts +++ b/packages/libs/wdk-client/src/StoreModules/RecordStoreModule.ts @@ -1,6 +1,10 @@ -import { chunk, difference, union, uniq } from 'lodash'; -import { ActionsObservable, StateObservable } from 'redux-observable'; -import { Observable, from } from 'rxjs'; +import { chunk, difference, get, union, uniq } from 'lodash'; +import { + ActionsObservable, + combineEpics, + StateObservable, +} from 'redux-observable'; +import { EMPTY, Observable, from, merge, of } from 'rxjs'; import { bufferTime, filter, @@ -22,11 +26,14 @@ import { REQUEST_PARTIAL_RECORD, SECTION_VISIBILITY, SET_COLLAPSED_SECTIONS, + TABLE_STATE_UPDATED, RequestPartialRecord, RecordReceivedAction, RecordUpdatedAction, getPrimaryKey, updateNavigationVisibility, + setCollapsedSections, + updateTableState, } from '../Actions/RecordActions'; import { BASKET_STATUS_ERROR, @@ -52,6 +59,12 @@ import { RecordClass, RecordInstance } from '../Utils/WdkModel'; export const key = 'record'; +export interface TableState { + selectedRow?: number; + searchTerm: string; + expandedRows: number[]; +} + export type State = { isLoading: boolean; record: RecordInstance; @@ -62,6 +75,9 @@ export type State = { collapsedSections: string[]; + // keyed by table name + tableStates: Record; + navigationVisible: boolean; navigationQuery: string; navigationCategoriesExpanded: string[]; @@ -104,6 +120,7 @@ export function reduce(state: State = {} as State, action: Action): State { ...state, record, recordClass, + tableStates: {}, collapsedSections, navigationCategoriesExpanded: state.navigationCategoriesExpanded || [], isLoading: false, @@ -111,6 +128,16 @@ export function reduce(state: State = {} as State, action: Action): State { }; } + case TABLE_STATE_UPDATED: { + return { + ...state, + tableStates: { + ...state.tableStates, + [action.payload.tableName]: action.payload.tableState, + }, + }; + } + case RECORD_UPDATE: { if (action.id !== state.requestId) return state; let { record } = action.payload; @@ -252,7 +279,34 @@ type RecordOptions = { tables: string[]; }; -export const observe = observeRecordRequests; +export const observe = combineEpics(observeRecordRequests, observeUserSettings); + +interface StorageDescriptor { + path: string; + isRecordScoped: boolean; + getValue?: (state: State) => unknown; +} + +const storageItems: Record = { + tables: { + path: 'tableStates', + isRecordScoped: true, + }, + collapsedSections: { + path: 'collapsedSections', + isRecordScoped: false, + }, + expandedSections: { + path: 'expandedSections', + getValue: (state) => + difference(getAllFields(state), state.collapsedSections), + isRecordScoped: false, + }, + navigationVisible: { + path: 'navigationVisible', + isRecordScoped: false, + }, +}; function observeRecordRequests( action$: ActionsObservable, @@ -308,6 +362,86 @@ function observeRecordRequests( ); } +/** + * When record is loaded, read state from storage and emit actions to restore state. + * When state is changed, write state to storage. + */ +function observeUserSettings( + action$: ActionsObservable, + state$: StateObservable, + deps: EpicDependencies +) { + return action$.pipe( + filter( + (action): action is RecordReceivedAction => + action.type === RECORD_RECEIVED + ), + switchMap((action) => { + let state = state$.value[key]; + let allFields = getAllFields(state); + + /** Show navigation for records with at least 5 categories */ + let navigationVisible = getStateFromStorage( + storageItems.navigationVisible, + state, + state.categoryTree.children.length >= 5 + ); + + /** merge stored visibleSections */ + let expandedSections = getStateFromStorage( + storageItems.expandedSections, + state, + action.payload.defaultExpandedSections ?? allFields + ); + + let collapsedSections = expandedSections + ? difference(allFields, expandedSections) + : state.collapsedSections; + + let tableStates = getStateFromStorage( + storageItems.tables, + state, + {} + ) as Record; + + return merge( + from( + Object.entries(tableStates).map(([tableName, tableState]) => + updateTableState(tableName, tableState) + ) + ), + of( + updateNavigationVisibility(navigationVisible), + setCollapsedSections(collapsedSections) + ), + action$.pipe( + mergeMap((action) => { + switch (action.type) { + case SECTION_VISIBILITY: + case ALL_FIELD_VISIBILITY: + setStateInStorage( + storageItems.expandedSections, + state$.value[key] + ); + break; + case NAVIGATION_VISIBILITY: + setStateInStorage( + storageItems.navigationVisible, + state$.value[key] + ); + break; + case TABLE_STATE_UPDATED: + setStateInStorage(storageItems.tables, state$.value[key]); + break; + } + return EMPTY; + }) + ) + ); + }) + ); +} + // Utility for making epics which... // (1) On record load, update the "navigationVisible" state based on the "navigationVisible" preference // (2) On change of "navigationVisible" state, update the "navigationVisible" preference @@ -365,3 +499,83 @@ export function makeNavigationVisibilityPreferenceEpics( observeNavigationVisibilityState, }; } + +/** Read state property value from storage */ +function getStateFromStorage( + descriptor: StorageDescriptor, + state: State, + defaultValue: unknown +) { + try { + let key = getStorageKey(descriptor, state.record); + return persistence.get(key, defaultValue); + } catch (error) { + console.error( + 'Warning: Could not retrieve %s from local storage.', + descriptor.path, + error + ); + return defaultValue; + } +} + +/** Write state property value to storage */ +function setStateInStorage(descriptor: StorageDescriptor, state: State) { + try { + let key = getStorageKey(descriptor, state.record); + persistence.set( + key, + typeof descriptor.getValue === 'function' + ? descriptor.getValue(state) + : get(state, descriptor.path) + ); + } catch (error) { + console.error( + 'Warning: Could not set %s to local storage.', + descriptor.path, + error + ); + } +} + +/** Create storage key for property */ +function getStorageKey(descriptor: StorageDescriptor, record: RecordInstance) { + let { path, isRecordScoped } = descriptor; + return ( + path + + '/' + + record.recordClassName + + (isRecordScoped ? '/' + record.id.map((p) => p.value).join('/') : '') + ); +} + +const persistence = (function makePersistenceModule() { + const store = window.localStorage; + const prefix = '@@ebrc@@'; + + /** + * Set the value for the key in the store + */ + function set(key: string, value: unknown) { + try { + store.setItem(prefix + '/' + key, JSON.stringify(value)); + } catch (e) { + console.error('Unable to set value to localStorage.', e); + } + } + + /** + * Get the value for the key from the store + */ + function get(key: string, defaultValue: unknown) { + try { + let item = store.getItem(prefix + '/' + key); + return item == null ? defaultValue : JSON.parse(item); + } catch (e) { + console.error('Unable to get value from localStorage.', e); + return defaultValue; + } + } + + return { get, set }; +})(); diff --git a/packages/libs/wdk-client/src/Views/Records/RecordMain/RecordMainCategorySection.jsx b/packages/libs/wdk-client/src/Views/Records/RecordMain/RecordMainCategorySection.jsx index 56398553ad..9b530b72b3 100644 --- a/packages/libs/wdk-client/src/Views/Records/RecordMain/RecordMainCategorySection.jsx +++ b/packages/libs/wdk-client/src/Views/Records/RecordMain/RecordMainCategorySection.jsx @@ -36,6 +36,8 @@ class RecordMainCategorySection extends React.PureComponent { let { record, recordClass, + tableStates, + updateTableState, category, depth, isCollapsed, @@ -62,6 +64,10 @@ class RecordMainCategorySection extends React.PureComponent { return ( + updateTableState(category.wdkReference.name, tableState) + } ontologyProperties={category.properties} record={record} recordClass={recordClass} diff --git a/packages/libs/wdk-client/src/Views/Records/RecordMain/RecordMainSection.jsx b/packages/libs/wdk-client/src/Views/Records/RecordMain/RecordMainSection.jsx index a17ea51ecc..c24bd517d0 100644 --- a/packages/libs/wdk-client/src/Views/Records/RecordMain/RecordMainSection.jsx +++ b/packages/libs/wdk-client/src/Views/Records/RecordMain/RecordMainSection.jsx @@ -12,6 +12,8 @@ const RecordMainSection = ({ depth = 0, record, recordClass, + tableStates, + updateTableState, categories, collapsedSections, parentEnumeration, @@ -39,17 +41,21 @@ const RecordMainSection = ({ onSectionToggle={onSectionToggle} record={record} recordClass={recordClass} + tableStates={tableStates} requestPartialRecord={requestPartialRecord} + updateTableState={updateTableState} > ); @@ -60,6 +66,7 @@ const RecordMainSection = ({ RecordMainSection.propTypes = { record: PropTypes.object.isRequired, recordClass: PropTypes.object.isRequired, + tableStates: PropTypes.object.isRequired, categories: PropTypes.array.isRequired, collapsedSections: PropTypes.array.isRequired, onSectionToggle: PropTypes.func.isRequired, diff --git a/packages/libs/wdk-client/src/Views/Records/RecordTable/RecordTableSection.tsx b/packages/libs/wdk-client/src/Views/Records/RecordTable/RecordTableSection.tsx index 9e3c570061..f9efe3bdb9 100644 --- a/packages/libs/wdk-client/src/Views/Records/RecordTable/RecordTableSection.tsx +++ b/packages/libs/wdk-client/src/Views/Records/RecordTable/RecordTableSection.tsx @@ -14,9 +14,12 @@ import RecordTable from '../../../Views/Records/RecordTable/RecordTable'; import RecordTableDescription from '../../../Views/Records/RecordTable/RecordTableDescription'; import { PartialRecordRequest } from '../../../Views/Records/RecordUtils'; import { DefaultSectionTitle } from '../../../Views/Records/SectionTitle'; +import { TableState } from '../../../StoreModules/RecordStoreModule'; export interface Props { table: TableField; + tableState: TableState; + updateTableState: (tableState: TableState) => void; isCollapsed: boolean; onCollapsedChange: () => void; ontologyProperties: CategoryTreeNode['properties']; @@ -30,6 +33,11 @@ export interface Props { function RecordTableSection(props: Props) { let { table, + tableState = { + expandedRows: [0], + searchTerm: '', + }, + updateTableState, record, recordClass, isCollapsed, @@ -85,6 +93,14 @@ function RecordTableSection(props: Props) { // @ts-ignore record={record} recordClass={recordClass} + expandedRows={tableState.expandedRows} + searchTerm={tableState.searchTerm} + onExpandedRowsChange={(expandedRows) => + updateTableState({ ...tableState, expandedRows }) + } + onSearchTermChange={(searchTerm) => + updateTableState({ ...tableState, searchTerm }) + } /> )} diff --git a/packages/libs/wdk-client/src/Views/Records/RecordUI.jsx b/packages/libs/wdk-client/src/Views/Records/RecordUI.jsx index 7e92638250..aaf661ee58 100644 --- a/packages/libs/wdk-client/src/Views/Records/RecordUI.jsx +++ b/packages/libs/wdk-client/src/Views/Records/RecordUI.jsx @@ -194,6 +194,8 @@ class RecordUI extends Component { collapsedSections={this.props.collapsedSections} onSectionToggle={this.props.updateSectionVisibility} requestPartialRecord={this.props.requestPartialRecord} + tableStates={this.props.tableStates} + updateTableState={this.props.updateTableState} /> diff --git a/packages/sites/genomics-site/webapp/wdkCustomization/js/client/actioncreators/RecordViewActionCreators.ts b/packages/sites/genomics-site/webapp/wdkCustomization/js/client/actioncreators/RecordViewActionCreators.ts index a3ba421eac..a20c596e27 100644 --- a/packages/sites/genomics-site/webapp/wdkCustomization/js/client/actioncreators/RecordViewActionCreators.ts +++ b/packages/sites/genomics-site/webapp/wdkCustomization/js/client/actioncreators/RecordViewActionCreators.ts @@ -4,15 +4,9 @@ import { AnswerSpec, } from '@veupathdb/wdk-client/lib/Utils/WdkModel'; -export const TABLE_STATE_UPDATED = 'eupathdb-record-view/table-state-updated'; export const PATHWAY_DYN_COLS_LOADED = 'pathway-record/dynamic-gene-cols-loaded'; -export const updateTableState = (tableName: string, tableState: any) => ({ - type: TABLE_STATE_UPDATED, - payload: { tableName, tableState }, -}); - export const loadPathwayGeneDynamicCols = ( geneStepId: number, diff --git a/packages/sites/genomics-site/webapp/wdkCustomization/js/client/componentWrappers.jsx b/packages/sites/genomics-site/webapp/wdkCustomization/js/client/componentWrappers.jsx index a0b04a04ec..5a77a63547 100644 --- a/packages/sites/genomics-site/webapp/wdkCustomization/js/client/componentWrappers.jsx +++ b/packages/sites/genomics-site/webapp/wdkCustomization/js/client/componentWrappers.jsx @@ -109,6 +109,11 @@ export function RecordController(WdkRecordController) { }, ]; } + getDefaultExpandedSections(recordClass) { + if (recordClass.urlSegment === 'gene') { + return ['GeneModelGbrowseUrl']; + } + } loadData(prevProps) { super.loadData(prevProps); // special loading for Pathways- if gene step ID (i.e. the step passed to @@ -154,8 +159,8 @@ export const RecordUI = makeDynamicWrapper( ); export const RecordMainSection = makeDynamicWrapper('RecordMainSection'); export const RecordTable = makeDynamicWrapper( - 'RecordTable', - RecordTableContainer + 'RecordTable' + // RecordTableContainer ); export const RecordTableDescription = makeDynamicWrapper( 'RecordTableDescription' diff --git a/packages/sites/genomics-site/webapp/wdkCustomization/js/client/storeModules/Record.js b/packages/sites/genomics-site/webapp/wdkCustomization/js/client/storeModules/Record.js index 0575a90391..383443b5fb 100644 --- a/packages/sites/genomics-site/webapp/wdkCustomization/js/client/storeModules/Record.js +++ b/packages/sites/genomics-site/webapp/wdkCustomization/js/client/storeModules/Record.js @@ -1,61 +1,24 @@ -import { empty, of, merge } from 'rxjs'; -import { - filter, - map, - mergeMap, - mergeMapTo, - switchMap, - tap, -} from 'rxjs/operators'; +import { EMPTY, of, merge } from 'rxjs'; +import { filter, map, mergeMap, mergeMapTo, tap } from 'rxjs/operators'; import * as RecordStoreModule from '@veupathdb/wdk-client/lib/StoreModules/RecordStoreModule'; import { QuestionActions, RecordActions, } from '@veupathdb/wdk-client/lib/Actions'; -import { difference, get, uniq, flow, partialRight } from 'lodash'; +import { uniq, flow, partialRight } from 'lodash'; import * as tree from '@veupathdb/wdk-client/lib/Utils/TreeUtils'; import * as cat from '@veupathdb/wdk-client/lib/Utils/CategoryUtils'; -import * as persistence from '@veupathdb/web-common/lib/util/persistence'; -import { - TABLE_STATE_UPDATED, - PATHWAY_DYN_COLS_LOADED, -} from '../actioncreators/RecordViewActionCreators'; +import { PATHWAY_DYN_COLS_LOADED } from '../actioncreators/RecordViewActionCreators'; import { isGenomicsService } from '../wrapWdkService'; -import { fullyCollapsedOnLoad } from '../components/common/RecordTableContainer'; export const key = 'record'; -const storageItems = { - tables: { - path: 'eupathdb.tables', - isRecordScoped: true, - }, - collapsedSections: { - path: 'collapsedSections', - isRecordScoped: false, - }, - expandedSections: { - path: 'expandedSections', - getValue: (state) => - difference( - RecordStoreModule.getAllFields(state), - state.collapsedSections - ), - isRecordScoped: false, - }, - navigationVisible: { - path: 'navigationVisible', - isRecordScoped: false, - }, -}; - export function reduce(state, action) { state = RecordStoreModule.reduce(state, action); if (state.questions == null) state = { ...state, questions: {} }; // state = QuestionStoreModule.reduce(state, action); state = Object.assign({}, state, { pathwayRecord: handlePathwayRecordAction(state.pathwayRecord, action), - eupathdb: handleEuPathDBAction(state.eupathdb, action), dynamicColsOfIncomingStep: handleDynColsOfIncomingStepAction( state.dynamicColsOfIncomingStep, action @@ -76,9 +39,7 @@ export function reduce(state, action) { export function observe(action$, state$, services) { return merge( RecordStoreModule.observe(action$, state$, services), - // QuestionStoreModule.observe(action$, state$, services), observeSnpsAlignment(action$, state$, services), - observeUserSettings(action$, state$, services), observeRequestedOrganisms(action$, state$, services) ); } @@ -122,21 +83,6 @@ function handlePathwayRecordAction(state = initialPathwayRecordState, action) { } } -/** Handle eupathdb actions */ -function handleEuPathDBAction(state = { tables: {} }, { type, payload }) { - switch (type) { - case TABLE_STATE_UPDATED: - return Object.assign({}, state, { - tables: Object.assign({}, state.tables, { - [payload.tableName]: payload.tableState, - }), - }); - - default: - return state; - } -} - /** prune categoryTree */ function pruneCategories(nextState) { let { record, categoryTree } = nextState; @@ -290,86 +236,6 @@ function pruneByDatasetCategory(categoryTree, record) { // An observer allows us to perform side-effects in response to actions that are // dispatched to the store. -/** - * When record is loaded, read state from storage and emit actions to restore state. - * When state is changed, write state to storage. - */ -function observeUserSettings(action$, state$) { - return action$.pipe( - filter((action) => action.type === RecordActions.RECORD_RECEIVED), - switchMap((action) => { - let state = state$.value[key]; - - /** Show navigation for genes, but hide for all other record types */ - let navigationVisible = getStateFromStorage( - storageItems.navigationVisible, - state, - isGeneRecord(state.record) - ); - - let allFields = RecordStoreModule.getAllFields(state); - - /** merge stored visibleSections */ - let expandedSections = getStateFromStorage( - storageItems.expandedSections, - state, - action.payload.recordClass.urlSegment === 'gene' - ? ['GeneModelGbrowseUrl'] - : allFields - ); - - let collapsedSections = expandedSections - ? difference(allFields, expandedSections) - : state.collapsedSections; - - let tableStates = getStateFromStorage(storageItems.tables, state, {}); - - return merge( - of( - RecordActions.updateNavigationVisibility(navigationVisible), - RecordActions.setCollapsedSections(collapsedSections), - ...Object.entries(tableStates).map(([tableName, tableState]) => ({ - type: TABLE_STATE_UPDATED, - payload: { tableName, tableState }, - })) - ), - action$.pipe( - mergeMap((action) => { - switch (action.type) { - case RecordActions.SECTION_VISIBILITY: - case RecordActions.ALL_FIELD_VISIBILITY: - setStateInStorage( - storageItems.expandedSections, - state$.value[key] - ); - break; - case RecordActions.NAVIGATION_VISIBILITY: - setStateInStorage( - storageItems.navigationVisible, - state$.value[key] - ); - break; - case TABLE_STATE_UPDATED: - // Do not store the expanded rows for these tables. - if (fullyCollapsedOnLoad.has(action.payload.tableName)) { - console.info( - 'Table state for', - action.payload.tableName, - 'is not being stored.' - ); - } else { - setStateInStorage(storageItems.tables, state$.value[key]); - } - break; - } - return empty(); - }) - ) - ); - }) - ); -} - /** * Load filterParam data for snp alignment form. */ @@ -382,7 +248,7 @@ function observeSnpsAlignment(action$) { ? of(action.payload.record.attributes.organism_full) : isSnpsRecord(action.payload.record) ? of(action.payload.record.attributes.organism_text) - : empty() + : EMPTY ), map((organismSinglePick) => { return QuestionActions.updateActiveQuestion({ @@ -419,7 +285,7 @@ function observeRequestedOrganisms(action$, state$, { wdkService }) { wdkService.incrementOrganismCount(recordOrganism); }); }), - mergeMapTo(empty()) + mergeMapTo(EMPTY) ); } @@ -454,51 +320,6 @@ function getRecordOrganisms({ } } -/** Read state property value from storage */ -function getStateFromStorage(descriptor, state, defaultValue) { - try { - let key = getStorageKey(descriptor, state.record); - return persistence.get(key, defaultValue); - } catch (error) { - console.error( - 'Warning: Could not retrieve %s from local storage.', - descriptor.path, - error - ); - return defaultValue; - } -} - -/** Write state property value to storage */ -function setStateInStorage(descriptor, state) { - try { - let key = getStorageKey(descriptor, state.record); - persistence.set( - key, - typeof descriptor.getValue === 'function' - ? descriptor.getValue(state) - : get(state, descriptor.path) - ); - } catch (error) { - console.error( - 'Warning: Could not set %s to local storage.', - descriptor.path, - error - ); - } -} - -/** Create storage key for property */ -function getStorageKey(descriptor, record) { - let { path, isRecordScoped } = descriptor; - return ( - path + - '/' + - record.recordClassName + - (isRecordScoped ? '/' + record.id.map((p) => p.value).join('/') : '') - ); -} - function isGeneRecord(record) { return record.recordClassName === 'GeneRecordClasses.GeneRecordClass'; }