浏览代码

Merge branch 'master' into fix/15691-refresh-issue-playlists

Peter Holmberg 6 年之前
父节点
当前提交
81afd68752
共有 34 个文件被更改,包括 467 次插入387 次删除
  1. 1 1
      docs/sources/reference/templating.md
  2. 8 7
      package.json
  3. 3 3
      packages/grafana-ui/package.json
  4. 1 0
      packages/grafana-ui/src/components/Select/SelectOption.test.tsx
  5. 1 0
      packages/grafana-ui/src/components/Select/__snapshots__/SelectOption.test.tsx.snap
  6. 13 3
      packages/grafana-ui/src/components/Table/Table.tsx
  7. 3 3
      public/app/core/components/Animations/FadeIn.tsx
  8. 12 4
      public/app/core/components/Animations/SlideDown.tsx
  9. 2 2
      public/app/core/components/CopyToClipboard/CopyToClipboard.tsx
  10. 2 2
      public/app/core/components/EmptyListCTA/EmptyListCTA.test.tsx
  11. 0 1
      public/app/core/components/JSONFormatter/JSONFormatter.tsx
  12. 17 2
      public/app/core/components/SharedPreferences/SharedPreferences.tsx
  13. 21 14
      public/app/core/components/form_dropdown/form_dropdown.ts
  14. 1 1
      public/app/core/components/json_explorer/json_explorer.ts
  15. 4 4
      public/app/core/components/layout_selector/layout_selector.ts
  16. 2 1
      public/app/core/components/manage_dashboards/manage_dashboards.ts
  17. 2 1
      public/app/core/services/backend_srv.ts
  18. 22 11
      public/app/core/services/search_srv.ts
  19. 1 0
      public/app/core/specs/manage_dashboards.test.ts
  20. 17 13
      public/app/core/specs/search_srv.test.ts
  21. 1 1
      public/app/features/api-keys/ApiKeysPage.tsx
  22. 1 1
      public/app/features/dashboard/components/DashboardPermissions/DashboardPermissions.tsx
  23. 6 6
      public/app/features/dashboard/state/PanelModel.ts
  24. 1 1
      public/app/features/folders/FolderPermissions.tsx
  25. 1 1
      public/app/features/teams/TeamGroupSync.tsx
  26. 1 1
      public/app/features/teams/TeamMembers.tsx
  27. 0 6
      public/app/plugins/panel/graph/threshold_manager.ts
  28. 2 2
      public/app/plugins/panel/graph/thresholds_form.html
  29. 15 1
      public/app/plugins/panel/graph/thresholds_form.ts
  30. 0 1
      public/app/plugins/panel/singlestat2/SingleStatPanel.tsx
  31. 0 0
      public/app/types/jquery/jquery.d.ts
  32. 14 3
      public/app/types/search.ts
  33. 1 1
      tsconfig.json
  34. 291 289
      yarn.lock

+ 1 - 1
docs/sources/reference/templating.md

@@ -110,7 +110,7 @@ Formats single & multi valued variables for use in URL parameters.
 
 ```bash
 servers = ['foo()bar BAZ', 'test2']
-String to interpolate: '${servers:lucene}'
+String to interpolate: '${servers:percentencode}'
 Interpolation result: 'foo%28%29bar%20BAZ%2Ctest2'
 ```
 

+ 8 - 7
package.json

@@ -27,12 +27,13 @@
     "@types/jest": "^23.3.2",
     "@types/jquery": "^1.10.35",
     "@types/node": "^8.0.31",
-    "@types/react": "^16.7.6",
-    "@types/react-dom": "^16.0.9",
+    "@types/react": "^16.8.8",
+    "@types/react-dom": "^16.8.2",
     "@types/react-grid-layout": "^0.16.6",
     "@types/react-select": "^2.0.4",
     "@types/react-transition-group": "^2.0.15",
     "@types/react-virtualized": "^9.18.12",
+    "@types/clipboard": "^2.0.1",
     "angular-mocks": "1.6.6",
     "autoprefixer": "^6.4.0",
     "axios": "^0.17.1",
@@ -107,7 +108,7 @@
     "systemjs-plugin-css": "^0.1.36",
     "ts-jest": "^23.10.4",
     "ts-loader": "^5.1.0",
-    "ts-node": "^8.0.2",
+    "ts-node": "8.0.2",
     "tslib": "^1.9.3",
     "tslint": "^5.8.0",
     "tslint-loader": "^3.5.3",
@@ -176,7 +177,7 @@
     "baron": "^3.0.3",
     "brace": "^0.10.0",
     "classnames": "^2.2.6",
-    "clipboard": "^1.7.1",
+    "clipboard": "^2.0.4",
     "d3": "^4.11.0",
     "d3-scale-chromatic": "^1.3.0",
     "eventemitter3": "^2.0.3",
@@ -191,8 +192,8 @@
     "prismjs": "^1.6.0",
     "prop-types": "^15.6.2",
     "rc-cascader": "^0.14.0",
-    "react": "^16.6.3",
-    "react-dom": "^16.6.3",
+    "react": "^16.8.4",
+    "react-dom": "^16.8.4",
     "react-grid-layout": "0.16.6",
     "react-highlight-words": "0.11.0",
     "react-popper": "^1.3.0",
@@ -219,7 +220,7 @@
   },
   "resolutions": {
     "caniuse-db": "1.0.30000772",
-    "**/@types/react": "16.7.6"
+    "**/@types/react": "16.8.8"
   },
   "workspaces": {
     "packages": [

+ 3 - 3
packages/grafana-ui/package.json

@@ -25,10 +25,10 @@
     "lodash": "^4.17.10",
     "moment": "^2.22.2",
     "papaparse": "^4.6.3",
-    "react": "^16.6.3",
+    "react": "^16.8.4",
     "react-color": "^2.17.0",
     "react-custom-scrollbars": "^4.2.1",
-    "react-dom": "^16.6.3",
+    "react-dom": "^16.8.4",
     "react-highlight-words": "0.11.0",
     "react-popper": "^1.3.0",
     "react-transition-group": "^2.2.1",
@@ -48,7 +48,7 @@
     "@types/lodash": "^4.14.119",
     "@types/node": "^10.12.18",
     "@types/papaparse": "^4.5.9",
-    "@types/react": "^16.7.6",
+    "@types/react": "^16.8.8",
     "@types/react-custom-scrollbars": "^4.0.5",
     "@types/react-test-renderer": "^16.0.3",
     "@types/react-transition-group": "^2.0.15",

+ 1 - 0
packages/grafana-ui/src/components/Select/SelectOption.test.tsx

@@ -25,6 +25,7 @@ const model: OptionProps<any> = {
     key: '',
     onClick: jest.fn(),
     onMouseOver: jest.fn(),
+    onMouseMove: jest.fn(),
     tabIndex: 1,
   },
   label: 'Option label',

+ 1 - 0
packages/grafana-ui/src/components/Select/__snapshots__/SelectOption.test.tsx.snap

@@ -4,6 +4,7 @@ exports[`SelectOption renders correctly 1`] = `
 <div
   id=""
   onClick={[MockFunction]}
+  onMouseMove={[MockFunction]}
   onMouseOver={[MockFunction]}
   tabIndex={1}
 >

+ 13 - 3
packages/grafana-ui/src/components/Table/Table.tsx

@@ -8,6 +8,7 @@ import {
   CellMeasurerCache,
   CellMeasurer,
   GridCellProps,
+  Index,
 } from 'react-virtualized';
 import { Themeable } from '../../types/theme';
 
@@ -26,6 +27,7 @@ import { stringToJsRegex } from '../../utils/index';
 export interface Props extends Themeable {
   data: TableData;
 
+  minColumnWidth: number;
   showHeader: boolean;
   fixedHeader: boolean;
   fixedColumns: number;
@@ -46,6 +48,7 @@ interface State {
 
 interface ColumnRenderInfo {
   header: string;
+  width: number;
   builder: TableCellBuilder;
 }
 
@@ -64,6 +67,7 @@ export class Table extends Component<Props, State> {
     fixedHeader: true,
     fixedColumns: 0,
     rotate: false,
+    minColumnWidth: 150,
   };
 
   constructor(props: Props) {
@@ -76,7 +80,7 @@ export class Table extends Component<Props, State> {
     this.renderer = this.initColumns(props);
     this.measurer = new CellMeasurerCache({
       defaultHeight: 30,
-      defaultWidth: 150,
+      fixedWidth: true,
     });
   }
 
@@ -110,7 +114,8 @@ export class Table extends Component<Props, State> {
 
   /** Given the configuration, setup how each column gets rendered */
   initColumns(props: Props): ColumnRenderInfo[] {
-    const { styles, data } = props;
+    const { styles, data, width, minColumnWidth } = props;
+    const columnWidth = Math.max(width / data.columns.length, minColumnWidth);
 
     return data.columns.map((col, index) => {
       let title = col.text;
@@ -131,6 +136,7 @@ export class Table extends Component<Props, State> {
 
       return {
         header: title,
+        width: columnWidth,
         builder: getCellBuilder(col, style, this.props),
       };
     });
@@ -228,6 +234,10 @@ export class Table extends Component<Props, State> {
     );
   };
 
+  getColumnWidth = (col: Index): number => {
+    return this.renderer[col.index].width;
+  };
+
   render() {
     const { showHeader, fixedHeader, fixedColumns, rotate, width, height } = this.props;
     const { data } = this.state;
@@ -269,7 +279,7 @@ export class Table extends Component<Props, State> {
         rowCount={rowCount}
         overscanColumnCount={8}
         overscanRowCount={8}
-        columnWidth={this.measurer.columnWidth}
+        columnWidth={this.getColumnWidth}
         deferredMeasurementCache={this.measurer}
         cellRenderer={this.cellRenderer}
         rowHeight={this.measurer.rowHeight}

+ 3 - 3
public/app/core/components/Animations/FadeIn.tsx

@@ -1,4 +1,4 @@
-import React, { FC } from 'react';
+import React, { FC, CSSProperties } from 'react';
 import Transition, { ExitHandler } from 'react-transition-group/Transition';
 
 interface Props {
@@ -10,12 +10,12 @@ interface Props {
 }
 
 export const FadeIn: FC<Props> = props => {
-  const defaultStyle = {
+  const defaultStyle: CSSProperties = {
     transition: `opacity ${props.duration}ms linear`,
     opacity: 0,
   };
 
-  const transitionStyles = {
+  const transitionStyles: { [str: string]: CSSProperties } = {
     exited: { opacity: 0, display: 'none' },
     entering: { opacity: 0 },
     entered: { opacity: 1 },

+ 12 - 4
public/app/core/components/Animations/SlideDown.tsx

@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { CSSProperties, FC } from 'react';
 import Transition from 'react-transition-group/Transition';
 
 interface Style {
@@ -16,11 +16,18 @@ export const defaultStyle: Style = {
   overflow: 'hidden',
 };
 
-export default ({ children, in: inProp, maxHeight = defaultMaxHeight, style = defaultStyle }) => {
+export interface Props {
+  children: React.ReactNode;
+  in: boolean;
+  maxHeight?: number;
+  style?: CSSProperties;
+}
+
+export const SlideDown: FC<Props> = ({ children, in: inProp, maxHeight = defaultMaxHeight, style = defaultStyle }) => {
   // There are 4 main states a Transition can be in:
   // ENTERING, ENTERED, EXITING, EXITED
-  // https://reactcommunity.org/react-transition-group/
-  const transitionStyles = {
+  // https://reactcommunity.or[g/react-transition-group/
+  const transitionStyles: { [str: string]: CSSProperties } = {
     exited: { maxHeight: 0 },
     entering: { maxHeight: maxHeight },
     entered: { maxHeight: 'unset', overflow: 'visible' },
@@ -34,6 +41,7 @@ export default ({ children, in: inProp, maxHeight = defaultMaxHeight, style = de
           style={{
             ...style,
             ...transitionStyles[state],
+            inProp,
           }}
         >
           {children}

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

@@ -11,10 +11,10 @@ interface Props {
 }
 
 export class CopyToClipboard extends PureComponent<Props> {
-  clipboardjs: any;
+  clipboardjs: ClipboardJS;
   myRef: any;
 
-  constructor(props) {
+  constructor(props: Props) {
     super(props);
     this.myRef = React.createRef();
   }

+ 2 - 2
public/app/core/components/EmptyListCTA/EmptyListCTA.test.tsx

@@ -1,5 +1,5 @@
 import React from 'react';
-import renderer from 'react-test-renderer';
+import { shallow } from 'enzyme';
 import EmptyListCTA from './EmptyListCTA';
 
 const model = {
@@ -16,7 +16,7 @@ const model = {
 
 describe('EmptyListCTA', () => {
   it('renders correctly', () => {
-    const tree = renderer.create(<EmptyListCTA model={model} />).toJSON();
+    const tree = shallow(<EmptyListCTA model={model} />);
     expect(tree).toMatchSnapshot();
   });
 });

+ 0 - 1
public/app/core/components/JSONFormatter/JSONFormatter.tsx

@@ -1,5 +1,4 @@
 import React, { PureComponent, createRef } from 'react';
-// import JSONFormatterJS, { JSONFormatterConfiguration } from 'json-formatter-js';
 import { JsonExplorer } from 'app/core/core'; // We have made some monkey-patching of json-formatter-js so we can't switch right now
 
 interface Props {

+ 17 - 2
public/app/core/components/SharedPreferences/SharedPreferences.tsx

@@ -3,7 +3,7 @@ import React, { PureComponent } from 'react';
 import { FormLabel, Select } from '@grafana/ui';
 import { getBackendSrv, BackendSrv } from 'app/core/services/backend_srv';
 
-import { DashboardSearchHit } from 'app/types';
+import { DashboardSearchHit, DashboardSearchHitType } from 'app/types';
 
 export interface Props {
   resourceUri: string;
@@ -41,6 +41,21 @@ export class SharedPreferences extends PureComponent<Props, State> {
   async componentDidMount() {
     const prefs = await this.backendSrv.get(`/api/${this.props.resourceUri}/preferences`);
     const dashboards = await this.backendSrv.search({ starred: true });
+    const defaultDashboardHit: DashboardSearchHit = {
+      id: 0,
+      title: 'Default',
+      tags: [],
+      type: '' as DashboardSearchHitType,
+      uid: '',
+      uri: '',
+      url: '',
+      folderId: 0,
+      folderTitle: '',
+      folderUid: '',
+      folderUrl: '',
+      isStarred: false,
+      slug: '',
+    };
 
     if (prefs.homeDashboardId > 0 && !dashboards.find(d => d.id === prefs.homeDashboardId)) {
       const missing = await this.backendSrv.search({ dashboardIds: [prefs.homeDashboardId] });
@@ -53,7 +68,7 @@ export class SharedPreferences extends PureComponent<Props, State> {
       homeDashboardId: prefs.homeDashboardId,
       theme: prefs.theme,
       timezone: prefs.timezone,
-      dashboards: [{ id: 0, title: 'Default', tags: [], type: '', uid: '', uri: '', url: '' }, ...dashboards],
+      dashboards: [defaultDashboardHit, ...dashboards],
     });
   }
 

+ 21 - 14
public/app/core/components/form_dropdown/form_dropdown.ts

@@ -1,7 +1,8 @@
 import _ from 'lodash';
 import coreModule from '../../core_module';
+import { ISCEService, IQService } from 'angular';
 
-function typeaheadMatcher(this: any, item) {
+function typeaheadMatcher(this: any, item: string) {
   let str = this.query;
   if (str === '') {
     return true;
@@ -16,8 +17,8 @@ function typeaheadMatcher(this: any, item) {
 }
 
 export class FormDropdownCtrl {
-  inputElement: any;
-  linkElement: any;
+  inputElement: JQLite;
+  linkElement: JQLite;
   model: any;
   display: any;
   text: any;
@@ -37,7 +38,13 @@ export class FormDropdownCtrl {
   debounce: number;
 
   /** @ngInject */
-  constructor(private $scope, $element, private $sce, private templateSrv, private $q) {
+  constructor(
+    private $scope: any,
+    $element: JQLite,
+    private $sce: ISCEService,
+    private templateSrv: any,
+    private $q: IQService
+  ) {
     this.inputElement = $element.find('input').first();
     this.linkElement = $element.find('a').first();
     this.linkMode = true;
@@ -99,7 +106,7 @@ export class FormDropdownCtrl {
     }
   }
 
-  getOptionsInternal(query) {
+  getOptionsInternal(query: string) {
     const result = this.getOptions({ $query: query });
     if (this.isPromiseLike(result)) {
       return result;
@@ -107,7 +114,7 @@ export class FormDropdownCtrl {
     return this.$q.when(result);
   }
 
-  isPromiseLike(obj) {
+  isPromiseLike(obj: any) {
     return obj && typeof obj.then === 'function';
   }
 
@@ -117,7 +124,7 @@ export class FormDropdownCtrl {
     } else {
       // if we have text use it
       if (this.lookupText) {
-        this.getOptionsInternal('').then(options => {
+        this.getOptionsInternal('').then((options: any) => {
           const item = _.find(options, { value: this.model });
           this.updateDisplay(item ? item.text : this.model);
         });
@@ -127,12 +134,12 @@ export class FormDropdownCtrl {
     }
   }
 
-  typeaheadSource(query, callback) {
-    this.getOptionsInternal(query).then(options => {
+  typeaheadSource(query: string, callback: (res: any) => void) {
+    this.getOptionsInternal(query).then((options: any) => {
       this.optionCache = options;
 
       // extract texts
-      const optionTexts = _.map(options, op => {
+      const optionTexts = _.map(options, (op: any) => {
         return _.escape(op.text);
       });
 
@@ -147,7 +154,7 @@ export class FormDropdownCtrl {
     });
   }
 
-  typeaheadUpdater(text) {
+  typeaheadUpdater(text: string) {
     if (text === this.text) {
       clearTimeout(this.cancelBlur);
       this.inputElement.focus();
@@ -159,7 +166,7 @@ export class FormDropdownCtrl {
     return text;
   }
 
-  switchToLink(fromClick) {
+  switchToLink(fromClick: boolean) {
     if (this.linkMode && !fromClick) {
       return;
     }
@@ -178,7 +185,7 @@ export class FormDropdownCtrl {
     this.cancelBlur = setTimeout(this.switchToLink.bind(this), 200);
   }
 
-  updateValue(text) {
+  updateValue(text: string) {
     text = _.unescape(text);
 
     if (text === '' || this.text === text) {
@@ -214,7 +221,7 @@ export class FormDropdownCtrl {
     });
   }
 
-  updateDisplay(text) {
+  updateDisplay(text: string) {
     this.text = text;
     this.display = this.$sce.trustAsHtml(this.templateSrv.highlightVariablesAsHtml(text));
   }

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

@@ -232,7 +232,7 @@ export class JsonExplorer {
 
     // some pretty handling of number arrays
     if (this.isNumberArray()) {
-      this.json.forEach((val, index) => {
+      this.json.forEach((val: any, index: number) => {
         if (index > 0) {
           arrayWrapperSpan.appendChild(createElement('span', 'array-comma', ','));
         }

+ 4 - 4
public/app/core/components/layout_selector/layout_selector.ts

@@ -16,7 +16,7 @@ export class LayoutSelectorCtrl {
   mode: string;
 
   /** @ngInject */
-  constructor(private $rootScope) {
+  constructor(private $rootScope: any) {
     this.mode = store.get('grafana.list.layout.mode') || 'grid';
   }
 
@@ -46,18 +46,18 @@ export function layoutSelector() {
 }
 
 /** @ngInject */
-export function layoutMode($rootScope) {
+export function layoutMode($rootScope: any) {
   return {
     restrict: 'A',
     scope: {},
-    link: (scope, elem) => {
+    link: (scope: any, elem: any) => {
       const layout = store.get('grafana.list.layout.mode') || 'grid';
       let className = 'card-list-layout-' + layout;
       elem.addClass(className);
 
       $rootScope.onAppEvent(
         'layout-mode-changed',
-        (evt, newLayout) => {
+        (evt: any, newLayout: any) => {
           elem.removeClass(className);
           className = 'card-list-layout-' + newLayout;
           elem.addClass(className);

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

@@ -11,7 +11,8 @@ export interface Section {
   id: number;
   uid: string;
   title: string;
-  expanded: false;
+  expanded: boolean;
+  removable: boolean;
   items: any[];
   url: string;
   icon: string;

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

@@ -3,6 +3,7 @@ import coreModule from 'app/core/core_module';
 import appEvents from 'app/core/app_events';
 import config from 'app/core/config';
 import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
+import { DashboardSearchHit } from 'app/types/search';
 
 export class BackendSrv {
   private inFlightRequests = {};
@@ -237,7 +238,7 @@ export class BackendSrv {
     return this.request({ url: '/api/login/ping', method: 'GET', retry: 1 });
   }
 
-  search(query) {
+  search(query): Promise<DashboardSearchHit[]> {
     return this.get('/api/search', query);
   }
 

+ 22 - 11
public/app/core/services/search_srv.ts

@@ -1,21 +1,32 @@
+// @ts-ignore
 import _ from 'lodash';
+// @ts-ignore
+import { IQService } from 'angular';
+
 import coreModule from 'app/core/core_module';
 import impressionSrv from 'app/core/services/impression_srv';
 import store from 'app/core/store';
 import { contextSrv } from 'app/core/services/context_srv';
+import { BackendSrv } from './backend_srv';
+import { Section } from '../components/manage_dashboards/manage_dashboards';
+import { DashboardSearchHit } from 'app/types/search';
+
+interface Sections {
+  [key: string]: Partial<Section>;
+}
 
 export class SearchSrv {
   recentIsOpen: boolean;
   starredIsOpen: boolean;
 
   /** @ngInject */
-  constructor(private backendSrv, private $q) {
+  constructor(private backendSrv: BackendSrv, private $q: IQService) {
     this.recentIsOpen = store.getBool('search.sections.recent', true);
     this.starredIsOpen = store.getBool('search.sections.starred', true);
   }
 
-  private getRecentDashboards(sections) {
-    return this.queryForRecentDashboards().then(result => {
+  private getRecentDashboards(sections: Sections) {
+    return this.queryForRecentDashboards().then((result: any[]) => {
       if (result.length > 0) {
         sections['recent'] = {
           title: 'Recent',
@@ -30,8 +41,8 @@ export class SearchSrv {
     });
   }
 
-  private queryForRecentDashboards() {
-    const dashIds = _.take(impressionSrv.getDashboardOpened(), 30);
+  private queryForRecentDashboards(): Promise<number[]> {
+    const dashIds: number[] = _.take(impressionSrv.getDashboardOpened(), 30);
     if (dashIds.length === 0) {
       return Promise.resolve([]);
     }
@@ -45,7 +56,7 @@ export class SearchSrv {
     });
   }
 
-  private toggleRecent(section) {
+  private toggleRecent(section: Section) {
     this.recentIsOpen = section.expanded = !section.expanded;
     store.set('search.sections.recent', this.recentIsOpen);
 
@@ -59,13 +70,13 @@ export class SearchSrv {
     });
   }
 
-  private toggleStarred(section) {
+  private toggleStarred(section: Section) {
     this.starredIsOpen = section.expanded = !section.expanded;
     store.set('search.sections.starred', this.starredIsOpen);
     return Promise.resolve(section);
   }
 
-  private getStarred(sections) {
+  private getStarred(sections: Sections) {
     if (!contextSrv.isSignedIn) {
       return Promise.resolve();
     }
@@ -84,7 +95,7 @@ export class SearchSrv {
     });
   }
 
-  search(options) {
+  search(options: any) {
     const sections: any = {};
     const promises = [];
     const query = _.clone(options);
@@ -118,7 +129,7 @@ export class SearchSrv {
     });
   }
 
-  private handleSearchResult(sections, results) {
+  private handleSearchResult(sections: Sections, results: DashboardSearchHit[]): any {
     if (results.length === 0) {
       return sections;
     }
@@ -177,7 +188,7 @@ export class SearchSrv {
     }
   }
 
-  private toggleFolder(section) {
+  private toggleFolder(section: Section) {
     section.expanded = !section.expanded;
     section.icon = section.expanded ? 'fa fa-folder-open' : 'fa fa-folder';
 

+ 1 - 0
public/app/core/specs/manage_dashboards.test.ts

@@ -16,6 +16,7 @@ const mockSection = (overides?: object): Section => {
     items: [],
     checked: false,
     expanded: false,
+    removable: false,
     hideHeader: false,
     icon: '',
     score: 0,

+ 17 - 13
public/app/core/specs/search_srv.test.ts

@@ -1,8 +1,12 @@
+// @ts-ignore
+import { IQService } from 'angular';
+
 import { SearchSrv } from 'app/core/services/search_srv';
 import { BackendSrvMock } from 'test/mocks/backend_srv';
 import impressionSrv from 'app/core/services/impression_srv';
 import { contextSrv } from 'app/core/services/context_srv';
 import { beforeEach } from 'test/lib/common';
+import { BackendSrv } from '../services/backend_srv';
 
 jest.mock('app/core/store', () => {
   return {
@@ -18,18 +22,18 @@ jest.mock('app/core/services/impression_srv', () => {
 });
 
 describe('SearchSrv', () => {
-  let searchSrv, backendSrvMock;
+  let searchSrv: SearchSrv, backendSrvMock: BackendSrvMock;
 
   beforeEach(() => {
     backendSrvMock = new BackendSrvMock();
-    searchSrv = new SearchSrv(backendSrvMock, Promise);
+    searchSrv = new SearchSrv(backendSrvMock as BackendSrv, (Promise as any) as IQService);
 
     contextSrv.isSignedIn = true;
     impressionSrv.getDashboardOpened = jest.fn().mockReturnValue([]);
   });
 
   describe('With recent dashboards', () => {
-    let results;
+    let results: any;
 
     beforeEach(() => {
       backendSrvMock.search = jest
@@ -56,7 +60,7 @@ describe('SearchSrv', () => {
     });
 
     describe('and 3 recent dashboards removed in backend', () => {
-      let results;
+      let results: any;
 
       beforeEach(() => {
         backendSrvMock.search = jest
@@ -80,7 +84,7 @@ describe('SearchSrv', () => {
   });
 
   describe('With starred dashboards', () => {
-    let results;
+    let results: any;
 
     beforeEach(() => {
       backendSrvMock.search = jest.fn().mockReturnValue(Promise.resolve([{ id: 1, title: 'starred' }]));
@@ -97,7 +101,7 @@ describe('SearchSrv', () => {
   });
 
   describe('With starred dashboards and recent', () => {
-    let results;
+    let results: any;
 
     beforeEach(() => {
       backendSrvMock.search = jest
@@ -125,7 +129,7 @@ describe('SearchSrv', () => {
   });
 
   describe('with no query string and dashboards with folders returned', () => {
-    let results;
+    let results: any;
 
     beforeEach(() => {
       backendSrvMock.search = jest
@@ -173,12 +177,10 @@ describe('SearchSrv', () => {
   });
 
   describe('with query string and dashboards with folders returned', () => {
-    let results;
+    let results: any;
 
     beforeEach(() => {
-      backendSrvMock.search = jest.fn();
-
-      backendSrvMock.search.mockReturnValue(
+      backendSrvMock.search = jest.fn().mockReturnValue(
         Promise.resolve([
           {
             id: 2,
@@ -249,8 +251,9 @@ describe('SearchSrv', () => {
       backendSrvMock.search = jest.fn();
       backendSrvMock.search.mockReturnValue(Promise.resolve([]));
 
-      searchSrv.getRecentDashboards = () => {
+      searchSrv['getRecentDashboards'] = () => {
         getRecentDashboardsCalled = true;
+        return Promise.resolve();
       };
 
       return searchSrv.search({ skipRecent: true }).then(() => {});
@@ -269,8 +272,9 @@ describe('SearchSrv', () => {
       backendSrvMock.search.mockReturnValue(Promise.resolve([]));
       impressionSrv.getDashboardOpened = jest.fn().mockReturnValue([]);
 
-      searchSrv.getStarred = () => {
+      searchSrv['getStarred'] = () => {
         getStarredCalled = true;
+        return Promise.resolve();
       };
 
       return searchSrv.search({ skipStarred: true }).then(() => {});

+ 1 - 1
public/app/features/api-keys/ApiKeysPage.tsx

@@ -7,7 +7,7 @@ import { getNavModel } from 'app/core/selectors/navModel';
 import { getApiKeys, getApiKeysCount } from './state/selectors';
 import { loadApiKeys, deleteApiKey, setSearchQuery, addApiKey } from './state/actions';
 import Page from 'app/core/components/Page/Page';
-import SlideDown from 'app/core/components/Animations/SlideDown';
+import { SlideDown } from 'app/core/components/Animations/SlideDown';
 import ApiKeysAddedModal from './ApiKeysAddedModal';
 import config from 'app/core/config';
 import appEvents from 'app/core/app_events';

+ 1 - 1
public/app/features/dashboard/components/DashboardPermissions/DashboardPermissions.tsx

@@ -1,6 +1,6 @@
 import React, { PureComponent } from 'react';
 import { Tooltip } from '@grafana/ui';
-import SlideDown from 'app/core/components/Animations/SlideDown';
+import { SlideDown } from 'app/core/components/Animations/SlideDown';
 import { StoreState, FolderInfo } from 'app/types';
 import { DashboardAcl, PermissionLevel, NewDashboardAclItem } from 'app/types/acl';
 import {

+ 6 - 6
public/app/features/dashboard/state/PanelModel.ts

@@ -111,12 +111,12 @@ export class PanelModel {
   cachedPluginOptions?: any;
   legend?: { show: boolean };
 
-  constructor(model) {
+  constructor(model: any) {
     this.events = new Emitter();
 
     // copy properties from persisted model
     for (const property in model) {
-      this[property] = model[property];
+      (this as any)[property] = model[property];
     }
 
     // defaults
@@ -150,7 +150,7 @@ export class PanelModel {
     }
   }
 
-  getOptions(panelDefaults) {
+  getOptions(panelDefaults: any) {
     return _.defaultsDeep(this.options || {}, panelDefaults);
   }
 
@@ -227,7 +227,7 @@ export class PanelModel {
       }
       return {
         ...acc,
-        [property]: this[property],
+        [property]: (this as any)[property],
       };
     }, {});
   }
@@ -236,7 +236,7 @@ export class PanelModel {
     const prevOptions = this.cachedPluginOptions[pluginId] || {};
 
     Object.keys(prevOptions).map(property => {
-      this[property] = prevOptions[property];
+      (this as any)[property] = prevOptions[property];
     });
   }
 
@@ -252,7 +252,7 @@ export class PanelModel {
         continue;
       }
 
-      delete this[key];
+      delete (this as any)[key];
     }
 
     this.cachedPluginOptions[oldPluginId] = oldOptions;

+ 1 - 1
public/app/features/folders/FolderPermissions.tsx

@@ -3,7 +3,7 @@ import { hot } from 'react-hot-loader';
 import { connect } from 'react-redux';
 import Page from 'app/core/components/Page/Page';
 import { Tooltip } from '@grafana/ui';
-import SlideDown from 'app/core/components/Animations/SlideDown';
+import { SlideDown } from 'app/core/components/Animations/SlideDown';
 import { getNavModel } from 'app/core/selectors/navModel';
 import { NavModel, StoreState, FolderState } from 'app/types';
 import { DashboardAcl, PermissionLevel, NewDashboardAclItem } from 'app/types/acl';

+ 1 - 1
public/app/features/teams/TeamGroupSync.tsx

@@ -1,6 +1,6 @@
 import React, { PureComponent } from 'react';
 import { connect } from 'react-redux';
-import SlideDown from 'app/core/components/Animations/SlideDown';
+import { SlideDown } from 'app/core/components/Animations/SlideDown';
 import { Tooltip } from '@grafana/ui';
 import { TeamGroup } from '../../types';
 import { addTeamGroup, loadTeamGroups, removeTeamGroup } from './state/actions';

+ 1 - 1
public/app/features/teams/TeamMembers.tsx

@@ -1,6 +1,6 @@
 import React, { PureComponent } from 'react';
 import { connect } from 'react-redux';
-import SlideDown from 'app/core/components/Animations/SlideDown';
+import { SlideDown } from 'app/core/components/Animations/SlideDown';
 import { UserPicker } from 'app/core/components/Select/UserPicker';
 import { TagBadge } from 'app/core/components/TagFilter/TagBadge';
 import { TeamMember, User } from 'app/types';

+ 0 - 6
public/app/plugins/panel/graph/threshold_manager.ts

@@ -216,12 +216,6 @@ export class ThresholdManager {
           break;
         }
         case 'custom': {
-          if (!threshold.fillColor) {
-            threshold.fillColor = 'rgba(255, 255, 255, 1)';
-          }
-          if (!threshold.lineColor) {
-            threshold.lineColor = 'rgba(255, 255, 255, 0)';
-          }
           fillColor = threshold.fillColor;
           lineColor = threshold.lineColor;
           break;

+ 2 - 2
public/app/plugins/panel/graph/thresholds_form.html

@@ -23,7 +23,7 @@
         <label class="gf-form-label">Color</label>
         <div class="gf-form-select-wrapper">
           <select class="gf-form-input" ng-model="threshold.colorMode"
-                  ng-options="f for f in ['custom', 'critical', 'warning', 'ok']" ng-change="ctrl.render()" ng-disabled="ctrl.disabled">
+                  ng-options="f for f in ['custom', 'critical', 'warning', 'ok']" ng-change="ctrl.onThresholdTypeChange($index)" ng-disabled="ctrl.disabled">
           </select>
         </div>
       </div>
@@ -73,4 +73,4 @@
       </button>
     </div>
   </div>
-</div>
+</div>

+ 15 - 1
public/app/plugins/panel/graph/thresholds_form.ts

@@ -1,5 +1,6 @@
 import coreModule from 'app/core/core_module';
-
+import config from 'app/core/config';
+import tinycolor from 'tinycolor2';
 export class ThresholdFormCtrl {
   panelCtrl: any;
   panel: any;
@@ -56,6 +57,19 @@ export class ThresholdFormCtrl {
       this.render();
     };
   }
+
+  onThresholdTypeChange(index) {
+    // Because of the ng-model binding, threshold's color mode is already set here
+    if (this.panel.thresholds[index].colorMode === 'custom') {
+      this.panel.thresholds[index].fillColor = tinycolor(config.theme.colors.blueBase)
+        .setAlpha(0.2)
+        .toRgbString();
+      this.panel.thresholds[index].lineColor = tinycolor(config.theme.colors.blueShade)
+        .setAlpha(0.6)
+        .toRgbString();
+    }
+    this.panelCtrl.render();
+  }
 }
 
 coreModule.directive('graphThresholdForm', () => {

+ 0 - 1
public/app/plugins/panel/singlestat2/SingleStatPanel.tsx

@@ -17,7 +17,6 @@ export const getSingleStatValues = (props: PanelProps<SingleStatBaseOptions>): D
     decimals: valueOptions.decimals,
     mappings: valueMappings,
     thresholds: options.thresholds,
-
     prefix: replaceVariables(valueOptions.prefix),
     suffix: replaceVariables(valueOptions.suffix),
     theme: config.theme,

+ 0 - 0
public/app/types/jquery.d.ts → public/app/types/jquery/jquery.d.ts


+ 14 - 3
public/app/types/search.ts

@@ -1,9 +1,20 @@
+export enum DashboardSearchHitType {
+  DashHitDB = 'dash-db',
+  DashHitHome = 'dash-home',
+  DashHitFolder = 'dash-folder',
+}
 export interface DashboardSearchHit {
   id: number;
-  tags: string[];
-  title: string;
-  type: string;
   uid: string;
+  title: string;
   uri: string;
   url: string;
+  slug: string;
+  type: DashboardSearchHitType;
+  tags: string[];
+  isStarred: boolean;
+  folderId: number;
+  folderUid: string;
+  folderTitle: string;
+  folderUrl: string;
 }

+ 1 - 1
tsconfig.json

@@ -27,7 +27,7 @@
     "noUnusedLocals": true,
     "baseUrl": "public",
     "pretty": true,
-    "typeRoots": ["node_modules/@types", "types"],
+    "typeRoots": ["node_modules/@types", "public/app/types"],
     "paths": {
       "app": ["app"],
       "sass": ["sass"]

文件差异内容过多而无法显示
+ 291 - 289
yarn.lock


部分文件因为文件数量过多而无法显示