diff --git a/meteor/server/publications/system.ts b/meteor/server/publications/system.ts index 306014f446..d95e8eaa98 100644 --- a/meteor/server/publications/system.ts +++ b/meteor/server/publications/system.ts @@ -5,6 +5,7 @@ import { RundownId, RundownPlaylistId, StudioId } from '@sofie-automation/coreli import { check } from 'meteor/check' import { SYSTEM_ID } from '@sofie-automation/meteor-lib/dist/collections/CoreSystem' import { triggerWriteAccessBecauseNoCheckNecessary } from '../security/securityVerify' +import { CorelibPubSub } from '@sofie-automation/corelib/dist/pubsub' meteorPublish(MeteorPubSub.coreSystem, async function (_token: string | undefined) { triggerWriteAccessBecauseNoCheckNecessary() @@ -26,7 +27,7 @@ meteorPublish(MeteorPubSub.coreSystem, async function (_token: string | undefine }) }) -meteorPublish(MeteorPubSub.notificationsForRundown, async function (studioId: StudioId, rundownId: RundownId) { +meteorPublish(CorelibPubSub.notificationsForRundown, async function (studioId: StudioId, rundownId: RundownId) { // HACK: This should do real auth triggerWriteAccessBecauseNoCheckNecessary() @@ -41,7 +42,7 @@ meteorPublish(MeteorPubSub.notificationsForRundown, async function (studioId: St }) meteorPublish( - MeteorPubSub.notificationsForRundownPlaylist, + CorelibPubSub.notificationsForRundownPlaylist, async function (studioId: StudioId, playlistId: RundownPlaylistId) { // HACK: This should do real auth triggerWriteAccessBecauseNoCheckNecessary() diff --git a/packages/corelib/src/pubsub.ts b/packages/corelib/src/pubsub.ts index 5a3bad8b2a..6a6e7783c4 100644 --- a/packages/corelib/src/pubsub.ts +++ b/packages/corelib/src/pubsub.ts @@ -38,6 +38,7 @@ import { BlueprintId, BucketId, RundownPlaylistActivationId, SegmentId, ShowStyl import { PackageInfoDB } from './dataModel/PackageInfos.js' import { UIPieceContentStatus } from './dataModel/PieceContentStatus.js' import { Bucket } from './dataModel/Bucket.js' +import { DBNotificationObj } from './dataModel/Notifications.js' /** * Ids of possible DDP subscriptions for any the UI and gateways accessing the Rundown & RundownPlaylist model. @@ -130,6 +131,14 @@ export enum CorelibPubSub { * Fetch all Expected Package statuses in the specified Studios */ expectedPackageWorkStatuses = 'expectedPackageWorkStatuses', + /** + * Fetch notifications for playlist + */ + notificationsForRundownPlaylist = 'notificationsForRundownPlaylist', + /** + * Fetch notifications for rundown + */ + notificationsForRundown = 'notificationsForRundown', /** * Fetch all Package container statuses in the specified Studios */ @@ -328,6 +337,11 @@ export interface CorelibPubSubTypes { studioIds: StudioId[], token?: string ) => CollectionName.PackageContainerStatuses + [CorelibPubSub.notificationsForRundown]: (studioId: StudioId, rundownId: RundownId) => CollectionName.Notifications + [CorelibPubSub.notificationsForRundownPlaylist]: ( + studioId: StudioId, + playlistId: RundownPlaylistId + ) => CollectionName.Notifications [CorelibPubSub.packageInfos]: (deviceId: PeripheralDeviceId, token?: string) => CollectionName.PackageInfos [CorelibPubSub.uiPieceContentStatuses]: ( @@ -345,6 +359,7 @@ export type CorelibPubSubCollections = { [CollectionName.ExpectedPackages]: ExpectedPackageDBBase [CollectionName.ExpectedPackageWorkStatuses]: ExpectedPackageWorkStatus [CollectionName.ExternalMessageQueue]: ExternalMessageQueueObj + [CollectionName.Notifications]: DBNotificationObj [CollectionName.NrcsIngestDataCache]: NrcsIngestDataCacheObj [CollectionName.PartInstances]: DBPartInstance [CollectionName.PackageContainerStatuses]: PackageContainerStatusDB diff --git a/packages/live-status-gateway-api/api/asyncapi.yaml b/packages/live-status-gateway-api/api/asyncapi.yaml index a3e2d72157..cb1004b851 100644 --- a/packages/live-status-gateway-api/api/asyncapi.yaml +++ b/packages/live-status-gateway-api/api/asyncapi.yaml @@ -47,3 +47,5 @@ channels: $ref: './topics/packages/packagesTopic.yaml' buckets: $ref: './topics/buckets/bucketsTopic.yaml' + notifications: + $ref: './topics/notifications/notificationsTopic.yaml' diff --git a/packages/live-status-gateway-api/api/components/notifications/events/notificationsEvent/notificationsEvent-example.yaml b/packages/live-status-gateway-api/api/components/notifications/events/notificationsEvent/notificationsEvent-example.yaml new file mode 100644 index 0000000000..714cdbfe00 --- /dev/null +++ b/packages/live-status-gateway-api/api/components/notifications/events/notificationsEvent/notificationsEvent-example.yaml @@ -0,0 +1,3 @@ +event: notifications +activeNotifications: + - $ref: '../../notificationObj/notificationObj-example.yaml' diff --git a/packages/live-status-gateway-api/api/components/notifications/events/notificationsEvent/notificationsEvent.yaml b/packages/live-status-gateway-api/api/components/notifications/events/notificationsEvent/notificationsEvent.yaml new file mode 100644 index 0000000000..3afe816c09 --- /dev/null +++ b/packages/live-status-gateway-api/api/components/notifications/events/notificationsEvent/notificationsEvent.yaml @@ -0,0 +1,18 @@ +$defs: + notificationsEvent: + type: object + title: NotificationsEvent + description: Active notifications in Sofie + properties: + event: + type: string + const: notifications + activeNotifications: + description: Active notifications in Sofie + type: array + items: + $ref: '../../notificationObj/notificationObj.yaml#/$defs/NotificationObj' + required: [event, activeNotifications] + additionalProperties: false + examples: + - $ref: './notificationsEvent-example.yaml' diff --git a/packages/live-status-gateway-api/api/components/notifications/messages/notificationsMessage.yaml b/packages/live-status-gateway-api/api/components/notifications/messages/notificationsMessage.yaml new file mode 100644 index 0000000000..0f23f8b8a1 --- /dev/null +++ b/packages/live-status-gateway-api/api/components/notifications/messages/notificationsMessage.yaml @@ -0,0 +1,10 @@ +components: + messages: + notificationsMessage: + messageId: notificationsUpdate + title: Active notifications in Sofie + payload: + $ref: '../events/notificationsEvent/notificationsEvent.yaml#/$defs/notificationsEvent' + examples: + - payload: + $ref: '../events/notificationsEvent/notificationsEvent-example.yaml' diff --git a/packages/live-status-gateway-api/api/components/notifications/notificationObj/notificationObj-example.yaml b/packages/live-status-gateway-api/api/components/notifications/notificationObj/notificationObj-example.yaml new file mode 100644 index 0000000000..67d29a6996 --- /dev/null +++ b/packages/live-status-gateway-api/api/components/notifications/notificationObj/notificationObj-example.yaml @@ -0,0 +1,7 @@ +_id: 'notif123' +severity: error +message: 'disk.space.low' +relatedTo: + $ref: '../target/pieceInstance/notificationTargetPieceInstance-example.yaml' +created: 1694784932 +modified: 1694784950 diff --git a/packages/live-status-gateway-api/api/components/notifications/notificationObj/notificationObj.yaml b/packages/live-status-gateway-api/api/components/notifications/notificationObj/notificationObj.yaml new file mode 100644 index 0000000000..7868f28627 --- /dev/null +++ b/packages/live-status-gateway-api/api/components/notifications/notificationObj/notificationObj.yaml @@ -0,0 +1,33 @@ +$defs: + NotificationObj: + type: object + title: NotificationObj + description: This describes a notification that should be shown to a user. These can come from various sources, and are added and removed dynamically during system usage + required: + - _id + - severity + - message + - relatedTo + - created + properties: + _id: + type: string + description: Unique identifier for the notification + severity: + $ref: '../notificationSeverity.yaml#/$defs/severity' + message: + type: string + description: The message of the notification + relatedTo: + $ref: '../target/notificationTarget.yaml#/$defs/NotificationTarget' + created: + type: integer + format: int64 + description: Unix timestamp of creation + modified: + type: integer + format: int64 + description: Unix timestamp of last modification + additionalProperties: false + examples: + - $ref: './notificationObj-example.yaml' diff --git a/packages/live-status-gateway-api/api/components/notifications/notificationSeverity.yaml b/packages/live-status-gateway-api/api/components/notifications/notificationSeverity.yaml new file mode 100644 index 0000000000..0e55e80481 --- /dev/null +++ b/packages/live-status-gateway-api/api/components/notifications/notificationSeverity.yaml @@ -0,0 +1,9 @@ +$defs: + severity: + type: string + title: NotificationSeverity + description: Severity level of the notification. + enum: + - warning + - error + - info diff --git a/packages/live-status-gateway-api/api/components/notifications/target/notificationTarget.yaml b/packages/live-status-gateway-api/api/components/notifications/target/notificationTarget.yaml new file mode 100644 index 0000000000..488ea87ad9 --- /dev/null +++ b/packages/live-status-gateway-api/api/components/notifications/target/notificationTarget.yaml @@ -0,0 +1,16 @@ +$defs: + NotificationTarget: + title: NotificationTarget + description: Describes what the notification is related to + oneOf: + - $ref: './rundown/notificationTargetRundown.yaml#/$defs/NotificationTargetRundown' + - $ref: './rundownPlaylist/notificationTargetRundownPlaylist.yaml#/$defs/NotificationTargetRundownPlaylist' + - $ref: './partInstance/notificationTargetPartInstance.yaml#/$defs/NotificationTargetPartInstance' + - $ref: './pieceInstance/notificationTargetPieceInstance.yaml#/$defs/NotificationTargetPieceInstance' + - $ref: './unknown/notificationTargetUnknown.yaml#/$defs/NotificationTargetUnknown' + examples: + - $ref: './rundown/notificationTargetRundown-example.yaml' + - $ref: './rundownPlaylist/notificationTargetRundownPlaylist-example.yaml' + - $ref: './partInstance/notificationTargetPartInstance-example.yaml' + - $ref: './pieceInstance/notificationTargetPieceInstance-example.yaml' + - $ref: './unknown/notificationTargetUnknown-example.yaml' diff --git a/packages/live-status-gateway-api/api/components/notifications/target/notificationTargetType.yaml b/packages/live-status-gateway-api/api/components/notifications/target/notificationTargetType.yaml new file mode 100644 index 0000000000..0955708016 --- /dev/null +++ b/packages/live-status-gateway-api/api/components/notifications/target/notificationTargetType.yaml @@ -0,0 +1,11 @@ +$defs: + NotificationTargetType: + type: string + title: NotificationTargetType + description: Possible NotificationTarget types + enum: + - rundown + - playlist + - partInstance + - pieceInstance + - unknown diff --git a/packages/live-status-gateway-api/api/components/notifications/target/partInstance/notificationTargetPartInstance-example.yaml b/packages/live-status-gateway-api/api/components/notifications/target/partInstance/notificationTargetPartInstance-example.yaml new file mode 100644 index 0000000000..4274914809 --- /dev/null +++ b/packages/live-status-gateway-api/api/components/notifications/target/partInstance/notificationTargetPartInstance-example.yaml @@ -0,0 +1,4 @@ +type: partInstance +studioId: studio01 +rundownId: rd123 +partInstanceId: pi789 diff --git a/packages/live-status-gateway-api/api/components/notifications/target/partInstance/notificationTargetPartInstance.yaml b/packages/live-status-gateway-api/api/components/notifications/target/partInstance/notificationTargetPartInstance.yaml new file mode 100644 index 0000000000..c0a8893ecb --- /dev/null +++ b/packages/live-status-gateway-api/api/components/notifications/target/partInstance/notificationTargetPartInstance.yaml @@ -0,0 +1,18 @@ +$defs: + NotificationTargetPartInstance: + type: object + title: NotificationTargetPartInstance + required: [type, studioId, rundownId, partInstanceId] + properties: + type: + $ref: '../notificationTargetType.yaml#/$defs/NotificationTargetType' + const: partInstance + studioId: + type: string + rundownId: + type: string + partInstanceId: + type: string + additionalProperties: false + examples: + - $ref: './notificationTargetPartInstance-example.yaml' diff --git a/packages/live-status-gateway-api/api/components/notifications/target/pieceInstance/notificationTargetPieceInstance-example.yaml b/packages/live-status-gateway-api/api/components/notifications/target/pieceInstance/notificationTargetPieceInstance-example.yaml new file mode 100644 index 0000000000..43f8d795ee --- /dev/null +++ b/packages/live-status-gateway-api/api/components/notifications/target/pieceInstance/notificationTargetPieceInstance-example.yaml @@ -0,0 +1,5 @@ +type: pieceInstance +studioId: studio01 +rundownId: rd123 +partInstanceId: pi789 +pieceInstanceId: pc1011 diff --git a/packages/live-status-gateway-api/api/components/notifications/target/pieceInstance/notificationTargetPieceInstance.yaml b/packages/live-status-gateway-api/api/components/notifications/target/pieceInstance/notificationTargetPieceInstance.yaml new file mode 100644 index 0000000000..ccae45683d --- /dev/null +++ b/packages/live-status-gateway-api/api/components/notifications/target/pieceInstance/notificationTargetPieceInstance.yaml @@ -0,0 +1,20 @@ +$defs: + NotificationTargetPieceInstance: + type: object + title: NotificationTargetPieceInstance + required: [type, studioId, rundownId, partInstanceId, pieceInstanceId] + properties: + type: + $ref: '../notificationTargetType.yaml#/$defs/NotificationTargetType' + const: pieceInstance + studioId: + type: string + rundownId: + type: string + partInstanceId: + type: string + pieceInstanceId: + type: string + additionalProperties: false + examples: + - $ref: './notificationTargetPieceInstance-example.yaml' diff --git a/packages/live-status-gateway-api/api/components/notifications/target/rundown/notificationTargetRundown-example.yaml b/packages/live-status-gateway-api/api/components/notifications/target/rundown/notificationTargetRundown-example.yaml new file mode 100644 index 0000000000..b2cccadde1 --- /dev/null +++ b/packages/live-status-gateway-api/api/components/notifications/target/rundown/notificationTargetRundown-example.yaml @@ -0,0 +1,3 @@ +type: rundown +studioId: studio01 +rundownId: rd123 diff --git a/packages/live-status-gateway-api/api/components/notifications/target/rundown/notificationTargetRundown.yaml b/packages/live-status-gateway-api/api/components/notifications/target/rundown/notificationTargetRundown.yaml new file mode 100644 index 0000000000..d6e5e11981 --- /dev/null +++ b/packages/live-status-gateway-api/api/components/notifications/target/rundown/notificationTargetRundown.yaml @@ -0,0 +1,16 @@ +$defs: + NotificationTargetRundown: + type: object + title: NotificationTargetRundown + required: [type, studioId, rundownId] + properties: + type: + $ref: '../notificationTargetType.yaml#/$defs/NotificationTargetType' + const: rundown + studioId: + type: string + rundownId: + type: string + additionalProperties: false + examples: + - $ref: './notificationTargetRundown-example.yaml' diff --git a/packages/live-status-gateway-api/api/components/notifications/target/rundownPlaylist/notificationTargetRundownPlaylist-example.yaml b/packages/live-status-gateway-api/api/components/notifications/target/rundownPlaylist/notificationTargetRundownPlaylist-example.yaml new file mode 100644 index 0000000000..9730599bd0 --- /dev/null +++ b/packages/live-status-gateway-api/api/components/notifications/target/rundownPlaylist/notificationTargetRundownPlaylist-example.yaml @@ -0,0 +1,3 @@ +type: playlist +studioId: studio01 +playlistId: pl456 diff --git a/packages/live-status-gateway-api/api/components/notifications/target/rundownPlaylist/notificationTargetRundownPlaylist.yaml b/packages/live-status-gateway-api/api/components/notifications/target/rundownPlaylist/notificationTargetRundownPlaylist.yaml new file mode 100644 index 0000000000..8d5af3af22 --- /dev/null +++ b/packages/live-status-gateway-api/api/components/notifications/target/rundownPlaylist/notificationTargetRundownPlaylist.yaml @@ -0,0 +1,16 @@ +$defs: + NotificationTargetRundownPlaylist: + type: object + title: NotificationTargetRundownPlaylist + required: [type, studioId, playlistId] + properties: + type: + $ref: '../notificationTargetType.yaml#/$defs/NotificationTargetType' + const: playlist + studioId: + type: string + playlistId: + type: string + additionalProperties: false + examples: + - $ref: './notificationTargetRundownPlaylist-example.yaml' diff --git a/packages/live-status-gateway-api/api/components/notifications/target/unknown/notificationTargetUnknown-example.yaml b/packages/live-status-gateway-api/api/components/notifications/target/unknown/notificationTargetUnknown-example.yaml new file mode 100644 index 0000000000..5fcf07e456 --- /dev/null +++ b/packages/live-status-gateway-api/api/components/notifications/target/unknown/notificationTargetUnknown-example.yaml @@ -0,0 +1 @@ +type: unknown diff --git a/packages/live-status-gateway-api/api/components/notifications/target/unknown/notificationTargetUnknown.yaml b/packages/live-status-gateway-api/api/components/notifications/target/unknown/notificationTargetUnknown.yaml new file mode 100644 index 0000000000..7969843797 --- /dev/null +++ b/packages/live-status-gateway-api/api/components/notifications/target/unknown/notificationTargetUnknown.yaml @@ -0,0 +1,12 @@ +$defs: + NotificationTargetUnknown: + type: object + title: NotificationTargetUnknown + required: [type] + properties: + type: + $ref: '../notificationTargetType.yaml#/$defs/NotificationTargetType' + const: unknown + additionalProperties: false + examples: + - $ref: './notificationTargetUnknown-example.yaml' diff --git a/packages/live-status-gateway-api/api/components/subscriptions/subscriptionName.yaml b/packages/live-status-gateway-api/api/components/subscriptions/subscriptionName.yaml index c77285dd71..f4e4e9369c 100644 --- a/packages/live-status-gateway-api/api/components/subscriptions/subscriptionName.yaml +++ b/packages/live-status-gateway-api/api/components/subscriptions/subscriptionName.yaml @@ -9,5 +9,6 @@ $defs: - activePieces - segments - adLibs + - notifications - buckets - packages diff --git a/packages/live-status-gateway-api/api/topics/notifications/notificationsTopic.yaml b/packages/live-status-gateway-api/api/topics/notifications/notificationsTopic.yaml new file mode 100644 index 0000000000..68391b15ed --- /dev/null +++ b/packages/live-status-gateway-api/api/topics/notifications/notificationsTopic.yaml @@ -0,0 +1,7 @@ +description: Notifications topic for websocket subscriptions. +subscribe: + operationId: receiveNotifications + description: Server sends notifications updates + message: + oneOf: + - $ref: '../../components/notifications/messages/notificationsMessage.yaml#/components/messages/notificationsMessage' diff --git a/packages/live-status-gateway-api/src/generated/asyncapi.yaml b/packages/live-status-gateway-api/src/generated/asyncapi.yaml index a5f3ced0e7..b747e97a84 100644 --- a/packages/live-status-gateway-api/src/generated/asyncapi.yaml +++ b/packages/live-status-gateway-api/src/generated/asyncapi.yaml @@ -158,6 +158,7 @@ channels: - activePieces - segments - adLibs + - notifications - buckets - packages status: @@ -1246,3 +1247,212 @@ channels: - *a46 examples: - payload: *a47 + notifications: + description: Notifications topic for websocket subscriptions. + subscribe: + operationId: receiveNotifications + description: Server sends notifications updates + message: + oneOf: + - messageId: notificationsUpdate + title: Active notifications in Sofie + payload: + type: object + title: NotificationsEvent + description: Active notifications in Sofie + properties: + event: + type: string + const: notifications + activeNotifications: + description: Active notifications in Sofie + type: array + items: + type: object + title: NotificationObj + description: This describes a notification that should be shown to a user. These + can come from various sources, and are added and removed + dynamically during system usage + required: + - _id + - severity + - message + - relatedTo + - created + properties: + _id: + type: string + description: Unique identifier for the notification + severity: + type: string + title: NotificationSeverity + description: Severity level of the notification. + enum: + - warning + - error + - info + message: + type: string + description: The message of the notification + relatedTo: + title: NotificationTarget + description: Describes what the notification is related to + oneOf: + - type: object + title: NotificationTargetRundown + required: + - type + - studioId + - rundownId + properties: + type: + const: rundown + type: string + title: NotificationTargetType + description: Possible NotificationTarget types + enum: &a48 + - rundown + - playlist + - partInstance + - pieceInstance + - unknown + studioId: + type: string + rundownId: + type: string + additionalProperties: false + examples: + - &a49 + type: rundown + studioId: studio01 + rundownId: rd123 + - type: object + title: NotificationTargetRundownPlaylist + required: + - type + - studioId + - playlistId + properties: + type: + const: playlist + type: string + title: NotificationTargetType + description: Possible NotificationTarget types + enum: *a48 + studioId: + type: string + playlistId: + type: string + additionalProperties: false + examples: + - &a50 + type: playlist + studioId: studio01 + playlistId: pl456 + - type: object + title: NotificationTargetPartInstance + required: + - type + - studioId + - rundownId + - partInstanceId + properties: + type: + const: partInstance + type: string + title: NotificationTargetType + description: Possible NotificationTarget types + enum: *a48 + studioId: + type: string + rundownId: + type: string + partInstanceId: + type: string + additionalProperties: false + examples: + - &a51 + type: partInstance + studioId: studio01 + rundownId: rd123 + partInstanceId: pi789 + - type: object + title: NotificationTargetPieceInstance + required: + - type + - studioId + - rundownId + - partInstanceId + - pieceInstanceId + properties: + type: + const: pieceInstance + type: string + title: NotificationTargetType + description: Possible NotificationTarget types + enum: *a48 + studioId: + type: string + rundownId: + type: string + partInstanceId: + type: string + pieceInstanceId: + type: string + additionalProperties: false + examples: + - &a52 + type: pieceInstance + studioId: studio01 + rundownId: rd123 + partInstanceId: pi789 + pieceInstanceId: pc1011 + - type: object + title: NotificationTargetUnknown + required: + - type + properties: + type: + const: unknown + type: string + title: NotificationTargetType + description: Possible NotificationTarget types + enum: *a48 + additionalProperties: false + examples: + - &a53 + type: unknown + examples: + - *a49 + - *a50 + - *a51 + - *a52 + - *a53 + created: + type: integer + format: int64 + description: Unix timestamp of creation + modified: + type: integer + format: int64 + description: Unix timestamp of last modification + additionalProperties: false + examples: + - &a54 + _id: notif123 + severity: error + message: disk.space.low + relatedTo: *a52 + created: 1694784932 + modified: 1694784950 + required: + - event + - activeNotifications + additionalProperties: false + examples: + - &a55 + event: notifications + activeNotifications: + - *a54 + examples: + - payload: *a55 diff --git a/packages/live-status-gateway-api/src/generated/schema.ts b/packages/live-status-gateway-api/src/generated/schema.ts index cb72dfc53c..b8f0970662 100644 --- a/packages/live-status-gateway-api/src/generated/schema.ts +++ b/packages/live-status-gateway-api/src/generated/schema.ts @@ -63,6 +63,7 @@ enum SubscriptionName { ACTIVE_PIECES = 'activePieces', SEGMENTS = 'segments', AD_LIBS = 'adLibs', + NOTIFICATIONS = 'notifications', BUCKETS = 'buckets', RESERVED_PACKAGES = 'packages', } @@ -766,12 +767,125 @@ interface BucketAdLibStatus { additionalProperties?: Record } +/** + * Active notifications in Sofie + */ +interface NotificationsEvent { + event: 'notifications' + /** + * Active notifications in Sofie + */ + activeNotifications: NotificationObj[] +} + +/** + * This describes a notification that should be shown to a user. These can come from various sources, and are added and removed dynamically during system usage + */ +interface NotificationObj { + /** + * Unique identifier for the notification + */ + _id: string + /** + * Severity level of the notification. + */ + severity: NotificationSeverity + /** + * The message of the notification + */ + message: string + /** + * Describes what the notification is related to + */ + relatedTo: + | NotificationTargetRundown + | NotificationTargetRundownPlaylist + | NotificationTargetPartInstance + | NotificationTargetPieceInstance + | NotificationTargetUnknown + /** + * Unix timestamp of creation + */ + created: number + /** + * Unix timestamp of last modification + */ + modified?: number +} + +/** + * Severity level of the notification. + */ +enum NotificationSeverity { + WARNING = 'warning', + ERROR = 'error', + INFO = 'info', +} + +interface NotificationTargetRundown { + /** + * Possible NotificationTarget types + */ + type: NotificationTargetType.RUNDOWN + studioId: string + rundownId: string +} + +/** + * Possible NotificationTarget types + */ +enum NotificationTargetType { + RUNDOWN = 'rundown', + PLAYLIST = 'playlist', + PART_INSTANCE = 'partInstance', + PIECE_INSTANCE = 'pieceInstance', + UNKNOWN = 'unknown', +} + +interface NotificationTargetRundownPlaylist { + /** + * Possible NotificationTarget types + */ + type: NotificationTargetType.PLAYLIST + studioId: string + playlistId: string +} + +interface NotificationTargetPartInstance { + /** + * Possible NotificationTarget types + */ + type: NotificationTargetType.PART_INSTANCE + studioId: string + rundownId: string + partInstanceId: string +} + +interface NotificationTargetPieceInstance { + /** + * Possible NotificationTarget types + */ + type: NotificationTargetType.PIECE_INSTANCE + studioId: string + rundownId: string + partInstanceId: string + pieceInstanceId: string +} + +interface NotificationTargetUnknown { + /** + * Possible NotificationTarget types + */ + type: NotificationTargetType.UNKNOWN +} + export type Slash = | ActivePiecesEvent | ActivePlaylistEvent | AdLibsEvent | BucketsEvent | HeartbeatEvent + | NotificationsEvent | PackagesEvent | PongEvent | SegmentsEvent @@ -824,4 +938,13 @@ export { BucketsEvent, BucketStatus, BucketAdLibStatus, + NotificationsEvent, + NotificationObj, + NotificationSeverity, + NotificationTargetRundown, + NotificationTargetType, + NotificationTargetRundownPlaylist, + NotificationTargetPartInstance, + NotificationTargetPieceInstance, + NotificationTargetUnknown, } diff --git a/packages/live-status-gateway/src/collections/notifications/notificationsHandler.ts b/packages/live-status-gateway/src/collections/notifications/notificationsHandler.ts new file mode 100644 index 0000000000..d436319ba3 --- /dev/null +++ b/packages/live-status-gateway/src/collections/notifications/notificationsHandler.ts @@ -0,0 +1,81 @@ +import { CollectionName } from '@sofie-automation/corelib/dist/dataModel/Collections' +import { CorelibPubSub } from '@sofie-automation/corelib/dist/pubsub' +import { Logger } from 'winston' +import { CoreHandler } from '../../coreHandler.js' +import { CollectionHandlers } from '../../liveStatusServer.js' +import { PublicationCollection } from '../../publicationCollection.js' +import { DBNotificationObj } from '@sofie-automation/corelib/dist/dataModel/Notifications' +import { PlaylistNotificationsHandler } from './playlistNotificationsHandler.js' +import { RundownNotificationsHandler } from './rundownNotificationsHandler.js' +import _ from 'underscore' + +const THROTTLE_PERIOD_MS = 100 + +/** + * NotificationsHandler + * Combines playlist-level and rundown-level notifications into a single collection + * + * This handler listens to the two lower-level handlers (playlist & rundown notifications) + * and merges their collection contents on change. + */ +export class NotificationsHandler extends PublicationCollection< + DBNotificationObj[], + CorelibPubSub.notificationsForRundownPlaylist | CorelibPubSub.notificationsForRundown, + CollectionName.Notifications +> { + private throttledNotify: (data: DBNotificationObj[]) => void + + private _playlistNotificationsHandler?: PlaylistNotificationsHandler + private _rundownNotificationsHandler?: RundownNotificationsHandler + + constructor(logger: Logger, coreHandler: CoreHandler) { + super(CollectionName.Notifications, CorelibPubSub.notificationsForRundownPlaylist, logger, coreHandler) + + this.throttledNotify = _.throttle(this.notify.bind(this), THROTTLE_PERIOD_MS, { + leading: false, + trailing: true, + }) + } + + init(handlers: CollectionHandlers): void { + super.init(handlers) + + this._playlistNotificationsHandler = + handlers.playlistNotificationsHandler as unknown as PlaylistNotificationsHandler + this._rundownNotificationsHandler = + handlers.rundownNotificationsHandler as unknown as RundownNotificationsHandler + + this._playlistNotificationsHandler.subscribe(this.onSourceUpdated) + this._rundownNotificationsHandler.subscribe(this.onSourceUpdated) + } + + protected changed(): void { + this.updateAndNotify() + } + + private onSourceUpdated = (): void => { + this.changed() + } + + private updateCollectionData(): boolean { + let merged: DBNotificationObj[] = [] + + if (this._playlistNotificationsHandler && this._rundownNotificationsHandler) { + merged = [ + ...this._playlistNotificationsHandler.getPublishedDocs(), + ...this._rundownNotificationsHandler.getPublishedDocs(), + ] + } + + const hasAnythingChanged = !_.isEqual(this._collectionData, merged) + if (hasAnythingChanged) { + this._collectionData = merged + } + + return hasAnythingChanged + } + + private updateAndNotify() { + if (this.updateCollectionData()) this.throttledNotify(this._collectionData ?? []) + } +} diff --git a/packages/live-status-gateway/src/collections/notifications/playlistNotificationsHandler.ts b/packages/live-status-gateway/src/collections/notifications/playlistNotificationsHandler.ts new file mode 100644 index 0000000000..5c8d407406 --- /dev/null +++ b/packages/live-status-gateway/src/collections/notifications/playlistNotificationsHandler.ts @@ -0,0 +1,94 @@ +import { CollectionName } from '@sofie-automation/corelib/dist/dataModel/Collections' +import { RundownPlaylistId } from '@sofie-automation/corelib/dist/dataModel/Ids' +import { DBRundownPlaylist } from '@sofie-automation/corelib/dist/dataModel/RundownPlaylist' +import { CorelibPubSub } from '@sofie-automation/corelib/dist/pubsub' +import throttleToNextTick from '@sofie-automation/shared-lib/dist/lib/throttleToNextTick' +import { PickKeys } from '@sofie-automation/shared-lib/dist/lib/types' +import { Logger } from 'winston' +import { CoreHandler } from '../../coreHandler.js' +import { CollectionHandlers } from '../../liveStatusServer.js' +import { PublicationCollection } from '../../publicationCollection.js' +import { + DBNotificationObj, + DBNotificationTargetRundownPlaylist, +} from '@sofie-automation/corelib/dist/dataModel/Notifications' + +const PLAYLIST_KEYS = ['_id'] as const +type Playlist = PickKeys + +/** + * Handler: playlist-level notifications (notificationsForRundownPlaylist) + * Publishes the notifications that are attached to the playlist as a whole. + */ +export class PlaylistNotificationsHandler extends PublicationCollection< + DBNotificationObj[], + CorelibPubSub.notificationsForRundownPlaylist, + CollectionName.Notifications +> { + private _currentPlaylistId: RundownPlaylistId | undefined + + private _throttledUpdateAndNotify = throttleToNextTick(() => { + this.updateAndNotify() + }) + + constructor(logger: Logger, coreHandler: CoreHandler) { + super(CollectionName.Notifications, CorelibPubSub.notificationsForRundownPlaylist, logger, coreHandler) + } + + init(handlers: CollectionHandlers): void { + super.init(handlers) + + handlers.playlistHandler.subscribe(this.onPlaylistUpdated, PLAYLIST_KEYS) + } + + protected changed(): void { + this._throttledUpdateAndNotify() + } + + private updateCollectionData() { + const collection = this.getCollectionOrFail() + this._collectionData = collection.find((doc: DBNotificationObj) => { + const relatedTo: DBNotificationTargetRundownPlaylist | undefined = (doc.relatedTo as any).playlistId + ? (doc.relatedTo as DBNotificationTargetRundownPlaylist) + : undefined + + return ( + relatedTo && relatedTo.playlistId === this._currentPlaylistId && this._studioId === relatedTo.studioId + ) + }) + } + + private clearCollectionData() { + this._collectionData = [] + } + + onPlaylistUpdated = (playlist: Playlist | undefined): void => { + this.logUpdateReceived('playlist', `rundownPlaylistId ${playlist?._id}`) + const prevPlaylistId = this._currentPlaylistId + this._currentPlaylistId = playlist?._id + + if (this._currentPlaylistId) { + if (prevPlaylistId !== this._currentPlaylistId) { + // stop old subscription(s) and set up new one for the new playlist + this.stopSubscription() + this.setupSubscription(this._studioId, this._currentPlaylistId) + } + } else { + this.clearAndNotify() + } + } + + private clearAndNotify() { + this.clearCollectionData() + this.notify(this._collectionData) + } + + private updateAndNotify() { + this.updateCollectionData() + this.notify(this._collectionData) + } + + public getPublishedDocs(): DBNotificationObj[] { + return this._collectionData ? [...this._collectionData] : [] + } +} diff --git a/packages/live-status-gateway/src/collections/notifications/rundownNotificationsHandler.ts b/packages/live-status-gateway/src/collections/notifications/rundownNotificationsHandler.ts new file mode 100644 index 0000000000..6b253cf2ae --- /dev/null +++ b/packages/live-status-gateway/src/collections/notifications/rundownNotificationsHandler.ts @@ -0,0 +1,114 @@ +// notificationsHandlers.ts +import { CollectionName } from '@sofie-automation/corelib/dist/dataModel/Collections' +import { RundownPlaylistId, RundownId } from '@sofie-automation/corelib/dist/dataModel/Ids' +import { CorelibPubSub } from '@sofie-automation/corelib/dist/pubsub' +import throttleToNextTick from '@sofie-automation/shared-lib/dist/lib/throttleToNextTick' +import { Logger } from 'winston' +import { CoreHandler } from '../../coreHandler.js' +import { CollectionHandlers } from '../../liveStatusServer.js' +import { PublicationCollection } from '../../publicationCollection.js' +import { DBNotificationObj, DBNotificationTargetRundown } from '@sofie-automation/corelib/dist/dataModel/Notifications' +import { PickKeys } from '@sofie-automation/shared-lib/dist/lib/types' +import { DBRundownPlaylist } from '@sofie-automation/corelib/dist/dataModel/RundownPlaylist' + +const PLAYLIST_KEYS = ['_id', 'rundownIdsInOrder'] as const +type Playlist = PickKeys + +/** + * Handler: rundown-level notifications (notificationsForRundown) + * Subscribes to notifications for each rundown that belongs to the active playlist. + */ +export class RundownNotificationsHandler extends PublicationCollection< + DBNotificationObj[], + CorelibPubSub.notificationsForRundown, + CollectionName.Notifications +> { + private _currentPlaylistId: RundownPlaylistId | undefined + private _currentRundownIds: RundownId[] = [] + + private _throttledUpdateAndNotify = throttleToNextTick(() => { + this.updateAndNotify() + }) + + constructor(logger: Logger, coreHandler: CoreHandler) { + super(CollectionName.Notifications, CorelibPubSub.notificationsForRundown, logger, coreHandler) + } + + init(handlers: CollectionHandlers): void { + super.init(handlers) + + // Listen to playlist updates so we can pick up rundown IDs + handlers.playlistHandler.subscribe(this.onPlaylistUpdated, PLAYLIST_KEYS) + } + + protected changed(): void { + this._throttledUpdateAndNotify() + } + + private updateCollectionData() { + const collection = this.getCollectionOrFail() + this._collectionData = collection.find((doc: DBNotificationObj) => { + const relatedTo: DBNotificationTargetRundown | undefined = (doc.relatedTo as any).rundownId + ? (doc.relatedTo as DBNotificationTargetRundown) + : undefined + + return ( + relatedTo && + this._currentRundownIds.includes(relatedTo.rundownId) && + this._studioId === relatedTo.studioId + ) + }) + } + + private clearCollectionData() { + this._collectionData = [] + } + + private setupRundownSubscriptionsForPlaylist(playlist: Playlist) { + this.stopSubscription() + + if (!playlist.rundownIdsInOrder) { + this._currentRundownIds = [] + return + } + + this._currentRundownIds = playlist.rundownIdsInOrder + + for (const rundownId of this._currentRundownIds) { + this.setupSubscription(this._studioId, rundownId) + } + } + + onPlaylistUpdated = (playlist: Playlist | undefined): void => { + this.logUpdateReceived('playlist', `rundownPlaylistId ${playlist?._id}`) + + const prevPlaylistId = this._currentPlaylistId + this._currentPlaylistId = playlist?._id + + if (playlist && this._currentPlaylistId) { + if ( + prevPlaylistId !== this._currentPlaylistId || + this._currentRundownIds.join(',') !== (playlist.rundownIdsInOrder ?? []).join(',') + ) { + this.setupRundownSubscriptionsForPlaylist(playlist) + } + } else { + this._currentRundownIds = [] + this.clearAndNotify() + } + } + + private clearAndNotify() { + this.clearCollectionData() + this.notify(this._collectionData) + } + + private updateAndNotify() { + this.updateCollectionData() + this.notify(this._collectionData) + } + + public getPublishedDocs(): DBNotificationObj[] { + return this._collectionData ? [...this._collectionData] : [] + } +} diff --git a/packages/live-status-gateway/src/liveStatusServer.ts b/packages/live-status-gateway/src/liveStatusServer.ts index 1dc3318691..00baa68fea 100644 --- a/packages/live-status-gateway/src/liveStatusServer.ts +++ b/packages/live-status-gateway/src/liveStatusServer.ts @@ -30,6 +30,10 @@ import { BucketsHandler } from './collections/bucketsHandler.js' import { BucketAdLibsHandler } from './collections/bucketAdLibsHandler.js' import { BucketAdLibActionsHandler } from './collections/bucketAdLibActionsHandler.js' import { BucketsTopic } from './topics/bucketsTopic.js' +import { NotificationsHandler } from './collections/notifications/notificationsHandler.js' +import { NotificationsTopic } from './topics/notificationsTopic.js' +import { PlaylistNotificationsHandler } from './collections/notifications/playlistNotificationsHandler.js' +import { RundownNotificationsHandler } from './collections/notifications/rundownNotificationsHandler.js' export interface CollectionHandlers { studioHandler: StudioHandler @@ -47,6 +51,9 @@ export interface CollectionHandlers { adLibsHandler: AdLibsHandler globalAdLibActionsHandler: GlobalAdLibActionsHandler globalAdLibsHandler: GlobalAdLibsHandler + playlistNotificationsHandler: PlaylistNotificationsHandler + rundownNotificationsHandler: RundownNotificationsHandler + notificationsHandler: NotificationsHandler pieceContentStatusesHandler: PieceContentStatusesHandler bucketsHandler: BucketsHandler bucketAdLibsHandler: BucketAdLibsHandler @@ -83,6 +90,9 @@ export class LiveStatusServer { const adLibsHandler = new AdLibsHandler(this._logger, this._coreHandler) const globalAdLibActionsHandler = new GlobalAdLibActionsHandler(this._logger, this._coreHandler) const globalAdLibsHandler = new GlobalAdLibsHandler(this._logger, this._coreHandler) + const playlistNotificationsHandler = new PlaylistNotificationsHandler(this._logger, this._coreHandler) + const rundownNotificationsHandler = new RundownNotificationsHandler(this._logger, this._coreHandler) + const notificationsHandler = new NotificationsHandler(this._logger, this._coreHandler) const pieceContentStatusesHandler = new PieceContentStatusesHandler(this._logger, this._coreHandler) const bucketsHandler = new BucketsHandler(this._logger, this._coreHandler) const bucketAdLibsHandler = new BucketAdLibsHandler(this._logger, this._coreHandler) @@ -104,6 +114,9 @@ export class LiveStatusServer { adLibsHandler, globalAdLibActionsHandler, globalAdLibsHandler, + playlistNotificationsHandler, + rundownNotificationsHandler, + notificationsHandler, pieceContentStatusesHandler, bucketsHandler, bucketAdLibsHandler, @@ -119,6 +132,7 @@ export class LiveStatusServer { const activePlaylistTopic = new ActivePlaylistTopic(this._logger, handlers) const segmentsTopic = new SegmentsTopic(this._logger, handlers) const adLibsTopic = new AdLibsTopic(this._logger, handlers) + const notificationsTopic = new NotificationsTopic(this._logger, handlers) const packageStatusTopic = new PackagesTopic(this._logger, handlers) const bucketsTopic = new BucketsTopic(this._logger, handlers) @@ -127,6 +141,7 @@ export class LiveStatusServer { rootChannel.addTopic(SubscriptionName.ACTIVE_PIECES, activePiecesTopic) rootChannel.addTopic(SubscriptionName.SEGMENTS, segmentsTopic) rootChannel.addTopic(SubscriptionName.AD_LIBS, adLibsTopic) + rootChannel.addTopic(SubscriptionName.NOTIFICATIONS, notificationsTopic) rootChannel.addTopic(SubscriptionName.RESERVED_PACKAGES, packageStatusTopic) rootChannel.addTopic(SubscriptionName.BUCKETS, bucketsTopic) diff --git a/packages/live-status-gateway/src/topics/helpers/notification/notificationTarget/toNotificationTarget.ts b/packages/live-status-gateway/src/topics/helpers/notification/notificationTarget/toNotificationTarget.ts new file mode 100644 index 0000000000..d1c29b9234 --- /dev/null +++ b/packages/live-status-gateway/src/topics/helpers/notification/notificationTarget/toNotificationTarget.ts @@ -0,0 +1,84 @@ +import { + DBNotificationTarget, + DBNotificationTargetPartInstance, + DBNotificationTargetPieceInstance, + DBNotificationTargetRundown, + DBNotificationTargetRundownPlaylist, + DBNotificationTargetType, +} from '@sofie-automation/corelib/dist/dataModel/Notifications' +import { + NotificationTargetPartInstance, + NotificationTargetPieceInstance, + NotificationTargetRundown, + NotificationTargetRundownPlaylist, + NotificationTargetType, + NotificationTargetUnknown, +} from '@sofie-automation/live-status-gateway-api' +import { assertNever, literal, unprotectString } from '@sofie-automation/server-core-integration' + +type NotificationTarget = + | NotificationTargetRundown + | NotificationTargetRundownPlaylist + | NotificationTargetPartInstance + | NotificationTargetPieceInstance + +export function toNotificationTarget(dbTarget: DBNotificationTarget): NotificationTarget | NotificationTargetUnknown { + switch (dbTarget.type) { + case DBNotificationTargetType.PARTINSTANCE: + return toNotificationTargetPartInstance(dbTarget) + case DBNotificationTargetType.RUNDOWN: + return toNotificationTargetRundown(dbTarget) + case DBNotificationTargetType.PLAYLIST: + return toNotificationTargetPlaylist(dbTarget) + case DBNotificationTargetType.PIECEINSTANCE: + return toNotificationTargetPieceInstance(dbTarget) + default: + assertNever(dbTarget) + return literal({ type: NotificationTargetType.UNKNOWN }) + } +} + +function toNotificationTargetBase(dbTarget: DBNotificationTarget): Pick { + return literal>({ + studioId: unprotectString(dbTarget.studioId), + }) +} + +function toNotificationTargetRundown(dbTarget: DBNotificationTargetRundown): NotificationTargetRundown { + return literal({ + ...toNotificationTargetBase(dbTarget), + type: NotificationTargetType.RUNDOWN, + rundownId: unprotectString(dbTarget.rundownId), + }) +} + +function toNotificationTargetPartInstance(dbTarget: DBNotificationTargetPartInstance): NotificationTargetPartInstance { + return literal({ + ...toNotificationTargetBase(dbTarget), + type: NotificationTargetType.PART_INSTANCE, + rundownId: unprotectString(dbTarget.rundownId), + partInstanceId: unprotectString(dbTarget.partInstanceId), + }) +} + +function toNotificationTargetPieceInstance( + dbTarget: DBNotificationTargetPieceInstance +): NotificationTargetPieceInstance { + return literal({ + ...toNotificationTargetBase(dbTarget), + type: NotificationTargetType.PIECE_INSTANCE, + rundownId: unprotectString(dbTarget.rundownId), + partInstanceId: unprotectString(dbTarget.partInstanceId), + pieceInstanceId: unprotectString(dbTarget.pieceInstanceId), + }) +} + +function toNotificationTargetPlaylist( + dbTarget: DBNotificationTargetRundownPlaylist +): NotificationTargetRundownPlaylist { + return literal({ + ...toNotificationTargetBase(dbTarget), + type: NotificationTargetType.PLAYLIST, + playlistId: unprotectString(dbTarget.playlistId), + }) +} diff --git a/packages/live-status-gateway/src/topics/helpers/notification/toNotificationStatus.ts b/packages/live-status-gateway/src/topics/helpers/notification/toNotificationStatus.ts new file mode 100644 index 0000000000..4628e87625 --- /dev/null +++ b/packages/live-status-gateway/src/topics/helpers/notification/toNotificationStatus.ts @@ -0,0 +1,28 @@ +import { NoteSeverity } from '@sofie-automation/blueprints-integration' +import { DBNotificationObj } from '@sofie-automation/corelib/dist/dataModel/Notifications' +import { interpollateTranslation } from '@sofie-automation/corelib/dist/TranslatableMessage' +import { NotificationObj, NotificationSeverity } from '@sofie-automation/live-status-gateway-api' +import { literal, unprotectString } from '@sofie-automation/server-core-integration' +import { toNotificationTarget } from './notificationTarget/toNotificationTarget.js' + +export function toNotificationStatus(dbNotification: DBNotificationObj): NotificationObj | undefined { + return literal({ + _id: unprotectString(dbNotification._id), + severity: toNotificationSeverity(dbNotification.severity), + message: interpollateTranslation(dbNotification.message.key, dbNotification.message.args), + relatedTo: toNotificationTarget(dbNotification.relatedTo), + created: dbNotification.created, + modified: dbNotification.modified, + }) +} + +function toNotificationSeverity(severity: NoteSeverity): NotificationSeverity { + switch (severity) { + case NoteSeverity.WARNING: + return NotificationSeverity.WARNING + case NoteSeverity.ERROR: + return NotificationSeverity.ERROR + case NoteSeverity.INFO: + return NotificationSeverity.ERROR + } +} diff --git a/packages/live-status-gateway/src/topics/notificationsTopic.ts b/packages/live-status-gateway/src/topics/notificationsTopic.ts new file mode 100644 index 0000000000..ee9c15161a --- /dev/null +++ b/packages/live-status-gateway/src/topics/notificationsTopic.ts @@ -0,0 +1,43 @@ +import { Logger } from 'winston' +import { WebSocket } from 'ws' +import { literal } from '@sofie-automation/shared-lib/dist/lib/lib' +import { WebSocketTopicBase, WebSocketTopic } from '../wsHandler.js' +import { CollectionHandlers } from '../liveStatusServer.js' +import { DBNotificationObj } from '@sofie-automation/corelib/dist/dataModel/Notifications' +import { toNotificationStatus } from './helpers/notification/toNotificationStatus.js' +import { NotificationObj } from '@sofie-automation/live-status-gateway-api' + +const THROTTLE_PERIOD_MS = 100 + +export interface NotificationsEvent { + event: 'notifications' + activeNotifications: NotificationObj[] +} + +export class NotificationsTopic extends WebSocketTopicBase implements WebSocketTopic { + private _notifications: DBNotificationObj[] = [] + + constructor(logger: Logger, handlers: CollectionHandlers) { + super(NotificationsTopic.name, logger, THROTTLE_PERIOD_MS) + + // Subscribe to notifications handler + handlers.notificationsHandler.subscribe(this.onNotificationsUpdate) + } + + sendStatus(subscribers: Iterable): void { + const message = literal({ + event: 'notifications', + activeNotifications: this._notifications + .map(toNotificationStatus) + .filter((notification) => notification !== undefined), + }) + + this.sendMessage(subscribers, message) + } + + private onNotificationsUpdate = (notifications: DBNotificationObj[] | undefined): void => { + this.logUpdateReceived('notifications') + this._notifications = notifications ?? [] + this.throttledSendStatusToAll() + } +} diff --git a/packages/meteor-lib/src/api/pubsub.ts b/packages/meteor-lib/src/api/pubsub.ts index 2ca9d5ee5e..93d9f2e00f 100644 --- a/packages/meteor-lib/src/api/pubsub.ts +++ b/packages/meteor-lib/src/api/pubsub.ts @@ -2,7 +2,6 @@ import { BucketId, PartId, PeripheralDeviceId, - RundownId, RundownPlaylistActivationId, RundownPlaylistId, ShowStyleBaseId, @@ -32,7 +31,6 @@ import { CorelibPubSub, CorelibPubSubCollections, CorelibPubSubTypes } from '@so import { CollectionName } from '@sofie-automation/corelib/dist/dataModel/Collections' import { DBPart } from '@sofie-automation/corelib/dist/dataModel/Part' import { PartInstance } from '../collections/PartInstances.js' -import type { DBNotificationObj } from '@sofie-automation/corelib/dist/dataModel/Notifications' /** * Ids of possible DDP subscriptions for the UI only @@ -80,14 +78,6 @@ export enum MeteorPubSub { * Fetch all translation bundles */ translationsBundles = 'translationsBundles', - /** - * Fetch notifications for playlist - */ - notificationsForRundownPlaylist = 'notificationsForRundownPlaylist', - /** - * Fetch notifications for rundown - */ - notificationsForRundown = 'notificationsForRundown', // custom publications: @@ -184,11 +174,6 @@ export interface MeteorPubSubTypes { token?: string ) => CollectionName.RundownLayouts [MeteorPubSub.translationsBundles]: (token?: string) => CollectionName.TranslationsBundles - [MeteorPubSub.notificationsForRundown]: (studioId: StudioId, rundownId: RundownId) => CollectionName.Notifications - [MeteorPubSub.notificationsForRundownPlaylist]: ( - studioId: StudioId, - playlistId: RundownPlaylistId - ) => CollectionName.Notifications // custom publications: @@ -260,7 +245,6 @@ export type MeteorPubSubCollections = { [CollectionName.Buckets]: Bucket [CollectionName.TranslationsBundles]: TranslationsBundle [CollectionName.ExpectedPlayoutItems]: ExpectedPlayoutItem - [CollectionName.Notifications]: DBNotificationObj } & MeteorPubSubCustomCollections export type MeteorPubSubCustomCollections = { diff --git a/packages/webui/src/client/ui/RundownView/RundownViewSubscriptions.ts b/packages/webui/src/client/ui/RundownView/RundownViewSubscriptions.ts index 6b3ae37bdd..cf8410371f 100644 --- a/packages/webui/src/client/ui/RundownView/RundownViewSubscriptions.ts +++ b/packages/webui/src/client/ui/RundownView/RundownViewSubscriptions.ts @@ -116,7 +116,7 @@ export function useRundownViewSubscriptions(playlistId: RundownPlaylistId): bool auxSubsReady.push( useSubscriptionIfEnabled( - MeteorPubSub.notificationsForRundownPlaylist, + CorelibPubSub.notificationsForRundownPlaylist, !!playlistId && !!playlistStudioId, playlistStudioId || protectString(''), playlistId @@ -135,7 +135,7 @@ export function useRundownViewSubscriptions(playlistId: RundownPlaylistId): bool ).fetch() as Pick[] for (const rundown of rundowns) { - meteorSubscribe(MeteorPubSub.notificationsForRundown, rundown.studioId, rundown._id) + meteorSubscribe(CorelibPubSub.notificationsForRundown, rundown.studioId, rundown._id) } }, [playlistId])