From 736c71eefc0955d6b7b4ea1c0d23a33d7b0d6856 Mon Sep 17 00:00:00 2001 From: Eli Ribble Date: Sun, 22 Mar 2026 00:55:48 +0000 Subject: [PATCH] Start adding other views and our initial stores --- html/template/sync/sudo.html | 420 --------------------------------- sync/routes.go | 2 +- ts/App.vue | 12 +- ts/components/MapAggregate.vue | 180 ++++++++++++++ ts/router.ts | 36 +++ ts/store/communication.ts | 43 ++++ ts/store/user.ts | 50 ++++ ts/view/Communication.vue | 46 +--- ts/view/Home.vue | 1 + 9 files changed, 332 insertions(+), 458 deletions(-) create mode 100644 ts/components/MapAggregate.vue create mode 100644 ts/store/communication.ts create mode 100644 ts/store/user.ts diff --git a/html/template/sync/sudo.html b/html/template/sync/sudo.html index 668d8ebd..013e4c66 100644 --- a/html/template/sync/sudo.html +++ b/html/template/sync/sudo.html @@ -5,424 +5,4 @@ {{ end }} {{ define "content" }} -
-

- Communications Testing -

-
-
- -
-
- SMS Testing -
-
-
-
- - -
-
- - -
- -
-
-
- - -
-
- MMS Testing -
-
-
-
- - -
-
- - -
-
- - -
- -
-
-
-
- -
- -
-
- RCS Testing -
-
-
-
- - -
-
- - -
-
- -
- - -
-
- -
-
-
- - -
-
- Email Testing -
-
-
-
- - -
-
- - -
-
- - -
-
- - -
- -
-
-
-
-
- - -
-
- Server-sent event testing -
-
-
-
-
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
-
- -
-
-
- -
- -
-
- Push Notification Testing -
-
-
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
- - -
- -
-
-
- -
- - -

- User Impersonation -

-
-
- Impersonate User -
-
-
-
- - -
-
- - -
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
User IDNameEmailRoleActions
1001John Doejohn.doe@example.comAdmin - -
1002Jane Smithjane.smith@example.comSupport - -
1003Robert Johnsonrobert@example.comPremium User - -
1004Maria Garciamaria@example.comStandard User - -
-
- - -
-
-
{{ end }} diff --git a/sync/routes.go b/sync/routes.go index 504a6fdb..6e0f75bd 100644 --- a/sync/routes.go +++ b/sync/routes.go @@ -41,11 +41,11 @@ func Router() chi.Router { r.Route("/api", api.AddRoutes) r.Method("GET", "/", authenticatedHandler(getRoot)) + r.Method("GET", "/communication", authenticatedHandler(getRoot)) r.Method("GET", "/intelligence", authenticatedHandler(getRoot)) r.Method("GET", "/admin", authenticatedHandler(getAdminDash)) r.Method("GET", "/cell/{cell}", authenticatedHandler(getCellDetails)) - r.Method("GET", "/communication", authenticatedHandler(getCommunicationRoot)) r.Method("GET", "/configuration", authenticatedHandler(getConfigurationRoot)) r.Method("GET", "/configuration/integration", authenticatedHandler(getConfigurationIntegration)) r.Method("GET", "/configuration/integration/arcgis", authenticatedHandler(getConfigurationIntegrationArcgis)) diff --git a/ts/App.vue b/ts/App.vue index 8c6e1b92..18f3624e 100644 --- a/ts/App.vue +++ b/ts/App.vue @@ -2,15 +2,25 @@
- +
Loading...
+
Error: {{ userStore.error }}
+
diff --git a/ts/router.ts b/ts/router.ts index 494fa7d4..82d75a2b 100644 --- a/ts/router.ts +++ b/ts/router.ts @@ -2,7 +2,13 @@ import { createRouter, createWebHistory } from "vue-router"; import type { RouteRecordRaw } from "vue-router"; import Home from "./view/Home.vue"; import About from "./view/About.vue"; +import Communication from "./view/Communication.vue"; +import Configuration from "./view/Configuration.vue"; import Intelligence from "./view/Intelligence.vue"; +import Operations from "./view/Operations.vue"; +import Planning from "./view/Planning.vue"; +import Review from "./view/Review.vue"; +import Sudo from "./view/Sudo.vue"; const routes: RouteRecordRaw[] = [ { @@ -10,11 +16,41 @@ const routes: RouteRecordRaw[] = [ name: "Home", component: Home, }, + { + path: "/communication", + name: "Communication", + component: Communication, + }, + { + path: "/configuration", + name: "Configuration", + component: Configuration, + }, { path: "/intelligence", name: "Intelligence", component: Intelligence, }, + { + path: "/operations", + name: "Operations", + component: Operations, + }, + { + path: "/planning", + name: "Planning", + component: Planning, + }, + { + path: "/review", + name: "Review", + component: Review, + }, + { + path: "/sudo", + name: "Sudo", + component: Sudo, + }, ]; const router = createRouter({ diff --git a/ts/store/communication.ts b/ts/store/communication.ts new file mode 100644 index 00000000..487bac3a --- /dev/null +++ b/ts/store/communication.ts @@ -0,0 +1,43 @@ +import { defineStore } from "pinia"; +import { ref, computed } from "vue"; + +export const useCommunicationStore = defineStore("communication", () => { + // State + const communications = ref(null); + const loading = ref(false); + const error = ref(null); + + // Actions + async function fetchCommunications() { + loading.value = true; + error.value = null; + try { + const params = new URLSearchParams(); + params.append("sort", "-created"); + if (typeFilter.value) params.append("type", typeFilter.value); + + const response = await fetch( + `$${apiBase.value}/communication?$${params}`, + ); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const data = await response.json(); + communications.value = data.communications; + + // if we already had something selected, reset it using the new data + if (selectedCommunication.value) { + const matching = communications.value.filter((report) => { + return report.id === selectedCommunication.value.id; + }); + if (matching.length > 0) { + selectedCommunication.value = matching[0]; + } + } + } catch (err) { + console.error("Error loading communications:", err); + throw err; + } + } +}); diff --git a/ts/store/user.ts b/ts/store/user.ts new file mode 100644 index 00000000..b84e2c36 --- /dev/null +++ b/ts/store/user.ts @@ -0,0 +1,50 @@ +import { defineStore } from "pinia"; +import { ref, computed } from "vue"; + +export const useUserStore = defineStore("user", () => { + // State + const user = ref(null); + const loading = ref(false); + const error = ref(null); + + // Getters + const isAuthenticated = computed(() => user.value !== null); + const userName = computed(() => user.value?.name ?? ""); + const organization = computed(() => user.value?.organization ?? ""); + + // Actions + async function fetchUser() { + loading.value = true; + error.value = null; + + try { + const response = await fetch("/api/user/self"); + if (!response.ok) throw new Error("Failed to fetch user"); + + user.value = await response.json(); + } catch (e) { + error.value = e.message; + console.error("Error fetching user:", e); + } finally { + loading.value = false; + } + } + + function clearUser() { + user.value = null; + } + + return { + // State + user, + loading, + error, + // Getters + isAuthenticated, + userName, + organization, + // Actions + fetchUser, + clearUser, + }; +}); diff --git a/ts/view/Communication.vue b/ts/view/Communication.vue index 843b93c6..54a5b443 100644 --- a/ts/view/Communication.vue +++ b/ts/view/Communication.vue @@ -133,8 +133,8 @@ import { ref, computed, onMounted, nextTick } from "vue"; import maplibregl from "maplibre-gl"; -// Import your custom components + +import { useCommunicationStore } from "../store/communication"; +import { useUserStore } from "../store/user"; import MapMultipoint from "../components/MapMultipoint.vue"; import TimeRelative from "../components/TimeRelative.vue"; +const user = useUserStore(); +onMounted(() => { + communicationStore.fetchCommunications(); +}); + // Props const props = defineProps({ - organizationId: { - type: String, - required: true, - }, tegolaUrl: { type: String, required: true, @@ -871,35 +874,6 @@ function formatDate(date) { return new Date(date).toLocaleString(); } -async function fetchCommunications() { - try { - const params = new URLSearchParams(); - params.append("sort", "-created"); - if (typeFilter.value) params.append("type", typeFilter.value); - - const response = await fetch(`$${apiBase.value}/communication?$${params}`); - - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - const data = await response.json(); - communications.value = data.communications; - - // if we already had something selected, reset it using the new data - if (selectedCommunication.value) { - const matching = communications.value.filter((report) => { - return report.id === selectedCommunication.value.id; - }); - if (matching.length > 0) { - selectedCommunication.value = matching[0]; - } - } - } catch (err) { - console.error("Error loading communications:", err); - throw err; - } -} - async function loadFromAPI() { loading.value = true; error.value = null; diff --git a/ts/view/Home.vue b/ts/view/Home.vue index 8737a948..78bffc1c 100644 --- a/ts/view/Home.vue +++ b/ts/view/Home.vue @@ -173,6 +173,7 @@