diff --git a/src/store/user/thunks.test.tsx b/src/store/user/thunks.test.tsx new file mode 100644 index 000000000..6f95d604c --- /dev/null +++ b/src/store/user/thunks.test.tsx @@ -0,0 +1,55 @@ +import { cloneDeep } from 'lodash'; +import { cleanupConfig } from './thunks'; +import { + emptyUserConfig, + updatedConfigDashboard, + updatedConfigParticipant, + updatedConfigSummary, + updatedConfigVariant, + userConfig, + userConfigWithoutVariant, +} from './thunksTestData'; + +describe('store/user/thunks', () => { + describe('cleanupConfig', () => { + it('should return and empty object if config and his update are empty', () => { + const result = cleanupConfig(emptyUserConfig, emptyUserConfig); + expect(result).toEqual({}); + }); + it('should return updated config if config is empty', () => { + const result = cleanupConfig(updatedConfigSummary, {}); + expect(result).toEqual(updatedConfigSummary); + }); + it('should return merged config if config not contains the updated config part', () => { + const result = cleanupConfig(updatedConfigVariant, userConfigWithoutVariant); + const mergedConfig = { ...cloneDeep(userConfigWithoutVariant), ...updatedConfigVariant }; + expect(result).toEqual(mergedConfig); + }); + + it('should return merged config if config and updated summary config are not empty', () => { + const result = cleanupConfig(updatedConfigSummary, userConfig); + const mergedConfig = cloneDeep(userConfig); + mergedConfig.data_exploration.summary = updatedConfigSummary.data_exploration.summary; + expect(result).toEqual(mergedConfig); + }); + it('should return merged config if config and updated tables config are not empty', () => { + const result = cleanupConfig(updatedConfigParticipant, userConfig); + const mergedConfig = cloneDeep(userConfig); + mergedConfig.data_exploration.tables.participants = + updatedConfigParticipant.data_exploration.tables.participants; + expect(result).toEqual(mergedConfig); + }); + it('should return merged config if config and updated variants config are not empty', () => { + const result = cleanupConfig(updatedConfigVariant, userConfig); + const mergedConfig = cloneDeep(userConfig); + mergedConfig.variants = updatedConfigVariant.variants; + expect(result).toEqual(mergedConfig); + }); + it('should return merged config if config and updated dashboard config are not empty', () => { + const result = cleanupConfig(updatedConfigDashboard, userConfig); + const mergedConfig = cloneDeep(userConfig); + mergedConfig.dashboard = updatedConfigDashboard.dashboard; + expect(result).toEqual(mergedConfig); + }); + }); +}); diff --git a/src/store/user/thunks.ts b/src/store/user/thunks.ts index 1d49a6003..127c928b4 100644 --- a/src/store/user/thunks.ts +++ b/src/store/user/thunks.ts @@ -70,28 +70,37 @@ const updateUser = createAsyncThunk< }, ); -const cleanupConfig = (config: TUserConfig): TUserConfig => { +export const cleanupConfig = (updateConfig: TUserConfig, config?: TUserConfig): TUserConfig => { // keep last item const removeDuplicates = (cols: TColumnStates) => cols.filter((c, i) => !cols.some((other, j) => c.key === other.key && j > i)); - // for every tables in config replace columns with no duplicates - keys(config.data_exploration?.tables).forEach((key) => { - const path = 'data_exploration.tables.' + key + '.columns'; - const cols = get(config, path, []); - set(config, path, removeDuplicates(cols)); - }); + const configMerged = merge(cloneDeep(config), cloneDeep(updateConfig)); - return config; + if (updateConfig.data_exploration?.tables) { + // for every tables in config replace columns with no duplicates + keys(configMerged.data_exploration?.tables).forEach((key) => { + const path = 'data_exploration.tables.' + key + '.columns'; + const cols = get(configMerged, path, []); + set(configMerged, path, removeDuplicates(cols)); + }); + + return configMerged; + } else if (updateConfig.data_exploration?.summary && config?.data_exploration?.summary) { + config.data_exploration.summary = updateConfig.data_exploration.summary; + return config; + } + + return configMerged; }; const updateUserConfig = createAsyncThunk( 'user/updateConfig', async (config, thunkAPI) => { const state = thunkAPI.getState(); - const mergedConfig = cleanupConfig( - merge(cloneDeep(state?.user?.userInfo?.config), cloneDeep(config)), - ); + + const mergedConfig = cleanupConfig(cloneDeep(config), cloneDeep(state?.user?.userInfo?.config)); + await UserApi.update({ config: mergedConfig }); return mergedConfig; diff --git a/src/store/user/thunksTestData.ts b/src/store/user/thunksTestData.ts new file mode 100644 index 000000000..f2d7649e5 --- /dev/null +++ b/src/store/user/thunksTestData.ts @@ -0,0 +1,400 @@ +export const emptyUserConfig = {}; + +export const userConfig = { + variants: { + tables: { + variants: { + columns: [ + { + key: 'variant_class', + index: 16, + visible: true, + }, + { + key: 'rsnumber', + index: 17, + visible: true, + }, + { + key: 'genes', + index: 18, + visible: true, + }, + ], + }, + }, + }, + dashboard: { + cards: { + order: ['7', '2', '3', '4', '5', '6'], + }, + }, + data_exploration: { + tables: { + datafiles: { + columns: [ + { + key: 'lock', + index: 16, + visible: true, + }, + { + key: 'controlled_access', + index: 17, + visible: true, + }, + { + key: 'file_id', + index: 18, + visible: true, + }, + { + key: 'study.study_code', + index: 19, + visible: true, + }, + ], + }, + biospecimens: { + columns: [ + { + key: 'sample_id', + index: 25, + visible: true, + }, + { + key: 'study.study_code', + index: 26, + visible: true, + }, + { + key: 'sample_type', + index: 27, + visible: true, + }, + ], + }, + participants: { + columns: [ + { + key: 'participant_id', + index: 20, + visible: true, + }, + { + key: 'study.study_code', + index: 21, + visible: true, + }, + { + key: 'study_external_id', + index: 22, + visible: true, + }, + ], + }, + }, + summary: { + layouts: [ + { + id: 'observed_phenotype', + lg: { + h: 4, + w: 8, + x: 0, + y: 0, + }, + base: { + h: 4, + w: 8, + x: 0, + y: 0, + isResizable: false, + }, + title: 'Observed Phenotypes (HPO)', + }, + { + id: 'mondo', + lg: { + h: 4, + w: 8, + x: 8, + y: 0, + }, + base: { + h: 4, + w: 8, + x: 8, + y: 0, + isResizable: false, + }, + title: ' Diagnosis (MONDO)', + }, + ], + }, + }, +}; + +export const userConfigWithoutVariant = { + dashboard: { + cards: { + order: ['7', '2', '3', '4', '5', '6'], + }, + }, + data_exploration: { + tables: { + datafiles: { + columns: [ + { + key: 'lock', + index: 16, + visible: true, + }, + { + key: 'controlled_access', + index: 17, + visible: true, + }, + { + key: 'file_id', + index: 18, + visible: true, + }, + { + key: 'study.study_code', + index: 19, + visible: true, + }, + ], + }, + biospecimens: { + columns: [ + { + key: 'sample_id', + index: 25, + visible: true, + }, + { + key: 'study.study_code', + index: 26, + visible: true, + }, + { + key: 'sample_type', + index: 27, + visible: true, + }, + ], + }, + participants: { + columns: [ + { + key: 'participant_id', + index: 20, + visible: true, + }, + { + key: 'study.study_code', + index: 21, + visible: true, + }, + { + key: 'study_external_id', + index: 22, + visible: true, + }, + ], + }, + }, + summary: { + layouts: [ + { + id: 'observed_phenotype', + lg: { + h: 4, + w: 8, + x: 0, + y: 0, + }, + base: { + h: 4, + w: 8, + x: 0, + y: 0, + isResizable: false, + }, + title: 'Observed Phenotypes (HPO)', + }, + { + id: 'mondo', + lg: { + h: 4, + w: 8, + x: 8, + y: 0, + }, + base: { + h: 4, + w: 8, + x: 8, + y: 0, + isResizable: false, + }, + title: ' Diagnosis (MONDO)', + }, + ], + }, + }, +}; + +export const updatedConfigSummary = { + data_exploration: { + summary: { + layouts: [ + { + title: 'Observed Phenotypes (HPO)', + id: 'observed_phenotype', + base: { + h: 4, + isResizable: false, + w: 8, + x: 0, + y: 0, + }, + lg: { + h: 4, + w: 8, + x: 0, + y: 0, + }, + md: { + h: 4, + w: 6, + x: 0, + y: 0, + }, + sm: { + h: 4, + w: 5, + x: 0, + y: 0, + }, + xs: { + h: 4, + w: 6, + x: 0, + y: 0, + }, + xxs: { + h: 4, + w: 4, + x: 0, + y: 0, + }, + hidden: true, + }, + { + title: ' Diagnosis (MONDO)', + id: 'mondo', + base: { + h: 4, + isResizable: false, + w: 8, + x: 8, + y: 0, + }, + lg: { + h: 4, + w: 8, + x: 8, + y: 0, + }, + md: { + h: 4, + w: 6, + x: 6, + y: 0, + }, + sm: { + h: 4, + w: 5, + x: 5, + y: 0, + }, + xs: { + h: 4, + w: 6, + x: 0, + y: 4, + }, + xxs: { + h: 4, + w: 4, + x: 0, + y: 4, + }, + }, + ], + }, + }, +}; + +export const updatedConfigParticipant = { + data_exploration: { + tables: { + participants: { + columns: [ + { + key: 'participant_id', + index: 20, + visible: true, + }, + { + key: 'study.study_code', + index: 21, + visible: true, + }, + { + key: 'study_external_id', + index: 22, + visible: false, + }, + ], + }, + }, + }, +}; + +export const updatedConfigVariant = { + variants: { + tables: { + variants: { + columns: [ + { + key: 'variant_class', + index: 16, + visible: true, + }, + { + key: 'rsnumber', + index: 17, + visible: false, + }, + { + key: 'genes', + index: 18, + visible: true, + }, + ], + }, + }, + }, +}; + +export const updatedConfigDashboard = { + dashboard: { + cards: { + order: ['2', '3', '4', '5', '6', '7'], + }, + }, +};