1818 * SPDX-License-Identifier: Apache-2.0
1919 */
2020
21- import React , { useEffect , useState , useRef , Suspense } from "react" ;
21+ import React , {
22+ useCallback ,
23+ useEffect ,
24+ useRef ,
25+ useState ,
26+ Suspense ,
27+ } from "react" ;
28+ import { ToggleButton , ToggleButtonGroup } from "react-bootstrap" ;
2229import type { Subscription } from "relay-runtime" ;
2330import { FormattedMessage , useIntl } from "react-intl" ;
2431import {
@@ -28,22 +35,23 @@ import {
2835 useRelayEnvironment ,
2936 usePaginationFragment ,
3037 usePreloadedQuery ,
31- PreloadedQuery ,
38+ useQueryLoader ,
3239} from "react-relay/hooks" ;
33- import { Form , Stack } from "react-bootstrap " ;
40+ import type { PreloadedQuery } from "react-relay/hooks " ;
3441
35- import type { Device_getBaseImageCollections_Query } from "@/api/__generated__/Device_getBaseImageCollections_Query .graphql" ;
36- import { SoftwareUpdateTab_createManualOtaOperation_Mutation } from "@/api/__generated__/SoftwareUpdateTab_createManualOtaOperation_Mutation .graphql" ;
42+ import type { SoftwareUpdateTab_createManualOtaOperation_Mutation } from "@/api/__generated__/SoftwareUpdateTab_createManualOtaOperation_Mutation .graphql" ;
43+ import type { SoftwareUpdateTab_getBaseImageCollections_Query } from "@/api/__generated__/SoftwareUpdateTab_getBaseImageCollections_Query .graphql" ;
3744import type { SoftwareUpdateTab_PaginationQuery } from "@/api/__generated__/SoftwareUpdateTab_PaginationQuery.graphql" ;
3845import type { SoftwareUpdateTab_otaOperations$key } from "@/api/__generated__/SoftwareUpdateTab_otaOperations.graphql" ;
3946
4047import Alert from "@/components/Alert" ;
4148import OperationTable from "@/components/OperationTable" ;
4249import Spinner from "@/components/Spinner" ;
50+ import Stack from "@/components/Stack" ;
4351import { Tab } from "@/components/Tabs" ;
52+ import { RECORDS_TO_LOAD_FIRST } from "@/constants" ;
4453import ManualOtaFromCollectionForm from "@/forms/ManualOtaFromCollectionForm" ;
4554import ManualOtaFromFileForm from "@/forms/ManualOtaFromFileForm" ;
46- import { GET_BASE_IMAGE_COLL_QUERY } from "@/pages/Device" ;
4755
4856const DEVICE_OTA_OPERATIONS_FRAGMENT = graphql `
4957 fragment SoftwareUpdateTab_otaOperations on Device
@@ -96,37 +104,60 @@ const DEVICE_CREATE_MANUAL_OTA_OPERATION_MUTATION = graphql`
96104 }
97105` ;
98106
99- export type GetBaseImageCollsQueryType = PreloadedQuery <
100- Device_getBaseImageCollections_Query ,
101- Record < string , unknown >
102- > ;
107+ const GET_BASE_IMAGE_COLL_QUERY = graphql `
108+ query SoftwareUpdateTab_getBaseImageCollections_Query(
109+ $first: Int
110+ $after: String
111+ $filterBaseImageCollections: BaseImageCollectionFilterInput = {}
112+ ) {
113+ ...ManualOtaFromCollectionForm_baseImageCollections_Fragment
114+ @arguments(filter: $filterBaseImageCollections)
115+ }
116+ ` ;
103117
104118type OtaOperationInput = {
105119 imageFile ?: File ;
106120 imageUrl ?: string ;
107121} ;
108122
123+ type ManualOtaFromCollectionFormWrapperProps = {
124+ baseImageCollsQueryRef : PreloadedQuery < SoftwareUpdateTab_getBaseImageCollections_Query > ;
125+ isCreatingOtaOperation : boolean ;
126+ launchManualOTAUpdate : ( input : OtaOperationInput ) => void ;
127+ } ;
128+
129+ const ManualOtaFromCollectionFormWrapper = ( {
130+ baseImageCollsQueryRef,
131+ isCreatingOtaOperation,
132+ launchManualOTAUpdate,
133+ } : ManualOtaFromCollectionFormWrapperProps ) => {
134+ const baseImageCollections = usePreloadedQuery (
135+ GET_BASE_IMAGE_COLL_QUERY ,
136+ baseImageCollsQueryRef ,
137+ ) ;
138+
139+ return (
140+ < ManualOtaFromCollectionForm
141+ baseImageCollectionsData = { baseImageCollections }
142+ isLoading = { isCreatingOtaOperation }
143+ onManualOTAImageSubmit = { launchManualOTAUpdate }
144+ />
145+ ) ;
146+ } ;
147+
109148type DeviceSoftwareUpdateTabProps = {
110149 deviceRef : SoftwareUpdateTab_otaOperations$key ;
111- getBaseImageCollsQuery : GetBaseImageCollsQueryType ;
112150} ;
113151
114152const DeviceSoftwareUpdateTab = ( {
115153 deviceRef,
116- getBaseImageCollsQuery,
117154} : DeviceSoftwareUpdateTabProps ) => {
118155 const [ isRefreshing , setIsRefreshing ] = useState ( false ) ;
119156 const [ errorFeedback , setErrorFeedback ] = useState < React . ReactNode > ( null ) ;
120157 const intl = useIntl ( ) ;
121158 const relayEnvironment = useRelayEnvironment ( ) ;
122159
123- const [ updateMode , setUpdateMode ] = useState < "collection" | "file" > (
124- "collection" ,
125- ) ;
126- const modeOnChange =
127- ( mode : "collection" | "file" ) =>
128- ( _event : React . ChangeEvent < HTMLInputElement > ) =>
129- setUpdateMode ( mode ) ;
160+ const [ updateMode , setUpdateMode ] = useState < "file" | "collection" > ( "file" ) ;
130161
131162 const { data } = usePaginationFragment <
132163 SoftwareUpdateTab_PaginationQuery ,
@@ -208,11 +239,22 @@ const DeviceSoftwareUpdateTab = ({
208239 deviceId ,
209240 ] ) ;
210241
211- const baseImageCollections = usePreloadedQuery (
212- GET_BASE_IMAGE_COLL_QUERY ,
213- getBaseImageCollsQuery ,
242+ const [ getBaseImageCollsQuery , getBaseImageColls ] =
243+ useQueryLoader < SoftwareUpdateTab_getBaseImageCollections_Query > (
244+ GET_BASE_IMAGE_COLL_QUERY ,
245+ ) ;
246+
247+ const fetchBaseImageColls = useCallback (
248+ ( ) =>
249+ getBaseImageColls (
250+ { first : RECORDS_TO_LOAD_FIRST } ,
251+ { fetchPolicy : "store-and-network" } ,
252+ ) ,
253+ [ getBaseImageColls ] ,
214254 ) ;
215255
256+ useEffect ( fetchBaseImageColls , [ fetchBaseImageColls ] ) ;
257+
216258 if ( ! data . capabilities . includes ( "SOFTWARE_UPDATES" ) ) {
217259 return null ;
218260 }
@@ -288,37 +330,56 @@ const DeviceSoftwareUpdateTab = ({
288330 { errorFeedback }
289331 </ Alert >
290332 < Suspense fallback = { < Spinner /> } >
291- < Stack direction = "vertical" className = "mt-3" >
292- < Form . Group key = "updateMode" >
293- < Form . Check
294- name = "updateMode"
295- inline
333+ < Stack direction = "vertical" gap = { 3 } className = "mt-3" >
334+ < div >
335+ < ToggleButtonGroup
296336 type = "radio"
297- label = "Collection"
298- id = "Collection"
299- onChange = { modeOnChange ( "collection" ) }
300- checked = { updateMode === "collection" }
301- />
302- < Form . Check
303337 name = "updateMode"
304- inline
305- type = "radio"
306- label = "File"
307- id = "File"
308- onChange = { modeOnChange ( "file" ) }
309- checked = { updateMode === "file" }
310- />
311- </ Form . Group >
338+ value = { updateMode }
339+ onChange = { setUpdateMode }
340+ size = "sm"
341+ >
342+ < ToggleButton
343+ id = "mode-file"
344+ value = "file"
345+ variant = {
346+ updateMode === "file" ? "primary" : "outline-secondary"
347+ }
348+ className = "fw-medium px-3"
349+ >
350+ < FormattedMessage
351+ id = "components.DeviceTabs.SoftwareUpdateTab.modeFile"
352+ defaultMessage = "File"
353+ />
354+ </ ToggleButton >
355+
356+ < ToggleButton
357+ id = "mode-collection"
358+ value = "collection"
359+ variant = {
360+ updateMode === "collection"
361+ ? "primary"
362+ : "outline-secondary"
363+ }
364+ className = "fw-medium px-3"
365+ >
366+ < FormattedMessage
367+ id = "components.DeviceTabs.SoftwareUpdateTab.modeCollection"
368+ defaultMessage = "Collection"
369+ />
370+ </ ToggleButton >
371+ </ ToggleButtonGroup >
372+ </ div >
312373 { updateMode === "collection" ? (
313- < ManualOtaFromCollectionForm
314- baseImageCollectionsData = { baseImageCollections }
315- className = "mt-3 w-75"
316- isLoading = { isCreatingOtaOperation }
317- onManualOTAImageSubmit = { launchManualOTAUpdate }
318- />
374+ getBaseImageCollsQuery && (
375+ < ManualOtaFromCollectionFormWrapper
376+ baseImageCollsQueryRef = { getBaseImageCollsQuery }
377+ isCreatingOtaOperation = { isCreatingOtaOperation }
378+ launchManualOTAUpdate = { launchManualOTAUpdate }
379+ />
380+ )
319381 ) : (
320382 < ManualOtaFromFileForm
321- className = "mt-3 w-75"
322383 isLoading = { isCreatingOtaOperation }
323384 onManualOTAImageSubmit = { launchManualOTAUpdate }
324385 />
0 commit comments