mirror of
https://github.com/OpenNebula/one.git
synced 2025-01-20 14:03:36 +03:00
F OpenNebula/one#6617: Fix multichart rendering in fullscreen (#3124)
* Fixes multichart rendering in fullscreen mode under the users quota tab - Also scales the chart renderer to look a lot more consistent * Fixes a bunch of hook violations by removing memoizaitons - might need to be refactored later on * Fixes accounting data handling bug for users where if only one record was returned by the core, no data would be displayed Signed-off-by: Victor Hansson <vhansson@opennebula.io>
This commit is contained in:
parent
b1ef325389
commit
81fc9f1ae0
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
import React, { useMemo } from 'react'
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import {
|
||||
Area,
|
||||
@ -128,20 +128,14 @@ export const ChartRenderer = ({
|
||||
return Tr(finalWord)
|
||||
})
|
||||
|
||||
const polarDataset = useMemo(
|
||||
() => (coordinateType === 'POLAR' ? FormatPolarDataset(datasets) : null),
|
||||
[coordinateType, datasets]
|
||||
)
|
||||
const polarDataset =
|
||||
coordinateType === 'POLAR' ? FormatPolarDataset(datasets) : null
|
||||
|
||||
const chartConfig = useMemo(
|
||||
() =>
|
||||
GetChartConfig(
|
||||
coordinateType,
|
||||
chartType,
|
||||
coordinateType === 'CARTESIAN' ? datasets : polarDataset,
|
||||
paginatedData
|
||||
),
|
||||
[coordinateType, chartType, datasets, polarDataset, paginatedData]
|
||||
const chartConfig = GetChartConfig(
|
||||
coordinateType,
|
||||
chartType,
|
||||
coordinateType === 'CARTESIAN' ? datasets : polarDataset,
|
||||
paginatedData
|
||||
)
|
||||
|
||||
// Translate columns in tables
|
||||
|
@ -39,7 +39,7 @@ const TIMEOUT = 8000 // 8 seconds
|
||||
* @param {number|string} id - The ID for which accounting data is to be fetched.
|
||||
* @returns {object} - Returns an object containing the processed data, loading state, and any error.
|
||||
*/
|
||||
export const useAccountingData = ({ user, group, id, start, end }) => {
|
||||
export const useAccountingData = ({ id, start, end }) => {
|
||||
// Create the hook to fetch data
|
||||
const [refetch, { data: fetchedData }] =
|
||||
useLazyGetAccountingPoolFilteredQuery()
|
||||
|
@ -108,20 +108,27 @@ const HostPciTab = ({ id }) => {
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Box>
|
||||
<MultiChart
|
||||
datasets={[
|
||||
{
|
||||
...transformedDataset.dataset,
|
||||
error: transformedDataset.error,
|
||||
isEmpty: transformedDataset.isEmpty,
|
||||
},
|
||||
]}
|
||||
metricNames={metricNames}
|
||||
chartType={chartType}
|
||||
ItemsPerPage={10}
|
||||
tableColumns={DataGridColumns}
|
||||
groupBy={'deviceName'}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
}}
|
||||
>
|
||||
<MultiChart
|
||||
datasets={[
|
||||
{
|
||||
...transformedDataset.dataset,
|
||||
error: transformedDataset.error,
|
||||
isEmpty: transformedDataset.isEmpty,
|
||||
},
|
||||
]}
|
||||
metricNames={metricNames}
|
||||
chartType={chartType}
|
||||
ItemsPerPage={10}
|
||||
tableColumns={DataGridColumns}
|
||||
groupBy={'deviceName'}
|
||||
/>
|
||||
</Box>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
import PropTypes from 'prop-types'
|
||||
import { useState, useMemo } from 'react'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { Box, Card, CardContent, Grid, Typography } from '@mui/material'
|
||||
import { MultiChart } from 'client/components/Charts'
|
||||
import { transformApiResponseToDataset } from 'client/components/Charts/MultiChart/helpers/scripts'
|
||||
@ -50,17 +50,23 @@ const generateQuotasInfoTab = ({ groups }) => {
|
||||
|
||||
const apiData = queryInfo?.data || {}
|
||||
|
||||
useMemo(() => {
|
||||
useEffect(() => {
|
||||
if (datastoresResponse.isSuccess && datastoresResponse.data) {
|
||||
setDsNameMap(nameMapper(datastoresResponse))
|
||||
}
|
||||
}, [datastoresResponse])
|
||||
|
||||
useEffect(() => {
|
||||
if (networksResponse.isSuccess && networksResponse.data) {
|
||||
setNetNameMap(nameMapper(networksResponse))
|
||||
}
|
||||
}, [networksResponse])
|
||||
|
||||
useEffect(() => {
|
||||
if (imagesResponse.isSuccess && imagesResponse.data) {
|
||||
setImgNameMap(nameMapper(imagesResponse))
|
||||
}
|
||||
}, [datastoresResponse, networksResponse, imagesResponse])
|
||||
}, [imagesResponse])
|
||||
|
||||
const nameMaps = {
|
||||
DATASTORE: dsNameMap,
|
||||
@ -207,7 +213,7 @@ const generateQuotasInfoTab = ({ groups }) => {
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
height: '100%',
|
||||
height: '100vh',
|
||||
minWidth: '300px',
|
||||
minHeight: '600px',
|
||||
}}
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
import PropTypes from 'prop-types'
|
||||
import { ReactElement, useMemo, useState } from 'react'
|
||||
import { ReactElement, useState } from 'react'
|
||||
|
||||
import {
|
||||
Fade,
|
||||
@ -87,49 +87,34 @@ const Tabs = ({
|
||||
}) => {
|
||||
const [tabSelected, setTab] = useState(() => 0)
|
||||
|
||||
const renderTabs = useMemo(
|
||||
() => (
|
||||
<MTabs
|
||||
value={tabSelected}
|
||||
variant="scrollable"
|
||||
allowScrollButtonsMobile
|
||||
scrollButtons="auto"
|
||||
onChange={(_, tab) => setTab(tab)}
|
||||
sx={{
|
||||
position: 'sticky',
|
||||
top: 0,
|
||||
zIndex: ({ zIndex }) => zIndex.appBar,
|
||||
...sx,
|
||||
}}
|
||||
{...tabsProps}
|
||||
>
|
||||
{tabs.map(
|
||||
({ value, name, id = name, label, error, icon: Icon }, idx) => (
|
||||
<MTab
|
||||
key={`tab-${id}`}
|
||||
id={`tab-${id}`}
|
||||
iconPosition="start"
|
||||
icon={error ? <WarningIcon /> : Icon && <Icon />}
|
||||
value={value ?? idx}
|
||||
label={Tr(label) ?? id}
|
||||
data-cy={`tab-${id}`}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</MTabs>
|
||||
),
|
||||
[tabs, tabSelected]
|
||||
)
|
||||
|
||||
const renderAllHiddenTabContents = useMemo(
|
||||
() =>
|
||||
tabs.map((tabProps, idx) => {
|
||||
const { name, value = idx } = tabProps
|
||||
const hidden = tabSelected !== value
|
||||
|
||||
return <Content key={`tab-${name}`} {...tabProps} hidden={hidden} />
|
||||
}),
|
||||
[tabSelected]
|
||||
// Removed memoization, might need to optimize later
|
||||
const renderTabs = (
|
||||
<MTabs
|
||||
value={tabSelected}
|
||||
variant="scrollable"
|
||||
allowScrollButtonsMobile
|
||||
scrollButtons="auto"
|
||||
onChange={(_, tab) => setTab(tab)}
|
||||
sx={{
|
||||
position: 'sticky',
|
||||
top: 0,
|
||||
zIndex: ({ zIndex }) => zIndex.appBar,
|
||||
...sx,
|
||||
}}
|
||||
{...tabsProps}
|
||||
>
|
||||
{tabs.map(({ value, name, id = name, label, error, icon: Icon }, idx) => (
|
||||
<MTab
|
||||
key={`tab-${id}`}
|
||||
id={`tab-${id}`}
|
||||
iconPosition="start"
|
||||
icon={error ? <WarningIcon /> : Icon && <Icon />}
|
||||
value={value ?? idx}
|
||||
label={Tr(label) ?? id}
|
||||
data-cy={`tab-${id}`}
|
||||
/>
|
||||
))}
|
||||
</MTabs>
|
||||
)
|
||||
|
||||
const logTabId = tabs
|
||||
@ -144,7 +129,12 @@ const Tabs = ({
|
||||
{renderTabs}
|
||||
</Fade>
|
||||
{renderHiddenTabs ? (
|
||||
renderAllHiddenTabContents
|
||||
tabs.map((tabProps, idx) => {
|
||||
const { name, value = idx } = tabProps
|
||||
const hidden = tabSelected !== value
|
||||
|
||||
return <Content key={`tab-${name}`} {...tabProps} hidden={hidden} />
|
||||
})
|
||||
) : (
|
||||
<Content
|
||||
addBorder={addBorder}
|
||||
|
@ -41,28 +41,26 @@ const DialogInfo = ({ info, handleClose }) => {
|
||||
const [tabSelected, setTab] = useState(0)
|
||||
const { name } = info?.TEMPLATE?.BODY
|
||||
|
||||
const renderTabs = useMemo(
|
||||
() => (
|
||||
<AppBar position="static">
|
||||
<Tabs
|
||||
value={tabSelected}
|
||||
variant="scrollable"
|
||||
scrollButtons="auto"
|
||||
onChange={(_, tab) => setTab(tab)}
|
||||
>
|
||||
{TABS.map(({ name: tabName, icon: Icon }, idx) => (
|
||||
<Tab
|
||||
key={`tab-${tabName}`}
|
||||
id={`tab-${tabName}`}
|
||||
icon={<Icon />}
|
||||
value={idx}
|
||||
label={String(tabName).toUpperCase()}
|
||||
/>
|
||||
))}
|
||||
</Tabs>
|
||||
</AppBar>
|
||||
),
|
||||
[tabSelected]
|
||||
// Removed memoization, might need to optimize later
|
||||
const renderTabs = (
|
||||
<AppBar position="static">
|
||||
<Tabs
|
||||
value={tabSelected}
|
||||
variant="scrollable"
|
||||
scrollButtons="auto"
|
||||
onChange={(_, tab) => setTab(tab)}
|
||||
>
|
||||
{TABS.map(({ name: tabName, icon: Icon }, idx) => (
|
||||
<Tab
|
||||
key={`tab-${tabName}`}
|
||||
id={`tab-${tabName}`}
|
||||
icon={<Icon />}
|
||||
value={idx}
|
||||
label={String(tabName).toUpperCase()}
|
||||
/>
|
||||
))}
|
||||
</Tabs>
|
||||
</AppBar>
|
||||
)
|
||||
|
||||
return (
|
||||
|
@ -86,14 +86,17 @@ const accounting = (
|
||||
const responseData = value
|
||||
|
||||
// Filter if there is not userId and there is a groupId
|
||||
if (!userId && groupId && responseData && responseData.HISTORY_RECORDS) {
|
||||
if (responseData && responseData.HISTORY_RECORDS) {
|
||||
// Filter data by group id
|
||||
const history = Array.isArray(responseData.HISTORY_RECORDS.HISTORY)
|
||||
? responseData.HISTORY_RECORDS.HISTORY
|
||||
: [responseData.HISTORY_RECORDS.HISTORY]
|
||||
responseData.HISTORY_RECORDS.HISTORY = history.filter(
|
||||
(item) => item.VM.GID === groupId
|
||||
)
|
||||
|
||||
if (!userId && groupId) {
|
||||
responseData.HISTORY_RECORDS.HISTORY = history.filter(
|
||||
(item) => item.VM.GID === groupId
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Return response
|
||||
|
Loading…
x
Reference in New Issue
Block a user