From 39fc6804939fd6df93eb53eacc7ac6c96320a744 Mon Sep 17 00:00:00 2001 From: Loup Theron Date: Mon, 22 Mar 2021 23:15:52 +0100 Subject: [PATCH 1/3] Add zones selection --- frontend/src/App.css | 10 +- frontend/src/api/fetch.js | 62 ++++++-- .../src/components/DownloadVesselListModal.js | 9 +- frontend/src/components/VesselListTable.js | 6 +- .../AdministrativeZones.js | 9 +- frontend/src/containers/MapWrapper.js | 14 +- frontend/src/containers/VesselList.js | 145 +++++++++++++++--- frontend/src/domain/entities/layers.js | 111 ++++++++++---- frontend/src/domain/reducers/Map.js | 24 ++- .../getAdministrativeZoneGeometry.js | 48 ++++++ frontend/src/domain/use_cases/showLayer.js | 2 +- 11 files changed, 355 insertions(+), 85 deletions(-) create mode 100644 frontend/src/domain/use_cases/getAdministrativeZoneGeometry.js diff --git a/frontend/src/App.css b/frontend/src/App.css index 197041de64..1c03cb2dd8 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -252,7 +252,7 @@ a:hover, a:focus { } .rs-picker-tag > .rs-picker-toggle { - width: 115px; + width: 125px; } .rs-picker-select-menu-item.rs-picker-select-menu-item-active, .rs-picker-select-menu-item.rs-picker-select-menu-item-active:hover, @@ -284,3 +284,11 @@ a:hover, a:focus { margin-top: -1px; margin-left: 5px; } + +.rs-picker-check-menu { + width: 280px; +} + +.rs-picker-tag .rs-tag { + max-width: calc(100% - 25px) !important; +} \ No newline at end of file diff --git a/frontend/src/api/fetch.js b/frontend/src/api/fetch.js index 883cfaf66c..231fc12cc2 100644 --- a/frontend/src/api/fetch.js +++ b/frontend/src/api/fetch.js @@ -104,32 +104,44 @@ export function getAllRegulatoryZonesFromAPI() { } - -export function getAdministrativeZoneFromAPI(type, extent) { - return fetch(getAdministrativeZoneURL(type, extent)) +export function getAdministrativeZoneFromAPI(administrativeZone, extent, subZone) { + return fetch(getAdministrativeZoneURL(administrativeZone, extent, subZone)) .then(response => { if (response.status === HTTP_OK) { return response.json().then(response => { return response }).catch(e => { - throwIrretrievableAdministrativeZoneError(e, type); + throwIrretrievableAdministrativeZoneError(e, administrativeZone); }) } else { response.text().then(response => { - throwIrretrievableAdministrativeZoneError(response, type); + throwIrretrievableAdministrativeZoneError(response, administrativeZone); }) } }).catch(e => { - throwIrretrievableAdministrativeZoneError(e, type); + throwIrretrievableAdministrativeZoneError(e, administrativeZone); }) } -export function getAdministrativeZoneURL(type, extent) { +export function getAdministrativeZoneURL(type, extent, subZone) { + let extentFilter = '' + if(extent) { + extentFilter = `&bbox=${extent.join(',')},${OPENLAYERS_PROJECTION}` + } + + let subZoneFilter = '' + if(subZone) { + let filter = `${subZone.replace(/'/g, '\'\'')}`; + + subZoneFilter = `&featureID=` + filter + .replace(/'/g, '%27') + .replace(/ /g, '%20') + } + return ( `${process.env.REACT_APP_GEOSERVER_LOCAL_URL}/geoserver/wfs?service=WFS&` + `version=1.1.0&request=GetFeature&typename=monitorfish:${type}&` + - `outputFormat=application/json&srsname=${WSG84_PROJECTION}&` + - `bbox=${extent.join(',')},${OPENLAYERS_PROJECTION}` + `outputFormat=application/json&srsname=${WSG84_PROJECTION}` + extentFilter + subZoneFilter ); } @@ -244,3 +256,35 @@ export function getVesselERSMessagesFromAPI(vesselIdentity) { .then(ers => ers) } +export function getAdministrativeSubZonesFromAPI(type) { + let query + if(type === Layers.FAO.code) { + let filter = `f_level='DIVISION'` + + query = `${process.env.REACT_APP_GEOSERVER_LOCAL_URL}/geoserver/wfs?service=WFS&` + + `version=1.1.0&request=GetFeature&typename=monitorfish:${type}&` + + `outputFormat=application/json&srsname=${WSG84_PROJECTION}&CQL_FILTER=` + + filter.replace(/'/g, '%27').replace(/ /g, '%20') + } else { + query = `${process.env.REACT_APP_GEOSERVER_LOCAL_URL}/geoserver/wfs?service=WFS&` + + `version=1.1.0&request=GetFeature&typename=monitorfish:${type}&` + + `outputFormat=application/json&srsname=${WSG84_PROJECTION}`; + } + + return fetch(query) + .then(response => { + if (response.status === HTTP_OK) { + return response.json().then(response => { + return response + }).catch(e => { + throwIrretrievableAdministrativeZoneError(e, type); + }) + } else { + response.text().then(response => { + throwIrretrievableAdministrativeZoneError(response, type); + }) + } + }).catch(e => { + throwIrretrievableAdministrativeZoneError(e, type); + }) +} diff --git a/frontend/src/components/DownloadVesselListModal.js b/frontend/src/components/DownloadVesselListModal.js index a3723a53ce..ba059d182f 100644 --- a/frontend/src/components/DownloadVesselListModal.js +++ b/frontend/src/components/DownloadVesselListModal.js @@ -1,4 +1,4 @@ -import React, {useState} from "react"; +import React, {useEffect, useState} from "react"; import styled from "styled-components"; import Modal from "rsuite/lib/Modal"; import {COLORS} from "../constants/constants"; @@ -92,7 +92,12 @@ function orderToCSVColumnOrder(valuesChecked, filteredVesselObject) { const DownloadVesselListModal = props => { const [indeterminate, setIndeterminate] = useState(false) const [checkAll, setCheckAll] = useState(true) - const [valuesChecked, setValuesChecked] = useState(Object.keys(options).map(value => options[value].code)) + const [valuesChecked, setValuesChecked] = useState([]) + + useEffect(() => { + let values = Object.keys(options).map(value => options[value].code) + setValuesChecked(values ? values : []) + }, []) const handleCheckAll = (value, checked) => { const nextValue = checked ? Object.keys(options).map(value => options[value].code) : []; diff --git a/frontend/src/components/VesselListTable.js b/frontend/src/components/VesselListTable.js index 0f97ea0bb2..0f541313fe 100644 --- a/frontend/src/components/VesselListTable.js +++ b/frontend/src/components/VesselListTable.js @@ -96,7 +96,7 @@ const VesselListTable = props => { { - + Cap - + Vitesse diff --git a/frontend/src/components/administratives_zones/AdministrativeZones.js b/frontend/src/components/administratives_zones/AdministrativeZones.js index bf9fbd3ca4..5926738843 100644 --- a/frontend/src/components/administratives_zones/AdministrativeZones.js +++ b/frontend/src/components/administratives_zones/AdministrativeZones.js @@ -24,9 +24,9 @@ const AdministrativeZones = props => { }, [props.hideZonesListWhenSearching]) useEffect(() => { - let zones = [] + let nextZones = [] if(props.administrativeZones && props.administrativeZones.length) { - zones = props.administrativeZones + nextZones = props.administrativeZones .filter(zone => !zone.group) .map(zone => [zone]) @@ -35,11 +35,10 @@ const AdministrativeZones = props => { .map(zone => zone.group))] groups.forEach(group => { - zones.push(props.administrativeZones + nextZones.push(props.administrativeZones .filter(zone => zone.group && zone.group === group)) }) - setZones(zones) - console.log(zones.length) + setZones(nextZones) } }, [props.administrativeZones]) diff --git a/frontend/src/containers/MapWrapper.js b/frontend/src/containers/MapWrapper.js index cace157c44..a8f246ed6e 100644 --- a/frontend/src/containers/MapWrapper.js +++ b/frontend/src/containers/MapWrapper.js @@ -8,7 +8,7 @@ import TileLayer from 'ol/layer/Tile' import {OSM} from 'ol/source'; import {transform} from 'ol/proj' import {toStringHDMS} from 'ol/coordinate'; -import LayersEnum, {vesselIconIsLight} from "../domain/entities/layers"; +import LayersEnum, {layersType as LayersType, vesselIconIsLight} from "../domain/entities/layers"; import MapCoordinatesBox from "../components/MapCoordinatesBox"; import {Interactions, OPENLAYERS_PROJECTION, WSG84_PROJECTION} from "../domain/entities/map"; import { @@ -28,11 +28,13 @@ import VesselTrackCard from "../components/VesselTrackCard"; import showVesselTrackAndSidebar from "../domain/use_cases/showVesselTrackAndSidebar"; import {useDispatch, useSelector} from "react-redux"; import { + addZoneSelected, hideVesselNames, isMoving, resetAnimateToRegulatoryLayer, - resetAnimateToVessel, resetInteraction, - setView, setZoneSelected + resetAnimateToVessel, + resetInteraction, + setView } from "../domain/reducers/Map"; import {COLORS} from "../constants/constants"; import {updateVesselFeatureAndIdentity} from "../domain/reducers/Vessel"; @@ -371,7 +373,11 @@ const MapWrapper = () => { map.addInteraction(draw) draw.on('drawend', event => { - dispatch(setZoneSelected(event.feature)) + dispatch(addZoneSelected({ + name: "Tracé libre", + code: LayersType.FREE_DRAW, + feature: event.feature + })) dispatch(resetInteraction()) map.removeInteraction(draw) }) diff --git a/frontend/src/containers/VesselList.js b/frontend/src/containers/VesselList.js index f562b88910..922136e7eb 100644 --- a/frontend/src/containers/VesselList.js +++ b/frontend/src/containers/VesselList.js @@ -7,18 +7,20 @@ import {ReactComponent as BoxFilterSVG} from '../components/icons/Filtre_zone_re import {ReactComponent as PolygonFilterSVG} from '../components/icons/Filtre_zone_polygone.svg'; import {ReactComponent as CloseIconSVG} from '../components/icons/Croix_grise_clair.svg'; import {COLORS} from "../constants/constants"; -import LayersEnum from "../domain/entities/layers"; +import LayersEnum, {layersType as LayersType, layersType} from "../domain/entities/layers"; import Modal from "rsuite/lib/Modal"; import TagPicker from "rsuite/lib/TagPicker"; import Tag from "rsuite/lib/Tag"; import SelectPicker from "rsuite/lib/SelectPicker"; -import {resetZoneSelected, setInteraction} from "../domain/reducers/Map"; +import {removeZoneSelected, resetZonesSelected, setInteraction, setZonesSelected} from "../domain/reducers/Map"; import {Interactions, OPENLAYERS_PROJECTION} from "../domain/entities/map"; import {resetTemporaryVesselsToHighLightOnMap, setTemporaryVesselsToHighLightOnMap} from "../domain/reducers/Vessel"; import VesselListTable from "../components/VesselListTable"; import DownloadVesselListModal from "../components/DownloadVesselListModal"; import countries from "i18n-iso-countries"; import {getCoordinates} from "../utils"; +import getAdministrativeZoneGeometry from "../domain/use_cases/getAdministrativeZoneGeometry"; +import {getAdministrativeSubZonesFromAPI} from "../api/fetch"; countries.registerLocale(require("i18n-iso-countries/langs/fr.json")); @@ -40,16 +42,53 @@ const VesselList = () => { const [vesselsCountShowed, setVesselsCountShowed] = useState(0) const [allVesselsChecked, setAllVesselsChecked] = useState({ globalCheckbox: true }) const [makeVesselListToNotUpdate, setMakeVesselListToNotUpdate] = useState(false) + const [zonesFilter, setZonesFilter] = useState([]) // Filters const [countriesFiltered, setCountriesFiltered] = useState([]) const [lastPositionTimeAgoFilter, setLastPositionTimeAgoFilter] = useState(2) - const zoneSelected = useSelector(state => state.map.zoneSelected) + const [administrativeZonesFiltered, setAdministrativeZonesFiltered] = useState([]) + const zonesSelected = useSelector(state => state.map.zonesSelected) useEffect(() => { if (vesselListModalIsOpen === true) { firstUpdate.current = false } + + const nextZonesPromises = Object.keys(LayersEnum) + .map(layerName => LayersEnum[layerName]) + .filter(layer => layer.type === layersType.ADMINISTRATIVE) + .map(zone => { + if(zone.containsMultipleZones) { + return getAdministrativeSubZonesFromAPI(zone.code).then(subZonesFeatures => { + return subZonesFeatures.features.map(subZone => { + return { + group: zone.name, + groupCode: zone.code, + label: subZone.properties[zone.subZoneFieldKey] ? subZone.properties[zone.subZoneFieldKey].replace(/[_]/g, ' ') : "Aucun nom", + name: subZone.properties[zone.subZoneFieldKey] ? subZone.properties[zone.subZoneFieldKey].replace(/[_]/g, ' ') : "Aucun nom", + code: subZone.id, + value: subZone.id, + isSubZone: true + } + }) + }) + } + + let nextZone = {...zone} + + nextZone.label = zone.name + nextZone.value = zone.code + nextZone.group = zone.group ? zone.group.name : 'Administratives' + + return nextZone + }) + + Promise.all(nextZonesPromises).then((nextZones) => { + setZonesFilter(nextZones.flat()) + }); + + }, [vesselListModalIsOpen]) useEffect(() => { @@ -62,7 +101,7 @@ const VesselList = () => { let coordinates = [...vessel.getGeometry().getCoordinates()] return { - targetNumber: null, + targetNumber: undefined, id: vessel.id_, checked: true, vesselName: vessel.getProperties().vesselName, @@ -107,17 +146,18 @@ const VesselList = () => { }) } - if(zoneSelected) { + if(zonesSelected && zonesSelected.length) { filteredVessels = filteredVessels.filter(vessel => { - return zoneSelected.getGeometry().intersectsCoordinate(vessel.olCoordinates) - }) - + return zonesSelected.some(zoneSelected => zoneSelected.feature.getGeometry() + .intersectsCoordinate(vessel.olCoordinates)) + }).filter((zone, index, acc) => acc + .findIndex(existingZone => (existingZone.id === zone.id)) === index) } setFilteredVessels(filteredVessels) setVesselsCountShowed(filteredVessels.length) } - }, [countriesFiltered, lastPositionTimeAgoFilter, zoneSelected, vessels]) + }, [countriesFiltered, lastPositionTimeAgoFilter, zonesSelected, vessels]) useEffect(() => { let nextVessels = vessels.map(vessel => { @@ -140,8 +180,9 @@ const VesselList = () => { setVesselListModalIsOpen(false) setMakeVesselListToNotUpdate(false) setCountriesFiltered([]) + setAdministrativeZonesFiltered([]) setLastPositionTimeAgoFilter(2) - dispatch(resetZoneSelected(null)) + dispatch(resetZonesSelected()) } const getCountries = () => { @@ -173,19 +214,27 @@ const VesselList = () => { setVesselListModalIsOpen(true) } - const callResetZoneSelected = () => { - dispatch(resetZoneSelected()) + const callRemoveZoneSelected = zoneSelectedToRemove => { + dispatch(removeZoneSelected(zoneSelectedToRemove.name)) } const download = () => { setDownloadVesselListModalIsOpen(true) } + const callGetAdministrativeZoneGeometry = (administrativeZones, administrativeZone) => { + if(administrativeZone.isSubZone) { + dispatch(getAdministrativeZoneGeometry(administrativeZone.groupCode, administrativeZone.code, administrativeZone.name)) + } else { + dispatch(getAdministrativeZoneGeometry(administrativeZone.code, null, administrativeZone.name)) + } + } + useEffect(() => { - if(zoneSelected) { + if(zonesSelected && zonesSelected.length) { setVesselListModalIsOpen(true) } - }, [zoneSelected]) + }, [zonesSelected]) useEffect(() => { if(temporaryVesselsToHighLightOnMap && temporaryVesselsToHighLightOnMap.length) { @@ -197,6 +246,24 @@ const VesselList = () => { } }, [temporaryVesselsToHighLightOnMap]) + useEffect(() => { + if(zonesSelected && zonesSelected.length && + administrativeZonesFiltered && + zonesSelected.length > administrativeZonesFiltered.length) { + + const nextZonesSelected = zonesSelected.filter(zoneSelected => { + if(zoneSelected.code === 'FREE_DRAW') { + return true + } + + return administrativeZonesFiltered + .find(zoneFiltered => zoneFiltered === zoneSelected.code) + }) + + dispatch(setZonesSelected(nextZonesSelected)) + } + }, [administrativeZonesFiltered]) + const getLastPositionTimeAgo = () => { return [ { @@ -271,7 +338,7 @@ const VesselList = () => { { @@ -291,15 +358,43 @@ const VesselList = () => { }} /> - Définir une zone + setAdministrativeZonesFiltered([])} + onChange={change => setAdministrativeZonesFiltered(change)} + groupBy="group" + preventOverflow + placeholder="Zone" + renderMenuItem={(name, item) => { + return ( + + ); + }} + onSelect={(change, item) => callGetAdministrativeZoneGeometry(change, item)} + renderValue={(values, items, tags) => { + return items.map((tag, index) => ( + + {tag.name} + + )); + }} + virtualized + /> + ou définir une zone selectBox()}/> selectPolygon()}/> { - zoneSelected ? - - Zone : tracé libre - callResetZoneSelected()}/> - : null + zonesSelected && zonesSelected.length && zonesSelected.find(zone => zone.code === LayersType.FREE_DRAW) ? + zonesSelected.filter(zone => zone.code === LayersType.FREE_DRAW).map(zoneSelected => { + return + Effacer la zone définie + callRemoveZoneSelected(zoneSelected)}/> + + }) : null } @@ -344,12 +439,11 @@ const VesselList = () => { const ZoneSelected = styled.span` background: ${COLORS.grayBackground}; - border: 1px solid ${COLORS.grayDarker}; - border-radius: 12px; + border-radius: 2px; color: ${COLORS.textGray}; margin-left: 10px; font-size: 13px; - padding: 3px 3px 3px 3px; + padding: 3px 3px 3px 5px; vertical-align: super; ` @@ -423,7 +517,7 @@ const DownloadButton = styled.button` const ZoneFilter = styled.div` display: inline-block; margin-right: 20px; - margin-left: 50px; + margin-left: 10px; font-size: 13px; vertical-align: sub; ` @@ -515,6 +609,7 @@ const PolygonFilter = styled(PolygonFilterSVG)` height: 30px; cursor: pointer; margin-left: 10px; + margin-right: 10px; vertical-align: text-bottom; ` diff --git a/frontend/src/domain/entities/layers.js b/frontend/src/domain/entities/layers.js index b88aec2502..d87697f1ea 100644 --- a/frontend/src/domain/entities/layers.js +++ b/frontend/src/domain/entities/layers.js @@ -17,7 +17,8 @@ export const layersType = { VESSEL: 'VESSEL', ADMINISTRATIVE: 'ADMINISTRATIVE', REGULATORY: 'REGULATORY', - BASE_LAYER: 'BASE_LAYER' + BASE_LAYER: 'BASE_LAYER', + FREE_DRAW: 'FREE_DRAW' } export default { @@ -25,163 +26,217 @@ export default { code: 'ol-layer', name: '', group: null, - type: layersType.BASE_LAYER + type: layersType.BASE_LAYER, + containsMultipleZones: false, + subZoneFieldKey: null }, VESSELS: { code: 'vessels', name: '', group: null, - type: layersType.VESSEL + type: layersType.VESSEL, + containsMultipleZones: false, + subZoneFieldKey: null }, VESSEL_TRACK: { code: 'vessel_track', name: '', group: null, - type: layersType.VESSEL + type: layersType.VESSEL, + containsMultipleZones: false, + subZoneFieldKey: null }, REGULATORY: { code: 'regulatory_areas', name: '', group: null, - type: layersType.REGULATORY + type: layersType.REGULATORY, + containsMultipleZones: false, + subZoneFieldKey: null }, EEZ: { code: 'eez_areas', name: 'Zones ZEE', group: null, - type: layersType.ADMINISTRATIVE + type: layersType.ADMINISTRATIVE, + containsMultipleZones: false, + subZoneFieldKey: null }, FAO: { code: 'fao_areas', name: 'Zones FAO/CIEM', group: null, - type: layersType.ADMINISTRATIVE + type: layersType.ADMINISTRATIVE, + containsMultipleZones: true, + subZoneFieldKey: 'f_division' }, THREE_MILES: { code: '3_miles_areas', name: '3 Milles', group: null, - type: layersType.ADMINISTRATIVE + type: layersType.ADMINISTRATIVE, + containsMultipleZones: false, + subZoneFieldKey: null }, SIX_MILES: { code: '6_miles_areas', name: '6 Milles', group: null, - type: layersType.ADMINISTRATIVE + type: layersType.ADMINISTRATIVE, + containsMultipleZones: false, + subZoneFieldKey: null }, TWELVE_MILES: { code: '12_miles_areas', name: '12 Milles', group: null, - type: layersType.ADMINISTRATIVE + type: layersType.ADMINISTRATIVE, + containsMultipleZones: false, + subZoneFieldKey: null }, eaux_occidentales_australes: { code: '1241_eaux_occidentales_australes_areas', name: 'Eaux occidentales australes', group: layersGroups.TWELVE_FORTY_ONE, - type: layersType.ADMINISTRATIVE + type: layersType.ADMINISTRATIVE, + containsMultipleZones: false, + subZoneFieldKey: null }, eaux_occidentales_septentrionales: { code: '1241_eaux_occidentales_septentrionales_areas', name: 'Eaux occidentales septentrionales', group: layersGroups.TWELVE_FORTY_ONE, - type: layersType.ADMINISTRATIVE + type: layersType.ADMINISTRATIVE, + containsMultipleZones: false, + subZoneFieldKey: null }, eaux_union_dans_oi_et_atl_ouest: { code: '1241_eaux_union_dans_oi_et_atl_ouest_areas', name: 'Eaux union dans oi et atl ouest', group: layersGroups.TWELVE_FORTY_ONE, - type: layersType.ADMINISTRATIVE + type: layersType.ADMINISTRATIVE, + containsMultipleZones: false, + subZoneFieldKey: null }, mer_baltique: { code: '1241_mer_baltique_areas', name: 'Mer baltique', group: layersGroups.TWELVE_FORTY_ONE, - type: layersType.ADMINISTRATIVE + type: layersType.ADMINISTRATIVE, + containsMultipleZones: false, + subZoneFieldKey: null }, mer_du_nord: { code: '1241_mer_du_nord_areas', name: 'Mer du nord', group: layersGroups.TWELVE_FORTY_ONE, - type: layersType.ADMINISTRATIVE + type: layersType.ADMINISTRATIVE, + containsMultipleZones: false, + subZoneFieldKey: null }, mer_mediterranee: { code: '1241_mer_mediterranee_areas', name: 'Mer mediterranee', group: layersGroups.TWELVE_FORTY_ONE, - type: layersType.ADMINISTRATIVE + type: layersType.ADMINISTRATIVE, + containsMultipleZones: false, + subZoneFieldKey: null }, mer_noire: { code: '1241_mer_noire_areas', name: 'Mer noire', group: layersGroups.TWELVE_FORTY_ONE, - type: layersType.ADMINISTRATIVE + type: layersType.ADMINISTRATIVE, + containsMultipleZones: false, + subZoneFieldKey: null }, cormoran: { code: 'cormoran_areas', name: 'Cormoran', group: null, - type: layersType.ADMINISTRATIVE + type: layersType.ADMINISTRATIVE, + containsMultipleZones: true, + subZoneFieldKey: 'zonex' }, CCAMLR: { code: 'fao_ccamlr_areas', name: 'CCAMLR', group: layersGroups.ORGP, - type: layersType.ADMINISTRATIVE + type: layersType.ADMINISTRATIVE, + containsMultipleZones: false, + subZoneFieldKey: null }, ICCAT: { code: 'fao_iccat_areas', name: 'ICCAT', group: layersGroups.ORGP, - type: layersType.ADMINISTRATIVE + type: layersType.ADMINISTRATIVE, + containsMultipleZones: false, + subZoneFieldKey: null }, IOTC: { code: 'fao_iotc_areas', name: 'IOTC', group: layersGroups.ORGP, - type: layersType.ADMINISTRATIVE + type: layersType.ADMINISTRATIVE, + containsMultipleZones: false, + subZoneFieldKey: null }, NEAFC: { code: 'fao_neafc_areas', name: 'NEAFC', group: layersGroups.ORGP, - type: layersType.ADMINISTRATIVE + type: layersType.ADMINISTRATIVE, + containsMultipleZones: false, + subZoneFieldKey: null }, SIOFA: { code: 'fao_siofa_areas', name: 'SIOFA', group: layersGroups.ORGP, - type: layersType.ADMINISTRATIVE + type: layersType.ADMINISTRATIVE, + containsMultipleZones: false, + subZoneFieldKey: null }, rectangles_stat: { code: 'rectangles_stat_areas', name: 'Rectangles stat', group: null, - type: layersType.ADMINISTRATIVE + type: layersType.ADMINISTRATIVE, + containsMultipleZones: false, + subZoneFieldKey: null }, situation_atlant: { code: 'situ_atlant_areas', name: 'Situation atlantique', group: layersGroups.VMS_SITUATION, - type: layersType.ADMINISTRATIVE + type: layersType.ADMINISTRATIVE, + containsMultipleZones: true, + subZoneFieldKey: 'libelle' }, situation_med: { code: 'situ_med_areas', name: 'Situation med', group: layersGroups.VMS_SITUATION, - type: layersType.ADMINISTRATIVE + type: layersType.ADMINISTRATIVE, + containsMultipleZones: true, + subZoneFieldKey: 'libelle' }, situation_memn: { code: 'situ_memn_areas', name: 'Situation MEMN', group: layersGroups.VMS_SITUATION, - type: layersType.ADMINISTRATIVE + type: layersType.ADMINISTRATIVE, + containsMultipleZones: true, + subZoneFieldKey: 'libelle' }, situation_outre_mer: { code: 'situ_outre_mer_areas', name: 'Situation outre mer', group: layersGroups.VMS_SITUATION, - type: layersType.ADMINISTRATIVE + type: layersType.ADMINISTRATIVE, + containsMultipleZones: true, + subZoneFieldKey: 'libelle' }, } diff --git a/frontend/src/domain/reducers/Map.js b/frontend/src/domain/reducers/Map.js index 55b5d62064..e0ad4acf15 100644 --- a/frontend/src/domain/reducers/Map.js +++ b/frontend/src/domain/reducers/Map.js @@ -26,7 +26,7 @@ const mapSlice = createSlice({ vesselNamesHiddenByZoom: undefined, isMoving: false, interaction: null, - zoneSelected: null, + zonesSelected: [], selectedBaseLayer: getLocalStorageState(baseLayers.OSM.code, baseLayerLocalStorageKey), view: getLocalStorageState({ zoom: null, @@ -82,11 +82,19 @@ const mapSlice = createSlice({ resetInteraction(state) { state.interaction = null }, - setZoneSelected(state, action) { - state.zoneSelected = action.payload + addZoneSelected(state, action) { + state.zonesSelected = state.zonesSelected.concat(action.payload) }, - resetZoneSelected(state) { - state.zoneSelected = null + removeZoneSelected(state, action) { + state.zonesSelected = state.zonesSelected.filter(zoneSelected => { + return zoneSelected.name !== action.payload + }) + }, + setZonesSelected(state, action) { + state.zonesSelected = action.payload + }, + resetZonesSelected(state) { + state.zonesSelected = [] } } }) @@ -106,8 +114,10 @@ export const { selectBaseLayer, setInteraction, resetInteraction, - setZoneSelected, - resetZoneSelected + addZoneSelected, + setZonesSelected, + removeZoneSelected, + resetZonesSelected } = mapSlice.actions export default mapSlice.reducer diff --git a/frontend/src/domain/use_cases/getAdministrativeZoneGeometry.js b/frontend/src/domain/use_cases/getAdministrativeZoneGeometry.js new file mode 100644 index 0000000000..00f5df1d1c --- /dev/null +++ b/frontend/src/domain/use_cases/getAdministrativeZoneGeometry.js @@ -0,0 +1,48 @@ +import VectorSource from "ol/source/Vector"; +import GeoJSON from "ol/format/GeoJSON"; +import {OPENLAYERS_PROJECTION, WSG84_PROJECTION} from "../entities/map"; +import {getAdministrativeZoneFromAPI} from "../../api/fetch"; +import {all} from "ol/loadingstrategy"; +import {setError} from "../reducers/Global"; +import {addZoneSelected} from "../reducers/Map"; + +const IRRETRIEVABLE_FEATURES_EVENT = 'IRRETRIEVABLE_FEATURES' + +const setIrretrievableFeaturesEvent = error => { + return { + type: IRRETRIEVABLE_FEATURES_EVENT, + error: error + } +} + +const getAdministrativeZoneGeometry = (administrativeZoneCode, subZoneCode, zoneName) => (dispatch) => { + let vectorSource = new VectorSource({ + format: new GeoJSON({ + dataProjection: WSG84_PROJECTION, + featureProjection: OPENLAYERS_PROJECTION + }), + strategy: all, + }) + + getAdministrativeZoneFromAPI(administrativeZoneCode, null, subZoneCode).then(administrativeZoneFeature => { + vectorSource.addFeatures(vectorSource.getFormat().readFeatures(administrativeZoneFeature)) + if(vectorSource.getFeatures().length === 1) { + dispatch(addZoneSelected({ + name: zoneName, + code: subZoneCode ? subZoneCode : administrativeZoneCode, + feature: vectorSource.getFeatures()[0] + })) + } else { + console.error(`Vector ${administrativeZoneFeature}:${subZoneCode} has ${vectorSource.getFeatures().length} features. It should have only one feature.`) + } + }).catch(e => { + vectorSource.dispatchEvent(setIrretrievableFeaturesEvent(e)) + }) + + vectorSource.once(IRRETRIEVABLE_FEATURES_EVENT, event => { + console.error(event.error) + dispatch(setError(event.error)) + }) +} + +export default getAdministrativeZoneGeometry \ No newline at end of file diff --git a/frontend/src/domain/use_cases/showLayer.js b/frontend/src/domain/use_cases/showLayer.js index 662470e3da..c8dee123f0 100644 --- a/frontend/src/domain/use_cases/showLayer.js +++ b/frontend/src/domain/use_cases/showLayer.js @@ -51,7 +51,7 @@ const showLayer = layerToShow => (dispatch, getState) => { } const getVectorLayer = dispatch => (type, regulatoryZone, hash, gearCategory) => new VectorLayer({ - source: getVectorSource(dispatch)(type, regulatoryZone, dispatch), + source: getVectorSource(dispatch)(type, regulatoryZone), renderMode: 'image', className: regulatoryZone ? `${Layers.REGULATORY.code}:${regulatoryZone.layerName}:${regulatoryZone.zone}` : type, style: feature => { From f7af8b1b4cbf28c9a04adbcbcb36c9ea96093acc Mon Sep 17 00:00:00 2001 From: Loup Theron Date: Tue, 23 Mar 2021 10:50:23 +0100 Subject: [PATCH 2/3] Add AEM zones and work on zones styles --- .../src/components/DownloadVesselListModal.js | 6 +- frontend/src/containers/VesselList.js | 32 +++++-- frontend/src/domain/entities/layers.js | 94 +++++++++++++------ .../src/layers/styles/vectorLayerStyles.js | 88 ++++++++++++++++- infra/init/geoserver_init_layers.sh | 15 ++- infra/local/postgis_insert_layers.sh | 1 + infra/remote/postgis_insert_layers.sh | 1 + 7 files changed, 196 insertions(+), 41 deletions(-) diff --git a/frontend/src/components/DownloadVesselListModal.js b/frontend/src/components/DownloadVesselListModal.js index ba059d182f..88d06ccc8c 100644 --- a/frontend/src/components/DownloadVesselListModal.js +++ b/frontend/src/components/DownloadVesselListModal.js @@ -7,7 +7,7 @@ import CheckboxGroup from "rsuite/lib/CheckboxGroup"; import {Radio} from "rsuite"; import { ExportToCsv } from 'export-to-csv'; import countries from "i18n-iso-countries"; -import {getDateTime} from "../utils"; +import {getDate, getDateTime} from "../utils"; countries.registerLocale(require("i18n-iso-countries/langs/fr.json")); @@ -19,7 +19,7 @@ const optionsCSV = { showTitle: false, useTextFile: false, useBom: true, - useKeysAsHeaders: true, + useKeysAsHeaders: true }; const csvExporter = new ExportToCsv(optionsCSV); @@ -129,6 +129,8 @@ const DownloadVesselListModal = props => { return orderToCSVColumnOrder(valuesChecked, filteredVesselObject) }) + const date = new Date() + csvExporter.options.filename = `export_vms_${getDate(date.toISOString())}_${Math.floor(Math.random() * 100) + 1 }` csvExporter.generateCsv(objectsToExports) } diff --git a/frontend/src/containers/VesselList.js b/frontend/src/containers/VesselList.js index 922136e7eb..073f36fcce 100644 --- a/frontend/src/containers/VesselList.js +++ b/frontend/src/containers/VesselList.js @@ -58,6 +58,7 @@ const VesselList = () => { const nextZonesPromises = Object.keys(LayersEnum) .map(layerName => LayersEnum[layerName]) .filter(layer => layer.type === layersType.ADMINISTRATIVE) + .filter(layer => layer.isIntersectable) .map(zone => { if(zone.containsMultipleZones) { return getAdministrativeSubZonesFromAPI(zone.code).then(subZonesFeatures => { @@ -301,6 +302,19 @@ const VesselList = () => { ] } + const compare = (a, b) => { + let nameA = a.toUpperCase(); + let nameB = b.toUpperCase(); + + if (nameA < nameB) { + return -1; + } + if (nameA > nameB) { + return 1; + } + return 0; + } + return ( <> @@ -382,6 +396,17 @@ const VesselList = () => { )); }} + sort={isGroup => { + if (isGroup) { + return (a, b) => { + return compare(a.groupTitle, b.groupTitle); + }; + } + + return (a, b) => { + return compare(a.value, b.value); + }; + }} virtualized /> ou définir une zone @@ -587,13 +612,6 @@ const BoxFilter = styled(BoxFilterSVG)` vertical-align: text-bottom; ` -const LittleBox = styled(BoxFilterSVG)` - width: 20px; - height: 20px; - margin-right: 5px; - vertical-align: text-bottom; -` - const CloseIcon = styled(CloseIconSVG)` width: 13px; height: 13px; diff --git a/frontend/src/domain/entities/layers.js b/frontend/src/domain/entities/layers.js index d87697f1ea..5603e4b116 100644 --- a/frontend/src/domain/entities/layers.js +++ b/frontend/src/domain/entities/layers.js @@ -28,7 +28,8 @@ export default { group: null, type: layersType.BASE_LAYER, containsMultipleZones: false, - subZoneFieldKey: null + subZoneFieldKey: null, + isIntersectable: false }, VESSELS: { code: 'vessels', @@ -36,7 +37,8 @@ export default { group: null, type: layersType.VESSEL, containsMultipleZones: false, - subZoneFieldKey: null + subZoneFieldKey: null, + isIntersectable: false }, VESSEL_TRACK: { code: 'vessel_track', @@ -44,7 +46,8 @@ export default { group: null, type: layersType.VESSEL, containsMultipleZones: false, - subZoneFieldKey: null + subZoneFieldKey: null, + isIntersectable: false }, REGULATORY: { code: 'regulatory_areas', @@ -52,15 +55,17 @@ export default { group: null, type: layersType.REGULATORY, containsMultipleZones: false, - subZoneFieldKey: null + subZoneFieldKey: null, + isIntersectable: false }, EEZ: { code: 'eez_areas', name: 'Zones ZEE', group: null, type: layersType.ADMINISTRATIVE, - containsMultipleZones: false, - subZoneFieldKey: null + containsMultipleZones: true, + subZoneFieldKey: 'union', + isIntersectable: true }, FAO: { code: 'fao_areas', @@ -68,7 +73,17 @@ export default { group: null, type: layersType.ADMINISTRATIVE, containsMultipleZones: true, - subZoneFieldKey: 'f_division' + subZoneFieldKey: 'f_division', + isIntersectable: true + }, + AEM: { + code: 'aem_areas', + name: 'Zones AEM', + group: null, + type: layersType.ADMINISTRATIVE, + containsMultipleZones: false, + subZoneFieldKey: 'name', + isIntersectable: false }, THREE_MILES: { code: '3_miles_areas', @@ -76,7 +91,8 @@ export default { group: null, type: layersType.ADMINISTRATIVE, containsMultipleZones: false, - subZoneFieldKey: null + subZoneFieldKey: null, + isIntersectable: false }, SIX_MILES: { code: '6_miles_areas', @@ -84,7 +100,8 @@ export default { group: null, type: layersType.ADMINISTRATIVE, containsMultipleZones: false, - subZoneFieldKey: null + subZoneFieldKey: null, + isIntersectable: false }, TWELVE_MILES: { code: '12_miles_areas', @@ -92,7 +109,8 @@ export default { group: null, type: layersType.ADMINISTRATIVE, containsMultipleZones: false, - subZoneFieldKey: null + subZoneFieldKey: null, + isIntersectable: false }, eaux_occidentales_australes: { code: '1241_eaux_occidentales_australes_areas', @@ -100,7 +118,8 @@ export default { group: layersGroups.TWELVE_FORTY_ONE, type: layersType.ADMINISTRATIVE, containsMultipleZones: false, - subZoneFieldKey: null + subZoneFieldKey: null, + isIntersectable: true }, eaux_occidentales_septentrionales: { code: '1241_eaux_occidentales_septentrionales_areas', @@ -108,7 +127,8 @@ export default { group: layersGroups.TWELVE_FORTY_ONE, type: layersType.ADMINISTRATIVE, containsMultipleZones: false, - subZoneFieldKey: null + subZoneFieldKey: null, + isIntersectable: true }, eaux_union_dans_oi_et_atl_ouest: { code: '1241_eaux_union_dans_oi_et_atl_ouest_areas', @@ -116,7 +136,8 @@ export default { group: layersGroups.TWELVE_FORTY_ONE, type: layersType.ADMINISTRATIVE, containsMultipleZones: false, - subZoneFieldKey: null + subZoneFieldKey: null, + isIntersectable: true }, mer_baltique: { code: '1241_mer_baltique_areas', @@ -124,7 +145,8 @@ export default { group: layersGroups.TWELVE_FORTY_ONE, type: layersType.ADMINISTRATIVE, containsMultipleZones: false, - subZoneFieldKey: null + subZoneFieldKey: null, + isIntersectable: true }, mer_du_nord: { code: '1241_mer_du_nord_areas', @@ -132,7 +154,8 @@ export default { group: layersGroups.TWELVE_FORTY_ONE, type: layersType.ADMINISTRATIVE, containsMultipleZones: false, - subZoneFieldKey: null + subZoneFieldKey: null, + isIntersectable: true }, mer_mediterranee: { code: '1241_mer_mediterranee_areas', @@ -140,7 +163,8 @@ export default { group: layersGroups.TWELVE_FORTY_ONE, type: layersType.ADMINISTRATIVE, containsMultipleZones: false, - subZoneFieldKey: null + subZoneFieldKey: null, + isIntersectable: true }, mer_noire: { code: '1241_mer_noire_areas', @@ -148,7 +172,8 @@ export default { group: layersGroups.TWELVE_FORTY_ONE, type: layersType.ADMINISTRATIVE, containsMultipleZones: false, - subZoneFieldKey: null + subZoneFieldKey: null, + isIntersectable: true }, cormoran: { code: 'cormoran_areas', @@ -156,7 +181,8 @@ export default { group: null, type: layersType.ADMINISTRATIVE, containsMultipleZones: true, - subZoneFieldKey: 'zonex' + subZoneFieldKey: 'zonex', + isIntersectable: true }, CCAMLR: { code: 'fao_ccamlr_areas', @@ -164,7 +190,8 @@ export default { group: layersGroups.ORGP, type: layersType.ADMINISTRATIVE, containsMultipleZones: false, - subZoneFieldKey: null + subZoneFieldKey: null, + isIntersectable: true }, ICCAT: { code: 'fao_iccat_areas', @@ -172,7 +199,8 @@ export default { group: layersGroups.ORGP, type: layersType.ADMINISTRATIVE, containsMultipleZones: false, - subZoneFieldKey: null + subZoneFieldKey: null, + isIntersectable: true }, IOTC: { code: 'fao_iotc_areas', @@ -180,7 +208,8 @@ export default { group: layersGroups.ORGP, type: layersType.ADMINISTRATIVE, containsMultipleZones: false, - subZoneFieldKey: null + subZoneFieldKey: null, + isIntersectable: true }, NEAFC: { code: 'fao_neafc_areas', @@ -188,7 +217,8 @@ export default { group: layersGroups.ORGP, type: layersType.ADMINISTRATIVE, containsMultipleZones: false, - subZoneFieldKey: null + subZoneFieldKey: null, + isIntersectable: true }, SIOFA: { code: 'fao_siofa_areas', @@ -196,15 +226,17 @@ export default { group: layersGroups.ORGP, type: layersType.ADMINISTRATIVE, containsMultipleZones: false, - subZoneFieldKey: null + subZoneFieldKey: null, + isIntersectable: true }, rectangles_stat: { code: 'rectangles_stat_areas', name: 'Rectangles stat', group: null, type: layersType.ADMINISTRATIVE, - containsMultipleZones: false, - subZoneFieldKey: null + containsMultipleZones: true, + subZoneFieldKey: 'icesname', + isIntersectable: true }, situation_atlant: { code: 'situ_atlant_areas', @@ -212,7 +244,8 @@ export default { group: layersGroups.VMS_SITUATION, type: layersType.ADMINISTRATIVE, containsMultipleZones: true, - subZoneFieldKey: 'libelle' + subZoneFieldKey: 'libelle', + isIntersectable: true }, situation_med: { code: 'situ_med_areas', @@ -220,7 +253,8 @@ export default { group: layersGroups.VMS_SITUATION, type: layersType.ADMINISTRATIVE, containsMultipleZones: true, - subZoneFieldKey: 'libelle' + subZoneFieldKey: 'libelle', + isIntersectable: true }, situation_memn: { code: 'situ_memn_areas', @@ -228,7 +262,8 @@ export default { group: layersGroups.VMS_SITUATION, type: layersType.ADMINISTRATIVE, containsMultipleZones: true, - subZoneFieldKey: 'libelle' + subZoneFieldKey: 'libelle', + isIntersectable: true }, situation_outre_mer: { code: 'situ_outre_mer_areas', @@ -236,7 +271,8 @@ export default { group: layersGroups.VMS_SITUATION, type: layersType.ADMINISTRATIVE, containsMultipleZones: true, - subZoneFieldKey: 'libelle' + subZoneFieldKey: 'libelle', + isIntersectable: true }, } diff --git a/frontend/src/layers/styles/vectorLayerStyles.js b/frontend/src/layers/styles/vectorLayerStyles.js index 6967199b3d..7f8e029b20 100644 --- a/frontend/src/layers/styles/vectorLayerStyles.js +++ b/frontend/src/layers/styles/vectorLayerStyles.js @@ -14,7 +14,7 @@ export const getVectorLayerStyle = type => { }), text: new Text({ font: '12px Avenir', - text: `${feature.get('union')}`, + text: `${feature.get(Layers.EEZ.subZoneFieldKey) ? feature.get(Layers.EEZ.subZoneFieldKey) : ''}`, fill: new Fill({color: '#05055E'}), stroke: new Stroke({color: 'rgba(255,255,255,0.9)', width: 2}) }) @@ -26,7 +26,91 @@ export const getVectorLayerStyle = type => { }), text: new Text({ font: '12px Avenir', - text: `${feature.get('f_division') ? feature.get('f_division') : ''}`, + text: `${feature.get(Layers.FAO.subZoneFieldKey) ? feature.get(Layers.FAO.subZoneFieldKey) : ''}`, + fill: new Fill({color: '#05055E'}), + stroke: new Stroke({color: 'rgba(255,255,255,0.4)', width: 2}) + }) + }) + case Layers.AEM.code: return feature => new Style({ + stroke: new Stroke({ + color: '#767AB2', + width: 1, + }), + text: new Text({ + font: '12px Avenir', + text: `${feature.get(Layers.AEM.subZoneFieldKey) ? feature.get(Layers.AEM.subZoneFieldKey) : ''}`, + fill: new Fill({color: '#05055E'}), + stroke: new Stroke({color: 'rgba(255,255,255,0.4)', width: 2}) + }) + }) + case Layers.cormoran.code: return feature => new Style({ + stroke: new Stroke({ + color: '#767AB2', + width: 1, + }), + text: new Text({ + font: '12px Avenir', + text: `${feature.get(Layers.cormoran.subZoneFieldKey) ? feature.get(Layers.cormoran.subZoneFieldKey) : ''}`, + fill: new Fill({color: '#05055E'}), + stroke: new Stroke({color: 'rgba(255,255,255,0.4)', width: 2}) + }) + }) + case Layers.situation_atlant.code: return feature => new Style({ + stroke: new Stroke({ + color: '#767AB2', + width: 1, + }), + text: new Text({ + font: '12px Avenir', + text: `${feature.get(Layers.situation_atlant.subZoneFieldKey) ? feature.get(Layers.situation_atlant.subZoneFieldKey) : ''}`, + fill: new Fill({color: '#05055E'}), + stroke: new Stroke({color: 'rgba(255,255,255,0.4)', width: 2}) + }) + }) + case Layers.situation_med.code: return feature => new Style({ + stroke: new Stroke({ + color: '#767AB2', + width: 1, + }), + text: new Text({ + font: '12px Avenir', + text: `${feature.get(Layers.situation_med.subZoneFieldKey) ? feature.get(Layers.situation_med.subZoneFieldKey) : ''}`, + fill: new Fill({color: '#05055E'}), + stroke: new Stroke({color: 'rgba(255,255,255,0.4)', width: 2}) + }) + }) + case Layers.situation_memn.code: return feature => new Style({ + stroke: new Stroke({ + color: '#767AB2', + width: 1, + }), + text: new Text({ + font: '12px Avenir', + text: `${feature.get(Layers.situation_memn.subZoneFieldKey) ? feature.get(Layers.situation_memn.subZoneFieldKey) : ''}`, + fill: new Fill({color: '#05055E'}), + stroke: new Stroke({color: 'rgba(255,255,255,0.4)', width: 2}) + }) + }) + case Layers.situation_outre_mer.code: return feature => new Style({ + stroke: new Stroke({ + color: '#767AB2', + width: 1, + }), + text: new Text({ + font: '12px Avenir', + text: `${feature.get(Layers.situation_outre_mer.subZoneFieldKey) ? feature.get(Layers.situation_outre_mer.subZoneFieldKey) : ''}`, + fill: new Fill({color: '#05055E'}), + stroke: new Stroke({color: 'rgba(255,255,255,0.4)', width: 2}) + }) + }) + case Layers.rectangles_stat.code: return feature => new Style({ + stroke: new Stroke({ + color: '#767AB2', + width: 1, + }), + text: new Text({ + font: '12px Avenir', + text: `${feature.get(Layers.rectangles_stat.subZoneFieldKey) ? feature.get(Layers.rectangles_stat.subZoneFieldKey) : ''}`, fill: new Fill({color: '#05055E'}), stroke: new Stroke({color: 'rgba(255,255,255,0.4)', width: 2}) }) diff --git a/infra/init/geoserver_init_layers.sh b/infra/init/geoserver_init_layers.sh index d55ab92374..7471b1f817 100755 --- a/infra/init/geoserver_init_layers.sh +++ b/infra/init/geoserver_init_layers.sh @@ -359,4 +359,17 @@ curl -v -u admin:geoserver -X POST http://localhost:8081/geoserver/rest/workspac "enabled": true, } } -EOF \ No newline at end of file +EOF + +curl -v -u admin:geoserver -X POST http://localhost:8081/geoserver/rest/workspaces/monitorfish/datastores/monitorfish_postgis/featuretypes -H "accept: text/html" -H "content-type: application/json" -d @- << EOF +{ + "featureType": { + "name": "aem_areas", + "nativeName": "aem_areas", + "title": "AEM areas", + "nativeCRS": "EPSG:4326", + "srs": "EPSG:4326", + "enabled": true, + } +} +EOF diff --git a/infra/local/postgis_insert_layers.sh b/infra/local/postgis_insert_layers.sh index 2345e8893c..3b0c3a2024 100644 --- a/infra/local/postgis_insert_layers.sh +++ b/infra/local/postgis_insert_layers.sh @@ -26,6 +26,7 @@ PGCLIENTENCODING=LATIN1 psql -d cnsp -U adl -f sig/layersdata/1241_mer_mediterra PGCLIENTENCODING=LATIN1 psql -d cnsp -U adl -f sig/layersdata/1241_mer_noire.sql PGCLIENTENCODING=LATIN1 psql -d cnsp -U adl -f sig/layersdata/cormoran_areas.sql +PGCLIENTENCODING=LATIN1 psql -d cnsp -U adl -f sig/layersdata/aem_areas.sql PGCLIENTENCODING=LATIN1 psql -d cnsp -U adl -f sig/layersdata/fao_CCAMLR_areas.sql PGCLIENTENCODING=LATIN1 psql -d cnsp -U adl -f sig/layersdata/fao_ICCAT_areas.sql diff --git a/infra/remote/postgis_insert_layers.sh b/infra/remote/postgis_insert_layers.sh index 036cd0f2f1..2c01fe2f13 100755 --- a/infra/remote/postgis_insert_layers.sh +++ b/infra/remote/postgis_insert_layers.sh @@ -19,6 +19,7 @@ PGCLIENTENCODING=LATIN1 psql -h 0.0.0.0 -d monitorfishdb -U postgres -f sig/laye PGCLIENTENCODING=LATIN1 psql -h 0.0.0.0 -d monitorfishdb -U postgres -f sig/layersdata/1241_mer_noire.sql PGCLIENTENCODING=LATIN1 psql -h 0.0.0.0 -d monitorfishdb -U postgres -f sig/layersdata/cormoran_areas.sql +PGCLIENTENCODING=LATIN1 psql -h 0.0.0.0 -d monitorfishdb -U postgres -f sig/layersdata/aem_areas.sql PGCLIENTENCODING=LATIN1 psql -h 0.0.0.0 -d monitorfishdb -U postgres -f sig/layersdata/fao_CCAMLR_areas.sql PGCLIENTENCODING=LATIN1 psql -h 0.0.0.0 -d monitorfishdb -U postgres -f sig/layersdata/fao_ICCAT_areas.sql From 5c9626e78be92e51a19b9d73dbd5314ecc1b3c6e Mon Sep 17 00:00:00 2001 From: Loup Theron Date: Tue, 23 Mar 2021 13:17:30 +0100 Subject: [PATCH 3/3] Try to fix css listt --- frontend/src/App.css | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frontend/src/App.css b/frontend/src/App.css index 1c03cb2dd8..774c3a0e83 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -291,4 +291,12 @@ a:hover, a:focus { .rs-picker-tag .rs-tag { max-width: calc(100% - 25px) !important; +} + +.rs-picker-check-menu-group[role="listitem"] { + height: 48px !important; +} + +.rs-picker-check-menu-items .rs-picker-check-menu-group:not(:first-child) { + padding-top: 0px !important; } \ No newline at end of file