1313 * See the License for the specific language governing permissions and *
1414 * limitations under the License. *
1515 * ------------------------------------------------------------------------- */
16- import { Box , Grid , useTheme } from '@mui/material'
1716import MultipleTags from '@modules/components/MultipleTags'
18- import { SubmitButton } from '@modules/components/FormControl'
19- import { Component , useEffect , useMemo , useState } from 'react'
20- import { DatastoreDialog } from '@modules/components/Tables/VrTemplates/DatastoreSelectionDialog'
17+ import { Component , useMemo , useCallback } from 'react'
18+ import { CloudDownload } from 'iconoir-react'
2119
2220import {
2321 useAuth ,
2422 useViews ,
25- useGeneralApi ,
26- MarketplaceAPI ,
23+ useModalsApi ,
2724 VrTemplateAPI ,
2825 MarketplaceAppAPI ,
29- DatastoreAPI ,
3026} from '@FeaturesModule'
3127import { getResourceLabels } from '@UtilsModule'
3228import { getColorFromString , timeToString } from '@ModelsModule'
3329import { RESOURCE_NAMES , T , STYLE_BUTTONS } from '@ConstantsModule'
34- import { BoxIso as DownloadIcon } from 'iconoir-react'
35-
36- import { Tr , Translate } from '@modules/components/HOC'
30+ import { Box } from '@mui/material'
3731import EnhancedTable , {
3832 createColumns ,
3933} from '@modules/components/Tables/Enhanced'
4034import WrapperRow from '@modules/components/Tables/Enhanced/WrapperRow'
4135import VrTemplateColumns from '@modules/components/Tables/VrTemplates/columns'
4236import VrTemplateRow from '@modules/components/Tables/VrTemplates/row'
43- import { useStyles } from '@modules/components/Tabs/EmptyTab/styles'
44- import InfoEmpty from 'iconoir-react/dist/InfoEmpty'
45- import { debounce } from 'lodash'
37+ import SubmitButton from '@modules/components/FormControl/SubmitButton'
38+ import { ExportForm } from '@modules/components/Forms/MarketplaceApp'
4639
4740const DEFAULT_DATA_CY = 'vrouter-templates'
4841
@@ -51,35 +44,32 @@ const DEFAULT_DATA_CY = 'vrouter-templates'
5144 * @returns {Component } - Vr Templates table
5245 */
5346const VrTemplatesTable = ( props ) => {
47+ const { showModal } = useModalsApi ( )
48+ const [ exportApp ] = MarketplaceAppAPI . useExportAppMutation ( )
49+ const { data : defaultVrApp = [ ] , isFetching : loadingApps } =
50+ MarketplaceAppAPI . useGetMarketplaceAppsQuery ( undefined , {
51+ selectFromResult : ( { data : result = [ ] } ) => ( {
52+ data : result ?. find (
53+ ( app ) =>
54+ app ?. MARKETPLACE === 'OpenNebula Public' &&
55+ app ?. NAME === 'Service Virtual Router'
56+ ) ,
57+ } ) ,
58+ } )
5459 const { rootProps = { } , searchProps = { } , ...rest } = props ?? { }
5560 const { labels = { } } = useAuth ( )
5661
57- const theme = useTheme ( )
58- const classes = useMemo ( ( ) => useStyles ( theme ) , [ theme ] )
59-
6062 rootProps [ 'data-cy' ] ??= DEFAULT_DATA_CY
6163 searchProps [ 'data-cy' ] ??= `search-${ DEFAULT_DATA_CY } `
6264
63- const { enqueueError, enqueueSuccess, enqueueInfo } = useGeneralApi ( )
6465 const { view, getResourceView } = useViews ( )
65- const [ loading , setLoading ] = useState ( false )
66- const [ oneMarket , setOneMarket ] = useState ( null )
67- const [ defaultImage , setDefaultImage ] = useState ( null )
68- const [ disableDownload , setDisableDownload ] = useState ( false )
69- const [ dialogOpen , setDialogOpen ] = useState ( false )
70- const [ enableMarketplace ] = MarketplaceAPI . useEnableMarketplaceMutation ( )
71- const [ exportApp ] = MarketplaceAppAPI . useExportAppMutation ( )
7266 const {
7367 data = [ ] ,
74- isFetching,
68+ isFetching : loadingTemplates ,
7569 refetch,
7670 } = VrTemplateAPI . useGetVrTemplatesQuery ( )
77- const [
78- fetchMarketplaces ,
79- { data : marketplaces = [ ] , isFetching : fetchingMarketplaces } ,
80- ] = MarketplaceAPI . useLazyGetMarketplacesQuery ( undefined , {
81- skip : true , // Does not run on initial render
82- } )
71+
72+ const loading = loadingTemplates || loadingApps
8373
8474 const fmtData = useMemo (
8575 ( ) =>
@@ -98,24 +88,6 @@ const VrTemplatesTable = (props) => {
9888 [ data , labels ]
9989 )
10090
101- const [
102- fetchDatastores ,
103- { data : datastores = [ ] , isFetching : fetchingDatastores } ,
104- ] = DatastoreAPI . useLazyGetDatastoresQuery ( undefined , {
105- skip : true , // Does not run on initial render
106- } )
107-
108- const [
109- fetchMarketplaceApps ,
110- { data : marketplaceApps = [ ] , isFetching : fetchingMarketplaceApps } ,
111- ] = MarketplaceAppAPI . useLazyGetMarketplaceAppsQuery ( undefined , {
112- skip : true ,
113- } ) // Does not run on initial render
114-
115- useEffect ( ( ) => {
116- setLoading ( isFetching || fetchingMarketplaces )
117- } , [ isFetching , fetchingMarketplaces ] )
118-
11991 const columns = useMemo (
12092 ( ) =>
12193 createColumns ( {
@@ -125,166 +97,47 @@ const VrTemplatesTable = (props) => {
12597 [ view ]
12698 )
12799
128- const submitDisabled = useMemo (
129- ( ) =>
130- ! (
131- ! fetchingMarketplaces &&
132- ! fetchingMarketplaceApps &&
133- ! fetchingDatastores
134- ) ,
135- [ fetchingMarketplaces , fetchingMarketplaceApps , fetchingDatastores ]
136- )
137-
138- const handleDownloadDefaultImage = debounce (
139- async ( ) => {
140- // Use cache if exists
141- setDisableDownload ( true )
142- await fetchMarketplaces ( undefined , true )
143- await fetchDatastores ( undefined , true )
144- if ( defaultImage !== null ) {
145- setDialogOpen ( true )
146- }
100+ const handleSubmit = useCallback (
101+ async ( formData ) => {
102+ await exportApp ( { id : defaultVrApp . ID , ...formData } )
103+ refetch ( )
147104 } ,
148- 4000 ,
149- { leading : true }
105+ [ defaultVrApp ]
150106 )
151107
152- useEffect ( ( ) => {
153- if ( marketplaces ?. length ) {
154- const mid =
155- marketplaces ?. find (
156- ( marketplace ) => marketplace ?. NAME === 'OpenNebula Public'
157- ) ?? null
158- mid !== null &&
159- setOneMarket ( {
160- ID : mid ?. ID ?? - 1 ,
161- STATE : mid ?. STATE === '0' ? 'ENABLED' : 'DISABLED' ,
162- } )
163- }
164- } , [ marketplaces ] )
165-
166- useEffect ( ( ) => {
167- // Internal ASYNC funcs -->
168-
169- const fetchApps = async ( ) => {
170- await fetchMarketplaceApps ( undefined , true ) // Prefer cache
171- }
172-
173- const enableMarket = async ( marketID ) => {
174- const response = await enableMarketplace ( { id : marketID } )
175- if ( response ?. data === parseInt ( marketID , 10 ) ) {
176- enqueueInfo ( T . InfoEnableOpenNebulaMarketplace )
177- setOneMarket ( { ...oneMarket , STATE : 'ENABLED' } )
178- fetchApps ( )
179- }
180-
181- return response
182- }
183-
184- // <--Internal ASYNC funcs
185-
186- try {
187- if (
188- oneMarket !== null &&
189- oneMarket ?. ID !== - 1 &&
190- oneMarket ?. STATE !== 'ENABLED'
191- ) {
192- enableMarket ( oneMarket ?. ID ) . catch ( console . error )
193-
194- // Prefer cache
195- } else if (
196- oneMarket !== null &&
197- oneMarket ?. ID !== - 1 &&
198- oneMarket ?. STATE === 'ENABLED'
199- ) {
200- fetchApps ( )
201- }
202- } catch { }
203- } , [ oneMarket ] )
204-
205- useEffect ( ( ) => {
206- if ( marketplaceApps ?. length && ! fetchingMarketplaceApps ) {
207- const vrTemplate =
208- marketplaceApps ?. find (
209- ( app ) => app ?. NAME === 'Service Virtual Router'
210- ) ?? null
211- setDefaultImage ( vrTemplate )
212- }
213- } , [ marketplaceApps ] )
214-
215- useEffect ( ( ) => {
216- if ( defaultImage !== null && ! fetchingDatastores ) {
217- setDisableDownload ( true )
218- setDialogOpen ( true )
219- }
220- } , [ defaultImage , datastores ] )
221-
222- const handleCloseDialog = ( ) => {
223- setDialogOpen ( false )
224- setDisableDownload ( false )
225- }
226-
227- const handleDownloadApp = async ( datastoreId ) => {
228- await exportApp ( {
229- id : defaultImage ?. ID ,
230- name : 'Service Virtual Router' ,
231- vmname : 'Service Virtual Router' ,
232- datastore : datastoreId ,
108+ const handleExportApp = ( ) => {
109+ showModal ( {
110+ id : 'export-default-vr' ,
111+ dialogProps : {
112+ title : T . DownloadDefaultImage ,
113+ dataCy : 'modal-download-vr-app' ,
114+ } ,
115+ form : ExportForm ( {
116+ initialValues : defaultVrApp ,
117+ stepProps : defaultVrApp ,
118+ } ) ,
119+ onSubmit : handleSubmit ,
233120 } )
234- . then ( ( res ) => {
235- if ( res ?. data ) {
236- enqueueSuccess ( T . SuccessDownloadDefaultImage ) && refetch ( )
237- } else if ( res ?. error ) {
238- enqueueError ( res . error )
239- } else {
240- throw new Error ( 'Unexpected problem occured' )
241- }
242- } )
243- . catch ( ( error ) => {
244- console . error ( error )
245- } )
246121 }
247122
248- const filterDatastores = useMemo ( ( ) =>
249- datastores ?. filter ( ( ds ) => ds ?. TYPE === '0' )
250- )
251-
252123 const NoDataAvailable = ( ) => (
253- < >
254- < Grid
255- container
256- sx = { {
257- alignItems : 'start' ,
258- justifyContent : 'start' ,
259- width : '100%' ,
260- height : '100%' ,
261- } }
262- >
263- < Grid item xs = { 12 } >
264- < Box className = { classes . noDataMessage } >
265- < InfoEmpty />
266- < Translate word = { T . NoDataAvailable } />
267- < SubmitButton
268- importance = { STYLE_BUTTONS . IMPORTANCE . MAIN }
269- size = { STYLE_BUTTONS . SIZE . MEDIUM }
270- type = { STYLE_BUTTONS . TYPE . FILLED }
271- disabled = { disableDownload }
272- icon = { < DownloadIcon /> }
273- onClick = { ( ) => handleDownloadDefaultImage ( ) }
274- label = { Tr ( T . DownloadDefaultImage ) }
275- />
276- </ Box >
277- </ Grid >
278- </ Grid >
279-
280- < DatastoreDialog
281- open = { dialogOpen }
282- onClose = { handleCloseDialog }
283- datastores = { filterDatastores }
284- submitDisabled = { submitDisabled }
285- onSelect = { ( ds ) => handleDownloadApp ( ds ?. ID ?? - 1 ) }
124+ < Box
125+ sx = { {
126+ width : 'fit-content' ,
127+ height : 'fit-content' ,
128+ } }
129+ >
130+ < SubmitButton
131+ dataCy = "download-vr-app"
132+ icon = < CloudDownload />
133+ label = { T . DownloadDefaultImage }
134+ importance = { STYLE_BUTTONS . IMPORTANCE . MAIN }
135+ size = { STYLE_BUTTONS . SIZE . MEDIUM }
136+ type = { STYLE_BUTTONS . TYPE . FILLED }
137+ disabled = { loading }
138+ onClick = { handleExportApp }
286139 />
287- </ >
140+ </ Box >
288141 )
289142
290143 const listHeader = [
0 commit comments