Keep unread notifications in sync with headerbar

This commit is contained in:
Johannes Zellner
2026-01-23 12:26:08 +01:00
parent 2040eb22a2
commit 106cc5238e
3 changed files with 20 additions and 22 deletions
+13 -1
View File
@@ -11,6 +11,7 @@ import { API_ORIGIN, TOKEN_TYPES } from './constants.js';
import { redirectIfNeeded } from './utils.js';
import ProfileModel from './models/ProfileModel.js';
import ProvisionModel from './models/ProvisionModel.js';
import NotificationsModel from './models/NotificationsModel.js';
import DashboardModel from './models/DashboardModel.js';
import BrandingModel from './models/BrandingModel.js';
import Headerbar from './components/Headerbar.vue';
@@ -275,12 +276,14 @@ fetcher.globalOptions.errorHook = (error) => {
const dashboardModel = DashboardModel.create();
const profileModel = ProfileModel.create();
const provisionModel = ProvisionModel.create();
const notificationModel = NotificationsModel.create();
const subscriptionRequiredDialog = useTemplateRef('subscriptionRequiredDialog');
const ready = ref(false);
const view = ref('');
const profile = ref({});
const dashboardDomain = ref('');
const notificationCount = ref(0);
const subscription = ref({
plan: {},
});
@@ -392,6 +395,12 @@ async function refreshConfigAndFeatures() {
dashboardDomain.value = result.adminDomain;
}
async function refreshNotifications() {
const [error, result] = await notificationModel.list(false);
if (error) return console.error(error);
notificationCount.value = result.length;
}
async function onOnline() {
ready.value = true;
await refreshConfigAndFeatures(); // reload dashboard if needed after an update
@@ -407,6 +416,7 @@ provide('features', features);
provide('profile', profile);
provide('refreshProfile', refreshProfile);
provide('refreshFeatures', refreshConfigAndFeatures);
provide('refreshNotifications', refreshNotifications);
provide('dashboardDomain', dashboardDomain);
provide('isMobile', isMobile);
@@ -443,6 +453,8 @@ onMounted(async () => {
console.log(`Cloudron dashboard v${config.value.version}`);
if (profile.value.isAtLeastAdmin) refreshNotifications();
ready.value = true;
});
@@ -463,7 +475,7 @@ onUnmounted(() => {
<SideBar v-if="profile.isAtLeastUserManager" :items="menuItems" :cloudron-name="config.cloudronName" :cloudron-avatar-url="avatarUrl"/>
<div style="flex-grow: 1; display: flex; flex-direction: column; overflow: hidden; height: 100%;">
<Headerbar :config="config" :subscription="subscription"/>
<Headerbar :config="config" :subscription="subscription" :notification-count="notificationCount"/>
<div style="display: flex; justify-content: center; overflow: auto; flex-grow: 1; padding: 0; margin: 0 10px; position: relative;">
<KeepAlive>
+2 -20
View File
@@ -7,11 +7,10 @@ const t = i18n.t;
import { onMounted, onUnmounted, ref, useTemplateRef, inject } from 'vue';
import { marked } from 'marked';
import { Menu, Popover, Icon, InputDialog, Spinner } from '@cloudron/pankow';
import NotificationsModel from '../models/NotificationsModel.js';
import ServicesModel from '../models/ServicesModel.js';
import ProfileModel from '../models/ProfileModel.js';
defineProps(['config', 'subscription']);
defineProps(['config', 'subscription', 'notificationCount']);
const profile = inject('profile');
@@ -25,21 +24,6 @@ function onOpenHelp(popover, event, elem) {
const servicesModel = ServicesModel.create();
const profileModel = ProfileModel.create();
const notificationModel = NotificationsModel.create();
const notifications = ref([]);
async function refresh() {
const [error, result] = await notificationModel.list(false);
if (error) return console.error(error);
result.forEach(n => {
n.isCollapsed = true;
n.busy = false;
});
notifications.value = result;
}
const subscriptionRequiredDialog = inject('subscriptionRequiredDialog');
function onSubscriptionRequired() {
@@ -95,8 +79,6 @@ function onAvatarClick(event) {
}
onMounted(async () => {
if (profile.value.isAtLeastAdmin) await refresh();
await trackPlatformStatus();
});
@@ -136,7 +118,7 @@ onUnmounted(() => {
<!-- Warnings if subscription is expired or unpaid -->
<div v-if="profile.isAtLeastOwner && subscription.plan.id === 'expired'" class="headerbar-action subscription-expired" style="gap: 6px" @click="onSubscriptionRequired()">Subscription Expired</div>
<a class="headerbar-action" v-if="profile.isAtLeastAdmin" href="/#/notifications"><Icon :icon="notifications.length ? 'fas fa-bell' : 'far fa-bell'"/> {{ notifications.length > 99 ? '99+' : notifications.length }}</a>
<a class="headerbar-action" v-if="profile.isAtLeastAdmin" href="/#/notifications"><Icon :icon="notificationCount > 0 ? 'fas fa-bell' : 'far fa-bell'"/> {{ notificationCount > 99 ? '99+' : notificationCount }}</a>
<div class="headerbar-action pankow-no-mobile" v-if="profile.isAtLeastAdmin" ref="helpButton" @click="onOpenHelp(helpPopover, $event, helpButton)"><Icon icon="fa fa-question"/></div>
<!-- <a class="headerbar-action" v-if="profile.isAtLeastAdmin" href="#/support"><Icon icon="fa fa-question"/></a> -->
<a class="headerbar-action" @click.capture="onAvatarClick($event)"><img :src="profile.avatarUrl" @error="event => event.target.src = '/img/avatar-default-symbolic.svg'"/> {{ profile.username }}</a>
+5 -1
View File
@@ -2,7 +2,7 @@
import { marked } from 'marked';
import { eachLimit } from 'async';
import { ref, onMounted } from 'vue';
import { ref, onMounted, inject } from 'vue';
import { Button } from '@cloudron/pankow';
import { prettyDate } from '@cloudron/pankow/utils';
import NotificationsModel from '../models/NotificationsModel.js';
@@ -12,6 +12,7 @@ const notificationsModel = NotificationsModel.create();
const busy = ref(true);
const notifications = ref([]);
const notificationsAllBusy = ref(false);
const refreshNotifications = inject('refreshNotifications');
async function refresh() {
const [error, result] = await notificationsModel.list();
@@ -30,6 +31,7 @@ async function onMarkNotificationRead(notification) {
if (error) return console.error(error);
await refresh();
refreshNotifications();
}
async function onMarkNotificationUnread(notification) {
@@ -38,6 +40,7 @@ async function onMarkNotificationUnread(notification) {
if (error) return console.error(error);
await refresh();
refreshNotifications();
}
async function onMarkAllNotificationRead() {
@@ -50,6 +53,7 @@ async function onMarkAllNotificationRead() {
});
await refresh();
refreshNotifications();
notificationsAllBusy.value = false;
}