From 5d72c14f79aba87398d222c27e004e9a096375be Mon Sep 17 00:00:00 2001 From: Jan Starzak Date: Fri, 15 Nov 2024 14:04:48 +0100 Subject: [PATCH 01/19] chore: move checkForMultipleVersions into a yarn script --- .github/workflows/node.yaml | 2 +- package.json | 3 ++- scripts/checkForMultipleVersions.mjs | 17 ++++++++++++++--- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/.github/workflows/node.yaml b/.github/workflows/node.yaml index fb50334747..ae6d82fd6f 100644 --- a/.github/workflows/node.yaml +++ b/.github/workflows/node.yaml @@ -748,6 +748,6 @@ jobs: CI: true - name: Run check run: | - node scripts/checkForMultipleVersions.mjs + yarn validate:versions env: CI: true diff --git a/package.json b/package.json index e232a83b9f..ac8dc02608 100644 --- a/package.json +++ b/package.json @@ -25,9 +25,10 @@ "meteor:run": "cd meteor && meteor yarn start", "lint": "run lint:meteor && run lint:packages", "unit": "run unit:meteor && run unit:packages", - "validate:release": "yarn install && run install-and-build && run validate:release:packages && run validate:release:meteor", + "validate:release": "yarn install && run install-and-build && run validate:versions && run validate:release:packages && run validate:release:meteor", "validate:release:meteor": "cd meteor && meteor yarn validate:prod-dependencies && meteor yarn license-validate && meteor yarn lint && meteor yarn test", "validate:release:packages": "cd packages && run validate:dependencies && run test", + "validate:versions": "node scripts/checkForMultipleVersions.mjs", "meteor": "cd meteor && meteor", "docs:serve": "cd packages && run docs:serve", "reset": "node scripts/reset.mjs", diff --git a/scripts/checkForMultipleVersions.mjs b/scripts/checkForMultipleVersions.mjs index b633852235..792aee1f79 100644 --- a/scripts/checkForMultipleVersions.mjs +++ b/scripts/checkForMultipleVersions.mjs @@ -1,5 +1,12 @@ import { buildDepTreeFromFiles } from "snyk-nodejs-lockfile-parser"; +function hr() { + // write regular dashes if this is a "simple" output stream () + if (!process.stdout.hasColors || !process.stdout.hasColors()) + return "-".repeat(process.stdout.columns ?? 40); + return '─'.repeat(process.stdout.columns ?? 40) +} + /** * These are the libs we want to consider. * Its an array of arrays, to allow for multiple names to be treated as one package @@ -58,6 +65,10 @@ await addDepsForRoot("./packages", "live-status-gateway"); let hasFailure = false; +console.log(hr()) +console.log(" 🔢 Checking dependency version consistency...") +console.log(hr()) + // check each library for (const libName of libsToConsider) { const allVersions = new Set(); @@ -73,11 +84,11 @@ for (const libName of libsToConsider) { // output some info const str = Array.from(allVersions).join(", "); if (allVersions.size === 0) { - console.log(`No versions of "${nameStr}" installed`); + console.log(`❔ No versions of "${nameStr}" installed`); } else if (allVersions.size === 1) { - console.log(`Single version of "${nameStr}" installed: ${str}`); + console.log(`✅ Single version of "${nameStr}" installed: ${str}`); } else { - console.error(`Multiple versions of "${nameStr}" installed: ${str}`); + console.error(`⚠️ Multiple versions of "${nameStr}" installed: ${str}`); hasFailure = true; } } From 96360510d78fcc9dbfd31a125d363aab272f8158 Mon Sep 17 00:00:00 2001 From: Jan Starzak Date: Fri, 15 Nov 2024 15:01:36 +0100 Subject: [PATCH 02/19] fix: release scripts broken on Windows --- packages/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/package.json b/packages/package.json index c379c53211..b38fcdc147 100644 --- a/packages/package.json +++ b/packages/package.json @@ -17,7 +17,7 @@ "build": "lerna run build --ignore @sofie-automation/openapi", "build:try": "lerna run --no-bail build --ignore @sofie-automation/openapi", "watch": "lerna run --parallel build:main --ignore @sofie-automation/openapi -- --watch --preserveWatchOutput", - "stage-versions": "git add -u */package.json */CHANGELOG.md lerna.json yarn.lock", + "stage-versions": "git add -u \"*/package.json\" \"*/CHANGELOG.md\" lerna.json yarn.lock", "set-version": "lerna version --exact --no-changelog --no-git-tag-version --no-push --yes", "set-version-and-commit": "lerna version --exact --no-changelog --no-changelog --no-commit-hooks --force-publish='*' --no-push --yes", "set-version-and-changelog": "lerna version --exact --force-publish --conventional-commits --no-git-tag-version --no-push --yes", @@ -65,4 +65,4 @@ }, "name": "packages", "packageManager": "yarn@3.5.0" -} +} \ No newline at end of file From 193815dccd92f1d86acff5b316bc0956b9e8f0e4 Mon Sep 17 00:00:00 2001 From: Jan Starzak Date: Fri, 29 Nov 2024 16:43:15 +0100 Subject: [PATCH 03/19] fix: Device Action Studio Context gets lost, Adlib previews are unstable --- .../deviceTriggers/RundownContentObserver.ts | 8 +- .../StudioDeviceTriggerManager.ts | 280 +++++++++--------- meteor/server/api/deviceTriggers/observer.ts | 43 +-- .../lib/ReactiveCacheCollection.ts | 49 +++ 4 files changed, 225 insertions(+), 155 deletions(-) diff --git a/meteor/server/api/deviceTriggers/RundownContentObserver.ts b/meteor/server/api/deviceTriggers/RundownContentObserver.ts index 3758160320..e0d7dddcef 100644 --- a/meteor/server/api/deviceTriggers/RundownContentObserver.ts +++ b/meteor/server/api/deviceTriggers/RundownContentObserver.ts @@ -32,7 +32,7 @@ export class RundownContentObserver { #observers: Meteor.LiveQueryHandle[] = [] #cache: ContentCache #cancelCache: () => void - #cleanup: () => void = () => { + #cleanup: (() => void) | undefined = () => { throw new Error('RundownContentObserver.#cleanup has not been set!') } #disposed = false @@ -45,8 +45,11 @@ export class RundownContentObserver { ) { logger.silly(`Creating RundownContentObserver for playlist "${rundownPlaylistId}"`) const { cache, cancel: cancelCache } = createReactiveContentCache(() => { + if (this.#disposed) { + this.#cleanup?.() + return + } this.#cleanup = onChanged(cache) - if (this.#disposed) this.#cleanup() }, REACTIVITY_DEBOUNCE) this.#cache = cache @@ -157,5 +160,6 @@ export class RundownContentObserver { this.#cancelCache() this.#observers.forEach((observer) => observer.stop()) this.#cleanup?.() + this.#cleanup = undefined } } diff --git a/meteor/server/api/deviceTriggers/StudioDeviceTriggerManager.ts b/meteor/server/api/deviceTriggers/StudioDeviceTriggerManager.ts index fc1b6ac0c2..bc3f205a82 100644 --- a/meteor/server/api/deviceTriggers/StudioDeviceTriggerManager.ts +++ b/meteor/server/api/deviceTriggers/StudioDeviceTriggerManager.ts @@ -38,20 +38,23 @@ export class StudioDeviceTriggerManager { StudioActionManagers.set(studioId, new StudioActionManager()) } - updateTriggers(cache: ContentCache, showStyleBaseId: ShowStyleBaseId): void { + async updateTriggers(cache: ContentCache, showStyleBaseId: ShowStyleBaseId): Promise { const studioId = this.studioId this.#lastShowStyleBaseId = showStyleBaseId - const rundownPlaylist = cache.RundownPlaylists.findOne({ - activationId: { - $exists: true, - }, - }) - if (!rundownPlaylist) { + const [showStyleBase, rundownPlaylist] = await Promise.all([ + cache.ShowStyleBases.findOneAsync(showStyleBaseId), + cache.RundownPlaylists.findOneAsync({ + activationId: { + $exists: true, + }, + }), + ]) + if (!showStyleBase || !rundownPlaylist) { return } - const context = createCurrentContextFromCache(cache) + const context = await createCurrentContextFromCache(cache) const actionManager = StudioActionManagers.get(studioId) if (!actionManager) throw new Meteor.Error( @@ -60,18 +63,13 @@ export class StudioDeviceTriggerManager { ) actionManager.setContext(context) - const showStyleBase = cache.ShowStyleBases.findOne(showStyleBaseId) - if (!showStyleBase) { - return - } - const { obj: sourceLayers } = applyAndValidateOverrides(showStyleBase.sourceLayersWithOverrides) - const allTriggeredActions = cache.TriggeredActions.find({ + const allTriggeredActions = await cache.TriggeredActions.find({ showStyleBaseId: { $in: [showStyleBaseId, null], }, - }) + }).fetchAsync() const upsertedDeviceTriggerMountedActionIds: DeviceTriggerMountedActionId[] = [] const touchedActionIds: DeviceActionId[] = [] @@ -83,116 +81,126 @@ export class StudioDeviceTriggerManager { const addedPreviewIds: PreviewWrappedAdLibId[] = [] - Object.entries(triggeredAction.actions).forEach(([key, action]) => { - // Since the compiled action is cached using this actionId as a key, having the action - // and the filterChain allows for a quicker invalidation without doing a deepEquals - const actionId = protectString( - `${studioId}_${triggeredAction._id}_${key}_${JSON.stringify(action)}` - ) - const existingAction = actionManager.getAction(actionId) - let thisAction: ExecutableAction - // Use the cached action or put a new one in the cache - if (existingAction) { - thisAction = existingAction - } else { - const compiledAction = createAction(action, sourceLayers) - actionManager.setAction(actionId, compiledAction) - thisAction = compiledAction - } - touchedActionIds.push(actionId) - - Object.entries(triggeredAction.triggers).forEach(([key, trigger]) => { - if (!isDeviceTrigger(trigger)) { - return + const updateActionsPromises = Object.entries(triggeredAction.actions).map( + async ([key, action]) => { + // Since the compiled action is cached using this actionId as a key, having the action + // and the filterChain allows for a quicker invalidation without doing a deepEquals + const actionId = protectString( + `${studioId}_${triggeredAction._id}_${key}_${JSON.stringify(action)}` + ) + const existingAction = actionManager.getAction(actionId) + let thisAction: ExecutableAction + // Use the cached action or put a new one in the cache + if (existingAction) { + thisAction = existingAction + } else { + const compiledAction = createAction(action, sourceLayers) + actionManager.setAction(actionId, compiledAction) + thisAction = compiledAction } + touchedActionIds.push(actionId) - let deviceActionArguments: ShiftRegisterActionArguments | undefined = undefined + const updateMountedActionsPromises = Object.entries( + triggeredAction.triggers + ).map(async ([key, trigger]) => { + if (!isDeviceTrigger(trigger)) { + return + } - if (action.action === DeviceActions.modifyShiftRegister) { - deviceActionArguments = { - type: 'modifyRegister', - register: action.register, - operation: action.operation, - value: action.value, - limitMin: action.limitMin, - limitMax: action.limitMax, + let deviceActionArguments: ShiftRegisterActionArguments | undefined = undefined + + if (action.action === DeviceActions.modifyShiftRegister) { + deviceActionArguments = { + type: 'modifyRegister', + register: action.register, + operation: action.operation, + value: action.value, + limitMin: action.limitMin, + limitMax: action.limitMax, + } } - } - const deviceTriggerMountedActionId = protectString( - `${actionId}_${key}` - ) - DeviceTriggerMountedActions.upsert(deviceTriggerMountedActionId, { - $set: { - studioId, - showStyleBaseId, - actionType: thisAction.action, - actionId, - deviceId: trigger.deviceId, - deviceTriggerId: trigger.triggerId, - values: trigger.values, - deviceActionArguments, - name: triggeredAction.name, - }, - }) - upsertedDeviceTriggerMountedActionIds.push(deviceTriggerMountedActionId) - }) - - if (!isPreviewableAction(thisAction)) { - const adLibPreviewId = protectString(`${actionId}_preview`) - DeviceTriggerMountedActionAdlibsPreview.upsert(adLibPreviewId, { - $set: literal({ - _id: adLibPreviewId, - _rank: 0, - partId: null, - type: undefined, - label: thisAction.action, - item: null, - triggeredActionId: triggeredAction._id, - actionId, - studioId, - showStyleBaseId, - sourceLayerType: undefined, - sourceLayerName: undefined, - styleClassNames: triggeredAction.styleClassNames, - }), + const deviceTriggerMountedActionId = protectString( + `${actionId}_${key}` + ) + upsertedDeviceTriggerMountedActionIds.push(deviceTriggerMountedActionId) + return DeviceTriggerMountedActions.upsertAsync(deviceTriggerMountedActionId, { + $set: { + studioId, + showStyleBaseId, + actionType: thisAction.action, + actionId, + deviceId: trigger.deviceId, + deviceTriggerId: trigger.triggerId, + values: trigger.values, + deviceActionArguments, + name: triggeredAction.name, + }, + }) }) - addedPreviewIds.push(adLibPreviewId) - } else { - const previewedAdLibs = thisAction.preview(context) + if (!isPreviewableAction(thisAction)) { + const adLibPreviewId = protectString(`${actionId}_preview`) - previewedAdLibs.forEach((adLib) => { - const adLibPreviewId = protectString( - `${triggeredAction._id}_${studioId}_${key}_${adLib._id}` - ) - DeviceTriggerMountedActionAdlibsPreview.upsert(adLibPreviewId, { + addedPreviewIds.push(adLibPreviewId) + await DeviceTriggerMountedActionAdlibsPreview.upsertAsync(adLibPreviewId, { $set: literal({ - ...adLib, _id: adLibPreviewId, + _rank: 0, + partId: null, + type: undefined, + label: thisAction.action, + item: null, triggeredActionId: triggeredAction._id, actionId, studioId, showStyleBaseId, - sourceLayerType: adLib.sourceLayerId - ? sourceLayers[adLib.sourceLayerId]?.type - : undefined, - sourceLayerName: adLib.sourceLayerId - ? { - name: sourceLayers[adLib.sourceLayerId]?.name, - abbreviation: sourceLayers[adLib.sourceLayerId]?.abbreviation, - } - : undefined, + sourceLayerType: undefined, + sourceLayerName: undefined, styleClassNames: triggeredAction.styleClassNames, }), }) + } else { + const previewedAdLibs = thisAction.preview(context) + + const previewedAdlibsUpdatePromises = previewedAdLibs.map(async (adLib) => { + const adLibPreviewId = protectString( + `${triggeredAction._id}_${studioId}_${key}_${adLib._id}` + ) + + addedPreviewIds.push(adLibPreviewId) + return DeviceTriggerMountedActionAdlibsPreview.upsertAsync(adLibPreviewId, { + $set: literal({ + ...adLib, + _id: adLibPreviewId, + triggeredActionId: triggeredAction._id, + actionId, + studioId, + showStyleBaseId, + sourceLayerType: adLib.sourceLayerId + ? sourceLayers[adLib.sourceLayerId]?.type + : undefined, + sourceLayerName: adLib.sourceLayerId + ? { + name: sourceLayers[adLib.sourceLayerId]?.name, + abbreviation: sourceLayers[adLib.sourceLayerId]?.abbreviation, + } + : undefined, + styleClassNames: triggeredAction.styleClassNames, + }), + }) + }) - addedPreviewIds.push(adLibPreviewId) - }) + await Promise.all(previewedAdlibsUpdatePromises) + } + + await Promise.all(updateMountedActionsPromises) } - }) + ) - DeviceTriggerMountedActionAdlibsPreview.remove({ + await Promise.all(updateActionsPromises) + + await DeviceTriggerMountedActionAdlibsPreview.removeAsync({ triggeredActionId: triggeredAction._id, _id: { $nin: addedPreviewIds, @@ -200,7 +208,7 @@ export class StudioDeviceTriggerManager { }) } - DeviceTriggerMountedActions.remove({ + await DeviceTriggerMountedActions.removeAsync({ studioId, showStyleBaseId, _id: { @@ -211,7 +219,7 @@ export class StudioDeviceTriggerManager { actionManager.deleteActionsOtherThan(touchedActionIds) } - clearTriggers(): void { + async clearTriggers(): Promise { const studioId = this.studioId const showStyleBaseId = this.#lastShowStyleBaseId @@ -226,28 +234,34 @@ export class StudioDeviceTriggerManager { `No Studio Action Manager available to handle action context in Studio "${studioId}"` ) - DeviceTriggerMountedActions.find({ + const mountedActions = await DeviceTriggerMountedActions.find({ studioId, showStyleBaseId, - }).forEach((mountedAction) => { + }).fetchAsync() + for (const mountedAction of mountedActions) { actionManager.deleteAction(mountedAction.actionId) - }) - DeviceTriggerMountedActions.remove({ - studioId, - showStyleBaseId, - }) - DeviceTriggerMountedActionAdlibsPreview.remove({ - studioId, - showStyleBaseId, - }) + } + + await Promise.all([ + DeviceTriggerMountedActions.removeAsync({ + studioId, + showStyleBaseId, + }), + DeviceTriggerMountedActionAdlibsPreview.removeAsync({ + studioId, + showStyleBaseId, + }), + ]) + actionManager.deleteContext() this.#lastShowStyleBaseId = null + return } - stop(): void { - this.clearTriggers() + async stop(): Promise { StudioActionManagers.delete(this.studioId) + return await this.clearTriggers() } } @@ -266,8 +280,8 @@ function convertDocument(doc: ReadonlyObjectDeep): UITrigger }) } -function createCurrentContextFromCache(cache: ContentCache): ReactivePlaylistActionContext { - const rundownPlaylist = cache.RundownPlaylists.findOne({ +async function createCurrentContextFromCache(cache: ContentCache): Promise { + const rundownPlaylist = await cache.RundownPlaylists.findOneAsync({ activationId: { $exists: true, }, @@ -275,24 +289,26 @@ function createCurrentContextFromCache(cache: ContentCache): ReactivePlaylistAct if (!rundownPlaylist) throw new Error('There should be an active RundownPlaylist!') - const currentPartInstance = rundownPlaylist.currentPartInfo - ? cache.PartInstances.findOne(rundownPlaylist.currentPartInfo.partInstanceId) - : undefined - const nextPartInstance = rundownPlaylist.nextPartInfo - ? cache.PartInstances.findOne(rundownPlaylist.nextPartInfo.partInstanceId) - : undefined + const [currentPartInstance, nextPartInstance] = await Promise.all([ + rundownPlaylist.currentPartInfo + ? cache.PartInstances.findOneAsync(rundownPlaylist.currentPartInfo.partInstanceId) + : undefined, + rundownPlaylist.nextPartInfo + ? cache.PartInstances.findOneAsync(rundownPlaylist.nextPartInfo.partInstanceId) + : undefined, + ]) const currentSegmentPartIds = currentPartInstance - ? cache.Parts.find({ + ? await cache.Parts.find({ segmentId: currentPartInstance.part.segmentId, - }).map((part) => part._id) + }).mapAsync((part) => part._id) : [] const nextSegmentPartIds = nextPartInstance ? nextPartInstance.part.segmentId === currentPartInstance?.part.segmentId ? currentSegmentPartIds - : cache.Parts.find({ + : await cache.Parts.find({ segmentId: nextPartInstance.part.segmentId, - }).map((part) => part._id) + }).mapAsync((part) => part._id) : [] return { diff --git a/meteor/server/api/deviceTriggers/observer.ts b/meteor/server/api/deviceTriggers/observer.ts index bcc7fa8853..ef3be0679c 100644 --- a/meteor/server/api/deviceTriggers/observer.ts +++ b/meteor/server/api/deviceTriggers/observer.ts @@ -29,28 +29,28 @@ Meteor.startup(() => { const studioObserversAndManagers = new Map() const jobQueue = new JobQueueWithClasses({ autoStart: true, - executionWrapper: Meteor.bindEnvironment, - resolutionWrapper: Meteor.defer, }) - function workInQueue(fnc: () => Promise) { - jobQueue.add(fnc).catch((e) => { - logger.error(`Error in DeviceTriggers Studio observer reaction: ${stringifyError(e)}`) - }) + function workInQueue(fnc: () => Promise) { + jobQueue + .add(async () => { + const res = await fnc() + return res + }) + .catch((e) => { + logger.error(`Error in DeviceTriggers Studio observer reaction: ${stringifyError(e)}`) + }) } function createObserverAndManager(studioId: StudioId) { logger.debug(`Creating observer for studio "${studioId}"`) const manager = new StudioDeviceTriggerManager(studioId) const observer = new StudioObserver(studioId, (showStyleBaseId, cache) => { - workInQueue(async () => { - manager.updateTriggers(cache, showStyleBaseId) - }) + logger.silly(`Studio observer updating triggers for "${studioId}":"${showStyleBaseId}"`) + workInQueue(async () => manager.updateTriggers(cache, showStyleBaseId)) return () => { - workInQueue(async () => { - manager.clearTriggers() - }) + workInQueue(async () => manager.clearTriggers()) } }) @@ -58,15 +58,16 @@ Meteor.startup(() => { } function destroyObserverAndManager(studioId: StudioId) { - logger.debug(`Destroying observer for studio "${studioId}"`) - const toRemove = studioObserversAndManagers.get(studioId) - if (toRemove) { - toRemove.observer.stop() - toRemove.manager.stop() - studioObserversAndManagers.delete(studioId) - } else { - logger.error(`Observer for studio "${studioId}" not found`) - } + workInQueue(async () => { + const toRemove = studioObserversAndManagers.get(studioId) + if (toRemove) { + toRemove.observer.stop() + await toRemove.manager.stop() + studioObserversAndManagers.delete(studioId) + } else { + logger.error(`Observer for studio "${studioId}" not found`) + } + }) } Studios.observeChanges( diff --git a/meteor/server/publications/lib/ReactiveCacheCollection.ts b/meteor/server/publications/lib/ReactiveCacheCollection.ts index 294430cab1..6b7df53a34 100644 --- a/meteor/server/publications/lib/ReactiveCacheCollection.ts +++ b/meteor/server/publications/lib/ReactiveCacheCollection.ts @@ -69,6 +69,55 @@ export class ReactiveCacheCollection, + options?: Omit, 'limit'> + ): Promise { + return this.#collection.findOne(selector as any, options) + } + + async insertAsync(doc: Mongo.OptionalId): Promise { + const id = await this.#collection.insertAsync(doc) + this.runReaction() + return id + } + + async removeAsync(selector: Document['_id'] | MongoQuery): Promise { + const num = await this.#collection.removeAsync(selector as any) + if (num > 0) { + this.runReaction() + } + return num + } + + async updateAsync( + selector: Document['_id'] | MongoQuery, + modifier: MongoModifier, + options?: { + multi?: boolean + upsert?: boolean + arrayFilters?: { [identifier: string]: any }[] + } + ): Promise { + const num = await this.#collection.updateAsync(selector as any, modifier as any, options) + if (num > 0) { + this.runReaction() + } + return num + } + + async upsertAsync( + selector: Document['_id'] | Mongo.Selector, + modifier: Mongo.Modifier, + options?: { multi?: boolean } + ): Promise<{ numberAffected?: number; insertedId?: string }> { + const res = await this.#collection.upsertAsync(selector as any, modifier as any, options) + if (res.numberAffected || res.insertedId) { + this.runReaction() + } + return res + } + link(cb?: () => void): ObserveChangesCallbacks { return { added: (id: Document['_id'], fields: Partial) => { From d2a3cdf425d49e40345537c62a97f635d1d1261e Mon Sep 17 00:00:00 2001 From: Jan Starzak Date: Wed, 4 Dec 2024 11:16:09 +0100 Subject: [PATCH 04/19] chore(release): 1.51.4 --- meteor/CHANGELOG.md | 10 +++++ meteor/package.json | 2 +- meteor/yarn.lock | 12 +++--- packages/blueprints-integration/CHANGELOG.md | 8 ++++ packages/blueprints-integration/package.json | 4 +- packages/corelib/package.json | 6 +-- packages/documentation/package.json | 2 +- packages/job-worker/package.json | 8 ++-- packages/lerna.json | 2 +- packages/live-status-gateway/package.json | 10 ++--- packages/mos-gateway/CHANGELOG.md | 8 ++++ packages/mos-gateway/package.json | 6 +-- packages/openapi/package.json | 2 +- packages/playout-gateway/CHANGELOG.md | 8 ++++ packages/playout-gateway/package.json | 6 +-- packages/server-core-integration/CHANGELOG.md | 8 ++++ packages/server-core-integration/package.json | 4 +- packages/shared-lib/package.json | 2 +- packages/yarn.lock | 38 +++++++++---------- 19 files changed, 94 insertions(+), 52 deletions(-) diff --git a/meteor/CHANGELOG.md b/meteor/CHANGELOG.md index be59164e1b..e4498ae87c 100644 --- a/meteor/CHANGELOG.md +++ b/meteor/CHANGELOG.md @@ -2,6 +2,16 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.51.4](///compare/v1.51.3...v1.51.4) (2024-12-04) + + +### Bug Fixes + +* Device Action Studio Context gets lost, Adlib previews are unstable 193815d +* Live Status Gateway Dockerfile (regular) still uses yarn to start 0ae53c4 +* release scripts broken on Windows 9636051 +* RundownView shows spinner when unMOSing a Rundown from a Playlist 874e85c + ### [1.51.2](https://github.com/nrkno/tv-automation-server-core/compare/v1.51.1...v1.51.2) (2024-11-21) diff --git a/meteor/package.json b/meteor/package.json index 3e27c5e714..91f635f3a0 100644 --- a/meteor/package.json +++ b/meteor/package.json @@ -1,6 +1,6 @@ { "name": "automation-core", - "version": "1.51.3", + "version": "1.51.4", "private": true, "engines": { "node": ">=14.19.1" diff --git a/meteor/yarn.lock b/meteor/yarn.lock index a6f56b2e2b..c22865dcff 100644 --- a/meteor/yarn.lock +++ b/meteor/yarn.lock @@ -1321,7 +1321,7 @@ __metadata: version: 0.0.0-use.local resolution: "@sofie-automation/blueprints-integration@portal:../packages/blueprints-integration::locator=automation-core%40workspace%3A." dependencies: - "@sofie-automation/shared-lib": 1.51.3 + "@sofie-automation/shared-lib": 1.51.4 tslib: ^2.6.2 type-fest: ^3.13.1 languageName: node @@ -1362,8 +1362,8 @@ __metadata: version: 0.0.0-use.local resolution: "@sofie-automation/corelib@portal:../packages/corelib::locator=automation-core%40workspace%3A." dependencies: - "@sofie-automation/blueprints-integration": 1.51.3 - "@sofie-automation/shared-lib": 1.51.3 + "@sofie-automation/blueprints-integration": 1.51.4 + "@sofie-automation/shared-lib": 1.51.4 fast-clone: ^1.5.13 i18next: ^21.10.0 influx: ^5.9.3 @@ -1394,9 +1394,9 @@ __metadata: resolution: "@sofie-automation/job-worker@portal:../packages/job-worker::locator=automation-core%40workspace%3A." dependencies: "@slack/webhook": ^6.1.0 - "@sofie-automation/blueprints-integration": 1.51.3 - "@sofie-automation/corelib": 1.51.3 - "@sofie-automation/shared-lib": 1.51.3 + "@sofie-automation/blueprints-integration": 1.51.4 + "@sofie-automation/corelib": 1.51.4 + "@sofie-automation/shared-lib": 1.51.4 amqplib: ^0.10.3 deepmerge: ^4.3.1 elastic-apm-node: ^3.51.0 diff --git a/packages/blueprints-integration/CHANGELOG.md b/packages/blueprints-integration/CHANGELOG.md index abf1b45e2d..4105116d47 100644 --- a/packages/blueprints-integration/CHANGELOG.md +++ b/packages/blueprints-integration/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.51.4](https://github.com/nrkno/sofie-core/compare/v1.51.3...v1.51.4) (2024-12-04) + +**Note:** Version bump only for package @sofie-automation/blueprints-integration + + + + + ## [1.51.3](https://github.com/nrkno/sofie-core/compare/v1.51.2...v1.51.3) (2024-11-21) **Note:** Version bump only for package @sofie-automation/blueprints-integration diff --git a/packages/blueprints-integration/package.json b/packages/blueprints-integration/package.json index fc71da3f4f..2af513ab05 100644 --- a/packages/blueprints-integration/package.json +++ b/packages/blueprints-integration/package.json @@ -1,6 +1,6 @@ { "name": "@sofie-automation/blueprints-integration", - "version": "1.51.3", + "version": "1.51.4", "description": "Library to define the interaction between core and the blueprints.", "main": "dist/index.js", "typings": "dist/index.d.ts", @@ -38,7 +38,7 @@ "/LICENSE" ], "dependencies": { - "@sofie-automation/shared-lib": "1.51.3", + "@sofie-automation/shared-lib": "1.51.4", "tslib": "^2.6.2", "type-fest": "^3.13.1" }, diff --git a/packages/corelib/package.json b/packages/corelib/package.json index 4ac419dab0..1be22fa65f 100644 --- a/packages/corelib/package.json +++ b/packages/corelib/package.json @@ -1,6 +1,6 @@ { "name": "@sofie-automation/corelib", - "version": "1.51.3", + "version": "1.51.4", "private": true, "description": "Internal library for some types shared by core and workers", "main": "dist/index.js", @@ -39,8 +39,8 @@ "/LICENSE" ], "dependencies": { - "@sofie-automation/blueprints-integration": "1.51.3", - "@sofie-automation/shared-lib": "1.51.3", + "@sofie-automation/blueprints-integration": "1.51.4", + "@sofie-automation/shared-lib": "1.51.4", "fast-clone": "^1.5.13", "i18next": "^21.10.0", "influx": "^5.9.3", diff --git a/packages/documentation/package.json b/packages/documentation/package.json index 3e30e7ac85..28ad6a1d6b 100644 --- a/packages/documentation/package.json +++ b/packages/documentation/package.json @@ -1,6 +1,6 @@ { "name": "sofie-documentation", - "version": "1.51.3", + "version": "1.51.4", "private": true, "scripts": { "docusaurus": "docusaurus", diff --git a/packages/job-worker/package.json b/packages/job-worker/package.json index bbac4c7c60..bbb939e723 100644 --- a/packages/job-worker/package.json +++ b/packages/job-worker/package.json @@ -1,6 +1,6 @@ { "name": "@sofie-automation/job-worker", - "version": "1.51.3", + "version": "1.51.4", "description": "Worker for things", "main": "dist/index.js", "license": "MIT", @@ -41,9 +41,9 @@ ], "dependencies": { "@slack/webhook": "^6.1.0", - "@sofie-automation/blueprints-integration": "1.51.3", - "@sofie-automation/corelib": "1.51.3", - "@sofie-automation/shared-lib": "1.51.3", + "@sofie-automation/blueprints-integration": "1.51.4", + "@sofie-automation/corelib": "1.51.4", + "@sofie-automation/shared-lib": "1.51.4", "amqplib": "^0.10.3", "deepmerge": "^4.3.1", "elastic-apm-node": "^3.51.0", diff --git a/packages/lerna.json b/packages/lerna.json index 74b8a3c69c..3aee830fb3 100644 --- a/packages/lerna.json +++ b/packages/lerna.json @@ -1,5 +1,5 @@ { - "version": "1.51.3", + "version": "1.51.4", "npmClient": "yarn", "useWorkspaces": true } diff --git a/packages/live-status-gateway/package.json b/packages/live-status-gateway/package.json index 4397d3b2f3..0cd6b534b4 100644 --- a/packages/live-status-gateway/package.json +++ b/packages/live-status-gateway/package.json @@ -1,6 +1,6 @@ { "name": "live-status-gateway", - "version": "1.51.3", + "version": "1.51.4", "private": true, "description": "Provides state from Sofie over sockets", "license": "MIT", @@ -53,10 +53,10 @@ "production" ], "dependencies": { - "@sofie-automation/blueprints-integration": "1.51.3", - "@sofie-automation/corelib": "1.51.3", - "@sofie-automation/server-core-integration": "1.51.3", - "@sofie-automation/shared-lib": "1.51.3", + "@sofie-automation/blueprints-integration": "1.51.4", + "@sofie-automation/corelib": "1.51.4", + "@sofie-automation/server-core-integration": "1.51.4", + "@sofie-automation/shared-lib": "1.51.4", "debug": "^4.3.4", "fast-clone": "^1.5.13", "influx": "^5.9.3", diff --git a/packages/mos-gateway/CHANGELOG.md b/packages/mos-gateway/CHANGELOG.md index 9a91703d98..12651308e8 100644 --- a/packages/mos-gateway/CHANGELOG.md +++ b/packages/mos-gateway/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.51.4](https://github.com/nrkno/sofie-core/compare/v1.51.3...v1.51.4) (2024-12-04) + +**Note:** Version bump only for package mos-gateway + + + + + ## [1.51.3](https://github.com/nrkno/sofie-core/compare/v1.51.2...v1.51.3) (2024-11-21) diff --git a/packages/mos-gateway/package.json b/packages/mos-gateway/package.json index e0085ca549..d8c3461b16 100644 --- a/packages/mos-gateway/package.json +++ b/packages/mos-gateway/package.json @@ -1,6 +1,6 @@ { "name": "mos-gateway", - "version": "1.51.3", + "version": "1.51.4", "private": true, "description": "MOS-Gateway for the Sofie project", "license": "MIT", @@ -66,8 +66,8 @@ ], "dependencies": { "@mos-connection/connector": "4.1.1", - "@sofie-automation/server-core-integration": "1.51.3", - "@sofie-automation/shared-lib": "1.51.3", + "@sofie-automation/server-core-integration": "1.51.4", + "@sofie-automation/shared-lib": "1.51.4", "tslib": "^2.6.2", "type-fest": "^3.13.1", "underscore": "^1.13.6", diff --git a/packages/openapi/package.json b/packages/openapi/package.json index a79735ff45..4f9e693cc6 100644 --- a/packages/openapi/package.json +++ b/packages/openapi/package.json @@ -1,6 +1,6 @@ { "name": "@sofie-automation/openapi", - "version": "1.51.3", + "version": "1.51.4", "license": "MIT", "repository": { "type": "git", diff --git a/packages/playout-gateway/CHANGELOG.md b/packages/playout-gateway/CHANGELOG.md index 560b526971..0396e96547 100644 --- a/packages/playout-gateway/CHANGELOG.md +++ b/packages/playout-gateway/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.51.4](https://github.com/nrkno/sofie-core/compare/v1.51.3...v1.51.4) (2024-12-04) + +**Note:** Version bump only for package playout-gateway + + + + + ## [1.51.3](https://github.com/nrkno/sofie-core/compare/v1.51.2...v1.51.3) (2024-11-21) diff --git a/packages/playout-gateway/package.json b/packages/playout-gateway/package.json index 0d8e33c4fa..77702d6d29 100644 --- a/packages/playout-gateway/package.json +++ b/packages/playout-gateway/package.json @@ -1,6 +1,6 @@ { "name": "playout-gateway", - "version": "1.51.3", + "version": "1.51.4", "private": true, "description": "Connect to Core, play stuff", "license": "MIT", @@ -56,8 +56,8 @@ "production" ], "dependencies": { - "@sofie-automation/server-core-integration": "1.51.3", - "@sofie-automation/shared-lib": "1.51.3", + "@sofie-automation/server-core-integration": "1.51.4", + "@sofie-automation/shared-lib": "1.51.4", "debug": "^4.3.4", "influx": "^5.9.3", "timeline-state-resolver": "9.2.1", diff --git a/packages/server-core-integration/CHANGELOG.md b/packages/server-core-integration/CHANGELOG.md index 7dfd8d5ce6..b259defec9 100644 --- a/packages/server-core-integration/CHANGELOG.md +++ b/packages/server-core-integration/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.51.4](https://github.com/nrkno/sofie-core/compare/v1.51.3...v1.51.4) (2024-12-04) + +**Note:** Version bump only for package @sofie-automation/server-core-integration + + + + + ## [1.51.3](https://github.com/nrkno/sofie-core/compare/v1.51.2...v1.51.3) (2024-11-21) **Note:** Version bump only for package @sofie-automation/server-core-integration diff --git a/packages/server-core-integration/package.json b/packages/server-core-integration/package.json index 954e9f8f04..e8be09e879 100644 --- a/packages/server-core-integration/package.json +++ b/packages/server-core-integration/package.json @@ -1,6 +1,6 @@ { "name": "@sofie-automation/server-core-integration", - "version": "1.51.3", + "version": "1.51.4", "description": "Library for connecting to Core", "main": "dist/index.js", "typings": "dist/index.d.ts", @@ -70,7 +70,7 @@ "production" ], "dependencies": { - "@sofie-automation/shared-lib": "1.51.3", + "@sofie-automation/shared-lib": "1.51.4", "ejson": "^2.2.3", "eventemitter3": "^4.0.7", "faye-websocket": "^0.11.4", diff --git a/packages/shared-lib/package.json b/packages/shared-lib/package.json index 22e2b6b7fc..60928b7eaa 100644 --- a/packages/shared-lib/package.json +++ b/packages/shared-lib/package.json @@ -1,6 +1,6 @@ { "name": "@sofie-automation/shared-lib", - "version": "1.51.3", + "version": "1.51.4", "description": "Library for types & values shared by core, workers and gateways", "main": "dist/index.js", "typings": "dist/index.d.ts", diff --git a/packages/yarn.lock b/packages/yarn.lock index cf52fe25db..2cd2a6209b 100644 --- a/packages/yarn.lock +++ b/packages/yarn.lock @@ -4565,11 +4565,11 @@ __metadata: languageName: node linkType: hard -"@sofie-automation/blueprints-integration@1.51.3, @sofie-automation/blueprints-integration@workspace:blueprints-integration": +"@sofie-automation/blueprints-integration@1.51.4, @sofie-automation/blueprints-integration@workspace:blueprints-integration": version: 0.0.0-use.local resolution: "@sofie-automation/blueprints-integration@workspace:blueprints-integration" dependencies: - "@sofie-automation/shared-lib": 1.51.3 + "@sofie-automation/shared-lib": 1.51.4 tslib: ^2.6.2 type-fest: ^3.13.1 languageName: unknown @@ -4606,12 +4606,12 @@ __metadata: languageName: node linkType: hard -"@sofie-automation/corelib@1.51.3, @sofie-automation/corelib@workspace:corelib": +"@sofie-automation/corelib@1.51.4, @sofie-automation/corelib@workspace:corelib": version: 0.0.0-use.local resolution: "@sofie-automation/corelib@workspace:corelib" dependencies: - "@sofie-automation/blueprints-integration": 1.51.3 - "@sofie-automation/shared-lib": 1.51.3 + "@sofie-automation/blueprints-integration": 1.51.4 + "@sofie-automation/shared-lib": 1.51.4 fast-clone: ^1.5.13 i18next: ^21.10.0 influx: ^5.9.3 @@ -4642,9 +4642,9 @@ __metadata: resolution: "@sofie-automation/job-worker@workspace:job-worker" dependencies: "@slack/webhook": ^6.1.0 - "@sofie-automation/blueprints-integration": 1.51.3 - "@sofie-automation/corelib": 1.51.3 - "@sofie-automation/shared-lib": 1.51.3 + "@sofie-automation/blueprints-integration": 1.51.4 + "@sofie-automation/corelib": 1.51.4 + "@sofie-automation/shared-lib": 1.51.4 amqplib: ^0.10.3 deepmerge: ^4.3.1 elastic-apm-node: ^3.51.0 @@ -4674,11 +4674,11 @@ __metadata: languageName: unknown linkType: soft -"@sofie-automation/server-core-integration@1.51.3, @sofie-automation/server-core-integration@workspace:server-core-integration": +"@sofie-automation/server-core-integration@1.51.4, @sofie-automation/server-core-integration@workspace:server-core-integration": version: 0.0.0-use.local resolution: "@sofie-automation/server-core-integration@workspace:server-core-integration" dependencies: - "@sofie-automation/shared-lib": 1.51.3 + "@sofie-automation/shared-lib": 1.51.4 ejson: ^2.2.3 eventemitter3: ^4.0.7 faye-websocket: ^0.11.4 @@ -4688,7 +4688,7 @@ __metadata: languageName: unknown linkType: soft -"@sofie-automation/shared-lib@1.51.3, @sofie-automation/shared-lib@workspace:shared-lib": +"@sofie-automation/shared-lib@1.51.4, @sofie-automation/shared-lib@workspace:shared-lib": version: 0.0.0-use.local resolution: "@sofie-automation/shared-lib@workspace:shared-lib" dependencies: @@ -15334,10 +15334,10 @@ asn1@evs-broadcast/node-asn1: "@asyncapi/generator": ^1.17.25 "@asyncapi/html-template": ^2.3.9 "@asyncapi/nodejs-ws-template": ^0.9.36 - "@sofie-automation/blueprints-integration": 1.51.3 - "@sofie-automation/corelib": 1.51.3 - "@sofie-automation/server-core-integration": 1.51.3 - "@sofie-automation/shared-lib": 1.51.3 + "@sofie-automation/blueprints-integration": 1.51.4 + "@sofie-automation/corelib": 1.51.4 + "@sofie-automation/server-core-integration": 1.51.4 + "@sofie-automation/shared-lib": 1.51.4 debug: ^4.3.4 fast-clone: ^1.5.13 influx: ^5.9.3 @@ -17410,8 +17410,8 @@ asn1@evs-broadcast/node-asn1: resolution: "mos-gateway@workspace:mos-gateway" dependencies: "@mos-connection/connector": 4.1.1 - "@sofie-automation/server-core-integration": 1.51.3 - "@sofie-automation/shared-lib": 1.51.3 + "@sofie-automation/server-core-integration": 1.51.4 + "@sofie-automation/shared-lib": 1.51.4 tslib: ^2.6.2 type-fest: ^3.13.1 underscore: ^1.13.6 @@ -19397,8 +19397,8 @@ asn1@evs-broadcast/node-asn1: version: 0.0.0-use.local resolution: "playout-gateway@workspace:playout-gateway" dependencies: - "@sofie-automation/server-core-integration": 1.51.3 - "@sofie-automation/shared-lib": 1.51.3 + "@sofie-automation/server-core-integration": 1.51.4 + "@sofie-automation/shared-lib": 1.51.4 debug: ^4.3.4 influx: ^5.9.3 timeline-state-resolver: 9.2.1 From 6c030a4f1aec8a94dfdb5a55b791483b67fdb336 Mon Sep 17 00:00:00 2001 From: Jonas Hummelstrand Date: Wed, 4 Dec 2024 11:30:55 +0100 Subject: [PATCH 05/19] chore: Create url-query-parameters.md Created a page that lists all available URL query parameters. --- .../for-developers/url-query-parameters.md | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 packages/documentation/docs/for-developers/url-query-parameters.md diff --git a/packages/documentation/docs/for-developers/url-query-parameters.md b/packages/documentation/docs/for-developers/url-query-parameters.md new file mode 100644 index 0000000000..ff8263a4dd --- /dev/null +++ b/packages/documentation/docs/for-developers/url-query-parameters.md @@ -0,0 +1,22 @@ +--- +sidebar_label: URL Query Parameters +sidebar_position: 10 +--- + +# URL Query Parameters +Appending query parameters to the URL will allow you to modify the behaviour of the GUI, as well as control the access level. + +| Query Parameter | Description | +| :---------------------------------- | :------------------------------------------------------------------------ | +| `?admin=0,1` | Default value is `0`. | +| `?studio=0,1` | Default value is `0`. | +| `?display=layout,buckets,inspector` | A comma-separated list of features to be displayed in the shelf. Available values are: `layout` \(for displaying the Rundown Layout\), `buckets` \(for displaying the Buckets\) and `inspector` \(for displaying the Inspector\). | +| `?buckets=0,1,...` | The buckets can be specified as base-0 indices of the buckets as seen by the user. This means that `?buckets=1` will display the second bucket as seen by the user when not filtering the buckets. This allows the user to decide which bucket is displayed on a secondary attached screen simply by reordering the buckets on their main view. | +| `?shelffollowsonair=0,1` | | +| `?speak=0,1` | Default value is `0`. | +| `?vibrate=0,1` | Default value is `0`. | +| `?help=0,1` | Default value is `0`. | +| `?zoom=0,1` | Default value is `0`. | +| `?show_hidden_source_layers=0,1` | Default value is `0`. | +| `?ignore_piece_content_status=0,1` | Default value is `0`. | +| `?reportNotificationsId=0,1` | Default value is `0`. | From fa2f4fe923aa5cbec422236d43db75dcadc6e269 Mon Sep 17 00:00:00 2001 From: Jonas Hummelstrand Date: Wed, 4 Dec 2024 11:50:02 +0100 Subject: [PATCH 06/19] chore: Fixed capitalization in headlines --- .../docs/user-guide/features/access-levels.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/documentation/docs/user-guide/features/access-levels.md b/packages/documentation/docs/user-guide/features/access-levels.md index 50307f970e..0faf2f82b6 100644 --- a/packages/documentation/docs/user-guide/features/access-levels.md +++ b/packages/documentation/docs/user-guide/features/access-levels.md @@ -15,15 +15,15 @@ The access level is persisted in browser's Local Storage. To disable, visit`?the | **Settings** | No | Yes | No | Yes | -### Basic mode +### Basic Mode Without enabling any additional modes in Sofie, the browser will have minimal access to the system. It will be able to view a rundown but, will not have the ability to manipulate it. This includes activating, deactivating, or resetting the rundown as well as taking the next part, adlib, etc. -### Studio mode +### Studio Mode Studio Mode gives the current browser full control of the studio and all information associated to it. This includes allowing actions like activating and deactivating rundowns, taking parts, adlibbing, etc. This mode is accessed by adding a `?studio=1` to the end of the URL. -### Configuration mode +### Configuration Mode Configuration mode gives the user full control over the Settings pages and allows full access to the system including the ability to modify _Blueprints_, _Studios_, or _Show Styles_, creating and restoring _Snapshots_, as well as modifying attached devices. @@ -44,3 +44,4 @@ Enables the page Test Tools, which contains various tools useful for testing the ### Developer Mode This mode will enable the browsers default right click menu to appear and can be accessed by adding `?develop=1` to the URL. It will also reveal the Manual Control section on the Rundown page. + From 97fd35d06215b5075e44381fbf04b09db5a49ca1 Mon Sep 17 00:00:00 2001 From: Jonas Hummelstrand Date: Wed, 4 Dec 2024 12:22:19 +0100 Subject: [PATCH 07/19] chore: Update description of parameters Work in progress. --- .../for-developers/url-query-parameters.md | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/packages/documentation/docs/for-developers/url-query-parameters.md b/packages/documentation/docs/for-developers/url-query-parameters.md index ff8263a4dd..c9fc76a557 100644 --- a/packages/documentation/docs/for-developers/url-query-parameters.md +++ b/packages/documentation/docs/for-developers/url-query-parameters.md @@ -4,19 +4,22 @@ sidebar_position: 10 --- # URL Query Parameters -Appending query parameters to the URL will allow you to modify the behaviour of the GUI, as well as control the access level. +Appending query parameter(s) to the URL will allow you to modify the behaviour of the GUI, as well as control the [access levels](../user-guide/features/access-levels.md). | Query Parameter | Description | | :---------------------------------- | :------------------------------------------------------------------------ | -| `?admin=0,1` | Default value is `0`. | -| `?studio=0,1` | Default value is `0`. | -| `?display=layout,buckets,inspector` | A comma-separated list of features to be displayed in the shelf. Available values are: `layout` \(for displaying the Rundown Layout\), `buckets` \(for displaying the Buckets\) and `inspector` \(for displaying the Inspector\). | -| `?buckets=0,1,...` | The buckets can be specified as base-0 indices of the buckets as seen by the user. This means that `?buckets=1` will display the second bucket as seen by the user when not filtering the buckets. This allows the user to decide which bucket is displayed on a secondary attached screen simply by reordering the buckets on their main view. | -| `?shelffollowsonair=0,1` | | -| `?speak=0,1` | Default value is `0`. | -| `?vibrate=0,1` | Default value is `0`. | -| `?help=0,1` | Default value is `0`. | -| `?zoom=0,1` | Default value is `0`. | -| `?show_hidden_source_layers=0,1` | Default value is `0`. | -| `?ignore_piece_content_status=0,1` | Default value is `0`. | -| `?reportNotificationsId=0,1` | Default value is `0`. | +| `admin=1` | Gives the GUI the same access as the combination of [Configuration Mode](../user-guide/features/access-levels.md#Configuration-Mode) and [Studio Mode](../user-guide/features/access-levels.md#Studio-Mode) as well as having access to a set of [Testing Mode](../user-guide/features/access-levels.md#Testing-Mode) tools and a Manual Control section on the Rundown page. _Default value is `0`._ | +| `studio=1` | [Studio Mode](../user-guide/features/access-levels.md#Studio-Mode) gives the GUI full control of the studio and all information associated to it. This includes allowing actions like activating and deactivating rundowns, taking parts, adlibbing, etcetera. _Default value is `0`._ | +| `buckets=0,1,...` | The buckets can be specified as base-0 indices of the buckets as seen by the user. This means that `?buckets=1` will display the second bucket as seen by the user when not filtering the buckets. This allows the user to decide which bucket is displayed on a secondary attached screen simply by reordering the buckets on their main view. | +| `display=layout,buckets,inspector` | A comma-separated list of features to be displayed in the shelf. Available values are: `layout` \(for displaying the Rundown Layout\), `buckets` \(for displaying the Buckets\) and `inspector` \(for displaying the Inspector\). | +| `help=1` | Enables some tooltips that might be useful to new users. _Default value is `0`._ | +| `ignore_piece_content_status=1` | Removes the "zebra" marking on VT pieces that have a "missing" status. _Default value is `0`._ | +| `reportNotificationsId=0,1,...` | Allows you to set a specific `reportNotificationsId`. _Default value is `0`, meaning the that default ID (i.e. not `0`) will be used._ | +| `shelffollowsonair=1` | _Default value is `0`._ | +| `show_hidden_source_layers=1` | _Default value is `0`._ | +| `speak=1` | _Default value is `0`._ | +| `vibrate=1` | _Default value is `0`._ | +| `zoom=1` | _Default value is `0`._ | + + + From 51bdcff1a204d976c550e49c50d6146826e2044d Mon Sep 17 00:00:00 2001 From: Jonas Hummelstrand Date: Wed, 4 Dec 2024 19:28:02 +0100 Subject: [PATCH 08/19] chore: Additional URL parameter info Updated the "zoom" parameter. --- .../documentation/docs/for-developers/url-query-parameters.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/documentation/docs/for-developers/url-query-parameters.md b/packages/documentation/docs/for-developers/url-query-parameters.md index c9fc76a557..0281d81cf3 100644 --- a/packages/documentation/docs/for-developers/url-query-parameters.md +++ b/packages/documentation/docs/for-developers/url-query-parameters.md @@ -19,7 +19,7 @@ Appending query parameter(s) to the URL will allow you to modify the behaviour o | `show_hidden_source_layers=1` | _Default value is `0`._ | | `speak=1` | _Default value is `0`._ | | `vibrate=1` | _Default value is `0`._ | -| `zoom=1` | _Default value is `0`._ | +| `zoom=1,...` | Sets the scaling of the entire GUI. _The unit is a percentage where `100` is the default scaling._ | From 98693365983ddf3fe71797f824232298d39d16eb Mon Sep 17 00:00:00 2001 From: Jonas Hummelstrand Date: Thu, 5 Dec 2024 10:04:52 +0100 Subject: [PATCH 09/19] chore: Add cross-link to URL parameters page --- .../documentation/docs/user-guide/features/access-levels.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/documentation/docs/user-guide/features/access-levels.md b/packages/documentation/docs/user-guide/features/access-levels.md index 0faf2f82b6..0aad239095 100644 --- a/packages/documentation/docs/user-guide/features/access-levels.md +++ b/packages/documentation/docs/user-guide/features/access-levels.md @@ -45,3 +45,6 @@ Enables the page Test Tools, which contains various tools useful for testing the This mode will enable the browsers default right click menu to appear and can be accessed by adding `?develop=1` to the URL. It will also reveal the Manual Control section on the Rundown page. +### See Also + +[URL Query Parameters](../for-developers/url-query-parameters.md) From 8679d157c3fa81e59462fb76fd51c49a6a0ef31d Mon Sep 17 00:00:00 2001 From: Jonas Hummelstrand Date: Thu, 5 Dec 2024 10:05:53 +0100 Subject: [PATCH 10/19] chore: Fixed bad link --- .../documentation/docs/user-guide/features/access-levels.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/documentation/docs/user-guide/features/access-levels.md b/packages/documentation/docs/user-guide/features/access-levels.md index 0aad239095..830a30153c 100644 --- a/packages/documentation/docs/user-guide/features/access-levels.md +++ b/packages/documentation/docs/user-guide/features/access-levels.md @@ -47,4 +47,4 @@ This mode will enable the browsers default right click menu to appear and can be ### See Also -[URL Query Parameters](../for-developers/url-query-parameters.md) +[URL Query Parameters](../../for-developers/url-query-parameters.md) From d9c6cc878977644ccac384a1f39d0c06c0fa2e12 Mon Sep 17 00:00:00 2001 From: Jonas Hummelstrand Date: Thu, 5 Dec 2024 10:09:33 +0100 Subject: [PATCH 11/19] chore: Updated URL params content --- .../docs/for-developers/url-query-parameters.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/documentation/docs/for-developers/url-query-parameters.md b/packages/documentation/docs/for-developers/url-query-parameters.md index 0281d81cf3..104fe42cb5 100644 --- a/packages/documentation/docs/for-developers/url-query-parameters.md +++ b/packages/documentation/docs/for-developers/url-query-parameters.md @@ -4,13 +4,14 @@ sidebar_position: 10 --- # URL Query Parameters -Appending query parameter(s) to the URL will allow you to modify the behaviour of the GUI, as well as control the [access levels](../user-guide/features/access-levels.md). +Appending query parameter(s) to the URL will allow you to modify the behaviour of the GUI, as well as control the [Access Levels](../user-guide/features/access-levels.md). | Query Parameter | Description | | :---------------------------------- | :------------------------------------------------------------------------ | | `admin=1` | Gives the GUI the same access as the combination of [Configuration Mode](../user-guide/features/access-levels.md#Configuration-Mode) and [Studio Mode](../user-guide/features/access-levels.md#Studio-Mode) as well as having access to a set of [Testing Mode](../user-guide/features/access-levels.md#Testing-Mode) tools and a Manual Control section on the Rundown page. _Default value is `0`._ | | `studio=1` | [Studio Mode](../user-guide/features/access-levels.md#Studio-Mode) gives the GUI full control of the studio and all information associated to it. This includes allowing actions like activating and deactivating rundowns, taking parts, adlibbing, etcetera. _Default value is `0`._ | | `buckets=0,1,...` | The buckets can be specified as base-0 indices of the buckets as seen by the user. This means that `?buckets=1` will display the second bucket as seen by the user when not filtering the buckets. This allows the user to decide which bucket is displayed on a secondary attached screen simply by reordering the buckets on their main view. | +| `develop=1` | Enables the browser's default right-click menu to appear. It will also reveal the _Manual Control_ section on the Rundown page. _Default value is `0`._ | | `display=layout,buckets,inspector` | A comma-separated list of features to be displayed in the shelf. Available values are: `layout` \(for displaying the Rundown Layout\), `buckets` \(for displaying the Buckets\) and `inspector` \(for displaying the Inspector\). | | `help=1` | Enables some tooltips that might be useful to new users. _Default value is `0`._ | | `ignore_piece_content_status=1` | Removes the "zebra" marking on VT pieces that have a "missing" status. _Default value is `0`._ | @@ -18,8 +19,8 @@ Appending query parameter(s) to the URL will allow you to modify the behaviour o | `shelffollowsonair=1` | _Default value is `0`._ | | `show_hidden_source_layers=1` | _Default value is `0`._ | | `speak=1` | _Default value is `0`._ | +| `theaccessmode=0` | If user accounts are enabled \(`enableUserAccounts` in [_Sofie Core_ settings](../configuration/sofie-core-settings#settings-file)\), the [access levels](../user-guide/features/access-levels.md) are set under the user settings. If no user accounts are set, the access level for a browser is set by adding `?theaccessmode=1` to the URL. The access level is persisted in browser's Local Storage. To disable; add the URL query parameter `?theaccessmode=0`. _Default value is `1`._ | | `vibrate=1` | _Default value is `0`._ | | `zoom=1,...` | Sets the scaling of the entire GUI. _The unit is a percentage where `100` is the default scaling._ | - From 25d514ade445135265eae4e6f1c2ba1b316b522e Mon Sep 17 00:00:00 2001 From: Jonas Hummelstrand Date: Thu, 5 Dec 2024 15:24:42 +0100 Subject: [PATCH 12/19] chore: Updated vibrate and speak content --- .../documentation/docs/for-developers/url-query-parameters.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/documentation/docs/for-developers/url-query-parameters.md b/packages/documentation/docs/for-developers/url-query-parameters.md index 104fe42cb5..24d0fa49ca 100644 --- a/packages/documentation/docs/for-developers/url-query-parameters.md +++ b/packages/documentation/docs/for-developers/url-query-parameters.md @@ -18,9 +18,9 @@ Appending query parameter(s) to the URL will allow you to modify the behaviour o | `reportNotificationsId=0,1,...` | Allows you to set a specific `reportNotificationsId`. _Default value is `0`, meaning the that default ID (i.e. not `0`) will be used._ | | `shelffollowsonair=1` | _Default value is `0`._ | | `show_hidden_source_layers=1` | _Default value is `0`._ | -| `speak=1` | _Default value is `0`._ | +| `speak=1` | Experimental feature that starts playing an audible countdown 10 seconds before each planned _Take_. __Default value is `0`._ | | `theaccessmode=0` | If user accounts are enabled \(`enableUserAccounts` in [_Sofie Core_ settings](../configuration/sofie-core-settings#settings-file)\), the [access levels](../user-guide/features/access-levels.md) are set under the user settings. If no user accounts are set, the access level for a browser is set by adding `?theaccessmode=1` to the URL. The access level is persisted in browser's Local Storage. To disable; add the URL query parameter `?theaccessmode=0`. _Default value is `1`._ | -| `vibrate=1` | _Default value is `0`._ | +| `vibrate=1` | Experimental feature that triggers the vibration API in the web browser 3 seconds before each planned _Take_. _Default value is `0`._ | | `zoom=1,...` | Sets the scaling of the entire GUI. _The unit is a percentage where `100` is the default scaling._ | From 53af0eef8db4b0098d00311ba46b52ac2645a38f Mon Sep 17 00:00:00 2001 From: Jonas Hummelstrand Date: Mon, 9 Dec 2024 14:41:56 +0100 Subject: [PATCH 13/19] chore: Remove one parameter, clarified the use of another --- .../documentation/docs/for-developers/url-query-parameters.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/documentation/docs/for-developers/url-query-parameters.md b/packages/documentation/docs/for-developers/url-query-parameters.md index 24d0fa49ca..e4833df651 100644 --- a/packages/documentation/docs/for-developers/url-query-parameters.md +++ b/packages/documentation/docs/for-developers/url-query-parameters.md @@ -15,11 +15,10 @@ Appending query parameter(s) to the URL will allow you to modify the behaviour o | `display=layout,buckets,inspector` | A comma-separated list of features to be displayed in the shelf. Available values are: `layout` \(for displaying the Rundown Layout\), `buckets` \(for displaying the Buckets\) and `inspector` \(for displaying the Inspector\). | | `help=1` | Enables some tooltips that might be useful to new users. _Default value is `0`._ | | `ignore_piece_content_status=1` | Removes the "zebra" marking on VT pieces that have a "missing" status. _Default value is `0`._ | -| `reportNotificationsId=0,1,...` | Allows you to set a specific `reportNotificationsId`. _Default value is `0`, meaning the that default ID (i.e. not `0`) will be used._ | +| `reportNotificationsId=1,...` | Sets a specific ID of the client GUI. Useful for troubleshooting since this ID shows up in _Sofie Core_'s log. _Default value is "0", which disables the feature and uses a user-defined string (user as-in whoever is opening the client GUI, not necessarily the actual end-user)._ | | `shelffollowsonair=1` | _Default value is `0`._ | | `show_hidden_source_layers=1` | _Default value is `0`._ | | `speak=1` | Experimental feature that starts playing an audible countdown 10 seconds before each planned _Take_. __Default value is `0`._ | -| `theaccessmode=0` | If user accounts are enabled \(`enableUserAccounts` in [_Sofie Core_ settings](../configuration/sofie-core-settings#settings-file)\), the [access levels](../user-guide/features/access-levels.md) are set under the user settings. If no user accounts are set, the access level for a browser is set by adding `?theaccessmode=1` to the URL. The access level is persisted in browser's Local Storage. To disable; add the URL query parameter `?theaccessmode=0`. _Default value is `1`._ | | `vibrate=1` | Experimental feature that triggers the vibration API in the web browser 3 seconds before each planned _Take_. _Default value is `0`._ | | `zoom=1,...` | Sets the scaling of the entire GUI. _The unit is a percentage where `100` is the default scaling._ | From 6ada91ca449ac23acfe2a56267e550cea47002a3 Mon Sep 17 00:00:00 2001 From: Jonas Hummelstrand Date: Mon, 9 Dec 2024 14:43:51 +0100 Subject: [PATCH 14/19] chore: Fixed text styling --- .../documentation/docs/for-developers/url-query-parameters.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/documentation/docs/for-developers/url-query-parameters.md b/packages/documentation/docs/for-developers/url-query-parameters.md index e4833df651..fe9aa1c5fa 100644 --- a/packages/documentation/docs/for-developers/url-query-parameters.md +++ b/packages/documentation/docs/for-developers/url-query-parameters.md @@ -18,7 +18,7 @@ Appending query parameter(s) to the URL will allow you to modify the behaviour o | `reportNotificationsId=1,...` | Sets a specific ID of the client GUI. Useful for troubleshooting since this ID shows up in _Sofie Core_'s log. _Default value is "0", which disables the feature and uses a user-defined string (user as-in whoever is opening the client GUI, not necessarily the actual end-user)._ | | `shelffollowsonair=1` | _Default value is `0`._ | | `show_hidden_source_layers=1` | _Default value is `0`._ | -| `speak=1` | Experimental feature that starts playing an audible countdown 10 seconds before each planned _Take_. __Default value is `0`._ | +| `speak=1` | Experimental feature that starts playing an audible countdown 10 seconds before each planned _Take_. _Default value is `0`._ | | `vibrate=1` | Experimental feature that triggers the vibration API in the web browser 3 seconds before each planned _Take_. _Default value is `0`._ | | `zoom=1,...` | Sets the scaling of the entire GUI. _The unit is a percentage where `100` is the default scaling._ | From 2eafb6aafe17b88301e54068a9dbf73860fb1491 Mon Sep 17 00:00:00 2001 From: Johan Nyman Date: Thu, 12 Dec 2024 11:25:36 +0100 Subject: [PATCH 15/19] chore: fix crashing job-worker on startup the job worker crashes on startup when moving from release51 --- packages/job-worker/src/jobs/studio.ts | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/packages/job-worker/src/jobs/studio.ts b/packages/job-worker/src/jobs/studio.ts index 00a2f87893..16368fec1a 100644 --- a/packages/job-worker/src/jobs/studio.ts +++ b/packages/job-worker/src/jobs/studio.ts @@ -48,11 +48,25 @@ export function convertStudioToJobStudio(studio: DBStudio): JobStudio { 'routeSetExclusivityGroupsWithOverrides', 'packageContainersWithOverrides' ), - mappings: applyAndValidateOverrides(studio.mappingsWithOverrides).obj, - blueprintConfig: applyAndValidateOverrides(studio.blueprintConfigWithOverrides).obj, - settings: applyAndValidateOverrides(studio.settingsWithOverrides).obj, - routeSets: applyAndValidateOverrides(studio.routeSetsWithOverrides).obj, - routeSetExclusivityGroups: applyAndValidateOverrides(studio.routeSetExclusivityGroupsWithOverrides).obj, - // packageContainers: applyAndValidateOverrides(studio.packageContainersWithOverrides).obj, + // Note: checking for the overrides properties to exist first, + // because if they might not exist when migrating from an older version + // and this would crash the job-worker, creating a catch-22 situation. + + mappings: studio.mappingsWithOverrides + ? applyAndValidateOverrides(studio.mappingsWithOverrides).obj + : (studio as any).mappings || {}, + blueprintConfig: studio.blueprintConfigWithOverrides + ? applyAndValidateOverrides(studio.blueprintConfigWithOverrides).obj + : (studio as any).blueprintConfig || {}, + settings: studio.settingsWithOverrides + ? applyAndValidateOverrides(studio.settingsWithOverrides).obj + : (studio as any).settings || {}, + routeSets: studio.routeSetsWithOverrides + ? applyAndValidateOverrides(studio.routeSetsWithOverrides).obj + : (studio as any).routeSets || {}, + routeSetExclusivityGroups: studio.routeSetExclusivityGroupsWithOverrides + ? applyAndValidateOverrides(studio.routeSetExclusivityGroupsWithOverrides).obj + : (studio as any).routeSetExclusivityGroups || {}, + // packageContainers: studio.packageContainersWithOverrides ? applyAndValidateOverrides(studio.packageContainersWithOverrides).obj : (studio as any).packageContainers || {}, } } From e6e9aa7a78458b5689c5fa56826333e5e6cecb8c Mon Sep 17 00:00:00 2001 From: Johan Nyman Date: Thu, 12 Dec 2024 11:46:08 +0100 Subject: [PATCH 16/19] Partially revert "Merge pull request #1341 from bbc/upstream/tidying" (keep Meteor.absoluteUrl) Because Meteor.absoluteUrl is used to determine the correct path for connecting the websocket for the client ddp-connection. --- meteor/__mocks__/meteor.ts | 3 + packages/webui/src/meteor/meteor.js | 72 +++++++++++++++++++ .../src/meteor/socket-stream-client/urls.js | 4 ++ 3 files changed, 79 insertions(+) diff --git a/meteor/__mocks__/meteor.ts b/meteor/__mocks__/meteor.ts index 593eab34c4..2de891f99e 100644 --- a/meteor/__mocks__/meteor.ts +++ b/meteor/__mocks__/meteor.ts @@ -195,6 +195,9 @@ export namespace MeteorMock { // but it'll do for now: return callAsync(methodName, ...args) } + export function absoluteUrl(path?: string): string { + return path + '' // todo + } export function setTimeout(fcn: () => void | Promise, time: number): number { return $.setTimeout(() => { Promise.resolve() diff --git a/packages/webui/src/meteor/meteor.js b/packages/webui/src/meteor/meteor.js index 049cad2f65..ada0224220 100644 --- a/packages/webui/src/meteor/meteor.js +++ b/packages/webui/src/meteor/meteor.js @@ -234,6 +234,78 @@ Meteor.Error.prototype.clone = function () { return new Meteor.Error(self.error, self.reason, self.details) } +/** + * @summary Generate an absolute URL pointing to the application. The server reads from the `ROOT_URL` environment variable to determine where it is running. This is taken care of automatically for apps deployed to Galaxy, but must be provided when using `meteor build`. + * @locus Anywhere + * @param {String} [path] A path to append to the root URL. Do not include a leading "`/`". + * @param {Object} [options] + * @param {Boolean} options.secure Create an HTTPS URL. + * @param {Boolean} options.replaceLocalhost Replace localhost with 127.0.0.1. Useful for services that don't recognize localhost as a domain name. + * @param {String} options.rootUrl Override the default ROOT_URL from the server environment. For example: "`http://foo.example.com`" + */ +Meteor.absoluteUrl = function (path, options) { + // path is optional + if (!options && typeof path === 'object') { + options = path + path = undefined + } + // merge options with defaults + options = Object.assign({}, Meteor.absoluteUrl.defaultOptions, options || {}) + + var url = options.rootUrl + if (!url) throw new Error('Must pass options.rootUrl or set ROOT_URL in the server environment') + + if (!/^http[s]?:\/\//i.test(url)) + // url starts with 'http://' or 'https://' + url = 'http://' + url // we will later fix to https if options.secure is set + + if (!url.endsWith('/')) { + url += '/' + } + + if (path) { + // join url and path with a / separator + while (path.startsWith('/')) { + path = path.slice(1) + } + url += path + } + + // turn http to https if secure option is set, and we're not talking + // to localhost. + if ( + options.secure && + /^http:/.test(url) && // url starts with 'http:' + !/http:\/\/localhost[:\/]/.test(url) && // doesn't match localhost + !/http:\/\/127\.0\.0\.1[:\/]/.test(url) + ) + // or 127.0.0.1 + url = url.replace(/^http:/, 'https:') + + if (options.replaceLocalhost) url = url.replace(/^http:\/\/localhost([:\/].*)/, 'http://127.0.0.1$1') + + return url +} + +// allow later packages to override default options +var defaultOptions = (Meteor.absoluteUrl.defaultOptions = {}) + +// available only in a browser environment +var location = typeof window === 'object' && window.location + +if (typeof window.__meteor_runtime_config__ === 'object' && window.__meteor_runtime_config__.ROOT_URL) { + defaultOptions.rootUrl = window.__meteor_runtime_config__.ROOT_URL +} else if (location && location.protocol && location.host) { + defaultOptions.rootUrl = location.protocol + '//' + location.host +} + +// Make absolute URLs use HTTPS by default if the current window.location +// uses HTTPS. Since this is just a default, it can be overridden by +// passing { secure: false } if necessary. +if (location && location.protocol === 'https:') { + defaultOptions.secure = true +} + Meteor._relativeToSiteRootUrl = function (link) { if (typeof window.__meteor_runtime_config__ === 'object' && link.substr(0, 1) === '/') link = (window.__meteor_runtime_config__.ROOT_URL_PATH_PREFIX || '') + link diff --git a/packages/webui/src/meteor/socket-stream-client/urls.js b/packages/webui/src/meteor/socket-stream-client/urls.js index d5bb41e57b..232c9bc247 100644 --- a/packages/webui/src/meteor/socket-stream-client/urls.js +++ b/packages/webui/src/meteor/socket-stream-client/urls.js @@ -12,6 +12,10 @@ function translateUrl(url, newSchemeBase, subPath) { newSchemeBase = 'http'; } + if (subPath !== "sockjs" && url.startsWith("/")) { + url = Meteor.absoluteUrl(url.substr(1)); + } + var ddpUrlMatch = url.match(/^ddp(i?)\+sockjs:\/\//); var httpUrlMatch = url.match(/^http(s?):\/\//); var newScheme; From ddab6dff7e714a0d0d53a8e1925b6e7c6307f409 Mon Sep 17 00:00:00 2001 From: Jan Starzak Date: Thu, 12 Dec 2024 12:07:17 +0100 Subject: [PATCH 17/19] fix: missing roboto font after scss cleanup Co-authored-by: olzzon --- packages/webui/src/client/styles/_robotoFont.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/webui/src/client/styles/_robotoFont.scss b/packages/webui/src/client/styles/_robotoFont.scss index 29e8bba293..a9c6cae584 100644 --- a/packages/webui/src/client/styles/_robotoFont.scss +++ b/packages/webui/src/client/styles/_robotoFont.scss @@ -1 +1,2 @@ $FontPath: '../../fonts/roboto-gh-pages/fonts'; +@import 'fonts/roboto'; \ No newline at end of file From 8292d9656ac40fb111078966d511f16a977bca38 Mon Sep 17 00:00:00 2001 From: Julian Waller Date: Mon, 16 Dec 2024 11:23:19 +0000 Subject: [PATCH 18/19] fix: remove Meteor.absoluteUrl and proxy ddp through vite. This is needed when using header auth in development, otherwise the websocket to meteor connects directly rather than through the reverse proxy which adds the auth headers. This reverts commit e6e9aa7a78458b5689c5fa56826333e5e6cecb8c. --- meteor/__mocks__/meteor.ts | 3 - packages/webui/src/meteor/meteor.js | 72 ------------------- .../src/meteor/socket-stream-client/urls.js | 4 -- packages/webui/vite.config.mts | 4 ++ 4 files changed, 4 insertions(+), 79 deletions(-) diff --git a/meteor/__mocks__/meteor.ts b/meteor/__mocks__/meteor.ts index 2de891f99e..593eab34c4 100644 --- a/meteor/__mocks__/meteor.ts +++ b/meteor/__mocks__/meteor.ts @@ -195,9 +195,6 @@ export namespace MeteorMock { // but it'll do for now: return callAsync(methodName, ...args) } - export function absoluteUrl(path?: string): string { - return path + '' // todo - } export function setTimeout(fcn: () => void | Promise, time: number): number { return $.setTimeout(() => { Promise.resolve() diff --git a/packages/webui/src/meteor/meteor.js b/packages/webui/src/meteor/meteor.js index ada0224220..049cad2f65 100644 --- a/packages/webui/src/meteor/meteor.js +++ b/packages/webui/src/meteor/meteor.js @@ -234,78 +234,6 @@ Meteor.Error.prototype.clone = function () { return new Meteor.Error(self.error, self.reason, self.details) } -/** - * @summary Generate an absolute URL pointing to the application. The server reads from the `ROOT_URL` environment variable to determine where it is running. This is taken care of automatically for apps deployed to Galaxy, but must be provided when using `meteor build`. - * @locus Anywhere - * @param {String} [path] A path to append to the root URL. Do not include a leading "`/`". - * @param {Object} [options] - * @param {Boolean} options.secure Create an HTTPS URL. - * @param {Boolean} options.replaceLocalhost Replace localhost with 127.0.0.1. Useful for services that don't recognize localhost as a domain name. - * @param {String} options.rootUrl Override the default ROOT_URL from the server environment. For example: "`http://foo.example.com`" - */ -Meteor.absoluteUrl = function (path, options) { - // path is optional - if (!options && typeof path === 'object') { - options = path - path = undefined - } - // merge options with defaults - options = Object.assign({}, Meteor.absoluteUrl.defaultOptions, options || {}) - - var url = options.rootUrl - if (!url) throw new Error('Must pass options.rootUrl or set ROOT_URL in the server environment') - - if (!/^http[s]?:\/\//i.test(url)) - // url starts with 'http://' or 'https://' - url = 'http://' + url // we will later fix to https if options.secure is set - - if (!url.endsWith('/')) { - url += '/' - } - - if (path) { - // join url and path with a / separator - while (path.startsWith('/')) { - path = path.slice(1) - } - url += path - } - - // turn http to https if secure option is set, and we're not talking - // to localhost. - if ( - options.secure && - /^http:/.test(url) && // url starts with 'http:' - !/http:\/\/localhost[:\/]/.test(url) && // doesn't match localhost - !/http:\/\/127\.0\.0\.1[:\/]/.test(url) - ) - // or 127.0.0.1 - url = url.replace(/^http:/, 'https:') - - if (options.replaceLocalhost) url = url.replace(/^http:\/\/localhost([:\/].*)/, 'http://127.0.0.1$1') - - return url -} - -// allow later packages to override default options -var defaultOptions = (Meteor.absoluteUrl.defaultOptions = {}) - -// available only in a browser environment -var location = typeof window === 'object' && window.location - -if (typeof window.__meteor_runtime_config__ === 'object' && window.__meteor_runtime_config__.ROOT_URL) { - defaultOptions.rootUrl = window.__meteor_runtime_config__.ROOT_URL -} else if (location && location.protocol && location.host) { - defaultOptions.rootUrl = location.protocol + '//' + location.host -} - -// Make absolute URLs use HTTPS by default if the current window.location -// uses HTTPS. Since this is just a default, it can be overridden by -// passing { secure: false } if necessary. -if (location && location.protocol === 'https:') { - defaultOptions.secure = true -} - Meteor._relativeToSiteRootUrl = function (link) { if (typeof window.__meteor_runtime_config__ === 'object' && link.substr(0, 1) === '/') link = (window.__meteor_runtime_config__.ROOT_URL_PATH_PREFIX || '') + link diff --git a/packages/webui/src/meteor/socket-stream-client/urls.js b/packages/webui/src/meteor/socket-stream-client/urls.js index 232c9bc247..d5bb41e57b 100644 --- a/packages/webui/src/meteor/socket-stream-client/urls.js +++ b/packages/webui/src/meteor/socket-stream-client/urls.js @@ -12,10 +12,6 @@ function translateUrl(url, newSchemeBase, subPath) { newSchemeBase = 'http'; } - if (subPath !== "sockjs" && url.startsWith("/")) { - url = Meteor.absoluteUrl(url.substr(1)); - } - var ddpUrlMatch = url.match(/^ddp(i?)\+sockjs:\/\//); var httpUrlMatch = url.match(/^http(s?):\/\//); var newScheme; diff --git a/packages/webui/vite.config.mts b/packages/webui/vite.config.mts index 86666f92e3..8ca2ac96c3 100644 --- a/packages/webui/vite.config.mts +++ b/packages/webui/vite.config.mts @@ -59,6 +59,10 @@ export default defineConfig({ '/api': 'http://127.0.0.1:3000', '/site.webmanifest': 'http://127.0.0.1:3000', '/meteor-runtime-config.js': 'http://127.0.0.1:3000', + '/websocket': { + target: `ws://127.0.0.1:3000`, + ws: true, + }, }, }, From e9f21fbbc4c1b64c17cfb984fae1514aa87a3465 Mon Sep 17 00:00:00 2001 From: olzzon Date: Tue, 17 Dec 2024 10:16:08 +0100 Subject: [PATCH 19/19] feat: Evaluation form is optional in studio settings, with default turned on. --- meteor/__mocks__/defaultCollectionObjects.ts | 1 + meteor/server/api/rest/v1/typeConversion.ts | 2 + meteor/server/api/studio/api.ts | 1 + meteor/server/lib/rest/v1/studios.ts | 1 + meteor/server/migration/0_1_0.ts | 1 + meteor/server/migration/X_X_X.ts | 50 +++++++++++++++++++ .../migration/__tests__/migrations.test.ts | 3 ++ .../__tests__/checkPieceContentStatus.test.ts | 1 + .../src/__mocks__/defaultCollectionObjects.ts | 1 + .../src/blueprints/__tests__/config.test.ts | 2 + packages/job-worker/src/playout/upgrade.ts | 1 + .../src/core/model/StudioSettings.ts | 5 ++ .../src/__mocks__/defaultCollectionObjects.ts | 1 + packages/webui/src/client/ui/RundownView.tsx | 3 +- .../src/client/ui/Settings/Studio/Generic.tsx | 10 ++++ 15 files changed, 82 insertions(+), 1 deletion(-) diff --git a/meteor/__mocks__/defaultCollectionObjects.ts b/meteor/__mocks__/defaultCollectionObjects.ts index 5e4784ece2..4e5c1e1563 100644 --- a/meteor/__mocks__/defaultCollectionObjects.ts +++ b/meteor/__mocks__/defaultCollectionObjects.ts @@ -113,6 +113,7 @@ export function defaultStudio(_id: StudioId): DBStudio { allowHold: false, allowPieceDirectPlay: false, enableBuckets: false, + enableEvaluationForm: true, }), _rundownVersionHash: '', routeSetsWithOverrides: wrapDefaultObject({}), diff --git a/meteor/server/api/rest/v1/typeConversion.ts b/meteor/server/api/rest/v1/typeConversion.ts index e1ec97bea5..e4142bcff0 100644 --- a/meteor/server/api/rest/v1/typeConversion.ts +++ b/meteor/server/api/rest/v1/typeConversion.ts @@ -371,6 +371,7 @@ export function studioSettingsFrom(apiStudioSettings: APIStudioSettings): Comple allowHold: apiStudioSettings.allowHold ?? true, // Backwards compatible allowPieceDirectPlay: apiStudioSettings.allowPieceDirectPlay ?? true, // Backwards compatible enableBuckets: apiStudioSettings.enableBuckets ?? true, // Backwards compatible + enableEvaluationForm: apiStudioSettings.enableEvaluationForm ?? true, // Backwards compatible } } @@ -394,6 +395,7 @@ export function APIStudioSettingsFrom(settings: IStudioSettings): Complete { + const studios = await Studios.findFetchAsync({ + 'settingsWithOverrides.defaults.enableBuckets': { $exists: false }, + }) + if (studios.length > 0) { + return 'studio is missing enableBuckets setting' + } + return false + }, + migrate: async () => { + const studios = await Studios.findFetchAsync({ + 'settingsWithOverrides.defaults.enableBuckets': { $exists: false }, + }) + for (const studio of studios) { + await Studios.updateAsync(studio._id, { + $set: { + 'settingsWithOverrides.defaults.enableBuckets': true, + }, + }) + } + }, + }, + { + id: `studios settings create default enableEvaluationForm=true`, + canBeRunAutomatically: true, + validate: async () => { + const studios = await Studios.findFetchAsync({ + 'settingsWithOverrides.defaults.enableEvaluationForm': { $exists: false }, + }) + if (studios.length > 0) { + return 'studio is missing enableEvaluationForm setting' + } + return false + }, + migrate: async () => { + const studios = await Studios.findFetchAsync({ + 'settingsWithOverrides.defaults.enableEvaluationForm': { $exists: false }, + }) + for (const studio of studios) { + await Studios.updateAsync(studio._id, { + $set: { + 'settingsWithOverrides.defaults.enableEvaluationForm': true, + }, + }) + } + }, + }, ]) interface PartialOldICoreSystem { diff --git a/meteor/server/migration/__tests__/migrations.test.ts b/meteor/server/migration/__tests__/migrations.test.ts index 973610f322..510d40c8ca 100644 --- a/meteor/server/migration/__tests__/migrations.test.ts +++ b/meteor/server/migration/__tests__/migrations.test.ts @@ -118,6 +118,7 @@ describe('Migrations', () => { allowHold: true, allowPieceDirectPlay: true, enableBuckets: true, + enableEvaluationForm: true, }), mappingsWithOverrides: wrapDefaultObject({}), blueprintConfigWithOverrides: wrapDefaultObject({}), @@ -160,6 +161,7 @@ describe('Migrations', () => { allowHold: true, allowPieceDirectPlay: true, enableBuckets: true, + enableEvaluationForm: true, }), mappingsWithOverrides: wrapDefaultObject({}), blueprintConfigWithOverrides: wrapDefaultObject({}), @@ -202,6 +204,7 @@ describe('Migrations', () => { allowHold: true, allowPieceDirectPlay: true, enableBuckets: true, + enableEvaluationForm: true, }), mappingsWithOverrides: wrapDefaultObject({}), blueprintConfigWithOverrides: wrapDefaultObject({}), diff --git a/meteor/server/publications/pieceContentStatusUI/__tests__/checkPieceContentStatus.test.ts b/meteor/server/publications/pieceContentStatusUI/__tests__/checkPieceContentStatus.test.ts index c4196d32f2..233b115872 100644 --- a/meteor/server/publications/pieceContentStatusUI/__tests__/checkPieceContentStatus.test.ts +++ b/meteor/server/publications/pieceContentStatusUI/__tests__/checkPieceContentStatus.test.ts @@ -252,6 +252,7 @@ describe('lib/mediaObjects', () => { allowHold: false, allowPieceDirectPlay: false, enableBuckets: false, + enableEvaluationForm: false, } const mockDefaultStudio = defaultStudio(protectString('studio0')) diff --git a/packages/job-worker/src/__mocks__/defaultCollectionObjects.ts b/packages/job-worker/src/__mocks__/defaultCollectionObjects.ts index 77f56c6b60..5d476afed9 100644 --- a/packages/job-worker/src/__mocks__/defaultCollectionObjects.ts +++ b/packages/job-worker/src/__mocks__/defaultCollectionObjects.ts @@ -110,6 +110,7 @@ export function defaultStudio(_id: StudioId): DBStudio { allowHold: true, allowPieceDirectPlay: true, enableBuckets: true, + enableEvaluationForm: true, }), routeSetsWithOverrides: wrapDefaultObject({}), routeSetExclusivityGroupsWithOverrides: wrapDefaultObject({}), diff --git a/packages/job-worker/src/blueprints/__tests__/config.test.ts b/packages/job-worker/src/blueprints/__tests__/config.test.ts index 3e7e8bef50..f1616eb38f 100644 --- a/packages/job-worker/src/blueprints/__tests__/config.test.ts +++ b/packages/job-worker/src/blueprints/__tests__/config.test.ts @@ -18,6 +18,7 @@ describe('Test blueprint config', () => { allowHold: true, allowPieceDirectPlay: true, enableBuckets: true, + enableEvaluationForm: true, }), blueprintConfigWithOverrides: wrapDefaultObject({ sdfsdf: 'one', another: 5 }), }) @@ -44,6 +45,7 @@ describe('Test blueprint config', () => { allowHold: true, allowPieceDirectPlay: true, enableBuckets: true, + enableEvaluationForm: true, }), blueprintConfigWithOverrides: wrapDefaultObject({ sdfsdf: 'one', another: 5 }), }) diff --git a/packages/job-worker/src/playout/upgrade.ts b/packages/job-worker/src/playout/upgrade.ts index b6d2b43cb4..7f887b3ac5 100644 --- a/packages/job-worker/src/playout/upgrade.ts +++ b/packages/job-worker/src/playout/upgrade.ts @@ -129,6 +129,7 @@ export async function handleBlueprintUpgradeForStudio(context: JobContext, _data allowHold: true, allowPieceDirectPlay: true, enableBuckets: true, + enableEvaluationForm: true, } await context.directCollections.Studios.update(context.studioId, { diff --git a/packages/shared-lib/src/core/model/StudioSettings.ts b/packages/shared-lib/src/core/model/StudioSettings.ts index f964362679..a57780824d 100644 --- a/packages/shared-lib/src/core/model/StudioSettings.ts +++ b/packages/shared-lib/src/core/model/StudioSettings.ts @@ -81,4 +81,9 @@ export interface IStudioSettings { * Enable buckets - the default behavior is to have buckets. */ enableBuckets: boolean + + /** + * Enable evaluation form - the default behavior is to have evaluation forms. + */ + enableEvaluationForm: boolean } diff --git a/packages/webui/src/__mocks__/defaultCollectionObjects.ts b/packages/webui/src/__mocks__/defaultCollectionObjects.ts index a17d5e18fb..7f0e55989c 100644 --- a/packages/webui/src/__mocks__/defaultCollectionObjects.ts +++ b/packages/webui/src/__mocks__/defaultCollectionObjects.ts @@ -108,6 +108,7 @@ export function defaultStudio(_id: StudioId): DBStudio { allowHold: true, allowPieceDirectPlay: true, enableBuckets: true, + enableEvaluationForm: true, }), _rundownVersionHash: '', routeSetsWithOverrides: wrapDefaultObject({}), diff --git a/packages/webui/src/client/ui/RundownView.tsx b/packages/webui/src/client/ui/RundownView.tsx index 8dd1c411a6..9210c801db 100644 --- a/packages/webui/src/client/ui/RundownView.tsx +++ b/packages/webui/src/client/ui/RundownView.tsx @@ -3029,7 +3029,8 @@ const RundownViewContent = translateWithTracker {this.props.matchedSegments && this.props.matchedSegments.length > 0 && - this.props.userPermissions.studio && } + this.props.userPermissions.studio && + studio.settings.enableEvaluationForm && } } + + {(value, handleUpdate) => } + +