Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/core_plugins/kibana/ui_setting_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -510,5 +510,13 @@ export function getUiSettingDefaults() {
is present and sortable in the current index pattern is used.`,
category: ['discover'],
},
'accessibility:disableAnimations': {
name: 'Disable Animations',
value: false,
description: `
Turn off all unnecessary animations in the Kibana UI. Refresh the page to apply the changes.
`,
category: ['accessibility'],
},
};
}
4 changes: 2 additions & 2 deletions src/es_archiver/es_archiver.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export class EsArchiver {
* @return Promise<Stats>
*/
async rebuildAll() {
return rebuildAllAction({
return await rebuildAllAction({
client: this.client,
dataDir: this.dataDir,
log: this.log
Expand All @@ -109,6 +109,6 @@ export class EsArchiver {
* @return Promise<Stats>
*/
async loadIfNeeded(name) {
return this.load(name, { skipExisting: true });
return await this.load(name, { skipExisting: true });
}
}
7 changes: 6 additions & 1 deletion src/functional_test_runner/lib/config/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,12 @@ export const schema = Joi.object().keys({

// settings for the esArchiver module
esArchiver: Joi.object().keys({
directory: Joi.string().default(defaultRelativeToConfigPath('fixtures/es_archiver'))
directory: Joi.string().default(defaultRelativeToConfigPath('fixtures/es_archiver')),
}).default(),

// settings for the kibanaServer.uiSettings module
uiSettings: Joi.object().keys({
defaults: Joi.object().unknown(true)
}).default(),

// settings for the screenshots module
Expand Down
11 changes: 10 additions & 1 deletion src/functional_test_runner/lib/providers/provider_collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ export class ProviderCollection {
this._getInstance('Service', name)
)

hasService = name => (
Boolean(this._findProvider('Service', name))
)

getPageObject = name => (
this._getInstance('PageObject', name)
)
Expand Down Expand Up @@ -68,8 +72,12 @@ export class ProviderCollection {
}
}

_findProvider(type, name) {
return this._providers.find(p => p.type === type && p.name === name);
}

_getProvider(type, name) {
const providerDef = this._providers.find(p => p.type === type && p.name === name);
const providerDef = this._findProvider(type, name);
if (!providerDef) {
throw new Error(`Unknown ${type} "${name}"`);
}
Expand All @@ -87,6 +95,7 @@ export class ProviderCollection {
if (!instances.has(provider)) {
let instance = provider({
getService: this.getService,
hasService: this.hasService,
getPageObject: this.getPageObject,
getPageObjects: this.getPageObjects,
});
Expand Down
3 changes: 3 additions & 0 deletions src/ui/public/autoload/styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,6 @@ theme.applyTheme('light');
// All Kibana styles inside of the /styles dir
const context = require.context('../styles', false, /[\/\\](?!mixins|variables|_|\.)[^\/\\]+\.less/);
context.keys().forEach(key => context(key));

// manually require non-less files
require('../styles/disable_animations');
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ exports[`kbnLoadingIndicator is hidden by default 1`] = `
data-test-subj="globalLoadingIndicator-hidden"
>
<div
className="loadingIndicator__bar"
className="loadingIndicator__bar essentialAnimation"
/>
</div>
`;
Expand All @@ -17,7 +17,7 @@ exports[`kbnLoadingIndicator is visible when loadingCount is > 0 1`] = `
data-test-subj="globalLoadingIndicator"
>
<div
className="loadingIndicator__bar"
className="loadingIndicator__bar essentialAnimation"
/>
</div>
`;
2 changes: 1 addition & 1 deletion src/ui/public/chrome/directives/loading_indicator.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export class LoadingIndicator extends React.Component {

return (
<div className={className} data-test-subj={testSubj}>
<div className="loadingIndicator__bar" />
<div className="loadingIndicator__bar essentialAnimation" />
</div>
);
}
Expand Down
14 changes: 14 additions & 0 deletions src/ui/public/styles/disable_animations/disable_animations.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
*:not(.essentialAnimation),
*:not(.essentialAnimation):before,
*:not(.essentialAnimation):after {
/**
* set the animation/transition duration to 0s so that animation callbacks are
* still triggered, allowing components that require them to remain functional
*/

-webkit-animation-duration: 0s !important;
animation-duration: 0s !important;

-webkit-transition-duration: 0s !important;
transition-duration: 0s !important;
}
46 changes: 46 additions & 0 deletions src/ui/public/styles/disable_animations/disable_animations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import chrome from 'ui/chrome';
import disableAnimationsCss from '!!raw-loader!./disable_animations.css';

const uiSettings = chrome.getUiSettingsClient();

// rather than silently ignore when the style element is missing in the tests
// like ui/theme does, we automatically create a style tag because ordering doesn't
// really matter for these styles, they should really take top priority because
// they all use `!important`, and we don't want to silently ignore the possibility
// of accidentally removing the style element from the chrome template.
const styleElement = document.createElement('style');
styleElement.setAttribute('id', 'disableAnimationsCss');
document.head.appendChild(styleElement);

function updateStyleSheet() {
styleElement.textContent = uiSettings.get('accessibility:disableAnimations')
? disableAnimationsCss
: '';
}

updateStyleSheet();
uiSettings.subscribe(({ key }) => {
if (key === 'accessibility:disableAnimations') {
updateStyleSheet();
}
});

20 changes: 20 additions & 0 deletions src/ui/public/styles/disable_animations/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import './disable_animations';
6 changes: 5 additions & 1 deletion src/ui/public/tooltip/tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,16 @@
*/

import html from './tooltip.html';
import chrome from 'ui/chrome';

require('ui-bootstrap')
.config(function ($tooltipProvider) {
// we use the uiSettings client because the config service is not available in the config phase
const uiSettings = chrome.getUiSettingsClient();

$tooltipProvider.options({
placement: 'bottom',
animation: true,
animation: !uiSettings.get('accessibility:disableAnimations'),
popupDelay: 150,
appendToBody: false
});
Expand Down
15 changes: 13 additions & 2 deletions test/common/services/es_archiver.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
*/

import { EsArchiver } from '../../../src/es_archiver';
import * as KibanaServer from './kibana_server';

export async function EsArchiverProvider({ getService }) {
export function EsArchiverProvider({ getService, hasService }) {
const config = getService('config');
const client = getService('es');
const log = getService('log');
Expand All @@ -30,9 +31,19 @@ export async function EsArchiverProvider({ getService }) {

const dataDir = config.get('esArchiver.directory');

return new EsArchiver({
const esArchiver = new EsArchiver({
client,
dataDir,
log,
});

if (hasService('kibanaServer')) {
KibanaServer.extendEsArchiver({
esArchiver,
kibanaServer: getService('kibanaServer'),
defaults: config.get('uiSettings.defaults'),
});
}

return esArchiver;
}
45 changes: 45 additions & 0 deletions test/common/services/kibana_server/extend_es_archiver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

const ES_ARCHIVER_LOAD_METHODS = ['load', 'loadIfNeeded'];
const KIBANA_INDEX = '.kibana';

export function extendEsArchiver({ esArchiver, kibanaServer, defaults }) {
// only extend the esArchiver if there are default uiSettings to restore
if (!defaults) {
return;
}

ES_ARCHIVER_LOAD_METHODS.forEach(method => {
const originalMethod = esArchiver[method];

esArchiver[method] = async (...args) => {
// esArchiver methods return a stats object, with information about the indexes created
const stats = await originalMethod.apply(esArchiver, args);

// if the kibana index was created by the esArchiver then update the uiSettings
// with the defaults to make sure that they are always in place initially
if (stats[KIBANA_INDEX] && stats[KIBANA_INDEX].created) {
await kibanaServer.uiSettings.update(defaults);
}

return stats;
};
});
}
1 change: 1 addition & 0 deletions test/common/services/kibana_server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@
*/

export { KibanaServerProvider } from './kibana_server';
export { extendEsArchiver } from './extend_es_archiver';
4 changes: 2 additions & 2 deletions test/common/services/kibana_server/kibana_server.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { KibanaServerStatus } from './status';
import { KibanaServerUiSettings } from './ui_settings';
import { KibanaServerVersion } from './version';

export async function KibanaServerProvider({ getService }) {
export function KibanaServerProvider({ getService }) {
const log = getService('log');
const config = getService('config');

Expand All @@ -32,7 +32,7 @@ export async function KibanaServerProvider({ getService }) {
const url = formatUrl(config.get('servers.kibana'));
this.status = new KibanaServerStatus(url);
this.version = new KibanaServerVersion(this.status);
this.uiSettings = new KibanaServerUiSettings(url, log, this.version);
this.uiSettings = new KibanaServerUiSettings(url, log, config.get('uiSettings.defaults'));
}
};
}
21 changes: 12 additions & 9 deletions test/common/services/kibana_server/ui_settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ const MINUTE = 60 * 1000;
const HOUR = 60 * MINUTE;

export class KibanaServerUiSettings {
constructor(url, log, kibanaVersion) {
constructor(url, log, defaults) {
this._log = log;
this._kibanaVersion = kibanaVersion;
this._defaults = defaults;
this._wreck = Wreck.defaults({
headers: { 'kbn-xsrf': 'ftr/services/uiSettings' },
baseUrl: url,
Expand All @@ -35,9 +35,9 @@ export class KibanaServerUiSettings {
});
}

/*
** Gets defaultIndex from the config doc.
*/
/**
* Gets defaultIndex from the config doc.
*/
async getDefaultIndex() {
const { payload } = await this._wreck.get('/api/kibana/settings');
const defaultIndex = get(payload, 'settings.defaultIndex.userValue');
Expand Down Expand Up @@ -75,15 +75,18 @@ export class KibanaServerUiSettings {

await this._wreck.post('/api/kibana/settings', {
payload: {
changes: doc
changes: {
...this._defaults,
...doc,
}
}
});
}

/**
* Add fields to the config doc (like setting timezone and defaultIndex)
* @return {Promise} A promise that is resolved when elasticsearch has a response
*/
* Add fields to the config doc (like setting timezone and defaultIndex)
* @return {Promise} A promise that is resolved when elasticsearch has a response
*/
async update(updates) {
this._log.debug('applying update to kibana config: %j', updates);
await this._wreck.post('/api/kibana/settings', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export default function ({ getService, getPageObjects }) {
describe('add new visualization link', () => {
it('adds a new visualization', async () => {
const originalPanelCount = await PageObjects.dashboard.getPanelCount();
await PageObjects.dashboard.clickEdit();
await PageObjects.dashboard.switchToEditMode();
await dashboardAddPanel.ensureAddPanelIsShowing();
await dashboardAddPanel.clickAddNewEmbeddableLink();
await PageObjects.visualize.clickAreaChart();
Expand Down
2 changes: 1 addition & 1 deletion test/functional/apps/dashboard/_dashboard_grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default function ({ getService, getPageObjects }) {
before(async () => {
await PageObjects.dashboard.gotoDashboardLandingPage();
await PageObjects.dashboard.loadSavedDashboard('few panels');
await PageObjects.dashboard.clickEdit();
await PageObjects.dashboard.switchToEditMode();
});

describe('move panel', () => {
Expand Down
2 changes: 1 addition & 1 deletion test/functional/apps/dashboard/_dashboard_options.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default function ({ getService, getPageObjects }) {

before(async () => {
await PageObjects.dashboard.loadSavedDashboard('few panels');
await PageObjects.dashboard.clickEdit();
await PageObjects.dashboard.switchToEditMode();
originalTitles = await PageObjects.dashboard.getPanelTitles();
});

Expand Down
Loading