-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Added resources component * Added resources popup with details * Added resources args * Added links to docs * Added links to docs * Fix and merge * Cleanup * Removed popup * Adjusted cpu resources * Adjusted cpu resources
- Loading branch information
Showing
6 changed files
with
249 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
import { Icon, Tooltip, Typography } from '@equinor/eds-core-react'; | ||
import { library_books } from '@equinor/eds-icons'; | ||
import * as PropTypes from 'prop-types'; | ||
import type { FunctionComponent } from 'react'; | ||
import { externalUrls } from '../../externalUrls'; | ||
import { | ||
type GetResourcesApiResponse, | ||
useGetResourcesQuery, | ||
} from '../../store/radix-api'; | ||
import { formatDateTimeYear } from '../../utils/datetime'; | ||
import AsyncResource from '../async-resource/async-resource'; | ||
|
||
import './style.css'; | ||
|
||
function getPeriod({ from, to }: GetResourcesApiResponse): string { | ||
return `${formatDateTimeYear(new Date(from))} - ${formatDateTimeYear( | ||
new Date(to) | ||
)}`; | ||
} | ||
|
||
export interface UsedResourcesProps { | ||
appName: string; | ||
} | ||
|
||
export const UsedResources: FunctionComponent<UsedResourcesProps> = ({ | ||
appName, | ||
}) => { | ||
const { data: resources, ...state } = useGetResourcesQuery( | ||
{ appName }, | ||
{ skip: !appName } | ||
); | ||
const formatCpuUsage = (value?: number): string => { | ||
if (!value) { | ||
return '-'; | ||
} | ||
if (value >= 1) { | ||
return parseFloat(value.toPrecision(3)).toString(); | ||
} | ||
|
||
const millicores = value * 1000.0; | ||
let formattedValue: string; | ||
if (millicores >= 1.0) { | ||
formattedValue = parseFloat(millicores.toPrecision(3)).toString(); | ||
return `${formattedValue}m`; | ||
} | ||
let mcStr = millicores.toFixed(20); // Use 20 decimal places to ensure precision | ||
mcStr = mcStr.replace(/0+$/, ''); | ||
// Find the position of the decimal point | ||
const decimalIndex = mcStr.indexOf('.'); | ||
// Find the index of the first non-zero digit after the decimal point | ||
let firstNonZeroIndex = -1; | ||
for (let i = decimalIndex + 1; i < mcStr.length; i++) { | ||
if (mcStr[i] !== '0') { | ||
firstNonZeroIndex = i; | ||
break; | ||
} | ||
} | ||
if (firstNonZeroIndex === -1) { | ||
return '0m'; | ||
} | ||
// Create a new number where the digit at firstNonZeroIndex becomes the first decimal digit | ||
const digits = `0.${mcStr.substring(firstNonZeroIndex)}`; | ||
let num = parseFloat(digits); | ||
// Round the number to one digit | ||
num = Math.round(num * 10) / 10; | ||
// Handle rounding that results in num >= 1 | ||
if (num >= 1) { | ||
num = 1; | ||
} | ||
let numStr = num.toString(); | ||
// Remove the decimal point and any following zeros | ||
numStr = numStr.replace('0.', '').replace(/0+$/, ''); | ||
// Replace the part of mcStr starting from firstNonZeroIndex - 1 | ||
let zerosCount = firstNonZeroIndex - decimalIndex - 1; | ||
// Adjust zerosCount, when num is 1 | ||
if (num === 1) { | ||
zerosCount -= 1; | ||
} | ||
const leadingDigitalZeros = '0'.repeat(Math.max(zerosCount, 0)); | ||
const output = `0.${leadingDigitalZeros}${numStr}`; | ||
return `${output}m`; | ||
}; | ||
|
||
const formatMemoryUsage = (value?: number): string => { | ||
if (!value) { | ||
return '-'; | ||
} | ||
const units = [ | ||
{ unit: 'P', size: 1e15 }, | ||
{ unit: 'T', size: 1e12 }, | ||
{ unit: 'G', size: 1e9 }, | ||
{ unit: 'M', size: 1e6 }, | ||
{ unit: 'k', size: 1e3 }, | ||
]; | ||
|
||
let unit = ''; // Default to bytes | ||
|
||
// Determine the appropriate unit | ||
for (const u of units) { | ||
if (value >= u.size) { | ||
value = value / u.size; | ||
unit = u.unit; | ||
break; | ||
} | ||
} | ||
const formattedValue = parseFloat(value.toPrecision(3)).toString(); | ||
return formattedValue + unit; | ||
}; | ||
|
||
return ( | ||
<div className="grid grid--gap-medium"> | ||
<div className="grid grid--gap-medium grid--auto-columns"> | ||
<Typography variant="h6"> Used resources</Typography> | ||
<Typography | ||
link | ||
href={externalUrls.resourcesDocs} | ||
rel="noopener noreferrer" | ||
> | ||
<Tooltip title="Read more in the documentation"> | ||
<Icon data={library_books} /> | ||
</Tooltip> | ||
</Typography> | ||
</div> | ||
<AsyncResource asyncState={state}> | ||
{resources ? ( | ||
<div className="resources-section grid grid--gap-medium"> | ||
<div className="grid grid--gap-small"> | ||
<Typography variant="overline">Period</Typography> | ||
<Typography group="input" variant="text"> | ||
{getPeriod(resources)} | ||
</Typography> | ||
</div> | ||
|
||
<div className="grid grid--gap-small grid--auto-columns"> | ||
<div> | ||
<Typography> | ||
CPU{' '} | ||
<strong> | ||
min {formatCpuUsage(resources?.cpu?.min)}, avg{' '} | ||
{formatCpuUsage(resources?.cpu?.avg)}, max{' '} | ||
{formatCpuUsage(resources?.cpu?.max)} | ||
</strong> | ||
</Typography> | ||
<Typography> | ||
Memory{' '} | ||
<strong> | ||
min {formatMemoryUsage(resources?.memory?.min)}, avg{' '} | ||
{formatMemoryUsage(resources?.memory?.avg)}, max{' '} | ||
{formatMemoryUsage(resources?.memory?.max)} | ||
</strong> | ||
</Typography> | ||
</div> | ||
</div> | ||
</div> | ||
) : ( | ||
<Typography variant="caption">No data</Typography> | ||
)} | ||
</AsyncResource> | ||
</div> | ||
); | ||
}; | ||
|
||
UsedResources.propTypes = { | ||
appName: PropTypes.string.isRequired, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
.resources-section > div { | ||
grid-auto-rows: min-content; | ||
} | ||
|
||
@media (min-width: 30rem) { | ||
.resources-section { | ||
grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr)); | ||
} | ||
} | ||
|
||
.icon-justify-end { | ||
justify-self: end; | ||
} | ||
|
||
.resources__scrim .resources__scrim-content { | ||
margin: var(--eds_spacing_medium); | ||
margin-top: initial; | ||
align-content: center; | ||
min-width: 500px; | ||
} | ||
|
||
.resources-content { | ||
padding: var(--eds_spacing_medium); | ||
padding-top: 0; | ||
overflow: auto; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters