]>
git.proxmox.com Git - proxmox-backup.git/blob - www/tape/window/TapeRestore.js
1 Ext
.define('PBS.TapeManagement.TapeRestoreWindow', {
2 extend
: 'Ext.window.Window',
3 alias
: 'widget.pbsTapeRestoreWindow',
4 mixins
: ['Proxmox.Mixin.CBind'],
8 title
: gettext('Restore Media Set'),
9 url
: '/api2/extjs/tape/restore',
14 cbindData: function(config
) {
16 if (me
.prefilter
!== undefined) {
17 me
.title
= gettext('Restore Snapshot(s)');
26 xclass
: 'Ext.app.ViewController',
28 panelIsValid: function(panel
) {
29 return panel
.query('[isFormField]').every(field
=> field
.isValid());
32 checkValidity: function() {
34 let tabpanel
= me
.lookup('tabpanel');
35 let items
= tabpanel
.items
;
37 let checkValidity
= true;
39 let indexOfActiveTab
= items
.indexOf(tabpanel
.getActiveTab());
40 let indexOfLastValidTab
= 0;
42 items
.each((panel
) => {
44 panel
.setDisabled(false);
45 indexOfLastValidTab
= items
.indexOf(panel
);
46 if (!me
.panelIsValid(panel
)) {
47 checkValidity
= false;
50 panel
.setDisabled(true);
56 if (indexOfLastValidTab
< indexOfActiveTab
) {
57 tabpanel
.setActiveTab(indexOfLastValidTab
);
59 me
.setButtonState(tabpanel
.getActiveTab());
63 setButtonState: function(panel
) {
65 let isValid
= me
.panelIsValid(panel
);
66 let nextButton
= me
.lookup('nextButton');
67 let finishButton
= me
.lookup('finishButton');
68 nextButton
.setDisabled(!isValid
);
69 finishButton
.setDisabled(!isValid
);
72 changeButtonVisibility: function(tabpanel
, newItem
) {
74 let items
= tabpanel
.items
;
76 let backButton
= me
.lookup('backButton');
77 let nextButton
= me
.lookup('nextButton');
78 let finishButton
= me
.lookup('finishButton');
80 let isLast
= items
.last() === newItem
;
81 let isFirst
= items
.first() === newItem
;
83 backButton
.setVisible(!isFirst
);
84 nextButton
.setVisible(!isLast
);
85 finishButton
.setVisible(isLast
);
87 me
.setButtonState(newItem
);
90 previousTab: function() {
92 let tabpanel
= me
.lookup('tabpanel');
93 let index
= tabpanel
.items
.indexOf(tabpanel
.getActiveTab());
94 tabpanel
.setActiveTab(index
- 1);
99 let tabpanel
= me
.lookup('tabpanel');
100 let index
= tabpanel
.items
.indexOf(tabpanel
.getActiveTab());
101 tabpanel
.setActiveTab(index
+ 1);
104 getValues: function() {
109 let tabpanel
= me
.lookup('tabpanel');
113 Proxmox
.Utils
.assemble_field_data(values
, panel
.getValues()));
120 let view
= me
.getView();
122 let values
= me
.getValues();
124 let method
= view
.method
;
126 Proxmox
.Utils
.API2Request({
131 failure: function(response
, options
) {
132 Ext
.Msg
.alert(gettext('Error'), response
.htmlStatus
);
134 success: function(response
, options
) {
135 // stay around so we can trigger our close events
136 // when background action is completed
139 Ext
.create('Proxmox.window.TaskViewer', {
141 upid
: response
.result
.data
,
143 destroy: function() {
152 updateDatastores: function() {
154 let grid
= me
.lookup('snapshotGrid');
155 let values
= grid
.getValue();
156 if (values
=== 'all') {
160 values
.forEach((snapshot
) => {
161 const [datastore
] = snapshot
.split(':');
162 datastores
[datastore
] = true;
165 me
.setDataStores(Object
.keys(datastores
));
168 setDataStores: function(datastores
, initial
) {
171 // save all datastores on the first setting, and
172 // restore them if we selected all
174 me
.datastores
= datastores
;
175 } else if (datastores
.length
=== 0) {
176 datastores
= me
.datastores
;
179 let label
= me
.lookup('mappingLabel');
180 let grid
= me
.lookup('mappingGrid');
181 let defaultField
= me
.lookup('defaultDatastore');
183 if (!datastores
|| datastores
.length
<= 1) {
184 label
.setVisible(false);
185 grid
.setVisible(false);
186 defaultField
.setFieldLabel(gettext('Target Datastore'));
187 defaultField
.setAllowBlank(false);
188 defaultField
.setEmptyText("");
192 label
.setVisible(true);
193 defaultField
.setFieldLabel(gettext('Default Datastore'));
194 defaultField
.setAllowBlank(true);
195 defaultField
.setEmptyText(Proxmox
.Utils
.NoneText
);
197 grid
.setDataStores(datastores
);
198 grid
.setVisible(true);
201 updateSnapshots: function() {
203 let view
= me
.getView();
204 let grid
= me
.lookup('snapshotGrid');
206 Proxmox
.Utils
.API2Request({
208 url
: `/tape/media/content?media-set=${view.uuid}`,
209 success: function(response
, opt
) {
211 for (const content
of response
.result
.data
) {
212 datastores
[content
.store
] = true;
214 me
.setDataStores(Object
.keys(datastores
), true);
215 if (response
.result
.data
.length
> 0) {
216 grid
.setDisabled(false);
217 grid
.setVisible(true);
218 grid
.getStore().setData(response
.result
.data
);
219 grid
.getSelectionModel().selectAll();
220 // we've shown a big list, center the window again
224 failure: function() {
225 // ignore failing api call, maybe catalog is missing
226 me
.setDataStores([], true);
233 change
: 'checkValidity',
234 validitychange
: 'checkValidity',
237 tabchange
: 'changeButtonVisibility',
244 text
: gettext('Back'),
245 reference
: 'backButton',
246 handler
: 'previousTab',
250 text
: gettext('Next'),
251 reference
: 'nextButton',
255 text
: gettext('Restore'),
256 reference
: 'finishButton',
265 reference
: 'tabpanel',
270 title
: gettext('Snapshot Selection'),
272 onGetValues: function(values
) {
275 if (values
.snapshots
=== 'all') {
276 delete values
.snapshots
;
277 } else if (Ext
.isString(values
.snapshots
) && values
.snapshots
) {
278 values
.snapshots
= values
.snapshots
.split(',');
286 xtype
: 'displayfield',
287 fieldLabel
: gettext('Media Set'),
296 xtype
: 'displayfield',
297 fieldLabel
: gettext('Media Set UUID'),
308 xtype
: 'pbsTapeSnapshotGrid',
309 reference
: 'snapshotGrid',
312 // will be shown/enabled on successful load
316 change
: 'updateDatastores',
319 prefilter
: '{prefilter}',
325 title
: gettext('Target'),
327 onGetValues: function(values
) {
330 if (values
.store
.toString() !== "") {
331 datastores
.push(values
.store
);
335 if (values
.mapping
.toString() !== "") {
336 datastores
.push(values
.mapping
);
338 delete values
.mapping
;
340 values
.store
= datastores
.join(',');
346 xtype
: 'pbsUserSelector',
348 fieldLabel
: gettext('Notify User'),
349 emptyText
: gettext('Current User'),
353 renderer
: Ext
.String
.htmlEncode
,
356 xtype
: 'pbsUserSelector',
358 fieldLabel
: gettext('Owner'),
359 emptyText
: gettext('Current User'),
363 renderer
: Ext
.String
.htmlEncode
,
369 xtype
: 'pbsDriveSelector',
370 fieldLabel
: gettext('Drive'),
375 xtype
: 'pbsDataStoreSelector',
376 fieldLabel
: gettext('Target Datastore'),
378 reference
: 'defaultDatastore',
381 change: function(field
, value
) {
383 let grid
= me
.up('window').lookup('mappingGrid');
384 grid
.setNeedStores(!value
);
392 fieldLabel
: gettext('Datastore Mapping'),
395 reference
: 'mappingLabel',
396 xtype
: 'displayfield',
399 xtype
: 'pbsDataStoreMappingField',
400 reference
: 'mappingGrid',
403 defaultBindProperty
: 'value',
413 afterrender
: 'updateSnapshots',
417 Ext
.define('PBS.TapeManagement.DataStoreMappingGrid', {
418 extend
: 'Ext.grid.Panel',
419 alias
: 'widget.pbsDataStoreMappingField',
420 mixins
: ['Ext.form.field.Field'],
424 getValue: function() {
427 me
.getStore().each((rec
) => {
428 let source
= rec
.data
.source
;
429 let target
= rec
.data
.target
;
430 if (target
&& target
!== "") {
431 datastores
.push(`${source}=${target}`);
435 return datastores
.join(',');
440 needStores
: false, // this determines if we need at least one valid mapping
443 emptyMeans
: get => get('needStores') ? Proxmox
.Utils
.NoneText
: Proxmox
.Utils
.defaultText
,
447 setNeedStores: function(needStores
) {
449 me
.getViewModel().set('needStores', needStores
);
454 setValue: function(value
) {
456 me
.setDataStores(value
);
460 getErrors: function(value
) {
464 if (me
.getViewModel().get('needStores')) {
466 me
.getStore().each((rec
) => {
467 if (rec
.data
.target
) {
473 let el
= me
.getActionEl();
475 me
.addCls(['x-form-trigger-wrap-default', 'x-form-trigger-wrap-invalid']);
476 let errorMsg
= gettext("Need at least one mapping");
478 el
.dom
.setAttribute('data-errorqtip', errorMsg
);
483 me
.removeCls(['x-form-trigger-wrap-default', 'x-form-trigger-wrap-invalid']);
485 el
.dom
.setAttribute('data-errorqtip', "");
490 setDataStores: function(datastores
) {
492 let store
= me
.getStore();
495 for (const datastore
of datastores
) {
513 text
: gettext('Source Datastore'),
518 text
: gettext('Target Datastore'),
519 xtype
: 'widgetcolumn',
523 xtype
: 'pbsDataStoreSelector',
526 emptyText
: '{emptyMeans}',
529 change: function(selector
, value
) {
531 let rec
= me
.getWidgetRecord();
535 rec
.set('target', value
);
536 me
.up('grid').checkChange();
544 Ext
.define('PBS.TapeManagement.SnapshotGrid', {
545 extend
: 'Ext.grid.Panel',
546 alias
: 'widget.pbsTapeSnapshotGrid',
547 mixins
: ['Ext.form.field.Field'],
549 getValue: function() {
553 me
.getSelection().forEach((rec
) => {
554 let id
= rec
.get('id');
555 let store
= rec
.data
.store
;
556 let snap
= rec
.data
.snapshot
;
557 // only add if not filtered
558 if (me
.store
.findExact('id', id
) !== -1) {
559 snapshots
.push(`${store}:${snap}`);
563 // getSource returns null if data is not filtered
564 let originalData
= me
.store
.getData().getSource() || me
.store
.getData();
566 if (snapshots
.length
=== originalData
.length
) {
573 setValue: function(value
) {
579 getErrors: function(value
) {
581 if (me
.getSelection().length
< 1) {
582 me
.addCls(['x-form-trigger-wrap-default', 'x-form-trigger-wrap-invalid']);
583 let errorMsg
= gettext("Need at least one snapshot");
584 let el
= me
.getActionEl();
586 el
.dom
.setAttribute('data-errorqtip', errorMsg
);
591 me
.removeCls(['x-form-trigger-wrap-default', 'x-form-trigger-wrap-invalid']);
592 let el
= me
.getActionEl();
594 el
.dom
.setAttribute('data-errorqtip', "");
600 plugins
: 'gridfilters',
603 emptyText
: gettext('No Snapshots'),
607 selModel
: 'checkboxmodel',
609 sorters
: ['store', 'snapshot'],
615 selectionchange: function() {
616 // to trigger validity and error checks
628 text
: gettext('Source Datastore'),
636 text
: gettext('Snapshot'),
637 dataIndex
: 'snapshot',
645 initComponent: function() {
648 if (me
.prefilter
!== undefined) {
649 me
.store
.filters
.add(
651 id
: 'x-gridfilter-store',
654 value
: [me
.prefilter
.store
],
657 id
: 'x-gridfilter-snapshot',
658 property
: 'snapshot',
659 value
: me
.prefilter
.snapshot
,
664 me
.mon(me
.store
, 'filterchange', () => me
.checkChange());