]> git.proxmox.com Git - proxmox-backup.git/blame - www/NavigationTree.js
ui: update icon in datastore list when in maintenance mode
[proxmox-backup.git] / www / NavigationTree.js
CommitLineData
7ece65a0
DC
1Ext.define('pbs-datastore-list', {
2 extend: 'Ext.data.Model',
adf5dcba 3 fields: ['name', 'comment', 'maintenance'],
7ece65a0
DC
4 proxy: {
5 type: 'proxmox',
6 url: "/api2/json/admin/datastore",
7 },
8 idProperty: 'store',
9});
10
2e268e31
DC
11Ext.define('pbs-tape-drive-list', {
12 extend: 'Ext.data.Model',
13 fields: ['name', 'changer'],
14 proxy: {
15 type: 'proxmox',
16 url: "/api2/json/tape/drive",
17 },
18 idProperty: 'name',
19});
20
b0ee976f
DM
21Ext.define('PBS.store.NavigationStore', {
22 extend: 'Ext.data.TreeStore',
23
24 storeId: 'NavigationStore',
25
26 root: {
27 expanded: true,
28 children: [
84b9eced
TL
29 {
30 text: gettext('Dashboard'),
31 iconCls: 'fa fa-tachometer',
32 path: 'pbsDashboard',
264c1958 33 leaf: true,
84b9eced 34 },
f3b02a9b
SS
35 {
36 text: gettext('Notes'),
37 iconCls: 'fa fa-sticky-note-o',
38 path: 'pbsNodeNotes',
39 leaf: true,
40 },
b0ee976f
DM
41 {
42 text: gettext('Configuration'),
43 iconCls: 'fa fa-gears',
44 path: 'pbsSystemConfiguration',
45 expanded: true,
46 children: [
88acc861 47 {
2f1a46f7
TL
48 text: gettext('Access Control'),
49 iconCls: 'fa fa-key',
50 path: 'pbsAccessControlPanel',
264c1958 51 leaf: true,
0542cfdf 52 },
9e2a4653
DC
53 {
54 text: gettext('Remotes'),
55 iconCls: 'fa fa-server',
56 path: 'pbsRemoteView',
57 leaf: true,
58 },
ac4e399a
DC
59 {
60 text: gettext('Traffic Control'),
f251367c 61 iconCls: 'fa fa-signal fa-rotate-90',
ac4e399a
DC
62 path: 'pbsTrafficControlView',
63 leaf: true,
64 },
4b5d9b6e
WB
65 {
66 text: gettext('Certificates'),
67 iconCls: 'fa fa-certificate',
68 path: 'pbsCertificateConfiguration',
69 leaf: true,
70 },
b0ee976f
DM
71 {
72 text: gettext('Subscription'),
73 iconCls: 'fa fa-support',
74 path: 'pbsSubscription',
264c1958
TL
75 leaf: true,
76 },
77 ],
b0ee976f
DM
78 },
79 {
80 text: gettext('Administration'),
81 iconCls: 'fa fa-wrench',
82 path: 'pbsServerAdministration',
7f17f744
DC
83 expanded: true,
84 leaf: false,
85 children: [
8e12e86f
DC
86 {
87 text: gettext('Shell'),
88 iconCls: 'fa fa-terminal',
89 path: 'pbsXtermJsConsole',
90 leaf: true,
91 },
7f17f744 92 {
ee0ab12d 93 text: gettext('Storage / Disks'),
7f17f744 94 iconCls: 'fa fa-hdd-o',
ee0ab12d
TL
95 path: 'pbsStorageAndDiskPanel',
96 leaf: true,
264c1958
TL
97 },
98 ],
98bb3b90 99 },
a21f9852
TL
100 {
101 text: "Tape Backup",
102 iconCls: 'pbs-icon-tape',
103 id: 'tape_management',
104 path: 'pbsTapeManagement',
105 expanded: true,
106 children: [],
107 },
98bb3b90 108 {
58f950c5 109 text: gettext('Datastore'),
98bb3b90 110 iconCls: 'fa fa-archive',
7ece65a0 111 id: 'datastores',
ed1329ec 112 path: 'pbsDataStores',
98bb3b90 113 expanded: true,
7ece65a0 114 expandable: false,
264c1958 115 leaf: false,
7ece65a0
DC
116 children: [
117 {
118 text: gettext('Add Datastore'),
119 iconCls: 'fa fa-plus-circle',
120 leaf: true,
121 id: 'addbutton',
bc42bb3c 122 virtualEntry: true,
7ece65a0
DC
123 },
124 ],
98bb3b90 125 },
264c1958
TL
126 ],
127 },
b0ee976f
DM
128});
129
130Ext.define('PBS.view.main.NavigationTree', {
131 extend: 'Ext.list.Tree',
132 xtype: 'navigationtree',
133
ca23a97f
DM
134 controller: {
135 xclass: 'Ext.app.ViewController',
136
137 init: function(view) {
ca23a97f
DM
138 view.rstore = Ext.create('Proxmox.data.UpdateStore', {
139 autoStart: true,
140 interval: 15 * 1000,
141 storeid: 'pbs-datastore-list',
264c1958 142 model: 'pbs-datastore-list',
ca23a97f
DM
143 });
144
145 view.rstore.on('load', this.onLoad, this);
146 view.on('destroy', view.rstore.stopUpdate);
2e268e31 147
fa29d7eb
TL
148 if (view.tapeStore === undefined) {
149 view.tapeStore = Ext.create('Proxmox.data.UpdateStore', {
a21f9852
TL
150 autoStart: true,
151 interval: 60 * 1000,
152 storeid: 'pbs-tape-drive-list',
153 model: 'pbs-tape-drive-list',
154 });
fa29d7eb
TL
155 view.tapeStore.on('load', this.onTapeDriveLoad, this);
156 view.on('destroy', view.tapeStore.stopUpdate);
2e268e31 157 }
ca23a97f
DM
158 },
159
2e268e31 160 onTapeDriveLoad: function(store, records, success) {
98bb3b90 161 if (!success) return;
ca23a97f 162
2e268e31 163 let view = this.getView();
ca23a97f
DM
164 let root = view.getStore().getRoot();
165
2e268e31 166 records.sort((a, b) => a.data.name.localeCompare(b.data.name));
2e268e31 167
94b7f56e
TL
168 let list = root.findChild('id', 'tape_management', false);
169 let existingChildren = {};
2e268e31
DC
170 for (const drive of records) {
171 let path, text, iconCls;
172 if (drive.data.changer !== undefined) {
173 text = drive.data.changer;
174 path = `Changer-${text}`;
9a8bf2ca 175 iconCls = 'fa fa-exchange';
2e268e31
DC
176 } else {
177 text = drive.data.name;
178 path = `Drive-${text}`;
9a8bf2ca 179 iconCls = 'pbs-icon-tape-drive';
2e268e31 180 }
94b7f56e 181 existingChildren[path] = {
2e268e31
DC
182 text,
183 path,
184 iconCls,
185 leaf: true,
186 };
187 }
188
94b7f56e 189 let paths = Object.keys(existingChildren).sort();
2e268e31
DC
190
191 let oldIdx = 0;
192 for (let newIdx = 0; newIdx < paths.length; newIdx++) {
193 let newPath = paths[newIdx];
194 // find index to insert
195 while (oldIdx < list.childNodes.length && newPath > list.getChildAt(oldIdx).data.path) {
196 oldIdx++;
197 }
198
199 if (oldIdx >= list.childNodes.length || list.getChildAt(oldIdx).data.path !== newPath) {
94b7f56e 200 list.insertChild(oldIdx, existingChildren[newPath]);
ff50c07e
DM
201 }
202 }
203
94b7f56e 204 let toRemove = [];
2e268e31 205 list.eachChild((child) => {
94b7f56e
TL
206 if (!existingChildren[child.data.path]) {
207 toRemove.push(child);
2e268e31
DC
208 }
209 });
94b7f56e 210 toRemove.forEach((child) => list.removeChild(child, true));
2e268e31
DC
211
212 if (view.pathToSelect !== undefined) {
213 let path = view.pathToSelect;
214 delete view.pathToSelect;
215 view.select(path, true);
216 }
217 },
218
219 onLoad: function(store, records, success) {
94b7f56e
TL
220 if (!success) {
221 return;
222 }
223 let view = this.getView();
2e268e31
DC
224 let root = view.getStore().getRoot();
225
7ece65a0 226 records.sort((a, b) => a.id.localeCompare(b.id));
8277f4ac 227
94b7f56e
TL
228 let list = root.findChild('id', 'datastores', false);
229 let getChildTextAt = i => list.getChildAt(i).data.text;
230 let existingChildren = {};
231 for (let i = 0, j = 0, length = records.length; i < length; i++) {
264c1958 232 let name = records[i].id;
94b7f56e 233 existingChildren[name] = true;
7ece65a0 234
94b7f56e 235 while (name.localeCompare(getChildTextAt(j)) > 0 && (j+1) < list.childNodes.length) {
7ece65a0
DC
236 j++;
237 }
238
adf5dcba
HL
239 let iconCls = 'fa fa-database';
240 const maintenance = records[i].data.maintenance;
241 if (maintenance) {
242 iconCls = 'fa fa-database pmx-tree-icon-custom maintenance';
243 }
244
245 const child = {
246 text: name,
247 path: `DataStore-${name}`,
248 iconCls,
249 leaf: true,
250 };
94b7f56e 251 if (getChildTextAt(j).localeCompare(name) !== 0) {
adf5dcba
HL
252 list.insertChild(j, child);
253 } else {
254 list.replaceChild(child, list.getChildAt(j));
ca23a97f
DM
255 }
256 }
257
94b7f56e
TL
258 // remove entries which are not existing anymore
259 let toRemove = [];
260 list.eachChild(child => {
bc42bb3c 261 if (!existingChildren[child.data.text] && !child.data.virtualEntry) {
94b7f56e 262 toRemove.push(child);
ca23a97f
DM
263 }
264 });
94b7f56e 265 toRemove.forEach(child => list.removeChild(child, true));
2565fdd0
DC
266
267 if (view.pathToSelect !== undefined) {
268 let path = view.pathToSelect;
269 delete view.pathToSelect;
270 view.select(path, true);
271 }
7ece65a0
DC
272 },
273 },
274
275 listeners: {
276 itemclick: function(tl, info) {
7ece65a0
DC
277 if (info.node.data.id === 'addbutton') {
278 let me = this;
279 Ext.create('PBS.DataStoreEdit', {
280 listeners: {
f05085ab 281 destroy: () => me.rstore.reload(),
7ece65a0
DC
282 },
283 }).show();
284 return false;
285 }
286 return true;
264c1958 287 },
ca23a97f
DM
288 },
289
dcf155da
DC
290 reloadTapeStore: function() {
291 let me = this;
fa29d7eb 292 me.tapeStore.load();
dcf155da
DC
293 },
294
2565fdd0 295 select: function(path, silent) {
b0ee976f 296 var me = this;
fa29d7eb 297 if (me.rstore.isLoaded() && me.tapeStore.isLoaded()) {
2565fdd0
DC
298 if (silent) {
299 me.suspendEvents(false);
300 }
301 var item = me.getStore().findRecord('path', path, 0, false, true, true);
302 me.setSelection(item);
303 if (silent) {
304 me.resumeEvents(true);
305 }
306 } else {
307 me.pathToSelect = path;
308 }
b0ee976f
DM
309 },
310
311 animation: false,
312 expanderOnly: true,
313 expanderFirst: false,
314 store: 'NavigationStore',
264c1958 315 ui: 'nav',
b0ee976f 316});