[PATCH 0/2] Adding new-ui to Wok and Kimchi-Hosts (pre-gingerbase)

From: samhenri <samuel.guimaraes@eldorado.org.br> Refactored patches 5/6 and 6/6 from previous patchset to include some bug-fixes. Kimchi/Hosts was updated with new-ui pre-gingerbase. Some CSS were left empty to avoid conflicts with git rm and git mv from other patches. Please note that some styles, modal windows and buttons may stop working or display incorrectly since this patch includes the new-ui main template that ignores theme-default.min.css rules that were overriding Bootstrap styles in the new-ui. samhenri (2): Adding new-ui JS, images and base template files Adding new-ui to Hosts tab and modal windows src/wok/plugins/kimchi/ui/config/tab-ext.xml | 10 +- .../plugins/kimchi/ui/css/theme-default/host.css | 270 ---------- .../kimchi/ui/css/theme-default/report-add.css | 20 - .../kimchi/ui/css/theme-default/report-rename.css | 22 - .../kimchi/ui/css/theme-default/repository-add.css | 25 - .../ui/css/theme-default/repository-edit.css | 62 --- src/wok/plugins/kimchi/ui/js/src/kimchi.api.js | 39 ++ src/wok/plugins/kimchi/ui/js/src/kimchi.host.js | 598 +++++++++++---------- src/wok/plugins/kimchi/ui/pages/host.html.tmpl | 207 +++---- .../plugins/kimchi/ui/pages/report-add.html.tmpl | 46 +- .../kimchi/ui/pages/report-rename.html.tmpl | 42 +- .../kimchi/ui/pages/repository-add.html.tmpl | 124 ++--- .../kimchi/ui/pages/repository-edit.html.tmpl | 138 ++--- ui/css/src/bootstrap-select.custom.scss | 1 + ui/css/src/modules/_menu-flat.scss | 6 +- ui/css/src/modules/_modal-flat.scss | 2 +- ui/css/src/modules/_navbar-flat.scss | 4 +- ui/css/src/modules/_toolbar.scss | 24 +- ui/css/src/modules/_wok-confirm.scss | 42 ++ ui/css/src/wok.scss | 6 +- ui/images/theme-default/Makefile.am | 2 +- ui/images/theme-default/logo-flat.svg | 43 ++ ui/images/theme-default/logo-white.png | Bin 9879 -> 7583 bytes ui/js/src/wok.grid.js | 416 ++++---------- ui/js/src/wok.line-chart.js | 74 ++- ui/js/src/wok.list.js | 282 ++++++++++ ui/js/src/wok.login.js | 9 +- ui/js/src/wok.main.js | 37 +- ui/js/src/wok.message.js | 110 ++-- ui/js/src/wok.window.js | 38 +- ui/pages/login.html.tmpl | 186 ++++--- ui/pages/wok-ui.html.tmpl | 219 ++++---- 32 files changed, 1445 insertions(+), 1659 deletions(-) create mode 100644 ui/css/src/modules/_wok-confirm.scss create mode 100644 ui/images/theme-default/logo-flat.svg create mode 100644 ui/js/src/wok.list.js -- 1.9.3

From: samhenri <samuel.guimaraes@eldorado.org.br> Signed-off-by: samhenri <samuel.guimaraes@eldorado.org.br> --- ui/css/src/bootstrap-select.custom.scss | 1 + ui/css/src/modules/_menu-flat.scss | 6 +- ui/css/src/modules/_modal-flat.scss | 2 +- ui/css/src/modules/_navbar-flat.scss | 4 +- ui/css/src/modules/_toolbar.scss | 24 +- ui/css/src/modules/_wok-confirm.scss | 42 ++++ ui/css/src/wok.scss | 6 +- ui/images/theme-default/Makefile.am | 2 +- ui/images/theme-default/logo-flat.svg | 43 ++++ ui/images/theme-default/logo-white.png | Bin 9879 -> 7583 bytes ui/js/src/wok.grid.js | 416 ++++++++------------------------ ui/js/src/wok.line-chart.js | 74 +++--- ui/js/src/wok.list.js | 282 ++++++++++++++++++++++ ui/js/src/wok.login.js | 9 +- ui/js/src/wok.main.js | 37 +-- ui/js/src/wok.message.js | 110 +++++---- ui/js/src/wok.window.js | 38 +-- ui/pages/login.html.tmpl | 186 +++++++------- ui/pages/wok-ui.html.tmpl | 219 +++++++++-------- 19 files changed, 874 insertions(+), 627 deletions(-) create mode 100644 ui/css/src/modules/_wok-confirm.scss create mode 100644 ui/images/theme-default/logo-flat.svg create mode 100644 ui/js/src/wok.list.js diff --git a/ui/css/src/bootstrap-select.custom.scss b/ui/css/src/bootstrap-select.custom.scss index 49f9bc2..dd895f2 100644 --- a/ui/css/src/bootstrap-select.custom.scss +++ b/ui/css/src/bootstrap-select.custom.scss @@ -25,6 +25,7 @@ &.btn-group { .btn { .caret { + position: absolute; top: 0; right: 40px; margin-top: 0; diff --git a/ui/css/src/modules/_menu-flat.scss b/ui/css/src/modules/_menu-flat.scss index 9d7036b..46ed21c 100644 --- a/ui/css/src/modules/_menu-flat.scss +++ b/ui/css/src/modules/_menu-flat.scss @@ -127,7 +127,7 @@ background-color: $menu-flat-dropdown-bg; border: 0; border-radius: 0; - @include box-shadow(none !important); + box-shadow: none !important; background-clip: padding-box; // Aligns the dropdown menu to right @@ -150,11 +150,11 @@ > li:first-child > a { border-top: 1px solid $menu-flat-dropdown-bg; - @include box-shadow(none); + box-shadow: none; } > li.critical:last-child > a { - @include box-shadow(none); + box-shadow: none; } // Links within the dropdown menu diff --git a/ui/css/src/modules/_modal-flat.scss b/ui/css/src/modules/_modal-flat.scss index 8265140..90ae44a 100644 --- a/ui/css/src/modules/_modal-flat.scss +++ b/ui/css/src/modules/_modal-flat.scss @@ -76,7 +76,7 @@ border-radius: 0; border: 3px solid #999; background-clip: padding-box; - @include box-shadow(none !important); + box-shadow: none !important; border-radius: 0; outline: 0; } diff --git a/ui/css/src/modules/_navbar-flat.scss b/ui/css/src/modules/_navbar-flat.scss index b54db68..47246a6 100644 --- a/ui/css/src/modules/_navbar-flat.scss +++ b/ui/css/src/modules/_navbar-flat.scss @@ -355,7 +355,7 @@ margin-right: 0; padding-top: 0; padding-bottom: 0; - @include box-shadow(none); + box-shadow: none; } } @@ -418,7 +418,7 @@ background-color: $menu-flat-dropdown-bg; border: 0; border-radius: 0; - @include box-shadow(none !important); + box-shadow: none !important; background-clip: padding-box; height: auto; max-height: 400px; diff --git a/ui/css/src/modules/_toolbar.scss b/ui/css/src/modules/_toolbar.scss index eaa962f..77455fd 100644 --- a/ui/css/src/modules/_toolbar.scss +++ b/ui/css/src/modules/_toolbar.scss @@ -16,7 +16,7 @@ // limitations under the License. // -.toolbar { +.navbar-default.toolbar { height: 40px; padding: 0; margin: 0; @@ -27,15 +27,29 @@ height: 40px; } - a { + .navbar-nav > li > a.dropdown-toggle > .caret { + margin-top: -5px; + width: 20px; + margin-left: 5px; + } + + .navbar-nav > li > a.dropdown-toggle > .caret:before { + top: 15px; + margin-left: 0; + } + + .navbar-right.tools > li > a { font-family: $font-family-alternate; display: inline-block; color: $highlights-color; text-decoration: none; font-size: 13pt; vertical-align: middle; - padding: 6px 0; - margin-left: 50px; + padding: 6px 0 !important; + margin-left: 50px !important; + font-weight: 400; + width: auto; + min-width: auto; } span, .fa { @@ -52,7 +66,7 @@ @each $page, $bgcolor in $colors { -##{$page}-root-container .toolbar { +##{$page}-root-container .navbar-default.toolbar.toolbar { background-color: $bgcolor !important; } } \ No newline at end of file diff --git a/ui/css/src/modules/_wok-confirm.scss b/ui/css/src/modules/_wok-confirm.scss new file mode 100644 index 0000000..21693ac --- /dev/null +++ b/ui/css/src/modules/_wok-confirm.scss @@ -0,0 +1,42 @@ +// +// Project Wok +// +// Copyright IBM, Corp. 2015 +// +// Licensed 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. +// + +#wok-confirm-modal { + + .modal-title .fa { + font-size: 47px; + color: #fdb813; + position: absolute; + left: 38px; + top: 19px; + } + + .modal-footer { + background-color: $state-warning-border; + } + + .modal-header, + .modal-body { + padding-left: 100px; + } + + .modal-header.icon { + padding: 19px 0 0 0; + } + +} \ No newline at end of file diff --git a/ui/css/src/wok.scss b/ui/css/src/wok.scss index 9c0dee2..a9685c3 100755 --- a/ui/css/src/wok.scss +++ b/ui/css/src/wok.scss @@ -64,7 +64,8 @@ // Override panels .panel { - @include box-shadow(none); + box-shadow: none !important; + -webkit-box-shadow: none !important; } .panel-title { @@ -91,6 +92,9 @@ // Wok Grid & Wok List @import "modules/wok-grid"; +// Wok Confirm Dialog +@import "modules/wok-confirm"; + // Utils .absolute-middle { margin: auto; diff --git a/ui/images/theme-default/Makefile.am b/ui/images/theme-default/Makefile.am index 85fdf5f..7deb55f 100644 --- a/ui/images/theme-default/Makefile.am +++ b/ui/images/theme-default/Makefile.am @@ -19,4 +19,4 @@ imagedir = $(datadir)/wok/ui/images/theme-default -dist_image_DATA = *.png *.gif +dist_image_DATA = *.png *.gif *.svg diff --git a/ui/images/theme-default/logo-flat.svg b/ui/images/theme-default/logo-flat.svg new file mode 100644 index 0000000..dda5822 --- /dev/null +++ b/ui/images/theme-default/logo-flat.svg @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> + <svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="387" height="366" id="svg2"> + <title id="title4148">Project Kimchi</title> + <metadata id="metadata20"> + <rdf:RDF> + <cc:Work rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title>Project Kimchi</dc:title> + <cc:license rdf:resource="http://www.apache.org/licenses/LICENSE-2.0" /> + <dc:date>2013 - 2015</dc:date> + <dc:creator> + <cc:Agent> + <dc:title>IBM, Corp.</dc:title> + </cc:Agent> + </dc:creator> + <dc:rights> + <cc:Agent> + <dc:title>IBM, Corp.</dc:title> + </cc:Agent> + </dc:rights> + <dc:publisher> + <cc:Agent> + <dc:title>IBM, Corp.</dc:title> + </cc:Agent> + </dc:publisher> + <dc:contributor> + <cc:Agent> + <dc:title>https://github.com/kimchi-project</dc:title> + </cc:Agent> + </dc:contributor> + <dc:description>An HTML5 management interface for KVM</dc:description> + </cc:Work> + </rdf:RDF> + </metadata> + <defs id="defs18" /> + <path fill="#D91F2F" d="M303.868,82.71c25.172-8.604,27.898-42.319,7.13-55.331c-1.923-1.04-16.93-10.998-43.506-11.999 c-39.783,1.486-71.632,13.167-92.662,62.139c-0.25,2.109-0.508,6.054,1.977,3.206c0,0,0.284-0.329,0.443-0.515 c15.153-23.034,69.707-29.756,88.572-8.681c0.625,0.72,1.297,1.634,2.003,2.274C276.457,82.654,293.688,86.191,303.868,82.71" id="path4" /> + <path fill="#F19125" d="M336.691,227.692c20.913,16.439,50.687,0.387,50.306-24.119c-0.174-2.18,0.018-20.188-13.601-43.033 c-22.892-32.571-50.019-52.939-102.551-43.944c-1.906,0.938-5.355,2.866-1.615,3.403c0,0,0.432,0.059,0.674,0.093 c27.571,0.183,62.889,42.3,55.469,69.596c-0.263,0.916-0.665,1.977-0.817,2.918C321.826,204.661,328.231,221.044,336.691,227.692" id="path6" /> + <path fill="#8CC643" d="M228.105,329.358c-4.421,26.23,23.926,44.686,45.259,32.619c1.831-1.197,17.731-9.65,31.27-32.543 c17.636-35.689,22.531-69.258-10.515-111.072c-1.737-1.225-5.082-3.33-3.762,0.211c0,0,0.152,0.406,0.24,0.637 c13.04,24.293-7.028,75.463-34.545,82.018c-0.932,0.207-2.055,0.361-2.955,0.68C241.207,305.282,229.893,318.749,228.105,329.358" id="path8" /> + <path fill="#27AEE4" d="M81.133,285.823c-25.04,8.973-27.272,42.725-6.314,55.43c1.939,1.01,17.088,10.746,43.677,11.357 c39.757-2.072,71.43-14.219,91.738-63.496c0.22-2.113,0.421-6.061-2.023-3.176c0,0-0.279,0.33-0.438,0.521 c-14.811,23.254-69.259,30.777-88.434,9.982c-0.637-0.711-1.321-1.615-2.038-2.246C108.544,285.476,91.262,282.192,81.133,285.823" id="path10" /> + <path fill="#06659E" d="M48.671,141.301c-21.969-14.995-50.596,3.023-48.569,27.447c0.321,2.165,1.34,20.143,16.463,42.022 c25.03,30.957,53.465,49.455,105.273,36.947c1.839-1.063,5.151-3.219,1.382-3.502c0,0-0.432-0.031-0.678-0.047 c-27.52,1.672-65.589-37.975-60.023-65.709c0.202-0.933,0.531-2.018,0.62-2.968C65.053,163.281,57.561,147.365,48.671,141.301" id="path12" /> + <path fill="#BA1E70" d="M164.882,38.837c6.497-25.793-20.29-46.448-42.516-36.122c-1.919,1.049-18.444,8.206-33.764,29.946 c-20.424,34.171-27.98,67.243,1.628,111.558c1.632,1.359,4.798,3.726,3.765,0.089c0,0-0.119-0.417-0.188-0.651 c-11.062-25.255,13.021-74.663,40.974-79.004c0.945-0.132,2.076-0.198,3-0.441C149.9,61.794,162.255,49.273,164.882,38.837" id="path14" /> + </svg> diff --git a/ui/images/theme-default/logo-white.png b/ui/images/theme-default/logo-white.png index 8ef8ae15aa40ceb7db5170c9806ac74b840eaa0f..f2630da0fd837573cd6ca69a46823260b899f9ac 100644 GIT binary patch literal 7583 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 BY-Rue literal 9879 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 JPDHLkV1gkP$2tH2 diff --git a/ui/js/src/wok.grid.js b/ui/js/src/wok.grid.js index 12f191c..0606bc6 100644 --- a/ui/js/src/wok.grid.js +++ b/ui/js/src/wok.grid.js @@ -18,106 +18,73 @@ * limitations under the License. */ wok.widget.Grid = function(opts) { + "use strict"; this.opts = $.extend({}, this.opts, opts); this.createDOM(); this.reload(); }; wok.widget.Grid.prototype = (function() { + "use strict"; var htmlStr = [ - '<div id="{id}" class="grid">', - '<div class="grid-content">', - '<div class="grid-header">', - '<div class="grid-frozen-header-view">', - '<table class="grid-frozen-header-container">', - '</table>', - '</div>', - '<div class="grid-header-view">', - '<div class="grid-header-wrapper">', - '<table class="grid-header-container">', - '</table>', - '</div>', - '</div>', - '</div>', - '<div class="grid-body">', - '<div class="grid-frozen-body-view">', - '<div class="grid-frozen-body-wrapper">', - '<table class="grid-frozen-body-container">', - '</table>', - '</div>', - '</div>', - '<div class="grid-body-view">', - '<div class="grid-body-wrapper">', - '<table class="grid-body-container">', - '</table>', - '</div>', - '</div>', + '<div id="{id}" class="grid wok-grid">', + '<div class="wok-grid-message hidden">', + '<div class="alert alert-danger fade in" role="alert">', + '<p><strong>{message}</strong> ', + '<span class="detailed-text"></span></p>', + '<p><button class="btn btn-primary btn-xs retry-button">', + '{buttonLabel}', + '</button></p>', '</div>', - '<div class="grid-resizer-leftmost hidden"></div>', - '<div class="grid-resizer hidden"></div>', '</div>', - '<div class="grid-footer"></div>', - '<div class="grid-mask hidden">', - '<div class="grid-loading">', - '<div class="grid-loading-icon"></div>', - '<div class="grid-loading-text">', - '{loading}', - '</div>', - '</div>', + '<div class="grid-content wok-grid-content">', + '<table class="wok-table table">', + '<thead class="wok-grid-header-container"></thead>', + '<tbody class="wok-grid-body-container">', + '</tbody>', + '</table>', '</div>', - '<div class="grid-message hidden">', - '<div class="grid-message-text">', - '{message}', - '<button class="retry-button btn-small">', - '{buttonLabel}', - '</button>', - '</div>', - '<div class="detailed-title">', - '{detailedLabel}', + '<div class="wok-grid-mask hidden">', + '<div class="wok-grid-loader-container">', + '<div class="wok-grid-loading">', + '<div class="wok-grid-loading-icon"></div>', + '<div class="wok-grid-loading-text">', + '{loading}', + '</div>', + '</div>', '</div>', - '<div class="detailed-text"></div>', '</div>', '</div>' ].join(''); - var CONTAINER_NORMAL = 0, CONTAINER_FROZEN = 1; - var setupHeaders = function(header, body, fields) { var colGroup = $('<colgroup></colgroup>').appendTo(header); - var headerHeader = $('<thead></thead>'); - var headerRow = $('<tr></tr>').appendTo(headerHeader); + var headerRow = $('<tr></tr>').appendTo(header); $.each(fields || [], function(i, field) { $('<col class="' + field['class'] + '"/>') .appendTo(colGroup); - $('<th><div class="cell-text-wrapper">' + + $('<th><div class="wok-text-header">' + field['label'] + '</div></th>').appendTo(headerRow); }); - headerHeader.appendTo(header); var totalWidth = 0; - $('col', colGroup).each(function(index, col) { - var width = $(col).width(); - totalWidth += width; - $(col).css('width', width + 'px'); - }); - $(body).append(colGroup.clone()); return totalWidth; }; var getValue = function(name, obj) { - var result=undefined; + var result; if(!Array.isArray(name)) { name=name.parseKey(); } - if(name.length!=0) { + if(name.length!==0) { var tmpName=name.shift(); - if(obj[tmpName]!=undefined) { + if(obj[tmpName]!==undefined) { result=obj[tmpName]; } - if(name.length!=0) { + if(name.length!==0) { result=getValue(name,obj[tmpName]); } } @@ -126,55 +93,18 @@ wok.widget.Grid.prototype = (function() { var fillBody = function(container, fields) { var data = this.data; - var tbody = ($('tbody', container).length && $('tbody', container)) - || $('<tbody></tbody>').appendTo(container); - tbody.empty(); $.each(data, function(i, row) { - var rowNode = $('<tr></tr>').appendTo(tbody); + var rowNode = $('<tr></tr>').appendTo(container); $.each(fields, function(fi, field) { var value = getValue(field['name'], row); - $('<td><div class="cell-text-wrapper"' + - (field['makeTitle'] === true - ? ' title="' + value + '"' - : '' - ) + '>' + value.toString() + '</div></td>' + $('<td><div class="wok-cell-text"' + (field['makeTitle'] === true ? ' title="' + value + '"' : '' ) + '>' + value.toString() + '</div></td>' ).appendTo(rowNode); }); }); }; - var fixTableLayout = function(style) { - $.each([ - this.frozenHeaderContainer, - this.headerContainer, - this.frozenBodyContainer, - this.bodyContainer - ], function(i, tableNode) { - $(tableNode).css('table-layout', style || 'fixed'); - }); - }; - - var initResizing = function(event) { - var resizer = event.data.resizer; - var pageX = event.pageX; - var tailPos = $(this).width() + $(this).offset()['left']; - var atResizer = Math.abs(pageX - tailPos) <= 2; - var isResizing = !$(resizer).hasClass('hidden'); - $('body')[(atResizer || isResizing) - ? 'addClass' - : 'removeClass' - ]('resizing'); - }; - - var clearResizing = function(event) { - $(event.data.resizer).hasClass('hidden') && - $('body').removeClass('resizing'); - }; - var stylingRow = function(row, className, add) { var index = $(row).index() + 1; - $('tr', this.frozenBodyContainer) - .removeClass(className); $('tr', this.bodyContainer) .removeClass(className); @@ -182,19 +112,18 @@ wok.widget.Grid.prototype = (function() { return; } - $('tr:nth-child(' + index + ')', this.frozenBodyContainer) - .addClass(className); $('tr:nth-child(' + index + ')', this.bodyContainer) .addClass(className); }; var setBodyListeners = function() { - if(this['opts']['rowSelection'] != 'disabled') { + if(this['opts']['rowSelection'] !== 'disabled') { $('tr', this.gridBody).on('mouseover', { grid: this }, function(event) { - if (! $(this).hasClass('no-hover')) + if (! $(this).hasClass('no-hover')) { stylingRow.call(event.data.grid, this, 'hover'); + } }); $('tr', this.gridBody).on('mouseout', { @@ -213,128 +142,16 @@ wok.widget.Grid.prototype = (function() { }); } - $('.grid-body-view', this.domNode).on('scroll', { - grid: this - }, function(event) { - var grid = event.data.grid; - $('.grid-header .grid-header-view', grid.domNode) - .prop('scrollLeft', this.scrollLeft); - $('.grid-body .grid-frozen-body-view', grid.domNode) - .prop('scrollTop', this.scrollTop); - }); }; var setData = function(data) { this.data = data; - fillBody.call(this, this.frozenBodyContainer, this['opts']['frozenFields']); fillBody.call(this, this.bodyContainer, this['opts']['fields']); setBodyListeners.call(this); }; var getSelected = function() { - return this.selectedIndex >= 0 - ? this.data[this.selectedIndex] - : null; - }; - - var startResizing = function(container, event) { - var grid = event.data.grid; - wok.widget.Grid.beingResized = grid; - if(!($('body').hasClass('resizing') - && $(grid.resizer).hasClass('hidden'))) { - return; - } - - grid.columnBeingResized = container; - var pageX = event.pageX; - var gridOffsetX = grid.domNode.offset()['left']; - var leftmostOffsetX = $(container).offset()['left'] - gridOffsetX; - var left = pageX - gridOffsetX; - var contentHeight = $('.grid-content', grid.domNode).height(); - $(grid.resizerLeftmost).css({ - left: leftmostOffsetX + 'px', - height: contentHeight + 'px' - }); - $(grid.resizer).css({ - left: left + 'px', - height: contentHeight + 'px' - }); - $(grid.resizerLeftmost).removeClass('hidden'); - $(grid.resizer).removeClass('hidden'); - event.preventDefault(); - }; - - var endResizing = function(event) { - var grid = wok.widget.Grid.beingResized; - if(!$('body').hasClass('resizing')) { - return; - } - $(grid.resizerLeftmost).addClass('hidden'); - $(grid.resizer).addClass('hidden'); - $('body').removeClass('resizing'); - var leftmostOffset = $(grid.columnBeingResized).offset()['left']; - var left = event.pageX; - if(leftmostOffset > left) { - return; - } - resizeColumnWidth.call( - grid, - $(grid.columnBeingResized).index(), - left - leftmostOffset - ); - fixTableLayout.call(grid); - grid.columnBeingResized = null; - wok.widget.Grid.beingResized = null; - }; - - var resizeColumnWidth = function(index, width) { - var width = Math.ceil(width); - var widthArray = []; - var totalWidth = 0; - var header = this.headerContainer; - var body = this.bodyContainer; - if(this.containerBeingResized === CONTAINER_FROZEN) { - header = this.frozenHeaderContainer; - body = this.frozenBodyContainer; - } - $('col', header).each(function(i, colNode) { - var w = index === i ? width : $(colNode).width(); - widthArray.push(w); - totalWidth += w; - }); - $.each([header, body], function(i, container) { - container.css({ - 'table-layout': 'fixed', - width: totalWidth + 'px' - }); - $('col:nth-child(' + (index + 1) + ')', container).css({ - width: width + 'px' - }); - }); - - if(this.containerBeingResized === CONTAINER_FROZEN) { - var headerView = $('.grid-header-view', this.domNode); - var bodyView = $('.grid-body-view', this.domNode); - $.each([headerView, bodyView], function(i, view) { - view.css({ - left: totalWidth + 'px' - }); - }); - } - }; - - var positionResizer = function(event) { - var grid = event.data.grid; - if($(grid.resizer).hasClass('hidden')) { - return; - } - - var pageX = event.pageX; - var gridOffsetX = $(grid.domNode).offset()['left']; - var leftMost = $(grid.resizerLeftmost).position()['left']; - var offsetX = pageX - gridOffsetX; - offsetX = offsetX >= leftMost ? offsetX : leftMost; - $(grid.resizer).css('left', offsetX + 'px'); + return this.selectedIndex >= 0 ? this.data[this.selectedIndex] : null; }; var showMessage = function(msg) { @@ -368,11 +185,6 @@ wok.widget.Grid.prototype = (function() { } }; - var destroy = function() { - $('body').off('mousemove.grid#' + this['opts']['id'], positionResizer); - $('body').off('mouseup.grid#' + this['opts']['id'], endResizing); - }; - var createDOM = function() { var containerID = this['opts']['container']; var container = $('#' + containerID); @@ -387,118 +199,91 @@ wok.widget.Grid.prototype = (function() { })).appendTo(container); this.domNode = domNode; + var theTable = $('.wok-table', domNode); + var theContainer = $('.wok-grid-content', domNode); + var headerContainer = $('.wok-grid-header-container', domNode); + var bodyContainer = $('.wok-grid-body-container', domNode); + setupHeaders(headerContainer, bodyContainer, this['opts']['fields']); + this.theTable = theTable; + this.theContainer = theContainer; + this.headerContainer = headerContainer; + this.bodyContainer = bodyContainer; + var height = domNode.height(); var width = domNode.width(); var title = this['opts']['title']; var titleNode = null; if(title) { - titleNode = $('<div class="grid-caption">' + title + '</div>') - .prependTo(domNode); + titleNode = $('<caption class="sr-only">' + title + '</caption>').prependTo(theTable); } var toolbarButtons = this['opts']['toolbarButtons']; var toolbarNode = null; + var btnHTML, dropHTML = []; if(toolbarButtons) { - toolbarNode = $('<div class="grid-toolbar"></div>'); - if(titleNode) { - titleNode.after(toolbarNode); - } - else { - toolbarNode.prependTo(domNode); + toolbarNode = $('<div class="btn-group"></div>'); + toolbarNode.prependTo(theContainer); + if(toolbarButtons.length > 1) { + dropHTML = ['<div class="dropdown menu-flat">', + '<button id="wok-dropdown-button-', containerID, '" class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">', + '<span class="edit-alt"></span>Actions<span class="caret"></span>', + '</button>', + '<ul class="dropdown-menu"></ul>', + '</div>' + ].join(''); + $(dropHTML).appendTo(toolbarNode); + $.each(toolbarButtons, function(i, button) { + btnHTML = [ + '<li role="presentation"', button.critical === true ? ' class="critical"' : '', '><a data-toggle="modal"', + button.id ? (' id="' + button.id + '"') : '', + ' class="', button.disabled === true ? ' disabled' : '', '">', + button.class ? ('<i class="' + button.class) + '"></i>' : '', + button.label, + '</a></li>' + ].join(''); + var btnNode = $(btnHTML).appendTo(toolbarNode[0].children[0].children[1]); + button.onClick && btnNode.on('click', button.onClick); + }); + }else { + $.each(toolbarButtons, function(i, button) { + btnHTML = [ + '<button data-dismiss="modal" ', + button['id'] ? (' id="' + button['id'] + '"') : '', + ' class="btn btn-primary', + button['class'] ? (' ' + button['class']) : '', + '"', + button['disabled'] === true ? ' disabled' : '', + '>', + button['label'], + '</button>' + ].join(''); + var btnNode = $(btnHTML).appendTo(toolbarNode); + button['onClick'] && + btnNode.on('click', button['onClick']); + }); } - $.each(toolbarButtons, function(i, button) { - var btnHTML = [ - '<button', - button['id'] ? (' id="' + button['id'] + '"') : '', - ' class="grid-toolbar-button', - button['class'] ? (' ' + button['class']) : '', - '"', - button['disabled'] === true ? ' disabled' : '', - '>', - button['label'], - '</button>' - ].join(''); - var btnNode = $(btnHTML).appendTo(toolbarNode); - button['onClick'] && - btnNode.on('click', button['onClick']); - }); } - var frozenHeaderContainer = $('.grid-frozen-header-container', domNode); - var frozenBodyContainer = $('.grid-frozen-body-container', domNode); - var frozenWidth = setupHeaders( - frozenHeaderContainer, - frozenBodyContainer, - this['opts']['frozenFields'] - ); - this.frozenHeaderContainer = frozenHeaderContainer; - this.frozenBodyContainer = frozenBodyContainer; - - var headerContainer = $('.grid-header-container', domNode); - var bodyContainer = $('.grid-body-container', domNode); - setupHeaders(headerContainer, bodyContainer, this['opts']['fields']); - this.headerContainer = headerContainer; - this.bodyContainer = bodyContainer; - - fixTableLayout.call(this, 'auto'); + // var domHeight = domNode && $(domNode).height() || 0; + // var toolbarHeight = toolbarNode && $(toolbarNode).height() || 0; + // var maskHeight = domHeight - toolbarHeight; - var gridContentNode = $('.grid-content', domNode); - var captionHeight = titleNode && $(titleNode).height() || 0; - var toolbarHeight = toolbarNode && $(toolbarNode).height() || 0; - gridContentNode.css('top', (captionHeight + toolbarHeight) + 'px'); + // var maskContainer = $('.wok-grid-loader-container',domNode); + // maskContainer.css({'top': toolbarHeight+'px', 'height': maskHeight+'px'}); + // this.maskContainer = maskContainer; - var maskNode = $('.grid-mask', domNode); - maskNode.css('top', captionHeight + 'px'); + var maskNode = $('.wok-grid-mask', domNode); this.maskNode = maskNode; - var messageNode = $('.grid-message', domNode); - messageNode.css('top', captionHeight + 'px'); + var messageNode = $('.wok-grid-message', domNode); this.messageNode = messageNode; - var headerView = $('.grid-header-view', domNode); - var bodyView = $('.grid-body-view', domNode); - headerView.css('left', (frozenWidth) + 'px'); - bodyView.css('left', (frozenWidth) + 'px'); + //fixTableLayout.call(this); - var bodyWidth = width - frozenWidth; - headerContainer.css('width', bodyWidth + 'px'); - bodyContainer.css('width', bodyWidth + 'px'); - - fixTableLayout.call(this); - - var gridBody = $('.grid-body', domNode); + var gridBody = $('.wok-grid-body', domNode); this.gridBody = gridBody; - this.resizerLeftmost = $('.grid-resizer-leftmost', domNode); - this.resizer = $('.grid-resizer', domNode); - var gridHeader = $('.grid-header', domNode); - $('th', gridHeader).on('mouseover mousemove', { - resizer: this.resizer - }, initResizing); - - $('th', gridHeader).on('mouseout', { - resizer: this.resizer - }, clearResizing); - - this.containerBeingResized = CONTAINER_NORMAL; - $('th', frozenHeaderContainer).on('mousedown', { - grid: this - }, function(event) { - event.data.grid.containerBeingResized = CONTAINER_FROZEN; - startResizing(this, event); - }); - $('th', headerContainer).on('mousedown', { - grid: this - }, function(event) { - event.data.grid.containerBeingResized = CONTAINER_NORMAL; - startResizing(this, event); - }); - - $('body').on('mousemove.grid#' + this['opts']['id'], { - grid: this - }, positionResizer); - $('body').on('mouseup.grid#' + this['opts']['id'], endResizing); var data = this['opts']['data']; @@ -517,14 +302,13 @@ wok.widget.Grid.prototype = (function() { onRowSelected: null, title: null, toolbarButtons: null, - frozenFields: null, fields: null }, createDOM: createDOM, setData: setData, getSelected: getSelected, reload: reload, - destroy: destroy, + //destroy: destroy, showMessage: showMessage }; -})(); +})(); \ No newline at end of file diff --git a/ui/js/src/wok.line-chart.js b/ui/js/src/wok.line-chart.js index 3c740e6..3eb3494 100644 --- a/ui/js/src/wok.line-chart.js +++ b/ui/js/src/wok.line-chart.js @@ -18,13 +18,15 @@ * limitations under the License. */ -/** +/* * new wok.widget.LineChart({ * node: 'line-chart-cpu', * id: 'line-chart', * type: 'value' * }); */ + + wok.widget.LineChart = function(params) { var container = $('#' + params['node']); container.addClass('chart-container'); @@ -82,6 +84,14 @@ wok.widget.LineChart = function(params) { } }); } + + var defs = [ + '<defs>', + '<pattern id="patternbg" x="0" y="0" width="6" height="6" patternUnits="userSpaceOnUse">', + '<rect x="0" y="0" width="3" height="6" style="stroke:none; fill: #eeeeee;"></rect>', + '</pattern>', + '</defs>' + ].join(''); var canvasNode = $('#' + canvasID); canvasNode.length && canvasNode.remove(); @@ -89,25 +99,10 @@ wok.widget.LineChart = function(params) { '<svg id="', canvasID, '" class="line-chart"', ' height="', height, '" width="', width, '"', '>', + defs, '<rect height="', height, '" width="', width, '" class="background" />' ]; - for(var x = linesOffset; x < width; x += linesSpace) { - htmlStr.push( - '<line x1="', x, '" y1="', 0, '" x2="', x, '" y2="', height, '" />' - ); - } - - linesOffset -= xFactor; - while(linesOffset < 0) { - linesOffset = linesSpace + linesOffset; - } - - for(var y = height - linesSpace; y > 0; y -= linesSpace) { - htmlStr.push( - '<line x1="', 0, '" y1="', y, '" x2="', width, '" y2="', y, '" />' - ); - } var maxValueLabel = i18n['KCHHOST6001M'] + ' ' + (type === 'value' @@ -124,12 +119,34 @@ wok.widget.LineChart = function(params) { chartVAxis.text(maxValueLabel); } + seriesNames = []; $.each(data, function(i, series) { var points = series['points']; var className = series['class']; var latestPoint = points.slice(-1).pop(); xStart = latestPoint['x'] - period; + htmlStr.push('<path', + ' class="series', className ? ' ' + className : '', '"', + ' d="M 0,92 ' + ); + var first = true; + $.each(points, function(i, point) { + if(first) { + first = false; + } + else { + htmlStr.push(' '); + } + + var x = xFactor * (point['x'] - xStart); + var y = height - yFactor * (type === 'value' ? + point['y'] * 100 / maxValue : + point['y'] + ); + htmlStr.push(x, ',', y); + }); + htmlStr.push(' 310,92z" />'); htmlStr.push('<polyline', ' class="series', className ? ' ' + className : '', '"', @@ -152,6 +169,7 @@ wok.widget.LineChart = function(params) { htmlStr.push(x, ',', y); }); htmlStr.push('" />'); + }); htmlStr.push('</svg>'); @@ -160,7 +178,7 @@ wok.widget.LineChart = function(params) { if(!chartLegend) { chartLegend = $('<div class="chart-legend-container"></div>'); - container.after(chartLegend); + container.before(chartLegend); } else { chartLegend.empty(); @@ -169,18 +187,15 @@ wok.widget.LineChart = function(params) { var wrapper = $('<div class="legend-wrapper"></div>') .appendTo(chartLegend); $([ - '<svg class="legend-icon" width="20" height="10">', - '<line x1="0" y1="5" x2="20" y2="5"/>', + '<svg class="legend-icon" width="5" height="40">', + '<rect width="5" height="40" />', '</svg>' ].join('')).appendTo(wrapper); - $('line', wrapper).css({ - stroke: $(polyline).css('stroke'), - 'stroke-width': $(polyline).css('stroke-width') + $('rect', wrapper).css({ + fill: $(polyline).css('stroke') }); var label = data[i]['legend']; var base = data[i]['base']; - $('<label class="legend-label">' + label + '</label>') - .appendTo(wrapper); var latestPoint = data[i]['points'].slice(-1).pop(); var latestValue = latestPoint['y']; if(type === 'value') { @@ -189,11 +204,12 @@ wok.widget.LineChart = function(params) { formatSettings ); } - else { - latestValue += '%'; + else { + latestValue = { v: latestValue, s: '%' }; } - $('<div class="latest-value">' + latestValue + '</div>') - .appendTo(wrapper); + $('<div class="latest-value"><span class="number">' + latestValue.v + '</span></div>').appendTo(wrapper); + $('<span class="legend-label">'+ latestValue.s +'</span><span class="legend-string">'+ label + '</span>').appendTo(wrapper[0].children[1]); + }); }; diff --git a/ui/js/src/wok.list.js b/ui/js/src/wok.list.js new file mode 100644 index 0000000..ea721c4 --- /dev/null +++ b/ui/js/src/wok.list.js @@ -0,0 +1,282 @@ +/* + * Project Wok + * + * Copyright IBM, Corp. 2013-2015 + * + * Licensed 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. + */ +wok.widget.List = function(opts) { + "use strict"; + this.opts = $.extend({}, this.opts, opts); + this.createDOM(); + this.reload(); +}; + +wok.widget.List.prototype = (function() { + "use strict"; + var htmlStr = [ + '<div id="{id}-section" class="panel panel-default">', + '<div class="panel-heading">', + '</div>', + '<div id="content-{id}" class="panel-body">', + '<div id="{id}-container">', + '<div class="wok-list-message clearfix hidden">', + '<div class="alert alert-danger fade in" role="alert">', + '<p><strong>{message}</strong> ', + '<span class="detailed-text"></span></p>', + '<p><button class="btn btn-primary btn-xs retry-button">', + '{buttonLabel}', + '</button></p>', + '</div>', + '</div>', + '<div id="{id}" class="row clearfix">', + '<div class="wok-list-content">', + '<table class="wok-list-table table table-striped" id="list">', + '</table>', + '</div>', + '</div>', + '<div class="wok-list-mask hidden">', + '<div class="wok-list-loader-container">', + '<div class="wok-list-loading">', + '<div class="wok-list-loading-icon"></div>', + '<div class="wok-list-loading-text">', + '{loading}', + '</div>', + '</div>', + '</div>', + '</div>', + '</div>', + '</div>', + '</div>' + ].join(''); + + var getValue = function(name, obj) { + var result; + if (!Array.isArray(name)) { + name = name.parseKey(); + } + if (name.length !== 0) { + var tmpName = name.shift(); + if (obj[tmpName] !== undefined) { + result = obj[tmpName]; + } + if (name.length !== 0) { + result = getValue(name, obj[tmpName]); + } + } + return (result); + }; + + var fillBody = function(container, fields) { + + var toolbarButtons = this.opts.toolbarButtons; + var actionDropdownHtml; + var data = this.data; + var tbody = ($('tbody', container).length && $('tbody', container)) || $('<tbody></tbody>').appendTo(container); + tbody.empty(); + //console.log(data.lenght); + $.each(data, function(i, row) { + var rowNode = $('<tr></tr>').appendTo(tbody); + var columnNodeHTML; + var columnData = ''; + var state = ''; + var styleClass = ''; + if (toolbarButtons) { + actionDropdownHtml = [ + '<td>', + '<div class="dropdown menu-flat">', + '<button id="wok-dropdown-button-', i, '" class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">', + '<span class="edit-alt"></span>Actions<span class="caret"></span>', + '</button>', + '<ul class="dropdown-menu" role="menu" aria-labelledby="action-dropdown-menu-', i, '">', + '</ul>', + '</div>', + '</td>' + ].join(''); + } + $.each(fields, function(fi, field) { + var value = getValue(field.name, row); + if (field.type === 'status' && field.name === 'enabled') { + styleClass = (value === true ? '' : ' disabled'); + state = [ + '<span class="wok-repository-status ', + value === true ? 'enabled' : 'disabled', + '"><i class="fa fa-power-off"></i></span>' + ].join(''); + } + columnData += (field.type === 'name') ? ('<span class="wok-list-name">' + value.toString() + '</span>') : (field.type !== 'status' ? '<span class="wok-list-description">' + value.toString() + '</span>' : ''); + + }); + columnNodeHTML = [ + '<td>', + '<div class="wok-list-cell', styleClass, '">', state, + columnData, + '</div>', + '</td>' + ].join(''); + $(columnNodeHTML).appendTo(rowNode); + + var actionMenuNode = $(actionDropdownHtml).appendTo(rowNode); + + $.each(toolbarButtons, function(i, button) { + var btnHTML = [ + '<li role="presentation"', button.critical === true ? ' class="critical"' : '', '>', + '<a role="menuitem" tabindex="-1" data-dismiss="modal"', (button.id ? (' id="' + button.id + '"') : ''), (button.disabled === true ? ' class="disabled"' : ''), + '>', + button.class ? ('<i class="' + button.class) + '"></i>' : '', + button.label, + '</a></li>' + ].join(''); + + var btnNode = $(btnHTML).appendTo($('.dropdown-menu', rowNode)); + button.onClick && btnNode.on('click', button.onClick); + + }); + + + }); + }; + + var stylingRow = function(row, className, add) { + console.log('stylingRow'); + var index = $(row).index() + 1; + $('tr', this.bodyContainer) + .removeClass(className); + if (add === false) { + return; + } + $('tr:nth-child(' + index + ')', this.bodyContainer) + .addClass(className); + }; + + var setBodyListeners = function() { + if (this['opts']['rowSelection'] != 'disabled') { + + $('tr', this.bodyContainer).on('click', { + grid: this + }, function(event) { + var grid = event.data.grid; + if ($(this).hasClass('selected')) { + console.log(this); + } + grid.selectedIndex = $(this).index(); + stylingRow.call(grid, this, 'selected'); + grid['opts']['onRowSelected'] && grid['opts']['onRowSelected'](); + }); + } + }; + + var setData = function(data) { + this.data = data; + fillBody.call(this, this.bodyContainer, this.opts.fields); + setBodyListeners.call(this); + }; + + var getSelected = function() { + return this.selectedIndex >= 0 ? this.data[this.selectedIndex] : null; + }; + + var showMessage = function(msg) { + $('.detailed-text', this.messageNode).text(msg); + $(this.messageNode).removeClass('hidden'); + }; + + var hideMessage = function() { + $(this.messageNode).addClass('hidden'); + }; + + var reload = function() { + var data = this.opts.data; + if (!data) { + return; + } + + if ($.isArray(data)) { + return this.setData(data); + } + + if ($.isFunction(data)) { + var loadData = data; + $(this.maskNode).removeClass('hidden'); + loadData($.proxy(function(data) { + this.setData(data); + $(this.maskNode).addClass('hidden'); + }, this)); + } + }; + + var createDOM = function() { + var containerID = this.opts.container; + var container = $('#' + containerID); + var gridID = this.opts.id; + var data = this.opts.data; + var rowSelection = this.opts.rowSelection || 'single'; + var domNode = $(wok.substitute(htmlStr, { + id: gridID, + loading: i18n.KCHGRD6001M, + message: i18n.KCHGRD6002M, + buttonLabel: i18n.KCHGRD6003M, + detailedLabel: i18n.KCHGRD6004 + })).appendTo(container); + this.domNode = domNode; + + + var titleContainer = $('.panel-heading', domNode); + this.titleContainer = titleContainer; + + var title = this.opts.title; + var titleNode = null; + + if (title) { + titleNode = $('<h3 class="panel-title">' + title + '</h3>').appendTo(titleContainer); + } + + var bodyContainer = $('.wok-list-table.table.table-striped', domNode); + this.bodyContainer = bodyContainer; + + var gridBody = $('.wok-list-content', domNode); + this.gridBody = gridBody; + + var maskNode = $('.wok-list-mask', domNode); + this.maskNode = maskNode; + + var messageNode = $('.wok-list-message', domNode); + this.messageNode = messageNode; + + $('.retry-button', domNode).on('click', { + grid: this + }, function(event) { + event.data.grid.reload(); + }); + + + }; + + return { + opts: { + container: null, + id: null, + rowSelection: 'single', + onRowSelected: null, + title: null, + toolbarButtons: null, + frozenFields: null, + fields: null + }, + createDOM: createDOM, + setData: setData, + getSelected: getSelected, + reload: reload, + showMessage: showMessage + }; +})(); diff --git a/ui/js/src/wok.login.js b/ui/js/src/wok.login.js index d9ccae6..13a1da0 100644 --- a/ui/js/src/wok.login.js +++ b/ui/js/src/wok.login.js @@ -18,9 +18,12 @@ * limitations under the License. */ wok.login_main = function() { - + "use strict"; var selectedLanguage = wok.lang.get(); $('#userLang').val(selectedLanguage); + $('#userLang option[value="'+selectedLanguage+'"]').attr("selected", "selected"); + $('#userLang').next().find('.selectpicker').attr('title',$('#userLang option[value="'+selectedLanguage+'"]').text()); + $('#userLang').next().children().find('.filter-option').text($('#userLang option[value="'+selectedLanguage+'"]').text()); $('#userLang').on('change', function() { wok.lang.set($(this).val()); @@ -29,7 +32,7 @@ wok.login_main = function() { var query = window.location.search; var error = /.*error=(.*?)(&|$)/g.exec(query); - if (error && error[1] == "sessionTimeout") { + if (error && error[1] === "sessionTimeout") { $("#messSession").show(); } @@ -59,7 +62,7 @@ wok.login_main = function() { var next_url = lastPage ? lastPage.replace(/\"/g,'') : "/"; } wok.cookie.set('roles',JSON.stringify(data.roles)); - window.location.replace(window.location.pathname.replace(/\/+login.html/, '') + next_url) + window.location.replace(window.location.pathname.replace(/\/+login.html/, '') + next_url); }, function() { $("#messUserPass").show(); $("#messSession").hide(); diff --git a/ui/js/src/wok.main.js b/ui/js/src/wok.main.js index 25fed31..af8695b 100644 --- a/ui/js/src/wok.main.js +++ b/ui/js/src/wok.main.js @@ -27,6 +27,7 @@ wok.main = function() { var tabsHtml = []; $(tabs).each(function(i, tab) { var title = tab['title']; + var cssClass = tab['css']; var path = tab['path']; var mode = tab['mode']; if (mode != 'none') { @@ -34,10 +35,10 @@ wok.main = function() { var disableHelp = (helpPath.length == 0 ? "disableHelp" : helpPath); tabsHtml.push( '<li>', - '<a class="item ', disableHelp,'" href="', path, '">', + '<a class="item ', disableHelp,' ',cssClass,'" href="', path, '">', title, '</a>', - '<input id="helpPathId" name="helpPath" value="' + helpPath + '" type="hidden"/>', + '<input id="helpPathId" name="helpPath" class="sr-only" value="' + helpPath + '" type="hidden"/>', '</li>' ); } @@ -51,6 +52,7 @@ wok.main = function() { var $tab = $(this); var titleKey = $tab.find('title').text(); var title = i18n[titleKey] ? i18n[titleKey] : titleKey; + var css = $tab.find('class').text(); var path = $tab.find('path').text(); var roles = wok.cookie.get('roles'); if (roles) { @@ -60,6 +62,7 @@ wok.main = function() { tabs.push({ title: title, path: path, + css: css, mode: mode }); } else { @@ -113,7 +116,8 @@ wok.main = function() { DEFAULT_HASH = defaultTabPath && defaultTabPath.substring(0, defaultTabPath.lastIndexOf('.')) } - $('#nav-menu').append(genTabs(tabs)); + $('#nav-menu ul.navbar-nav li.hostname').after(genTabs(tabs)); + wok.getHostname(); callback && callback(); }, function(data) { @@ -142,7 +146,7 @@ wok.main = function() { * point to the tab. If nothing found, inform user the URL is invalid * and clear location.hash to jump to home page. */ - var tab = $('#nav-menu a[href="' + url + '"]'); + var tab = $('#nav-menu ul li a[href="' + url + '"]'); if (tab.length === 0 && url!='wok-empty.html') { location.hash = ''; return; @@ -150,20 +154,14 @@ wok.main = function() { //Remove the tab arrow indicator for no plugin if(url=='wok-empty.html'){ - $('.menu-arrow').hide(); $('#main').html('No plugins installed currently.You can download the available plugins <a href="https://github.com/kimchi-project/kimchi">Kimchi</a> and <a href="https://github.com/kimchi-project/ginger">Ginger</a> from Github').addClass('noPluginMessage'); }else{ - // Animate arrow indicator. - var left = $(tab).parent().position().left; - var width = $(tab).parent().width(); - $('.menu-arrow').stop().animate({ - left : left + width / 2 - 10 - }); - + // Update the visual style of tabs; focus the selected one. - $('#nav-menu a').removeClass('current'); - $(tab).addClass('current'); + $('#nav-menu ul li').removeClass('active'); + $(tab).parent().addClass('active'); $(tab).focus(); + // Disable Help button according to selected tab if ($(tab).hasClass("disableHelp")) { $('#btn-help').css('cursor', "not-allowed"); @@ -240,7 +238,7 @@ wok.main = function() { * Register click listener of tabs. Replace the default reloading page * behavior of <a> with Ajax loading. */ - $('#nav-menu').on('click', 'a.item', function(event) { + $('#nav-menu ul li').on('click', 'a.item', function(event) { var href = $(this).attr('href'); // Remove file extension from 'href' location.hash = href.substring(0,href.lastIndexOf('.')) @@ -279,7 +277,7 @@ wok.main = function() { $('#peers').on('click', function() { // Check if any request is in progress - if ($('.popover', '#peers').is(':visible') || searchingPeers == true) + if ($('.dropdown', '#peers').is('.open') || searchingPeers == true) return $('#search-peers').show(); @@ -294,7 +292,7 @@ wok.main = function() { $('#no-peers').removeClass('hide-content'); for(var i=0; i<data.length; i++){ - $('.dropdown', '#peers').append("<a href='"+data[i]+"' target='_blank'>"+data[i]+"</a>"); + $('.dropdown-menu ', '#peers').append("<li><a href='"+data[i]+"' target='_blank'>"+data[i]+"</a></li>"); } searchingPeers = false; }); @@ -361,6 +359,11 @@ wok.checkHelpFile = function(path) { return url; }; +wok.getHostname = function(e) { + host = window.location.hostname; + $('span.host-location').text(host); + return host; +} wok.openHelp = function(e) { var tab = $('#nav-menu a.current'); diff --git a/ui/js/src/wok.message.js b/ui/js/src/wok.message.js index bd650e0..7012f9c 100644 --- a/ui/js/src/wok.message.js +++ b/ui/js/src/wok.message.js @@ -18,31 +18,32 @@ * limitations under the License. */ wok.message = function(msg, level, node) { - var container = node || $('#messageField'); + "use strict"; + var container = node || $('#alert-fields'); if ($(container).size() < 1) { - container = $('<div id="messageField"/>').appendTo(document.body); + container = $('<div id="alert-fields"/>').appendTo($('#alert-container')); } - var message = '<div class="message ' + (level || '') + '" style="display: none;">'; + var message = '<div role="alert" class="alert ' + (level || '') + ' alert-dismissible fade in" style="display: none;">'; if(!node) { - message += '<div class="close">X</div>'; + message += '<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true"><i class="fa fa-times-circle"></i></span></button>'; } - message += '<div class="content">' + msg + '</div>'; + message += msg; message += '</div>'; var $message = $(message); $(container).append($message); + $message.alert(); $message.fadeIn(100); setTimeout(function() { $message.fadeOut(2000, function() { + $message.alert('close'); $(this).remove(); + $(container).remove(); + if ($(container).children().length < 1) { + $(container).remove(); + } }); }, 4000); - - $(container).on("click", ".close", function(e) { - $(this).parent().fadeOut(200, function() { - $(this).remove(); - }); - }); }; /** @@ -64,55 +65,78 @@ wok.message = function(msg, level, node) { * The callback function of click the cancel and X button. */ wok.confirm = function(settings, confirmCallback, cancelCallback) { - if ($('#confirmbox-container ').size() < 1) { - $(document.body).append('<div id="confirmbox-container" class="bgmask"></div>'); + "use strict"; + var modalStr = '<div id="wok-confirm-modal" class="modal fade host-modal" tabindex="-1" role="dialog" aria-labelledby="confirmModalLabel" aria-hidden="true"></div>'; + if ($('#wok-confirm-modal ').size() < 1 && $('#modalWindow').size() < 1 ) { + $(document.body).append(modalStr); + } else if ($('#wok-confirm-modal ').size() < 1) { + $('#modalWindow').after(modalStr); } - var confirmboxHtml = '<div class="confirmbox">'; - confirmboxHtml += '<header>'; - confirmboxHtml += '<h4 class="title">' + (settings.title || '') + '</h4>'; - confirmboxHtml += '<div class="close cancel">X</div>'; - confirmboxHtml += '</header>'; - confirmboxHtml += '<div class="content">'; - confirmboxHtml += settings.content + '</div>'; - confirmboxHtml += '<footer>'; - confirmboxHtml += '<div class="btn-group">'; - confirmboxHtml += '<button id="button-confirm" class="btn-small"><span class="text">' + (settings.confirm || i18n['KCHAPI6004M']) + '</span></button>'; - confirmboxHtml += '<button id="button-cancel" class="btn-small cancel"><span class="text">' + (settings.cancel || i18n['KCHAPI6003M']) + '</span></button>'; - confirmboxHtml += '</div>'; - confirmboxHtml += '</footer>'; - confirmboxHtml += '</div>'; - var confirmboxNode = $(confirmboxHtml); - $('#confirmbox-container').append(confirmboxNode); - confirmboxNode.fadeIn(); - $('#confirmbox-container').on("click", "#button-confirm", function(e) { + var confirmboxHeader = [ + '<div class="modal-header', (settings.title === true ? '' : '' ) ,' icon">', + '<h4 class="modal-title"><i class="fa fa-exclamation-triangle"></i>'+(settings.title || '')+'</h4>', + '</div>' + ].join(''); + + var confirmboxHtml = [ + '<div class="modal-dialog modal-sm">', + '<div class="modal-content">', + '<div class="modal-header">', + confirmboxHeader, + '</div>', + '<div class="modal-body">', + settings.content, + '</div>', + '<div class="modal-footer">', + '<button id="button-confirm" class="btn btn-default">' + (settings.confirm || i18n['KCHAPI6004M']) + '</button>', + '<button id="button-cancel" class="btn btn-default">' + (settings.cancel || i18n['KCHAPI6003M']) + '</button>', + '</div>', + '</div>', + '</div>' + ].join(''); + var confirmboxNode = $(confirmboxHtml); + $('#wok-confirm-modal').append(confirmboxNode); + $('#wok-confirm-modal').modal('show'); + $('#wok-confirm-modal').on("click", "#button-confirm", function(e) { if (confirmCallback) { confirmCallback(); } - confirmboxNode.fadeOut(1, function() { - $('#confirmbox-container').remove(); - }); + $('#wok-confirm-modal').modal('hide'); }); - $('#confirmbox-container').on("click", ".cancel", function(e) { + $('#wok-confirm-modal').on("click", "#button-cancel", function(e) { if (cancelCallback) { cancelCallback(); } - confirmboxNode.fadeOut(1, function() { - $('#confirmbox-container').remove(); - }); + $('#wok-confirm-modal').modal('hide'); + }); + + $('#wok-confirm-modal').on('hidden.bs.modal', function () { + close(); }); + + var close = function(){ + "use strict"; + $('#wok-confirm-modal').removeData('bs.modal'); + $('#wok-confirm-modal').remove(); + }; + }; wok.message.warn = function(msg, node) { - wok.message(msg, 'warn', node); + "use strict"; + wok.message(msg, 'alert-warning', node); }; wok.message.error = function(msg, node) { - wok.message(msg, 'error', node); + "use strict"; + wok.message(msg, 'alert-danger', node); }; wok.message.error.code = function(code) { - msg = code + ": " + i18n[code] - wok.message(msg, 'error'); + "use strict"; + msg = code + ": " + i18n[code]; + wok.message(msg, 'alert-danger'); }; wok.message.success = function(msg, node) { - wok.message(msg, 'success', node); + "use strict"; + wok.message(msg, 'alert-success', node); }; diff --git a/ui/js/src/wok.window.js b/ui/js/src/wok.window.js index ef00a77..2c2a440 100644 --- a/ui/js/src/wok.window.js +++ b/ui/js/src/wok.window.js @@ -17,11 +17,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -wok.window = (function() { + wok.window = (function() { + "use strict"; var _windows = []; var _listeners = {}; var open = function(settings) { - var settings = jQuery.type(settings) === 'object' ? settings : { + settings = jQuery.type(settings) === 'object' ? settings : { url: settings }; @@ -33,14 +34,15 @@ wok.window = (function() { _windows.push(windowID); _listeners[windowID] = settings['close']; - var windowNode = $('<div></div>', { - id: windowID, - 'class': settings['class'] ? settings['class'] + ' bgmask remove-when-logged-off' : 'bgmask remove-when-logged-off' - }); + var windowNode = $('<div id="'+windowID+'" class="modal-dialog"></div>'); + + $('#modalWindow').modal('show'); - $(windowNode).css(settings['style'] || ''); + $('#modalWindow').on('hidden.bs.modal', function () { + wok.window.close(); + }); - $(windowNode).appendTo('body').on('click', '.window .close', function() { + $(windowNode).appendTo('#modalWindow').on('click', '.window .close', function() { wok.window.close(); }); @@ -53,20 +55,18 @@ wok.window = (function() { }; var close = function() { - var windowID = _windows.pop(); - if(_listeners[windowID]) { - _listeners[windowID](); - _listeners[windowID] = null; - } - delete _listeners[windowID]; - - $('#' + windowID).fadeOut(100, function() { - $(this).remove(); - }); + $('#modalWindow').removeData('bs.modal'); + var windowID = _windows.pop(); + if(_listeners[windowID]) { + _listeners[windowID](); + _listeners[windowID] = null; + } + delete _listeners[windowID]; + $('#' + windowID).remove(); }; return { open: open, close: close }; -})(); +})(); \ No newline at end of file diff --git a/ui/pages/login.html.tmpl b/ui/pages/login.html.tmpl index 2703d02..ee9d107 100644 --- a/ui/pages/login.html.tmpl +++ b/ui/pages/login.html.tmpl @@ -28,95 +28,109 @@ <!DOCTYPE html> <html lang="$lang.lang[0]"> <head> -<meta charset="UTF-8"> -<title>Kimchi</title> -<meta http-equiv="X-UA-Compatible" content="IE=edge"/> -<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" /> -<meta name="apple-mobile-web-app-capable" content="yes"> -<meta name="apple-mobile-web-app-title" content="Wok"> -<link href="images/apple-touch-icon-152.png" sizes="152x152" rel="apple-touch-icon-precomposed"> -<link href="images/apple-touch-icon-144.png" sizes="144x144" rel="apple-touch-icon-precomposed"> -<link href="images/apple-touch-icon-76.png" sizes="76x76" rel="apple-touch-icon-precomposed"> -<link href="images/apple-touch-icon-72.png" sizes="72x72" rel="apple-touch-icon-precomposed"> -<link href="images/apple-touch-icon-180x180.png" sizes="120x120" rel="apple-touch-icon-precomposed"> -<link href="images/apple-touch-icon-114x114.png" sizes="114x114" rel="apple-touch-icon-precomposed"> -<link href="images/apple-touch-icon-57x57.png" sizes="57x57" rel="apple-touch-icon-precomposed"> -<link rel="icon" type="image/png" href="images/android-chrome-192x192.png" sizes="192x192"> -<!--[if IE lte 9]><link rel="shortcut icon" href="images/favicon.ico"><![endif]--> -<link rel="shortcut icon" href="images/favicon.png"> -<meta name="application-name" content="Wok"> -<meta name="msapplication-config" content="none" /> -<meta name="msapplication-TileColor" content="#4f4f4f"/> -<meta name="msapplication-square70x70logo" content="images/tiny.png"/> -<meta name="msapplication-square150x150logo" content="images/square.png"/> -<meta name="msapplication-wide310x150logo" content="images/wide.png"/> -<meta name="msapplication-square310x310logo" content="images/large.png"/> -<link rel="stylesheet" href="$href('libs/jquery-ui/themes/base/jquery-ui.min.css')"> -<link rel="stylesheet" href="$href('css/jquery-ui.custom.css')"> -<link rel="stylesheet" href="$href('css/theme-default.min.css')"> -<script src="$href('libs/jquery/jquery.min.js')"></script> -<script src="$href('libs/jquery-ui/jquery-ui.min.js')"></script> -<script src="$href('libs/jquery-ui/jquery-ui-i18n.min.js')"></script> -<script src="$href('js/wok.min.js')"></script> -<style type="text/css"> -.topbar select { - float: right; - margin-top: 12px; - margin-right: 10px; -} -.login-area { - margin: 120px auto 0; -} -#login-window { - width: 315px; -} -.err-area { - height: auto; - margin-bottom: 10px; -} -.err-mess { - color: #C85305; -} -</style> + <meta charset="UTF-8"> + <title>Kimchi</title> + <meta http-equiv="X-UA-Compatible" content="IE=edge" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" /> + <meta name="apple-mobile-web-app-capable" content="yes"> + <meta name="apple-mobile-web-app-title" content="Wok"> + <link href="images/apple-touch-icon-152.png" sizes="152x152" rel="apple-touch-icon-precomposed"> + <link href="images/apple-touch-icon-144.png" sizes="144x144" rel="apple-touch-icon-precomposed"> + <link href="images/apple-touch-icon-76.png" sizes="76x76" rel="apple-touch-icon-precomposed"> + <link href="images/apple-touch-icon-72.png" sizes="72x72" rel="apple-touch-icon-precomposed"> + <link href="images/apple-touch-icon-180x180.png" sizes="120x120" rel="apple-touch-icon-precomposed"> + <link href="images/apple-touch-icon-114x114.png" sizes="114x114" rel="apple-touch-icon-precomposed"> + <link href="images/apple-touch-icon-57x57.png" sizes="57x57" rel="apple-touch-icon-precomposed"> + <link rel="icon" type="image/png" href="images/android-chrome-192x192.png" sizes="192x192"> + <!--[if IE lte 9]><link rel="shortcut icon" href="images/favicon.ico"><![endif]--> + <link rel="shortcut icon" href="images/favicon.png"> + <meta name="application-name" content="Wok"> + <meta name="msapplication-config" content="none" /> + <meta name="msapplication-TileColor" content="#4f4f4f" /> + <meta name="msapplication-square70x70logo" content="images/tiny.png" /> + <meta name="msapplication-square150x150logo" content="images/square.png" /> + <meta name="msapplication-wide310x150logo" content="images/wide.png" /> + <meta name="msapplication-square310x310logo" content="images/large.png" /> + <link rel="stylesheet" href="$href('libs/jquery-ui/themes/base/jquery-ui.min.css')"> + <link rel="stylesheet" href="$href('css/jquery-ui.custom.css')"> + <link rel="stylesheet" href="$href('css/bootstrap.custom.css')"> + <link rel="stylesheet" href="$href('libs/bootstrap-select/dist/css/bootstrap-select.min.css')"> + <link rel="stylesheet" href="$href('css/fontawesome/fontawesome.css')"> + <link rel="stylesheet" href="$href('css/opensans/opensans.css')"> + <link rel="stylesheet" href="$href('css/bootstrap-select.custom.css')"> + <link rel="stylesheet" href="$href('css/wok.css')"> + <script src="$href('libs/es5-shim/es5-shim.min.js')"></script> + <script src="$href('libs/jquery/jquery.min.js')"></script> + <script src="$href('libs/jquery-ui/jquery-ui.min.js')"></script> + <script src="$href('libs/jquery-ui/jquery-ui-i18n.min.js')"></script> + <script src="$href('libs/jquery-i18n/jquery.i18n.min.js')"></script> + <script src="$href('libs/bootstrap/bootstrap.min.js')"></script> + <script src="$href('libs/bootstrap-select/dist/js/bootstrap-select.min.js')"></script> + <script src="$href('js/wok.min.js')"></script> </head> <body onload="wok.login_main()"> -<div class="container topbar"> - <span id="logo"><img alt="Project Wok" src="images/theme-default/logo-white.png"></span> - <select id="userLang"> - <option value="en_US">English (US)</option> - <option value="zh_CN">中文(简体)</option> - <option value="pt_BR">Português (Brasil)</option> - <option value="de_DE">Deutsch (Deutschland)</option> - <option value="es_ES">Español (España)</option> - <option value="fr_FR">Français (France)</option> - <option value="it_IT">Italiano (Italia)</option> - <option value="ja_JP">日本語 (日本)</option> - <option value="ko_KR">한국어 (대한민국)</option> - <option value="ru_RU">Русский (Россия)</option> - <option value="zh_TW">中文(繁體)</option> - </select> -</div> -<div id="login-window" class="login-area"> - <div class="err-area"> - <div id="messUserPass" class="err-mess" style="display: none;">$_("The username or password you entered is incorrect. Please try again.")</div> - <div id="messSession" class="err-mess" style="display: none;">$_("Session timeout, please re-login.")</div> + <div class="topbar"> + <nav class="navbar navbar-inverse"> + <div class="container"> + <div class="navbar-header"> + <a class="navbar-brand" href="#">Kimchi</a> + </div> + </div> + </nav> + <nav class="navbar navbar-default"> + <div class="container"> + <div class="navbar-header"> + <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#nav-menu" aria-expanded="false"> + <span class="sr-only">Toggle navigation</span> + <span class="icon-bar"><!-- Hamburguer button here --></span> + </button> + </div> + <div class="collapse navbar-collapse" id="nav-menu"> + <ul class="nav navbar-nav"> + <li class="hostname"><span class="host-location"></span></li> + </ul> + </div> + </div> + </nav> </div> - <form id="form-login" class="login-panel" method="post"> - <div class="row"> - <input type="text" id="username" name="username" required="required" placeholder="$_("User Name")" autofocus/> - <div id="username-msg" class="msg-required"></div> + <div class="content"> + <div id="login-window" class="login-area"> + <div class="err-area"> + <div id="messUserPass" class="alert alert-danger" style="display: none;">$_("The username or password you entered is incorrect. Please try again.")</div> + <div id="messSession" class="alert alert-danger" style="display: none;">$_("Session timeout, please re-login.")</div> + </div> + <form id="form-login" class="form-horizontal" method="post"> + <div class="form-group"> + <label for="username" class="sr-only">$_("User Name")</label> + <input type="text" class="form-control" id="username" name="username" required="required" placeholder="$_(" User Name ")" autofocus/> + <div id="username-msg" class="msg-required"></div> + </div> + <div class="form-group"> + <label for="password" class="sr-only">$_("Password")</label> + <input type="password" class="form-control" id="password" name="password" required="required" placeholder="$_(" Password ")" /> + <div id="password-msg" class="msg-required"></div> + </div> + <div class="form-group"> + <button id="btn-login" class="btn btn-login col-md-12 col-lg-12"> + <span id="login">$_("Log in")</span> + <span id="logging" style="display: none;">$_("Logging in...")</span> + </button> + </div> + <select id="userLang" class="selectpicker col-md-12 col-lg-12"> + <option value="en_US">English (US)</option> + <option value="zh_CN">中文(简体)</option> + <option value="pt_BR">Português (Brasil)</option> + <option value="de_DE">Deutsch (Deutschland)</option> + <option value="es_ES">Español (España)</option> + <option value="fr_FR">Français (France)</option> + <option value="it_IT">Italiano (Italia)</option> + <option value="ja_JP">日本語 (日本)</option> + <option value="ko_KR">한국어 (대한민국)</option> + <option value="ru_RU">Русский (Россия)</option> + <option value="zh_TW">中文(繁體)</option> + </select> + </form> </div> - <div class="row"> - <input type="password" id="password" name="password" required="required" placeholder="$_("Password")" /> - <div id="password-msg" class="msg-required"></div> - </div> - <div class="row"> - <button id="btn-login" class="btn-normal-1"> - <label id="login">$_("Log in")</label> - <label id="logging" style="display: none;">$_("Logging in...")</label> - </button> - </div> - </form> -</div> + </div> </body> </html> diff --git a/ui/pages/wok-ui.html.tmpl b/ui/pages/wok-ui.html.tmpl index 669ae29..59a7612 100644 --- a/ui/pages/wok-ui.html.tmpl +++ b/ui/pages/wok-ui.html.tmpl @@ -24,117 +24,134 @@ #silent _ = t.gettext #silent _t = t.gettext #from wok.config import get_version -<!DOCTYPE html> <html lang="$lang.lang[0]"> <head> -<meta charset="UTF-8"> -<title>Kimchi</title> -<meta http-equiv="X-UA-Compatible" content="IE=edge"/> -<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" /> -<meta name="apple-mobile-web-app-capable" content="yes"> -<meta name="apple-mobile-web-app-title" content="Wok"> -<link href="images/apple-touch-icon-152.png" sizes="152x152" rel="apple-touch-icon-precomposed"> -<link href="images/apple-touch-icon-144.png" sizes="144x144" rel="apple-touch-icon-precomposed"> -<link href="images/apple-touch-icon-76.png" sizes="76x76" rel="apple-touch-icon-precomposed"> -<link href="images/apple-touch-icon-72.png" sizes="72x72" rel="apple-touch-icon-precomposed"> -<link href="images/apple-touch-icon-180x180.png" sizes="120x120" rel="apple-touch-icon-precomposed"> -<link href="images/apple-touch-icon-114x114.png" sizes="114x114" rel="apple-touch-icon-precomposed"> -<link href="images/apple-touch-icon-57x57.png" sizes="57x57" rel="apple-touch-icon-precomposed"> -<link rel="icon" type="image/png" href="images/android-chrome-192x192.png" sizes="192x192"> -<!--[if IE lte 9]><link rel="shortcut icon" href="images/favicon.ico"><![endif]--> -<link rel="shortcut icon" href="images/favicon.png"> -<meta name="application-name" content="Wok"> -<meta name="msapplication-config" content="none" /> -<meta name="msapplication-TileColor" content="#4f4f4f"/> -<meta name="msapplication-square70x70logo" content="images/tiny.png"/> -<meta name="msapplication-square150x150logo" content="images/square.png"/> -<meta name="msapplication-wide310x150logo" content="images/wide.png"/> -<meta name="msapplication-square310x310logo" content="images/large.png"/> -<link rel="stylesheet" href="$href('libs/jquery-ui/themes/base/jquery-ui.min.css')"> -<link rel="stylesheet" href="$href('css/jquery-ui.custom.css')"> -<link rel="stylesheet" href="$href('css/theme-default.min.css')"> -<script src="$href('base64/jquery.base64.js')"></script> -<script src="$href('libs/jquery/jquery.min.js')"></script> -<script src="$href('libs/jquery-ui/jquery-ui.min.js')"></script> -<script src="$href('libs/jquery-ui/jquery-ui-i18n.min.js')"></script> -<script src="$href('js/wok.min.js')"></script> + <meta charset="UTF-8"> + <title>Kimchi</title> + <meta http-equiv="X-UA-Compatible" content="IE=edge" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" /> + <meta name="apple-mobile-web-app-capable" content="yes"> + <meta name="apple-mobile-web-app-title" content="Wok"> + <link href="images/apple-touch-icon-152.png" sizes="152x152" rel="apple-touch-icon-precomposed"> + <link href="images/apple-touch-icon-144.png" sizes="144x144" rel="apple-touch-icon-precomposed"> + <link href="images/apple-touch-icon-76.png" sizes="76x76" rel="apple-touch-icon-precomposed"> + <link href="images/apple-touch-icon-72.png" sizes="72x72" rel="apple-touch-icon-precomposed"> + <link href="images/apple-touch-icon-180x180.png" sizes="120x120" rel="apple-touch-icon-precomposed"> + <link href="images/apple-touch-icon-114x114.png" sizes="114x114" rel="apple-touch-icon-precomposed"> + <link href="images/apple-touch-icon-57x57.png" sizes="57x57" rel="apple-touch-icon-precomposed"> + <link rel="icon" type="image/png" href="images/android-chrome-192x192.png" sizes="192x192"> + <!--[if IE lte 9]><link rel="shortcut icon" href="images/favicon.ico"><![endif]--> + <link rel="shortcut icon" href="images/favicon.png"> + <meta name="application-name" content="Wok"> + <meta name="msapplication-config" content="none" /> + <meta name="msapplication-TileColor" content="#4f4f4f" /> + <meta name="msapplication-square70x70logo" content="images/tiny.png" /> + <meta name="msapplication-square150x150logo" content="images/square.png" /> + <meta name="msapplication-wide310x150logo" content="images/wide.png" /> + <meta name="msapplication-square310x310logo" content="images/large.png" /> + <link rel="stylesheet" href="$href('libs/jquery-ui/themes/base/jquery-ui.min.css')"> + <link rel="stylesheet" href="$href('css/jquery-ui.custom.css')"> + <link rel="stylesheet" href="$href('css/bootstrap.custom.css')"> + <link rel="stylesheet" href="$href('libs/bootstrap-select/dist/css/bootstrap-select.min.css')"> + <link rel="stylesheet" href="$href('css/fontawesome/fontawesome.css')"> + <link rel="stylesheet" href="$href('css/opensans/opensans.css')"> + <link rel="stylesheet" href="$href('css/bootstrap-select.custom.css')"> + <link rel="stylesheet" href="$href('css/wok.css')"> + <script src="$href('libs/es5-shim/es5-shim.min.js')"></script> + <script src="$href('libs/jquery/jquery.min.js')"></script> + <script src="$href('libs/jquery-ui/jquery-ui.min.js')"></script> + <script src="$href('libs/jquery-ui/jquery-ui-i18n.min.js')"></script> + <script src="$href('libs/jquery-i18n/jquery.i18n.min.js')"></script> + <script src="$href('libs/bootstrap/bootstrap.min.js')"></script> + <script src="$href('libs/bootstrap-select/dist/js/bootstrap-select.min.js')"></script> + <script src="$href('js/wok.min.js')"></script> + <!-- This is used for detecting if the UI needs to be built --> + <style type="text/css"> + #buildme { + position: fixed; + background: rgba(0, 0, 0, 0.5); + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 10000; + } -<!-- This is used for detecting if the UI needs to be built --> -<style type="text/css"> -#buildme { - position: fixed; - background: rgba(0, 0, 0, 0.5); - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 10000; -} - -#buildme div { - background-color: #FFB2C0; - border-style: solid; - border-color: #FF0000; - padding: 30px; - width: 75%; - margin-left: auto; - margin-right: auto; - margin-top: 50px; - -moz-border-radius: 15px; - border-radius: 15px; -} -</style> -</head> + #buildme div { + background-color: #FFB2C0; + border-style: solid; + border-color: #FF0000; + padding: 30px; + width: 75%; + margin-left: auto; + margin-right: auto; + margin-top: 50px; + -moz-border-radius: 15px; + border-radius: 15px; + } + </style> + </head> <body onload="wok.main()"> -<div class="container"> -<header class="topbar"> - <h1 id="logo"><img alt="Project Wok" src="images/theme-default/logo-white.png"></h1> - <ul class="nav-top"> - <li> - <div id="peers" class="peers hide-content popable"> - <span>$_("Peers")</span> - <span class="arrow"></span> - <div class="dropdown popover right-side"> - <p id="search-peers">$_("Searching")...</p> - <p id="no-peers" class="hide-content">$_("No peers found.")</p> - </div> + <div class="topbar"> + <nav class="navbar navbar-inverse"> + <div class="container"> + <div class="navbar-header"> + <a id="logo" class="navbar-brand" href="#" title="Project Kimchi">Kimchi</a> </div> - </li> - <li> - <div id="user" class="popable"> - <span id="user-icon"></span> - <span id="user-name" class="empty-when-logged-off"></span> - <span class="arrow"></span> - <div class="action-panel popover right-side"> - <a id="btn-help" class="user-menu-item" href="javascript:void(0);">$_("Help")</a> - <br/> - <br/> - <a id="btn-about" class="user-menu-item" href="javascript:void(0);">$_("About")</a> - <br/> - <hr/> - <a id="btn-logout" class="user-menu-item" href="javascript: void(0);">$_("Log out")</a> - </div> + <ul class="nav navbar-nav navbar-right"> + <li class="dropdown hide-content peers" id="peers"> + <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="topbar-text">$_("Peers")</span><span class="caret"></span></a> + <ul class="dropdown-menu"> + <li id="search-peers"><span>$_("Searching")...</span></li> + <li id="no-peers" class="hide-content">$_("No peers found.")</li> + </ul> + </li> + <li class="dropdown" id="user"> + <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"> + <i class="fa fa-user" id="user-icon"></i><span class="topbar-text empty-when-logged-off" id="user-name"></span><span class="caret"></span> + </a> + <ul class="dropdown-menu"> + <li class="critical"><a id="btn-logout" href="javascript: void(0);"><i class="fa fa-ban"></i><span>$_("Log out")</span></a></li> + </ul> + </li> + <li class="dropdown"> + <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><i class="fa fa-question-circle"></i><span class="topbar-text">$_("Help")</span><span class="caret"></span></a> + <ul class="dropdown-menu"> + <li><a id="btn-help" href="javascript: void(0);">$_("Help")</a></li> + <li><a id="btn-about" href="javascript:void(0);">$_("About")</a></li> + </ul> + </li> + </ul> + </div> + </nav> + <nav class="navbar navbar-default"> + <div class="container"> + <div class="navbar-header"> + <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#nav-menu" aria-expanded="false"> + <span class="sr-only">Toggle navigation</span> + <span class="icon-bar"><!-- Hamburguer button here --></span> + </button> </div> - </li> - </ul> -</header> -<div class="content"> - <nav class="navbar"> - <ul id="nav-menu" class="nav-menu"> - <li class="menu-arrow"></li> - </ul> - </nav> - <div id="main"> + <div class="collapse navbar-collapse" id="nav-menu"> + <ul class="nav navbar-nav"> + <li class="hostname"><span class="host-location"></span></li> + </ul> + </div> + </div> + </nav> + </div> + <div class="content"> + <div id="main"> + </div> + </div> </div> -</div> -</div> -<div id="buildme"> - <div><p>Oops! It looks like I am running from a source tree and you forgot to build! + <div id="buildme" style="display:none"> + <div><p>Oops! It looks like I am running from a source tree and you forgot to build! Please run the following command from the wok and kimchi directories and reload this page:</p> - <p><code>make</code></p> + <p><code>make</code></p> + </div> </div> -</div> <script id="about-tmpl" type="wok/template"> <div class="window about-window"> -- 1.9.3

From: samhenri <samuel.guimaraes@eldorado.org.br> Some CSS files are empty to avoid conflicts with next patches and or commits when deleted/moved to gingerbase Signed-off-by: samhenri <samuel.guimaraes@eldorado.org.br> --- src/wok/plugins/kimchi/ui/config/tab-ext.xml | 10 +- .../plugins/kimchi/ui/css/theme-default/host.css | 270 ---------- .../kimchi/ui/css/theme-default/report-add.css | 20 - .../kimchi/ui/css/theme-default/report-rename.css | 22 - .../kimchi/ui/css/theme-default/repository-add.css | 25 - .../ui/css/theme-default/repository-edit.css | 62 --- src/wok/plugins/kimchi/ui/js/src/kimchi.api.js | 39 ++ src/wok/plugins/kimchi/ui/js/src/kimchi.host.js | 598 +++++++++++---------- src/wok/plugins/kimchi/ui/pages/host.html.tmpl | 207 +++---- .../plugins/kimchi/ui/pages/report-add.html.tmpl | 46 +- .../kimchi/ui/pages/report-rename.html.tmpl | 42 +- .../kimchi/ui/pages/repository-add.html.tmpl | 124 ++--- .../kimchi/ui/pages/repository-edit.html.tmpl | 138 ++--- 13 files changed, 571 insertions(+), 1032 deletions(-) diff --git a/src/wok/plugins/kimchi/ui/config/tab-ext.xml b/src/wok/plugins/kimchi/ui/config/tab-ext.xml index ee88c88..b2a842b 100644 --- a/src/wok/plugins/kimchi/ui/config/tab-ext.xml +++ b/src/wok/plugins/kimchi/ui/config/tab-ext.xml @@ -3,35 +3,35 @@ <tab> <access role="admin" mode="admin"/> <access role="user" mode="none"/> - + <class>host</class> <title>Host</title> <path>plugins/kimchi/host.html</path> </tab> <tab> <access role="admin" mode="admin"/> <access role="user" mode="byInstance"/> - + <class>guests</class> <title>Guests</title> <path>plugins/kimchi/guests.html</path> </tab> <tab> <access role="admin" mode="admin"/> <access role="user" mode="none"/> - + <class>templates</class> <title>Templates</title> <path>plugins/kimchi/templates.html</path> </tab> <tab> <access role="admin" mode="admin"/> <access role="user" mode="read-only"/> - + <class>storage</class> <title>Storage</title> <path>plugins/kimchi/storage.html</path> </tab> <tab> <access role="admin" mode="admin"/> <access role="user" mode="read-only"/> - + <class>network</class> <title>Network</title> <path>plugins/kimchi/network.html</path> </tab> diff --git a/src/wok/plugins/kimchi/ui/css/theme-default/host.css b/src/wok/plugins/kimchi/ui/css/theme-default/host.css index a0cccb1..bb693cc 100644 --- a/src/wok/plugins/kimchi/ui/css/theme-default/host.css +++ b/src/wok/plugins/kimchi/ui/css/theme-default/host.css @@ -15,273 +15,3 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -.host-panel { - font-size: 12px; - margin-bottom: 100px; -} - -.host-panel .logo-container, .host-panel .info-container, -.host-panel .section-label, .host-panel .section-value { - display: inline-block; - vertical-align: top; -} - -.host-panel .section-label { - display: inline-block; - margin-right: 1em; - vertical-align: top; -} - -.host-panel .logo { - background: url("plugins/kimchi/images/icon-vm.png") no-repeat left top; - height: 128px; - width: 128px; -} - -.host-panel .hostname { - text-decoration: underline; -} - -.host-panel .action-panel { - margin-top: 2em; - padding-left: 10px; -} - -.host-panel .button-icon { - background: url("../images/theme-default/host-icon-sprite.png") no-repeat - left top; - display: inline-block; - height: 12px; - width: 12px; -} - -.host-panel .action-icon-stop { - background-position: -14px 0; -} - -.host-panel .action-icon-restart { - background-position: -28px 0; -} - -.host-panel .action-icon-download { - background-position: -42px 0; -} - -.host-panel .action-icon-connect { - background-position: -56px 0; -} - -.host-panel .action-icon-add { - background-position: -70px 0; -} - -.host-panel .action-icon-edit { - background-position: -84px 0; -} - -.host-panel .action-icon-remove { - background-position: -98px 0; -} - -.host-panel button:disabled .action-icon-start { - background-position: 0 -14px; -} - -.host-panel button:disabled .action-icon-stop { - background-position: -14px -14px; -} - -.host-panel button:disabled .action-icon-restart { - background-position: -28px -14px; -} - -.host-panel button:disabled .action-icon-download { - background-position: -42px -14px; -} - -.host-panel button:disabled .action-icon-connect { - background-position: -56px -14px; -} - -.host-panel button:disabled .action-icon-add { - background-position: -70px -14px; -} - -.host-panel button:disabled .action-icon-edit { - background-position: -84px -14px; -} - -.host-panel button:disabled .action-icon-remove { - background-position: -98px -14px; -} - -.host-panel .info-container { - padding-top: 16px; - width: 890px; -} - -.host-panel .section-header { - background: #EEE; - border-radius: 5px; - cursor: pointer; - line-height: 2em; - margin: 1em 0 1em; - padding-left: 6px; -} - -.host-panel .section-header:hover { - background: #06f; - color: white; -} - -.host-panel .section-content { - padding-left: 1em; -} - -.host-panel .section-header .arrow { - border-color: transparent; - border-style: solid; - display: inline-block; - margin-right: 6px; - width: 0; -} - -.host-panel .section-header[aria-expanded="true"] .arrow { - border-top-color: black; - border-width: 8px 4px 0; - border-bottom: none; -} - -.host-panel .section-header[aria-expanded="true"]:hover .arrow { - border-top-color: white; -} - -.host-panel .section-header[aria-expanded="false"] .arrow { - border-left-color: black; - border-right: none; - border-width: 4px 0 4px 8px; -} - -.host-panel .section-header[aria-expanded="false"]:hover .arrow { - border-left-color: white; -} - -.host-panel .section-row { - line-height: 1.6em; - margin-bottom: 1em; -} - -.host-panel .section-label { - width: 100px; -} - -#frequency-textbox { - width: 20px; -} - -#container-chart-cpu, -#container-chart-memory, -#container-chart-disk-io, -#container-chart-network-io { - border: 1px solid white; - box-shadow: 2px 2px 2px gray, 2px -2px 2px gray, -2px -2px 2px gray, -2px - 2px 2px gray; - height: 100px; - width: 500px; -} - -#container-chart-disk-io .disk-write, -#container-chart-network-io .network-sent { - stroke: #f80; -} - -/* Debug Report */ -.cell-text-wrapper { - margin-left: 10px; -} - -.host-panel #available-reports-grid { - border-color: #ddd; - height: 400px; - width: 850px; -} - -.host-panel select#available-reports-list { - width: 300px; -} - -.host-panel select#available-reports-list option { - margin: .2em 1em; -} - -.debug-report-name, -.debug-report-time { - width: 424px; -} - -#id-debug-img { - background: url(../images/theme-default/kimchi-loading15x15.gif) 12px - center no-repeat; - padding-left: 23px; -} - -/* End of Debug Report */ - -/* Software Updates */ -.host-panel #software-updates-grid { - border-color: #ddd; - height: 300px; - width: 850px; -} - -.software-update-name, -.software-update-repos { - width: 224px; -} - -.software-update-version, -.software-update-arch { - width: 200px; -} - -.host-panel #software-updates-progress-textarea { - border: 1px solid #ddd; - box-sizing: border-box; - height: 100px; - padding: .2em .5em; - resize: vertical; - width: 852px; -} -/* End of Software Updates */ - -/* Repository */ -.host-panel #repositories-grid { - border-color: #ddd; - height: 200px; - width: 850px; -} - -.host-panel #repositories-grid .repository-id { - width: 120px; -} - -.host-panel #repositories-grid .repository-name { - width: 640px; -} - -.host-panel #repositories-grid .repository-enabled { - width: 88px; -} - -.host-panel #repositories-grid .repository-baseurl.deb { - width: 400px; -} - -.host-panel #repositories-grid .repository-enabled.deb { - width: 100px; -} - -.host-panel #repositories-grid .repository-gpgcheck.deb { - width: 150px; -} -/* End of Repository */ diff --git a/src/wok/plugins/kimchi/ui/css/theme-default/report-add.css b/src/wok/plugins/kimchi/ui/css/theme-default/report-add.css index 8020182..3769daa 100644 --- a/src/wok/plugins/kimchi/ui/css/theme-default/report-add.css +++ b/src/wok/plugins/kimchi/ui/css/theme-default/report-add.css @@ -15,23 +15,3 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#report-add-window { - height: 300px; - width: 400px; -} - -#report-add-window .field { - font-size: 12px; -} - -#report-name-textbox { - margin: 0; - width: 100%; -} - -.info-add-debug-report { - font-size: 12px; - color: #999999; - font-weight: lighter; - font-family: 'Helvetica Neue', Helvetica, Arial; -} \ No newline at end of file diff --git a/src/wok/plugins/kimchi/ui/css/theme-default/report-rename.css b/src/wok/plugins/kimchi/ui/css/theme-default/report-rename.css index 2fb2698..2d9e4a2 100644 --- a/src/wok/plugins/kimchi/ui/css/theme-default/report-rename.css +++ b/src/wok/plugins/kimchi/ui/css/theme-default/report-rename.css @@ -15,25 +15,3 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#report-rename-window { - height: 300px; - width: 400px; -} - -#report-rename-window .field { - font-size: 12px; -} - -#report-name-textbox { - -moz-box-sizing: border-box; - box-sizing: border-box; - margin: 0; - width: 100%; -} - -.info-debug-report-rename { - font-size: 12px; - color: #999999; - font-weight: lighter; - font-family: 'Helvetica Neue', Helvetica, Arial; -} diff --git a/src/wok/plugins/kimchi/ui/css/theme-default/repository-add.css b/src/wok/plugins/kimchi/ui/css/theme-default/repository-add.css index 4344569..2d9e4a2 100644 --- a/src/wok/plugins/kimchi/ui/css/theme-default/repository-add.css +++ b/src/wok/plugins/kimchi/ui/css/theme-default/repository-add.css @@ -15,28 +15,3 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#repository-add-window { - height: 500px; - width: 1000px; -} - -#repository-add-window span.required { - color: red; - padding-left: 5px; - vertical-align: top; -} - -#repository-add-window .textbox-wrapper input[type="text"] { - box-sizing: border-box; - width: 100%; -} - -#repository-add-window .textbox-wrapper label { - vertical-align: middle; -} - -#isMirrorLabel { - font-size: 14px; - font-weight: lighter; - font-family: 'Helvetica Neue', Helvetica, Arial; -} \ No newline at end of file diff --git a/src/wok/plugins/kimchi/ui/css/theme-default/repository-edit.css b/src/wok/plugins/kimchi/ui/css/theme-default/repository-edit.css index 383a7fe..d50bbc1 100644 --- a/src/wok/plugins/kimchi/ui/css/theme-default/repository-edit.css +++ b/src/wok/plugins/kimchi/ui/css/theme-default/repository-edit.css @@ -15,68 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -.yum div#repository-edit-window { - height: 680px; - width: 1000px; -} - -.deb div#repository-edit-window { - height: 480px; - width: 1000px; -} - - -.repository-edit-fieldset { - float: left; - padding: 0 30px; - width: 95%; -} - -.repository-edit-wrapper-label, .repository-edit-wrapper-controls { - display: inline-block; - height: 30px; - line-height: 30px; - font-size: 14px; - vertical-align: top; -} - -.repository-edit-wrapper-label { - margin-top: 10px; - width: 150px; -} - -.repository-edit-wrapper-controls label { - vertical-align: middle; -} - -.repository-edit-wrapper-controls { - width: 100%; -} - -.repository-edit-wrapper-controls input[type="text"] { - font-size: 16px; - height: 30px; - line-height: 30px; - padding: 0 10px; - width: 100%; - -moz-box-sizing: border-box; - box-sizing: border-box; - border: 1px solid #CCCCCC; -} - - -.repository-edit-wrapper-controls input[type="text"][readonly] { - color: #bbb; - background-color: #fafafa; -} - - -.repository-edit-wrapper-controls input[type="text"][disabled] { - color: #bbb; - background-color: #fafafa; - cursor: not-allowed; -} - .deb .yum{ display: none; diff --git a/src/wok/plugins/kimchi/ui/js/src/kimchi.api.js b/src/wok/plugins/kimchi/ui/js/src/kimchi.api.js index c82d040..f5839f1 100644 --- a/src/wok/plugins/kimchi/ui/js/src/kimchi.api.js +++ b/src/wok/plugins/kimchi/ui/js/src/kimchi.api.js @@ -884,6 +884,45 @@ var kimchi = { }); }, + tailSoftwareUpdateLogs : function(suc, err, progress) { + var taskID = -1; + var onResponse = function(data) { + taskID = data['id']; + trackTask(); + }; + + var trackTask = function() { + kimchi.getTask(taskID, onTaskResponse, err); + }; + + var onTaskResponse = function(result) { + var taskStatus = result['status']; + switch(taskStatus) { + case 'running': + progress && progress(result); + setTimeout(function() { + trackTask(); + }, 1000); + break; + case 'finished': + case 'failed': + suc(result); + break; + default: + break; + } + }; + + wok.requestJSON({ + url : 'plugins/kimchi/host/taillogs', + type : "POST", + contentType : "application/json", + dataType : "json", + success : onResponse, + error : err + }); + }, + updateSoftware : function(suc, err, progress) { var taskID = -1; var onResponse = function(data) { diff --git a/src/wok/plugins/kimchi/ui/js/src/kimchi.host.js b/src/wok/plugins/kimchi/ui/js/src/kimchi.host.js index c3765dc..654df2e 100644 --- a/src/wok/plugins/kimchi/ui/js/src/kimchi.host.js +++ b/src/wok/plugins/kimchi/ui/js/src/kimchi.host.js @@ -15,87 +15,92 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -kimchi.host={}; +kimchi.host = {}; kimchi.host_main = function() { - var expand = function(header, toExpand) { - var controlledNode = $(header).attr('aria-controls'); - $('#' + controlledNode)[toExpand ? 'removeClass' : 'addClass']('hidden'); - $(header).attr('aria-expanded', toExpand ? 'true' : 'false'); - }; - + "use strict"; var repositoriesGrid = null; var initRepositoriesGrid = function(repo_type) { - var gridFields=[]; - if (repo_type == "yum") { - gridFields=[{ - name: 'repo_id', - label: i18n['KCHREPO6004M'], - 'class': 'repository-id' - }, { - name: 'config[display_repo_name]', - label: i18n['KCHREPO6005M'], - 'class': 'repository-name' - }, { - name: 'enabled', - label: i18n['KCHREPO6009M'], - 'class': 'repository-enabled' - }]; - } - else if (repo_type == "deb") { - gridFields=[{ - name: 'baseurl', - label: i18n['KCHREPO6006M'], - makeTitle: true, - 'class': 'repository-baseurl deb' - }, { - name: 'enabled', - label: i18n['KCHREPO6009M'], - 'class': 'repository-enabled deb' - }, { - name: 'config[dist]', - label: "dist", - 'class': 'repository-gpgcheck deb' - }, { - name: 'config[comps]', - label: "comps", - 'class': 'repository-gpgcheck deb' - }]; - } - else { - gridFields=[{ + var gridFields = []; + if (repo_type === "yum") { + gridFields = [{ name: 'repo_id', label: i18n['KCHREPO6004M'], - 'class': 'repository-id' - }, { - name: 'enabled', - label: i18n['KCHREPO6009M'], - 'class': 'repository-enabled' - }, { - name: 'baseurl', - label: i18n['KCHREPO6006M'], - makeTitle: true, - 'class': 'repository-baseurl' - }]; + 'class': 'repository-id', + type: 'name' + }, { + name: 'config[display_repo_name]', + label: i18n['KCHREPO6005M'], + 'class': 'repository-name', + type: 'description' + }, { + name: 'enabled', + label: i18n['KCHREPO6009M'], + 'class': 'repository-enabled', + type: 'status' + }]; + } else if (repo_type === "deb") { + gridFields = [{ + name: 'baseurl', + label: i18n['KCHREPO6006M'], + makeTitle: true, + 'class': 'repository-baseurl deb', + type: 'description' + }, { + name: 'enabled', + label: i18n['KCHREPO6009M'], + 'class': 'repository-enabled deb', + type: 'status' + }, { + name: 'config[dist]', + label: "dist", + 'class': 'repository-gpgcheck deb' + }, { + name: 'config[comps]', + label: "comps", + 'class': 'repository-gpgcheck deb' + }]; + } else { + gridFields = [{ + name: 'repo_id', + label: i18n['KCHREPO6004M'], + 'class': 'repository-id', + type: 'name' + }, { + name: 'enabled', + label: i18n['KCHREPO6009M'], + 'class': 'repository-enabled', + type: 'status' + }, { + name: 'baseurl', + label: i18n['KCHREPO6006M'], + makeTitle: true, + 'class': 'repository-baseurl', + type: 'description' + }]; } - repositoriesGrid = new wok.widget.Grid({ + repositoriesGrid = new wok.widget.List({ container: 'repositories-grid-container', id: 'repositories-grid', title: i18n['KCHREPO6003M'], toolbarButtons: [{ id: 'repositories-grid-add-button', label: i18n['KCHREPO6012M'], + class: 'fa fa-plus-circle', onClick: function(event) { - wok.window.open({url:'plugins/kimchi/repository-add.html', - class: repo_type}); + wok.window.open({ + url: 'plugins/kimchi/repository-add.html', + class: repo_type + }); } }, { id: 'repositories-grid-enable-button', label: i18n['KCHREPO6016M'], + class: 'fa fa-play-circle-o', disabled: true, onClick: function(event) { var repository = repositoriesGrid.getSelected(); - if(!repository) { + if (!repository) { return; } var name = repository['repo_id']; @@ -108,31 +113,36 @@ kimchi.host_main = function() { }, { id: 'repositories-grid-edit-button', label: i18n['KCHREPO6013M'], + class: 'fa fa-pencil', disabled: true, onClick: function(event) { var repository = repositoriesGrid.getSelected(); - if(!repository) { + if (!repository) { return; } kimchi.selectedRepository = repository['repo_id']; - wok.window.open({url:'plugins/kimchi/repository-edit.html', - class: repo_type}); + wok.window.open({ + url: 'plugins/kimchi/repository-edit.html', + class: repo_type + }); } }, { id: 'repositories-grid-remove-button', label: i18n['KCHREPO6014M'], + class: 'fa fa-minus-circle', + critical: true, disabled: true, onClick: function(event) { var repository = repositoriesGrid.getSelected(); - if(!repository) { + if (!repository) { return; } var settings = { - title : i18n['KCHREPO6001M'], - content : i18n['KCHREPO6002M'], - confirm : i18n['KCHAPI6004M'], - cancel : i18n['KCHAPI6003M'] + title: i18n['KCHREPO6001M'], + content: i18n['KCHREPO6002M'], + confirm: i18n['KCHAPI6004M'], + cancel: i18n['KCHAPI6003M'] }; wok.confirm(settings, function() { @@ -140,15 +150,15 @@ kimchi.host_main = function() { repository['repo_id'], function(result) { wok.topic('kimchi/repositoryDeleted').publish(result); - }, function(error) { - } + }, + function(error) {} ); }); } }], onRowSelected: function(row) { var repository = repositoriesGrid.getSelected(); - if(!repository) { + if (!repository) { return; } $('#repositories-grid-remove-button').prop('disabled', false); @@ -166,28 +176,26 @@ kimchi.host_main = function() { var listRepositories = function(gridCallback) { kimchi.listRepositories(function(repositories) { - if($.isFunction(gridCallback)) { - gridCallback(repositories); - } - else { - if(repositoriesGrid) { - repositoriesGrid.setData(repositories); - } - else { - initRepositoriesGrid(); - repositoriesGrid.setData(repositories); + if ($.isFunction(gridCallback)) { + gridCallback(repositories); + } else { + if (repositoriesGrid) { + repositoriesGrid.setData(repositories); + } else { + initRepositoriesGrid(); + repositoriesGrid.setData(repositories); + } } - } - }, - function(error) { - var message = error && error['responseJSON'] && error['responseJSON']['reason']; + }, + function(error) { + var message = error && error['responseJSON'] && error['responseJSON']['reason']; - if($.isFunction(gridCallback)) { - gridCallback([]); - } - repositoriesGrid && - repositoriesGrid.showMessage(message || i18n['KCHUPD6008M']); - }); + if ($.isFunction(gridCallback)) { + gridCallback([]); + } + repositoriesGrid && + repositoriesGrid.showMessage(message || i18n['KCHUPD6008M']); + }); $('#repositories-grid-remove-button').prop('disabled', true); $('#repositories-grid-edit-button').prop('disabled', true); @@ -258,16 +266,32 @@ kimchi.host_main = function() { }); }; + var startSoftwareUpdateProgress = function() { + var progressArea = $('#' + progressAreaID)[0]; + $('#software-updates-progress-container').removeClass('hidden'); + $(progressArea).text(''); + !wok.isElementInViewport(progressArea) && + progressArea.scrollIntoView(); + + kimchi.tailSoftwareUpdateLogs(function(result) { + reloadProgressArea(result); + wok.topic('kimchi/softwareUpdated').publish({ + result: result + }); + wok.message.warn(i18n['KCHUPD6010M']); + }, function(error) { + wok.message.error(i18n['KCHUPD6011M']); + }, reloadProgressArea); + }; + var listSoftwareUpdates = function(gridCallback) { kimchi.listSoftwareUpdates(function(softwareUpdates) { - if($.isFunction(gridCallback)) { + if ($.isFunction(gridCallback)) { gridCallback(softwareUpdates); - } - else { - if(softwareUpdatesGrid) { + } else { + if (softwareUpdatesGrid) { softwareUpdatesGrid.setData(softwareUpdates); - } - else { + } else { initSoftwareUpdatesGrid(softwareUpdates); } } @@ -276,7 +300,18 @@ kimchi.host_main = function() { $(updateButton).prop('disabled', softwareUpdates.length === 0); }, function(error) { var message = error && error['responseJSON'] && error['responseJSON']['reason']; - if($.isFunction(gridCallback)) { + + // cannot get the list of packages because there is another + // package manager instance running, so follow that instance updates + if (message.indexOf("KCHPKGUPD0005E") !== -1) { + startSoftwareUpdateProgress(); + if ($.isFunction(gridCallback)) { + gridCallback([]); + } + return; + } + + if ($.isFunction(gridCallback)) { gridCallback([]); } softwareUpdatesGrid && @@ -296,23 +331,25 @@ kimchi.host_main = function() { }); }; var initReportGrid = function(reports) { - reportGrid = new wok.widget.Grid({ + reportGrid = new wok.widget.List({ container: 'available-reports-grid-container', id: reportGridID, title: i18n['KCHDR6002M'], toolbarButtons: [{ id: reportGridID + '-generate-button', + class: 'fa fa-plus-circle', label: i18n['KCHDR6006M'], onClick: function(event) { wok.window.open('plugins/kimchi/report-add.html'); } }, { id: reportGridID + '-rename-button', + class: 'fa fa-pencil', label: i18n['KCHDR6008M'], disabled: true, onClick: function(event) { var report = reportGrid.getSelected(); - if(!report) { + if (!report) { return; } @@ -320,20 +357,37 @@ kimchi.host_main = function() { wok.window.open('plugins/kimchi/report-rename.html'); } }, { + id: reportGridID + '-download-button', + label: i18n['KCHDR6010M'], + class: 'fa fa-download', + disabled: true, + onClick: function(event) { + var report = reportGrid.getSelected(); + if (!report) { + return; + } + + kimchi.downloadReport({ + file: report['uri'] + }); + } + }, { id: reportGridID + '-remove-button', + class: 'fa fa-minus-circle', label: i18n['KCHDR6009M'], + critical: true, disabled: true, onClick: function(event) { var report = reportGrid.getSelected(); - if(!report) { + if (!report) { return; } var settings = { - title : i18n['KCHAPI6004M'], - content : i18n['KCHDR6001M'], - confirm : i18n['KCHAPI6002M'], - cancel : i18n['KCHAPI6003M'] + title: i18n['KCHAPI6004M'], + content: i18n['KCHDR6001M'], + confirm: i18n['KCHAPI6002M'], + cancel: i18n['KCHAPI6003M'] }; wok.confirm(settings, function() { @@ -342,36 +396,21 @@ kimchi.host_main = function() { }, function(result) { listDebugReports(); }, function(error) { - wok.message.error(error.responseJSON.reason); + wok.message.error(error.responseJSON.reason); }); }); } - }, { - id: reportGridID + '-download-button', - label: i18n['KCHDR6010M'], - disabled: true, - onClick: function(event) { - var report = reportGrid.getSelected(); - if(!report) { - return; - } - - kimchi.downloadReport({ - file: report['uri'] - }); - } }], onRowSelected: function(row) { var report = reportGrid.getSelected(); // Only enable report buttons if the selected line is not a // pending report - if (report['time'] == i18n['KCHDR6007M']) { - var gridElement = $('#'+ reportGridID); + if (report['time'] === i18n['KCHDR6007M']) { + var gridElement = $('#' + reportGridID); var row = $('tr:contains(' + report['name'] + ')', gridElement); enableReportButtons(false); row.attr('class', ''); - } - else { + } else { enableReportButtons(true); } }, @@ -379,26 +418,31 @@ kimchi.host_main = function() { fields: [{ name: 'name', label: i18n['KCHDR6003M'], - 'class': 'debug-report-name' + 'class': 'debug-report-name', + type: 'name' }, { name: 'time', label: i18n['KCHDR6005M'], - 'class': 'debug-report-time' + 'class': 'debug-report-time', + type: 'description' }], data: reports }); }; var getPendingReports = function() { - var reports = [] - var filter = 'status=running&target_uri=' + encodeURIComponent('^/plugins/kimchi/debugreports/*') + var reports = []; + var filter = 'status=running&target_uri=' + encodeURIComponent('^/plugins/kimchi/debugreports/*'); kimchi.getTasksByFilter(filter, function(tasks) { - for(var i = 0; i < tasks.length; i++) { + for (var i = 0; i < tasks.length; i++) { reportName = tasks[i].target_uri.replace(/^\/plugins\/kimchi\/debugreports\//, '') || i18n['KCHDR6012M']; - reports.push({'name': reportName, 'time': i18n['KCHDR6007M']}) + reports.push({ + 'name': reportName, + 'time': i18n['KCHDR6007M'] + }); - if(kimchi.trackingTasks.indexOf(tasks[i].id) >= 0) { + if (kimchi.trackingTasks.indexOf(tasks[i].id) >= 0) { continue; } @@ -424,29 +468,28 @@ kimchi.host_main = function() { var listDebugReports = function() { kimchi.listReports(function(reports) { - pendingReports = getPendingReports(); - allReports = pendingReports.concat(reports); + var pendingReports = getPendingReports(); + var allReports = pendingReports.concat(reports); $('#debug-report-section').removeClass('hidden'); // Row selection will be cleared so disable buttons here enableReportButtons(false); - if(reportGrid) { + if (reportGrid) { reportGrid.setData(allReports); - } - else { + } else { initReportGrid(allReports); } // Set id-debug-img to pending reports // It will display a loading icon var gridElement = $('#' + reportGridID); - $.each($('td:contains(' + i18n['KCHDR6007M'] + ')', gridElement), function(index, row) { + $.each($('td:contains(' + i18n['KCHDR6007M'] + ')', gridElement), function(index, row) { $(row).parent().addClass('no-hover'); $(row).attr('id', 'id-debug-img'); }); }, function(error) { - if(error['status'] == 403) { + if (error['status'] === 403) { $('#debug-report-section').addClass('hidden'); return; } @@ -458,10 +501,9 @@ kimchi.host_main = function() { var restartButtonID = '#host-button-restart'; var shutdownHost = function(params) { var settings = { - title : i18n['KCHAPI6004M'], - content : i18n['KCHHOST6008M'], - confirm : i18n['KCHAPI6002M'], - cancel : i18n['KCHAPI6003M'] + content: i18n['KCHHOST6008M'], + confirm: i18n['KCHAPI6002M'], + cancel: i18n['KCHAPI6003M'] }; wok.confirm(settings, function() { @@ -470,8 +512,8 @@ kimchi.host_main = function() { $(restartButtonID).prop('disabled', true); // Check if there is any VM is running. kimchi.listVMs(function(vms) { - for(var i = 0; i < vms.length; i++) { - if(vms[i]['state'] === 'running') { + for (var i = 0; i < vms.length; i++) { + if (vms[i]['state'] === 'running') { wok.message.error.code('KCHHOST6001E'); $(shutdownButtonID).prop('disabled', false); $(restartButtonID).prop('disabled', false); @@ -480,39 +522,30 @@ kimchi.host_main = function() { } }); - }, function() { - }); + }, function() {}); }; var initPage = function() { - $('#host-info-container .section-header').each(function(i, header) { - $('<span class="arrow"></span>').prependTo(header); - var toExpand = $(header).attr('aria-expanded') !== 'false'; - expand(header, toExpand); - }); - - $('#host-info-container').on('click', '.section-header', function(event) { - var toExpand = $(this).attr('aria-expanded') === 'false'; - expand(this, toExpand); - }); $('#host-button-shutdown').on('click', function(event) { + event.preventDefault(); shutdownHost(null); }); $('#host-button-restart').on('click', function(event) { + event.preventDefault(); shutdownHost({ reboot: true }); }); var setupUI = function() { - if (kimchi.capabilities == undefined) { + if (kimchi.capabilities === undefined) { setTimeout(setupUI, 2000); return; } - if((kimchi.capabilities['repo_mngt_tool']) && (kimchi.capabilities['repo_mngt_tool']!="None")) { + if ((kimchi.capabilities['repo_mngt_tool']) && (kimchi.capabilities['repo_mngt_tool'] !== "None")) { initRepositoriesGrid(kimchi.capabilities['repo_mngt_tool']); $('#repositories-section').switchClass('hidden', kimchi.capabilities['repo_mngt_tool']); wok.topic('kimchi/repositoryAdded') @@ -523,7 +556,7 @@ kimchi.host_main = function() { .subscribe(listRepositories); } - if(kimchi.capabilities['update_tool']) { + if (kimchi.capabilities['update_tool']) { $('#software-update-section').removeClass('hidden'); initSoftwareUpdatesGrid(); wok.topic('kimchi/softwareUpdated') @@ -533,7 +566,7 @@ kimchi.host_main = function() { }); } - if(kimchi.capabilities['system_report_tool']) { + if (kimchi.capabilities['system_report_tool']) { listDebugReports(); wok.topic('kimchi/debugReportAdded') .subscribe(listDebugReports); @@ -576,40 +609,40 @@ kimchi.host_main = function() { } }, diskIO: { - r: { + w: { type: 'value', base: 2, fixed: 2, unit: 'B/s', - legend: i18n['KCHHOST6004M'], + legend: i18n['KCHHOST6005M'], + 'class': 'disk-write', points: [] }, - w: { + r: { type: 'value', base: 2, fixed: 2, unit: 'B/s', - legend: i18n['KCHHOST6005M'], - 'class': 'disk-write', + legend: i18n['KCHHOST6004M'], points: [] } }, networkIO: { - r: { + s: { type: 'value', base: 2, fixed: 2, unit: 'B/s', - legend: i18n['KCHHOST6006M'], + legend: i18n['KCHHOST6007M'], + 'class': 'network-sent', points: [] }, - s: { + r: { type: 'value', base: 2, fixed: 2, unit: 'B/s', - legend: i18n['KCHHOST6007M'], - 'class': 'network-sent', + legend: i18n['KCHHOST6006M'], points: [] } } @@ -618,38 +651,36 @@ kimchi.host_main = function() { var cursor = SIZE; var add = function(stats) { - for(var key in stats) { + for (var key in stats) { var item = stats[key]; - for(var metrics in item) { + for (var metrics in item) { var value = item[metrics]['v']; var max = item[metrics]['max']; var unifiedMetrics = statsArray[key][metrics]; var ps = unifiedMetrics['points']; - if(!Array.isArray(value)){ + if (!Array.isArray(value)) { ps.push(value); - if(ps.length > SIZE + 1) { + if (ps.length > SIZE + 1) { ps.shift(); } + } else { + ps = ps.concat(value); + ps.splice(0, ps.length - SIZE - 1); + unifiedMetrics['points'] = ps; } - else{ - ps=ps.concat(value); - ps.splice(0, ps.length-SIZE-1); - unifiedMetrics['points']=ps; - } - if(max !== undefined) { + if (max !== undefined) { unifiedMetrics['max'] = max; - } - else { - if(unifiedMetrics['type'] !== 'value') { + } else { + if (unifiedMetrics['type'] !== 'value') { continue; } max = -Infinity; $.each(ps, function(i, value) { - if(value > max) { + if (value > max) { max = value; } }); - if(max === 0) { + if (max === 0) { ++max; } max *= 1.1; @@ -663,7 +694,7 @@ kimchi.host_main = function() { var get = function(which) { var stats = statsArray[which]; var lines = []; - for(var k in stats) { + for (var k in stats) { var obj = stats[k]; var line = { type: obj['type'], @@ -672,10 +703,10 @@ kimchi.host_main = function() { fixed: obj['fixed'], legend: obj['legend'] }; - if(obj['max']) { + if (obj['max']) { line['max'] = obj['max']; } - if(obj['class']) { + if (obj['class']) { line['class'] = obj['class']; } var ps = obj['points']; @@ -700,104 +731,102 @@ kimchi.host_main = function() { }; var Tracker = function(charts) { - var charts = charts; - var timer = null; - var statsPool = new StatsMgr(); - var setCharts = function(newCharts) { - charts = newCharts; - for(var key in charts) { - var chart = charts[key]; - chart.updateUI(statsPool.get(key)); - } - }; - - var self = this; - - var UnifyStats = function(stats) { - var result= { - cpu: { - u: { - v: stats['cpu_utilization'] - } - }, - memory: { - u: { - } - }, - diskIO: { - r: { - v: stats['disk_read_rate'] - }, - w: { - v: stats['disk_write_rate'] - } - }, - networkIO: { - r: { - v: stats['net_recv_rate'] - }, - s: { - v: stats['net_sent_rate'] - } - } - }; - if(Array.isArray(stats['memory'])){ - result.memory.u['v']=[]; - result.memory.u['max']=-Infinity; - for(var i=0;i<stats['memory'].length;i++){ - result.memory.u['v'].push(stats['memory'][i]['avail']); - result.memory.u['max']=Math.max(result.memory.u['max'],stats['memory'][i]['total']); - } - } - else { - result.memory.u['v']=stats['memory']['avail'], - result.memory.u['max']=stats['memory']['total'] - } - return(result); - }; - - - var statsCallback = function(stats) { - var unifiedStats = UnifyStats(stats); - statsPool.add(unifiedStats); - for(var key in charts) { - var chart = charts[key]; - chart.updateUI(statsPool.get(key)); - } - timer = setTimeout(function() { - continueTrack(); - }, 1000); - }; - - var track = function() { - kimchi.getHostStatsHistory(statsCallback, - function() { - continueTrack(); - }); - }; + var charts = charts; + var timer = null; + var statsPool = new StatsMgr(); + var setCharts = function(newCharts) { + charts = newCharts; + for (var key in charts) { + var chart = charts[key]; + chart.updateUI(statsPool.get(key)); + } + }; + + var self = this; + + var UnifyStats = function(stats) { + var result = { + cpu: { + u: { + v: stats['cpu_utilization'] + } + }, + memory: { + u: {} + }, + diskIO: { + w: { + v: stats['disk_write_rate'] + }, + r: { + v: stats['disk_read_rate'] + } + }, + networkIO: { + s: { + v: stats['net_sent_rate'] + }, + r: { + v: stats['net_recv_rate'] + } + } + }; + if (Array.isArray(stats['memory'])) { + result.memory.u['v'] = []; + result.memory.u['max'] = -Infinity; + for (var i = 0; i < stats['memory'].length; i++) { + result.memory.u['v'].push(stats['memory'][i]['avail']); + result.memory.u['max'] = Math.max(result.memory.u['max'], stats['memory'][i]['total']); + } + } else { + result.memory.u['v'] = stats['memory']['avail'], + result.memory.u['max'] = stats['memory']['total'] + } + return (result); + }; - var continueTrack = function() { - kimchi.getHostStats(statsCallback, - function() { + + var statsCallback = function(stats) { + var unifiedStats = UnifyStats(stats); + statsPool.add(unifiedStats); + for (var key in charts) { + var chart = charts[key]; + chart.updateUI(statsPool.get(key)); + } + timer = setTimeout(function() { continueTrack(); - }); - }; - - var destroy = function() { - timer && clearTimeout(timer); - timer = null; - }; - - return { - setCharts: setCharts, - start: track, - stop: destroy - }; + }, 1000); + }; + + var track = function() { + kimchi.getHostStatsHistory(statsCallback, + function() { + continueTrack(); + }); + }; + + var continueTrack = function() { + kimchi.getHostStats(statsCallback, + function() { + continueTrack(); + }); + }; + + var destroy = function() { + timer && clearTimeout(timer); + timer = null; + }; + + return { + setCharts: setCharts, + start: track, + stop: destroy + }; }; var initTracker = function() { // TODO: Extend tabs with onUnload event to unregister timers. - if(kimchi.hostTimer) { + if (kimchi.hostTimer) { kimchi.hostTimer.stop(); delete kimchi.hostTimer; } @@ -825,20 +854,19 @@ kimchi.host_main = function() { }) }; - if(kimchi.hostTimer) { + if (kimchi.hostTimer) { kimchi.hostTimer.setCharts(trackedCharts); - } - else { + } else { kimchi.hostTimer = new Tracker(trackedCharts); kimchi.hostTimer.start(); } }; $('#host-root-container').on('remove', function() { - if(kimchi.hostTimer) { + if (kimchi.hostTimer) { kimchi.hostTimer.stop(); delete kimchi.hostTimer; - } + } repositoriesGrid && repositoriesGrid.destroy(); wok.topic('kimchi/repositoryAdded') diff --git a/src/wok/plugins/kimchi/ui/pages/host.html.tmpl b/src/wok/plugins/kimchi/ui/pages/host.html.tmpl index d87debc..3c6eda8 100644 --- a/src/wok/plugins/kimchi/ui/pages/host.html.tmpl +++ b/src/wok/plugins/kimchi/ui/pages/host.html.tmpl @@ -23,153 +23,124 @@ #silent _ = t.gettext #silent _t = t.gettext <!DOCTYPE html> -<html> +<html> <head> <link rel="stylesheet" href="plugins/kimchi/css/theme-default.min.css"> <script src="plugins/kimchi/js/kimchi.min.js"></script> </head> <body> <div id="host-root-container"> - <div class="toolbar"> - <div class="tools"> - </div> +<nav class="navbar navbar-default toolbar"> + <div class="container"> + <!-- Brand and toggle get grouped for better mobile display --> + <div class="navbar-header"> + <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#toolbar" aria-expanded="false"> + <span class="sr-only">Toggle navigation</span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </button> + </div> + + <!-- Collect the nav links, forms, and other content for toggling --> + <div class="collapse navbar-collapse" id="toolbar"> + <ul class="nav navbar-nav navbar-right tools"> + <li><a id="host-button-restart" href="javascript:void(0);"><i class="fa fa-refresh"></i><span>$_("Restart")</span></a></li> + <li><a id="host-button-shutdown" href="javascript:void(0);"><i class="fa fa-ban"></i><span>$_("Shut down")</span></a></li> + <!-- <li><a href="javascript:void(0);"><i class="fa fa-desktop"></i><span>$_("Connect")</span></a></li> --> + </ul> </div> + </div> +</nav> <div id="host-content-container" class="empty-when-logged-off"></div> </div> <script id="host-tmpl" type="kimchi/template"> - <div class="host-panel"> - <div class="logo-container"> - <div class="logo" style="background-image: url({logo});"></div> - </div> - <div id="host-info-container" class="info-container"> - <h2 class="hostname">{hostname}</h2> - <div class="action-panel"> - <button id="host-button-shutdown" class="btn-normal-1 stop"> - <div class="button-icon action-icon-stop"></div> - $_("Shut down") - </button> - <button id="host-button-restart" class="btn-normal-1 restart"> - <div class="button-icon action-icon-restart"></div> - $_("Restart") - </button> - <button class="btn-normal-1 connect" disabled="disabled"> - <div class="button-icon action-icon-connect"></div> - $_("Connect") - </button> - </div> - <div class="host-section"> - <h3 class="section-header" - aria-expanded="false" - aria-controls="content-sys-info"> - $_("Basic Information") - </h3> - <div id="content-sys-info" class="section-content"> - <div class="section-row"> - <div class="section-label">$_("OS Distro")</div> - <div class="section-value">{os_distro}</div> - </div> - <div class="section-row"> - <div class="section-label">$_("OS Version")</div> - <div class="section-value">{os_version}</div> - </div> - <div class="section-row"> - <div class="section-label">$_("OS Code Name")</div> - <div class="section-value">{os_codename}</div> - </div> - <div class="section-row"> - <div class="section-label">$_("Processor")</div> - <div class="section-value">{cpu_model}</div> - </div> - <div class="section-row"> - <div class="section-label">$_("CPU(s)")</div> - <div class="section-value">{cpus}</div> - </div> - <div class="section-row"> - <div class="section-label">$_("Memory")</div> - <div class="section-value">{memory}</div> +<div class="host-dashboard"> + <div class="container"> + <div id="alert-container"></div> + <div id="content-sys-statistics" class="row"> + <div class="col-md-3"> + <div id="cpu-dashboard"> + <h3 class="section-label">$_("CPU")</h3> + <div class="section-value"> + <div id="container-chart-cpu" class="inline-block"></div> </div> </div> </div> - <div class="host-section"> - <h3 class="section-header" - aria-controls="content-sys-statistics"> - $_("System Statistics") - </h3> - <div id="content-sys-statistics" class="section-content"> - <div class="section-row"> - <div class="section-label">$_("CPU")</div> - <div class="section-value"> - <div id="container-chart-cpu" class="inline-block"></div> - </div> - </div> - <div class="section-row"> - <div class="section-label">$_("Memory")</div> - <div class="section-value"> - <div id="container-chart-memory" class="inline-block"></div> - </div> - </div> - <div class="section-row"> - <div class="section-label">$_("Disk I/O")</div> - <div class="section-value"> - <div id="container-chart-disk-io" class="inline-block"></div> - </div> - </div> - <div class="section-row"> - <div class="section-label">$_("Network I/O")</div> - <div class="section-value"> - <div id="container-chart-network-io" class="inline-block"></div> - </div> + <div class="col-md-3"> + <div id="memory-dashboard"> + <h3 class="section-label">$_("Memory")</h3> + <div class="section-value"> + <div id="container-chart-memory" class="inline-block"></div> </div> </div> </div> - <div id="software-update-section" class="host-section hidden"> - <h3 class="section-header" - aria-controls="content-software-update"> - $_("Software Updates") - </h3> - <div id="content-software-update" class="section-content"> - <div class="section-row"> - <div class="section-value"> - <div id="software-updates-grid-container"></div> - <div id="software-updates-progress-container" class="hidden"> - <label for="software-updates-progress-textarea">$_("Update Progress")</label> - <textarea id="software-updates-progress-textarea" readonly></textarea> - </div> - </div> + <div class="col-md-3"> + <div id="disk-dashboard"> + <h3 class="section-label">$_("Disk I/O")</h3> + <div class="section-value"> + <div id="container-chart-disk-io" class="inline-block"></div> </div> </div> </div> - <div id="repositories-section" class="host-section hidden"> - <h3 class="section-header" - aria-controls="content-repositories"> - $_("Repositories") - </h3> - <div id="content-repositories" class="section-content"> - <div class="section-row"> - <div class="section-value"> - <div id="repositories-grid-container"></div> - </div> + <div class="col-md-3"> + <div id="network-dashboard"> + <h3 class="section-label">$_("Network I/O")</h3> + <div class="section-value"> + <div id="container-chart-network-io" class="inline-block"></div> </div> </div> </div> - <div id="debug-report-section" class="host-section hidden"> - <h3 class="section-header" - aria-controls="content-sys-reports"> - $_("Debug Reports") - </h3> - <div id="content-sys-reports" class="section-content"> - <div class="section-row"> - <div class="section-value"> - <div id="available-reports-grid-container"></div> - </div> + </div> + </div> +</div> +<div class="host-panel"> + <div class="container"> + <div id="host-info-container" class="row"> + <div id="content-sys-info" class="panel panel-default col-md-4"> + <div class="panel-heading"> + <h3 class="panel-title">$_("Basic Information")</h3> + </div> + <div class="panel-body"> + <dl class="basic-information-list"> + <dt>{os_distro}</dt> + <dd>$_("OS Distro")</dd> + <dt>{os_version}</dt> + <dd>$_("OS Version")</dd> + <dt>{os_codename}</dt> + <dd>$_("OS Code Name")</dd> + <dt>{cpu_model}</dt> + <dd>$_("Processor")</dd> + <dt>{cpus}</dt> + <dd>$_("CPU(s)")</dd> + <dt>{memory}</dt> + <dd>$_("Memory")</dd> + </dl> + </div> + </div> + <div id="repositories-grid-container" class="col-md-4"></div> + <div id="available-reports-grid-container" class="col-md-4"></div> + </div> + <div class="row"> + <div id="software-update-section" class="panel panel-default col-md-12"> + <div class="panel-heading"> + <h3 class="panel-title">$_("Software Updates")</h3> + </div> + <div id="content-software-update" class="panel panel-default"> + <div id="software-updates-grid-container"></div> + <div id="software-updates-progress-container" class="hidden"> + <label for="software-updates-progress-textarea">$_("Update Progress")</label> + <textarea id="software-updates-progress-textarea" readonly></textarea> </div> </div> </div> </div> </div> +</div> </script> - +<div id="modalWindow" class="modal fade host-modal" tabindex="-1" role="dialog" aria-labelledby="hostsModalLabel" aria-hidden="true"> +</div> <script type="text/javascript"> kimchi.host_main(); </script> diff --git a/src/wok/plugins/kimchi/ui/pages/report-add.html.tmpl b/src/wok/plugins/kimchi/ui/pages/report-add.html.tmpl index 25bf0a9..8d6fb38 100644 --- a/src/wok/plugins/kimchi/ui/pages/report-add.html.tmpl +++ b/src/wok/plugins/kimchi/ui/pages/report-add.html.tmpl @@ -22,35 +22,25 @@ #silent _ = t.gettext #silent _t = t.gettext <!DOCTYPE html> -<div id="report-add-window" class="window"> - <header> - <h1 class="title h1 grey">$_("Generate a New Debug Report")</h1> - </header> - <div class="content"> - <form id="form-report-add"> - <section class="form-section"> - <h2> - <label for="report-name-textbox">$_("Report Name")</label> - </h2> - <div class="field"> - <input type="text" class="text" id="report-name-textbox" name="name" /> - <span class="icon-info-circled light-grey c1"></span> - <span class="info-add-debug-report"> - $_("The name used to identify the report. If omitted, a name will be chosen based on current time. Name can contain: letters, digits, underscore (\"_\") and hyphen (\"-\").") - </span> - </div> - </section> - </form> - </div> - <footer> - <div class="btn-group"> - <button id="button-report-add" class="btn-normal"><span class="text">$_("Generate")</span></button> - <button id="button-report-cancel" class="btn-normal close" type="button"> - <span calss="text">$_("Cancel")</span> - </button> +<div class="modal-content"> + <div class="modal-header"> + <h4 class="modal-title">$_("Generate a New Debug Report")</h4> + </div> + <div class="modal-body"> + <form id="form-report-add"> + <div class="form-group"> + <label for="report-name-textbox">$_("Report Name")</label> + <input type="text" class="form-control" id="report-name-textbox" name="name" /> + <p class="help-block"><i class="fa fa-info-circle"></i> $_("The name used to identify the report. If omitted, a name will be chosen based on current time. Name can contain: letters, digits, underscore (\"_\") and hyphen (\"-\").") + </p> </div> - </footer> + </form> + </div> + <div class="modal-footer"> + <button type="button" id="button-report-add" class="btn btn-default" data-dismiss="modal">$_("Generate")</button> + <button type="button" id="button-report-cancel" class="btn btn-default" data-dismiss="modal">$_("Cancel")</button> + </div> </div> <script> kimchi.report_add_main(); -</script> +</script> \ No newline at end of file diff --git a/src/wok/plugins/kimchi/ui/pages/report-rename.html.tmpl b/src/wok/plugins/kimchi/ui/pages/report-rename.html.tmpl index 90a0a80..f89da19 100644 --- a/src/wok/plugins/kimchi/ui/pages/report-rename.html.tmpl +++ b/src/wok/plugins/kimchi/ui/pages/report-rename.html.tmpl @@ -22,35 +22,27 @@ #silent _ = t.gettext #silent _t = t.gettext <!DOCTYPE html> -<div id="report-rename-window" class="window"> - <header> - <h1 class="title h1 grey">$_("Rename a Debug Report")</h1> - </header> - <div class="content"> +<div class="modal-content"> + <div class="modal-header"> + <h4 class="modal-title">$_("Rename a Debug Report")</h4> + </div> + <div class="modal-body"> <form id="form-report-rename"> - <section class="form-section"> - <h2> - <label for="report-name-textbox">$_("Report Name")</label> - </h2> - <div class="field"> - <input type="text" class="text" id="report-name-textbox" name="name" /> - <span class="icon-info-circled light-grey c1"></span> - <span class="info-debug-report-rename"> - $_("The name used to identify the report. Name can contain: letters, digits and hyphen (\"-\").") - </span> - </div> - </section> + <div class="form-group"> + <label for="report-name-textbox">$_("Report Name")</label> + <input type="text" class="form-control" id="report-name-textbox" name="name" /> + <p class="help-block"><i class="fa fa-info-circle"></i> $_("The name used to identify the report. Name can contain: letters, digits and hyphen (\"-\").") + </p> + </div> </form> </div> - <footer> - <div class="btn-group"> - <button id="button-report-rename" class="btn-normal"><span class="text">$_("Submit")</span></button> - <button id-"button-report-rename-cancel" class="btn-normal close" type="button"> - <span class="text">$_("Cancel")</span> - </button> - </div> - </footer> + <div class="modal-footer"> + <button type="button" id="button-report-rename" class="btn btn-default" data-dismiss="modal">$_("Submit")</button> + <button type="button" id- "button-report-rename-cancel" class="btn btn-default" type="button" data-dismiss="modal">$_("Cancel") + </button> + </div> </div> <script> kimchi.report_rename_main(); </script> + \ No newline at end of file diff --git a/src/wok/plugins/kimchi/ui/pages/repository-add.html.tmpl b/src/wok/plugins/kimchi/ui/pages/repository-add.html.tmpl index 950252a..6da8c05 100644 --- a/src/wok/plugins/kimchi/ui/pages/repository-add.html.tmpl +++ b/src/wok/plugins/kimchi/ui/pages/repository-add.html.tmpl @@ -21,93 +21,51 @@ #silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) #silent _ = t.gettext #silent _t = t.gettext -<div id="repository-add-window" class="window"> - <form id="form-repository-add"> - <header class="window-header"> - <h1 class="title h1 grey">$_("Add a Repository")</h1> - </header> - <section> - <div class="content"> - <div class="form-section yum"> - <h2>$_("Identifier")</h2> - <div class="field"> - <div class="textbox-wrapper"> - <input type="text" class="text" name="repo_id" /> - </div> - <div class="icon-info-circled light-grey c1 help-inline"></div> - <p class="text-help help-inline"> - $_("Single word, unique identifier for the repository.") +<div class="modal-content"> + <div class="modal-header"> + <h4 class="modal-title">$_("Add a Repository")</h4> + </div> + <div class="modal-body"> + <form id="form-repository-add"> + <div class="form-group yum"> + <label for="repo_id">$_("Identifier")</label> + <input type="text" class="form-control" name="repo_id" /> + <p class="help-block"><i class="fa fa-info-circle"></i> $_("Single word, unique identifier for the repository.") </p> - </div> </div> - <section class="form-section yum"> - <h2>$_("Name")</h2> - <div class="field"> - <div class="textbox-wrapper"> - <input type="text" class="text" name="config[repo_name]" /> - </div> - <div class="icon-info-circled light-grey c1 help-inline"></div> - <p class="text-help help-inline"> - $_("Textual name for the repository.") + <div class="form-group yum"> + <label for="repo_name">$_("Name")</label> + <input type="text" class="form-control" id="repo_name" name="config[repo_name]" /> + <p class="help-block"><i class="fa fa-info-circle"></i> $_("Textual name for the repository.") </p> - </div> - </section> - <section class="form-section"> - <h2>$_("URL")<span class="required" role="presentation" title='$_("Required Field")'>*</span></h2> - <div class="field"> - <div class="textbox-wrapper"> - <input type="text" class="text required" name="baseurl" /> - </div> - <div class="icon-info-circled light-grey c1 help-inline"></div> - <p class="text-help help-inline"> - $_("URL to the repository. Supported protocols are http, ftp, and file.") - </p> - </div> - <div class="field yum"> - <p class="yum"> - <input type="checkbox" name="isMirror" value="true" id="isMirror" /> - <label id="isMirrorLabel" for="isMirror">$_("Repository is a mirror")</label> - </p> - </div> - </section> - <section class="form-section repository-dist deb"> - <h2>$_("Distribution")</h2> - <div class="field"> - <div class="textbox-wrapper"> - <input type="text" class="text" name="config[dist]" /> - </div> - <div class="icon-info-circled light-grey c1 help-inline"></div> - <p class="text-help help-inline"> - $_("Distribution of the DEB repository.") - </p> - </div> - </section> - <section class="form-section repository-comps deb"> - <h2>$_("Components")</h2> - <div class="field"> - <div class="textbox-wrapper"> - <input type="text" class="text" name="config[comps]" /> - </div> - <div class="icon-info-circled light-grey c1 help-inline"></div> - <p class="text-help help-inline"> - $_("List of components in DEB repository.") - </p> - </div> - </section> - </div> - </section> - <footer> - <div class="btn-group"> - <button type="submit" id="button-repository-add" class="btn-normal" disabled="disabled"> - <span class="text">$_("Add")</span> - </button> - <button type="button" id="button-repository-close" class="btn-normal close"> - <span class="text">$("Cancel")</span> - </button> - </div> - </footer> - </form> + </div> + <div class="form-group"> + <label for="baseurl">$_("URL")<span class="required" role="presentation" title='$_("Required Field")'>*</span></label> + <input type="text" class="form-control required" id="baseurl" name="baseurl" /> + <p class="help-block"><i class="fa fa-info-circle"></i> $_("URL to the repository. Supported protocols are http, ftp, and file.")</p> + </div> + <div class="checkbox yum"> + <label id="isMirrorLabel" for="isMirror"> + <input type="checkbox" name="isMirror" value="true" id="isMirror" /> $_("Repository is a mirror")</label> + </div> + <div class="form-group repository-dist deb"> + <label>$_("Distribution")</label> + <input type="text" class="form-control" name="config[dist]" /> + <p class="help-block"><i class="fa fa-info-circle"></i> $_("Distribution of the DEB repository.")</p> + </div> + <div class="form-group repository-comps deb"> + <label>$_("Components")</label> + <input type="text" class="form-control" name="config[comps]" /> + <p class="help-block"><i class="fa fa-info-circle"></i> $_("List of components in DEB repository.")</p> + </div> + </form> + </div> + <div class="modal-footer"> + <button type="submit" id="button-repository-add" class="btn btn-default" disabled="disabled">$_("Add")</button> + <button type="button" id="button-repository-close" data-dismiss="modal" class="btn btn-default">$("Cancel")</button> + </div> </div> <script> kimchi.repository_add_main(); </script> + \ No newline at end of file diff --git a/src/wok/plugins/kimchi/ui/pages/repository-edit.html.tmpl b/src/wok/plugins/kimchi/ui/pages/repository-edit.html.tmpl index e5a3cfb..33e5eee 100644 --- a/src/wok/plugins/kimchi/ui/pages/repository-edit.html.tmpl +++ b/src/wok/plugins/kimchi/ui/pages/repository-edit.html.tmpl @@ -21,97 +21,57 @@ #silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) #silent _ = t.gettext #silent _t = t.gettext - -<div id="repository-edit-window" class="window"> - <form id="form-repository-edit"> - <header> - <h1 class="title h1 grey">$_("Edit Repository")</h1> - </header> - <div class="content"> - <section id="form-repository-edit"> - <fieldset class="repository-edit-fieldset"> - <div class="repository-id yum"> - <div class="repository-edit-wrapper-label"> - <label for="repository-edit-id-textbox">$_("ID")</label> - </div> - <div class="repository-edit-wrapper-controls"> - <input id="repository-edit-id-textbox" name="repo_id" type="text" disabled="disabled" readonly="readonly"/> - </div> - </div> - <div class="repository-name yum"> - <div class="repository-edit-wrapper-label"> - <label for="repository-edit-name-textbox">$_("Name")</label> - </div> - <div class="repository-edit-wrapper-controls"> - <input id="repository-edit-name-textbox" class="yum" name="config[repo_name]" type="text" /> - </div> - </div> - <div class="repository-url"> - <div class="repository-edit-wrapper-label"> - <label for="repository-edit-baseurl-textbox">$_("URL")</label> - </div> - <div class="repository-edit-wrapper-controls"> - <input id="repository-edit-baseurl-textbox" name="baseurl" type="text" /> - </div> - </div> - <div class="repository-dist deb"> - <div class="repository-edit-wrapper-label"> - <label for="repository-edit-urlargs-textbox">$_("Distribution")</label> - </div> - <div class="repository-edit-wrapper-controls"> - <input id="repository-edit-urlargs-textbox" class="deb" name="config[dist]" type="text" /> - </div> - </div> - <div class="repository-mirrorlist yum"> - <div class="repository-edit-wrapper-label"> - <label for="repository-edit-urlargs-textbox">$_("Mirror List URL")</label> - </div> - <div class="repository-edit-wrapper-controls"> - <input id="repository-edit-urlargs-textbox" class="yum" name="config[mirrorlist]" type="text" /> - </div> - </div> - <div class="repository-comps deb"> - <div class="repository-edit-wrapper-label"> - <label for="repository-edit-urlargs-textbox">$_("Components")</label> - </div> - <div class="repository-edit-wrapper-controls"> - <input id="repository-edit-urlargs-textbox" class="deb" name="config[comps]" type="text" /> - </div> - </div> - <div class="repository-gpgkey yum"> - <div class="repository-edit-wrapper-label"> - <label for="repository-edit-gpgkey-textbox">$_("GPG Key")</label> - </div> - <div class="repository-edit-wrapper-controls"> - <input id="repository-edit-gpgkey-textbox" class="yum" name="config[gpgkey]" type="text" /> - </div> - </div> - <div class="repository-gpgcheck yum"> - <div class="repository-edit-wrapper-label"> - <label>$_("GPG Check")</label> - </div> - <div class="repository-edit-wrapper-controls"> - <input id="repository-edit-gpgcheck-radio-true" class="yum" name="config[gpgcheck]" type="radio" value="true" /> - <label for="repository-edit-gpgcheck-radio-true">$_("Yes")</label> - <input id="repository-edit-gpgcheck-radio-false" class="yum" name="config[gpgcheck]" type="radio" value="false" /> - <label for="repository-edit-gpgcheck-radio-false">$_("No")</label> - </div> - </div> - </fieldset> - </section> - </div> - <footer> - <div class="btn-group"> - <button type="submit" id="repository-edit-button-save" class="btn-normal"> - <span class="text">$_("Save")</span> - </button> - <button type="button" id="repository-edit-button-cancel" class="close btn-normal"> - <span class="text">$_("Cancel")</span> - </button> +<div class="modal-content"> + <div class="modal-header"> + <h4 class="modal-title">$_("Edit Repository")</h4> + </div> + <div class="modal-body"> + <form id="form-repository-edit"> + <div class="form-group repository-id yum"> + <label for="repository-edit-id-textbox">$_("ID")</label> + <input id="repository-edit-id-textbox" class="form-control" name="repo_id" type="text" disabled="disabled" readonly="readonly" /> </div> - </footer> - </form> + <div class="form-group repository-name yum"> + <label for="repository-edit-name-textbox">$_("Name")</label> + <input id="repository-edit-name-textbox" class="form-control yum" name="config[repo_name]" type="text" /> + </div> + <div class="form-group repository-url"> + <label for="repository-edit-baseurl-textbox">$_("URL")</label> + <input id="repository-edit-baseurl-textbox" class="form-control" name="baseurl" type="text" /> + </div> + <div class="form-group repository-dist deb"> + <label for="repository-edit-urlargs-textbox">$_("Distribution")</label> + <input id="repository-edit-urlargs-textbox" class="form-control deb" name="config[dist]" type="text" /> + </div> + <div class="form-group repository-mirrorlist yum"> + <label for="repository-edit-urlargs-textbox">$_("Mirror List URL")</label> + <input id="repository-edit-urlargs-textbox" class="form-control yum" name="config[mirrorlist]" type="text" /> + </div> + <div class="form-group repository-comps deb"> + <label for="repository-edit-urlargs-textbox">$_("Components")</label> + <input id="repository-edit-urlargs-textbox" class="form-control deb" name="config[comps]" type="text" /> + </div> + <div class="form-group repository-gpgkey yum"> + <label for="repository-edit-gpgkey-textbox">$_("GPG Key")</label> + <input id="repository-edit-gpgkey-textbox" class="form-control yum" name="config[gpgkey]" type="text" /> + </div> + <div class="form-group repository-gpgcheck yum"> + <label>$_("GPG Check")</label> + <label for="repository-edit-gpgcheck-radio-true" class="radio inline control-label"> + <input id="repository-edit-gpgcheck-radio-true" class="yum" name="config[gpgcheck]" type="radio" value="true" /> $_("Yes") + </label> + <label for="repository-edit-gpgcheck-radio-false" class="radio inline control-label"> + <input id="repository-edit-gpgcheck-radio-false" class="yum" name="config[gpgcheck]" type="radio" value="false" /> $_("No") + </label> + </div> + </form> + </div> + <div class="modal-footer"> + <button type="submit" id="repository-edit-button-save" class="btn btn-default">$_("Save")</button> + <button type="button" id="repository-edit-button-cancel" class="btn btn-default">$_("Cancel")</button> + </div> </div> <script type="text/javascript"> kimchi.repository_edit_main(); </script> + \ No newline at end of file -- 1.9.3
participants (1)
-
sguimaraes943@gmail.com