21126: Merge branch 'main' into 21126-trash-when-ro
[arvados.git] / services / workbench2 / src / common / formatters.ts
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import { PropertyValue } from 'models/search-bar';
6 import {
7     Vocabulary,
8     getTagKeyLabel,
9     getTagValueLabel,
10 } from 'models/vocabulary';
11
12 export const formatDate = (isoDate?: string | null, utc: boolean = false) => {
13     if (isoDate) {
14         const date = new Date(isoDate);
15         let text: string;
16         if (utc) {
17             text = date.toUTCString();
18         } else {
19             text = date.toLocaleString();
20         }
21         return text === 'Invalid Date' ? '(none)' : text;
22     }
23     return '-';
24 };
25
26 export const formatFileSize = (size?: number | string) => {
27     if (typeof size === 'number') {
28         if (size === 0) {
29             return '0 B';
30         }
31
32         for (const { base, unit } of FILE_SIZES) {
33             if (size >= base) {
34                 return `${(size / base).toFixed(base === 1 ? 0 : 1)} ${unit}`;
35             }
36         }
37     }
38     if ((typeof size === 'string' && size === '') || size === undefined) {
39         return '-';
40     }
41     return '0 B';
42 };
43
44 export const formatTime = (time: number, seconds?: boolean) => {
45     const minutes = Math.floor((time / (1000 * 60)) % 60).toFixed(0);
46     const hours = Math.floor(time / (1000 * 60 * 60)).toFixed(0);
47
48     if (seconds) {
49         const seconds = Math.floor((time / 1000) % 60).toFixed(0);
50         return hours + 'h ' + minutes + 'm ' + seconds + 's';
51     }
52
53     return hours + 'h ' + minutes + 'm';
54 };
55
56 export const getTimeDiff = (endTime: string, startTime: string) => {
57     return new Date(endTime).getTime() - new Date(startTime).getTime();
58 };
59
60 export const formatProgress = (loaded: number, total: number) => {
61     const progress = loaded >= 0 && total > 0 ? (loaded * 100) / total : 0;
62     return `${progress.toFixed(2)}%`;
63 };
64
65 export function formatUploadSpeed(
66     prevLoaded: number,
67     loaded: number,
68     prevTime: number,
69     currentTime: number
70 ) {
71     const speed =
72         loaded > prevLoaded && currentTime > prevTime
73             ? (loaded - prevLoaded) / (currentTime - prevTime)
74             : 0;
75
76     return `${(speed / 1000).toFixed(2)} MB/s`;
77 }
78
79 const FILE_SIZES = [
80     {
81         base: 1099511627776,
82         unit: 'TiB',
83     },
84     {
85         base: 1073741824,
86         unit: 'GiB',
87     },
88     {
89         base: 1048576,
90         unit: 'MiB',
91     },
92     {
93         base: 1024,
94         unit: 'KiB',
95     },
96     {
97         base: 1,
98         unit: 'B',
99     },
100 ];
101
102 export const formatPropertyValue = (
103     pv: PropertyValue,
104     vocabulary?: Vocabulary
105 ) => {
106     if (vocabulary && pv.keyID && pv.valueID) {
107         return `${getTagKeyLabel(pv.keyID, vocabulary)}: ${getTagValueLabel(
108             pv.keyID,
109             pv.valueID!,
110             vocabulary
111         )}`;
112     }
113     if (pv.key) {
114         return pv.value ? `${pv.key}: ${pv.value}` : pv.key;
115     }
116     return '';
117 };
118
119 export const formatContainerCost = (cost: number): string => {
120     const decimalPlaces = 3;
121
122     const factor = Math.pow(10, decimalPlaces);
123     const rounded = Math.round(cost * factor) / factor;
124     if (cost > 0 && rounded === 0) {
125         // Display min value of 0.001
126         return `$${1 / factor}`;
127     } else {
128         // Otherwise use rounded value to proper decimal places
129         return `$${rounded}`;
130     }
131 };