Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion packages/blueprints-integration/src/documents/part.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { UserEditingDefinition } from '../userEditing'
import { UserEditingDefinition, UserEditingProperties } from '../userEditing'
import type { NoteSeverity } from '../lib'
import type { ITranslatableMessage } from '../translations'

Expand Down Expand Up @@ -88,6 +88,12 @@ export interface IBlueprintMutatablePart<TPrivateData = unknown, TPublicData = u
* User editing definitions for this part
*/
userEditOperations?: UserEditingDefinition[]

/**
* Properties that are user editable from the properties panel in the Sofie UI, if the user saves changes to these
* it will trigger a user edit operation of type DefaultUserOperationEditProperties
*/
userEditProperties?: UserEditingProperties
}

export interface HackPartMediaObjectSubscription {
Expand Down
8 changes: 7 additions & 1 deletion packages/blueprints-integration/src/documents/segment.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { UserEditingDefinition } from '../userEditing'
import { UserEditingDefinition, UserEditingProperties } from '../userEditing'

export enum SegmentDisplayMode {
Timeline = 'timeline',
Expand Down Expand Up @@ -52,6 +52,12 @@ export interface IBlueprintSegment<TPrivateData = unknown, TPublicData = unknown
* User editing definitions for this segment
*/
userEditOperations?: UserEditingDefinition[]

/**
* Properties that are user editable from the properties panel in the Sofie UI, if the user saves changes to these
* it will trigger a user edit operation of type DefaultUserOperationEditProperties
*/
userEditProperties?: UserEditingProperties
}
/** The Segment sent from Core */
export interface IBlueprintSegmentDB<TPrivateData = unknown, TPublicData = unknown>
Expand Down
20 changes: 13 additions & 7 deletions packages/blueprints-integration/src/ingest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,10 @@ export interface UserOperationTarget {
}

export enum DefaultUserOperationsTypes {
REVERT_SEGMENT = 'revert-segment',
REVERT_PART = 'revert-part',
REVERT_RUNDOWN = 'revert-rundown',
REVERT_SEGMENT = '__sofie-revert-segment',
REVERT_PART = '__sofie-revert-part',
REVERT_RUNDOWN = '__sofie-revert-rundown',
UPDATE_PROPS = '__sofie-update-props',
}

export interface DefaultUserOperationRevertRundown {
Expand All @@ -144,14 +145,19 @@ export interface DefaultUserOperationRevertPart {
id: DefaultUserOperationsTypes.REVERT_PART
}

export interface DefaultUserOperationEditProperties {
id: DefaultUserOperationsTypes.UPDATE_PROPS
payload: {
pieceTypeProperties: { type: string; value: Record<string, any> }
globalProperties: Record<string, any>
}
}

export type DefaultUserOperations =
| {
id: '__sofie-move-segment' // Future: define properly
payload: Record<string, never>
}
| DefaultUserOperationRevertRundown
| DefaultUserOperationRevertSegment
| DefaultUserOperationRevertPart
| DefaultUserOperationEditProperties

export interface UserOperationChange<TCustomBlueprintOperations extends { id: string } = never> {
/** Indicate that this change is from user operations */
Expand Down
41 changes: 41 additions & 0 deletions packages/blueprints-integration/src/userEditing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export interface UserEditingSourceLayer {
sourceLayerLabel: string
sourceLayerType: SourceLayerType
schema: JSONBlob<JSONSchema>
defaultValue?: Record<string, any>
}

export enum UserEditingButtonType {
Expand All @@ -87,3 +88,43 @@ export enum UserEditingButtonType {
/** Hidden */
HIDDEN = 'hidden',
}

export interface UserEditingProperties {
/**
* These properties are dependent on the (primary) piece type, the user will get the option
* to select the type of piece (from the SourceLayerTypes i.e. Camera or Split etc.) and then
* be presented the corresponding form
*
* example:
* {
* schema: {
* camera: '{ "type": "object", "properties": { "input": { "type": "number" } } }',
* split: '{ "type": "object", ... }',
* },
* currentValue: {
* type: 'camera',
* value: {
* input: 3
* },
* }
* }
*/
pieceTypeProperties?: {
schema: Record<string, UserEditingSourceLayer>
currentValue: { type: string; value: Record<string, any> }
}

/**
* These are properties that are available to edit regardless of the piece type, examples
* could be whether it an element is locked from NRCS updates
*
* if you do not want the piece type to be changed, then use only this field.
*/
globalProperties?: { schema: JSONBlob<JSONSchema>; currentValue: Record<string, any> }

/**
* A list of id's of operations to be exposed on the properties panel as buttons. These operations
* must be available on the element
*/
operations?: UserEditingDefinitionAction[]
}
8 changes: 7 additions & 1 deletion packages/corelib/src/dataModel/Part.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ITranslatableMessage } from '../TranslatableMessage'
import { PartId, RundownId, SegmentId } from './Ids'
import { PartNote } from './Notes'
import { ReadonlyDeep } from 'type-fest'
import { CoreUserEditingDefinition } from './UserEditingDefinitions'
import { CoreUserEditingDefinition, CoreUserEditingProperties } from './UserEditingDefinitions'

export interface PartInvalidReason {
message: ITranslatableMessage
Expand Down Expand Up @@ -41,6 +41,12 @@ export interface DBPart extends Omit<IBlueprintPart, 'userEditOperations'> {
* User editing definitions for this part
*/
userEditOperations?: CoreUserEditingDefinition[]

/**
* Properties that are user editable from the properties panel in the Sofie UI, if the user saves changes to these
* it will trigger a user edit operation of type DefaultUserOperationEditProperties
*/
userEditProperties?: CoreUserEditingProperties
}

export function isPartPlayable(part: Pick<ReadonlyDeep<DBPart>, 'invalid' | 'floated'>): boolean {
Expand Down
8 changes: 7 additions & 1 deletion packages/corelib/src/dataModel/Segment.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { SegmentDisplayMode, SegmentTimingInfo } from '@sofie-automation/blueprints-integration'
import { SegmentId, RundownId } from './Ids'
import { SegmentNote } from './Notes'
import { CoreUserEditingDefinition } from './UserEditingDefinitions'
import { CoreUserEditingDefinition, CoreUserEditingProperties } from './UserEditingDefinitions'

export enum SegmentOrphanedReason {
/** Segment is deleted from the NRCS but we still need it */
Expand Down Expand Up @@ -51,4 +51,10 @@ export interface DBSegment {
* User editing definitions for this segment
*/
userEditOperations?: CoreUserEditingDefinition[]

/**
* Properties that are user editable from the properties panel in the Sofie UI, if the user saves changes to these
* it will trigger a user edit operation of type DefaultUserOperationEditProperties
*/
userEditProperties?: CoreUserEditingProperties
}
45 changes: 45 additions & 0 deletions packages/corelib/src/dataModel/UserEditingDefinitions.ts
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still want/need the CoreUserEditingDefinitionSourceLayerForm and similar types?
I don't mind if they stay, just want to ask the question

Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,48 @@ export interface CoreUserEditingDefinitionSourceLayerForm {
value: Record<string, any>
}
}

export interface CoreUserEditingProperties {
/**
* These properties are dependent on the (primary) piece type, the user will get the option
* to select the type of piece (from the SourceLayerTypes i.e. Camera or Split etc.) and then
* be presented the corresponding form
*
* example:
* {
* schema: {
* camera: '{ "type": "object", "properties": { "input": { "type": "number" } } }',
* split: '{ "type": "object", ... }',
* },
* currentValue: {
* type: 'camera',
* value: {
* input: 3
* },
* }
* }
*/
pieceTypeProperties?: {
schema: Record<string, UserEditingSourceLayer>
currentValue: { type: string; value: Record<string, any> }
}

/**
* These are properties that are available to edit regardless of the piece type, examples
* could be whether it an element is locked from NRCS updates
*
* if you do not want the piece type to be changed, then use only this field.
*/
globalProperties?: { schema: JSONBlob<JSONSchema>; currentValue: Record<string, any> }

/**
* A list of id's of operations to be exposed on the properties panel as buttons. These operations
* must be available on the element
*
* note - perhaps these should have their own full definitions?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this note be handled in this PR?

As the blueprint version of this interface has the full definition for these, it would make sense to keep that here too. It looks like the ui is expecting them to be the full definitions too

*/
operations?: CoreUserEditingDefinitionAction[]

/** Translation namespaces to use when rendering this form */
translationNamespaces: string[]
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ If an integer property, whether to treat it as zero-based
### `ui:displayType`

Override the presentation with a special mode.
Currently only valid for string properties. Valid values are 'json'.

Currently only valid for:

- object properties. Valid values are 'json'.
- string properties. Valid values are 'base64-image'.
- boolean properties. Valid values are 'switch'.

### `tsEnumNames`

Expand Down
64 changes: 64 additions & 0 deletions packages/job-worker/src/blueprints/context/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
CoreUserEditingDefinitionAction,
CoreUserEditingDefinitionForm,
CoreUserEditingDefinitionSourceLayerForm,
CoreUserEditingProperties,
} from '@sofie-automation/corelib/dist/dataModel/UserEditingDefinitions'
import { DBSegment } from '@sofie-automation/corelib/dist/dataModel/Segment'
import { assertNever, clone, Complete, literal, omit } from '@sofie-automation/corelib/dist/lib'
Expand Down Expand Up @@ -58,6 +59,7 @@ import {
UserEditingDefinitionAction,
UserEditingDefinitionForm,
UserEditingDefinitionSourceLayerForm,
UserEditingProperties,
UserEditingType,
} from '@sofie-automation/blueprints-integration/dist/userEditing'
import type { PlayoutMutatablePart } from '../../playout/model/PlayoutPartInstanceModel'
Expand Down Expand Up @@ -121,6 +123,7 @@ export const IBlueprintMutatablePartSampleKeys = allKeysOfObject<IBlueprintMutat
identifier: true,
hackListenToMediaObjectUpdates: true,
userEditOperations: true,
userEditProperties: true,
})

/*
Expand Down Expand Up @@ -281,6 +284,7 @@ export function convertPartToBlueprints(part: ReadonlyDeep<DBPart>): IBlueprintP
part.hackListenToMediaObjectUpdates
),
userEditOperations: translateUserEditsToBlueprint(part.userEditOperations),
userEditProperties: translateUserEditPropertiesToBlueprint(part.userEditProperties),
}

return obj
Expand Down Expand Up @@ -349,6 +353,7 @@ export function convertSegmentToBlueprints(segment: ReadonlyDeep<DBSegment>): IB
showShelf: segment.showShelf,
segmentTiming: segment.segmentTiming,
userEditOperations: translateUserEditsToBlueprint(segment.userEditOperations),
userEditProperties: translateUserEditPropertiesToBlueprint(segment.userEditProperties),
}

return obj
Expand Down Expand Up @@ -540,6 +545,30 @@ function translateUserEditsToBlueprint(
)
}

function translateUserEditPropertiesToBlueprint(
props: ReadonlyDeep<CoreUserEditingProperties> | undefined
): UserEditingProperties | undefined {
if (!props) return undefined

return {
globalProperties: props.globalProperties,
pieceTypeProperties: props.pieceTypeProperties,

operations: props.operations?.map(
(userEdit) =>
({
type: UserEditingType.ACTION,
id: userEdit.id,
label: omit(userEdit.label, 'namespaces'),
svgIcon: userEdit.svgIcon,
svgIconInactive: userEdit.svgIconInactive,
isActive: userEdit.isActive,
buttonType: userEdit.buttonType,
} satisfies Complete<UserEditingDefinitionAction>)
),
}
}

export function translateUserEditsFromBlueprint(
userEdits: UserEditingDefinition[] | undefined,
blueprintIds: BlueprintId[]
Expand Down Expand Up @@ -585,6 +614,33 @@ export function translateUserEditsFromBlueprint(
)
}

export function translateUserEditPropertiesFromBlueprint(
props: UserEditingProperties | undefined,
blueprintIds: BlueprintId[]
): CoreUserEditingProperties | undefined {
if (!props) return undefined

return {
globalProperties: clone(props.globalProperties),
pieceTypeProperties: clone(props.pieceTypeProperties),

operations: props.operations?.map(
(userEdit) =>
({
type: UserEditingType.ACTION,
id: userEdit.id,
label: wrapTranslatableMessageFromBlueprints(userEdit.label, blueprintIds),
svgIcon: userEdit.svgIcon,
svgIconInactive: userEdit.svgIconInactive,
isActive: userEdit.isActive,
buttonType: userEdit.buttonType,
} satisfies Complete<UserEditingDefinitionAction>)
),

translationNamespaces: blueprintIds.map((id) => `blueprint_${id}`),
}
}

export function convertPartialBlueprintMutablePartToCore(
updatePart: Partial<IBlueprintMutatablePart>,
blueprintId: BlueprintId
Expand All @@ -602,5 +658,13 @@ export function convertPartialBlueprintMutablePartToCore(
delete playoutUpdatePart.userEditOperations
}

if ('userEditProperties' in updatePart) {
playoutUpdatePart.userEditProperties = translateUserEditPropertiesFromBlueprint(updatePart.userEditProperties, [
blueprintId,
])
} else {
delete playoutUpdatePart.userEditOperations
}

return playoutUpdatePart
}
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@ export class PartAndPieceInstanceActionService {
floated: false,
expectedDurationWithTransition: undefined, // Filled in later
userEditOperations: [], // Adlibbed parts can't be edited by ingest
userEditProperties: undefined,
}

const pieces = postProcessPieces(
Expand Down
8 changes: 7 additions & 1 deletion packages/job-worker/src/ingest/generationSegment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { IngestReplacePartType, IngestSegmentModel } from './model/IngestSegment
import { ReadonlyDeep } from 'type-fest'
import { Rundown } from '@sofie-automation/corelib/dist/dataModel/Rundown'
import { WrappedShowStyleBlueprint } from '../blueprints/cache'
import { translateUserEditsFromBlueprint } from '../blueprints/context/lib'
import { translateUserEditPropertiesFromBlueprint, translateUserEditsFromBlueprint } from '../blueprints/context/lib'

async function getWatchedPackagesHelper(
context: JobContext,
Expand Down Expand Up @@ -293,6 +293,9 @@ function updateModelWithGeneratedSegment(
userEditOperations: translateUserEditsFromBlueprint(blueprintSegment.segment.userEditOperations, [
blueprintId,
]),
userEditProperties: translateUserEditPropertiesFromBlueprint(blueprintSegment.segment.userEditProperties, [
blueprintId,
]),
})
)

Expand Down Expand Up @@ -376,6 +379,9 @@ function updateModelWithGeneratedPart(
}
: undefined,
userEditOperations: translateUserEditsFromBlueprint(blueprintPart.part.userEditOperations, [blueprintId]),
userEditProperties: translateUserEditPropertiesFromBlueprint(blueprintPart.part.userEditProperties, [
blueprintId,
]),
})

// Update pieces
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,7 @@ export class PlayoutPartInstanceModelImpl implements PlayoutPartInstanceModel {
...this.partInstanceImpl.part,
...trimmedProps,
userEditOperations: this.partInstanceImpl.part.userEditOperations, // Replaced below if changed
userEditProperties: this.partInstanceImpl.part.userEditProperties,
}

// Only replace `userEditOperations` if new values were provided
Expand Down
Loading
Loading