]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/Workspace.js
ui: save ui options from /cluster/options instead of version
[pve-manager.git] / www / manager6 / Workspace.js
CommitLineData
787ae72a
DM
1/*
2 * Workspace base class
3 *
4 * popup login window when auth fails (call onLogin handler)
5 * update (re-login) ticket every 15 minutes
6 *
7 */
8
9Ext.define('PVE.Workspace', {
10 extend: 'Ext.container.Viewport',
11
12 title: 'Proxmox Virtual Environment',
13
14 loginData: null, // Data from last login call
15
063997ed
TL
16 onLogin: function(loginData) {
17 // override me
18 },
787ae72a
DM
19
20 // private
21 updateLoginData: function(loginData) {
063997ed 22 let me = this;
787ae72a 23 me.loginData = loginData;
24d2ed8c 24 Proxmox.Utils.setAuthData(loginData);
787ae72a 25
063997ed 26 let rt = me.down('pveResourceTree');
3d7b2aa9 27 rt.setDatacenterText(loginData.clustername);
9ebe2165 28 PVE.ClusterName = loginData.clustername;
3d7b2aa9 29
787ae72a
DM
30 if (loginData.cap) {
31 Ext.state.Manager.set('GuiCap', loginData.cap);
32 }
1370f628 33 me.response401count = 0;
787ae72a 34
787ae72a
DM
35 me.onLogin(loginData);
36 },
37
38 // private
39 showLogin: function() {
063997ed 40 let me = this;
787ae72a 41
e7ade592 42 Proxmox.Utils.authClear();
9fd1198e 43 Ext.state.Manager.clear('GuiCap');
35a04562 44 Proxmox.UserName = null;
787ae72a
DM
45 me.loginData = null;
46
47 if (!me.login) {
48 me.login = Ext.create('PVE.window.LoginWindow', {
49 handler: function(data) {
50 me.login = null;
51 me.updateLoginData(data);
063997ed 52 Proxmox.Utils.checked_command(Ext.emptyFn); // display subscription status
f6710aac 53 },
787ae72a
DM
54 });
55 }
56 me.onLogin(null);
57 me.login.show();
58 },
59
8058410f 60 initComponent: function() {
063997ed 61 let me = this;
787ae72a
DM
62
63 Ext.tip.QuickTipManager.init();
64
65 // fixme: what about other errors
66 Ext.Ajax.on('requestexception', function(conn, response, options) {
063997ed 67 if ((response.status === 401 || response.status === '401') && !PVE.Utils.silenceAuthFailures) { // auth failure
1370f628
TL
68 // don't immediately show as logged out to cope better with some big
69 // upgrades, which may temporarily produce a false positive 401 err
70 me.response401count++;
71 if (me.response401count > 5) {
72 me.showLogin();
73 }
787ae72a
DM
74 }
75 });
76
787ae72a
DM
77 me.callParent();
78
e7ade592 79 if (!Proxmox.Utils.authOK()) {
787ae72a 80 me.showLogin();
063997ed
TL
81 } else if (me.loginData) {
82 me.onLogin(me.loginData);
787ae72a
DM
83 }
84
85 Ext.TaskManager.start({
86 run: function() {
063997ed 87 let ticket = Proxmox.Utils.authOK();
35a04562 88 if (!ticket || !Proxmox.UserName) {
787ae72a
DM
89 return;
90 }
91
92 Ext.Ajax.request({
7c8051b4 93 params: {
35a04562 94 username: Proxmox.UserName,
f6710aac 95 password: ticket,
787ae72a
DM
96 },
97 url: '/api2/json/access/ticket',
98 method: 'POST',
99 success: function(response, opts) {
063997ed 100 let obj = Ext.decode(response.responseText);
787ae72a 101 me.updateLoginData(obj.data);
f6710aac 102 },
787ae72a
DM
103 });
104 },
063997ed 105 interval: 15 * 60 * 1000,
787ae72a 106 });
f6710aac 107 },
787ae72a
DM
108});
109
787ae72a
DM
110Ext.define('PVE.StdWorkspace', {
111 extend: 'PVE.Workspace',
112
113 alias: ['widget.pveStdWorkspace'],
114
115 // private
116 setContent: function(comp) {
063997ed 117 let me = this;
7c8051b4 118
063997ed
TL
119 let view = me.child('#content');
120 let layout = view.getLayout();
121 let current = layout.getActiveItem();
787ae72a
DM
122
123 if (comp) {
063997ed 124 Proxmox.Utils.setErrorMask(view, false);
787ae72a 125 comp.border = false;
063997ed
TL
126 view.add(comp);
127 if (current !== null && layout.getNext()) {
128 layout.next();
129 let task = Ext.create('Ext.util.DelayedTask', function() {
130 view.remove(current);
834ba9e4
DC
131 });
132 task.delay(10);
133 }
8058410f 134 } else {
063997ed 135 view.removeAll(); // helper for cleaning the content when logging out
de7eeaac 136 }
787ae72a
DM
137 },
138
139 selectById: function(nodeid) {
063997ed
TL
140 let me = this;
141 me.down('pveResourceTree').selectById(nodeid);
787ae72a
DM
142 },
143
787ae72a 144 onLogin: function(loginData) {
063997ed 145 let me = this;
787ae72a
DM
146
147 me.updateUserInfo();
148
149 if (loginData) {
150 PVE.data.ResourceStore.startUpdate();
151
e7ade592 152 Proxmox.Utils.API2Request({
787ae72a
DM
153 url: '/version',
154 method: 'GET',
155 success: function(response) {
156 PVE.VersionInfo = response.result.data;
157 me.updateVersionInfo();
f6710aac 158 },
787ae72a 159 });
f1ca55fb 160
b7f4cb7c
DC
161 PVE.Utils.updateUIOptions();
162
f1ca55fb
AD
163 Proxmox.Utils.API2Request({
164 url: '/cluster/sdn',
165 method: 'GET',
166 success: function(response) {
167 PVE.SDNInfo = response.result.data;
35ffde01
TL
168 },
169 failure: function(response) {
170 PVE.SDNInfo = null;
171 let ui = Ext.ComponentQuery.query('treelistitem[text="SDN"]')[0];
172 if (ui) {
173 ui.addCls('x-hidden-display');
174 }
175 },
f1ca55fb 176 });
c5be8d39
DC
177
178 Proxmox.Utils.API2Request({
179 url: '/access/domains',
180 method: 'GET',
181 success: function(response) {
182 let [_username, realm] = Proxmox.Utils.parse_userid(Proxmox.UserName);
183 response.result.data.forEach((domain) => {
184 if (domain.realm === realm) {
185 let schema = PVE.Utils.authSchema[domain.type];
186 if (schema) {
187 me.query('#tfaitem')[0].setHidden(!schema.tfa);
188 me.query('#passworditem')[0].setHidden(!schema.pwchange);
189 }
190 }
191 });
192 },
193 });
787ae72a
DM
194 }
195 },
196
197 updateUserInfo: function() {
063997ed
TL
198 let me = this;
199 let ui = me.query('#userinfo')[0];
1011b569 200 ui.setText(Ext.String.htmlEncode(Proxmox.UserName || ''));
6a71fe01 201 ui.updateLayout();
787ae72a
DM
202 },
203
204 updateVersionInfo: function() {
063997ed 205 let me = this;
787ae72a 206
063997ed 207 let ui = me.query('#versioninfo')[0];
787ae72a
DM
208
209 if (PVE.VersionInfo) {
063997ed 210 let version = PVE.VersionInfo.version;
55d727ca 211 ui.update('Virtual Environment ' + version);
787ae72a 212 } else {
55d727ca 213 ui.update('Virtual Environment');
787ae72a 214 }
6a71fe01 215 ui.updateLayout();
787ae72a
DM
216 },
217
8058410f 218 initComponent: function() {
063997ed 219 let me = this;
787ae72a
DM
220
221 Ext.History.init();
222
063997ed
TL
223 let appState = Ext.create('PVE.StateProvider');
224 Ext.state.Manager.setProvider(appState);
787ae72a 225
063997ed 226 let selview = Ext.create('PVE.form.ViewSelector');
787ae72a 227
063997ed 228 let rtree = Ext.createWidget('pveResourceTree', {
787ae72a
DM
229 viewFilter: selview.getViewFilter(),
230 flex: 1,
aeb5e2f6
EK
231 selModel: {
232 selType: 'treemodel',
787ae72a
DM
233 listeners: {
234 selectionchange: function(sm, selected) {
063997ed
TL
235 if (selected.length <= 0) {
236 return;
787ae72a 237 }
063997ed
TL
238 let treeNode = selected[0];
239 let treeTypeToClass = {
240 root: 'PVE.dc.Config',
241 node: 'PVE.node.Config',
242 qemu: 'PVE.qemu.Config',
f31d010c 243 lxc: 'pveLXCConfig',
063997ed
TL
244 storage: 'PVE.storage.Browser',
245 sdn: 'PVE.sdn.Browser',
246 pool: 'pvePoolConfig',
247 };
248 PVE.curSelectedNode = treeNode;
249 me.setContent({
250 xtype: treeTypeToClass[treeNode.data.type || 'root'] || 'pvePanelConfig',
251 showSearch: treeNode.data.id === 'root' || Ext.isDefined(treeNode.data.groupbyid),
252 pveSelNode: treeNode,
253 workspace: me,
254 viewFilter: selview.getViewFilter(),
255 });
f6710aac
TL
256 },
257 },
258 },
787ae72a
DM
259 });
260
7c8051b4 261 selview.on('select', function(combo, records) {
fb387756 262 if (records) {
063997ed 263 let view = combo.getViewFilter();
787ae72a
DM
264 rtree.setViewFilter(view);
265 }
266 });
267
063997ed 268 let caps = appState.get('GuiCap');
787ae72a 269
063997ed 270 let createVM = Ext.createWidget('button', {
787ae72a 271 pack: 'end',
f01259ee 272 margin: '3 5 0 0',
787ae72a 273 baseCls: 'x-btn',
d1f155b8 274 iconCls: 'fa fa-desktop',
787ae72a
DM
275 text: gettext("Create VM"),
276 disabled: !caps.vms['VM.Allocate'],
277 handler: function() {
063997ed 278 let wiz = Ext.create('PVE.qemu.CreateWizard', {});
787ae72a 279 wiz.show();
f6710aac 280 },
787ae72a
DM
281 });
282
063997ed 283 let createCT = Ext.createWidget('button', {
787ae72a 284 pack: 'end',
f01259ee 285 margin: '3 5 0 0',
787ae72a 286 baseCls: 'x-btn',
d1f155b8 287 iconCls: 'fa fa-cube',
787ae72a
DM
288 text: gettext("Create CT"),
289 disabled: !caps.vms['VM.Allocate'],
290 handler: function() {
063997ed 291 let wiz = Ext.create('PVE.lxc.CreateWizard', {});
787ae72a 292 wiz.show();
f6710aac 293 },
787ae72a
DM
294 });
295
063997ed 296 appState.on('statechange', function(sp, key, value) {
787ae72a
DM
297 if (key === 'GuiCap' && value) {
298 caps = value;
299 createVM.setDisabled(!caps.vms['VM.Allocate']);
300 createCT.setDisabled(!caps.vms['VM.Allocate']);
301 }
302 });
303
304 Ext.apply(me, {
305 layout: { type: 'border' },
306 border: false,
307 items: [
308 {
309 region: 'north',
916e739f
TL
310 title: gettext('Header'), // for ARIA
311 header: false, // avoid rendering the title
7c8051b4 312 layout: {
787ae72a 313 type: 'hbox',
f6710aac 314 align: 'middle',
787ae72a 315 },
7c8051b4 316 baseCls: 'x-plain',
787ae72a 317 defaults: {
f6710aac 318 baseCls: 'x-plain',
787ae72a
DM
319 },
320 border: false,
f76884fd 321 margin: '2 0 2 5',
787ae72a
DM
322 items: [
323 {
d1efcadf 324 xtype: 'proxmoxlogo',
787ae72a
DM
325 },
326 {
bbcfa5ab 327 minWidth: 150,
787ae72a 328 id: 'versioninfo',
f6710aac 329 html: 'Virtual Environment',
8de6ef28
TL
330 style: {
331 'font-size': '14px',
332 'line-height': '18px',
333 },
787ae72a 334 },
839eed58
DC
335 {
336 xtype: 'pveGlobalSearchField',
f6710aac 337 tree: rtree,
839eed58
DC
338 },
339 {
f6710aac 340 flex: 1,
839eed58 341 },
3ef58611 342 {
672a6270 343 xtype: 'proxmoxHelpButton',
3ef58611 344 hidden: false,
1e4a853c 345 baseCls: 'x-btn',
41e024ee 346 iconCls: 'fa fa-book x-btn-icon-el-default-toolbar-small ',
3ef58611 347 listenToGlobalEvent: false,
c8802a60 348 onlineHelp: 'pve_documentation_index',
41e024ee 349 text: gettext('Documentation'),
f6710aac 350 margin: '0 5 0 0',
3ef58611 351 },
7c8051b4 352 createVM,
6a7465ae 353 createCT,
787ae72a
DM
354 {
355 pack: 'end',
f76884fd 356 margin: '0 5 0 0',
d962846d 357 id: 'userinfo',
787ae72a
DM
358 xtype: 'button',
359 baseCls: 'x-btn',
404bf6c8
TL
360 style: {
361 // proxmox dark grey p light grey as border
362 backgroundColor: '#464d4d',
f6710aac 363 borderColor: '#ABBABA',
404bf6c8 364 },
d962846d
DC
365 iconCls: 'fa fa-user',
366 menu: [
367 {
368 iconCls: 'fa fa-gear',
369 text: gettext('My Settings'),
370 handler: function() {
371 var win = Ext.create('PVE.window.Settings');
372 win.show();
f6710aac 373 },
d962846d
DC
374 },
375 {
376 text: gettext('Password'),
c5be8d39 377 itemId: 'passworditem',
d962846d
DC
378 iconCls: 'fa fa-fw fa-key',
379 handler: function() {
380 var win = Ext.create('Proxmox.window.PasswordEdit', {
f6710aac 381 userid: Proxmox.UserName,
d962846d
DC
382 });
383 win.show();
f6710aac 384 },
d962846d
DC
385 },
386 {
387 text: 'TFA',
c5be8d39 388 itemId: 'tfaitem',
d962846d
DC
389 iconCls: 'fa fa-fw fa-lock',
390 handler: function(btn, event, rec) {
e90127be
WB
391 Ext.state.Manager.getProvider().set('dctab', { value: 'tfa' }, true);
392 me.selectById('root');
f6710aac 393 },
d962846d 394 },
428d5e78
DC
395 {
396 iconCls: 'fa fa-language',
397 text: gettext('Language'),
398 handler: function() {
399 Ext.create('Proxmox.window.LanguageEditWindow')
400 .show();
401 },
402 },
d962846d
DC
403 '-',
404 {
405 iconCls: 'fa fa-fw fa-sign-out',
406 text: gettext("Logout"),
407 handler: function() {
408 PVE.data.ResourceStore.loadData([], false);
409 me.showLogin();
410 me.setContent(null);
411 var rt = me.down('pveResourceTree');
412 rt.setDatacenterText(undefined);
413 rt.clearTree();
414
415 // empty the stores of the StatusPanel child items
416 var statusPanels = Ext.ComponentQuery.query('pveStatusPanel grid');
417 Ext.Array.forEach(statusPanels, function(comp) {
418 if (comp.getStore()) {
419 comp.getStore().loadData([], false);
420 }
421 });
f6710aac
TL
422 },
423 },
424 ],
425 },
426 ],
787ae72a
DM
427 },
428 {
429 region: 'center',
29aedb75
DC
430 stateful: true,
431 stateId: 'pvecenter',
432 minWidth: 100,
433 minHeight: 100,
787ae72a
DM
434 id: 'content',
435 xtype: 'container',
834ba9e4 436 layout: { type: 'card' },
787ae72a 437 border: false,
f01259ee 438 margin: '0 5 0 0',
f6710aac 439 items: [],
787ae72a
DM
440 },
441 {
442 region: 'west',
29aedb75
DC
443 stateful: true,
444 stateId: 'pvewest',
445 itemId: 'west',
787ae72a
DM
446 xtype: 'container',
447 border: false,
448 layout: { type: 'vbox', align: 'stretch' },
f01259ee 449 margin: '0 0 0 5',
787ae72a
DM
450 split: true,
451 width: 200,
8058410f 452 items: [selview, rtree],
29aedb75
DC
453 listeners: {
454 resize: function(panel, width, height) {
455 var viewWidth = me.getSize().width;
456 if (width > viewWidth - 100) {
457 panel.setWidth(viewWidth - 100);
458 }
f6710aac
TL
459 },
460 },
787ae72a
DM
461 },
462 {
80e8b725 463 xtype: 'pveStatusPanel',
29aedb75
DC
464 stateful: true,
465 stateId: 'pvesouth',
466 itemId: 'south',
787ae72a 467 region: 'south',
8058410f 468 margin: '0 5 5 5',
6a87871f
DC
469 title: gettext('Logs'),
470 collapsible: true,
471 header: false,
29aedb75 472 height: 200,
8058410f 473 split: true,
29aedb75
DC
474 listeners: {
475 resize: function(panel, width, height) {
29aedb75 476 var viewHeight = me.getSize().height;
53e3ea84 477 if (height > viewHeight - 150) {
29aedb75
DC
478 panel.setHeight(viewHeight - 150);
479 }
f6710aac
TL
480 },
481 },
482 },
483 ],
787ae72a
DM
484 });
485
486 me.callParent();
487
488 me.updateUserInfo();
6c18be66
DC
489
490 // on resize, center all modal windows
8058410f 491 Ext.on('resize', function() {
063997ed
TL
492 let modalWindows = Ext.ComponentQuery.query('window[modal]');
493 if (modalWindows.length > 0) {
494 modalWindows.forEach(win => win.alignTo(me, 'c-c'));
6c18be66
DC
495 }
496 });
f6710aac 497 },
787ae72a
DM
498});
499