diff --git a/plugins/notifications/frontend/views/NotificationForm.vue b/plugins/notifications/frontend/views/NotificationForm.vue
index fa5cbf65..528df1c5 100644
--- a/plugins/notifications/frontend/views/NotificationForm.vue
+++ b/plugins/notifications/frontend/views/NotificationForm.vue
@@ -231,6 +231,34 @@
+
+
+
+
+ Optional: Filter alerts by asset type, location, or business unit (JSON format)
+
+
+
+
+
+ Minutes until auto-dismiss (0 = manual acknowledgment only)
+
+
+
{{ error }}
@@ -304,6 +332,32 @@ const form = ref({
// site's wall clock, not the viewer's browser zone. Loaded in onMounted.
const siteTimezone = ref(DEFAULT_TZ)
+// Alert scope as text for editing (converts to/from JSON)
+const alertScopeText = ref('')
+
+watch(() => form.value.alertscope, (newVal) => {
+ if (newVal && typeof newVal === 'object') {
+ alertScopeText.value = JSON.stringify(newVal, null, 2)
+ } else if (newVal && typeof newVal === 'string') {
+ alertScopeText.value = newVal
+ } else {
+ alertScopeText.value = ''
+ }
+}, { immediate: true })
+
+watch(alertScopeText, (newVal) => {
+ if (!newVal.trim()) {
+ form.value.alertscope = null
+ return
+ }
+ try {
+ form.value.alertscope = JSON.parse(newVal)
+ } catch (e) {
+ // Keep the text as-is until it's valid JSON
+ form.value.alertscope = newVal
+ }
+})
+
function selectedTypeName() {
const selectedType = types.value.find(t => t.notificationtypeid === parseInt(form.value.notificationtypeid))
return selectedType?.typename?.toLowerCase() || ''
diff --git a/plugins/notifications/migrations/versions/0006_add_fleet_alerts.py b/plugins/notifications/migrations/versions/0006_add_fleet_alerts.py
index 05d142fd..cec8b136 100644
--- a/plugins/notifications/migrations/versions/0006_add_fleet_alerts.py
+++ b/plugins/notifications/migrations/versions/0006_add_fleet_alerts.py
@@ -5,7 +5,7 @@ to support fleet-wide alert broadcasting. Creates notificationacknowledgements
table to track which assets have acknowledged fleet alerts.
Fleet alerts can be scoped to specific asset types, locations, or business units
-via the alertscope JSONB field. alerttimeout=0 means no auto-dismiss (manual only).
+via the alertscope TEXT field (JSON string). alerttimeout=0 means no auto-dismiss (manual only).
Idempotent: column and table creation are skipped when they already exist.
@@ -14,7 +14,6 @@ Revises: notifications0005boardorder
"""
from alembic import op
import sqlalchemy as sa
-from sqlalchemy.dialects.postgresql import JSONB
revision = 'notifications0006fleetalerts'
@@ -43,7 +42,7 @@ def upgrade():
if 'alertscope' not in cols:
op.add_column('notifications',
- sa.Column('alertscope', JSONB, nullable=True))
+ sa.Column('alertscope', sa.Text, nullable=True))
if 'alerttimeout' not in cols:
op.add_column('notifications',