1
0
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:
vichansson 2024-06-24 19:14:19 +03:00 committed by GitHub
parent b1ef325389
commit 81fc9f1ae0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 102 additions and 104 deletions

View File

@ -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

View File

@ -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()

View File

@ -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>
</>
)
}

View File

@ -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',
}}

View File

@ -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}

View File

@ -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 (

View File

@ -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