Bläddra i källkod

Chore: No implict any fixes (#17020)

Torkel Ödegaard 6 år sedan
förälder
incheckning
e0b760e08e
53 ändrade filer med 321 tillägg och 241 borttagningar
  1. 2 1
      package.json
  2. 6 0
      packages/grafana-ui/src/types/datasource.ts
  3. 1 1
      public/app/core/components/PasswordStrength.tsx
  4. 1 1
      public/app/core/components/TagFilter/TagBadge.tsx
  5. 14 10
      public/app/core/components/TagFilter/TagFilter.tsx
  6. 2 0
      public/app/core/components/TagFilter/TagOption.tsx
  7. 2 3
      public/app/core/components/TagFilter/TagValue.tsx
  8. 2 2
      public/app/core/components/ToggleButtonGroup/ToggleButtonGroup.tsx
  9. 2 1
      public/app/core/components/dashboard_selector.ts
  10. 3 2
      public/app/core/components/info_popover.ts
  11. 4 3
      public/app/core/components/org_switcher.ts
  12. 1 1
      public/app/core/components/sql_part/sql_part.ts
  13. 13 13
      public/app/core/components/sql_part/sql_part_editor.ts
  14. 1 1
      public/app/core/components/switch.ts
  15. 1 1
      public/app/core/jquery_extended.ts
  16. 5 5
      public/app/core/logs_model.ts
  17. 1 1
      public/app/core/nav_model_srv.ts
  18. 1 1
      public/app/core/partials.ts
  19. 2 2
      public/app/core/profiler.ts
  20. 1 1
      public/app/core/services/backend_srv.ts
  21. 48 36
      public/app/core/services/segment_srv.ts
  22. 14 9
      public/app/core/table_model.ts
  23. 10 10
      public/app/core/time_series2.ts
  24. 1 1
      public/app/core/utils/connectWithReduxStore.tsx
  25. 11 8
      public/app/features/admin/AdminEditOrgCtrl.ts
  26. 14 10
      public/app/features/admin/AdminEditUserCtrl.ts
  27. 7 4
      public/app/features/admin/AdminListOrgsCtrl.ts
  28. 9 6
      public/app/features/admin/AdminListUsersCtrl.ts
  29. 1 0
      public/app/features/admin/ServerStats.test.tsx
  30. 4 2
      public/app/features/admin/StyleGuideCtrl.ts
  31. 7 5
      public/app/features/admin/index.ts
  32. 1 1
      public/app/features/alerting/AlertRuleItem.test.tsx
  33. 1 0
      public/app/features/alerting/AlertRuleItem.tsx
  34. 31 34
      public/app/features/alerting/AlertTabCtrl.ts
  35. 19 12
      public/app/features/alerting/NotificationsEditCtrl.ts
  36. 7 6
      public/app/features/alerting/NotificationsListCtrl.ts
  37. 3 3
      public/app/features/alerting/StateHistory.tsx
  38. 4 2
      public/app/features/alerting/state/ThresholdMapper.ts
  39. 4 4
      public/app/features/alerting/state/alertDef.ts
  40. 2 2
      public/app/features/alerting/state/reducers.test.ts
  41. 11 7
      public/app/features/alerting/state/reducers.ts
  42. 3 3
      public/app/features/alerting/state/selectors.test.ts
  43. 4 2
      public/app/features/alerting/state/selectors.ts
  44. 1 1
      public/app/features/dashboard/dashgrid/PanelChrome.tsx
  45. 1 1
      public/app/features/explore/Explore.tsx
  46. 11 10
      public/app/features/explore/QueryRow.tsx
  47. 1 0
      public/app/features/explore/Wrapper.tsx
  48. 3 6
      public/app/features/org/state/actions.ts
  49. 1 1
      public/app/features/panel/panel_ctrl.ts
  50. 1 1
      public/app/plugins/datasource/prometheus/datasource.ts
  51. 2 2
      public/app/types/alerting.ts
  52. 1 1
      scripts/ci-frontend-metrics.sh
  53. 18 1
      yarn.lock

+ 2 - 1
package.json

@@ -187,6 +187,7 @@
   "dependencies": {
     "@babel/polyfill": "7.2.5",
     "@torkelo/react-select": "2.4.1",
+    "@types/react-redux": "^7.0.8",
     "@types/reselect": "2.2.0",
     "angular": "1.6.6",
     "angular-bindonce": "0.3.1",
@@ -201,8 +202,8 @@
     "d3": "4.13.0",
     "d3-scale-chromatic": "1.3.3",
     "eventemitter3": "2.0.3",
-    "file-saver": "1.3.8",
     "fast-text-encoding": "^1.0.0",
+    "file-saver": "1.3.8",
     "immutable": "3.8.2",
     "jquery": "3.4.0",
     "lodash": "4.17.11",

+ 6 - 0
packages/grafana-ui/src/types/datasource.ts

@@ -78,6 +78,7 @@ export interface DataSourcePluginMeta extends PluginMeta {
   logs?: boolean;
   explore?: boolean;
   annotations?: boolean;
+  alerting?: boolean;
   mixed?: boolean;
   hasQueryHelp?: boolean;
   category?: string;
@@ -181,6 +182,11 @@ export abstract class DataSourceApi<
    * static information about the datasource
    */
   meta?: DataSourcePluginMeta;
+
+  /**
+   * Used by alerting to check if query contains template variables
+   */
+  targetContainsTemplate?(query: TQuery): boolean;
 }
 
 export abstract class ExploreDataSourceApi<

+ 1 - 1
public/app/core/components/PasswordStrength.tsx

@@ -5,7 +5,7 @@ export interface Props {
 }
 
 export class PasswordStrength extends React.Component<Props, any> {
-  constructor(props) {
+  constructor(props: Props) {
     super(props);
   }
 

+ 1 - 1
public/app/core/components/TagFilter/TagBadge.tsx

@@ -9,7 +9,7 @@ export interface Props {
 }
 
 export class TagBadge extends React.Component<Props, any> {
-  constructor(props) {
+  constructor(props: Props) {
     super(props);
   }
 

+ 14 - 10
public/app/core/components/TagFilter/TagFilter.tsx

@@ -1,10 +1,14 @@
+// Libraries
 import React from 'react';
-import { NoOptionsMessage, IndicatorsContainer, resetSelectStyles } from '@grafana/ui';
+// @ts-ignore
+import { components } from '@torkelo/react-select';
+// @ts-ignore
 import AsyncSelect from '@torkelo/react-select/lib/Async';
 
+// Components
 import { TagOption } from './TagOption';
 import { TagBadge } from './TagBadge';
-import { components } from '@torkelo/react-select';
+import { NoOptionsMessage, IndicatorsContainer, resetSelectStyles } from '@grafana/ui';
 import { escapeStringForRegex } from '../FilterInput/FilterInput';
 
 export interface Props {
@@ -16,12 +20,12 @@ export interface Props {
 export class TagFilter extends React.Component<Props, any> {
   inlineTags: boolean;
 
-  constructor(props) {
+  constructor(props: Props) {
     super(props);
   }
 
-  onLoadOptions = query => {
-    return this.props.tagOptions().then(options => {
+  onLoadOptions = (query: string) => {
+    return this.props.tagOptions().then((options: any[]) => {
       return options.map(option => ({
         value: option.term,
         label: option.term,
@@ -47,11 +51,11 @@ export class TagFilter extends React.Component<Props, any> {
       placeholder: 'Tags',
       loadingMessage: () => 'Loading...',
       noOptionsMessage: () => 'No tags found',
-      getOptionValue: i => i.value,
-      getOptionLabel: i => i.label,
+      getOptionValue: (i: any) => i.value,
+      getOptionLabel: (i: any) => i.label,
       value: tags,
       styles: resetSelectStyles(),
-      filterOption: (option, searchQuery) => {
+      filterOption: (option: any, searchQuery: string) => {
         const regex = RegExp(escapeStringForRegex(searchQuery), 'i');
         return regex.test(option.value);
       },
@@ -59,10 +63,10 @@ export class TagFilter extends React.Component<Props, any> {
         Option: TagOption,
         IndicatorsContainer,
         NoOptionsMessage,
-        MultiValueLabel: () => {
+        MultiValueLabel: (): any => {
           return null; // We want the whole tag to be clickable so we use MultiValueRemove instead
         },
-        MultiValueRemove: props => {
+        MultiValueRemove: (props: any) => {
           const { data } = props;
 
           return (

+ 2 - 0
public/app/core/components/TagFilter/TagOption.tsx

@@ -1,4 +1,6 @@
+// Libraries
 import React from 'react';
+// @ts-ignore
 import { components } from '@torkelo/react-select';
 import { OptionProps } from 'react-select/lib/components/Option';
 import { TagBadge } from './TagBadge';

+ 2 - 3
public/app/core/components/TagFilter/TagValue.tsx

@@ -9,18 +9,17 @@ export interface Props {
 }
 
 export class TagValue extends React.Component<Props, any> {
-  constructor(props) {
+  constructor(props: Props) {
     super(props);
     this.onClick = this.onClick.bind(this);
   }
 
-  onClick(event) {
+  onClick(event: React.SyntheticEvent) {
     this.props.onRemove(this.props.value, event);
   }
 
   render() {
     const { value } = this.props;
-
     return <TagBadge label={value.label} removeIcon={false} count={0} onClick={this.onClick} />;
   }
 }

+ 2 - 2
public/app/core/components/ToggleButtonGroup/ToggleButtonGroup.tsx

@@ -21,7 +21,7 @@ export default class ToggleButtonGroup extends PureComponent<ToggleButtonGroupPr
 }
 
 interface ToggleButtonProps {
-  onChange?: (value) => void;
+  onChange?: (value: any) => void;
   selected?: boolean;
   value: any;
   className?: string;
@@ -37,7 +37,7 @@ export const ToggleButton: FC<ToggleButtonProps> = ({
   tooltip,
   onChange,
 }) => {
-  const onClick = event => {
+  const onClick = (event: React.SyntheticEvent) => {
     event.stopPropagation();
     if (onChange) {
       onChange(value);

+ 2 - 1
public/app/core/components/dashboard_selector.ts

@@ -1,4 +1,5 @@
 import coreModule from 'app/core/core_module';
+import { BackendSrv } from '../services/backend_srv';
 
 const template = `
 <select class="gf-form-input" ng-model="ctrl.model" ng-options="f.value as f.text for f in ctrl.options"></select>
@@ -9,7 +10,7 @@ export class DashboardSelectorCtrl {
   options: any;
 
   /** @ngInject */
-  constructor(private backendSrv) {}
+  constructor(private backendSrv: BackendSrv) {}
 
   $onInit() {
     this.options = [{ value: 0, text: 'Default' }];

+ 3 - 2
public/app/core/components/info_popover.ts

@@ -1,5 +1,6 @@
 import _ from 'lodash';
 import coreModule from 'app/core/core_module';
+// @ts-ignore
 import Drop from 'tether-drop';
 
 export function infoPopover() {
@@ -7,7 +8,7 @@ export function infoPopover() {
     restrict: 'E',
     template: '<i class="fa fa-info-circle"></i>',
     transclude: true,
-    link: (scope, elem, attrs, ctrl, transclude) => {
+    link: (scope: any, elem: any, attrs: any, transclude: any) => {
       const offset = attrs.offset || '0 -10px';
       const position = attrs.position || 'right middle';
       let classes = 'drop-help drop-hide-out-of-bounds';
@@ -23,7 +24,7 @@ export function infoPopover() {
         elem.addClass('gf-form-help-icon--' + attrs.mode);
       }
 
-      transclude((clone, newScope) => {
+      transclude((clone: any, newScope: any) => {
         const content = document.createElement('div');
         content.className = 'markdown-html';
 

+ 4 - 3
public/app/core/components/org_switcher.ts

@@ -1,6 +1,7 @@
 import coreModule from 'app/core/core_module';
 import { contextSrv } from 'app/core/services/context_srv';
 import config from 'app/core/config';
+import { BackendSrv } from '../services/backend_srv';
 
 const template = `
 <div class="modal-body">
@@ -47,18 +48,18 @@ export class OrgSwitchCtrl {
   currentOrgId: any;
 
   /** @ngInject */
-  constructor(private backendSrv) {
+  constructor(private backendSrv: BackendSrv) {
     this.currentOrgId = contextSrv.user.orgId;
     this.getUserOrgs();
   }
 
   getUserOrgs() {
-    this.backendSrv.get('/api/user/orgs').then(orgs => {
+    this.backendSrv.get('/api/user/orgs').then((orgs: any) => {
       this.orgs = orgs;
     });
   }
 
-  setUsingOrg(org) {
+  setUsingOrg(org: any) {
     return this.backendSrv.post('/api/user/using/' + org.orgId).then(() => {
       this.setWindowLocation(config.appSubUrl + (config.appSubUrl.endsWith('/') ? '' : '/') + '?orgId=' + org.orgId);
     });

+ 1 - 1
public/app/core/components/sql_part/sql_part.ts

@@ -61,7 +61,7 @@ export class SqlPart {
     this.params = part.params;
   }
 
-  updateParam(strValue, index) {
+  updateParam(strValue: string, index: number) {
     // handle optional parameters
     if (strValue === '' && this.def.params[index].optional) {
       this.params.splice(index, 1);

+ 13 - 13
public/app/core/components/sql_part/sql_part_editor.ts

@@ -14,7 +14,7 @@ const template = `
 `;
 
 /** @ngInject */
-export function sqlPartEditorDirective($compile, templateSrv) {
+export function sqlPartEditorDirective(templateSrv: any) {
   const paramTemplate = '<input type="text" class="hide input-mini"></input>';
 
   return {
@@ -25,16 +25,16 @@ export function sqlPartEditorDirective($compile, templateSrv) {
       handleEvent: '&',
       debounce: '@',
     },
-    link: function postLink($scope, elem) {
+    link: function postLink($scope: any, elem: any) {
       const part = $scope.part;
       const partDef = part.def;
       const $paramsContainer = elem.find('.query-part-parameters');
       const debounceLookup = $scope.debounce;
-      let cancelBlur = null;
+      let cancelBlur: any = null;
 
       $scope.partActions = [];
 
-      function clickFuncParam(this: any, paramIndex) {
+      function clickFuncParam(this: any, paramIndex: number) {
         /*jshint validthis:true */
         const $link = $(this);
         const $input = $link.next();
@@ -54,13 +54,13 @@ export function sqlPartEditorDirective($compile, templateSrv) {
         }
       }
 
-      function inputBlur($input, paramIndex) {
+      function inputBlur($input: JQuery, paramIndex: number) {
         cancelBlur = setTimeout(() => {
           switchToLink($input, paramIndex);
         }, 200);
       }
 
-      function switchToLink($input, paramIndex) {
+      function switchToLink($input: JQuery, paramIndex: number) {
         /*jshint validthis:true */
         const $link = $input.prev();
         const newValue = $input.val();
@@ -78,7 +78,7 @@ export function sqlPartEditorDirective($compile, templateSrv) {
         $link.show();
       }
 
-      function inputKeyPress(this: any, paramIndex, e) {
+      function inputKeyPress(this: any, paramIndex: number, e: any) {
         /*jshint validthis:true */
         if (e.which === 13) {
           switchToLink($(this), paramIndex);
@@ -90,12 +90,12 @@ export function sqlPartEditorDirective($compile, templateSrv) {
         this.style.width = (3 + this.value.length) * 8 + 'px';
       }
 
-      function addTypeahead($input, param, paramIndex) {
+      function addTypeahead($input: JQuery, param: any, paramIndex: number) {
         if (!param.options && !param.dynamicLookup) {
           return;
         }
 
-        const typeaheadSource = (query, callback) => {
+        const typeaheadSource = (query: string, callback: any) => {
           if (param.options) {
             let options = param.options;
             if (param.type === 'int') {
@@ -107,7 +107,7 @@ export function sqlPartEditorDirective($compile, templateSrv) {
           }
 
           $scope.$apply(() => {
-            $scope.handleEvent({ $event: { name: 'get-param-options', param: param } }).then(result => {
+            $scope.handleEvent({ $event: { name: 'get-param-options', param: param } }).then((result: any) => {
               const dynamicOptions = _.map(result, op => {
                 return _.escape(op.value);
               });
@@ -128,7 +128,7 @@ export function sqlPartEditorDirective($compile, templateSrv) {
           source: typeaheadSource,
           minLength: 0,
           items: 1000,
-          updater: value => {
+          updater: (value: string) => {
             value = _.unescape(value);
             if (value === part.params[paramIndex]) {
               clearTimeout(cancelBlur);
@@ -152,12 +152,12 @@ export function sqlPartEditorDirective($compile, templateSrv) {
       }
 
       $scope.showActionsMenu = () => {
-        $scope.handleEvent({ $event: { name: 'get-part-actions' } }).then(res => {
+        $scope.handleEvent({ $event: { name: 'get-part-actions' } }).then((res: any) => {
           $scope.partActions = res;
         });
       };
 
-      $scope.triggerPartAction = action => {
+      $scope.triggerPartAction = (action: string) => {
         $scope.handleEvent({ $event: { name: 'action', action: action } });
       };
 

+ 1 - 1
public/app/core/components/switch.ts

@@ -38,7 +38,7 @@ export class SwitchCtrl {
   label: string;
 
   /** @ngInject */
-  constructor($scope, private $timeout) {
+  constructor($scope: any, private $timeout: any) {
     this.show = true;
     this.id = $scope.$id;
   }

+ 1 - 1
public/app/core/jquery_extended.ts

@@ -9,7 +9,7 @@ $.fn.place_tt = (() => {
     offset: 5,
   };
 
-  return function(this: any, x, y, opts) {
+  return function(this: any, x: number, y: number, opts: any) {
     opts = $.extend(true, {}, defaults, opts);
 
     return this.each(() => {

+ 5 - 5
public/app/core/logs_model.ts

@@ -123,7 +123,7 @@ export const LogsParsers: { [name: string]: LogsParser } = {
   JSON: {
     buildMatcher: label => new RegExp(`(?:{|,)\\s*"${label}"\\s*:\\s*"?([\\d\\.]+|[^"]*)"?`),
     getFields: line => {
-      const fields = [];
+      const fields: string[] = [];
       try {
         const parsed = JSON.parse(line);
         _.map(parsed, (value, key) => {
@@ -149,7 +149,7 @@ export const LogsParsers: { [name: string]: LogsParser } = {
   logfmt: {
     buildMatcher: label => new RegExp(`(?:^|\\s)${label}=("[^"]*"|\\S+)`),
     getFields: line => {
-      const fields = [];
+      const fields: string[] = [];
       line.replace(new RegExp(LOGFMT_REGEXP, 'g'), substring => {
         fields.push(substring.trim());
         return '';
@@ -273,9 +273,9 @@ export function makeSeriesForLogs(rows: LogRowModel[], intervalMs: number): Time
   // intervalMs = intervalMs * 10;
 
   // Graph time series by log level
-  const seriesByLevel = {};
+  const seriesByLevel: any = {};
   const bucketSize = intervalMs * 10;
-  const seriesList = [];
+  const seriesList: any[] = [];
 
   for (const row of rows) {
     let series = seriesByLevel[row.logLevel];
@@ -312,7 +312,7 @@ export function makeSeriesForLogs(rows: LogRowModel[], intervalMs: number): Time
   }
 
   return seriesList.map(series => {
-    series.datapoints.sort((a, b) => {
+    series.datapoints.sort((a: number[], b: number[]) => {
       return a[1] - b[1];
     });
 

+ 1 - 1
public/app/core/nav_model_srv.ts

@@ -15,7 +15,7 @@ export class NavModelSrv {
     return _.find(this.navItems, { id: 'cfg' });
   }
 
-  getNav(...args) {
+  getNav(...args: string[]) {
     let children = this.navItems;
     const nav = {
       breadcrumbs: [],

+ 1 - 1
public/app/core/partials.ts

@@ -1,4 +1,4 @@
 let templates = (require as any).context('../', true, /\.html$/);
-templates.keys().forEach(key => {
+templates.keys().forEach((key: string) => {
   templates(key);
 });

+ 2 - 2
public/app/core/profiler.ts

@@ -4,7 +4,7 @@ export class Profiler {
   $rootScope: any;
   window: any;
 
-  init(config, $rootScope) {
+  init(config: any, $rootScope: any) {
     this.$rootScope = $rootScope;
     this.window = window;
 
@@ -13,7 +13,7 @@ export class Profiler {
     }
   }
 
-  renderingCompleted(panelId) {
+  renderingCompleted() {
     // add render counter to root scope
     // used by phantomjs render.js to know when panel has rendered
     this.panelsRendered = (this.panelsRendered || 0) + 1;

+ 1 - 1
public/app/core/services/backend_srv.ts

@@ -29,7 +29,7 @@ export class BackendSrv {
     return this.request({ method: 'DELETE', url });
   }
 
-  post(url: string, data: any) {
+  post(url: string, data?: any) {
     return this.request({ method: 'POST', url, data });
   }
 

+ 48 - 36
public/app/core/services/segment_srv.ts

@@ -2,39 +2,51 @@ import _ from 'lodash';
 import coreModule from '../core_module';
 
 /** @ngInject */
-export function uiSegmentSrv(this: any, $sce, templateSrv) {
+export function uiSegmentSrv(this: any, $sce: any, templateSrv: any) {
   const self = this;
 
-  function MetricSegment(this: any, options) {
-    if (options === '*' || options.value === '*') {
-      this.value = '*';
-      this.html = $sce.trustAsHtml('<i class="fa fa-asterisk"><i>');
-      this.type = options.type;
-      this.expandable = true;
-      return;
-    }
+  class MetricSegment {
+    value: string;
+    html: any;
+    type: any;
+    expandable: boolean;
+    text: string;
+    cssClass: string;
+    fake: boolean;
+    custom: boolean;
+    selectMode: any;
+
+    constructor(options: any) {
+      if (options === '*' || options.value === '*') {
+        this.value = '*';
+        this.html = $sce.trustAsHtml('<i class="fa fa-asterisk"><i>');
+        this.type = options.type;
+        this.expandable = true;
+        return;
+      }
 
-    if (_.isString(options)) {
-      this.value = options;
-      this.html = $sce.trustAsHtml(templateSrv.highlightVariablesAsHtml(this.value));
-      return;
-    }
+      if (_.isString(options)) {
+        this.value = options;
+        this.html = $sce.trustAsHtml(templateSrv.highlightVariablesAsHtml(this.value));
+        return;
+      }
 
-    // temp hack to work around legacy inconsistency in segment model
-    this.text = options.value;
-
-    this.cssClass = options.cssClass;
-    this.custom = options.custom;
-    this.type = options.type;
-    this.fake = options.fake;
-    this.value = options.value;
-    this.selectMode = options.selectMode;
-    this.type = options.type;
-    this.expandable = options.expandable;
-    this.html = options.html || $sce.trustAsHtml(templateSrv.highlightVariablesAsHtml(this.value));
+      // temp hack to work around legacy inconsistency in segment model
+      this.text = options.value;
+
+      this.cssClass = options.cssClass;
+      this.custom = options.custom;
+      this.type = options.type;
+      this.fake = options.fake;
+      this.value = options.value;
+      this.selectMode = options.selectMode;
+      this.type = options.type;
+      this.expandable = options.expandable;
+      this.html = options.html || $sce.trustAsHtml(templateSrv.highlightVariablesAsHtml(this.value));
+    }
   }
 
-  this.getSegmentForValue = function(value, fallbackText) {
+  this.getSegmentForValue = function(value: string, fallbackText: string) {
     if (value) {
       return this.newSegment(value);
     } else {
@@ -46,38 +58,38 @@ export function uiSegmentSrv(this: any, $sce, templateSrv) {
     return new MetricSegment({ value: 'select measurement', fake: true });
   };
 
-  this.newFake = (text, type, cssClass) => {
+  this.newFake = (text: string, type: string, cssClass: string) => {
     return new MetricSegment({ value: text, fake: true, type: type, cssClass: cssClass });
   };
 
-  this.newSegment = options => {
+  this.newSegment = (options: any) => {
     return new MetricSegment(options);
   };
 
-  this.newKey = key => {
+  this.newKey = (key: string) => {
     return new MetricSegment({ value: key, type: 'key', cssClass: 'query-segment-key' });
   };
 
-  this.newKeyValue = value => {
+  this.newKeyValue = (value: string) => {
     return new MetricSegment({ value: value, type: 'value', cssClass: 'query-segment-value' });
   };
 
-  this.newCondition = condition => {
+  this.newCondition = (condition: string) => {
     return new MetricSegment({ value: condition, type: 'condition', cssClass: 'query-keyword' });
   };
 
-  this.newOperator = op => {
+  this.newOperator = (op: string) => {
     return new MetricSegment({ value: op, type: 'operator', cssClass: 'query-segment-operator' });
   };
 
-  this.newOperators = ops => {
+  this.newOperators = (ops: string[]) => {
     return _.map(ops, op => {
       return new MetricSegment({ value: op, type: 'operator', cssClass: 'query-segment-operator' });
     });
   };
 
-  this.transformToSegments = (addTemplateVars, variableTypeFilter) => {
-    return results => {
+  this.transformToSegments = (addTemplateVars: boolean, variableTypeFilter: string) => {
+    return (results: any[]) => {
       const segments = _.map(results, segment => {
         return self.newSegment({ value: segment.text, expandable: segment.expandable });
       });

+ 14 - 9
public/app/core/table_model.ts

@@ -26,15 +26,19 @@ export default class TableModel implements TableData {
 
     if (table) {
       if (table.columns) {
-        table.columns.forEach(col => this.addColumn(col));
+        for (const col of table.columns) {
+          this.addColumn(col);
+        }
       }
       if (table.rows) {
-        table.rows.forEach(row => this.addRow(row));
+        for (const row of table.rows) {
+          this.addRow(row);
+        }
       }
     }
   }
 
-  sort(options) {
+  sort(options: { col: number; desc: boolean }) {
     if (options.col === null || this.columns.length <= options.col) {
       return;
     }
@@ -54,21 +58,21 @@ export default class TableModel implements TableData {
     this.columns[options.col].desc = options.desc;
   }
 
-  addColumn(col) {
+  addColumn(col: Column) {
     if (!this.columnMap[col.text]) {
       this.columns.push(col);
       this.columnMap[col.text] = col;
     }
   }
 
-  addRow(row) {
+  addRow(row: any[]) {
     this.rows.push(row);
   }
 }
 
 // Returns true if both rows have matching non-empty fields as well as matching
 // indexes where one field is empty and the other is not
-function areRowsMatching(columns, row, otherRow) {
+function areRowsMatching(columns: Column[], row: any[], otherRow: any[]) {
   let foundFieldToMatch = false;
   for (let columnIndex = 0; columnIndex < columns.length; columnIndex++) {
     if (row[columnIndex] !== undefined && otherRow[columnIndex] !== undefined) {
@@ -96,7 +100,7 @@ export function mergeTablesIntoModel(dst?: TableModel, ...tables: TableModel[]):
   }
 
   // Track column indexes of union: name -> index
-  const columnNames = {};
+  const columnNames: { [key: string]: any } = {};
 
   // Union of all non-value columns
   const columnsUnion = tables.slice().reduce((acc, series) => {
@@ -119,7 +123,7 @@ export function mergeTablesIntoModel(dst?: TableModel, ...tables: TableModel[]):
   const flattenedRows = tables.reduce((acc, series, seriesIndex) => {
     const mapper = columnIndexMapper[seriesIndex];
     series.rows.forEach(row => {
-      const alteredRow = [];
+      const alteredRow: any[] = [];
       // Shifting entries according to index mapper
       mapper.forEach((to, from) => {
         alteredRow[to] = row[from];
@@ -130,7 +134,8 @@ export function mergeTablesIntoModel(dst?: TableModel, ...tables: TableModel[]):
   }, []);
 
   // Merge rows that have same values for columns
-  const mergedRows = {};
+  const mergedRows: { [key: string]: any } = {};
+
   const compactedRows = flattenedRows.reduce((acc, row, rowIndex) => {
     if (!mergedRows[rowIndex]) {
       // Look from current row onwards

+ 10 - 10
public/app/core/time_series2.ts

@@ -1,8 +1,8 @@
 import { getFlotTickDecimals } from 'app/core/utils/ticks';
 import _ from 'lodash';
-import { getValueFormat, stringToJsRegex } from '@grafana/ui';
+import { getValueFormat, stringToJsRegex, ValueFormatter, DecimalCount } from '@grafana/ui';
 
-function matchSeriesOverride(aliasOrRegex, seriesAlias) {
+function matchSeriesOverride(aliasOrRegex: string, seriesAlias: string) {
   if (!aliasOrRegex) {
     return false;
   }
@@ -15,7 +15,7 @@ function matchSeriesOverride(aliasOrRegex, seriesAlias) {
   return aliasOrRegex === seriesAlias;
 }
 
-function translateFillOption(fill) {
+function translateFillOption(fill: number) {
   return fill === 0 ? 0.001 : fill / 10;
 }
 
@@ -25,7 +25,7 @@ function translateFillOption(fill) {
  * @param panel
  * @param height
  */
-export function updateLegendValues(data: TimeSeries[], panel, height) {
+export function updateLegendValues(data: TimeSeries[], panel: any, height: number) {
   for (let i = 0; i < data.length; i++) {
     const series = data[i];
     const yaxes = panel.yaxes;
@@ -97,7 +97,7 @@ export default class TimeSeries {
   flotpairs: any;
   unit: any;
 
-  constructor(opts) {
+  constructor(opts: any) {
     this.datapoints = opts.datapoints;
     this.label = opts.alias;
     this.id = opts.alias;
@@ -112,7 +112,7 @@ export default class TimeSeries {
     this.hasMsResolution = this.isMsResolutionNeeded();
   }
 
-  applySeriesOverrides(overrides) {
+  applySeriesOverrides(overrides: any[]) {
     this.lines = {};
     this.dashes = {
       dashLength: [],
@@ -192,7 +192,7 @@ export default class TimeSeries {
     }
   }
 
-  getFlotPairs(fillStyle) {
+  getFlotPairs(fillStyle: string) {
     const result = [];
 
     this.stats.total = 0;
@@ -314,13 +314,13 @@ export default class TimeSeries {
     return result;
   }
 
-  updateLegendValues(formater, decimals, scaledDecimals) {
+  updateLegendValues(formater: ValueFormatter, decimals: DecimalCount, scaledDecimals: DecimalCount) {
     this.valueFormater = formater;
     this.decimals = decimals;
     this.scaledDecimals = scaledDecimals;
   }
 
-  formatValue(value) {
+  formatValue(value: number) {
     if (!_.isFinite(value)) {
       value = null; // Prevent NaN formatting
     }
@@ -339,7 +339,7 @@ export default class TimeSeries {
     return false;
   }
 
-  hideFromLegend(options) {
+  hideFromLegend(options: any) {
     if (options.hideEmpty && this.allIsNull) {
       return true;
     }

+ 1 - 1
public/app/core/utils/connectWithReduxStore.tsx

@@ -3,7 +3,7 @@ import { connect } from 'react-redux';
 import { store } from '../../store/store';
 
 export function connectWithStore(WrappedComponent, ...args) {
-  const ConnectedWrappedComponent = connect(...args)(WrappedComponent);
+  const ConnectedWrappedComponent = (connect as any)(...args)(WrappedComponent);
 
   return props => {
     return <ConnectedWrappedComponent {...props} store={store} />;

+ 11 - 8
public/app/features/admin/AdminEditOrgCtrl.ts

@@ -1,8 +1,11 @@
+import { BackendSrv } from 'app/core/services/backend_srv';
+import { NavModelSrv } from 'app/core/core';
+
 export default class AdminEditOrgCtrl {
   /** @ngInject */
-  constructor($scope, $routeParams, backendSrv, $location, navModelSrv) {
+  constructor($scope: any, $routeParams: any, backendSrv: BackendSrv, $location: any, navModelSrv: NavModelSrv) {
     $scope.init = () => {
-      $scope.navModel = navModelSrv.getNav('admin', 'global-orgs', 0);
+      $scope.navModel = navModelSrv.getNav('admin', 'global-orgs');
 
       if ($routeParams.id) {
         $scope.getOrg($routeParams.id);
@@ -10,14 +13,14 @@ export default class AdminEditOrgCtrl {
       }
     };
 
-    $scope.getOrg = id => {
-      backendSrv.get('/api/orgs/' + id).then(org => {
+    $scope.getOrg = (id: number) => {
+      backendSrv.get('/api/orgs/' + id).then((org: any) => {
         $scope.org = org;
       });
     };
 
-    $scope.getOrgUsers = id => {
-      backendSrv.get('/api/orgs/' + id + '/users').then(orgUsers => {
+    $scope.getOrgUsers = (id: number) => {
+      backendSrv.get('/api/orgs/' + id + '/users').then((orgUsers: any) => {
         $scope.orgUsers = orgUsers;
       });
     };
@@ -32,11 +35,11 @@ export default class AdminEditOrgCtrl {
       });
     };
 
-    $scope.updateOrgUser = orgUser => {
+    $scope.updateOrgUser = (orgUser: any) => {
       backendSrv.patch('/api/orgs/' + orgUser.orgId + '/users/' + orgUser.userId, orgUser);
     };
 
-    $scope.removeOrgUser = orgUser => {
+    $scope.removeOrgUser = (orgUser: any) => {
       backendSrv.delete('/api/orgs/' + orgUser.orgId + '/users/' + orgUser.userId).then(() => {
         $scope.getOrgUsers($scope.org.id);
       });

+ 14 - 10
public/app/features/admin/AdminEditUserCtrl.ts

@@ -1,12 +1,15 @@
 import _ from 'lodash';
+import { BackendSrv } from 'app/core/services/backend_srv';
+import { NavModelSrv } from 'app/core/core';
+import { User } from 'app/core/services/context_srv';
 
 export default class AdminEditUserCtrl {
   /** @ngInject */
-  constructor($scope, $routeParams, backendSrv, $location, navModelSrv) {
+  constructor($scope: any, $routeParams: any, backendSrv: BackendSrv, $location: any, navModelSrv: NavModelSrv) {
     $scope.user = {};
     $scope.newOrg = { name: '', role: 'Editor' };
     $scope.permissions = {};
-    $scope.navModel = navModelSrv.getNav('admin', 'global-users', 0);
+    $scope.navModel = navModelSrv.getNav('admin', 'global-users');
 
     $scope.init = () => {
       if ($routeParams.id) {
@@ -15,8 +18,8 @@ export default class AdminEditUserCtrl {
       }
     };
 
-    $scope.getUser = id => {
-      backendSrv.get('/api/users/' + id).then(user => {
+    $scope.getUser = (id: number) => {
+      backendSrv.get('/api/users/' + id).then((user: User) => {
         $scope.user = user;
         $scope.user_id = id;
         $scope.permissions.isGrafanaAdmin = user.isGrafanaAdmin;
@@ -52,8 +55,8 @@ export default class AdminEditUserCtrl {
       });
     };
 
-    $scope.getUserOrgs = id => {
-      backendSrv.get('/api/users/' + id + '/orgs').then(orgs => {
+    $scope.getUserOrgs = (id: number) => {
+      backendSrv.get('/api/users/' + id + '/orgs').then((orgs: any) => {
         $scope.orgs = orgs;
       });
     };
@@ -68,11 +71,11 @@ export default class AdminEditUserCtrl {
       });
     };
 
-    $scope.updateOrgUser = orgUser => {
+    $scope.updateOrgUser = (orgUser: { orgId: string }) => {
       backendSrv.patch('/api/orgs/' + orgUser.orgId + '/users/' + $scope.user_id, orgUser).then(() => {});
     };
 
-    $scope.removeOrgUser = orgUser => {
+    $scope.removeOrgUser = (orgUser: { orgId: string }) => {
       backendSrv.delete('/api/orgs/' + orgUser.orgId + '/users/' + $scope.user_id).then(() => {
         $scope.getUser($scope.user_id);
         $scope.getUserOrgs($scope.user_id);
@@ -81,13 +84,13 @@ export default class AdminEditUserCtrl {
 
     $scope.orgsSearchCache = [];
 
-    $scope.searchOrgs = (queryStr, callback) => {
+    $scope.searchOrgs = (queryStr: any, callback: any) => {
       if ($scope.orgsSearchCache.length > 0) {
         callback(_.map($scope.orgsSearchCache, 'name'));
         return;
       }
 
-      backendSrv.get('/api/orgs', { query: '' }).then(result => {
+      backendSrv.get('/api/orgs', { query: '' }).then((result: any) => {
         $scope.orgsSearchCache = result;
         callback(_.map(result, 'name'));
       });
@@ -101,6 +104,7 @@ export default class AdminEditUserCtrl {
       const orgInfo: any = _.find($scope.orgsSearchCache, {
         name: $scope.newOrg.name,
       });
+
       if (!orgInfo) {
         return;
       }

+ 7 - 4
public/app/features/admin/AdminListOrgsCtrl.ts

@@ -1,18 +1,21 @@
+import { BackendSrv } from 'app/core/services/backend_srv';
+import { NavModelSrv } from 'app/core/core';
+
 export default class AdminListOrgsCtrl {
   /** @ngInject */
-  constructor($scope, backendSrv, navModelSrv) {
+  constructor($scope: any, backendSrv: BackendSrv, navModelSrv: NavModelSrv) {
     $scope.init = () => {
-      $scope.navModel = navModelSrv.getNav('admin', 'global-orgs', 0);
+      $scope.navModel = navModelSrv.getNav('admin', 'global-orgs');
       $scope.getOrgs();
     };
 
     $scope.getOrgs = () => {
-      backendSrv.get('/api/orgs').then(orgs => {
+      backendSrv.get('/api/orgs').then((orgs: any) => {
         $scope.orgs = orgs;
       });
     };
 
-    $scope.deleteOrg = org => {
+    $scope.deleteOrg = (org: any) => {
       $scope.appEvent('confirm-modal', {
         title: 'Delete',
         text: 'Do you want to delete organization ' + org.name + '?',

+ 9 - 6
public/app/features/admin/AdminListUsersCtrl.ts

@@ -1,6 +1,9 @@
+import { BackendSrv } from 'app/core/services/backend_srv';
+import { NavModelSrv } from 'app/core/core';
+
 export default class AdminListUsersCtrl {
   users: any;
-  pages = [];
+  pages: any[] = [];
   perPage = 50;
   page = 1;
   totalPages: number;
@@ -9,8 +12,8 @@ export default class AdminListUsersCtrl {
   navModel: any;
 
   /** @ngInject */
-  constructor(private $scope, private backendSrv, navModelSrv) {
-    this.navModel = navModelSrv.getNav('admin', 'global-users', 0);
+  constructor(private $scope: any, private backendSrv: BackendSrv, navModelSrv: NavModelSrv) {
+    this.navModel = navModelSrv.getNav('admin', 'global-users');
     this.query = '';
     this.getUsers();
   }
@@ -18,7 +21,7 @@ export default class AdminListUsersCtrl {
   getUsers() {
     this.backendSrv
       .get(`/api/users/search?perpage=${this.perPage}&page=${this.page}&query=${this.query}`)
-      .then(result => {
+      .then((result: any) => {
         this.users = result.users;
         this.page = result.page;
         this.perPage = result.perPage;
@@ -32,12 +35,12 @@ export default class AdminListUsersCtrl {
       });
   }
 
-  navigateToPage(page) {
+  navigateToPage(page: any) {
     this.page = page.page;
     this.getUsers();
   }
 
-  deleteUser(user) {
+  deleteUser(user: any) {
     this.$scope.appEvent('confirm-modal', {
       title: 'Delete',
       text: 'Do you want to delete ' + user.login + '?',

+ 1 - 0
public/app/features/admin/ServerStats.test.tsx

@@ -1,4 +1,5 @@
 import React from 'react';
+// @ts-ignore
 import renderer from 'react-test-renderer';
 import { ServerStats } from './ServerStats';
 import { createNavModel } from 'test/mocks/common';

+ 4 - 2
public/app/features/admin/StyleGuideCtrl.ts

@@ -1,4 +1,6 @@
 import config from 'app/core/config';
+import { BackendSrv } from 'app/core/services/backend_srv';
+import { NavModelSrv } from 'app/core/core';
 
 export default class StyleGuideCtrl {
   theme: string;
@@ -8,8 +10,8 @@ export default class StyleGuideCtrl {
   navModel: any;
 
   /** @ngInject */
-  constructor(private $routeParams, private backendSrv, navModelSrv) {
-    this.navModel = navModelSrv.getNav('admin', 'styleguide', 0);
+  constructor(private $routeParams: any, private backendSrv: BackendSrv, navModelSrv: NavModelSrv) {
+    this.navModel = navModelSrv.getNav('admin', 'styleguide');
     this.theme = config.bootData.user.lightTheme ? 'light' : 'dark';
   }
 

+ 7 - 5
public/app/features/admin/index.ts

@@ -5,15 +5,17 @@ import AdminEditOrgCtrl from './AdminEditOrgCtrl';
 import StyleGuideCtrl from './StyleGuideCtrl';
 
 import coreModule from 'app/core/core_module';
+import { BackendSrv } from 'app/core/services/backend_srv';
+import { NavModelSrv } from 'app/core/core';
 
 class AdminSettingsCtrl {
   navModel: any;
 
   /** @ngInject */
-  constructor($scope, backendSrv, navModelSrv) {
-    this.navModel = navModelSrv.getNav('admin', 'server-settings', 0);
+  constructor($scope: any, backendSrv: BackendSrv, navModelSrv: NavModelSrv) {
+    this.navModel = navModelSrv.getNav('admin', 'server-settings');
 
-    backendSrv.get('/api/admin/settings').then(settings => {
+    backendSrv.get('/api/admin/settings').then((settings: any) => {
       $scope.settings = settings;
     });
   }
@@ -23,8 +25,8 @@ class AdminHomeCtrl {
   navModel: any;
 
   /** @ngInject */
-  constructor(navModelSrv) {
-    this.navModel = navModelSrv.getNav('admin', 0);
+  constructor(navModelSrv: NavModelSrv) {
+    this.navModel = navModelSrv.getNav('admin');
   }
 }
 

+ 1 - 1
public/app/features/alerting/AlertRuleItem.test.tsx

@@ -3,7 +3,7 @@ import { shallow } from 'enzyme';
 import AlertRuleItem, { Props } from './AlertRuleItem';
 
 jest.mock('react-redux', () => ({
-  connect: () => params => params,
+  connect: () => (params: any) => params,
 }));
 
 const setup = (propOverrides?: object) => {

+ 1 - 0
public/app/features/alerting/AlertRuleItem.tsx

@@ -1,4 +1,5 @@
 import React, { PureComponent } from 'react';
+// @ts-ignore
 import Highlighter from 'react-highlight-words';
 import classNames from 'classnames';
 import { AlertRule } from '../../types';

+ 31 - 34
public/app/features/alerting/AlertTabCtrl.ts

@@ -5,9 +5,14 @@ import { QueryPart } from 'app/core/components/query_part/query_part';
 import alertDef from './state/alertDef';
 import config from 'app/core/config';
 import appEvents from 'app/core/app_events';
+import { BackendSrv } from 'app/core/services/backend_srv';
+import { DashboardSrv } from '../dashboard/services/DashboardSrv';
+import DatasourceSrv from '../plugins/datasource_srv';
+import { DataQuery } from '@grafana/ui/src/types/datasource';
+import { PanelModel } from 'app/features/dashboard/state';
 
 export class AlertTabCtrl {
-  panel: any;
+  panel: PanelModel;
   panelCtrl: any;
   subTabIndex: number;
   conditionTypes: any;
@@ -17,21 +22,21 @@ export class AlertTabCtrl {
   evalOperators: any;
   noDataModes: any;
   executionErrorModes: any;
-  addNotificationSegment;
-  notifications;
-  alertNotifications;
+  addNotificationSegment: any;
+  notifications: any;
+  alertNotifications: any;
   error: string;
   appSubUrl: string;
   alertHistory: any;
 
   /** @ngInject */
   constructor(
-    private $scope,
-    private backendSrv,
-    private dashboardSrv,
-    private uiSegmentSrv,
-    private $q,
-    private datasourceSrv
+    private $scope: any,
+    private backendSrv: BackendSrv,
+    private dashboardSrv: DashboardSrv,
+    private uiSegmentSrv: any,
+    private $q: any,
+    private datasourceSrv: DatasourceSrv
   ) {
     this.panelCtrl = $scope.ctrl;
     this.panel = this.panelCtrl.panel;
@@ -65,7 +70,7 @@ export class AlertTabCtrl {
     this.alertNotifications = [];
     this.alertHistory = [];
 
-    return this.backendSrv.get('/api/alert-notifications').then(res => {
+    return this.backendSrv.get('/api/alert-notifications').then((res: any) => {
       this.notifications = res;
 
       this.initModel();
@@ -76,7 +81,7 @@ export class AlertTabCtrl {
   getAlertHistory() {
     this.backendSrv
       .get(`/api/annotations?dashboardId=${this.panelCtrl.dashboard.id}&panelId=${this.panel.id}&limit=50&type=alert`)
-      .then(res => {
+      .then((res: any) => {
         this.alertHistory = _.map(res, ah => {
           ah.time = this.dashboardSrv.getCurrent().formatDate(ah.time, 'MMM D, YYYY HH:mm:ss');
           ah.stateModel = alertDef.getStateDisplayModel(ah.newState);
@@ -86,7 +91,7 @@ export class AlertTabCtrl {
       });
   }
 
-  getNotificationIcon(type): string {
+  getNotificationIcon(type: string): string {
     switch (type) {
       case 'email':
         return 'fa fa-envelope';
@@ -114,20 +119,12 @@ export class AlertTabCtrl {
 
   getNotifications() {
     return this.$q.when(
-      this.notifications.map(item => {
+      this.notifications.map((item: any) => {
         return this.uiSegmentSrv.newSegment(item.name);
       })
     );
   }
 
-  changeTabIndex(newTabIndex) {
-    this.subTabIndex = newTabIndex;
-
-    if (this.subTabIndex === 2) {
-      this.getAlertHistory();
-    }
-  }
-
   notificationAdded() {
     const model: any = _.find(this.notifications, {
       name: this.addNotificationSegment.value,
@@ -154,7 +151,7 @@ export class AlertTabCtrl {
     this.addNotificationSegment.fake = true;
   }
 
-  removeNotification(an) {
+  removeNotification(an: any) {
     // remove notifiers refeered to by id and uid to support notifiers added
     // before and after we added support for uid
     _.remove(this.alert.notifications, (n: any) => n.uid === an.uid || n.id === an.id);
@@ -220,7 +217,7 @@ export class AlertTabCtrl {
     this.panelCtrl.render();
   }
 
-  graphThresholdChanged(evt) {
+  graphThresholdChanged(evt: any) {
     for (const condition of this.alert.conditions) {
       if (condition.type === 'query') {
         condition.evaluator.params[evt.handleIndex] = evt.threshold.value;
@@ -234,8 +231,8 @@ export class AlertTabCtrl {
     return {
       type: 'query',
       query: { params: ['A', '5m', 'now'] },
-      reducer: { type: 'avg', params: [] },
-      evaluator: { type: 'gt', params: [null] },
+      reducer: { type: 'avg', params: [] as any[] },
+      evaluator: { type: 'gt', params: [null] as any[] },
       operator: { type: 'and' },
     };
   }
@@ -246,7 +243,7 @@ export class AlertTabCtrl {
     }
 
     let firstTarget;
-    let foundTarget = null;
+    let foundTarget: DataQuery = null;
 
     for (const condition of this.alert.conditions) {
       if (condition.type !== 'query') {
@@ -285,7 +282,7 @@ export class AlertTabCtrl {
     }
   }
 
-  buildConditionModel(source) {
+  buildConditionModel(source: any) {
     const cm: any = { source: source, type: source.type };
 
     cm.queryPart = new QueryPart(source.query, alertDef.alertQueryDef);
@@ -296,7 +293,7 @@ export class AlertTabCtrl {
     return cm;
   }
 
-  handleQueryPartEvent(conditionModel, evt) {
+  handleQueryPartEvent(conditionModel: any, evt: any) {
     switch (evt.name) {
       case 'action-remove-part': {
         break;
@@ -317,7 +314,7 @@ export class AlertTabCtrl {
     }
   }
 
-  handleReducerPartEvent(conditionModel, evt) {
+  handleReducerPartEvent(conditionModel: any, evt: any) {
     switch (evt.name) {
       case 'action': {
         conditionModel.source.reducer.type = evt.action.value;
@@ -336,7 +333,7 @@ export class AlertTabCtrl {
     }
   }
 
-  addCondition(type) {
+  addCondition(type: string) {
     const condition = this.buildDefaultCondition();
     // add to persited model
     this.alert.conditions.push(condition);
@@ -344,7 +341,7 @@ export class AlertTabCtrl {
     this.conditionModels.push(this.buildConditionModel(condition));
   }
 
-  removeCondition(index) {
+  removeCondition(index: number) {
     this.alert.conditions.splice(index, 1);
     this.conditionModels.splice(index, 1);
   }
@@ -378,7 +375,7 @@ export class AlertTabCtrl {
     this.panelCtrl.render();
   }
 
-  evaluatorTypeChanged(evaluator) {
+  evaluatorTypeChanged(evaluator: any) {
     // ensure params array is correct length
     switch (evaluator.type) {
       case 'lt':
@@ -411,7 +408,7 @@ export class AlertTabCtrl {
             dashboardId: this.panelCtrl.dashboard.id,
             panelId: this.panel.id,
           })
-          .then(res => {
+          .then(() => {
             this.alertHistory = [];
             this.panelCtrl.refresh();
           });

+ 19 - 12
public/app/features/alerting/NotificationsEditCtrl.ts

@@ -1,5 +1,6 @@
 import _ from 'lodash';
-import { appEvents, coreModule } from 'app/core/core';
+import { appEvents, coreModule, NavModelSrv } from 'app/core/core';
+import { BackendSrv } from 'app/core/services/backend_srv';
 
 export class AlertNotificationEditCtrl {
   theForm: any;
@@ -24,8 +25,14 @@ export class AlertNotificationEditCtrl {
   getFrequencySuggestion: any;
 
   /** @ngInject */
-  constructor(private $routeParams, private backendSrv, private $location, private $templateCache, navModelSrv) {
-    this.navModel = navModelSrv.getNav('alerting', 'channels', 0);
+  constructor(
+    private $routeParams: any,
+    private backendSrv: BackendSrv,
+    private $location: any,
+    private $templateCache: any,
+    navModelSrv: NavModelSrv
+  ) {
+    this.navModel = navModelSrv.getNav('alerting', 'channels');
     this.isNew = !this.$routeParams.id;
 
     this.getFrequencySuggestion = () => {
@@ -34,7 +41,7 @@ export class AlertNotificationEditCtrl {
 
     this.backendSrv
       .get(`/api/alert-notifiers`)
-      .then(notifiers => {
+      .then((notifiers: any) => {
         this.notifiers = notifiers;
 
         // add option templates
@@ -48,14 +55,14 @@ export class AlertNotificationEditCtrl {
           return _.defaults(this.model, this.defaults);
         }
 
-        return this.backendSrv.get(`/api/alert-notifications/${this.$routeParams.id}`).then(result => {
+        return this.backendSrv.get(`/api/alert-notifications/${this.$routeParams.id}`).then((result: any) => {
           this.navModel.breadcrumbs.push({ text: result.name });
           this.navModel.node = { text: result.name };
           result.settings = _.defaults(result.settings, this.defaults.settings);
           return result;
         });
       })
-      .then(model => {
+      .then((model: any) => {
         this.model = model;
         this.notifierTemplateId = this.getNotifierTemplateId(this.model.type);
       });
@@ -69,11 +76,11 @@ export class AlertNotificationEditCtrl {
     if (this.model.id) {
       this.backendSrv
         .put(`/api/alert-notifications/${this.model.id}`, this.model)
-        .then(res => {
+        .then((res: any) => {
           this.model = res;
           appEvents.emit('alert-success', ['Notification updated', '']);
         })
-        .catch(err => {
+        .catch((err: any) => {
           if (err.data && err.data.error) {
             appEvents.emit('alert-error', [err.data.error]);
           }
@@ -81,11 +88,11 @@ export class AlertNotificationEditCtrl {
     } else {
       this.backendSrv
         .post(`/api/alert-notifications`, this.model)
-        .then(res => {
+        .then((res: any) => {
           appEvents.emit('alert-success', ['Notification created', '']);
           this.$location.path('alerting/notifications');
         })
-        .catch(err => {
+        .catch((err: any) => {
           if (err.data && err.data.error) {
             appEvents.emit('alert-error', [err.data.error]);
           }
@@ -93,7 +100,7 @@ export class AlertNotificationEditCtrl {
     }
   }
 
-  getNotifierTemplateId(type) {
+  getNotifierTemplateId(type: string) {
     return `notifier-options-${type}`;
   }
 
@@ -114,7 +121,7 @@ export class AlertNotificationEditCtrl {
       settings: this.model.settings,
     };
 
-    this.backendSrv.post(`/api/alert-notifications/test`, payload).then(res => {
+    this.backendSrv.post(`/api/alert-notifications/test`, payload).then((res: any) => {
       appEvents.emit('alert-success', ['Test notification sent', '']);
     });
   }

+ 7 - 6
public/app/features/alerting/NotificationsListCtrl.ts

@@ -1,24 +1,25 @@
-import { coreModule } from 'app/core/core';
+import { coreModule, NavModelSrv } from 'app/core/core';
+import { BackendSrv } from 'app/core/services/backend_srv';
 
 export class AlertNotificationsListCtrl {
   notifications: any;
   navModel: any;
 
   /** @ngInject */
-  constructor(private backendSrv, navModelSrv) {
+  constructor(private backendSrv: BackendSrv, navModelSrv: NavModelSrv) {
     this.loadNotifications();
-    this.navModel = navModelSrv.getNav('alerting', 'channels', 0);
+    this.navModel = navModelSrv.getNav('alerting', 'channels');
   }
 
   loadNotifications() {
-    this.backendSrv.get(`/api/alert-notifications`).then(result => {
+    this.backendSrv.get(`/api/alert-notifications`).then((result: any) => {
       this.notifications = result;
     });
   }
 
-  deleteNotification(id) {
+  deleteNotification(id: number) {
     this.backendSrv.delete(`/api/alert-notifications/${id}`).then(() => {
-      this.notifications = this.notifications.filter(notification => {
+      this.notifications = this.notifications.filter((notification: any) => {
         return notification.id !== id;
       });
     });

+ 3 - 3
public/app/features/alerting/StateHistory.tsx

@@ -15,7 +15,7 @@ interface State {
 }
 
 class StateHistory extends PureComponent<Props, State> {
-  state = {
+  state: State = {
     stateHistoryItems: [],
   };
 
@@ -24,8 +24,8 @@ class StateHistory extends PureComponent<Props, State> {
 
     getBackendSrv()
       .get(`/api/annotations?dashboardId=${dashboard.id}&panelId=${panelId}&limit=50&type=alert`)
-      .then(res => {
-        const items = res.map(item => {
+      .then((res: any[]) => {
+        const items = res.map((item: any) => {
           return {
             stateModel: alertDef.getStateDisplayModel(item.newState),
             time: dashboard.formatDate(item.time, 'MMM D, YYYY HH:mm:ss'),

+ 4 - 2
public/app/features/alerting/state/ThresholdMapper.ts

@@ -1,5 +1,7 @@
+import { PanelModel } from 'app/features/dashboard/state';
+
 export class ThresholdMapper {
-  static alertToGraphThresholds(panel) {
+  static alertToGraphThresholds(panel: PanelModel) {
     for (let i = 0; i < panel.alert.conditions.length; i++) {
       const condition = panel.alert.conditions[i];
       if (condition.type !== 'query') {
@@ -7,7 +9,7 @@ export class ThresholdMapper {
       }
 
       const evaluator = condition.evaluator;
-      const thresholds = (panel.thresholds = []);
+      const thresholds: any[] = (panel.thresholds = []);
 
       switch (evaluator.type) {
         case 'gt': {

+ 4 - 4
public/app/features/alerting/state/alertDef.ts

@@ -57,12 +57,12 @@ const noDataModes = [
 
 const executionErrorModes = [{ text: 'Alerting', value: 'alerting' }, { text: 'Keep Last State', value: 'keep_state' }];
 
-function createReducerPart(model) {
+function createReducerPart(model: any) {
   const def = new QueryPartDef({ type: model.type, defaultParams: [] });
   return new QueryPart(model, def);
 }
 
-function getStateDisplayModel(state) {
+function getStateDisplayModel(state: string) {
   switch (state) {
     case 'ok': {
       return {
@@ -111,7 +111,7 @@ function getStateDisplayModel(state) {
   throw { message: 'Unknown alert state' };
 }
 
-function joinEvalMatches(matches, separator: string) {
+function joinEvalMatches(matches: any, separator: string) {
   return _.reduce(
     matches,
     (res, ev) => {
@@ -130,7 +130,7 @@ function joinEvalMatches(matches, separator: string) {
   ).join(separator);
 }
 
-function getAlertAnnotationInfo(ah) {
+function getAlertAnnotationInfo(ah: any) {
   // backward compatibility, can be removed in grafana 5.x
   // old way stored evalMatches in data property directly,
   // new way stores it in evalMatches property on new data object

+ 2 - 2
public/app/features/alerting/state/reducers.test.ts

@@ -85,7 +85,7 @@ describe('Alert rules', () => {
     };
 
     const result = alertRulesReducer(initialState, action);
-
-    expect(result.items).toEqual(payload);
+    expect(result.items.length).toEqual(payload.length);
+    expect(result.items[0].stateClass).toEqual('alert-state-critical');
   });
 });

+ 11 - 7
public/app/features/alerting/state/reducers.ts

@@ -5,14 +5,18 @@ import { dateTime } from '@grafana/ui/src/utils/moment_wrapper';
 
 export const initialState: AlertRulesState = { items: [], searchQuery: '', isLoading: false };
 
-function convertToAlertRule(rule, state): AlertRule {
+function convertToAlertRule(dto: AlertRuleDTO, state: string): AlertRule {
   const stateModel = alertDef.getStateDisplayModel(state);
-  rule.stateText = stateModel.text;
-  rule.stateIcon = stateModel.iconClass;
-  rule.stateClass = stateModel.stateClass;
-  rule.stateAge = dateTime(rule.newStateDate)
-    .fromNow()
-    .replace(' ago', '');
+
+  const rule: AlertRule = {
+    ...dto,
+    stateText: stateModel.text,
+    stateIcon: stateModel.iconClass,
+    stateClass: stateModel.stateClass,
+    stateAge: dateTime(dto.newStateDate)
+      .fromNow()
+      .replace(' ago', ''),
+  };
 
   if (rule.state !== 'paused') {
     if (rule.executionError) {

+ 3 - 3
public/app/features/alerting/state/selectors.test.ts

@@ -3,7 +3,7 @@ import { getSearchQuery, getAlertRuleItems } from './selectors';
 describe('Get search query', () => {
   it('should get search query', () => {
     const state = { searchQuery: 'dashboard' };
-    const result = getSearchQuery(state);
+    const result = getSearchQuery(state as any);
 
     expect(result).toEqual(state.searchQuery);
   });
@@ -29,7 +29,7 @@ describe('Get alert rule items', () => {
       searchQuery: '',
     };
 
-    const result = getAlertRuleItems(state);
+    const result = getAlertRuleItems(state as any);
     expect(result.length).toEqual(1);
   });
 
@@ -88,7 +88,7 @@ describe('Get alert rule items', () => {
       searchQuery: 'dashboard',
     };
 
-    const result = getAlertRuleItems(state);
+    const result = getAlertRuleItems(state as any);
     expect(result.length).toEqual(3);
   });
 });

+ 4 - 2
public/app/features/alerting/state/selectors.ts

@@ -1,6 +1,8 @@
-export const getSearchQuery = state => state.searchQuery;
+import { AlertRulesState } from 'app/types';
 
-export const getAlertRuleItems = state => {
+export const getSearchQuery = (state: AlertRulesState) => state.searchQuery;
+
+export const getAlertRuleItems = (state: AlertRulesState) => {
   const regex = new RegExp(state.searchQuery, 'i');
 
   return state.items.filter(item => {

+ 1 - 1
public/app/features/dashboard/dashgrid/PanelChrome.tsx

@@ -234,7 +234,7 @@ export class PanelChrome extends PureComponent<Props, State> {
     // image rendering (phantomjs/headless chrome) to know when to capture image
     const loading = data.state;
     if (loading === LoadingState.Done) {
-      profiler.renderingCompleted(panel.id);
+      profiler.renderingCompleted();
     }
 
     // do not render component until we have first data

+ 1 - 1
public/app/features/explore/Explore.tsx

@@ -365,4 +365,4 @@ export default hot(module)(
     mapStateToProps,
     mapDispatchToProps
   )(Explore)
-);
+) as React.ComponentType<{ exploreId: ExploreId }>;

+ 11 - 10
public/app/features/explore/QueryRow.tsx

@@ -28,19 +28,22 @@ import { Emitter } from 'app/core/utils/emitter';
 import { highlightLogsExpressionAction, removeQueryRowAction } from './state/actionTypes';
 import QueryStatus from './QueryStatus';
 
-interface QueryRowProps {
+interface PropsFromParent {
+  exploreId: ExploreId;
+  index: number;
+  exploreEvents: Emitter;
+}
+
+interface QueryRowProps extends PropsFromParent {
   addQueryRow: typeof addQueryRow;
   changeQuery: typeof changeQuery;
   className?: string;
-  exploreId: ExploreId;
   datasourceInstance: ExploreDataSourceApi;
   datasourceStatus: DataSourceStatus;
   highlightLogsExpressionAction: typeof highlightLogsExpressionAction;
   history: HistoryItem[];
-  index: number;
   query: DataQuery;
   modifyQueries: typeof modifyQueries;
-  exploreEvents: Emitter;
   range: TimeRange;
   removeQueryRowAction: typeof removeQueryRowAction;
   runQueries: typeof runQueries;
@@ -219,9 +222,7 @@ const mapDispatchToProps = {
   runQueries,
 };
 
-export default hot(module)(
-  connect(
-    mapStateToProps,
-    mapDispatchToProps
-  )(QueryRow)
-);
+export default hot(module)(connect(
+  mapStateToProps,
+  mapDispatchToProps
+)(QueryRow) as React.ComponentType<PropsFromParent>);

+ 1 - 0
public/app/features/explore/Wrapper.tsx

@@ -36,6 +36,7 @@ export class Wrapper extends Component<WrapperProps> {
               </ErrorBoundary>
             )}
           </div>
+          x
         </CustomScrollbar>
       </div>
     );

+ 3 - 6
public/app/features/org/state/actions.ts

@@ -1,9 +1,6 @@
-import { ThunkAction } from 'redux-thunk';
-import { Organization, StoreState } from 'app/types';
+import { Organization, ThunkResult } from 'app/types';
 import { getBackendSrv } from 'app/core/services/backend_srv';
 
-type ThunkResult<R> = ThunkAction<R, StoreState, undefined, any>;
-
 export enum ActionTypes {
   LoadOrganization = 'LOAD_ORGANIZATION',
   SetOrganizationName = 'SET_ORGANIZATION_NAME',
@@ -31,7 +28,7 @@ export const setOrganizationName = (orgName: string) => ({
 
 export type Action = LoadOrganizationAction | SetOrganizationNameAction;
 
-export function loadOrganization(): ThunkResult<void> {
+export function loadOrganization(): ThunkResult<any> {
   return async dispatch => {
     const organizationResponse = await getBackendSrv().get('/api/org');
     dispatch(organizationLoaded(organizationResponse));
@@ -40,7 +37,7 @@ export function loadOrganization(): ThunkResult<void> {
   };
 }
 
-export function updateOrganization() {
+export function updateOrganization(): ThunkResult<any> {
   return async (dispatch, getStore) => {
     const organization = getStore().organization.organization;
 

+ 1 - 1
public/app/features/panel/panel_ctrl.ts

@@ -60,7 +60,7 @@ export class PanelCtrl {
   }
 
   renderingCompleted() {
-    profiler.renderingCompleted(this.panel.id);
+    profiler.renderingCompleted();
   }
 
   refresh() {

+ 1 - 1
public/app/plugins/datasource/prometheus/datasource.ts

@@ -137,7 +137,7 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
     return escapedValues.join('|');
   }
 
-  targetContainsTemplate(target) {
+  targetContainsTemplate(target: PromQuery) {
     return this.templateSrv.variableExists(target.expr);
   }
 

+ 2 - 2
public/app/types/alerting.ts

@@ -8,7 +8,7 @@ export interface AlertRuleDTO {
   state: string;
   newStateDate: string;
   evalDate: string;
-  evalData?: object;
+  evalData?: { noData?: boolean; evalMatches?: any };
   executionError: string;
   url: string;
 }
@@ -26,7 +26,7 @@ export interface AlertRule {
   url: string;
   info?: string;
   executionError?: string;
-  evalData?: { noData: boolean };
+  evalData?: { noData?: boolean; evalMatches?: any };
 }
 
 export interface AlertRulesState {

+ 1 - 1
scripts/ci-frontend-metrics.sh

@@ -2,7 +2,7 @@
 
 echo -e "Collecting code stats (typescript errors & more)"
 
-ERROR_COUNT_LIMIT=5386
+ERROR_COUNT_LIMIT=5150
 DIRECTIVES_LIMIT=172
 CONTROLLERS_LIMIT=139
 

+ 18 - 1
yarn.lock

@@ -2219,6 +2219,14 @@
     "@types/minimatch" "*"
     "@types/node" "*"
 
+"@types/hoist-non-react-statics@^3.3.0":
+  version "3.3.1"
+  resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
+  integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
+  dependencies:
+    "@types/react" "*"
+    hoist-non-react-statics "^3.3.0"
+
 "@types/inquirer@0.0.43":
   version "0.0.43"
   resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-0.0.43.tgz#1eb0bbb4648e6cc568bd396c1e989f620ad01273"
@@ -2384,6 +2392,15 @@
   dependencies:
     "@types/react" "*"
 
+"@types/react-redux@^7.0.8":
+  version "7.0.8"
+  resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.0.8.tgz#c928863058e334d41031c6bedd0f113bc514e234"
+  integrity sha512-vIBC15E84ehN6RzdGwRVa41whp9e4CkfPm+WfD0r6y6vqBf4tQPKZeKEBfLLM8k79uSwQC7rh3rH/MFaN1IESQ==
+  dependencies:
+    "@types/hoist-non-react-statics" "^3.3.0"
+    "@types/react" "*"
+    redux "^4.0.0"
+
 "@types/react-select@2.0.15":
   version "2.0.15"
   resolved "https://registry.yarnpkg.com/@types/react-select/-/react-select-2.0.15.tgz#51d607667f59a12e980abcc5bbf9636307293e44"
@@ -14671,7 +14688,7 @@ redux-thunk@2.3.0:
   resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622"
   integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==
 
-redux@4.0.1:
+redux@4.0.1, redux@^4.0.0:
   version "4.0.1"
   resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.1.tgz#436cae6cc40fbe4727689d7c8fae44808f1bfef5"
   integrity sha512-R7bAtSkk7nY6O/OYMVR9RiBI+XghjF9rlbl5806HJbQph0LJVHZrU5oaO4q70eUKiqMRqm4y07KLTlMZ2BlVmg==