2020-10-27 15:20:09 +00:00
|
|
|
Ext.define('pbs-datastore-list', {
|
|
|
|
extend: 'Ext.data.Model',
|
|
|
|
fields: ['name', 'comment'],
|
|
|
|
proxy: {
|
|
|
|
type: 'proxmox',
|
|
|
|
url: "/api2/json/admin/datastore",
|
|
|
|
},
|
|
|
|
idProperty: 'store',
|
|
|
|
});
|
|
|
|
|
2021-03-01 11:22:41 +00:00
|
|
|
Ext.define('pbs-tape-drive-list', {
|
|
|
|
extend: 'Ext.data.Model',
|
|
|
|
fields: ['name', 'changer'],
|
|
|
|
proxy: {
|
|
|
|
type: 'proxmox',
|
|
|
|
url: "/api2/json/tape/drive",
|
|
|
|
},
|
|
|
|
idProperty: 'name',
|
|
|
|
});
|
|
|
|
|
2019-01-22 10:48:00 +00:00
|
|
|
Ext.define('PBS.store.NavigationStore', {
|
|
|
|
extend: 'Ext.data.TreeStore',
|
|
|
|
|
|
|
|
storeId: 'NavigationStore',
|
|
|
|
|
|
|
|
root: {
|
|
|
|
expanded: true,
|
|
|
|
children: [
|
2019-12-18 16:29:05 +00:00
|
|
|
{
|
|
|
|
text: gettext('Dashboard'),
|
|
|
|
iconCls: 'fa fa-tachometer',
|
|
|
|
path: 'pbsDashboard',
|
2020-09-25 16:36:58 +00:00
|
|
|
leaf: true,
|
2019-12-18 16:29:05 +00:00
|
|
|
},
|
2019-01-22 10:48:00 +00:00
|
|
|
{
|
|
|
|
text: gettext('Configuration'),
|
|
|
|
iconCls: 'fa fa-gears',
|
|
|
|
path: 'pbsSystemConfiguration',
|
|
|
|
expanded: true,
|
|
|
|
children: [
|
2020-05-18 12:18:38 +00:00
|
|
|
{
|
2020-10-29 15:47:18 +00:00
|
|
|
text: gettext('Access Control'),
|
|
|
|
iconCls: 'fa fa-key',
|
|
|
|
path: 'pbsAccessControlPanel',
|
2020-09-25 16:36:58 +00:00
|
|
|
leaf: true,
|
2020-05-20 10:15:37 +00:00
|
|
|
},
|
2020-05-26 10:23:25 +00:00
|
|
|
{
|
|
|
|
text: gettext('Remotes'),
|
|
|
|
iconCls: 'fa fa-server',
|
|
|
|
path: 'pbsRemoteView',
|
|
|
|
leaf: true,
|
|
|
|
},
|
2019-01-22 10:48:00 +00:00
|
|
|
{
|
|
|
|
text: gettext('Subscription'),
|
|
|
|
iconCls: 'fa fa-support',
|
|
|
|
path: 'pbsSubscription',
|
2020-09-25 16:36:58 +00:00
|
|
|
leaf: true,
|
|
|
|
},
|
|
|
|
],
|
2019-01-22 10:48:00 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
text: gettext('Administration'),
|
|
|
|
iconCls: 'fa fa-wrench',
|
|
|
|
path: 'pbsServerAdministration',
|
2020-06-16 09:13:34 +00:00
|
|
|
expanded: true,
|
|
|
|
leaf: false,
|
|
|
|
children: [
|
2020-11-04 14:35:08 +00:00
|
|
|
{
|
|
|
|
text: gettext('Shell'),
|
|
|
|
iconCls: 'fa fa-terminal',
|
|
|
|
path: 'pbsXtermJsConsole',
|
|
|
|
leaf: true,
|
|
|
|
},
|
2020-06-16 09:13:34 +00:00
|
|
|
{
|
2020-11-10 09:15:44 +00:00
|
|
|
text: gettext('Storage / Disks'),
|
2020-06-16 09:13:34 +00:00
|
|
|
iconCls: 'fa fa-hdd-o',
|
2020-11-10 09:15:44 +00:00
|
|
|
path: 'pbsStorageAndDiskPanel',
|
|
|
|
leaf: true,
|
2020-09-25 16:36:58 +00:00
|
|
|
},
|
|
|
|
],
|
2020-06-05 08:11:51 +00:00
|
|
|
},
|
2021-04-12 10:31:56 +00:00
|
|
|
{
|
|
|
|
text: "Tape Backup",
|
|
|
|
iconCls: 'pbs-icon-tape',
|
|
|
|
id: 'tape_management',
|
|
|
|
path: 'pbsTapeManagement',
|
|
|
|
expanded: true,
|
|
|
|
children: [],
|
|
|
|
},
|
2020-06-05 08:11:51 +00:00
|
|
|
{
|
2020-07-02 15:20:38 +00:00
|
|
|
text: gettext('Datastore'),
|
2020-06-05 08:11:51 +00:00
|
|
|
iconCls: 'fa fa-archive',
|
2020-10-27 15:20:09 +00:00
|
|
|
id: 'datastores',
|
2020-11-09 15:01:30 +00:00
|
|
|
path: 'pbsDataStores',
|
2020-06-05 08:11:51 +00:00
|
|
|
expanded: true,
|
2020-10-27 15:20:09 +00:00
|
|
|
expandable: false,
|
2020-09-25 16:36:58 +00:00
|
|
|
leaf: false,
|
2020-10-27 15:20:09 +00:00
|
|
|
children: [
|
|
|
|
{
|
|
|
|
text: gettext('Add Datastore'),
|
|
|
|
iconCls: 'fa fa-plus-circle',
|
|
|
|
leaf: true,
|
|
|
|
id: 'addbutton',
|
2021-04-12 12:10:57 +00:00
|
|
|
virtualEntry: true,
|
2020-10-27 15:20:09 +00:00
|
|
|
},
|
|
|
|
],
|
2020-06-05 08:11:51 +00:00
|
|
|
},
|
2020-09-25 16:36:58 +00:00
|
|
|
],
|
|
|
|
},
|
2019-01-22 10:48:00 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
Ext.define('PBS.view.main.NavigationTree', {
|
|
|
|
extend: 'Ext.list.Tree',
|
|
|
|
xtype: 'navigationtree',
|
|
|
|
|
2019-12-20 11:46:09 +00:00
|
|
|
controller: {
|
|
|
|
xclass: 'Ext.app.ViewController',
|
|
|
|
|
|
|
|
init: function(view) {
|
|
|
|
view.rstore = Ext.create('Proxmox.data.UpdateStore', {
|
|
|
|
autoStart: true,
|
|
|
|
interval: 15 * 1000,
|
|
|
|
storeid: 'pbs-datastore-list',
|
2020-09-25 16:36:58 +00:00
|
|
|
model: 'pbs-datastore-list',
|
2019-12-20 11:46:09 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
view.rstore.on('load', this.onLoad, this);
|
|
|
|
view.on('destroy', view.rstore.stopUpdate);
|
2021-03-01 11:22:41 +00:00
|
|
|
|
2021-04-12 10:34:26 +00:00
|
|
|
if (view.tapeStore === undefined) {
|
|
|
|
view.tapeStore = Ext.create('Proxmox.data.UpdateStore', {
|
2021-04-12 10:31:56 +00:00
|
|
|
autoStart: true,
|
|
|
|
interval: 60 * 1000,
|
|
|
|
storeid: 'pbs-tape-drive-list',
|
|
|
|
model: 'pbs-tape-drive-list',
|
|
|
|
});
|
2021-04-12 10:34:26 +00:00
|
|
|
view.tapeStore.on('load', this.onTapeDriveLoad, this);
|
|
|
|
view.on('destroy', view.tapeStore.stopUpdate);
|
2021-03-01 11:22:41 +00:00
|
|
|
}
|
2019-12-20 11:46:09 +00:00
|
|
|
},
|
|
|
|
|
2021-03-01 11:22:41 +00:00
|
|
|
onTapeDriveLoad: function(store, records, success) {
|
2020-06-05 08:11:51 +00:00
|
|
|
if (!success) return;
|
2019-12-20 11:46:09 +00:00
|
|
|
|
2021-03-01 11:22:41 +00:00
|
|
|
let view = this.getView();
|
2019-12-20 11:46:09 +00:00
|
|
|
let root = view.getStore().getRoot();
|
|
|
|
|
2021-03-01 11:22:41 +00:00
|
|
|
records.sort((a, b) => a.data.name.localeCompare(b.data.name));
|
|
|
|
|
2021-04-12 12:09:29 +00:00
|
|
|
let list = root.findChild('id', 'tape_management', false);
|
|
|
|
let existingChildren = {};
|
2021-03-01 11:22:41 +00:00
|
|
|
for (const drive of records) {
|
|
|
|
let path, text, iconCls;
|
|
|
|
if (drive.data.changer !== undefined) {
|
|
|
|
text = drive.data.changer;
|
|
|
|
path = `Changer-${text}`;
|
2021-03-08 16:06:49 +00:00
|
|
|
iconCls = 'fa fa-exchange';
|
2021-03-01 11:22:41 +00:00
|
|
|
} else {
|
|
|
|
text = drive.data.name;
|
|
|
|
path = `Drive-${text}`;
|
2021-03-08 16:06:49 +00:00
|
|
|
iconCls = 'pbs-icon-tape-drive';
|
2021-03-01 11:22:41 +00:00
|
|
|
}
|
2021-04-12 12:09:29 +00:00
|
|
|
existingChildren[path] = {
|
2021-03-01 11:22:41 +00:00
|
|
|
text,
|
|
|
|
path,
|
|
|
|
iconCls,
|
|
|
|
leaf: true,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-04-12 12:09:29 +00:00
|
|
|
let paths = Object.keys(existingChildren).sort();
|
2021-03-01 11:22:41 +00:00
|
|
|
|
|
|
|
let oldIdx = 0;
|
|
|
|
for (let newIdx = 0; newIdx < paths.length; newIdx++) {
|
|
|
|
let newPath = paths[newIdx];
|
|
|
|
// find index to insert
|
|
|
|
while (oldIdx < list.childNodes.length && newPath > list.getChildAt(oldIdx).data.path) {
|
|
|
|
oldIdx++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (oldIdx >= list.childNodes.length || list.getChildAt(oldIdx).data.path !== newPath) {
|
2021-04-12 12:09:29 +00:00
|
|
|
list.insertChild(oldIdx, existingChildren[newPath]);
|
2020-12-04 11:50:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-12 12:09:29 +00:00
|
|
|
let toRemove = [];
|
2021-03-01 11:22:41 +00:00
|
|
|
list.eachChild((child) => {
|
2021-04-12 12:09:29 +00:00
|
|
|
if (!existingChildren[child.data.path]) {
|
|
|
|
toRemove.push(child);
|
2021-03-01 11:22:41 +00:00
|
|
|
}
|
|
|
|
});
|
2021-04-12 12:09:29 +00:00
|
|
|
toRemove.forEach((child) => list.removeChild(child, true));
|
2021-03-01 11:22:41 +00:00
|
|
|
|
|
|
|
if (view.pathToSelect !== undefined) {
|
|
|
|
let path = view.pathToSelect;
|
|
|
|
delete view.pathToSelect;
|
|
|
|
view.select(path, true);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
onLoad: function(store, records, success) {
|
2021-04-12 12:09:29 +00:00
|
|
|
if (!success) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let view = this.getView();
|
2021-03-01 11:22:41 +00:00
|
|
|
let root = view.getStore().getRoot();
|
|
|
|
|
2020-10-27 15:20:09 +00:00
|
|
|
records.sort((a, b) => a.id.localeCompare(b.id));
|
2020-05-25 17:46:43 +00:00
|
|
|
|
2021-04-12 12:09:29 +00:00
|
|
|
let list = root.findChild('id', 'datastores', false);
|
|
|
|
let getChildTextAt = i => list.getChildAt(i).data.text;
|
|
|
|
let existingChildren = {};
|
|
|
|
for (let i = 0, j = 0, length = records.length; i < length; i++) {
|
2020-09-25 16:36:58 +00:00
|
|
|
let name = records[i].id;
|
2021-04-12 12:09:29 +00:00
|
|
|
existingChildren[name] = true;
|
2020-10-27 15:20:09 +00:00
|
|
|
|
2021-04-12 12:09:29 +00:00
|
|
|
while (name.localeCompare(getChildTextAt(j)) > 0 && (j+1) < list.childNodes.length) {
|
2020-10-27 15:20:09 +00:00
|
|
|
j++;
|
|
|
|
}
|
|
|
|
|
2021-04-12 12:09:29 +00:00
|
|
|
if (getChildTextAt(j).localeCompare(name) !== 0) {
|
2020-10-27 15:20:09 +00:00
|
|
|
list.insertChild(j, {
|
2019-12-20 11:46:09 +00:00
|
|
|
text: name,
|
2020-05-20 10:15:38 +00:00
|
|
|
path: `DataStore-${name}`,
|
2019-12-21 08:15:57 +00:00
|
|
|
iconCls: 'fa fa-database',
|
2020-09-25 16:36:58 +00:00
|
|
|
leaf: true,
|
2019-12-20 11:46:09 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-12 12:09:29 +00:00
|
|
|
// remove entries which are not existing anymore
|
|
|
|
let toRemove = [];
|
|
|
|
list.eachChild(child => {
|
2021-04-12 12:10:57 +00:00
|
|
|
if (!existingChildren[child.data.text] && !child.data.virtualEntry) {
|
2021-04-12 12:09:29 +00:00
|
|
|
toRemove.push(child);
|
2019-12-20 11:46:09 +00:00
|
|
|
}
|
|
|
|
});
|
2021-04-12 12:09:29 +00:00
|
|
|
toRemove.forEach(child => list.removeChild(child, true));
|
2020-10-27 15:20:10 +00:00
|
|
|
|
|
|
|
if (view.pathToSelect !== undefined) {
|
|
|
|
let path = view.pathToSelect;
|
|
|
|
delete view.pathToSelect;
|
|
|
|
view.select(path, true);
|
|
|
|
}
|
2020-10-27 15:20:09 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
listeners: {
|
|
|
|
itemclick: function(tl, info) {
|
|
|
|
if (info.node.data.id === 'addbutton') {
|
|
|
|
let me = this;
|
|
|
|
Ext.create('PBS.DataStoreEdit', {
|
|
|
|
listeners: {
|
2021-04-12 12:11:18 +00:00
|
|
|
destroy: () => me.rstore.reload(),
|
2020-10-27 15:20:09 +00:00
|
|
|
},
|
|
|
|
}).show();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
2020-09-25 16:36:58 +00:00
|
|
|
},
|
2019-12-20 11:46:09 +00:00
|
|
|
},
|
|
|
|
|
2021-03-10 09:10:47 +00:00
|
|
|
reloadTapeStore: function() {
|
|
|
|
let me = this;
|
2021-04-12 10:34:26 +00:00
|
|
|
me.tapeStore.load();
|
2021-03-10 09:10:47 +00:00
|
|
|
},
|
|
|
|
|
2020-10-27 15:20:10 +00:00
|
|
|
select: function(path, silent) {
|
2019-01-22 10:48:00 +00:00
|
|
|
var me = this;
|
2021-04-12 10:34:26 +00:00
|
|
|
if (me.rstore.isLoaded() && me.tapeStore.isLoaded()) {
|
2020-10-27 15:20:10 +00:00
|
|
|
if (silent) {
|
|
|
|
me.suspendEvents(false);
|
|
|
|
}
|
|
|
|
var item = me.getStore().findRecord('path', path, 0, false, true, true);
|
|
|
|
me.setSelection(item);
|
|
|
|
if (silent) {
|
|
|
|
me.resumeEvents(true);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
me.pathToSelect = path;
|
|
|
|
}
|
2019-01-22 10:48:00 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
animation: false,
|
|
|
|
expanderOnly: true,
|
|
|
|
expanderFirst: false,
|
|
|
|
store: 'NavigationStore',
|
2020-09-25 16:36:58 +00:00
|
|
|
ui: 'nav',
|
2019-01-22 10:48:00 +00:00
|
|
|
});
|