Skip to content
Snippets Groups Projects
Commit 691908f3 authored by Miłosz Grocholewski's avatar Miłosz Grocholewski
Browse files

Merge branch 'feat/MIN-83-spinner-when-diagram-is-loading' into 'development'

feat(vector-map): add spinner when diagram is loading

Closes MIN-83

See merge request !314
parents 68d6ca25 793ecb9b
No related branches found
No related tags found
1 merge request!314feat(vector-map): add spinner when diagram is loading
Pipeline #98274 passed
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
import { Drawer } from '@/components/Map/Drawer'; import { Drawer } from '@/components/Map/Drawer';
import { Legend } from '@/components/Map/Legend'; import { Legend } from '@/components/Map/Legend';
import { MapViewer } from '@/components/Map/MapViewer'; import { MapViewer } from '@/components/Map/MapViewer';
import { MapLoader } from '@/components/Map/MapLoader/MapLoader.component';
import { MapAdditionalActions } from './MapAdditionalActions'; import { MapAdditionalActions } from './MapAdditionalActions';
import { MapAdditionalOptions } from './MapAdditionalOptions'; import { MapAdditionalOptions } from './MapAdditionalOptions';
import { PluginsDrawer } from './PluginsDrawer'; import { PluginsDrawer } from './PluginsDrawer';
...@@ -18,6 +19,7 @@ export const Map = (): JSX.Element => { ...@@ -18,6 +19,7 @@ export const Map = (): JSX.Element => {
<PluginsDrawer /> <PluginsDrawer />
<Legend /> <Legend />
<MapAdditionalActions /> <MapAdditionalActions />
<MapLoader />
</div> </div>
); );
}; };
import React from 'react';
import { render, screen } from '@testing-library/react';
import {
getReduxWrapperWithStore,
InitialStoreState,
} from '@/utils/testing/getReduxWrapperWithStore';
import { StoreType } from '@/redux/store';
import { useAppSelector } from '@/redux/hooks/useAppSelector';
import { newReactionsLoadingSelector } from '@/redux/newReactions/newReactions.selectors';
import { modelElementsLoadingSelector } from '@/redux/modelElements/modelElements.selector';
import { isDrawerOpenSelector } from '@/redux/drawer/drawer.selectors';
import { vectorRenderingSelector } from '@/redux/models/models.selectors';
import {
arrowTypesLoadingSelector,
bioShapesLoadingSelector,
lineTypesLoadingSelector,
} from '@/redux/shapes/shapes.selectors';
import { layersLoadingSelector } from '@/redux/layers/layers.selectors';
import { MapLoader } from './MapLoader.component';
jest.mock('../../../redux/hooks/useAppSelector', () => ({
useAppSelector: jest.fn(),
}));
type SelectorFunction = (state: never) => string | boolean;
const renderComponent = (initialStore?: InitialStoreState): { store: StoreType } => {
const { Wrapper, store } = getReduxWrapperWithStore(initialStore);
return (
render(
<Wrapper>
<MapLoader />
</Wrapper>,
),
{
store,
}
);
};
describe('MapLoader', () => {
const mockUseAppSelector = useAppSelector as jest.Mock;
afterEach(() => {
jest.clearAllMocks();
});
it('should not render the LoadingIndicator when no data is loading', () => {
mockUseAppSelector.mockImplementation(selector => {
const selectorMap = new Map<SelectorFunction, string | boolean>([
[newReactionsLoadingSelector, 'succeeded'],
[modelElementsLoadingSelector, 'succeeded'],
[vectorRenderingSelector, true],
[bioShapesLoadingSelector, 'succeeded'],
[lineTypesLoadingSelector, 'succeeded'],
[arrowTypesLoadingSelector, 'succeeded'],
[layersLoadingSelector, 'succeeded'],
[isDrawerOpenSelector, false],
]);
return selectorMap.get(selector) ?? false;
});
renderComponent();
expect(screen.queryByTestId('loading-indicator')).not.toBeInTheDocument();
});
it('should render the LoadingIndicator when vectorRendering is true and data is loading', () => {
mockUseAppSelector.mockImplementation(selector => {
const selectorMap = new Map<SelectorFunction, string | boolean>([
[newReactionsLoadingSelector, 'pending'],
[modelElementsLoadingSelector, 'succeeded'],
[vectorRenderingSelector, true],
[bioShapesLoadingSelector, 'succeeded'],
[lineTypesLoadingSelector, 'succeeded'],
[arrowTypesLoadingSelector, 'succeeded'],
[layersLoadingSelector, 'succeeded'],
[isDrawerOpenSelector, false],
]);
return selectorMap.get(selector) ?? false;
});
renderComponent();
expect(screen.queryByTestId('loading-indicator')).toBeInTheDocument();
});
it('should not render the LoadingIndicator when vectorRendering is false even when data is loading', () => {
mockUseAppSelector.mockImplementation(selector => {
const selectorMap = new Map<SelectorFunction, string | boolean>([
[newReactionsLoadingSelector, 'pending'],
[modelElementsLoadingSelector, 'succeeded'],
[vectorRenderingSelector, false],
[bioShapesLoadingSelector, 'succeeded'],
[lineTypesLoadingSelector, 'succeeded'],
[arrowTypesLoadingSelector, 'succeeded'],
[layersLoadingSelector, 'succeeded'],
[isDrawerOpenSelector, false],
]);
return selectorMap.get(selector) ?? false;
});
renderComponent();
expect(screen.queryByTestId('loading-indicator')).not.toBeInTheDocument();
});
});
import { LoadingIndicator } from '@/shared/LoadingIndicator';
import { useMemo } from 'react';
import { newReactionsLoadingSelector } from '@/redux/newReactions/newReactions.selectors';
import { modelElementsLoadingSelector } from '@/redux/modelElements/modelElements.selector';
import { vectorRenderingSelector } from '@/redux/models/models.selectors';
import {
arrowTypesLoadingSelector,
bioShapesLoadingSelector,
lineTypesLoadingSelector,
} from '@/redux/shapes/shapes.selectors';
import { layersLoadingSelector } from '@/redux/layers/layers.selectors';
import './MapLoader.styles.css';
import { isDrawerOpenSelector } from '@/redux/drawer/drawer.selectors';
import { useAppSelector } from '@/redux/hooks/useAppSelector';
export const MapLoader = (): JSX.Element => {
const reactionsFetching = useAppSelector(newReactionsLoadingSelector);
const modelElementsFetching = useAppSelector(modelElementsLoadingSelector);
const vectorRendering = useAppSelector(vectorRenderingSelector);
const bioShapesFetching = useAppSelector(bioShapesLoadingSelector);
const lineTypesFetching = useAppSelector(lineTypesLoadingSelector);
const arrowTypesFetching = useAppSelector(arrowTypesLoadingSelector);
const layersLoading = useAppSelector(layersLoadingSelector);
const isDrawerOpen = useAppSelector(isDrawerOpenSelector);
const showLoader = useMemo(() => {
return [
reactionsFetching,
modelElementsFetching,
bioShapesFetching,
lineTypesFetching,
arrowTypesFetching,
layersLoading,
].includes('pending');
}, [
reactionsFetching,
modelElementsFetching,
bioShapesFetching,
lineTypesFetching,
arrowTypesFetching,
layersLoading,
]);
return (
<div className={`map-loader transition-all duration-500 ${isDrawerOpen ? 'move-right' : ''}`}>
{vectorRendering && showLoader && <LoadingIndicator width={48} height={48} />}
</div>
);
};
.map-loader {
position: absolute;
left: 120px;
top: 128px;
}
.map-loader.move-right {
left: 550px;
}
...@@ -62,8 +62,10 @@ export const useOlMapReactionsLayer = ({ ...@@ -62,8 +62,10 @@ export const useOlMapReactionsLayer = ({
const pointToProjection = usePointToProjection(); const pointToProjection = usePointToProjection();
useEffect(() => { useEffect(() => {
dispatch(getModelElements(currentModelId)); if (currentModelId) {
dispatch(getNewReactions(currentModelId)); dispatch(getModelElements(currentModelId));
dispatch(getNewReactions(currentModelId));
}
}, [currentModelId, dispatch]); }, [currentModelId, dispatch]);
const groupedElementsOverlays = useMemo(() => { const groupedElementsOverlays = useMemo(() => {
......
...@@ -474,6 +474,7 @@ export const CORE_PD_MODEL_MOCK: MapModel = { ...@@ -474,6 +474,7 @@ export const CORE_PD_MODEL_MOCK: MapModel = {
modificationDates: [], modificationDates: [],
minZoom: 2, minZoom: 2,
maxZoom: 9, maxZoom: 9,
vectorRendering: true,
}; };
export const MODEL_WITH_DESCRIPTION: MapModel = { export const MODEL_WITH_DESCRIPTION: MapModel = {
......
...@@ -6,6 +6,8 @@ export const layersSelector = createSelector( ...@@ -6,6 +6,8 @@ export const layersSelector = createSelector(
state => state.layers?.data?.layers || [], state => state.layers?.data?.layers || [],
); );
export const layersLoadingSelector = createSelector(rootSelector, state => state.layers.loading);
export const layersVisibilitySelector = createSelector( export const layersVisibilitySelector = createSelector(
rootSelector, rootSelector,
state => state.layers?.data?.layersVisibility || {}, state => state.layers?.data?.layersVisibility || {},
......
...@@ -5,3 +5,8 @@ export const modelElementsSelector = createSelector( ...@@ -5,3 +5,8 @@ export const modelElementsSelector = createSelector(
rootSelector, rootSelector,
state => state.modelElements.data, state => state.modelElements.data,
); );
export const modelElementsLoadingSelector = createSelector(
rootSelector,
state => state.modelElements.loading,
);
...@@ -3,6 +3,11 @@ import { rootSelector } from '../root/root.selectors'; ...@@ -3,6 +3,11 @@ import { rootSelector } from '../root/root.selectors';
export const newReactionsSelector = createSelector(rootSelector, state => state.newReactions); export const newReactionsSelector = createSelector(rootSelector, state => state.newReactions);
export const newReactionsLoadingSelector = createSelector(
newReactionsSelector,
state => state.loading,
);
export const newReactionsDataSelector = createSelector( export const newReactionsDataSelector = createSelector(
newReactionsSelector, newReactionsSelector,
reactions => reactions.data || [], reactions => reactions.data || [],
......
...@@ -8,12 +8,27 @@ export const bioShapesSelector = createSelector( ...@@ -8,12 +8,27 @@ export const bioShapesSelector = createSelector(
shapes => shapes.bioShapesState.data, shapes => shapes.bioShapesState.data,
); );
export const bioShapesLoadingSelector = createSelector(
shapesSelector,
shapes => shapes.bioShapesState.loading,
);
export const lineTypesSelector = createSelector( export const lineTypesSelector = createSelector(
shapesSelector, shapesSelector,
shapes => shapes.lineTypesState.data || {}, shapes => shapes.lineTypesState.data || {},
); );
export const lineTypesLoadingSelector = createSelector(
shapesSelector,
shapes => shapes.lineTypesState.loading,
);
export const arrowTypesSelector = createSelector( export const arrowTypesSelector = createSelector(
shapesSelector, shapesSelector,
shapes => shapes.arrowTypesState.data || {}, shapes => shapes.arrowTypesState.data || {},
); );
export const arrowTypesLoadingSelector = createSelector(
shapesSelector,
shapes => shapes.arrowTypesState.loading,
);
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment