Skip to content

Commit

Permalink
Better live notification label
Browse files Browse the repository at this point in the history
  • Loading branch information
Chocobozzz committed Jan 16, 2025
1 parent d5c4cc2 commit 82246a0
Show file tree
Hide file tree
Showing 13 changed files with 73 additions and 35 deletions.
1 change: 1 addition & 0 deletions client/src/app/header/notification-dropdown.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
</div>

<my-user-notifications
#userNotifications
[ignoreLoadingBar]="true" [infiniteScroll]="false" [itemsPerPage]="10"
[markAllAsReadSubject]="markAllAsReadSubject" (notificationsLoaded)="onNotificationLoaded()"
></my-user-notifications>
Expand Down
3 changes: 3 additions & 0 deletions client/src/app/header/notification-dropdown.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export class NotificationDropdownComponent implements OnInit, OnDestroy {
opened = false

markAllAsReadSubject = new Subject<boolean>()
userNotificationReload = new Subject<boolean>()

private notificationSub: Subscription
private routeSub: Subscription
Expand Down Expand Up @@ -78,6 +79,8 @@ export class NotificationDropdownComponent implements OnInit, OnDestroy {
}

onDropdownShown () {
if (this.loaded) this.userNotificationReload.next(true)

this.opened = true
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,15 @@
<ng-container *ngSwitchCase="15"> <!-- UserNotificationType.ABUSE_STATE_CHANGE -->
<my-global-icon iconName="flag" aria-hidden="true"></my-global-icon>

<div class="message" i18n>
<a (click)="markAsRead(notification)" [routerLink]="notification.abuseUrl" [queryParams]="notification.abuseQueryParams">Your abuse {{ notification.abuse.id }}</a> has been
<ng-container *ngIf="isAccepted(notification)">accepted</ng-container>
<ng-container *ngIf="!isAccepted(notification)">rejected</ng-container>
</div>
@if (isAbuseAccepted(notification)) {
<div class="message" i18n>
<a (click)="markAsRead(notification)" [routerLink]="notification.abuseUrl" [queryParams]="notification.abuseQueryParams">Your abuse {{ notification.abuse.id }}</a> has been accepted
</div>
} @else {
<div class="message" i18n>
<a (click)="markAsRead(notification)" [routerLink]="notification.abuseUrl" [queryParams]="notification.abuseQueryParams">Your abuse {{ notification.abuse.id }}</a> has been accepted
</div>
}
</ng-container>

<ng-container *ngSwitchCase="16"> <!-- UserNotificationType.ABUSE_NEW_MESSAGE -->
Expand Down Expand Up @@ -227,9 +231,15 @@
<img alt="" aria-labelledby="avatar" class="avatar" [src]="notification.video.channel.avatarUrl" />
</a>

<div class="message" i18n>
{{ notification.video.channel.displayName }} is live streaming in <a (click)="markAsRead(notification)" [routerLink]="notification.videoUrl">{{ notification.video.name }}</a>
</div>
@if (isVideoPublished(notification)) {
<div class="message" i18n>
{{ notification.video.channel.displayName }} is live streaming: <a (click)="markAsRead(notification)" [routerLink]="notification.videoUrl">{{ notification.video.name }}</a>
</div>
} @else {
<div class="message" i18n>
{{ notification.video.channel.displayName }} went live: <a (click)="markAsRead(notification)" [routerLink]="notification.videoUrl">{{ notification.video.name }}</a>
</div>
}
} @else {
<my-global-icon iconName="alert" aria-hidden="true"></my-global-icon>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Subject } from 'rxjs'
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'
import { ComponentPagination, hasMoreItems, Notifier } from '@app/core'
import { AbuseState } from '@peertube/peertube-models'
import { AbuseState, VideoState } from '@peertube/peertube-models'
import { CommonModule } from '@angular/common'
import { GlobalIconComponent } from '../shared-icons/global-icon.component'
import { RouterLink } from '@angular/router'
Expand All @@ -22,6 +22,7 @@ export class UserNotificationsComponent implements OnInit {
@Input() infiniteScroll = true
@Input() itemsPerPage = 20
@Input() markAllAsReadSubject: Subject<boolean>
@Input() userNotificationReload: Subject<boolean>

@Output() notificationsLoaded = new EventEmitter()

Expand Down Expand Up @@ -49,9 +50,15 @@ export class UserNotificationsComponent implements OnInit {
if (this.markAllAsReadSubject) {
this.markAllAsReadSubject.subscribe(() => this.markAllAsRead())
}

if (this.userNotificationReload) {
this.userNotificationReload.subscribe(() => this.loadNotifications(true))
}
}

loadNotifications (reset?: boolean) {
if (reset) this.componentPagination.currentPage = 1

const options = {
pagination: this.componentPagination,
ignoreLoadingBar: this.ignoreLoadingBar,
Expand Down Expand Up @@ -123,7 +130,11 @@ export class UserNotificationsComponent implements OnInit {
this.loadNotifications(true)
}

isAccepted (notification: UserNotification) {
isAbuseAccepted (notification: UserNotification) {
return notification.abuse.state === AbuseState.ACCEPTED
}

isVideoPublished (notification: UserNotification) {
return notification.video.state.id === VideoState.PUBLISHED
}
}
5 changes: 5 additions & 0 deletions packages/models/src/users/user-notification.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { FollowState } from '../actors/index.js'
import { AbuseStateType } from '../moderation/index.js'
import { PluginType_Type } from '../plugins/index.js'
import { VideoConstant } from '../videos/video-constant.model.js'
import { VideoStateType } from '../videos/video-state.enum.js'

export const UserNotificationType = {
NEW_VIDEO_FROM_SUBSCRIPTION: 1,
Expand Down Expand Up @@ -49,6 +50,10 @@ export interface VideoInfo {
uuid: string
shortUUID: string
name: string
state: {
id: VideoStateType
label: string
}
}

export interface AvatarInfo {
Expand Down
1 change: 1 addition & 0 deletions packages/tests/src/shared/notifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,7 @@ function checkVideo (video: any, videoName?: string, shortUUID?: string) {
expect(video.shortUUID).to.equal(shortUUID)
}

expect(video.state).to.exist
expect(video.id).to.be.a('number')
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export class NewVideoOrLiveForSubscribers extends AbstractNotification <MVideoAc
return {
to,
subject: channelName + ' is live streaming',
text: `Your subscription ${channelName} is live streaming in "${this.payload.name}".`,
text: `Your subscription ${channelName} is live streaming: "${this.payload.name}".`,
locals: {
title: 'New content ',
action: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export class UserNotificationListQueryBuilder extends AbstractRunQuery {
"Video"."id" AS "Video.id",
"Video"."uuid" AS "Video.uuid",
"Video"."name" AS "Video.name",
"Video"."state" AS "Video.state",
"Video->VideoChannel"."id" AS "Video.VideoChannel.id",
"Video->VideoChannel"."name" AS "Video.VideoChannel.name",
"Video->VideoChannel->Actor"."id" AS "Video.VideoChannel.Actor.id",
Expand All @@ -106,18 +107,21 @@ export class UserNotificationListQueryBuilder extends AbstractRunQuery {
"VideoComment->Video"."id" AS "VideoComment.Video.id",
"VideoComment->Video"."uuid" AS "VideoComment.Video.uuid",
"VideoComment->Video"."name" AS "VideoComment.Video.name",
"VideoComment->Video"."state" AS "VideoComment.Video.state",
"Abuse"."id" AS "Abuse.id",
"Abuse"."state" AS "Abuse.state",
"Abuse->VideoAbuse"."id" AS "Abuse.VideoAbuse.id",
"Abuse->VideoAbuse->Video"."id" AS "Abuse.VideoAbuse.Video.id",
"Abuse->VideoAbuse->Video"."uuid" AS "Abuse.VideoAbuse.Video.uuid",
"Abuse->VideoAbuse->Video"."name" AS "Abuse.VideoAbuse.Video.name",
"Abuse->VideoAbuse->Video"."state" AS "Abuse.VideoAbuse.Video.state",
"Abuse->VideoCommentAbuse"."id" AS "Abuse.VideoCommentAbuse.id",
"Abuse->VideoCommentAbuse->VideoComment"."id" AS "Abuse.VideoCommentAbuse.VideoComment.id",
"Abuse->VideoCommentAbuse->VideoComment"."originCommentId" AS "Abuse.VideoCommentAbuse.VideoComment.originCommentId",
"Abuse->VideoCommentAbuse->VideoComment->Video"."id" AS "Abuse.VideoCommentAbuse.VideoComment.Video.id",
"Abuse->VideoCommentAbuse->VideoComment->Video"."name" AS "Abuse.VideoCommentAbuse.VideoComment.Video.name",
"Abuse->VideoCommentAbuse->VideoComment->Video"."uuid" AS "Abuse.VideoCommentAbuse.VideoComment.Video.uuid",
"Abuse->VideoCommentAbuse->VideoComment->Video"."state" AS "Abuse.VideoCommentAbuse.VideoComment.Video.state",
"Abuse->FlaggedAccount"."id" AS "Abuse.FlaggedAccount.id",
"Abuse->FlaggedAccount"."name" AS "Abuse.FlaggedAccount.name",
"Abuse->FlaggedAccount"."description" AS "Abuse.FlaggedAccount.description",
Expand All @@ -138,13 +142,15 @@ export class UserNotificationListQueryBuilder extends AbstractRunQuery {
"VideoBlacklist->Video"."id" AS "VideoBlacklist.Video.id",
"VideoBlacklist->Video"."uuid" AS "VideoBlacklist.Video.uuid",
"VideoBlacklist->Video"."name" AS "VideoBlacklist.Video.name",
"VideoBlacklist->Video"."state" AS "VideoBlacklist.Video.name",
"VideoImport"."id" AS "VideoImport.id",
"VideoImport"."magnetUri" AS "VideoImport.magnetUri",
"VideoImport"."targetUrl" AS "VideoImport.targetUrl",
"VideoImport"."torrentName" AS "VideoImport.torrentName",
"VideoImport->Video"."id" AS "VideoImport.Video.id",
"VideoImport->Video"."uuid" AS "VideoImport.Video.uuid",
"VideoImport->Video"."name" AS "VideoImport.Video.name",
"VideoImport->Video"."state" AS "VideoImport.Video.name",
"Plugin"."id" AS "Plugin.id",
"Plugin"."name" AS "Plugin.name",
"Plugin"."type" AS "Plugin.type",
Expand Down Expand Up @@ -188,7 +194,8 @@ export class UserNotificationListQueryBuilder extends AbstractRunQuery {
"VideoCaption"."language" AS "VideoCaption.language",
"VideoCaption->Video"."id" AS "VideoCaption.Video.id",
"VideoCaption->Video"."uuid" AS "VideoCaption.Video.uuid",
"VideoCaption->Video"."name" AS "VideoCaption.Video.name"`
"VideoCaption->Video"."name" AS "VideoCaption.Video.name",
"VideoCaption->Video"."state" AS "VideoCaption.Video.state"`
}

private getJoins () {
Expand Down
14 changes: 7 additions & 7 deletions server/core/models/user/user-notification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { ActorFollowModel } from '../actor/actor-follow.js'
import { ApplicationModel } from '../application/application.js'
import { PluginModel } from '../server/plugin.js'
import { SequelizeModel, throwIfNotValid } from '../shared/index.js'
import { getStateLabel } from '../video/formatter/video-api-format.js'
import { VideoBlacklistModel } from '../video/video-blacklist.js'
import { VideoCaptionModel } from '../video/video-caption.js'
import { VideoCommentModel } from '../video/video-comment.js'
Expand Down Expand Up @@ -490,7 +491,11 @@ export class UserNotificationModel extends SequelizeModel<UserNotificationModel>
id: video.id,
uuid: video.uuid,
shortUUID: uuidToShort(video.uuid),
name: video.name
name: video.name,
state: {
id: video.state,
label: getStateLabel(video.state)
}
}
}

Expand All @@ -500,12 +505,7 @@ export class UserNotificationModel extends SequelizeModel<UserNotificationModel>
threadId: abuse.VideoCommentAbuse.VideoComment.getThreadId(),

video: abuse.VideoCommentAbuse.VideoComment.Video
? {
id: abuse.VideoCommentAbuse.VideoComment.Video.id,
name: abuse.VideoCommentAbuse.VideoComment.Video.name,
shortUUID: uuidToShort(abuse.VideoCommentAbuse.VideoComment.Video.uuid),
uuid: abuse.VideoCommentAbuse.VideoComment.Video.uuid
}
? this.formatVideo(abuse.VideoCommentAbuse.VideoComment.Video)
: undefined
}
: undefined
Expand Down
24 changes: 11 additions & 13 deletions server/core/models/video/video-caption.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,16 @@ import { SequelizeModel, buildWhereIdOrUUID, throwIfNotValid } from '../shared/i
import { VideoModel } from './video.js'

export enum ScopeNames {
WITH_VIDEO_UUID_AND_REMOTE = 'WITH_VIDEO_UUID_AND_REMOTE'
CAPTION_WITH_VIDEO = 'CAPTION_WITH_VIDEO'
}

const videoAttributes = [ 'id', 'name', 'remote', 'uuid', 'url', 'state' ]

@Scopes(() => ({
[ScopeNames.WITH_VIDEO_UUID_AND_REMOTE]: {
[ScopeNames.CAPTION_WITH_VIDEO]: {
include: [
{
attributes: [ 'id', 'uuid', 'remote' ],
attributes: videoAttributes,
model: VideoModel.unscoped(),
required: true
}
Expand Down Expand Up @@ -130,17 +132,13 @@ export class VideoCaptionModel extends SequelizeModel<VideoCaptionModel> {
static loadByVideoIdAndLanguage (videoId: string | number, language: string, transaction?: Transaction): Promise<MVideoCaptionVideo> {
const videoInclude = {
model: VideoModel.unscoped(),
attributes: [ 'id', 'name', 'remote', 'uuid', 'url' ],
attributes: videoAttributes,
where: buildWhereIdOrUUID(videoId)
}

const query = {
where: {
language
},
include: [
videoInclude
],
where: { language },
include: [ videoInclude ],
transaction
}

Expand All @@ -155,7 +153,7 @@ export class VideoCaptionModel extends SequelizeModel<VideoCaptionModel> {
include: [
{
model: VideoModel.unscoped(),
attributes: [ 'id', 'remote', 'uuid' ]
attributes: videoAttributes
}
]
}
Expand Down Expand Up @@ -186,7 +184,7 @@ export class VideoCaptionModel extends SequelizeModel<VideoCaptionModel> {
transaction
}

return VideoCaptionModel.scope(ScopeNames.WITH_VIDEO_UUID_AND_REMOTE).findAll(query)
return VideoCaptionModel.scope(ScopeNames.CAPTION_WITH_VIDEO).findAll(query)
}

static async listCaptionsOfMultipleVideos (videoIds: number[], transaction?: Transaction) {
Expand All @@ -200,7 +198,7 @@ export class VideoCaptionModel extends SequelizeModel<VideoCaptionModel> {
transaction
}

const captions = await VideoCaptionModel.scope(ScopeNames.WITH_VIDEO_UUID_AND_REMOTE).findAll<MVideoCaptionVideo>(query)
const captions = await VideoCaptionModel.scope(ScopeNames.CAPTION_WITH_VIDEO).findAll<MVideoCaptionVideo>(query)
const result: { [ id: number ]: MVideoCaptionVideo[] } = {}

for (const id of videoIds) {
Expand Down
4 changes: 2 additions & 2 deletions server/core/types/models/user/user-notification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type Use<K extends keyof UserNotificationModel, M> = PickWith<UserNotificationMo
export module UserNotificationIncludes {
export type ActorImageInclude = Pick<ActorImageModel, 'createdAt' | 'filename' | 'getStaticPath' | 'width' | 'updatedAt'>

export type VideoInclude = Pick<VideoModel, 'id' | 'uuid' | 'name'>
export type VideoInclude = Pick<VideoModel, 'id' | 'uuid' | 'name' | 'state'>
export type VideoIncludeChannel =
VideoInclude &
PickWith<VideoModel, 'VideoChannel', VideoChannelIncludeActor>
Expand Down Expand Up @@ -58,7 +58,7 @@ export module UserNotificationIncludes {
Pick<VideoCommentAbuseModel, 'id'> &
PickWith<VideoCommentAbuseModel, 'VideoComment',
Pick<VideoCommentModel, 'id' | 'originCommentId' | 'getThreadId'> &
PickWith<VideoCommentModel, 'Video', Pick<VideoModel, 'id' | 'name' | 'uuid'>>>
PickWith<VideoCommentModel, 'Video', Pick<VideoModel, 'id' | 'name' | 'uuid' | 'state'>>>

export type AbuseInclude =
Pick<AbuseModel, 'id' | 'state'> &
Expand Down
2 changes: 1 addition & 1 deletion server/core/types/models/video/video-caption.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export type MVideoCaptionLanguageUrl =

export type MVideoCaptionVideo =
MVideoCaption &
Use<'Video', Pick<MVideo, 'id' | 'name' | 'remote' | 'uuid' | 'url' | 'getWatchStaticPath'>>
Use<'Video', Pick<MVideo, 'id' | 'name' | 'remote' | 'uuid' | 'url' | 'state' | 'getWatchStaticPath'>>

// ############################################################################

Expand Down
2 changes: 2 additions & 0 deletions support/doc/api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8252,6 +8252,8 @@ components:
$ref: '#/components/schemas/Video/properties/uuid'
name:
$ref: '#/components/schemas/Video/properties/name'
state:
$ref: '#/components/schemas/Video/properties/state'
Video:
properties:
id:
Expand Down

0 comments on commit 82246a0

Please sign in to comment.