]> git.proxmox.com Git - proxmox-widget-toolkit.git/blame - Utils.js
place space on correct side of colon
[proxmox-widget-toolkit.git] / Utils.js
CommitLineData
0bb29d35
DM
1Ext.ns('Proxmox');
2Ext.ns('Proxmox.Setup');
3
0ee4c725
DM
4if (!Ext.isFunction(gettext)) {
5 function gettext(buf) { return buf; }
6}
0bb29d35 7
757cc58a
DM
8if (!Ext.isDefined(Proxmox.Setup.auth_cookie_name)) {
9 throw "Proxmox library not initialized";
0bb29d35
DM
10}
11
12// avoid errors related to Accessible Rich Internet Applications
13// (access for people with disabilities)
14// TODO reenable after all components are upgraded
15Ext.enableAria = false;
16Ext.enableAriaButtons = false;
17Ext.enableAriaPanels = false;
18
19// avoid errors when running without development tools
20if (!Ext.isDefined(Ext.global.console)) {
21 var console = {
22 dir: function() {},
23 log: function() {}
24 };
25}
26
27Ext.Ajax.defaultHeaders = {
28 'Accept': 'application/json'
29};
30
31Ext.Ajax.on('beforerequest', function(conn, options) {
32 if (Proxmox.CSRFPreventionToken) {
33 if (!options.headers) {
34 options.headers = {};
35 }
36 options.headers.CSRFPreventionToken = Proxmox.CSRFPreventionToken;
37 }
38});
39
40Ext.define('Proxmox.Utils', { utilities: {
41
42 // this singleton contains miscellaneous utilities
43
30f885cb
DM
44 yesText: gettext('Yes'),
45 noText: gettext('No'),
46 enabledText: gettext('Enabled'),
47 disabledText: gettext('Disabled'),
48 noneText: gettext('none'),
49 errorText: gettext('Error'),
a58001dd 50 unknownText: gettext('Unknown'),
30f885cb
DM
51 defaultText: gettext('Default'),
52 daysText: gettext('days'),
53 dayText: gettext('day'),
54 runningText: gettext('running'),
55 stoppedText: gettext('stopped'),
56 neverText: gettext('never'),
57 totalText: gettext('Total'),
58 usedText: gettext('Used'),
59 directoryText: gettext('Directory'),
60 stateText: gettext('State'),
61 groupText: gettext('Group'),
62
f6f0066a
DM
63 language_map: {
64 en: 'English',
65 fr: 'French',
66 de: 'German',
67 it: 'Italian',
68 es: 'Spanish'
69 },
70
71 render_language: function (value) {
72 if (!value) {
73 return Proxmox.Utils.defaultText + ' (English)';
74 }
75 var text = Proxmox.Utils.language_map[value];
76 if (text) {
77 return text + ' (' + value + ')';
78 }
79 return value;
80 },
81
82 language_array: function() {
83 var data = [['__default__', Proxmox.Utils.render_language('')]];
84 Ext.Object.each(Proxmox.Utils.language_map, function(key, value) {
85 data.push([key, Proxmox.Utils.render_language(value)]);
86 });
87
88 return data;
89 },
90
5f93e010
DM
91 getNoSubKeyHtml: function(url) {
92 // url http://www.proxmox.com/products/proxmox-ve/subscription-service-plans
93 return Ext.String.format('You do not have a valid subscription for this server. Please visit <a target="_blank" href="{0}">www.proxmox.com</a> to get a list of available options.', url || 'http://www.proxmox.com');
94 },
95
b0d9b5d1
DM
96 format_boolean_with_default: function(value) {
97 if (Ext.isDefined(value) && value !== '__default__') {
98 return value ? Proxmox.Utils.yesText : Proxmox.Utils.noText;
99 }
100 return Proxmox.Utils.defaultText;
101 },
102
103 format_boolean: function(value) {
104 return value ? Proxmox.Utils.yesText : Proxmox.Utils.noText;
105 },
106
107 format_neg_boolean: function(value) {
108 return !value ? Proxmox.Utils.yesText : Proxmox.Utils.noText;
109 },
a58001dd 110
0e49da6d
DM
111 format_enabled_toggle: function(value) {
112 return value ? Proxmox.Utils.enabledText : Proxmox.Utils.disabledText;
113 },
114
2d0153a5
DM
115 format_expire: function(date) {
116 if (!date) {
117 return Proxmox.Utils.neverText;
118 }
119 return Ext.Date.format(date, "Y-m-d");
120 },
121
452892df
DM
122 format_duration_long: function(ut) {
123
124 var days = Math.floor(ut / 86400);
125 ut -= days*86400;
126 var hours = Math.floor(ut / 3600);
127 ut -= hours*3600;
128 var mins = Math.floor(ut / 60);
129 ut -= mins*60;
130
131 var hours_str = '00' + hours.toString();
132 hours_str = hours_str.substr(hours_str.length - 2);
133 var mins_str = "00" + mins.toString();
134 mins_str = mins_str.substr(mins_str.length - 2);
135 var ut_str = "00" + ut.toString();
136 ut_str = ut_str.substr(ut_str.length - 2);
137
138 if (days) {
139 var ds = days > 1 ? Proxmox.Utils.daysText : Proxmox.Utils.dayText;
140 return days.toString() + ' ' + ds + ' ' +
141 hours_str + ':' + mins_str + ':' + ut_str;
142 } else {
143 return hours_str + ':' + mins_str + ':' + ut_str;
144 }
145 },
146
147 format_duration_short: function(ut) {
148
149 if (ut < 60) {
150 return ut.toString() + 's';
151 }
152
153 if (ut < 3600) {
154 var mins = ut / 60;
155 return mins.toFixed(0) + 'm';
156 }
157
158 if (ut < 86400) {
159 var hours = ut / 3600;
160 return hours.toFixed(0) + 'h';
161 }
162
163 var days = ut / 86400;
164 return days.toFixed(0) + 'd';
165 },
166
02ef30c9
DM
167 format_subscription_level: function(level) {
168 if (level === 'c') {
8f5a1a08 169 return 'Community';
02ef30c9 170 } else if (level === 'b') {
8f5a1a08 171 return 'Basic';
02ef30c9 172 } else if (level === 's') {
8f5a1a08 173 return 'Standard';
02ef30c9 174 } else if (level === 'p') {
8f5a1a08 175 return 'Premium';
02ef30c9
DM
176 } else {
177 return Proxmox.Utils.noneText;
178 }
179 },
180
28e54f37
DM
181 compute_min_label_width: function(text, width) {
182
183 if (width === undefined) { width = 100; }
184
185 var tm = new Ext.util.TextMetrics();
186 var min = tm.getWidth(text + ':');
187
188 return min < width ? width : min;
189 },
190
0bb29d35
DM
191 authOK: function() {
192 return (Proxmox.UserName !== '') && Ext.util.Cookies.get(Proxmox.Setup.auth_cookie_name);
193 },
194
195 authClear: function() {
196 Ext.util.Cookies.clear(Proxmox.Setup.auth_cookie_name);
197 },
198
199 // comp.setLoading() is buggy in ExtJS 4.0.7, so we
200 // use el.mask() instead
201 setErrorMask: function(comp, msg) {
202 var el = comp.el;
203 if (!el) {
204 return;
205 }
206 if (!msg) {
207 el.unmask();
208 } else {
209 if (msg === true) {
210 el.mask(gettext("Loading..."));
211 } else {
212 el.mask(msg);
213 }
214 }
215 },
216
5b4b3ffd
DM
217 monStoreErrors: function(me, store, clearMaskBeforeLoad) {
218 if (clearMaskBeforeLoad) {
219 me.mon(store, 'beforeload', function(s, operation, eOpts) {
220 Proxmox.Utils.setErrorMask(me, false);
e94c0767 221 });
5b4b3ffd
DM
222 } else {
223 me.mon(store, 'beforeload', function(s, operation, eOpts) {
224 if (!me.loadCount) {
225 me.loadCount = 0; // make sure it is numeric
226 Proxmox.Utils.setErrorMask(me, true);
227 }
228 });
229 }
0bb29d35
DM
230
231 // only works with 'proxmox' proxy
232 me.mon(store.proxy, 'afterload', function(proxy, request, success) {
233 me.loadCount++;
234
235 if (success) {
236 Proxmox.Utils.setErrorMask(me, false);
237 return;
238 }
239
240 var msg;
241 /*jslint nomen: true */
242 var operation = request._operation;
243 var error = operation.getError();
244 if (error.statusText) {
245 msg = error.statusText + ' (' + error.status + ')';
246 } else {
247 msg = gettext('Connection error');
248 }
249 Proxmox.Utils.setErrorMask(me, msg);
250 });
251 },
252
253 extractRequestError: function(result, verbose) {
254 var msg = gettext('Successful');
255
256 if (!result.success) {
257 msg = gettext("Unknown error");
258 if (result.message) {
259 msg = result.message;
260 if (result.status) {
261 msg += ' (' + result.status + ')';
262 }
263 }
264 if (verbose && Ext.isObject(result.errors)) {
265 msg += "<br>";
266 Ext.Object.each(result.errors, function(prop, desc) {
267 msg += "<br><b>" + Ext.htmlEncode(prop) + "</b>: " +
268 Ext.htmlEncode(desc);
269 });
270 }
271 }
272
273 return msg;
274 },
275
276 // Ext.Ajax.request
277 API2Request: function(reqOpts) {
278
279 var newopts = Ext.apply({
280 waitMsg: gettext('Please wait...')
281 }, reqOpts);
282
283 if (!newopts.url.match(/^\/api2/)) {
284 newopts.url = '/api2/extjs' + newopts.url;
285 }
286 delete newopts.callback;
287
288 var createWrapper = function(successFn, callbackFn, failureFn) {
289 Ext.apply(newopts, {
290 success: function(response, options) {
291 if (options.waitMsgTarget) {
292 options.waitMsgTarget.setLoading(false);
293 }
294 var result = Ext.decode(response.responseText);
295 response.result = result;
296 if (!result.success) {
297 response.htmlStatus = Proxmox.Utils.extractRequestError(result, true);
298 Ext.callback(callbackFn, options.scope, [options, false, response]);
299 Ext.callback(failureFn, options.scope, [response, options]);
300 return;
301 }
302 Ext.callback(callbackFn, options.scope, [options, true, response]);
303 Ext.callback(successFn, options.scope, [response, options]);
304 },
305 failure: function(response, options) {
306 if (options.waitMsgTarget) {
307 options.waitMsgTarget.setLoading(false);
308 }
309 response.result = {};
310 try {
311 response.result = Ext.decode(response.responseText);
312 } catch(e) {}
313 var msg = gettext('Connection error') + ' - server offline?';
314 if (response.aborted) {
315 msg = gettext('Connection error') + ' - aborted.';
316 } else if (response.timedout) {
317 msg = gettext('Connection error') + ' - Timeout.';
318 } else if (response.status && response.statusText) {
319 msg = gettext('Connection error') + ' ' + response.status + ': ' + response.statusText;
320 }
321 response.htmlStatus = msg;
322 Ext.callback(callbackFn, options.scope, [options, false, response]);
323 Ext.callback(failureFn, options.scope, [response, options]);
324 }
325 });
326 };
327
328 createWrapper(reqOpts.success, reqOpts.callback, reqOpts.failure);
329
330 var target = newopts.waitMsgTarget;
331 if (target) {
332 // Note: ExtJS bug - this does not work when component is not rendered
333 target.setLoading(newopts.waitMsg);
334 }
335 Ext.Ajax.request(newopts);
336 },
337
5f93e010
DM
338 checked_command: function(orig_cmd) {
339 Proxmox.Utils.API2Request({
340 url: '/nodes/localhost/subscription',
341 method: 'GET',
342 //waitMsgTarget: me,
343 failure: function(response, opts) {
344 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
345 },
346 success: function(response, opts) {
347 var data = response.result.data;
348
349 if (data.status !== 'Active') {
350 Ext.Msg.show({
351 title: gettext('No valid subscription'),
352 icon: Ext.Msg.WARNING,
353 msg: Proxmox.Utils.getNoSubKeyHtml(data.url),
354 buttons: Ext.Msg.OK,
355 callback: function(btn) {
356 if (btn !== 'ok') {
357 return;
358 }
359 orig_cmd();
360 }
361 });
362 } else {
363 orig_cmd();
364 }
365 }
366 });
367 },
368
06694509
DM
369 assemble_field_data: function(values, data) {
370 if (Ext.isObject(data)) {
371 Ext.Object.each(data, function(name, val) {
372 if (values.hasOwnProperty(name)) {
373 var bucket = values[name];
374 if (!Ext.isArray(bucket)) {
375 bucket = values[name] = [bucket];
376 }
377 if (Ext.isArray(val)) {
378 values[name] = bucket.concat(val);
379 } else {
380 bucket.push(val);
381 }
382 } else {
383 values[name] = val;
384 }
385 });
386 }
387 },
388
389 dialog_title: function(subject, create, isAdd) {
390 if (create) {
391 if (isAdd) {
392 return gettext('Add') + ': ' + subject;
393 } else {
394 return gettext('Create') + ': ' + subject;
395 }
396 } else {
397 return gettext('Edit') + ': ' + subject;
398 }
399 },
400
a58001dd
DM
401 network_iface_types: {
402 eth: gettext("Network Device"),
403 bridge: 'Linux Bridge',
404 bond: 'Linux Bond',
405 OVSBridge: 'OVS Bridge',
406 OVSBond: 'OVS Bond',
407 OVSPort: 'OVS Port',
408 OVSIntPort: 'OVS IntPort'
409 },
410
411 render_network_iface_type: function(value) {
412 return Proxmox.Utils.network_iface_types[value] ||
413 Proxmox.Utils.unknownText;
414 },
415
53ac9bca
DM
416 // you can override this to provide nicer task descriptions
417 format_task_description: function(type, id) {
418 return type + ' ' + id;
419 },
420
b91c7ce2
DC
421 format_size: function(size) {
422 /*jslint confusion: true */
423
424 var units = ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi'];
425 var num = 0;
426
427 while (size >= 1024 && ((num++)+1) < units.length) {
428 size = size / 1024;
429 }
430
431 return size.toFixed((num > 0)?2:0) + " " + units[num] + "B";
432 },
433
53ac9bca
DM
434 render_upid: function(value, metaData, record) {
435 var type = record.data.type;
436 var id = record.data.id;
437
438 return Proxmox.Utils.format_task_description(type, id);
439 },
440
452892df
DM
441 render_uptime: function(value) {
442
443 var uptime = value;
444
445 if (uptime === undefined) {
446 return '';
447 }
448
449 if (uptime <= 0) {
450 return '-';
451 }
452
453 return Proxmox.Utils.format_duration_long(uptime);
454 },
455
06694509
DM
456 parse_task_upid: function(upid) {
457 var task = {};
458
459 var res = upid.match(/^UPID:(\S+):([0-9A-Fa-f]{8}):([0-9A-Fa-f]{8,9}):([0-9A-Fa-f]{8}):([^:\s]+):([^:\s]*):([^:\s]+):$/);
460 if (!res) {
461 throw "unable to parse upid '" + upid + "'";
462 }
463 task.node = res[1];
464 task.pid = parseInt(res[2], 16);
465 task.pstart = parseInt(res[3], 16);
466 task.starttime = parseInt(res[4], 16);
467 task.type = res[5];
468 task.id = res[6];
469 task.user = res[7];
470
53ac9bca
DM
471 task.desc = Proxmox.Utils.format_task_description(task.type, task.id);
472
06694509
DM
473 return task;
474 },
475
476 render_timestamp: function(value, metaData, record, rowIndex, colIndex, store) {
477 var servertime = new Date(value * 1000);
478 return Ext.Date.format(servertime, 'Y-m-d H:i:s');
881c9c0c
DC
479 },
480
481 openXtermJsViewer: function(vmtype, vmid, nodename, vmname) {
482 var url = Ext.urlEncode({
483 console: vmtype, // kvm, lxc, upgrade or shell
484 xtermjs: 1,
485 vmid: vmid,
486 vmname: vmname,
487 node: nodename
488 });
489 var nw = window.open("?" + url, '_blank', 'toolbar=no,location=no,status=no,menubar=no,resizable=yes,width=800,height=420');
490 nw.focus();
e94c0767 491 }
06694509 492
881c9c0c 493},
5ffef550 494
0bb29d35
DM
495 singleton: true,
496 constructor: function() {
497 var me = this;
498 Ext.apply(me, me.utilities);
499
500 var IPV4_OCTET = "(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])";
501 var IPV4_REGEXP = "(?:(?:" + IPV4_OCTET + "\\.){3}" + IPV4_OCTET + ")";
502 var IPV6_H16 = "(?:[0-9a-fA-F]{1,4})";
503 var IPV6_LS32 = "(?:(?:" + IPV6_H16 + ":" + IPV6_H16 + ")|" + IPV4_REGEXP + ")";
504
505
506 me.IP4_match = new RegExp("^(?:" + IPV4_REGEXP + ")$");
507 me.IP4_cidr_match = new RegExp("^(?:" + IPV4_REGEXP + ")\/([0-9]{1,2})$");
508
509 var IPV6_REGEXP = "(?:" +
510 "(?:(?:" + "(?:" + IPV6_H16 + ":){6})" + IPV6_LS32 + ")|" +
511 "(?:(?:" + "::" + "(?:" + IPV6_H16 + ":){5})" + IPV6_LS32 + ")|" +
512 "(?:(?:(?:" + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){4})" + IPV6_LS32 + ")|" +
513 "(?:(?:(?:(?:" + IPV6_H16 + ":){0,1}" + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){3})" + IPV6_LS32 + ")|" +
514 "(?:(?:(?:(?:" + IPV6_H16 + ":){0,2}" + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){2})" + IPV6_LS32 + ")|" +
515 "(?:(?:(?:(?:" + IPV6_H16 + ":){0,3}" + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){1})" + IPV6_LS32 + ")|" +
516 "(?:(?:(?:(?:" + IPV6_H16 + ":){0,4}" + IPV6_H16 + ")?::" + ")" + IPV6_LS32 + ")|" +
517 "(?:(?:(?:(?:" + IPV6_H16 + ":){0,5}" + IPV6_H16 + ")?::" + ")" + IPV6_H16 + ")|" +
518 "(?:(?:(?:(?:" + IPV6_H16 + ":){0,7}" + IPV6_H16 + ")?::" + ")" + ")" +
519 ")";
520
521 me.IP6_match = new RegExp("^(?:" + IPV6_REGEXP + ")$");
522 me.IP6_cidr_match = new RegExp("^(?:" + IPV6_REGEXP + ")\/([0-9]{1,3})$");
523 me.IP6_bracket_match = new RegExp("^\\[(" + IPV6_REGEXP + ")\\]");
524
525 me.IP64_match = new RegExp("^(?:" + IPV6_REGEXP + "|" + IPV4_REGEXP + ")$");
526
527 var DnsName_REGEXP = "(?:(([a-zA-Z0-9]([a-zA-Z0-9\\-]*[a-zA-Z0-9])?)\\.)*([A-Za-z0-9]([A-Za-z0-9\\-]*[A-Za-z0-9])?))";
528 me.DnsName_match = new RegExp("^" + DnsName_REGEXP + "$");
529
530 me.HostPort_match = new RegExp("^(" + IPV4_REGEXP + "|" + DnsName_REGEXP + ")(:\\d+)?$");
531 me.HostPortBrackets_match = new RegExp("^\\[(?:" + IPV6_REGEXP + "|" + IPV4_REGEXP + "|" + DnsName_REGEXP + ")\\](:\\d+)?$");
532 me.IP6_dotnotation_match = new RegExp("^" + IPV6_REGEXP + "(\\.\\d+)?$");
533 }
534});