]>
Commit | Line | Data |
---|---|---|
07d6c096 DC |
1 | Ext.define('PBS.TapeManagement.BackupOverview', { |
2 | extend: 'Ext.tree.Panel', | |
3 | alias: 'widget.pbsBackupOverview', | |
4 | ||
5 | controller: { | |
6 | xclass: 'Ext.app.ViewController', | |
7 | ||
8 | backup: function() { | |
9 | let me = this; | |
10 | Ext.create('PBS.TapeManagement.TapeBackupWindow', { | |
11 | listeners: { | |
12 | destroy: function() { | |
13 | me.reload(); | |
14 | }, | |
15 | }, | |
104ae609 TL |
16 | autoShow: true, |
17 | }); | |
07d6c096 DC |
18 | }, |
19 | ||
afb790db DC |
20 | restore: function() { |
21 | Ext.create('PBS.TapeManagement.TapeRestoreWindow', { | |
22 | autoShow: true, | |
23 | }); | |
24 | }, | |
25 | ||
104ae609 | 26 | restoreBackups: function(view, rI, cI, item, e, rec) { |
68b10226 | 27 | let me = this; |
68b10226 | 28 | |
4923a76f | 29 | let mediaset = rec.data.is_media_set ? rec.data.text : rec.data['media-set']; |
631e5509 | 30 | Ext.create('PBS.TapeManagement.TapeRestoreWindow', { |
f36c6593 | 31 | autoShow: true, |
104ae609 TL |
32 | uuid: rec.data['media-set-uuid'], |
33 | prefilter: rec.data.prefilter, | |
631e5509 | 34 | mediaset, |
f36c6593 | 35 | }); |
631e5509 | 36 | }, |
07d6c096 | 37 | |
631e5509 | 38 | loadContent: async function() { |
69ebbec4 | 39 | let me = this; |
3006d70e | 40 | let content_response = await Proxmox.Async.api2({ |
159100b9 | 41 | url: '/api2/extjs/tape/media/list?update-status=false', |
631e5509 DC |
42 | }); |
43 | let data = {}; | |
44 | ||
45 | for (const entry of content_response.result.data) { | |
46 | let pool = entry.pool; | |
3ddbab61 DC |
47 | if (pool === undefined) { |
48 | continue; // pools not belonging to a pool cannot contain data | |
49 | } | |
631e5509 | 50 | let media_set = entry['media-set-name']; |
32b88d92 DC |
51 | if (media_set === undefined) { |
52 | continue; // tape does not belong to media-set (yet)) | |
53 | } | |
631e5509 DC |
54 | if (data[pool] === undefined) { |
55 | data[pool] = {}; | |
56 | } | |
07d6c096 | 57 | |
69ebbec4 DC |
58 | if (data[pool][media_set] === undefined) { |
59 | data[pool][media_set] = entry; | |
60 | data[pool][media_set].text = media_set; | |
f9b824ac | 61 | data[pool][media_set].restore = true; |
69ebbec4 DC |
62 | data[pool][media_set].tapes = 1; |
63 | data[pool][media_set]['seq-nr'] = undefined; | |
64 | data[pool][media_set].is_media_set = true; | |
f9b824ac | 65 | data[pool][media_set].typeText = 'media-set'; |
69ebbec4 DC |
66 | } else { |
67 | data[pool][media_set].tapes++; | |
631e5509 | 68 | } |
631e5509 | 69 | } |
07d6c096 | 70 | |
631e5509 DC |
71 | let list = []; |
72 | ||
69ebbec4 DC |
73 | for (const [pool, media_sets] of Object.entries(data)) { |
74 | let pool_entry = Ext.create('Ext.data.TreeModel', { | |
631e5509 | 75 | text: pool, |
2914e99f | 76 | iconCls: 'fa fa-object-group', |
927ebc70 | 77 | expanded: true, |
631e5509 | 78 | leaf: false, |
69ebbec4 DC |
79 | }); |
80 | ||
81 | let children = []; | |
82 | ||
83 | for (const media_set of Object.values(media_sets)) { | |
84 | let entry = Ext.create('Ext.data.TreeModel', media_set); | |
85 | entry.on('beforeexpand', (node) => me.beforeExpand(node)); | |
86 | children.push(entry); | |
07d6c096 | 87 | } |
69ebbec4 DC |
88 | |
89 | pool_entry.set('children', children); | |
631e5509 DC |
90 | list.push(pool_entry); |
91 | } | |
07d6c096 | 92 | |
631e5509 DC |
93 | return list; |
94 | }, | |
95 | ||
96 | reload: async function() { | |
97 | let me = this; | |
98 | let view = me.getView(); | |
99 | ||
100 | Proxmox.Utils.setErrorMask(view, true); | |
101 | ||
102 | try { | |
103 | let list = await me.loadContent(); | |
07d6c096 DC |
104 | |
105 | view.setRootNode({ | |
106 | expanded: true, | |
107 | children: list, | |
108 | }); | |
109 | ||
110 | Proxmox.Utils.setErrorMask(view, false); | |
111 | } catch (error) { | |
112 | Proxmox.Utils.setErrorMask(view, error.toString()); | |
113 | } | |
114 | }, | |
69ebbec4 DC |
115 | |
116 | loadMediaSet: async function(node) { | |
117 | let me = this; | |
118 | let view = me.getView(); | |
119 | ||
120 | Proxmox.Utils.setErrorMask(view, true); | |
00a5072a DC |
121 | const media_set_uuid = node.data['media-set-uuid']; |
122 | const media_set = node.data.text; | |
69ebbec4 DC |
123 | |
124 | try { | |
3006d70e | 125 | let list = await Proxmox.Async.api2({ |
69ebbec4 DC |
126 | method: 'GET', |
127 | url: `/api2/extjs/tape/media/content`, | |
128 | params: { | |
00a5072a | 129 | 'media-set': media_set_uuid, |
69ebbec4 DC |
130 | }, |
131 | }); | |
132 | ||
0af8c26b DC |
133 | list.result.data.sort(function(a, b) { |
134 | let storeRes = a.store.localeCompare(b.store); | |
135 | if (storeRes === 0) { | |
136 | return a.snapshot.localeCompare(b.snapshot); | |
137 | } else { | |
138 | return storeRes; | |
139 | } | |
140 | }); | |
69ebbec4 | 141 | |
0af8c26b | 142 | let stores = {}; |
dfde34e6 | 143 | |
69ebbec4 DC |
144 | for (let entry of list.result.data) { |
145 | entry.text = entry.snapshot; | |
4db4b970 | 146 | entry.restore = true; |
69ebbec4 DC |
147 | entry.leaf = true; |
148 | entry.children = []; | |
00a5072a | 149 | entry['media-set'] = media_set; |
4923a76f DC |
150 | entry.prefilter = { |
151 | store: entry.store, | |
152 | snapshot: entry.snapshot, | |
153 | }; | |
69ebbec4 DC |
154 | let iconCls = PBS.Utils.get_type_icon_cls(entry.snapshot); |
155 | if (iconCls !== '') { | |
156 | entry.iconCls = `fa ${iconCls}`; | |
157 | } | |
dfde34e6 | 158 | |
0af8c26b | 159 | let store = entry.store; |
dfde34e6 | 160 | let tape = entry['label-text']; |
0af8c26b DC |
161 | if (stores[store] === undefined) { |
162 | stores[store] = { | |
163 | text: store, | |
164 | 'media-set-uuid': entry['media-set-uuid'], | |
165 | iconCls: 'fa fa-database', | |
f9b824ac | 166 | typeText: 'datastore', |
e0168997 DC |
167 | restore: true, |
168 | 'media-set': media_set, | |
169 | prefilter: { | |
170 | store, | |
171 | }, | |
0af8c26b DC |
172 | tapes: {}, |
173 | }; | |
174 | } | |
175 | ||
176 | if (stores[store].tapes[tape] === undefined) { | |
177 | stores[store].tapes[tape] = { | |
dfde34e6 DC |
178 | text: tape, |
179 | 'media-set-uuid': entry['media-set-uuid'], | |
180 | 'seq-nr': entry['seq-nr'], | |
181 | iconCls: 'pbs-icon-tape', | |
182 | expanded: true, | |
183 | children: [], | |
184 | }; | |
185 | } | |
d938c933 DC |
186 | let [type, group, _id] = PBS.Utils.parse_snapshot_id(entry.snapshot); |
187 | ||
0af8c26b | 188 | let children = stores[store].tapes[tape].children; |
d938c933 DC |
189 | let text = `${type}/${group}`; |
190 | if (children.length < 1 || children[children.length - 1].text !== text) { | |
191 | children.push({ | |
192 | text, | |
193 | 'media-set-uuid': entry['media-set-uuid'], | |
194 | leaf: false, | |
47e5cbdb DC |
195 | restore: true, |
196 | prefilter: { | |
197 | store, | |
198 | snapshot: `${type}/${group}/`, | |
199 | }, | |
200 | 'media-set': media_set, | |
d938c933 | 201 | iconCls: `fa ${iconCls}`, |
f9b824ac | 202 | typeText: `group`, |
d938c933 DC |
203 | children: [], |
204 | }); | |
205 | } | |
206 | children[children.length - 1].children.push(entry); | |
dfde34e6 DC |
207 | } |
208 | ||
0af8c26b | 209 | let storeList = Object.values(stores); |
657c47db | 210 | let storeNameList = Object.keys(stores); |
0af8c26b DC |
211 | let expand = storeList.length === 1; |
212 | for (const store of storeList) { | |
213 | store.children = Object.values(store.tapes); | |
214 | store.expanded = expand; | |
215 | delete store.tapes; | |
216 | node.appendChild(store); | |
69ebbec4 DC |
217 | } |
218 | ||
219 | if (list.result.data.length === 0) { | |
220 | node.set('leaf', true); | |
221 | } | |
222 | ||
223 | node.set('loaded', true); | |
657c47db | 224 | node.set('datastores', storeNameList); |
69ebbec4 DC |
225 | Proxmox.Utils.setErrorMask(view, false); |
226 | node.expand(); | |
3006d70e | 227 | } catch (response) { |
00286540 | 228 | Proxmox.Utils.setErrorMask(view, false); |
3006d70e | 229 | Ext.Msg.alert('Error', response.result.message.toString()); |
69ebbec4 DC |
230 | } |
231 | }, | |
232 | ||
233 | beforeExpand: function(node, e) { | |
234 | let me = this; | |
235 | if (node.isLoaded()) { | |
236 | return true; | |
237 | } | |
238 | ||
239 | me.loadMediaSet(node); | |
240 | ||
241 | return false; | |
242 | }, | |
07d6c096 DC |
243 | }, |
244 | ||
245 | listeners: { | |
246 | activate: 'reload', | |
247 | }, | |
248 | ||
249 | store: { | |
07d6c096 | 250 | data: [], |
631e5509 | 251 | sorters: function(a, b) { |
69ebbec4 DC |
252 | if (a.data.is_media_set && b.data.is_media_set) { |
253 | return a.data['media-set-ctime'] - b.data['media-set-ctime']; | |
631e5509 DC |
254 | } else { |
255 | return a.data.text.localeCompare(b.data.text); | |
256 | } | |
257 | }, | |
07d6c096 DC |
258 | }, |
259 | ||
260 | rootVisible: false, | |
261 | ||
262 | tbar: [ | |
263 | { | |
264 | text: gettext('Reload'), | |
07875ce1 | 265 | iconCls: 'fa fa-refresh', |
07d6c096 DC |
266 | handler: 'reload', |
267 | }, | |
268 | '-', | |
269 | { | |
270 | text: gettext('New Backup'), | |
01a99f56 | 271 | iconCls: 'fa fa-floppy-o', |
07d6c096 DC |
272 | handler: 'backup', |
273 | }, | |
01a99f56 | 274 | '-', |
afb790db | 275 | { |
e21a15ab | 276 | text: gettext('Restore'), |
01a99f56 | 277 | iconCls: 'fa fa-undo', |
afb790db DC |
278 | handler: 'restore', |
279 | }, | |
07d6c096 DC |
280 | ], |
281 | ||
282 | columns: [ | |
283 | { | |
284 | xtype: 'treecolumn', | |
f44254b4 | 285 | text: gettext('Pool/Media-Set/Snapshot'), |
631e5509 DC |
286 | dataIndex: 'text', |
287 | sortable: false, | |
07d6c096 DC |
288 | flex: 3, |
289 | }, | |
4db4b970 | 290 | { |
1336be16 | 291 | header: gettext('Restore'), |
4db4b970 | 292 | xtype: 'actioncolumn', |
f9b824ac | 293 | dataIndex: 'text', |
4db4b970 DC |
294 | items: [ |
295 | { | |
104ae609 | 296 | handler: 'restoreBackups', |
f9b824ac TL |
297 | getTip: (v, m, rec) => { |
298 | let typeText = rec.get('typeText'); | |
299 | if (typeText) { | |
300 | v = `${typeText} '${v}'`; | |
301 | } | |
302 | return Ext.String.format(gettext("Open restore wizard for {0}"), v); | |
303 | }, | |
4db4b970 | 304 | getClass: (v, m, rec) => rec.data.restore ? 'fa fa-fw fa-undo' : 'pmx-hidden', |
4e0faf5e | 305 | isActionDisabled: (v, r, c, i, rec) => !rec.data.restore, |
4db4b970 DC |
306 | }, |
307 | ], | |
308 | }, | |
69ebbec4 | 309 | { |
1576c7a0 | 310 | text: gettext('Tapes'), |
69ebbec4 DC |
311 | dataIndex: 'tapes', |
312 | sortable: false, | |
69ebbec4 DC |
313 | }, |
314 | { | |
1576c7a0 | 315 | text: gettext('Seq. Nr.'), |
69ebbec4 DC |
316 | dataIndex: 'seq-nr', |
317 | sortable: false, | |
69ebbec4 | 318 | }, |
07d6c096 | 319 | { |
f44254b4 | 320 | text: gettext('Media-Set UUID'), |
69ebbec4 | 321 | dataIndex: 'media-set-uuid', |
1576c7a0 | 322 | hidden: true, |
631e5509 | 323 | sortable: false, |
1576c7a0 | 324 | width: 280, |
07d6c096 DC |
325 | }, |
326 | ], | |
327 | }); | |
328 |