mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge branch 'master' into cli/watch-sass-var
This commit is contained in:
@@ -27,7 +27,7 @@ class ErrorBoundary extends Component<Props, State> {
|
||||
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
|
||||
this.setState({
|
||||
error: error,
|
||||
errorInfo: errorInfo
|
||||
errorInfo: errorInfo,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
51
public/app/core/components/FilterInput/FilterInput.tsx
Normal file
51
public/app/core/components/FilterInput/FilterInput.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import React, { forwardRef } from 'react';
|
||||
|
||||
const specialChars = ['(', '[', '{', '}', ']', ')', '|', '*', '+', '-', '.', '?', '<', '>', '#', '&', '^', '$'];
|
||||
|
||||
export const escapeStringForRegex = (value: string) => {
|
||||
if (!value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
const newValue = specialChars.reduce(
|
||||
(escaped, currentChar) => escaped.replace(currentChar, '\\' + currentChar),
|
||||
value
|
||||
);
|
||||
|
||||
return newValue;
|
||||
};
|
||||
|
||||
export const unEscapeStringFromRegex = (value: string) => {
|
||||
if (!value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
const newValue = specialChars.reduce(
|
||||
(escaped, currentChar) => escaped.replace('\\' + currentChar, currentChar),
|
||||
value
|
||||
);
|
||||
|
||||
return newValue;
|
||||
};
|
||||
|
||||
export interface Props {
|
||||
value: string | undefined;
|
||||
placeholder?: string;
|
||||
labelClassName?: string;
|
||||
inputClassName?: string;
|
||||
onChange: (value: string) => void;
|
||||
}
|
||||
|
||||
export const FilterInput = forwardRef<HTMLInputElement, Props>((props, ref) => (
|
||||
<label className={props.labelClassName}>
|
||||
<input
|
||||
ref={ref}
|
||||
type="text"
|
||||
className={props.inputClassName}
|
||||
value={unEscapeStringFromRegex(props.value)}
|
||||
onChange={event => props.onChange(escapeStringForRegex(event.target.value))}
|
||||
placeholder={props.placeholder ? props.placeholder : null}
|
||||
/>
|
||||
<i className="gf-form-input-icon fa fa-search" />
|
||||
</label>
|
||||
));
|
||||
@@ -9,42 +9,49 @@ interface Props {
|
||||
newGrafanaVersion: string;
|
||||
}
|
||||
|
||||
export const Footer: FC<Props> = React.memo(({appName, buildVersion, buildCommit, newGrafanaVersionExists, newGrafanaVersion}) => {
|
||||
return (
|
||||
<footer className="footer">
|
||||
<div className="text-center">
|
||||
<ul>
|
||||
<li>
|
||||
<a href="http://docs.grafana.org" target="_blank">
|
||||
<i className="fa fa-file-code-o" /> Docs
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://grafana.com/services/support" target="_blank">
|
||||
<i className="fa fa-support" /> Support Plans
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://community.grafana.com/" target="_blank">
|
||||
<i className="fa fa-comments-o" /> Community
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://grafana.com" target="_blank">{appName}</a> <span>v{buildVersion} (commit: {buildCommit})</span>
|
||||
</li>
|
||||
{newGrafanaVersionExists && (
|
||||
export const Footer: FC<Props> = React.memo(
|
||||
({ appName, buildVersion, buildCommit, newGrafanaVersionExists, newGrafanaVersion }) => {
|
||||
return (
|
||||
<footer className="footer">
|
||||
<div className="text-center">
|
||||
<ul>
|
||||
<li>
|
||||
<Tooltip placement="auto" content={newGrafanaVersion}>
|
||||
<a href="https://grafana.com/get" target="_blank">
|
||||
New version available!
|
||||
</a>
|
||||
</Tooltip>
|
||||
<a href="http://docs.grafana.org" target="_blank">
|
||||
<i className="fa fa-file-code-o" /> Docs
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
});
|
||||
<li>
|
||||
<a href="https://grafana.com/services/support" target="_blank">
|
||||
<i className="fa fa-support" /> Support Plans
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://community.grafana.com/" target="_blank">
|
||||
<i className="fa fa-comments-o" /> Community
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://grafana.com" target="_blank">
|
||||
{appName}
|
||||
</a>{' '}
|
||||
<span>
|
||||
v{buildVersion} (commit: {buildCommit})
|
||||
</span>
|
||||
</li>
|
||||
{newGrafanaVersionExists && (
|
||||
<li>
|
||||
<Tooltip placement="auto" content={newGrafanaVersion}>
|
||||
<a href="https://grafana.com/get" target="_blank">
|
||||
New version available!
|
||||
</a>
|
||||
</Tooltip>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default Footer;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import LayoutSelector, { LayoutMode } from '../LayoutSelector/LayoutSelector';
|
||||
import { FilterInput } from '../FilterInput/FilterInput';
|
||||
|
||||
export interface Props {
|
||||
searchQuery: string;
|
||||
@@ -22,16 +23,13 @@ export default class OrgActionBar extends PureComponent<Props> {
|
||||
return (
|
||||
<div className="page-action-bar">
|
||||
<div className="gf-form gf-form--grow">
|
||||
<label className="gf-form--has-input-icon">
|
||||
<input
|
||||
type="text"
|
||||
className="gf-form-input width-20"
|
||||
value={searchQuery}
|
||||
onChange={event => setSearchQuery(event.target.value)}
|
||||
placeholder="Filter by name or type"
|
||||
/>
|
||||
<i className="gf-form-input-icon fa fa-search" />
|
||||
</label>
|
||||
<FilterInput
|
||||
labelClassName="gf-form--has-input-icon"
|
||||
inputClassName="gf-form-input width-20"
|
||||
value={searchQuery}
|
||||
onChange={setSearchQuery}
|
||||
placeholder={'Filter by name or type'}
|
||||
/>
|
||||
<LayoutSelector mode={layoutMode} onLayoutModeChanged={(mode: LayoutMode) => onSetLayoutMode(mode)} />
|
||||
</div>
|
||||
<div className="page-action-bar__spacer" />
|
||||
|
||||
@@ -7,20 +7,13 @@ exports[`Render should render component 1`] = `
|
||||
<div
|
||||
className="gf-form gf-form--grow"
|
||||
>
|
||||
<label
|
||||
className="gf-form--has-input-icon"
|
||||
>
|
||||
<input
|
||||
className="gf-form-input width-20"
|
||||
onChange={[Function]}
|
||||
placeholder="Filter by name or type"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<i
|
||||
className="gf-form-input-icon fa fa-search"
|
||||
/>
|
||||
</label>
|
||||
<ForwardRef
|
||||
inputClassName="gf-form-input width-20"
|
||||
labelClassName="gf-form--has-input-icon"
|
||||
onChange={[MockFunction]}
|
||||
placeholder="Filter by name or type"
|
||||
value=""
|
||||
/>
|
||||
<LayoutSelector
|
||||
onLayoutModeChanged={[Function]}
|
||||
/>
|
||||
|
||||
@@ -33,9 +33,9 @@ class Page extends Component<Props> {
|
||||
updateTitle = () => {
|
||||
const title = this.getPageTitle;
|
||||
document.title = title ? title + ' - Grafana' : 'Grafana';
|
||||
}
|
||||
};
|
||||
|
||||
get getPageTitle () {
|
||||
get getPageTitle() {
|
||||
const { navModel } = this.props;
|
||||
if (navModel) {
|
||||
return getTitleFromNavModel(navModel) || undefined;
|
||||
@@ -47,20 +47,21 @@ class Page extends Component<Props> {
|
||||
const { navModel } = this.props;
|
||||
const { buildInfo } = config;
|
||||
return (
|
||||
<div className="page-scrollbar-wrapper">
|
||||
<CustomScrollbar autoHeightMin={'100%'}>
|
||||
<div className="page-scrollbar-content">
|
||||
<PageHeader model={navModel} />
|
||||
{this.props.children}
|
||||
<Footer
|
||||
appName="Grafana"
|
||||
buildCommit={buildInfo.commit}
|
||||
buildVersion={buildInfo.version}
|
||||
newGrafanaVersion={buildInfo.latestVersion}
|
||||
newGrafanaVersionExists={buildInfo.hasUpdate} />
|
||||
</div>
|
||||
</CustomScrollbar>
|
||||
</div>
|
||||
<div className="page-scrollbar-wrapper">
|
||||
<CustomScrollbar autoHeightMin={'100%'}>
|
||||
<div className="page-scrollbar-content">
|
||||
<PageHeader model={navModel} />
|
||||
{this.props.children}
|
||||
<Footer
|
||||
appName="Grafana"
|
||||
buildCommit={buildInfo.commit}
|
||||
buildVersion={buildInfo.version}
|
||||
newGrafanaVersion={buildInfo.latestVersion}
|
||||
newGrafanaVersionExists={buildInfo.hasUpdate}
|
||||
/>
|
||||
</div>
|
||||
</CustomScrollbar>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ interface Props {
|
||||
}
|
||||
|
||||
class PageContents extends Component<Props> {
|
||||
|
||||
render() {
|
||||
const { isLoading } = this.props;
|
||||
|
||||
|
||||
@@ -61,15 +61,14 @@ export default class PermissionsListItem extends PureComponent<Props> {
|
||||
{item.name} <ItemDescription item={item} />
|
||||
</td>
|
||||
<td>
|
||||
{item.inherited &&
|
||||
folderInfo && (
|
||||
<em className="muted no-wrap">
|
||||
Inherited from folder{' '}
|
||||
<a className="text-link" href={`${folderInfo.url}/permissions`}>
|
||||
{folderInfo.title}
|
||||
</a>{' '}
|
||||
</em>
|
||||
)}
|
||||
{item.inherited && folderInfo && (
|
||||
<em className="muted no-wrap">
|
||||
Inherited from folder{' '}
|
||||
<a className="text-link" href={`${folderInfo.url}/permissions`}>
|
||||
{folderInfo.title}
|
||||
</a>{' '}
|
||||
</em>
|
||||
)}
|
||||
{inheritedFromRoot && <em className="muted no-wrap">Default Permission</em>}
|
||||
</td>
|
||||
<td className="query-keyword">Can</td>
|
||||
|
||||
@@ -5,6 +5,7 @@ import AsyncSelect from '@torkelo/react-select/lib/Async';
|
||||
import { TagOption } from './TagOption';
|
||||
import { TagBadge } from './TagBadge';
|
||||
import { components } from '@torkelo/react-select';
|
||||
import { escapeStringForRegex } from '../FilterInput/FilterInput';
|
||||
|
||||
export interface Props {
|
||||
tags: string[];
|
||||
@@ -51,7 +52,7 @@ export class TagFilter extends React.Component<Props, any> {
|
||||
value: tags,
|
||||
styles: resetSelectStyles(),
|
||||
filterOption: (option, searchQuery) => {
|
||||
const regex = RegExp(searchQuery, 'i');
|
||||
const regex = RegExp(escapeStringForRegex(searchQuery), 'i');
|
||||
return regex.test(option.value);
|
||||
},
|
||||
components: {
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
|
||||
/*
|
||||
* Escapes `"` characters from string
|
||||
*/
|
||||
*/
|
||||
function escapeString(str: string): string {
|
||||
return str.replace('"', '"');
|
||||
}
|
||||
|
||||
/*
|
||||
* Determines if a value is an object
|
||||
*/
|
||||
*/
|
||||
export function isObject(value: any): boolean {
|
||||
const type = typeof value;
|
||||
return !!value && type === 'object';
|
||||
@@ -20,7 +20,7 @@ export function isObject(value: any): boolean {
|
||||
* Gets constructor name of an object.
|
||||
* From http://stackoverflow.com/a/332429
|
||||
*
|
||||
*/
|
||||
*/
|
||||
export function getObjectName(object: object): string {
|
||||
if (object === undefined) {
|
||||
return '';
|
||||
@@ -43,7 +43,7 @@ export function getObjectName(object: object): string {
|
||||
|
||||
/*
|
||||
* Gets type of an object. Returns "null" for null objects
|
||||
*/
|
||||
*/
|
||||
export function getType(object: object): string {
|
||||
if (object === null) {
|
||||
return 'null';
|
||||
@@ -53,7 +53,7 @@ export function getType(object: object): string {
|
||||
|
||||
/*
|
||||
* Generates inline preview for a JavaScript object based on a value
|
||||
*/
|
||||
*/
|
||||
export function getValuePreview(object: object, value: string): string {
|
||||
const type = getType(object);
|
||||
|
||||
@@ -78,7 +78,7 @@ export function getValuePreview(object: object, value: string): string {
|
||||
|
||||
/*
|
||||
* Generates inline preview for a JavaScript object
|
||||
*/
|
||||
*/
|
||||
let value = '';
|
||||
export function getPreview(obj: object): string {
|
||||
if (isObject(obj)) {
|
||||
@@ -94,15 +94,15 @@ export function getPreview(obj: object): string {
|
||||
|
||||
/*
|
||||
* Generates a prefixed CSS class name
|
||||
*/
|
||||
*/
|
||||
export function cssClass(className: string): string {
|
||||
return `json-formatter-${className}`;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a new DOM element with given type and class
|
||||
* TODO: move me to helpers
|
||||
*/
|
||||
* Creates a new DOM element with given type and class
|
||||
* TODO: move me to helpers
|
||||
*/
|
||||
export function createElement(type: string, className?: string, content?: Element | string): Element {
|
||||
const el = document.createElement(type);
|
||||
if (className) {
|
||||
|
||||
@@ -83,7 +83,7 @@ export class JsonExplorer {
|
||||
|
||||
/*
|
||||
* is formatter open?
|
||||
*/
|
||||
*/
|
||||
private get isOpen(): boolean {
|
||||
if (this._isOpen !== null) {
|
||||
return this._isOpen;
|
||||
@@ -94,14 +94,14 @@ export class JsonExplorer {
|
||||
|
||||
/*
|
||||
* set open state (from toggler)
|
||||
*/
|
||||
*/
|
||||
private set isOpen(value: boolean) {
|
||||
this._isOpen = value;
|
||||
}
|
||||
|
||||
/*
|
||||
* is this a date string?
|
||||
*/
|
||||
*/
|
||||
private get isDate(): boolean {
|
||||
return (
|
||||
this.type === 'string' &&
|
||||
@@ -111,14 +111,14 @@ export class JsonExplorer {
|
||||
|
||||
/*
|
||||
* is this a URL string?
|
||||
*/
|
||||
*/
|
||||
private get isUrl(): boolean {
|
||||
return this.type === 'string' && this.json.indexOf('http') === 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* is this an array?
|
||||
*/
|
||||
*/
|
||||
private get isArray(): boolean {
|
||||
return Array.isArray(this.json);
|
||||
}
|
||||
@@ -126,21 +126,21 @@ export class JsonExplorer {
|
||||
/*
|
||||
* is this an object?
|
||||
* Note: In this context arrays are object as well
|
||||
*/
|
||||
*/
|
||||
private get isObject(): boolean {
|
||||
return isObject(this.json);
|
||||
}
|
||||
|
||||
/*
|
||||
* is this an empty object with no properties?
|
||||
*/
|
||||
*/
|
||||
private get isEmptyObject(): boolean {
|
||||
return !this.keys.length && !this.isArray;
|
||||
}
|
||||
|
||||
/*
|
||||
* is this an empty object or array?
|
||||
*/
|
||||
*/
|
||||
private get isEmpty(): boolean {
|
||||
return this.isEmptyObject || (this.keys && !this.keys.length && this.isArray);
|
||||
}
|
||||
@@ -148,14 +148,14 @@ export class JsonExplorer {
|
||||
/*
|
||||
* did we receive a key argument?
|
||||
* This means that the formatter was called as a sub formatter of a parent formatter
|
||||
*/
|
||||
*/
|
||||
private get hasKey(): boolean {
|
||||
return typeof this.key !== 'undefined';
|
||||
}
|
||||
|
||||
/*
|
||||
* if this is an object, get constructor function name
|
||||
*/
|
||||
*/
|
||||
private get constructorName(): string {
|
||||
return getObjectName(this.json);
|
||||
}
|
||||
@@ -163,7 +163,7 @@ export class JsonExplorer {
|
||||
/*
|
||||
* get type of this value
|
||||
* Possible values: all JavaScript primitive types plus "array" and "null"
|
||||
*/
|
||||
*/
|
||||
private get type(): string {
|
||||
return getType(this.json);
|
||||
}
|
||||
@@ -171,7 +171,7 @@ export class JsonExplorer {
|
||||
/*
|
||||
* get object keys
|
||||
* If there is an empty key we pad it wit quotes to make it visible
|
||||
*/
|
||||
*/
|
||||
private get keys(): string[] {
|
||||
if (this.isObject) {
|
||||
return Object.keys(this.json).map(key => (key ? key : '""'));
|
||||
|
||||
@@ -47,7 +47,8 @@ class BottomNavLinks extends PureComponent<Props> {
|
||||
<div className="sidemenu-org-switcher__org-current">Current Org:</div>
|
||||
</div>
|
||||
<div className="sidemenu-org-switcher__switch">
|
||||
<i className="fa fa-fw fa-random" />Switch
|
||||
<i className="fa fa-fw fa-random" />
|
||||
Switch
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -29,7 +29,8 @@ export class SideMenu extends PureComponent {
|
||||
<div className="sidemenu__logo_small_breakpoint" onClick={this.toggleSideMenuSmallBreakpoint} key="hamburger">
|
||||
<i className="fa fa-bars" />
|
||||
<span className="sidemenu__close">
|
||||
<i className="fa fa-times" /> Close
|
||||
<i className="fa fa-times" />
|
||||
Close
|
||||
</span>
|
||||
</div>,
|
||||
<TopSection key="topsection" />,
|
||||
|
||||
@@ -57,7 +57,7 @@ export class Settings {
|
||||
isEnterprise: false,
|
||||
},
|
||||
viewersCanEdit: false,
|
||||
disableSanitizeHtml: false
|
||||
disableSanitizeHtml: false,
|
||||
};
|
||||
|
||||
_.extend(this, defaults, options);
|
||||
|
||||
@@ -14,4 +14,3 @@ export const DASHBOARD_TOP_PADDING = 20;
|
||||
|
||||
export const PANEL_HEADER_HEIGHT = 27;
|
||||
export const PANEL_BORDER = 2;
|
||||
export const PANEL_OPTIONS_KEY_PREFIX = 'options-';
|
||||
|
||||
@@ -28,7 +28,7 @@ export function autofillEventFix($compile) {
|
||||
input.removeEventListener('animationstart', onAnimationStart);
|
||||
// input.removeEventListener('change', onChange);
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ export function dropdownTypeahead2($compile) {
|
||||
const $input = $(inputTemplate);
|
||||
const $button = $(buttonTemplate);
|
||||
const timeoutId = {
|
||||
blur: null
|
||||
blur: null,
|
||||
};
|
||||
$input.appendTo(elem);
|
||||
$button.appendTo(elem);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
export class Profiler {
|
||||
panelsRendered: number;
|
||||
enabled: boolean;
|
||||
|
||||
@@ -43,5 +43,5 @@ export function getNavModel(navIndex: NavIndex, id: string, fallback?: NavModel)
|
||||
}
|
||||
|
||||
export const getTitleFromNavModel = (navModel: NavModel) => {
|
||||
return `${navModel.main.text}${navModel.node.text ? ': ' + navModel.node.text : '' }`;
|
||||
return `${navModel.main.text}${navModel.node.text ? ': ' + navModel.node.text : ''}`;
|
||||
};
|
||||
|
||||
@@ -27,7 +27,9 @@ export class AngularLoader {
|
||||
compiledElem.remove();
|
||||
},
|
||||
digest: () => {
|
||||
scope.$digest();
|
||||
if (!scope.$$phase) {
|
||||
scope.$digest();
|
||||
}
|
||||
},
|
||||
getScope: () => {
|
||||
return scope;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
const backendSrv = {
|
||||
get: jest.fn(),
|
||||
getDashboard: jest.fn(),
|
||||
@@ -10,5 +9,3 @@ const backendSrv = {
|
||||
export function getBackendSrv() {
|
||||
return backendSrv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,24 +1,21 @@
|
||||
import React from 'react';
|
||||
import {shallow} from 'enzyme';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import {PasswordStrength} from '../components/PasswordStrength';
|
||||
import { PasswordStrength } from '../components/PasswordStrength';
|
||||
|
||||
describe('PasswordStrength', () => {
|
||||
|
||||
it('should have class bad if length below 4', () => {
|
||||
const wrapper = shallow(<PasswordStrength password="asd" />);
|
||||
expect(wrapper.find(".password-strength-bad")).toHaveLength(1);
|
||||
expect(wrapper.find('.password-strength-bad')).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('should have class ok if length below 8', () => {
|
||||
const wrapper = shallow(<PasswordStrength password="asdasd" />);
|
||||
expect(wrapper.find(".password-strength-ok")).toHaveLength(1);
|
||||
expect(wrapper.find('.password-strength-ok')).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('should have class good if length above 8', () => {
|
||||
const wrapper = shallow(<PasswordStrength password="asdaasdda" />);
|
||||
expect(wrapper.find(".password-strength-good")).toHaveLength(1);
|
||||
expect(wrapper.find('.password-strength-good')).toHaveLength(1);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ export function buildQueryTransaction(
|
||||
};
|
||||
}
|
||||
|
||||
export const clearQueryKeys: ((query: DataQuery) => object) = ({ key, refId, ...rest }) => rest;
|
||||
export const clearQueryKeys: (query: DataQuery) => object = ({ key, refId, ...rest }) => rest;
|
||||
|
||||
const isMetricSegment = (segment: { [key: string]: string }) => segment.hasOwnProperty('expr');
|
||||
const isUISegment = (segment: { [key: string]: string }) => segment.hasOwnProperty('ui');
|
||||
|
||||
@@ -143,7 +143,7 @@ kbn.secondsToHhmmss = seconds => {
|
||||
};
|
||||
|
||||
kbn.to_percent = (nr, outof) => {
|
||||
return Math.floor(nr / outof * 10000) / 100 + '%';
|
||||
return Math.floor((nr / outof) * 10000) / 100 + '%';
|
||||
};
|
||||
|
||||
kbn.addslashes = str => {
|
||||
@@ -289,21 +289,21 @@ kbn.getUnitFormats = () => {
|
||||
//
|
||||
// Backward compatible layer for value formats to support old plugins
|
||||
//
|
||||
if (typeof Proxy !== "undefined") {
|
||||
if (typeof Proxy !== 'undefined') {
|
||||
kbn.valueFormats = new Proxy(kbn.valueFormats, {
|
||||
get(target, name, receiver) {
|
||||
if (typeof name !== 'string') {
|
||||
throw {message: `Value format ${String(name)} is not a string` };
|
||||
throw { message: `Value format ${String(name)} is not a string` };
|
||||
}
|
||||
|
||||
const formatter = getValueFormat(name);
|
||||
if (formatter) {
|
||||
if (formatter) {
|
||||
return formatter;
|
||||
}
|
||||
|
||||
// default to look here
|
||||
return Reflect.get(target, name, receiver);
|
||||
}
|
||||
},
|
||||
});
|
||||
} else {
|
||||
kbn.valueFormats = getValueFormatterIndex();
|
||||
|
||||
@@ -15,7 +15,7 @@ export default function getScrollbarWidth() {
|
||||
position: 'absolute',
|
||||
top: '-9999px',
|
||||
overflow: 'scroll',
|
||||
MsOverflowStyle: 'scrollbar'
|
||||
MsOverflowStyle: 'scrollbar',
|
||||
};
|
||||
|
||||
Object.keys(newStyles).map(style => {
|
||||
@@ -23,7 +23,7 @@ export default function getScrollbarWidth() {
|
||||
});
|
||||
|
||||
document.body.appendChild(div);
|
||||
scrollbarWidth = (div.offsetWidth - div.clientWidth);
|
||||
scrollbarWidth = div.offsetWidth - div.clientWidth;
|
||||
document.body.removeChild(div);
|
||||
} else {
|
||||
scrollbarWidth = 0;
|
||||
|
||||
@@ -50,7 +50,7 @@ const XSSWL = Object.keys(xss.whiteList).reduce((acc, element) => {
|
||||
}, {});
|
||||
|
||||
const sanitizeXSS = new xss.FilterXSS({
|
||||
whiteList: XSSWL
|
||||
whiteList: XSSWL,
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -60,7 +60,7 @@ const sanitizeXSS = new xss.FilterXSS({
|
||||
* Info: https://github.com/leizongmin/js-xss#customize-css-filter
|
||||
* Whitelist: https://github.com/leizongmin/js-css-filter/blob/master/lib/default.js
|
||||
*/
|
||||
export function sanitize (unsanitizedString: string): string {
|
||||
export function sanitize(unsanitizedString: string): string {
|
||||
try {
|
||||
return sanitizeXSS.process(unsanitizedString);
|
||||
} catch (error) {
|
||||
@@ -68,3 +68,7 @@ export function sanitize (unsanitizedString: string): string {
|
||||
return unsanitizedString;
|
||||
}
|
||||
}
|
||||
|
||||
export function hasAnsiCodes(input: string): boolean {
|
||||
return /\u001b\[\d{1,2}m/.test(input);
|
||||
}
|
||||
|
||||
@@ -12,13 +12,13 @@ export function renderUrl(path: string, query: UrlQueryMap | undefined): string
|
||||
}
|
||||
|
||||
export function encodeURIComponentAsAngularJS(val, pctEncodeSpaces) {
|
||||
return encodeURIComponent(val).
|
||||
replace(/%40/gi, '@').
|
||||
replace(/%3A/gi, ':').
|
||||
replace(/%24/g, '$').
|
||||
replace(/%2C/gi, ',').
|
||||
replace(/%3B/gi, ';').
|
||||
replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
|
||||
return encodeURIComponent(val)
|
||||
.replace(/%40/gi, '@')
|
||||
.replace(/%3A/gi, ':')
|
||||
.replace(/%24/g, '$')
|
||||
.replace(/%2C/gi, ',')
|
||||
.replace(/%3B/gi, ';')
|
||||
.replace(/%20/g, pctEncodeSpaces ? '%20' : '+');
|
||||
}
|
||||
|
||||
export function toUrlParams(a) {
|
||||
|
||||
Reference in New Issue
Block a user