21700: Install Bundler system-wide in Rails postinst
[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 formatCWLResourceSize = (size: number) => {
45     return `${(size / CWL_SIZE.base).toFixed(0)} ${CWL_SIZE.unit}`;
46 };
47
48 export const formatTime = (time: number, seconds?: boolean) => {
49     const minutes = Math.floor((time / (1000 * 60)) % 60).toFixed(0);
50     const hours = Math.floor(time / (1000 * 60 * 60)).toFixed(0);
51
52     if (seconds) {
53         const seconds = Math.floor((time / 1000) % 60).toFixed(0);
54         return hours + 'h ' + minutes + 'm ' + seconds + 's';
55     }
56
57     return hours + 'h ' + minutes + 'm';
58 };
59
60 export const getTimeDiff = (endTime: string, startTime: string) => {
61     return new Date(endTime).getTime() - new Date(startTime).getTime();
62 };
63
64 export const formatProgress = (loaded: number, total: number) => {
65     const progress = loaded >= 0 && total > 0 ? (loaded * 100) / total : 0;
66     return `${progress.toFixed(2)}%`;
67 };
68
69 export function formatUploadSpeed(
70     prevLoaded: number,
71     loaded: number,
72     prevTime: number,
73     currentTime: number
74 ) {
75     const speed =
76         loaded > prevLoaded && currentTime > prevTime
77             ? (loaded - prevLoaded) / (currentTime - prevTime)
78             : 0;
79
80     return `${(speed / 1000).toFixed(2)} MB/s`;
81 }
82
83 const FILE_SIZES = [
84     {
85         base: 1024 ** 4,
86         unit: 'TiB',
87     },
88     {
89         base: 1024 ** 3,
90         unit: 'GiB',
91     },
92     {
93         base: 1024 ** 2,
94         unit: 'MiB',
95     },
96     {
97         base: 1024,
98         unit: 'KiB',
99     },
100     {
101         base: 1,
102         unit: 'B',
103     },
104 ];
105
106 const CWL_SIZE = {
107     base: 1024 ** 2,
108     unit: 'MiB',
109 };
110
111 export const formatPropertyValue = (
112     pv: PropertyValue,
113     vocabulary?: Vocabulary
114 ) => {
115     if (vocabulary && pv.keyID && pv.valueID) {
116         return `${getTagKeyLabel(pv.keyID, vocabulary)}: ${getTagValueLabel(
117             pv.keyID,
118             pv.valueID!,
119             vocabulary
120         )}`;
121     }
122     if (pv.key) {
123         return pv.value ? `${pv.key}: ${pv.value}` : pv.key;
124     }
125     return '';
126 };
127
128 export const formatCost = (cost: number): string => {
129     const decimalPlaces = 3;
130
131     const factor = Math.pow(10, decimalPlaces);
132     const rounded = Math.round(cost * factor) / factor;
133     if (cost > 0 && rounded === 0) {
134         // Display min value of 0.001
135         return `$${1 / factor}`;
136     } else {
137         // Otherwise use rounded value to proper decimal places
138         return `$${rounded}`;
139     }
140 };