Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract angular configuration from ui/chrome #34314

Merged
merged 2 commits into from
Apr 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ new CoreSystem({
legacyMetadata: {
version: '1.2.3',
buildNum: 1234,
devMode: true,
uiSettings: {
defaults: ${JSON.stringify(defaultUiSettings, null, 2).split('\n').join('\n ')},
user: {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import ngMock from 'ng_mock';
import expect from '@kbn/expect';

import { SubUrlRouteFilterProvider } from '../sub_url_route_filter';
import { SubUrlRouteFilterProvider } from '../sub_url_hooks';

describe('kbn-chrome subUrlRouteFilter()', () => {
describe('no ngRoute', () => {
Expand Down
116 changes: 0 additions & 116 deletions src/legacy/ui/public/chrome/api/__tests__/xsrf.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,12 @@
* under the License.
*/

import $ from 'jquery';
import expect from '@kbn/expect';
import sinon from 'sinon';
import ngMock from 'ng_mock';

import { initChromeXsrfApi } from '../xsrf';
import { version } from '../../../../../utils/package_json';

const xsrfHeader = 'kbn-version';

describe('chrome xsrf apis', function () {
const sandbox = sinon.createSandbox();

Expand All @@ -41,116 +37,4 @@ describe('chrome xsrf apis', function () {
expect(chrome.getXsrfToken()).to.be(version);
});
});

describe('jQuery support', function () {
it('adds a global jQuery prefilter', function () {
sandbox.stub($, 'ajaxPrefilter');
initChromeXsrfApi({}, { version });
expect($.ajaxPrefilter.callCount).to.be(1);
});

describe('jQuery prefilter', function () {
let prefilter;

beforeEach(function () {
sandbox.stub($, 'ajaxPrefilter');
initChromeXsrfApi({}, { version });
prefilter = $.ajaxPrefilter.args[0][0];
});

it(`sets the ${xsrfHeader} header`, function () {
const setHeader = sinon.stub();
prefilter({}, {}, { setRequestHeader: setHeader });

expect(setHeader.callCount).to.be(1);
expect(setHeader.args[0]).to.eql([
xsrfHeader,
version
]);
});

it('can be canceled by setting the kbnXsrfToken option', function () {
const setHeader = sinon.stub();
prefilter({ kbnXsrfToken: false }, {}, { setRequestHeader: setHeader });
expect(setHeader.callCount).to.be(0);
});
});

describe('Angular support', function () {

let $http;
let $httpBackend;

beforeEach(function () {
sandbox.stub($, 'ajaxPrefilter');
const chrome = {};
initChromeXsrfApi(chrome, { version });
ngMock.module(chrome.$setupXsrfRequestInterceptor);
});

beforeEach(ngMock.inject(function ($injector) {
$http = $injector.get('$http');
$httpBackend = $injector.get('$httpBackend');

$httpBackend
.when('POST', '/api/test')
.respond('ok');
}));

afterEach(function () {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});

it(`injects a ${xsrfHeader} header on every request`, function () {
$httpBackend.expectPOST('/api/test', undefined, function (headers) {
return headers[xsrfHeader] === version;
}).respond(200, '');

$http.post('/api/test');
$httpBackend.flush();
});

it('skips requests with the kbnXsrfToken set falsy', function () {
$httpBackend.expectPOST('/api/test', undefined, function (headers) {
return !(xsrfHeader in headers);
}).respond(200, '');

$http({
method: 'POST',
url: '/api/test',
kbnXsrfToken: 0
});

$http({
method: 'POST',
url: '/api/test',
kbnXsrfToken: ''
});

$http({
method: 'POST',
url: '/api/test',
kbnXsrfToken: false
});

$httpBackend.flush();
});

it('treats the kbnXsrfToken option as boolean-y', function () {
const customToken = `custom:${version}`;
$httpBackend.expectPOST('/api/test', undefined, function (headers) {
return headers[xsrfHeader] === version;
}).respond(200, '');

$http({
method: 'POST',
url: '/api/test',
kbnXsrfToken: customToken
});

$httpBackend.flush();
});
});
});
});
112 changes: 5 additions & 107 deletions src/legacy/ui/public/chrome/api/angular.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,125 +17,23 @@
* under the License.
*/

import React, { Fragment } from 'react';
import _ from 'lodash';
import { modifyUrl } from 'ui/url';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';

import { uiModules } from '../../modules';
import { toastNotifications } from '../../notify';
import { UrlOverflowServiceProvider } from '../../error_url_overflow';

import { directivesProvider } from '../directives';

const URL_LIMIT_WARN_WITHIN = 1000;
import { registerSubUrlHooks } from './sub_url_hooks';
import { configureAppAngularModule } from 'ui/legacy_compat';

export function initAngularApi(chrome, internals) {
chrome.getFirstPathSegment = _.noop;

chrome.setupAngular = function () {
const kibana = uiModules.get('kibana');

_.forOwn(chrome.getInjected(), function (val, name) {
kibana.value(name, val);
});
configureAppAngularModule(kibana);

kibana
.value('kbnVersion', internals.version)
.value('buildNum', internals.buildNum)
.value('buildSha', internals.buildSha)
.value('serverName', internals.serverName)
.value('sessionId', Date.now())
.value('chrome', chrome)
.value('esUrl', (function () {
const a = document.createElement('a');
a.href = chrome.addBasePath('/elasticsearch');
const protocolPort = /https/.test(a.protocol) ? 443 : 80;
const port = a.port || protocolPort;
return {
host: a.hostname,
port,
protocol: a.protocol,
pathname: a.pathname
};
}()))
.config($locationProvider => {
$locationProvider.html5Mode({
enabled: false,
requireBase: false,
rewriteLinks: false,
});
})
.config(chrome.$setupXsrfRequestInterceptor)
.config(function ($compileProvider, $locationProvider) {
if (!internals.devMode) {
$compileProvider.debugInfoEnabled(false);
}

$locationProvider.hashPrefix('');
})
.run(internals.capture$httpLoadingCount)
.run(internals.$setupBreadcrumbsAutoClear)
.run(internals.$setupHelpExtensionAutoClear)
.run(internals.$initNavLinksDeepWatch)
.run(($location, $rootScope, Private, config) => {
chrome.getFirstPathSegment = () => {
return $location.path().split('/')[1];
};

const urlOverflow = Private(UrlOverflowServiceProvider);
const check = () => {
// disable long url checks when storing state in session storage
if (config.get('state:storeInSessionStorage')) {
return;
}

if ($location.path() === '/error/url-overflow') {
return;
}

try {
if (urlOverflow.check($location.absUrl()) <= URL_LIMIT_WARN_WITHIN) {
toastNotifications.addWarning({
title: i18n.translate('common.ui.chrome.bigUrlWarningNotificationTitle', {
defaultMessage: 'The URL is big and Kibana might stop working'
}),
text: (
<Fragment>
<FormattedMessage
id="common.ui.chrome.bigUrlWarningNotificationMessage"
defaultMessage="Either enable the {storeInSessionStorageParam} option
in {advancedSettingsLink} or simplify the onscreen visuals."
values={{
storeInSessionStorageParam: <code>state:storeInSessionStorage</code>,
advancedSettingsLink: (
<a href="#/management/kibana/settings">
<FormattedMessage
id="common.ui.chrome.bigUrlWarningNotificationMessage.advancedSettingsLinkText"
defaultMessage="advanced settings"
/>
</a>
)
}}
/>
</Fragment>
),
});
}
} catch (e) {
window.location.href = modifyUrl(window.location.href, parts => {
parts.hash = '#/error/url-overflow';
});
// force the browser to reload to that Kibana's potentially unstable state is unloaded
window.location.reload();
}
};

$rootScope.$on('$routeUpdate', check);
$rootScope.$on('$routeChangeStart', check);
});
.run(internals.$initNavLinksDeepWatch);

registerSubUrlHooks(kibana, internals);
directivesProvider(chrome, internals);

uiModules.link(kibana);
Expand Down
42 changes: 1 addition & 41 deletions src/legacy/ui/public/chrome/api/breadcrumbs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
* under the License.
*/

import { IRootScopeService } from 'angular';
import { fatalError } from 'ui/notify/fatal_error';
import { ChromeBreadcrumb, ChromeSetup } from '../../../../../core/public';
export type Breadcrumb = ChromeBreadcrumb;

Expand All @@ -34,16 +32,12 @@ export function __newPlatformInit__(instance: ChromeSetup) {
}

function createBreadcrumbsApi(chrome: { [key: string]: any }) {
// A flag used to determine if we should automatically
// clear the breadcrumbs between angular route changes.
let breadcrumbSetSinceRouteChange = false;
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) {
breadcrumbSetSinceRouteChange = true;
currentBreadcrumbs = nextBreadcrumbs;
},
});
Expand Down Expand Up @@ -79,47 +73,13 @@ function createBreadcrumbsApi(chrome: { [key: string]: any }) {
newPlatformChrome.setBreadcrumbs(currentBreadcrumbs.filter(fn));
},
},

/**
* internal angular run function that will be called when angular bootstraps and
* lets us integrate with the angular router so that we can automatically clear
* the breadcrumbs if we switch to a Kibana app that does not use breadcrumbs correctly
*/
$setupBreadcrumbsAutoClear: ($rootScope: IRootScopeService, $injector: any) => {
const $route = $injector.has('$route') ? $injector.get('$route') : {};

$rootScope.$on('$routeChangeStart', () => {
breadcrumbSetSinceRouteChange = false;
});

$rootScope.$on('$routeChangeSuccess', () => {
const current = $route.current || {};

if (breadcrumbSetSinceRouteChange || (current.$$route && current.$$route.redirectTo)) {
return;
}

const k7BreadcrumbsProvider = current.k7Breadcrumbs;
if (!k7BreadcrumbsProvider) {
newPlatformChrome.setBreadcrumbs([]);
return;
}

try {
chrome.breadcrumbs.set($injector.invoke(k7BreadcrumbsProvider));
} catch (error) {
fatalError(error);
}
});
},
};
}

export function initBreadcrumbsApi(
chrome: { [key: string]: any },
internals: { [key: string]: any }
) {
const { breadcrumbs, $setupBreadcrumbsAutoClear } = createBreadcrumbsApi(chrome);
const { breadcrumbs } = createBreadcrumbsApi(chrome);
chrome.breadcrumbs = breadcrumbs;
internals.$setupBreadcrumbsAutoClear = $setupBreadcrumbsAutoClear;
}
Loading