controllers/dashboard/mean_build_times_controller.js

import { Controller } from "@hotwired/stimulus"
import { subscription } from "~/javascripts/store/mixins/subscription"
import { targetLineValues } from "~/javascripts/dashboard/utils"

/**
 * @class Dashboard.MeanBuildTimesController
 * @classdesc Stimulus controller that populates the mean build time per build context.
 * @extends Controller
 **/
export default class extends Controller {
  static targets = [ "production", "deployPreview", "cms" ]
  static values = {
    loading: String,
    storeId: String
  }
  static classes = [ "success", "warning", "error", "unavailable" ]

  /** 
   * Subscribe to the store.
   * 
   * @instance
   * @memberof Dashboard.MeanBuildTimesController
   **/
  connect() {
    subscription(this)
    this.subscribe()

    this.reconnect()
  }

  /** 
   * Handles a repeated Turbo visit to the dashboard page.
   * 
   * @instance
   * @memberof Dashboard.MeanBuildTimesController
   **/
  reconnect() {
    if (this.store("selectedDataVizData")) {
      this.storeUpdated("selectedDataVizData", this.storeIdValue)
    }
  }

  /** 
   * Sets the text for the mean build time and changes the color to match the KPI
   * 
   * @instance
   * @memberof Dashboard.MeanBuildTimesController
   **/
  updateMeanBuildTimesValue(target, text, context) {
    const meanBuildTime = this.calculateMeanBuildTime(context)
    target.innerHTML = `${text} ${meanBuildTime}`
    this.removeAlertColors(target)
    target.classList.add(this.alertColor(meanBuildTime, context))
  }

  /** 
   * Sets the text whilst waiting for the mean build time
   * 
   * @instance
   * @memberof Dashboard.MeanBuildTimesController
   **/
  loadingMeanBuildTimesValue(target, text) {
    target.innerHTML = `${text} ${this.loadingValue}`
    this.removeAlertColors(target)
  }

  /** 
   * @instance
   * @memberof Dashboard.MeanBuildTimesController
   **/
  calculateMeanBuildTime(context) {
    const totals = this.store("selectedDataVizData").reduce((acc , data) => {
      return data.context === context ? { count: acc.count + 1, time: acc.time + data.deploy_time } : acc
    }, { count: 0, time: 0 })
    return Math.round((totals.time / totals.count) * 100) / 100 || "N/A"
  }

  /** 
   * Remove all of the color classes for the mean build time
   * 
   * @instance
   * @memberof Dashboard.MeanBuildTimesController
   **/
  removeAlertColors(target) {
    target.classList.remove(this.successClass, this.warningClass, this.errorClass, this.unavailableClass)
  }

  /** 
   * Return the color depending on the time in relation to the KPI
   * 
   * @instance
   * @memberof Dashboard.MeanBuildTimesController
   **/
  alertColor(value, context) {
    const lineValues = targetLineValues(context)

    if (value == "N/A") return this.unavailableClass
    if (value <= lineValues.successLineValue) return this.successClass
    if (value <= lineValues.failLineValue) return this.warningClass
    return this.errorClass
  }

  /** 
   * Triggered by the store whenever any store data changes. Controls whether the mean build time should
   * be populated or display the loading indicator
   * 
   * @instance
   * @memberof Dashboard.MeanBuildTimesController
   **/
  storeUpdated(prop, storeId) {
    if (this.store("fetchingDataVizData")) {
      this.loadingMeanBuildTimesValue(this.productionTarget, "Production")
      this.loadingMeanBuildTimesValue(this.deployPreviewTarget, "Deploy preview")
      this.loadingMeanBuildTimesValue(this.cmsTarget, "CMS")
    }
    if (prop === "selectedDataVizData" && storeId === this.storeIdValue) {
      this.updateMeanBuildTimesValue(this.productionTarget, "Production ...", "production")
      this.updateMeanBuildTimesValue(this.deployPreviewTarget, "Deploy preview ...", "deploy-preview")
      this.updateMeanBuildTimesValue(this.cmsTarget, "CMS ...", "cms")
    }
  }

  /** 
   * Unsubscribe from the store
   * 
   * @instance
   * @memberof Dashboard.MeanBuildTimesController
   **/
  disconnect() {
    this.unsubscribe()
  }
}