[PATCH V4 0/4] Authorization: disable non-root user functions in UI

From: Wen Wang <wenwang@linux.vnet.ibm.com> V3 -> V4: Removed the additional white border line in user mode(Aline) Minor change to the layout of the storage tab of user mode that makes the arrow-down/arrow-up more consistent(Aline) V2 -> V3: stored the mode into global _tabMode that can be used for each tab.(Aline) Making the buttons that is not avaiable for non-root users invisible by default and enable when user is admin.(Yu Xin) Fixed css inconsistent under "Storage" tab. Removed the onClick function if the buttons are not avaiable. V1 -> V2: Store "roles" parameter in cookie instead of each tab's mode.(Aline) read only "roles" from cookie instead of roles of each tab(Aline) Minor changes in method of removing "Action" title under network tab (Hongliang Wang) This patch defines user privilege according to different user roles In this release, only two roles are supported: "admin" and "user", conbined with four modes: "admin", "byInstance", "read-only" and "none", each of which has own privileges to different tabs as well as instances. modes are stored in cookie and functions of different roles are protected in the back-end. Wen Wang (4): Add roles into cookie Authorization: remove host/template tabs for non-root users Authorization: remove [+] icon from non-root users view Authorization: Remove actions based on roles ui/css/theme-default/network.css | 4 + ui/css/theme-default/storage.css | 22 ++++--- ui/js/src/kimchi.guest_main.js | 10 ++- ui/js/src/kimchi.login.js | 16 +++-- ui/js/src/kimchi.main.js | 26 +++++-- ui/js/src/kimchi.network.js | 12 +++- ui/js/src/kimchi.storage_main.js | 137 ++++++++++++++++++++----------------- ui/js/src/kimchi.template_main.js | 21 ++++-- ui/pages/tabs/guests.html.tmpl | 4 +- ui/pages/tabs/network.html.tmpl | 6 +- ui/pages/tabs/storage.html.tmpl | 6 +- ui/pages/tabs/templates.html.tmpl | 2 +- 12 files changed, 159 insertions(+), 107 deletions(-)

From: Wen Wang <wenwang@linux.vnet.ibm.com> V1 -> V2: This patch add "roles" parameter into cookie instead of each tab's mode(Aline) This patch add each tab's mode into cookie Signed-off-by: Wen Wang <wenwang@linux.vnet.ibm.com> --- ui/js/src/kimchi.login.js | 16 +++++++++------- 1 files changed, 9 insertions(+), 7 deletions(-) diff --git a/ui/js/src/kimchi.login.js b/ui/js/src/kimchi.login.js index 72d2ee3..b20f0b0 100644 --- a/ui/js/src/kimchi.login.js +++ b/ui/js/src/kimchi.login.js @@ -36,8 +36,8 @@ kimchi.login_main = function() { var loginButton = $('#btn-login'); var login = function(event) { - $("#login").hide() - $("#logging").show() + $("#login").hide(); + $("#logging").show(); var userName = userNameBox.val(); userName && kimchi.user.setUserName(userName); @@ -50,18 +50,20 @@ kimchi.login_main = function() { var query = window.location.search; var next = /.*next=(.*?)(&|$)/g.exec(query); if (next) { - var next_url = decodeURIComponent(next[1]) + var next_url = decodeURIComponent(next[1]); } else { var lastPage = kimchi.cookie.get('lastPage'); - var next_url = lastPage ? lastPage.replace(/\"/g,'') : "/" + var next_url = lastPage ? lastPage.replace(/\"/g,'') : "/"; } + var next_url = lastPage ? lastPage.replace(/\"/g,'') : "/"; + kimchi.cookie.set('roles',JSON.stringify(data.roles), 365); window.location.replace(next_url) }, function() { - $("#messUserPass").show() + $("#messUserPass").show(); $("#messSession").hide(); - $("#logging").hide() - $("#login").show() + $("#logging").hide(); + $("#login").show(); }); return false; -- 1.7.1

From: Wen Wang <wenwang@linux.vnet.ibm.com> v2 -> V3: Add a global variable "_tabMode" into JS code under kimchi.main.js that indicates mode for each tab(Yu Xin, Aline) V1 -> V2: read only "roles" from cookie instead of roles of each tab(Aline) This patch removed host/template tabs from non-root users Signed-off-by: Wen Wang <wenwang@linux.vnet.ibm.com> --- ui/js/src/kimchi.main.js | 26 ++++++++++++++++++-------- 1 files changed, 18 insertions(+), 8 deletions(-) diff --git a/ui/js/src/kimchi.main.js b/ui/js/src/kimchi.main.js index 8eb4d73..01ebded 100644 --- a/ui/js/src/kimchi.main.js +++ b/ui/js/src/kimchi.main.js @@ -15,6 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +var _tabMode = {}; kimchi.main = function() { kimchi.popable(); @@ -23,13 +24,16 @@ kimchi.main = function() { $(tabs).each(function(i, tab) { var title = tab['title']; var path = tab['path']; - tabsHtml.push( - '<li>', - '<a class="item" href="', path, '">', - title, - '</a>', - '</li>' - ); + var mode = tab['mode']; + if (mode != 'none') { + tabsHtml.push( + '<li>', + '<a class="item" href="', path, '">', + title, + '</a>', + '</li>' + ); + } }); return tabsHtml.join(''); }; @@ -41,9 +45,15 @@ kimchi.main = function() { var titleKey = $tab.find('title').text(); var title = i18n[titleKey] ? i18n[titleKey] : titleKey; var path = $tab.find('path').text(); + var roles = kimchi.cookie.get('roles'); + var roleString = 'JSON.parse(roles).' + titleKey.toLowerCase(); + var role = eval(roleString); + var mode = $tab.find('[role="' + role + '"]').attr('mode'); + _tabMode[titleKey.toLowerCase()] = mode; tabs.push({ title: title, - path: path + path: path, + mode: mode }); }); -- 1.7.1

From: Wen Wang <wenwang@linux.vnet.ibm.com> V1 -> V2: Changed the [+] button invisible by default and show if the _tabMode is admin.(Yu Xin) This patch removes [+] icon from the toolbar for users without 'admin' role Signed-off-by: Wen Wang <wenwang@linux.vnet.ibm.com> --- ui/js/src/kimchi.guest_main.js | 10 +++++++--- ui/js/src/kimchi.network.js | 6 +++++- ui/js/src/kimchi.storage_main.js | 10 +++++++--- ui/js/src/kimchi.template_main.js | 21 +++++++++++++-------- ui/pages/tabs/guests.html.tmpl | 4 ++-- ui/pages/tabs/network.html.tmpl | 2 +- ui/pages/tabs/storage.html.tmpl | 2 +- ui/pages/tabs/templates.html.tmpl | 2 +- 8 files changed, 37 insertions(+), 20 deletions(-) diff --git a/ui/js/src/kimchi.guest_main.js b/ui/js/src/kimchi.guest_main.js index acbae15..d81c6b7 100644 --- a/ui/js/src/kimchi.guest_main.js +++ b/ui/js/src/kimchi.guest_main.js @@ -323,9 +323,13 @@ kimchi.guestSetRequestHeader = function(xhr) { }; kimchi.guest_main = function() { - $("#vm-add").on("click", function(event) { - kimchi.window.open('guest-add.html'); - }); + var guestsMode = _tabMode['guests']; + if(guestsMode === 'admin') { + $('.tools').attr('style','display'); + $("#vm-add").on("click", function(event) { + kimchi.window.open('guest-add.html'); + }); + } kimchi.guestTemplate = $('#guest-tmpl').html(); kimchi.guestElem=$('<div/>').html(kimchi.guestTemplate).find('li'); $('#guests-root-container').on('remove', function() { diff --git a/ui/js/src/kimchi.network.js b/ui/js/src/kimchi.network.js index cbd967f..c0978da 100644 --- a/ui/js/src/kimchi.network.js +++ b/ui/js/src/kimchi.network.js @@ -19,9 +19,13 @@ kimchi.NETWORK_TYPE_BRIDGE = "bridged"; kimchi.initNetwork = function() { + var networkMode = _tabMode['network']; + if(networkMode === 'admin') { + $('.tools').attr('style','display'); + kimchi.initNetworkCreation(); + } kimchi.initNetworkListView(); kimchi.initNetworkDialog(); - kimchi.initNetworkCreation(); kimchi.initNetworkCleanup(); }; diff --git a/ui/js/src/kimchi.storage_main.js b/ui/js/src/kimchi.storage_main.js index 3a18f82..a84ce0f 100644 --- a/ui/js/src/kimchi.storage_main.js +++ b/ui/js/src/kimchi.storage_main.js @@ -234,9 +234,13 @@ kimchi.initLogicalPoolExtend = function() { } kimchi.storage_main = function() { - $('#storage-pool-add').on('click', function() { - kimchi.window.open('storagepool-add.html'); - }); + var storageMode = _tabMode['storage']; + if(storageMode === 'admin') { + $('.tools').attr('style','display'); + $('#storage-pool-add').on('click', function() { + kimchi.window.open('storagepool-add.html'); + }); + } kimchi.doListStoragePools(); kimchi.initLogicalPoolExtend(); } diff --git a/ui/js/src/kimchi.template_main.js b/ui/js/src/kimchi.template_main.js index 48354c9..7ce408f 100644 --- a/ui/js/src/kimchi.template_main.js +++ b/ui/js/src/kimchi.template_main.js @@ -83,15 +83,20 @@ kimchi.hideTitle = function() { }; kimchi.template_main = function() { - $("#template-add").on("click", function(event) { - kimchi.window.open({ - url: 'template-add.html', - close: function() { - if (kimchi.deepScanHandler) { - kimchi.deepScanHandler.stop = true; + var templatesMode = _tabMode['templates']; + if(templatesMode === 'admin') { + $('.tools').attr('style','display'); + $("#template-add").on("click", function(event) { + kimchi.window.open({ + url: 'template-add.html', + close: function() { + if (kimchi.deepScanHandler) { + kimchi.deepScanHandler.stop = true; + } } - } + }); }); - }); + } + kimchi.doListTemplates(); }; diff --git a/ui/pages/tabs/guests.html.tmpl b/ui/pages/tabs/guests.html.tmpl index 3aa2fdd..bc6a0cf 100644 --- a/ui/pages/tabs/guests.html.tmpl +++ b/ui/pages/tabs/guests.html.tmpl @@ -28,11 +28,11 @@ <div id="guests-root-container"> <div class="toolbar"> - <div class="tools"> + <div class="tools" style="display:none"> <a id="vm-add" class="btn-tool" href="javascript:void(0);"><span class="icon add">+</span></a> </div> </div> - <div id="guestListField" style="display: none;"> + <div id="guestListField" style="display: none"> <ul class="list-title"> <li class="guest-type">$_("Name")</li> <li class="guest-cpu">$_("CPU")</li> diff --git a/ui/pages/tabs/network.html.tmpl b/ui/pages/tabs/network.html.tmpl index 92985ff..b6091f8 100644 --- a/ui/pages/tabs/network.html.tmpl +++ b/ui/pages/tabs/network.html.tmpl @@ -26,7 +26,7 @@ <html> <body> <div class="toolbar"> - <div class="tools"> + <div class="tools" style="display:none"> <a id="networkAdd" class="btn-tool" href="javascript:void(0);"><span class="icon add">+</span></a> </div> </div> diff --git a/ui/pages/tabs/storage.html.tmpl b/ui/pages/tabs/storage.html.tmpl index d4d54ea..72eaafd 100644 --- a/ui/pages/tabs/storage.html.tmpl +++ b/ui/pages/tabs/storage.html.tmpl @@ -25,7 +25,7 @@ <html> <body> <div class="toolbar"> - <div class="tools"> + <div class="tools" style="display:none"> <a id="storage-pool-add" class="btn-tool" href="javascript:void(0);"><span class="icon add">+</span></a> </div> </div> diff --git a/ui/pages/tabs/templates.html.tmpl b/ui/pages/tabs/templates.html.tmpl index 5e6b5aa..5551d66 100644 --- a/ui/pages/tabs/templates.html.tmpl +++ b/ui/pages/tabs/templates.html.tmpl @@ -25,7 +25,7 @@ <html> <body> <div class="toolbar"> - <div class="tools"> + <div class="tools" style="display:none"> <a id="template-add" class="btn-tool" href="javascript:void(0);"><span class="icon add">+</span></a> </div> </div> -- 1.7.1

From: Wen Wang <wenwang@linux.vnet.ibm.com> V3 -> V4: Removed the additional white border line in user mode(Aline) Minor change to the layout of the storage tab of user mode that makes the arrow-down/arrow-up more consistent(Aline) V2 -> V3: Fixed the cookie usage error. Hide the actions buttons and show if user has admin mode. Fixed css inconsistence in storage tab Remove associated actions of the action button if user is not root V1 -> V2: Minor changes in method of removing "Action" title under network tab (Hongliang Wang) Authorization: remove actions menu from storage/network tabs for non-root users Signed-off-by: Wen Wang <wenwang@linux.vnet.ibm.com> --- ui/css/theme-default/network.css | 4 + ui/css/theme-default/storage.css | 22 ++++--- ui/js/src/kimchi.network.js | 6 ++ ui/js/src/kimchi.storage_main.js | 127 ++++++++++++++++++++------------------ ui/pages/tabs/network.html.tmpl | 4 +- ui/pages/tabs/storage.html.tmpl | 4 +- 6 files changed, 95 insertions(+), 72 deletions(-) diff --git a/ui/css/theme-default/network.css b/ui/css/theme-default/network.css index df66b75..a993fd6 100644 --- a/ui/css/theme-default/network.css +++ b/ui/css/theme-default/network.css @@ -94,6 +94,10 @@ width: 270px; } +.network .list .item .column-space-no-border-right { + border-right: none; +} + .network .list .column-action { display: inline-block; position: absolute; diff --git a/ui/css/theme-default/storage.css b/ui/css/theme-default/storage.css index e94c1ec..dfd8410 100644 --- a/ui/css/theme-default/storage.css +++ b/ui/css/theme-default/storage.css @@ -17,7 +17,11 @@ */ /* STORAGE */ .handle { - width: 5%; + width: 49px; +} + +.storage-allocate-padding-user { + padding-right: 108px; } .storage-title { @@ -148,37 +152,37 @@ } .storage-name { - width: 20%; + width: 199px; } .storage-state { - width: 5%; + width: 51px; } .storage-location { - width: 29%; + width: 288px; } .storage-type { - width: 10%; + width: 98px; } .storage-capacity { - width: 10%; + width: 98px; } .storage-allocate { - width: 10%; + width: 98px; } .storage-button { - width: 11%; + width: 108px; text-align: center; } .title-name { - width: 198px; + width: 199px; } .title-state { diff --git a/ui/js/src/kimchi.network.js b/ui/js/src/kimchi.network.js index c0978da..5b811ca 100644 --- a/ui/js/src/kimchi.network.js +++ b/ui/js/src/kimchi.network.js @@ -22,6 +22,7 @@ kimchi.initNetwork = function() { var networkMode = _tabMode['network']; if(networkMode === 'admin') { $('.tools').attr('style','display'); + $('#network-content .header span:last-child').attr('style','display'); kimchi.initNetworkCreation(); } kimchi.initNetworkListView(); @@ -52,6 +53,11 @@ kimchi.initNetworkListView = function() { kimchi.addNetworkItem = function(network) { $("#networkBody").append(kimchi.getNetworkItemHtml(network)); + if(_tabMode["network"] === "admin") { + $(".column-action").attr("style","display"); + } else { + $(".column-space").addClass('column-space-no-border-right'); + } kimchi.addNetworkActions(network); }; diff --git a/ui/js/src/kimchi.storage_main.js b/ui/js/src/kimchi.storage_main.js index a84ce0f..4b6fd13 100644 --- a/ui/js/src/kimchi.storage_main.js +++ b/ui/js/src/kimchi.storage_main.js @@ -30,6 +30,11 @@ kimchi.doListStoragePools = function() { } }); $('#storagepoolsList').html(listHtml); + if(_tabMode['storage'] === 'admin') { + $('.storage-button').attr('style','display'); + } else { + $('.storage-allocate').addClass('storage-allocate-padding-user'); + } kimchi.storageBindClick(); } else { $('#storagepoolsList').html(''); @@ -74,79 +79,82 @@ kimchi.storageBindClick = function() { } }); - $('.pool-delete').on('click', function(event) { - var $pool = $(this); - var settings = { - title : i18n['KCHAPI6001M'], - content : i18n['KCHPOOL6001M'], - confirm : i18n['KCHAPI6002M'], - cancel : i18n['KCHAPI6003M'] - }; - kimchi.confirm(settings, function() { - var poolName = $pool.data('name'); - kimchi.deleteStoragePool(poolName, function() { + if(_tabMode['storage'] === 'admin') { + $('.pool-delete').on('click', function(event) { + var $pool = $(this); + var settings = { + title : i18n['KCHAPI6001M'], + content : i18n['KCHPOOL6001M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] + }; + kimchi.confirm(settings, function() { + var poolName = $pool.data('name'); + kimchi.deleteStoragePool(poolName, function() { + kimchi.doListStoragePools(); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); + }); + }); + }); + + $('.pool-activate').on('click', function(event) { + var poolName = $(this).data('name'); + kimchi.changePoolState(poolName, 'activate', function() { kimchi.doListStoragePools(); }, function(err) { kimchi.message.error(err.responseJSON.reason); }); }); - }); - $('.pool-activate').on('click', function(event) { - var poolName = $(this).data('name'); - kimchi.changePoolState(poolName, 'activate', function() { - kimchi.doListStoragePools(); - }, function(err) { - kimchi.message.error(err.responseJSON.reason); - }); - }); - - $('.pool-deactivate').on('click', function(event) { - var poolName = $(this).data('name'); - var settings = { - title : i18n['KCHAPI6001M'], - content : i18n['KCHPOOL6012M'], - confirm : i18n['KCHAPI6002M'], - cancel : i18n['KCHAPI6003M'] - }; - if (!$(this).data('persistent')) { - kimchi.confirm(settings, function() { + $('.pool-deactivate').on('click', function(event) { + var poolName = $(this).data('name'); + var settings = { + title : i18n['KCHAPI6001M'], + content : i18n['KCHPOOL6012M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] + }; + if (!$(this).data('persistent')) { + kimchi.confirm(settings, function() { + kimchi.changePoolState(poolName, 'deactivate', function() { + kimchi.doListStoragePools(); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); + }); + }, function() { + return false; + }); + } + else { kimchi.changePoolState(poolName, 'deactivate', function() { kimchi.doListStoragePools(); }, function(err) { kimchi.message.error(err.responseJSON.reason); }); - }, function() { - return false; - }); - } - else { - kimchi.changePoolState(poolName, 'deactivate', function() { - kimchi.doListStoragePools(); - }, function(err) { - kimchi.message.error(err.responseJSON.reason); - }); - } - }); + } + }); - $('.storage-action').on('click', function() { - var storage_action = $(this); - var deleteButton = storage_action.find('.pool-delete'); - if ('active' === deleteButton.data('stat')) { - deleteButton.attr('disabled', 'disabled'); - } else { - deleteButton.removeAttr('disabled'); - } - }); + $('.storage-action').on('click', function() { + var storage_action = $(this); + var deleteButton = storage_action.find('.pool-delete'); + if ('active' === deleteButton.data('stat')) { + deleteButton.attr('disabled', 'disabled'); + } else { + deleteButton.removeAttr('disabled'); + } + }); - $('.pool-extend').on('click', function() { - $("#logicalPoolExtend").dialog("option", "poolName", $(this).data('name')); - $("#logicalPoolExtend").dialog("open"); - }); + $('.pool-extend').on('click', function() { + $("#logicalPoolExtend").dialog("option", "poolName", $(this).data('name')); + $("#logicalPoolExtend").dialog("open"); + }); + + $('#volume-doAdd').on('click', function() { + kimchi.window.open('storagevolume-add.html'); + }); + } - $('#volume-doAdd').on('click', function() { - kimchi.window.open('storagevolume-add.html'); - }); $('.storage-li').on('click', function(event) { if (!$(event.target).parents().hasClass('bottom')) { if ($(this).data('stat') === 'active') { @@ -240,6 +248,7 @@ kimchi.storage_main = function() { $('#storage-pool-add').on('click', function() { kimchi.window.open('storagepool-add.html'); }); + $('.list-title .title-actions').attr('style','display'); } kimchi.doListStoragePools(); kimchi.initLogicalPoolExtend(); diff --git a/ui/pages/tabs/network.html.tmpl b/ui/pages/tabs/network.html.tmpl index b6091f8..ab57c98 100644 --- a/ui/pages/tabs/network.html.tmpl +++ b/ui/pages/tabs/network.html.tmpl @@ -38,7 +38,7 @@ --><span class="column column-type">$_("Network Type")</span><!-- --><span class="column column-interface">$_("Interface")</span><!-- --><span class="column column-space">$_("Address Space")</span><!-- - --><span class="column">$_("Actions")</span> + --><span class="column" style="display:none">$_("Actions")</span> </div> <div id="networkBody" class="empty-when-logged-off"></div> </div> @@ -104,7 +104,7 @@ --><span class='column column-type cell'>{type}</span><!-- --><span class='column column-interface cell'>{interface}</span><!-- --><span class='column column-space cell'>{addrSpace}</span><!-- - --><span class='column-action'> + --><span class='column-action' style="display:none"> <span class="ui-button-secondary dropdown popable action-button"> $_("Actions") <ul class='popover actionsheet right-side menu-container'> diff --git a/ui/pages/tabs/storage.html.tmpl b/ui/pages/tabs/storage.html.tmpl index 72eaafd..3b11e55 100644 --- a/ui/pages/tabs/storage.html.tmpl +++ b/ui/pages/tabs/storage.html.tmpl @@ -37,7 +37,7 @@ <li class="title-type">$_("Type")</li> <li class="title-capacity">$_("Capacity")</li> <li class="title-allocate">$_("Allocated")</li> - <li class="title-actions">$_("Actions")</li> + <li class="title-actions" style="display:none">$_("Actions")</li> </div> <ul id="storagepoolsList" class="list-storage empty-when-logged-off"></ul> </div> @@ -76,7 +76,7 @@ <div class="storage-allocate"> <div class="storage-text" data-type="{type}">{allocated}</div> </div> - <div class="bottom storage-button"> + <div class="bottom storage-button" style="display:none"> <div class="btn dropdown popable storage-action" data-state="{state}" data-type="{type}" data-name="{name}"> <span class="text">$_("Actions")</span><span class="arrow"></span> <div class="popover actionsheet right-side" style="width: 250px"> -- 1.7.1

Reviewed-by: Aline Manera <alinefm@linux.vnet.ibm.com> On 07/22/2014 11:26 PM, wenwang@linux.vnet.ibm.com wrote:
From: Wen Wang <wenwang@linux.vnet.ibm.com>
V3 -> V4: Removed the additional white border line in user mode(Aline) Minor change to the layout of the storage tab of user mode that makes the arrow-down/arrow-up more consistent(Aline)
V2 -> V3: stored the mode into global _tabMode that can be used for each tab.(Aline) Making the buttons that is not avaiable for non-root users invisible by default and enable when user is admin.(Yu Xin) Fixed css inconsistent under "Storage" tab. Removed the onClick function if the buttons are not avaiable.
V1 -> V2: Store "roles" parameter in cookie instead of each tab's mode.(Aline) read only "roles" from cookie instead of roles of each tab(Aline) Minor changes in method of removing "Action" title under network tab (Hongliang Wang)
This patch defines user privilege according to different user roles In this release, only two roles are supported: "admin" and "user", conbined with four modes: "admin", "byInstance", "read-only" and "none", each of which has own privileges to different tabs as well as instances. modes are stored in cookie and functions of different roles are protected in the back-end.
Wen Wang (4): Add roles into cookie Authorization: remove host/template tabs for non-root users Authorization: remove [+] icon from non-root users view Authorization: Remove actions based on roles
ui/css/theme-default/network.css | 4 + ui/css/theme-default/storage.css | 22 ++++--- ui/js/src/kimchi.guest_main.js | 10 ++- ui/js/src/kimchi.login.js | 16 +++-- ui/js/src/kimchi.main.js | 26 +++++-- ui/js/src/kimchi.network.js | 12 +++- ui/js/src/kimchi.storage_main.js | 137 ++++++++++++++++++++----------------- ui/js/src/kimchi.template_main.js | 21 ++++-- ui/pages/tabs/guests.html.tmpl | 4 +- ui/pages/tabs/network.html.tmpl | 6 +- ui/pages/tabs/storage.html.tmpl | 6 +- ui/pages/tabs/templates.html.tmpl | 2 +- 12 files changed, 159 insertions(+), 107 deletions(-)
_______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel
participants (2)
-
Aline Manera
-
wenwang@linux.vnet.ibm.com