]>
Commit | Line | Data |
---|---|---|
5c7a1b15 DM |
1 | Ext.define('PBS.MainView', { |
2 | extend: 'Ext.container.Container', | |
3 | xtype: 'mainview', | |
4 | ||
5 | title: 'Proxmox Backup Server', | |
6 | ||
7 | controller: { | |
8 | xclass: 'Ext.app.ViewController', | |
9 | routes: { | |
10 | ':path:subpath': { | |
11 | action: 'changePath', | |
12 | before: 'beforeChangePath', | |
8acd4d9a TL |
13 | conditions: { |
14 | ':path': '(?:([%a-zA-Z0-9\\-\\_\\s,.]+))', | |
15 | ':subpath': '(?:(?::)([%a-zA-Z0-9\\-\\_\\s,]+))?', | |
16 | }, | |
17 | }, | |
5c7a1b15 | 18 | }, |
2e75b6d8 | 19 | |
3e182fd8 | 20 | parseRouterPath: function(path) { |
c0ac2074 | 21 | let xtype = path; |
3e182fd8 DC |
22 | let config = {}; |
23 | if (PBS.Utils.isDataStorePath(path)) { | |
24 | config.datastore = PBS.Utils.getDataStoreFromPath(path); | |
c0ac2074 | 25 | xtype = 'pbsDataStorePanel'; |
3e182fd8 DC |
26 | } else if (path.indexOf('Changer-') === 0) { |
27 | config.changer = path.slice('Changer-'.length); | |
28 | xtype = 'pbsChangerStatus'; | |
29 | } else if (path.indexOf('Drive-') === 0) { | |
30 | config.drive = path.slice('Drive-'.length); | |
31 | xtype = 'pbsDriveStatus'; | |
c0ac2074 DC |
32 | } |
33 | ||
3e182fd8 DC |
34 | return [xtype, config]; |
35 | }, | |
36 | ||
90066d22 | 37 | beforeChangePath: function(path, subpathOrAction, action) { |
3e182fd8 DC |
38 | var me = this; |
39 | ||
90066d22 DC |
40 | let subpath = subpathOrAction; |
41 | if (!action) { | |
42 | action = subpathOrAction; | |
43 | subpath = undefined; | |
44 | } | |
45 | ||
3e182fd8 DC |
46 | let [xtype, config] = me.parseRouterPath(path); |
47 | ||
c0ac2074 DC |
48 | if (!Ext.ClassManager.getByAlias(`widget.${xtype}`)) { |
49 | console.warn(`xtype ${xtype} not found`); | |
b0ee976f DM |
50 | action.stop(); |
51 | return; | |
52 | } | |
53 | ||
54 | var lastpanel = me.lookupReference('contentpanel').getLayout().getActiveItem(); | |
c0ac2074 | 55 | if (lastpanel && lastpanel.xtype === xtype) { |
3e182fd8 DC |
56 | for (const [prop, value] of Object.entries(config)) { |
57 | if (lastpanel[prop] !== value) { | |
58 | action.resume(); | |
ca23a97f DM |
59 | return; |
60 | } | |
3e182fd8 DC |
61 | } |
62 | // we have the right component already, | |
63 | // we just need to select the correct tab | |
64 | // default to the first | |
65 | subpath = subpath || 0; | |
66 | if (lastpanel.getActiveTab) { | |
67 | // we assume lastpanel is a tabpanel | |
68 | if (lastpanel.getActiveTab().getItemId() !== subpath) { | |
69 | // set the active tab | |
70 | lastpanel.setActiveTab(subpath); | |
b0ee976f | 71 | } |
3e182fd8 | 72 | // else we are already there |
b0ee976f | 73 | } |
3e182fd8 DC |
74 | action.stop(); |
75 | return; | |
b0ee976f DM |
76 | } |
77 | ||
5c7a1b15 DM |
78 | action.resume(); |
79 | }, | |
2e75b6d8 | 80 | |
ca23a97f | 81 | changePath: function(path, subpath) { |
5c7a1b15 DM |
82 | var me = this; |
83 | var contentpanel = me.lookupReference('contentpanel'); | |
84 | var lastpanel = contentpanel.getLayout().getActiveItem(); | |
85 | ||
2565fdd0 DC |
86 | let tabChangeListener = function(tp, newc, oldc) { |
87 | let newpath = path; | |
b0ee976f | 88 | |
2565fdd0 DC |
89 | // only add the subpath part for the |
90 | // non-default tabs | |
91 | if (tp.items.findIndex('id', newc.id) !== 0) { | |
92 | newpath += `:${newc.getItemId()}`; | |
93 | } | |
b0ee976f | 94 | |
2565fdd0 DC |
95 | me.redirectTo(newpath); |
96 | }; | |
b0ee976f | 97 | |
3e182fd8 | 98 | let [xtype, config] = me.parseRouterPath(path); |
2565fdd0 | 99 | var obj; |
2565fdd0 | 100 | if (PBS.Utils.isDataStorePath(path)) { |
3e182fd8 | 101 | if (lastpanel && lastpanel.xtype === xtype && !subpath) { |
2565fdd0 DC |
102 | let activeTab = lastpanel.getActiveTab(); |
103 | let newpath = path; | |
104 | if (lastpanel.items.indexOf(activeTab) !== 0) { | |
105 | subpath = activeTab.getItemId(); | |
106 | newpath += `:${subpath}`; | |
b0ee976f | 107 | } |
b0ee976f | 108 | me.redirectTo(newpath); |
2565fdd0 | 109 | } |
b0ee976f | 110 | } |
3e182fd8 | 111 | obj = contentpanel.add(Ext.apply(config, { |
2565fdd0 | 112 | xtype, |
2565fdd0 DC |
113 | nodename: 'localhost', |
114 | border: false, | |
115 | activeTab: subpath || 0, | |
116 | listeners: { | |
117 | tabchange: tabChangeListener, | |
118 | }, | |
3e182fd8 | 119 | })); |
2565fdd0 DC |
120 | |
121 | var treelist = me.lookupReference('navtree'); | |
122 | ||
123 | treelist.select(path, true); | |
b0ee976f DM |
124 | |
125 | contentpanel.setActiveItem(obj); | |
126 | ||
127 | if (lastpanel) { | |
128 | contentpanel.remove(lastpanel, { destroy: true }); | |
129 | } | |
b0ee976f DM |
130 | }, |
131 | ||
34f956bc DM |
132 | logout: function() { |
133 | PBS.app.logout(); | |
134 | }, | |
135 | ||
b0ee976f DM |
136 | navigate: function(treelist, item) { |
137 | this.redirectTo(item.get('path')); | |
5c7a1b15 DM |
138 | }, |
139 | ||
34f956bc | 140 | control: { |
f6e964b9 | 141 | '[reference=logoutButton]': { |
8acd4d9a TL |
142 | click: 'logout', |
143 | }, | |
34f956bc DM |
144 | }, |
145 | ||
5c7a1b15 DM |
146 | init: function(view) { |
147 | var me = this; | |
5c7a1b15 | 148 | |
cc83c136 | 149 | PBS.data.RunningTasksStore.startUpdate(); |
f6e964b9 | 150 | me.lookupReference('usernameinfo').setText(Proxmox.UserName); |
a602faeb | 151 | |
8af272fd TL |
152 | // show login on requestexception |
153 | // fixme: what about other errors | |
154 | Ext.Ajax.on('requestexception', function(conn, response, options) { | |
8acd4d9a | 155 | if (response.status === 401 || response.status === '401') { // auth failure |
8af272fd TL |
156 | me.logout(); |
157 | } | |
158 | }); | |
159 | ||
a602faeb TL |
160 | // get ticket periodically |
161 | Ext.TaskManager.start({ | |
162 | run: function() { | |
163 | var ticket = Proxmox.Utils.authOK(); | |
164 | if (!ticket || !Proxmox.UserName) { | |
165 | return; | |
166 | } | |
167 | ||
168 | Ext.Ajax.request({ | |
169 | params: { | |
170 | username: Proxmox.UserName, | |
8acd4d9a | 171 | password: ticket, |
a602faeb TL |
172 | }, |
173 | url: '/api2/json/access/ticket', | |
174 | method: 'POST', | |
175 | failure: function() { | |
176 | me.logout(); | |
177 | }, | |
178 | success: function(response, opts) { | |
179 | var obj = Ext.decode(response.responseText); | |
323515c2 | 180 | PBS.Utils.updateLoginData(obj.data); |
8acd4d9a | 181 | }, |
a602faeb TL |
182 | }); |
183 | }, | |
8acd4d9a | 184 | interval: 15*60*1000, |
a602faeb | 185 | }); |
9710e5d0 | 186 | |
a662274e DC |
187 | Proxmox.Utils.API2Request({ |
188 | url: `/api2/extjs/nodes/localhost/status`, | |
189 | success: function({ result }) { | |
190 | if (result?.data?.info?.fingerprint) { | |
191 | Proxmox.Fingerprint = result.data.info.fingerprint; | |
192 | } | |
193 | }, | |
194 | failure: function() { | |
195 | // silently ignore errors | |
196 | }, | |
197 | }); | |
9710e5d0 TL |
198 | |
199 | // select treeitem and load page from url fragment, if set | |
200 | let token = Ext.util.History.getToken() || 'pbsDashboard'; | |
67466ce5 | 201 | this.redirectTo(token, { force: true }); |
8acd4d9a | 202 | }, |
5c7a1b15 DM |
203 | }, |
204 | ||
205 | plugins: 'viewport', | |
206 | ||
207 | layout: { type: 'border' }, | |
208 | ||
209 | items: [ | |
210 | { | |
211 | region: 'north', | |
212 | xtype: 'container', | |
213 | layout: { | |
214 | type: 'hbox', | |
8acd4d9a | 215 | align: 'middle', |
5c7a1b15 | 216 | }, |
86443141 | 217 | margin: '2 0 2 5', |
5c7a1b15 DM |
218 | height: 38, |
219 | items: [ | |
220 | { | |
1d8ef0dc DC |
221 | xtype: 'proxmoxlogo', |
222 | prefix: '', | |
5c7a1b15 DM |
223 | }, |
224 | { | |
86443141 TL |
225 | padding: '0 0 0 5', |
226 | xtype: 'versioninfo', | |
5c7a1b15 DM |
227 | }, |
228 | { | |
bd260569 DC |
229 | flex: 1, |
230 | baseCls: 'x-plain', | |
5c7a1b15 | 231 | }, |
9c01e73c TL |
232 | { |
233 | xtype: 'button', | |
234 | baseCls: 'x-btn', | |
235 | cls: 'x-btn-default-toolbar-small proxmox-inline-button', | |
236 | iconCls: 'fa fa-book x-btn-icon-el-default-toolbar-small ', | |
237 | text: gettext('Documentation'), | |
238 | href: '/docs/index.html', | |
239 | margin: '0 5 0 0', | |
240 | }, | |
a3970d6c DC |
241 | { |
242 | xtype: 'pbsTaskButton', | |
243 | margin: '0 5 0 0', | |
244 | }, | |
5c7a1b15 | 245 | { |
5c7a1b15 | 246 | xtype: 'button', |
f6e964b9 TL |
247 | reference: 'usernameinfo', |
248 | style: { | |
249 | // proxmox dark grey p light grey as border | |
250 | backgroundColor: '#464d4d', | |
8acd4d9a | 251 | borderColor: '#ABBABA', |
f6e964b9 TL |
252 | }, |
253 | margin: '0 5 0 0', | |
254 | iconCls: 'fa fa-user', | |
255 | menu: [ | |
85eedfb7 DC |
256 | { |
257 | iconCls: 'fa fa-gear', | |
258 | text: gettext('My Settings'), | |
259 | handler: () => Ext.create('PBS.window.Settings').show(), | |
260 | }, | |
a443dd5c SS |
261 | { |
262 | iconCls: 'fa fa-paint-brush', | |
18c2110b | 263 | text: gettext('Color Theme'), |
a443dd5c SS |
264 | handler: () => Ext.create('Proxmox.window.ThemeEditWindow', { |
265 | cookieName: 'PBSThemeCookie', | |
266 | autoShow: true, | |
267 | }), | |
268 | }, | |
f6e964b9 | 269 | { |
f8a682a8 TL |
270 | iconCls: 'fa fa-language', |
271 | text: gettext('Language'), | |
272 | reference: 'languageButton', | |
273 | handler: () => Ext.create('Proxmox.window.LanguageEditWindow', { | |
274 | cookieName: 'PBSLangCookie', | |
275 | autoShow: true, | |
276 | }), | |
277 | }, | |
278 | '-', | |
279 | { | |
f6e964b9 TL |
280 | iconCls: 'fa fa-sign-out', |
281 | text: gettext('Logout'), | |
f8a682a8 | 282 | reference: 'logoutButton', |
f6e964b9 TL |
283 | }, |
284 | ], | |
285 | }, | |
8acd4d9a | 286 | ], |
5c7a1b15 DM |
287 | }, |
288 | { | |
ecf5f468 | 289 | xtype: 'container', |
5c7a1b15 DM |
290 | scrollable: 'y', |
291 | border: false, | |
292 | region: 'west', | |
293 | layout: { | |
294 | type: 'vbox', | |
8acd4d9a | 295 | align: 'stretch', |
5c7a1b15 | 296 | }, |
b0ee976f DM |
297 | items: [{ |
298 | xtype: 'navigationtree', | |
299 | minWidth: 180, | |
c793da1e | 300 | ui: 'pve-nav', |
b0ee976f DM |
301 | reference: 'navtree', |
302 | // we have to define it here until extjs 6.2 | |
303 | // because of a bug where a viewcontroller does not detect | |
304 | // the selectionchange event of a treelist | |
305 | listeners: { | |
8acd4d9a TL |
306 | selectionchange: 'navigate', |
307 | }, | |
b0ee976f DM |
308 | }, { |
309 | xtype: 'box', | |
c793da1e | 310 | cls: 'x-treelist-pve-nav', |
8acd4d9a TL |
311 | flex: 1, |
312 | }], | |
5c7a1b15 DM |
313 | }, |
314 | { | |
ecf5f468 | 315 | xtype: 'container', |
5c7a1b15 DM |
316 | layout: { type: 'card' }, |
317 | region: 'center', | |
318 | border: false, | |
8acd4d9a TL |
319 | reference: 'contentpanel', |
320 | }, | |
321 | ], | |
5c7a1b15 | 322 | }); |