EditExperimentParam.tsx 9.71 KB
Newer Older
1
2
import React, { useState, useCallback, useContext } from 'react';
import axios from 'axios';
3
import { Dropdown } from '@fluentui/react';
4
import { EXPERIMENT } from '../../../static/datamodel';
5
import { toSeconds } from '../../../static/experimentConfig';
6
import { AppContext } from '../../../App';
7
import { EditExpeParamContext } from './context';
8
9
import { durationUnit } from '../overviewConst';
import { MANAGER_IP, MAX_TRIAL_NUMBERS } from '../../../static/const';
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import { Edit, CheckMark, Cancel } from '../../buttons/Icon';
import MessageInfo from '../../modals/MessageInfo';
import '../../../static/style/overview/count.scss';

const DurationInputRef = React.createRef<HTMLInputElement>();

export const EditExperimentParam = (): any => {
    const [isShowPencil, setShowPencil] = useState(true);
    const [isShowSucceedInfo, setShowSucceedInfo] = useState(false);
    const [typeInfo, setTypeInfo] = useState('');
    const [info, setInfo] = useState('');
    const showPencil = useCallback(() => {
        setShowPencil(true);
    }, []);
    const hidePencil = useCallback(() => {
        setShowPencil(false);
    }, []);
    const showSucceedInfo = useCallback(() => setShowSucceedInfo(true), []);
    const hideSucceedInfo = useCallback(() => {
        setShowSucceedInfo(false);
    }, []);
31
32
    const { title, field, editType, maxExecDuration, maxTrialNum, trialConcurrency, updateOverviewPage } =
        useContext(EditExpeParamContext);
33
    const originMaxDurationStr = EXPERIMENT.profile.params.maxExperimentDuration;
34
35
    const { maxDurationUnit, changeMaxDurationUnit } = useContext(AppContext);
    const [unit, setUnit] = useState(maxDurationUnit);
36
37
38
39
40
    let defaultVal = '';
    let editVal = '';
    if (title === 'Max duration') {
        defaultVal = maxExecDuration;
        editVal = maxExecDuration;
41
    } else if (title === MAX_TRIAL_NUMBERS) {
42
43
44
45
46
47
48
49
50
51
52
53
        defaultVal = maxTrialNum.toString();
        editVal = maxTrialNum.toString();
    } else {
        defaultVal = trialConcurrency.toString();
        editVal = trialConcurrency.toString();
    }
    const [editInputVal, setEditValInput] = useState(editVal);

    function setInputVal(event: any): void {
        setEditValInput(event.target.value);
    }

54
55
56
57
58
59
60
61
62
63
64
    function showMessageInfo(info: string, typeInfo: string): any {
        setInfo(info);
        setTypeInfo(typeInfo);
        showSucceedInfo();
        setTimeout(hideSucceedInfo, 2000);
    }

    function updateUnit(event: React.FormEvent<HTMLDivElement>, item: any): void {
        if (item !== undefined) {
            setUnit(item.key);
        }
65
66
    }

67
68
69
70
71
    function promptErrorMessage(mess: string, type: string, value: string): void {
        showMessageInfo(mess, type);
        setEditValInput(value);
    }

72
73
74
75
    async function confirmEdit(): Promise<void> {
        const isMaxDuration = title === 'Max duration';
        const newProfile = Object.assign({}, EXPERIMENT.profile);
        let beforeParam = '';
76
77
        if (isMaxDuration) {
            if (!editInputVal.match(/^\d+(?=\.{0,1}\d+$|$)/)) {
78
79
80
81
82
83
84
85
86
87
                promptErrorMessage('Please enter a number!', 'error', defaultVal);
                return;
            }
            if (toSeconds(`${editInputVal}${unit}`) < EXPERIMENT.profile.execDuration) {
                // maxDuration should > current run time(execDuration)
                promptErrorMessage(
                    'Please input a valid value. (Current duration is more than the number you input.)',
                    'error',
                    defaultVal
                );
88
89
90
91
                return;
            }
        } else {
            if (!editInputVal.match(/^[1-9]\d*$/)) {
92
                promptErrorMessage('Please enter a positive integer!', 'error', defaultVal);
93
94
                return;
            }
95
96
97
        }
        if (isMaxDuration) {
            beforeParam = maxExecDuration;
98
        } else if (title === MAX_TRIAL_NUMBERS) {
99
100
101
102
            beforeParam = maxTrialNum.toString();
        } else {
            beforeParam = trialConcurrency.toString();
        }
103

104
        if (editInputVal === beforeParam) {
105
106
107
108
109
110
111
112
113
            if (isMaxDuration) {
                if (maxDurationUnit === unit) {
                    showMessageInfo(`Trial ${field} has not changed`, 'error');
                    return;
                }
            } else {
                showMessageInfo(`Trial ${field} has not changed`, 'error');
                return;
            }
114
115
        }
        if (isMaxDuration) {
116
            const maxDura = JSON.parse(editInputVal);
liuzhe-lz's avatar
liuzhe-lz committed
117
            newProfile.params[field] = `${maxDura}${unit}`;
118
119
120
121
122
123
124
125
126
        } else {
            newProfile.params[field] = parseInt(editInputVal, 10);
        }
        // rest api, modify trial concurrency value
        try {
            const res = await axios.put(`${MANAGER_IP}/experiment`, newProfile, {
                params: { update_type: editType }
            });
            if (res.status === 200) {
127
128
129
                if (isMaxDuration) {
                    changeMaxDurationUnit(unit);
                }
130
                showMessageInfo(`Successfully updated experiment's ${field}`, 'success');
131
                updateOverviewPage();
132
133
134
135
136
137
138
139
140
141
142
            }
        } catch (error) {
            if (error.response && error.response.data.error) {
                showMessageInfo(`Failed to update trial ${field}\n${error.response.data.error}`, 'error');
            } else if (error.response) {
                showMessageInfo(`Failed to update trial ${field}\nServer responsed ${error.response.status}`, 'error');
            } else if (error.message) {
                showMessageInfo(`Failed to update trial ${field}\n${error.message}`, 'error');
            } else {
                showMessageInfo(`Failed to update trial ${field}\nUnknown error`, 'error');
            }
143
            setEditValInput(defaultVal);
144
145
146
147
148
149
            // confirm trial config panel val
            if (isMaxDuration) {
                newProfile.params[field] = originMaxDurationStr;
            } else {
                newProfile.params[field] = beforeParam;
            }
150
151
152
153
        }
        showPencil();
    }

154
155
156
157
    function cancelEdit(): void {
        setEditValInput(defaultVal);
        showPencil();
        setUnit(maxDurationUnit);
158
159
    }

160
161
162
163
164
165
166
167
168
169
170
    function convertUnit(val: string): string {
        if (val === 'd') {
            return 'day';
        } else if (val === 'h') {
            return 'hour';
        } else if (val === 'm') {
            return 'min';
        } else {
            return val;
        }
    }
Lijiaoa's avatar
Lijiaoa committed
171

172
    return (
173
174
        <AppContext.Consumer>
            {(values): React.ReactNode => {
175
                return (
176
177
178
                    <EditExpeParamContext.Consumer>
                        {(value): React.ReactNode => {
                            let editClassName = '';
liuzhe-lz's avatar
liuzhe-lz committed
179
                            if (value.field === 'maxExperimentDuration') {
180
181
182
183
184
                                editClassName = isShowPencil ? 'noEditDuration' : 'editDuration';
                            }
                            return (
                                <React.Fragment>
                                    <div className={`${editClassName} editparam`}>
185
                                        <div className='title'>{value.title}</div>
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
                                        <input
                                            className={`${value.field} editparam-Input`}
                                            ref={DurationInputRef}
                                            disabled={isShowPencil ? true : false}
                                            value={editInputVal}
                                            onChange={setInputVal}
                                        />
                                        {isShowPencil && title === 'Max duration' && (
                                            <span>{convertUnit(values.maxDurationUnit)}</span>
                                        )}
                                        {!isShowPencil && title === 'Max duration' && (
                                            <Dropdown
                                                selectedKey={unit}
                                                options={durationUnit}
                                                className='editparam-dropdown'
                                                onChange={updateUnit}
                                            />
                                        )}
                                        {isShowPencil && (
205
                                            <span className='edit cursor' onClick={hidePencil}>
206
207
208
209
210
                                                {Edit}
                                            </span>
                                        )}
                                        {!isShowPencil && (
                                            <span className='series'>
211
                                                <span className='confirm cursor' onClick={confirmEdit}>
212
213
                                                    {CheckMark}
                                                </span>
214
                                                <span className='cancel cursor' onClick={cancelEdit}>
215
216
217
218
                                                    {Cancel}
                                                </span>
                                            </span>
                                        )}
219

220
221
222
223
224
225
226
227
                                        {isShowSucceedInfo && (
                                            <MessageInfo className='info' typeInfo={typeInfo} info={info} />
                                        )}
                                    </div>
                                </React.Fragment>
                            );
                        }}
                    </EditExpeParamContext.Consumer>
228
229
                );
            }}
230
        </AppContext.Consumer>
231
232
    );
};