mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-22 18:50:08 +03:00
parent
083f86a21f
commit
e84d1d2be4
@ -0,0 +1,78 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2021, OpenNebula Project, OpenNebula Systems *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may *
|
||||
* not use this file except in compliance with the License. You may obtain *
|
||||
* a copy of the License at *
|
||||
* *
|
||||
* http://www.apache.org/licenses/LICENSE-2.0 *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, *
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
/* eslint-disable jsdoc/require-jsdoc */
|
||||
import { useMemo } from 'react'
|
||||
// import { useHistory } from 'react-router-dom'
|
||||
import { RefreshDouble } from 'iconoir-react'
|
||||
|
||||
import { useAuth } from 'client/features/Auth'
|
||||
import { useMarketplaceAppApi } from 'client/features/One'
|
||||
import { Translate } from 'client/components/HOC'
|
||||
|
||||
import { createActions } from 'client/components/Tables/Enhanced/Utils'
|
||||
// import { PATH } from 'client/apps/sunstone/routesOne'
|
||||
import { T, MARKETPLACE_APP_ACTIONS } from 'client/constants'
|
||||
|
||||
const MessageToConfirmAction = rows => {
|
||||
const names = rows?.map?.(({ original }) => original?.NAME)
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
<Translate word={T.Apps} />
|
||||
{`: ${names.join(', ')}`}
|
||||
</p>
|
||||
<p>
|
||||
<Translate word={T.DoYouWantProceed} />
|
||||
</p>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
MessageToConfirmAction.displayName = 'MessageToConfirmAction'
|
||||
|
||||
const Actions = () => {
|
||||
const { view, getResourceView } = useAuth()
|
||||
const { getMarketplaceApps } = useMarketplaceAppApi()
|
||||
|
||||
const marketplaceAppActions = useMemo(() => createActions({
|
||||
filters: getResourceView('MARKETPLACE-APP')?.actions,
|
||||
actions: [
|
||||
{
|
||||
accessor: MARKETPLACE_APP_ACTIONS.REFRESH,
|
||||
tooltip: T.Refresh,
|
||||
icon: RefreshDouble,
|
||||
action: async () => {
|
||||
await getMarketplaceApps()
|
||||
}
|
||||
}
|
||||
/* {
|
||||
accessor: MARKETPLACE_APP_ACTIONS.CREATE_DIALOG,
|
||||
tooltip: T.CreateMarketApp,
|
||||
icon: AddSquare,
|
||||
action: () => {
|
||||
const path = PATH.STORAGE.MARKETPLACE_APPS.CREATE
|
||||
|
||||
history.push(path)
|
||||
}
|
||||
} */
|
||||
]
|
||||
}), [view])
|
||||
|
||||
return marketplaceAppActions
|
||||
}
|
||||
|
||||
export default Actions
|
@ -21,15 +21,20 @@ import { useFetch } from 'client/hooks'
|
||||
import { useMarketplaceApp, useMarketplaceAppApi } from 'client/features/One'
|
||||
|
||||
import { SkeletonTable, EnhancedTable } from 'client/components/Tables'
|
||||
import { createColumns } from 'client/components/Tables/Enhanced/Utils'
|
||||
import MarketplaceAppColumns from 'client/components/Tables/MarketplaceApps/columns'
|
||||
import MarketplaceAppRow from 'client/components/Tables/MarketplaceApps/row'
|
||||
|
||||
const MarketplaceAppsTable = () => {
|
||||
const columns = useMemo(() => MarketplaceAppColumns, [])
|
||||
const MarketplaceAppsTable = props => {
|
||||
const { view, getResourceView, filterPool } = useAuth()
|
||||
|
||||
const columns = useMemo(() => createColumns({
|
||||
filters: getResourceView('MARKETPLACE-APP')?.filters,
|
||||
columns: MarketplaceAppColumns
|
||||
}), [view])
|
||||
|
||||
const marketplaceApps = useMarketplaceApp()
|
||||
const { getMarketplaceApps } = useMarketplaceAppApi()
|
||||
const { filterPool } = useAuth()
|
||||
|
||||
const { status, fetchRequest, loading, reloading, STATUS } = useFetch(getMarketplaceApps)
|
||||
const { INIT, PENDING } = STATUS
|
||||
@ -47,6 +52,7 @@ const MarketplaceAppsTable = () => {
|
||||
isLoading={loading || reloading}
|
||||
getRowId={row => String(row.ID)}
|
||||
RowComponent={MarketplaceAppRow}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -0,0 +1,134 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2021, OpenNebula Project, OpenNebula Systems *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may *
|
||||
* not use this file except in compliance with the License. You may obtain *
|
||||
* a copy of the License at *
|
||||
* *
|
||||
* http://www.apache.org/licenses/LICENSE-2.0 *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, *
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
/* eslint-disable jsdoc/require-jsdoc */
|
||||
import { useContext } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { useMarketplaceAppApi } from 'client/features/One'
|
||||
import { TabContext } from 'client/components/Tabs/TabProvider'
|
||||
import { Permissions, Ownership, AttributePanel } from 'client/components/Tabs/Common'
|
||||
import Information from 'client/components/Tabs/MarketplaceApp/Info/information'
|
||||
|
||||
import { Tr } from 'client/components/HOC'
|
||||
import { getActionsAvailable, filterAttributes, jsonToXml } from 'client/models/Helper'
|
||||
import { cloneObject, set } from 'client/utils'
|
||||
import { T } from 'client/constants'
|
||||
|
||||
const HIDDEN_ATTRIBUTES_REG = /^(VMTEMPLATE64|APPTEMPLATE64)$/
|
||||
|
||||
const MarketplaceAppInfoTab = ({ tabProps = {} }) => {
|
||||
const {
|
||||
information_panel: informationPanel,
|
||||
permissions_panel: permissionsPanel,
|
||||
ownership_panel: ownershipPanel,
|
||||
attributes_panel: attributesPanel
|
||||
} = tabProps
|
||||
|
||||
const { rename, changeOwnership, changePermissions, updateTemplate } = useMarketplaceAppApi()
|
||||
const { handleRefetch, data: marketplaceApp = {} } = useContext(TabContext)
|
||||
const { ID, UNAME, UID, GNAME, GID, PERMISSIONS, TEMPLATE } = marketplaceApp
|
||||
|
||||
const handleChangeOwnership = async newOwnership => {
|
||||
const response = await changeOwnership(ID, newOwnership)
|
||||
String(response) === String(ID) && (await handleRefetch?.())
|
||||
}
|
||||
|
||||
const handleChangePermission = async newPermission => {
|
||||
const response = await changePermissions(ID, newPermission)
|
||||
String(response) === String(ID) && (await handleRefetch?.())
|
||||
}
|
||||
|
||||
const handleRename = async (_, newName) => {
|
||||
const response = await rename(ID, newName)
|
||||
String(response) === String(ID) && (await handleRefetch?.())
|
||||
}
|
||||
|
||||
const handleAttributeInXml = async (path, newValue) => {
|
||||
const newTemplate = cloneObject(TEMPLATE)
|
||||
|
||||
set(newTemplate, path, newValue)
|
||||
|
||||
const xml = jsonToXml(newTemplate)
|
||||
|
||||
// 0: Replace the whole template
|
||||
const response = await updateTemplate(ID, xml, 0)
|
||||
String(response) === String(ID) && (await handleRefetch?.())
|
||||
}
|
||||
|
||||
const getActions = actions => getActionsAvailable(actions)
|
||||
|
||||
const { attributes } = filterAttributes(TEMPLATE, { hidden: HIDDEN_ATTRIBUTES_REG })
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
display: 'grid',
|
||||
gap: '1em',
|
||||
gridTemplateColumns: 'repeat(auto-fit, minmax(480px, 1fr))',
|
||||
padding: '0.8em'
|
||||
}}>
|
||||
{informationPanel?.enabled && (
|
||||
<Information
|
||||
actions={getActions(informationPanel?.actions)}
|
||||
handleRename={handleRename}
|
||||
marketplaceApp={marketplaceApp}
|
||||
/>
|
||||
)}
|
||||
{permissionsPanel?.enabled && (
|
||||
<Permissions
|
||||
actions={getActions(permissionsPanel?.actions)}
|
||||
ownerUse={PERMISSIONS.OWNER_U}
|
||||
ownerManage={PERMISSIONS.OWNER_M}
|
||||
ownerAdmin={PERMISSIONS.OWNER_A}
|
||||
groupUse={PERMISSIONS.GROUP_U}
|
||||
groupManage={PERMISSIONS.GROUP_M}
|
||||
groupAdmin={PERMISSIONS.GROUP_A}
|
||||
otherUse={PERMISSIONS.OTHER_U}
|
||||
otherManage={PERMISSIONS.OTHER_M}
|
||||
otherAdmin={PERMISSIONS.OTHER_A}
|
||||
handleEdit={handleChangePermission}
|
||||
/>
|
||||
)}
|
||||
{ownershipPanel?.enabled && (
|
||||
<Ownership
|
||||
actions={getActions(ownershipPanel?.actions)}
|
||||
userId={UID}
|
||||
userName={UNAME}
|
||||
groupId={GID}
|
||||
groupName={GNAME}
|
||||
handleEdit={handleChangeOwnership}
|
||||
/>
|
||||
)}
|
||||
{attributesPanel?.enabled && attributes && (
|
||||
<AttributePanel
|
||||
attributes={attributes}
|
||||
actions={getActions(attributesPanel?.actions)}
|
||||
title={Tr(T.Attributes)}
|
||||
handleAdd={handleAttributeInXml}
|
||||
handleEdit={handleAttributeInXml}
|
||||
handleDelete={handleAttributeInXml}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
MarketplaceAppInfoTab.propTypes = {
|
||||
tabProps: PropTypes.object
|
||||
}
|
||||
|
||||
MarketplaceAppInfoTab.displayName = 'MarketplaceAppInfoTab'
|
||||
|
||||
export default MarketplaceAppInfoTab
|
@ -0,0 +1,80 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2021, OpenNebula Project, OpenNebula Systems *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may *
|
||||
* not use this file except in compliance with the License. You may obtain *
|
||||
* a copy of the License at *
|
||||
* *
|
||||
* http://www.apache.org/licenses/LICENSE-2.0 *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, *
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
/* eslint-disable jsdoc/require-jsdoc */
|
||||
import PropTypes from 'prop-types'
|
||||
import { generatePath } from 'react-router'
|
||||
|
||||
import { StatusChip } from 'client/components/Status'
|
||||
import { List } from 'client/components/Tabs/Common'
|
||||
|
||||
import { getType, getState } from 'client/models/MarketplaceApp'
|
||||
import { timeToString, levelLockToString } from 'client/models/Helper'
|
||||
import { prettyBytes } from 'client/utils'
|
||||
import { T, MARKETPLACE_APP_ACTIONS } from 'client/constants'
|
||||
import { PATH } from 'client/apps/sunstone/routesOne'
|
||||
|
||||
const InformationPanel = ({ marketplaceApp = {}, handleRename, actions }) => {
|
||||
const { ID, NAME, REGTIME, LOCK, MARKETPLACE, MARKETPLACE_ID, SIZE, FORMAT, VERSION } = marketplaceApp
|
||||
const typeName = getType(marketplaceApp)
|
||||
const { name: stateName, color: stateColor } = getState(marketplaceApp)
|
||||
|
||||
const info = [
|
||||
{ name: T.ID, value: ID },
|
||||
{
|
||||
name: T.Name,
|
||||
value: NAME,
|
||||
canEdit: actions?.includes?.(MARKETPLACE_APP_ACTIONS.RENAME),
|
||||
handleEdit: handleRename
|
||||
},
|
||||
{
|
||||
name: T.Marketplace,
|
||||
value: `#${MARKETPLACE_ID} ${MARKETPLACE}`,
|
||||
link: !Number.isNaN(+MARKETPLACE_ID) &&
|
||||
generatePath(PATH.STORAGE.MARKETPLACES.DETAIL, { id: MARKETPLACE_ID })
|
||||
},
|
||||
{
|
||||
name: T.StartTime,
|
||||
value: timeToString(REGTIME)
|
||||
},
|
||||
{ name: T.Type, value: typeName },
|
||||
{ name: T.Size, value: prettyBytes(SIZE, 'MB') },
|
||||
{
|
||||
name: T.State,
|
||||
value: <StatusChip text={stateName} stateColor={stateColor} />
|
||||
},
|
||||
{ name: T.Locked, value: levelLockToString(LOCK?.LOCKED) },
|
||||
{ name: T.Format, value: FORMAT },
|
||||
{ name: T.Version, value: VERSION }
|
||||
]
|
||||
|
||||
return (
|
||||
<List
|
||||
title={T.Information}
|
||||
list={info}
|
||||
containerProps={{ style: { gridRow: 'span 3' } }}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
InformationPanel.displayName = 'InformationPanel'
|
||||
|
||||
InformationPanel.propTypes = {
|
||||
actions: PropTypes.arrayOf(PropTypes.string),
|
||||
handleRename: PropTypes.func,
|
||||
marketplaceApp: PropTypes.object
|
||||
}
|
||||
|
||||
export default InformationPanel
|
@ -0,0 +1,70 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2021, OpenNebula Project, OpenNebula Systems *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may *
|
||||
* not use this file except in compliance with the License. You may obtain *
|
||||
* a copy of the License at *
|
||||
* *
|
||||
* http://www.apache.org/licenses/LICENSE-2.0 *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, *
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
/* eslint-disable jsdoc/require-jsdoc */
|
||||
import { useContext, useMemo } from 'react'
|
||||
import { Accordion, AccordionDetails, AccordionSummary } from '@mui/material'
|
||||
import { NavArrowDown as ExpandMoreIcon } from 'iconoir-react'
|
||||
|
||||
import { TabContext } from 'client/components/Tabs/TabProvider'
|
||||
import { Translate } from 'client/components/HOC'
|
||||
import { T } from 'client/constants'
|
||||
|
||||
const parseTemplateInB64 = template => {
|
||||
try {
|
||||
return decodeURIComponent(escape(atob(template)))
|
||||
} catch (e) { return {} }
|
||||
}
|
||||
|
||||
const AppTemplateTab = () => {
|
||||
const { data: marketplaceApp = {} } = useContext(TabContext)
|
||||
const { TEMPLATE: { APPTEMPLATE64, VMTEMPLATE64 } } = marketplaceApp
|
||||
|
||||
const appTemplate = useMemo(() => parseTemplateInB64(APPTEMPLATE64), [APPTEMPLATE64])
|
||||
const vmTemplate = useMemo(() => parseTemplateInB64(VMTEMPLATE64), [VMTEMPLATE64])
|
||||
|
||||
return (
|
||||
<>
|
||||
<Accordion TransitionProps={{ unmountOnExit: true }}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<Translate word={T.AppTemplate} />
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<pre>
|
||||
<code style={{ whiteSpace: 'break-spaces', wordBreak: 'break-all' }}>
|
||||
{appTemplate}
|
||||
</code>
|
||||
</pre>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
<Accordion TransitionProps={{ unmountOnExit: true }}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<Translate word={T.VMTemplate} />
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<pre>
|
||||
<code style={{ whiteSpace: 'break-spaces', wordBreak: 'break-all' }}>
|
||||
{vmTemplate}
|
||||
</code>
|
||||
</pre>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
AppTemplateTab.displayName = 'AppTemplateTab'
|
||||
|
||||
export default AppTemplateTab
|
@ -0,0 +1,84 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2021, OpenNebula Project, OpenNebula Systems *
|
||||
* *
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may *
|
||||
* not use this file except in compliance with the License. You may obtain *
|
||||
* a copy of the License at *
|
||||
* *
|
||||
* http://www.apache.org/licenses/LICENSE-2.0 *
|
||||
* *
|
||||
* Unless required by applicable law or agreed to in writing, software *
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, *
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
/* eslint-disable jsdoc/require-jsdoc */
|
||||
import { memo, useEffect, useState } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { LinearProgress } from '@mui/material'
|
||||
|
||||
import { useFetch } from 'client/hooks'
|
||||
import { useAuth } from 'client/features/Auth'
|
||||
import { useMarketplaceAppApi } from 'client/features/One'
|
||||
|
||||
import Tabs from 'client/components/Tabs'
|
||||
import { camelCase } from 'client/utils'
|
||||
|
||||
import TabProvider from 'client/components/Tabs/TabProvider'
|
||||
import Info from 'client/components/Tabs/MarketplaceApp/Info'
|
||||
import Template from 'client/components/Tabs/MarketplaceApp/Template'
|
||||
|
||||
const getTabComponent = tabName => ({
|
||||
info: Info,
|
||||
template: Template
|
||||
}[tabName])
|
||||
|
||||
const MarketplaceAppTabs = memo(({ id }) => {
|
||||
const { getMarketplaceApp } = useMarketplaceAppApi()
|
||||
const { data, fetchRequest, loading, error } = useFetch(getMarketplaceApp)
|
||||
|
||||
const handleRefetch = () => fetchRequest(id, { reload: true })
|
||||
|
||||
const [tabsAvailable, setTabs] = useState(() => [])
|
||||
const { view, getResourceView } = useAuth()
|
||||
|
||||
useEffect(() => {
|
||||
fetchRequest(id)
|
||||
}, [id])
|
||||
|
||||
useEffect(() => {
|
||||
const infoTabs = getResourceView('MARKETPLACE-APP')?.['info-tabs'] ?? {}
|
||||
|
||||
setTabs(() => Object.entries(infoTabs)
|
||||
?.filter(([_, { enabled } = {}]) => !!enabled)
|
||||
?.map(([tabName, tabProps]) => {
|
||||
const camelName = camelCase(tabName)
|
||||
const TabContent = getTabComponent(camelName)
|
||||
|
||||
return TabContent && {
|
||||
name: camelName,
|
||||
renderContent: props => TabContent({ ...props, tabProps })
|
||||
}
|
||||
})
|
||||
?.filter(Boolean))
|
||||
}, [view])
|
||||
|
||||
if ((!data && !error) || loading) {
|
||||
return <LinearProgress color='secondary' style={{ width: '100%' }} />
|
||||
}
|
||||
|
||||
return (
|
||||
<TabProvider initialState={{ data, handleRefetch }}>
|
||||
<Tabs tabs={tabsAvailable} />
|
||||
</TabProvider>
|
||||
)
|
||||
})
|
||||
|
||||
MarketplaceAppTabs.propTypes = {
|
||||
id: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
MarketplaceAppTabs.displayName = 'MarketplaceAppTabs'
|
||||
|
||||
export default MarketplaceAppTabs
|
@ -15,5 +15,6 @@
|
||||
* ------------------------------------------------------------------------- */
|
||||
export const MARKETPLACE_APP_ACTIONS = {
|
||||
REFRESH: 'refresh',
|
||||
CREATE_DIALOG: 'create_dialog'
|
||||
CREATE_DIALOG: 'create_dialog',
|
||||
RENAME: 'rename'
|
||||
}
|
||||
|
@ -286,6 +286,7 @@ module.exports = {
|
||||
ID: 'ID',
|
||||
Name: 'Name',
|
||||
State: 'State',
|
||||
Size: 'Size',
|
||||
Description: 'Description',
|
||||
RegistrationTime: 'Registration time',
|
||||
StartTime: 'Start time',
|
||||
@ -295,6 +296,7 @@ module.exports = {
|
||||
Type: 'Type',
|
||||
Data: 'Data',
|
||||
Validate: 'Validate',
|
||||
Format: 'Format',
|
||||
|
||||
/* permissions */
|
||||
Permissions: 'Permissions',
|
||||
@ -578,6 +580,11 @@ module.exports = {
|
||||
ReservedMemory: 'Allocated Memory',
|
||||
ReservedCpu: 'Allocated CPU',
|
||||
|
||||
/* Marketplace App schema */
|
||||
/* Marketplace App - general */
|
||||
Version: 'Version',
|
||||
AppTemplate: 'App Template',
|
||||
|
||||
/* User inputs */
|
||||
UserInputs: 'User Inputs',
|
||||
UserInputsConcept: `
|
||||
|
@ -13,24 +13,53 @@
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
/* eslint-disable jsdoc/require-jsdoc */
|
||||
|
||||
import { Container, Box } from '@mui/material'
|
||||
import { useState, JSXElementConstructor } from 'react'
|
||||
import { Container, Stack, Chip } from '@mui/material'
|
||||
|
||||
import { MarketplaceAppsTable } from 'client/components/Tables'
|
||||
import MarketplaceAppActions from 'client/components/Tables/MarketplaceApps/actions'
|
||||
import MarketplaceAppsTabs from 'client/components/Tabs/MarketplaceApp'
|
||||
import SplitPane from 'client/components/SplitPane'
|
||||
import MultipleTags from 'client/components/MultipleTags'
|
||||
|
||||
/**
|
||||
* Displays a Marketplace Apps list.
|
||||
*
|
||||
* @returns {JSXElementConstructor} List of Marketplace Apps
|
||||
*/
|
||||
function MarketplaceApps () {
|
||||
const [selectedRows, onSelectedRowsChange] = useState(() => [])
|
||||
const actions = MarketplaceAppActions()
|
||||
|
||||
return (
|
||||
<Box
|
||||
height={1}
|
||||
py={2}
|
||||
overflow='auto'
|
||||
display='flex'
|
||||
flexDirection='column'
|
||||
component={Container}
|
||||
>
|
||||
<MarketplaceAppsTable />
|
||||
</Box>
|
||||
<Stack height={1} py={2} overflow='auto' component={Container}>
|
||||
<SplitPane>
|
||||
<MarketplaceAppsTable
|
||||
onSelectedRowsChange={onSelectedRowsChange}
|
||||
globalActions={actions}
|
||||
/>
|
||||
|
||||
{selectedRows?.length > 0 && (
|
||||
<Stack overflow='auto'>
|
||||
{selectedRows?.length === 1
|
||||
? <MarketplaceAppsTabs id={selectedRows[0]?.values.ID} />
|
||||
: <Stack direction='row' flexWrap='wrap' gap={1} alignItems='center'>
|
||||
<MultipleTags
|
||||
limitTags={10}
|
||||
tags={selectedRows?.map(({ original, id, toggleRowSelected }) => (
|
||||
<Chip key={id}
|
||||
variant='text'
|
||||
label={original?.NAME ?? id}
|
||||
onDelete={() => toggleRowSelected(false)}
|
||||
/>
|
||||
))}
|
||||
/>
|
||||
</Stack>
|
||||
}
|
||||
</Stack>
|
||||
)}
|
||||
</SplitPane>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ export const marketplaceAppService = ({
|
||||
|
||||
if (!res?.id || res?.id !== httpCodes.ok.id) throw res
|
||||
|
||||
return res?.data?.MARKETAPP ?? {}
|
||||
return res?.data?.MARKETPLACEAPP ?? {}
|
||||
},
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user