bosun.org@v0.0.0-20210513094433-e25bc3e69a1f/cmd/bosun/web/static/js/0-bosun.ts (about)

     1  /// <reference path="angular.d.ts" />
     2  /// <reference path="angular-route.d.ts" />
     3  /// <reference path="angular-sanitize.d.ts" />
     4  /// <reference path="bootstrap.d.ts" />
     5  /// <reference path="jquery.d.ts" />
     6  /// <reference path="underscore.d.ts" />
     7  /// <reference path="models.ts" />
     8  
     9  declare var d3: any;
    10  
    11  var bosunApp = angular.module('bosunApp', [
    12      'ngRoute',
    13      'bosunControllers',
    14      'mgcrea.ngStrap',
    15      'mgcrea.ngStrap.tooltip',
    16      'ngSanitize',
    17      'ui.ace',
    18      'ngclipboard',
    19  ]);
    20  
    21  interface ITitleRoute extends ng.route.IRoute {
    22      title?: string;
    23  }
    24  
    25  bosunApp.config(['$routeProvider', '$locationProvider', '$httpProvider', function ($routeProvider: ng.route.IRouteProvider, $locationProvider: ng.ILocationProvider, $httpProvider: ng.IHttpProvider) {
    26      $locationProvider.html5Mode({
    27          enabled: true,
    28          requireBase: false
    29      });
    30  
    31      var when = (u: string, r: ITitleRoute) => {
    32          $routeProvider.when(u, r);
    33      }
    34  
    35      when('/', {
    36          title: 'Dashboard',
    37          templateUrl: 'partials/dashboard.html',
    38          controller: 'DashboardCtrl',
    39      })
    40      when('/items', {
    41          title: 'Items',
    42          templateUrl: 'partials/items.html',
    43          controller: 'ItemsCtrl',
    44      })
    45      when('/expr', {
    46          title: 'Expression',
    47          templateUrl: 'partials/expr.html',
    48          controller: 'ExprCtrl',
    49      })
    50      when('/errors', {
    51          title: 'Errors',
    52          templateUrl: 'partials/errors.html',
    53          controller: 'ErrorCtrl',
    54      })
    55      when('/graph', {
    56          title: 'Graph',
    57          templateUrl: 'partials/graph.html',
    58          controller: 'GraphCtrl',
    59      })
    60      when('/host', {
    61          title: 'Host View',
    62          templateUrl: 'partials/host.html',
    63          controller: 'HostCtrl',
    64          reloadOnSearch: false,
    65      })
    66      when('/silence', {
    67          title: 'Silence',
    68          templateUrl: 'partials/silence.html',
    69          controller: 'SilenceCtrl',
    70      })
    71      when('/config', {
    72          title: 'Configuration',
    73          templateUrl: 'partials/config.html',
    74          controller: 'ConfigCtrl',
    75          reloadOnSearch: false,
    76      })
    77      when('/action', {
    78          title: 'Action',
    79          templateUrl: 'partials/action.html',
    80          controller: 'ActionCtrl',
    81      })
    82      when('/history', {
    83          title: 'Alert History',
    84          templateUrl: 'partials/history.html',
    85          controller: 'HistoryCtrl',
    86      })
    87      when('/put', {
    88          title: 'Data Entry',
    89          templateUrl: 'partials/put.html',
    90          controller: 'PutCtrl',
    91      })
    92      when('/annotation', {
    93          title: 'Annotation',
    94          templateUrl: 'partials/annotation.html',
    95          controller: 'AnnotationCtrl',
    96      })
    97      when('/incident', {
    98          title: 'Incident',
    99          templateUrl: 'partials/incident.html',
   100          controller: 'IncidentCtrl',
   101      })
   102      when('/tokens', {
   103          title: 'Access Tokens',
   104          template: `<token-list></token-list>`,
   105      })
   106      when('/tokens/new', {
   107          title: 'New Access Token',
   108          template: `<new-token></new-token>`,
   109      })
   110      $routeProvider.otherwise({
   111          redirectTo: '/',
   112      });
   113      $httpProvider.interceptors.push(function ($q) {
   114          return {
   115              'request': function (config) {
   116                  config.headers['X-Miniprofiler'] = 'true';
   117                  return config;
   118              },
   119          };
   120      });
   121  }]);
   122  
   123  interface IRootScope extends ng.IScope {
   124      title: string;
   125      shortlink: boolean;
   126  }
   127  
   128  interface IAuthService {
   129      Init: (authEnabled: boolean, username: string, roles: RoleDefs, userPerms: number) => void;
   130      HasPermission: (role: string) => boolean;
   131      GetRoles: () => RoleDefs;
   132      Username: (u: string) => string;
   133      GetUsername: () => string;
   134      Enabled: () => boolean;
   135      PermissionsFor: (bits: number) => string[];
   136      RoleFor: (bits: number) => string;
   137  }
   138  
   139  interface ILinkService {
   140  	GetEditSilenceLink: (silence: any, silenceId: string) => string;
   141  }
   142  
   143  bosunApp.run(['$location', '$rootScope', function ($location: ng.ILocationService, $rootScope: IRootScope) {
   144      $rootScope.$on('$routeChangeSuccess', function (event, current, previous) {
   145          $rootScope.title = current.$$route.title;
   146          $rootScope.shortlink = false;
   147      });
   148  }]);
   149  
   150  var bosunControllers = angular.module('bosunControllers', []);
   151  
   152  interface RootScope extends ng.IScope {
   153      setKey: (key: string, value: any) => void;
   154      getKey: (key: string) => any;
   155  }
   156  
   157  interface IBosunScope extends RootScope {
   158      active: (v: string) => any;
   159      json: (v: any) => string;
   160      btoa: (v: any) => string;
   161      encode: (v: string) => string;
   162      panelClass: (v: string) => string;
   163      timeanddate: number[];
   164      req_from_m: (m: string) => GraphRequest;
   165      schedule: StateGroups;
   166      refresh: (filter: string) => any;
   167      animate: () => any;
   168      stop: (all?: boolean) => any;
   169      shorten: () => any;
   170      shortlink: any;
   171      values: any;
   172      annotateEnabled: boolean;
   173      opentsdbEnabled: boolean;
   174      saveEnabled: boolean;
   175      quiet: boolean;
   176      version: any;
   177      init: any;
   178      auth: IAuthService;
   179      tokensEnabled: boolean;
   180  }
   181  
   182  bosunControllers.controller('BosunCtrl', ['$scope', '$route', '$http', '$q', '$rootScope', 'authService',
   183      function ($scope: IBosunScope, $route: ng.route.IRouteService, $http: ng.IHttpService, $q: ng.IQService, $rootScope: IRootScope, AuthService: IAuthService) {
   184          $scope.$on('$routeChangeSuccess', function (event, current, previous) {
   185              $scope.stop(true);
   186          });
   187          $scope.active = (v: string) => {
   188              if (!$route.current) {
   189                  return null;
   190              }
   191              if ($route.current.loadedTemplateUrl == 'partials/' + v + '.html') {
   192                  return { active: true };
   193              }
   194              return null;
   195          };
   196          $scope.init = (settings: any) => {
   197              $scope.saveEnabled = settings.SaveEnabled;
   198              $scope.annotateEnabled = settings.AnnotateEnabled;
   199              $scope.quiet = settings.Quiet;
   200              $scope.version = settings.Version;
   201              $scope.opentsdbEnabled = $scope.version.Major != 0 && $scope.version.Minor != 0;
   202              $scope.exampleExpression = settings.ExampleExpression;
   203              $scope.tokensEnabled = settings.TokensEnabled;
   204              $scope.auth = AuthService;
   205              AuthService.Init(settings.AuthEnabled, settings.Username, settings.Roles, settings.Permissions)
   206          }
   207          $scope.json = (v: any) => {
   208              return JSON.stringify(v, null, '  ');
   209          };
   210          $scope.btoa = (v: any) => {
   211              return encodeURIComponent(btoa(v));
   212          };
   213          $scope.encode = (v: string) => {
   214              return encodeURIComponent(v);
   215          };
   216          $scope.req_from_m = (m: string) => {
   217              var r = new GraphRequest();
   218              var q = new Query(false);
   219              q.metric = m;
   220              r.queries.push(q);
   221              return r;
   222          };
   223          $scope.panelClass = (status: string, prefix = "panel-") => {
   224              switch (status) {
   225                  case "critical": return prefix + "danger";
   226                  case "unknown": return prefix + "info";
   227                  case "warning": return prefix + "warning";
   228                  case "normal": return prefix + "success";
   229                  case "error": return prefix + "danger";
   230                  default: return prefix + "default";
   231              }
   232          };
   233          $scope.values = {};
   234          $scope.setKey = (key: string, value: any) => {
   235              if (value === undefined) {
   236                  delete $scope.values[key];
   237              } else {
   238                  $scope.values[key] = value;
   239              }
   240          };
   241          $scope.getKey = (key: string) => {
   242              return $scope.values[key];
   243          };
   244          var scheduleFilter: string;
   245          $scope.refresh = (filter: string) => {
   246              var d = $q.defer();
   247              scheduleFilter = filter;
   248              $scope.animate();
   249  
   250              var p = $http.get('/api/alerts?filter=' + encodeURIComponent(filter || ""))
   251                  .success((data: any) => {
   252                      $scope.schedule = new StateGroups(data);
   253                      $scope.timeanddate = data.TimeAndDate;
   254                      d.resolve();
   255                  })
   256                  .error(err => {
   257                      d.reject(err);
   258                  });
   259              p.finally($scope.stop);
   260              return d.promise;
   261          };
   262          // Size of the logo in (width and height) of the Bosun logo in the navbar
   263          var sz = 25;
   264          var orig = 700;
   265          var light = '#4ba2d9';
   266          var dark = '#1f5296';
   267          var med = '#356eb6';
   268          var mult = sz / orig;
   269          var bgrad = 25 * mult;
   270          var circles = [
   271              [150, 150, dark],
   272              [550, 150, dark],
   273              [150, 550, light],
   274              [550, 550, light],
   275          ];
   276          var svg = d3.select('#logo')
   277              .append('svg')
   278              .attr('height', sz)
   279              .attr('width', sz);
   280          svg.selectAll('rect.bg')
   281              .data([[0, light], [sz / 2, dark]])
   282              .enter()
   283              .append('rect')
   284              .attr('class', 'bg')
   285              .attr('width', sz)
   286              .attr('height', sz / 2)
   287              .attr('rx', bgrad)
   288              .attr('ry', bgrad)
   289              .attr('fill', (d: any) => { return d[1]; })
   290              .attr('y', (d: any) => { return d[0]; });
   291          svg.selectAll('path.diamond')
   292              .data([150, 550])
   293              .enter()
   294              .append('path')
   295              .attr('d', (d: any) => {
   296                  var s = 'M ' + d * mult + ' ' + 150 * mult;
   297                  var w = 200 * mult;
   298                  s += ' l ' + w + ' ' + w;
   299                  s += ' l ' + -w + ' ' + w;
   300                  s += ' l ' + -w + ' ' + -w + ' Z';
   301                  return s;
   302              })
   303              .attr('fill', med)
   304              .attr('stroke', 'white')
   305              .attr('stroke-width', 15 * mult);
   306          svg.selectAll('rect.white')
   307              .data([150, 350, 550])
   308              .enter()
   309              .append('rect')
   310              .attr('class', 'white')
   311              .attr('width', .5)
   312              .attr('height', '100%')
   313              .attr('fill', 'white')
   314              .attr('x', (d: any) => { return d * mult; });
   315          svg.selectAll('circle')
   316              .data(circles)
   317              .enter()
   318              .append('circle')
   319              .attr('cx', (d: any) => { return d[0] * mult; })
   320              .attr('cy', (d: any) => { return d[1] * mult; })
   321              .attr('r', 62.5 * mult)
   322              .attr('fill', (d: any) => { return d[2]; })
   323              .attr('stroke', 'white')
   324              .attr('stroke-width', 25 * mult);
   325          var transitionDuration = 750;
   326          var animateCount = 0;
   327          $scope.animate = () => {
   328              animateCount++;
   329              if (animateCount == 1) {
   330                  doAnimate();
   331              }
   332          };
   333          function doAnimate() {
   334              if (!animateCount) {
   335                  return;
   336              }
   337              d3.shuffle(circles);
   338              svg.selectAll('circle')
   339                  .data(circles, (d: any, i: any) => { return i; })
   340                  .transition()
   341                  .duration(transitionDuration)
   342                  .attr('cx', (d: any) => { return d[0] * mult; })
   343                  .attr('cy', (d: any) => { return d[1] * mult; })
   344                  .attr('fill', (d: any) => { return d[2]; });
   345              setTimeout(doAnimate, transitionDuration);
   346          }
   347          $scope.stop = (all = false) => {
   348              if (all) {
   349                  animateCount = 0;
   350              } else if (animateCount > 0) {
   351                  animateCount--;
   352              }
   353          };
   354          var short: any = $('#shortlink')[0];
   355          $scope.shorten = () => {
   356              $http.get('/api/shorten').success((data: any) => {
   357                  if (data.id) {
   358                      short.value = data.id;
   359                      $rootScope.shortlink = true;
   360                      setTimeout(() => {
   361                          short.setSelectionRange(0, data.id.length);
   362                      });
   363                  }
   364              });
   365          };
   366      }]);
   367  
   368  
   369  var tsdbDateFormat = 'YYYY/MM/DD-HH:mm:ss';
   370  
   371  interface MomentStatic {
   372      defaultFormat: string;
   373  }
   374  
   375  moment.defaultFormat = tsdbDateFormat;
   376  
   377  moment.locale('en', {
   378      relativeTime: {
   379          future: "in %s",
   380          past: "%s-ago",
   381          s: "%ds",
   382          m: "%dm",
   383          mm: "%dm",
   384          h: "%dh",
   385          hh: "%dh",
   386          d: "%dd",
   387          dd: "%dd",
   388          M: "%dn",
   389          MM: "%dn",
   390          y: "%dy",
   391          yy: "%dy"
   392      },
   393  });
   394  
   395  function ruleUrl(ak, fromTime) {
   396      var openBrack = ak.indexOf("{");
   397      var closeBrack = ak.indexOf("}");
   398      var alertName = ak.substr(0, openBrack);
   399      var template = ak.substring(openBrack + 1, closeBrack);
   400      var url = '/api/rule?' +
   401          'alert=' + encodeURIComponent(alertName) +
   402          '&from=' + encodeURIComponent(fromTime.format()) +
   403          '&template_group=' + encodeURIComponent(template);
   404      return url
   405  }
   406  
   407  function configUrl(ak, fromTime) {
   408      var openBrack = ak.indexOf("{");
   409      var closeBrack = ak.indexOf("}");
   410      var alertName = ak.substr(0, openBrack);
   411      var template = ak.substring(openBrack + 1, closeBrack);
   412      // http://bosun/config?alert=haproxy.server.downtime.ny&fromDate=2016-07-10&fromTime=21%3A03
   413      var url = '/config?' +
   414          'alert=' + encodeURIComponent(alertName) +
   415          '&fromDate=' + encodeURIComponent(fromTime.format("YYYY-MM-DD")) +
   416          '&fromTime=' + encodeURIComponent(fromTime.format("HH:mm"));
   417      return url
   418  }
   419  
   420  
   421  // From http://www.quirksmode.org/js/cookies.html
   422  
   423  declare function escape(string: string): string;
   424  
   425  declare function unescape(string: string): string;
   426  
   427  function createCookie(name, value, days) {
   428      var expires;
   429      if (days) {
   430          var date = new Date();
   431          date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
   432          expires = "; expires=" + date.toUTCString();
   433      } else {
   434          expires = "";
   435      }
   436      document.cookie = escape(name) + "=" + escape(value) + expires + "; path=/";
   437  }
   438  
   439  function readCookie(name) {
   440      var nameEQ = escape(name) + "=";
   441      var ca = document.cookie.split(';');
   442      for (var i = 0; i < ca.length; i++) {
   443          var c = ca[i];
   444          while (c.charAt(0) === ' ') c = c.substring(1, c.length);
   445          if (c.indexOf(nameEQ) === 0) return unescape(c.substring(nameEQ.length, c.length));
   446      }
   447      return null;
   448  }
   449  
   450  function eraseCookie(name) {
   451      createCookie(name, "", -1);
   452  }
   453  
   454  function getOwner() {
   455      return readCookie('action-owner');
   456  }
   457  
   458  function setOwner(name) {
   459      createCookie('action-owner', name, 1000);
   460  }
   461  
   462  function getShowAnnotations() {
   463      return readCookie('annotations-show');
   464  }
   465  
   466  function setShowAnnotations(yes) {
   467      createCookie('annotations-show', yes, 1000);
   468  }
   469  
   470  
   471  
   472  // from: http://stackoverflow.com/a/15267754/864236
   473  
   474  bosunApp.filter('reverse', function () {
   475      return function (items) {
   476          if (!angular.isArray(items)) {
   477              return [];
   478          }
   479          return items.slice().reverse();
   480      };
   481  });
   482  
   483  var timeFormat = 'YYYY-MM-DDTHH:mm:ssZ';