These changes are meant to make it possible for new events that come in to immediately render in the components that depend on them.
This commit is contained in:
parent
74ef9a8b3a
commit
cecb9ef0f0
5 changed files with 92 additions and 59 deletions
|
|
@ -144,6 +144,7 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted } from "vue";
|
||||
import { computedAsync } from "@vueuse/core";
|
||||
import MapMultipoint from "@/components/MapMultipoint.vue";
|
||||
import TimeRelative from "@/components/TimeRelative.vue";
|
||||
|
|
@ -151,6 +152,7 @@ import PublicReportCardCompliance from "@/components/PublicReportCardCompliance.
|
|||
import PublicReportCardNuisance from "@/components/PublicReportCardNuisance.vue";
|
||||
import PublicReportCardWater from "@/components/PublicReportCardWater.vue";
|
||||
import { formatAddress } from "@/format";
|
||||
import { log } from "@/log";
|
||||
import { useStoreResource } from "@/store/resource";
|
||||
import {
|
||||
PublicReport,
|
||||
|
|
@ -169,10 +171,15 @@ const emit = defineEmits<Emits>();
|
|||
const props = defineProps<Props>();
|
||||
const storeResource = useStoreResource();
|
||||
|
||||
const report = computedAsync(() => {
|
||||
return storeResource.publicreport.byURI(props.reportURI);
|
||||
const report = computed(() => {
|
||||
const result = storeResource.publicreport.byURI.get(props.reportURI);
|
||||
log.info("geting computed resource", props.reportURI, result);
|
||||
return result;
|
||||
});
|
||||
function openPhotoViewer(index: number) {
|
||||
emit("viewImage", index);
|
||||
}
|
||||
onMounted(async () => {
|
||||
await storeResource.publicreport.fetchByURI(props.reportURI);
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -203,6 +203,7 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, ref } from "vue";
|
||||
import ListCardCommunication from "@/components/ListCardCommunication.vue";
|
||||
import { log } from "@/log";
|
||||
import { Communication, LogEntry, PublicReport } from "@/type/api";
|
||||
|
||||
interface Props {
|
||||
|
|
@ -263,11 +264,15 @@ const activeFilterCount = computed(() => {
|
|||
|
||||
// Filtered communications
|
||||
const filteredCommunications = computed((): Communication[] => {
|
||||
log.info(
|
||||
"getting communication column list filteredCommunications",
|
||||
props.all,
|
||||
);
|
||||
if (props.all == null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return props.all.filter((comm) => {
|
||||
const filtered = props.all.filter((comm) => {
|
||||
// Status filter
|
||||
const selectedStatuses = Object.entries(statusFilters.value)
|
||||
.filter(([_, isSelected]) => isSelected)
|
||||
|
|
@ -299,5 +304,10 @@ const filteredCommunications = computed((): Communication[] => {
|
|||
|
||||
return true;
|
||||
});
|
||||
const sorted = filtered.sort((a: Communication, b: Communication): number => {
|
||||
return b.created.getTime() - a.created.getTime();
|
||||
});
|
||||
log.info("filtered and sorted to", sorted);
|
||||
return sorted;
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { defineStore } from "pinia";
|
||||
import { ref, shallowRef } from "vue";
|
||||
import { ref, shallowRef, shallowReactive } from "vue";
|
||||
|
||||
import { log } from "@/log";
|
||||
import { SSEManager, SSEMessageResource } from "@/SSEManager";
|
||||
import { useSessionStore } from "@/store/session";
|
||||
|
||||
import { apiClient } from "@/client";
|
||||
import {
|
||||
|
|
@ -23,7 +23,7 @@ function createResourceStore<dto, full extends uriHaver>(
|
|||
api_base: string,
|
||||
from_json: jsonConverter<dto, full>,
|
||||
) {
|
||||
const _resourceByURI = shallowRef<Map<string, full>>(new Map());
|
||||
const byURI = shallowReactive<Map<string, full>>(new Map());
|
||||
const _resourceFetchAll = ref<Promise<full[]> | null>(null);
|
||||
const _resourceFetchByURI = shallowRef<Map<string, Promise<full> | null>>(
|
||||
new Map(),
|
||||
|
|
@ -33,32 +33,43 @@ function createResourceStore<dto, full extends uriHaver>(
|
|||
SSEManager.subscribe((msg: SSEMessageResource) => {
|
||||
if (msg.resource.startsWith(resource_name)) {
|
||||
if (msg.type == "created") {
|
||||
console.log("New resource", resource_name, msg.resource, msg.uri);
|
||||
fetchByURI(msg.uri);
|
||||
} else if (msg.type == "updated") {
|
||||
console.log("Updated resource", resource_name, msg.resource, msg.uri);
|
||||
fetchByURI(msg.uri);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
async function byAll(): Promise<full[]> {
|
||||
const cur = _resourceFetchAll.value;
|
||||
if (cur) {
|
||||
return cur;
|
||||
}
|
||||
return fetchAll();
|
||||
}
|
||||
async function byID(id: string): Promise<full> {
|
||||
const uri = uriFromID(id);
|
||||
return byURI(uri);
|
||||
return ensureURI(uri);
|
||||
}
|
||||
async function byURI(uri: string): Promise<full> {
|
||||
let cur = _resourceFetchByURI.value.get(uri);
|
||||
if (cur) {
|
||||
return cur;
|
||||
async function ensureURI(uri: string): Promise<full> {
|
||||
// Check if we already have the data
|
||||
const existing = byURI.get(uri);
|
||||
if (existing) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
// Check if we're already fetching it
|
||||
let fetchPromise = _resourceFetchByURI.value.get(uri);
|
||||
if (fetchPromise) {
|
||||
return fetchPromise;
|
||||
}
|
||||
|
||||
// Start fetching
|
||||
fetchPromise = fetchByURI(uri);
|
||||
_resourceFetchByURI.value.set(uri, fetchPromise);
|
||||
|
||||
try {
|
||||
const result = await fetchPromise;
|
||||
return result;
|
||||
} finally {
|
||||
// Clean up the promise after it resolves
|
||||
_resourceFetchByURI.value.delete(uri);
|
||||
}
|
||||
cur = fetchByURI(uri);
|
||||
_resourceFetchByURI.value.set(uri, cur);
|
||||
return cur;
|
||||
}
|
||||
async function fetchAll(): Promise<full[]> {
|
||||
/*
|
||||
|
|
@ -71,9 +82,13 @@ function createResourceStore<dto, full extends uriHaver>(
|
|||
const url = `/api${api_base}`;
|
||||
const dtos = (await apiClient.JSONGet(url)) as dto[];
|
||||
const resources = dtos.map((m: dto) => from_json(m));
|
||||
//let new_all = new Map<string, full>();
|
||||
resources.forEach((r: full) => {
|
||||
_resourceByURI.value.set(r.uri, r);
|
||||
byURI.set(r.uri, r);
|
||||
//new_all.set(r.uri, r);
|
||||
log.info("Set", resource_name, r);
|
||||
});
|
||||
//byURI.value = new_all;
|
||||
return resources;
|
||||
}
|
||||
async function fetchByID(id: string): Promise<full> {
|
||||
|
|
@ -89,19 +104,16 @@ function createResourceStore<dto, full extends uriHaver>(
|
|||
}
|
||||
const body: dto = await response.json();
|
||||
const report = from_json(body);
|
||||
_resourceByURI.value.set(report.uri, report);
|
||||
//let new_all = new Map<string, full>(byURI.value);
|
||||
//new_all.set(report.uri, report);
|
||||
byURI.set(report.uri, report);
|
||||
//byURI.value = new_all;
|
||||
return report;
|
||||
} catch (err) {
|
||||
console.error("Error loading users:", err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
function getAll(): full[] | null {
|
||||
if (_resourceFetchAll) {
|
||||
return Array.from(_resourceByURI.value.values());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function hasAll(): boolean {
|
||||
return !!_resourceFetchAll.value;
|
||||
}
|
||||
|
|
@ -118,13 +130,12 @@ function createResourceStore<dto, full extends uriHaver>(
|
|||
return `${api_base}/${id}`;
|
||||
}
|
||||
return {
|
||||
byAll,
|
||||
byID,
|
||||
byURI,
|
||||
ensureURI,
|
||||
fetchAll,
|
||||
fetchByID,
|
||||
fetchByURI,
|
||||
getAll,
|
||||
hasAll,
|
||||
loadingAll,
|
||||
loadingURI,
|
||||
|
|
|
|||
|
|
@ -23,10 +23,7 @@
|
|||
</template>
|
||||
<template #center>
|
||||
<CommunicationColumnDetail
|
||||
:loading="
|
||||
storePublicReport.loading ||
|
||||
storeResource.communication.loadingURI(selectedCommunication?.uri)
|
||||
"
|
||||
:loading="storePublicReport.loading || loadingSelectedCommunication"
|
||||
:mapBounds="mapBounds || undefined"
|
||||
:mapMarkers="mapMarkers"
|
||||
:selectedCommunication="selectedCommunication"
|
||||
|
|
@ -36,10 +33,7 @@
|
|||
</template>
|
||||
<template #right>
|
||||
<CommunicationColumnAction
|
||||
:isLoading="
|
||||
storePublicReport.loading ||
|
||||
storeResource.communication.loadingURI(selectedCommunication?.uri)
|
||||
"
|
||||
:isLoading="storePublicReport.loading || loadingSelectedCommunication"
|
||||
@markInvalid="markInvalid"
|
||||
@markPendingResponse="markPendingResponse"
|
||||
@markPossibleIssue="markPossibleIssue"
|
||||
|
|
@ -78,6 +72,7 @@ import ImageViewerModal from "@/components/ImageViewerModal.vue";
|
|||
import ThreeColumn from "@/components/layout/ThreeColumn.vue";
|
||||
import ToastNotification from "@/components/ToastNotification.vue";
|
||||
import { useQueryParam } from "@/composable/use-query-param";
|
||||
import { log } from "@/log";
|
||||
import { SSEManager } from "@/SSEManager";
|
||||
import { useStoreResource } from "@/store/resource";
|
||||
import { useSessionStore } from "@/store/session";
|
||||
|
|
@ -111,10 +106,13 @@ const currentImages = computed(() => {
|
|||
}
|
||||
return selectedReport.value?.images ?? [];
|
||||
});
|
||||
const loadingSelectedCommunication = computed<boolean>((): boolean => {
|
||||
return !!selectedCommunication.value;
|
||||
});
|
||||
const mapBounds = computed<LngLatBounds | null>((): LngLatBounds | null => {
|
||||
let bounds = new Bounds();
|
||||
const loc = selectedReport.value?.location;
|
||||
console.log("updating for loc", loc);
|
||||
log.info("updating for loc", loc);
|
||||
if (loc && loc.latitude != 0 && loc.longitude != 0) {
|
||||
bounds.addLocation(loc);
|
||||
}
|
||||
|
|
@ -174,15 +172,16 @@ const mapMarkers = computed<Marker[]>((): Marker[] => {
|
|||
}
|
||||
return markers;
|
||||
});
|
||||
const selectedCommunication = computedAsync(
|
||||
async (): Promise<Communication | undefined> => {
|
||||
if (selectedId.value == undefined) {
|
||||
return undefined;
|
||||
}
|
||||
const all = await storeResource.communication.byAll();
|
||||
return all.find((c: Communication) => c.id == selectedId.value);
|
||||
},
|
||||
);
|
||||
const selectedCommunication = computed((): Communication | undefined => {
|
||||
log.info("get selectedCommunication", selectedId.value);
|
||||
if (!selectedId.value) {
|
||||
return undefined;
|
||||
}
|
||||
const all = Array.from(storeResource.communication.byURI.values());
|
||||
const result = all.find((c: Communication) => c.id == selectedId.value);
|
||||
log.info("selectedCommunication", selectedId.value, result);
|
||||
return result;
|
||||
});
|
||||
const selectedReport = computedAsync(
|
||||
async (): Promise<PublicReport | undefined> => {
|
||||
if (
|
||||
|
|
@ -195,14 +194,20 @@ const selectedReport = computedAsync(
|
|||
return await storePublicReport.byURI(selectedCommunication.value.source);
|
||||
},
|
||||
);
|
||||
const visibleCommunications = computedAsync(
|
||||
async (): Promise<Communication[]> => {
|
||||
const all = await storeResource.communication.byAll();
|
||||
return all.filter((c: Communication) => {
|
||||
return c.status == "new" || c.status == "opened";
|
||||
});
|
||||
},
|
||||
);
|
||||
const visibleCommunications = computed((): Communication[] | undefined => {
|
||||
log.info("get visibleCommunications", storeResource.communication.byURI);
|
||||
if (!storeResource.communication.byURI) {
|
||||
return undefined;
|
||||
}
|
||||
const all: Communication[] = Array.from(
|
||||
storeResource.communication.byURI.values(),
|
||||
);
|
||||
const result = all.filter((c: Communication) => {
|
||||
return c.status == "new" || c.status == "opened";
|
||||
});
|
||||
log.info("visibleCommunications:", result);
|
||||
return result;
|
||||
});
|
||||
const handleDeselect = (id: string) => {
|
||||
selectedId.value = undefined;
|
||||
};
|
||||
|
|
@ -256,7 +261,7 @@ async function sendMessage(message: string) {
|
|||
if (selectedCommunication.value == null) return;
|
||||
if (selectedReport.value == null) return;
|
||||
if (session.urls == null) return;
|
||||
console.log("Sending message reporter:", message);
|
||||
log.info("Sending message reporter:", message);
|
||||
|
||||
const payload = {
|
||||
message: message,
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import { Contact } from "@/type/api";
|
|||
|
||||
const storeResource = useStoreResource();
|
||||
const contacts = computedAsync(() => {
|
||||
return storeResource.contact.byAll();
|
||||
return Array.from(storeResource.contact.byURI.values());
|
||||
});
|
||||
const selectedContact = ref<Contact | undefined>(undefined);
|
||||
const handleSelectionChange = (selection: Contact | undefined) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue