2018-12-04 16:53:10 +00:00
|
|
|
Ext.define('PBS.MainView', {
|
|
|
|
extend: 'Ext.container.Container',
|
|
|
|
xtype: 'mainview',
|
|
|
|
|
|
|
|
title: 'Proxmox Backup Server',
|
|
|
|
|
|
|
|
controller: {
|
|
|
|
xclass: 'Ext.app.ViewController',
|
|
|
|
routes: {
|
|
|
|
':path:subpath': {
|
|
|
|
action: 'changePath',
|
|
|
|
before: 'beforeChangePath',
|
2020-09-25 16:34:54 +00:00
|
|
|
conditions: {
|
|
|
|
':path': '(?:([%a-zA-Z0-9\\-\\_\\s,.]+))',
|
|
|
|
':subpath': '(?:(?::)([%a-zA-Z0-9\\-\\_\\s,]+))?',
|
|
|
|
},
|
|
|
|
},
|
2018-12-04 16:53:10 +00:00
|
|
|
},
|
2019-12-18 18:21:59 +00:00
|
|
|
|
2021-03-01 11:22:40 +00:00
|
|
|
parseRouterPath: function(path) {
|
2020-05-20 10:15:38 +00:00
|
|
|
let xtype = path;
|
2021-03-01 11:22:40 +00:00
|
|
|
let config = {};
|
|
|
|
if (PBS.Utils.isDataStorePath(path)) {
|
|
|
|
config.datastore = PBS.Utils.getDataStoreFromPath(path);
|
2020-05-20 10:15:38 +00:00
|
|
|
xtype = 'pbsDataStorePanel';
|
2021-03-01 11:22:40 +00:00
|
|
|
} else if (path.indexOf('Changer-') === 0) {
|
|
|
|
config.changer = path.slice('Changer-'.length);
|
|
|
|
xtype = 'pbsChangerStatus';
|
|
|
|
} else if (path.indexOf('Drive-') === 0) {
|
|
|
|
config.drive = path.slice('Drive-'.length);
|
|
|
|
xtype = 'pbsDriveStatus';
|
2020-05-20 10:15:38 +00:00
|
|
|
}
|
|
|
|
|
2021-03-01 11:22:40 +00:00
|
|
|
return [xtype, config];
|
|
|
|
},
|
|
|
|
|
2021-05-26 09:12:04 +00:00
|
|
|
beforeChangePath: function(path, subpathOrAction, action) {
|
2021-03-01 11:22:40 +00:00
|
|
|
var me = this;
|
|
|
|
|
2021-05-26 09:12:04 +00:00
|
|
|
let subpath = subpathOrAction;
|
|
|
|
if (!action) {
|
|
|
|
action = subpathOrAction;
|
|
|
|
subpath = undefined;
|
|
|
|
}
|
|
|
|
|
2021-03-01 11:22:40 +00:00
|
|
|
let [xtype, config] = me.parseRouterPath(path);
|
|
|
|
|
2020-05-20 10:15:38 +00:00
|
|
|
if (!Ext.ClassManager.getByAlias(`widget.${xtype}`)) {
|
|
|
|
console.warn(`xtype ${xtype} not found`);
|
2019-01-22 10:48:00 +00:00
|
|
|
action.stop();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var lastpanel = me.lookupReference('contentpanel').getLayout().getActiveItem();
|
2020-05-20 10:15:38 +00:00
|
|
|
if (lastpanel && lastpanel.xtype === xtype) {
|
2021-03-01 11:22:40 +00:00
|
|
|
for (const [prop, value] of Object.entries(config)) {
|
|
|
|
if (lastpanel[prop] !== value) {
|
|
|
|
action.resume();
|
2019-12-20 11:46:09 +00:00
|
|
|
return;
|
|
|
|
}
|
2021-03-01 11:22:40 +00:00
|
|
|
}
|
|
|
|
// we have the right component already,
|
|
|
|
// we just need to select the correct tab
|
|
|
|
// default to the first
|
|
|
|
subpath = subpath || 0;
|
|
|
|
if (lastpanel.getActiveTab) {
|
|
|
|
// we assume lastpanel is a tabpanel
|
|
|
|
if (lastpanel.getActiveTab().getItemId() !== subpath) {
|
|
|
|
// set the active tab
|
|
|
|
lastpanel.setActiveTab(subpath);
|
2019-01-22 10:48:00 +00:00
|
|
|
}
|
2021-03-01 11:22:40 +00:00
|
|
|
// else we are already there
|
2019-01-22 10:48:00 +00:00
|
|
|
}
|
2021-03-01 11:22:40 +00:00
|
|
|
action.stop();
|
|
|
|
return;
|
2019-01-22 10:48:00 +00:00
|
|
|
}
|
|
|
|
|
2018-12-04 16:53:10 +00:00
|
|
|
action.resume();
|
|
|
|
},
|
2019-12-18 18:21:59 +00:00
|
|
|
|
2019-12-20 11:46:09 +00:00
|
|
|
changePath: function(path, subpath) {
|
2018-12-04 16:53:10 +00:00
|
|
|
var me = this;
|
|
|
|
var contentpanel = me.lookupReference('contentpanel');
|
|
|
|
var lastpanel = contentpanel.getLayout().getActiveItem();
|
|
|
|
|
2020-10-27 15:20:10 +00:00
|
|
|
let tabChangeListener = function(tp, newc, oldc) {
|
|
|
|
let newpath = path;
|
2019-01-22 10:48:00 +00:00
|
|
|
|
2020-10-27 15:20:10 +00:00
|
|
|
// only add the subpath part for the
|
|
|
|
// non-default tabs
|
|
|
|
if (tp.items.findIndex('id', newc.id) !== 0) {
|
|
|
|
newpath += `:${newc.getItemId()}`;
|
|
|
|
}
|
2019-01-22 10:48:00 +00:00
|
|
|
|
2020-10-27 15:20:10 +00:00
|
|
|
me.redirectTo(newpath);
|
|
|
|
};
|
2019-01-22 10:48:00 +00:00
|
|
|
|
2021-03-01 11:22:40 +00:00
|
|
|
let [xtype, config] = me.parseRouterPath(path);
|
2020-10-27 15:20:10 +00:00
|
|
|
var obj;
|
|
|
|
if (PBS.Utils.isDataStorePath(path)) {
|
2021-03-01 11:22:40 +00:00
|
|
|
if (lastpanel && lastpanel.xtype === xtype && !subpath) {
|
2020-10-27 15:20:10 +00:00
|
|
|
let activeTab = lastpanel.getActiveTab();
|
|
|
|
let newpath = path;
|
|
|
|
if (lastpanel.items.indexOf(activeTab) !== 0) {
|
|
|
|
subpath = activeTab.getItemId();
|
|
|
|
newpath += `:${subpath}`;
|
2019-01-22 10:48:00 +00:00
|
|
|
}
|
|
|
|
me.redirectTo(newpath);
|
2020-10-27 15:20:10 +00:00
|
|
|
}
|
2019-01-22 10:48:00 +00:00
|
|
|
}
|
2021-03-01 11:22:40 +00:00
|
|
|
obj = contentpanel.add(Ext.apply(config, {
|
2020-10-27 15:20:10 +00:00
|
|
|
xtype,
|
|
|
|
nodename: 'localhost',
|
|
|
|
border: false,
|
|
|
|
activeTab: subpath || 0,
|
|
|
|
listeners: {
|
|
|
|
tabchange: tabChangeListener,
|
|
|
|
},
|
2021-03-01 11:22:40 +00:00
|
|
|
}));
|
2020-10-27 15:20:10 +00:00
|
|
|
|
|
|
|
var treelist = me.lookupReference('navtree');
|
|
|
|
|
|
|
|
treelist.select(path, true);
|
2019-01-22 10:48:00 +00:00
|
|
|
|
|
|
|
contentpanel.setActiveItem(obj);
|
|
|
|
|
|
|
|
if (lastpanel) {
|
|
|
|
contentpanel.remove(lastpanel, { destroy: true });
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2019-01-30 14:14:20 +00:00
|
|
|
logout: function() {
|
|
|
|
PBS.app.logout();
|
|
|
|
},
|
|
|
|
|
2019-01-22 10:48:00 +00:00
|
|
|
navigate: function(treelist, item) {
|
|
|
|
this.redirectTo(item.get('path'));
|
2018-12-04 16:53:10 +00:00
|
|
|
},
|
|
|
|
|
2019-01-30 14:14:20 +00:00
|
|
|
control: {
|
2020-07-09 12:24:33 +00:00
|
|
|
'[reference=logoutButton]': {
|
2020-09-25 16:34:54 +00:00
|
|
|
click: 'logout',
|
|
|
|
},
|
2019-01-30 14:14:20 +00:00
|
|
|
},
|
|
|
|
|
2018-12-04 16:53:10 +00:00
|
|
|
init: function(view) {
|
|
|
|
var me = this;
|
|
|
|
|
2020-07-09 11:38:20 +00:00
|
|
|
PBS.data.RunningTasksStore.startUpdate();
|
2020-07-09 12:24:33 +00:00
|
|
|
me.lookupReference('usernameinfo').setText(Proxmox.UserName);
|
2019-12-17 13:44:25 +00:00
|
|
|
|
2019-12-17 13:45:13 +00:00
|
|
|
// show login on requestexception
|
|
|
|
// fixme: what about other errors
|
|
|
|
Ext.Ajax.on('requestexception', function(conn, response, options) {
|
2020-09-25 16:34:54 +00:00
|
|
|
if (response.status === 401 || response.status === '401') { // auth failure
|
2019-12-17 13:45:13 +00:00
|
|
|
me.logout();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2019-12-17 13:44:25 +00:00
|
|
|
// get ticket periodically
|
|
|
|
Ext.TaskManager.start({
|
|
|
|
run: function() {
|
|
|
|
var ticket = Proxmox.Utils.authOK();
|
|
|
|
if (!ticket || !Proxmox.UserName) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ext.Ajax.request({
|
|
|
|
params: {
|
|
|
|
username: Proxmox.UserName,
|
2020-09-25 16:34:54 +00:00
|
|
|
password: ticket,
|
2019-12-17 13:44:25 +00:00
|
|
|
},
|
|
|
|
url: '/api2/json/access/ticket',
|
|
|
|
method: 'POST',
|
|
|
|
failure: function() {
|
|
|
|
me.logout();
|
|
|
|
},
|
|
|
|
success: function(response, opts) {
|
|
|
|
var obj = Ext.decode(response.responseText);
|
2019-12-17 14:42:59 +00:00
|
|
|
PBS.Utils.updateLoginData(obj.data);
|
2020-09-25 16:34:54 +00:00
|
|
|
},
|
2019-12-17 13:44:25 +00:00
|
|
|
});
|
|
|
|
},
|
2020-09-25 16:34:54 +00:00
|
|
|
interval: 15*60*1000,
|
2019-12-17 13:44:25 +00:00
|
|
|
});
|
2019-12-18 18:19:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
// select treeitem and load page from url fragment, if set
|
|
|
|
let token = Ext.util.History.getToken() || 'pbsDashboard';
|
|
|
|
this.redirectTo(token, true);
|
2020-09-25 16:34:54 +00:00
|
|
|
},
|
2018-12-04 16:53:10 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
plugins: 'viewport',
|
|
|
|
|
|
|
|
layout: { type: 'border' },
|
|
|
|
|
|
|
|
items: [
|
|
|
|
{
|
|
|
|
region: 'north',
|
|
|
|
xtype: 'container',
|
|
|
|
layout: {
|
|
|
|
type: 'hbox',
|
2020-09-25 16:34:54 +00:00
|
|
|
align: 'middle',
|
2018-12-04 16:53:10 +00:00
|
|
|
},
|
2020-07-09 12:25:14 +00:00
|
|
|
margin: '2 0 2 5',
|
2018-12-04 16:53:10 +00:00
|
|
|
height: 38,
|
|
|
|
items: [
|
|
|
|
{
|
2020-05-18 12:18:37 +00:00
|
|
|
xtype: 'proxmoxlogo',
|
|
|
|
prefix: '',
|
2018-12-04 16:53:10 +00:00
|
|
|
},
|
|
|
|
{
|
2020-07-09 12:25:14 +00:00
|
|
|
padding: '0 0 0 5',
|
|
|
|
xtype: 'versioninfo',
|
2018-12-04 16:53:10 +00:00
|
|
|
},
|
|
|
|
{
|
2020-07-03 10:48:50 +00:00
|
|
|
flex: 1,
|
|
|
|
baseCls: 'x-plain',
|
2018-12-04 16:53:10 +00:00
|
|
|
},
|
2022-06-02 15:34:45 +00:00
|
|
|
{
|
|
|
|
xtype: 'proxmoxEOLNotice',
|
|
|
|
product: 'Proxmox Backup Server',
|
|
|
|
version: '1.1',
|
|
|
|
eolDate: '2022-07-31',
|
|
|
|
href: 'pbs.proxmox.com/docs/faq.html#how-long-will-my-proxmox-backup-server-version-be-supported',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
flex: 1,
|
|
|
|
},
|
2019-12-16 17:16:06 +00:00
|
|
|
{
|
|
|
|
xtype: 'button',
|
|
|
|
baseCls: 'x-btn',
|
|
|
|
cls: 'x-btn-default-toolbar-small proxmox-inline-button',
|
|
|
|
iconCls: 'fa fa-book x-btn-icon-el-default-toolbar-small ',
|
|
|
|
text: gettext('Documentation'),
|
|
|
|
href: '/docs/index.html',
|
|
|
|
margin: '0 5 0 0',
|
|
|
|
},
|
2020-07-09 11:38:21 +00:00
|
|
|
{
|
|
|
|
xtype: 'pbsTaskButton',
|
|
|
|
margin: '0 5 0 0',
|
|
|
|
},
|
2018-12-04 16:53:10 +00:00
|
|
|
{
|
|
|
|
xtype: 'button',
|
2020-07-09 12:24:33 +00:00
|
|
|
reference: 'usernameinfo',
|
|
|
|
style: {
|
|
|
|
// proxmox dark grey p light grey as border
|
|
|
|
backgroundColor: '#464d4d',
|
2020-09-25 16:34:54 +00:00
|
|
|
borderColor: '#ABBABA',
|
2020-07-09 12:24:33 +00:00
|
|
|
},
|
|
|
|
margin: '0 5 0 0',
|
|
|
|
iconCls: 'fa fa-user',
|
|
|
|
menu: [
|
2021-02-19 14:40:48 +00:00
|
|
|
{
|
|
|
|
iconCls: 'fa fa-gear',
|
|
|
|
text: gettext('My Settings'),
|
|
|
|
handler: () => Ext.create('PBS.window.Settings').show(),
|
|
|
|
},
|
2020-07-09 12:24:33 +00:00
|
|
|
{
|
2020-10-30 08:46:04 +00:00
|
|
|
iconCls: 'fa fa-language',
|
|
|
|
text: gettext('Language'),
|
|
|
|
reference: 'languageButton',
|
|
|
|
handler: () => Ext.create('Proxmox.window.LanguageEditWindow', {
|
|
|
|
cookieName: 'PBSLangCookie',
|
|
|
|
autoShow: true,
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
'-',
|
|
|
|
{
|
2020-07-09 12:24:33 +00:00
|
|
|
iconCls: 'fa fa-sign-out',
|
|
|
|
text: gettext('Logout'),
|
2020-10-30 08:46:04 +00:00
|
|
|
reference: 'logoutButton',
|
2020-07-09 12:24:33 +00:00
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
2020-09-25 16:34:54 +00:00
|
|
|
],
|
2018-12-04 16:53:10 +00:00
|
|
|
},
|
|
|
|
{
|
2021-05-26 09:11:58 +00:00
|
|
|
xtype: 'container',
|
2018-12-04 16:53:10 +00:00
|
|
|
scrollable: 'y',
|
|
|
|
border: false,
|
|
|
|
region: 'west',
|
|
|
|
layout: {
|
|
|
|
type: 'vbox',
|
2020-09-25 16:34:54 +00:00
|
|
|
align: 'stretch',
|
2018-12-04 16:53:10 +00:00
|
|
|
},
|
2019-01-22 10:48:00 +00:00
|
|
|
items: [{
|
|
|
|
xtype: 'navigationtree',
|
|
|
|
minWidth: 180,
|
2021-05-26 09:12:02 +00:00
|
|
|
ui: 'pve-nav',
|
2019-01-22 10:48:00 +00:00
|
|
|
reference: 'navtree',
|
|
|
|
// we have to define it here until extjs 6.2
|
|
|
|
// because of a bug where a viewcontroller does not detect
|
|
|
|
// the selectionchange event of a treelist
|
|
|
|
listeners: {
|
2020-09-25 16:34:54 +00:00
|
|
|
selectionchange: 'navigate',
|
|
|
|
},
|
2019-01-22 10:48:00 +00:00
|
|
|
}, {
|
|
|
|
xtype: 'box',
|
2021-05-26 09:12:02 +00:00
|
|
|
cls: 'x-treelist-pve-nav',
|
2020-09-25 16:34:54 +00:00
|
|
|
flex: 1,
|
|
|
|
}],
|
2018-12-04 16:53:10 +00:00
|
|
|
},
|
|
|
|
{
|
2021-05-26 09:11:58 +00:00
|
|
|
xtype: 'container',
|
2018-12-04 16:53:10 +00:00
|
|
|
layout: { type: 'card' },
|
|
|
|
region: 'center',
|
|
|
|
border: false,
|
2020-09-25 16:34:54 +00:00
|
|
|
reference: 'contentpanel',
|
|
|
|
},
|
|
|
|
],
|
2018-12-04 16:53:10 +00:00
|
|
|
});
|