mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge remote-tracking branch 'origin/master' into reactify-stackdriver
# Conflicts: # yarn.lock
This commit is contained in:
@@ -323,7 +323,7 @@ jobs:
|
||||
|
||||
deploy-enterprise-master:
|
||||
docker:
|
||||
- image: grafana/grafana-ci-deploy:1.0.0
|
||||
- image: grafana/grafana-ci-deploy:1.1.0
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: .
|
||||
@@ -346,7 +346,7 @@ jobs:
|
||||
|
||||
deploy-enterprise-release:
|
||||
docker:
|
||||
- image: grafana/grafana-ci-deploy:1.0.0
|
||||
- image: grafana/grafana-ci-deploy:1.1.0
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: .
|
||||
@@ -365,10 +365,20 @@ jobs:
|
||||
- run:
|
||||
name: Deploy to Grafana.com
|
||||
command: './scripts/build/publish.sh --enterprise'
|
||||
- run:
|
||||
name: Load GPG private key
|
||||
comand: './scripts/build/load-signing-key.sh'
|
||||
- run:
|
||||
name: Update Debian repository
|
||||
command: './scripts/build/update_repo/update-deb.sh "enterprise" "$GPG_KEY_PASSWORD" "$CIRCLE_TAG"'
|
||||
- run:
|
||||
name: Update RPM repository
|
||||
command: './scripts/build/update_repo/update-rpm.sh "enterprise" "$GPG_KEY_PASSWORD" "$CIRCLE_TAG"'
|
||||
|
||||
|
||||
deploy-master:
|
||||
docker:
|
||||
- image: grafana/grafana-ci-deploy:1.0.0
|
||||
- image: grafana/grafana-ci-deploy:1.1.0
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: .
|
||||
@@ -398,8 +408,9 @@ jobs:
|
||||
|
||||
deploy-release:
|
||||
docker:
|
||||
- image: grafana/grafana-ci-deploy:1.0.0
|
||||
- image: grafana/grafana-ci-deploy:1.1.0
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run:
|
||||
@@ -417,6 +428,15 @@ jobs:
|
||||
- run:
|
||||
name: Deploy to Grafana.com
|
||||
command: './scripts/build/publish.sh'
|
||||
- run:
|
||||
name: Load GPG private key
|
||||
comand: './scripts/build/load-signing-key.sh'
|
||||
- run:
|
||||
name: Update Debian repository
|
||||
command: './scripts/build/update_repo/update-deb.sh "oss" "$GPG_KEY_PASSWORD" "$CIRCLE_TAG"'
|
||||
- run:
|
||||
name: Update RPM repository
|
||||
command: './scripts/build/update_repo/update-rpm.sh "oss" "$GPG_KEY_PASSWORD" "$CIRCLE_TAG"'
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
* **Proxy whitelist**: Add CIDR capability to auth_proxy whitelist [#14546](https://github.com/grafana/grafana/issues/14546), thx [@jacobrichard](https://github.com/jacobrichard)
|
||||
* **OAuth**: Support OAuth providers that are not RFC6749 compliant [#14562](https://github.com/grafana/grafana/issues/14562), thx [@tdabasinskas](https://github.com/tdabasinskas)
|
||||
* **Units**: Add blood glucose level units mg/dL and mmol/L [#14519](https://github.com/grafana/grafana/issues/14519), thx [@kjedamzik](https://github.com/kjedamzik)
|
||||
* **Stackdriver**: Aggregating series returns more than one series [#14581](https://github.com/grafana/grafana/issues/14581) and [#13914](https://github.com/grafana/grafana/issues/13914), thx [@kinok](https://github.com/kinok)
|
||||
|
||||
### Bug fixes
|
||||
* **Search**: Fix for issue with scrolling the "tags filter" dropdown, fixes [#14486](https://github.com/grafana/grafana/issues/14486)
|
||||
|
||||
@@ -47,6 +47,12 @@ Create a file `/etc/apt/sources.list.d/grafana.list` and add the following to it
|
||||
deb https://packages.grafana.com/oss/deb stable main
|
||||
```
|
||||
|
||||
There is a separate repository if you want beta releases.
|
||||
|
||||
```bash
|
||||
deb https://packages.grafana.com/oss/deb beta main
|
||||
```
|
||||
|
||||
Use the above line even if you are on Ubuntu or another Debian version. Then add our gpg key. This allows you to install signed packages.
|
||||
|
||||
```bash
|
||||
|
||||
@@ -76,6 +76,20 @@ sslverify=1
|
||||
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
|
||||
```
|
||||
|
||||
There is a separate repository if you want beta releases.
|
||||
|
||||
```bash
|
||||
[grafana]
|
||||
name=grafana
|
||||
baseurl=https://packages.grafana.com/oss/rpm-beta
|
||||
repo_gpgcheck=1
|
||||
enabled=1
|
||||
gpgcheck=1
|
||||
gpgkey=https://packages.grafana.com/gpg.key
|
||||
sslverify=1
|
||||
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
|
||||
```
|
||||
|
||||
Then install Grafana via the `yum` command.
|
||||
|
||||
```bash
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
"@types/jquery": "^1.10.35",
|
||||
"@types/node": "^8.0.31",
|
||||
"@types/react": "^16.7.6",
|
||||
"@types/react-custom-scrollbars": "^4.0.5",
|
||||
"@types/react-dom": "^16.0.9",
|
||||
"@types/react-select": "^2.0.4",
|
||||
"angular-mocks": "1.6.6",
|
||||
@@ -72,8 +71,8 @@
|
||||
"ng-annotate-loader": "^0.6.1",
|
||||
"ng-annotate-webpack-plugin": "^0.3.0",
|
||||
"ngtemplate-loader": "^2.0.1",
|
||||
"npm": "^5.4.2",
|
||||
"node-sass": "^4.11.0",
|
||||
"npm": "^5.4.2",
|
||||
"optimize-css-assets-webpack-plugin": "^4.0.2",
|
||||
"phantomjs-prebuilt": "^2.1.15",
|
||||
"postcss-browser-reporter": "^0.5.0",
|
||||
@@ -167,7 +166,6 @@
|
||||
"prop-types": "^15.6.2",
|
||||
"rc-cascader": "^0.14.0",
|
||||
"react": "^16.6.3",
|
||||
"react-custom-scrollbars": "^4.2.1",
|
||||
"react-dom": "^16.6.3",
|
||||
"react-grid-layout": "0.16.6",
|
||||
"react-highlight-words": "0.11.0",
|
||||
|
||||
@@ -11,11 +11,14 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@torkelo/react-select": "2.1.1",
|
||||
"@types/react-test-renderer": "^16.0.3",
|
||||
"@types/react-transition-group": "^2.0.15",
|
||||
"classnames": "^2.2.5",
|
||||
"jquery": "^3.2.1",
|
||||
"lodash": "^4.17.10",
|
||||
"moment": "^2.22.2",
|
||||
"react": "^16.6.3",
|
||||
"react-custom-scrollbars": "^4.2.1",
|
||||
"react-dom": "^16.6.3",
|
||||
"react-highlight-words": "0.11.0",
|
||||
"react-popper": "^1.3.0",
|
||||
@@ -23,11 +26,14 @@
|
||||
"react-virtualized": "^9.21.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/classnames": "^2.2.6",
|
||||
"@types/jest": "^23.3.2",
|
||||
"@types/jquery": "^1.10.35",
|
||||
"@types/lodash": "^4.14.119",
|
||||
"@types/react": "^16.7.6",
|
||||
"@types/classnames": "^2.2.6",
|
||||
"@types/jquery": "^1.10.35",
|
||||
"@types/react-custom-scrollbars": "^4.0.5",
|
||||
"@types/react-test-renderer": "^16.0.3",
|
||||
"react-test-renderer": "^16.7.0",
|
||||
"typescript": "^3.2.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ interface Props {
|
||||
/**
|
||||
* Wraps component into <Scrollbars> component from `react-custom-scrollbars`
|
||||
*/
|
||||
class CustomScrollbar extends PureComponent<Props> {
|
||||
export class CustomScrollbar extends PureComponent<Props> {
|
||||
static defaultProps: Partial<Props> = {
|
||||
customClassName: 'custom-scrollbars',
|
||||
autoHide: true,
|
||||
@@ -0,0 +1,40 @@
|
||||
.custom-scrollbars {
|
||||
// Fix for Firefox. For some reason sometimes .view container gets a height of its content, but in order to
|
||||
// make scroll working it should fit outer container size (scroll appears only when inner container size is
|
||||
// greater than outer one).
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
|
||||
.view {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.track-vertical {
|
||||
border-radius: 3px;
|
||||
width: 6px !important;
|
||||
right: 2px;
|
||||
bottom: 2px;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
.track-horizontal {
|
||||
border-radius: 3px;
|
||||
height: 6px !important;
|
||||
|
||||
right: 2px;
|
||||
bottom: 2px;
|
||||
left: 2px;
|
||||
}
|
||||
|
||||
.thumb-vertical {
|
||||
@include gradient-vertical($scrollbarBackground, $scrollbarBackground2);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.thumb-horizontal {
|
||||
@include gradient-horizontal($scrollbarBackground, $scrollbarBackground2);
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
@@ -6,11 +6,11 @@ interface Props {
|
||||
root?: HTMLElement;
|
||||
}
|
||||
|
||||
export default class BodyPortal extends PureComponent<Props> {
|
||||
export class Portal extends PureComponent<Props> {
|
||||
node: HTMLElement = document.createElement('div');
|
||||
portalRoot: HTMLElement;
|
||||
|
||||
constructor(props) {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
const { className, root = document.body } = this.props;
|
||||
|
||||
@@ -1,49 +1,53 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import Portal from 'app/core/components/Portal/Portal';
|
||||
import { Manager, Popper as ReactPopper, Reference } from 'react-popper';
|
||||
import * as PopperJS from 'popper.js';
|
||||
import { Manager, Popper as ReactPopper } from 'react-popper';
|
||||
import { Portal } from '@grafana/ui';
|
||||
import Transition from 'react-transition-group/Transition';
|
||||
|
||||
export enum Themes {
|
||||
Default = 'popper__background--default',
|
||||
Error = 'popper__background--error',
|
||||
}
|
||||
|
||||
const defaultTransitionStyles = {
|
||||
transition: 'opacity 200ms linear',
|
||||
opacity: 0,
|
||||
};
|
||||
|
||||
const transitionStyles = {
|
||||
const transitionStyles: {[key: string]: object} = {
|
||||
exited: { opacity: 0 },
|
||||
entering: { opacity: 0 },
|
||||
entered: { opacity: 1 },
|
||||
exiting: { opacity: 0 },
|
||||
};
|
||||
|
||||
interface Props {
|
||||
interface Props extends React.DOMAttributes<HTMLDivElement> {
|
||||
renderContent: (content: any) => any;
|
||||
show: boolean;
|
||||
placement?: any;
|
||||
placement?: PopperJS.Placement;
|
||||
content: string | ((props: any) => JSX.Element);
|
||||
refClassName?: string;
|
||||
referenceElement: PopperJS.ReferenceObject;
|
||||
theme?: Themes;
|
||||
}
|
||||
|
||||
class Popper extends PureComponent<Props> {
|
||||
render() {
|
||||
const { children, renderContent, show, placement, refClassName } = this.props;
|
||||
const { renderContent, show, placement, onMouseEnter, onMouseLeave, theme } = this.props;
|
||||
const { content } = this.props;
|
||||
|
||||
const popperBackgroundClassName = 'popper__background' + (theme ? ' ' + theme : '');
|
||||
|
||||
return (
|
||||
<Manager>
|
||||
<Reference>
|
||||
{({ ref }) => (
|
||||
<div className={`popper_ref ${refClassName || ''}`} ref={ref}>
|
||||
{children}
|
||||
</div>
|
||||
)}
|
||||
</Reference>
|
||||
<Transition in={show} timeout={100} mountOnEnter={true} unmountOnExit={true}>
|
||||
{transitionState => (
|
||||
<Portal>
|
||||
<ReactPopper placement={placement}>
|
||||
<ReactPopper placement={placement} referenceElement={this.props.referenceElement}>
|
||||
{({ ref, style, placement, arrowProps }) => {
|
||||
return (
|
||||
<div
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
ref={ref}
|
||||
style={{
|
||||
...style,
|
||||
@@ -53,7 +57,7 @@ class Popper extends PureComponent<Props> {
|
||||
data-placement={placement}
|
||||
className="popper"
|
||||
>
|
||||
<div className="popper__background">
|
||||
<div className={popperBackgroundClassName}>
|
||||
{renderContent(content)}
|
||||
<div ref={arrowProps.ref} data-placement={placement} className="popper__arrow" />
|
||||
</div>
|
||||
@@ -0,0 +1,99 @@
|
||||
import React from 'react';
|
||||
import * as PopperJS from 'popper.js';
|
||||
import { Themes } from './Popper';
|
||||
|
||||
type PopperContent = string | (() => JSX.Element);
|
||||
|
||||
export interface UsingPopperProps {
|
||||
show?: boolean;
|
||||
placement?: PopperJS.Placement;
|
||||
content: PopperContent;
|
||||
children: JSX.Element;
|
||||
renderContent?: (content: PopperContent) => JSX.Element;
|
||||
theme?: Themes;
|
||||
}
|
||||
|
||||
type PopperControllerRenderProp = (
|
||||
showPopper: () => void,
|
||||
hidePopper: () => void,
|
||||
popperProps: {
|
||||
show: boolean;
|
||||
placement: PopperJS.Placement;
|
||||
content: string | ((props: any) => JSX.Element);
|
||||
renderContent: (content: any) => any;
|
||||
theme?: Themes;
|
||||
}
|
||||
) => JSX.Element;
|
||||
|
||||
interface Props {
|
||||
placement?: PopperJS.Placement;
|
||||
content: PopperContent;
|
||||
className?: string;
|
||||
children: PopperControllerRenderProp;
|
||||
theme?: Themes;
|
||||
}
|
||||
|
||||
interface State {
|
||||
placement: PopperJS.Placement;
|
||||
show: boolean;
|
||||
}
|
||||
|
||||
class PopperController extends React.Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
placement: this.props.placement || 'auto',
|
||||
show: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps: Props) {
|
||||
if (nextProps.placement && nextProps.placement !== this.state.placement) {
|
||||
this.setState((prevState: State) => {
|
||||
return {
|
||||
...prevState,
|
||||
placement: nextProps.placement || 'auto',
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
showPopper = () => {
|
||||
this.setState(prevState => ({
|
||||
...prevState,
|
||||
show: true,
|
||||
}));
|
||||
};
|
||||
|
||||
hidePopper = () => {
|
||||
this.setState(prevState => ({
|
||||
...prevState,
|
||||
show: false,
|
||||
}));
|
||||
};
|
||||
|
||||
renderContent(content: PopperContent) {
|
||||
if (typeof content === 'function') {
|
||||
// If it's a function we assume it's a React component
|
||||
const ReactComponent = content;
|
||||
return <ReactComponent />;
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { children, content, theme } = this.props;
|
||||
const { show, placement } = this.state;
|
||||
|
||||
return children(this.showPopper, this.hidePopper, {
|
||||
show,
|
||||
placement,
|
||||
content,
|
||||
renderContent: this.renderContent,
|
||||
theme,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default PopperController;
|
||||
@@ -1,13 +1,15 @@
|
||||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
import Tooltip from './Tooltip';
|
||||
import { Tooltip } from './Tooltip';
|
||||
|
||||
describe('Tooltip', () => {
|
||||
it('renders correctly', () => {
|
||||
const tree = renderer
|
||||
.create(
|
||||
<Tooltip className="test-class" placement="auto" content="Tooltip text">
|
||||
<a href="http://www.grafana.com">Link with tooltip</a>
|
||||
<Tooltip placement="auto" content="Tooltip text">
|
||||
<a className="test-class" href="http://www.grafana.com">
|
||||
Link with tooltip
|
||||
</a>
|
||||
</Tooltip>
|
||||
)
|
||||
.toJSON();
|
||||
32
packages/grafana-ui/src/components/Tooltip/Tooltip.tsx
Normal file
32
packages/grafana-ui/src/components/Tooltip/Tooltip.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
import React, { createRef } from 'react';
|
||||
import * as PopperJS from 'popper.js';
|
||||
import Popper from './Popper';
|
||||
import PopperController, { UsingPopperProps } from './PopperController';
|
||||
|
||||
export const Tooltip = ({ children, renderContent, ...controllerProps }: UsingPopperProps) => {
|
||||
const tooltipTriggerRef = createRef<PopperJS.ReferenceObject>();
|
||||
|
||||
return (
|
||||
<PopperController {...controllerProps}>
|
||||
{(showPopper, hidePopper, popperProps) => {
|
||||
return (
|
||||
<>
|
||||
{tooltipTriggerRef.current && (
|
||||
<Popper
|
||||
{...popperProps}
|
||||
onMouseEnter={showPopper}
|
||||
onMouseLeave={hidePopper}
|
||||
referenceElement={tooltipTriggerRef.current}
|
||||
/>
|
||||
)}
|
||||
{React.cloneElement(children, {
|
||||
ref: tooltipTriggerRef,
|
||||
onMouseEnter: showPopper,
|
||||
onMouseLeave: hidePopper,
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}}
|
||||
</PopperController>
|
||||
);
|
||||
};
|
||||
@@ -8,7 +8,22 @@ $popper-margin-from-ref: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.popper .popper__arrow {
|
||||
.popper__background {
|
||||
background: $tooltipBackground;
|
||||
border-radius: $border-radius;
|
||||
box-shadow: 0 0 2px rgba(0, 0, 0, 0.5);
|
||||
padding: 10px;
|
||||
|
||||
// Themes
|
||||
&.popper__background--error {
|
||||
background: $tooltipBackgroundError;
|
||||
.popper__arrow {
|
||||
border-color: $tooltipBackgroundError;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.popper__arrow {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
@@ -16,17 +31,10 @@ $popper-margin-from-ref: 5px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.popper .popper__arrow {
|
||||
.popper__arrow {
|
||||
border-color: $tooltipBackground;
|
||||
}
|
||||
|
||||
.popper__background {
|
||||
background: $tooltipBackground;
|
||||
border-radius: $border-radius;
|
||||
box-shadow: 0 0 2px rgba(0, 0, 0, 0.5);
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
// Top
|
||||
.popper[data-placement^='top'] {
|
||||
padding-bottom: $popper-margin-from-ref;
|
||||
@@ -0,0 +1,12 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Tooltip renders correctly 1`] = `
|
||||
<a
|
||||
className="test-class"
|
||||
href="http://www.grafana.com"
|
||||
onMouseEnter={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
>
|
||||
Link with tooltip
|
||||
</a>
|
||||
`;
|
||||
@@ -1 +1,3 @@
|
||||
@import 'CustomScrollbar/CustomScrollbar';
|
||||
@import 'DeleteButton/DeleteButton';
|
||||
@import 'Tooltip/Tooltip';
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
export { DeleteButton } from './DeleteButton/DeleteButton';
|
||||
export { Tooltip } from './Tooltip/Tooltip';
|
||||
export { Portal } from './Portal/Portal';
|
||||
export { CustomScrollbar } from './CustomScrollbar/CustomScrollbar';
|
||||
|
||||
@@ -98,6 +98,7 @@ export class Graph extends PureComponent<GraphProps> {
|
||||
$.plot(this.element, timeSeries, flotOptions);
|
||||
} catch (err) {
|
||||
console.log('Graph rendering error', err, flotOptions, timeSeries);
|
||||
throw new Error('Error rendering panel');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package cloudwatch
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -43,7 +42,7 @@ func GetCredentials(dsInfo *DatasourceInfo) (*credentials.Credentials, error) {
|
||||
secretAccessKey := ""
|
||||
sessionToken := ""
|
||||
var expiration *time.Time = nil
|
||||
if dsInfo.AuthType == "arn" && strings.Index(dsInfo.AssumeRoleArn, "arn:aws:iam:") == 0 {
|
||||
if dsInfo.AuthType == "arn" {
|
||||
params := &sts.AssumeRoleInput{
|
||||
RoleArn: aws.String(dsInfo.AssumeRoleArn),
|
||||
RoleSessionName: aws.String("GrafanaSession"),
|
||||
|
||||
44
public/app/core/components/ErrorBoundary/ErrorBoundary.tsx
Normal file
44
public/app/core/components/ErrorBoundary/ErrorBoundary.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import { Component } from 'react';
|
||||
|
||||
interface ErrorInfo {
|
||||
componentStack: string;
|
||||
}
|
||||
|
||||
interface RenderProps {
|
||||
error: Error;
|
||||
errorInfo: ErrorInfo;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
children: (r: RenderProps) => JSX.Element;
|
||||
}
|
||||
|
||||
interface State {
|
||||
error: Error;
|
||||
errorInfo: ErrorInfo;
|
||||
}
|
||||
|
||||
class ErrorBoundary extends Component<Props, State> {
|
||||
readonly state: State = {
|
||||
error: null,
|
||||
errorInfo: null,
|
||||
};
|
||||
|
||||
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
|
||||
this.setState({
|
||||
error: error,
|
||||
errorInfo: errorInfo
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { children } = this.props;
|
||||
const { error, errorInfo } = this.state;
|
||||
return children({
|
||||
error,
|
||||
errorInfo,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default ErrorBoundary;
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { SFC, ReactNode } from 'react';
|
||||
import Tooltip from '../Tooltip/Tooltip';
|
||||
import { Tooltip } from '@grafana/ui';
|
||||
|
||||
interface Props {
|
||||
tooltip?: string;
|
||||
@@ -14,8 +14,10 @@ export const Label: SFC<Props> = props => {
|
||||
<span className={`gf-form-label width-${props.width ? props.width : '10'}`}>
|
||||
<span>{props.children}</span>
|
||||
{props.tooltip && (
|
||||
<Tooltip className="gf-form-help-icon--right-normal" placement="auto" content={props.tooltip}>
|
||||
<i className="gicon gicon-question gicon--has-hover" />
|
||||
<Tooltip placement="auto" content={props.tooltip}>
|
||||
<div className="gf-form-help-icon--right-normal">
|
||||
<i className="gicon gicon-question gicon--has-hover" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
</span>
|
||||
|
||||
@@ -11,7 +11,7 @@ import OptionGroup from './OptionGroup';
|
||||
import IndicatorsContainer from './IndicatorsContainer';
|
||||
import NoOptionsMessage from './NoOptionsMessage';
|
||||
import ResetStyles from './ResetStyles';
|
||||
import CustomScrollbar from '../CustomScrollbar/CustomScrollbar';
|
||||
import { CustomScrollbar } from '@grafana/ui';
|
||||
|
||||
export interface SelectOptionItem {
|
||||
label?: string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { SFC, ReactNode, PureComponent } from 'react';
|
||||
import Tooltip from 'app/core/components/Tooltip/Tooltip';
|
||||
import { Tooltip } from '@grafana/ui';
|
||||
|
||||
interface ToggleButtonGroupProps {
|
||||
label?: string;
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
import Popover from './Popover';
|
||||
|
||||
describe('Popover', () => {
|
||||
it('renders correctly', () => {
|
||||
const tree = renderer
|
||||
.create(
|
||||
<Popover className="test-class" placement="auto" content="Popover text">
|
||||
<button>Button with Popover</button>
|
||||
</Popover>
|
||||
)
|
||||
.toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -1,19 +0,0 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import Popper from './Popper';
|
||||
import withPopper, { UsingPopperProps } from './withPopper';
|
||||
|
||||
class Popover extends PureComponent<UsingPopperProps> {
|
||||
render() {
|
||||
const { children, hidePopper, showPopper, className, ...restProps } = this.props;
|
||||
|
||||
const togglePopper = restProps.show ? hidePopper : showPopper;
|
||||
|
||||
return (
|
||||
<div className={`popper__manager ${className}`} onClick={togglePopper}>
|
||||
<Popper {...restProps}>{children}</Popper>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withPopper(Popover);
|
||||
@@ -1,17 +0,0 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import Popper from './Popper';
|
||||
import withPopper, { UsingPopperProps } from './withPopper';
|
||||
|
||||
class Tooltip extends PureComponent<UsingPopperProps> {
|
||||
render() {
|
||||
const { children, hidePopper, showPopper, className, ...restProps } = this.props;
|
||||
|
||||
return (
|
||||
<div className={`popper__manager ${className}`} onMouseEnter={showPopper} onMouseLeave={hidePopper}>
|
||||
<Popper {...restProps}>{children}</Popper>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withPopper(Tooltip);
|
||||
@@ -1,16 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Popover renders correctly 1`] = `
|
||||
<div
|
||||
className="popper__manager test-class"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<div
|
||||
className="popper_ref "
|
||||
>
|
||||
<button>
|
||||
Button with Popover
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -1,19 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Tooltip renders correctly 1`] = `
|
||||
<div
|
||||
className="popper__manager test-class"
|
||||
onMouseEnter={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
>
|
||||
<div
|
||||
className="popper_ref "
|
||||
>
|
||||
<a
|
||||
href="http://www.grafana.com"
|
||||
>
|
||||
Link with tooltip
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -1,88 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
export interface UsingPopperProps {
|
||||
showPopper: (prevState: object) => void;
|
||||
hidePopper: (prevState: object) => void;
|
||||
renderContent: (content: any) => any;
|
||||
show: boolean;
|
||||
placement?: string;
|
||||
content: string | ((props: any) => JSX.Element);
|
||||
className?: string;
|
||||
refClassName?: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
placement?: string;
|
||||
className?: string;
|
||||
refClassName?: string;
|
||||
content: string | ((props: any) => JSX.Element);
|
||||
}
|
||||
|
||||
interface State {
|
||||
placement: string;
|
||||
show: boolean;
|
||||
}
|
||||
|
||||
export default function withPopper(WrappedComponent) {
|
||||
return class extends React.Component<Props, State> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.setState = this.setState.bind(this);
|
||||
this.state = {
|
||||
placement: this.props.placement || 'auto',
|
||||
show: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.placement && nextProps.placement !== this.state.placement) {
|
||||
this.setState(prevState => {
|
||||
return {
|
||||
...prevState,
|
||||
placement: nextProps.placement,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
showPopper = () => {
|
||||
this.setState(prevState => ({
|
||||
...prevState,
|
||||
show: true,
|
||||
}));
|
||||
};
|
||||
|
||||
hidePopper = () => {
|
||||
this.setState(prevState => ({
|
||||
...prevState,
|
||||
show: false,
|
||||
}));
|
||||
};
|
||||
|
||||
renderContent(content) {
|
||||
if (typeof content === 'function') {
|
||||
// If it's a function we assume it's a React component
|
||||
const ReactComponent = content;
|
||||
return <ReactComponent />;
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { show, placement } = this.state;
|
||||
const className = this.props.className || '';
|
||||
|
||||
return (
|
||||
<WrappedComponent
|
||||
{...this.props}
|
||||
showPopper={this.showPopper}
|
||||
hidePopper={this.hidePopper}
|
||||
renderContent={this.renderContent}
|
||||
show={show}
|
||||
placement={placement}
|
||||
className={className}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -6,14 +6,14 @@ import { AngularComponent, getAngularLoader } from 'app/core/services/AngularLoa
|
||||
import appEvents from 'app/core/app_events';
|
||||
|
||||
// Components
|
||||
import { EditorTabBody, EditorToolbarView } from './EditorTabBody';
|
||||
import { EditorTabBody, EditorToolbarView } from '../dashboard/dashgrid/EditorTabBody';
|
||||
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
|
||||
import StateHistory from './StateHistory';
|
||||
import 'app/features/alerting/AlertTabCtrl';
|
||||
|
||||
// Types
|
||||
import { DashboardModel } from '../dashboard_model';
|
||||
import { PanelModel } from '../panel_model';
|
||||
import { DashboardModel } from '../dashboard/dashboard_model';
|
||||
import { PanelModel } from '../dashboard/panel_model';
|
||||
|
||||
interface Props {
|
||||
angularPanel?: AngularComponent;
|
||||
@@ -1,8 +1,8 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import alertDef from '../../alerting/state/alertDef';
|
||||
import alertDef from './state/alertDef';
|
||||
import { getBackendSrv } from 'app/core/services/backend_srv';
|
||||
import { DashboardModel } from '../dashboard_model';
|
||||
import appEvents from '../../../core/app_events';
|
||||
import { DashboardModel } from '../dashboard/dashboard_model';
|
||||
import appEvents from '../../core/app_events';
|
||||
|
||||
interface Props {
|
||||
dashboard: DashboardModel;
|
||||
@@ -1,5 +1,9 @@
|
||||
// Library
|
||||
import React, { Component } from 'react';
|
||||
import { Tooltip } from '@grafana/ui';
|
||||
import { Themes } from '@grafana/ui/src/components/Tooltip/Popper';
|
||||
|
||||
import ErrorBoundary from 'app/core/components/ErrorBoundary/ErrorBoundary';
|
||||
|
||||
// Services
|
||||
import { getDatasourceSrv, DatasourceSrv } from 'app/features/plugins/datasource_srv';
|
||||
@@ -11,6 +15,8 @@ import kbn from 'app/core/utils/kbn';
|
||||
import { DataQueryOptions, DataQueryResponse } from 'app/types';
|
||||
import { TimeRange, TimeSeries, LoadingState } from '@grafana/ui';
|
||||
|
||||
const DEFAULT_PLUGIN_ERROR = 'Error in plugin';
|
||||
|
||||
interface RenderProps {
|
||||
loading: LoadingState;
|
||||
timeSeries: TimeSeries[];
|
||||
@@ -33,6 +39,7 @@ export interface Props {
|
||||
export interface State {
|
||||
isFirstLoad: boolean;
|
||||
loading: LoadingState;
|
||||
errorMessage: string;
|
||||
response: DataQueryResponse;
|
||||
}
|
||||
|
||||
@@ -51,6 +58,7 @@ export class DataPanel extends Component<Props, State> {
|
||||
|
||||
this.state = {
|
||||
loading: LoadingState.NotStarted,
|
||||
errorMessage: '',
|
||||
response: {
|
||||
data: [],
|
||||
},
|
||||
@@ -90,7 +98,7 @@ export class DataPanel extends Component<Props, State> {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({ loading: LoadingState.Loading });
|
||||
this.setState({ loading: LoadingState.Loading, errorMessage: '' });
|
||||
|
||||
try {
|
||||
const ds = await this.dataSourceSrv.get(datasource);
|
||||
@@ -128,7 +136,17 @@ export class DataPanel extends Component<Props, State> {
|
||||
});
|
||||
} catch (err) {
|
||||
console.log('Loading error', err);
|
||||
this.setState({ loading: LoadingState.Error, isFirstLoad: false });
|
||||
this.onError('Request Error');
|
||||
}
|
||||
};
|
||||
|
||||
onError = (errorMessage: string) => {
|
||||
if (this.state.loading !== LoadingState.Error || this.state.errorMessage !== errorMessage) {
|
||||
this.setState({
|
||||
loading: LoadingState.Error,
|
||||
isFirstLoad: false,
|
||||
errorMessage: errorMessage,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -139,7 +157,7 @@ export class DataPanel extends Component<Props, State> {
|
||||
const timeSeries = response.data;
|
||||
|
||||
if (isFirstLoad && loading === LoadingState.Loading) {
|
||||
return this.renderLoadingSpinner();
|
||||
return this.renderLoadingStates();
|
||||
}
|
||||
|
||||
if (!queries.length) {
|
||||
@@ -152,24 +170,44 @@ export class DataPanel extends Component<Props, State> {
|
||||
|
||||
return (
|
||||
<>
|
||||
{this.renderLoadingSpinner()}
|
||||
{this.props.children({
|
||||
timeSeries,
|
||||
loading,
|
||||
})}
|
||||
{this.renderLoadingStates()}
|
||||
<ErrorBoundary>
|
||||
{({ error, errorInfo }) => {
|
||||
if (errorInfo) {
|
||||
this.onError(error.message || DEFAULT_PLUGIN_ERROR);
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{this.props.children({
|
||||
timeSeries,
|
||||
loading,
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}}
|
||||
</ErrorBoundary>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
private renderLoadingSpinner(): JSX.Element {
|
||||
const { loading } = this.state;
|
||||
|
||||
private renderLoadingStates(): JSX.Element {
|
||||
const { loading, errorMessage } = this.state;
|
||||
if (loading === LoadingState.Loading) {
|
||||
return (
|
||||
<div className="panel-loading">
|
||||
<i className="fa fa-spinner fa-spin" />
|
||||
</div>
|
||||
);
|
||||
} else if (loading === LoadingState.Error) {
|
||||
return (
|
||||
<Tooltip content={errorMessage} placement="bottom-start" theme={Themes.Error}>
|
||||
<div className="panel-info-corner panel-info-corner--error">
|
||||
<i className="fa" />
|
||||
<span className="panel-info-corner-inner" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { SFC } from 'react';
|
||||
import Tooltip from 'app/core/components/Tooltip/Tooltip';
|
||||
import { Tooltip } from '@grafana/ui';
|
||||
|
||||
interface Props {
|
||||
label: string;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
// Components
|
||||
import CustomScrollbar from 'app/core/components/CustomScrollbar/CustomScrollbar';
|
||||
import { CustomScrollbar } from '@grafana/ui';
|
||||
import { FadeIn } from 'app/core/components/Animations/FadeIn';
|
||||
import { PanelOptionSection } from './PanelOptionSection';
|
||||
|
||||
|
||||
@@ -87,7 +87,6 @@ export class PanelChrome extends PureComponent<Props, State> {
|
||||
const { datasource, targets, transparent } = panel;
|
||||
const PanelComponent = plugin.exports.Panel;
|
||||
const containerClassNames = `panel-container panel-container--absolute ${transparent ? 'panel-transparent' : ''}`;
|
||||
|
||||
return (
|
||||
<AutoSizer>
|
||||
{({ width, height }) => {
|
||||
|
||||
@@ -4,7 +4,7 @@ import classNames from 'classnames';
|
||||
import { QueriesTab } from './QueriesTab';
|
||||
import { VisualizationTab } from './VisualizationTab';
|
||||
import { GeneralTab } from './GeneralTab';
|
||||
import { AlertTab } from './AlertTab';
|
||||
import { AlertTab } from '../../alerting/AlertTab';
|
||||
|
||||
import config from 'app/core/config';
|
||||
import { store } from 'app/store/store';
|
||||
@@ -15,7 +15,7 @@ import { PanelModel } from '../panel_model';
|
||||
import { DashboardModel } from '../dashboard_model';
|
||||
import { PanelPlugin } from 'app/types/plugins';
|
||||
|
||||
import Tooltip from 'app/core/components/Tooltip/Tooltip';
|
||||
import { Tooltip } from '@grafana/ui';
|
||||
|
||||
interface PanelEditorProps {
|
||||
panel: PanelModel;
|
||||
@@ -138,7 +138,7 @@ function TabItem({ tab, activeTab, onClick }: TabItemParams) {
|
||||
return (
|
||||
<div className="panel-editor-tabs__item" onClick={() => onClick(tab)}>
|
||||
<a className={tabClasses}>
|
||||
<Tooltip content={`${tab.text}`} className="popper__manager--block" placement="auto">
|
||||
<Tooltip content={`${tab.text}`} placement="auto">
|
||||
<i className={`gicon gicon-${tab.id}${activeTab === tab.id ? '-active' : ''}`} />
|
||||
</Tooltip>
|
||||
</a>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import React, { Component } from 'react';
|
||||
import Remarkable from 'remarkable';
|
||||
import { Tooltip } from '@grafana/ui';
|
||||
import { PanelModel } from 'app/features/dashboard/panel_model';
|
||||
import Tooltip from 'app/core/components/Tooltip/Tooltip';
|
||||
import templateSrv from 'app/features/templating/template_srv';
|
||||
import { LinkSrv } from 'app/features/dashboard/panellinks/link_srv';
|
||||
import { getTimeSrv, TimeSrv } from 'app/features/dashboard/time_srv';
|
||||
import Remarkable from 'remarkable';
|
||||
|
||||
enum InfoModes {
|
||||
Error = 'Error',
|
||||
@@ -78,12 +78,14 @@ export class PanelHeaderCorner extends Component<Props> {
|
||||
{infoMode === InfoModes.Info || infoMode === InfoModes.Links ? (
|
||||
<Tooltip
|
||||
content={this.getInfoContent}
|
||||
className="popper__manager--block"
|
||||
refClassName={`panel-info-corner panel-info-corner--${infoMode.toLowerCase()}`}
|
||||
placement="bottom-start"
|
||||
>
|
||||
<i className="fa" />
|
||||
<span className="panel-info-corner-inner" />
|
||||
<div
|
||||
className={`panel-info-corner panel-info-corner--${infoMode.toLowerCase()}`}
|
||||
>
|
||||
<i className="fa" />
|
||||
<span className="panel-info-corner-inner" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
</>
|
||||
|
||||
@@ -50,17 +50,21 @@ export class QueriesTab extends PureComponent<Props, State> {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const { panel } = props;
|
||||
|
||||
this.state = {
|
||||
currentDS: this.datasources.find(datasource => datasource.value === panel.datasource),
|
||||
isLoadingHelp: false,
|
||||
currentDS: this.findCurrentDataSource(),
|
||||
helpContent: null,
|
||||
isPickerOpen: false,
|
||||
isAddingMixed: false,
|
||||
};
|
||||
}
|
||||
|
||||
findCurrentDataSource(): DataSourceSelectItem {
|
||||
const { panel } = this.props;
|
||||
return this.datasources.find(datasource => datasource.value === panel.datasource) || this.datasources[0];
|
||||
}
|
||||
|
||||
getAngularQueryComponentScope(): AngularQueryComponentScope {
|
||||
const { panel, dashboard } = this.props;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import Tooltip from 'app/core/components/Tooltip/Tooltip';
|
||||
import { Tooltip } from '@grafana/ui';
|
||||
import SlideDown from 'app/core/components/Animations/SlideDown';
|
||||
import { StoreState, FolderInfo } from 'app/types';
|
||||
import { DashboardAcl, PermissionLevel, NewDashboardAclItem } from 'app/types/acl';
|
||||
@@ -70,8 +70,10 @@ export class DashboardPermissions extends PureComponent<Props, State> {
|
||||
<div className="dashboard-settings__header">
|
||||
<div className="page-action-bar">
|
||||
<h3 className="d-inline-block">Permissions</h3>
|
||||
<Tooltip className="page-sub-heading-icon" placement="auto" content={PermissionsInfo}>
|
||||
<i className="gicon gicon-question gicon--has-hover" />
|
||||
<Tooltip placement="auto" content={PermissionsInfo}>
|
||||
<div className="page-sub-heading-icon">
|
||||
<i className="gicon gicon-question gicon--has-hover" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<div className="page-action-bar__spacer" />
|
||||
<button className="btn btn-success pull-right" onClick={this.onOpenAddPermissions} disabled={isAdding}>
|
||||
|
||||
@@ -944,7 +944,7 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
|
||||
<div className="navbar-buttons relative">
|
||||
<button className="btn navbar-button navbar-button--primary" onClick={this.onSubmit}>
|
||||
Run Query{' '}
|
||||
{loading ? <i className="fa fa-spinner fa-spin run-icon" /> : <i className="fa fa-level-down run-icon" />}
|
||||
{loading ? <i className="fa fa-spinner fa-fw fa-spin run-icon" /> : <i className="fa fa-level-down fa-fw run-icon" />}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { PureComponent } from 'react';
|
||||
import { hot } from 'react-hot-loader';
|
||||
import { connect } from 'react-redux';
|
||||
import PageHeader from 'app/core/components/PageHeader/PageHeader';
|
||||
import Tooltip from 'app/core/components/Tooltip/Tooltip';
|
||||
import { Tooltip } from '@grafana/ui';
|
||||
import SlideDown from 'app/core/components/Animations/SlideDown';
|
||||
import { getNavModel } from 'app/core/selectors/navModel';
|
||||
import { NavModel, StoreState, FolderState } from 'app/types';
|
||||
@@ -84,8 +84,10 @@ export class FolderPermissions extends PureComponent<Props, State> {
|
||||
<div className="page-container page-body">
|
||||
<div className="page-action-bar">
|
||||
<h3 className="page-sub-heading">Folder Permissions</h3>
|
||||
<Tooltip className="page-sub-heading-icon" placement="auto" content={PermissionsInfo}>
|
||||
<i className="gicon gicon-question gicon--has-hover" />
|
||||
<Tooltip placement="auto" content={PermissionsInfo}>
|
||||
<div className="page-sub-heading-icon">
|
||||
<i className="gicon gicon-question gicon--has-hover" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<div className="page-action-bar__spacer" />
|
||||
<button className="btn btn-success pull-right" onClick={this.onOpenAddPermissions} disabled={isAdding}>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import SlideDown from 'app/core/components/Animations/SlideDown';
|
||||
import Tooltip from 'app/core/components/Tooltip/Tooltip';
|
||||
import { Tooltip } from '@grafana/ui';
|
||||
import { TeamGroup } from '../../types';
|
||||
import { addTeamGroup, loadTeamGroups, removeTeamGroup } from './state/actions';
|
||||
import { getTeamGroups } from './state/selectors';
|
||||
@@ -77,8 +77,10 @@ export class TeamGroupSync extends PureComponent<Props, State> {
|
||||
<div>
|
||||
<div className="page-action-bar">
|
||||
<h3 className="page-sub-heading">External group sync</h3>
|
||||
<Tooltip className="page-sub-heading-icon" placement="auto" content={headerTooltip}>
|
||||
<i className="gicon gicon-question gicon--has-hover" />
|
||||
<Tooltip placement="auto" content={headerTooltip}>
|
||||
<div className="page-sub-heading-icon">
|
||||
<i className="gicon gicon-question gicon--has-hover" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<div className="page-action-bar__spacer" />
|
||||
{groups.length > 0 && (
|
||||
|
||||
@@ -60,6 +60,7 @@ export class TeamSettings extends React.Component<Props, State> {
|
||||
onChange={this.onChangeName}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="gf-form max-width-30">
|
||||
<Label tooltip="This is optional and is primarily used to set the team profile avatar (via gravatar service)">
|
||||
Email
|
||||
|
||||
@@ -10,15 +10,18 @@ exports[`Render should render component 1`] = `
|
||||
>
|
||||
External group sync
|
||||
</h3>
|
||||
<class_1
|
||||
className="page-sub-heading-icon"
|
||||
<Component
|
||||
content="Sync LDAP or OAuth groups with your Grafana teams."
|
||||
placement="auto"
|
||||
>
|
||||
<i
|
||||
className="gicon gicon-question gicon--has-hover"
|
||||
/>
|
||||
</class_1>
|
||||
<div
|
||||
className="page-sub-heading-icon"
|
||||
>
|
||||
<i
|
||||
className="gicon gicon-question gicon--has-hover"
|
||||
/>
|
||||
</div>
|
||||
</Component>
|
||||
<div
|
||||
className="page-action-bar__spacer"
|
||||
/>
|
||||
@@ -116,15 +119,18 @@ exports[`Render should render groups table 1`] = `
|
||||
>
|
||||
External group sync
|
||||
</h3>
|
||||
<class_1
|
||||
className="page-sub-heading-icon"
|
||||
<Component
|
||||
content="Sync LDAP or OAuth groups with your Grafana teams."
|
||||
placement="auto"
|
||||
>
|
||||
<i
|
||||
className="gicon gicon-question gicon--has-hover"
|
||||
/>
|
||||
</class_1>
|
||||
<div
|
||||
className="page-sub-heading-icon"
|
||||
>
|
||||
<i
|
||||
className="gicon gicon-question gicon--has-hover"
|
||||
/>
|
||||
</div>
|
||||
</Component>
|
||||
<div
|
||||
className="page-action-bar__spacer"
|
||||
/>
|
||||
|
||||
@@ -151,32 +151,32 @@ export const aggOptions = [
|
||||
{
|
||||
text: 'mean',
|
||||
value: 'REDUCE_MEAN',
|
||||
valueTypes: [ValueTypes.INT64, ValueTypes.DOUBLE, ValueTypes.MONEY],
|
||||
valueTypes: [ValueTypes.INT64, ValueTypes.DOUBLE, ValueTypes.MONEY, ValueTypes.DISTRIBUTION],
|
||||
metricKinds: [MetricKind.GAUGE, MetricKind.DELTA],
|
||||
},
|
||||
{
|
||||
text: 'min',
|
||||
value: 'REDUCE_MIN',
|
||||
valueTypes: [ValueTypes.INT64, ValueTypes.DOUBLE, ValueTypes.MONEY],
|
||||
metricKinds: [MetricKind.GAUGE, MetricKind.DELTA],
|
||||
metricKinds: [MetricKind.GAUGE, MetricKind.DELTA, MetricKind.CUMULATIVE, MetricKind.METRIC_KIND_UNSPECIFIED],
|
||||
},
|
||||
{
|
||||
text: 'max',
|
||||
value: 'REDUCE_MAX',
|
||||
valueTypes: [ValueTypes.INT64, ValueTypes.DOUBLE, ValueTypes.MONEY],
|
||||
metricKinds: [MetricKind.GAUGE, MetricKind.DELTA],
|
||||
metricKinds: [MetricKind.GAUGE, MetricKind.DELTA, MetricKind.CUMULATIVE, MetricKind.METRIC_KIND_UNSPECIFIED],
|
||||
},
|
||||
{
|
||||
text: 'sum',
|
||||
value: 'REDUCE_SUM',
|
||||
valueTypes: [ValueTypes.INT64, ValueTypes.DOUBLE, ValueTypes.MONEY, ValueTypes.DISTRIBUTION],
|
||||
metricKinds: [MetricKind.GAUGE, MetricKind.DELTA],
|
||||
metricKinds: [MetricKind.GAUGE, MetricKind.DELTA, MetricKind.CUMULATIVE, MetricKind.METRIC_KIND_UNSPECIFIED],
|
||||
},
|
||||
{
|
||||
text: 'std. dev.',
|
||||
value: 'REDUCE_STDDEV',
|
||||
valueTypes: [ValueTypes.INT64, ValueTypes.DOUBLE, ValueTypes.MONEY, ValueTypes.DISTRIBUTION],
|
||||
metricKinds: [MetricKind.GAUGE, MetricKind.DELTA],
|
||||
metricKinds: [MetricKind.GAUGE, MetricKind.DELTA, MetricKind.CUMULATIVE, MetricKind.METRIC_KIND_UNSPECIFIED],
|
||||
},
|
||||
{
|
||||
text: 'count',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import _ from 'lodash';
|
||||
import React, { PureComponent } from 'react';
|
||||
import { TimeSeries } from 'app/core/core';
|
||||
import CustomScrollbar from 'app/core/components/CustomScrollbar/CustomScrollbar';
|
||||
import { CustomScrollbar } from '@grafana/ui';
|
||||
import { LegendItem, LEGEND_STATS } from './LegendSeriesItem';
|
||||
|
||||
interface LegendProps {
|
||||
|
||||
@@ -10,10 +10,6 @@ import { Options } from './types';
|
||||
interface Props extends PanelProps<Options> {}
|
||||
|
||||
export class GraphPanel extends PureComponent<Props> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { timeSeries, timeRange, width, height } = this.props;
|
||||
const { showLines, showBars, showPoints } = this.props.options;
|
||||
|
||||
@@ -97,7 +97,6 @@
|
||||
@import 'components/page_header';
|
||||
@import 'components/dashboard_settings';
|
||||
@import 'components/empty_list_cta';
|
||||
@import 'components/popper';
|
||||
@import 'components/form_select_box';
|
||||
@import 'components/panel_editor';
|
||||
@import 'components/toolbar';
|
||||
|
||||
@@ -103,6 +103,7 @@ $panel-bg: #212124;
|
||||
$panel-border-color: $dark-1;
|
||||
$panel-border: solid 1px $panel-border-color;
|
||||
$panel-header-hover-bg: $dark-4;
|
||||
$panel-corner: $panel-bg;
|
||||
|
||||
// page header
|
||||
$page-header-bg: linear-gradient(90deg, #292a2d, black);
|
||||
@@ -302,12 +303,14 @@ $popover-error-bg: $btn-danger-bg;
|
||||
// Tooltips and popovers
|
||||
// -------------------------
|
||||
$tooltipColor: $popover-help-color;
|
||||
$tooltipBackground: $popover-help-bg;
|
||||
$tooltipArrowWidth: 5px;
|
||||
$tooltipArrowColor: $tooltipBackground;
|
||||
$tooltipLinkColor: $link-color;
|
||||
$graph-tooltip-bg: $dark-1;
|
||||
|
||||
$tooltipBackground: $popover-help-bg;
|
||||
$tooltipArrowColor: $tooltipBackground;
|
||||
$tooltipBackgroundError: $brand-danger;
|
||||
|
||||
// images
|
||||
$checkboxImageUrl: '../img/checkbox.png';
|
||||
|
||||
|
||||
@@ -76,8 +76,7 @@ $textShadow: none;
|
||||
|
||||
// gradients
|
||||
$brand-gradient: linear-gradient(to right, rgba(255, 213, 0, 1) 0%, rgba(255, 68, 0, 1) 99%, rgba(255, 68, 0, 1) 100%);
|
||||
$page-gradient: linear-gradient(-60deg, $gray-7, #f5f6f9 70%, $gray-7 98%);
|
||||
//$page-gradient: linear-gradient(180deg, $white 10px, $gray-7 100px);
|
||||
$page-gradient: linear-gradient(180deg, $white 10px, $gray-7 100px);
|
||||
$edit-gradient: linear-gradient(-60deg, $gray-7, #f5f6f9 70%, $gray-7 98%);
|
||||
|
||||
// Links
|
||||
@@ -102,6 +101,7 @@ $panel-bg: $white;
|
||||
$panel-border-color: $gray-5;
|
||||
$panel-border: solid 1px $panel-border-color;
|
||||
$panel-header-hover-bg: $gray-6;
|
||||
$panel-corner: $gray-4;
|
||||
|
||||
// Page header
|
||||
$page-header-bg: linear-gradient(90deg, $white, $gray-7);
|
||||
@@ -307,12 +307,14 @@ $popover-error-bg: $btn-danger-bg;
|
||||
// Tooltips and popovers
|
||||
// -------------------------
|
||||
$tooltipColor: $popover-help-color;
|
||||
$tooltipBackground: $popover-help-bg;
|
||||
$tooltipArrowWidth: 5px;
|
||||
$tooltipArrowColor: $tooltipBackground;
|
||||
$tooltipLinkColor: lighten($popover-help-color, 5%);
|
||||
$graph-tooltip-bg: $gray-5;
|
||||
|
||||
$tooltipBackground: $popover-help-bg;
|
||||
$tooltipArrowColor: $tooltipBackground; // Used by Angular tooltip
|
||||
$tooltipBackgroundError: $brand-danger;
|
||||
|
||||
// images
|
||||
$checkboxImageUrl: '../img/checkbox_white.png';
|
||||
|
||||
|
||||
@@ -295,50 +295,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Custom styles for 'react-custom-scrollbars'
|
||||
|
||||
.custom-scrollbars {
|
||||
// Fix for Firefox. For some reason sometimes .view container gets a height of its content, but in order to
|
||||
// make scroll working it should fit outer container size (scroll appears only when inner container size is
|
||||
// greater than outer one).
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
|
||||
.view {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.track-vertical {
|
||||
border-radius: 3px;
|
||||
width: 6px !important;
|
||||
|
||||
right: 2px;
|
||||
bottom: 2px;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
.track-horizontal {
|
||||
border-radius: 3px;
|
||||
height: 6px !important;
|
||||
|
||||
right: 2px;
|
||||
bottom: 2px;
|
||||
left: 2px;
|
||||
}
|
||||
|
||||
.thumb-vertical {
|
||||
@include gradient-vertical($scrollbarBackground, $scrollbarBackground2);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.thumb-horizontal {
|
||||
@include gradient-horizontal($scrollbarBackground, $scrollbarBackground2);
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-margin-helper {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ div.flot-text {
|
||||
|
||||
&--info {
|
||||
display: block;
|
||||
@include panel-corner-color(lighten($panel-bg, 4%));
|
||||
@include panel-corner-color(lighten($panel-corner, 4%));
|
||||
.fa:before {
|
||||
content: '\f129';
|
||||
}
|
||||
@@ -222,7 +222,7 @@ div.flot-text {
|
||||
|
||||
&--links {
|
||||
display: block;
|
||||
@include panel-corner-color(lighten($panel-bg, 4%));
|
||||
@include panel-corner-color(lighten($panel-corner, 4%));
|
||||
.fa {
|
||||
left: 4px;
|
||||
}
|
||||
@@ -233,7 +233,7 @@ div.flot-text {
|
||||
|
||||
&--error {
|
||||
display: block;
|
||||
color: $text-color;
|
||||
color: $white;
|
||||
@include panel-corner-color($popover-error-bg);
|
||||
.fa:before {
|
||||
content: '\f12a';
|
||||
|
||||
@@ -160,7 +160,7 @@
|
||||
}
|
||||
|
||||
.run-icon {
|
||||
margin-left: 0.5em;
|
||||
margin-left: 0.25em;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
FROM circleci/golang:1.11
|
||||
|
||||
RUN git clone https://github.com/aptly-dev/aptly $GOPATH/src/github.com/aptly-dev/aptly && \
|
||||
cd $GOPATH/src/github.com/aptly-dev/aptly && \
|
||||
# pin aptly to a specific commit after 1.3.0 that contains gpg2 support
|
||||
git reset --hard a64807efdaf5e380bfa878c71bc88eae10d62be1 && \
|
||||
make install
|
||||
|
||||
FROM circleci/python:2.7-stretch
|
||||
|
||||
RUN sudo pip install awscli && \
|
||||
curl https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-222.0.0-linux-x86_64.tar.gz | \
|
||||
sudo tar xvzf - -C /opt
|
||||
ENV PATH=$PATH:/opt/google-cloud-sdk/bin
|
||||
|
||||
USER root
|
||||
|
||||
RUN pip install awscli && \
|
||||
curl https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-222.0.0-linux-x86_64.tar.gz | \
|
||||
tar xvzf - -C /opt && \
|
||||
apt update && \
|
||||
apt install -y createrepo expect && \
|
||||
apt-get autoremove -y && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY --from=0 /go/bin/aptly /usr/local/bin/aptly
|
||||
|
||||
USER circleci
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
_version="1.0.0"
|
||||
_version="1.1.0"
|
||||
_tag="grafana/grafana-ci-deploy:${_version}"
|
||||
|
||||
docker build -t $_tag .
|
||||
|
||||
7
scripts/build/load-signing-key.sh
Normal file
7
scripts/build/load-signing-key.sh
Normal file
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
git clone git@github.com:torkelo/private.git ~/private-repo
|
||||
gpg --batch --allow-secret-key-import --import ~/private-repo/signing/private.key
|
||||
pkill gpg-agent
|
||||
27
scripts/build/update_repo/aptly.conf
Normal file
27
scripts/build/update_repo/aptly.conf
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"rootDir": "/deb-repo/db",
|
||||
"downloadConcurrency": 4,
|
||||
"downloadSpeedLimit": 0,
|
||||
"architectures": [],
|
||||
"dependencyFollowSuggests": false,
|
||||
"dependencyFollowRecommends": false,
|
||||
"dependencyFollowAllVariants": false,
|
||||
"dependencyFollowSource": false,
|
||||
"dependencyVerboseResolve": false,
|
||||
"gpgDisableSign": false,
|
||||
"gpgDisableVerify": false,
|
||||
"gpgProvider": "gpg2",
|
||||
"downloadSourcePackages": false,
|
||||
"skipLegacyPool": true,
|
||||
"ppaDistributorID": "ubuntu",
|
||||
"ppaCodename": "",
|
||||
"skipContentsPublishing": false,
|
||||
"FileSystemPublishEndpoints": {
|
||||
"repo": {
|
||||
"rootDir": "/deb-repo/repo",
|
||||
"linkMethod": "copy"
|
||||
}
|
||||
},
|
||||
"S3PublishEndpoints": {},
|
||||
"SwiftPublishEndpoints": {}
|
||||
}
|
||||
7
scripts/build/update_repo/sign-rpm-repo.sh
Executable file
7
scripts/build/update_repo/sign-rpm-repo.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env expect
|
||||
|
||||
set password [lindex $argv 0]
|
||||
spawn gpg --detach-sign --armor /rpm-repo/repodata/repomd.xml
|
||||
expect "Enter passphrase: "
|
||||
send -- "$password\r"
|
||||
expect eof
|
||||
7
scripts/build/update_repo/unlock-gpg-key.sh
Executable file
7
scripts/build/update_repo/unlock-gpg-key.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env expect
|
||||
|
||||
set password [lindex $argv 0]
|
||||
spawn gpg --detach-sign --armor /tmp/sign-this
|
||||
expect "Enter passphrase: "
|
||||
send -- "$password\r"
|
||||
expect eof
|
||||
58
scripts/build/update_repo/update-deb.sh
Executable file
58
scripts/build/update_repo/update-deb.sh
Executable file
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
RELEASE_TYPE="${1:-}"
|
||||
GPG_PASS="${2:-}"
|
||||
RELEASE_TAG="${3:-}"
|
||||
REPO="grafana"
|
||||
|
||||
if [ -z "$RELEASE_TYPE" -o -z "$GPG_PASS" ]; then
|
||||
echo "Both RELEASE_TYPE (arg 1) and GPG_PASS (arg 2) has to be set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$RELEASE_TYPE" != "oss" && "$RELEASE_TYPE" != "enterprise" ]]; then
|
||||
echo "RELEASE_TYPE (arg 1) must be either oss or enterprise."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if echo "$RELEASE_TAG" | grep -q "beta"; then
|
||||
REPO="beta"
|
||||
fi
|
||||
|
||||
set -e
|
||||
|
||||
# Setup environment
|
||||
cp scripts/build/update_repo/aptly.conf /etc/aptly.conf
|
||||
mkdir -p /deb-repo/db \
|
||||
/deb-repo/repo \
|
||||
/deb-repo/tmp
|
||||
|
||||
# Download the database
|
||||
gsutil -m rsync -r "gs://grafana-aptly-db/$RELEASE_TYPE" /deb-repo/db
|
||||
|
||||
# Add the new release to the repo
|
||||
aptly publish drop grafana filesystem:repo:grafana || true
|
||||
aptly publish drop beta filesystem:repo:grafana || true
|
||||
cp ./dist/*.deb /deb-repo/tmp
|
||||
rm /deb-repo/tmp/grafana_latest*.deb || true
|
||||
aptly repo add "$REPO" ./dist
|
||||
|
||||
# Setup signing and sign the repo
|
||||
|
||||
echo "allow-loopback-pinentry" > ~/.gnupg/gpg-agent.conf
|
||||
echo "pinentry-mode loopback" > ~/.gnupg/gpg.conf
|
||||
|
||||
touch /tmp/sign-this
|
||||
./scripts/build/update_repo/unlock-gpg-key.sh "$GPG_PASS"
|
||||
rm /tmp/sign-this /tmp/sign-this.asc
|
||||
|
||||
aptly publish repo grafana filesystem:repo:grafana
|
||||
aptly publish repo beta filesystem:repo:grafana
|
||||
|
||||
# Update the repo and db on gcp
|
||||
gsutil -m rsync -r -d /deb-repo/db "gs://grafana-aptly-db/$RELEASE_TYPE"
|
||||
gsutil -m rsync -r -d /deb-repo/repo/grafana "gs://grafana-repo/$RELEASE_TYPE/deb"
|
||||
|
||||
# usage:
|
||||
#
|
||||
# deb https://packages.grafana.com/oss/deb stable main
|
||||
59
scripts/build/update_repo/update-rpm.sh
Executable file
59
scripts/build/update_repo/update-rpm.sh
Executable file
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
RELEASE_TYPE="${1:-}"
|
||||
GPG_PASS="${2:-}"
|
||||
|
||||
RELEASE_TAG="${3:-}"
|
||||
REPO="rpm"
|
||||
|
||||
if [ -z "$RELEASE_TYPE" -o -z "$GPG_PASS" ]; then
|
||||
echo "Both RELEASE_TYPE (arg 1) and GPG_PASS (arg 2) has to be set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$RELEASE_TYPE" != "oss" && "$RELEASE_TYPE" != "enterprise" ]]; then
|
||||
echo "RELEASE_TYPE (arg 1) must be either oss or enterprise."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if echo "$RELEASE_TAG" | grep -q "beta"; then
|
||||
REPO="rpm-beta"
|
||||
fi
|
||||
|
||||
set -e
|
||||
|
||||
# Setup environment
|
||||
BUCKET="gs://grafana-repo/$RELEASE_TYPE/$REPO"
|
||||
mkdir -p /rpm-repo
|
||||
|
||||
# Download the database
|
||||
gsutil -m rsync -r "$BUCKET" /rpm-repo
|
||||
|
||||
# Add the new release to the repo
|
||||
cp ./dist/*.rpm /rpm-repo
|
||||
rm /rpm-repo/grafana-latest-1*.rpm || true
|
||||
cd /rpm-repo
|
||||
createrepo .
|
||||
|
||||
# Setup signing and sign the repo
|
||||
|
||||
echo "allow-loopback-pinentry" > ~/.gnupg/gpg-agent.conf
|
||||
echo "pinentry-mode loopback" > ~/.gnupg/gpg.conf
|
||||
|
||||
rm /rpm-repo/repodata/repomd.xml.asc || true
|
||||
pkill gpg-agent || true
|
||||
./scripts/build/update_repo/sign-rpm-repo.sh "$GPG_PASS"
|
||||
|
||||
# Update the repo and db on gcp
|
||||
gsutil -m rsync -r -d /rpm-repo "$BUCKET"
|
||||
|
||||
# usage:
|
||||
# [grafana]
|
||||
# name=grafana
|
||||
# baseurl=https://packages.grafana.com/oss/rpm
|
||||
# repo_gpgcheck=1
|
||||
# enabled=1
|
||||
# gpgcheck=1
|
||||
# gpgkey=https://packages.grafana.com/gpg.key
|
||||
# sslverify=1
|
||||
# sslcacert=/etc/pki/tls/certs/ca-bundle.crt
|
||||
13
yarn.lock
13
yarn.lock
@@ -937,7 +937,14 @@
|
||||
"@types/react-dom" "*"
|
||||
"@types/react-transition-group" "*"
|
||||
|
||||
"@types/react-transition-group@*":
|
||||
"@types/react-test-renderer@^16.0.3":
|
||||
version "16.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-16.0.3.tgz#cce5c983d66cc5c3582e7c2f44b274ab635a8acc"
|
||||
integrity sha512-NWOAxVQeJxpXuNKgw83Hah0nquiw1nUexM9qY/Hk3a+XhZwgMtaa6GLA9E1TKMT75Odb3/KE/jiBO4enTuEJjQ==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-transition-group@*", "@types/react-transition-group@^2.0.15":
|
||||
version "2.0.15"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-2.0.15.tgz#e5ee3fe558832e141cc6041bdd54caea7b787af8"
|
||||
dependencies:
|
||||
@@ -2743,6 +2750,7 @@ caniuse-api@^1.5.2:
|
||||
caniuse-db@1.0.30000772, caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
|
||||
version "1.0.30000772"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000772.tgz#51aae891768286eade4a3d8319ea76d6a01b512b"
|
||||
integrity sha1-UarokXaChureSj2DGep21qAbUSs=
|
||||
|
||||
caniuse-lite@^1.0.30000925:
|
||||
version "1.0.30000926"
|
||||
@@ -10561,7 +10569,7 @@ react-table@^6.8.6:
|
||||
dependencies:
|
||||
classnames "^2.2.5"
|
||||
|
||||
react-test-renderer@^16.0.0-0, react-test-renderer@^16.5.0:
|
||||
react-test-renderer@^16.0.0-0, react-test-renderer@^16.5.0, react-test-renderer@^16.7.0:
|
||||
version "16.7.0"
|
||||
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.7.0.tgz#1ca96c2b450ab47c36ba92cd8c03fcefc52ea01c"
|
||||
dependencies:
|
||||
@@ -11298,6 +11306,7 @@ sax@^1.2.4, sax@~1.2.1:
|
||||
scheduler@^0.12.0:
|
||||
version "0.12.0"
|
||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.12.0.tgz#8ab17699939c0aedc5a196a657743c496538647b"
|
||||
integrity sha512-t7MBR28Akcp4Jm+QoR63XgAi9YgCUmgvDHqf5otgAj4QvdoBE4ImCX0ffehefePPG+aitiYHp0g/mW6s4Tp+dw==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
object-assign "^4.1.1"
|
||||
|
||||
Reference in New Issue
Block a user