mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
Fix bug where the loading indicator was wider than the screen (#8854)
* Fix bug where the loading indicator was wider than the screen, allowing you to drag a dashboard panel very wide and break the UI. * Refactor kbnLoadingIndicator to be a standalone component. * Make loadingIndicator fixed position so it doesn't disrupt the layout when it appears and disappears. * Uncouple from .spinner styles. * Set a max-width on it. * Rename Common PageObject getSpinnerDone method to isGlobalLoadingIndicatorHidden.
This commit is contained in:
parent
25e995eb60
commit
59d65fd672
18 changed files with 114 additions and 86 deletions
|
@ -3,8 +3,7 @@ import expect from 'expect.js';
|
|||
import uiModules from 'ui/modules';
|
||||
import $ from 'jquery';
|
||||
|
||||
import '../directives/kbn_loading_indicator';
|
||||
|
||||
import '../directives/loading_indicator/loading_indicator';
|
||||
|
||||
describe('kbnLoadingIndicator', function () {
|
||||
let compile;
|
||||
|
@ -14,23 +13,24 @@ describe('kbnLoadingIndicator', function () {
|
|||
ngMock.inject(function ($compile, $rootScope) {
|
||||
compile = function (hasActiveConnections) {
|
||||
$rootScope.chrome = {
|
||||
httpActive: (hasActiveConnections ? [1] : [])
|
||||
httpActive: hasActiveConnections ? [1] : []
|
||||
};
|
||||
const $el = $('<kbn-loading-indicator></kbn-loading-indicator>');
|
||||
$rootScope.$apply();
|
||||
$compile($el)($rootScope);
|
||||
$rootScope.$apply();
|
||||
return $el;
|
||||
};
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('injects a loading .spinner into the element', function () {
|
||||
const $el = compile();
|
||||
expect($el.find('.spinner')).to.have.length(1);
|
||||
it(`doesn't have ng-hide class when there are connections`, function () {
|
||||
const $el = compile(true);
|
||||
expect($el.hasClass('ng-hide')).to.be(false);
|
||||
});
|
||||
it('applies removes ng-hide class when there are connections', function () {
|
||||
const $el = compile(true);
|
||||
expect($el.find('.spinner.ng-hide')).to.have.length(0);
|
||||
|
||||
it('has ng-hide class when there are no connections', function () {
|
||||
const $el = compile(false);
|
||||
expect($el.hasClass('ng-hide')).to.be(true);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@ import './global_nav';
|
|||
|
||||
import kbnChromeProv from './kbn_chrome';
|
||||
import kbnChromeNavControlsProv from './append_nav_controls';
|
||||
import './kbn_loading_indicator';
|
||||
import './loading_indicator/loading_indicator';
|
||||
|
||||
export default function (chrome, internals) {
|
||||
kbnChromeProv(chrome, internals);
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<div
|
||||
class="loadingIndicator"
|
||||
ng-show="chrome.httpActive.length"
|
||||
data-test-subj="globalLoadingIndicator"
|
||||
>
|
||||
<div class="loadingIndicator__bar"></div>
|
||||
</div>
|
|
@ -1,13 +1,14 @@
|
|||
import UiModules from 'ui/modules';
|
||||
import angular from 'angular';
|
||||
|
||||
const spinnerTemplate = '<div class="spinner" ng-show="chrome.httpActive.length"><div class="spinner-bar"></div></div>';
|
||||
import template from './loading_indicator.html';
|
||||
import './loading_indicator.less';
|
||||
|
||||
UiModules
|
||||
.get('ui/kibana')
|
||||
.directive('kbnLoadingIndicator', function ($compile) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
template: spinnerTemplate,
|
||||
replace: true,
|
||||
template,
|
||||
};
|
||||
});
|
|
@ -0,0 +1,53 @@
|
|||
@import "~ui/styles/variables";
|
||||
|
||||
@loadingIndicatorBackgroundSize: 400px;
|
||||
@loadingIndicatorHeight: 2px;
|
||||
@loadingIndcatorColor1: @kibanaPink1;
|
||||
@loadingIndcatorColor2: @kibanaPink2;
|
||||
|
||||
/**
|
||||
* 1. Position this loader on top of the content.
|
||||
* 2. Make sure indicator isn't wider than the screen.
|
||||
*/
|
||||
.loadingIndicator {
|
||||
position: fixed; // 1
|
||||
top: 0; // 1
|
||||
left: 0; // 1
|
||||
right: 0; // 1
|
||||
z-index: 1; // 1
|
||||
overflow: hidden; // 2
|
||||
height: @loadingIndicatorHeight;
|
||||
|
||||
&.ng-hide {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition-delay: 0.25s;
|
||||
}
|
||||
}
|
||||
|
||||
.loadingIndicator__bar {
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
visibility: visible;
|
||||
display: block;
|
||||
animation: animate-loading-indcator 2s linear infinite;
|
||||
background-color: @kibanaPink2;
|
||||
background-image: linear-gradient(to right,
|
||||
@loadingIndcatorColor1 0%,
|
||||
@loadingIndcatorColor1 50%,
|
||||
@loadingIndcatorColor2 50%,
|
||||
@loadingIndcatorColor2 100%
|
||||
);
|
||||
background-repeat: repeat-x;
|
||||
background-size: @loadingIndicatorBackgroundSize @loadingIndicatorBackgroundSize;
|
||||
width: 200%;
|
||||
}
|
||||
|
||||
@keyframes animate-loading-indcator {
|
||||
from { transform: translateX(0); }
|
||||
to { transform: translateX(-@loadingIndicatorBackgroundSize); }
|
||||
}
|
|
@ -1,39 +1,6 @@
|
|||
@import "~ui/styles/variables";
|
||||
|
||||
@size: 400px;
|
||||
@color1: @kibanaPink1;
|
||||
@color2: @kibanaPink2;
|
||||
|
||||
.spinner.ng-hide {
|
||||
visibility: hidden;
|
||||
display: block !important;
|
||||
opacity: 0;
|
||||
transition-delay: 0.25s;
|
||||
}
|
||||
|
||||
.spinner-bar {
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
visibility: visible;
|
||||
display: block;
|
||||
animation: move 2s linear infinite;
|
||||
background-color: @kibanaPink2;
|
||||
background-image: linear-gradient(to right,
|
||||
@color1 0%,
|
||||
@color1 50%,
|
||||
@color2 50%,
|
||||
@color2 100%
|
||||
);
|
||||
background-repeat: repeat-x;
|
||||
background-size: @size @size;
|
||||
width: 200%;
|
||||
}
|
||||
|
||||
@keyframes move {
|
||||
from { transform: translateX(0); }
|
||||
to { transform: translateX(-@size); }
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ bdd.describe('dashboard tab', function describeIndexTests() {
|
|||
PageObjects.common.debug('Set absolute time range from \"' + fromTime + '\" to \"' + toTime + '\"');
|
||||
return PageObjects.header.setAbsoluteRange(fromTime, toTime)
|
||||
.then(function () {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
})
|
||||
.then(function takeScreenshot() {
|
||||
PageObjects.common.saveScreenshot('Dashboard-set-timepicker');
|
||||
|
|
|
@ -53,9 +53,9 @@ bdd.describe('visualize app', function describeIndexTests() {
|
|||
.then(function clickGo() {
|
||||
return PageObjects.visualize.clickGo();
|
||||
})
|
||||
.then(function getSpinnerDone() {
|
||||
.then(function isGlobalLoadingIndicatorHidden() {
|
||||
PageObjects.common.debug('Waiting...');
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ bdd.describe('visualize app', function describeIndexTests() {
|
|||
return PageObjects.visualize.clickGo();
|
||||
})
|
||||
.then(function () {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ bdd.describe('visualize app', function describeIndexTests() {
|
|||
return PageObjects.visualize.clickGo();
|
||||
})
|
||||
.then(function () {
|
||||
return PageObjects.header.getSpinnerDone(); // only matches the hidden spinner
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ bdd.describe('visualize app', function describeIndexTests() {
|
|||
return PageObjects.visualize.selectField('memory');
|
||||
})
|
||||
.then(function () {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
})
|
||||
.then(function sleep() {
|
||||
return PageObjects.common.sleep(1003);
|
||||
|
@ -53,7 +53,7 @@ bdd.describe('visualize app', function describeIndexTests() {
|
|||
return PageObjects.visualize.clickGo();
|
||||
})
|
||||
.then(function () {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ bdd.describe('visualize app', function describeIndexTests() {
|
|||
return PageObjects.visualize.clickGo();
|
||||
})
|
||||
.then(function () {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ bdd.describe('visualize app', function describeIndexTests() {
|
|||
return PageObjects.visualize.clickGo();
|
||||
})
|
||||
.then(function () {
|
||||
return PageObjects.header.getSpinnerDone(); // only matches the hidden spinner
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
})
|
||||
.then(function waitForVisualization() {
|
||||
return PageObjects.visualize.waitForVisualization();
|
||||
|
@ -66,7 +66,7 @@ bdd.describe('visualize app', function describeIndexTests() {
|
|||
return PageObjects.visualize.loadSavedVisualization(vizName1);
|
||||
})
|
||||
.then(function () {
|
||||
return PageObjects.header.getSpinnerDone(); // only matches the hidden spinner
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
})
|
||||
.then(function waitForVisualization() {
|
||||
return PageObjects.visualize.waitForVisualization();
|
||||
|
|
|
@ -74,7 +74,7 @@ export default class DashboardPage {
|
|||
.findByCssSelector('[aria-label="Save Dashboard"]')
|
||||
.click()
|
||||
.then(() => {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
})
|
||||
.then(() => {
|
||||
return PageObjects.common.sleep(1000);
|
||||
|
@ -86,7 +86,7 @@ export default class DashboardPage {
|
|||
.type(dashName);
|
||||
})
|
||||
.then(() => {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
})
|
||||
.then(() => {
|
||||
return PageObjects.common.sleep(1000);
|
||||
|
@ -101,7 +101,7 @@ export default class DashboardPage {
|
|||
});
|
||||
})
|
||||
.then(() => {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
})
|
||||
// verify that green message at the top of the page.
|
||||
// it's only there for about 5 seconds
|
||||
|
@ -136,7 +136,7 @@ export default class DashboardPage {
|
|||
.type(dashName.replace('-',' '));
|
||||
})
|
||||
.then(() => {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
})
|
||||
.then(() => {
|
||||
return PageObjects.common.sleep(1000);
|
||||
|
@ -146,7 +146,7 @@ export default class DashboardPage {
|
|||
.clickDashboardByLinkText(dashName);
|
||||
})
|
||||
.then(() => {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ export default class DiscoverPage {
|
|||
this.findTimeout.findByLinkText(searchName).click();
|
||||
})
|
||||
.then(() => {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,7 @@ export default class DiscoverPage {
|
|||
}
|
||||
|
||||
getBarChartData() {
|
||||
return PageObjects.header.getSpinnerDone()
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden()
|
||||
.then(() => {
|
||||
return this.findTimeout
|
||||
.findAllByCssSelector('rect[data-label="Count"]');
|
||||
|
@ -134,12 +134,12 @@ export default class DiscoverPage {
|
|||
.click();
|
||||
})
|
||||
.then(() => {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
});
|
||||
}
|
||||
|
||||
getHitCount() {
|
||||
return PageObjects.header.getSpinnerDone()
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden()
|
||||
.then(() => {
|
||||
return PageObjects.common.findTestSubject('discoverQueryHits')
|
||||
.getVisibleText();
|
||||
|
@ -157,7 +157,7 @@ export default class DiscoverPage {
|
|||
.click();
|
||||
})
|
||||
.then(() => {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ export default class HeaderPage {
|
|||
.findByClassName('kbn-timepicker-go')
|
||||
.click()
|
||||
.then(function () {
|
||||
return self.getSpinnerDone();
|
||||
return self.isGlobalLoadingIndicatorHidden();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -101,7 +101,7 @@ export default class HeaderPage {
|
|||
return this.clickGoButton();
|
||||
})
|
||||
.then(() => {
|
||||
return this.getSpinnerDone();
|
||||
return this.isGlobalLoadingIndicatorHidden();
|
||||
})
|
||||
.then(() => {
|
||||
return this.clickTimepicker();
|
||||
|
@ -125,9 +125,9 @@ export default class HeaderPage {
|
|||
.click();
|
||||
}
|
||||
|
||||
getSpinnerDone() {
|
||||
isGlobalLoadingIndicatorHidden() {
|
||||
return this.remote.setFindTimeout(defaultFindTimeout * 10)
|
||||
.findByCssSelector('.spinner.ng-hide');
|
||||
.findByCssSelector('[data-test-subj="globalLoadingIndicator"].ng-hide');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ export default class SettingsPage {
|
|||
return PageObjects.common.findTestSubject('advancedSetting-' + propertyName + '-editButton')
|
||||
.click()
|
||||
.then(() => {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
})
|
||||
.then(() => {
|
||||
return PageObjects.common.sleep(1000);
|
||||
|
@ -53,14 +53,14 @@ export default class SettingsPage {
|
|||
.click();
|
||||
})
|
||||
.then(() => {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
})
|
||||
.then(function setAdvancedSettingsClickSaveButton() {
|
||||
return PageObjects.common.findTestSubject('advancedSetting-' + propertyName + '-saveButton')
|
||||
.click();
|
||||
})
|
||||
.then(() => {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -105,7 +105,7 @@ export default class SettingsPage {
|
|||
return this.getTimeFieldNameField().click();
|
||||
})
|
||||
.then(() => {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
})
|
||||
.then(() => {
|
||||
return PageObjects.common.try(() => {
|
||||
|
@ -134,7 +134,7 @@ export default class SettingsPage {
|
|||
return this.remote.setFindTimeout(defaultFindTimeout)
|
||||
.findByCssSelector('button.btn.btn-success.ng-scope').click()
|
||||
.then(() => {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -167,7 +167,7 @@ export default class SettingsPage {
|
|||
if (chartString === columnName) {
|
||||
return chart.click()
|
||||
.then(function () {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -240,7 +240,7 @@ export default class SettingsPage {
|
|||
(pageNum + 1) + ') a.ng-binding')
|
||||
.click()
|
||||
.then(function () {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -262,7 +262,7 @@ export default class SettingsPage {
|
|||
.findByCssSelector('button.btn.btn-default[aria-label="Plus"]')
|
||||
.click()
|
||||
.then(() => {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -279,7 +279,7 @@ export default class SettingsPage {
|
|||
.findByCssSelector('button.btn.btn-primary[aria-label="Cancel"]')
|
||||
.click()
|
||||
.then(() => {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -288,7 +288,7 @@ export default class SettingsPage {
|
|||
.findByCssSelector('button.btn.btn-success.ng-binding[aria-label="Update Field"]')
|
||||
.click()
|
||||
.then(() => {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -297,7 +297,7 @@ export default class SettingsPage {
|
|||
.findByCssSelector('form.form-inline.pagination-size.ng-scope.ng-pristine.ng-valid div.form-group option[label="' + size + '"]')
|
||||
.click()
|
||||
.then(() => {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -315,7 +315,7 @@ export default class SettingsPage {
|
|||
});
|
||||
})
|
||||
.then(() => {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
})
|
||||
.then(() => {
|
||||
return PageObjects.common.try(() => {
|
||||
|
|
|
@ -288,7 +288,7 @@ export default class VisualizePage {
|
|||
.findByCssSelector('.btn-success')
|
||||
.click()
|
||||
.then(function () {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -323,7 +323,7 @@ export default class VisualizePage {
|
|||
.click();
|
||||
})
|
||||
.then(function () {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
})
|
||||
// verify that green message at the top of the page.
|
||||
// it's only there for about 5 seconds
|
||||
|
@ -704,7 +704,7 @@ export default class VisualizePage {
|
|||
return PageObjects.common.sleep(1000);
|
||||
})
|
||||
.then(() => {
|
||||
return PageObjects.header.getSpinnerDone();
|
||||
return PageObjects.header.isGlobalLoadingIndicatorHidden();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue