Skip to content

Commit

Permalink
HOSTSD-276 Storage trend size type
Browse files Browse the repository at this point in the history
  • Loading branch information
Fosol committed Mar 21, 2024
1 parent 508c8ac commit 071b9e3
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 42 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client';

import { DateRangePicker } from '@/components';
import { IServerItemListModel } from '@/hooks';
import { useDashboard } from '@/hooks/dashboard';
import { useStorageTrendsStore } from '@/store';
import {
Expand Down Expand Up @@ -31,8 +32,13 @@ interface LineChartProps {
loading?: boolean;
/** Date range selected for the filter. */
dateRange?: string[];
/** An array of server items */
serverItems?: IServerItemListModel[];
/** Whether to show the export button. */
showExport?: boolean;
/** Whether the export button is disabled. */
exportDisabled?: boolean;
/** Event fires when export button is clicked. */
onExport?: (startDate?: string, endDate?: string) => void;
}

Expand All @@ -46,6 +52,7 @@ export const StorageTrendsChart: React.FC<LineChartProps> = ({
loading,
minColumns,
dateRange: initDateRange,
serverItems = [],
showExport,
exportDisabled,
onExport,
Expand All @@ -56,6 +63,8 @@ export const StorageTrendsChart: React.FC<LineChartProps> = ({
const { isReady: serverHistoryItemsIsReady, findServerHistoryItems } = useServerHistoryItems();
const { tenantId, organizationId, operatingSystemItemId, serverItemKey } = useDashboard();

const [forceFetch, setForceFetch] = React.useState(0);

React.useEffect(() => {
const values = [
initDateRange?.length && initDateRange[0]
Expand All @@ -68,22 +77,29 @@ export const StorageTrendsChart: React.FC<LineChartProps> = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [initDateRange?.[0], initDateRange?.[1], setDateRange]);

const fetch = React.useCallback(
(startDate?: string, endDate?: string) => {
if (startDate) {
// A single server was selected, fetch the history for this server.
return findServerHistoryItems({
tenantId: tenantId,
organizationId: organizationId,
operatingSystemItemId: operatingSystemItemId,
serviceNowKey: serverItemKey,
startDate: startDate,
endDate: endDate ? endDate : undefined,
}).catch((ex) => {
const error = ex as Error;
toast.error(error.message);
console.error(error);
});
}
},
[findServerHistoryItems, operatingSystemItemId, organizationId, serverItemKey, tenantId],
);

React.useEffect(() => {
if (dateRange[0]) {
// A single server was selected, fetch the history for this server.
findServerHistoryItems({
tenantId: tenantId,
organizationId: organizationId,
operatingSystemItemId: operatingSystemItemId,
serviceNowKey: serverItemKey,
startDate: dateRange[0],
endDate: dateRange[1] ? dateRange[1] : undefined,
}).catch((ex) => {
const error = ex as Error;
toast.error(error.message);
console.error(error);
});
}
fetch(dateRange[0], dateRange[1])?.catch(() => {});
// Values array will cause infinite loop, we're only interested in when values change.
// findServerHistoryItems will cause infinite loop.
// eslint-disable-next-line react-hooks/exhaustive-deps
Expand All @@ -97,11 +113,12 @@ export const StorageTrendsChart: React.FC<LineChartProps> = ({
dateRange[0],
// eslint-disable-next-line react-hooks/exhaustive-deps
dateRange[1],
forceFetch,
]);

return (
<LineChart
data={getStorageTrendsData(minColumns, dateRange)}
data={getStorageTrendsData(minColumns, dateRange, serverItems)}
label="Storage Trends"
loading={loading || !serverHistoryItemsIsReady}
large={large}
Expand All @@ -115,8 +132,9 @@ export const StorageTrendsChart: React.FC<LineChartProps> = ({
<div className={styles.date}>
<DateRangePicker
values={dateRange}
onChange={async (values, e) => {
setDateRange(values);
onChange={(values, e) => {
if (values[0] !== dateRange[0] || values[1] !== dateRange[1]) setDateRange(values);
else setForceFetch(Date.now());
}}
showButton
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { IServerHistoryItemModel } from '@/hooks';
import { IServerHistoryItemModel, IServerItemListModel } from '@/hooks';
import { useStorageTrendsStore } from '@/store';
import { convertToStorageSize } from '@/utils';
import { ChartData } from 'chart.js';
import moment from 'moment';
import React from 'react';
import { generateStorageHistoryForDateRange } from '../../utils';
import { convertStorageSize } from './../../../../utils/convertToStorageSize';

/**
* Generates line chart data based on the current filtered server history items.
Expand All @@ -14,13 +15,25 @@ import { generateStorageHistoryForDateRange } from '../../utils';
export const useStorageTrendsData = (): ((
minColumns?: number,
dateRange?: string[],
serverItems?: IServerItemListModel[],
) => ChartData<'line', number[], string>) => {
const serverHistoryItems = useStorageTrendsStore((state) => state.serverHistoryItems);

return React.useCallback(
(minColumns: number = 1, dateRange: string[] = []) => {
(
minColumns: number = 1,
dateRange: string[] = [],
serverItems: IServerItemListModel[] = [],
) => {
const groups = generateStorageHistoryForDateRange(minColumns, dateRange);

// Determine the output size type to use based on the current total storage of the selected servers.
const storageSizeType = convertStorageSize(
serverItems.map((i) => i.capacity ?? 0).reduce((a, b) => a + b, 0),
'B',
'TB',
).type;

// server history is returned for each server, however some servers may lack history.
// This process needs to group each month.
const items = serverHistoryItems
Expand Down Expand Up @@ -49,15 +62,15 @@ export const useStorageTrendsData = (): ((
.map((i) => i.capacity)
.reduce((result, value) => (result ?? 0) + (value ?? 0), 0) ?? 0,
'B',
'TB',
storageSizeType,
{ type: 'number' },
);
group.availableSpace = convertToStorageSize<number>(
values
.map((i) => i.availableSpace)
.reduce((result, value) => (result ?? 0) + (value ?? 0), 0) ?? 0,
'B',
'TB',
storageSizeType,
{ type: 'number' },
);
group.usedSpace = group.capacity - group.availableSpace;
Expand All @@ -67,14 +80,14 @@ export const useStorageTrendsData = (): ((
labels: groups.map((i) => i.label),
datasets: [
{
label: 'Total Used in TB',
label: `Total Used in ${storageSizeType}`,
data: groups.map((i) => i.usedSpace),
borderColor: '#313132',
backgroundColor: '#313132',
fill: false,
},
{
label: 'Total Allocated in TB',
label: `Total Allocated in ${storageSizeType}`,
data: groups.map((i) => i.capacity),
borderColor: '#476E94',
backgroundColor: '#476E94',
Expand Down
18 changes: 7 additions & 11 deletions src/dashboard/src/components/dashboard/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ export const Dashboard = () => {
}}
showExport
onExport={async () => {
const toastLoading = toast.loading("Generating Excel document...");
const toastLoading = toast.loading('Generating Excel document...');

try {
await download({
Expand All @@ -214,7 +214,6 @@ export const Dashboard = () => {
});
toast.dismiss(toastLoading);
toast.success('Excel document has been downloaded successfully.');

} catch (ex) {
toast.dismiss(toastLoading);

Expand All @@ -237,15 +236,14 @@ export const Dashboard = () => {
loading={!isReadyOrganizations || !isReadyServerItems}
showExport
onExport={async () => {
const toastLoading = toast.loading("Generating Excel document...");
const toastLoading = toast.loading('Generating Excel document...');

try {
await download({
tenantId: dashboardTenant?.id,
});
toast.dismiss(toastLoading);
toast.success('Excel document has been downloaded successfully.');

} catch (ex) {
toast.dismiss(toastLoading);

Expand All @@ -258,9 +256,10 @@ export const Dashboard = () => {
)}
<StorageTrendsChart
large={!!dashboardOrganization || !!dashboardOperatingSystemItem || !!dashboardServerItem}
serverItems={dashboardServerItem ? [dashboardServerItem] : dashboardServerItems}
showExport
onExport={async (startDate, endDate) => {
const toastLoading = toast.loading("Generating Excel document...");
const toastLoading = toast.loading('Generating Excel document...');

try {
await downloadHistory({
Expand All @@ -273,7 +272,6 @@ export const Dashboard = () => {
});
toast.dismiss(toastLoading);
toast.success('Excel document has been downloaded successfully.');

} catch (ex) {
toast.dismiss(toastLoading);

Expand Down Expand Up @@ -365,7 +363,7 @@ export const Dashboard = () => {
}
}}
onExport={async (search) => {
const toastLoading = toast.loading("Generating Excel document...");
const toastLoading = toast.loading('Generating Excel document...');

try {
await download({
Expand All @@ -374,7 +372,6 @@ export const Dashboard = () => {
});
toast.dismiss(toastLoading);
toast.success('Excel document has been downloaded successfully.');

} catch (ex) {
toast.dismiss(toastLoading);

Expand Down Expand Up @@ -403,7 +400,7 @@ export const Dashboard = () => {
}}
showExport
onExport={async (search) => {
const toastLoading = toast.loading("Generating Excel document...");
const toastLoading = toast.loading('Generating Excel document...');

try {
await download({
Expand All @@ -414,10 +411,9 @@ export const Dashboard = () => {
});
toast.dismiss(toastLoading);
toast.success('Excel document has been downloaded successfully.');

} catch (ex) {
toast.dismiss(toastLoading);

const error = ex as Error;
toast.error('Failed to download data. ' + error.message);
console.error(error);
Expand Down
38 changes: 31 additions & 7 deletions src/dashboard/src/utils/convertToStorageSize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* @param options Configuration options.
* @returns A string representing the storage size.
*/
export const convertToStorageSize = <T extends string | number>(
export const convertStorageSize = <T extends string | number>(
value: number,
input: 'TB' | 'GB' | 'MB' | 'KB' | 'B' | '' = '',
output: 'TB' | 'GB' | 'MB' | 'KB' | 'B' | '' = '',
Expand All @@ -17,7 +17,7 @@ export const convertToStorageSize = <T extends string | number>(
locales?: Intl.LocalesArgument;
} & Intl.NumberFormatOptions)
| undefined,
): T => {
): { value: T; type: 'TB' | 'GB' | 'MB' | 'KB' | 'B' | '' } => {
var result = value;
if (input === output) result = value;
else if (input === 'TB') {
Expand Down Expand Up @@ -65,13 +65,37 @@ export const convertToStorageSize = <T extends string | number>(
}
result = options?.formula?.(result) ?? result;

return { value: result as T, type: output };
};

/**
* Converts a storage value to a specified size type.
* @param value The initial value to convert.
* @param input The input size type.
* @param output The output size type.
* @param options Configuration options.
* @returns A string representing the storage size.
*/
export const convertToStorageSize = <T extends string | number>(
value: number,
input: 'TB' | 'GB' | 'MB' | 'KB' | 'B' | '' = '',
output: 'TB' | 'GB' | 'MB' | 'KB' | 'B' | '' = '',
options?:
| ({
formula?: (value: number) => number;
type?: 'string' | 'number';
locales?: Intl.LocalesArgument;
} & Intl.NumberFormatOptions)
| undefined,
): T => {
const result = convertStorageSize<T>(value, input, output, options);

return (
options?.type === 'number'
? result
: `${result.toLocaleString(
options?.locales ?? navigator.language,
options,
)} ${output}`.trimEnd()
? result.value
: `${result.value.toLocaleString(options?.locales ?? navigator.language, options)} ${
result.type
}`.trimEnd()
) as T;
};

Expand Down

0 comments on commit 071b9e3

Please sign in to comment.