77 WrappedOverridableItemDeleted ,
88 WrappedOverridableItemNormal ,
99} from '../../util/OverrideOpHelper.js'
10- import { faCheck , faPencilAlt , faSync , faTrash } from '@fortawesome/free-solid-svg-icons'
10+ import { faCheck , faPencilAlt , faSync , faTrash , faSave , faBan } from '@fortawesome/free-solid-svg-icons'
1111import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
1212import { JSONBlob , JSONBlobParse , JSONSchema } from '@sofie-automation/blueprints-integration'
1313import { DropdownInputControl , DropdownInputOption } from '../../../../lib/Components/DropdownInput.js'
@@ -32,12 +32,24 @@ interface PeripheralDeviceTranslated {
3232export interface SubDevicesTableProps {
3333 subDevices : WrappedOverridableItem < any > [ ]
3434 overrideHelper : OverrideOpHelper
35+ instantSaveOverrideHelper : OverrideOpHelper
3536 peripheralDevices : PeripheralDevice [ ]
37+ hasUnsavedChanges : boolean
38+ saveChanges : ( ) => void
39+ discardChanges : ( ) => void
40+ updateObjectId : ( oldId : string , newId : string ) => void
41+ updatedIds : Map < string , string >
3642}
3743export function GenericSubDevicesTable ( {
3844 subDevices,
3945 overrideHelper,
4046 peripheralDevices,
47+ hasUnsavedChanges,
48+ instantSaveOverrideHelper,
49+ saveChanges,
50+ discardChanges,
51+ updateObjectId,
52+ updatedIds,
4153} : Readonly < SubDevicesTableProps > ) : JSX . Element {
4254 const { t } = useTranslation ( )
4355 const { toggleExpanded, isExpanded } = useToggleExpandHelper ( )
@@ -59,15 +71,14 @@ export function GenericSubDevicesTable({
5971
6072 return devicesMap
6173 } , [ peripheralDevices ] )
62-
6374 const confirmRemove = useCallback (
6475 ( subdeviceId : string ) => {
6576 doModalDialog ( {
6677 title : t ( 'Remove this device?' ) ,
6778 no : t ( 'Cancel' ) ,
6879 yes : t ( 'Remove' ) ,
6980 onAccept : ( ) => {
70- overrideHelper ( ) . deleteItem ( subdeviceId ) . commit ( )
81+ instantSaveOverrideHelper ( ) . deleteItem ( subdeviceId ) . commit ( )
7182 } ,
7283 message : (
7384 < React . Fragment >
@@ -82,7 +93,7 @@ export function GenericSubDevicesTable({
8293 ) ,
8394 } )
8495 } ,
85- [ t , overrideHelper ]
96+ [ t , instantSaveOverrideHelper ]
8697 )
8798
8899 const peripheralDeviceOptions = useMemo ( ( ) => {
@@ -145,6 +156,7 @@ export function GenericSubDevicesTable({
145156 isEdited = { isExpanded ( item . id ) }
146157 editItemWithId = { toggleExpanded }
147158 removeItemWithId = { confirmRemove }
159+ updatedIds = { updatedIds }
148160 />
149161 { isExpanded ( item . id ) && (
150162 < SubDeviceEditRow
@@ -153,6 +165,11 @@ export function GenericSubDevicesTable({
153165 editItemWithId = { toggleExpanded }
154166 item = { item }
155167 overrideHelper = { overrideHelper }
168+ hasUnsavedChanges = { hasUnsavedChanges }
169+ saveChanges = { saveChanges }
170+ discardChanges = { discardChanges }
171+ updateObjectId = { updateObjectId }
172+ updatedIds = { updatedIds }
156173 />
157174 ) }
158175 </ React . Fragment >
@@ -170,13 +187,15 @@ interface SummaryRowProps {
170187 isEdited : boolean
171188 editItemWithId : ( itemId : string ) => void
172189 removeItemWithId : ( itemId : string ) => void
190+ updatedIds : Map < string , string >
173191}
174192function SummaryRow ( {
175193 item,
176194 peripheralDevice,
177195 isEdited,
178196 editItemWithId,
179197 removeItemWithId,
198+ updatedIds,
180199} : Readonly < SummaryRowProps > ) : JSX . Element {
181200 const editItem = useCallback ( ( ) => editItemWithId ( item . id ) , [ editItemWithId , item . id ] )
182201 const removeItem = useCallback ( ( ) => removeItemWithId ( item . id ) , [ removeItemWithId , item . id ] )
@@ -185,13 +204,17 @@ function SummaryRow({
185204 ? ( peripheralDevice . subdeviceManifest ?. [ item . computed . options . type ] ?. displayName ?? '-' )
186205 : '-'
187206
207+ const idChanged = Array . from ( updatedIds ?. entries ( ) || [ ] ) . some ( ( [ key , value ] ) => value === item . id || key === item . id )
208+
188209 return (
189210 < tr
190211 className = { classNames ( {
191212 hl : isEdited ,
192213 } ) }
193214 >
194- < th className = "settings-studio-device__name c2" > { item . id } </ th >
215+ < th className = "settings-studio-device__name c2" >
216+ { item . id } { idChanged && '(pending save)' }
217+ </ th >
195218
196219 < th className = "settings-studio-device__parent c2" >
197220 { peripheralDevice ?. name || item . computed . peripheralDeviceId || '-' }
@@ -252,31 +275,41 @@ interface SubDeviceEditRowProps {
252275 editItemWithId : ( subdeviceId : string , forceState ?: boolean ) => void
253276 item : WrappedOverridableItemNormal < any >
254277 overrideHelper : OverrideOpHelper
278+ hasUnsavedChanges : boolean
279+ saveChanges : ( ) => void
280+ discardChanges : ( ) => void
281+ updateObjectId : ( oldId : string , newId : string ) => void
282+ updatedIds : Map < string , string >
255283}
256284function SubDeviceEditRow ( {
257285 peripheralDevice,
258286 peripheralDeviceOptions,
259287 editItemWithId,
260288 item,
261289 overrideHelper,
290+ hasUnsavedChanges,
291+ saveChanges,
292+ discardChanges,
293+ updateObjectId,
294+ updatedIds,
262295} : Readonly < SubDeviceEditRowProps > ) {
263296 const { t } = useTranslation ( )
264297
265298 const finishEditItem = useCallback ( ( ) => editItemWithId ( item . id , false ) , [ editItemWithId , item . id ] )
266299
267- const updateObjectId = useCallback (
300+ const handleUpdateId = useCallback (
268301 ( newId : string ) => {
269- if ( item . id === newId ) return
270-
271- overrideHelper ( ) . changeItemId ( item . id , newId ) . commit ( )
302+ updateObjectId ( item . id , newId )
272303
273304 // toggle ui visibility
274305 editItemWithId ( item . id , false )
275306 editItemWithId ( newId , true )
276307 } ,
277- [ item . id , overrideHelper , editItemWithId ]
308+ [ item . id , updateObjectId ]
278309 )
279310
311+ const idToShowInInput = updatedIds ?. get ( item . id ) || item . id
312+
280313 return (
281314 < tr className = "expando-details hl" key = { item . id + '-details' } >
282315 < td colSpan = { 99 } >
@@ -294,7 +327,7 @@ function SubDeviceEditRow({
294327 </ LabelAndOverridesForDropdown >
295328 < label className = "field" >
296329 < LabelActual label = { t ( 'Device ID' ) } />
297- < TextInputControl value = { item . id } handleUpdate = { updateObjectId } disabled = { ! ! item . defaults } />
330+ < TextInputControl value = { idToShowInInput } handleUpdate = { handleUpdateId } disabled = { ! ! item . defaults } />
298331 </ label >
299332
300333 { ! item . computed . peripheralDeviceId && (
@@ -308,9 +341,23 @@ function SubDeviceEditRow({
308341 ) }
309342 </ div >
310343 < div className = "m-1 me-2 text-end" >
311- < button className = { classNames ( 'btn btn-primary' ) } onClick = { finishEditItem } >
312- < FontAwesomeIcon icon = { faCheck } />
313- </ button >
344+ { hasUnsavedChanges ? (
345+ < >
346+ < button className = "btn btn-warning ms-2" onClick = { discardChanges } >
347+ < FontAwesomeIcon icon = { faBan } />
348+ { t ( 'Discard' ) }
349+ </ button >
350+
351+ < button className = "btn btn-primary ms-2" onClick = { saveChanges } >
352+ < FontAwesomeIcon icon = { faSave } />
353+ { t ( 'Save' ) }
354+ </ button >
355+ </ >
356+ ) : (
357+ < button className = { classNames ( 'btn btn-primary' ) } onClick = { finishEditItem } >
358+ < FontAwesomeIcon icon = { faCheck } />
359+ </ button >
360+ ) }
314361 </ div >
315362 </ td >
316363 </ tr >
0 commit comments