From 4c6556de3f33d31508803db853851c3ff26326ab Mon Sep 17 00:00:00 2001 From: baldo Date: Thu, 1 Sep 2022 14:38:41 +0200 Subject: [PATCH] Ask for confirmation for nodes outside of community bounds. --- frontend/package.json | 1 + frontend/src/components/FloatingIcon.vue | 36 ++++++ frontend/src/components/NodeMap.vue | 8 ++ .../src/components/nodes/NodeCreateForm.vue | 74 +++++++++--- .../OutsideOfCommunityConfirmationForm.vue | 112 ++++++++++++++++++ frontend/yarn.lock | 5 + 6 files changed, 222 insertions(+), 14 deletions(-) create mode 100644 frontend/src/components/FloatingIcon.vue create mode 100644 frontend/src/components/nodes/OutsideOfCommunityConfirmationForm.vue diff --git a/frontend/package.json b/frontend/package.json index c778b08..1652cbe 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -19,6 +19,7 @@ }, "dependencies": { "fork-awesome": "^1.2.0", + "geolib": "^3.3.3", "leaflet": "^1.8.0", "pinia": "^2.0.21", "sparkson": "^1.3.6", diff --git a/frontend/src/components/FloatingIcon.vue b/frontend/src/components/FloatingIcon.vue new file mode 100644 index 0000000..43c0306 --- /dev/null +++ b/frontend/src/components/FloatingIcon.vue @@ -0,0 +1,36 @@ + + + + + diff --git a/frontend/src/components/NodeMap.vue b/frontend/src/components/NodeMap.vue index ed00361..07ca648 100644 --- a/frontend/src/components/NodeMap.vue +++ b/frontend/src/components/NodeMap.vue @@ -133,6 +133,14 @@ function centerOnCoordinates() { function renderMap() { const { layers, defaultLayers } = getLayers(); createMap(defaultLayers, layers); + if ( + map && + configStore.getConfig.otherCommunityInfo.showBorderForDebugging + ) { + new L.Polygon( + configStore.getConfig.otherCommunityInfo.localCommunityPolygon + ).addTo(map); + } centerOnCoordinates(); updateMarker(); } diff --git a/frontend/src/components/nodes/NodeCreateForm.vue b/frontend/src/components/nodes/NodeCreateForm.vue index b7295d0..d2f1667 100644 --- a/frontend/src/components/nodes/NodeCreateForm.vue +++ b/frontend/src/components/nodes/NodeCreateForm.vue @@ -19,6 +19,7 @@ import { ComponentVariant, hasOwnProperty, } from "@/types"; +import FloatingIcon from "@/components/FloatingIcon.vue"; import ErrorCard from "@/components/ErrorCard.vue"; import ButtonGroup from "@/components/form/ButtonGroup.vue"; import ValidationForm from "@/components/form/ValidationForm.vue"; @@ -27,8 +28,12 @@ import { route, RouteName } from "@/router"; import RouteButton from "@/components/form/RouteButton.vue"; import { ApiError } from "@/utils/Api"; import NodeCoordinatesInput from "@/components/nodes/NodeCoordinatesInput.vue"; +import OutsideOfCommunityConfirmationForm from "@/components/nodes/OutsideOfCommunityConfirmationForm.vue"; import CheckboxInput from "@/components/form/CheckboxInput.vue"; import InfoCard from "@/components/InfoCard.vue"; +import { isPointInPolygon } from "geolib"; +import { parseToFloat } from "@/utils/Numbers"; +import { forConstraint } from "../../shared/validation/validator"; const configStore = useConfigStore(); const nodeStore = useNodeStore(); @@ -63,6 +68,9 @@ const nicknameModel = ref("" as Nickname); const emailModel = ref("" as EmailAddress); const monitoringModel = ref(false); +const showOutsideOfCommunityForm = ref(false); +const confirmedOutsideOfCommunity = ref(false); + onMounted(() => { if (props.hostname) { hostnameModel.value = props.hostname; @@ -75,6 +83,30 @@ onMounted(() => { } }); +function isOutsideCommunity(): boolean { + if (!forConstraint(CONSTRAINTS.node.coords, false)(coordsModel.value)) { + return false; + } + const [lat, lng] = coordsModel.value.split(" ").map(parseToFloat); + + return !isPointInPolygon( + { lat, lng }, + configStore.getConfig.otherCommunityInfo.localCommunityPolygon + ); +} + +async function onConfirmOutsideOfCommunity() { + showOutsideOfCommunityForm.value = false; + confirmedOutsideOfCommunity.value = true; + + await onSubmit(); +} + +async function onCancelOutsideOfCommunity() { + showOutsideOfCommunityForm.value = false; + window.scrollTo(0, 0); +} + async function onSubmit() { generalError.value = false; conflictErrorMessage.value = undefined; @@ -82,6 +114,18 @@ async function onSubmit() { // Make sure to re-render error message to trigger scrolling into view. await nextTick(); + if ( + configStore.getConfig.otherCommunityInfo.showInfo && + isOutsideCommunity() && + !confirmedOutsideOfCommunity.value + ) { + showOutsideOfCommunityForm.value = true; + } else { + await createNode(); + } +} + +async function createNode(): Promise { try { const node = await nodeStore.create({ hostname: hostnameModel.value, @@ -115,7 +159,17 @@ async function onSubmit() { - + diff --git a/frontend/src/components/nodes/OutsideOfCommunityConfirmationForm.vue b/frontend/src/components/nodes/OutsideOfCommunityConfirmationForm.vue new file mode 100644 index 0000000..5741353 --- /dev/null +++ b/frontend/src/components/nodes/OutsideOfCommunityConfirmationForm.vue @@ -0,0 +1,112 @@ + + + + + diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 311ba96..973e0c5 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -1291,6 +1291,11 @@ functional-red-black-tree@^1.0.1: resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +geolib@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/geolib/-/geolib-3.3.3.tgz#17f5a0dcdc0b051bd631b66f7131d2c14c54a15b" + integrity sha512-YO704pzdB/8QQekQuDmFD5uv5RAwAf4rOUPdcMhdEOz+HoPWD0sC7Qqdwb+LAvwIjXVRawx0QgZlocKYh8PFOQ== + get-func-name@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"