Skip to content

Commit da1e7ba

Browse files
Merge pull request #116 from geoCML/frontend-mobile-fixes
Fix mobile frontend issues
2 parents 1e64ac1 + 8f11078 commit da1e7ba

File tree

7 files changed

+141
-88
lines changed

7 files changed

+141
-88
lines changed

build-resources/geocml-server/portal/src/App.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,18 @@ import { collectInfoFromWMS } from "./utils/wms.util";
66
import { HostedLayers } from "./components/HostedLayers";
77
import { reportInvalidWMS, showWebMap } from "./app-slice";
88
import { Recommendations } from "./components/Recommendations";
9+
import { setIsMobile } from "./app-slice";
910

1011
export default function App() {
1112
const dispatch = useDispatch();
1213
const wmsInfo = useSelector((state) => state.app.wmsInfo);
1314
const wmsInfoValid = useSelector((state) => state.app.wmsInfoValid);
1415
const layers = useSelector((state) => state.app.layers);
16+
const isMobile = useSelector((state) => state.app.isMobile);
1517

1618
useEffect(() => {
1719
collectInfoFromWMS(dispatch);
20+
if (window.innerWidth <= 768) dispatch(setIsMobile())
1821
}, []);
1922

2023
if (wmsInfoValid) {
@@ -141,13 +144,13 @@ export default function App() {
141144
alt="Map Preview"
142145
className="w-100"
143146
/>
144-
<p className="pt-3" id="description">
147+
<p className="pt-3 w-100 text-break" id="description">
145148
{wmsInfo.WMS_Capabilities.Service.Abstract}
146149
</p>
147150
</div>
148151
</div>
149-
<Recommendations/>
150-
</div>
152+
<Recommendations/>
153+
</div>
151154
);
152155
} catch (err) {
153156
console.log(err);
@@ -169,6 +172,7 @@ export default function App() {
169172
Deployment because of an invalid WMS configuration.
170173
</p>
171174
</div>
175+
{ !isMobile ? (
172176
<div className="row">
173177
<p className="py-4 text-center">
174178
Follow these instructions to configure geoCML Server Portal:
@@ -231,6 +235,9 @@ export default function App() {
231235
<li>Click OK.</li>
232236
</ol>
233237
</div>
238+
) : (
239+
<div></div>
240+
) }
234241
</div>
235242
);
236243
}

build-resources/geocml-server/portal/src/app-slice.js

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@ export const appSlice = createSlice({
77
wmsInfo: {},
88
wmsInfoValid: true,
99
webMapVisible: false,
10+
layersPaneVisible: false,
11+
legendVisible: false,
12+
isMobile: false,
1013
layers: [],
11-
recommendations: []
14+
recommendations: []
1215
},
1316

1417
reducers: {
@@ -44,15 +47,27 @@ export const appSlice = createSlice({
4447
state.layers = action.payload;
4548
},
4649

47-
setRecommendations: (state, action) => {
48-
state.recommendations = action.payload
49-
},
50+
setRecommendations: (state, action) => {
51+
state.recommendations = action.payload;
52+
},
53+
54+
toggleLayersPane: (state) => {
55+
state.layersPaneVisible = !state.layersPaneVisible;
56+
},
57+
58+
toggleLegend: (state) => {
59+
state.legendVisible = !state.legendVisible;
60+
},
5061

5162
toggleLayer: (state, action) => {
5263
for (const layer of state.layers) {
5364
if (layer.name === action.payload) layer.visible = !layer.visible;
5465
}
5566
},
67+
68+
setIsMobile: (state) => {
69+
state.isMobile = true;
70+
}
5671
},
5772
});
5873

@@ -67,6 +82,9 @@ export const {
6782
showWebMap,
6883
hideWebMap,
6984
toggleLayer,
85+
toggleLayersPane,
86+
toggleLegend,
87+
setIsMobile
7088
} = appSlice.actions;
7189

7290
export default appSlice.reducer;

build-resources/geocml-server/portal/src/components/HostedLayers.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export function HostedLayers() {
99
return (
1010
<div className="px-2 py-5">
1111
<h3 className="row justify-content-center">Hosted Layers</h3>
12-
<table className="table table-responsive py-2">
12+
<table className="table py-2">
1313
<thead>
1414
<tr>
1515
<th>Layer Name</th>
@@ -26,7 +26,7 @@ export function HostedLayers() {
2626
type="button"
2727
className="btn btn-light border"
2828
style={{
29-
width: "225px",
29+
width: "100%",
3030
}}
3131
href={`/cgi-bin/qgis_mapserv.fcgi?SERVICE=WFS&VERSION=1.3.0&REQUEST=GetFeature&TYPENAME=${layer.name}`}
3232
>

build-resources/geocml-server/portal/src/components/LayersPane.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ export function LayersPane() {
1010
id="layers-pane"
1111
className="position-absolute bg-light rounded p-2 overflow-auto"
1212
style={{
13-
bottom: 0,
13+
bottom: 70,
1414
zIndex: 99,
15-
maxHeight: "40%",
16-
maxWidth: "20%",
15+
maxHeight: "43%",
16+
maxWidth: "50%",
1717
}}
1818
>
1919
{layers.map((layer) => {

build-resources/geocml-server/portal/src/components/Legend.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@ export function Legend() {
88
id="legend"
99
className="position-absolute bg-light rounded p-2 overflow-auto"
1010
style={{
11-
bottom: "25px",
12-
right: 0,
11+
bottom: 70,
12+
right: 0,
1313
zIndex: 99,
1414
maxHeight: "40%",
15-
maxWidth: "20%",
15+
maxWidth: "30%",
1616
}}
1717
>
18-
<img src={`/cgi-bin/qgis_mapserv.fcgi?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetLegendGraphic&FORMAT=image%2Fpng&TRANSPARENT=true&LAYERTITLE=true&RULELABEL=true&LAYERS=${layers.map((layer) => {
19-
return layer.name
20-
}).reverse().join(",")}`} alt="Legend"/>
18+
<img className="w-100" src={`/cgi-bin/qgis_mapserv.fcgi?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetLegendGraphic&FORMAT=image%2Fpng&TRANSPARENT=true&LAYERTITLE=true&RULELABEL=true&LAYERS=${layers.map((layer) => {
19+
return layer.name
20+
}).reverse().join(",")}`} alt="Legend"/>
2121
</div>
2222
);
2323
}

build-resources/geocml-server/portal/src/components/Recommendations.js

Lines changed: 48 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -4,77 +4,59 @@ import { useEffect } from "react";
44
import { useDispatch, useSelector } from "react-redux";
55

66
export function collectRecommendations(dispatch, wmsInfo) {
7-
const tags = []
8-
for (const [_, value] of Object.entries(wmsInfo.WMS_Capabilities.Service.KeywordList)) {
9-
for (let i = 1; i < value.length; i++) {
10-
tags.push(value[i])
11-
}
12-
}
7+
const tags = []
8+
for (const [_, value] of Object.entries(wmsInfo.WMS_Capabilities.Service.KeywordList)) {
9+
for (let i = 1; i < value.length; i++) {
10+
tags.push(value[i])
11+
}
12+
}
1313

14-
axios.get(`${process.env.REACT_APP_DRGON_HOST}/recommendations`, {
15-
params: {
16-
"tags": tags.join(","),
17-
"limit": 10
18-
}
19-
}).then((res) => {
20-
dispatch(setRecommendations(res.data.deployments))
21-
})
14+
axios.get(`${process.env.REACT_APP_DRGON_HOST}/recommendations`, {
15+
params: {
16+
"tags": tags.join(","),
17+
"limit": 10
18+
}
19+
}).then((res) => {
20+
dispatch(setRecommendations(res.data.deployments))
21+
})
2222
}
2323

2424
export function Recommendations() {
25-
const dispatch = useDispatch()
26-
const wmsInfo = useSelector((state) => state.app.wmsInfo)
27-
const recommendations = useSelector((state) => state.app.recommendations)
25+
const dispatch = useDispatch()
26+
const wmsInfo = useSelector((state) => state.app.wmsInfo)
27+
const recommendations = useSelector((state) => state.app.recommendations)
2828

29-
useEffect(() => {
30-
collectRecommendations(dispatch, wmsInfo)
31-
}, [])
29+
useEffect(() => {
30+
collectRecommendations(dispatch, wmsInfo)
31+
}, [])
3232

33-
return (
34-
recommendations.length > 0 ? (
35-
<div>
36-
<h3 className="row justify-content-center pt-5">Explore Similar Datasets</h3>
37-
<i className="row justify-content-center pb-2">Results powered by DRGON</i>
38-
<table id="drgon-recommendations" className="table table-responsive" style={{ width: "100%" }}>
39-
<thead>
40-
<tr>
41-
<th>Title</th>
42-
<th>Description</th>
43-
<th>Owner</th>
44-
<th>URL</th>
45-
<th>Tags</th>
46-
</tr>
47-
</thead>
48-
<tbody>
49-
{ recommendations.map((recommendation) => {
50-
return (
51-
<tr>
52-
<td>
53-
{recommendation[0].title}
54-
</td>
55-
<td>
56-
{recommendation[0].description}
57-
</td>
58-
<td>
59-
{recommendation[0].owner}
60-
</td>
61-
<td>
62-
<a href={recommendation[0].url}>{recommendation[0].url}</a>
63-
</td>
64-
<td>{recommendation[0].tags.split(",").map((tag) => {
65-
return (
66-
<span className="rounded bg-info p-2 mx-2">{tag}</span>
67-
)
68-
})}</td>
69-
</tr>
70-
)
71-
}) }
72-
</tbody>
73-
</table>
74-
</div>
75-
) : (
76-
<div></div>
77-
)
78-
)
33+
return (
34+
recommendations.length > 0 ? (
35+
<div className="px-2 py-5 table-responsive">
36+
<h3 className="row justify-content-center pt-2">Explore Similar Datasets</h3>
37+
<i className="row justify-content-center pb-3">Results powered by DRGON</i>
38+
<table id="drgon-recommendations" className="table">
39+
<tbody>
40+
{ recommendations.map((recommendation) => {
41+
return (
42+
<tr className="py-2">
43+
<div>
44+
<span className="font-weight-light">
45+
<a href={recommendation[0].url}>{recommendation[0].url}</a> | {recommendation[0].owner}
46+
</span>
47+
<h3>{recommendation[0].title}</h3>
48+
<p>{recommendation[0].description}</p>
49+
<p className="font-italic">Tags: {recommendation[0].tags}</p>
50+
</div>
51+
</tr>
52+
)
53+
}) }
54+
</tbody>
55+
</table>
56+
</div>
57+
) : (
58+
<div></div>
59+
)
60+
)
7961
}
8062

build-resources/geocml-server/portal/src/components/WebMap.js

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { useEffect, useRef } from "react";
22
import { useDispatch, useSelector } from "react-redux";
33
import { LayersPane } from "./LayersPane";
44
import { Legend } from "./Legend";
5-
import { hideWebMap } from "../app-slice";
5+
import { hideWebMap, toggleLayersPane, toggleLegend } from "../app-slice";
66

77
const L = require("leaflet");
88

@@ -11,6 +11,9 @@ export function WebMap() {
1111
const map = useRef(undefined);
1212
const layers = useSelector((state) => state.app.layers);
1313
const webMapVisible = useSelector((state) => state.app.webMapVisible);
14+
const layersPaneVisible = useSelector((state) => state.app.layersPaneVisible)
15+
const legendVisible = useSelector((state) => state.app.legendVisible)
16+
1417

1518
useEffect(() => {
1619
if (webMapVisible) {
@@ -67,9 +70,52 @@ export function WebMap() {
6770
Close
6871
</div>
6972

70-
<LayersPane />
71-
<Legend />
72-
</div>
73+
<div
74+
id="toggle-layers-btn"
75+
className="position-absolute rounded-circle btn btn-light"
76+
style={{
77+
bottom: 25,
78+
left: 10,
79+
zIndex: 99,
80+
}}
81+
onClick= {() => {
82+
dispatch(toggleLayersPane())
83+
}}
84+
>
85+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-layers" viewBox="0 0 16 16">
86+
<path d="M8.235 1.559a.5.5 0 0 0-.47 0l-7.5 4a.5.5 0 0 0 0 .882L3.188 8 .264 9.559a.5.5 0 0 0 0 .882l7.5 4a.5.5 0 0 0 .47 0l7.5-4a.5.5 0 0 0 0-.882L12.813 8l2.922-1.559a.5.5 0 0 0 0-.882zm3.515 7.008L14.438 10 8 13.433 1.562 10 4.25 8.567l3.515 1.874a.5.5 0 0 0 .47 0zM8 9.433 1.562 6 8 2.567 14.438 6z"/>
87+
</svg>
88+
</div>
89+
90+
<div
91+
id="toggle-legend-btn"
92+
className="position-absolute rounded-circle btn btn-light"
93+
style={{
94+
bottom: 25,
95+
right: 10,
96+
zIndex: 99,
97+
}}
98+
onClick= {() => {
99+
dispatch(toggleLegend())
100+
}}
101+
>
102+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-list-ul" viewBox="0 0 16 16">
103+
<path fill-rule="evenodd" d="M5 11.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5m0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5m0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5m-3 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2m0 4a1 1 0 1 0 0-2 1 1 0 0 0 0 2m0 4a1 1 0 1 0 0-2 1 1 0 0 0 0 2"/>
104+
</svg>
105+
</div>
106+
107+
{ layersPaneVisible ? (
108+
<LayersPane />
109+
) : (
110+
<div></div>
111+
) }
112+
113+
{ legendVisible ? (
114+
<Legend />
115+
) : (
116+
<div></div>
117+
) }
118+
</div>
73119
);
74120
}
75121
}

0 commit comments

Comments
 (0)