diff --git a/eslint-suppressions.json b/eslint-suppressions.json index 78b270677..ad5244136 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -849,11 +849,6 @@ "count": 4 } }, - "src/views/standalone/monitoring/PingLatencyMonitorView.vue": { - "@typescript-eslint/no-explicit-any": { - "count": 1 - } - }, "src/views/standalone/monitoring/RealTimeMonitoringView.vue": { "@typescript-eslint/no-explicit-any": { "count": 1 @@ -916,7 +911,7 @@ }, "src/views/standalone/users_objects/UsersDatabaseView.vue": { "@typescript-eslint/no-explicit-any": { - "count": 2 + "count": 1 } }, "src/views/standalone/vpn/IPsecTunnelView.vue": { diff --git a/package.json b/package.json index 4034d44d0..82d80fd75 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "preview": "vite preview", "build-only": "vite build", "type-check": "vue-tsc --build", - "lint": "eslint . --max-warnings 1229", + "lint": "eslint . --max-warnings 645", "lint-fix": "npm run lint -- --fix", "format": "prettier --list-different src/", "format-fix": "prettier --write src/", diff --git a/src/assets/main.css b/src/assets/main.css index d0f376184..5eff62d1b 100644 --- a/src/assets/main.css +++ b/src/assets/main.css @@ -146,7 +146,7 @@ } @utility text-primary-neutral { - @apply text-gray-600 dark:text-gray-50; + @apply text-gray-900 dark:text-gray-50; } @utility text-secondary { @@ -154,7 +154,7 @@ } @utility text-secondary-neutral { - @apply dark:text-gray-200; + @apply text-gray-700 dark:text-gray-200; } @utility text-tertiary-neutral { @@ -165,6 +165,18 @@ @apply text-green-700 dark:text-green-500; } +@utility text-danger { + @apply text-rose-700 dark:text-rose-500; +} + @utility text-disabled { @apply text-gray-400 dark:text-gray-600; } + +@utility bg-icon-danger { + @apply bg-rose-700 dark:bg-rose-500; +} + +@utility border-elevation-0 { + @apply border-white dark:border-gray-950; +} diff --git a/src/components/NotificationDrawer.vue b/src/components/NotificationDrawer.vue index 545916b6c..add5dadae 100644 --- a/src/components/NotificationDrawer.vue +++ b/src/components/NotificationDrawer.vue @@ -4,18 +4,35 @@ --> diff --git a/src/components/charts/TimeLineChart.vue b/src/components/charts/TimeLineChart.vue index 3a7fefd54..b5f52e0c1 100644 --- a/src/components/charts/TimeLineChart.vue +++ b/src/components/charts/TimeLineChart.vue @@ -125,11 +125,16 @@ const defaultOptions: any = { } const allOptions = computed(() => { - return merge(typeof props.options === 'object' ? props.options : {}, defaultOptions) + const customOptions = props.options && typeof props.options === 'object' ? props.options : {} + return merge({}, defaultOptions, customOptions) }) const chartData: any = computed(() => { - return { labels: props.labels, datasets: props.datasets } + // Deep-clone to strip Vue readonly proxies before handing data to Chart.js. + // Chart.js internally mutates dataset objects (attaches _meta, controllers, etc.) + // and Vue will block those mutations with "target is readonly" warnings if the + // objects are still wrapped in a shallowReadonly prop proxy. + return JSON.parse(JSON.stringify({ labels: props.labels, datasets: props.datasets })) }) const chartStyle = computed(() => { diff --git a/src/components/standalone/SideMenu.vue b/src/components/standalone/SideMenu.vue index 98584f1b7..0f05a14fb 100644 --- a/src/components/standalone/SideMenu.vue +++ b/src/components/standalone/SideMenu.vue @@ -51,6 +51,10 @@ const navigation: Ref = ref([ { name: 'standalone.ping_latency_monitor.title', to: 'monitoring/ping-latency-monitor' + }, + { + name: 'standalone.metrics.title', + to: 'monitoring/metrics' } ] }, diff --git a/src/components/standalone/StandaloneTopBar.vue b/src/components/standalone/StandaloneTopBar.vue index 716bb3c5c..2c092ec9e 100644 --- a/src/components/standalone/StandaloneTopBar.vue +++ b/src/components/standalone/StandaloneTopBar.vue @@ -18,6 +18,7 @@ import { isStandaloneMode } from '@/lib/config' import UciChangesModal from './UciChangesModal.vue' import { faAward, + faBell, faCircleUser, faMoon, faRightFromBracket, @@ -25,6 +26,7 @@ import { } from '@fortawesome/free-solid-svg-icons' import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' import { useSubscriptionStore } from '@/stores/standalone/subscription.ts' +import { useAlerts } from '@/composables/useAlerts' const emit = defineEmits(['openSidebar']) @@ -34,6 +36,7 @@ const themeStore = useThemeStore() const uciChangesStore = useUciPendingChangesStore() const notificationsStore = useNotificationsStore() const subscriptionStore = useSubscriptionStore() +const { notifications: alertNotifications } = useAlerts() const showUciChangesModal = ref(false) const isChangesButtonFlashing = ref(false) @@ -106,6 +109,22 @@ watch( } ) +watch( + () => alertNotifications.value.length, + (newAlerts, oldAlerts) => { + if (newAlerts > oldAlerts) { + // briefly shake notifications icon + setTimeout(() => { + shakeNotificationsIcon.value = true + }, 700) + + setTimeout(() => { + shakeNotificationsIcon.value = false + }, 2700) + } + } +) + onMounted(() => { getSystemBoard() }) @@ -223,16 +242,22 @@ function openNotificationsDrawer() { - - + +
- + @@ -123,7 +130,6 @@ function editZone(zone: Zone) { t('standalone.zones_and_policies.traffic_to_same_zone') }} {{ t('standalone.zones_and_policies.interfaces') }} - {{ t('standalone.zones_and_policies.logging') }} @@ -140,14 +146,33 @@ function editZone(zone: Zone) { -
-
- +
+
+
+
+ +
+ {{ item.name }} +
+
+
+ + + +
- {{ item.name }}
@@ -171,24 +196,38 @@ function editZone(zone: Zone) { -
- + {{ item.input.toUpperCase() }}
- + {{ item.forward.toUpperCase() }}
@@ -198,16 +237,6 @@ function editZone(zone: Zone) { - -
-
-
+ + + + diff --git a/src/views/standalone/monitoring/PingLatencyMonitorView.vue b/src/views/standalone/monitoring/PingLatencyMonitorView.vue index 00810df3f..0f42325d7 100644 --- a/src/views/standalone/monitoring/PingLatencyMonitorView.vue +++ b/src/views/standalone/monitoring/PingLatencyMonitorView.vue @@ -3,10 +3,10 @@ SPDX-License-Identifier: GPL-3.0-or-later --> - diff --git a/src/views/standalone/users_objects/UsersDatabaseView.vue b/src/views/standalone/users_objects/UsersDatabaseView.vue index dd4547543..def523519 100644 --- a/src/views/standalone/users_objects/UsersDatabaseView.vue +++ b/src/views/standalone/users_objects/UsersDatabaseView.vue @@ -7,8 +7,7 @@ import { NeSkeleton, NeInlineNotification, getAxiosErrorMessage, - NeTabs, - NeTooltip + NeTabs } from '@nethesis/vue-components' import { onMounted } from 'vue' import { ref } from 'vue' @@ -31,10 +30,7 @@ const { t } = useI18n() const uciChangesStore = useUciPendingChangesStore() const notificationsStore = useNotificationsStore() -const loading = ref({ - listDatabases: true, - getSubscriptionInfo: true -}) +const loadingDatabases = ref(true) const databases = ref([]) const error = ref({ listDatabases: '', @@ -43,13 +39,12 @@ const error = ref({ getSubscriptionInfoDetails: '' }) const showCreateDrawer = ref(false) -const activeSubscription = ref(false) const { tabs, selectedTab } = useTabs([]) async function fetchDatabases(resetSelectedTab: boolean = false) { try { - loading.value.listDatabases = true + loadingDatabases.value = true if (resetSelectedTab) { selectedTab.value = '' } @@ -65,7 +60,7 @@ async function fetchDatabases(resetSelectedTab: boolean = false) { error.value.listDatabases = t(getAxiosErrorMessage(err)) error.value.listDatabasesDetails = err.toString() } finally { - loading.value.listDatabases = false + loadingDatabases.value = false } } @@ -76,30 +71,14 @@ async function reloadDatabases(resetSelectedTab: boolean = false) { onMounted(() => { fetchDatabases() - fetchSubscriptionInfo() }) - -async function fetchSubscriptionInfo() { - loading.value.getSubscriptionInfo = true - - try { - const res = await ubusCall('ns.subscription', 'info') - - activeSubscription.value = (res.data?.systemd_id && res.data?.active) || false - } catch (err: any) { - error.value.getSubscriptionInfo = t(getAxiosErrorMessage(err)) - error.value.getSubscriptionInfoDetails = err.toString() - } finally { - loading.value.getSubscriptionInfo = false - } -}