wip
							
								
								
									
										114
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						@@ -8,11 +8,15 @@
 | 
				
			|||||||
      "name": "lts-stats-web",
 | 
					      "name": "lts-stats-web",
 | 
				
			||||||
      "version": "0.0.0",
 | 
					      "version": "0.0.0",
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@fortawesome/fontawesome-svg-core": "^6.2.1",
 | 
				
			||||||
 | 
					        "@fortawesome/free-solid-svg-icons": "^6.2.1",
 | 
				
			||||||
 | 
					        "@fortawesome/vue-fontawesome": "^3.0.2",
 | 
				
			||||||
        "@headlessui/vue": "^1.7.7",
 | 
					        "@headlessui/vue": "^1.7.7",
 | 
				
			||||||
        "@heroicons/vue": "^2.0.13",
 | 
					        "@heroicons/vue": "^2.0.13",
 | 
				
			||||||
        "@popperjs/core": "^2.11.6",
 | 
					        "@popperjs/core": "^2.11.6",
 | 
				
			||||||
        "axios": "^1.2.2",
 | 
					        "axios": "^1.2.2",
 | 
				
			||||||
        "bootstrap": "^5.2.3",
 | 
					        "bootstrap": "^5.2.3",
 | 
				
			||||||
 | 
					        "leaflet-rotatedmarker": "^0.2.0",
 | 
				
			||||||
        "lodash": "^4.17.21",
 | 
					        "lodash": "^4.17.21",
 | 
				
			||||||
        "moment": "^2.29.4",
 | 
					        "moment": "^2.29.4",
 | 
				
			||||||
        "pinia": "^2.0.29",
 | 
					        "pinia": "^2.0.29",
 | 
				
			||||||
@@ -25,11 +29,13 @@
 | 
				
			|||||||
      "devDependencies": {
 | 
					      "devDependencies": {
 | 
				
			||||||
        "@rushstack/eslint-patch": "^1.1.4",
 | 
					        "@rushstack/eslint-patch": "^1.1.4",
 | 
				
			||||||
        "@vitejs/plugin-vue": "^4.0.0",
 | 
					        "@vitejs/plugin-vue": "^4.0.0",
 | 
				
			||||||
 | 
					        "@vue-leaflet/vue-leaflet": "^0.8.0",
 | 
				
			||||||
        "@vue/eslint-config-prettier": "^7.0.0",
 | 
					        "@vue/eslint-config-prettier": "^7.0.0",
 | 
				
			||||||
        "bulma": "^0.9.4",
 | 
					        "bulma": "^0.9.4",
 | 
				
			||||||
        "eslint": "^8.22.0",
 | 
					        "eslint": "^8.22.0",
 | 
				
			||||||
        "eslint-plugin-vue": "^9.3.0",
 | 
					        "eslint-plugin-vue": "^9.3.0",
 | 
				
			||||||
        "http-server": "^14.1.1",
 | 
					        "http-server": "^14.1.1",
 | 
				
			||||||
 | 
					        "leaflet": "^1.9.3",
 | 
				
			||||||
        "prettier": "^2.7.1",
 | 
					        "prettier": "^2.7.1",
 | 
				
			||||||
        "sass": "^1.57.1",
 | 
					        "sass": "^1.57.1",
 | 
				
			||||||
        "vite": "^4.0.0"
 | 
					        "vite": "^4.0.0"
 | 
				
			||||||
@@ -421,6 +427,48 @@
 | 
				
			|||||||
        "url": "https://opencollective.com/eslint"
 | 
					        "url": "https://opencollective.com/eslint"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@fortawesome/fontawesome-common-types": {
 | 
				
			||||||
 | 
					      "version": "6.2.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.2.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-Sz07mnQrTekFWLz5BMjOzHl/+NooTdW8F8kDQxjWwbpOJcnoSg4vUDng8d/WR1wOxM0O+CY9Zw0nR054riNYtQ==",
 | 
				
			||||||
 | 
					      "hasInstallScript": true,
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=6"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@fortawesome/fontawesome-svg-core": {
 | 
				
			||||||
 | 
					      "version": "6.2.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.2.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-HELwwbCz6C1XEcjzyT1Jugmz2NNklMrSPjZOWMlc+ZsHIVk+XOvOXLGGQtFBwSyqfJDNgRq4xBCwWOaZ/d9DEA==",
 | 
				
			||||||
 | 
					      "hasInstallScript": true,
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@fortawesome/fontawesome-common-types": "6.2.1"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=6"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@fortawesome/free-solid-svg-icons": {
 | 
				
			||||||
 | 
					      "version": "6.2.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.2.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-oKuqrP5jbfEPJWTij4sM+/RvgX+RMFwx3QZCZcK9PrBDgxC35zuc7AOFsyMjMd/PIFPeB2JxyqDr5zs/DZFPPw==",
 | 
				
			||||||
 | 
					      "hasInstallScript": true,
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@fortawesome/fontawesome-common-types": "6.2.1"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=6"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@fortawesome/vue-fontawesome": {
 | 
				
			||||||
 | 
					      "version": "3.0.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@fortawesome/vue-fontawesome/-/vue-fontawesome-3.0.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-xHVtVY8ASUeEvgcA/7vULUesENhD+pi/EirRHdMBqooHlXBqK+yrV6d8tUye1m5UKQKVgYAHMhUBfOnoiwvc8Q==",
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "@fortawesome/fontawesome-svg-core": "~1 || ~6",
 | 
				
			||||||
 | 
					        "vue": ">= 3.0.0 < 4"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/@headlessui/vue": {
 | 
					    "node_modules/@headlessui/vue": {
 | 
				
			||||||
      "version": "1.7.7",
 | 
					      "version": "1.7.7",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@headlessui/vue/-/vue-1.7.7.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@headlessui/vue/-/vue-1.7.7.tgz",
 | 
				
			||||||
@@ -667,6 +715,16 @@
 | 
				
			|||||||
        "vue": "^3.2.25"
 | 
					        "vue": "^3.2.25"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@vue-leaflet/vue-leaflet": {
 | 
				
			||||||
 | 
					      "version": "0.8.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@vue-leaflet/vue-leaflet/-/vue-leaflet-0.8.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-oHPdD4zq243NvK98T+HiRT9qf1zvRys5KO0eDdRkZKd09i9Epj9ALPoRqF2NFUPcS8G2yEO1qCLiKAgFQ26ARQ==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "leaflet": "^1.6.0",
 | 
				
			||||||
 | 
					        "vue": "^3.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/@vue/compiler-core": {
 | 
					    "node_modules/@vue/compiler-core": {
 | 
				
			||||||
      "version": "3.2.45",
 | 
					      "version": "3.2.45",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.45.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.45.tgz",
 | 
				
			||||||
@@ -1959,6 +2017,17 @@
 | 
				
			|||||||
      "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
 | 
					      "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
 | 
				
			||||||
      "dev": true
 | 
					      "dev": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/leaflet": {
 | 
				
			||||||
 | 
					      "version": "1.9.3",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.3.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-iB2cR9vAkDOu5l3HAay2obcUHZ7xwUBBjph8+PGtmW/2lYhbLizWtG7nTeYht36WfOslixQF9D/uSIzhZgGMfQ==",
 | 
				
			||||||
 | 
					      "dev": true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/leaflet-rotatedmarker": {
 | 
				
			||||||
 | 
					      "version": "0.2.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/leaflet-rotatedmarker/-/leaflet-rotatedmarker-0.2.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-yc97gxLXwbZa+Gk9VCcqI0CkvIBC9oNTTjFsHqq4EQvANrvaboib4UdeQLyTnEqDpaXHCqzwwVIDHtvz2mUiDg=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/levn": {
 | 
					    "node_modules/levn": {
 | 
				
			||||||
      "version": "0.4.1",
 | 
					      "version": "0.4.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
 | 
				
			||||||
@@ -3223,6 +3292,33 @@
 | 
				
			|||||||
        "strip-json-comments": "^3.1.1"
 | 
					        "strip-json-comments": "^3.1.1"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "@fortawesome/fontawesome-common-types": {
 | 
				
			||||||
 | 
					      "version": "6.2.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.2.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-Sz07mnQrTekFWLz5BMjOzHl/+NooTdW8F8kDQxjWwbpOJcnoSg4vUDng8d/WR1wOxM0O+CY9Zw0nR054riNYtQ=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "@fortawesome/fontawesome-svg-core": {
 | 
				
			||||||
 | 
					      "version": "6.2.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.2.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-HELwwbCz6C1XEcjzyT1Jugmz2NNklMrSPjZOWMlc+ZsHIVk+XOvOXLGGQtFBwSyqfJDNgRq4xBCwWOaZ/d9DEA==",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "@fortawesome/fontawesome-common-types": "6.2.1"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "@fortawesome/free-solid-svg-icons": {
 | 
				
			||||||
 | 
					      "version": "6.2.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.2.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-oKuqrP5jbfEPJWTij4sM+/RvgX+RMFwx3QZCZcK9PrBDgxC35zuc7AOFsyMjMd/PIFPeB2JxyqDr5zs/DZFPPw==",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "@fortawesome/fontawesome-common-types": "6.2.1"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "@fortawesome/vue-fontawesome": {
 | 
				
			||||||
 | 
					      "version": "3.0.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@fortawesome/vue-fontawesome/-/vue-fontawesome-3.0.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-xHVtVY8ASUeEvgcA/7vULUesENhD+pi/EirRHdMBqooHlXBqK+yrV6d8tUye1m5UKQKVgYAHMhUBfOnoiwvc8Q==",
 | 
				
			||||||
 | 
					      "requires": {}
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "@headlessui/vue": {
 | 
					    "@headlessui/vue": {
 | 
				
			||||||
      "version": "1.7.7",
 | 
					      "version": "1.7.7",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@headlessui/vue/-/vue-1.7.7.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@headlessui/vue/-/vue-1.7.7.tgz",
 | 
				
			||||||
@@ -3411,6 +3507,13 @@
 | 
				
			|||||||
      "dev": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "requires": {}
 | 
					      "requires": {}
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "@vue-leaflet/vue-leaflet": {
 | 
				
			||||||
 | 
					      "version": "0.8.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@vue-leaflet/vue-leaflet/-/vue-leaflet-0.8.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-oHPdD4zq243NvK98T+HiRT9qf1zvRys5KO0eDdRkZKd09i9Epj9ALPoRqF2NFUPcS8G2yEO1qCLiKAgFQ26ARQ==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "requires": {}
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "@vue/compiler-core": {
 | 
					    "@vue/compiler-core": {
 | 
				
			||||||
      "version": "3.2.45",
 | 
					      "version": "3.2.45",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.45.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.45.tgz",
 | 
				
			||||||
@@ -4386,6 +4489,17 @@
 | 
				
			|||||||
      "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
 | 
					      "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
 | 
				
			||||||
      "dev": true
 | 
					      "dev": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "leaflet": {
 | 
				
			||||||
 | 
					      "version": "1.9.3",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.3.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-iB2cR9vAkDOu5l3HAay2obcUHZ7xwUBBjph8+PGtmW/2lYhbLizWtG7nTeYht36WfOslixQF9D/uSIzhZgGMfQ==",
 | 
				
			||||||
 | 
					      "dev": true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "leaflet-rotatedmarker": {
 | 
				
			||||||
 | 
					      "version": "0.2.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/leaflet-rotatedmarker/-/leaflet-rotatedmarker-0.2.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-yc97gxLXwbZa+Gk9VCcqI0CkvIBC9oNTTjFsHqq4EQvANrvaboib4UdeQLyTnEqDpaXHCqzwwVIDHtvz2mUiDg=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "levn": {
 | 
					    "levn": {
 | 
				
			||||||
      "version": "0.4.1",
 | 
					      "version": "0.4.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,11 +11,15 @@
 | 
				
			|||||||
    "docker-build": "docker build -t arhuako/ltsweb ."
 | 
					    "docker-build": "docker build -t arhuako/ltsweb ."
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
 | 
					    "@fortawesome/fontawesome-svg-core": "^6.2.1",
 | 
				
			||||||
 | 
					    "@fortawesome/free-solid-svg-icons": "^6.2.1",
 | 
				
			||||||
 | 
					    "@fortawesome/vue-fontawesome": "^3.0.2",
 | 
				
			||||||
    "@headlessui/vue": "^1.7.7",
 | 
					    "@headlessui/vue": "^1.7.7",
 | 
				
			||||||
    "@heroicons/vue": "^2.0.13",
 | 
					    "@heroicons/vue": "^2.0.13",
 | 
				
			||||||
    "@popperjs/core": "^2.11.6",
 | 
					    "@popperjs/core": "^2.11.6",
 | 
				
			||||||
    "axios": "^1.2.2",
 | 
					    "axios": "^1.2.2",
 | 
				
			||||||
    "bootstrap": "^5.2.3",
 | 
					    "bootstrap": "^5.2.3",
 | 
				
			||||||
 | 
					    "leaflet-rotatedmarker": "^0.2.0",
 | 
				
			||||||
    "lodash": "^4.17.21",
 | 
					    "lodash": "^4.17.21",
 | 
				
			||||||
    "moment": "^2.29.4",
 | 
					    "moment": "^2.29.4",
 | 
				
			||||||
    "pinia": "^2.0.29",
 | 
					    "pinia": "^2.0.29",
 | 
				
			||||||
@@ -28,11 +32,13 @@
 | 
				
			|||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "@rushstack/eslint-patch": "^1.1.4",
 | 
					    "@rushstack/eslint-patch": "^1.1.4",
 | 
				
			||||||
    "@vitejs/plugin-vue": "^4.0.0",
 | 
					    "@vitejs/plugin-vue": "^4.0.0",
 | 
				
			||||||
 | 
					    "@vue-leaflet/vue-leaflet": "^0.8.0",
 | 
				
			||||||
    "@vue/eslint-config-prettier": "^7.0.0",
 | 
					    "@vue/eslint-config-prettier": "^7.0.0",
 | 
				
			||||||
    "bulma": "^0.9.4",
 | 
					    "bulma": "^0.9.4",
 | 
				
			||||||
    "eslint": "^8.22.0",
 | 
					    "eslint": "^8.22.0",
 | 
				
			||||||
    "eslint-plugin-vue": "^9.3.0",
 | 
					    "eslint-plugin-vue": "^9.3.0",
 | 
				
			||||||
    "http-server": "^14.1.1",
 | 
					    "http-server": "^14.1.1",
 | 
				
			||||||
 | 
					    "leaflet": "^1.9.3",
 | 
				
			||||||
    "prettier": "^2.7.1",
 | 
					    "prettier": "^2.7.1",
 | 
				
			||||||
    "sass": "^1.57.1",
 | 
					    "sass": "^1.57.1",
 | 
				
			||||||
    "vite": "^4.0.0"
 | 
					    "vite": "^4.0.0"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										14
									
								
								src/App.vue
									
									
									
									
									
								
							
							
						
						@@ -46,9 +46,9 @@ export default {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
      const user = await authenticate(this.username, this.password);
 | 
					      const user = await authenticate(this.username, this.password);
 | 
				
			||||||
      this.setUser(user);
 | 
					      this.setUser(user);
 | 
				
			||||||
      console.log('user :>> ', user);
 | 
					 | 
				
			||||||
      this.username = '';
 | 
					      this.username = '';
 | 
				
			||||||
      this.password = '';
 | 
					      this.password = '';
 | 
				
			||||||
 | 
					      window.location.reload();
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    async logout() {
 | 
					    async logout() {
 | 
				
			||||||
      await logout();
 | 
					      await logout();
 | 
				
			||||||
@@ -81,8 +81,9 @@ export default {
 | 
				
			|||||||
      <div class="navbar-start">
 | 
					      <div class="navbar-start">
 | 
				
			||||||
        <router-link class="navbar-item" to="/">ICAO</router-link>
 | 
					        <router-link class="navbar-item" to="/">ICAO</router-link>
 | 
				
			||||||
        <router-link class="navbar-item" to="/acars">Acars</router-link>
 | 
					        <router-link class="navbar-item" to="/acars">Acars</router-link>
 | 
				
			||||||
 | 
					        <router-link class="navbar-item" to="/map">Live Map</router-link>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <router-link v-if="hasRoles(['cabal'])" class="navbar-item" to="/cabal">Capt Cabal</router-link>
 | 
					        <router-link v-if="hasRoles(['admin', 'cabal'])" class="navbar-item" to="/cabal">Capt Cabal</router-link>
 | 
				
			||||||
        <router-link v-if="hasRoles(['admin'])" class="navbar-item" to="/admin">Admin</router-link>
 | 
					        <router-link v-if="hasRoles(['admin'])" class="navbar-item" to="/admin">Admin</router-link>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
@@ -129,10 +130,13 @@ export default {
 | 
				
			|||||||
.logo {
 | 
					.logo {
 | 
				
			||||||
  margin-right: 0.2rem;
 | 
					  margin-right: 0.2rem;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
.tag {
 | 
					 | 
				
			||||||
  font-size: 60% !important;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.input-login {
 | 
					.input-login {
 | 
				
			||||||
  width: 100px;
 | 
					  width: 100px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					.loading-icon {
 | 
				
			||||||
 | 
					  margin-top: 24px;
 | 
				
			||||||
 | 
					  color: #ddd;
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  text-align: center;;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										15
									
								
								src/assets/images/coloring.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 15 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/map/location-blue.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 653 B  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/map/location-gray.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 199 B  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/map/location-green.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 638 B  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/map/location-lightblue.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 589 B  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/map/location-red.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1023 B  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/map/location-yellow.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 701 B  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/map/marker-here.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 987 B  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/map/marker-landing.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1.0 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/map/marker-takeoff.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1.3 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/map/plane.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 498 B  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/ranks/01.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.0 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/ranks/02.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.5 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/ranks/03.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.7 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/ranks/04.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.6 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/ranks/05.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.6 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/ranks/06.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.2 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/ranks/07.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.5 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/ranks/08.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.6 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/ranks/09.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.6 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/ranks/10.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.6 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/ranks/11.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.7 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/ranks/12.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 5.0 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/ranks/13.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 5.1 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/ranks/14.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 5.1 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/ranks/15.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 5.1 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/ranks/16.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 5.1 KiB  | 
@@ -1,7 +1,7 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <section class="">
 | 
					  <section class="">
 | 
				
			||||||
    <div class="solari-container">
 | 
					    <div class="solari-container">
 | 
				
			||||||
      <SolariBoard :headers="headers" :loading="isLoading" :config="colsConfig" :data="list" :size="18" />
 | 
					      <SolariBoard :headers="headers" :loading="isLoading" :config="colsConfig" :data="list" :length="18" />
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </section>
 | 
					  </section>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
@@ -31,15 +31,15 @@
 | 
				
			|||||||
        colsConfig: [
 | 
					        colsConfig: [
 | 
				
			||||||
          {
 | 
					          {
 | 
				
			||||||
            align: 'left',
 | 
					            align: 'left',
 | 
				
			||||||
            size: 8
 | 
					            length: 8
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          {
 | 
					          {
 | 
				
			||||||
            align: 'right',
 | 
					            align: 'right',
 | 
				
			||||||
            size: 9
 | 
					            length: 9
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          {
 | 
					          {
 | 
				
			||||||
            align: 'right',
 | 
					            align: 'right',
 | 
				
			||||||
            size: 5
 | 
					            length: 5
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,7 @@
 | 
				
			|||||||
        <SolariBoardRow :ref="`line_${j - 1}`" 
 | 
					        <SolariBoardRow :ref="`line_${j - 1}`" 
 | 
				
			||||||
          :textToShow="getValue(j - 1)" 
 | 
					          :textToShow="getValue(j - 1)" 
 | 
				
			||||||
          :loops="getConfigValue(j - 1, 'loop')" 
 | 
					          :loops="getConfigValue(j - 1, 'loop')" 
 | 
				
			||||||
          :size="getConfigValue(j - 1, 'size')" 
 | 
					          :length="getConfigValue(j - 1, 'length')" 
 | 
				
			||||||
          :delay="getConfigValue(j - 1, 'delay')" 
 | 
					          :delay="getConfigValue(j - 1, 'delay')" 
 | 
				
			||||||
          :align="getConfigValue(j - 1, 'align')"></SolariBoardRow>
 | 
					          :align="getConfigValue(j - 1, 'align')"></SolariBoardRow>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
@@ -36,7 +36,7 @@ export default {
 | 
				
			|||||||
      type: Number,
 | 
					      type: Number,
 | 
				
			||||||
      default: () => 200
 | 
					      default: () => 200
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    size: {
 | 
					    length: {
 | 
				
			||||||
      type: Number,
 | 
					      type: Number,
 | 
				
			||||||
      default: () => 25
 | 
					      default: () => 25
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
@@ -107,7 +107,7 @@ export default {
 | 
				
			|||||||
    mapRow(r, i) {
 | 
					    mapRow(r, i) {
 | 
				
			||||||
      r.loops = (_isNil(r.loops)) ? this.loops : r.loops;
 | 
					      r.loops = (_isNil(r.loops)) ? this.loops : r.loops;
 | 
				
			||||||
      r.delay = ((_isNil(r.delay)) ? this.delay : r.delay) * i;
 | 
					      r.delay = ((_isNil(r.delay)) ? this.delay : r.delay) * i;
 | 
				
			||||||
      r.size = (_isNil(r.size)) ? this.size : r.size;
 | 
					      r.length = (_isNil(r.length)) ? this.length : r.length;
 | 
				
			||||||
      r.align = (_isNil(r.align)) ? this.align : r.align;
 | 
					      r.align = (_isNil(r.align)) ? this.align : r.align;
 | 
				
			||||||
      return r;
 | 
					      return r;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div class="board-line">
 | 
					  <div class="board-line" :class="size">
 | 
				
			||||||
    <div class="board-letter" :ref="'letter' + $index" :class="{'animating': isAnimating[$index]}" v-for="(char, $index) in charsToShow" :key="$index">{{ char }}</div>
 | 
					    <div class="board-letter" :ref="'letter' + $index" :class="{'animating': isAnimating[$index]}" v-for="(char, $index) in charsToShow" :key="$index">{{ char }}</div>
 | 
				
			||||||
  </div>  
 | 
					  </div>  
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
@@ -29,6 +29,12 @@
 | 
				
			|||||||
    position: relative;
 | 
					    position: relative;
 | 
				
			||||||
    line-height: 1;
 | 
					    line-height: 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .big & {
 | 
				
			||||||
 | 
					      font-size: 32px;
 | 
				
			||||||
 | 
					      height: 38px;
 | 
				
			||||||
 | 
					      width: 24px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    &::after {
 | 
					    &::after {
 | 
				
			||||||
      content:' ';
 | 
					      content:' ';
 | 
				
			||||||
      display: inline-block;
 | 
					      display: inline-block;
 | 
				
			||||||
@@ -60,6 +66,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  export default {
 | 
					  export default {
 | 
				
			||||||
    props: {
 | 
					    props: {
 | 
				
			||||||
 | 
					      size: {
 | 
				
			||||||
 | 
					        type: String,
 | 
				
			||||||
 | 
					        default: () => ''
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
      textToShow: {
 | 
					      textToShow: {
 | 
				
			||||||
        type: String,
 | 
					        type: String,
 | 
				
			||||||
        default: () => ''
 | 
					        default: () => ''
 | 
				
			||||||
@@ -68,7 +78,7 @@
 | 
				
			|||||||
        type: Number,
 | 
					        type: Number,
 | 
				
			||||||
        default: () => 0
 | 
					        default: () => 0
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      size: {
 | 
					      length: {
 | 
				
			||||||
        type: Number,
 | 
					        type: Number,
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      loops: {
 | 
					      loops: {
 | 
				
			||||||
@@ -81,10 +91,10 @@
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    data() {
 | 
					    data() {
 | 
				
			||||||
      const newArray = Array.apply(null, Array(this.size)).map(() => ' ');
 | 
					      const newArray = Array.apply(null, Array(this.length)).map(() => ' ');
 | 
				
			||||||
      const newArrayAnimating = Array.apply(null, Array(this.size)).map(() => false);
 | 
					      const newArrayAnimating = Array.apply(null, Array(this.length)).map(() => false);
 | 
				
			||||||
      return {
 | 
					      return {
 | 
				
			||||||
        charsAll: ' ABCDEFGHIJKLMNÑOPQRSTUVWXYZ0123456789-:.>*',
 | 
					        charsAll: ' ABCDEFGHIJKLMNÑOPQRSTUVWXYZ0123456789-:.>*¡!¿?@#',
 | 
				
			||||||
        charsReference: _clone(newArray),
 | 
					        charsReference: _clone(newArray),
 | 
				
			||||||
        charsToShow: _clone(newArray),
 | 
					        charsToShow: _clone(newArray),
 | 
				
			||||||
        isAnimating: newArrayAnimating,
 | 
					        isAnimating: newArrayAnimating,
 | 
				
			||||||
@@ -93,7 +103,7 @@
 | 
				
			|||||||
    computed: {
 | 
					    computed: {
 | 
				
			||||||
      chars() {
 | 
					      chars() {
 | 
				
			||||||
        const text =  this.getText(this.textToShow);
 | 
					        const text =  this.getText(this.textToShow);
 | 
				
			||||||
        const chars = Array.apply(null, Array(this.size)).map(() => ' ');
 | 
					        const chars = Array.apply(null, Array(this.length)).map(() => ' ');
 | 
				
			||||||
        const offset = (this.align === 'left') ? 0 : chars.length - text.length;
 | 
					        const offset = (this.align === 'left') ? 0 : chars.length - text.length;
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        for (let index = 0; index < text.length; index++) {
 | 
					        for (let index = 0; index < text.length; index++) {
 | 
				
			||||||
@@ -122,7 +132,7 @@
 | 
				
			|||||||
        return this.charsAll.indexOf(letter);
 | 
					        return this.charsAll.indexOf(letter);
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      getText(text) {
 | 
					      getText(text) {
 | 
				
			||||||
        return (text.length > this.size) ? text.substring(0, this.size) : text;
 | 
					        return (text.length > this.length) ? text.substring(0, this.length) : text;
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      async startAnimation() {
 | 
					      async startAnimation() {
 | 
				
			||||||
        const cts = _clone(this.charsReference);
 | 
					        const cts = _clone(this.charsReference);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,4 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <loading v-model:active="isLoading"
 | 
					 | 
				
			||||||
                 :can-cancel="false"
 | 
					 | 
				
			||||||
                 :is-full-page="fullPage"/>
 | 
					 | 
				
			||||||
  <section class="section">
 | 
					  <section class="section">
 | 
				
			||||||
      <h1 class="title">Pilotos activos con mas de 200 horas en ACARS</h1>      
 | 
					      <h1 class="title">Pilotos activos con mas de 200 horas en ACARS</h1>      
 | 
				
			||||||
        <table class="table is-striped is-hoverable is-fullwidth">
 | 
					        <table class="table is-striped is-hoverable is-fullwidth">
 | 
				
			||||||
@@ -13,6 +10,15 @@
 | 
				
			|||||||
              <th class="has-text-centered">Horas totales</th>
 | 
					              <th class="has-text-centered">Horas totales</th>
 | 
				
			||||||
            </tr>
 | 
					            </tr>
 | 
				
			||||||
          </thead>
 | 
					          </thead>
 | 
				
			||||||
 | 
					          <tbody v-show="isLoading">
 | 
				
			||||||
 | 
					            <tr>
 | 
				
			||||||
 | 
					              <td colspan="4">
 | 
				
			||||||
 | 
					                <div class="loading-icon">
 | 
				
			||||||
 | 
					                  <font-awesome-icon spin icon="fa-solid fa-spinner" size="2x" />
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					              </td>
 | 
				
			||||||
 | 
					            </tr>
 | 
				
			||||||
 | 
					          </tbody>
 | 
				
			||||||
          <tbody>
 | 
					          <tbody>
 | 
				
			||||||
            <tr v-for="item in whitelist" :key="item.vid">
 | 
					            <tr v-for="item in whitelist" :key="item.vid">
 | 
				
			||||||
              <td class="has-text-centered">
 | 
					              <td class="has-text-centered">
 | 
				
			||||||
@@ -41,7 +47,6 @@
 | 
				
			|||||||
  import moment from 'moment';
 | 
					  import moment from 'moment';
 | 
				
			||||||
  import { getWhitelist } from '../data/http/listRequest.js';
 | 
					  import { getWhitelist } from '../data/http/listRequest.js';
 | 
				
			||||||
  import FormatTime from './FormatTime.vue';
 | 
					  import FormatTime from './FormatTime.vue';
 | 
				
			||||||
  import Loading from 'vue-loading-overlay';
 | 
					 | 
				
			||||||
  import 'vue-loading-overlay/dist/css/index.css';
 | 
					  import 'vue-loading-overlay/dist/css/index.css';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  export default {
 | 
					  export default {
 | 
				
			||||||
@@ -69,7 +74,6 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    components: {
 | 
					    components: {
 | 
				
			||||||
      FormatTime,
 | 
					      FormatTime,
 | 
				
			||||||
      Loading,
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
@@ -1,8 +1,7 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <!-- <loading v-model:active="isLoading"
 | 
					 | 
				
			||||||
                 :can-cancel="false"
 | 
					 | 
				
			||||||
                 :is-full-page="fullPage"/> -->
 | 
					 | 
				
			||||||
  <section class="section">
 | 
					  <section class="section">
 | 
				
			||||||
 | 
					    <!-- <loading class="mt-6" v-model:active="isLoading" 
 | 
				
			||||||
 | 
					                 :can-cancel="false"/> -->
 | 
				
			||||||
      <h1 class="title">Status mensual IVAO</h1> 
 | 
					      <h1 class="title">Status mensual IVAO</h1> 
 | 
				
			||||||
        <table class="table is-striped is-hoverable is-fullwidth" v-if="!$isMobile()">
 | 
					        <table class="table is-striped is-hoverable is-fullwidth" v-if="!$isMobile()">
 | 
				
			||||||
          <thead>
 | 
					          <thead>
 | 
				
			||||||
@@ -14,6 +13,15 @@
 | 
				
			|||||||
              <th class="has-text-centered">Último vuelo</th>
 | 
					              <th class="has-text-centered">Último vuelo</th>
 | 
				
			||||||
            </tr>
 | 
					            </tr>
 | 
				
			||||||
          </thead>
 | 
					          </thead>
 | 
				
			||||||
 | 
					          <tbody v-show="isLoading">
 | 
				
			||||||
 | 
					            <tr>
 | 
				
			||||||
 | 
					              <td colspan="5">
 | 
				
			||||||
 | 
					                <div class="loading-icon">
 | 
				
			||||||
 | 
					                  <font-awesome-icon spin icon="fa-solid fa-spinner" size="2x" />
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					              </td>
 | 
				
			||||||
 | 
					            </tr>
 | 
				
			||||||
 | 
					          </tbody>
 | 
				
			||||||
          <tbody>
 | 
					          <tbody>
 | 
				
			||||||
            <tr v-for="item in list" :key="item.vid">
 | 
					            <tr v-for="item in list" :key="item.vid">
 | 
				
			||||||
              <td class="has-text-centered">
 | 
					              <td class="has-text-centered">
 | 
				
			||||||
@@ -81,7 +89,11 @@
 | 
				
			|||||||
    </section>
 | 
					    </section>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss">
 | 
					<style lang="scss" scoped>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .tag {
 | 
				
			||||||
 | 
					    font-size: 60% !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  .box {
 | 
					  .box {
 | 
				
			||||||
    border: 1px  solid hsl(0, 0%, 86%);
 | 
					    border: 1px  solid hsl(0, 0%, 86%);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -91,7 +103,6 @@
 | 
				
			|||||||
  import moment from 'moment';
 | 
					  import moment from 'moment';
 | 
				
			||||||
  import { getMonthlyList } from '../data/http/listRequest.js';
 | 
					  import { getMonthlyList } from '../data/http/listRequest.js';
 | 
				
			||||||
  import FormatTime from './FormatTime.vue';
 | 
					  import FormatTime from './FormatTime.vue';
 | 
				
			||||||
  import Loading from 'vue-loading-overlay';
 | 
					 | 
				
			||||||
  import 'vue-loading-overlay/dist/css/index.css';
 | 
					  import 'vue-loading-overlay/dist/css/index.css';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  export default {
 | 
					  export default {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,3 +24,9 @@ export async function getFlightplansNow() {
 | 
				
			|||||||
  const response = await get(`${VITE_API_BASE}${VITE_API_PATH_NOW_FLIGHTPLANS}`);
 | 
					  const response = await get(`${VITE_API_BASE}${VITE_API_PATH_NOW_FLIGHTPLANS}`);
 | 
				
			||||||
  return response;
 | 
					  return response;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					export async function getWazzup() {
 | 
				
			||||||
 | 
					  const { VITE_API_BASE } =
 | 
				
			||||||
 | 
					  import.meta.env;
 | 
				
			||||||
 | 
					  const response = await get(`${VITE_API_BASE}/ivao/wazzup`);
 | 
				
			||||||
 | 
					  return response;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										82
									
								
								src/helpers/MapHelper.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,82 @@
 | 
				
			|||||||
 | 
					import { icon } from 'leaflet';
 | 
				
			||||||
 | 
					const popupAnchor = [0, -30];
 | 
				
			||||||
 | 
					export const customIcons = {
 | 
				
			||||||
 | 
					  iconHere: icon({
 | 
				
			||||||
 | 
					    iconUrl: new URL('/src/assets/images/map/marker-here.png',
 | 
				
			||||||
 | 
					      import.meta.url).href,
 | 
				
			||||||
 | 
					    iconSize: [21, 32],
 | 
				
			||||||
 | 
					    iconAnchor: [10, 32],
 | 
				
			||||||
 | 
					    popupAnchor,
 | 
				
			||||||
 | 
					  }),
 | 
				
			||||||
 | 
					  iconLanding: icon({
 | 
				
			||||||
 | 
					    iconUrl: new URL('/src/assets/images/map/marker-landing.png',
 | 
				
			||||||
 | 
					      import.meta.url).href,
 | 
				
			||||||
 | 
					    iconSize: [21, 32],
 | 
				
			||||||
 | 
					    iconAnchor: [10, 32],
 | 
				
			||||||
 | 
					    popupAnchor,
 | 
				
			||||||
 | 
					  }),
 | 
				
			||||||
 | 
					  iconTakeoff: icon({
 | 
				
			||||||
 | 
					    iconUrl: new URL('/src/assets/images/map/marker-takeoff.png',
 | 
				
			||||||
 | 
					      import.meta.url).href,
 | 
				
			||||||
 | 
					    iconSize: [21, 32],
 | 
				
			||||||
 | 
					    iconAnchor: [10, 32],
 | 
				
			||||||
 | 
					    popupAnchor,
 | 
				
			||||||
 | 
					  }),
 | 
				
			||||||
 | 
					  iconPlane: icon({
 | 
				
			||||||
 | 
					    iconUrl: new URL('/src/assets/images/map/plane.png',
 | 
				
			||||||
 | 
					      import.meta.url).href,
 | 
				
			||||||
 | 
					    iconSize: [15, 15],
 | 
				
			||||||
 | 
					    iconAnchor: [15, 15],
 | 
				
			||||||
 | 
					    popupAnchor: [0, -20],
 | 
				
			||||||
 | 
					    className: 'plane'
 | 
				
			||||||
 | 
					  }),
 | 
				
			||||||
 | 
					  ownPlane: icon({
 | 
				
			||||||
 | 
					    iconUrl: new URL('/src/assets/images/map/plane.png',
 | 
				
			||||||
 | 
					      import.meta.url).href,
 | 
				
			||||||
 | 
					    iconSize: [15, 15],
 | 
				
			||||||
 | 
					    iconAnchor: [15, 15],
 | 
				
			||||||
 | 
					    popupAnchor: [0, -20],
 | 
				
			||||||
 | 
					  }),
 | 
				
			||||||
 | 
					  iconLocationRed: icon({
 | 
				
			||||||
 | 
					    iconUrl: new URL('/src/assets/images/map/location-red.png',
 | 
				
			||||||
 | 
					      import.meta.url).href,
 | 
				
			||||||
 | 
					    iconSize: [12, 16],
 | 
				
			||||||
 | 
					    iconAnchor: [6, 16],
 | 
				
			||||||
 | 
					    popupAnchor: [0, -20],
 | 
				
			||||||
 | 
					  }),
 | 
				
			||||||
 | 
					  iconLocationYellow: icon({
 | 
				
			||||||
 | 
					    iconUrl: new URL('/src/assets/images/map/location-yellow.png',
 | 
				
			||||||
 | 
					      import.meta.url).href,
 | 
				
			||||||
 | 
					    iconSize: [12, 16],
 | 
				
			||||||
 | 
					    iconAnchor: [6, 16],
 | 
				
			||||||
 | 
					    popupAnchor: [0, -20],
 | 
				
			||||||
 | 
					  }),
 | 
				
			||||||
 | 
					  iconLocationBlue: icon({
 | 
				
			||||||
 | 
					    iconUrl: new URL('/src/assets/images/map/location-blue.png',
 | 
				
			||||||
 | 
					      import.meta.url).href,
 | 
				
			||||||
 | 
					    iconSize: [12, 16],
 | 
				
			||||||
 | 
					    iconAnchor: [6, 16],
 | 
				
			||||||
 | 
					    popupAnchor: [0, -20],
 | 
				
			||||||
 | 
					  }),
 | 
				
			||||||
 | 
					  iconLocationLightBlue: icon({
 | 
				
			||||||
 | 
					    iconUrl: new URL('/src/assets/images/map/location-lightblue.png',
 | 
				
			||||||
 | 
					      import.meta.url).href,
 | 
				
			||||||
 | 
					    iconSize: [12, 16],
 | 
				
			||||||
 | 
					    iconAnchor: [6, 16],
 | 
				
			||||||
 | 
					    popupAnchor: [0, -20],
 | 
				
			||||||
 | 
					  }),
 | 
				
			||||||
 | 
					  iconLocationGreen: icon({
 | 
				
			||||||
 | 
					    iconUrl: new URL('/src/assets/images/map/location-green.png',
 | 
				
			||||||
 | 
					      import.meta.url).href,
 | 
				
			||||||
 | 
					    iconSize: [12, 16],
 | 
				
			||||||
 | 
					    iconAnchor: [6, 16],
 | 
				
			||||||
 | 
					    popupAnchor: [0, -20],
 | 
				
			||||||
 | 
					  }),
 | 
				
			||||||
 | 
					  iconLocationGray: icon({
 | 
				
			||||||
 | 
					    iconUrl: new URL('/src/assets/images/map/location-gray.png',
 | 
				
			||||||
 | 
					      import.meta.url).href,
 | 
				
			||||||
 | 
					    iconSize: [12, 16],
 | 
				
			||||||
 | 
					    iconAnchor: [6, 16],
 | 
				
			||||||
 | 
					    popupAnchor: [0, -20],
 | 
				
			||||||
 | 
					  }),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										10
									
								
								src/main.js
									
									
									
									
									
								
							
							
						
						@@ -6,12 +6,22 @@ import VueMobileDetection from 'vue-mobile-detection';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import './assets/css/main.css';
 | 
					import './assets/css/main.css';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { library } from '@fortawesome/fontawesome-svg-core';
 | 
				
			||||||
 | 
					import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
 | 
				
			||||||
 | 
					import { faSpinner, faPaperPlane, faDeleteLeft, faXmark } from '@fortawesome/free-solid-svg-icons';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					library.add(faPaperPlane);
 | 
				
			||||||
 | 
					library.add(faDeleteLeft);
 | 
				
			||||||
 | 
					library.add(faXmark);
 | 
				
			||||||
 | 
					library.add(faSpinner);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const pinia = createPinia();
 | 
					const pinia = createPinia();
 | 
				
			||||||
const app = createApp(App);
 | 
					const app = createApp(App);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
app.use(pinia);
 | 
					app.use(pinia);
 | 
				
			||||||
app.use(router);
 | 
					app.use(router);
 | 
				
			||||||
app.use(VueMobileDetection);
 | 
					app.use(VueMobileDetection);
 | 
				
			||||||
 | 
					app.component('font-awesome-icon', FontAwesomeIcon);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
app.mount('#app');
 | 
					app.mount('#app');
 | 
				
			||||||
@@ -1,11 +1,21 @@
 | 
				
			|||||||
import { createRouter, createWebHistory } from 'vue-router';
 | 
					import { createRouter, createWebHashHistory } from 'vue-router';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { useSessionStore } from '../stores/session-store';
 | 
				
			||||||
import TableAcars from '../components/TableAcars.vue';
 | 
					import TableAcars from '../components/TableAcars.vue';
 | 
				
			||||||
import IvaoView from '../views/IvaoView.vue';
 | 
					import IvaoView from '../views/IvaoView.vue';
 | 
				
			||||||
import CabalView from '../views/CabalView.vue';
 | 
					import CabalView from '../views/CabalView.vue';
 | 
				
			||||||
 | 
					import AdminView from '../views/AdminView.vue';
 | 
				
			||||||
 | 
					import MapView from '../views/MapView/MapView.vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const checkRolesFn = (roles) => {
 | 
				
			||||||
 | 
					  return () => {
 | 
				
			||||||
 | 
					    const store = useSessionStore();
 | 
				
			||||||
 | 
					    return store.isAuthenticated && store.hasRoles(roles);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const router = createRouter({
 | 
					const router = createRouter({
 | 
				
			||||||
  history: createWebHistory(
 | 
					  history: createWebHashHistory(),
 | 
				
			||||||
    import.meta.env.BASE_URL),
 | 
					 | 
				
			||||||
  routes: [{
 | 
					  routes: [{
 | 
				
			||||||
      path: '/',
 | 
					      path: '/',
 | 
				
			||||||
      name: 'home',
 | 
					      name: 'home',
 | 
				
			||||||
@@ -16,11 +26,23 @@ const router = createRouter({
 | 
				
			|||||||
      name: 'acars',
 | 
					      name: 'acars',
 | 
				
			||||||
      component: TableAcars,
 | 
					      component: TableAcars,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      path: '/admin',
 | 
				
			||||||
 | 
					      name: 'admin',
 | 
				
			||||||
 | 
					      component: AdminView,
 | 
				
			||||||
 | 
					      beforeEnter: checkRolesFn(['admin']),
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      path: '/cabal',
 | 
					      path: '/cabal',
 | 
				
			||||||
      name: 'cabal',
 | 
					      name: 'cabal',
 | 
				
			||||||
      component: CabalView,
 | 
					      component: CabalView,
 | 
				
			||||||
 | 
					      beforeEnter: checkRolesFn(['admin', 'cabal']),
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      path: '/map',
 | 
				
			||||||
 | 
					      name: 'map',
 | 
				
			||||||
 | 
					      component: MapView
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    // {
 | 
					    // {
 | 
				
			||||||
    //   path: '/about',
 | 
					    //   path: '/about',
 | 
				
			||||||
    //   name: 'about',
 | 
					    //   name: 'about',
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								src/views/AdminView.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <h1>TODO: Admin page</h1>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
@@ -1,8 +1,286 @@
 | 
				
			|||||||
<script setup>
 | 
					<script>
 | 
				
			||||||
 | 
					import SolariBoardRow from '../components/SolariBoardRow.vue';
 | 
				
			||||||
 | 
					export default {
 | 
				
			||||||
 | 
					  mounted() {
 | 
				
			||||||
 | 
					    const sts = localStorage.getItem('defined_statuses');
 | 
				
			||||||
 | 
					    if (sts !== null) {
 | 
				
			||||||
 | 
					      this.addedStatuses = JSON.parse(sts);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  data() {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      route: '',
 | 
				
			||||||
 | 
					      status: '',
 | 
				
			||||||
 | 
					      routeAlign: 'left',
 | 
				
			||||||
 | 
					      statusAlign: 'left',
 | 
				
			||||||
 | 
					      routeToSend: '',
 | 
				
			||||||
 | 
					      routeError: '',
 | 
				
			||||||
 | 
					      statusError: '',
 | 
				
			||||||
 | 
					      addingError: '',
 | 
				
			||||||
 | 
					      statusToSend: '',
 | 
				
			||||||
 | 
					      statusToAdd: '',
 | 
				
			||||||
 | 
					      charRegexp: /[a-zA-Z0-9Ññ\-:.>*¡!¿?@#]/g,
 | 
				
			||||||
 | 
					      defaultStatuses: [
 | 
				
			||||||
 | 
					        'BIENVENIDOS!',
 | 
				
			||||||
 | 
					        'BOARDING',
 | 
				
			||||||
 | 
					        'TAXI OUT',
 | 
				
			||||||
 | 
					        'TAKEOFF',
 | 
				
			||||||
 | 
					        'CLIMB',
 | 
				
			||||||
 | 
					        'DESCENT',
 | 
				
			||||||
 | 
					        'APPROACH',
 | 
				
			||||||
 | 
					        'LANDING',
 | 
				
			||||||
 | 
					        'TAXI TO GATE'
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      addedStatuses: []
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  methods: {
 | 
				
			||||||
 | 
					    setRoute(val = '') {
 | 
				
			||||||
 | 
					      const newVal = val.trim();
 | 
				
			||||||
 | 
					      if (newVal && !this.charRegexp.test(newVal)) {
 | 
				
			||||||
 | 
					        this.routeError = 'Hay carácteres inválidos';
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      this.route = newVal.toUpperCase();
 | 
				
			||||||
 | 
					      this.routeError = '';
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    setStatus(val = '') {
 | 
				
			||||||
 | 
					      const newVal = val.trim();
 | 
				
			||||||
 | 
					      if (newVal && !this.charRegexp.test(newVal)) {
 | 
				
			||||||
 | 
					        this.statusError = 'Hay carácteres inválidos';
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      this.status = newVal.toUpperCase();
 | 
				
			||||||
 | 
					      this.statusError = '';
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    deleteStatus() {
 | 
				
			||||||
 | 
					      this.setStatus(this.statusToSend = '');
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    deleteRoute() {
 | 
				
			||||||
 | 
					      this.setRoute(this.routeToSend = '');
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    setQuickStatus(value) {
 | 
				
			||||||
 | 
					      this.setStatus(this.statusToSend = value);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    addQuickStatus() {
 | 
				
			||||||
 | 
					      const newStatus = this.statusToAdd.trim();
 | 
				
			||||||
 | 
					      if (!newStatus) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (newStatus && !this.charRegexp.test(newStatus)) {
 | 
				
			||||||
 | 
					        this.addingError = 'Hay carácteres inválidos';
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (this.defaultStatuses.indexOf(newStatus) === -1 && this.addedStatuses.indexOf(newStatus) === -1) {
 | 
				
			||||||
 | 
					        this.addedStatuses.push(newStatus.toUpperCase());
 | 
				
			||||||
 | 
					        this.updateStatuses();
 | 
				
			||||||
 | 
					        this.statusToAdd = '';
 | 
				
			||||||
 | 
					        this.addingError = '';
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    deleteQuickStatus(val) {
 | 
				
			||||||
 | 
					      const index = this.addedStatuses.indexOf(val);
 | 
				
			||||||
 | 
					      this.addedStatuses.splice(index, 1);
 | 
				
			||||||
 | 
					      this.updateStatuses();
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    updateStatuses() {
 | 
				
			||||||
 | 
					      localStorage.setItem('defined_statuses', JSON.stringify(this.addedStatuses));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  components: {
 | 
				
			||||||
 | 
					    SolariBoardRow
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <main class="section">
 | 
					  <main class="section">
 | 
				
			||||||
    <h1 class="title is-2"> Capitán Cabal Hub</h1>
 | 
					    <h1 class="title is-4"> Capitán Cabal Hub</h1>
 | 
				
			||||||
 | 
					    <div class="board">
 | 
				
			||||||
 | 
					      <div class="board-content">
 | 
				
			||||||
 | 
					        <h2>Ruta</h2>
 | 
				
			||||||
 | 
					        <h2>Estado</h2>
 | 
				
			||||||
 | 
					        <div class="solari-row">
 | 
				
			||||||
 | 
					          <SolariBoardRow ref="solari" :length="9" size="big" :align="routeAlign"
 | 
				
			||||||
 | 
					                :textToShow="route"></SolariBoardRow>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="solari-row">
 | 
				
			||||||
 | 
					          <SolariBoardRow ref="solari" :length="15" :align="statusAlign"  size="big"
 | 
				
			||||||
 | 
					              :textToShow="status"></SolariBoardRow>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div class="form-board">
 | 
				
			||||||
 | 
					      <div class="field is-horizontal">
 | 
				
			||||||
 | 
					        <div class="field-label">
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="field-body">
 | 
				
			||||||
 | 
					          <p class="title is-5">Quick Statuses</p>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					        <div class="field is-horizontal">
 | 
				
			||||||
 | 
					          <div class="field-label"></div>
 | 
				
			||||||
 | 
					          <div class="field-body">
 | 
				
			||||||
 | 
					            <div class="field">
 | 
				
			||||||
 | 
					              <div class="tags">
 | 
				
			||||||
 | 
					                <span v-for="s in defaultStatuses" @click="setQuickStatus(s)" :key="s" class="tag is-rounded is-medium is-info is-light is-tag-clickable">{{ s }}</span>
 | 
				
			||||||
 | 
					                <span v-for="s in addedStatuses"  @click="setQuickStatus(s)" :key="s" class="tag is-rounded is-medium is-info is-tag-clickable">{{ s }}
 | 
				
			||||||
 | 
					                  <button @click.prevent.stop="deleteQuickStatus(s)" class="delete is-small"></button>
 | 
				
			||||||
 | 
					                </span>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      <div class="field is-horizontal mt-6">
 | 
				
			||||||
 | 
					        <div class="field-label">
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="field-body">
 | 
				
			||||||
 | 
					          <p class="title is-6">Carácteres aceptados: (espacio)ABCDEFGHIJKLMNÑOPQRSTUVWXYZ0123456789-:.>*¡!¿?@#</p>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <div class="field is-horizontal">
 | 
				
			||||||
 | 
					          <div class="field-label">
 | 
				
			||||||
 | 
					            <label class="field">Ruta</label>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div class="field-body">
 | 
				
			||||||
 | 
					            <div class="field">
 | 
				
			||||||
 | 
					              <div class="control">
 | 
				
			||||||
 | 
					                <input class="input" @keydown.enter="setRoute(routeToSend)" maxlength="9" v-model="routeToSend" type="text" placeholder="Route">
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					              <p v-if="routeError" class="help is-danger">{{ routeError }}</p>
 | 
				
			||||||
 | 
					              <p v-if="!routeError" class="help">9 carácteres</p>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div class="field is-narrow">
 | 
				
			||||||
 | 
					              <div class="control">
 | 
				
			||||||
 | 
					                <div class="select is-fullwidth">
 | 
				
			||||||
 | 
					                  <select v-model="routeAlign">
 | 
				
			||||||
 | 
					                    <option value="left">Left</option>
 | 
				
			||||||
 | 
					                    <option value="right">Right</option>
 | 
				
			||||||
 | 
					                  </select>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div class="field">
 | 
				
			||||||
 | 
					              <div class="control">
 | 
				
			||||||
 | 
					                <div class="buttons">
 | 
				
			||||||
 | 
					                  <button class="button is-info" @click="setRoute(routeToSend)"><span class="icon"><font-awesome-icon :icon="['fas', 'paper-plane']" /></span></button>
 | 
				
			||||||
 | 
					                  <button class="button is-danger" @click="deleteRoute"><span class="icon"><font-awesome-icon :icon="['fas', 'delete-left']" /></span></button>
 | 
				
			||||||
 | 
					                </div>  
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="field is-horizontal">
 | 
				
			||||||
 | 
					          <div class="field-label">
 | 
				
			||||||
 | 
					            <label class="field">Estado</label>
 | 
				
			||||||
 | 
					          </div>        
 | 
				
			||||||
 | 
					          <div class="field-body">
 | 
				
			||||||
 | 
					            <div class="field">
 | 
				
			||||||
 | 
					              <div class="control">
 | 
				
			||||||
 | 
					                <input class="input" @keydown.enter="setStatus(statusToSend)" maxlength="15" v-model="statusToSend" type="text" placeholder="Status">
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					              <p v-if="statusError" class="help is-danger">{{ statusError }}</p>
 | 
				
			||||||
 | 
					              <p v-if="!statusError" class="help">15 carácteres</p>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div class="field is-narrow">
 | 
				
			||||||
 | 
					              <div class="control">
 | 
				
			||||||
 | 
					                <div class="select is-fullwidth">
 | 
				
			||||||
 | 
					                  <select v-model="statusAlign">
 | 
				
			||||||
 | 
					                    <option value="left">Left</option>
 | 
				
			||||||
 | 
					                    <option value="right">Right</option>
 | 
				
			||||||
 | 
					                  </select>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div class="field">
 | 
				
			||||||
 | 
					              <div class="control">
 | 
				
			||||||
 | 
					                <div class="buttons">
 | 
				
			||||||
 | 
					                  <button class="button is-info" @click="setStatus(statusToSend)"><span class="icon"><font-awesome-icon :icon="['fas', 'paper-plane']" /></span></button>
 | 
				
			||||||
 | 
					                  <button class="button is-danger" @click="deleteStatus"><span class="icon"><font-awesome-icon :icon="['fas', 'delete-left']" /></span></button>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="field is-horizontal mt-6">
 | 
				
			||||||
 | 
					          <div class="field-label"></div>
 | 
				
			||||||
 | 
					          <div class="field-body">
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            <div class="field is-narrow">
 | 
				
			||||||
 | 
					              <div class="control">
 | 
				
			||||||
 | 
					                <input @keydown.enter="addQuickStatus" :class="{ 'is-danger': addingError }" class="input" maxlength="15" v-model="statusToAdd" type="text" placeholder="Add a Quick Status">
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					              <p v-if="addingError" class="help is-danger">{{ addingError }}</p>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div class="field">
 | 
				
			||||||
 | 
					              <div class="control">
 | 
				
			||||||
 | 
					                <button class="button is-light is-info" @click="addQuickStatus">Add</button>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
  </main>
 | 
					  </main>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style lang="scss" scoped>
 | 
				
			||||||
 | 
					  *{
 | 
				
			||||||
 | 
					    box-sizing: border-box;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .form-board{
 | 
				
			||||||
 | 
					    border: 1px solid #dedede;
 | 
				
			||||||
 | 
					    margin-top: 130px;
 | 
				
			||||||
 | 
					    padding: 16px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .board {
 | 
				
			||||||
 | 
					    margin: 16px auto;
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					    background-color: #333;
 | 
				
			||||||
 | 
					    padding: 32px;
 | 
				
			||||||
 | 
					    border-radius: 4px;
 | 
				
			||||||
 | 
					    text-align: center;
 | 
				
			||||||
 | 
					    height: 130px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .board-content{
 | 
				
			||||||
 | 
					    display: inline-grid;
 | 
				
			||||||
 | 
					    grid-template-columns: auto auto;
 | 
				
			||||||
 | 
					    margin: auto;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .is-tag-clickable {
 | 
				
			||||||
 | 
					    cursor: pointer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &.is-info:hover {
 | 
				
			||||||
 | 
					      background-color: #3488ce;
 | 
				
			||||||
 | 
					      border-color: transparent;
 | 
				
			||||||
 | 
					      color: #fff;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    &.is-light.is-info:hover {
 | 
				
			||||||
 | 
					      background-color: #e4eff9;
 | 
				
			||||||
 | 
					      border-color: transparent;
 | 
				
			||||||
 | 
					      color: #296fa8;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  h2 {
 | 
				
			||||||
 | 
					    margin: 0;
 | 
				
			||||||
 | 
					    text-align: center;
 | 
				
			||||||
 | 
					    color: #eff1ed;
 | 
				
			||||||
 | 
					    text-transform: uppercase;
 | 
				
			||||||
 | 
					    font-size: 60%;
 | 
				
			||||||
 | 
					    font-weight: 600;
 | 
				
			||||||
 | 
					    margin-bottom: 4px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .solari-row {
 | 
				
			||||||
 | 
					    margin-right: 16px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &:last-child {
 | 
				
			||||||
 | 
					      margin-right: 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										8
									
								
								src/views/MapView/MapView.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					<h1>Map</h1>
 | 
				
			||||||
 | 
					<section class="hero">
 | 
				
			||||||
 | 
					  <div class="livemap-wrapper">
 | 
				
			||||||
 | 
					    <l-map ref="map" :zoom="zoom" :center="[51, -0.09]">
 | 
				
			||||||
 | 
					      <l-tile-layer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" layer-type="base" name="OpenStreetMap"></l-tile-layer>
 | 
				
			||||||
 | 
					    </l-map>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</section>
 | 
				
			||||||
							
								
								
									
										14
									
								
								src/views/MapView/MapView.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					h1 {
 | 
				
			||||||
 | 
					  color: green
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.livemap-wrapper {
 | 
				
			||||||
 | 
					  // position: absolute;
 | 
				
			||||||
 | 
					  // bottom: 0;
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  height: 90vh;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					img.leaflet-marker-icon.plane {
 | 
				
			||||||
 | 
					  opacity: 0.5 !important;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										97
									
								
								src/views/MapView/MapView.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,97 @@
 | 
				
			|||||||
 | 
					<template>  
 | 
				
			||||||
 | 
					  <div>
 | 
				
			||||||
 | 
					    <h1>Map</h1>
 | 
				
			||||||
 | 
					    <div id="map" class="livemap-wrapper" ref="map"></div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!-- <template src="./MapView.html">  
 | 
				
			||||||
 | 
					</template> -->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style src="./MapView.scss" lang="scss" scoped>
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					import 'leaflet/dist/leaflet.css';
 | 
				
			||||||
 | 
					import leaflet from 'leaflet'
 | 
				
			||||||
 | 
					import 'leaflet-rotatedmarker';
 | 
				
			||||||
 | 
					// import { LatLng, latLngBounds, latLng, point } from 'leaflet';
 | 
				
			||||||
 | 
					import { customIcons } from '../../helpers/MapHelper';
 | 
				
			||||||
 | 
					import { getWazzup } from '../../data/http/listRequest';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default {
 | 
				
			||||||
 | 
					  props: {
 | 
				
			||||||
 | 
					    tilesUrl: {
 | 
				
			||||||
 | 
					      type: String,
 | 
				
			||||||
 | 
					      default: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
 | 
				
			||||||
 | 
					      // default: 'https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    attribution: {
 | 
				
			||||||
 | 
					      type: String,
 | 
				
			||||||
 | 
					      default: '© <a href=\'https://www.openstreetmap.org/copyright\'>OpenStreetMap</a> contributors',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  data() {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      zoom: 13.5,
 | 
				
			||||||
 | 
					      map: null,
 | 
				
			||||||
 | 
					      tileLayer: null,
 | 
				
			||||||
 | 
					      markers: {},
 | 
				
			||||||
 | 
					      testPilot: null,
 | 
				
			||||||
 | 
					      updateInterval: null
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  async mounted() {
 | 
				
			||||||
 | 
					    this.start();
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  unmounted() {
 | 
				
			||||||
 | 
					    clearInterval(this.updateInterval);
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  methods: {
 | 
				
			||||||
 | 
					    createMap() {
 | 
				
			||||||
 | 
					      this.map = leaflet.map(this.$refs.map).setView([0,0], 4);
 | 
				
			||||||
 | 
					      this.tileLayer = leaflet.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
 | 
				
			||||||
 | 
					        attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
 | 
				
			||||||
 | 
					      }).addTo(this.map);
 | 
				
			||||||
 | 
					    },  
 | 
				
			||||||
 | 
					    async start() {
 | 
				
			||||||
 | 
					      this.createMap();
 | 
				
			||||||
 | 
					      const wazzup = await getWazzup();
 | 
				
			||||||
 | 
					      const pilots= wazzup.clients.pilots;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const latitudes = [];
 | 
				
			||||||
 | 
					      const longitudes = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      pilots.forEach(pilot => {
 | 
				
			||||||
 | 
					        if (pilot.lastTrack) {
 | 
				
			||||||
 | 
					          const { latitude, longitude, heading } = pilot.lastTrack;
 | 
				
			||||||
 | 
					          this.markers[pilot.userId] = leaflet.marker([latitude, longitude], {
 | 
				
			||||||
 | 
					            icon: customIcons.iconPlane
 | 
				
			||||||
 | 
					          }).addTo(this.map).setRotationAngle(heading);
 | 
				
			||||||
 | 
					          latitudes.push(latitude);
 | 
				
			||||||
 | 
					          longitudes.push(longitude);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });      
 | 
				
			||||||
 | 
					      this.updateInterval = setInterval(this.update, 5000);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    async update() {
 | 
				
			||||||
 | 
					      console.log('update');
 | 
				
			||||||
 | 
					      const wazzup = await getWazzup();
 | 
				
			||||||
 | 
					      const pilots= wazzup.clients.pilots;
 | 
				
			||||||
 | 
					      pilots.forEach(pilot => {
 | 
				
			||||||
 | 
					        if (pilot.lastTrack) {
 | 
				
			||||||
 | 
					          const { latitude, longitude, heading } = pilot.lastTrack;
 | 
				
			||||||
 | 
					          let marker = this.markers[pilot.userId];
 | 
				
			||||||
 | 
					          if (marker) {
 | 
				
			||||||
 | 
					            marker.setLatLng([latitude, longitude]).setRotationAngle(heading);
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            this.markers[pilot.userId] = leaflet.marker([latitude, longitude], {
 | 
				
			||||||
 | 
					              icon: customIcons.iconPlane
 | 
				
			||||||
 | 
					            }).addTo(this.map).setRotationAngle(heading);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||