mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
Delete src/legacy/ui/public folder (#76085)
* delete src/legacy/ui/public folder * remove jest.mock('ui/XXX'); from tests * adapt stubbedLogstashIndexPatternService * remove delete keys from translation files * fix types import with Capabilities * remove legacy test utils * remove dead file referencing ui/newPlatform * move saved-object-finder styles to timelion plugin
This commit is contained in:
parent
086e488392
commit
e70ef657d4
290 changed files with 88 additions and 25467 deletions
|
@ -28,12 +28,6 @@ const createMockStorage = () => ({
|
|||
length: 0,
|
||||
});
|
||||
|
||||
jest.mock('ui/chrome', () => {
|
||||
return {
|
||||
getBasePath: () => `/some/base/path`,
|
||||
};
|
||||
});
|
||||
|
||||
const historyName = 'testHistory';
|
||||
const historyLimit = 10;
|
||||
const payload = [
|
||||
|
|
|
@ -59,7 +59,6 @@ export default {
|
|||
'@elastic/eui/lib/(.*)?': '<rootDir>/node_modules/@elastic/eui/test-env/$1',
|
||||
'^src/plugins/(.*)': '<rootDir>/src/plugins/$1',
|
||||
'^plugins/([^/.]*)(.*)': '<rootDir>/src/legacy/core_plugins/$1/public$2',
|
||||
'^ui/(.*)': '<rootDir>/src/legacy/ui/public/$1',
|
||||
'^uiExports/(.*)': '<rootDir>/src/dev/jest/mocks/file_mock.js',
|
||||
'^test_utils/(.*)': '<rootDir>/src/test_utils/public/$1',
|
||||
'^fixtures/(.*)': '<rootDir>/src/fixtures/$1',
|
||||
|
|
|
@ -34,10 +34,6 @@
|
|||
* The mocks that are enabled that way live inside the `__mocks__` folders beside their implementation files.
|
||||
*/
|
||||
|
||||
jest.mock('ui/metadata');
|
||||
jest.mock('ui/documentation_links/documentation_links');
|
||||
jest.mock('ui/chrome');
|
||||
|
||||
jest.mock('moment-timezone', () => {
|
||||
// We always want to mock the timezone moment-timezone guesses, since otherwise
|
||||
// test results might be depending on which time zone you are running them.
|
||||
|
|
|
@ -21,7 +21,12 @@ import StubIndexPattern from 'test_utils/stub_index_pattern';
|
|||
import stubbedLogstashFields from 'fixtures/logstash_fields';
|
||||
|
||||
import { getKbnFieldType } from '../plugins/data/common';
|
||||
import { npSetup } from '../legacy/ui/public/new_platform/new_platform.karma_mock';
|
||||
import { uiSettingsServiceMock } from '../core/public/ui_settings/ui_settings_service.mock';
|
||||
|
||||
const uiSettingSetupMock = uiSettingsServiceMock.createSetupContract();
|
||||
uiSettingSetupMock.get.mockImplementation((item, defaultValue) => {
|
||||
return defaultValue;
|
||||
});
|
||||
|
||||
export default function stubbedLogstashIndexPatternService() {
|
||||
const mockLogstashFields = stubbedLogstashFields();
|
||||
|
@ -41,13 +46,9 @@ export default function stubbedLogstashIndexPatternService() {
|
|||
};
|
||||
});
|
||||
|
||||
const indexPattern = new StubIndexPattern(
|
||||
'logstash-*',
|
||||
(cfg) => cfg,
|
||||
'time',
|
||||
fields,
|
||||
npSetup.core
|
||||
);
|
||||
const indexPattern = new StubIndexPattern('logstash-*', (cfg) => cfg, 'time', fields, {
|
||||
uiSettings: uiSettingSetupMock,
|
||||
});
|
||||
|
||||
indexPattern.id = 'logstash-*';
|
||||
indexPattern.isTimeNanosBased = () => false;
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
rules:
|
||||
no-console: 2
|
||||
'import/no-default-export': error
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* 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 { metadata as metadataImpl } from '../metadata';
|
||||
|
||||
export const metadata: typeof metadataImpl = {
|
||||
branch: 'jest-metadata-mock-branch',
|
||||
version: '42.23.26',
|
||||
};
|
|
@ -1,244 +0,0 @@
|
|||
/*
|
||||
* 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 _ from 'lodash';
|
||||
import sinon from 'sinon';
|
||||
import ngMock from 'ng_mock';
|
||||
import { EventsProvider } from '../events';
|
||||
import expect from '@kbn/expect';
|
||||
import '../private';
|
||||
import { createDefer } from 'ui/promises';
|
||||
import { createLegacyClass } from '../utils/legacy_class';
|
||||
|
||||
describe('Events', function () {
|
||||
require('test_utils/no_digest_promises').activateForSuite();
|
||||
|
||||
let Events;
|
||||
let Promise;
|
||||
let eventsInstance;
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
beforeEach(
|
||||
ngMock.inject(function ($injector, Private) {
|
||||
Promise = $injector.get('Promise');
|
||||
Events = Private(EventsProvider);
|
||||
eventsInstance = new Events();
|
||||
})
|
||||
);
|
||||
|
||||
it('should handle on events', function () {
|
||||
const obj = new Events();
|
||||
const prom = obj.on('test', function (message) {
|
||||
expect(message).to.equal('Hello World');
|
||||
});
|
||||
|
||||
obj.emit('test', 'Hello World');
|
||||
|
||||
return prom;
|
||||
});
|
||||
|
||||
it('should work with inherited objects', function () {
|
||||
createLegacyClass(MyEventedObject).inherits(Events);
|
||||
function MyEventedObject() {
|
||||
MyEventedObject.Super.call(this);
|
||||
}
|
||||
const obj = new MyEventedObject();
|
||||
|
||||
const prom = obj.on('test', function (message) {
|
||||
expect(message).to.equal('Hello World');
|
||||
});
|
||||
|
||||
obj.emit('test', 'Hello World');
|
||||
|
||||
return prom;
|
||||
});
|
||||
|
||||
it('should clear events when off is called', function () {
|
||||
const obj = new Events();
|
||||
obj.on('test', _.noop);
|
||||
expect(obj._listeners).to.have.property('test');
|
||||
expect(obj._listeners.test).to.have.length(1);
|
||||
obj.off();
|
||||
expect(obj._listeners).to.not.have.property('test');
|
||||
});
|
||||
|
||||
it('should clear a specific handler when off is called for an event', function () {
|
||||
const obj = new Events();
|
||||
const handler1 = sinon.stub();
|
||||
const handler2 = sinon.stub();
|
||||
obj.on('test', handler1);
|
||||
obj.on('test', handler2);
|
||||
expect(obj._listeners).to.have.property('test');
|
||||
obj.off('test', handler1);
|
||||
|
||||
return obj.emit('test', 'Hello World').then(function () {
|
||||
sinon.assert.calledOnce(handler2);
|
||||
sinon.assert.notCalled(handler1);
|
||||
});
|
||||
});
|
||||
|
||||
it('should clear a all handlers when off is called for an event', function () {
|
||||
const obj = new Events();
|
||||
const handler1 = sinon.stub();
|
||||
obj.on('test', handler1);
|
||||
expect(obj._listeners).to.have.property('test');
|
||||
obj.off('test');
|
||||
expect(obj._listeners).to.not.have.property('test');
|
||||
|
||||
return obj.emit('test', 'Hello World').then(function () {
|
||||
sinon.assert.notCalled(handler1);
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle multiple identical emits in the same tick', function () {
|
||||
const obj = new Events();
|
||||
const handler1 = sinon.stub();
|
||||
|
||||
obj.on('test', handler1);
|
||||
const emits = [obj.emit('test', 'one'), obj.emit('test', 'two'), obj.emit('test', 'three')];
|
||||
|
||||
return Promise.all(emits).then(function () {
|
||||
expect(handler1.callCount).to.be(emits.length);
|
||||
expect(handler1.getCall(0).calledWith('one')).to.be(true);
|
||||
expect(handler1.getCall(1).calledWith('two')).to.be(true);
|
||||
expect(handler1.getCall(2).calledWith('three')).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle emits from the handler', function () {
|
||||
const obj = new Events();
|
||||
const secondEmit = createDefer(Promise);
|
||||
|
||||
const handler1 = sinon.spy(function () {
|
||||
if (handler1.calledTwice) {
|
||||
return;
|
||||
}
|
||||
obj.emit('test').then(_.bindKey(secondEmit, 'resolve'));
|
||||
});
|
||||
|
||||
obj.on('test', handler1);
|
||||
|
||||
return Promise.all([obj.emit('test'), secondEmit.promise]).then(function () {
|
||||
expect(handler1.callCount).to.be(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('should only emit to handlers registered before emit is called', function () {
|
||||
const obj = new Events();
|
||||
const handler1 = sinon.stub();
|
||||
const handler2 = sinon.stub();
|
||||
|
||||
obj.on('test', handler1);
|
||||
const emits = [obj.emit('test', 'one'), obj.emit('test', 'two'), obj.emit('test', 'three')];
|
||||
|
||||
return Promise.all(emits).then(function () {
|
||||
expect(handler1.callCount).to.be(emits.length);
|
||||
|
||||
obj.on('test', handler2);
|
||||
|
||||
const emits2 = [obj.emit('test', 'four'), obj.emit('test', 'five'), obj.emit('test', 'six')];
|
||||
|
||||
return Promise.all(emits2).then(function () {
|
||||
expect(handler1.callCount).to.be(emits.length + emits2.length);
|
||||
expect(handler2.callCount).to.be(emits2.length);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass multiple arguments from the emitter', function () {
|
||||
const obj = new Events();
|
||||
const handler = sinon.stub();
|
||||
const payload = ['one', { hello: 'tests' }, null];
|
||||
|
||||
obj.on('test', handler);
|
||||
|
||||
return obj.emit('test', payload[0], payload[1], payload[2]).then(function () {
|
||||
expect(handler.callCount).to.be(1);
|
||||
expect(handler.calledWithExactly(payload[0], payload[1], payload[2])).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should preserve the scope of the handler', function () {
|
||||
const obj = new Events();
|
||||
const expected = 'some value';
|
||||
let testValue;
|
||||
|
||||
function handler() {
|
||||
testValue = this.getVal();
|
||||
}
|
||||
handler.getVal = _.constant(expected);
|
||||
|
||||
obj.on('test', handler);
|
||||
return obj.emit('test').then(function () {
|
||||
expect(testValue).to.equal(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('should always emit in the same order', function () {
|
||||
const handler = sinon.stub();
|
||||
|
||||
const obj = new Events();
|
||||
obj.on('block', _.partial(handler, 'block'));
|
||||
obj.on('last', _.partial(handler, 'last'));
|
||||
|
||||
return Promise.all([
|
||||
obj.emit('block'),
|
||||
obj.emit('block'),
|
||||
obj.emit('block'),
|
||||
obj.emit('block'),
|
||||
obj.emit('block'),
|
||||
obj.emit('block'),
|
||||
obj.emit('block'),
|
||||
obj.emit('block'),
|
||||
obj.emit('block'),
|
||||
obj.emit('last'),
|
||||
]).then(function () {
|
||||
expect(handler.callCount).to.be(10);
|
||||
handler.args.forEach(function (args, i) {
|
||||
expect(args[0]).to.be(i < 9 ? 'block' : 'last');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('calls emitted handlers asynchronously', (done) => {
|
||||
const listenerStub = sinon.stub();
|
||||
eventsInstance.on('test', listenerStub);
|
||||
eventsInstance.emit('test');
|
||||
sinon.assert.notCalled(listenerStub);
|
||||
|
||||
setTimeout(() => {
|
||||
sinon.assert.calledOnce(listenerStub);
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('calling off after an emit that has not yet triggered the handler, will not call the handler', (done) => {
|
||||
const listenerStub = sinon.stub();
|
||||
eventsInstance.on('test', listenerStub);
|
||||
eventsInstance.emit('test');
|
||||
// It's called asynchronously so it shouldn't be called yet.
|
||||
sinon.assert.notCalled(listenerStub);
|
||||
eventsInstance.off('test', listenerStub);
|
||||
|
||||
setTimeout(() => {
|
||||
sinon.assert.notCalled(listenerStub);
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
});
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
* 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 expect from '@kbn/expect';
|
||||
import { metadata } from '../metadata';
|
||||
describe('ui/metadata', () => {
|
||||
it('is immutable', () => {
|
||||
expect(() => (metadata.foo = 'something')).to.throw;
|
||||
expect(() => (metadata.version = 'something')).to.throw;
|
||||
expect(() => (metadata.vars = {})).to.throw;
|
||||
expect(() => (metadata.vars.kbnIndex = 'something')).to.throw;
|
||||
});
|
||||
});
|
|
@ -1,9 +0,0 @@
|
|||
// Prefix all styles with "kbn" to avoid conflicts.
|
||||
// Examples
|
||||
// kbnChart
|
||||
// kbnChart__legend
|
||||
// kbnChart__legend--small
|
||||
// kbnChart__legend-isLoading
|
||||
|
||||
@import './accessibility/index';
|
||||
@import './directives/index';
|
|
@ -1,127 +0,0 @@
|
|||
/*
|
||||
* 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 angular from 'angular';
|
||||
import sinon from 'sinon';
|
||||
import expect from '@kbn/expect';
|
||||
import ngMock from 'ng_mock';
|
||||
import '../kbn_accessible_click';
|
||||
import { keys } from '@elastic/eui';
|
||||
|
||||
describe('kbnAccessibleClick directive', () => {
|
||||
let $compile;
|
||||
let $rootScope;
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
|
||||
beforeEach(
|
||||
ngMock.inject(function (_$compile_, _$rootScope_) {
|
||||
$compile = _$compile_;
|
||||
$rootScope = _$rootScope_;
|
||||
})
|
||||
);
|
||||
|
||||
describe('throws an error', () => {
|
||||
it('when the element is a button', () => {
|
||||
const html = `<button kbn-accessible-click></button>`;
|
||||
expect(() => {
|
||||
$compile(html)($rootScope);
|
||||
}).to.throwError(/kbnAccessibleClick doesn't need to be used on a button./);
|
||||
});
|
||||
|
||||
it('when the element is a link with an href', () => {
|
||||
const html = `<a href="#" kbn-accessible-click></a>`;
|
||||
expect(() => {
|
||||
$compile(html)($rootScope);
|
||||
}).to.throwError(
|
||||
/kbnAccessibleClick doesn't need to be used on a link if it has a href attribute./
|
||||
);
|
||||
});
|
||||
|
||||
it(`when the element doesn't have an ng-click`, () => {
|
||||
const html = `<div kbn-accessible-click></div>`;
|
||||
expect(() => {
|
||||
$compile(html)($rootScope);
|
||||
}).to.throwError(/kbnAccessibleClick requires ng-click to be defined on its element./);
|
||||
});
|
||||
});
|
||||
|
||||
describe(`doesn't throw an error`, () => {
|
||||
it('when the element is a link without an href', () => {
|
||||
const html = `<a ng-click="noop" kbn-accessible-click></a>`;
|
||||
expect(() => {
|
||||
$compile(html)($rootScope);
|
||||
}).not.to.throwError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('adds accessibility attributes', () => {
|
||||
it('tabindex', () => {
|
||||
const html = `<div ng-click="noop" kbn-accessible-click></div>`;
|
||||
const element = $compile(html)($rootScope);
|
||||
expect(element.attr('tabindex')).to.be('0');
|
||||
});
|
||||
|
||||
it('role', () => {
|
||||
const html = `<div ng-click="noop" kbn-accessible-click></div>`;
|
||||
const element = $compile(html)($rootScope);
|
||||
expect(element.attr('role')).to.be('button');
|
||||
});
|
||||
});
|
||||
|
||||
describe(`doesn't override pre-existing accessibility attributes`, () => {
|
||||
it('tabindex', () => {
|
||||
const html = `<div ng-click="noop" kbn-accessible-click tabindex="1"></div>`;
|
||||
const element = $compile(html)($rootScope);
|
||||
expect(element.attr('tabindex')).to.be('1');
|
||||
});
|
||||
|
||||
it('role', () => {
|
||||
const html = `<div ng-click="noop" kbn-accessible-click role="submit"></div>`;
|
||||
const element = $compile(html)($rootScope);
|
||||
expect(element.attr('role')).to.be('submit');
|
||||
});
|
||||
});
|
||||
|
||||
describe(`calls ng-click`, () => {
|
||||
let scope;
|
||||
let element;
|
||||
|
||||
beforeEach(function () {
|
||||
scope = $rootScope.$new();
|
||||
scope.handleClick = sinon.stub();
|
||||
const html = `<div ng-click="handleClick()" kbn-accessible-click></div>`;
|
||||
element = $compile(html)(scope);
|
||||
});
|
||||
|
||||
it(`on ENTER keyup`, () => {
|
||||
const e = angular.element.Event('keyup'); // eslint-disable-line new-cap
|
||||
e.key = keys.ENTER;
|
||||
element.trigger(e);
|
||||
sinon.assert.calledOnce(scope.handleClick);
|
||||
});
|
||||
|
||||
it(`on SPACE keyup`, () => {
|
||||
const e = angular.element.Event('keyup'); // eslint-disable-line new-cap
|
||||
e.key = keys.SPACE;
|
||||
element.trigger(e);
|
||||
sinon.assert.calledOnce(scope.handleClick);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,129 +0,0 @@
|
|||
/*
|
||||
* 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 angular from 'angular';
|
||||
import sinon from 'sinon';
|
||||
import expect from '@kbn/expect';
|
||||
import ngMock from 'ng_mock';
|
||||
import '../kbn_ui_ace_keyboard_mode';
|
||||
import { keys } from '@elastic/eui';
|
||||
|
||||
describe('kbnUiAceKeyboardMode directive', () => {
|
||||
let element;
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
|
||||
beforeEach(
|
||||
ngMock.inject(($compile, $rootScope) => {
|
||||
element = $compile(`<div ui-ace kbn-ui-ace-keyboard-mode></div>`)($rootScope.$new());
|
||||
})
|
||||
);
|
||||
|
||||
it('should add the hint element', () => {
|
||||
expect(element.find('.kbnUiAceKeyboardHint').length).to.be(1);
|
||||
});
|
||||
|
||||
describe('hint element', () => {
|
||||
it('should be tabable', () => {
|
||||
expect(element.find('.kbnUiAceKeyboardHint').attr('tabindex')).to.be('0');
|
||||
});
|
||||
|
||||
it('should move focus to textbox and be inactive if pressed enter on it', () => {
|
||||
const textarea = element.find('textarea');
|
||||
sinon.spy(textarea[0], 'focus');
|
||||
const ev = angular.element.Event('keydown'); // eslint-disable-line new-cap
|
||||
ev.key = keys.ENTER;
|
||||
element.find('.kbnUiAceKeyboardHint').trigger(ev);
|
||||
expect(textarea[0].focus.called).to.be(true);
|
||||
expect(
|
||||
element.find('.kbnUiAceKeyboardHint').hasClass('kbnUiAceKeyboardHint-isInactive')
|
||||
).to.be(true);
|
||||
});
|
||||
|
||||
it('should be shown again, when pressing Escape in ace editor', () => {
|
||||
const textarea = element.find('textarea');
|
||||
const hint = element.find('.kbnUiAceKeyboardHint');
|
||||
sinon.spy(hint[0], 'focus');
|
||||
const ev = angular.element.Event('keydown'); // eslint-disable-line new-cap
|
||||
ev.key = keys.ESCAPE;
|
||||
textarea.trigger(ev);
|
||||
expect(hint[0].focus.called).to.be(true);
|
||||
expect(hint.hasClass('kbnUiAceKeyboardHint-isInactive')).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ui-ace textarea', () => {
|
||||
it('should not be tabable anymore', () => {
|
||||
expect(element.find('textarea').attr('tabindex')).to.be('-1');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('kbnUiAceKeyboardModeService', () => {
|
||||
let element;
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
|
||||
beforeEach(
|
||||
ngMock.inject(($compile, $rootScope, kbnUiAceKeyboardModeService) => {
|
||||
const scope = $rootScope.$new();
|
||||
element = $compile(`<div ui-ace></div>`)(scope);
|
||||
kbnUiAceKeyboardModeService.initialize(scope, element);
|
||||
})
|
||||
);
|
||||
|
||||
it('should add the hint element', () => {
|
||||
expect(element.find('.kbnUiAceKeyboardHint').length).to.be(1);
|
||||
});
|
||||
|
||||
describe('hint element', () => {
|
||||
it('should be tabable', () => {
|
||||
expect(element.find('.kbnUiAceKeyboardHint').attr('tabindex')).to.be('0');
|
||||
});
|
||||
|
||||
it('should move focus to textbox and be inactive if pressed enter on it', () => {
|
||||
const textarea = element.find('textarea');
|
||||
sinon.spy(textarea[0], 'focus');
|
||||
const ev = angular.element.Event('keydown'); // eslint-disable-line new-cap
|
||||
ev.key = keys.ENTER;
|
||||
element.find('.kbnUiAceKeyboardHint').trigger(ev);
|
||||
expect(textarea[0].focus.called).to.be(true);
|
||||
expect(
|
||||
element.find('.kbnUiAceKeyboardHint').hasClass('kbnUiAceKeyboardHint-isInactive')
|
||||
).to.be(true);
|
||||
});
|
||||
|
||||
it('should be shown again, when pressing Escape in ace editor', () => {
|
||||
const textarea = element.find('textarea');
|
||||
const hint = element.find('.kbnUiAceKeyboardHint');
|
||||
sinon.spy(hint[0], 'focus');
|
||||
const ev = angular.element.Event('keydown'); // eslint-disable-line new-cap
|
||||
ev.key = keys.ESCAPE;
|
||||
textarea.trigger(ev);
|
||||
expect(hint[0].focus.called).to.be(true);
|
||||
expect(hint.hasClass('kbnUiAceKeyboardHint-isInactive')).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ui-ace textarea', () => {
|
||||
it('should not be tabable anymore', () => {
|
||||
expect(element.find('textarea').attr('tabindex')).to.be('-1');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* 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 sinon from 'sinon';
|
||||
import expect from '@kbn/expect';
|
||||
import ngMock from 'ng_mock';
|
||||
import '../scrollto_activedescendant';
|
||||
|
||||
describe('scrolltoActivedescendant directive', () => {
|
||||
let $compile;
|
||||
let $rootScope;
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
|
||||
beforeEach(
|
||||
ngMock.inject((_$compile_, _$rootScope_) => {
|
||||
$compile = _$compile_;
|
||||
$rootScope = _$rootScope_;
|
||||
})
|
||||
);
|
||||
|
||||
it('should call scrollIntoView on aria-activedescendant changes', () => {
|
||||
const scope = $rootScope.$new();
|
||||
scope.ad = '';
|
||||
const element = $compile(`<div aria-activedescendant="{{ad}}" scrollto-activedescendant>
|
||||
<span id="child1"></span>
|
||||
<span id="child2"></span>
|
||||
</div>`)(scope);
|
||||
const child1 = element.find('#child1');
|
||||
const child2 = element.find('#child2');
|
||||
sinon.spy(child1[0], 'scrollIntoView');
|
||||
sinon.spy(child2[0], 'scrollIntoView');
|
||||
scope.ad = 'child1';
|
||||
scope.$digest();
|
||||
expect(child1[0].scrollIntoView.calledOnce).to.be.eql(true);
|
||||
scope.ad = 'child2';
|
||||
scope.$digest();
|
||||
expect(child2[0].scrollIntoView.calledOnce).to.be.eql(true);
|
||||
});
|
||||
});
|
|
@ -1 +0,0 @@
|
|||
@import './kbn_ui_ace_keyboard_mode';
|
|
@ -1,24 +0,0 @@
|
|||
.kbnUiAceKeyboardHint {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
background: transparentize($euiColorEmptyShade, 0.3);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
opacity: 0;
|
||||
|
||||
&:focus {
|
||||
opacity: 1;
|
||||
border: 2px solid $euiColorPrimary;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
&.kbnUiAceKeyboardHint-isInactive {
|
||||
display: none;
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* 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 'angular-aria';
|
||||
import { uiModules } from '../modules';
|
||||
|
||||
/**
|
||||
* This module will take care of attaching appropriate aria tags related to some angular stuff,
|
||||
* e.g. it will attach aria-invalid if the model state is set to invalid.
|
||||
*
|
||||
* You can find more infos in the official documentation: https://docs.angularjs.org/api/ngAria.
|
||||
*
|
||||
* Three settings are disabled: it won't automatically attach `tabindex`, `role=button` or
|
||||
* handling keyboard events for `ngClick` directives. Kibana uses `kbnAccessibleClick` to handle
|
||||
* those cases where you need an `ngClick` non button element to have keyboard access.
|
||||
*/
|
||||
uiModules.get('kibana', ['ngAria']).config(($ariaProvider) => {
|
||||
$ariaProvider.config({
|
||||
bindKeydown: false,
|
||||
bindRoleForClick: false,
|
||||
tabindex: false,
|
||||
});
|
||||
});
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
* 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 './angular_aria';
|
||||
import './kbn_accessible_click';
|
||||
import './scrollto_activedescendant';
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Interactive elements must be able to receive focus.
|
||||
*
|
||||
* Ideally, this means using elements that are natively keyboard accessible (<a href="">,
|
||||
* <input type="button">, or <button>). Note that links should be used when navigating and buttons
|
||||
* should be used when performing an action on the page.
|
||||
*
|
||||
* If you need to use a <div>, <p>, or <a> without the href attribute, then you need to allow
|
||||
* them to receive focus and to respond to keyboard input. The workaround is to:
|
||||
*
|
||||
* - Give the element tabindex="0" so that it can receive keyboard focus.
|
||||
* - Add a JavaScript onkeyup event handler that triggers element functionality if the Enter key
|
||||
* is pressed while the element is focused. This is necessary because some browsers do not trigger
|
||||
* onclick events for such elements when activated via the keyboard.
|
||||
* - If the item is meant to function as a button, the onkeyup event handler should also detect the
|
||||
* Spacebar in addition to the Enter key, and the element should be given role="button".
|
||||
*
|
||||
* Apply this directive to any of these elements to automatically do the above.
|
||||
*/
|
||||
|
||||
import { uiModules } from '../modules';
|
||||
import { KbnAccessibleClickProvider } from '../../../../plugins/kibana_legacy/public';
|
||||
|
||||
uiModules.get('kibana').directive('kbnAccessibleClick', KbnAccessibleClickProvider);
|
|
@ -1,129 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The `kbn-ui-ace-keyboard-mode` directive should be used on any element, that
|
||||
* `ui-ace` is used on. It will prevent the keyboard trap, that ui-ace usually
|
||||
* has, i.e. tabbing into the box won't give you any possibilities to leave
|
||||
* it via keyboard again, since tab inside the textbox works like a tab character.
|
||||
*
|
||||
* This directive won't change anything, if the user uses the mouse. But if she
|
||||
* tabs to the ace editor, an overlay will be shown, that you have to press Enter
|
||||
* to enter editing mode, and that it can be left by pressing Escape again.
|
||||
*
|
||||
* That way the ui-ace editor won't trap keyboard focus, and won't cause that
|
||||
* accessibility issue anymore.
|
||||
*/
|
||||
|
||||
import angular from 'angular';
|
||||
import { uiModules } from '../modules';
|
||||
import { keys } from '@elastic/eui';
|
||||
|
||||
let aceKeyboardModeId = 0;
|
||||
|
||||
uiModules
|
||||
.get('kibana')
|
||||
.factory('kbnUiAceKeyboardModeService', () => ({
|
||||
initialize(scope, element) {
|
||||
const uniqueId = `kbnUiAceKeyboardHint-${scope.$id}-${aceKeyboardModeId++}`;
|
||||
|
||||
const hint = angular.element(
|
||||
`<div
|
||||
class="kbnUiAceKeyboardHint"
|
||||
id="${uniqueId}"
|
||||
tabindex="0"
|
||||
role="application"
|
||||
>
|
||||
<p class="kuiText kuiVerticalRhythmSmall">
|
||||
Press Enter to start editing.
|
||||
</p>
|
||||
<p class="kuiText kuiVerticalRhythmSmall">
|
||||
When you’re done, press Escape to stop editing.
|
||||
</p>
|
||||
</div>`
|
||||
);
|
||||
|
||||
const uiAceTextbox = element.find('textarea');
|
||||
|
||||
function startEditing() {
|
||||
// We are not using ng-class in the element, so that we won't need to $compile it
|
||||
hint.addClass('kbnUiAceKeyboardHint-isInactive');
|
||||
uiAceTextbox.focus();
|
||||
}
|
||||
|
||||
function enableOverlay() {
|
||||
hint.removeClass('kbnUiAceKeyboardHint-isInactive');
|
||||
}
|
||||
|
||||
hint.keydown((ev) => {
|
||||
if (ev.key === keys.ENTER) {
|
||||
ev.preventDefault();
|
||||
startEditing();
|
||||
}
|
||||
});
|
||||
|
||||
uiAceTextbox.blur(() => {
|
||||
enableOverlay();
|
||||
});
|
||||
|
||||
let isAutoCompleterOpen;
|
||||
|
||||
// We have to capture this event on the 'capture' phase, otherwise Ace will have already
|
||||
// dismissed the autocompleter when the user hits ESC.
|
||||
document.addEventListener(
|
||||
'keydown',
|
||||
() => {
|
||||
const autoCompleter = document.querySelector('.ace_autocomplete');
|
||||
|
||||
if (!autoCompleter) {
|
||||
isAutoCompleterOpen = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// The autoComplete is just hidden when it's closed, not removed from the DOM.
|
||||
isAutoCompleterOpen = autoCompleter.style.display !== 'none';
|
||||
},
|
||||
{ capture: true }
|
||||
);
|
||||
|
||||
uiAceTextbox.keydown((ev) => {
|
||||
if (ev.key === keys.ESCAPE) {
|
||||
// If the autocompletion context menu is open then we want to let ESC close it but
|
||||
// **not** exit out of editing mode.
|
||||
if (!isAutoCompleterOpen) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
enableOverlay();
|
||||
hint.focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
hint.click(startEditing);
|
||||
// Prevent tabbing into the ACE textarea, we now handle all focusing for it
|
||||
uiAceTextbox.attr('tabindex', '-1');
|
||||
element.prepend(hint);
|
||||
},
|
||||
}))
|
||||
.directive('kbnUiAceKeyboardMode', (kbnUiAceKeyboardModeService) => ({
|
||||
restrict: 'A',
|
||||
link(scope, element) {
|
||||
kbnUiAceKeyboardModeService.initialize(scope, element);
|
||||
},
|
||||
}));
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This directive can be applied to an element, that has also aria-activedescendant applied.
|
||||
* It will make sure, that whenever aria-activedescendant changes, the new element
|
||||
* referenced by it, will be scrolled into visible view, by calling its `scrollIntoView`
|
||||
* method.
|
||||
*/
|
||||
|
||||
import { uiModules } from '../modules';
|
||||
|
||||
uiModules.get('kibana').directive('scrolltoActivedescendant', () => ({
|
||||
link(scope, element, attrs) {
|
||||
scope.$watch(
|
||||
() => attrs.ariaActivedescendant,
|
||||
(val) => {
|
||||
if (val) {
|
||||
const activeDescendant = element.find(`#${val}`);
|
||||
if (activeDescendant.length) {
|
||||
activeDescendant[0].scrollIntoView();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
}));
|
28
src/legacy/ui/public/angular_ui_select.js
vendored
28
src/legacy/ui/public/angular_ui_select.js
vendored
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* 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 'jquery';
|
||||
import 'angular';
|
||||
// required for `ngSanitize` angular module
|
||||
import 'angular-sanitize';
|
||||
import 'ui-select/dist/select';
|
||||
|
||||
import { uiModules } from 'ui/modules';
|
||||
|
||||
uiModules.get('kibana', ['ui.select', 'ngSanitize']);
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* 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 '../accessibility';
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
* 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 './accessibility';
|
||||
import './modules';
|
||||
import './settings';
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* 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 'angular';
|
||||
import '../chrome';
|
||||
import '../config';
|
||||
import '../notify';
|
||||
import '../private';
|
||||
import '../promises';
|
||||
import '../state_management/app_state';
|
||||
import '../state_management/global_state';
|
||||
import '../url';
|
||||
import '../directives/watch_multi';
|
||||
import '../react_components';
|
||||
import '../i18n';
|
||||
|
||||
import '@elastic/ui-ace';
|
||||
import { uiModules } from 'ui/modules';
|
||||
uiModules.get('kibana', ['ui.ace']);
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/** Left intentionally empty to avoid breaking plugins that import this file during the NP migration */
|
|
@ -1,88 +0,0 @@
|
|||
/*
|
||||
* 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 sinon from 'sinon';
|
||||
import expect from '@kbn/expect';
|
||||
import ngMock from 'ng_mock';
|
||||
|
||||
import { Binder } from '..';
|
||||
import $ from 'jquery';
|
||||
|
||||
describe('Binder class', function () {
|
||||
let $scope;
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
beforeEach(
|
||||
ngMock.inject(function ($rootScope) {
|
||||
$scope = $rootScope.$new();
|
||||
})
|
||||
);
|
||||
|
||||
describe('Constructing with a $scope', function () {
|
||||
it('accepts a $scope and listens for $destroy', function () {
|
||||
sinon.stub($scope, '$on');
|
||||
new Binder($scope);
|
||||
expect($scope.$on.callCount).to.be(1);
|
||||
expect($scope.$on.args[0][0]).to.be('$destroy');
|
||||
});
|
||||
|
||||
it('unbinds when the $scope is destroyed', function () {
|
||||
const binder = new Binder($scope);
|
||||
sinon.stub(binder, 'destroy');
|
||||
$scope.$destroy();
|
||||
expect(binder.destroy.callCount).to.be(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Binder#on', function () {
|
||||
it('binds to normal event emitters', function () {
|
||||
const binder = new Binder();
|
||||
const emitter = {
|
||||
on: sinon.stub(),
|
||||
removeListener: sinon.stub(),
|
||||
};
|
||||
const handler = sinon.stub();
|
||||
|
||||
binder.on(emitter, 'click', handler);
|
||||
expect(emitter.on.callCount).to.be(1);
|
||||
expect(emitter.on.args[0][0]).to.be('click');
|
||||
expect(emitter.on.args[0][1]).to.be(handler);
|
||||
|
||||
binder.destroy();
|
||||
expect(emitter.removeListener.callCount).to.be(1);
|
||||
expect(emitter.removeListener.args[0][0]).to.be('click');
|
||||
expect(emitter.removeListener.args[0][1]).to.be(handler);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Binder#jqOn', function () {
|
||||
it('binds jquery event handlers', function () {
|
||||
const binder = new Binder();
|
||||
const el = document.createElement('div');
|
||||
const handler = sinon.stub();
|
||||
|
||||
binder.jqOn(el, 'click', handler);
|
||||
$(el).click();
|
||||
expect(handler.callCount).to.be(1);
|
||||
binder.destroy();
|
||||
$(el).click();
|
||||
expect(handler.callCount).to.be(1);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* 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 d3 from 'd3';
|
||||
import $ from 'jquery';
|
||||
|
||||
import { BinderBase } from '../../../utils/binder';
|
||||
|
||||
export class Binder extends BinderBase {
|
||||
constructor($scope) {
|
||||
super();
|
||||
|
||||
// support auto-binding to $scope objects
|
||||
if ($scope) {
|
||||
$scope.$on('$destroy', () => this.destroy());
|
||||
}
|
||||
}
|
||||
|
||||
jqOn(el, ...args) {
|
||||
const $el = $(el);
|
||||
$el.on(...args);
|
||||
this.disposal.push(() => $el.off(...args));
|
||||
}
|
||||
|
||||
fakeD3Bind(el, event, handler) {
|
||||
this.jqOn(el, event, (e) => {
|
||||
// mimic https://github.com/mbostock/d3/blob/3abb00113662463e5c19eb87cd33f6d0ddc23bc0/src/selection/on.js#L87-L94
|
||||
const o = d3.event; // Events can be reentrant (e.g., focus).
|
||||
d3.event = e;
|
||||
try {
|
||||
handler.apply(this, [this.__data__]);
|
||||
} finally {
|
||||
d3.event = o;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { Binder } from './binder';
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* 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 _ from 'lodash';
|
||||
|
||||
export function BoundToConfigObjProvider(config) {
|
||||
/**
|
||||
* Create an object with properties that may be bound to config values.
|
||||
* The input object is basically cloned unless one of it's own properties
|
||||
* resolved to a string value that starts with an equal sign. When that is
|
||||
* found, that property is forever bound to the corresponding config key.
|
||||
*
|
||||
* example:
|
||||
*
|
||||
* // name is cloned, height is bound to the defaultHeight config key
|
||||
* { name: 'john', height: '=defaultHeight' };
|
||||
*
|
||||
* @param {Object} input
|
||||
* @return {Object}
|
||||
*/
|
||||
function BoundToConfigObj(input) {
|
||||
const self = this;
|
||||
|
||||
_.forOwn(input, function (value, prop) {
|
||||
if (!_.isString(value) || value.charAt(0) !== '=') {
|
||||
self[prop] = value;
|
||||
return;
|
||||
}
|
||||
|
||||
const configKey = value.substr(1);
|
||||
|
||||
config.watch(configKey, function update(value) {
|
||||
self[prop] = value;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return BoundToConfigObj;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
* 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 { npStart } from 'ui/new_platform';
|
||||
import { Capabilities as UICapabilities } from '../../../../core/public';
|
||||
|
||||
export { UICapabilities };
|
||||
|
||||
export const capabilities = {
|
||||
get() {
|
||||
return npStart.core.application.capabilities;
|
||||
},
|
||||
};
|
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { UICapabilitiesProvider } from './ui_capabilities_provider';
|
||||
export { injectUICapabilities } from './inject_ui_capabilities';
|
|
@ -1,116 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
jest.mock('ui/capabilities', () => ({
|
||||
capabilities: {
|
||||
get: () => ({
|
||||
uiCapability1: true,
|
||||
uiCapability2: {
|
||||
nestedProp: 'nestedValue',
|
||||
},
|
||||
}),
|
||||
},
|
||||
}));
|
||||
|
||||
import { mount } from 'enzyme';
|
||||
import React from 'react';
|
||||
import { UICapabilities } from '..';
|
||||
import { injectUICapabilities } from './inject_ui_capabilities';
|
||||
import { UICapabilitiesProvider } from './ui_capabilities_provider';
|
||||
|
||||
describe('injectUICapabilities', () => {
|
||||
it('provides UICapabilities to FCs', () => {
|
||||
interface FCProps {
|
||||
uiCapabilities: UICapabilities;
|
||||
}
|
||||
|
||||
const MyFC = injectUICapabilities(({ uiCapabilities }: FCProps) => {
|
||||
return <span>{uiCapabilities.uiCapability2.nestedProp}</span>;
|
||||
});
|
||||
|
||||
const wrapper = mount(
|
||||
<UICapabilitiesProvider>
|
||||
<MyFC />
|
||||
</UICapabilitiesProvider>
|
||||
);
|
||||
|
||||
expect(wrapper).toMatchInlineSnapshot(`
|
||||
<UICapabilitiesProvider>
|
||||
<InjectUICapabilities(Component)>
|
||||
<Component
|
||||
uiCapabilities={
|
||||
Object {
|
||||
"uiCapability1": true,
|
||||
"uiCapability2": Object {
|
||||
"nestedProp": "nestedValue",
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<span>
|
||||
nestedValue
|
||||
</span>
|
||||
</Component>
|
||||
</InjectUICapabilities(Component)>
|
||||
</UICapabilitiesProvider>
|
||||
`);
|
||||
});
|
||||
|
||||
it('provides UICapabilities to class components', () => {
|
||||
interface ClassProps {
|
||||
uiCapabilities: UICapabilities;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react/prefer-stateless-function
|
||||
class MyClassComponent extends React.Component<ClassProps, {}> {
|
||||
public render() {
|
||||
return <span>{this.props.uiCapabilities.uiCapability2.nestedProp}</span>;
|
||||
}
|
||||
}
|
||||
|
||||
const WrappedComponent = injectUICapabilities(MyClassComponent);
|
||||
|
||||
const wrapper = mount(
|
||||
<UICapabilitiesProvider>
|
||||
<WrappedComponent />
|
||||
</UICapabilitiesProvider>
|
||||
);
|
||||
|
||||
expect(wrapper).toMatchInlineSnapshot(`
|
||||
<UICapabilitiesProvider>
|
||||
<InjectUICapabilities(MyClassComponent)>
|
||||
<MyClassComponent
|
||||
uiCapabilities={
|
||||
Object {
|
||||
"uiCapability1": true,
|
||||
"uiCapability2": Object {
|
||||
"nestedProp": "nestedValue",
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<span>
|
||||
nestedValue
|
||||
</span>
|
||||
</MyClassComponent>
|
||||
</InjectUICapabilities(MyClassComponent)>
|
||||
</UICapabilitiesProvider>
|
||||
`);
|
||||
});
|
||||
});
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* 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 React, { Component, ComponentClass, ComponentType } from 'react';
|
||||
import { UICapabilitiesContext } from './ui_capabilities_context';
|
||||
import { UICapabilities } from '..';
|
||||
|
||||
function getDisplayName(component: ComponentType<any>) {
|
||||
return component.displayName || component.name || 'Component';
|
||||
}
|
||||
|
||||
interface InjectedProps {
|
||||
uiCapabilities: UICapabilities;
|
||||
}
|
||||
|
||||
export function injectUICapabilities<P>(
|
||||
WrappedComponent: ComponentType<P & InjectedProps>
|
||||
): ComponentClass<Pick<P, Exclude<keyof P, keyof InjectedProps>>> & {
|
||||
WrappedComponent: ComponentType<P & InjectedProps>;
|
||||
} {
|
||||
class InjectUICapabilities extends Component<P, any> {
|
||||
public static displayName = `InjectUICapabilities(${getDisplayName(WrappedComponent)})`;
|
||||
|
||||
public static WrappedComponent: ComponentType<P & InjectedProps> = WrappedComponent;
|
||||
|
||||
public static contextType = UICapabilitiesContext;
|
||||
|
||||
constructor(props: any, context: any) {
|
||||
super(props, context);
|
||||
}
|
||||
|
||||
public render() {
|
||||
return <WrappedComponent {...this.props} {...{ uiCapabilities: this.context }} />;
|
||||
}
|
||||
}
|
||||
return InjectUICapabilities;
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { UICapabilitiesProvider } from './ui_capabilities_provider';
|
||||
export { injectUICapabilities } from './inject_ui_capabilities';
|
|
@ -1,116 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
jest.mock('ui/capabilities', () => ({
|
||||
capabilities: {
|
||||
get: () => ({
|
||||
uiCapability1: true,
|
||||
uiCapability2: {
|
||||
nestedProp: 'nestedValue',
|
||||
},
|
||||
}),
|
||||
},
|
||||
}));
|
||||
|
||||
import { mount } from 'enzyme';
|
||||
import React from 'react';
|
||||
import { UICapabilities } from '../..';
|
||||
import { injectUICapabilities } from './inject_ui_capabilities';
|
||||
import { UICapabilitiesProvider } from './ui_capabilities_provider';
|
||||
|
||||
describe('injectUICapabilities', () => {
|
||||
it('provides UICapabilities to FCs', () => {
|
||||
interface FCProps {
|
||||
uiCapabilities: UICapabilities;
|
||||
}
|
||||
|
||||
const MyFC = injectUICapabilities(({ uiCapabilities }: FCProps) => {
|
||||
return <span>{uiCapabilities.uiCapability2.nestedProp}</span>;
|
||||
});
|
||||
|
||||
const wrapper = mount(
|
||||
<UICapabilitiesProvider>
|
||||
<MyFC />
|
||||
</UICapabilitiesProvider>
|
||||
);
|
||||
|
||||
expect(wrapper).toMatchInlineSnapshot(`
|
||||
<UICapabilitiesProvider>
|
||||
<InjectUICapabilities(Component)>
|
||||
<Component
|
||||
uiCapabilities={
|
||||
Object {
|
||||
"uiCapability1": true,
|
||||
"uiCapability2": Object {
|
||||
"nestedProp": "nestedValue",
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<span>
|
||||
nestedValue
|
||||
</span>
|
||||
</Component>
|
||||
</InjectUICapabilities(Component)>
|
||||
</UICapabilitiesProvider>
|
||||
`);
|
||||
});
|
||||
|
||||
it('provides UICapabilities to class components', () => {
|
||||
interface ClassProps {
|
||||
uiCapabilities: UICapabilities;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react/prefer-stateless-function
|
||||
class MyClassComponent extends React.Component<ClassProps, {}> {
|
||||
public render() {
|
||||
return <span>{this.props.uiCapabilities.uiCapability2.nestedProp}</span>;
|
||||
}
|
||||
}
|
||||
|
||||
const WrappedComponent = injectUICapabilities(MyClassComponent);
|
||||
|
||||
const wrapper = mount(
|
||||
<UICapabilitiesProvider>
|
||||
<WrappedComponent />
|
||||
</UICapabilitiesProvider>
|
||||
);
|
||||
|
||||
expect(wrapper).toMatchInlineSnapshot(`
|
||||
<UICapabilitiesProvider>
|
||||
<InjectUICapabilities(MyClassComponent)>
|
||||
<MyClassComponent
|
||||
uiCapabilities={
|
||||
Object {
|
||||
"uiCapability1": true,
|
||||
"uiCapability2": Object {
|
||||
"nestedProp": "nestedValue",
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<span>
|
||||
nestedValue
|
||||
</span>
|
||||
</MyClassComponent>
|
||||
</InjectUICapabilities(MyClassComponent)>
|
||||
</UICapabilitiesProvider>
|
||||
`);
|
||||
});
|
||||
});
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
* 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 PropTypes from 'prop-types';
|
||||
import React, { Component, ComponentClass, ComponentType } from 'react';
|
||||
import { UICapabilities } from '../..';
|
||||
|
||||
function getDisplayName(component: ComponentType<any>) {
|
||||
return component.displayName || component.name || 'Component';
|
||||
}
|
||||
|
||||
interface InjectedProps {
|
||||
uiCapabilities: UICapabilities;
|
||||
}
|
||||
|
||||
export function injectUICapabilities<P>(
|
||||
WrappedComponent: ComponentType<P & InjectedProps>
|
||||
): ComponentClass<Pick<P, Exclude<keyof P, keyof InjectedProps>>> & {
|
||||
WrappedComponent: ComponentType<P & InjectedProps>;
|
||||
} {
|
||||
class InjectUICapabilities extends Component<P, any> {
|
||||
public static displayName = `InjectUICapabilities(${getDisplayName(WrappedComponent)})`;
|
||||
|
||||
public static WrappedComponent: ComponentType<P & InjectedProps> = WrappedComponent;
|
||||
|
||||
public static contextTypes = {
|
||||
uiCapabilities: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
constructor(props: any, context: any) {
|
||||
super(props, context);
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<WrappedComponent {...this.props} {...{ uiCapabilities: this.context.uiCapabilities }} />
|
||||
);
|
||||
}
|
||||
}
|
||||
return InjectUICapabilities;
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* 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 PropTypes from 'prop-types';
|
||||
import React, { ReactNode } from 'react';
|
||||
import { capabilities, UICapabilities } from '../..';
|
||||
|
||||
interface Props {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
interface ProviderContext {
|
||||
uiCapabilities: UICapabilities;
|
||||
}
|
||||
|
||||
export class UICapabilitiesProvider extends React.Component<Props, {}> {
|
||||
public static displayName: string = 'UICapabilitiesProvider';
|
||||
|
||||
public static childContextTypes = {
|
||||
uiCapabilities: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
public getChildContext(): ProviderContext {
|
||||
return {
|
||||
uiCapabilities: capabilities.get(),
|
||||
};
|
||||
}
|
||||
|
||||
public render() {
|
||||
return React.Children.only(this.props.children);
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* 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 React from 'react';
|
||||
import { UICapabilities } from '..';
|
||||
|
||||
export const UICapabilitiesContext = React.createContext<UICapabilities>({
|
||||
navLinks: {},
|
||||
catalogue: {},
|
||||
management: {},
|
||||
});
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* 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 React from 'react';
|
||||
import { UICapabilitiesContext } from './ui_capabilities_context';
|
||||
import { capabilities } from '..';
|
||||
|
||||
export const UICapabilitiesProvider: React.FC = (props) => (
|
||||
<UICapabilitiesContext.Provider value={capabilities.get()}>
|
||||
{props.children}
|
||||
</UICapabilitiesContext.Provider>
|
||||
);
|
||||
|
||||
UICapabilitiesProvider.displayName = 'UICapabilitiesProvider';
|
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
* 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 { uiSettingsServiceMock } from '../../../../../core/public/mocks';
|
||||
|
||||
const uiSettingsClient = {
|
||||
...uiSettingsServiceMock.createSetupContract(),
|
||||
getUpdate$: () => ({
|
||||
subscribe: jest.fn(),
|
||||
}),
|
||||
};
|
||||
|
||||
const chrome = {
|
||||
addBasePath: (path) => (path ? path : 'test/base/path'),
|
||||
breadcrumbs: {
|
||||
set: () => ({}),
|
||||
},
|
||||
getBasePath: () => '/test/base/path',
|
||||
getInjected: jest.fn(),
|
||||
getUiSettingsClient: () => uiSettingsClient,
|
||||
getSavedObjectsClient: () => '',
|
||||
getXsrfToken: () => 'kbn-xsrf-token',
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default chrome;
|
||||
|
||||
// Copied from `src/legacy/ui/public/chrome/chrome.js`
|
||||
import _ from 'lodash';
|
||||
import angular from 'angular';
|
||||
import { metadata } from '../../metadata';
|
||||
|
||||
const internals = _.defaults(_.cloneDeep(metadata), {
|
||||
basePath: '',
|
||||
rootController: null,
|
||||
rootTemplate: null,
|
||||
showAppsLink: null,
|
||||
xsrfToken: null,
|
||||
devMode: true,
|
||||
brand: null,
|
||||
nav: [],
|
||||
applicationClasses: [],
|
||||
});
|
||||
|
||||
const waitForBootstrap = new Promise((resolve) => {
|
||||
chrome.bootstrap = function (targetDomElement) {
|
||||
// sets attribute on body for stylesheet sandboxing
|
||||
document.body.setAttribute('id', `${internals.app.id}-app`);
|
||||
|
||||
chrome.setupAngular();
|
||||
targetDomElement.setAttribute('kbn-chrome', 'true');
|
||||
targetDomElement.setAttribute('ng-class', "{ 'hidden-chrome': !chrome.getVisible() }");
|
||||
targetDomElement.className = 'app-wrapper';
|
||||
angular.bootstrap(targetDomElement, ['kibana']);
|
||||
resolve(targetDomElement);
|
||||
};
|
||||
});
|
||||
|
||||
chrome.dangerouslyGetActiveInjector = () => {
|
||||
return waitForBootstrap.then((targetDomElement) => {
|
||||
const $injector = angular.element(targetDomElement).injector();
|
||||
if (!$injector) {
|
||||
return Promise.reject('targetDomElement had no angular context after bootstrapping');
|
||||
}
|
||||
return $injector;
|
||||
});
|
||||
};
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* 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 { initAngularApi } from '../angular';
|
||||
import { noop } from 'lodash';
|
||||
|
||||
describe('Chrome API :: Angular', () => {
|
||||
describe('location helper methods', () => {
|
||||
it('should return the sub app based on the url', () => {
|
||||
const chrome = {
|
||||
getInjected: noop,
|
||||
addBasePath: noop,
|
||||
};
|
||||
initAngularApi(chrome, {
|
||||
devMode: true,
|
||||
});
|
||||
});
|
||||
it('should return breadcrumbs based on the url', () => {});
|
||||
});
|
||||
});
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
* 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 expect from '@kbn/expect';
|
||||
|
||||
import setup from '../apps';
|
||||
|
||||
describe('Chrome API :: apps', function () {
|
||||
describe('#get/setShowAppsLink()', function () {
|
||||
describe('defaults to false if there are less than two apps', function () {
|
||||
it('appCount = 0', function () {
|
||||
const chrome = {};
|
||||
setup(chrome, { nav: [] });
|
||||
expect(chrome.getShowAppsLink()).to.equal(false);
|
||||
});
|
||||
|
||||
it('appCount = 1', function () {
|
||||
const chrome = {};
|
||||
setup(chrome, { nav: [{ url: '/' }] });
|
||||
expect(chrome.getShowAppsLink()).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('defaults to true if there are two or more apps', function () {
|
||||
it('appCount = 2', function () {
|
||||
const chrome = {};
|
||||
setup(chrome, { nav: [{ url: '/' }, { url: '/2' }] });
|
||||
expect(chrome.getShowAppsLink()).to.equal(true);
|
||||
});
|
||||
|
||||
it('appCount = 3', function () {
|
||||
const chrome = {};
|
||||
setup(chrome, { nav: [{ url: '/' }, { url: '/2' }, { url: '/3' }] });
|
||||
expect(chrome.getShowAppsLink()).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('is chainable', function () {
|
||||
const chrome = {};
|
||||
setup(chrome, { nav: [{ url: '/' }] });
|
||||
expect(chrome.setShowAppsLink(true)).to.equal(chrome);
|
||||
});
|
||||
|
||||
it('can be changed', function () {
|
||||
const chrome = {};
|
||||
setup(chrome, { nav: [{ url: '/' }] });
|
||||
|
||||
expect(chrome.setShowAppsLink(true).getShowAppsLink()).to.equal(true);
|
||||
expect(chrome.getShowAppsLink()).to.equal(true);
|
||||
|
||||
expect(chrome.setShowAppsLink(false).getShowAppsLink()).to.equal(false);
|
||||
expect(chrome.getShowAppsLink()).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getApp()', function () {
|
||||
it('returns a clone of the current app', function () {
|
||||
const chrome = {};
|
||||
const app = { url: '/' };
|
||||
setup(chrome, { app });
|
||||
|
||||
expect(chrome.getApp()).to.eql(app);
|
||||
expect(chrome.getApp()).to.not.equal(app);
|
||||
});
|
||||
|
||||
it('returns undefined if no active app', function () {
|
||||
const chrome = {};
|
||||
setup(chrome, {});
|
||||
expect(chrome.getApp()).to.equal(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getAppTitle()', function () {
|
||||
it('returns the title property of the current app', function () {
|
||||
const chrome = {};
|
||||
const app = { url: '/', title: 'foo' };
|
||||
setup(chrome, { app });
|
||||
expect(chrome.getAppTitle()).to.eql('foo');
|
||||
});
|
||||
|
||||
it('returns undefined if no active app', function () {
|
||||
const chrome = {};
|
||||
setup(chrome, {});
|
||||
expect(chrome.getAppTitle()).to.equal(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getAppUrl()', function () {
|
||||
it('returns the resolved url of the current app', function () {
|
||||
const chrome = {};
|
||||
const app = { navLink: { url: '/foo' } };
|
||||
setup(chrome, { app });
|
||||
|
||||
const a = document.createElement('a');
|
||||
a.setAttribute('href', app.navLink.url);
|
||||
expect(chrome.getAppUrl()).to.equal(a.href);
|
||||
});
|
||||
|
||||
it('returns undefined if no active app', function () {
|
||||
const chrome = {};
|
||||
setup(chrome, {});
|
||||
expect(chrome.getAppUrl()).to.equal(undefined);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,143 +0,0 @@
|
|||
/*
|
||||
* 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 expect from '@kbn/expect';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import { initChromeNavApi } from '../nav';
|
||||
import { StubBrowserStorage } from 'test_utils/stub_browser_storage';
|
||||
import { npStart } from 'ui/new_platform';
|
||||
import { absoluteToParsedUrl } from '../../../url/absolute_to_parsed_url';
|
||||
|
||||
const basePath = '/someBasePath';
|
||||
|
||||
function init(customInternals = { basePath }) {
|
||||
const chrome = {
|
||||
addBasePath: (path) => path,
|
||||
getBasePath: () => customInternals.basePath || '',
|
||||
};
|
||||
const internals = {
|
||||
nav: [],
|
||||
...customInternals,
|
||||
};
|
||||
initChromeNavApi(chrome, internals);
|
||||
return { chrome, internals };
|
||||
}
|
||||
|
||||
describe('chrome nav apis', function () {
|
||||
let coreNavLinks;
|
||||
let fakedLinks = [];
|
||||
|
||||
const baseUrl = (function () {
|
||||
const a = document.createElement('a');
|
||||
a.setAttribute('href', '/');
|
||||
return a.href.slice(0, a.href.length - 1);
|
||||
})();
|
||||
|
||||
beforeEach(() => {
|
||||
coreNavLinks = npStart.core.chrome.navLinks;
|
||||
sinon.stub(coreNavLinks, 'update').callsFake((linkId, updateAttrs) => {
|
||||
const link = fakedLinks.find(({ id }) => id === linkId);
|
||||
for (const key of Object.keys(updateAttrs)) {
|
||||
link[key] = updateAttrs[key];
|
||||
}
|
||||
return link;
|
||||
});
|
||||
sinon.stub(coreNavLinks, 'getAll').callsFake(() => fakedLinks);
|
||||
sinon
|
||||
.stub(coreNavLinks, 'get')
|
||||
.callsFake((linkId) => fakedLinks.find(({ id }) => id === linkId));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
coreNavLinks.update.restore();
|
||||
coreNavLinks.getAll.restore();
|
||||
coreNavLinks.get.restore();
|
||||
});
|
||||
|
||||
describe('#untrackNavLinksForDeletedSavedObjects', function () {
|
||||
const appId = 'appId';
|
||||
const appUrl = `${baseUrl}/app/kibana#test`;
|
||||
const deletedId = 'IAMDELETED';
|
||||
|
||||
it('should clear last url when last url contains link to deleted saved object', function () {
|
||||
const appUrlStore = new StubBrowserStorage();
|
||||
fakedLinks = [
|
||||
{
|
||||
id: appId,
|
||||
title: 'Discover',
|
||||
url: `${appUrl}?id=${deletedId}`,
|
||||
baseUrl: appUrl,
|
||||
linkToLastSubUrl: true,
|
||||
legacy: true,
|
||||
},
|
||||
];
|
||||
|
||||
const { chrome } = init({ appUrlStore });
|
||||
chrome.untrackNavLinksForDeletedSavedObjects([deletedId]);
|
||||
expect(coreNavLinks.update.calledWith(appId, { url: appUrl })).to.be(true);
|
||||
});
|
||||
|
||||
it('should not clear last url when last url does not contains link to deleted saved object', function () {
|
||||
const lastUrl = `${appUrl}?id=anotherSavedObjectId`;
|
||||
const appUrlStore = new StubBrowserStorage();
|
||||
fakedLinks = [
|
||||
{
|
||||
id: appId,
|
||||
title: 'Discover',
|
||||
url: lastUrl,
|
||||
baseUrl: appUrl,
|
||||
linkToLastSubUrl: true,
|
||||
legacy: true,
|
||||
},
|
||||
];
|
||||
|
||||
const { chrome } = init({ appUrlStore });
|
||||
chrome.untrackNavLinksForDeletedSavedObjects([deletedId]);
|
||||
expect(coreNavLinks.update.calledWith(appId, { url: appUrl })).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('chrome.trackSubUrlForApp()', function () {
|
||||
it('injects a manual app url', function () {
|
||||
const appUrlStore = new StubBrowserStorage();
|
||||
fakedLinks = [
|
||||
{
|
||||
id: 'visualize',
|
||||
baseUrl: `${baseUrl}/app/visualize#`,
|
||||
url: `${baseUrl}/app/visualize#`,
|
||||
subUrlBase: '/app/visualize#',
|
||||
legacy: true,
|
||||
},
|
||||
];
|
||||
|
||||
const { chrome } = init({ appUrlStore });
|
||||
const kibanaParsedUrl = absoluteToParsedUrl(
|
||||
`${baseUrl}/xyz/app/visualize#/1234?_g=globalstate`,
|
||||
'/xyz'
|
||||
);
|
||||
chrome.trackSubUrlForApp('visualize', kibanaParsedUrl);
|
||||
expect(
|
||||
coreNavLinks.update.calledWith('visualize', {
|
||||
url: `${baseUrl}/xyz/app/visualize#/1234?_g=globalstate`,
|
||||
})
|
||||
).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,130 +0,0 @@
|
|||
/*
|
||||
* 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 ngMock from 'ng_mock';
|
||||
import expect from '@kbn/expect';
|
||||
|
||||
import { SubUrlRouteFilterProvider } from '../sub_url_hooks';
|
||||
|
||||
describe('kbn-chrome subUrlRouteFilter()', () => {
|
||||
describe('no ngRoute', () => {
|
||||
beforeEach(ngMock.module('kibana/private'));
|
||||
beforeEach(
|
||||
ngMock.inject(($injector) => {
|
||||
expect($injector.has('$route')).to.be(false);
|
||||
})
|
||||
);
|
||||
|
||||
it(
|
||||
'always returns true when there is no $route service',
|
||||
ngMock.inject((Private) => {
|
||||
const subUrlRouteFilter = Private(SubUrlRouteFilterProvider);
|
||||
expect(subUrlRouteFilter()).to.be(true);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
describe('with ngRoute', () => {
|
||||
beforeEach(
|
||||
ngMock.module('kibana/private', 'ngRoute', ($routeProvider) => {
|
||||
$routeProvider.when('/foo', {
|
||||
redirectTo: '/bar',
|
||||
});
|
||||
|
||||
$routeProvider.when('/bar', {
|
||||
template: '<div>foo => bar</div>',
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
let test;
|
||||
beforeEach(
|
||||
ngMock.inject((Private, $location, $rootScope, $route) => {
|
||||
test = ({ path, assert }) => {
|
||||
const subUrlRouteFilter = Private(SubUrlRouteFilterProvider);
|
||||
$location.path(path);
|
||||
|
||||
let result;
|
||||
function runAssert() {
|
||||
if (result) {
|
||||
// only run once
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
assert($route, subUrlRouteFilter);
|
||||
result = {};
|
||||
} catch (error) {
|
||||
result = { error };
|
||||
}
|
||||
}
|
||||
|
||||
$rootScope.$on('$routeUpdate', runAssert);
|
||||
$rootScope.$on('$routeChangeSuccess', runAssert);
|
||||
$rootScope.$apply();
|
||||
|
||||
// when no route matches there is no event so we run manually
|
||||
if (!result) {
|
||||
runAssert();
|
||||
}
|
||||
|
||||
if (result.error) {
|
||||
throw result.error;
|
||||
}
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
describe('no current route', () => {
|
||||
it('returns false', () => {
|
||||
test({
|
||||
path: '/baz',
|
||||
assert($route, subUrlRouteFilter) {
|
||||
expect($route.current).to.not.be.ok();
|
||||
expect(subUrlRouteFilter()).to.eql(false);
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('redirectTo route', () => {
|
||||
it('is called on target route', () => {
|
||||
test({
|
||||
path: '/foo',
|
||||
assert($route) {
|
||||
expect($route.current.$$route.originalPath).to.be('/bar');
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('standard route', () => {
|
||||
it('returns true', () => {
|
||||
test({
|
||||
path: '/bar',
|
||||
assert($route, subUrlRouteFilter) {
|
||||
expect($route.current).to.be.ok();
|
||||
expect($route.current.template).to.be.ok();
|
||||
expect(subUrlRouteFilter()).to.eql(true);
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* 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 expect from '@kbn/expect';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import { initChromeXsrfApi } from '../xsrf';
|
||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import { version } from '../../../../../../core/server/utils/package_json';
|
||||
|
||||
describe('chrome xsrf apis', function () {
|
||||
const sandbox = sinon.createSandbox();
|
||||
|
||||
afterEach(function () {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe('#getXsrfToken()', function () {
|
||||
it('exposes the token', function () {
|
||||
const chrome = {};
|
||||
initChromeXsrfApi(chrome, { version });
|
||||
expect(chrome.getXsrfToken()).to.be(version);
|
||||
});
|
||||
});
|
||||
});
|
40
src/legacy/ui/public/chrome/api/angular.js
vendored
40
src/legacy/ui/public/chrome/api/angular.js
vendored
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* 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 { uiModules } from '../../modules';
|
||||
|
||||
import { directivesProvider } from '../directives';
|
||||
import { registerSubUrlHooks } from './sub_url_hooks';
|
||||
import { configureAppAngularModule } from 'ui/legacy_compat';
|
||||
import { npStart } from '../../new_platform/new_platform';
|
||||
|
||||
export function initAngularApi(chrome, internals) {
|
||||
chrome.setupAngular = function () {
|
||||
const kibana = uiModules.get('kibana');
|
||||
|
||||
configureAppAngularModule(kibana, npStart.core, false);
|
||||
|
||||
kibana.value('chrome', chrome);
|
||||
|
||||
registerSubUrlHooks(kibana, internals);
|
||||
directivesProvider(chrome, internals);
|
||||
|
||||
uiModules.link(kibana);
|
||||
};
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
* 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 { clone, get } from 'lodash';
|
||||
import { resolve } from 'url';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default function (chrome, internals) {
|
||||
if (get(internals, 'app.navLink.url')) {
|
||||
internals.app.navLink.url = resolve(window.location.href, internals.app.navLink.url);
|
||||
}
|
||||
|
||||
internals.appUrlStore = internals.appUrlStore || window.sessionStorage;
|
||||
try {
|
||||
const verifySessionStorage = 'verify sessionStorage';
|
||||
internals.appUrlStore.setItem(verifySessionStorage, 1);
|
||||
internals.appUrlStore.removeItem(verifySessionStorage);
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
'Kibana requires access to sessionStorage, and it looks like ' +
|
||||
"your browser is restricting it. If you're " +
|
||||
'using Safari with private browsing enabled, you can solve this ' +
|
||||
'problem by disabling private browsing, or by using another browser.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* ui/chrome apps API
|
||||
*
|
||||
* ui/chrome has some metadata about the current app, and enables the
|
||||
* navbar link, a small grid to the left of the tabs, when there is more
|
||||
* than one app installed.
|
||||
*/
|
||||
|
||||
chrome.setShowAppsLink = function (val) {
|
||||
internals.showAppsLink = !!val;
|
||||
return chrome;
|
||||
};
|
||||
|
||||
chrome.getShowAppsLink = function () {
|
||||
return internals.showAppsLink == null ? internals.nav.length > 1 : internals.showAppsLink;
|
||||
};
|
||||
|
||||
chrome.getKibanaVersion = function () {
|
||||
return internals.version;
|
||||
};
|
||||
|
||||
chrome.getApp = function () {
|
||||
return clone(internals.app);
|
||||
};
|
||||
|
||||
chrome.getAppTitle = function () {
|
||||
return get(internals, ['app', 'title']);
|
||||
};
|
||||
|
||||
chrome.getAppUrl = function () {
|
||||
return get(internals, ['app', 'navLink', 'url']);
|
||||
};
|
||||
|
||||
chrome.getLastUrlFor = function (appId) {
|
||||
return internals.appUrlStore.getItem(`appLastUrl:${appId}`);
|
||||
};
|
||||
|
||||
chrome.setLastUrlFor = function (appId, url) {
|
||||
internals.appUrlStore.setItem(`appLastUrl:${appId}`, url);
|
||||
};
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* 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 { chromeServiceMock } from '../../../../../core/public/mocks';
|
||||
|
||||
export const newPlatformChrome = chromeServiceMock.createStartContract();
|
||||
jest.doMock('ui/new_platform', () => ({
|
||||
npStart: {
|
||||
core: { chrome: newPlatformChrome },
|
||||
},
|
||||
}));
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
* 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 * as Rx from 'rxjs';
|
||||
|
||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import { ChromeBadge } from 'src/core/public/chrome';
|
||||
import { newPlatformChrome } from './badge.test.mocks';
|
||||
import { initChromeBadgeApi } from './badge';
|
||||
|
||||
function setup() {
|
||||
const getBadge$ = new Rx.BehaviorSubject<ChromeBadge | undefined>(undefined);
|
||||
newPlatformChrome.getBadge$.mockReturnValue(getBadge$);
|
||||
|
||||
const chrome: any = {};
|
||||
initChromeBadgeApi(chrome);
|
||||
return { chrome, getBadge$ };
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
describe('badge', () => {
|
||||
describe('#get$()', () => {
|
||||
it('returns newPlatformChrome.getBadge$()', () => {
|
||||
const { chrome } = setup();
|
||||
expect(chrome.badge.get$()).toBe(newPlatformChrome.getBadge$());
|
||||
});
|
||||
});
|
||||
|
||||
describe('#set()', () => {
|
||||
it('calls newPlatformChrome.setBadge', () => {
|
||||
const { chrome } = setup();
|
||||
const badge = {
|
||||
text: 'foo',
|
||||
tooltip: `foo's tooltip`,
|
||||
iconType: 'alert',
|
||||
};
|
||||
chrome.badge.set(badge);
|
||||
expect(newPlatformChrome.setBadge).toHaveBeenCalledTimes(1);
|
||||
expect(newPlatformChrome.setBadge).toHaveBeenCalledWith(badge);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* 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 { npStart } from 'ui/new_platform';
|
||||
import { ChromeBadge } from '../../../../../core/public';
|
||||
export type Badge = ChromeBadge;
|
||||
|
||||
export type BadgeApi = ReturnType<typeof createBadgeApi>['badge'];
|
||||
|
||||
const newPlatformChrome = npStart.core.chrome;
|
||||
|
||||
function createBadgeApi() {
|
||||
return {
|
||||
badge: {
|
||||
/**
|
||||
* Get an observable that emits the current badge
|
||||
* and emits each update to the badge
|
||||
*/
|
||||
get$() {
|
||||
return newPlatformChrome.getBadge$();
|
||||
},
|
||||
|
||||
/**
|
||||
* Replace the badge with a new one
|
||||
*/
|
||||
set(newBadge?: Badge) {
|
||||
newPlatformChrome.setBadge(newBadge);
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function initChromeBadgeApi(chrome: Chrome) {
|
||||
const { badge } = createBadgeApi();
|
||||
chrome.badge = badge;
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* 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 { httpServiceMock } from '../../../../../core/public/mocks';
|
||||
|
||||
const newPlatformHttp = httpServiceMock.createSetupContract({ basePath: 'npBasePath' });
|
||||
jest.doMock('ui/new_platform', () => ({
|
||||
npSetup: {
|
||||
core: { http: newPlatformHttp },
|
||||
},
|
||||
}));
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* 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 './base_path.test.mocks';
|
||||
import { initChromeBasePathApi } from './base_path';
|
||||
|
||||
function initChrome() {
|
||||
const chrome: any = {};
|
||||
initChromeBasePathApi(chrome);
|
||||
return chrome;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('#getBasePath()', () => {
|
||||
it('proxies to newPlatformHttp.basePath.get()', () => {
|
||||
const chrome = initChrome();
|
||||
expect(chrome.getBasePath()).toBe('npBasePath');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#addBasePath()', () => {
|
||||
it('proxies to newPlatformHttp.basePath.prepend(path)', () => {
|
||||
const chrome = initChrome();
|
||||
expect(chrome.addBasePath('/foo/bar')).toBe('npBasePath/foo/bar');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#removeBasePath', () => {
|
||||
it('proxies to newPlatformBasePath.basePath.remove(path)', () => {
|
||||
const chrome = initChrome();
|
||||
expect(chrome.removeBasePath('npBasePath/foo/bar')).toBe('/foo/bar');
|
||||
});
|
||||
});
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* 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 { npSetup } from 'ui/new_platform';
|
||||
|
||||
const newPlatformHttp = npSetup.core.http;
|
||||
|
||||
export function initChromeBasePathApi(chrome: { [key: string]: any }) {
|
||||
chrome.getBasePath = newPlatformHttp.basePath.get;
|
||||
chrome.addBasePath = newPlatformHttp.basePath.prepend;
|
||||
chrome.removeBasePath = newPlatformHttp.basePath.remove;
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
* 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 { npStart } from 'ui/new_platform';
|
||||
import { ChromeBreadcrumb } from '../../../../../core/public';
|
||||
export type Breadcrumb = ChromeBreadcrumb;
|
||||
|
||||
export type BreadcrumbsApi = ReturnType<typeof createBreadcrumbsApi>['breadcrumbs'];
|
||||
|
||||
const newPlatformChrome = npStart.core.chrome;
|
||||
|
||||
function createBreadcrumbsApi(chrome: { [key: string]: any }) {
|
||||
let currentBreadcrumbs: Breadcrumb[] = [];
|
||||
|
||||
// reset breadcrumbSetSinceRouteChange any time the breadcrumbs change, even
|
||||
// if it was done directly through the new platform
|
||||
newPlatformChrome.getBreadcrumbs$().subscribe({
|
||||
next(nextBreadcrumbs) {
|
||||
currentBreadcrumbs = nextBreadcrumbs;
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
breadcrumbs: {
|
||||
/**
|
||||
* Get an observerable that emits the current list of breadcrumbs
|
||||
* and emits each update to the breadcrumbs
|
||||
*/
|
||||
get$() {
|
||||
return newPlatformChrome.getBreadcrumbs$();
|
||||
},
|
||||
|
||||
/**
|
||||
* Replace the set of breadcrumbs with a new set
|
||||
*/
|
||||
set(newBreadcrumbs: Breadcrumb[]) {
|
||||
newPlatformChrome.setBreadcrumbs(newBreadcrumbs);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a breadcrumb to the end of the list of breadcrumbs
|
||||
*/
|
||||
push(breadcrumb: Breadcrumb) {
|
||||
newPlatformChrome.setBreadcrumbs([...currentBreadcrumbs, breadcrumb]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Filter the current set of breadcrumbs with a function. Works like Array#filter()
|
||||
*/
|
||||
filter(fn: (breadcrumb: Breadcrumb, i: number, all: Breadcrumb[]) => boolean) {
|
||||
newPlatformChrome.setBreadcrumbs(currentBreadcrumbs.filter(fn));
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove last element of the breadcrumb
|
||||
*/
|
||||
pop() {
|
||||
newPlatformChrome.setBreadcrumbs(currentBreadcrumbs.slice(0, -1));
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function initBreadcrumbsApi(
|
||||
chrome: { [key: string]: any },
|
||||
internals: { [key: string]: any }
|
||||
) {
|
||||
const { breadcrumbs } = createBreadcrumbsApi(chrome);
|
||||
chrome.breadcrumbs = breadcrumbs;
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* 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 { chromeServiceMock } from '../../../../../core/public/mocks';
|
||||
|
||||
export const newPlatformChrome = chromeServiceMock.createStartContract();
|
||||
jest.doMock('ui/new_platform', () => ({
|
||||
npStart: {
|
||||
core: { chrome: newPlatformChrome },
|
||||
},
|
||||
}));
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* 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 * as Rx from 'rxjs';
|
||||
|
||||
import { newPlatformChrome } from './controls.test.mocks';
|
||||
import { initChromeControlsApi } from './controls';
|
||||
|
||||
function setup() {
|
||||
const isVisible$ = new Rx.BehaviorSubject(true);
|
||||
newPlatformChrome.getIsVisible$.mockReturnValue(isVisible$);
|
||||
|
||||
const chrome: any = {};
|
||||
initChromeControlsApi(chrome);
|
||||
return { chrome, isVisible$ };
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
describe('setVisible', () => {
|
||||
it('passes the visibility to the newPlatform', () => {
|
||||
const { chrome } = setup();
|
||||
chrome.setVisible(true);
|
||||
chrome.setVisible(false);
|
||||
chrome.setVisible(false);
|
||||
expect(newPlatformChrome.setIsVisible.mock.calls).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
true,
|
||||
],
|
||||
Array [
|
||||
false,
|
||||
],
|
||||
Array [
|
||||
false,
|
||||
],
|
||||
]
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getVisible', () => {
|
||||
it('returns a the cached value emitted by the newPlatformChrome', () => {
|
||||
const { chrome, isVisible$ } = setup();
|
||||
isVisible$.next(true);
|
||||
expect(chrome.getVisible()).toBe(true);
|
||||
isVisible$.next(false);
|
||||
expect(chrome.getVisible()).toBe(false);
|
||||
});
|
||||
});
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* 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 * as Rx from 'rxjs';
|
||||
import { npStart } from 'ui/new_platform';
|
||||
|
||||
const newPlatformChrome = npStart.core.chrome;
|
||||
|
||||
export function initChromeControlsApi(chrome: { [key: string]: any }) {
|
||||
// cache of chrome visibility state
|
||||
const visible$ = new Rx.BehaviorSubject(false);
|
||||
newPlatformChrome.getIsVisible$().subscribe(visible$);
|
||||
|
||||
/**
|
||||
* Set the temporary visibility for the chrome. This does nothing if the chrome is hidden
|
||||
* by default and should be used to hide the chrome for things like full-screen modes
|
||||
* with an exit button.
|
||||
*/
|
||||
chrome.setVisible = (visibility: boolean) => {
|
||||
newPlatformChrome.setIsVisible(visibility);
|
||||
return chrome;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current visibility state of the chrome. Note that this drives the UI so it
|
||||
* might be incorrect in the moments just before the UI is updated.
|
||||
*/
|
||||
chrome.getVisible = () => visible$.getValue();
|
||||
|
||||
chrome.visible$ = visible$.asObservable();
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* 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 { npStart } from 'ui/new_platform';
|
||||
import { ChromeHelpExtension } from '../../../../../core/public';
|
||||
|
||||
const newPlatformChrome = npStart.core.chrome;
|
||||
|
||||
export type HelpExtensionApi = ReturnType<typeof createHelpExtensionApi>['helpExtension'];
|
||||
export type HelpExtension = ChromeHelpExtension;
|
||||
|
||||
function createHelpExtensionApi() {
|
||||
return {
|
||||
helpExtension: {
|
||||
/**
|
||||
* Set the custom help extension, or clear it by passing undefined. This
|
||||
* will be rendered within the help popover in the header
|
||||
*/
|
||||
set: (helpExtension: HelpExtension | undefined) => {
|
||||
newPlatformChrome.setHelpExtension(helpExtension);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the current help extension that should be rendered in the header
|
||||
*/
|
||||
get$: () => newPlatformChrome.getHelpExtension$(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function initHelpExtensionApi(
|
||||
chrome: { [key: string]: any },
|
||||
internal: { [key: string]: any }
|
||||
) {
|
||||
const { helpExtension } = createHelpExtensionApi();
|
||||
chrome.helpExtension = helpExtension;
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export const newPlatformInjectedMetadata: any = {
|
||||
getInjectedVars: jest.fn(),
|
||||
getInjectedVar: jest.fn(),
|
||||
};
|
||||
jest.doMock('ui/new_platform', () => ({
|
||||
npSetup: {
|
||||
core: { injectedMetadata: newPlatformInjectedMetadata },
|
||||
},
|
||||
}));
|
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
* 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 { newPlatformInjectedMetadata } from './injected_vars.test.mocks';
|
||||
import { initChromeInjectedVarsApi } from './injected_vars';
|
||||
|
||||
function initChrome() {
|
||||
const chrome: any = {};
|
||||
initChromeInjectedVarsApi(chrome);
|
||||
return chrome;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
describe('#getInjected()', () => {
|
||||
it('proxies to newPlatformInjectedMetadata service', () => {
|
||||
const chrome = initChrome();
|
||||
|
||||
chrome.getInjected();
|
||||
chrome.getInjected('foo');
|
||||
chrome.getInjected('foo', 'bar');
|
||||
expect(newPlatformInjectedMetadata.getInjectedVars.mock.calls).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [],
|
||||
]
|
||||
`);
|
||||
expect(newPlatformInjectedMetadata.getInjectedVar.mock.calls).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
"foo",
|
||||
undefined,
|
||||
],
|
||||
Array [
|
||||
"foo",
|
||||
"bar",
|
||||
],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it('returns mutable values, but does not persist changes internally', () => {
|
||||
const chrome = initChrome();
|
||||
|
||||
newPlatformInjectedMetadata.getInjectedVars.mockReturnValue(
|
||||
Object.freeze({
|
||||
foo: Object.freeze({
|
||||
bar: Object.freeze({
|
||||
baz: 1,
|
||||
}),
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
const vars = chrome.getInjected();
|
||||
expect(() => {
|
||||
vars.newProperty = true;
|
||||
}).not.toThrowError();
|
||||
expect(chrome.getInjected()).not.toHaveProperty('newProperty');
|
||||
});
|
||||
});
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* 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 { cloneDeep } from 'lodash';
|
||||
import { npSetup } from 'ui/new_platform';
|
||||
|
||||
const newPlatformInjectedVars = npSetup.core.injectedMetadata;
|
||||
|
||||
export function initChromeInjectedVarsApi(chrome: { [key: string]: any }) {
|
||||
chrome.getInjected = (name?: string, defaultValue?: any) =>
|
||||
cloneDeep(
|
||||
name
|
||||
? newPlatformInjectedVars.getInjectedVar(name, defaultValue)
|
||||
: newPlatformInjectedVars.getInjectedVars()
|
||||
);
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* 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 * as Rx from 'rxjs';
|
||||
import { npSetup } from 'ui/new_platform';
|
||||
|
||||
const newPlatformHttp = npSetup.core.http;
|
||||
|
||||
export function initLoadingCountApi(chrome) {
|
||||
const manualCount$ = new Rx.BehaviorSubject(0);
|
||||
newPlatformHttp.addLoadingCountSource(manualCount$);
|
||||
|
||||
chrome.loadingCount = new (class ChromeLoadingCountApi {
|
||||
/**
|
||||
* Call to add a subscriber to for the loading count that
|
||||
* will be called every time the loading count changes.
|
||||
*
|
||||
* @type {Observable<number>}
|
||||
* @return {Function} unsubscribe
|
||||
*/
|
||||
subscribe(handler) {
|
||||
const subscription = newPlatformHttp.getLoadingCount$().subscribe({
|
||||
next(count) {
|
||||
handler(count);
|
||||
},
|
||||
});
|
||||
|
||||
return () => {
|
||||
subscription.unsubscribe();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the loading count by one
|
||||
* @return {undefined}
|
||||
*/
|
||||
increment() {
|
||||
manualCount$.next(manualCount$.getValue() + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrement the loading count by one
|
||||
* @return {undefined}
|
||||
*/
|
||||
decrement() {
|
||||
manualCount$.next(manualCount$.getValue() - 1);
|
||||
}
|
||||
})();
|
||||
}
|
|
@ -1,157 +0,0 @@
|
|||
/*
|
||||
* 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 { KibanaParsedUrl } from 'ui/url/kibana_parsed_url';
|
||||
import { absoluteToParsedUrl } from '../../url/absolute_to_parsed_url';
|
||||
import { npStart } from '../../new_platform';
|
||||
import { ChromeNavLink } from '../../../../../core/public';
|
||||
import { relativeToAbsolute } from '../../url/relative_to_absolute';
|
||||
|
||||
export interface ChromeNavLinks {
|
||||
untrackNavLinksForDeletedSavedObjects(deletedIds: string[]): void;
|
||||
trackSubUrlForApp(linkId: string, parsedKibanaUrl: KibanaParsedUrl): void;
|
||||
}
|
||||
|
||||
interface NavInternals {
|
||||
appUrlStore: Storage;
|
||||
trackPossibleSubUrl(url: string): void;
|
||||
}
|
||||
|
||||
export function initChromeNavApi(chrome: any, internals: NavInternals) {
|
||||
const coreNavLinks = npStart.core.chrome.navLinks;
|
||||
|
||||
/**
|
||||
* Clear last url for deleted saved objects to avoid loading pages with "Could not locate..."
|
||||
*/
|
||||
chrome.untrackNavLinksForDeletedSavedObjects = (deletedIds: string[]) => {
|
||||
function urlContainsDeletedId(url: string) {
|
||||
const includedId = deletedIds.find((deletedId) => {
|
||||
return url.includes(deletedId);
|
||||
});
|
||||
return includedId !== undefined;
|
||||
}
|
||||
|
||||
coreNavLinks.getAll().forEach((link) => {
|
||||
if (link.linkToLastSubUrl && urlContainsDeletedId(link.url!)) {
|
||||
setLastUrl(link, link.baseUrl);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Manually sets the last url for the given app. The last url for a given app is updated automatically during
|
||||
* normal page navigation, so this should only need to be called to insert a last url that was not actually
|
||||
* navigated to. For instance, when saving an object and redirecting to another page, the last url of the app
|
||||
* should be the saved instance, but because of the redirect to a different page (e.g. `Save and Add to Dashboard`
|
||||
* on visualize tab), it won't be tracked automatically and will need to be inserted manually. See
|
||||
* https://github.com/elastic/kibana/pull/11932 for more background on why this was added.
|
||||
*
|
||||
* @param id {String} - an id that represents the navigation link.
|
||||
* @param kibanaParsedUrl {KibanaParsedUrl} the url to track
|
||||
*/
|
||||
chrome.trackSubUrlForApp = (id: string, kibanaParsedUrl: KibanaParsedUrl) => {
|
||||
const navLink = coreNavLinks.get(id);
|
||||
if (navLink) {
|
||||
setLastUrl(navLink, kibanaParsedUrl.getAbsoluteUrl());
|
||||
}
|
||||
};
|
||||
|
||||
internals.trackPossibleSubUrl = async function (url: string) {
|
||||
const kibanaParsedUrl = absoluteToParsedUrl(url, chrome.getBasePath());
|
||||
|
||||
coreNavLinks
|
||||
.getAll()
|
||||
// Filter only legacy links
|
||||
.filter((link) => link.legacy && !link.disableSubUrlTracking)
|
||||
.forEach((link) => {
|
||||
const active = url.startsWith(link.subUrlBase!);
|
||||
link = coreNavLinks.update(link.id, { active })!;
|
||||
|
||||
if (active) {
|
||||
setLastUrl(link, url);
|
||||
return;
|
||||
}
|
||||
|
||||
link = refreshLastUrl(link);
|
||||
|
||||
const newGlobalState = kibanaParsedUrl.getGlobalState();
|
||||
if (newGlobalState) {
|
||||
injectNewGlobalState(link, kibanaParsedUrl.appId, newGlobalState);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function lastSubUrlKey(link: ChromeNavLink) {
|
||||
return `lastSubUrl:${link.baseUrl}`;
|
||||
}
|
||||
|
||||
function getLastUrl(link: ChromeNavLink) {
|
||||
return internals.appUrlStore.getItem(lastSubUrlKey(link));
|
||||
}
|
||||
|
||||
function setLastUrl(link: ChromeNavLink, url: string) {
|
||||
if (link.linkToLastSubUrl === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
internals.appUrlStore.setItem(lastSubUrlKey(link), url);
|
||||
refreshLastUrl(link);
|
||||
}
|
||||
|
||||
function refreshLastUrl(link: ChromeNavLink) {
|
||||
const lastSubUrl = getLastUrl(link);
|
||||
|
||||
return coreNavLinks.update(link.id, {
|
||||
url: lastSubUrl || link.url || link.baseUrl,
|
||||
})!;
|
||||
}
|
||||
|
||||
function injectNewGlobalState(
|
||||
link: ChromeNavLink,
|
||||
fromAppId: string,
|
||||
newGlobalState: string | string[]
|
||||
) {
|
||||
const kibanaParsedUrl = absoluteToParsedUrl(
|
||||
getLastUrl(link) || link.url || link.baseUrl,
|
||||
chrome.getBasePath()
|
||||
);
|
||||
|
||||
// don't copy global state if links are for different apps
|
||||
if (fromAppId !== kibanaParsedUrl.appId) return;
|
||||
|
||||
kibanaParsedUrl.setGlobalState(newGlobalState);
|
||||
|
||||
coreNavLinks.update(link.id, {
|
||||
url: kibanaParsedUrl.getAbsoluteUrl(),
|
||||
});
|
||||
}
|
||||
|
||||
// simulate a possible change in url to initialize the
|
||||
// link.active and link.lastUrl properties
|
||||
coreNavLinks
|
||||
.getAll()
|
||||
.filter((link) => link.subUrlBase && !link.disableSubUrlTracking)
|
||||
.forEach((link) => {
|
||||
coreNavLinks.update(link.id, {
|
||||
subUrlBase: relativeToAbsolute(chrome.addBasePath(link.subUrlBase)),
|
||||
});
|
||||
});
|
||||
|
||||
internals.trackPossibleSubUrl(document.location.href);
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
* 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 { npStart } from 'ui/new_platform';
|
||||
import { Chrome } from '..';
|
||||
|
||||
const savedObjectsClient = npStart.core.savedObjects.client;
|
||||
|
||||
export function initSavedObjectClient(chrome: Chrome) {
|
||||
chrome.getSavedObjectsClient = function () {
|
||||
return savedObjectsClient;
|
||||
};
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
/*
|
||||
* 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 { unhashUrl } from '../../../../../plugins/kibana_utils/public';
|
||||
import { toastNotifications } from '../../notify/toasts';
|
||||
import { npSetup } from '../../new_platform';
|
||||
import { areHashesDifferentButDecodedHashesEquals } from './sub_url_hooks_utils';
|
||||
|
||||
export function registerSubUrlHooks(angularModule, internals) {
|
||||
angularModule.run(($rootScope, Private, $location) => {
|
||||
const subUrlRouteFilter = Private(SubUrlRouteFilterProvider);
|
||||
|
||||
function updateSubUrls() {
|
||||
const urlWithHashes = window.location.href;
|
||||
let urlWithStates;
|
||||
try {
|
||||
urlWithStates = unhashUrl(urlWithHashes);
|
||||
} catch (e) {
|
||||
toastNotifications.addDanger(e.message);
|
||||
}
|
||||
|
||||
internals.trackPossibleSubUrl(urlWithStates || urlWithHashes);
|
||||
}
|
||||
|
||||
function onRouteChange($event) {
|
||||
if (subUrlRouteFilter($event)) {
|
||||
updateUsage($event);
|
||||
updateSubUrls();
|
||||
}
|
||||
}
|
||||
|
||||
$rootScope.$on('$locationChangeStart', (e, newUrl) => {
|
||||
// This handler fixes issue #31238 where browser back navigation
|
||||
// fails due to angular 1.6 parsing url encoded params wrong.
|
||||
if (areHashesDifferentButDecodedHashesEquals($location.absUrl(), newUrl)) {
|
||||
// replace the urlencoded hash with the version that angular sees.
|
||||
const newHash = newUrl.split('#')[1] || '';
|
||||
$location.url(newHash).replace();
|
||||
}
|
||||
});
|
||||
|
||||
$rootScope.$on('$routeChangeSuccess', onRouteChange);
|
||||
$rootScope.$on('$routeUpdate', onRouteChange);
|
||||
updateSubUrls();
|
||||
});
|
||||
}
|
||||
|
||||
function updateUsage($event) {
|
||||
const scope = $event.targetScope;
|
||||
const app = scope.chrome.getApp();
|
||||
const appId = app.id === 'kibana' ? scope.getFirstPathSegment() : app.id;
|
||||
if (npSetup.plugins.usageCollection) npSetup.plugins.usageCollection.__LEGACY.appChanged(appId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function that will be called on each route change
|
||||
* to determine if the event should be used to update the last
|
||||
* subUrl of chrome links/tabs
|
||||
* @injected
|
||||
*/
|
||||
export function SubUrlRouteFilterProvider($injector) {
|
||||
if (!$injector.has('$route')) {
|
||||
return function alwaysUpdate() {
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
const $route = $injector.get('$route');
|
||||
return function ignoreRedirectToRoutes() {
|
||||
return Boolean($route.current && !$route.current.redirectTo);
|
||||
};
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* 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 { areHashesDifferentButDecodedHashesEquals } from './sub_url_hooks_utils';
|
||||
|
||||
test('false for different hashes', () => {
|
||||
const url1 = `https://localhost/kibana/#/dashboard/id`;
|
||||
const url2 = `https://localhost/kibana/#/dashboard/DIFFERENT`;
|
||||
expect(areHashesDifferentButDecodedHashesEquals(url1, url2)).toBeFalsy();
|
||||
});
|
||||
|
||||
test('false for same hashes', () => {
|
||||
const hash = `/dashboard/id?_a=(filters:!(),query:(language:kuery,query:''))&_g=(filters:!(),time:(from:now-120m,to:now))`;
|
||||
const url1 = `https://localhost/kibana/#/${hash}`;
|
||||
expect(areHashesDifferentButDecodedHashesEquals(url1, url1)).toBeFalsy();
|
||||
});
|
||||
|
||||
test('true for same hashes, but one is encoded', () => {
|
||||
const hash = `/dashboard/id?_a=(filters:!(),query:(language:kuery,query:''))&_g=(filters:!(),time:(from:now-120m,to:now))`;
|
||||
const url1 = `https://localhost/kibana/#/${hash}`;
|
||||
const url2 = `https://localhost/kibana/#/${encodeURIComponent(hash)}`;
|
||||
expect(areHashesDifferentButDecodedHashesEquals(url1, url2)).toBeTruthy();
|
||||
});
|
||||
|
||||
/**
|
||||
* This edge case occurs when trying to navigate within kibana app using core's `navigateToApp` api
|
||||
* and there is reserved characters in hash (see: query:'' part)
|
||||
* For example:
|
||||
* ```ts
|
||||
* navigateToApp('kibana', {
|
||||
* path: '#/dashboard/f8bc19f0-6918-11ea-9258-a74c2ded064d?_a=(filters:!(),query:(language:kuery,query:''))&_g=(filters:!(),time:(from:now-120m,to:now))'
|
||||
* })
|
||||
* ```
|
||||
* Core internally is using url.parse which parses ' -> %27 and performs the navigation
|
||||
* Then angular decodes it back and causes redundant history record if not the fix which is covered by the test below
|
||||
*/
|
||||
test("true for same hashes, but one has reserved character (') encoded", () => {
|
||||
const hash = `/dashboard/id?_a=(filters:!(),query:(language:kuery,query:''))&_g=(filters:!(),time:(from:now-120m,to:now))`;
|
||||
const url1 = `https://localhost/kibana/#/${hash}`;
|
||||
const url2 = `https://localhost/kibana/#/${hash.replace(/\'/g, '%27')}`;
|
||||
expect(areHashesDifferentButDecodedHashesEquals(url1, url2)).toBeTruthy();
|
||||
});
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export function areHashesDifferentButDecodedHashesEquals(urlA: string, urlB: string): boolean {
|
||||
const getHash = (url: string) => url.split('#')[1] ?? '';
|
||||
const hashA = getHash(urlA);
|
||||
const decodedHashA = decodeURIComponent(hashA);
|
||||
|
||||
const hashB = getHash(urlB);
|
||||
const decodedHashB = decodeURIComponent(hashB);
|
||||
|
||||
return hashA !== hashB && decodedHashA === decodedHashB;
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default function (chrome, internals) {
|
||||
/**
|
||||
* ui/chrome Template API
|
||||
*
|
||||
* Root Template
|
||||
* The root template is rendered within the primary chrome ui and should
|
||||
* be used when building an app that is more of a page, or to override the
|
||||
* placement of ng-view. When including a root template, the mark-up will
|
||||
* look something like this:
|
||||
*
|
||||
* body
|
||||
* notifs
|
||||
* div.content
|
||||
* nav
|
||||
* config
|
||||
* div.application
|
||||
* <-- your template here -->
|
||||
*
|
||||
* Root Controller
|
||||
* To attach a controller to the root of ui/chrome's content area, outside of
|
||||
* where it attaches the ng-view directive (assuming no rootTemplate is used)
|
||||
* which will allow cause the controller to persist across views or make for
|
||||
* a simple place to define some quick global functionality for a very simple
|
||||
* app (like the status page).
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {string} template
|
||||
* @return {chrome}
|
||||
*/
|
||||
chrome.setRootTemplate = function (template) {
|
||||
internals.rootTemplate = template;
|
||||
return chrome;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} as - the name that the controller should bind to
|
||||
* @param {Function} controller - the controller initializer function
|
||||
* @return {chrome}
|
||||
*/
|
||||
chrome.setRootController = function (as, controllerName) {
|
||||
if (controllerName === undefined) {
|
||||
controllerName = as;
|
||||
as = null;
|
||||
}
|
||||
|
||||
if (typeof controllerName === 'function') {
|
||||
chrome.$$rootControllerConstruct = controllerName;
|
||||
controllerName = 'chrome.$$rootControllerConstruct';
|
||||
}
|
||||
|
||||
internals.rootController = controllerName + (as ? ' as ' + as : '');
|
||||
return chrome;
|
||||
};
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* 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 { chromeServiceMock } from '../../../../../core/public/mocks';
|
||||
|
||||
export const newPlatformChrome = chromeServiceMock.createStartContract();
|
||||
jest.doMock('ui/new_platform', () => ({
|
||||
npStart: {
|
||||
core: { chrome: newPlatformChrome },
|
||||
},
|
||||
}));
|
|
@ -1,144 +0,0 @@
|
|||
/*
|
||||
* 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 * as Rx from 'rxjs';
|
||||
|
||||
import { newPlatformChrome } from './theme.test.mocks';
|
||||
import { initChromeThemeApi } from './theme';
|
||||
|
||||
function setup() {
|
||||
const brand$ = new Rx.BehaviorSubject({ logo: 'foo', smallLogo: 'foo' });
|
||||
newPlatformChrome.getBrand$.mockReturnValue(brand$);
|
||||
|
||||
const applicationClasses$ = new Rx.BehaviorSubject([] as string[]);
|
||||
newPlatformChrome.getApplicationClasses$.mockReturnValue(applicationClasses$);
|
||||
|
||||
const chrome: any = {};
|
||||
initChromeThemeApi(chrome);
|
||||
return { chrome, brand$, applicationClasses$ };
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
describe('setBrand', () => {
|
||||
it('proxies to newPlatformChrome', () => {
|
||||
const { chrome } = setup();
|
||||
|
||||
chrome.setBrand({
|
||||
logo: 'foo.svg',
|
||||
smallLogo: 'smallFoo.svg',
|
||||
});
|
||||
|
||||
chrome.setBrand({
|
||||
logo: 'baz',
|
||||
});
|
||||
|
||||
expect(newPlatformChrome.setBrand.mock.calls).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
Object {
|
||||
"logo": "foo.svg",
|
||||
"smallLogo": "smallFoo.svg",
|
||||
},
|
||||
],
|
||||
Array [
|
||||
Object {
|
||||
"logo": "baz",
|
||||
},
|
||||
],
|
||||
]
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getBrand', () => {
|
||||
it('returns named properties from cached values emitted from newPlatformChrome', () => {
|
||||
const { chrome, brand$ } = setup();
|
||||
expect(chrome.getBrand('logo')).toBe('foo');
|
||||
expect(chrome.getBrand('smallLogo')).toBe('foo');
|
||||
expect(chrome.getBrand()).toBe(undefined);
|
||||
|
||||
brand$.next({
|
||||
logo: 'bar.svg',
|
||||
smallLogo: 'smallBar.svg',
|
||||
});
|
||||
|
||||
expect(chrome.getBrand('logo')).toBe('bar.svg');
|
||||
expect(chrome.getBrand('smallLogo')).toBe('smallBar.svg');
|
||||
expect(chrome.getBrand()).toBe(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addApplicationClass', () => {
|
||||
it('proxies each class as a separate argument to newPlatformChrome', () => {
|
||||
const { chrome } = setup();
|
||||
chrome.addApplicationClass('foo');
|
||||
chrome.addApplicationClass(['bar', 'baz']);
|
||||
chrome.addApplicationClass([]);
|
||||
expect(newPlatformChrome.addApplicationClass.mock.calls).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
"foo",
|
||||
],
|
||||
Array [
|
||||
"bar",
|
||||
],
|
||||
Array [
|
||||
"baz",
|
||||
],
|
||||
]
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeApplicationClass', () => {
|
||||
it('proxies each class as a separate argument to newPlatformChrome', () => {
|
||||
const { chrome } = setup();
|
||||
chrome.removeApplicationClass('foo');
|
||||
chrome.removeApplicationClass(['bar', 'baz']);
|
||||
chrome.removeApplicationClass([]);
|
||||
expect(newPlatformChrome.removeApplicationClass.mock.calls).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
"foo",
|
||||
],
|
||||
Array [
|
||||
"bar",
|
||||
],
|
||||
Array [
|
||||
"baz",
|
||||
],
|
||||
]
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getApplicationClasses', () => {
|
||||
it('returns cached values emitted from newPlatformChrome as a single string', () => {
|
||||
const { chrome, applicationClasses$ } = setup();
|
||||
|
||||
expect(chrome.getApplicationClasses()).toBe('');
|
||||
applicationClasses$.next(['foo', 'bar']);
|
||||
expect(chrome.getApplicationClasses()).toBe('foo bar');
|
||||
applicationClasses$.next(['bar']);
|
||||
expect(chrome.getApplicationClasses()).toBe('bar');
|
||||
});
|
||||
});
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
* 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 * as Rx from 'rxjs';
|
||||
|
||||
import { npStart } from 'ui/new_platform';
|
||||
import { ChromeBrand } from '../../../../../core/public';
|
||||
|
||||
const newPlatformChrome = npStart.core.chrome;
|
||||
|
||||
export function initChromeThemeApi(chrome: { [key: string]: any }) {
|
||||
const brandCache$ = new Rx.BehaviorSubject<ChromeBrand>({});
|
||||
newPlatformChrome.getBrand$().subscribe(brandCache$);
|
||||
|
||||
const applicationClassesCache$ = new Rx.BehaviorSubject<string[]>([]);
|
||||
newPlatformChrome.getApplicationClasses$().subscribe(applicationClassesCache$);
|
||||
|
||||
chrome.setBrand = (brand: ChromeBrand) => {
|
||||
newPlatformChrome.setBrand(brand);
|
||||
return chrome;
|
||||
};
|
||||
|
||||
chrome.getBrand = (key: keyof ChromeBrand) => {
|
||||
return brandCache$.getValue()[key];
|
||||
};
|
||||
|
||||
chrome.addApplicationClass = (classNames: string | string[] = []) => {
|
||||
if (typeof classNames === 'string') {
|
||||
classNames = [classNames];
|
||||
}
|
||||
|
||||
for (const className of classNames) {
|
||||
newPlatformChrome.addApplicationClass(className);
|
||||
}
|
||||
|
||||
return chrome;
|
||||
};
|
||||
|
||||
chrome.removeApplicationClass = (classNames: string | string[]) => {
|
||||
if (typeof classNames === 'string') {
|
||||
classNames = [classNames];
|
||||
}
|
||||
|
||||
for (const className of classNames) {
|
||||
newPlatformChrome.removeApplicationClass(className);
|
||||
}
|
||||
return chrome;
|
||||
};
|
||||
|
||||
chrome.getApplicationClasses = () => {
|
||||
return applicationClassesCache$.getValue().join(' ');
|
||||
};
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* 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 { npSetup } from 'ui/new_platform';
|
||||
|
||||
const newPlatformUiSettingsClient = npSetup.core.uiSettings;
|
||||
|
||||
export function initUiSettingsApi(chrome) {
|
||||
chrome.getUiSettingsClient = function () {
|
||||
return newPlatformUiSettingsClient;
|
||||
};
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export function initChromeXsrfApi(chrome, internals) {
|
||||
chrome.getXsrfToken = function () {
|
||||
return internals.version;
|
||||
};
|
||||
}
|
|
@ -1,118 +0,0 @@
|
|||
/*
|
||||
* 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 _ from 'lodash';
|
||||
import angular from 'angular';
|
||||
|
||||
import { metadata } from '../metadata';
|
||||
import '../state_management/global_state';
|
||||
import '../config';
|
||||
import '../notify';
|
||||
import '../private';
|
||||
import '../promises';
|
||||
import '../directives/storage';
|
||||
import '../directives/watch_multi';
|
||||
import '../react_components';
|
||||
import '../i18n';
|
||||
|
||||
import { initAngularApi } from './api/angular';
|
||||
import appsApi from './api/apps';
|
||||
import { initChromeControlsApi } from './api/controls';
|
||||
import { initChromeNavApi } from './api/nav';
|
||||
import { initChromeBadgeApi } from './api/badge';
|
||||
import { initBreadcrumbsApi } from './api/breadcrumbs';
|
||||
import templateApi from './api/template';
|
||||
import { initChromeThemeApi } from './api/theme';
|
||||
import { initChromeXsrfApi } from './api/xsrf';
|
||||
import { initUiSettingsApi } from './api/ui_settings';
|
||||
import { initLoadingCountApi } from './api/loading_count';
|
||||
import { initSavedObjectClient } from './api/saved_object_client';
|
||||
import { initChromeBasePathApi } from './api/base_path';
|
||||
import { initChromeInjectedVarsApi } from './api/injected_vars';
|
||||
import { initHelpExtensionApi } from './api/help_extension';
|
||||
import { npStart } from '../new_platform';
|
||||
|
||||
export const chrome = {};
|
||||
const internals = _.defaults(_.cloneDeep(metadata), {
|
||||
basePath: '',
|
||||
rootController: null,
|
||||
rootTemplate: null,
|
||||
showAppsLink: null,
|
||||
xsrfToken: null,
|
||||
devMode: true,
|
||||
brand: null,
|
||||
nav: [],
|
||||
applicationClasses: [],
|
||||
});
|
||||
|
||||
initUiSettingsApi(chrome);
|
||||
initSavedObjectClient(chrome);
|
||||
appsApi(chrome, internals);
|
||||
initChromeXsrfApi(chrome, internals);
|
||||
initChromeBasePathApi(chrome);
|
||||
initChromeInjectedVarsApi(chrome);
|
||||
initChromeNavApi(chrome, internals);
|
||||
initChromeBadgeApi(chrome);
|
||||
initBreadcrumbsApi(chrome, internals);
|
||||
initLoadingCountApi(chrome, internals);
|
||||
initHelpExtensionApi(chrome, internals);
|
||||
initAngularApi(chrome, internals);
|
||||
initChromeControlsApi(chrome);
|
||||
templateApi(chrome, internals);
|
||||
initChromeThemeApi(chrome);
|
||||
|
||||
npStart.core.chrome.setAppTitle(chrome.getAppTitle());
|
||||
|
||||
const waitForBootstrap = new Promise((resolve) => {
|
||||
chrome.bootstrap = function (targetDomElement) {
|
||||
// sets attribute on body for stylesheet sandboxing
|
||||
document.body.setAttribute('id', `${internals.app.id}-app`);
|
||||
|
||||
chrome.setupAngular();
|
||||
targetDomElement.setAttribute('kbn-chrome', 'true');
|
||||
targetDomElement.setAttribute('ng-class', "{ 'hidden-chrome': !chrome.getVisible() }");
|
||||
targetDomElement.className = 'app-wrapper';
|
||||
angular.bootstrap(targetDomElement, ['kibana']);
|
||||
resolve(targetDomElement);
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* ---- ATTENTION: Read documentation carefully before using this! ----
|
||||
*
|
||||
* Returns a promise, that resolves with an instance of the currently used Angular
|
||||
* $injector service for usage outside of Angular.
|
||||
* You can use this injector to get access to any other injectable component (service,
|
||||
* constant, etc.) by using its get method.
|
||||
*
|
||||
* If you ever use Angular outside of an Angular context via this method, you should
|
||||
* be really sure you know what you are doing!
|
||||
*
|
||||
* When using this method inside your code, you will need to stub it while running
|
||||
* tests. Look into 'src/test_utils/public/stub_get_active_injector' for more information.
|
||||
*/
|
||||
chrome.dangerouslyGetActiveInjector = () => {
|
||||
return waitForBootstrap.then((targetDomElement) => {
|
||||
const $injector = angular.element(targetDomElement).injector();
|
||||
if (!$injector) {
|
||||
return Promise.reject('targetDomElement had no angular context after bootstrapping');
|
||||
}
|
||||
return $injector;
|
||||
});
|
||||
};
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* 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 { kbnChromeProvider } from './kbn_chrome';
|
||||
|
||||
export function directivesProvider(chrome, internals) {
|
||||
kbnChromeProvider(chrome, internals);
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
<div class="app-wrapper-panel" data-test-subj="appA11yRoot">
|
||||
<div id="globalBannerList"></div>
|
||||
|
||||
<div
|
||||
class="application"
|
||||
ng-class="'tab-' + getFirstPathSegment() + ' ' + chrome.getApplicationClasses()"
|
||||
ng-view
|
||||
></div>
|
||||
</div>
|
|
@ -1,106 +0,0 @@
|
|||
/*
|
||||
* 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 React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import $ from 'jquery';
|
||||
import { fatalError } from 'ui/notify/fatal_error';
|
||||
|
||||
import { uiModules } from '../../modules';
|
||||
import template from './kbn_chrome.html';
|
||||
|
||||
import { I18nContext } from '../../i18n';
|
||||
import { npStart } from '../../new_platform';
|
||||
import {
|
||||
chromeHeaderNavControlsRegistry,
|
||||
NavControlSide,
|
||||
} from '../../registry/chrome_header_nav_controls';
|
||||
import { subscribeWithScope } from '../../../../../plugins/kibana_legacy/public';
|
||||
|
||||
export function kbnChromeProvider(chrome, internals) {
|
||||
uiModules.get('kibana').directive('kbnChrome', () => {
|
||||
return {
|
||||
template() {
|
||||
const $content = $(template);
|
||||
const $app = $content.find('.application');
|
||||
|
||||
if (internals.rootController) {
|
||||
$app.attr('ng-controller', internals.rootController);
|
||||
}
|
||||
|
||||
if (internals.rootTemplate) {
|
||||
$app.removeAttr('ng-view');
|
||||
$app.html(internals.rootTemplate);
|
||||
}
|
||||
|
||||
return $content;
|
||||
},
|
||||
|
||||
controllerAs: 'chrome',
|
||||
controller($scope, $location, Private) {
|
||||
$scope.getFirstPathSegment = () => {
|
||||
return $location.path().split('/')[1];
|
||||
};
|
||||
|
||||
// Continue to support legacy nav controls not registered with the NP.
|
||||
const navControls = Private(chromeHeaderNavControlsRegistry);
|
||||
(navControls.bySide[NavControlSide.Left] || []).forEach((navControl) =>
|
||||
npStart.core.chrome.navControls.registerLeft({
|
||||
order: navControl.order,
|
||||
mount: navControl.render,
|
||||
})
|
||||
);
|
||||
(navControls.bySide[NavControlSide.Right] || []).forEach((navControl) =>
|
||||
npStart.core.chrome.navControls.registerRight({
|
||||
order: navControl.order,
|
||||
mount: navControl.render,
|
||||
})
|
||||
);
|
||||
|
||||
// Non-scope based code (e.g., React)
|
||||
|
||||
// Banners
|
||||
const bannerListContainer = document.getElementById('globalBannerList');
|
||||
if (bannerListContainer) {
|
||||
// This gets rendered manually by the legacy platform because this component must be inside the .app-wrapper
|
||||
ReactDOM.render(
|
||||
<I18nContext>{npStart.core.overlays.banners.getComponent()}</I18nContext>,
|
||||
bannerListContainer
|
||||
);
|
||||
}
|
||||
|
||||
const chromeVisibility = subscribeWithScope(
|
||||
$scope,
|
||||
chrome.visible$,
|
||||
{
|
||||
next: () => {
|
||||
// just makes sure change detection is triggered when chrome visibility changes
|
||||
},
|
||||
},
|
||||
fatalError
|
||||
);
|
||||
$scope.$on('$destroy', () => {
|
||||
chromeVisibility.unsubscribe();
|
||||
});
|
||||
|
||||
return chrome;
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
64
src/legacy/ui/public/chrome/index.d.ts
vendored
64
src/legacy/ui/public/chrome/index.d.ts
vendored
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* 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 { SavedObjectsClientContract } from 'src/core/public';
|
||||
import { ChromeBrand } from '../../../../core/public';
|
||||
import { BadgeApi } from './api/badge';
|
||||
import { BreadcrumbsApi } from './api/breadcrumbs';
|
||||
import { HelpExtensionApi } from './api/help_extension';
|
||||
import { ChromeNavLinks } from './api/nav';
|
||||
|
||||
export interface IInjector {
|
||||
get<T>(injectable: string): T;
|
||||
invoke<T, T2>(
|
||||
injectable: (this: T2, ...args: any[]) => T,
|
||||
self?: T2,
|
||||
locals?: { [key: string]: any }
|
||||
): T;
|
||||
instantiate(constructor: Function, locals?: { [key: string]: any }): any;
|
||||
}
|
||||
|
||||
declare interface Chrome extends ChromeNavLinks {
|
||||
badge: BadgeApi;
|
||||
breadcrumbs: BreadcrumbsApi;
|
||||
helpExtension: HelpExtensionApi;
|
||||
addBasePath<T = string>(path: T): T;
|
||||
dangerouslyGetActiveInjector(): Promise<IInjector>;
|
||||
getBasePath(): string;
|
||||
getXsrfToken(): string;
|
||||
getKibanaVersion(): string;
|
||||
getSavedObjectsClient(): SavedObjectsClientContract;
|
||||
getUiSettingsClient(): any;
|
||||
setVisible(visible: boolean): any;
|
||||
getInjected(key: string, defaultValue?: any): any;
|
||||
setRootController(name: string, Controller: any): any;
|
||||
setBrand(brand: ChromeBrand): this;
|
||||
getBrand(key: keyof ChromeBrand): ChromeBrand[keyof ChromeBrand];
|
||||
addApplicationClass(classNames: string | string[]): this;
|
||||
removeApplicationClass(classNames: string | string[]): this;
|
||||
getApplicationClasses(): string;
|
||||
}
|
||||
|
||||
declare const chrome: Chrome;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default chrome;
|
||||
export { Chrome };
|
||||
export { Breadcrumb } from './api/breadcrumbs';
|
||||
export { HelpExtension } from './api/help_extension';
|
|
@ -1,23 +0,0 @@
|
|||
/*
|
||||
* 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 './chrome';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default chrome;
|
|
@ -1,208 +0,0 @@
|
|||
/*
|
||||
* 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 expect from '@kbn/expect';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import ngMock from 'ng_mock';
|
||||
import chrome from '../../chrome';
|
||||
|
||||
describe('Config service', () => {
|
||||
let config;
|
||||
let uiSettings;
|
||||
let $q;
|
||||
let $rootScope;
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
beforeEach(
|
||||
ngMock.inject(($injector) => {
|
||||
config = $injector.get('config');
|
||||
uiSettings = chrome.getUiSettingsClient();
|
||||
$q = $injector.get('$q');
|
||||
$rootScope = $injector.get('$rootScope');
|
||||
})
|
||||
);
|
||||
|
||||
describe('#getAll', () => {
|
||||
it('calls uiSettings.getAll()', () => {
|
||||
sinon.stub(uiSettings, 'getAll');
|
||||
config.getAll();
|
||||
sinon.assert.calledOnce(uiSettings.getAll);
|
||||
sinon.assert.calledWithExactly(uiSettings.getAll);
|
||||
uiSettings.getAll.restore();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#get', () => {
|
||||
it('calls uiSettings.get(key, default)', () => {
|
||||
sinon.stub(uiSettings, 'get');
|
||||
config.get('key', 'default');
|
||||
sinon.assert.calledOnce(uiSettings.get);
|
||||
sinon.assert.calledWithExactly(uiSettings.get, 'key', 'default');
|
||||
uiSettings.get.restore();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#isDeclared', () => {
|
||||
it('calls uiSettings.isDeclared(key)', () => {
|
||||
sinon.stub(uiSettings, 'isDeclared');
|
||||
config.isDeclared('key');
|
||||
sinon.assert.calledOnce(uiSettings.isDeclared);
|
||||
sinon.assert.calledWithExactly(uiSettings.isDeclared, 'key');
|
||||
uiSettings.isDeclared.restore();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#isDefault', () => {
|
||||
it('calls uiSettings.isDefault(key)', () => {
|
||||
sinon.stub(uiSettings, 'isDefault');
|
||||
config.isDefault('key');
|
||||
sinon.assert.calledOnce(uiSettings.isDefault);
|
||||
sinon.assert.calledWithExactly(uiSettings.isDefault, 'key');
|
||||
uiSettings.isDefault.restore();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#isCustom', () => {
|
||||
it('calls uiSettings.isCustom(key)', () => {
|
||||
sinon.stub(uiSettings, 'isCustom');
|
||||
config.isCustom('key');
|
||||
sinon.assert.calledOnce(uiSettings.isCustom);
|
||||
sinon.assert.calledWithExactly(uiSettings.isCustom, 'key');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#remove', () => {
|
||||
it('calls uiSettings.remove(key)', () => {
|
||||
sinon.stub(uiSettings, 'remove');
|
||||
config.remove('foobar');
|
||||
sinon.assert.calledOnce(uiSettings.remove);
|
||||
sinon.assert.calledWithExactly(uiSettings.remove, 'foobar');
|
||||
uiSettings.remove.restore();
|
||||
});
|
||||
|
||||
it('returns an angular promise', () => {
|
||||
const promise = config.remove('dateFormat:tz');
|
||||
expect(promise).to.be.a($q);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#set', () => {
|
||||
it('returns an angular promise', () => {
|
||||
const promise = config.set('dateFormat:tz', 'foo');
|
||||
expect(promise).to.be.a($q);
|
||||
});
|
||||
|
||||
it('strips $$-prefixed properties from plain objects', () => {
|
||||
config.set('dateFormat:scaled', {
|
||||
foo: 'bar',
|
||||
$$bax: 'box',
|
||||
});
|
||||
|
||||
expect(config.get('dateFormat:scaled')).to.eql({
|
||||
foo: 'bar',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('$scope events', () => {
|
||||
it('synchronously emits change:config on $rootScope when config changes', () => {
|
||||
const stub = sinon.stub();
|
||||
$rootScope.$on('change:config', stub);
|
||||
config.set('foobar', 'baz');
|
||||
sinon.assert.calledOnce(stub);
|
||||
sinon.assert.calledWithExactly(stub, sinon.match({}), 'baz', undefined, 'foobar', config);
|
||||
});
|
||||
|
||||
it('synchronously emits change:config.${key} on $rootScope when config changes', () => {
|
||||
const stub = sinon.stub();
|
||||
$rootScope.$on('change:config.foobar', stub);
|
||||
config.set('foobar', 'baz');
|
||||
sinon.assert.calledOnce(stub);
|
||||
sinon.assert.calledWithExactly(stub, sinon.match({}), 'baz', undefined, 'foobar', config);
|
||||
});
|
||||
|
||||
it('synchronously emits change:config on child scope when config changes', () => {
|
||||
const stub = sinon.stub();
|
||||
const $parent = $rootScope.$new(false);
|
||||
const $scope = $rootScope.$new(false, $parent);
|
||||
$scope.$on('change:config', stub);
|
||||
config.set('foobar', 'baz');
|
||||
sinon.assert.calledOnce(stub);
|
||||
sinon.assert.calledWithExactly(stub, sinon.match({}), 'baz', undefined, 'foobar', config);
|
||||
});
|
||||
|
||||
it('synchronously emits change:config.${key} on child scope when config changes', () => {
|
||||
const stub = sinon.stub();
|
||||
const $parent = $rootScope.$new(false);
|
||||
const $scope = $rootScope.$new(false, $parent);
|
||||
$scope.$on('change:config.foobar', stub);
|
||||
config.set('foobar', 'baz');
|
||||
sinon.assert.calledOnce(stub);
|
||||
sinon.assert.calledWithExactly(stub, sinon.match({}), 'baz', undefined, 'foobar', config);
|
||||
});
|
||||
|
||||
it('synchronously emits change:config on isolate scope when config changes', () => {
|
||||
const stub = sinon.stub();
|
||||
const $scope = $rootScope.$new(true);
|
||||
$scope.$on('change:config', stub);
|
||||
config.set('foobar', 'baz');
|
||||
sinon.assert.calledOnce(stub);
|
||||
sinon.assert.calledWithExactly(stub, sinon.match({}), 'baz', undefined, 'foobar', config);
|
||||
});
|
||||
|
||||
it('synchronously emits change:config.${key} on isolate scope when config changes', () => {
|
||||
const stub = sinon.stub();
|
||||
const $scope = $rootScope.$new(true);
|
||||
$scope.$on('change:config.foobar', stub);
|
||||
config.set('foobar', 'baz');
|
||||
sinon.assert.calledOnce(stub);
|
||||
sinon.assert.calledWithExactly(stub, sinon.match({}), 'baz', undefined, 'foobar', config);
|
||||
});
|
||||
|
||||
it('synchronously emits events when changes are inside a digest cycle', async () => {
|
||||
const stub = sinon.stub();
|
||||
|
||||
$rootScope.$apply(() => {
|
||||
$rootScope.$on('change:config.foobar', stub);
|
||||
config.set('foobar', 'baz');
|
||||
});
|
||||
|
||||
sinon.assert.calledOnce(stub);
|
||||
sinon.assert.calledWithExactly(stub, sinon.match({}), 'baz', undefined, 'foobar', config);
|
||||
});
|
||||
|
||||
it('synchronously emits events when changes are outside a digest cycle', async () => {
|
||||
const stub = sinon.stub();
|
||||
|
||||
await new Promise((resolve) => {
|
||||
setTimeout(function () {
|
||||
const off = $rootScope.$on('change:config.foobar', stub);
|
||||
config.set('foobar', 'baz');
|
||||
// we unlisten to make sure that stub is not called before our assertions below
|
||||
off();
|
||||
resolve();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
sinon.assert.calledOnce(stub);
|
||||
sinon.assert.calledWithExactly(stub, sinon.match({}), 'baz', undefined, 'foobar', config);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,110 +0,0 @@
|
|||
/*
|
||||
* 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 angular from 'angular';
|
||||
import { fatalError } from 'ui/notify/fatal_error';
|
||||
import chrome from '../chrome';
|
||||
import { isPlainObject } from 'lodash';
|
||||
import { uiModules } from '../modules';
|
||||
import { subscribeWithScope } from '../../../../plugins/kibana_legacy/public';
|
||||
|
||||
const module = uiModules.get('kibana/config');
|
||||
|
||||
/**
|
||||
* Angular tie-in to UiSettingsClient, which is implemented in vanilla JS. Designed
|
||||
* to expose the exact same API as the config service that has existed since forever.
|
||||
* @name config
|
||||
*/
|
||||
module.service(`config`, function ($rootScope, Promise) {
|
||||
const uiSettings = chrome.getUiSettingsClient();
|
||||
|
||||
// direct bind sync methods
|
||||
this.getAll = (...args) => uiSettings.getAll(...args);
|
||||
this.get = (...args) => uiSettings.get(...args);
|
||||
this.isDeclared = (...args) => uiSettings.isDeclared(...args);
|
||||
this.isDefault = (...args) => uiSettings.isDefault(...args);
|
||||
this.isCustom = (...args) => uiSettings.isCustom(...args);
|
||||
this.isOverridden = (...args) => uiSettings.isOverridden(...args);
|
||||
|
||||
// modify remove() to use angular Promises
|
||||
this.remove = (key) => Promise.resolve(uiSettings.remove(key));
|
||||
|
||||
// modify set() to use angular Promises and angular.toJson()
|
||||
this.set = (key, value) =>
|
||||
Promise.resolve(uiSettings.set(key, isPlainObject(value) ? angular.toJson(value) : value));
|
||||
|
||||
//////////////////////////////
|
||||
//* angular specific methods *
|
||||
//////////////////////////////
|
||||
|
||||
const subscription = subscribeWithScope(
|
||||
$rootScope,
|
||||
uiSettings.getUpdate$(),
|
||||
{
|
||||
next: ({ key, newValue, oldValue }) => {
|
||||
$rootScope.$broadcast('change:config', newValue, oldValue, key, this);
|
||||
$rootScope.$broadcast(`change:config.${key}`, newValue, oldValue, key, this);
|
||||
},
|
||||
},
|
||||
fatalError
|
||||
);
|
||||
$rootScope.$on('$destroy', () => subscription.unsubscribe());
|
||||
|
||||
this.watchAll = function (handler, scope = $rootScope) {
|
||||
// call handler immediately to initialize
|
||||
handler(null, null, null, this);
|
||||
|
||||
return scope.$on('change:config', (event, ...args) => {
|
||||
handler(...args);
|
||||
});
|
||||
};
|
||||
|
||||
this.watch = function (key, handler, scope = $rootScope) {
|
||||
if (!this.isDeclared(key)) {
|
||||
throw new Error(`Unexpected \`config.watch("${key}", fn)\` call on unrecognized configuration setting "${key}".
|
||||
Setting an initial value via \`config.set("${key}", value)\` before binding
|
||||
any custom setting configuration watchers for "${key}" may fix this issue.`);
|
||||
}
|
||||
|
||||
// call handler immediately with current value
|
||||
handler(this.get(key), null, key, uiSettings);
|
||||
|
||||
// call handler again on each change for this key
|
||||
return scope.$on(`change:config.${key}`, (event, ...args) => {
|
||||
handler(...args);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* A little helper for binding config variables to $scopes
|
||||
*
|
||||
* @param {Scope} $scope - an angular $scope object
|
||||
* @param {string} key - the config key to bind to
|
||||
* @param {string} [property] - optional property name where the value should
|
||||
* be stored. Defaults to the config key
|
||||
* @return {function} - an unbind function
|
||||
*/
|
||||
this.bindToScope = function (scope, key, property = key) {
|
||||
const onUpdate = (newVal) => {
|
||||
scope[property] = newVal;
|
||||
};
|
||||
|
||||
return this.watch(key, onUpdate, scope);
|
||||
};
|
||||
});
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* 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 './config';
|
|
@ -1,89 +0,0 @@
|
|||
/*
|
||||
* 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 expect from '@kbn/expect';
|
||||
import ngMock from 'ng_mock';
|
||||
import $ from 'jquery';
|
||||
import '../input_focus';
|
||||
import uiRoutes from 'ui/routes';
|
||||
|
||||
describe('Input focus directive', function () {
|
||||
let $compile;
|
||||
let $rootScope;
|
||||
let $timeout;
|
||||
let element;
|
||||
let $el;
|
||||
let selectedEl;
|
||||
let selectedText;
|
||||
const inputValue = 'Input Text Value';
|
||||
|
||||
uiRoutes.enable();
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
beforeEach(
|
||||
ngMock.inject(function (_$compile_, _$rootScope_, _$timeout_) {
|
||||
$compile = _$compile_;
|
||||
$rootScope = _$rootScope_;
|
||||
$timeout = _$timeout_;
|
||||
|
||||
$el = $('<div>');
|
||||
$el.appendTo('body');
|
||||
})
|
||||
);
|
||||
|
||||
afterEach(function () {
|
||||
$el.remove();
|
||||
$el = null;
|
||||
});
|
||||
|
||||
function renderEl(html) {
|
||||
$rootScope.value = inputValue;
|
||||
element = $compile(html)($rootScope);
|
||||
element.appendTo($el);
|
||||
$rootScope.$digest();
|
||||
$timeout.flush();
|
||||
selectedEl = document.activeElement;
|
||||
if (selectedEl.value) {
|
||||
selectedText = selectedEl.value.slice(selectedEl.selectionStart, selectedEl.selectionEnd);
|
||||
}
|
||||
}
|
||||
|
||||
it('should focus the input', function () {
|
||||
renderEl('<input type="text" ng-model="value" input-focus />');
|
||||
expect(selectedEl).to.equal(element[0]);
|
||||
expect(selectedText.length).to.equal(0);
|
||||
});
|
||||
|
||||
it('should select the text in the input', function () {
|
||||
renderEl('<input type="text" ng-model="value" input-focus="select" />');
|
||||
expect(selectedEl).to.equal(element[0]);
|
||||
expect(selectedText.length).to.equal(inputValue.length);
|
||||
expect(selectedText).to.equal(inputValue);
|
||||
});
|
||||
|
||||
it('should not focus the input if disable-input-focus is set to true on the same element', function () {
|
||||
renderEl('<input type="text" ng-model="value" input-focus disable-input-focus="true">');
|
||||
expect(selectedEl).not.to.be(element[0]);
|
||||
});
|
||||
|
||||
it('should still focus the input if disable-input-focus is falsy', function () {
|
||||
renderEl('<input type="text" ng-model="value" input-focus disable-input-focus="false">');
|
||||
expect(selectedEl).to.be(element[0]);
|
||||
});
|
||||
});
|
|
@ -1,2 +0,0 @@
|
|||
@import './input_datetime';
|
||||
@import './saved_object_paginated_selectable'
|
|
@ -1,5 +0,0 @@
|
|||
.input-datetime-format {
|
||||
font-size: $euiFontSizeXS;
|
||||
color: $euiColorMediumShade;
|
||||
padding: $euiSizeXS $euiSize;
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
saved-object-finder,
|
||||
paginated-selectable-list {
|
||||
|
||||
.list-sort-button {
|
||||
border-top-left-radius: 0 !important;
|
||||
border-top-right-radius: 0 !important;
|
||||
border: none;
|
||||
padding: $euiSizeS $euiSize;
|
||||
font-weight: $euiFontWeightRegular;
|
||||
background-color: $euiColorLightestShade;
|
||||
}
|
||||
|
||||
ul.li-striped {
|
||||
li {
|
||||
border: none;
|
||||
}
|
||||
|
||||
li:nth-child(even) {
|
||||
background-color: $euiColorLightestShade;
|
||||
}
|
||||
|
||||
li:nth-child(odd) {
|
||||
background-color: $euiColorEmptyShade;
|
||||
}
|
||||
|
||||
.paginate-heading {
|
||||
font-weight: $euiFontWeightRegular;
|
||||
color: $euiColorDarkestShade;
|
||||
}
|
||||
|
||||
.list-group-item {
|
||||
padding: $euiSizeS $euiSize;
|
||||
|
||||
ul {
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
.finder-type {
|
||||
margin-right: $euiSizeS;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
display: block;
|
||||
color: $euiColorPrimary !important;
|
||||
|
||||
i {
|
||||
color: shade($euiColorPrimary, 10%) !important;
|
||||
margin-right: $euiSizeS;
|
||||
}
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
border-top-left-radius: 0 !important;
|
||||
border-top-right-radius: 0 !important;
|
||||
}
|
||||
|
||||
&.list-group-no-results p {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
paginate {
|
||||
paginate-controls {
|
||||
margin: $euiSize;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
* 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 expect from '@kbn/expect';
|
||||
import ngMock from 'ng_mock';
|
||||
describe('$scope.$bind', function () {
|
||||
let $rootScope;
|
||||
let $scope;
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
beforeEach(
|
||||
ngMock.inject(function ($injector) {
|
||||
$rootScope = $injector.get('$rootScope');
|
||||
$scope = $rootScope.$new();
|
||||
})
|
||||
);
|
||||
|
||||
it('exposes $bind on all scopes', function () {
|
||||
expect($rootScope.$bind).to.be.a('function');
|
||||
expect($scope).to.have.property('$bind', $rootScope.$bind);
|
||||
|
||||
const $isoScope = $scope.$new(true);
|
||||
expect($isoScope).to.have.property('$bind', $rootScope.$bind);
|
||||
});
|
||||
|
||||
it("sets up binding from a parent scope to it's child", function () {
|
||||
$rootScope.val = 'foo';
|
||||
$scope.$bind('localVal', 'val');
|
||||
expect($scope.localVal).to.be('foo');
|
||||
|
||||
$rootScope.val = 'bar';
|
||||
expect($scope.localVal).to.be('foo'); // shouldn't have changed yet
|
||||
|
||||
$rootScope.$apply();
|
||||
expect($scope.localVal).to.be('bar');
|
||||
});
|
||||
|
||||
it('sets up a binding from the child to the parent scope', function () {
|
||||
$rootScope.val = 'foo';
|
||||
$scope.$bind('localVal', 'val');
|
||||
expect($scope.localVal).to.be('foo');
|
||||
|
||||
$scope.localVal = 'bar';
|
||||
expect($rootScope.val).to.be('foo'); // shouldn't have changed yet
|
||||
|
||||
$scope.$apply();
|
||||
expect($rootScope.val).to.be('bar');
|
||||
});
|
||||
|
||||
it('pulls from the scopes $parent by default', function () {
|
||||
const $parent = $rootScope.$new();
|
||||
const $self = $parent.$new();
|
||||
|
||||
$parent.val = 'foo';
|
||||
$self.val = 'bar';
|
||||
|
||||
$self.$bind('localVal', 'val');
|
||||
expect($self.localVal).to.be('foo');
|
||||
});
|
||||
|
||||
it('accepts an alternate scope to read from', function () {
|
||||
const $parent = $rootScope.$new();
|
||||
const $self = $parent.$new();
|
||||
|
||||
$parent.val = 'foo';
|
||||
$self.val = 'bar';
|
||||
|
||||
$self.$bind('localVal', 'val', $self);
|
||||
expect($self.localVal).to.be('bar');
|
||||
});
|
||||
});
|
|
@ -1,116 +0,0 @@
|
|||
/*
|
||||
* 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 angular from 'angular';
|
||||
import { uiModules } from '../../modules';
|
||||
|
||||
uiModules.get('kibana').config(function ($provide) {
|
||||
function strictEquality(a, b) {
|
||||
// are the values equal? or, are they both NaN?
|
||||
return a === b || (a !== a && b !== b);
|
||||
}
|
||||
|
||||
function errorNotAssignable(source, target) {
|
||||
throw Error(
|
||||
'Unable to accept change to bound $scope property "' +
|
||||
source +
|
||||
'"' +
|
||||
' because source expression "' +
|
||||
target +
|
||||
'" is not assignable!'
|
||||
);
|
||||
}
|
||||
|
||||
$provide.decorator('$rootScope', function ($delegate, $parse) {
|
||||
/**
|
||||
* Two-way bind a value from scope to another property on scope. This
|
||||
* allow values on scope that work like they do in an isolate scope, but
|
||||
* without requiring one.
|
||||
*
|
||||
* @param {expression} to - the location on scope to bind to
|
||||
* @param {expression} from - the location on scope to bind from
|
||||
* @param {Scope} $sourceScope - the scope to read "from" expression from
|
||||
* @return {undefined}
|
||||
*/
|
||||
$delegate.constructor.prototype.$bind = function (to, from, $sourceScope) {
|
||||
const $source = $sourceScope || this.$parent;
|
||||
const $target = this;
|
||||
|
||||
// parse expressions
|
||||
const $to = $parse(to);
|
||||
if (!$to.assign) errorNotAssignable(to, from);
|
||||
const $from = $parse(from);
|
||||
|
||||
// bind scopes to expressions
|
||||
const getTarget = function () {
|
||||
return $to($target);
|
||||
};
|
||||
const setTarget = function (v) {
|
||||
return $to.assign($target, v);
|
||||
};
|
||||
const getSource = function () {
|
||||
return $from($source);
|
||||
};
|
||||
const setSource = function (v) {
|
||||
return $from.assignOrFail($source, v);
|
||||
};
|
||||
|
||||
// to support writing from the child to the parent we need to know
|
||||
// which source has changed. Track the source value and anytime it
|
||||
// changes (even if the target value changed too) push from source
|
||||
// to target. If the source hasn't changed then the change is from
|
||||
// the target and push accordingly
|
||||
let lastSourceVal = getSource();
|
||||
|
||||
$from.assignOrFail =
|
||||
$from.assign ||
|
||||
function () {
|
||||
// revert the change and throw an error, child writes aren't supported
|
||||
$to($target, (lastSourceVal = $from($source)));
|
||||
errorNotAssignable(from, to);
|
||||
};
|
||||
|
||||
// if we are syncing down a literal, then we use loose equality check
|
||||
const strict = !$from.literal;
|
||||
const compare = strict ? strictEquality : angular.equals;
|
||||
|
||||
// push the initial value down, start off in sync
|
||||
setTarget(lastSourceVal);
|
||||
|
||||
$target.$watch(
|
||||
function () {
|
||||
const sourceVal = getSource();
|
||||
const targetVal = getTarget();
|
||||
|
||||
const outOfSync = !compare(sourceVal, targetVal);
|
||||
const sourceChanged = outOfSync && !compare(sourceVal, lastSourceVal);
|
||||
|
||||
if (sourceChanged) setTarget(sourceVal);
|
||||
else if (outOfSync) setSource(targetVal);
|
||||
|
||||
return (lastSourceVal = sourceVal);
|
||||
},
|
||||
null,
|
||||
!strict
|
||||
);
|
||||
};
|
||||
|
||||
return $delegate;
|
||||
});
|
||||
});
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* 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 './bind';
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* 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 { uiModules } from '../modules';
|
||||
const module = uiModules.get('kibana');
|
||||
|
||||
module.directive('inputFocus', function ($parse, $timeout) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: function ($scope, $elem, attrs) {
|
||||
const isDisabled = attrs.disableInputFocus && $parse(attrs.disableInputFocus)($scope);
|
||||
if (!isDisabled) {
|
||||
$timeout(function () {
|
||||
$elem.focus();
|
||||
if (attrs.inputFocus === 'select') $elem.select();
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* 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 { uiModules } from '../modules';
|
||||
import { words, kebabCase } from 'lodash';
|
||||
|
||||
export function kbnUrlDirective(name) {
|
||||
const attr = kebabCase(words(name).slice(1));
|
||||
|
||||
uiModules.get('kibana').directive(name, function (chrome) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: function ($scope, $el, $attr) {
|
||||
$attr.$observe(name, function (val) {
|
||||
$attr.$set(attr, chrome.addBasePath(val));
|
||||
});
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
kbnUrlDirective('kbnHref');
|
|
@ -1,96 +0,0 @@
|
|||
/*
|
||||
* 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 sinon from 'sinon';
|
||||
import expect from '@kbn/expect';
|
||||
import ngMock from 'ng_mock';
|
||||
import '..';
|
||||
import { EventsProvider } from '../../../events';
|
||||
|
||||
describe('listen component', function () {
|
||||
let $rootScope;
|
||||
let Events;
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
beforeEach(
|
||||
ngMock.inject(function ($injector, Private) {
|
||||
$rootScope = $injector.get('$rootScope');
|
||||
Events = Private(EventsProvider);
|
||||
})
|
||||
);
|
||||
|
||||
it('exposes the $listen method on all scopes', function () {
|
||||
expect($rootScope.$listen).to.be.a('function');
|
||||
expect($rootScope.$new().$listen).to.be.a('function');
|
||||
});
|
||||
|
||||
it('binds to an event emitter', function () {
|
||||
const emitter = new Events();
|
||||
const $scope = $rootScope.$new();
|
||||
|
||||
function handler() {}
|
||||
$scope.$listen(emitter, 'hello', handler);
|
||||
|
||||
expect(emitter._listeners.hello).to.have.length(1);
|
||||
expect(emitter._listeners.hello[0].handler).to.be(handler);
|
||||
});
|
||||
|
||||
it('binds to $scope, waiting for the destroy event', function () {
|
||||
const emitter = new Events();
|
||||
const $scope = $rootScope.$new();
|
||||
|
||||
sinon.stub($scope, '$on');
|
||||
sinon.stub($rootScope, '$on');
|
||||
|
||||
function handler() {}
|
||||
$scope.$listen(emitter, 'hello', handler);
|
||||
|
||||
expect($rootScope.$on).to.have.property('callCount', 0);
|
||||
expect($scope.$on).to.have.property('callCount', 1);
|
||||
|
||||
const call = $scope.$on.firstCall;
|
||||
expect(call.args[0]).to.be('$destroy');
|
||||
expect(call.args[1]).to.be.a('function');
|
||||
});
|
||||
|
||||
it('unbinds the event handler when $destroy is triggered', function () {
|
||||
const emitter = new Events();
|
||||
const $scope = $rootScope.$new();
|
||||
|
||||
sinon.stub($scope, '$on');
|
||||
sinon.stub(emitter, 'off');
|
||||
|
||||
// set the listener
|
||||
function handler() {}
|
||||
$scope.$listen(emitter, 'hello', handler);
|
||||
|
||||
// get the unbinder that was registered to $scope
|
||||
const unbinder = $scope.$on.firstCall.args[1];
|
||||
|
||||
// call the unbinder
|
||||
expect(emitter.off).to.have.property('callCount', 0);
|
||||
unbinder();
|
||||
expect(emitter.off).to.have.property('callCount', 1);
|
||||
|
||||
// check that the off args were as expected
|
||||
const call = emitter.off.firstCall;
|
||||
expect(call.args[0]).to.be('hello');
|
||||
expect(call.args[1]).to.be(handler);
|
||||
});
|
||||
});
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* 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 './listen';
|
|
@ -1,23 +0,0 @@
|
|||
/*
|
||||
* 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 { uiModules } from '../../modules';
|
||||
import { registerListenEventListener } from '../../../../../plugins/kibana_legacy/public';
|
||||
|
||||
uiModules.get('kibana').run(registerListenEventListener);
|
|
@ -1,123 +0,0 @@
|
|||
/*
|
||||
* 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 angular from 'angular';
|
||||
import sinon from 'sinon';
|
||||
import expect from '@kbn/expect';
|
||||
import ngMock from 'ng_mock';
|
||||
import '..';
|
||||
|
||||
let init;
|
||||
let $rootScope;
|
||||
let $compile;
|
||||
|
||||
describe('render_directive', function () {
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
beforeEach(
|
||||
ngMock.inject(function ($injector) {
|
||||
$rootScope = $injector.get('$rootScope');
|
||||
$compile = $injector.get('$compile');
|
||||
init = function init(markup = '', definition = {}) {
|
||||
const $parentScope = $rootScope;
|
||||
|
||||
// create the markup
|
||||
const $elem = angular.element('<render-directive>');
|
||||
$elem.html(markup);
|
||||
if (definition !== null) {
|
||||
$parentScope.definition = definition;
|
||||
$elem.attr('definition', 'definition');
|
||||
}
|
||||
|
||||
// compile the directive
|
||||
$compile($elem)($parentScope);
|
||||
$parentScope.$apply();
|
||||
|
||||
const $directiveScope = $elem.isolateScope();
|
||||
|
||||
return { $parentScope, $directiveScope, $elem };
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
describe('directive requirements', function () {
|
||||
it('should throw if not given a definition', function () {
|
||||
expect(() => init('', null)).to.throwException(/must have a definition/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('rendering with definition', function () {
|
||||
it('should call link method', function () {
|
||||
const markup = '<p>hello world</p>';
|
||||
const definition = {
|
||||
link: sinon.stub(),
|
||||
};
|
||||
|
||||
init(markup, definition);
|
||||
|
||||
sinon.assert.callCount(definition.link, 1);
|
||||
});
|
||||
|
||||
it('should call controller method', function () {
|
||||
const markup = '<p>hello world</p>';
|
||||
const definition = {
|
||||
controller: sinon.stub(),
|
||||
};
|
||||
|
||||
init(markup, definition);
|
||||
|
||||
sinon.assert.callCount(definition.controller, 1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('definition scope binding', function () {
|
||||
it('should accept two-way, attribute, and expression binding directives', function () {
|
||||
const $el = angular.element(`
|
||||
<render-directive
|
||||
definition="definition"
|
||||
two-way-prop="parentTwoWay"
|
||||
attr="Simple Attribute"
|
||||
expr="parentExpression()"
|
||||
>
|
||||
{{two}},{{attr}},{{expr()}}
|
||||
</render-directive>
|
||||
`);
|
||||
|
||||
const $parentScope = $rootScope.$new();
|
||||
$parentScope.definition = {
|
||||
scope: {
|
||||
two: '=twoWayProp',
|
||||
attr: '@',
|
||||
expr: '&expr',
|
||||
},
|
||||
};
|
||||
$parentScope.parentTwoWay = true;
|
||||
$parentScope.parentExpression = function () {
|
||||
return !$parentScope.parentTwoWay;
|
||||
};
|
||||
|
||||
$compile($el)($parentScope);
|
||||
$parentScope.$apply();
|
||||
|
||||
expect($el.text().trim()).to.eql('true,Simple Attribute,false');
|
||||
$parentScope.parentTwoWay = false;
|
||||
$parentScope.$apply();
|
||||
expect($el.text().trim()).to.eql('false,Simple Attribute,true');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
* 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 { forOwn, noop } from 'lodash';
|
||||
|
||||
import '../../directives/bind';
|
||||
|
||||
const bindingRE = /^(=|=\?|&|@)([a-zA-Z0-9_$]+)?$/;
|
||||
|
||||
export function ApplyScopeBindingsProvider($parse) {
|
||||
return function (bindings, $scope, $attrs) {
|
||||
forOwn(bindings, (binding, local) => {
|
||||
if (!bindingRE.test(binding)) {
|
||||
throw new Error(`Invalid scope binding "${binding}". Expected it to match ${bindingRE}`);
|
||||
}
|
||||
|
||||
const [, type, attribute = local] = binding.match(bindingRE);
|
||||
const attr = $attrs[attribute];
|
||||
switch (type) {
|
||||
case '=':
|
||||
$scope.$bind(local, attr);
|
||||
break;
|
||||
case '=?':
|
||||
throw new Error(
|
||||
'<render-directive> does not currently support optional two-way bindings.'
|
||||
);
|
||||
break;
|
||||
case '&':
|
||||
if (attr) {
|
||||
const getter = $parse(attr);
|
||||
$scope[local] = function () {
|
||||
return getter($scope.$parent);
|
||||
};
|
||||
} else {
|
||||
$scope[local] = noop;
|
||||
}
|
||||
break;
|
||||
case '@':
|
||||
$scope[local] = attr;
|
||||
$attrs.$observe(attribute, (v) => ($scope[local] = v));
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* 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 './render_directive';
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
* 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 { isPlainObject } from 'lodash';
|
||||
import { uiModules } from '../../modules';
|
||||
import { ApplyScopeBindingsProvider } from './apply_scope_bindings';
|
||||
|
||||
/**
|
||||
* The <render-directive> directive is useful for programmatically modifying or
|
||||
* extending a view. It allows defining the majority of the directives behavior
|
||||
* using a "definition" object, which the implementer can obtain from plugins (for instance).
|
||||
*
|
||||
* The definition object supports the parts of a directive definition that are
|
||||
* easy enough to implement without having to hack angular, and does it's best to
|
||||
* make sure standard directive life-cycle timing is respected.
|
||||
*
|
||||
* @param [Object] definition - the external configuration for this directive to assume
|
||||
* @param [Function] definition.controller - a constructor used to create the controller for this directive
|
||||
* @param [String] definition.controllerAs - a name where the controller should be stored on scope
|
||||
* @param [Object] definition.scope - an object defining the binding properties for values read from
|
||||
* attributes and bound to $scope. The keys of this object are the
|
||||
* local names of $scope properties, and the values are a combination
|
||||
* of the binding style (=, @, or &) and the external attribute name.
|
||||
* See [the Angular docs]
|
||||
* (https://code.angularjs.org/1.4.9/docs/api/ng/service/$compile#-scope-)
|
||||
* for more info
|
||||
* @param [Object|Function] definition.link - either a post link function or an object with pre and/or
|
||||
* post link functions.
|
||||
*/
|
||||
uiModules.get('kibana').directive('renderDirective', function (Private) {
|
||||
const applyScopeBindings = Private(ApplyScopeBindingsProvider);
|
||||
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
definition: '=',
|
||||
},
|
||||
template: function ($el) {
|
||||
return $el.html();
|
||||
},
|
||||
controller: function ($scope, $element, $attrs, $transclude, $injector) {
|
||||
if (!$scope.definition) throw new Error('render-directive must have a definition attribute');
|
||||
|
||||
const { controller, controllerAs, scope } = $scope.definition;
|
||||
|
||||
applyScopeBindings(scope, $scope, $attrs);
|
||||
|
||||
if (controller) {
|
||||
if (controllerAs) {
|
||||
$scope[controllerAs] = this;
|
||||
}
|
||||
|
||||
const locals = { $scope, $element, $attrs, $transclude };
|
||||
const controllerInstance = $injector.invoke(controller, this, locals) || this;
|
||||
|
||||
if (controllerAs) {
|
||||
$scope[controllerAs] = controllerInstance;
|
||||
}
|
||||
}
|
||||
},
|
||||
link: {
|
||||
pre($scope, $el, $attrs, controller) {
|
||||
const { link } = $scope.definition;
|
||||
const preLink = isPlainObject(link) ? link.pre : null;
|
||||
if (preLink) preLink($scope, $el, $attrs, controller);
|
||||
},
|
||||
post($scope, $el, $attrs, controller) {
|
||||
const { link } = $scope.definition;
|
||||
const postLink = isPlainObject(link) ? link.post : link;
|
||||
if (postLink) postLink($scope, $el, $attrs, controller);
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* 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 { uiModules } from '../../modules';
|
||||
import { Storage } from '../../../../../plugins/kibana_utils/public';
|
||||
|
||||
const createService = function (type) {
|
||||
return function ($window) {
|
||||
return new Storage($window[type]);
|
||||
};
|
||||
};
|
||||
|
||||
uiModules
|
||||
.get('kibana/storage')
|
||||
.service('localStorage', createService('localStorage'))
|
||||
.service('sessionStorage', createService('sessionStorage'));
|
|
@ -1,216 +0,0 @@
|
|||
/*
|
||||
* 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 _ from 'lodash';
|
||||
import ngMock from 'ng_mock';
|
||||
import expect from '@kbn/expect';
|
||||
import sinon from 'sinon';
|
||||
|
||||
describe('$scope.$watchMulti', function () {
|
||||
let $rootScope;
|
||||
let $scope;
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
beforeEach(
|
||||
ngMock.inject(function ($injector) {
|
||||
$rootScope = $injector.get('$rootScope');
|
||||
$scope = $rootScope.$new();
|
||||
})
|
||||
);
|
||||
|
||||
describe('basic functionality', function () {
|
||||
it('exposes $watchMulti on all scopes', function () {
|
||||
expect($rootScope.$watchMulti).to.be.a('function');
|
||||
expect($scope).to.have.property('$watchMulti', $rootScope.$watchMulti);
|
||||
|
||||
const $isoScope = $scope.$new(true);
|
||||
expect($isoScope).to.have.property('$watchMulti', $rootScope.$watchMulti);
|
||||
});
|
||||
|
||||
it('returns a working unwatch function', function () {
|
||||
$scope.a = 0;
|
||||
$scope.b = 0;
|
||||
let triggers = 0;
|
||||
const unwatch = $scope.$watchMulti(['a', 'b'], function () {
|
||||
triggers++;
|
||||
});
|
||||
|
||||
// initial watch
|
||||
$scope.$apply();
|
||||
expect(triggers).to.be(1);
|
||||
|
||||
// prove that it triggers on change
|
||||
$scope.a++;
|
||||
$scope.$apply();
|
||||
expect(triggers).to.be(2);
|
||||
|
||||
// remove watchers
|
||||
expect($scope.$$watchers).to.not.have.length(0);
|
||||
unwatch();
|
||||
expect($scope.$$watchers).to.have.length(0);
|
||||
|
||||
// prove that it doesn't trigger anymore
|
||||
$scope.a++;
|
||||
$scope.$apply();
|
||||
expect(triggers).to.be(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('simple scope watchers', function () {
|
||||
it('only triggers a single watch on initialization', function () {
|
||||
const stub = sinon.stub();
|
||||
|
||||
$scope.$watchMulti(['one', 'two', 'three'], stub);
|
||||
$rootScope.$apply();
|
||||
|
||||
expect(stub.callCount).to.be(1);
|
||||
});
|
||||
|
||||
it('only triggers a single watch when multiple values change', function () {
|
||||
const stub = sinon.spy(function () {});
|
||||
|
||||
$scope.$watchMulti(['one', 'two', 'three'], stub);
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(stub.callCount).to.be(1);
|
||||
|
||||
$scope.one = 'a';
|
||||
$scope.two = 'b';
|
||||
$scope.three = 'c';
|
||||
$rootScope.$apply();
|
||||
|
||||
expect(stub.callCount).to.be(2);
|
||||
});
|
||||
|
||||
it('passes an array of the current and previous values, in order', function () {
|
||||
const stub = sinon.spy(function () {});
|
||||
|
||||
$scope.one = 'a';
|
||||
$scope.two = 'b';
|
||||
$scope.three = 'c';
|
||||
$scope.$watchMulti(['one', 'two', 'three'], stub);
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(stub.firstCall.args).to.eql([
|
||||
['a', 'b', 'c'],
|
||||
['a', 'b', 'c'],
|
||||
]);
|
||||
|
||||
$scope.one = 'do';
|
||||
$scope.two = 're';
|
||||
$scope.three = 'mi';
|
||||
$rootScope.$apply();
|
||||
|
||||
expect(stub.secondCall.args).to.eql([
|
||||
['do', 're', 'mi'],
|
||||
['a', 'b', 'c'],
|
||||
]);
|
||||
});
|
||||
|
||||
it('always has an up to date value', function () {
|
||||
let count = 0;
|
||||
|
||||
$scope.vals = [1, 0];
|
||||
$scope.$watchMulti(['vals[0]', 'vals[1]'], function (cur) {
|
||||
expect(cur).to.eql($scope.vals);
|
||||
count++;
|
||||
});
|
||||
|
||||
const $child = $scope.$new();
|
||||
$child.$watch('vals[0]', function (cur) {
|
||||
$child.vals[1] = cur;
|
||||
});
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(count).to.be(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('complex watch expressions', function () {
|
||||
let stateWatchers;
|
||||
let firstValue;
|
||||
let secondValue;
|
||||
|
||||
beforeEach(function () {
|
||||
const firstGetter = function () {
|
||||
return firstValue;
|
||||
};
|
||||
|
||||
const secondGetter = function () {
|
||||
return secondValue;
|
||||
};
|
||||
|
||||
stateWatchers = [
|
||||
{
|
||||
fn: $rootScope.$watch,
|
||||
get: firstGetter,
|
||||
},
|
||||
{
|
||||
fn: $rootScope.$watch,
|
||||
get: secondGetter,
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
it('should trigger the watcher on initialization', function () {
|
||||
const stub = sinon.stub();
|
||||
firstValue = 'first';
|
||||
secondValue = 'second';
|
||||
|
||||
$scope.$watchMulti(stateWatchers, stub);
|
||||
$rootScope.$apply();
|
||||
|
||||
expect(stub.callCount).to.be(1);
|
||||
|
||||
expect(stub.firstCall.args[0]).to.eql([firstValue, secondValue]);
|
||||
expect(stub.firstCall.args[1]).to.eql([firstValue, secondValue]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('nested watchers', function () {
|
||||
it('should trigger the handler at least once', function () {
|
||||
const $scope = $rootScope.$new();
|
||||
$scope.$$watchers = [
|
||||
{
|
||||
get: _.noop,
|
||||
fn: _.noop,
|
||||
eq: false,
|
||||
last: false,
|
||||
},
|
||||
{
|
||||
get: _.noop,
|
||||
fn: registerWatchers,
|
||||
eq: false,
|
||||
last: false,
|
||||
},
|
||||
];
|
||||
|
||||
const first = sinon.stub();
|
||||
const second = sinon.stub();
|
||||
|
||||
function registerWatchers() {
|
||||
$scope.$watchMulti([first, second], function () {
|
||||
expect(first.callCount).to.be.greaterThan(0);
|
||||
expect(second.callCount).to.be.greaterThan(0);
|
||||
});
|
||||
}
|
||||
$scope.$digest();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
* 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 { uiModules } from '../../modules';
|
||||
import { watchMultiDecorator } from '../../../../../plugins/kibana_legacy/public';
|
||||
uiModules.get('kibana').config(watchMultiDecorator);
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue