Skip to content

Commit db0ae30

Browse files
committed
fix: resolve issues highlighted in code review
chore: lint chore: lint
1 parent 1fc1e9b commit db0ae30

8 files changed

Lines changed: 108 additions & 66 deletions

File tree

packages/blueprints-integration/src/userEditing.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ export interface UserEditingDefinitionSofieDefault {
9090
}
9191

9292
export enum UserEditingType {
93-
/** Action */
93+
/** State */
9494
STATE = 'state',
9595
/** Action */
9696
ACTION = 'action',

packages/playout-gateway/src/tsrHandler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ export class TSRHandler {
295295

296296
if (!e || typeof e !== 'object' || !('message' in e)) {
297297
return {
298-
message: name + ': ' + 'Unknown error: ' + JSON.stringify(e),
298+
message: name + ': ' + 'Unknown error: ' + stringifyError(e, true),
299299
}
300300
}
301301

packages/webui/src/client/lib/Components/FloatInput.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ export function FloatInputControl({
5151
)
5252
const handleBlur = useCallback(
5353
(event: React.FocusEvent<HTMLInputElement>) => {
54-
if (readOnly) return
54+
if (readOnly) {
55+
setEditingValue(null)
56+
return
57+
}
5558

5659
const number = parseFloat(event.currentTarget.value.replace(',', '.'))
5760
if (!isNaN(number)) {
@@ -62,9 +65,13 @@ export function FloatInputControl({
6265
},
6366
[handleUpdate, zeroBased, readOnly]
6467
)
65-
const handleFocus = useCallback((event: React.FocusEvent<HTMLInputElement>) => {
66-
setEditingValue(parseFloat(event.currentTarget.value.replace(',', '.')))
67-
}, [])
68+
const handleFocus = useCallback(
69+
(event: React.FocusEvent<HTMLInputElement>) => {
70+
if (readOnly) return
71+
setEditingValue(parseFloat(event.currentTarget.value.replace(',', '.')))
72+
},
73+
[readOnly]
74+
)
6875
const handleKeyUp = useCallback(
6976
(event: React.KeyboardEvent<HTMLInputElement>) => {
7077
if (readOnly) return

packages/webui/src/client/lib/forms/SchemaFormOneOfButtons/OneOfButtons.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
display: flex;
33
flex-direction: row;
44
flex-wrap: wrap;
5-
justify-items: flex-start;
5+
justify-content: flex-start;
66
align-items: flex-start;
77
gap: 0.5em;
88
}

packages/webui/src/client/lib/forms/SchemaFormOneOfButtons/OneOfButtons.tsx

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
import { faQuestionCircle, faSync } from '@fortawesome/free-solid-svg-icons'
22
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
3-
import { getSchemaUIField, JSONSchema, SchemaFormUIField } from '@sofie-automation/blueprints-integration'
3+
import { getSchemaUIField, type JSONSchema, SchemaFormUIField } from '@sofie-automation/blueprints-integration'
44
import { objectPathGet } from '@sofie-automation/corelib/dist/lib'
55
import classNames from 'classnames'
66
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
77
import Button from 'react-bootstrap/Button'
88
import { useTranslation } from 'react-i18next'
9-
import {
9+
import type {
1010
OverrideOpHelperForItemContents,
1111
WrappedOverridableItemNormal,
1212
} from '../../../ui/Settings/util/OverrideOpHelper.js'
13-
import { LabelActual, LabelAndOverridesProps } from '../../Components/LabelAndOverrides.js'
13+
import { LabelActual, type LabelAndOverridesProps } from '../../Components/LabelAndOverrides.js'
1414
import { hasOpWithPath } from '../../Components/util.js'
15-
import { SchemaFormCommonProps, translateStringIfHasNamespaces } from '../schemaFormUtil.js'
15+
import { type SchemaFormCommonProps, translateStringIfHasNamespaces } from '../schemaFormUtil.js'
1616
import { SchemaFormWithState } from '../SchemaFormWithState.js'
17-
import { TypeName } from '@sofie-automation/shared-lib/src/lib/JSONSchemaTypes.js'
17+
import { TypeName } from '@sofie-automation/shared-lib/dist/lib/JSONSchemaTypes'
1818
import { BlueprintAssetIcon } from '../../Components/BlueprintAssetIcon.js'
1919

2020
export const OneOfButtonsWithOverrides = (
@@ -152,6 +152,12 @@ function OneOfVariantButtonComplex({
152152
}>): JSX.Element {
153153
const typeValue = schema.properties?.[discProperty]?.const
154154

155+
const handleUpdateRef = useRef(handleUpdate)
156+
157+
useEffect(() => {
158+
handleUpdateRef.current = handleUpdate
159+
}, [handleUpdate])
160+
155161
const [editingValue, setEditingValue] = useState<Record<string, any>>(
156162
selected
157163
? (value ?? {
@@ -173,13 +179,13 @@ function OneOfVariantButtonComplex({
173179

174180
useEffect(() => {
175181
if (selected && value !== undefined && oldValue.current !== value && oldValue.current === undefined) {
176-
handleUpdate?.(editingValue)
182+
handleUpdateRef.current?.(editingValue)
177183
} else if (selected && value !== undefined && oldValue.current !== value) {
178184
setEditingValue(value)
179185
}
180186

181187
oldValue.current = value
182-
}, [value, discProperty, typeValue, editingValue, selected, handleUpdate])
188+
}, [value, discProperty, typeValue, editingValue, selected])
183189

184190
const variantTitle = getSchemaUIField(schema, SchemaFormUIField.Title)
185191
const variantIcon = getSchemaUIField(schema, SchemaFormUIField.Icon)
@@ -191,17 +197,17 @@ function OneOfVariantButtonComplex({
191197
...update,
192198
}))
193199
} else {
194-
handleUpdate?.(update)
200+
handleUpdateRef.current?.(update)
195201
}
196202
},
197-
[selected, handleUpdate]
203+
[selected]
198204
)
199205

200206
const handleSelect = useCallback(() => {
201207
if (!selected) {
202-
handleUpdate?.(editingValue)
208+
handleUpdateRef.current?.(editingValue)
203209
}
204-
}, [editingValue, discProperty, typeValue, selected, handleUpdate])
210+
}, [editingValue, discProperty, typeValue, selected])
205211

206212
return (
207213
<label className="field-one-of-button-complex">

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

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -83,38 +83,38 @@ input {
8383
@import 'shelf/textLabelPanel';
8484
@import 'shelf/timeOfDayPanel';
8585

86-
@import '../lib/forms/SchemaFormTable/ObjectTable.scss';
87-
@import '../lib/forms/SchemaFormOneOfButtons/OneOfButtons.scss';
88-
@import '../lib/Components/PromiseButton.scss';
89-
@import '../lib/VideoPreviewPlayer.scss';
90-
@import '../ui/ClipTrimPanel/ClipTrimPanel.scss';
91-
@import '../ui/ClipTrimPanel/TimecodeEncoder.scss';
92-
@import '../ui/ClipTrimPanel/VideoEditMonitor.scss';
93-
@import '../ui/SegmentStoryboard/StoryboardPartThumbnail/StoryboardPartThumbnail.scss';
94-
@import '../ui/SegmentStoryboard/SegmentStoryboard.scss';
95-
@import '../ui/SegmentStoryboard/StoryboardPartSecondaryPieces/StoryboardPartSecondaryPieces.scss';
96-
@import '../ui/Settings/components/triggeredActions/TriggeredActionsEditor.scss';
97-
@import '../ui/Settings/Forms.scss';
98-
@import '../ui/SegmentTimeline/SegmentTimeline.scss';
99-
@import '../ui/Status/media-status/MediaStatusListItem.scss';
100-
@import '../ui/Status/media-status/MediaStatusList.scss';
101-
@import '../ui/Status/media-status/MediaStatusListHeader.scss';
102-
@import '../ui/Status/package-status/package-status.scss';
103-
@import '../ui/SegmentList/LinePartPieceIndicator/LinePartPieceIndicator.scss';
104-
@import '../ui/SegmentList/LinePartPieceIndicator/PieceIndicatorMenu.scss';
105-
@import '../ui/SegmentList/SegmentList.scss';
106-
@import '../ui/SegmentList/LinePartMainPiece/LinePartMainPiece.scss';
107-
@import '../ui/SegmentList/LinePartTransitionPiece/LinePartTransitionPiece.scss';
108-
@import '../ui/SegmentList/LinePartSecondaryPiece/LinePartSecondaryPiece.scss';
109-
@import '../ui/PieceIcons/IconColors.scss';
86+
@import '../lib/forms/SchemaFormTable/ObjectTable';
87+
@import '../lib/forms/SchemaFormOneOfButtons/OneOfButtons';
88+
@import '../lib/Components/PromiseButton';
89+
@import '../lib/VideoPreviewPlayer';
90+
@import '../ui/ClipTrimPanel/ClipTrimPanel';
91+
@import '../ui/ClipTrimPanel/TimecodeEncoder';
92+
@import '../ui/ClipTrimPanel/VideoEditMonitor';
93+
@import '../ui/SegmentStoryboard/StoryboardPartThumbnail/StoryboardPartThumbnail';
94+
@import '../ui/SegmentStoryboard/SegmentStoryboard';
95+
@import '../ui/SegmentStoryboard/StoryboardPartSecondaryPieces/StoryboardPartSecondaryPieces';
96+
@import '../ui/Settings/components/triggeredActions/TriggeredActionsEditor';
97+
@import '../ui/Settings/Forms';
98+
@import '../ui/SegmentTimeline/SegmentTimeline';
99+
@import '../ui/Status/media-status/MediaStatusListItem';
100+
@import '../ui/Status/media-status/MediaStatusList';
101+
@import '../ui/Status/media-status/MediaStatusListHeader';
102+
@import '../ui/Status/package-status/package-status';
103+
@import '../ui/SegmentList/LinePartPieceIndicator/LinePartPieceIndicator';
104+
@import '../ui/SegmentList/LinePartPieceIndicator/PieceIndicatorMenu';
105+
@import '../ui/SegmentList/SegmentList';
106+
@import '../ui/SegmentList/LinePartMainPiece/LinePartMainPiece';
107+
@import '../ui/SegmentList/LinePartTransitionPiece/LinePartTransitionPiece';
108+
@import '../ui/SegmentList/LinePartSecondaryPiece/LinePartSecondaryPiece';
109+
@import '../ui/PieceIcons/IconColors';
110110
@import '../ui/PieceIcons/PieceIcons';
111111
@import '../ui/ClockView/ClockViewPieceIcons/ClockViewPieceIcons';
112-
@import '../ui/ClockView/CameraScreen/CameraScreen.scss';
113-
@import '../ui/RundownView/MediaStatusPopUp/MediaStatusPopUpItem.scss';
114-
@import '../ui/RundownView/MediaStatusPopUp/MediaStatusPopUp.scss';
115-
@import '../ui/RundownView/MediaStatusPopUp/MediaStatusPopUpHeader.scss';
116-
@import '../ui/RundownView/MediaStatusPopUp/MediaStatusPopUpSegmentRule.scss';
117-
@import '../ui/SegmentAdlibTesting/SegmentAdlibTesting.scss';
112+
@import '../ui/ClockView/CameraScreen/CameraScreen';
113+
@import '../ui/RundownView/MediaStatusPopUp/MediaStatusPopUpItem';
114+
@import '../ui/RundownView/MediaStatusPopUp/MediaStatusPopUp';
115+
@import '../ui/RundownView/MediaStatusPopUp/MediaStatusPopUpHeader';
116+
@import '../ui/RundownView/MediaStatusPopUp/MediaStatusPopUpSegmentRule';
117+
@import '../ui/SegmentAdlibTesting/SegmentAdlibTesting';
118118

119119
@import 'rundownView';
120120

packages/webui/src/client/ui/SegmentTimeline/Renderers/CustomLayerItemRenderer.tsx

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import type { OffsetPosition } from '../../../utils/positions.js'
1010
import { LoopingPieceIcon } from '../../../lib/ui/icons/looping.js'
1111
import type { PieceUi } from '@sofie-automation/corelib/src/dataModel/Piece.js'
1212
import { BlueprintAssetIcon } from '../../../lib/Components/BlueprintAssetIcon.js'
13-
import { ReadonlyObjectDeep } from 'type-fest/source/readonly-deep.js'
14-
import {
13+
import type { ReadonlyObjectDeep } from 'type-fest/source/readonly-deep.js'
14+
import type {
1515
CoreUserEditingDefinitionAction,
1616
CoreUserEditingDefinitionForm,
1717
CoreUserEditingDefinitionSofie,
@@ -126,30 +126,56 @@ export class CustomLayerItemRenderer<IProps extends ICustomLayerItemProps, IStat
126126
return <LoopingPieceIcon className="segment-timeline__piece__label-icon" playing={this.props.showPreviewPopUp} />
127127
}
128128

129+
private operationWithUsefulIcon(
130+
op:
131+
| ReadonlyObjectDeep<CoreUserEditingDefinitionState>
132+
| ReadonlyObjectDeep<CoreUserEditingDefinitionAction>
133+
| ReadonlyObjectDeep<CoreUserEditingDefinitionForm>
134+
| ReadonlyObjectDeep<CoreUserEditingDefinitionSofie>
135+
): op is ReadonlyObjectDeep<CoreUserEditingDefinitionState> | ReadonlyObjectDeep<CoreUserEditingDefinitionAction> {
136+
return (
137+
((op.type === UserEditingType.ACTION || op.type === UserEditingType.STATE) &&
138+
((op.icon && op.isActive) || (op.iconInactive && !op.isActive))) ||
139+
false
140+
)
141+
}
142+
143+
protected customPieceIconsChanged(prevProps: Readonly<IProps>): boolean {
144+
if (this.props.piece.instance.piece.userEditOperations === prevProps.piece.instance.piece.userEditOperations) {
145+
return false
146+
}
147+
148+
if (
149+
this.props.piece.instance.piece.userEditOperations?.length !==
150+
prevProps.piece.instance.piece.userEditOperations?.length
151+
) {
152+
return true
153+
}
154+
155+
const currentIconSignature =
156+
this.props.piece.instance.piece.userEditOperations
157+
?.filter(this.operationWithUsefulIcon)
158+
?.map((op) => `${op.id}:${op.isActive}:${op.icon ?? ''}:${op.iconInactive ?? ''}`)
159+
.join('|') ?? ''
160+
const prevIconSignature =
161+
prevProps.piece.instance.piece.userEditOperations
162+
?.filter(this.operationWithUsefulIcon)
163+
?.map((op) => `${op.id}:${op.isActive}:${op.icon ?? ''}:${op.iconInactive ?? ''}`)
164+
.join('|') ?? ''
165+
166+
return currentIconSignature !== prevIconSignature
167+
}
168+
129169
protected renderCustomPieceIcons(): JSX.Element | null {
130170
if (
131171
!this.props.piece.instance.piece.userEditOperations ||
132172
this.props.piece.instance.piece.userEditOperations.length === 0
133173
)
134174
return null
135175

136-
function operationWithUsefulIcon(
137-
op:
138-
| ReadonlyObjectDeep<CoreUserEditingDefinitionState>
139-
| ReadonlyObjectDeep<CoreUserEditingDefinitionAction>
140-
| ReadonlyObjectDeep<CoreUserEditingDefinitionForm>
141-
| ReadonlyObjectDeep<CoreUserEditingDefinitionSofie>
142-
): op is ReadonlyObjectDeep<CoreUserEditingDefinitionState> | ReadonlyObjectDeep<CoreUserEditingDefinitionAction> {
143-
return (
144-
((op.type === UserEditingType.ACTION || op.type === UserEditingType.STATE) &&
145-
((op.icon && op.isActive) || (op.iconInactive && !op.isActive))) ||
146-
false
147-
)
148-
}
149-
150176
return (
151177
<>
152-
{this.props.piece.instance.piece.userEditOperations.filter(operationWithUsefulIcon).map((op) => (
178+
{this.props.piece.instance.piece.userEditOperations.filter(this.operationWithUsefulIcon).map((op) => (
153179
<div className="segment-timeline__piece__label label-icon label-custom-icon" key={op.id}>
154180
{op.isActive && op.icon && <BlueprintAssetIcon src={op.icon} />}
155181
{!op.isActive && op.iconInactive && <BlueprintAssetIcon src={op.iconInactive} />}

packages/webui/src/client/ui/SegmentTimeline/Renderers/DefaultLayerItemRenderer.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ export class DefaultLayerItemRenderer extends CustomLayerItemRenderer<IProps, IS
3333
super.componentDidUpdate(prevProps, prevState)
3434
}
3535

36-
if (this.props.piece.instance.piece.name !== prevProps.piece.instance.piece.name) {
36+
if (
37+
this.props.piece.instance.piece.name !== prevProps.piece.instance.piece.name ||
38+
this.customPieceIconsChanged(prevProps)
39+
) {
3740
this.updateAnchoredElsWidths()
3841
}
3942
}

0 commit comments

Comments
 (0)