Browse Source

Compatibility with grafana 7 #442 (#444)

* fixes to make it work

* todo

* initial ui
master
rozetko 4 years ago committed by GitHub
parent
commit
36a34f982d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      src/panel/graph_panel/controllers/analytic_controller.ts
  2. 21
      src/panel/graph_panel/graph_ctrl.ts
  3. 0
      src/panel/graph_panel/partials/analytic_unit_5.x_6.x.html
  4. 148
      src/panel/graph_panel/partials/analytic_unit_7.x.html
  5. 2
      src/panel/graph_panel/partials/analytic_units_5.x.html
  6. 2
      src/panel/graph_panel/partials/analytic_units_6.x.html
  7. 106
      src/panel/graph_panel/partials/analytic_units_7.x.html
  8. 14
      src/panel/graph_panel/partials/new_analytic_unit_7.x.html
  9. 4
      src/panel/graph_panel/partials/tab_analytics.html

4
src/panel/graph_panel/controllers/analytic_controller.ts

@ -631,6 +631,10 @@ export class AnalyticController {
get inspectedAnalyticUnit(): AnalyticUnit | null {
for(let analyticUnit of this.analyticUnits) {
// TODO: inspect flag isn't persisted on the server,
// so it resets when closing panel editor in Grafana 7
// (because AnalyticController is re-created)
// P.S. it works in Grafana 5 and 6
if(analyticUnit.inspect) {
return analyticUnit;
}

21
src/panel/graph_panel/graph_ctrl.ts

@ -189,7 +189,9 @@ class GraphCtrl extends MetricsPanelCtrl {
throw new Error('Cannot parse grafana url');
}
this._panelId = `${this.dashboard.uid}/${this.panel.id}`;
// editSourceId is a true panel ID in panel editor mode in Grafana 7.x
const panelId = this.panel.editSourceId || this.panel.id;
this._panelId = `${this.dashboard.uid}/${panelId}`;
this._datasources = {};
this._dataTimerange = {};
}
@ -469,7 +471,7 @@ class GraphCtrl extends MetricsPanelCtrl {
}
for(let series of this.seriesList) {
if(series.unit) {
if(series.unit !== undefined && series.yaxis !== undefined) {
this.panel.yaxes[series.yaxis - 1].format = series.unit;
}
}
@ -670,26 +672,29 @@ class GraphCtrl extends MetricsPanelCtrl {
return `${this.panelPath}/partials`;
}
get grafanaVersion() {
get grafanaVersion(): string | null {
if(_.has(window, 'grafanaBootData.settings.buildInfo.version')) {
return window.grafanaBootData.settings.buildInfo.version;
}
return null;
}
getTemplatePath(filename: string) {
getTemplatePath(filename: string): string {
const grafanaVersion = this.grafanaVersion;
if(grafanaVersion === null) {
throw new Error('Unknown Grafana version');
}
if(grafanaVersion[0] === '5') {
switch(grafanaVersion[0]) {
case '5':
return `${this.partialsPath}/${filename}_5.x.html`;
}
if(grafanaVersion[0] === '6') {
case '6':
return `${this.partialsPath}/${filename}_6.x.html`;
}
case '7':
return `${this.partialsPath}/${filename}_7.x.html`;
default:
throw new Error(`Unsupported Grafana version: ${grafanaVersion}`);
}
}
createNew() {
this.analyticsController.createNew();

0
src/panel/graph_panel/partials/analytic_unit.html → src/panel/graph_panel/partials/analytic_unit_5.x_6.x.html

148
src/panel/graph_panel/partials/analytic_unit_7.x.html

@ -0,0 +1,148 @@
<div class="section gf-form-group">
<div class="gf-form">
<label class="gf-form-label query-keyword">
Name
</label>
<input
type="text" class="gf-form-input"
ng-model="analyticUnit.name"
ng-blur="ctrl.onAnalyticUnitChange(analyticUnit)"
>
</div>
<div class="gf-form">
<label class="gf-form-label query-keyword"> Type </label>
<div class="gf-form-select-wrapper">
<select class="gf-form-input"
ng-model="analyticUnit.type"
ng-options="type.value as type.name for type in ctrl.analyticUnitTypes[analyticUnit.detectorType]"
ng-disabled="true"
/>
</div>
</div>
</div>
<div class="section gf-form-group">
<div class="gf-form">
<label class="gf-form-label query-keyword"> Positive Color </label>
<label class="gf-form-label">
<color-picker
color="analyticUnit.labeledColor"
onChange="ctrl.onColorChange.bind(ctrl, analyticUnit.id, false)"
/>
</label>
</div>
<div class="gf-form"
ng-if="analyticUnit.detectorType === 'pattern' || analyticUnit.detectorType === 'anomaly'"
>
<label class="gf-form-label query-keyword"> Negative Color </label>
<label class="gf-form-label">
<color-picker
color="analyticUnit.deletedColor"
onChange="ctrl.onColorChange.bind(ctrl, analyticUnit.id, true)"
/>
</label>
</div>
</div>
<div class="section gf-form-group" ng-if="analyticUnit.detectorType === 'threshold'">
<!-- TODO: move analytic-unit-specific fields rendering to class -->
<div class="gf-form">
<label class="gf-form-label query-keyword"> Condition </label>
<select class="gf-form-input"
ng-class="{
'width-5': analyticUnit.condition !== 'NO_DATA',
'width-9': analyticUnit.condition === 'NO_DATA'
}"
ng-model="analyticUnit.condition"
ng-options="type for type in ctrl.analyticsController.conditions"
ng-change="ctrl.onAnalyticUnitChange(analyticUnit)"
/>
<input class="gf-form-input"
ng-if="analyticUnit.condition !== 'NO_DATA'"
type="number"
ng-model="analyticUnit.value"
ng-blur="ctrl.onAnalyticUnitChange(analyticUnit)"
/>
</div>
</div>
<div class="section gf-form-group" ng-if="analyticUnit.detectorType === 'anomaly'">
<div class="gf-form">
<label class="gf-form-label query-keyword">
Alpha
&nbsp;
<i class="fa fa-info" bs-tooltip="'Takes value from 0 to 1. Less Alpha means smoother bounds'"></i>
</label>
<input class="gf-form-input"
min="0"
max="1"
type="number"
ng-model="analyticUnit.alpha"
ng-blur="ctrl.onAnalyticUnitChange(analyticUnit)"
/>
</div>
<div class="gf-form">
<label class="gf-form-label query-keyword">
Сonfidence
&nbsp;
<i class="fa fa-info" bs-tooltip="'Bounds for the metric'"></i>
</label>
<input class="gf-form-input"
min="0"
type="number"
ng-model="analyticUnit.confidence"
ng-blur="ctrl.onAnalyticUnitChange(analyticUnit)"
/>
</div>
</div>
<div class="section gf-form-group" ng-if="analyticUnit.detectorType === 'anomaly'">
<div class="gf-form">
<gf-form-switch
class="gf-form"
label="Seasonality"
label-class="query-keyword"
on-change="ctrl.onAnalyticUnitChange(analyticUnit)"
checked="analyticUnit.hasSeasonality"
/>
</div>
<div class="gf-form" ng-if="analyticUnit.hasSeasonality">
<label class="gf-form-label query-keyword"> Seasonality Period </label>
<input
type="number" class="gf-form-input"
ng-init="seasonalityValue = analyticUnit.seasonalityPeriod.value"
ng-model="seasonalityValue"
ng-blur="ctrl.onSeasonalityChange(analyticUnit.id, seasonalityValue)"
min="0"
>
</div>
<div class="gf-form" ng-if="analyticUnit.hasSeasonality">
<div class="gf-form-select-wrapper">
<!-- TODO: move periods from ng-options -->
<select class="gf-form-input"
ng-model="analyticUnit.seasonalityPeriod.unit"
ng-change="ctrl.onSeasonalityChange(analyticUnit.id)"
ng-options="type for type in ['seconds', 'minutes', 'hours', 'days', 'years']"
/>
</div>
</div>
</div>
<div class="section gf-form-group" ng-if="analyticUnit.detectorType === 'anomaly'">
<div class="gf-form">
<label class="gf-form-label query-keyword"> Enabled bounds </label>
<div class="gf-form-select-wrapper">
<select class="gf-form-input"
ng-model="analyticUnit.enableBounds"
ng-change="ctrl.onAnalyticUnitChange(analyticUnit)"
ng-options="bound.value as bound.name for bound in ctrl.boundTypes"
/>
</div>
</div>
</div>

2
src/panel/graph_panel/partials/analytic_units_5.x.html

@ -48,7 +48,7 @@
</div>
<div class="gf-form-query-content" ng-if="!analyticUnit.collapsed">
<ng-include src="ctrl.partialsPath + '/analytic_unit.html'"></ng-include>
<ng-include src="ctrl.partialsPath + '/analytic_unit_5.x_6.x.html'"></ng-include>
</div>
<div class="gf-form">

2
src/panel/graph_panel/partials/analytic_units_6.x.html

@ -129,6 +129,6 @@
class="query-editor-row__body gf-form-query"
ng-class="analyticUnit.collapsed && 'query-editor-row__body--collapsed'"
>
<ng-include src="ctrl.partialsPath + '/analytic_unit.html'"></ng-include>
<ng-include src="ctrl.partialsPath + '/analytic_unit_5.x_6.x.html'"></ng-include>
</div>
</div>

106
src/panel/graph_panel/partials/analytic_units_7.x.html

@ -0,0 +1,106 @@
<div class="query-editor-row" ng-repeat="analyticUnit in ctrl.analyticsController.analyticUnits">
<div class="query-editor-row__header">
<div class="query-editor-row__ref-id" ng-click="ctrl.onToggleCollapsed(analyticUnit.id)">
<i class="fa fa-fw fa-caret-down" ng-hide="analyticUnit.collapsed"></i>
<i class="fa fa-fw fa-caret-right" ng-show="analyticUnit.collapsed"></i>
<span>{{analyticUnit.name}}</span>
<em class="query-editor-row__context-info">({{analyticUnit.id}})</em>
</div>
<div
class="query-editor-row__collapsed-text"
style="line-height: 0px;"
>
&nbsp;
<i ng-if="analyticUnit.status === 'READY'"
class="fa fa-fw fa-check-circle"
bs-tooltip="'Ready'"
></i>
<i ng-if="analyticUnit.status === 'SUCCESS'"
class="fa fa-fw fa-check"
bs-tooltip="'Learning succeeded'"
></i>
<i ng-if="analyticUnit.status === 'LEARNING'"
class="fa fa-fw fa-leanpub"
bs-tooltip="'Learning'"
></i>
<i ng-if="analyticUnit.status === 'DETECTION'"
class="fa fa-fw fa-search"
bs-tooltip="'Detection'"
></i>
<i ng-if="analyticUnit.status === 'PENDING'"
class="fa fa-fw fa-list-ul"
bs-tooltip="'Pending'"
></i>
<i ng-if="analyticUnit.status === 'FAILED'"
class="fa fa-fw fa-exclamation-circle"
bs-tooltip="'Error: ' + analyticUnit.error"
></i>
</div>
</div>
<div
class="gf-form-query"
ng-class="analyticUnit.collapsed && 'query-editor-row__body--collapsed'"
>
<div class="query-editor-row__header">
<button class="query-editor-row__action" ng-click=ctrl.onToggleVisibility(analyticUnit.id)>
<a ng-if="analyticUnit.visible" bs-tooltip="'Hide. It`s visible now.'" class="pointer">
<i class="fa fa-fw fa-eye"></i>
</a>
<a ng-if="!analyticUnit.visible" bs-tooltip="'Show. It`s hidden now.'" class="pointer">
<i class="fa fa-fw fa-eye-slash"></i>
</a>
</button>
<button class="query-editor-row__action" ng-click="ctrl.onToggleInspect(analyticUnit.id)" bs-tooltip="'Inspect Mode'">
<a class="pointer">
<!--use ctrl.pluginPath-->
<img src="public/plugins/corpglory-hastic-app/img/inspect_enabled.svg" class="fa fa-fw"
ng-if="analyticUnit.inspect"></img>
<img src="public/plugins/corpglory-hastic-app/img/inspect_disabled.svg" class="fa fa-fw"
ng-if="!analyticUnit.inspect"></img>
</a>
</button>
<button class="query-editor-row__action" ng-click="ctrl.onRemove(analyticUnit.id)" bs-tooltip="'Delete'">
<a class="pointer">
<i class="fa fa-fw fa-trash"></i>
</a>
</button>
<button class="query-editor-row__action" ng-if="
(analyticUnit.detectorType === 'pattern' ||
(analyticUnit.detectorType === 'anomaly' && analyticUnit.hasSeasonality)) &&
!analyticUnit.selected" bs-tooltip="'Label'">
<a class="pointer" ng-style="analyticUnit.status === 'LEARNING' && { 'cursor': 'not-allowed' }"
ng-click="ctrl.onToggleLabelingMode(analyticUnit.id)" ng-disabled="analyticUnit.status === 'LEARNING'">
<i class="fa fa-fw fa-bar-chart" ng-if="!analyticUnit.saving"></i>
<i class="fa fa-fw fa-spinner fa-spin" ng-if="analyticUnit.saving"></i>
Label
</a>
</button>
<select class="gf-form-input width-11" ng-if="analyticUnit.selected && !analyticUnit.saving"
ng-model="ctrl.analyticsController.labelingMode"
ng-options="type.value as type.name for type in analyticUnit.labelingModes"
ng-disabled="analyticUnit.status === 'LEARNING'" />
<button class="query-editor-row__action" ng-if="analyticUnit.selected && !analyticUnit.saving"
bs-tooltip="'Cancel labeling'">
<a class="pointer" ng-click="ctrl.onCancelLabeling(analyticUnit.id)">
<i class="fa fa-fw fa-ban"></i>
</a>
</button>
<button class="query-editor-row__action" ng-click="ctrl.runDetectInCurrentRange(analyticUnit)"
ng-disabled="analyticUnit.saving" bs-tooltip="'Learn & Detect'">
<a class="pointer">
Apply
</a>
</button>
</div>
<div class="query-editor-row__body">
<ng-include src="ctrl.partialsPath + '/analytic_unit_7.x.html'"></ng-include>
</div>
</div>
</div>

14
src/panel/graph_panel/partials/new_analytic_unit_7.x.html

@ -0,0 +1,14 @@
<div class="query-editor-row">
<div class="query-editor-row__header">
<div class="query-editor-row__ref-id width-25" style="cursor: default;">
<span>New analytic unit</span>
</div>
<div class="query-editor-row__collapsed-text">
</div>
</div>
<div class="query-editor-row__body gf-form-query">
<ng-include src="ctrl.partialsPath + '/new_analytic_unit.html'"></ng-include>
</div>
</div>

4
src/panel/graph_panel/partials/tab_analytics.html

@ -1,7 +1,7 @@
<div class="gf-form-group">
<div class="section gf-form-group">
<div class="gf-form">
<label class="gf-form-label">Select Hastic datasource</label>
<select class="gf-form-input width-15"
<select class="gf-form-input"
ng-model="ctrl.panel.hasticDatasource"
ng-options="ds.id as ds.name for ds in ctrl.hasticDatasources"
ng-change="ctrl.onHasticDatasourceChange()"

Loading…
Cancel
Save