github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/ui/src/redux/timewindow.ts (about)

     1  // Copyright 2018 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  /**
    12   * This module maintains a globally-available time window, currently used by all
    13   * metrics graphs in the ui.
    14   */
    15  
    16  import { Action } from "redux";
    17  import { PayloadAction } from "src/interfaces/action";
    18  import _ from "lodash";
    19  import moment from "moment";
    20  
    21  export const SET_WINDOW = "cockroachui/timewindow/SET_WINDOW";
    22  export const SET_RANGE = "cockroachui/timewindow/SET_RANGE";
    23  export const SET_SCALE = "cockroachui/timewindow/SET_SCALE";
    24  
    25  /**
    26   * TimeWindow represents an absolute window of time, defined with a start and
    27   * end time.
    28   */
    29  export interface TimeWindow {
    30    start: moment.Moment;
    31    end: moment.Moment;
    32  }
    33  
    34  /**
    35   * TimeScale describes the requested dimensions of TimeWindows; it
    36   * prescribes a length for the window, along with a period of time that a
    37   * newly created TimeWindow will remain valid.
    38   */
    39  export interface TimeScale {
    40    // The key used to index in to the availableTimeScales collection.
    41    key?: string;
    42    // The size of a global time window. Default is ten minutes.
    43    windowSize: moment.Duration;
    44    // The length of time the global time window is valid. The current time window
    45    // is invalid if now > (currentWindow.end + windowValid). Default is ten
    46    // seconds. If windowEnd is set this is ignored.
    47    windowValid?: moment.Duration;
    48    // The expected duration of individual samples for queries at this time scale.
    49    sampleSize: moment.Duration;
    50    // The end time of the window if it isn't the present
    51    windowEnd?: moment.Moment;
    52  }
    53  
    54  export interface TimeScaleCollection {
    55    [key: string]: TimeScale;
    56  }
    57  
    58  /**
    59   * availableTimeScales is a preconfigured set of time scales that can be
    60   * selected by the user.
    61   */
    62  export let availableTimeScales: TimeScaleCollection = _.mapValues(
    63    {
    64      "Past 10 Minutes": {
    65        windowSize: moment.duration(10, "minutes"),
    66        windowValid: moment.duration(10, "seconds"),
    67        sampleSize: moment.duration(10, "seconds"),
    68      },
    69      "Past 1 Hour": {
    70        windowSize: moment.duration(1, "hour"),
    71        windowValid: moment.duration(1, "minute"),
    72        sampleSize: moment.duration(30, "seconds"),
    73      },
    74      "Past 6 Hours": {
    75        windowSize: moment.duration(6, "hours"),
    76        windowValid: moment.duration(5, "minutes"),
    77        sampleSize: moment.duration(1, "minutes"),
    78      },
    79      "Past 1 Day": {
    80        windowSize: moment.duration(1, "day"),
    81        windowValid: moment.duration(10, "minutes"),
    82        sampleSize: moment.duration(5, "minutes"),
    83      },
    84      "Past 2 Days": {
    85        windowSize: moment.duration(2, "day"),
    86        windowValid: moment.duration(10, "minutes"),
    87        sampleSize: moment.duration(5, "minutes"),
    88      },
    89      "Past 3 Days": {
    90        windowSize: moment.duration(3, "day"),
    91        windowValid: moment.duration(10, "minutes"),
    92        sampleSize: moment.duration(5, "minutes"),
    93      },
    94      "Past Week": {
    95        windowSize: moment.duration(7, "days"),
    96        windowValid: moment.duration(10, "minutes"),
    97        sampleSize: moment.duration(30, "minutes"),
    98      },
    99      "Past 2 Weeks": {
   100        windowSize: moment.duration(14, "days"),
   101        windowValid: moment.duration(10, "minutes"),
   102        sampleSize: moment.duration(30, "minutes"),
   103      },
   104      "Past Month": {
   105        windowSize: moment.duration(moment().daysInMonth(), "days"),
   106        windowValid: moment.duration(20, "minutes"),
   107        sampleSize: moment.duration(1, "hour"),
   108      },
   109      "Past 2 Months": {
   110        windowSize: moment.duration(moment().daysInMonth() * 2, "days"),
   111        windowValid: moment.duration(20, "minutes"),
   112        sampleSize: moment.duration(1, "hour"),
   113      },
   114    },
   115    (v, k) => {
   116      // This weirdness is to work around an apparent issue in TypeScript:
   117      // https://github.com/Microsoft/TypeScript/issues/20305
   118      const result: TimeScale = v;
   119      // Set the "key" attribute.
   120      result.key = k;
   121      return result;
   122    },
   123  );
   124  
   125  export const findClosestTimeScale = (seconds: number) => {
   126    const data: TimeScale[] = [];
   127    Object.keys(availableTimeScales).forEach((val) => data.push(availableTimeScales[val]));
   128    data.sort( (a, b) => (Math.abs(seconds - a.windowSize.asSeconds()) - Math.abs(seconds - b.windowSize.asSeconds())) );
   129    return data[0].windowSize.asSeconds() === seconds ? data[0] : { ...data[0], key: "Custom" };
   130  };
   131  
   132  export class TimeWindowState {
   133    // Currently selected scale.
   134    scale: TimeScale;
   135    // Currently established time window.
   136    currentWindow: TimeWindow;
   137    // True if scale has changed since currentWindow was generated.
   138    scaleChanged: boolean;
   139    useTimeRange: boolean;
   140    constructor() {
   141      this.scale = availableTimeScales["Past 10 Minutes"];
   142      this.useTimeRange = false;
   143      this.scaleChanged = false;
   144    }
   145  }
   146  
   147  export function timeWindowReducer(state = new TimeWindowState(), action: Action): TimeWindowState {
   148    switch (action.type) {
   149      case SET_WINDOW:
   150        const { payload: tw } = action as PayloadAction<TimeWindow>;
   151        state = _.clone(state);
   152        state.currentWindow = tw;
   153        state.scaleChanged = false;
   154        return state;
   155      case SET_RANGE:
   156        const { payload: data } = action as PayloadAction<TimeWindow>;
   157        state = _.clone(state);
   158        state.currentWindow = data;
   159        state.useTimeRange = true;
   160        state.scaleChanged = false;
   161        return state;
   162      case SET_SCALE:
   163        const { payload: scale } = action as PayloadAction<TimeScale>;
   164        state = _.clone(state);
   165        if (scale.key === "Custom") {
   166          state.useTimeRange = true;
   167        } else {
   168          state.useTimeRange = false;
   169        }
   170        state.scale = scale;
   171        state.scaleChanged = true;
   172        return state;
   173      default:
   174        return state;
   175    }
   176  }
   177  
   178  export function setTimeWindow(tw: TimeWindow): PayloadAction<TimeWindow> {
   179    return {
   180      type: SET_WINDOW,
   181      payload: tw,
   182    };
   183  }
   184  
   185  export function setTimeRange(tw: TimeWindow): PayloadAction<TimeWindow> {
   186    return {
   187      type: SET_RANGE,
   188      payload: tw,
   189    };
   190  }
   191  
   192  export function setTimeScale(ts: TimeScale): PayloadAction<TimeScale> {
   193    return {
   194      type: SET_SCALE,
   195      payload: ts,
   196    };
   197  }