Skip to content

Commit

Permalink
Merge pull request #1469 from weirdwiz/master
Browse files Browse the repository at this point in the history
support negative values in humanizeBinaryBytes
  • Loading branch information
openshift-merge-bot[bot] authored Jul 23, 2024
2 parents 82df1de + 7c65ce7 commit e4d70c8
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 32 deletions.
9 changes: 5 additions & 4 deletions locales/en/plugin__odf-console.json
Original file line number Diff line number Diff line change
Expand Up @@ -559,14 +559,15 @@
"Select a namespace:": "Select a namespace:",
"Only showing PVCs that are being mounted on an active pod": "Only showing PVCs that are being mounted on an active pod",
"This card shows the requested capacity for different Kubernetes resources. The figures shown represent the usable storage, meaning that data replication is not taken into consideration.": "This card shows the requested capacity for different Kubernetes resources. The figures shown represent the usable storage, meaning that data replication is not taken into consideration.",
"The {{estimationName}} is a rough estimation. The calculation is based on the data gathered on day to day basis.": "The {{estimationName}} is a rough estimation. The calculation is based on the data gathered on day to day basis.",
"<0><0>Understand terms</0><1>Net storage consumption</1><2>Indicates the daily net change in storage capacity.</2><3>Average storage consumption </3><4>Refers to the amount of data used over a specified period. A positive average indicates how quickly the cluster is filling up, while a negative average indicates the rate at which the cluster is clearing up.</4><5>Estimated days until full ** </5><6>Indicates the number of days remaining before a storage system reaches its maximum capacity based on current usage trends.</6><7>Calculations for above metrics are based on the data gathered day to day basis. **This is only a rough estimation These calculations are based on the data gathered on day to day basis</7></0>": "<0><0>Understand terms</0><1>Net storage consumption</1><2>Indicates the daily net change in storage capacity.</2><3>Average storage consumption </3><4>Refers to the amount of data used over a specified period. A positive average indicates how quickly the cluster is filling up, while a negative average indicates the rate at which the cluster is clearing up.</4><5>Estimated days until full ** </5><6>Indicates the number of days remaining before a storage system reaches its maximum capacity based on current usage trends.</6><7>Calculations for above metrics are based on the data gathered day to day basis. **This is only a rough estimation These calculations are based on the data gathered on day to day basis</7></0>",
"Consumption trend": "Consumption trend",
"Storage consumption per day": "Storage consumption per day",
"Storage consumption": "Storage consumption",
"Over the past {{daysUp}} ": "Over the past {{daysUp}} ",
"day": "day",
"Average consumption": "Average consumption",
"Net storage consumption": "Net storage consumption",
"Average storage consumption": "Average storage consumption",
"Estimated days until full": "Estimated days until full",
"number of days left": "number of days left",
"Understanding these terms": "Understanding these terms",
"Internal": "Internal",
"Raw capacity is the absolute total disk space available to the array subsystem.": "Raw capacity is the absolute total disk space available to the array subsystem.",
"Active health checks": "Active health checks",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
import { ConfigMapModel } from '@odf/shared/models';
import { ConfigMapKind } from '@odf/shared/types';
import { useCustomTranslation } from '@odf/shared/useCustomTranslationHook';
import { humanizeBinaryBytes, parser } from '@odf/shared/utils';
import { humanizeBinaryBytesWithNegatives, parser } from '@odf/shared/utils';
import { useK8sWatchResource } from '@openshift-console/dynamic-plugin-sdk';
import { TFunction } from 'i18next';
import { Trans } from 'react-i18next';
Expand All @@ -29,12 +29,14 @@ import {
CardTitle,
Flex,
FlexItem,
PopoverPosition,
Text,
TextContent,
TextVariants,
} from '@patternfly/react-core';
import {
CAPACITY_TREND_QUERIES,
CEPH_CAPACITY_BREAKDOWN_QUERIES,
StorageDashboardQuery,
} from '../../../queries/ceph-storage';
import { ODFSystemParams } from '../../../types';
Expand All @@ -50,11 +52,38 @@ const calculateDaysUp = (timespan: number): number | null => {
return Math.ceil(daysPassed); // If days passed is half a day or more, round up to the nearest whole day
};

const roughEstimationToolTip = (t: TFunction, estimationName: string) => {
const understandingToolTip = (t: TFunction) => {
return (
<Trans t={t}>
The {{ estimationName }} is a rough estimation. The calculation is based
on the data gathered on day to day basis.
<TextContent>
<Text component={TextVariants.h2}>Understand terms</Text>
<Text component={TextVariants.h4}>Net storage consumption</Text>

<Text component={TextVariants.p}>
Indicates the daily net change in storage capacity.
</Text>

<Text component={TextVariants.h4}>Average storage consumption </Text>

<Text component={TextVariants.p}>
Refers to the amount of data used over a specified period. A positive
average indicates how quickly the cluster is filling up, while a
negative average indicates the rate at which the cluster is clearing
up.
</Text>
<Text component={TextVariants.h4}>Estimated days until full ** </Text>

<Text component={TextVariants.p}>
Indicates the number of days remaining before a storage system reaches
its maximum capacity based on current usage trends.
</Text>

<Text component={TextVariants.small}>
Calculations for above metrics are based on the data gathered day to
day basis. **This is only a rough estimation These calculations are
based on the data gathered on day to day basis
</Text>
</TextContent>
</Trans>
);
};
Expand Down Expand Up @@ -115,28 +144,58 @@ const CapacityTrendCard: React.FC = () => {
basePath: usePrometheusBasePath(),
});

const loadError = availableCapacityError || totalUtilError || uptimeError;
const [totalCapacity, totalCapacityError, totalCapacityLoading] =
useCustomPrometheusPoll({
query:
CEPH_CAPACITY_BREAKDOWN_QUERIES[
StorageDashboardQuery.CEPH_CAPACITY_TOTAL
],
endpoint: 'api/v1/query' as any,
basePath: usePrometheusBasePath(),
});

const loadError =
availableCapacityError ||
totalUtilError ||
uptimeError ||
totalCapacityError;
const loading =
availableCapacityLoading || totalUtilLoading || uptimeUtilLoading;
availableCapacityLoading ||
totalUtilLoading ||
uptimeUtilLoading ||
totalCapacityLoading;

let daysUp: number;
if (!loading && !loadError) {
daysUp = calculateDaysUp(parser(uptime));
}

const totalUtilMetric = parser(totalUtil);
const totalCapacityMetric = parser(totalCapacity);
const avgUtilMetric =
!!daysUp && !!totalUtilMetric
? totalUtilMetric / Math.ceil(daysUp) // do a ceil function, if it's a new cluster (dayUp < 1)
: 0;
const avgUtilMetricByte = humanizeBinaryBytes(avgUtilMetric.toFixed(0));

const avgUtilMetricByte = humanizeBinaryBytesWithNegatives(
avgUtilMetric.toFixed(0)
);
const availableCapacityMetric = parser(availableCapacity);
const daysLeft =
let daysLeft =
!!availableCapacityMetric && avgUtilMetric
? Math.floor(availableCapacityMetric / avgUtilMetric)
: 0;

if (daysLeft < 0) {
// Clean up negative average values, if a user empties a cluster the average value goes to negative we need to make
// sure that estimated days left takes into account the average rate of filling up the cluster.
// This will give better information about estimated days
const clusterCleanUpToZeroDays =
(totalCapacityMetric - availableCapacityMetric) / Math.abs(avgUtilMetric);
const clusterFillUpToMaxDays =
totalCapacityMetric / Math.abs(avgUtilMetric);
daysLeft = clusterCleanUpToZeroDays + clusterFillUpToMaxDays;
}
return (
<Card>
<CardHeader>
Expand All @@ -149,7 +208,7 @@ const CapacityTrendCard: React.FC = () => {
<FlexItem flex={{ default: 'flex_4' }}>
<TextContent>
<Text component={TextVariants.h4}>
{t('Storage consumption per day')}
{t('Storage consumption')}
</Text>
<Text component={TextVariants.small}>
{t('Over the past {{daysUp}} ', {
Expand All @@ -160,12 +219,13 @@ const CapacityTrendCard: React.FC = () => {
</TextContent>
<PrometheusUtilizationItem
title=""
description={t('Net storage consumption')}
utilizationQuery={
CAPACITY_TREND_QUERIES(ocsCluster)[
StorageDashboardQuery.UTILIZATION_1D
]
}
humanizeValue={humanizeBinaryBytes}
humanizeValue={humanizeBinaryBytesWithNegatives}
hideHorizontalBorder={true}
hideCurrentHumanized={true}
formatDate={
Expand All @@ -176,32 +236,35 @@ const CapacityTrendCard: React.FC = () => {
: undefined
}
chartType="grouped-line"
showLegend={false}
showLegend={true}
timespan={daysUp * 24 * 60 * 60 * 1000}
showHumanizedInLegend={true}
/>
</FlexItem>
<FlexItem
flex={{ default: 'flex_1' }}
alignSelf={{ default: 'alignSelfCenter' }}
spacer={{ default: 'spacerLg' }}
>
</Flex>
<Flex justifyContent={{ default: 'justifyContentSpaceBetween' }}>
<FlexItem flex={{ default: 'flex_1' }}>
<Text component={TextVariants.h4}>
{t('Average consumption')}
{t('Average storage consumption')}
</Text>
{avgUtilMetricByte.string} / {t('day')}
{avgUtilMetricByte.string}
</FlexItem>
</Flex>
<Flex justifyContent={{ default: 'justifyContentSpaceBetween' }}>
<FlexItem flex={{ default: 'flex_1' }}>
<Text component={TextVariants.h4}>
{t('Estimated days until full')}
<FieldLevelHelp>
{roughEstimationToolTip(t, t('number of days left'))}
</FieldLevelHelp>
</Text>
{daysLeft} {pluralize(daysUp, t('day'), t('days'), false)}
</FlexItem>
</Flex>
<Flex>
<FieldLevelHelp
position={PopoverPosition.right}
buttonText={t('Understanding these terms')}
popoverHasAutoWidth
>
{understandingToolTip(t)}
</FieldLevelHelp>
</Flex>
</Flex>
)}
{loading && !loadError && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export const AreaChart: React.FC<AreaChartProps> = ({
tickCount = 4,
height = 200,
showLegend,
legendComponent,
}) => {
const [containerRef, width] = useRefWidth();

Expand Down Expand Up @@ -146,6 +147,7 @@ export const AreaChart: React.FC<AreaChartProps> = ({
padding={{ top: 20, left: 70, bottom: 60, right: 0 }}
legendData={chartType && showLegend ? legendData : null}
legendPosition="bottom-left"
legendComponent={legendComponent}
>
{xAxis && (
<ChartAxis tickCount={tickCount} tickFormat={xTickFormat} />
Expand Down Expand Up @@ -194,4 +196,5 @@ export type AreaChartProps = {
tickCount?: number;
height?: number;
showLegend?: boolean;
legendComponent?: React.ReactElement<any>;
};
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export const PrometheusUtilizationItem: React.FC<PrometheusUtilizationItemProps>
CustomUtilizationSummary,
formatDate,
timespan,
showHumanizedInLegend,
}) => {
const { duration } = useUtilizationDuration();
const defaultBasePath = usePrometheusBasePath();
Expand Down Expand Up @@ -94,6 +95,7 @@ export const PrometheusUtilizationItem: React.FC<PrometheusUtilizationItemProps>
showLegend={showLegend}
CustomUtilizationSummary={CustomUtilizationSummary}
formatDate={formatDate}
showHumanizedInLegend={showHumanizedInLegend}
/>
);
};
Expand Down Expand Up @@ -175,4 +177,5 @@ type PrometheusUtilizationItemProps = PrometheusCommonProps & {
CustomUtilizationSummary?: React.FC<CustomUtilizationSummaryProps>;
formatDate?: (date: Date, showSeconds?: boolean) => string;
timespan?: number;
showHumanizedInLegend?: boolean;
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import { ByteDataTypes } from '@openshift-console/dynamic-plugin-sdk/lib/api/internal-types';
import { global_danger_color_100 as dangerColor } from '@patternfly/react-tokens/dist/js/global_danger_color_100';
import { global_warning_color_100 as warningColor } from '@patternfly/react-tokens/dist/js/global_warning_color_100';
import { ChartThemeColor, ChartLegend } from '@patternfly/react-charts';
import { useCustomTranslation } from '../../useCustomTranslationHook';

enum LIMIT_STATE {
Expand Down Expand Up @@ -59,6 +60,7 @@ export const UtilizationItem: React.FC<UtilizationItemProps> = React.memo(
showLegend,
CustomUtilizationSummary,
formatDate,
showHumanizedInLegend,
}) => {
const { t } = useCustomTranslation();
const { data, chartStyle } = mapLimitsRequests({
Expand Down Expand Up @@ -92,6 +94,14 @@ export const UtilizationItem: React.FC<UtilizationItemProps> = React.memo(

humanAvailable = humanizeValue(max - current).string;
}
let humanizedLegend: JSX.Element;
if (!!showHumanizedInLegend && current)
humanizedLegend = (
<ChartLegend
themeColor={ChartThemeColor.purple}
data={[{ name: description + ' : ' + humanizeValue(current).string }]}
/>
);

const chart = (
<AreaChart
Expand All @@ -110,6 +120,7 @@ export const UtilizationItem: React.FC<UtilizationItemProps> = React.memo(
mainDataName="usage"
showLegend={showLegend}
formatDate={formatDate}
legendComponent={humanizedLegend}
/>
);

Expand Down Expand Up @@ -277,4 +288,5 @@ type UtilizationItemProps = {
hideHorizontalBorder?: boolean;
CustomUtilizationSummary?: React.FC<CustomUtilizationSummaryProps>;
formatDate?: (date: Date, showSeconds?: boolean) => string;
showHumanizedInLegend?: boolean;
};
4 changes: 3 additions & 1 deletion packages/shared/src/generic/FieldLevelHelp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useCustomTranslation } from '../useCustomTranslationHook';
import './field-level-help.scss';

export const FieldLevelHelp: React.FC<FieldLevelHelpProps> = React.memo(
({ children, popoverHasAutoWidth, testId, position }) => {
({ children, popoverHasAutoWidth, testId, position, buttonText }) => {
const { t } = useCustomTranslation();
if (React.Children.count(children) === 0) {
return null;
Expand All @@ -24,6 +24,7 @@ export const FieldLevelHelp: React.FC<FieldLevelHelpProps> = React.memo(
className="odf-field-level-help"
data-test-id={testId || null}
>
{!!buttonText && buttonText + ' '}
<OutlinedQuestionCircleIcon className="odf-field-level-help__icon" />
</Button>
</Popover>
Expand All @@ -38,4 +39,5 @@ type FieldLevelHelpProps = {
popoverHasAutoWidth?: PopoverProps['hasAutoWidth'];
testId?: string;
position?: PopoverProps['position'];
buttonText?: string;
};
Loading

0 comments on commit e4d70c8

Please sign in to comment.