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