Error Toast
The ErrorToast.vue
component is used to display errors and warnings generated by abnormal vehicle or mission statuses.
This component uses the Button and Sonner components from shadcn/vue.
Features
Section titled “Features”- Row of placeholder buttons to generate toasts.
- This component is not complete as it is missing backend integration. To trigger errors/warnings, we have test buttons at the button of the screen.
- Toasts sync between screens.
- Toasts position themselves based on the current screen.
- Toasts don’t expire nor have a limit.
MISSING: Toasts do not persist through page refreshes. This can be added when this component is integrated with the backend.
Toast Synchronization
Section titled “Toast Synchronization”Because we have two application windows or screens, we need a way to synchronize the toasts and interactions between them. Since we do not have backend integration for toasts yet, the current solution is to use Tauri listeners/emitters. This approach will very likely be replaced in the future.
As mentioned earlier, these toasts do not persist on page refreshes. If you refresh one screen/page, the toasts will be out of sync.
First, we need a data structure to store the toasts. Just for our purposes, we can use Maps
which offer fast lookups, flexible types, and preserved order of the added toasts.
const toastMap = new Map<string, string>();var id: String;
Next, setup the listeners for each event— creating toast, dismissing toast, and dismissing all toasts.
When creating the toast, we create a Dismiss button under the action
property.
Do note that Dismiss All is emitted by a test button, opposed to a button that is located on the toast itself like the regular Dismiss.
listen("create-toast", (event) => { const { id, type, title, description } = event.payload as { id: string; type: "error" | "warning" | "info"; title: string; description: string; };
const toastId = toast[type](title, { id, description, duration: Infinity, action: { label: "Dismiss", onClick: () => emit("dismiss-toast", { id }) } // Dismiss button on toast });
toastMap.set(id, String(toastId));});
listen("dismiss-toast", (event) => { const { id } = event.payload as { id: string }; toast.dismiss(id);});
listen("dismiss-all-toasts", (event) => { toast.dismiss();});
Lastly, setup the test buttons to emit the events. Here’s one button as an example.
<Button variant="outline" @click=" () => { id = generateId(); emit('create-toast', { id, type: 'error', title: 'Error: Connection Failure', description: `Unable to connect to \${vehicle}` }); } "> Connection Error</Button>
Toast Positioning
Section titled “Toast Positioning”We do not want the toasts to cover the sidebars, which contain critical information. Thus, we position the ErrorToast
component based on which screen it is.
On the Camera Screen
, the toasts will be positioned at the bottom-right. On the Over View
screen, the toasts will be positioned at the bottom-left.
In the toast component, we retrieve the route and then set toasterPosition
as the result of the computation.
const route = useRoute();
const toasterPosition = computed(() => { return route.path === "/" ? "bottom-right" : "bottom-left"; // '/' is the route of Camera Screen});
Then under <template>
, add the position property.
<template> <Toaster richColors :position="toasterPosition" /> ...
If you also want to know the routes of each screen, go to the respective view and add this:
import { useRoute } from 'vue-router'
const route = useRoute()
...
<template> <div class="text-xs text-gray-500 fixed bottom-2 right-2 z-50"> Route: {{ route.name }} ({{ route.path }}) </div> ...
Toast Expiration
Section titled “Toast Expiration”By default, the Sonner component has a set expiration and limit for the toasts. We can adjust this in the following ways.
Under an event listener that creates a toast, we set the duration
property to Infinity
.
listen("create-toast", (event) => { ...
const toastId = toast[type](title, { id, description, duration: Infinity, // Set duration to infinity action: { label: "Dismiss", onClick: () => emit("dismiss-toast", { id }) } });
...});
Alternatively, we simply set the TOAST_REMOVE_DELAY
to a high number. The number is in seconds.
const TOAST_REMOVE_DELAY = 1000000
You might be able to get away with removing TOAST_REMOVE_DELAY
instead of having both ways to remove toast expiration, but this has not been tested yet.
Toast Limit
Section titled “Toast Limit”To remove the toast limit, simply comment out this line:
const TOAST_LIMIT = 5
If you want to restore this limit, you need to slice the list of toasts stored in the state by adding .slice(0, TOAST_LIMIT)
.
function dispatch(action: Action) { switch (action.type) { case actionTypes.ADD_TOAST: state.value.toasts = [action.toast, ...state.value.toasts].slice(0, TOAST_LIMIT) // Add this break
...
Implementation
Section titled “Implementation”Errors and Warnings
Section titled “Errors and Warnings”Here is the list of Errors or Warnings that can be generated.
- Error: Connection Failure
Unable to connect to [vehicle] - Error: Abnormal Status
Abnormal [vehicle] status (low battery, system error/failure)! - Warning: Signal Integrity
Weak signal integrity/connection lost to [vehicle]! - Warning: Keep-Out
[Vehicle] within [distance] ft of keep-out zone! - Warning: Vehicle Proximity
[Vehicle 1] and [Vehicle 2] are within [distance] ft of each other!