Skip to content

Commit

Permalink
geosolutions-it#9683: add Details Panel for MS dashboard
Browse files Browse the repository at this point in the history
-  The tool have the same options (eg. show as modal, show at startup etc.)
- The tool is defined in the same way of the corresponding one for maps.
- Edit the layout to put add widget & show/hide connection buttons to the sidebar menu
  • Loading branch information
mahmoudadel54 committed Nov 10, 2023
1 parent dc6b993 commit 51fc25e
Show file tree
Hide file tree
Showing 32 changed files with 770 additions and 129 deletions.
2 changes: 1 addition & 1 deletion web/client/actions/__tests__/details-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ describe('details actions tests', () => {
const a = detailsLoaded(mapId, detailsUri);
expect(a.type).toBe(DETAILS_LOADED);
expect(a.detailsUri).toBe(detailsUri);
expect(a.mapId).toBe(mapId);
expect(a.id).toBe(mapId);
});
it('updateDetails', () => {
const a = updateDetails('text');
Expand Down
8 changes: 4 additions & 4 deletions web/client/actions/details.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,19 @@ export const NO_DETAILS_AVAILABLE = "NO_DETAILS_AVAILABLE";
* @memberof actions.details
* @return {action} type `UPDATE_DETAILS`
*/
export const updateDetails = (detailsText) => ({
export const updateDetails = (detailsText, resourceId) => ({
type: UPDATE_DETAILS,
detailsText
detailsText, id: resourceId
});

/**
* detailsLoaded
* @memberof actions.details
* @return {action} type `DETAILS_LOADED`
*/
export const detailsLoaded = (mapId, detailsUri, detailsSettings) => ({
export const detailsLoaded = (resourceId, detailsUri, detailsSettings) => ({
type: DETAILS_LOADED,
mapId,
id: resourceId,
detailsUri,
detailsSettings
});
Expand Down
9 changes: 6 additions & 3 deletions web/client/components/details/DetailsPanel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ class DetailsPanel extends React.Component {
panelClassName: PropTypes.string,
style: PropTypes.object,
onClose: PropTypes.func,
width: PropTypes.number
width: PropTypes.number,
isDashboard: PropTypes.bool
};

static contextTypes = {
Expand All @@ -41,7 +42,8 @@ class DetailsPanel extends React.Component {
},
active: false,
panelClassName: "details-panel",
width: 550
width: 550,
isDashboard: false
};

render() {
Expand All @@ -58,9 +60,10 @@ class DetailsPanel extends React.Component {
onClose={() => this.props.onClose()}
glyph="sheet"
style={this.props.dockStyle}
isDashboard={this.props.isDashboard}
>
<Panel id={this.props.id} style={this.props.panelStyle} className={this.props.panelClassName}>
<BorderLayout>
<BorderLayout isDashboard={this.props.isDashboard}>
{this.props.children}
</BorderLayout>
</Panel>
Expand Down
3 changes: 2 additions & 1 deletion web/client/components/layout/BorderLayout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ import React from 'react';
* /></BorderLayout>
*
*/
export default ({id, children, header, footer, columns, height, style = {}, className, bodyClassName = "ms2-border-layout-body"}) =>
export default ({id, children, header, footer, columns, height, style = {}, className, bodyClassName = "ms2-border-layout-body", isDashboard }) =>
(<div id={id} className={className} style={{
display: "flex",
flexDirection: "column",
width: "100%",
height: "100%",
overflow: "hidden",
paddingRight: isDashboard ? "1rem" : "auto",
...style
}}>
{header}
Expand Down
5 changes: 3 additions & 2 deletions web/client/components/misc/panels/DockPanel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,10 @@ export default withState('fullscreen', 'onFullscreen', false)(
onFullscreen = () => {},
fixed = false,
resizable = false,
hideHeader
hideHeader,
isDashboard
}) =>
<div className={'ms-side-panel ' + (!fixed ? 'ms-absolute-dock ' : '') + (!resizable ? 'react-dock-no-resize ' : '') + className}>
<div className={'ms-side-panel ' + (!fixed ? 'ms-absolute-dock ' : '') + (!resizable ? 'react-dock-no-resize ' : '') + (isDashboard ? 'ms-dashboard-opened ' : '') + className}>
<Dock
fluid={fluid || fullscreen}
position={position}
Expand Down
2 changes: 1 addition & 1 deletion web/client/components/resources/ResourceGrid.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export default ({
edit,
nameFieldFilter,
category: categoryName,
enableDetails: categoryName === 'MAP',
enableDetails: categoryName === 'MAP' || categoryName === 'DASHBOARD',
onResourceLoad
// resource
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ export default mapPropsStream(props$ => {
.withLatestFrom(props$)
.switchMap(([resource, props]) =>
updateResource(resource)
.flatMap(rid => resource.category === 'MAP' ? updateResourceAttribute({
.flatMap(rid => updateResourceAttribute({
id: rid,
name: 'detailsSettings',
value: JSON.stringify(resource.attributes?.detailsSettings || {})
}) : Rx.Observable.of(rid))
}))
.do(() => {
if (props) {
if (props.onClose) {
Expand Down
10 changes: 9 additions & 1 deletion web/client/configs/localConfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,15 @@
"FeedbackMask"
],
"dashboard": [
"BurgerMenu",
"Details",
"AddWidgetDashboard",
"MapConnectionDashboard",
{
"name": "SidebarMenu",
"cfg" : {
"containerPosition": "columns"
}
},
"Dashboard",
"Notifications",
"Login",
Expand Down
107 changes: 105 additions & 2 deletions web/client/epics/__tests__/config-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import expect from 'expect';
import {head} from 'lodash';
import {loadMapConfigAndConfigureMap, loadMapInfoEpic, storeDetailsInfoEpic} from '../config';
import {loadMapConfigAndConfigureMap, loadMapInfoEpic, storeDetailsInfoDashboardEpic, storeDetailsInfoEpic} from '../config';
import {LOAD_USER_SESSION} from '../../actions/usersession';
import {
loadMapConfig,
Expand All @@ -30,6 +30,7 @@ import testConfigEPSG31468 from "raw-loader!../../test-resources/testConfigEPSG3
import ConfigUtils from "../../utils/ConfigUtils";
import { DETAILS_LOADED } from '../../actions/details';
import { EMPTY_RESOURCE_VALUE } from '../../utils/MapInfoUtils';
import { dashboardLoaded } from '../../actions/dashboard';

const api = {
getResource: () => Promise.resolve({mapId: 1234})
Expand Down Expand Up @@ -345,7 +346,7 @@ describe('config epics', () => {

switch (action.type) {
case DETAILS_LOADED:
expect(action.mapId).toBe(mapId);
expect(action.id).toBe(mapId);
expect(action.detailsUri).toBe("rest/geostore/data/1/raw?decode=datauri");
break;
default:
Expand Down Expand Up @@ -379,5 +380,107 @@ describe('config epics', () => {
}});
});
});

describe("storeDetailsInfoDashboardEpic", () => {
beforeEach(done => {
mockAxios = new MockAdapter(axios);
setTimeout(done);
});

afterEach(done => {
mockAxios.restore();
setTimeout(done);
});
const dashboardId = 1;
const dashboardAttributesEmptyDetails = {
"AttributeList": {
"Attribute": [
{
"name": "details",
"type": "STRING",
"value": EMPTY_RESOURCE_VALUE
}
]
}
};

const dashboardAttributesWithoutDetails = {
"AttributeList": {
"Attribute": []
}
};

const dashboardAttributesWithDetails = {
AttributeList: {
Attribute: [
{
name: 'details',
type: 'STRING',
value: 'rest\/geostore\/data\/1\/raw?decode=datauri'
},
{
name: "thumbnail",
type: "STRING",
value: 'rest\/geostore\/data\/1\/raw?decode=datauri'
},
{
name: 'owner',
type: 'STRING',
value: 'admin'
}
]
}
};
it('test storeDetailsInfoDashboardEpic', (done) => {
mockAxios.onGet().reply(200, dashboardAttributesWithDetails);
testEpic(addTimeoutEpic(storeDetailsInfoDashboardEpic), 1, dashboardLoaded("RES", "DATA"), actions => {
expect(actions.length).toBe(1);
actions.map((action) => {

switch (action.type) {
case DETAILS_LOADED:
expect(action.id).toBe(dashboardId);
expect(action.detailsUri).toBe("rest/geostore/data/1/raw?decode=datauri");
break;
default:
expect(true).toBe(false);
}
});
done();
}, {dashboard: {
resource: {
id: dashboardId,
attributes: {}
}
}});
});
it('test storeDetailsInfoDashboardEpic when api returns NODATA value', (done) => {
// const mock = new MockAdapter(axios);
mockAxios.onGet().reply(200, dashboardAttributesWithoutDetails);
testEpic(addTimeoutEpic(storeDetailsInfoDashboardEpic), 1, dashboardLoaded("RES", "DATA"), actions => {
expect(actions.length).toBe(1);
actions.map((action) => expect(action.type).toBe(TEST_TIMEOUT));
done();
}, {dashboard: {
resource: {
id: dashboardId,
attributes: {}
}
}});
});
it('test storeDetailsInfoDashboardEpic when api doesnt return details', (done) => {
mockAxios.onGet().reply(200, dashboardAttributesEmptyDetails);
testEpic(addTimeoutEpic(storeDetailsInfoDashboardEpic), 1, dashboardLoaded("RES", "DATA"), actions => {
expect(actions.length).toBe(1);
actions.map((action) => expect(action.type).toBe(TEST_TIMEOUT));
done();
}, {dashboard: {
resource: {
id: dashboardId,
attributes: {}
}
}});
});
});
});

30 changes: 15 additions & 15 deletions web/client/epics/__tests__/dashboard-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -338,16 +338,16 @@ describe('saveDashboard', () => {

const startActions = [saveDashboard(RESOURCE)];
testEpic(saveDashboardMethod, actionsCount, startActions, actions => {
expect(actions.length).toBe(actionsCount);
expect(actions[0].type).toBe(DASHBOARD_LOADING);
expect(actions[0].value).toBe(true);
expect(actions[1].type).toBe(SAVE_ERROR);
expect(actions.length).toBe(2);
// expect(actions[0].type).toBe(DASHBOARD_LOADING);
// expect(actions[0].value).toBe(true);
expect(actions[0].type).toBe(SAVE_ERROR);
expect(
actions[1].error.status === 403
|| actions[1].error.status === 404
actions[0].error.status === 403
|| actions[0].error.status === 404
).toBeTruthy();
expect(actions[2].type).toBe(DASHBOARD_LOADING);
expect(actions[2].value).toBe(false);
expect(actions[1].type).toBe(DASHBOARD_LOADING);
expect(actions[1].value).toBe(false);
}, BASE_STATE, done);
});

Expand All @@ -364,13 +364,13 @@ describe('saveDashboard', () => {

const startActions = [saveDashboard(withoutMetadata)];
testEpic(saveDashboardMethod, actionsCount, startActions, actions => {
expect(actions.length).toBe(3);
expect(actions[0].type).toBe(DASHBOARD_LOADING);
expect(actions[0].value).toBe(true);
expect(actions[1].type).toBe(SAVE_ERROR);
expect(typeof(actions[1].error) === 'string').toBeTruthy();
expect(actions[2].type).toBe(DASHBOARD_LOADING);
expect(actions[2].value).toBe(false);
expect(actions.length).toBe(2);
// expect(actions[0].type).toBe(DASHBOARD_LOADING);
// expect(actions[0].value).toBe(true);
expect(actions[0].type).toBe(SAVE_ERROR);
expect(typeof(actions[0].error) === 'string').toBeTruthy();
expect(actions[1].type).toBe(DASHBOARD_LOADING);
expect(actions[1].value).toBe(false);
}, BASE_STATE, done);
});
});
Expand Down
Loading

0 comments on commit 51fc25e

Please sign in to comment.