]>
Commit | Line | Data |
---|---|---|
7ece65a0 DC |
1 | Ext.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 |
11 | Ext.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 |
21 | Ext.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', | |
104 | }, | |
105 | ], | |
98bb3b90 | 106 | }, |
264c1958 TL |
107 | ], |
108 | }, | |
b0ee976f DM |
109 | }); |
110 | ||
111 | Ext.define('PBS.view.main.NavigationTree', { | |
112 | extend: 'Ext.list.Tree', | |
113 | xtype: 'navigationtree', | |
114 | ||
ca23a97f DM |
115 | controller: { |
116 | xclass: 'Ext.app.ViewController', | |
117 | ||
118 | init: function(view) { | |
ca23a97f DM |
119 | view.rstore = Ext.create('Proxmox.data.UpdateStore', { |
120 | autoStart: true, | |
121 | interval: 15 * 1000, | |
122 | storeid: 'pbs-datastore-list', | |
264c1958 | 123 | model: 'pbs-datastore-list', |
ca23a97f DM |
124 | }); |
125 | ||
126 | view.rstore.on('load', this.onLoad, this); | |
127 | view.on('destroy', view.rstore.stopUpdate); | |
2e268e31 | 128 | |
fa29d7eb TL |
129 | if (view.tapeStore === undefined) { |
130 | view.tapeStore = Ext.create('Proxmox.data.UpdateStore', { | |
a21f9852 TL |
131 | autoStart: true, |
132 | interval: 60 * 1000, | |
133 | storeid: 'pbs-tape-drive-list', | |
134 | model: 'pbs-tape-drive-list', | |
135 | }); | |
fa29d7eb TL |
136 | view.tapeStore.on('load', this.onTapeDriveLoad, this); |
137 | view.on('destroy', view.tapeStore.stopUpdate); | |
2e268e31 | 138 | } |
ca23a97f DM |
139 | }, |
140 | ||
2e268e31 | 141 | onTapeDriveLoad: function(store, records, success) { |
98bb3b90 | 142 | if (!success) return; |
ca23a97f | 143 | |
2e268e31 | 144 | let view = this.getView(); |
ca23a97f DM |
145 | let root = view.getStore().getRoot(); |
146 | ||
2e268e31 | 147 | records.sort((a, b) => a.data.name.localeCompare(b.data.name)); |
2e268e31 | 148 | |
94b7f56e TL |
149 | let list = root.findChild('id', 'tape_management', false); |
150 | let existingChildren = {}; | |
2e268e31 DC |
151 | for (const drive of records) { |
152 | let path, text, iconCls; | |
153 | if (drive.data.changer !== undefined) { | |
154 | text = drive.data.changer; | |
155 | path = `Changer-${text}`; | |
9a8bf2ca | 156 | iconCls = 'fa fa-exchange'; |
2e268e31 DC |
157 | } else { |
158 | text = drive.data.name; | |
159 | path = `Drive-${text}`; | |
9a8bf2ca | 160 | iconCls = 'pbs-icon-tape-drive'; |
2e268e31 | 161 | } |
94b7f56e | 162 | existingChildren[path] = { |
2e268e31 DC |
163 | text, |
164 | path, | |
165 | iconCls, | |
166 | leaf: true, | |
167 | }; | |
168 | } | |
169 | ||
94b7f56e | 170 | let paths = Object.keys(existingChildren).sort(); |
2e268e31 DC |
171 | |
172 | let oldIdx = 0; | |
173 | for (let newIdx = 0; newIdx < paths.length; newIdx++) { | |
174 | let newPath = paths[newIdx]; | |
175 | // find index to insert | |
176 | while (oldIdx < list.childNodes.length && newPath > list.getChildAt(oldIdx).data.path) { | |
177 | oldIdx++; | |
178 | } | |
179 | ||
180 | if (oldIdx >= list.childNodes.length || list.getChildAt(oldIdx).data.path !== newPath) { | |
94b7f56e | 181 | list.insertChild(oldIdx, existingChildren[newPath]); |
ff50c07e DM |
182 | } |
183 | } | |
184 | ||
94b7f56e | 185 | let toRemove = []; |
2e268e31 | 186 | list.eachChild((child) => { |
94b7f56e TL |
187 | if (!existingChildren[child.data.path]) { |
188 | toRemove.push(child); | |
2e268e31 DC |
189 | } |
190 | }); | |
94b7f56e | 191 | toRemove.forEach((child) => list.removeChild(child, true)); |
2e268e31 DC |
192 | |
193 | if (view.pathToSelect !== undefined) { | |
194 | let path = view.pathToSelect; | |
195 | delete view.pathToSelect; | |
196 | view.select(path, true); | |
197 | } | |
198 | }, | |
199 | ||
200 | onLoad: function(store, records, success) { | |
94b7f56e TL |
201 | if (!success) { |
202 | return; | |
203 | } | |
204 | let view = this.getView(); | |
2e268e31 DC |
205 | let root = view.getStore().getRoot(); |
206 | ||
7ece65a0 | 207 | records.sort((a, b) => a.id.localeCompare(b.id)); |
8277f4ac | 208 | |
94b7f56e TL |
209 | let list = root.findChild('id', 'datastores', false); |
210 | let getChildTextAt = i => list.getChildAt(i).data.text; | |
211 | let existingChildren = {}; | |
212 | for (let i = 0, j = 0, length = records.length; i < length; i++) { | |
264c1958 | 213 | let name = records[i].id; |
94b7f56e | 214 | existingChildren[name] = true; |
7ece65a0 | 215 | |
94b7f56e | 216 | while (name.localeCompare(getChildTextAt(j)) > 0 && (j+1) < list.childNodes.length) { |
7ece65a0 DC |
217 | j++; |
218 | } | |
219 | ||
94b7f56e | 220 | if (getChildTextAt(j).localeCompare(name) !== 0) { |
7ece65a0 | 221 | list.insertChild(j, { |
ca23a97f | 222 | text: name, |
c0ac2074 | 223 | path: `DataStore-${name}`, |
bc9c306c | 224 | iconCls: 'fa fa-database', |
264c1958 | 225 | leaf: true, |
ca23a97f DM |
226 | }); |
227 | } | |
228 | } | |
229 | ||
94b7f56e TL |
230 | // remove entries which are not existing anymore |
231 | let toRemove = []; | |
232 | list.eachChild(child => { | |
233 | if (!existingChildren[child.data.text] && child.data.id !== 'addbutton') { | |
234 | toRemove.push(child); | |
ca23a97f DM |
235 | } |
236 | }); | |
94b7f56e | 237 | toRemove.forEach(child => list.removeChild(child, true)); |
2565fdd0 DC |
238 | |
239 | if (view.pathToSelect !== undefined) { | |
240 | let path = view.pathToSelect; | |
241 | delete view.pathToSelect; | |
242 | view.select(path, true); | |
243 | } | |
7ece65a0 DC |
244 | }, |
245 | }, | |
246 | ||
247 | listeners: { | |
248 | itemclick: function(tl, info) { | |
7ece65a0 DC |
249 | if (info.node.data.id === 'addbutton') { |
250 | let me = this; | |
251 | Ext.create('PBS.DataStoreEdit', { | |
252 | listeners: { | |
253 | destroy: function() { | |
254 | me.rstore.reload(); | |
255 | }, | |
256 | }, | |
257 | }).show(); | |
258 | return false; | |
259 | } | |
260 | return true; | |
264c1958 | 261 | }, |
ca23a97f DM |
262 | }, |
263 | ||
dcf155da DC |
264 | reloadTapeStore: function() { |
265 | let me = this; | |
fa29d7eb | 266 | me.tapeStore.load(); |
dcf155da DC |
267 | }, |
268 | ||
2565fdd0 | 269 | select: function(path, silent) { |
b0ee976f | 270 | var me = this; |
fa29d7eb | 271 | if (me.rstore.isLoaded() && me.tapeStore.isLoaded()) { |
2565fdd0 DC |
272 | if (silent) { |
273 | me.suspendEvents(false); | |
274 | } | |
275 | var item = me.getStore().findRecord('path', path, 0, false, true, true); | |
276 | me.setSelection(item); | |
277 | if (silent) { | |
278 | me.resumeEvents(true); | |
279 | } | |
280 | } else { | |
281 | me.pathToSelect = path; | |
282 | } | |
b0ee976f DM |
283 | }, |
284 | ||
285 | animation: false, | |
286 | expanderOnly: true, | |
287 | expanderFirst: false, | |
288 | store: 'NavigationStore', | |
264c1958 | 289 | ui: 'nav', |
b0ee976f | 290 | }); |