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

Implement/better warning for url length #6773

Merged
merged 13 commits into from
Apr 27, 2016
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
7 changes: 4 additions & 3 deletions src/plugins/kibana/public/dashboard/directives/grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,15 @@ app.directive('dashboardGrid', function ($compile, Notifier) {
});

$scope.$on('$destroy', function () {
safeLayout.cancel();
$window.off('resize', safeLayout);

if (!gridster) return;
gridster.$widgets.each(function (i, el) {
const panel = getPanelFor(el);
removePanel(panel);
// stop any animations
panel.$el.stop();
removePanel(panel, true);
// not that we will, but lets be safe
makePanelSerializeable(panel);
});
Expand Down Expand Up @@ -125,9 +126,9 @@ app.directive('dashboardGrid', function ($compile, Notifier) {
}

// tell gridster to remove the panel, and cleanup our metadata
function removePanel(panel) {
function removePanel(panel, silent) {
// remove from grister 'silently' (don't reorganize after)
gridster.remove_widget(panel.$el);
gridster.remove_widget(panel.$el, silent);

// destroy the scope
panel.$scope.$destroy();
Expand Down
31 changes: 30 additions & 1 deletion src/ui/public/chrome/api/angular.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import _ from 'lodash';
import { format as formatUrl, parse as parseUrl } from 'url';

import modules from 'ui/modules';
import Notifier from 'ui/notify/notifier';
import { UrlOverflowServiceProvider } from '../../error_url_overflow';

const URL_LIMIT_WARN_WITHIN = 150;

module.exports = function (chrome, internals) {

Expand All @@ -26,14 +32,37 @@ module.exports = function (chrome, internals) {
return a.href;
}()))
.config(chrome.$setupXsrfRequestInterceptor)
.run(($location) => {
.run(($location, $rootScope, Private) => {
chrome.getFirstPathSegment = () => {
return $location.path().split('/')[1];
};

chrome.getBreadcrumbs = () => {
return $location.path().split('/').slice(1);
};

const notify = new Notifier();
const urlOverflow = Private(UrlOverflowServiceProvider);
const check = (event) => {
if ($location.path() === '/error/url-overflow') return;

try {
if (urlOverflow.check($location.absUrl()) <= URL_LIMIT_WARN_WITHIN) {
notify.warning(`
The URL has gotten big and may cause Kibana
to stop working. Please simplify the data on screen.
`);
}
} catch (e) {
const { host, path, search, protocol } = parseUrl(window.location.href);
// rewrite the entire url to force the browser to reload and
// discard any potentially unstable state from before
window.location.href = formatUrl({ host, path, search, protocol, hash: '#/error/url-overflow' });
}
};

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

require('../directives')(chrome, internals);
Expand Down
2 changes: 1 addition & 1 deletion src/ui/public/config/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,6 @@ export default function configDefaultsProvider() {
value: 5000,
description: 'The time in milliseconds which an information notification ' +
'will be displayed on-screen for. Setting to Infinity will disable.'
}
},
};
};
18 changes: 18 additions & 0 deletions src/ui/public/error_url_overflow/error_url_overflow.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<div class="app-container error-url-overflow-app">
<h3>
<i aria-hidden="true" class="fa fa-warning text-danger"></i> Woah there!
</h3>
<p>
That's a big URL you have there. I have some unfortunate news: Your browser doesn't play nice with Kibana's bacon-double-cheese-burger-with-extra-fries sized URL. To keep you from running into problems Kibana limits URLs in your browser to {{controller.limit}} characters for your safety.
</p>

<h3>Ok, how do I fix this?</h3>
<p>This usually only happens with big, complex dashboards, so you have some options:</p>
<ol>
<li>Remove some stuff from your dashboard. This will reduce the length of the URL and keep IE in a good place.</li>
<li>Don't use IE. Every other supported browser we know of doesn't have this limit.</li>
</ol>
<br>
<br>
<p><small>Foot note: Party size candy bars are tiny. Party size sub sandwiches are massive. Really makes you think.</small></p>
</div>
30 changes: 30 additions & 0 deletions src/ui/public/error_url_overflow/error_url_overflow.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import uiRoutes from 'ui/routes';
import uiModules from 'ui/modules';
import KbnUrlProvider from 'ui/url';

import './error_url_overflow.less';
import template from './error_url_overflow.html';
import { UrlOverflowServiceProvider } from './url_overflow_service';

export * from './url_overflow_service';

uiRoutes
.when('/error/url-overflow', {
template,
controllerAs: 'controller',
controller: class OverflowController {
constructor(Private, config, $scope) {
const kbnUrl = Private(KbnUrlProvider);
const urlOverflow = Private(UrlOverflowServiceProvider);

if (!urlOverflow.get()) {
kbnUrl.redirectPath('/');
return;
}

this.url = urlOverflow.get();
this.limit = urlOverflow.failLength();
$scope.$on('$destroy', () => urlOverflow.clear());
}
}
});
7 changes: 7 additions & 0 deletions src/ui/public/error_url_overflow/error_url_overflow.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.error-url-overflow-app {
padding: 25px;

pre {
white-space: pre-wrap;
}
}
65 changes: 65 additions & 0 deletions src/ui/public/error_url_overflow/url_overflow_service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
const URL_MAX_IE = 2000;
const URL_MAX_OTHERS = 25000;
const IE_REGEX = /(;MSIE |Edge\/\d)/;

export class UrlOverflowService {
constructor() {
const key = 'error/url-overflow/url';
const store = window.sessionStorage || {
getItem() {},
setItem() {},
removeItem() {},
};

// FIXME: Couldn't find a way to test for browser compatibility without
// complex redirect and cookie based "feature-detection" page, so going
// with user-agent detection for now.
this._ieLike = IE_REGEX.test(window.navigator.userAgent);

this._val = store.getItem(key);
this._sync = () => {
if (this._val == null) store.removeItem(key);
else store.setItem(key, this._val);
};
}

failLength() {
return this._ieLike ? URL_MAX_IE : URL_MAX_OTHERS;
}

set(v) {
this._val = v;
this._sync();
}

get() {
return this._val;
}

check(absUrl) {
if (!this.get()) {
const urlLength = absUrl.length;
const remaining = this.failLength() - urlLength;

if (remaining > 0) {
return remaining;
}

this.set(absUrl);
}

throw new Error(`
The URL has gotten too big and kibana can no longer
continue. Please refresh to return to your previous state.
`);
}

clear() {
this._val = undefined;
this._sync();
}
}

export function UrlOverflowServiceProvider() {
return new UrlOverflowService();
}
6 changes: 3 additions & 3 deletions src/ui/public/state_management/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import applyDiff from 'ui/utils/diff_object';
import qs from 'ui/utils/query_string';
import EventsProvider from 'ui/events';
import Notifier from 'ui/notify/notifier';
import KbnUrlProvider from 'ui/url';


const notify = new Notifier();
export default function StateProvider(Private, $rootScope, $location) {
let Events = Private(EventsProvider);
const Events = Private(EventsProvider);

_.class(State).inherits(Events);
function State(urlParam, defaults) {
Expand Down Expand Up @@ -44,7 +45,6 @@ export default function StateProvider(Private, $rootScope, $location) {
try {
return search[this._urlParam] ? rison.decode(search[this._urlParam]) : null;
} catch (e) {
let notify = new Notifier();
notify.error('Unable to parse URL');
search[this._urlParam] = rison.encode(this._defaults);
$location.search(search).replace();
Expand Down