summaryrefslogtreecommitdiffstats
path: root/src/pybind/mgr/dashboard/frontend/src/app/shared/directives/dimless-binary-per-second.directive.ts
blob: a90e2b8f8aba91859f84ce08991e34e52b2047a9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import {
  Directive,
  ElementRef,
  EventEmitter,
  HostListener,
  Input,
  OnInit,
  Output
} from '@angular/core';
import { NgControl } from '@angular/forms';

import _ from 'lodash';

import { DimlessBinaryPerSecondPipe } from '../pipes/dimless-binary-per-second.pipe';
import { FormatterService } from '../services/formatter.service';

@Directive({
  selector: '[cdDimlessBinaryPerSecond]'
})
export class DimlessBinaryPerSecondDirective implements OnInit {
  @Output()
  ngModelChange: EventEmitter<any> = new EventEmitter();

  /**
   * Event emitter for letting this directive know that the data has (asynchronously) been loaded
   * and the value needs to be adapted by this directive.
   */
  @Input()
  ngDataReady: EventEmitter<any>;

  /**
   * Minimum size in bytes.
   * If user enter a value lower than <minBytes>,
   * the model will automatically be update to <minBytes>.
   *
   * If <roundPower> is used, this value should be a power of <roundPower>.
   *
   * Example:
   *   Given minBytes=4096 (4KiB), if user type 1KiB, then model will be updated to 4KiB
   */
  @Input()
  minBytes: number;

  /**
   * Maximum size in bytes.
   * If user enter a value greater than <maxBytes>,
   * the model will automatically be update to <maxBytes>.
   *
   * If <roundPower> is used, this value should be a power of <roundPower>.
   *
   * Example:
   *   Given maxBytes=3145728 (3MiB), if user type 4MiB, then model will be updated to 3MiB
   */
  @Input()
  maxBytes: number;

  /**
   * Value will be rounded up the nearest power of <roundPower>
   *
   * Example:
   *   Given roundPower=2, if user type 7KiB, then model will be updated to 8KiB
   *   Given roundPower=2, if user type 5KiB, then model will be updated to 4KiB
   */
  @Input()
  roundPower: number;

  /**
   * Default unit that should be used when user do not type a unit.
   * By default, "MiB" will be used.
   *
   * Example:
   *   Given defaultUnit=null, if user type 7, then model will be updated to 7MiB
   *   Given defaultUnit=k, if user type 7, then model will be updated to 7KiB
   */
  @Input()
  defaultUnit: string;

  private el: HTMLInputElement;

  constructor(
    private elementRef: ElementRef,
    private control: NgControl,
    private dimlessBinaryPerSecondPipe: DimlessBinaryPerSecondPipe,
    private formatter: FormatterService
  ) {
    this.el = this.elementRef.nativeElement;
  }

  ngOnInit() {
    this.setValue(this.el.value);
    if (this.ngDataReady) {
      this.ngDataReady.subscribe(() => this.setValue(this.el.value));
    }
  }

  setValue(value: string) {
    if (/^[\d.]+$/.test(value)) {
      value += this.defaultUnit || 'm';
    }
    const size = this.formatter.toBytes(value, 0);
    const roundedSize = this.round(size);
    this.el.value = this.dimlessBinaryPerSecondPipe.transform(roundedSize);
    if (size !== null) {
      this.ngModelChange.emit(this.el.value);
      this.control.control.setValue(this.el.value);
    } else {
      this.ngModelChange.emit(null);
      this.control.control.setValue(null);
    }
  }

  round(size: number) {
    if (size !== null && size !== 0) {
      if (!_.isUndefined(this.minBytes) && size < this.minBytes) {
        return this.minBytes;
      }
      if (!_.isUndefined(this.maxBytes) && size > this.maxBytes) {
        return this.maxBytes;
      }
      if (!_.isUndefined(this.roundPower)) {
        const power = Math.round(Math.log(size) / Math.log(this.roundPower));
        return Math.pow(this.roundPower, power);
      }
    }
    return size;
  }

  @HostListener('blur', ['$event.target.value'])
  onBlur(value: string) {
    this.setValue(value);
  }
}