From 5bf6b7efa7e3ba18761a45113b518d1f6d3d7fc2 Mon Sep 17 00:00:00 2001 From: Suren Date: Wed, 22 Nov 2023 20:28:09 +0530 Subject: [PATCH] #9702: Fix - Background selector in contexts won't retain thumbnail in view mode (#9720) * #9702: Fix - Background selector in contexts won't retain thumbnail in view mode * Update web/client/epics/config.js --------- Co-authored-by: Matteo V --- web/client/epics/__tests__/config-test.js | 82 ++++++++++++++++++++++- web/client/epics/backgroundselector.js | 26 ------- web/client/epics/config.js | 39 ++++++++++- 3 files changed, 118 insertions(+), 29 deletions(-) diff --git a/web/client/epics/__tests__/config-test.js b/web/client/epics/__tests__/config-test.js index 3aa9a63d34..90ef131145 100644 --- a/web/client/epics/__tests__/config-test.js +++ b/web/client/epics/__tests__/config-test.js @@ -8,7 +8,7 @@ import expect from 'expect'; import {head} from 'lodash'; -import {loadMapConfigAndConfigureMap, loadMapInfoEpic, storeDetailsInfoDashboardEpic, storeDetailsInfoEpic} from '../config'; +import {loadMapConfigAndConfigureMap, loadMapInfoEpic, storeDetailsInfoDashboardEpic, storeDetailsInfoEpic, backgroundsListInitEpic} from '../config'; import {LOAD_USER_SESSION} from '../../actions/usersession'; import { loadMapConfig, @@ -18,7 +18,8 @@ import { MAP_INFO_LOADED, MAP_INFO_LOAD_START, loadMapInfo, - mapInfoLoaded + mapInfoLoaded, + configureMap } from '../../actions/config'; import { TEST_TIMEOUT, addTimeoutEpic, testEpic } from './epicTestUtils'; @@ -480,6 +481,83 @@ describe('config epics', () => { attributes: {} } }}); + }, {}); + }); + describe("backgroundsListInitEpic", () => { + const base64 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII"; + it('test layer update with thumbnail on background init', (done) => { + testEpic(addTimeoutEpic(backgroundsListInitEpic), 3, configureMap({ + map: { + backgrounds: [{id: "1", thumbnail: base64}], + layers: [{id: "1", group: "background", name: "layer_1", visibility: true}] + } + }), actions => { + expect(actions.length).toBe(3); + actions.map((action) => { + switch (action.type) { + case "CHANGE_LAYER_PROPERTIES": + expect(action.newProperties.thumbURL).toBeTruthy(); + expect(action.layer).toBe("1"); + break; + case "BACKGROUND_SELECTOR:CREATE_BACKGROUNDS_LIST": + expect(action.backgrounds.length).toBe(1); + expect(action.backgrounds[0].id).toBe("1"); + expect(action.backgrounds[0].thumbnail).toBe(base64); + break; + case "BACKGROUND_SELECTOR:SET_CURRENT_BACKGROUND_LAYER": + expect(action.layerId).toBe("1"); + break; + default: + expect(true).toBe(false); + } + }); + done(); + }); + }); + it('test layer update with thumbnail with layer not visible', (done) => { + testEpic(addTimeoutEpic(backgroundsListInitEpic), 2, configureMap({ + map: { + backgrounds: [{id: "1", thumbnail: base64}], + layers: [{id: "1", group: "background", name: "layer_1", visibility: false}] + } + }), actions => { + expect(actions.length).toBe(2); + actions.map((action) => { + switch (action.type) { + case "CHANGE_LAYER_PROPERTIES": + expect(action.newProperties.thumbURL).toBeTruthy(); + expect(action.layer).toBe("1"); + break; + case "BACKGROUND_SELECTOR:CREATE_BACKGROUNDS_LIST": + expect(action.backgrounds.length).toBe(1); + expect(action.backgrounds[0].id).toBe("1"); + expect(action.backgrounds[0].thumbnail).toBe(base64); + break; + default: + expect(true).toBe(false); + } + }); + done(); + }, {}); + }); + it('test backgroundsListInitEpic with no background layer', (done) => { + testEpic(addTimeoutEpic(backgroundsListInitEpic), 1, configureMap({ + map: { + layers: [{id: "1", name: "layer_1", visibility: false}] + } + }), actions => { + expect(actions.length).toBe(1); + actions.map((action) => { + switch (action.type) { + case "BACKGROUND_SELECTOR:CREATE_BACKGROUNDS_LIST": + expect(action.backgrounds.length).toBe(0); + break; + default: + expect(true).toBe(false); + } + }); + done(); + }, {}); }); }); }); diff --git a/web/client/epics/backgroundselector.js b/web/client/epics/backgroundselector.js index 2a133afe98..41cf887381 100644 --- a/web/client/epics/backgroundselector.js +++ b/web/client/epics/backgroundselector.js @@ -18,7 +18,6 @@ import { BACKGROUND_EDITED, REMOVE_BACKGROUND, SYNC_CURRENT_BACKGROUND_LAYER, - createBackgroundsList, clearModalParameters, setBackgroundModalParams, setCurrentBackgroundLayer, @@ -27,7 +26,6 @@ import { } from '../actions/backgroundselector'; import { setControlProperty } from '../actions/controls'; -import { MAP_CONFIG_LOADED } from '../actions/config'; import { changeSelectedService } from '../actions/catalog'; import {ADD_LAYER, changeLayerProperties, removeNode} from '../actions/layers'; import { getLayerFromId, currentBackgroundSelector } from '../selectors/layers'; @@ -58,29 +56,6 @@ const addBackgroundPropertiesEpic = (action$) => : defaultAction; }); -const backgroundsListInit = (action$) => - action$.ofType(MAP_CONFIG_LOADED) - .switchMap(({config}) => { - const backgrounds = config.map && config.map.backgrounds || []; - const backgroundLayers = (config.map && config.map.layers || []).filter(layer => layer.group === 'background'); - const layerUpdateActions = backgrounds.filter(background => !!background.thumbnail).map(background => { - const toBlob = (data) => { - const bytes = atob(data.split(',')[1]); - const mimeType = data.split(',')[0].split(':')[1].split(';')[0]; - let buffer = new ArrayBuffer(bytes.length); - let byteArray = new Uint8Array(buffer); - for (let i = 0; i < bytes.length; ++i) { - byteArray[i] = bytes.charCodeAt(i); - } - return URL.createObjectURL(new Blob([buffer], {type: mimeType})); - }; - return changeLayerProperties(background.id, {thumbURL: toBlob(background.thumbnail)}); - }); - const currentBackground = head(backgroundLayers.filter(layer => layer.visibility)); - return Rx.Observable.of(...layerUpdateActions.concat(createBackgroundsList(backgrounds)), - ...(currentBackground ? [setCurrentBackgroundLayer(currentBackground.id)] : [])); - }); - const setCurrentBackgroundLayerEpic = (action$, store) => action$.ofType(SET_CURRENT_BACKGROUND_LAYER) .switchMap(({layerId}) => { @@ -151,7 +126,6 @@ const syncSelectedBackgroundEpic = (action$) => export default { accessMetadataExplorer, addBackgroundPropertiesEpic, - backgroundsListInit, setCurrentBackgroundLayerEpic, backgroundAddedEpic, backgroundEditedEpic, diff --git a/web/client/epics/config.js b/web/client/epics/config.js index 37dc56b1b6..171f3ea9b5 100644 --- a/web/client/epics/config.js +++ b/web/client/epics/config.js @@ -7,7 +7,7 @@ */ import { Observable } from 'rxjs'; import axios from '../libs/ajax'; -import { get, merge, isNaN, find } from 'lodash'; +import { get, merge, isNaN, find, head } from 'lodash'; import { LOAD_NEW_MAP, LOAD_MAP_CONFIG, @@ -34,6 +34,8 @@ import { detailsLoaded, openDetailsPanel } from '../actions/details'; import {userSessionEnabledSelector, buildSessionName} from "../selectors/usersession"; import {getRequestParameterValue} from "../utils/QueryParamsUtils"; import { EMPTY_RESOURCE_VALUE } from '../utils/MapInfoUtils'; +import { changeLayerProperties } from '../actions/layers'; +import { createBackgroundsList, setCurrentBackgroundLayer } from '../actions/backgroundselector'; const prepareMapConfiguration = (data, override, state) => { const queryParamsMap = getRequestParameterValue('map', state); @@ -243,3 +245,38 @@ export const storeDetailsInfoDashboardEpic = (action$, store) => ); }); }); + +/** + * Intercept MAP_CONFIG_LOADED and update background layers thumbnail + * Epic is placed here to better intercept and update background layers thumbnail info, + * when loading context with map and to avoid race condition + * when loading plugins and map configuration + * @memberof epics.config + * @param {Observable} action$ stream of actions + * @param {object} store redux store + * @return {external:Observable} + */ +export const backgroundsListInitEpic = (action$) => + action$.ofType(MAP_CONFIG_LOADED) + .switchMap(({config}) => { + const backgrounds = config.map && config.map.backgrounds || []; + const backgroundLayers = (config.map && config.map.layers || []).filter(layer => layer.group === 'background'); + const layerUpdateActions = backgrounds.filter(background => !!background.thumbnail).map(background => { + const toBlob = (data) => { + const bytes = atob(data.split(',')[1]); + const mimeType = data.split(',')[0].split(':')[1].split(';')[0]; + let buffer = new ArrayBuffer(bytes.length); + let byteArray = new Uint8Array(buffer); + for (let i = 0; i < bytes.length; ++i) { + byteArray[i] = bytes.charCodeAt(i); + } + return URL.createObjectURL(new Blob([buffer], {type: mimeType})); + }; + return changeLayerProperties(background.id, {thumbURL: toBlob(background.thumbnail)}); + }); + const currentBackground = head(backgroundLayers.filter(layer => layer.visibility)); + return Observable.of( + ...layerUpdateActions.concat(createBackgroundsList(backgrounds)), + ...(currentBackground ? [setCurrentBackgroundLayer(currentBackground.id)] : []) + ); + });