mirror of
git://git.proxmox.com/git/proxmox-backup.git
synced 2025-01-03 01:18:02 +03:00
a662274e69
by globally calling the 'status' api once and saving the fingerprint into the global Proxmox variable. since not all users might have that permission, ignore errors for that, and don't show the fingerprint in this case Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
323 lines
7.3 KiB
JavaScript
323 lines
7.3 KiB
JavaScript
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',
|
|
conditions: {
|
|
':path': '(?:([%a-zA-Z0-9\\-\\_\\s,.]+))',
|
|
':subpath': '(?:(?::)([%a-zA-Z0-9\\-\\_\\s,]+))?',
|
|
},
|
|
},
|
|
},
|
|
|
|
parseRouterPath: function(path) {
|
|
let xtype = path;
|
|
let config = {};
|
|
if (PBS.Utils.isDataStorePath(path)) {
|
|
config.datastore = PBS.Utils.getDataStoreFromPath(path);
|
|
xtype = 'pbsDataStorePanel';
|
|
} 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';
|
|
}
|
|
|
|
return [xtype, config];
|
|
},
|
|
|
|
beforeChangePath: function(path, subpathOrAction, action) {
|
|
var me = this;
|
|
|
|
let subpath = subpathOrAction;
|
|
if (!action) {
|
|
action = subpathOrAction;
|
|
subpath = undefined;
|
|
}
|
|
|
|
let [xtype, config] = me.parseRouterPath(path);
|
|
|
|
if (!Ext.ClassManager.getByAlias(`widget.${xtype}`)) {
|
|
console.warn(`xtype ${xtype} not found`);
|
|
action.stop();
|
|
return;
|
|
}
|
|
|
|
var lastpanel = me.lookupReference('contentpanel').getLayout().getActiveItem();
|
|
if (lastpanel && lastpanel.xtype === xtype) {
|
|
for (const [prop, value] of Object.entries(config)) {
|
|
if (lastpanel[prop] !== value) {
|
|
action.resume();
|
|
return;
|
|
}
|
|
}
|
|
// 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);
|
|
}
|
|
// else we are already there
|
|
}
|
|
action.stop();
|
|
return;
|
|
}
|
|
|
|
action.resume();
|
|
},
|
|
|
|
changePath: function(path, subpath) {
|
|
var me = this;
|
|
var contentpanel = me.lookupReference('contentpanel');
|
|
var lastpanel = contentpanel.getLayout().getActiveItem();
|
|
|
|
let tabChangeListener = function(tp, newc, oldc) {
|
|
let newpath = path;
|
|
|
|
// only add the subpath part for the
|
|
// non-default tabs
|
|
if (tp.items.findIndex('id', newc.id) !== 0) {
|
|
newpath += `:${newc.getItemId()}`;
|
|
}
|
|
|
|
me.redirectTo(newpath);
|
|
};
|
|
|
|
let [xtype, config] = me.parseRouterPath(path);
|
|
var obj;
|
|
if (PBS.Utils.isDataStorePath(path)) {
|
|
if (lastpanel && lastpanel.xtype === xtype && !subpath) {
|
|
let activeTab = lastpanel.getActiveTab();
|
|
let newpath = path;
|
|
if (lastpanel.items.indexOf(activeTab) !== 0) {
|
|
subpath = activeTab.getItemId();
|
|
newpath += `:${subpath}`;
|
|
}
|
|
me.redirectTo(newpath);
|
|
}
|
|
}
|
|
obj = contentpanel.add(Ext.apply(config, {
|
|
xtype,
|
|
nodename: 'localhost',
|
|
border: false,
|
|
activeTab: subpath || 0,
|
|
listeners: {
|
|
tabchange: tabChangeListener,
|
|
},
|
|
}));
|
|
|
|
var treelist = me.lookupReference('navtree');
|
|
|
|
treelist.select(path, true);
|
|
|
|
contentpanel.setActiveItem(obj);
|
|
|
|
if (lastpanel) {
|
|
contentpanel.remove(lastpanel, { destroy: true });
|
|
}
|
|
},
|
|
|
|
logout: function() {
|
|
PBS.app.logout();
|
|
},
|
|
|
|
navigate: function(treelist, item) {
|
|
this.redirectTo(item.get('path'));
|
|
},
|
|
|
|
control: {
|
|
'[reference=logoutButton]': {
|
|
click: 'logout',
|
|
},
|
|
},
|
|
|
|
init: function(view) {
|
|
var me = this;
|
|
|
|
PBS.data.RunningTasksStore.startUpdate();
|
|
me.lookupReference('usernameinfo').setText(Proxmox.UserName);
|
|
|
|
// show login on requestexception
|
|
// fixme: what about other errors
|
|
Ext.Ajax.on('requestexception', function(conn, response, options) {
|
|
if (response.status === 401 || response.status === '401') { // auth failure
|
|
me.logout();
|
|
}
|
|
});
|
|
|
|
// 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,
|
|
password: ticket,
|
|
},
|
|
url: '/api2/json/access/ticket',
|
|
method: 'POST',
|
|
failure: function() {
|
|
me.logout();
|
|
},
|
|
success: function(response, opts) {
|
|
var obj = Ext.decode(response.responseText);
|
|
PBS.Utils.updateLoginData(obj.data);
|
|
},
|
|
});
|
|
},
|
|
interval: 15*60*1000,
|
|
});
|
|
|
|
Proxmox.Utils.API2Request({
|
|
url: `/api2/extjs/nodes/localhost/status`,
|
|
success: function({ result }) {
|
|
if (result?.data?.info?.fingerprint) {
|
|
Proxmox.Fingerprint = result.data.info.fingerprint;
|
|
}
|
|
},
|
|
failure: function() {
|
|
// silently ignore errors
|
|
},
|
|
});
|
|
|
|
// select treeitem and load page from url fragment, if set
|
|
let token = Ext.util.History.getToken() || 'pbsDashboard';
|
|
this.redirectTo(token, { force: true });
|
|
},
|
|
},
|
|
|
|
plugins: 'viewport',
|
|
|
|
layout: { type: 'border' },
|
|
|
|
items: [
|
|
{
|
|
region: 'north',
|
|
xtype: 'container',
|
|
layout: {
|
|
type: 'hbox',
|
|
align: 'middle',
|
|
},
|
|
margin: '2 0 2 5',
|
|
height: 38,
|
|
items: [
|
|
{
|
|
xtype: 'proxmoxlogo',
|
|
prefix: '',
|
|
},
|
|
{
|
|
padding: '0 0 0 5',
|
|
xtype: 'versioninfo',
|
|
},
|
|
{
|
|
flex: 1,
|
|
baseCls: 'x-plain',
|
|
},
|
|
{
|
|
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',
|
|
},
|
|
{
|
|
xtype: 'pbsTaskButton',
|
|
margin: '0 5 0 0',
|
|
},
|
|
{
|
|
xtype: 'button',
|
|
reference: 'usernameinfo',
|
|
style: {
|
|
// proxmox dark grey p light grey as border
|
|
backgroundColor: '#464d4d',
|
|
borderColor: '#ABBABA',
|
|
},
|
|
margin: '0 5 0 0',
|
|
iconCls: 'fa fa-user',
|
|
menu: [
|
|
{
|
|
iconCls: 'fa fa-gear',
|
|
text: gettext('My Settings'),
|
|
handler: () => Ext.create('PBS.window.Settings').show(),
|
|
},
|
|
{
|
|
iconCls: 'fa fa-paint-brush',
|
|
text: gettext('Color Theme'),
|
|
handler: () => Ext.create('Proxmox.window.ThemeEditWindow', {
|
|
cookieName: 'PBSThemeCookie',
|
|
autoShow: true,
|
|
}),
|
|
},
|
|
{
|
|
iconCls: 'fa fa-language',
|
|
text: gettext('Language'),
|
|
reference: 'languageButton',
|
|
handler: () => Ext.create('Proxmox.window.LanguageEditWindow', {
|
|
cookieName: 'PBSLangCookie',
|
|
autoShow: true,
|
|
}),
|
|
},
|
|
'-',
|
|
{
|
|
iconCls: 'fa fa-sign-out',
|
|
text: gettext('Logout'),
|
|
reference: 'logoutButton',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
xtype: 'container',
|
|
scrollable: 'y',
|
|
border: false,
|
|
region: 'west',
|
|
layout: {
|
|
type: 'vbox',
|
|
align: 'stretch',
|
|
},
|
|
items: [{
|
|
xtype: 'navigationtree',
|
|
minWidth: 180,
|
|
ui: 'pve-nav',
|
|
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: {
|
|
selectionchange: 'navigate',
|
|
},
|
|
}, {
|
|
xtype: 'box',
|
|
cls: 'x-treelist-pve-nav',
|
|
flex: 1,
|
|
}],
|
|
},
|
|
{
|
|
xtype: 'container',
|
|
layout: { type: 'card' },
|
|
region: 'center',
|
|
border: false,
|
|
reference: 'contentpanel',
|
|
},
|
|
],
|
|
});
|