mirror of
https://github.com/HangarMC/Hangar.git
synced 2024-11-27 06:01:08 +08:00
More work on notification dropdown
This commit is contained in:
parent
2bd3ba466b
commit
15e2e1813d
@ -22,12 +22,14 @@ import IconMdiBellOutline from "~icons/mdi/bell-outline";
|
||||
import IconMdiBellBadge from "~icons/mdi/bell-badge";
|
||||
import IconMdiAlertOutline from "~icons/mdi/alert-outline";
|
||||
import IconMdiInformationOutline from "~icons/mdi/information-outline";
|
||||
import IconMdiMessageOutline from "~icons/mdi/message-outline";
|
||||
import IconMdiCheck from "~icons/mdi/check";
|
||||
|
||||
import { useAuthStore } from "~/store/auth";
|
||||
import { useAuth } from "~/composables/useAuth";
|
||||
import { useBackendDataStore } from "~/store/backendData";
|
||||
import { authLog } from "~/composables/useLog";
|
||||
import { lastUpdated } from "~/composables/useTime";
|
||||
import { hasPerms } from "~/composables/usePerm";
|
||||
import { NamedPermission } from "~/types/enums";
|
||||
import UserAvatar from "~/components/UserAvatar.vue";
|
||||
@ -43,7 +45,6 @@ import { useInternalApi } from "~/composables/useApi";
|
||||
const settings = useSettingsStore();
|
||||
const { t } = useI18n();
|
||||
const backendData = useBackendDataStore();
|
||||
|
||||
const ctx = useContext();
|
||||
const i18n = useI18n();
|
||||
const authStore = useAuthStore();
|
||||
@ -96,15 +97,19 @@ const auth = useAuth;
|
||||
const authHost = import.meta.env.HANGAR_AUTH_HOST;
|
||||
authLog("render with user " + authStore.user?.name);
|
||||
|
||||
async function markNotificationRead() {
|
||||
function markNotificationsRead() {
|
||||
for (const notification of notifications.value) {
|
||||
if (!notification.read) {
|
||||
useInternalApi(`notifications/${notification.id}`, true, "post").catch((e) => handleRequestError(e, ctx, i18n));
|
||||
notification.read = true;
|
||||
}
|
||||
markNotificationRead(notification);
|
||||
}
|
||||
unreadNotifications.value = false;
|
||||
}
|
||||
|
||||
async function markNotificationRead(notification: HangarNotification) {
|
||||
if (!notification.read) {
|
||||
useInternalApi(`notifications/${notification.id}`, true, "post").catch((e) => handleRequestError(e, ctx, i18n));
|
||||
notification.read = true;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -195,7 +200,6 @@ async function markNotificationRead() {
|
||||
<icon-mdi-white-balance-sunny v-else class="text-[1.2em]"></icon-mdi-white-balance-sunny>
|
||||
</button>
|
||||
<div v-if="authStore.user">
|
||||
<!-- todo: make prettier (show all unread and not just recent 20 unread/read, actually use action field) -->
|
||||
<Menu>
|
||||
<MenuButton>
|
||||
<div class="flex items-center gap-2 rounded-md p-2" hover="text-primary-400 bg-primary-0">
|
||||
@ -205,25 +209,34 @@ async function markNotificationRead() {
|
||||
</MenuButton>
|
||||
<MenuItems class="absolute flex flex-col mt-1 z-10 rounded border-t-2 border-primary-400 background-default drop-shadow-xl overflow-auto shadow-md">
|
||||
<div v-if="notifications.length === 0">
|
||||
<span class="flex shadow-0 p-2 mt-1 ml-3 mr-2">{{ i18n.t("notifications.empty.recent") }}</span>
|
||||
<span class="flex shadow-0 p-2 mt-2 ml-3 mr-2">{{ i18n.t("notifications.empty.recent") }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-for="notification in notifications"
|
||||
:key="notification.id"
|
||||
:class="'text-sm flex shadow-0 p-3 pr-4 inline-flex items-center ' + (!notification.read ? 'bg-blue-100 dark:bg-slate-700' : '')"
|
||||
:class="'text-sm flex shadow-0 p-3 pt-2 pr-4 inline-flex items-center ' + (!notification.read ? 'bg-blue-100 dark:bg-slate-700' : '')"
|
||||
>
|
||||
<div class="text-lg mr-2">
|
||||
<IconMdiInformationOutline v-if="notification.type === 'info'" class="text-lightBlue-600" />
|
||||
<IconMdiCheck v-else-if="notification.type === 'success'" class="text-lime-600" />
|
||||
<IconMdiAlertOutline v-else-if="notification.type === 'warning'" class="text-red-600" />
|
||||
<IconMdiMessageOutline v-else-if="notification.type === 'neutral'" />
|
||||
</div>
|
||||
|
||||
<router-link v-if="notification.action" :to="'/' + notification.action" active-class="">
|
||||
{{ i18n.t(notification.message[0], notification.message.slice(1)) }}
|
||||
<div class="text-xs mt-1">{{ lastUpdated(new Date(notification.createdAt)) }}</div>
|
||||
</router-link>
|
||||
<div v-else>
|
||||
{{ i18n.t(notification.message[0], notification.message.slice(1)) }}
|
||||
<div class="text-xs mt-1">{{ lastUpdated(new Date(notification.createdAt)) }}</div>
|
||||
</div>
|
||||
{{ i18n.t(notification.message[0], notification.message.slice(1)) }}
|
||||
</div>
|
||||
<div class="p-2 mb-1 ml-2 space-x-3 text-sm">
|
||||
<Link to="/notifications"
|
||||
><span>{{ i18n.t("notifications.viewAll") }}</span></Link
|
||||
>
|
||||
<span v-if="unreadNotifications" class="color-primary font-bold hover:(underline)" @click="markNotificationRead">Mark as read</span>
|
||||
<span v-if="unreadNotifications" class="color-primary font-bold hover:(underline)" @click="markNotificationsRead">Mark as read</span>
|
||||
</div>
|
||||
</MenuItems>
|
||||
</Menu>
|
||||
|
1
frontend-new/src/types/internal/users.d.ts
vendored
1
frontend-new/src/types/internal/users.d.ts
vendored
@ -4,6 +4,7 @@ declare module "hangar-internal" {
|
||||
import type { RoleCategory } from "~/types/enums";
|
||||
|
||||
interface HangarNotification {
|
||||
createdAt: string;
|
||||
id: number;
|
||||
action: string;
|
||||
message: string[];
|
||||
|
@ -12,7 +12,7 @@ import java.util.List;
|
||||
public interface HangarNotificationsDAO {
|
||||
|
||||
@RegisterConstructorMapper(HangarNotification.class)
|
||||
@SqlQuery("SELECT n.id, n.type, n.action, n.message_args message, n.read, u.name as origin_user_name" +
|
||||
@SqlQuery("SELECT n.created_at, n.id, n.type, n.action, n.message_args message, n.read, u.name as origin_user_name" +
|
||||
" FROM notifications n" +
|
||||
" LEFT OUTER JOIN users u ON u.id = n.origin_id" +
|
||||
" WHERE n.user_id = :userId" +
|
||||
|
@ -2,10 +2,12 @@ package io.papermc.hangar.model.internal.user.notifications;
|
||||
|
||||
import org.jdbi.v3.core.enums.EnumByOrdinal;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
|
||||
public class HangarNotification {
|
||||
|
||||
private final OffsetDateTime createdAt;
|
||||
private final long id;
|
||||
private final String action;
|
||||
private final List<String> message;
|
||||
@ -13,7 +15,8 @@ public class HangarNotification {
|
||||
private final String originUserName;
|
||||
private final NotificationType type;
|
||||
|
||||
public HangarNotification(long id, String action, List<String> message, boolean read, String originUserName, @EnumByOrdinal NotificationType type) {
|
||||
public HangarNotification(OffsetDateTime createdAt, long id, String action, List<String> message, boolean read, String originUserName, @EnumByOrdinal NotificationType type) {
|
||||
this.createdAt = createdAt;
|
||||
this.id = id;
|
||||
this.action = action;
|
||||
this.message = message;
|
||||
@ -22,6 +25,10 @@ public class HangarNotification {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public OffsetDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
@ -44,10 +44,10 @@ public class NotificationService extends HangarComponent {
|
||||
List<NotificationTable> notificationTables = new ArrayList<>();
|
||||
for (UserTable projectWatcher : projectWatchers) {
|
||||
notificationTables.add(new NotificationTable(
|
||||
projectWatcher.getId(),
|
||||
projectTable.getOwnerName() + "/" + projectTable.getSlug(),
|
||||
projectTable.getId(),
|
||||
new String[]{"notifications.project.newVersion", projectTable.getName(), projectVersionTable.getVersionString()}, NotificationType.NEUTRAL)
|
||||
projectWatcher.getId(),
|
||||
projectTable.getOwnerName() + "/" + projectTable.getSlug() + "/versions/" + projectVersionTable.getVersionString(),
|
||||
projectTable.getId(),
|
||||
new String[]{"notifications.project.newVersion", projectTable.getName(), projectVersionTable.getVersionString()}, NotificationType.NEUTRAL)
|
||||
);
|
||||
}
|
||||
notificationsDAO.insert(notificationTables);
|
||||
@ -58,13 +58,13 @@ public class NotificationService extends HangarComponent {
|
||||
ProjectTable projectTable = projectsDAO.getById(projectVersionTable.getProjectId());
|
||||
permissionService.getProjectMemberPermissions(projectVersionTable.getProjectId()).forEach((user, perm) -> {
|
||||
if (perm.has(Permission.EditVersion)) {
|
||||
if (partial) {
|
||||
notificationTables.add(new NotificationTable(user.getId(), null, null,
|
||||
new String[]{"notifications.project.reviewedPartial", projectTable.getSlug(), projectVersionTable.getVersionString()}, NotificationType.SUCCESS));
|
||||
} else {
|
||||
notificationTables.add(new NotificationTable(user.getId(), null, null,
|
||||
new String[]{"notifications.project.reviewed", projectTable.getSlug(), projectVersionTable.getVersionString()}, NotificationType.SUCCESS));
|
||||
}
|
||||
notificationTables.add(new NotificationTable(
|
||||
user.getId(),
|
||||
projectTable.getOwnerName() + "/" + projectTable.getSlug() + "/versions/" + projectVersionTable.getVersionString(),
|
||||
projectTable.getId(),
|
||||
new String[]{partial ? "notifications.project.reviewedPartial" : "notifications.project.reviewed", projectTable.getSlug(), projectVersionTable.getVersionString()},
|
||||
NotificationType.SUCCESS)
|
||||
);
|
||||
}
|
||||
});
|
||||
notificationsDAO.insert(notificationTables);
|
||||
|
@ -31,7 +31,7 @@ public abstract class JoinableNotificationService<RT extends ExtendedRoleTable<?
|
||||
public void invited(Collection<RT> inviteeRoleTables, J joinable) {
|
||||
Collection<NotificationTable> notificationTables = new HashSet<>();
|
||||
for (RT rt : inviteeRoleTables) {
|
||||
notificationTables.add(new NotificationTable(rt.getUserId(), null, joinable.getId(), new String[]{this.msgPrefix + "invite", rt.getRole().getTitle(), joinable.getName()}, NotificationType.INFO));
|
||||
notificationTables.add(new NotificationTable(rt.getUserId(), "notifications", joinable.getId(), new String[]{this.msgPrefix + "invite", rt.getRole().getTitle(), joinable.getName()}, NotificationType.INFO));
|
||||
}
|
||||
notificationsDAO.insert(notificationTables);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user