mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
We want to support hiding table columns, specifically in metrics table, through config file so that users can make the relevant bits hidden as per their organization. Current work will support the metrics table but can be extended to any table with minimal work in future. Config file will take the key of the metrics column from metrics.js file for the sake of minimal changes and simplicity of development. Problem: The keyboard list in the UI is not consistent across views such as in the instance wizard and in the register template form. There is also no way to custom about url/text and doc title and help URL in the UI. Root Cause: The list is hardcoded in the UI allowing no centralised configuration. Solution: Introduce a new config.js file installed at the /usr/share/cloudstackmanagement/webapp/config.js location. The config.js allows configurable keyboard list, about url/text, doc title, and help URL. Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
489 lines
17 KiB
JavaScript
489 lines
17 KiB
JavaScript
// Licensed to the Apache Software Foundation (ASF) under one
|
|
// or more contributor license agreements. See the NOTICE file
|
|
// distributed with this work for additional information
|
|
// regarding copyright ownership. The ASF licenses this file
|
|
// to you under the Apache License, Version 2.0 (the
|
|
// "License"); you may not use this file except in compliance
|
|
// with the License. You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing,
|
|
// software distributed under the License is distributed on an
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations
|
|
// under the License.
|
|
(function($, cloudStack) {
|
|
$.extend(cloudStack, {
|
|
ui: {
|
|
widgets: {} // Defines API methods for UI widgets
|
|
},
|
|
uiCustom: {}
|
|
});
|
|
|
|
/**
|
|
* Generate navigation <li>s
|
|
*
|
|
* @param args cloudStack data args
|
|
*/
|
|
var makeNavigation = function(args) {
|
|
var $navList = $('<ul>');
|
|
var preFilter = cloudStack.sectionPreFilter ?
|
|
cloudStack.sectionPreFilter({
|
|
context: $.extend(true, {}, args.context, {
|
|
sections: $.map(cloudStack.sections, function(value, key) {
|
|
return key;
|
|
})
|
|
})
|
|
}) : null;
|
|
|
|
$.each(args.sections, function(sectionID, args) {
|
|
if (preFilter && $.inArray(sectionID, preFilter) == -1) {
|
|
if (!(args.preFilter && args.preFilter())) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
var $li = $('<li>')
|
|
.addClass('navigation-item')
|
|
.addClass(sectionID)
|
|
.append($('<span>').addClass('icon').html(' '))
|
|
.append($('<span>').text(_l(args.title)))
|
|
.data('cloudStack-section-id', sectionID);
|
|
|
|
if (args.customIcon) {
|
|
$li.addClass('custom-icon').find('span.icon').html('').append(
|
|
$('<img>').attr({
|
|
src: args.customIcon
|
|
})
|
|
);
|
|
}
|
|
|
|
if (args.isPlugin && !args.showOnNavigation) {
|
|
$li.hide();
|
|
}
|
|
|
|
$li.appendTo($navList);
|
|
|
|
return true;
|
|
});
|
|
|
|
// Special classes for first and last items
|
|
$navList.find('li:first').addClass('first');
|
|
$navList.find('li:last').addClass('last');
|
|
|
|
return $navList;
|
|
};
|
|
|
|
/**
|
|
* Create section contents
|
|
*
|
|
* @param sectionID Section's ID to show
|
|
* @param args CloudStack3 configuration
|
|
*/
|
|
var showSection = function(sectionID, args, $browser) {
|
|
var $navItem = $('#navigation').find('li').filter(function() {
|
|
return $(this).hasClass(sectionID);
|
|
});
|
|
var data = args.sections[sectionID];
|
|
var isPlugin = data.isPlugin && !data.showOnNavigation;
|
|
|
|
data.$browser = $browser;
|
|
|
|
// Reset browser panels
|
|
if (!isPlugin) {
|
|
$navItem.siblings().removeClass('active');
|
|
$navItem.addClass('active');
|
|
$browser.cloudBrowser('removeAllPanels');
|
|
}
|
|
|
|
$browser.cloudBrowser('addPanel', {
|
|
title: '<span class="section">' + _l(data.title) + '</span>' + '<span class="subsection"></span>',
|
|
data: '',
|
|
complete: function($panel, $breadcrumb) {
|
|
if(!isPlugin) {
|
|
$breadcrumb.attr('title', _l(data.title));
|
|
}
|
|
|
|
data.$breadcrumb = $breadcrumb;
|
|
|
|
// Hide breadcrumb if this is the home section
|
|
if (args.home === sectionID) {
|
|
$('#breadcrumbs').find('li:first, div.end:last').hide();
|
|
}
|
|
|
|
// Append specified widget to view
|
|
if (data.show)
|
|
$panel.append(data.show(data));
|
|
else if (data.treeView)
|
|
$panel.treeView(data, {
|
|
context: args.context
|
|
});
|
|
else
|
|
$panel.listView(data, {
|
|
context: args.context
|
|
});
|
|
}
|
|
});
|
|
|
|
return $navItem;
|
|
};
|
|
|
|
// Define page element generation fns
|
|
var pageElems = {
|
|
header: function(args) {
|
|
// Make notification area
|
|
var $notificationArea = $('<div>').addClass('button notifications')
|
|
.append(
|
|
$('<div>').addClass('total')
|
|
// Total notifications
|
|
.append($('<span>').html(0))
|
|
)
|
|
.append($('<span>').html(_l('label.notifications')))
|
|
.notifications();
|
|
|
|
// Project switcher
|
|
var $viewSwitcher = $('<div>').addClass('button view-switcher')
|
|
.append(
|
|
// Default View
|
|
$('<div>').addClass('select default-view active')
|
|
.html(_l('label.default.view'))
|
|
.prepend(
|
|
$('<span>').addClass('icon').html(' ')
|
|
|
|
|
|
)
|
|
)
|
|
.append(
|
|
// Project View
|
|
$('<div>').addClass('select project-view')
|
|
.html(_l('label.project.view'))
|
|
.prepend(
|
|
$('<span>').addClass('icon').html(' ')
|
|
)
|
|
)
|
|
.click(function(event) {
|
|
var $target = $(event.target);
|
|
var $projectSwitcher = $(this);
|
|
var $container = $('html body');
|
|
var $navDisabled = $(
|
|
$.map([
|
|
'projects',
|
|
'accounts',
|
|
'domains',
|
|
'system',
|
|
'global-settings',
|
|
'configuration'
|
|
], function(id) {
|
|
return '#navigation li.' + id;
|
|
}).join(',')
|
|
);
|
|
|
|
if ($target.closest('.select.project-view').length) {
|
|
$('#cloudStack3-container').addClass('project-view');
|
|
$projectSwitcher.addClass('alt');
|
|
$projectSwitcher.find('.select.project-view').addClass('active')
|
|
.siblings().removeClass('active');
|
|
|
|
// Activate project view
|
|
$navDisabled.hide();
|
|
cloudStack.uiCustom.projects({
|
|
$projectSelect: $projectSelect.hide().find('select')
|
|
});
|
|
} else {
|
|
$navDisabled.show();
|
|
$('#cloudStack3-container').removeClass('project-view');
|
|
$projectSwitcher.removeClass('alt');
|
|
$projectSelect.hide();
|
|
$projectSwitcher.find('.select.default-view').addClass('active')
|
|
.siblings().removeClass('active');
|
|
|
|
// Put project name in header
|
|
$('.select.project-view').html(
|
|
'<span class="icon"> </span>' + _l('label.project.view')
|
|
).attr('title', '');
|
|
|
|
// Clear out project
|
|
cloudStack.context.projects = null;
|
|
}
|
|
|
|
$('#navigation li.dashboard').click();
|
|
|
|
return false;
|
|
});
|
|
var $projectSelect = $('<div>').addClass('view-switcher').hide()
|
|
.append($('<select>'));
|
|
|
|
// User status area
|
|
var userLabel = args.context.users[0].name ?
|
|
args.context.users[0].name : args.context.users[0].login;
|
|
var $userInfo = $('<div>').attr({
|
|
id: 'user'
|
|
}).addClass('button')
|
|
.append(
|
|
$('<div>').addClass('name').text(
|
|
args.context && args.context.users ?
|
|
cloudStack.concat(userLabel, 21) : 'Invalid User'
|
|
)
|
|
)
|
|
.append(
|
|
$('<div>').addClass('icon options')
|
|
.append(
|
|
$('<div>').addClass('icon arrow')
|
|
)
|
|
);
|
|
$userInfo.attr('title', userLabel);
|
|
|
|
return [
|
|
$('<div>').addClass('logo'),
|
|
$('<div>').addClass('controls')
|
|
.append($notificationArea)
|
|
.append($viewSwitcher)
|
|
.append($projectSelect)
|
|
.append($userInfo)
|
|
];
|
|
},
|
|
|
|
'main-area': function(args) {
|
|
var $navigation = $('<div>').attr({
|
|
id: 'navigation'
|
|
});
|
|
var $browser = $('<div>').attr({
|
|
id: 'browser'
|
|
})
|
|
.append(
|
|
// Home breadcrumb
|
|
$('<div>').attr({
|
|
id: 'breadcrumbs'
|
|
})
|
|
.append($('<div>').addClass('home').text(_l('label.home')))
|
|
.append($('<div>').addClass('end'))
|
|
)
|
|
|
|
.append(
|
|
// Panel container
|
|
$('<div>').addClass('container')
|
|
);
|
|
|
|
makeNavigation(args).appendTo($navigation);
|
|
|
|
return [
|
|
$navigation, $browser
|
|
];
|
|
}
|
|
};
|
|
|
|
$.fn.cloudStack = function(args) {
|
|
var $container = $('<div>')
|
|
.attr({
|
|
id: 'container',
|
|
'cloudStack-container': true
|
|
})
|
|
.data('cloudStack-args', args)
|
|
.appendTo(this);
|
|
var context = args.context;
|
|
|
|
// Cleanup login
|
|
$('.login').remove();
|
|
|
|
// Create pageElems
|
|
$.each(pageElems, function(id, fn) {
|
|
var $elem = $('<div>').attr({
|
|
id: id
|
|
});
|
|
|
|
$(fn(args)).each(function() {
|
|
$elem.append($(this));
|
|
});
|
|
|
|
$elem.appendTo($container);
|
|
});
|
|
|
|
// User options
|
|
var $options = $('<div>').attr({
|
|
id: 'user-options'
|
|
})
|
|
.appendTo($('#user'));
|
|
|
|
$(['label.logout', 'label.help', 'label.about']).each(function() {
|
|
var $link = $('<a>')
|
|
.attr({
|
|
href: '#'
|
|
})
|
|
.text(_l(this.toString()))
|
|
.appendTo($options);
|
|
|
|
if (this == 'label.help') {
|
|
$link.addClass('help').click(function() {
|
|
window.open(cloudStackOptions.helpURL, '_blank');
|
|
return false;
|
|
});
|
|
}
|
|
if (this == 'label.about') {
|
|
$link.addClass('about').click(function() {
|
|
var $logo = $('<div>').addClass('logo').text(_l(cloudStackOptions.aboutText)),
|
|
$version = $('<div>').addClass('version').text(_l(g_cloudstackversion)),
|
|
$about = $('<div>').addClass('about').append($logo).append($version);
|
|
|
|
var $aboutDialog = $about.dialog({
|
|
modal: true,
|
|
width: 300,
|
|
title: _l(cloudStackOptions.aboutTitle),
|
|
closeOnEscape: false,
|
|
dialogClass: 'dialog-about',
|
|
buttons: {
|
|
'Close': function() {
|
|
$(this).dialog("close");
|
|
$(':ui-dialog, .overlay').remove();
|
|
}
|
|
}
|
|
});
|
|
cloudStack.applyDefaultZindexAndOverlayOnJqueryDialogAndRemoveCloseButton($aboutDialog);
|
|
return false;
|
|
});
|
|
}
|
|
});
|
|
|
|
// Initialize browser
|
|
$container.find('#browser div.container').cloudBrowser();
|
|
$container.find('#navigation li')
|
|
.filter(function() {
|
|
return $(this).hasClass(args.home);
|
|
})
|
|
.click();
|
|
|
|
// Validation
|
|
$.extend($.validator.messages, {
|
|
required: _l('label.required')
|
|
});
|
|
|
|
$.validator.addMethod(
|
|
"disallowSpecialCharacters",
|
|
function(value, element) {
|
|
return (value.indexOf("<") == -1 && value.indexOf(">") == -1);
|
|
},
|
|
jQuery.validator.format('message.disallowed.characters')
|
|
);
|
|
|
|
// Check for pending project invitations
|
|
if (args.projects) {
|
|
args.projects.invitationCheck({
|
|
context: cloudStack.context,
|
|
response: {
|
|
success: function(args) {
|
|
if (!args.data.length) return;
|
|
|
|
var projectList = $.map(args.data, function(invitation) {
|
|
return '<li>' + invitation.project + '</li>';
|
|
}).join('');
|
|
|
|
cloudStack.dialog.notice({
|
|
message: _l('message.pending.projects.1') + '<ul>' + projectList + '</ul>' + '<p>' + _l('message.pending.projects.2') + '</p>'
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// Hide logo conditionally
|
|
if (!args.hasLogo) $('#header, #header .controls').addClass('nologo');
|
|
|
|
$(window).trigger('cloudStack.ready');
|
|
|
|
return this;
|
|
};
|
|
|
|
// Events
|
|
$(function() {
|
|
// Check if target should be hovered
|
|
function checkHoveredLabel($target) {
|
|
var $multiWizard = $('div.ui-dialog div.multi-wizard');
|
|
if (($target.is('label[for]') && !$target.parents('body.login')) ||
|
|
($multiWizard.length &&
|
|
($target.is('.multi-wizard label') && $target.prev('input[type="radio"],input[type="checkbox"]').length) ||
|
|
($target.is('.multi-wizard .select-desc div.name') && $target.parent('div.select-desc').prev('input[type="radio"],input[type="checkbox"]').length)
|
|
))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
// Rollover behavior for user options
|
|
$(document).bind('mouseover', function(event) {
|
|
var $target = $(event.target);
|
|
if (checkHoveredLabel($target)) {
|
|
$target.addClass('label-hovered');
|
|
}
|
|
if ($target.closest('#user, #user-options').length) {
|
|
return false;
|
|
} else $('#user-options').hide();
|
|
|
|
return false;
|
|
});
|
|
|
|
$(document).bind('mouseout', function(event) {
|
|
var $target = $(event.target);
|
|
if (checkHoveredLabel($target)) {
|
|
$target.removeClass('label-hovered');
|
|
}
|
|
});
|
|
|
|
$(document).bind('click', function(event) {
|
|
var $target = $(event.target);
|
|
var $container = $target.closest('[cloudStack-container]');
|
|
var args = $container.data('cloudStack-args');
|
|
var $browser = $container.find('#browser .container');
|
|
var $multiWizard = $('div.ui-dialog div.multi-wizard');
|
|
|
|
// Wizard: trigger click event for input when click it label
|
|
if ($multiWizard.length) {
|
|
if ($target.is('.multi-wizard label') && $target.prev('input[type="radio"],input[type="checkbox"]').length) {
|
|
$target.prev('input').trigger('click');
|
|
}
|
|
if ($target.is('.multi-wizard .select-desc div.name') && $target.parent('div.select-desc').prev('input[type="radio"],input[type="checkbox"]').length) {
|
|
$target.parent('div.select-desc').prev('input').trigger('click');
|
|
}
|
|
}
|
|
|
|
if (!$container.length) return true;
|
|
|
|
// Navigation items
|
|
if ($target.closest('li.navigation-item').length && $target.closest('#navigation').length) {
|
|
var $navItem = $target.closest('li.navigation-item');
|
|
|
|
if ($navItem.is('.disabled')) return false;
|
|
showSection($navItem.data('cloudStack-section-id'), args, $browser);
|
|
|
|
return false;
|
|
}
|
|
|
|
// Browser expand
|
|
if ($target.hasClass('control expand') && $target.closest('div.panel div.toolbar').length) {
|
|
$browser.cloudBrowser('toggleMaximizePanel', {
|
|
panel: $target.closest('div.panel')
|
|
});
|
|
|
|
return false;
|
|
}
|
|
|
|
// Home breadcrumb
|
|
if ($target.is('#breadcrumbs div.home')) {
|
|
showSection(args.home, args, $browser);
|
|
return false;
|
|
}
|
|
|
|
// User options
|
|
if ($target.closest('#user div.icon.options').length) {
|
|
$('#user-options').toggle();
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
});
|
|
});
|
|
})(window.jQuery,
|
|
window.cloudStack ? window.cloudStack : window.cloudStack = {});
|