mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge branch 'panel-edit-in-react' of https://github.com/grafana/grafana into panel-edit-in-react
This commit is contained in:
commit
4f38af12a8
@ -67,7 +67,7 @@
|
||||
<gf-form-checkbox
|
||||
on-change="ctrl.onSelectAllChanged()"
|
||||
checked="ctrl.selectAllChecked"
|
||||
switch-class="gf-form-switch--transparent"
|
||||
switch-class="gf-form-checkbox--transparent"
|
||||
/>
|
||||
<div class="search-results-filter-row__filters">
|
||||
<div class="gf-form-select-wrapper" ng-show="!(ctrl.canMove || ctrl.canDelete)">
|
||||
|
@ -1,11 +1,11 @@
|
||||
<div ng-repeat="section in ctrl.results" class="search-section">
|
||||
<div class="search-section__header pointer" ng-hide="section.hideHeader" ng-class="{'selected': section.selected}" ng-click="ctrl.toggleFolderExpand(section)">
|
||||
<div ng-click="ctrl.toggleSelection(section, $event)">
|
||||
<div ng-click="ctrl.toggleSelection(section, $event)" class="center-vh">
|
||||
<gf-form-checkbox
|
||||
ng-show="ctrl.editable"
|
||||
on-change="ctrl.selectionChanged($event)"
|
||||
checked="section.checked"
|
||||
switch-class="gf-form-switch--transparent gf-form-switch--search-result__section">
|
||||
switch-class="gf-form-checkbox--transparent">
|
||||
</gf-form-checkbox>
|
||||
</div>
|
||||
<i class="search-section__header__icon" ng-class="section.icon"></i>
|
||||
@ -21,12 +21,12 @@
|
||||
|
||||
<div ng-if="section.expanded">
|
||||
<a ng-repeat="item in section.items" class="search-item search-item--indent" ng-class="{'selected': item.selected}" ng-href="{{::item.url}}" >
|
||||
<div ng-click="ctrl.toggleSelection(item, $event)">
|
||||
<div ng-click="ctrl.toggleSelection(item, $event)" class="center-vh">
|
||||
<gf-form-checkbox
|
||||
ng-show="ctrl.editable"
|
||||
on-change="ctrl.selectionChanged()"
|
||||
checked="item.checked"
|
||||
switch-class="gf-form-switch--transparent gf-form-switch--search-result__item">
|
||||
switch-class="gf-form-checkbox--transparent">
|
||||
</gf-form-checkbox>
|
||||
</div>
|
||||
<span class="search-item__icon">
|
||||
|
@ -79,10 +79,6 @@ export class DataSourcePicker extends PureComponent<Props, State> {
|
||||
/>
|
||||
<i className="gf-form-input-icon fa fa-search" />
|
||||
</label>
|
||||
<div className="p-l-1">
|
||||
<button className="btn toggle-btn gf-form-btn active">All</button>
|
||||
<button className="btn toggle-btn gf-form-btn">Favorites</button>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -8,11 +8,7 @@ import { DashboardModel } from '../dashboard_model';
|
||||
import './../../panel/metrics_tab';
|
||||
import config from 'app/core/config';
|
||||
import { QueryInspector } from './QueryInspector';
|
||||
import { Switch } from 'app/core/components/Switch/Switch';
|
||||
import { Input } from 'app/core/components/Form';
|
||||
import { InputStatus, EventsWithValidation } from 'app/core/components/Form/Input';
|
||||
import { isValidTimeSpan } from 'app/core/utils/rangeutil';
|
||||
import { ValidationEvents } from 'app/types';
|
||||
import { TimeRangeOptions } from './TimeRangeOptions';
|
||||
|
||||
// Services
|
||||
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
||||
@ -43,20 +39,6 @@ interface LoadingPlaceholderProps {
|
||||
|
||||
const LoadingPlaceholder: SFC<LoadingPlaceholderProps> = ({ text }) => <h2>{text}</h2>;
|
||||
|
||||
const timeRangeValidationEvents: ValidationEvents = {
|
||||
[EventsWithValidation.onBlur]: [
|
||||
{
|
||||
rule: value => {
|
||||
if (!value) {
|
||||
return true;
|
||||
}
|
||||
return isValidTimeSpan(value);
|
||||
},
|
||||
errorMessage: 'Not a valid timespan',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export class QueriesTab extends PureComponent<Props, State> {
|
||||
element: any;
|
||||
component: AngularComponent;
|
||||
@ -220,10 +202,19 @@ export class QueriesTab extends PureComponent<Props, State> {
|
||||
},
|
||||
};
|
||||
|
||||
return Object.keys(queryOptions).map(key => {
|
||||
const dsOptions = queryOptions
|
||||
? Object.keys(queryOptions).map(key => {
|
||||
const options = allOptions[key];
|
||||
return <DataSourceOption key={key} {...options} onChange={onChangeFn(allOptions[key].panelKey || key)} />;
|
||||
});
|
||||
})
|
||||
: null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<TimeRangeOptions panel={this.props.panel} />
|
||||
{dsOptions}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
renderQueryInspector = () => {
|
||||
@ -236,42 +227,9 @@ export class QueriesTab extends PureComponent<Props, State> {
|
||||
return isLoading ? <LoadingPlaceholder text="Loading help..." /> : helpHtml;
|
||||
};
|
||||
|
||||
emptyToNull = (value: string) => {
|
||||
return value === '' ? null : value;
|
||||
};
|
||||
|
||||
onOverrideTime = (evt, status: InputStatus) => {
|
||||
const { value } = evt.target;
|
||||
const { panel } = this.props;
|
||||
const emptyToNullValue = this.emptyToNull(value);
|
||||
if (status === InputStatus.Valid && panel.timeFrom !== emptyToNullValue) {
|
||||
panel.timeFrom = emptyToNullValue;
|
||||
panel.refresh();
|
||||
}
|
||||
};
|
||||
|
||||
onTimeShift = (evt, status: InputStatus) => {
|
||||
const { value } = evt.target;
|
||||
const { panel } = this.props;
|
||||
const emptyToNullValue = this.emptyToNull(value);
|
||||
if (status === InputStatus.Valid && panel.timeShift !== emptyToNullValue) {
|
||||
panel.timeShift = emptyToNullValue;
|
||||
panel.refresh();
|
||||
}
|
||||
};
|
||||
|
||||
onToggleTimeOverride = () => {
|
||||
const { panel } = this.props;
|
||||
panel.hideTimeOverride = !panel.hideTimeOverride;
|
||||
panel.refresh();
|
||||
};
|
||||
|
||||
render() {
|
||||
const { currentDatasource } = this.state;
|
||||
const hideTimeOverride = this.props.panel.hideTimeOverride;
|
||||
console.log('hideTimeOverride', hideTimeOverride);
|
||||
const { hasQueryHelp, queryOptions } = currentDatasource.meta;
|
||||
const hasQueryOptions = !!queryOptions;
|
||||
const { hasQueryHelp } = currentDatasource.meta;
|
||||
const dsInformation = {
|
||||
title: currentDatasource.name,
|
||||
imgSrc: currentDatasource.meta.info.logos.small,
|
||||
@ -302,7 +260,7 @@ export class QueriesTab extends PureComponent<Props, State> {
|
||||
const options = {
|
||||
title: '',
|
||||
icon: 'fa fa-cog',
|
||||
disabled: !hasQueryOptions,
|
||||
disabled: false,
|
||||
render: this.renderOptions,
|
||||
};
|
||||
|
||||
@ -310,52 +268,6 @@ export class QueriesTab extends PureComponent<Props, State> {
|
||||
<EditorTabBody heading="Queries" main={dsInformation} toolbarItems={[options, queryInspector, dsHelp]}>
|
||||
<>
|
||||
<div ref={element => (this.element = element)} style={{ width: '100%' }} />
|
||||
|
||||
<h5 className="section-heading">Time Range</h5>
|
||||
|
||||
<div className="gf-form-group">
|
||||
<div className="gf-form">
|
||||
<span className="gf-form-label">
|
||||
<i className="fa fa-clock-o" />
|
||||
</span>
|
||||
|
||||
<span className="gf-form-label width-12">Override relative time</span>
|
||||
<span className="gf-form-label width-6">Last</span>
|
||||
<Input
|
||||
type="text"
|
||||
className="gf-form-input max-width-8"
|
||||
placeholder="1h"
|
||||
onBlur={this.onOverrideTime}
|
||||
validationEvents={timeRangeValidationEvents}
|
||||
hideErrorMessage={true}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="gf-form">
|
||||
<span className="gf-form-label">
|
||||
<i className="fa fa-clock-o" />
|
||||
</span>
|
||||
<span className="gf-form-label width-12">Add time shift</span>
|
||||
<span className="gf-form-label width-6">Amount</span>
|
||||
<Input
|
||||
type="text"
|
||||
className="gf-form-input max-width-8"
|
||||
placeholder="1h"
|
||||
onBlur={this.onTimeShift}
|
||||
validationEvents={timeRangeValidationEvents}
|
||||
hideErrorMessage={true}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<span className="gf-form-label">
|
||||
<i className="fa fa-clock-o" />
|
||||
</span>
|
||||
</div>
|
||||
<Switch label="Hide time override info" checked={hideTimeOverride} onChange={this.onToggleTimeOverride} />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</EditorTabBody>
|
||||
);
|
||||
|
111
public/app/features/dashboard/dashgrid/TimeRangeOptions.tsx
Normal file
111
public/app/features/dashboard/dashgrid/TimeRangeOptions.tsx
Normal file
@ -0,0 +1,111 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Switch } from 'app/core/components/Switch/Switch';
|
||||
import { Input } from 'app/core/components/Form';
|
||||
import { isValidTimeSpan } from 'app/core/utils/rangeutil';
|
||||
import { ValidationEvents } from 'app/types';
|
||||
import { EventsWithValidation } from 'app/core/components/Form/Input';
|
||||
import { PanelModel } from '../panel_model';
|
||||
import { InputStatus } from 'app/core/components/Form/Input';
|
||||
|
||||
const timeRangeValidationEvents: ValidationEvents = {
|
||||
[EventsWithValidation.onBlur]: [
|
||||
{
|
||||
rule: value => {
|
||||
if (!value) {
|
||||
return true;
|
||||
}
|
||||
return isValidTimeSpan(value);
|
||||
},
|
||||
errorMessage: 'Not a valid timespan',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const emptyToNull = (value: string) => {
|
||||
return value === '' ? null : value;
|
||||
};
|
||||
|
||||
interface Props {
|
||||
panel: PanelModel;
|
||||
}
|
||||
|
||||
export class TimeRangeOptions extends PureComponent<Props> {
|
||||
onOverrideTime = (evt, status: InputStatus) => {
|
||||
const { value } = evt.target;
|
||||
const { panel } = this.props;
|
||||
const emptyToNullValue = emptyToNull(value);
|
||||
if (status === InputStatus.Valid && panel.timeFrom !== emptyToNullValue) {
|
||||
panel.timeFrom = emptyToNullValue;
|
||||
panel.refresh();
|
||||
}
|
||||
};
|
||||
|
||||
onTimeShift = (evt, status: InputStatus) => {
|
||||
const { value } = evt.target;
|
||||
const { panel } = this.props;
|
||||
const emptyToNullValue = emptyToNull(value);
|
||||
if (status === InputStatus.Valid && panel.timeShift !== emptyToNullValue) {
|
||||
panel.timeShift = emptyToNullValue;
|
||||
panel.refresh();
|
||||
}
|
||||
};
|
||||
|
||||
onToggleTimeOverride = () => {
|
||||
const { panel } = this.props;
|
||||
panel.hideTimeOverride = !panel.hideTimeOverride;
|
||||
panel.refresh();
|
||||
};
|
||||
|
||||
render = () => {
|
||||
const hideTimeOverride = this.props.panel.hideTimeOverride;
|
||||
return (
|
||||
<>
|
||||
<h5 className="section-heading">Time Range</h5>
|
||||
|
||||
<div className="gf-form-group">
|
||||
<div className="gf-form">
|
||||
<span className="gf-form-label">
|
||||
<i className="fa fa-clock-o" />
|
||||
</span>
|
||||
|
||||
<span className="gf-form-label width-12">Override relative time</span>
|
||||
<span className="gf-form-label width-6">Last</span>
|
||||
<Input
|
||||
type="text"
|
||||
className="gf-form-input max-width-8"
|
||||
placeholder="1h"
|
||||
onBlur={this.onOverrideTime}
|
||||
validationEvents={timeRangeValidationEvents}
|
||||
hideErrorMessage={true}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="gf-form">
|
||||
<span className="gf-form-label">
|
||||
<i className="fa fa-clock-o" />
|
||||
</span>
|
||||
<span className="gf-form-label width-12">Add time shift</span>
|
||||
<span className="gf-form-label width-6">Amount</span>
|
||||
<Input
|
||||
type="text"
|
||||
className="gf-form-input max-width-8"
|
||||
placeholder="1h"
|
||||
onBlur={this.onTimeShift}
|
||||
validationEvents={timeRangeValidationEvents}
|
||||
hideErrorMessage={true}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<span className="gf-form-label">
|
||||
<i className="fa fa-clock-o" />
|
||||
</span>
|
||||
</div>
|
||||
<Switch label="Hide time override info" checked={hideTimeOverride} onChange={this.onToggleTimeOverride} />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
}
|
@ -84,6 +84,13 @@ class TestDataDatasource {
|
||||
}
|
||||
return this.$q.when(events);
|
||||
}
|
||||
|
||||
testDatasource() {
|
||||
return Promise.resolve({
|
||||
status: 'success',
|
||||
message: 'Data source is working',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export { TestDataDatasource };
|
||||
|
@ -79,7 +79,7 @@ $brand-gradient: linear-gradient(
|
||||
);
|
||||
|
||||
$page-gradient: linear-gradient(180deg, #222426 10px, rgb(22, 23, 25) 100px);
|
||||
$edit-gradient: linear-gradient(180deg, rgb(22, 23, 25) 00px, #090909 60%);
|
||||
$edit-gradient: linear-gradient(180deg, rgb(22, 23, 25) 50%, #090909);
|
||||
|
||||
// Links
|
||||
// -------------------------
|
||||
@ -383,3 +383,6 @@ $panel-editor-viz-item-bg: $black;
|
||||
$panel-editor-tabs-line-color: #e3e3e3;
|
||||
$panel-editor-viz-item-bg-hover: darken($blue, 47%);
|
||||
$panel-editor-viz-item-bg-hover-active: darken($orange, 45%);
|
||||
|
||||
$panel-grid-placeholder-bg: darken($blue, 47%);
|
||||
$panel-grid-placeholder-shadow: 0 0 4px $blue;
|
||||
|
@ -393,3 +393,6 @@ $panel-editor-viz-item-bg: $white;
|
||||
$panel-editor-tabs-line-color: $dark-5;
|
||||
$panel-editor-viz-item-bg-hover: lighten($blue, 62%);
|
||||
$panel-editor-viz-item-bg-hover-active: lighten($orange, 34%);
|
||||
|
||||
$panel-grid-placeholder-bg: lighten($blue, 62%);
|
||||
$panel-grid-placeholder-shadow: 0 0 4px $blue-light;
|
||||
|
@ -57,6 +57,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
.react-grid-item.react-grid-placeholder {
|
||||
box-shadow: $panel-grid-placeholder-shadow;
|
||||
background: $panel-grid-placeholder-bg;
|
||||
z-index: 0;
|
||||
opacity: unset;
|
||||
}
|
||||
|
||||
.theme-dark {
|
||||
.react-grid-item > .react-resizable-handle::after {
|
||||
border-right: 2px solid $gray-1;
|
||||
|
@ -12,6 +12,7 @@
|
||||
height: 35px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.gf-form-button-row {
|
||||
padding-top: 0;
|
||||
|
@ -141,19 +141,6 @@ $input-border: 1px solid $input-border-color;
|
||||
@include border-radius($label-border-radius-sm);
|
||||
}
|
||||
|
||||
.gf-form-checkbox {
|
||||
flex-shrink: 0;
|
||||
padding: $input-padding-y $input-padding-x;
|
||||
line-height: $input-line-height;
|
||||
|
||||
.checkbox-label {
|
||||
display: inline;
|
||||
cursor: pointer;
|
||||
padding: $input-padding-y 0.4rem;
|
||||
line-height: $input-line-height;
|
||||
}
|
||||
}
|
||||
|
||||
.gf-form-textarea {
|
||||
max-width: 650px;
|
||||
}
|
||||
|
@ -159,8 +159,6 @@
|
||||
transition: transform 1 ease;
|
||||
|
||||
&:hover {
|
||||
//background: $card-background-hover;
|
||||
transform: scale(1.05);
|
||||
box-shadow: $panel-editor-viz-item-shadow-hover;
|
||||
background: $panel-editor-viz-item-bg-hover;
|
||||
border: $panel-editor-viz-item-border-hover;
|
||||
@ -171,7 +169,6 @@
|
||||
border: 1px solid $orange;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.05);
|
||||
box-shadow: 0 0 6px $orange;
|
||||
border: 1px solid $orange;
|
||||
background: $panel-editor-viz-item-bg-hover-active;
|
||||
@ -268,11 +265,9 @@
|
||||
height: 44px;
|
||||
|
||||
&:hover {
|
||||
background: $card-background-hover;
|
||||
transform: scaleY(1.1);
|
||||
box-shadow: $panel-editor-viz-item-shadow-hover;
|
||||
background: $panel-editor-viz-item-bg-hover;
|
||||
border: $panel-editor-viz-item-border-hover;
|
||||
box-shadow: $panel-editor-viz-item-shadow-hover;
|
||||
}
|
||||
|
||||
&--selected {
|
||||
|
@ -78,6 +78,9 @@ input:checked + .gf-form-switch__slider::before {
|
||||
border: 1px solid $input-border-color;
|
||||
border-left: none;
|
||||
border-radius: $input-border-radius;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
input {
|
||||
opacity: 0;
|
||||
@ -88,25 +91,14 @@ input:checked + .gf-form-switch__slider::before {
|
||||
&--transparent {
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
&--search-result__section {
|
||||
width: 3.05rem;
|
||||
width: 20px;
|
||||
height: auto;
|
||||
position: relative;
|
||||
top: -5px;
|
||||
left: 3px;
|
||||
}
|
||||
|
||||
&--search-result__item {
|
||||
width: 2.7rem;
|
||||
height: auto;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
padding-left: 7px;
|
||||
}
|
||||
|
||||
&--table-cell {
|
||||
width: 40px;
|
||||
width: 20px;
|
||||
background: transparent;
|
||||
height: auto;
|
||||
border: none;
|
||||
@ -116,17 +108,14 @@ input:checked + .gf-form-switch__slider::before {
|
||||
}
|
||||
|
||||
.gf-form-switch__checkbox {
|
||||
position: absolute;
|
||||
left: 16px;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
border-radius: 3px;
|
||||
border: $checkbox-border;
|
||||
background: $checkbox-bg;
|
||||
top: 8px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
input:checked + .gf-form-switch__checkbox::before {
|
||||
|
@ -25,6 +25,7 @@ div.flot-text {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
margin: 0;
|
||||
|
||||
.panel-container {
|
||||
border: none;
|
||||
z-index: $zindex-sidemenu + 1;
|
||||
|
@ -82,3 +82,10 @@ button.close {
|
||||
.absolute {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.center-vh {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
justify-items: center;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user