Skip to content

Commit c2556cd

Browse files
committed
Merge branch 'release51' into release52
# Conflicts: # packages/job-worker/src/playout/timeline/multi-gateway.ts
2 parents d46adb1 + 94214a3 commit c2556cd

File tree

6 files changed

+144
-28
lines changed

6 files changed

+144
-28
lines changed

.github/workflows/node.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ jobs:
252252
echo "image=$image" >> $GITHUB_OUTPUT
253253
- name: Trivy scanning
254254
if: steps.check-build-and-push.outputs.enable == 'true' && steps.check-ghcr.outputs.enable == 'true' && steps.ghcr-tag.outputs.tags != 0
255-
uses: aquasecurity/trivy-action@0.29.0
255+
uses: aquasecurity/trivy-action@0.30.0
256256
env:
257257
TRIVY_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-db
258258
with:
@@ -405,7 +405,7 @@ jobs:
405405
echo "image=$image" >> $GITHUB_OUTPUT
406406
- name: Trivy scanning
407407
if: steps.check-build-and-push.outputs.enable == 'true' && steps.check-ghcr.outputs.enable == 'true' && steps.ghcr-tag.outputs.tags != 0
408-
uses: aquasecurity/trivy-action@0.29.0
408+
uses: aquasecurity/trivy-action@0.30.0
409409
env:
410410
TRIVY_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-db
411411
with:

.github/workflows/trivy.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717

1818
steps:
1919
- name: Run Trivy vulnerability scanner (json)
20-
uses: aquasecurity/trivy-action@0.29.0
20+
uses: aquasecurity/trivy-action@0.30.0
2121
env:
2222
TRIVY_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-db
2323
with:
@@ -26,7 +26,7 @@ jobs:
2626
output: "${{ matrix.image }}-trivy-scan-results.json"
2727

2828
- name: Run Trivy vulnerability scanner (table)
29-
uses: aquasecurity/trivy-action@0.29.0
29+
uses: aquasecurity/trivy-action@0.30.0
3030
env:
3131
TRIVY_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-db
3232
with:
@@ -44,7 +44,7 @@ jobs:
4444
echo $CODE_BLOCK >> $GITHUB_STEP_SUMMARY
4545
4646
- name: Run Trivy in GitHub SBOM mode and submit results to Dependency Graph
47-
uses: aquasecurity/trivy-action@0.29.0
47+
uses: aquasecurity/trivy-action@0.30.0
4848
env:
4949
TRIVY_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-db
5050
with:

packages/documentation/docs/for-developers/contribution-guidelines.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,22 @@ Before you start, there are a few things you should know:
3030

3131
**Minor changes** (most bug fixes and small features) can be submitted directly as pull requests to the appropriate official repo.
3232

33-
However, Sofie is a big project with many differing users and use cases. **Larger changes** might be more difficult to merge into an official repository if NRK has not been made aware of their existence beforehand. To facilitate a timely handling of larger contributions, there’s a workflow intended to keep an open dialogue between all interested parties:
33+
However, Sofie is a big project with many differing users and use cases. **Larger changes** may be difficult to merge into an official repository if NRK and other contributors have not been made aware of their existence beforehand. Since figuring out what side-effects a new feature or a change may have for other Sofie users can be tricky, we advise opening an RFC issue (_Request for Comments_) early in your process. Good moments to open an RFC include:
34+
* When a user need is identified and described
35+
* When you have a rough idea about how a feature may be implemented
36+
* When you have a sketch of how a feature could look like to the user
37+
38+
To facilitate timely handling of larger contributions, there’s a workflow intended to keep an open dialogue between all interested parties:
3439

3540
1. Contributor opens an RFC (as a _GitHub issue_) in the appropriate repository.
3641
2. NRK evaluates the RFC, usually within a week.
37-
3. (If needed) NRK establishes contact with the RFC author, who will be invited to a workshop where the RFC is discussed. Meeting notes are published publicly on the RFC thread.
38-
4. The contributor references the RFC when a pull request is ready.
42+
3. If needed, NRK establishes contact with the RFC author, who will be invited to a workshop where the RFC is discussed. Meeting notes are published publicly on the RFC thread.
43+
4. Discussions about the RFC continue as needed, either in workshops or in comments in the RFC thread.
44+
5. The contributor references the RFC when a pull request is ready.
45+
46+
It will be very helpful if your RFC includes specific use-cases that you are facing. Providing a background on how your users are using Sofie can clear up situations in which certain phrases or processes may be ambiguous. If during your process you have already identified various solutions as favorable or unfavorable, offering this context will move the discussion further still.
47+
48+
Via the RFC process, we're looking to maximize involvement from various stakeholders, so you probably don't need to come up with a very detailed design of your proposed change or feature in the RFC. An end-user oriented description will be most valuable in creating a constructive dialogue, but don't shy away from also adding a more technical description, if you find that will convey your ideas better.
3949

4050
### Base contributions on the in-development branch
4151
In order to facilitate merging, we ask that contributions are based on the latest (at the time of the pull request) _in-development_ branch (often named `release*`).

packages/job-worker/src/playout/timeline/multi-gateway.ts

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { TimelineObjRundown } from '@sofie-automation/corelib/dist/dataModel/Tim
55
import { normalizeArray } from '@sofie-automation/corelib/dist/lib'
66
import { PieceTimelineMetadata } from './pieceGroup'
77
import { StudioPlayoutModelBase } from '../../studio/model/StudioPlayoutModel'
8+
import { logger } from '../../logging'
89
import { JobContext } from '../../jobs'
910
import { getCurrentTime } from '../../lib'
1011
import { PlayoutModel } from '../model/PlayoutModel'
@@ -46,7 +47,7 @@ export function deNowifyMultiGatewayTimeline(
4647
playoutModel.nextPartInstance
4748
)
4849

49-
deNowifyCurrentPieces(
50+
const { objectsNotDeNowified } = deNowifyCurrentPieces(
5051
targetNowTime,
5152
timingContext,
5253
currentPartInstance,
@@ -55,6 +56,9 @@ export function deNowifyMultiGatewayTimeline(
5556
)
5657

5758
updatePlannedTimingsForPieceInstances(playoutModel, currentPartInstance, partGroupTimings, timelineObjsMap)
59+
60+
// Because updatePlannedTimingsForPieceInstances changes start times of infinites, we can now run deNowifyInfinites()
61+
deNowifyInfinites(targetNowTime, objectsNotDeNowified, timelineObjsMap)
5862
}
5963

6064
/**
@@ -142,16 +146,83 @@ function updatePartInstancePlannedTimes(
142146
}
143147
}
144148

149+
/**
150+
* Replace the `now` time in any timeline objects in freshly-placed infinites.
151+
*
152+
* This is effectively only needed when a new item has been placed on the timeline just now and changes made by
153+
* `updatePlannedTimingsForPieceInstances` haven't been taken into account when generating the timeline. On the next
154+
* regeneration, items will already use the timestamps persited by `updatePlannedTimingsForPieceInstances` and will not
155+
* be included in `infiniteObjs`.
156+
*/
157+
function deNowifyInfinites(
158+
targetNowTime: number,
159+
/** A list of objects that need to be updated */
160+
infiniteObjs: TimelineObjRundown[],
161+
timelineObjsMap: Record<string, TimelineObjRundown>
162+
) {
163+
/**
164+
* Recursively look up the absolute starttime of a timeline object
165+
* taking into account its parent's times.
166+
* Note: This only supports timeline objects that have absolute enable.start times.
167+
*/
168+
const getStartTime = (obj: TimelineObjRundown): number | undefined => {
169+
if (Array.isArray(obj.enable)) return undefined
170+
171+
const myStartTime = typeof obj.enable.start === 'number' ? obj.enable.start : undefined
172+
173+
if (!obj.inGroup) return myStartTime
174+
175+
if (myStartTime === undefined) return undefined
176+
177+
const parentObject = timelineObjsMap[obj.inGroup]
178+
if (!parentObject) return undefined
179+
180+
const parentStartTime = getStartTime(parentObject)
181+
if (parentStartTime === undefined) return undefined
182+
183+
return parentStartTime + myStartTime
184+
}
185+
186+
for (const obj of infiniteObjs) {
187+
if (Array.isArray(obj.enable) || obj.enable.start !== 'now') continue
188+
189+
if (!obj.inGroup) {
190+
obj.enable = { start: targetNowTime }
191+
continue
192+
}
193+
194+
const parentObject = timelineObjsMap[obj.inGroup]
195+
if (!parentObject) {
196+
logger.error(`deNowifyInfinites: Parent obj "${obj.inGroup}" not found of object "${obj.id}"`)
197+
continue
198+
}
199+
200+
const parentStartTime = getStartTime(parentObject)
201+
if (parentStartTime === undefined) {
202+
logger.error(
203+
`deNowifyInfinites: Unable to derive an absolute start time of parent "${obj.inGroup}" for object "${obj.id}"`
204+
)
205+
continue
206+
}
207+
208+
obj.enable = { start: targetNowTime - parentStartTime }
209+
logger.silly(
210+
`deNowifyInfinites: Setting "${obj.id}" enable.start = ${obj.enable.start}, ${targetNowTime} ${parentStartTime} parentObject: "${parentObject.id}"`
211+
)
212+
}
213+
}
145214
/**
146215
* Replace the `now` time in any Pieces on the timeline from the current Part with concrete start times
216+
* @returns a list of object that couldn't be updated at this time.
147217
*/
148218
function deNowifyCurrentPieces(
149219
targetNowTime: number,
150220
timingContext: RundownTimelineTimingContext,
151221
currentPartInstance: PlayoutPartInstanceModel,
152222
currentPartGroupStartTime: number,
153223
timelineObjsMap: Record<string, TimelineObjRundown>
154-
) {
224+
): { objectsNotDeNowified: TimelineObjRundown[] } {
225+
const objectsNotDeNowified: TimelineObjRundown[] = []
155226
// The relative time for 'now' to be resolved to, inside of the part group
156227
const nowInPart = targetNowTime - currentPartGroupStartTime
157228

@@ -176,6 +247,8 @@ function deNowifyCurrentPieces(
176247
obj.enable = { ...obj.enable, start: nowInPart }
177248
} else if (!obj.inGroup) {
178249
obj.enable = { ...obj.enable, start: targetNowTime }
250+
} else {
251+
objectsNotDeNowified.push(obj)
179252
}
180253
}
181254
}
@@ -203,6 +276,7 @@ function deNowifyCurrentPieces(
203276
}
204277
}
205278
}
279+
return { objectsNotDeNowified }
206280
}
207281

208282
function updatePlannedTimingsForPieceInstances(

packages/webui/src/client/styles/shelf/shelf.scss

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -128,33 +128,61 @@
128128
}
129129

130130
.rundown-view__shelf__tabs__tab {
131+
position: relative;
131132
display: block;
132133
background: none;
133134
border: none;
134-
position: relative;
135135
flex: 1 1;
136136
max-width: 7em;
137-
min-width: 13em;
137+
min-width: min-content;
138138
overflow: hidden;
139139
text-overflow: ellipsis;
140140
white-space: nowrap;
141141
text-align: center;
142-
color: #8f8f8f;
143142
line-height: $inspector-shelf-tabs-height;
144143
cursor: pointer;
145144
user-select: none;
145+
padding-inline: 1.5em;
146146

147147
outline-offset: -5px;
148148

149+
// this is a setup that ensures that the min-content is calculated with this font-weight,
150+
// while we display the button with differing font-weights depending on state
151+
font-weight: 500;
152+
color: transparent;
153+
149154
&:hover {
150-
color: #fff;
151-
transition: 0.3s;
155+
// color: #fff;
156+
// transition: 0.3s;
157+
158+
> .rundown-view__shelf__tabs__tab-label {
159+
color: #fff;
160+
transition: 0.3s;
161+
}
162+
}
163+
164+
> .rundown-view__shelf__tabs__tab-label {
165+
position: absolute;
166+
top: 0;
167+
left: 0;
168+
right: 0;
169+
line-height: inherit;
170+
font-weight: 300;
171+
color: #b0b0b0;
152172
}
153173

154174
&.selected {
155-
color: #fff;
156-
font-weight: 500;
157-
text-shadow: 0 0 5px #000;
175+
// color: #fff;
176+
// font-weight: 500;
177+
// text-shadow: 0 0 5px #000;
178+
// transition: 0s;
179+
180+
> .rundown-view__shelf__tabs__tab-label {
181+
color: #fff;
182+
font-weight: 500;
183+
text-shadow: 0 0 5px #000;
184+
transition: 0s;
185+
}
158186

159187
&::after {
160188
content: ' ';

packages/webui/src/client/ui/Shelf/ShelfRundownLayout.tsx

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export function ShelfRundownLayout(props: Readonly<IShelfRundownLayoutProps>): J
5151
tabIndex={0}
5252
role="tab"
5353
>
54+
<div className="rundown-view__shelf__tabs__tab-label">{t('AdLib')}</div>
5455
{t('AdLib')}
5556
</button>
5657
<button
@@ -61,6 +62,7 @@ export function ShelfRundownLayout(props: Readonly<IShelfRundownLayoutProps>): J
6162
tabIndex={0}
6263
role="tab"
6364
>
65+
<div className="rundown-view__shelf__tabs__tab-label">{t('Global AdLib')}</div>
6466
{t('Global AdLib')}
6567
</button>
6668
</>
@@ -78,21 +80,23 @@ export function ShelfRundownLayout(props: Readonly<IShelfRundownLayoutProps>): J
7880
tabIndex={0}
7981
role="tab"
8082
>
83+
<div className="rundown-view__shelf__tabs__tab-label">{panel.name}</div>
8184
{panel.name}
8285
</button>
8386
))
8487
)}
88+
<button
89+
className={ClassNames('rundown-view__shelf__tabs__tab', {
90+
selected: (props.selectedTab || SHELF_DEFAULT_TAB) === ShelfTabs.SYSTEM_HOTKEYS,
91+
})}
92+
onClick={() => onSwitchTab(ShelfTabs.SYSTEM_HOTKEYS)}
93+
tabIndex={0}
94+
role="tab"
95+
>
96+
<div className="rundown-view__shelf__tabs__tab-label">{t('Shortcuts')}</div>
97+
{t('Shortcuts')}
98+
</button>
8599
</OverflowingContainer>
86-
<button
87-
className={ClassNames('rundown-view__shelf__tabs__tab', {
88-
selected: (props.selectedTab || SHELF_DEFAULT_TAB) === ShelfTabs.SYSTEM_HOTKEYS,
89-
})}
90-
onClick={() => onSwitchTab(ShelfTabs.SYSTEM_HOTKEYS)}
91-
tabIndex={0}
92-
role="tab"
93-
>
94-
{t('Shortcuts')}
95-
</button>
96100
</div>
97101
<div className="rundown-view__shelf__panel super-dark" role="tabpanel">
98102
{!rundownLayout ? (

0 commit comments

Comments
 (0)