function.ts 8.75 KB
Newer Older
chicm-ms's avatar
chicm-ms committed
1
import * as JSON5 from 'json5';
Lijiao's avatar
Lijiao committed
2
3
import axios from 'axios';
import { MANAGER_IP } from './const';
4
import { MetricDataRecord, FinalType, TableObj } from './interface';
Lijiao's avatar
Lijiao committed
5

6
async function requestAxios(url: string): Promise<any> {
Lijiaoa's avatar
Lijiaoa committed
7
8
9
10
11
12
13
14
15
16
17
18
    const response = await axios.get(url);
    if (response.status === 200) {
        if (response.data.error !== undefined) {
            throw new Error(`API ${url} ${response.data.error}`);
        } else {
            return response.data as any;
        }
    } else {
        throw new Error(`API ${url} ${response.status} error`);
    }
}

Lijiao's avatar
Lijiao committed
19
const convertTime = (num: number): string => {
20
21
22
    if (num <= 0) {
        return '0';
    }
Lijiao's avatar
Lijiao committed
23
24
25
26
    if (num % 3600 === 0) {
        return num / 3600 + 'h';
    } else {
        const hour = Math.floor(num / 3600);
27
        const min = Math.floor((num / 60) % 60);
Lijiao's avatar
Lijiao committed
28
29
30
31
32
        return hour > 0 ? `${hour}h ${min}min` : `${min}min`;
    }
};

// trial's duration, accurate to seconds for example 10min 30s
33
34
35
36
37
38
const convertDuration = (seconds: number): string => {
    let str = '';

    const d = Math.floor(seconds / (24 * 3600));
    if (d > 0) {
        str += `${d}d `;
39
    }
40
41
42
43
44
    seconds -= d * 24 * 3600;

    const h = Math.floor(seconds / 3600);
    if (h > 0) {
        str += `${h}h `;
45
    }
46
47
48
49
50
    seconds -= h * 3600;

    const m = Math.floor(seconds / 60);
    if (m > 0) {
        str += `${m}m `;
51
    }
52
53
54
55
    seconds -= m * 60;

    if (seconds > 0) {
        str += `${Math.floor(seconds)}s`;
Lijiao's avatar
Lijiao committed
56
    }
57
    return str ? str : '0s';
Lijiao's avatar
Lijiao committed
58
59
};

60
61
62
63
64
65
66
67
68
69
70
71
// according the unit(d,h,m) to convert duration
function convertTimeAsUnit(unit: string, value: number): number {
    let divisor = 1;
    if (unit === 'h') {
        divisor = 3600;
    } else if (unit === 'm') {
        divisor = 60;
    } else {
        divisor = 24 * 3600;
    }
    return value / divisor;
}
72
function parseMetrics(metricData: string): any {
Lijiaoa's avatar
Lijiaoa committed
73
    if (metricData.includes('NaN') || metricData.includes('Infinity')) {
74
75
76
77
78
79
        return JSON5.parse(JSON5.parse(metricData));
    } else {
        return JSON.parse(JSON.parse(metricData));
    }
}

80
81
const isArrayType = (list: any): boolean | undefined => {
    return Array.isArray(list);
82
};
83

Lijiao's avatar
Lijiao committed
84
// get final result value
85
// draw Accuracy point graph
Lijiao's avatar
Lijiao committed
86
const getFinalResult = (final?: MetricDataRecord[]): number => {
Lijiao's avatar
Lijiao committed
87
88
89
    let acc;
    let showDefault = 0;
    if (final) {
90
        acc = parseMetrics(final[final.length - 1].data);
91
        if (typeof acc === 'object' && !isArrayType(acc)) {
Lijiao's avatar
Lijiao committed
92
93
94
            if (acc.default) {
                showDefault = acc.default;
            }
95
        } else if (typeof acc === 'number') {
Lijiao's avatar
Lijiao committed
96
            showDefault = acc;
97
98
        } else {
            showDefault = NaN;
Lijiao's avatar
Lijiao committed
99
100
101
102
103
104
        }
        return showDefault;
    } else {
        return 0;
    }
};
105

Lijiaoa's avatar
Lijiaoa committed
106
107
108
109
function isNaNorInfinity(val: number): boolean {
    return Object.is(val, NaN) || Object.is(val, Infinity);
}

110
// get final result value // acc obj
111
const getFinal = (final?: MetricDataRecord[]): FinalType | undefined => {
112
113
    let showDefault: FinalType;
    if (final) {
114
        showDefault = parseMetrics(final[final.length - 1].data);
115
        if (typeof showDefault === 'number') {
116
            if (!isNaNorInfinity(showDefault)) {
Lijiaoa's avatar
Lijiaoa committed
117
                return { default: showDefault };
118
            }
119
120
121
122
123
        } else if (isArrayType(showDefault)) {
            // not support final type
            return undefined;
        } else if (typeof showDefault === 'object' && showDefault.hasOwnProperty('default')) {
            return showDefault;
124
125
126
127
128
129
        }
    } else {
        return undefined;
    }
};

Lijiao's avatar
Lijiao committed
130
// detail page table intermediate button
Lijiao's avatar
Lijiao committed
131
const intermediateGraphOption = (intermediateArr: number[], id: string): any => {
Lijiao's avatar
Lijiao committed
132
133
134
135
136
137
138
139
140
141
142
    const sequence: number[] = [];
    const lengthInter = intermediateArr.length;
    for (let i = 1; i <= lengthInter; i++) {
        sequence.push(i);
    }
    return {
        title: {
            text: id,
            left: 'center',
            textStyle: {
                fontSize: 16,
143
                color: '#333'
Lijiao's avatar
Lijiao committed
144
145
146
147
148
149
            }
        },
        tooltip: {
            trigger: 'item'
        },
        xAxis: {
150
            // name: '#Intermediate result',
Lijiao's avatar
Lijiao committed
151
152
153
            data: sequence
        },
        yAxis: {
Lijiao's avatar
Lijiao committed
154
            name: 'Default metric',
Lijiao's avatar
Lijiao committed
155
            type: 'value',
Lijiaoa's avatar
Lijiaoa committed
156
157
            data: intermediateArr,
            scale: true
Lijiao's avatar
Lijiao committed
158
        },
159
160
161
162
163
164
165
        series: [
            {
                symbolSize: 6,
                type: 'scatter',
                data: intermediateArr
            }
        ]
Lijiao's avatar
Lijiao committed
166
167
168
169
    };
};

// kill job
Lijiao's avatar
Lijiao committed
170
const killJob = (key: number, id: string, status: string, updateList?: Function): void => {
Lijiao's avatar
Lijiao committed
171
172
173
174
175
176
177
178
    axios(`${MANAGER_IP}/trial-jobs/${id}`, {
        method: 'DELETE',
        headers: {
            'Content-Type': 'application/json;charset=utf-8'
        }
    })
        .then(res => {
            if (res.status === 200) {
179
180
                // TODO: use Message.txt to tooltip
                alert('Cancel the job successfully');
Lijiao's avatar
Lijiao committed
181
                // render the table
182
                if (updateList) {
183
                    updateList(); // FIXME
184
                }
Lijiao's avatar
Lijiao committed
185
            } else {
186
                alert('fail to cancel the job');
Lijiao's avatar
Lijiao committed
187
188
189
190
191
            }
        })
        .catch(error => {
            if (error.response.status === 500) {
                if (error.response.data.error) {
Lijiaoa's avatar
Lijiaoa committed
192
                    alert(error.response.data.error);
Lijiao's avatar
Lijiao committed
193
                } else {
Lijiaoa's avatar
Lijiaoa committed
194
                    alert('500 error, fail to cancel the job');
Lijiao's avatar
Lijiao committed
195
196
197
198
199
                }
            }
        });
};

200
const filterByStatus = (item: TableObj): boolean => {
201
202
203
    return item.status === 'SUCCEEDED';
};

204
// a waittiong trial may havn't start time
205
const filterDuration = (item: TableObj): boolean => {
206
207
208
    return item.status !== 'WAITING';
};

Lijiao's avatar
Lijiao committed
209
const downFile = (content: string, fileName: string): void => {
v-liguo's avatar
v-liguo committed
210
211
212
213
214
215
216
217
218
219
220
    const aTag = document.createElement('a');
    const isEdge = navigator.userAgent.indexOf('Edge') !== -1 ? true : false;
    const file = new Blob([content], { type: 'application/json' });
    aTag.download = fileName;
    aTag.href = URL.createObjectURL(file);
    aTag.click();
    if (!isEdge) {
        URL.revokeObjectURL(aTag.href);
    }
    if (navigator.userAgent.indexOf('Firefox') > -1) {
        const downTag = document.createElement('a');
221
        downTag.addEventListener('click', function() {
v-liguo's avatar
v-liguo committed
222
223
224
            downTag.download = fileName;
            downTag.href = URL.createObjectURL(file);
        });
chicm-ms's avatar
chicm-ms committed
225
        const eventMouse = document.createEvent('MouseEvents');
v-liguo's avatar
v-liguo committed
226
227
228
229
230
        eventMouse.initEvent('click', false, false);
        downTag.dispatchEvent(eventMouse);
    }
};

231
232
233
234
235
// function formatTimestamp(timestamp?: number, placeholder?: string = 'N/A'): string {
function formatTimestamp(timestamp?: number, placeholder?: string): string {
    if (placeholder === undefined) {
        placeholder = 'N/A';
    }
236
237
238
239
    return timestamp ? new Date(timestamp).toLocaleString('en-US') : placeholder;
}

function metricAccuracy(metric: MetricDataRecord): number {
chicm-ms's avatar
chicm-ms committed
240
    const data = parseMetrics(metric.data);
241
242
243
244
245
246
    // return typeof data === 'number' ? data : NaN;
    if (typeof data === 'number') {
        return data;
    } else {
        return data.default;
    }
247
248
249
250
}

function formatAccuracy(accuracy: number): string {
    // TODO: how to format NaN?
251
252
253
254
    return accuracy
        .toFixed(6)
        .replace(/0+$/, '')
        .replace(/\.$/, '');
255
256
}

Lijiaoa's avatar
Lijiaoa committed
257
258
259
260
261
262
263
264
function formatComplexTypeValue(value: any): string | number {
    if (['number', 'string'].includes(typeof value)) {
        return value;
    } else {
        return value.toString();
    }
}

265
266
267
268
269
270
271
function caclMonacoEditorHeight(height): number {
    // [Search space 56px] + [marginBottom 18px] +
    // button[height: 32px, marginTop: 45px, marginBottom: 7px]
    // panel own padding-bottom: 20px;
    return height - 178;
}

272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
function copyAndSort<T>(items: T[], columnKey: string, isSortedDescending?: boolean): any {
    const key = columnKey as keyof T;
    return items.slice(0).sort(function(a: T, b: T): any {
        if (
            a[key] === undefined ||
            Object.is(a[key], NaN) ||
            Object.is(a[key], Infinity) ||
            Object.is(a[key], -Infinity) ||
            typeof a[key] === 'object'
        ) {
            return 1;
        }
        if (
            b[key] === undefined ||
            Object.is(b[key], NaN) ||
            Object.is(b[key], Infinity) ||
            Object.is(b[key], -Infinity) ||
            typeof b[key] === 'object'
        ) {
            return -1;
        }
        return (isSortedDescending ? a[key] < b[key] : a[key] > b[key]) ? 1 : -1;
    });
}
296
export {
297
298
    convertTime,
    convertDuration,
299
    convertTimeAsUnit,
300
301
302
303
304
305
306
307
308
309
310
311
312
313
    getFinalResult,
    getFinal,
    downFile,
    intermediateGraphOption,
    killJob,
    filterByStatus,
    filterDuration,
    formatAccuracy,
    formatTimestamp,
    metricAccuracy,
    parseMetrics,
    isArrayType,
    requestAxios,
    isNaNorInfinity,
314
    formatComplexTypeValue,
315
316
    caclMonacoEditorHeight,
    copyAndSort
317
};