Skip to content

Commit

Permalink
Merge remote-tracking branch 'grafana/master' into graph-with-series-…
Browse files Browse the repository at this point in the history
…data

* grafana/master:
  Changelog: Typo guage -> gauge (grafana#16982)
  TestData: stream via fetch (grafana#16963)
  plugins: fix how datemath utils are exposed to plugins (grafana#16976)
  NewDataSource: Updated page header title
  fix(prometheus): issue with click label to filter for recording rules in Explore
  Explore: Removes Promise.All from runQueries thunk (grafana#16957)
  Chore: Add prometheus basic auth proxy (grafana#16882)
  Snapshot: use given key and deleteKey (grafana#16876)
  DataSourcePlugins: more generics improvements (grafana#16965)
  AddDataSource: Updated page design & categories (grafana#16971)
  Templating: Support selecting all filtered values of multi-value variable (grafana#16873)
  Chore: Add Input stories (grafana#16897)
  • Loading branch information
ryantxu committed May 9, 2019
2 parents 1f18bc5 + d4a3521 commit 72a48fc
Show file tree
Hide file tree
Showing 52 changed files with 608 additions and 178 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@

### Breaking changes

* **Gauge Panel**: The suffix / prefix options have been removed from the new Guage Panel (introduced in v6.0). [#16870](https://github.com/grafana/grafana/issues/16870).
* **Gauge Panel**: The suffix / prefix options have been removed from the new Gauge Panel (introduced in v6.0). [#16870](https://github.com/grafana/grafana/issues/16870).


# 6.1.6 (2019-04-29)
Expand Down
4 changes: 4 additions & 0 deletions devenv/docker/blocks/prometheus_basic_auth_proxy/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
FROM nginx:alpine

COPY nginx.conf /etc/nginx/nginx.conf
COPY htpasswd /etc/nginx/htpasswd
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# This will proxy all requests for http://localhost:10090 to
# http://prometheus:9090 (Prometheus inside the docker compose)

nginxproxy:
build: docker/blocks/nginx_proxy
network_mode: host
1 change: 1 addition & 0 deletions devenv/docker/blocks/prometheus_basic_auth_proxy/htpasswd
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
prom:$apr1$bfu32njz$HHDDTjaeWHDzQs2UMXP.C1
34 changes: 34 additions & 0 deletions devenv/docker/blocks/prometheus_basic_auth_proxy/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
events { }

http {
server {

listen 10090;

location / {

# Removes any Access-Control-Allow-Origin from Prometheus itself. When accessing from browser, having * or
# multiple values is not allowed in some cases
proxy_hide_header Access-Control-Allow-Origin;

# Allow the origin access. This is kinda wildcard but for browser it seems more strict and is needed for
# withCredentials requests.
add_header Access-Control-Allow-Origin $http_origin;

# When using withCredentials requests this must be true.
add_header Access-Control-Allow-Credentials true;

# Ask for basic auth except for pre flight OPTIONS request.
limit_except OPTIONS {
################################################################
# The htpasswd file contains user:
# prom: test
################################################################
auth_basic "prom";
auth_basic_user_file /etc/nginx/htpasswd;
}

proxy_pass http://prometheus:9090/;
}
}
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@
"d3-scale-chromatic": "1.3.3",
"eventemitter3": "2.0.3",
"file-saver": "1.3.8",
"fast-text-encoding": "^1.0.0",
"immutable": "3.8.2",
"jquery": "3.4.0",
"lodash": "4.17.11",
Expand Down
40 changes: 40 additions & 0 deletions packages/grafana-ui/src/components/Input/Input.story.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React, { useState } from 'react';
import { zip, fromPairs } from 'lodash';

import { storiesOf } from '@storybook/react';
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
import { Input } from './Input';
import { text, select } from '@storybook/addon-knobs';
import { EventsWithValidation } from '../../utils';

const getKnobs = () => {
return {
validation: text('Validation regex (will do a partial match if you do not anchor it)', ''),
validationErrorMessage: text('Validation error message', 'Input not valid'),
validationEvent: select(
'Validation event',
fromPairs(zip(Object.keys(EventsWithValidation), Object.values(EventsWithValidation))),
EventsWithValidation.onBlur
),
};
};

const Wrapper = () => {
const { validation, validationErrorMessage, validationEvent } = getKnobs();
const [value, setValue] = useState('');
const validations = {
[validationEvent]: [
{
rule: (value: string) => {
return !!value.match(validation);
},
errorMessage: validationErrorMessage,
},
],
};
return <Input value={value} onChange={e => setValue(e.currentTarget.value)} validationEvents={validations} />;
};

const story = storiesOf('UI/Input', module);
story.addDecorator(withCenteredStory);
story.add('input', () => <Wrapper />);
6 changes: 5 additions & 1 deletion packages/grafana-ui/src/components/Input/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ interface Props extends React.HTMLProps<HTMLInputElement> {
onChange?: (event: React.ChangeEvent<HTMLInputElement>, status?: InputStatus) => void;
}

export class Input extends PureComponent<Props> {
interface State {
error: string | null;
}

export class Input extends PureComponent<Props, State> {
static defaultProps = {
className: '',
};
Expand Down
53 changes: 27 additions & 26 deletions packages/grafana-ui/src/components/SetInterval/SetInterval.tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,48 @@
import { PureComponent } from 'react';
import { interval, Subscription, empty, Subject } from 'rxjs';
import { tap, switchMap } from 'rxjs/operators';

import { stringToMs } from '../../utils/string';

interface Props {
func: () => any; // TODO
loading: boolean;
interval: string;
}

export class SetInterval extends PureComponent<Props> {
private intervalId = 0;
private propsSubject: Subject<Props>;
private subscription: Subscription | null;

componentDidMount() {
this.addInterval();
constructor(props: Props) {
super(props);
this.propsSubject = new Subject<Props>();
this.subscription = null;
}

componentDidUpdate(prevProps: Props) {
const { interval } = this.props;
if (interval !== prevProps.interval) {
this.clearInterval();
this.addInterval();
}
componentDidMount() {
this.subscription = this.propsSubject
.pipe(
switchMap(props => {
return props.loading ? empty() : interval(stringToMs(props.interval));
}),
tap(() => this.props.func())
)
.subscribe();
this.propsSubject.next(this.props);
}

componentWillUnmount() {
this.clearInterval();
componentDidUpdate() {
this.propsSubject.next(this.props);
}

addInterval = () => {
const { func, interval } = this.props;

if (interval) {
func().then(() => {
if (interval) {
this.intervalId = window.setTimeout(() => {
this.addInterval();
}, stringToMs(interval));
}
});
componentWillUnmount() {
if (this.subscription) {
this.subscription.unsubscribe();
}
};

clearInterval = () => {
window.clearTimeout(this.intervalId);
};
this.propsSubject.unsubscribe();
}

render() {
return null;
Expand Down
22 changes: 22 additions & 0 deletions packages/grafana-ui/src/components/Switch/Switch.story.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React, { useState } from 'react';

import { storiesOf } from '@storybook/react';
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
import { Switch } from './Switch';
import { text } from '@storybook/addon-knobs';

const getKnobs = () => {
return {
label: text('Label Text', 'Label'),
};
};

const SwitchWrapper = () => {
const { label } = getKnobs();
const [checked, setChecked] = useState(false);
return <Switch label={label} checked={checked} onChange={() => setChecked(!checked)} />;
};

const story = storiesOf('UI/Switch', module);
story.addDecorator(withCenteredStory);
story.add('switch', () => <SwitchWrapper />);
2 changes: 1 addition & 1 deletion packages/grafana-ui/src/components/Switch/Switch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export interface Props {
}

export interface State {
id: any;
id: string;
}

export class Switch extends PureComponent<Props, State> {
Expand Down
1 change: 1 addition & 0 deletions packages/grafana-ui/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export { UnitPicker } from './UnitPicker/UnitPicker';
export { StatsPicker } from './StatsPicker/StatsPicker';
export { Input, InputStatus } from './Input/Input';
export { RefreshPicker } from './RefreshPicker/RefreshPicker';
export { List } from './List/List';

// Renderless
export { SetInterval } from './SetInterval/SetInterval';
Expand Down
47 changes: 32 additions & 15 deletions packages/grafana-ui/src/types/datasource.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ComponentClass } from 'react';
import { ComponentType, ComponentClass } from 'react';
import { TimeRange } from './time';
import { PluginMeta, GrafanaPlugin } from './plugin';
import { TableData, TimeSeries, SeriesData, LoadingState } from './data';
Expand All @@ -11,19 +11,20 @@ export interface DataSourcePluginOptionsEditorProps<TOptions> {
}

export class DataSourcePlugin<
DSType extends DataSourceApi<TQuery, TOptions>,
TQuery extends DataQuery = DataQuery,
TOptions extends DataSourceJsonData = DataSourceJsonData
> extends GrafanaPlugin<DataSourcePluginMeta> {
DataSourceClass: DataSourceConstructor<TQuery, TOptions>;
components: DataSourcePluginComponents<TQuery, TOptions>;
DataSourceClass: DataSourceConstructor<DSType, TQuery, TOptions>;
components: DataSourcePluginComponents<DSType, TQuery, TOptions>;

constructor(DataSourceClass: DataSourceConstructor<TQuery, TOptions>) {
constructor(DataSourceClass: DataSourceConstructor<DSType, TQuery, TOptions>) {
super();
this.DataSourceClass = DataSourceClass;
this.components = {};
}

setConfigEditor(editor: React.ComponentType<DataSourcePluginOptionsEditorProps<DataSourceSettings<TOptions>>>) {
setConfigEditor(editor: ComponentType<DataSourcePluginOptionsEditorProps<DataSourceSettings<TOptions>>>) {
this.components.ConfigEditor = editor;
return this;
}
Expand All @@ -38,12 +39,12 @@ export class DataSourcePlugin<
return this;
}

setQueryEditor(QueryEditor: ComponentClass<QueryEditorProps<DataSourceApi, TQuery>>) {
setQueryEditor(QueryEditor: ComponentType<QueryEditorProps<DSType, TQuery, TOptions>>) {
this.components.QueryEditor = QueryEditor;
return this;
}

setExploreQueryField(ExploreQueryField: ComponentClass<ExploreQueryFieldProps<DataSourceApi, TQuery>>) {
setExploreQueryField(ExploreQueryField: ComponentClass<ExploreQueryFieldProps<DSType, TQuery, TOptions>>) {
this.components.ExploreQueryField = ExploreQueryField;
return this;
}
Expand Down Expand Up @@ -79,7 +80,9 @@ export interface DataSourcePluginMeta extends PluginMeta {
annotations?: boolean;
mixed?: boolean;
hasQueryHelp?: boolean;
category?: string;
queryOptions?: PluginMetaQueryOptions;
sort?: number;
}

interface PluginMetaQueryOptions {
Expand All @@ -89,23 +92,26 @@ interface PluginMetaQueryOptions {
}

export interface DataSourcePluginComponents<
DSType extends DataSourceApi<TQuery, TOptions>,
TQuery extends DataQuery = DataQuery,
TOptions extends DataSourceJsonData = DataSourceJsonData
> {
QueryCtrl?: any;
AnnotationsQueryCtrl?: any;
VariableQueryEditor?: any;
QueryEditor?: ComponentClass<QueryEditorProps<DataSourceApi, TQuery>>;
ExploreQueryField?: ComponentClass<ExploreQueryFieldProps<DataSourceApi, TQuery>>;
QueryEditor?: ComponentType<QueryEditorProps<DSType, TQuery, TOptions>>;
ExploreQueryField?: ComponentClass<ExploreQueryFieldProps<DSType, TQuery, TOptions>>;
ExploreStartPage?: ComponentClass<ExploreStartPageProps>;
ConfigEditor?: React.ComponentType<DataSourcePluginOptionsEditorProps<DataSourceSettings<TOptions>>>;
ConfigEditor?: ComponentType<DataSourcePluginOptionsEditorProps<DataSourceSettings<TOptions>>>;
}

// Only exported for tests
export interface DataSourceConstructor<
DSType extends DataSourceApi<TQuery, TOptions>,
TQuery extends DataQuery = DataQuery,
TOptions extends DataSourceJsonData = DataSourceJsonData
> {
new (instanceSettings: DataSourceInstanceSettings<TOptions>, ...args: any[]): DataSourceApi<TQuery, TOptions>;
new (instanceSettings: DataSourceInstanceSettings<TOptions>, ...args: any[]): DSType;
}

/**
Expand Down Expand Up @@ -164,21 +170,28 @@ export interface DataSourceApi<
* Set after constructor call, as the data source instance is the most common thing to pass around
* we attach the components to this instance for easy access
*/
components?: DataSourcePluginComponents<TQuery, TOptions>;
components?: DataSourcePluginComponents<DataSourceApi<TQuery, TOptions>, TQuery, TOptions>;

/**
* static information about the datasource
*/
meta?: DataSourcePluginMeta;
}

export interface ExploreDataSourceApi<TQuery extends DataQuery = DataQuery> extends DataSourceApi {
export interface ExploreDataSourceApi<
TQuery extends DataQuery = DataQuery,
TOptions extends DataSourceJsonData = DataSourceJsonData
> extends DataSourceApi<TQuery, TOptions> {
modifyQuery?(query: TQuery, action: QueryFixAction): TQuery;
getHighlighterExpression?(query: TQuery): string;
languageProvider?: any;
}

export interface QueryEditorProps<DSType extends DataSourceApi, TQuery extends DataQuery> {
export interface QueryEditorProps<
DSType extends DataSourceApi<TQuery, TOptions>,
TQuery extends DataQuery = DataQuery,
TOptions extends DataSourceJsonData = DataSourceJsonData
> {
datasource: DSType;
query: TQuery;
onRunQuery: () => void;
Expand All @@ -192,7 +205,11 @@ export enum DataSourceStatus {
Disconnected,
}

export interface ExploreQueryFieldProps<DSType extends DataSourceApi, TQuery extends DataQuery> {
export interface ExploreQueryFieldProps<
DSType extends DataSourceApi<TQuery, TOptions>,
TQuery extends DataQuery = DataQuery,
TOptions extends DataSourceJsonData = DataSourceJsonData
> {
datasource: DSType;
datasourceStatus: DataSourceStatus;
query: TQuery;
Expand Down
1 change: 1 addition & 0 deletions packages/grafana-ui/src/types/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
}

export interface ValidationEvents {
// Event name should be one of EventsWithValidation enum
[eventName: string]: ValidationRule[];
}
10 changes: 8 additions & 2 deletions pkg/api/dashboard_snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,14 @@ func CreateDashboardSnapshot(c *m.ReqContext, cmd m.CreateDashboardSnapshotComma

metrics.M_Api_Dashboard_Snapshot_External.Inc()
} else {
cmd.Key = util.GetRandomString(32)
cmd.DeleteKey = util.GetRandomString(32)
if cmd.Key == "" {
cmd.Key = util.GetRandomString(32)
}

if cmd.DeleteKey == "" {
cmd.DeleteKey = util.GetRandomString(32)
}

url = setting.ToAbsUrl("dashboard/snapshot/" + cmd.Key)

metrics.M_Api_Dashboard_Snapshot_Create.Inc()
Expand Down
1 change: 1 addition & 0 deletions pkg/api/dtos/plugins.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type PluginListItem struct {
LatestVersion string `json:"latestVersion"`
HasUpdate bool `json:"hasUpdate"`
DefaultNavUrl string `json:"defaultNavUrl"`
Category string `json:"category"`
State plugins.PluginState `json:"state"`
}

Expand Down
Loading

0 comments on commit 72a48fc

Please sign in to comment.