diff --git a/src/content/docs/gcs/User Interface/UI Components/error-toast.mdx b/src/content/docs/gcs/User Interface/UI Components/error-toast.mdx
index a69524b..769af1f 100644
--- a/src/content/docs/gcs/User Interface/UI Components/error-toast.mdx
+++ b/src/content/docs/gcs/User Interface/UI Components/error-toast.mdx
@@ -1,49 +1,41 @@
---
-title: Error Toast
+title: Alert Toast
---
import { Aside } from '@astrojs/starlight/components';
-
-
-The `ErrorToast.vue` component is used to display [errors and warnings](#errors-and-warnings) generated by abnormal vehicle or mission statuses.
+The `AlertToast.vue` component is used to display [errors and warnings](#errors-and-warnings) generated by abnormal vehicle or mission statuses.
This component uses the [Button](https://www.shadcn-vue.com/docs/components/button.html) and [Sonner](https://www.shadcn-vue.com/docs/components/sonner.html) components from [shadcn/vue](https://www.shadcn-vue.com/docs/introduction.html).
## 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](#toast-synchronization).
- [Toasts position themselves based on the current screen](#toast-positioning).
- Toasts don't [expire](#toast-expiration) nor have a [limit](#toast-limit).
+- [Backend Integration](#backend-integration).
+- Row of placeholder buttons to generate/test toasts.
+
-*MISSING: Toasts do not persist through page refreshes. This can be added when this component is integrated with the backend.*
### 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.
+Because we have two application windows or screens, we need a way to synchronize the toasts and interactions between them. The system uses Tauri listeners/emitters to ensure alerts appear consistently across all windows.
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.
-
-```js
-// src/components/ErrorToast.vue
-const toastMap = new Map();
-var id: String;
-```
+#### Event System
-Next, setup the listeners for each event-- creating toast, dismissing toast, and dismissing all toasts.
+First, we set up 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.
+Do note that Dismiss All is emitted by a test button, as opposed to a button that is located on the toast itself like the regular Dismiss.
+
+The AlertToast.vue component listens for three events:
+
```js
-// src/components/ErrorToast.vue
+// src/components/AlertToast.vue
listen("create-toast", (event) => {
const { id, type, title, description } = event.payload as {
id: string;
@@ -52,44 +44,43 @@ listen("create-toast", (event) => {
description: string;
};
- const toastId = toast[type](title, {
+ toast[type](title, {
id,
description,
duration: Infinity,
- action: { label: "Dismiss", onClick: () => emit("dismiss-toast", { id }) } // Dismiss button on toast
+ action: { label: "Dismiss", onClick: () => emit("dismiss-toast", { id }) }
});
-
- toastMap.set(id, String(toastId));
});
listen("dismiss-toast", (event) => {
const { id } = event.payload as { id: string };
toast.dismiss(id);
+ console.log(`Alert cleared: ${id}`);
});
-listen("dismiss-all-toasts", (event) => {
+listen("dismiss-all-toasts", () => {
toast.dismiss();
+ console.log(`All toast cleared`);
});
```
Lastly, setup the test buttons to emit the events. Here's one button as an example.
```vue
-// src/components/ErrorToast.vue
+// src/components/AlertToast.vue
```
@@ -97,14 +88,14 @@ Lastly, setup the test buttons to emit the events. Here's one button as an examp
### 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.
+We do not want the toasts to cover the sidebars, which contain critical information. Thus, we position the `AlertToast` 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.
```js
-// src/components/ErrorToast.vue
+// src/components/AlertToast.vue
const route = useRoute();
const toasterPosition = computed(() => {
@@ -115,7 +106,7 @@ const toasterPosition = computed(() => {
Then under ``, add the position property.
```js
-// src/components/ErrorToast.vue
+// src/components/AlertToast.vue
...
@@ -145,7 +136,8 @@ By default, the Sonner component has a set expiration and limit for the toasts.
Under an event listener that creates a toast, we set the `duration` property to `Infinity`.
```ts
-// src/components/ErrorToast.vue
+// src/components/AlertToast.vue
+
listen("create-toast", (event) => {
...
@@ -191,8 +183,6 @@ function dispatch(action: Action) {
...
```
-#### Implementation
-
## Errors and Warnings
Here is the list of Errors or Warnings that can be generated.
@@ -208,6 +198,121 @@ Weak signal integrity/connection lost to [vehicle]!
- **Warning: Vehicle Proximity**
[Vehicle 1] and [Vehicle 2] are within [distance] ft of each other!
+## Backend Integration
+
+The alert system is fully integrated with the backend through a reactive monitoring architecture. When telemetry data is received from RabbitMQ and processed by the Rust backend, it flows through TauRPC to update the `TelemetryStore` (Pinia).
+The `StoresSync` module subscribes to telemetry state changes and triggers the `checkAlerts()` function from the `alertMonitoring` module on every update.
+This module evaluates all vehicle conditions against configured thresholds and emits Tauri events `(create-toast, dismiss-toast)` when alerts are triggered or resolved.
+The AlertToast.vue component listens for these events and displays the corresponding toasts.
+
+### Alert Monitoring Module
+
+The `src/lib/alertMonitoring.ts` module contains all alert detection logic:
+
+#### Configurable Thresholds
+
+```typescript
+// src/lib/alertMonitoring.ts
+export const ALERT_THRESHOLDS = {
+ SIGNAL_STRENGTH: -70, // dBm
+ LOW_BATTERY: 20, // percent
+ PROXIMITY: 100, // feet
+};
+```
+
+Adjust these values to change alert sensitivity.
+
+#### Debouncing Configuration
+
+```typescript
+// src/lib/alertMonitoring.ts
+const ALERT_UPDATE_DEBOUNCE = 3000; // 3 seconds
+```
+
+This prevents excessive toast updates for the same alert. If a condition persists, the alert will update every 3 seconds with the latest data.
+Increase/decrease this value to adjust update frequency
+
+#### Example: Signal Strength Alert
+
+```typescript
+// src/lib/alertMonitoring.ts
+const checkSignalStrength = (vehicle: string, signalStrength: number): void => {
+ if (signalStrength < ALERT_THRESHOLDS.SIGNAL_STRENGTH) {
+ emitAlert(
+ vehicle,
+ "signal_strength",
+ "warning",
+ "Warning: Signal Integrity",
+ `Weak signal integrity/connection lost to ${vehicle}!`
+ );
+ } else {
+ clearAlert(vehicle, "signal_strength");
+ }
+};
+```
+
+### Alert Detection Flow
+
+1. **Telemetry Update**: Backend receives new telemetry data from RabbitMQ
+2. **Store Update**: TauRPC emits `on_updated` event → TelemetryStore syncs
+3. **Subscription Trigger**: StoresSync detects telemetry state change
+4. **Condition Check**: `alertMonitoring.checkAlerts()` evaluates all conditions
+5. **Alert Emission**: If condition met → emit `create-toast` event
+6. **Toast Display**: AlertToast.vue receives event → displays toast
+
+
+### Integration with StoresSync
+
+In `src/lib/StoresSync.ts`, the telemetry store is monitored for changes:
+
+```typescript
+// src/lib/StoresSync.ts
+import { checkAlerts } from "./alertMonitoring";
+
+export const establishTaurpcConnection = () => {
+ // ... existing setup ...
+
+ telemetryStore = telemetryPiniaStore();
+
+ // Subscribe to telemetry changes and check for alerts
+ telemetryStore.$subscribe((mutation, state) => {
+ checkAlerts(state.telemetryState);
+ });
+};
+```
+
+### Alert Deduplication and Updates
+
+#### Key-Based System
+
+Each alert has a unique key generated from the vehicle and alert type:
+
+```typescript
+// src/components/AlertToast.vue
+const getAlertKey = (vehicle: string, type: string): string => {
+ return `${vehicle}_${type}`; // e.g., "ERU_signal_strength"
+};
+```
+
+This key serves two purposes:
+1. **Deduplication**: Prevents multiple toasts for the same condition
+2. **Toast ID**: Used by vue-sonner to update existing toasts
+
+#### How Vue-Sonner Handles Updates
+
+When an alert is emitted with the same ID as an existing toast:
+- Vue-sonner **updates** the existing toast in-place
+- The toast does **not** disappear and reappear
+- Content smoothly transitions to the new description
+
+#### Important Behavior
+
+If a user manually dismisses a toast using the "Dismiss" button, but the underlying condition still exists:
+- The toast will **reappear** on the next telemetry update (after debounce period)
+- This is intentional - alerts represent real conditions that need attention
+- To permanently dismiss: **resolve the underlying condition** (e.g., improve signal strength)
+
+
## Gallery

\ No newline at end of file