]>
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 ( 'Ext.ux.IFrame' , {
123 extend
: 'Ext.Component' ,
125 alias
: 'widget.uxiframe' ,
127 loadMask
: 'Loading...' ,
132 '<iframe src="{src}" name="{frameName}" width="100%" height="100%" frameborder="0"></iframe>'
135 initComponent : function () {
138 this . frameName
= this . frameName
|| this . id
+ '-frame' ;
145 Ext
. apply ( this . renderSelectors
, {
150 initEvents : function () {
153 me
. iframeEl
. on ( 'load' , me
. onLoad
, me
);
156 initRenderData : function () {
157 return Ext
. apply ( this . callParent (), {
159 frameName
: this . frameName
163 getBody : function () {
164 var doc
= this . getDoc ();
165 return doc
. body
|| doc
. documentElement
;
170 return this . getWin (). document
;
180 ? me
. iframeEl
. dom
. contentWindow
181 : window
. frames
[ name
];
185 getFrame : function () {
187 return me
. iframeEl
. dom
;
190 beforeDestroy : function () {
191 this . cleanupListeners ( true );
195 cleanupListeners : function ( destroying
){
202 Ext
. EventManager
. removeAll ( doc
);
205 if ( doc
. hasOwnProperty
&& doc
. hasOwnProperty ( prop
)) {
218 fn
= me
. onRelayedEvent
;
222 Ext
. EventManager
. removeAll ( doc
);
224 // These events need to be relayed from the inner document (where they stop
225 // bubbling) up to the outer document. This has to be done at the DOM level so
226 // the event reaches listeners on elements like the document body. The effected
227 // mechanisms that depend on this bubbling behavior are listed to the right
229 Ext
. EventManager
. on ( doc
, {
230 mousedown
: fn
, // menu dismisal (MenuManager) and Window onMouseDown (toFront)
231 mousemove
: fn
, // window resize drag detection
232 mouseup
: fn
, // window resize termination
233 click
: fn
, // not sure, but just to be safe
234 dblclick
: fn
, // not sure again
238 // cannot do this xss
241 // We need to be sure we remove all our events from the iframe on unload or we're going to LEAK!
242 Ext
. EventManager
. on ( this . getWin (), 'beforeunload' , me
. cleanupListeners
, me
);
245 this . fireEvent ( 'load' , this );
247 } else if ( me
. src
&& me
. src
!= '' ) {
250 this . fireEvent ( 'error' , this );
256 load : function ( src
) {
259 frame
= me
. getFrame ();
261 if ( me
. fireEvent ( 'beforeload' , me
, src
) !== false ) {
266 frame
. src
= me
. src
= ( src
|| me
. src
);
271 Ext
. define ( 'PVE.Utils' , { statics
: {
273 // this class only contains static functions
286 support_level_hash
: {
287 'c' : gettext ( 'Community' ),
288 'b' : gettext ( 'Basic' ),
289 's' : gettext ( 'Standard' ),
290 'p' : gettext ( 'Premium' )
293 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.' ,
296 other
: gettext ( 'Other OS types' ),
297 wxp
: 'Microsoft Windows XP/2003' ,
298 w2k
: 'Microsoft Windows 2000' ,
299 w2k8
: 'Microsoft Windows Vista/2008' ,
300 win7
: 'Microsoft Windows 7/2008r2' ,
301 win8
: 'Microsoft Windows 8/2012' ,
302 l24
: 'Linux 2.4 Kernel' ,
303 l26
: 'Linux 3.X/2.6 Kernel' ,
304 solaris
: 'Solaris Kernel'
307 render_kvm_ostype : function ( value
) {
309 return gettext ( 'Other OS types' );
311 var text
= PVE
. Utils
. kvm_ostypes
[ value
];
313 return text
+ ' (' + value
+ ')' ;
318 network_iface_types
: {
319 eth
: gettext ( "Network Device" ),
320 bridge
: 'Linux Bridge' ,
322 OVSBridge
: 'OVS Bridge' ,
325 OVSIntPort
: 'OVS IntPort'
328 render_network_iface_type : function ( value
) {
329 return PVE
. Utils
. network_iface_types
[ value
] ||
330 PVE
. Utils
. unknownText
;
333 render_scsihw : function ( value
) {
335 return PVE
. Utils
. defaultText
+ ' (LSI 53C895A)' ;
336 } else if ( value
=== 'lsi' ) {
337 return 'LSI 53C895A' ;
338 } else if ( value
=== 'lsi53c810' ) {
340 } else if ( value
=== 'megasas' ) {
341 return 'MegaRAID SAS 8708EM2' ;
342 } else if ( value
=== 'virtio-scsi-pci' ) {
344 } else if ( value
=== 'pvscsi' ) {
345 return 'VMware PVSCSI' ;
351 // fixme: auto-generate this
352 // for now, please keep in sync with PVE::Tools::kvmkeymaps
357 'de-ch' : 'German (Swiss)' ,
358 'en-gb' : 'English (UK)' ,
359 'en-us' : 'English (USA' ,
363 //fo: 'Faroe Islands',
365 'fr-be' : 'French (Belgium)' ,
366 'fr-ca' : 'French (Canada)' ,
367 'fr-ch' : 'French (Swiss)' ,
377 //'nl-be': 'Dutch (Belgium)',
381 'pt-br' : 'Portuguese (Brazil)' ,
390 std
: gettext ( 'Standard VGA' ),
391 vmware
: gettext ( 'VMWare compatible' ),
392 cirrus
: 'Cirrus Logic GD5446' ,
394 qxl2
: 'SPICE dual monitor' ,
395 qxl3
: 'SPICE three monitors' ,
396 qxl4
: 'SPICE four monitors' ,
397 serial0
: gettext ( 'Serial terminal' ) + ' 0' ,
398 serial1
: gettext ( 'Serial terminal' ) + ' 1' ,
399 serial2
: gettext ( 'Serial terminal' ) + ' 2' ,
400 serial3
: gettext ( 'Serial terminal' ) + ' 3'
403 render_kvm_language : function ( value
) {
405 return PVE
. Utils
. defaultText
;
407 var text
= PVE
. Utils
. kvm_keymaps
[ value
];
409 return text
+ ' (' + value
+ ')' ;
414 kvm_keymap_array : function () {
415 var data
= [[ '' , PVE
. Utils
. render_kvm_language ( '' )]];
416 Ext
. Object
. each ( PVE
. Utils
. kvm_keymaps
, function ( key
, value
) {
417 data
. push ([ key
, PVE
. Utils
. render_kvm_language ( value
)]);
423 render_console_viewer : function ( value
) {
425 return PVE
. Utils
. defaultText
+ ' (Java VNC Applet)' ;
426 } else if ( value
=== 'applet' ) {
427 return 'Java VNC Applet' ;
428 } else if ( value
=== 'vv' ) {
429 return 'SPICE (remote-viewer)' ;
443 eu
: 'Euskera (Basque)' ,
446 nb
: 'Norwegian (Bokmal)' ,
447 nn
: 'Norwegian (Nynorsk)' ,
452 pt_BR
: 'Portuguese (Brazil)' ,
456 render_language : function ( value
) {
458 return PVE
. Utils
. defaultText
+ ' (English)' ;
460 var text
= PVE
. Utils
. language_map
[ value
];
462 return text
+ ' (' + value
+ ')' ;
467 language_array : function () {
468 var data
= [[ '' , PVE
. Utils
. render_language ( '' )]];
469 Ext
. Object
. each ( PVE
. Utils
. language_map
, function ( key
, value
) {
470 data
. push ([ key
, PVE
. Utils
. render_language ( value
)]);
476 render_kvm_vga_driver : function ( value
) {
478 return PVE
. Utils
. defaultText
;
480 var text
= PVE
. Utils
. kvm_vga_drivers
[ value
];
482 return text
+ ' (' + value
+ ')' ;
487 kvm_vga_driver_array : function () {
488 var data
= [[ '' , PVE
. Utils
. render_kvm_vga_driver ( '' )]];
489 Ext
. Object
. each ( PVE
. Utils
. kvm_vga_drivers
, function ( key
, value
) {
490 data
. push ([ key
, PVE
. Utils
. render_kvm_vga_driver ( value
)]);
496 render_kvm_startup : function ( value
) {
497 var startup
= PVE
. Parser
. parseStartup ( value
);
500 if ( startup
. order
=== undefined ) {
503 res
+= startup
. order
;
505 if ( startup
. up
!== undefined ) {
506 res
+= ',up=' + startup
. up
;
508 if ( startup
. down
!== undefined ) {
509 res
+= ',down=' + startup
. down
;
516 return Ext
. util
. Cookies
. get ( 'PVEAuthCookie' );
519 authClear : function () {
520 Ext
. util
. Cookies
. clear ( "PVEAuthCookie" );
523 // fixme: remove - not needed?
524 gridLineHeigh : function () {
532 extractRequestError : function ( result
, verbose
) {
533 var msg
= gettext ( 'Successful' );
535 if (! result
. success
) {
536 msg
= gettext ( "Unknown error" );
537 if ( result
. message
) {
538 msg
= result
. message
;
540 msg
+= ' (' + result
. status
+ ')' ;
543 if ( verbose
&& Ext
. isObject ( result
. errors
)) {
545 Ext
. Object
. each ( result
. errors
, function ( prop
, desc
) {
546 msg
+= "<br><b>" + Ext
. htmlEncode ( prop
) + "</b>: " +
547 Ext
. htmlEncode ( desc
);
555 extractFormActionError : function ( action
) {
557 switch ( action
. failureType
) {
558 case Ext
. form
. action
. Action
. CLIENT_INVALID
:
559 msg
= gettext ( 'Form fields may not be submitted with invalid values' );
561 case Ext
. form
. action
. Action
. CONNECT_FAILURE
:
562 msg
= gettext ( 'Connection error' );
563 var resp
= action
. response
;
564 if ( resp
. status
&& resp
. statusText
) {
565 msg
+= " " + resp
. status
+ ": " + resp
. statusText
;
568 case Ext
. form
. action
. Action
. LOAD_FAILURE
:
569 case Ext
. form
. action
. Action
. SERVER_INVALID
:
570 msg
= PVE
. Utils
. extractRequestError ( action
. result
, true );
577 API2Request : function ( reqOpts
) {
579 var newopts
= Ext
. apply ({
580 waitMsg
: gettext ( 'Please wait...' )
583 if (! newopts
. url
. match ( /^\/api2/ )) {
584 newopts
. url
= '/api2/extjs' + newopts
. url
;
586 delete newopts
. callback
;
588 var createWrapper = function ( successFn
, callbackFn
, failureFn
) {
590 success : function ( response
, options
) {
591 if ( options
. waitMsgTarget
) {
592 options
. waitMsgTarget
. setLoading ( false );
594 var result
= Ext
. decode ( response
. responseText
);
595 response
. result
= result
;
596 if (! result
. success
) {
597 response
. htmlStatus
= PVE
. Utils
. extractRequestError ( result
, true );
598 Ext
. callback ( callbackFn
, options
. scope
, [ options
, false , response
]);
599 Ext
. callback ( failureFn
, options
. scope
, [ response
, options
]);
602 Ext
. callback ( callbackFn
, options
. scope
, [ options
, true , response
]);
603 Ext
. callback ( successFn
, options
. scope
, [ response
, options
]);
605 failure : function ( response
, options
) {
606 if ( options
. waitMsgTarget
) {
607 options
. waitMsgTarget
. setLoading ( false );
609 response
. result
= {};
611 response
. result
= Ext
. decode ( response
. responseText
);
613 var msg
= gettext ( 'Connection error' ) + ' - server offline?' ;
614 if ( response
. aborted
) {
615 msg
= gettext ( 'Connection error' ) + ' - aborted.' ;
616 } else if ( response
. timedout
) {
617 msg
= gettext ( 'Connection error' ) + ' - Timeout.' ;
618 } else if ( response
. status
&& response
. statusText
) {
619 msg
= gettext ( 'Connection error' ) + ' ' + response
. status
+ ': ' + response
. statusText
;
621 response
. htmlStatus
= msg
;
622 Ext
. callback ( callbackFn
, options
. scope
, [ options
, false , response
]);
623 Ext
. callback ( failureFn
, options
. scope
, [ response
, options
]);
628 createWrapper ( reqOpts
. success
, reqOpts
. callback
, reqOpts
. failure
);
630 var target
= newopts
. waitMsgTarget
;
632 // Note: ExtJS bug - this does not work when component is not rendered
633 target
. setLoading ( newopts
. waitMsg
);
635 Ext
. Ajax
. request ( newopts
);
638 assemble_field_data : function ( values
, data
) {
639 if ( Ext
. isObject ( data
)) {
640 Ext
. Object
. each ( data
, function ( name
, val
) {
641 if ( values
. hasOwnProperty ( name
)) {
642 var bucket
= values
[ name
];
643 if (! Ext
. isArray ( bucket
)) {
644 bucket
= values
[ name
] = [ bucket
];
646 if ( Ext
. isArray ( val
)) {
647 values
[ name
] = bucket
. concat ( val
);
658 checked_command : function ( orig_cmd
) {
659 PVE
. Utils
. API2Request ({
660 url
: '/nodes/localhost/subscription' ,
663 failure : function ( response
, opts
) {
664 Ext
. Msg
. alert ( gettext ( 'Error' ), response
. htmlStatus
);
666 success : function ( response
, opts
) {
667 var data
= response
. result
. data
;
669 if ( data
. status
!== 'Active' ) {
671 title
: gettext ( 'No valid subscription' ),
672 icon
: Ext
. Msg
. WARNING
,
673 msg
: PVE
. Utils
. noSubKeyHtml
,
675 callback : function ( btn
) {
690 vncproxy
: [ 'VM/CT' , gettext ( 'Console' ) ],
691 spiceproxy
: [ 'VM/CT' , gettext ( 'Console' ) + ' (Spice)' ],
692 vncshell
: [ '' , gettext ( 'Shell' ) ],
693 spiceshell
: [ '' , gettext ( 'Shell' ) + ' (Spice)' ],
694 qmsnapshot
: [ 'VM' , gettext ( 'Snapshot' ) ],
695 qmrollback
: [ 'VM' , gettext ( 'Rollback' ) ],
696 qmdelsnapshot
: [ 'VM' , gettext ( 'Delete Snapshot' ) ],
697 qmcreate
: [ 'VM' , gettext ( 'Create' ) ],
698 qmrestore
: [ 'VM' , gettext ( 'Restore' ) ],
699 qmdestroy
: [ 'VM' , gettext ( 'Destroy' ) ],
700 qmigrate
: [ 'VM' , gettext ( 'Migrate' ) ],
701 qmclone
: [ 'VM' , gettext ( 'Clone' ) ],
702 qmmove
: [ 'VM' , gettext ( 'Move disk' ) ],
703 qmtemplate
: [ 'VM' , gettext ( 'Convert to template' ) ],
704 qmstart
: [ 'VM' , gettext ( 'Start' ) ],
705 qmstop
: [ 'VM' , gettext ( 'Stop' ) ],
706 qmreset
: [ 'VM' , gettext ( 'Reset' ) ],
707 qmshutdown
: [ 'VM' , gettext ( 'Shutdown' ) ],
708 qmsuspend
: [ 'VM' , gettext ( 'Suspend' ) ],
709 qmresume
: [ 'VM' , gettext ( 'Resume' ) ],
710 qmconfig
: [ 'VM' , gettext ( 'Configure' ) ],
711 vzcreate
: [ 'CT' , gettext ( 'Create' ) ],
712 vzrestore
: [ 'CT' , gettext ( 'Restore' ) ],
713 vzdestroy
: [ 'CT' , gettext ( 'Destroy' ) ],
714 vzmigrate
: [ 'CT' , gettext ( 'Migrate' ) ],
715 vzstart
: [ 'CT' , gettext ( 'Start' ) ],
716 vzstop
: [ 'CT' , gettext ( 'Stop' ) ],
717 vzmount
: [ 'CT' , gettext ( 'Mount' ) ],
718 vzumount
: [ 'CT' , gettext ( 'Unmount' ) ],
719 vzshutdown
: [ 'CT' , gettext ( 'Shutdown' ) ],
720 hamigrate
: [ 'HA' , gettext ( 'Migrate' ) ],
721 hastart
: [ 'HA' , gettext ( 'Start' ) ],
722 hastop
: [ 'HA' , gettext ( 'Stop' ) ],
723 srvstart
: [ 'SRV' , gettext ( 'Start' ) ],
724 srvstop
: [ 'SRV' , gettext ( 'Stop' ) ],
725 srvrestart
: [ 'SRV' , gettext ( 'Restart' ) ],
726 srvreload
: [ 'SRV' , gettext ( 'Reload' ) ],
727 cephcreatemon
: [ 'Ceph Monitor' , gettext ( 'Create' ) ],
728 cephdestroymon
: [ 'Ceph Monitor' , gettext ( 'Destroy' ) ],
729 cephcreateosd
: [ 'Ceph OSD' , gettext ( 'Create' ) ],
730 cephdestroyosd
: [ 'Ceph OSD' , gettext ( 'Destroy' ) ],
731 imgcopy
: [ '' , gettext ( 'Copy data' ) ],
732 imgdel
: [ '' , gettext ( 'Erase data' ) ],
733 download
: [ '' , gettext ( 'Download' ) ],
734 vzdump
: [ '' , gettext ( 'Backup' ) ],
735 aptupdate
: [ '' , gettext ( 'Update package database' ) ],
736 startall
: [ '' , gettext ( 'Start all VMs and Containers' ) ],
737 stopall
: [ '' , gettext ( 'Stop all VMs and Containers' ) ]
740 format_task_description : function ( type
, id
) {
741 var farray
= PVE
. Utils
. task_desc_table
[ type
];
745 var prefix
= farray
[ 0 ];
746 var text
= farray
[ 1 ];
748 return prefix
+ ' ' + id
+ ' - ' + text
;
753 parse_task_upid : function ( upid
) {
756 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]+):$/ );
758 throw "unable to parse upid '" + upid
+ "'" ;
761 task
. pid
= parseInt ( res
[ 2 ], 16 );
762 task
. pstart
= parseInt ( res
[ 3 ], 16 );
763 task
. starttime
= parseInt ( res
[ 4 ], 16 );
768 task
. desc
= PVE
. Utils
. format_task_description ( task
. type
, task
. id
);
773 format_size : function ( size
) {
774 /*jslint confusion: true */
780 var kb
= size
/ 1024 ;
783 return kb
. toFixed ( 0 ) + "KB" ;
786 var mb
= size
/ ( 1024 * 1024 );
789 return mb
. toFixed ( 0 ) + "MB" ;
795 return gb
. toFixed ( 2 ) + "GB" ;
800 return tb
. toFixed ( 2 ) + "TB" ;
804 format_html_bar : function ( per
, text
) {
806 return "<div class='pve-bar-wrap'>" + text
+ "<div class='pve-bar-border'>" +
807 "<div class='pve-bar-inner' style='width:" + per
+ "%;'></div>" +
812 format_cpu_bar : function ( per1
, per2
, text
) {
814 return "<div class='pve-bar-border'>" +
815 "<div class='pve-bar-inner' style='width:" + per1
+ "%;'></div>" +
816 "<div class='pve-bar-inner2' style='width:" + per2
+ "%;'></div>" +
817 "<div class='pve-bar-text'>" + text
+ "</div>" +
821 format_large_bar : function ( per
, text
) {
824 text
= per
. toFixed ( 1 ) + "%" ;
827 return "<div class='pve-largebar-border'>" +
828 "<div class='pve-largebar-inner' style='width:" + per
+ "%;'></div>" +
829 "<div class='pve-largebar-text'>" + text
+ "</div>" +
833 format_duration_long : function ( ut
) {
835 var days
= Math
. floor ( ut
/ 86400 );
837 var hours
= Math
. floor ( ut
/ 3600 );
839 var mins
= Math
. floor ( ut
/ 60 );
842 var hours_str
= '00' + hours
. toString ();
843 hours_str
= hours_str
. substr ( hours_str
. length
- 2 );
844 var mins_str
= "00" + mins
. toString ();
845 mins_str
= mins_str
. substr ( mins_str
. length
- 2 );
846 var ut_str
= "00" + ut
. toString ();
847 ut_str
= ut_str
. substr ( ut_str
. length
- 2 );
850 var ds
= days
> 1 ? PVE
. Utils
. daysText
: PVE
. Utils
. dayText
;
851 return days
. toString () + ' ' + ds
+ ' ' +
852 hours_str
+ ':' + mins_str
+ ':' + ut_str
;
854 return hours_str
+ ':' + mins_str
+ ':' + ut_str
;
858 format_duration_short : function ( ut
) {
861 return ut
. toString () + 's' ;
866 return mins
. toFixed ( 0 ) + 'm' ;
870 var hours
= ut
/ 3600 ;
871 return hours
. toFixed ( 0 ) + 'h' ;
874 var days
= ut
/ 86400 ;
875 return days
. toFixed ( 0 ) + 'd' ;
878 yesText
: gettext ( 'Yes' ),
879 noText
: gettext ( 'No' ),
880 errorText
: gettext ( 'Error' ),
881 unknownText
: gettext ( 'Unknown' ),
882 defaultText
: gettext ( 'Default' ),
883 daysText
: gettext ( 'days' ),
884 dayText
: gettext ( 'day' ),
885 runningText
: gettext ( 'running' ),
886 stoppedText
: gettext ( 'stopped' ),
887 neverText
: gettext ( 'never' ),
888 totalText
: gettext ( 'Total' ),
889 usedText
: gettext ( 'Used' ),
891 format_expire : function ( date
) {
893 return PVE
. Utils
. neverText
;
895 return Ext
. Date
. format ( date
, "Y-m-d" );
898 format_storage_type : function ( value
) {
899 if ( value
=== 'dir' ) {
901 } else if ( value
=== 'nfs' ) {
903 } else if ( value
=== 'glusterfs' ) {
905 } else if ( value
=== 'lvm' ) {
907 } else if ( value
=== 'iscsi' ) {
909 } else if ( value
=== 'rbd' ) {
911 } else if ( value
=== 'sheepdog' ) {
913 } else if ( value
=== 'zfs' ) {
915 } else if ( value
=== 'iscsidirect' ) {
916 return 'iSCSIDirect' ;
918 return PVE
. Utils
. unknownText
;
922 format_boolean_with_default : function ( value
) {
923 if ( Ext
. isDefined ( value
) && value
!== '' ) {
924 return value
? PVE
. Utils
. yesText
: PVE
. Utils
. noText
;
926 return PVE
. Utils
. defaultText
;
929 format_boolean : function ( value
) {
930 return value
? PVE
. Utils
. yesText
: PVE
. Utils
. noText
;
933 format_neg_boolean : function ( value
) {
934 return ! value
? PVE
. Utils
. yesText
: PVE
. Utils
. noText
;
937 format_content_types : function ( value
) {
940 Ext
. each ( value
. split ( ',' ). sort (), function ( ct
) {
941 if ( ct
=== 'images' ) {
943 } else if ( ct
=== 'backup' ) {
945 } else if ( ct
=== 'vztmpl' ) {
946 cta
. push ( 'Templates' );
947 } else if ( ct
=== 'iso' ) {
949 } else if ( ct
=== 'rootdir' ) {
950 cta
. push ( 'Containers' );
954 return cta
. join ( ', ' );
957 render_storage_content : function ( value
, metaData
, record
) {
958 var data
= record
. data
;
959 if ( Ext
. isNumber ( data
. channel
) &&
960 Ext
. isNumber ( data
. id
) &&
961 Ext
. isNumber ( data
. lun
)) {
963 Ext
. String
. leftPad ( data
. channel
, 2 , '0' ) +
964 " ID " + data
. id
+ " LUN " + data
. lun
;
966 return data
. volid
. replace ( /^.*:(.*\/)?/ , '' );
969 render_serverity : function ( value
) {
970 return PVE
. Utils
. log_severity_hash
[ value
] || value
;
973 render_cpu : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
975 if (!( record
. data
. uptime
&& Ext
. isNumeric ( value
))) {
979 var maxcpu
= record
. data
. maxcpu
|| 1 ;
981 if (! Ext
. isNumeric ( maxcpu
) && ( maxcpu
>= 1 )) {
985 var per
= value
* 100 ;
987 return per
. toFixed ( 1 ) + '% of ' + maxcpu
. toString () + ( maxcpu
> 1 ? 'CPUs' : 'CPU' );
990 render_size : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
991 /*jslint confusion: true */
993 if (! Ext
. isNumeric ( value
)) {
997 return PVE
. Utils
. format_size ( value
);
1000 render_timestamp : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
1001 var servertime
= new Date ( value
* 1000 );
1002 return Ext
. Date
. format ( servertime
, 'Y-m-d H:i:s' );
1005 render_mem_usage : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
1008 var maxmem
= record
. data
. maxmem
;
1010 if (! record
. data
. uptime
) {
1014 if (!( Ext
. isNumeric ( mem
) && maxmem
)) {
1018 var per
= ( mem
* 100 ) / maxmem
;
1020 return per
. toFixed ( 1 ) + '%' ;
1023 render_disk_usage : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
1026 var maxdisk
= record
. data
. maxdisk
;
1028 if (!( Ext
. isNumeric ( disk
) && maxdisk
)) {
1032 var per
= ( disk
* 100 ) / maxdisk
;
1034 return per
. toFixed ( 1 ) + '%' ;
1037 render_resource_type : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
1039 var cls
= 'pve-itype-icon-' + value
;
1041 if ( record
. data
. running
) {
1042 metaData
. tdCls
= cls
+ "-running" ;
1043 } else if ( record
. data
. template
) {
1044 metaData
. tdCls
= cls
+ "-template" ;
1046 metaData
. tdCls
= cls
;
1052 render_uptime : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
1056 if ( uptime
=== undefined ) {
1064 return PVE
. Utils
. format_duration_long ( uptime
);
1067 render_support_level : function ( value
, metaData
, record
) {
1068 return PVE
. Utils
. support_level_hash
[ value
] || '-' ;
1071 render_upid : function ( value
, metaData
, record
) {
1072 var type
= record
. data
. type
;
1073 var id
= record
. data
. id
;
1075 return PVE
. Utils
. format_task_description ( type
, id
);
1078 dialog_title : function ( subject
, create
, isAdd
) {
1081 return gettext ( 'Add' ) + ': ' + subject
;
1083 return gettext ( 'Create' ) + ': ' + subject
;
1086 return gettext ( 'Edit' ) + ': ' + subject
;
1090 openConsoleWindow : function ( vmtype
, vmid
, nodename
, vmname
) {
1091 var url
= Ext
. urlEncode ({
1092 console
: vmtype
, // kvm, openvz or shell
1097 var nw
= window
. open ( "?" + url
, '_blank' ,
1098 "innerWidth=745,innerheight=427" );
1102 defaultViewer : function (){
1103 return PVE
. VersionInfo
. console
|| 'applet' ;
1107 openSpiceViewer : function ( url
, params
){
1109 var downloadWithName = function ( uri
, name
) {
1110 var link
= Ext
. DomHelper
. append ( document
. body
, {
1113 css
: 'display:none;visibility:hidden;height:0px;'
1116 // Note: we need to tell android the correct file name extension
1117 // but we do not set 'download' tag for other environments, because
1118 // It can have strange side effects (additional user prompt on firefox)
1119 var andriod
= navigator
. userAgent
. match ( /Android/i ) ? true : false ;
1121 link
. download
= name
;
1124 if ( link
. fireEvent
) {
1125 link
. fireEvent ( 'onclick' );
1127 var evt
= document
. createEvent ( "MouseEvents" );
1128 evt
. initMouseEvent ( 'click' , true , true , window
, 1 , 0 , 0 , 0 , 0 , false , false , false , false , 0 , null );
1129 link
. dispatchEvent ( evt
);
1133 PVE
. Utils
. API2Request ({
1137 failure : function ( response
, opts
){
1138 Ext
. Msg
. alert ( 'Error' , response
. htmlStatus
);
1140 success : function ( response
, opts
){
1141 var raw
= "[virt-viewer] \n " ;
1142 Ext
. Object
. each ( response
. result
. data
, function ( k
, v
) {
1143 raw
+= k
+ "=" + v
+ " \n " ;
1145 var url
= 'data:application/x-virt-viewer;charset=UTF-8,' +
1146 encodeURIComponent ( raw
);
1148 downloadWithName ( url
, "pve-spice.vv" );
1153 // comp.setLoading() is buggy in ExtJS 4.0.7, so we
1154 // use el.mask() instead
1155 setErrorMask : function ( comp
, msg
) {
1164 el
. mask ( gettext ( "Loading..." ));
1171 monStoreErrors : function ( me
, store
) {
1172 me
. mon ( store
, 'beforeload' , function ( s
, operation
, eOpts
) {
1173 if (! me
. loadCount
) {
1174 me
. loadCount
= 0 ; // make sure it is numeric
1175 PVE
. Utils
. setErrorMask ( me
, true );
1179 // only works with 'pve' proxy
1180 me
. mon ( store
. proxy
, 'afterload' , function ( proxy
, request
, success
) {
1184 PVE
. Utils
. setErrorMask ( me
, false );
1189 var operation
= request
. operation
;
1190 var error
= operation
. getError ();
1191 if ( error
. statusText
) {
1192 msg
= error
. statusText
+ ' (' + error
. status
+ ')' ;
1194 msg
= gettext ( 'Connection error' );
1196 PVE
. Utils
. setErrorMask ( me
, msg
);