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