]>
git.proxmox.com Git - pve-manager.git/blob - www/manager/Utils.js
3 // avoid errors when running without development tools
4 if (! Ext
. isDefined ( Ext
. global
. console
)) {
10 console
. log ( "Starting PVE Manager" );
12 Ext
. Ajax
. defaultHeaders
= {
13 'Accept' : 'application/json'
16 // do not send '_dc' parameter
17 Ext
. Ajax
. disableCaching
= false ;
19 Ext
. Ajax
. on ( 'beforerequest' , function ( conn
, options
) {
20 if ( PVE
. CSRFPreventionToken
) {
21 if (! options
. headers
) {
24 options
. headers
. CSRFPreventionToken
= PVE
. CSRFPreventionToken
;
28 var IPV4_OCTET
= "(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])" ;
29 var IPV4_REGEXP
= "(?:(?:" + IPV4_OCTET
+ " \\ .){3}" + IPV4_OCTET
+ ")" ;
30 var IPV6_H16
= "(?:[0-9a-fA-F]{1,4})" ;
31 var IPV6_LS32
= "(?:(?:" + IPV6_H16
+ ":" + IPV6_H16
+ ")|" + IPV4_REGEXP
+ ")" ;
34 var IP4_match
= new RegExp ( "^(?:" + IPV4_REGEXP
+ ")$" );
36 var IPV6_REGEXP
= "(?:" +
37 "(?:(?:" + "(?:" + IPV6_H16
+ ":){6})" + IPV6_LS32
+ ")|" +
38 "(?:(?:" + "::" + "(?:" + IPV6_H16
+ ":){5})" + IPV6_LS32
+ ")|" +
39 "(?:(?:(?:" + IPV6_H16
+ ")?::" + "(?:" + IPV6_H16
+ ":){4})" + IPV6_LS32
+ ")|" +
40 "(?:(?:(?:(?:" + IPV6_H16
+ ":){0,1}" + IPV6_H16
+ ")?::" + "(?:" + IPV6_H16
+ ":){3})" + IPV6_LS32
+ ")|" +
41 "(?:(?:(?:(?:" + IPV6_H16
+ ":){0,2}" + IPV6_H16
+ ")?::" + "(?:" + IPV6_H16
+ ":){2})" + IPV6_LS32
+ ")|" +
42 "(?:(?:(?:(?:" + IPV6_H16
+ ":){0,3}" + IPV6_H16
+ ")?::" + "(?:" + IPV6_H16
+ ":){1})" + IPV6_LS32
+ ")|" +
43 "(?:(?:(?:(?:" + IPV6_H16
+ ":){0,4}" + IPV6_H16
+ ")?::" + ")" + IPV6_LS32
+ ")|" +
44 "(?:(?:(?:(?:" + IPV6_H16
+ ":){0,5}" + IPV6_H16
+ ")?::" + ")" + IPV6_H16
+ ")|" +
45 "(?:(?:(?:(?:" + IPV6_H16
+ ":){0,7}" + IPV6_H16
+ ")?::" + ")" + ")" +
48 var IP64_match
= new RegExp ( "^(?:" + IPV6_REGEXP
+ "|" + IPV4_REGEXP
+ ")$" );
51 Ext
. apply ( Ext
. form
. field
. VTypes
, {
52 IPAddress : function ( v
) {
53 return IP4_match
. test ( v
);
55 IPAddressText
: gettext ( 'Example' ) + ': 192.168.1.1' ,
56 IPAddressMask
: /[\d\.]/i ,
58 IP64Address : function ( v
) {
59 return IP64_match
. test ( v
);
61 IP64AddressText
: gettext ( 'Example' ) + ': 192.168.1.1 2001:DB8::42' ,
62 IP64AddressMask
: /[A-Fa-f0-9\.:]/ ,
64 MacAddress : function ( v
) {
65 return ( /^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$/ ). test ( v
);
67 MacAddressMask
: /[a-fA-F0-9:]/ ,
68 MacAddressText
: gettext ( 'Example' ) + ': 01:23:45:67:89:ab' ,
70 BridgeName : function ( v
) {
71 return ( /^vmbr\d{1,4}$/ ). test ( v
);
73 BridgeNameText
: gettext ( 'Format' ) + ': vmbr<b>N</b>, where 0 <= <b>N</b> <= 9999' ,
75 BondName : function ( v
) {
76 return ( /^bond\d{1,4}$/ ). test ( v
);
78 BondNameText
: gettext ( 'Format' ) + ': bond<b>N</b>, where 0 <= <b>N</b> <= 9999' ,
80 InterfaceName : function ( v
) {
81 return ( /^[a-z][a-z0-9_]{1,20}$/ ). test ( v
);
83 InterfaceNameText
: gettext ( 'Format' ) + ': [a-z][a-z0-9_]{1,20}' ,
86 QemuStartDate : function ( v
) {
87 return ( /^(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)$/ ). test ( v
);
89 QemuStartDateText
: gettext ( 'Format' ) + ': "now" or "2006-06-17T16:01:21" or "2006-06-17"' ,
91 StorageId : function ( v
) {
92 return ( /^[a-z][a-z0-9\-\_\.]*[a-z0-9]$/i ). test ( v
);
94 StorageIdText
: gettext ( "Allowed characters" ) + ": 'a-z', '0-9', '-', '_', '.'" ,
96 HttpProxy : function ( v
) {
97 return ( /^http:\/\/.*$/ ). test ( v
);
99 HttpProxyText
: gettext ( 'Example' ) + ": http://username:password@host:port/" ,
101 DnsName : function ( v
) {
102 return ( /^(([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?)\.)*([A-Za-z0-9]([A-Za-z0-9\-]*[A-Za-z0-9])?)$/ ). test ( v
);
104 DnsNameText
: gettext ( 'This is not a valid DNS name' )
107 // we dont want that a displayfield set the form dirty flag!
108 Ext
. override ( Ext
. form
. field
. Display
, {
109 isDirty : function () { return false ; }
112 // hack: ExtJS does not display the correct value if we
113 // call setValue while the store is loading, so we need
114 // to call it again after loading
115 Ext
. override ( Ext
. form
. field
. ComboBox
, {
117 this . setValue ( this . value
, false );
118 this . callOverridden ( arguments
);
122 Ext
. define ( 'PVE.Utils' , { statics
: {
124 // this class only contains static functions
137 support_level_hash
: {
138 'c' : gettext ( 'Community' ),
139 'b' : gettext ( 'Basic' ),
140 's' : gettext ( 'Standard' ),
141 'p' : gettext ( 'Premium' )
144 noSubKeyHtml
: 'You do not have a valid subscription for this server. Please visit <a target="_blank" href="http://www.proxmox.com/products/proxmox-ve/subscription-service-plans">www.proxmox.com</a> to get a list of available options.' ,
147 other
: gettext ( 'Other OS types' ),
148 wxp
: 'Microsoft Windows XP/2003' ,
149 w2k
: 'Microsoft Windows 2000' ,
150 w2k8
: 'Microsoft Windows Vista/2008' ,
151 win7
: 'Microsoft Windows 7/2008r2' ,
152 win8
: 'Microsoft Windows 8/2012' ,
153 l24
: 'Linux 2.4 Kernel' ,
154 l26
: 'Linux 3.X/2.6 Kernel' ,
155 solaris
: 'Solaris Kernel'
158 render_kvm_ostype : function ( value
) {
160 return gettext ( 'Other OS types' );
162 var text
= PVE
. Utils
. kvm_ostypes
[ value
];
164 return text
+ ' (' + value
+ ')' ;
169 network_iface_types
: {
170 eth
: gettext ( "Network Device" ),
171 bridge
: 'Linux Bridge' ,
173 OVSBridge
: 'OVS Bridge' ,
176 OVSIntPort
: 'OVS IntPort'
179 render_network_iface_type : function ( value
) {
180 return PVE
. Utils
. network_iface_types
[ value
] ||
181 PVE
. Utils
. unknownText
;
184 render_scsihw : function ( value
) {
186 return PVE
. Utils
. defaultText
+ ' (LSI 53C895A)' ;
187 } else if ( value
=== 'lsi' ) {
188 return 'LSI 53C895A' ;
189 } else if ( value
=== 'lsi53c810' ) {
191 } else if ( value
=== 'megasas' ) {
192 return 'MegaRAID SAS 8708EM2' ;
193 } else if ( value
=== 'virtio-scsi-pci' ) {
195 } else if ( value
=== 'pvscsi' ) {
196 return 'VMware PVSCSI' ;
202 // fixme: auto-generate this
203 // for now, please keep in sync with PVE::Tools::kvmkeymaps
208 'de-ch' : 'German (Swiss)' ,
209 'en-gb' : 'English (UK)' ,
210 'en-us' : 'English (USA' ,
214 //fo: 'Faroe Islands',
216 'fr-be' : 'French (Belgium)' ,
217 'fr-ca' : 'French (Canada)' ,
218 'fr-ch' : 'French (Swiss)' ,
228 //'nl-be': 'Dutch (Belgium)',
232 'pt-br' : 'Portuguese (Brazil)' ,
241 std
: gettext ( 'Standard VGA' ),
242 vmware
: gettext ( 'VMWare compatible' ),
243 cirrus
: 'Cirrus Logic GD5446' ,
245 qxl2
: 'SPICE dual monitor' ,
246 qxl3
: 'SPICE three monitors' ,
247 qxl4
: 'SPICE four monitors' ,
248 serial0
: gettext ( 'Serial terminal' ) + ' 0' ,
249 serial1
: gettext ( 'Serial terminal' ) + ' 1' ,
250 serial2
: gettext ( 'Serial terminal' ) + ' 2' ,
251 serial3
: gettext ( 'Serial terminal' ) + ' 3'
254 render_kvm_language : function ( value
) {
256 return PVE
. Utils
. defaultText
;
258 var text
= PVE
. Utils
. kvm_keymaps
[ value
];
260 return text
+ ' (' + value
+ ')' ;
265 kvm_keymap_array : function () {
266 var data
= [[ '' , PVE
. Utils
. render_kvm_language ( '' )]];
267 Ext
. Object
. each ( PVE
. Utils
. kvm_keymaps
, function ( key
, value
) {
268 data
. push ([ key
, PVE
. Utils
. render_kvm_language ( value
)]);
274 render_console_viewer : function ( value
) {
276 return PVE
. Utils
. defaultText
+ ' (Java VNC Applet)' ;
277 } else if ( value
=== 'applet' ) {
278 return 'Java VNC Applet' ;
279 } else if ( value
=== 'vv' ) {
280 return 'SPICE (remote-viewer)' ;
296 nb
: 'Norwegian (Bokmal)' ,
297 nn
: 'Norwegian (Nynorsk)' ,
302 pt_BR
: 'Portuguese (Brazil)' ,
306 render_language : function ( value
) {
308 return PVE
. Utils
. defaultText
+ ' (English)' ;
310 var text
= PVE
. Utils
. language_map
[ value
];
312 return text
+ ' (' + value
+ ')' ;
317 language_array : function () {
318 var data
= [[ '' , PVE
. Utils
. render_language ( '' )]];
319 Ext
. Object
. each ( PVE
. Utils
. language_map
, function ( key
, value
) {
320 data
. push ([ key
, PVE
. Utils
. render_language ( value
)]);
326 render_kvm_vga_driver : function ( value
) {
328 return PVE
. Utils
. defaultText
;
330 var text
= PVE
. Utils
. kvm_vga_drivers
[ value
];
332 return text
+ ' (' + value
+ ')' ;
337 kvm_vga_driver_array : function () {
338 var data
= [[ '' , PVE
. Utils
. render_kvm_vga_driver ( '' )]];
339 Ext
. Object
. each ( PVE
. Utils
. kvm_vga_drivers
, function ( key
, value
) {
340 data
. push ([ key
, PVE
. Utils
. render_kvm_vga_driver ( value
)]);
346 render_kvm_startup : function ( value
) {
347 var startup
= PVE
. Parser
. parseStartup ( value
);
350 if ( startup
. order
=== undefined ) {
353 res
+= startup
. order
;
355 if ( startup
. up
!== undefined ) {
356 res
+= ',up=' + startup
. up
;
358 if ( startup
. down
!== undefined ) {
359 res
+= ',down=' + startup
. down
;
366 return Ext
. util
. Cookies
. get ( 'PVEAuthCookie' );
369 authClear : function () {
370 Ext
. util
. Cookies
. clear ( "PVEAuthCookie" );
373 // fixme: remove - not needed?
374 gridLineHeigh : function () {
382 extractRequestError : function ( result
, verbose
) {
383 var msg
= gettext ( 'Successful' );
385 if (! result
. success
) {
386 msg
= gettext ( "Unknown error" );
387 if ( result
. message
) {
388 msg
= result
. message
;
390 msg
+= ' (' + result
. status
+ ')' ;
393 if ( verbose
&& Ext
. isObject ( result
. errors
)) {
395 Ext
. Object
. each ( result
. errors
, function ( prop
, desc
) {
396 msg
+= "<br><b>" + Ext
. htmlEncode ( prop
) + "</b>: " +
397 Ext
. htmlEncode ( desc
);
405 extractFormActionError : function ( action
) {
407 switch ( action
. failureType
) {
408 case Ext
. form
. action
. Action
. CLIENT_INVALID
:
409 msg
= gettext ( 'Form fields may not be submitted with invalid values' );
411 case Ext
. form
. action
. Action
. CONNECT_FAILURE
:
412 msg
= gettext ( 'Connection error' );
413 var resp
= action
. response
;
414 if ( resp
. status
&& resp
. statusText
) {
415 msg
+= " " + resp
. status
+ ": " + resp
. statusText
;
418 case Ext
. form
. action
. Action
. LOAD_FAILURE
:
419 case Ext
. form
. action
. Action
. SERVER_INVALID
:
420 msg
= PVE
. Utils
. extractRequestError ( action
. result
, true );
427 API2Request : function ( reqOpts
) {
429 var newopts
= Ext
. apply ({
430 waitMsg
: gettext ( 'Please wait...' )
433 if (! newopts
. url
. match ( /^\/api2/ )) {
434 newopts
. url
= '/api2/extjs' + newopts
. url
;
436 delete newopts
. callback
;
438 var createWrapper = function ( successFn
, callbackFn
, failureFn
) {
440 success : function ( response
, options
) {
441 if ( options
. waitMsgTarget
) {
442 options
. waitMsgTarget
. setLoading ( false );
444 var result
= Ext
. decode ( response
. responseText
);
445 response
. result
= result
;
446 if (! result
. success
) {
447 response
. htmlStatus
= PVE
. Utils
. extractRequestError ( result
, true );
448 Ext
. callback ( callbackFn
, options
. scope
, [ options
, false , response
]);
449 Ext
. callback ( failureFn
, options
. scope
, [ response
, options
]);
452 Ext
. callback ( callbackFn
, options
. scope
, [ options
, true , response
]);
453 Ext
. callback ( successFn
, options
. scope
, [ response
, options
]);
455 failure : function ( response
, options
) {
456 if ( options
. waitMsgTarget
) {
457 options
. waitMsgTarget
. setLoading ( false );
459 response
. result
= {};
461 response
. result
= Ext
. decode ( response
. responseText
);
463 var msg
= gettext ( 'Connection error' ) + ' - server offline?' ;
464 if ( response
. aborted
) {
465 msg
= gettext ( 'Connection error' ) + ' - aborted.' ;
466 } else if ( response
. timedout
) {
467 msg
= gettext ( 'Connection error' ) + ' - Timeout.' ;
468 } else if ( response
. status
&& response
. statusText
) {
469 msg
= gettext ( 'Connection error' ) + ' ' + response
. status
+ ': ' + response
. statusText
;
471 response
. htmlStatus
= msg
;
472 Ext
. callback ( callbackFn
, options
. scope
, [ options
, false , response
]);
473 Ext
. callback ( failureFn
, options
. scope
, [ response
, options
]);
478 createWrapper ( reqOpts
. success
, reqOpts
. callback
, reqOpts
. failure
);
480 var target
= newopts
. waitMsgTarget
;
482 // Note: ExtJS bug - this does not work when component is not rendered
483 target
. setLoading ( newopts
. waitMsg
);
485 Ext
. Ajax
. request ( newopts
);
488 assemble_field_data : function ( values
, data
) {
489 if ( Ext
. isObject ( data
)) {
490 Ext
. Object
. each ( data
, function ( name
, val
) {
491 if ( values
. hasOwnProperty ( name
)) {
492 var bucket
= values
[ name
];
493 if (! Ext
. isArray ( bucket
)) {
494 bucket
= values
[ name
] = [ bucket
];
496 if ( Ext
. isArray ( val
)) {
497 values
[ name
] = bucket
. concat ( val
);
508 checked_command : function ( orig_cmd
) {
509 PVE
. Utils
. API2Request ({
510 url
: '/nodes/localhost/subscription' ,
513 failure : function ( response
, opts
) {
514 Ext
. Msg
. alert ( gettext ( 'Error' ), response
. htmlStatus
);
516 success : function ( response
, opts
) {
517 var data
= response
. result
. data
;
519 if ( data
. status
!== 'Active' ) {
521 title
: gettext ( 'No valid subscription' ),
522 icon
: Ext
. Msg
. WARNING
,
523 msg
: PVE
. Utils
. noSubKeyHtml
,
525 callback : function ( btn
) {
540 vncproxy
: [ 'VM/CT' , gettext ( 'Console' ) ],
541 spiceproxy
: [ 'VM/CT' , gettext ( 'Console' ) + ' (Spice)' ],
542 vncshell
: [ '' , gettext ( 'Shell' ) ],
543 spiceshell
: [ '' , gettext ( 'Shell' ) + ' (Spice)' ],
544 qmsnapshot
: [ 'VM' , gettext ( 'Snapshot' ) ],
545 qmrollback
: [ 'VM' , gettext ( 'Rollback' ) ],
546 qmdelsnapshot
: [ 'VM' , gettext ( 'Delete Snapshot' ) ],
547 qmcreate
: [ 'VM' , gettext ( 'Create' ) ],
548 qmrestore
: [ 'VM' , gettext ( 'Restore' ) ],
549 qmdestroy
: [ 'VM' , gettext ( 'Destroy' ) ],
550 qmigrate
: [ 'VM' , gettext ( 'Migrate' ) ],
551 qmclone
: [ 'VM' , gettext ( 'Clone' ) ],
552 qmmove
: [ 'VM' , gettext ( 'Move disk' ) ],
553 qmtemplate
: [ 'VM' , gettext ( 'Convert to template' ) ],
554 qmstart
: [ 'VM' , gettext ( 'Start' ) ],
555 qmstop
: [ 'VM' , gettext ( 'Stop' ) ],
556 qmreset
: [ 'VM' , gettext ( 'Reset' ) ],
557 qmshutdown
: [ 'VM' , gettext ( 'Shutdown' ) ],
558 qmsuspend
: [ 'VM' , gettext ( 'Suspend' ) ],
559 qmresume
: [ 'VM' , gettext ( 'Resume' ) ],
560 qmconfig
: [ 'VM' , gettext ( 'Configure' ) ],
561 vzcreate
: [ 'CT' , gettext ( 'Create' ) ],
562 vzrestore
: [ 'CT' , gettext ( 'Restore' ) ],
563 vzdestroy
: [ 'CT' , gettext ( 'Destroy' ) ],
564 vzmigrate
: [ 'CT' , gettext ( 'Migrate' ) ],
565 vzstart
: [ 'CT' , gettext ( 'Start' ) ],
566 vzstop
: [ 'CT' , gettext ( 'Stop' ) ],
567 vzmount
: [ 'CT' , gettext ( 'Mount' ) ],
568 vzumount
: [ 'CT' , gettext ( 'Unmount' ) ],
569 vzshutdown
: [ 'CT' , gettext ( 'Shutdown' ) ],
570 hamigrate
: [ 'HA' , gettext ( 'Migrate' ) ],
571 hastart
: [ 'HA' , gettext ( 'Start' ) ],
572 hastop
: [ 'HA' , gettext ( 'Stop' ) ],
573 srvstart
: [ 'SRV' , gettext ( 'Start' ) ],
574 srvstop
: [ 'SRV' , gettext ( 'Stop' ) ],
575 srvrestart
: [ 'SRV' , gettext ( 'Restart' ) ],
576 srvreload
: [ 'SRV' , gettext ( 'Reload' ) ],
577 cephcreatemon
: [ 'Ceph Monitor' , gettext ( 'Create' ) ],
578 cephdestroymon
: [ 'Ceph Monitor' , gettext ( 'Destroy' ) ],
579 cephcreateosd
: [ 'Ceph OSD' , gettext ( 'Create' ) ],
580 cephdestroyosd
: [ 'Ceph OSD' , gettext ( 'Destroy' ) ],
581 imgcopy
: [ '' , gettext ( 'Copy data' ) ],
582 imgdel
: [ '' , gettext ( 'Erase data' ) ],
583 download
: [ '' , gettext ( 'Download' ) ],
584 vzdump
: [ '' , gettext ( 'Backup' ) ],
585 aptupdate
: [ '' , gettext ( 'Update package database' ) ],
586 startall
: [ '' , gettext ( 'Start all VMs and Containers' ) ],
587 stopall
: [ '' , gettext ( 'Stop all VMs and Containers' ) ]
590 format_task_description : function ( type
, id
) {
591 var farray
= PVE
. Utils
. task_desc_table
[ type
];
595 var prefix
= farray
[ 0 ];
596 var text
= farray
[ 1 ];
598 return prefix
+ ' ' + id
+ ' - ' + text
;
603 parse_task_upid : function ( upid
) {
606 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]+):$/ );
608 throw "unable to parse upid '" + upid
+ "'" ;
611 task
. pid
= parseInt ( res
[ 2 ], 16 );
612 task
. pstart
= parseInt ( res
[ 3 ], 16 );
613 task
. starttime
= parseInt ( res
[ 4 ], 16 );
618 task
. desc
= PVE
. Utils
. format_task_description ( task
. type
, task
. id
);
623 format_size : function ( size
) {
624 /*jslint confusion: true */
630 var kb
= size
/ 1024 ;
633 return kb
. toFixed ( 0 ) + "KB" ;
636 var mb
= size
/ ( 1024 * 1024 );
639 return mb
. toFixed ( 0 ) + "MB" ;
645 return gb
. toFixed ( 2 ) + "GB" ;
650 return tb
. toFixed ( 2 ) + "TB" ;
654 format_html_bar : function ( per
, text
) {
656 return "<div class='pve-bar-wrap'>" + text
+ "<div class='pve-bar-border'>" +
657 "<div class='pve-bar-inner' style='width:" + per
+ "%;'></div>" +
662 format_cpu_bar : function ( per1
, per2
, text
) {
664 return "<div class='pve-bar-border'>" +
665 "<div class='pve-bar-inner' style='width:" + per1
+ "%;'></div>" +
666 "<div class='pve-bar-inner2' style='width:" + per2
+ "%;'></div>" +
667 "<div class='pve-bar-text'>" + text
+ "</div>" +
671 format_large_bar : function ( per
, text
) {
674 text
= per
. toFixed ( 1 ) + "%" ;
677 return "<div class='pve-largebar-border'>" +
678 "<div class='pve-largebar-inner' style='width:" + per
+ "%;'></div>" +
679 "<div class='pve-largebar-text'>" + text
+ "</div>" +
683 format_duration_long : function ( ut
) {
685 var days
= Math
. floor ( ut
/ 86400 );
687 var hours
= Math
. floor ( ut
/ 3600 );
689 var mins
= Math
. floor ( ut
/ 60 );
692 var hours_str
= '00' + hours
. toString ();
693 hours_str
= hours_str
. substr ( hours_str
. length
- 2 );
694 var mins_str
= "00" + mins
. toString ();
695 mins_str
= mins_str
. substr ( mins_str
. length
- 2 );
696 var ut_str
= "00" + ut
. toString ();
697 ut_str
= ut_str
. substr ( ut_str
. length
- 2 );
700 var ds
= days
> 1 ? PVE
. Utils
. daysText
: PVE
. Utils
. dayText
;
701 return days
. toString () + ' ' + ds
+ ' ' +
702 hours_str
+ ':' + mins_str
+ ':' + ut_str
;
704 return hours_str
+ ':' + mins_str
+ ':' + ut_str
;
708 format_duration_short : function ( ut
) {
711 return ut
. toString () + 's' ;
716 return mins
. toFixed ( 0 ) + 'm' ;
720 var hours
= ut
/ 3600 ;
721 return hours
. toFixed ( 0 ) + 'h' ;
724 var days
= ut
/ 86400 ;
725 return days
. toFixed ( 0 ) + 'd' ;
728 yesText
: gettext ( 'Yes' ),
729 noText
: gettext ( 'No' ),
730 errorText
: gettext ( 'Error' ),
731 unknownText
: gettext ( 'Unknown' ),
732 defaultText
: gettext ( 'Default' ),
733 daysText
: gettext ( 'days' ),
734 dayText
: gettext ( 'day' ),
735 runningText
: gettext ( 'running' ),
736 stoppedText
: gettext ( 'stopped' ),
737 neverText
: gettext ( 'never' ),
738 totalText
: gettext ( 'Total' ),
739 usedText
: gettext ( 'Used' ),
741 format_expire : function ( date
) {
743 return PVE
. Utils
. neverText
;
745 return Ext
. Date
. format ( date
, "Y-m-d" );
748 format_storage_type : function ( value
) {
749 if ( value
=== 'dir' ) {
751 } else if ( value
=== 'nfs' ) {
753 } else if ( value
=== 'glusterfs' ) {
755 } else if ( value
=== 'lvm' ) {
757 } else if ( value
=== 'iscsi' ) {
759 } else if ( value
=== 'rbd' ) {
761 } else if ( value
=== 'sheepdog' ) {
763 } else if ( value
=== 'zfs' ) {
765 } else if ( value
=== 'iscsidirect' ) {
766 return 'iSCSIDirect' ;
768 return PVE
. Utils
. unknownText
;
772 format_boolean_with_default : function ( value
) {
773 if ( Ext
. isDefined ( value
) && value
!== '' ) {
774 return value
? PVE
. Utils
. yesText
: PVE
. Utils
. noText
;
776 return PVE
. Utils
. defaultText
;
779 format_boolean : function ( value
) {
780 return value
? PVE
. Utils
. yesText
: PVE
. Utils
. noText
;
783 format_neg_boolean : function ( value
) {
784 return ! value
? PVE
. Utils
. yesText
: PVE
. Utils
. noText
;
787 format_content_types : function ( value
) {
790 Ext
. each ( value
. split ( ',' ). sort (), function ( ct
) {
791 if ( ct
=== 'images' ) {
793 } else if ( ct
=== 'backup' ) {
795 } else if ( ct
=== 'vztmpl' ) {
796 cta
. push ( 'Templates' );
797 } else if ( ct
=== 'iso' ) {
799 } else if ( ct
=== 'rootdir' ) {
800 cta
. push ( 'Containers' );
804 return cta
. join ( ', ' );
807 render_storage_content : function ( value
, metaData
, record
) {
808 var data
= record
. data
;
809 if ( Ext
. isNumber ( data
. channel
) &&
810 Ext
. isNumber ( data
. id
) &&
811 Ext
. isNumber ( data
. lun
)) {
813 Ext
. String
. leftPad ( data
. channel
, 2 , '0' ) +
814 " ID " + data
. id
+ " LUN " + data
. lun
;
816 return data
. volid
. replace ( /^.*:(.*\/)?/ , '' );
819 render_serverity : function ( value
) {
820 return PVE
. Utils
. log_severity_hash
[ value
] || value
;
823 render_cpu : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
825 if (!( record
. data
. uptime
&& Ext
. isNumeric ( value
))) {
829 var maxcpu
= record
. data
. maxcpu
|| 1 ;
831 if (! Ext
. isNumeric ( maxcpu
) && ( maxcpu
>= 1 )) {
835 var per
= value
* 100 ;
837 return per
. toFixed ( 1 ) + '% of ' + maxcpu
. toString () + ( maxcpu
> 1 ? 'CPUs' : 'CPU' );
840 render_size : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
841 /*jslint confusion: true */
843 if (! Ext
. isNumeric ( value
)) {
847 return PVE
. Utils
. format_size ( value
);
850 render_timestamp : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
851 var servertime
= new Date ( value
* 1000 );
852 return Ext
. Date
. format ( servertime
, 'Y-m-d H:i:s' );
855 render_mem_usage : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
858 var maxmem
= record
. data
. maxmem
;
860 if (! record
. data
. uptime
) {
864 if (!( Ext
. isNumeric ( mem
) && maxmem
)) {
868 var per
= ( mem
* 100 ) / maxmem
;
870 return per
. toFixed ( 1 ) + '%' ;
873 render_disk_usage : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
876 var maxdisk
= record
. data
. maxdisk
;
878 if (!( Ext
. isNumeric ( disk
) && maxdisk
)) {
882 var per
= ( disk
* 100 ) / maxdisk
;
884 return per
. toFixed ( 1 ) + '%' ;
887 render_resource_type : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
889 var cls
= 'pve-itype-icon-' + value
;
891 if ( record
. data
. running
) {
892 metaData
. tdCls
= cls
+ "-running" ;
893 } else if ( record
. data
. template
) {
894 metaData
. tdCls
= cls
+ "-template" ;
896 metaData
. tdCls
= cls
;
902 render_uptime : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
906 if ( uptime
=== undefined ) {
914 return PVE
. Utils
. format_duration_long ( uptime
);
917 render_support_level : function ( value
, metaData
, record
) {
918 return PVE
. Utils
. support_level_hash
[ value
] || '-' ;
921 render_upid : function ( value
, metaData
, record
) {
922 var type
= record
. data
. type
;
923 var id
= record
. data
. id
;
925 return PVE
. Utils
. format_task_description ( type
, id
);
928 dialog_title : function ( subject
, create
, isAdd
) {
931 return gettext ( 'Add' ) + ': ' + subject
;
933 return gettext ( 'Create' ) + ': ' + subject
;
936 return gettext ( 'Edit' ) + ': ' + subject
;
940 openConsoleWindow : function ( vmtype
, vmid
, nodename
, vmname
) {
941 var url
= Ext
. urlEncode ({
942 console
: vmtype
, // kvm, openvz or shell
947 var nw
= window
. open ( "?" + url
, '_blank' ,
948 "innerWidth=745,innerheight=427" );
952 defaultViewer : function (){
953 return PVE
. VersionInfo
. console
|| 'applet' ;
957 openSpiceViewer : function ( url
, params
){
959 var downloadWithName = function ( uri
, name
) {
960 var link
= Ext
. DomHelper
. append ( document
. body
, {
963 css
: 'display:none;visibility:hidden;height:0px;'
966 // Note: we need to tell android the correct file name extension
967 // but we do not set 'download' tag for other environments, because
968 // It can have strange side effects (additional user prompt on firefox)
969 var andriod
= navigator
. userAgent
. match ( /Android/i ) ? true : false ;
971 link
. download
= name
;
974 if ( link
. fireEvent
) {
975 link
. fireEvent ( 'onclick' );
977 var evt
= document
. createEvent ( "MouseEvents" );
978 evt
. initMouseEvent ( 'click' , true , true , window
, 1 , 0 , 0 , 0 , 0 , false , false , false , false , 0 , null );
979 link
. dispatchEvent ( evt
);
983 PVE
. Utils
. API2Request ({
987 failure : function ( response
, opts
){
988 Ext
. Msg
. alert ( 'Error' , response
. htmlStatus
);
990 success : function ( response
, opts
){
991 var raw
= "[virt-viewer] \n " ;
992 Ext
. Object
. each ( response
. result
. data
, function ( k
, v
) {
993 raw
+= k
+ "=" + v
+ " \n " ;
995 var url
= 'data:application/x-virt-viewer;charset=UTF-8,' +
996 encodeURIComponent ( raw
);
998 downloadWithName ( url
, "pve-spice.vv" );
1003 // comp.setLoading() is buggy in ExtJS 4.0.7, so we
1004 // use el.mask() instead
1005 setErrorMask : function ( comp
, msg
) {
1014 el
. mask ( gettext ( "Loading..." ));
1021 monStoreErrors : function ( me
, store
) {
1022 me
. mon ( store
, 'beforeload' , function ( s
, operation
, eOpts
) {
1023 if (! me
. loadCount
) {
1024 me
. loadCount
= 0 ; // make sure it is numeric
1025 PVE
. Utils
. setErrorMask ( me
, true );
1029 // only works with 'pve' proxy
1030 me
. mon ( store
. proxy
, 'afterload' , function ( proxy
, request
, success
) {
1034 PVE
. Utils
. setErrorMask ( me
, false );
1039 var operation
= request
. operation
;
1040 var error
= operation
. getError ();
1041 if ( error
. statusText
) {
1042 msg
= error
. statusText
+ ' (' + error
. status
+ ')' ;
1044 msg
= gettext ( 'Connection error' );
1046 PVE
. Utils
. setErrorMask ( me
, msg
);