Skip to content

Commit aace1e5

Browse files
authored
Merge pull request Sofie-Automation#1698 from bbc/feat/SOFIE-282
feat: fix scroll issues in properties editor and enable properties editor for invalid parts (SOFIE-282 and SOFIE-283)
2 parents 39ff60d + ac282e2 commit aace1e5

4 files changed

Lines changed: 131 additions & 127 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1576,7 +1576,7 @@ svg.icon {
15761576
bottom: 0;
15771577
right: 1px;
15781578
z-index: 10;
1579-
pointer-events: all;
1579+
pointer-events: none;
15801580
background-image: repeating-linear-gradient(
15811581
45deg,
15821582
var(--invalid-reason-color-transparent) 0%,

packages/webui/src/client/ui/RundownView/SelectedElementsContext.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { createContext, useCallback, useContext, useEffect, useMemo, useReducer, useState } from 'react'
1+
import React, { createContext, useCallback, useContext, useEffect, useMemo, useReducer, useRef, useState } from 'react'
22
import {
33
AdLibActionId,
44
PartId,
@@ -215,12 +215,21 @@ export function useSelectedElements(
215215
const [segment, setSegment] = useState<DBSegment | undefined>(undefined)
216216
const rundownId = piece ? piece.startRundownId : part ? part.rundownId : segment?.rundownId
217217

218+
const lastValidPiece = useRef<Piece | undefined>(undefined)
219+
218220
useEffect(() => {
219221
clearPendingChange() // element id changed so any pending change is for an old element
220222

221223
const computation = Tracker.nonreactive(() =>
222224
Tracker.autorun(() => {
223-
const piece = Pieces.findOne(selectedElement?.elementId)
225+
let piece = Pieces.findOne(selectedElement?.elementId)
226+
227+
if (!piece && lastValidPiece.current && lastValidPiece.current._id === selectedElement?.elementId) {
228+
piece = lastValidPiece.current
229+
} else if (piece) {
230+
lastValidPiece.current = piece
231+
}
232+
224233
const part = UIParts.findOne({ _id: piece?.startPartId ?? selectedElement?.elementId })
225234
const segment = Segments.findOne({ _id: part ? part.segmentId : selectedElement?.elementId })
226235

packages/webui/src/client/ui/SegmentTimeline/SegmentContextMenu.tsx

Lines changed: 116 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -179,144 +179,142 @@ export function SegmentContextMenu({
179179
<hr />
180180
</>
181181
)}
182-
{part &&
183-
isPartNext !== undefined &&
184-
isPartOrphaned !== undefined &&
185-
!part.instance.part.invalid &&
186-
timecode !== null && (
187-
<>
188-
<MenuItem
189-
onClick={(e) => onSetNext(part.instance.part, e)}
190-
disabled={!!part.instance.orphaned || !canSetAsNext}
191-
>
192-
<span
193-
dangerouslySetInnerHTML={{
194-
__html: t(`Set part as <strong>Next</strong>`),
195-
}}
196-
></span>
197-
</MenuItem>
198-
{startsAt !== undefined && part && enablePlayFromAnywhere ? (
199-
<>
200-
<MenuItem
201-
onClick={(e) =>
202-
onSetAsNextFromHere(
203-
part.instance,
204-
playlist?.nextPartInfo?.partInstanceId ?? null,
205-
playlist?.currentPartInfo?.partInstanceId ?? null,
206-
e
207-
)
208-
}
209-
disabled={getIsPlayFromHereDisabled()}
210-
>
211-
<span
212-
dangerouslySetInnerHTML={{
213-
__html: t(
214-
`Set part from ${RundownUtils.formatTimeToShortTime(Math.floor(timecode / 1000) * 1000)} as <strong>Next</strong>`
215-
),
216-
}}
217-
></span>
218-
</MenuItem>
219-
<MenuItem
220-
onClick={(e) =>
221-
onSetAsNextFromHere(
222-
part.instance,
223-
playlist?.nextPartInfo?.partInstanceId ?? null,
224-
playlist?.currentPartInfo?.partInstanceId ?? null,
225-
e,
226-
true
227-
)
228-
}
229-
disabled={getIsPlayFromHereDisabled(true)}
230-
>
231-
<span>
232-
{t(`Play part from ${RundownUtils.formatTimeToShortTime(Math.floor(timecode / 1000) * 1000)}`)}
233-
</span>
234-
</MenuItem>
235-
</>
236-
) : null}
237-
{enableQuickLoop && !isLoopLocked(playlist) && (
238-
<>
239-
{isQuickLoopStart(part.partId, playlist) ? (
240-
<MenuItem onClick={(e) => onSetQuickLoopStart(null, e)}>
241-
<span>{t('Clear QuickLoop Start')}</span>
242-
</MenuItem>
243-
) : (
182+
{part && isPartNext !== undefined && isPartOrphaned !== undefined && timecode !== null && (
183+
<>
184+
{!part.instance.part.invalid && (
185+
<>
186+
<MenuItem
187+
onClick={(e) => onSetNext(part.instance.part, e)}
188+
disabled={!!part.instance.orphaned || !canSetAsNext}
189+
>
190+
<span
191+
dangerouslySetInnerHTML={{
192+
__html: t(`Set part as <strong>Next</strong>`),
193+
}}
194+
></span>
195+
</MenuItem>
196+
{startsAt !== undefined && part && enablePlayFromAnywhere ? (
197+
<>
244198
<MenuItem
245199
onClick={(e) =>
246-
onSetQuickLoopStart({ type: QuickLoopMarkerType.PART, id: part.instance.part._id }, e)
200+
onSetAsNextFromHere(
201+
part.instance,
202+
playlist?.nextPartInfo?.partInstanceId ?? null,
203+
playlist?.currentPartInfo?.partInstanceId ?? null,
204+
e
205+
)
247206
}
248-
disabled={!!part.instance.orphaned || !canSetAsNext}
207+
disabled={getIsPlayFromHereDisabled()}
249208
>
250-
<span>{t('Set as QuickLoop Start')}</span>
251-
</MenuItem>
252-
)}
253-
{isQuickLoopEnd(part.partId, playlist) ? (
254-
<MenuItem onClick={(e) => onSetQuickLoopEnd(null, e)}>
255-
<span>{t('Clear QuickLoop End')}</span>
209+
<span
210+
dangerouslySetInnerHTML={{
211+
__html: t(
212+
`Set part from ${RundownUtils.formatTimeToShortTime(Math.floor(timecode / 1000) * 1000)} as <strong>Next</strong>`
213+
),
214+
}}
215+
></span>
256216
</MenuItem>
257-
) : (
258217
<MenuItem
259218
onClick={(e) =>
260-
onSetQuickLoopEnd({ type: QuickLoopMarkerType.PART, id: part.instance.part._id }, e)
219+
onSetAsNextFromHere(
220+
part.instance,
221+
playlist?.nextPartInfo?.partInstanceId ?? null,
222+
playlist?.currentPartInfo?.partInstanceId ?? null,
223+
e,
224+
true
225+
)
261226
}
262-
disabled={!!part.instance.orphaned || !canSetAsNext}
227+
disabled={getIsPlayFromHereDisabled(true)}
263228
>
264-
<span>{t('Set as QuickLoop End')}</span>
229+
<span>
230+
{t(`Play part from ${RundownUtils.formatTimeToShortTime(Math.floor(timecode / 1000) * 1000)}`)}
231+
</span>
265232
</MenuItem>
266-
)}
267-
</>
268-
)}
233+
</>
234+
) : null}
235+
</>
236+
)}
237+
{enableQuickLoop && !isLoopLocked(playlist) && (
238+
<>
239+
{isQuickLoopStart(part.partId, playlist) ? (
240+
<MenuItem onClick={(e) => onSetQuickLoopStart(null, e)}>
241+
<span>{t('Clear QuickLoop Start')}</span>
242+
</MenuItem>
243+
) : (
244+
<MenuItem
245+
onClick={(e) =>
246+
onSetQuickLoopStart({ type: QuickLoopMarkerType.PART, id: part.instance.part._id }, e)
247+
}
248+
disabled={!!part.instance.orphaned || !canSetAsNext}
249+
>
250+
<span>{t('Set as QuickLoop Start')}</span>
251+
</MenuItem>
252+
)}
253+
{isQuickLoopEnd(part.partId, playlist) ? (
254+
<MenuItem onClick={(e) => onSetQuickLoopEnd(null, e)}>
255+
<span>{t('Clear QuickLoop End')}</span>
256+
</MenuItem>
257+
) : (
258+
<MenuItem
259+
onClick={(e) =>
260+
onSetQuickLoopEnd({ type: QuickLoopMarkerType.PART, id: part.instance.part._id }, e)
261+
}
262+
disabled={!!part.instance.orphaned || !canSetAsNext}
263+
>
264+
<span>{t('Set as QuickLoop End')}</span>
265+
</MenuItem>
266+
)}
267+
</>
268+
)}
269+
270+
<UserEditOperationMenuItems
271+
rundownId={part.instance.rundownId}
272+
targetName={part.instance.part.title}
273+
operationTarget={{
274+
segmentExternalId: segment?.externalId,
275+
partExternalId: part.instance.part.externalId,
276+
pieceExternalId: undefined,
277+
}}
278+
userEditOperations={part.instance.part.userEditOperations}
279+
isFormEditable={isPartEditAble}
280+
/>
269281

282+
{piece && piece.instance.piece.userEditOperations && (
270283
<UserEditOperationMenuItems
271284
rundownId={part.instance.rundownId}
272-
targetName={part.instance.part.title}
285+
targetName={piece.instance.piece.name}
273286
operationTarget={{
274287
segmentExternalId: segment?.externalId,
275288
partExternalId: part.instance.part.externalId,
276-
pieceExternalId: undefined,
289+
pieceExternalId: piece.instance.piece.externalId,
277290
}}
278-
userEditOperations={part.instance.part.userEditOperations}
291+
userEditOperations={piece.instance.piece.userEditOperations as CoreUserEditingDefinition[] | undefined}
279292
isFormEditable={isPartEditAble}
280293
/>
294+
)}
281295

282-
{piece && piece.instance.piece.userEditOperations && (
283-
<UserEditOperationMenuItems
284-
rundownId={part.instance.rundownId}
285-
targetName={piece.instance.piece.name}
286-
operationTarget={{
287-
segmentExternalId: segment?.externalId,
288-
partExternalId: part.instance.part.externalId,
289-
pieceExternalId: piece.instance.piece.externalId,
290-
}}
291-
userEditOperations={
292-
piece.instance.piece.userEditOperations as CoreUserEditingDefinition[] | undefined
293-
}
294-
isFormEditable={isPartEditAble}
295-
/>
296-
)}
297-
298-
{enableUserEdits && (segmentHasEditableContent || partHasEditableContent || pieceHasEditableContent) && (
299-
<>
300-
<hr />
301-
{segmentHasEditableContent && (
302-
<MenuItem onClick={() => onEditProps({ type: 'segment', elementId: part.instance.segmentId })}>
303-
<span>{t('Edit Segment Properties')}</span>
304-
</MenuItem>
305-
)}
306-
{partHasEditableContent && (
307-
<MenuItem onClick={() => onEditProps({ type: 'part', elementId: part.instance.part._id })}>
308-
<span>{t('Edit Part Properties')}</span>
309-
</MenuItem>
310-
)}
311-
{pieceHasEditableContent && piece && (
312-
<MenuItem onClick={() => onEditProps({ type: 'piece', elementId: piece.instance.piece._id })}>
313-
<span>{t('Edit Piece Properties')}</span>
314-
</MenuItem>
315-
)}
316-
</>
317-
)}
318-
</>
319-
)}
296+
{enableUserEdits && (segmentHasEditableContent || partHasEditableContent || pieceHasEditableContent) && (
297+
<>
298+
<hr />
299+
{segmentHasEditableContent && (
300+
<MenuItem onClick={() => onEditProps({ type: 'segment', elementId: part.instance.segmentId })}>
301+
<span>{t('Edit Segment Properties')}</span>
302+
</MenuItem>
303+
)}
304+
{partHasEditableContent && (
305+
<MenuItem onClick={() => onEditProps({ type: 'part', elementId: part.instance.part._id })}>
306+
<span>{t('Edit Part Properties')}</span>
307+
</MenuItem>
308+
)}
309+
{pieceHasEditableContent && piece && (
310+
<MenuItem onClick={() => onEditProps({ type: 'piece', elementId: piece.instance.piece._id })}>
311+
<span>{t('Edit Piece Properties')}</span>
312+
</MenuItem>
313+
)}
314+
</>
315+
)}
316+
</>
317+
)}
320318
</ContextMenu>
321319
</Escape>
322320
) : null

packages/webui/src/client/ui/SegmentTimeline/SourceLayerItem.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -191,12 +191,9 @@ export const SourceLayerItem = (props: Readonly<ISourceLayerItemProps>): JSX.Ele
191191
if (!hasEditableContent) return
192192

193193
const pieceId = innerPiece._id
194-
if (!selectElementContext.isSelected(pieceId)) {
195-
RundownViewEventBus.emit(RundownViewEvents.CLOSE_NOTIFICATIONS)
196-
selectElementContext.clearAndSetSelection({ type: 'piece', elementId: pieceId })
197-
} else {
198-
selectElementContext.clearSelections()
199-
}
194+
195+
RundownViewEventBus.emit(RundownViewEvents.CLOSE_NOTIFICATIONS)
196+
selectElementContext.clearAndSetSelection({ type: 'piece', elementId: pieceId })
200197
} else if (typeof onDoubleClick === 'function') {
201198
onDoubleClick(piece, e)
202199
}

0 commit comments

Comments
 (0)