controllers/dashboard/select_context_controller.js

  1. import { Controller } from "@hotwired/stimulus"
  2. import { subscription } from "~/javascripts/store/mixins/subscription"
  3. import { metricsInPercentile } from "~/javascripts/dashboard/utils"
  4. /**
  5. * @class Dashboard.SelectContextController
  6. * @classdesc Stimulus controller that handles the buttons for the various contexts.
  7. * @extends Controller
  8. **/
  9. export default class extends Controller {
  10. static targets = [ "button" ]
  11. static values = {
  12. contextKey: String,
  13. defaultContext: String,
  14. storeId: String
  15. }
  16. /**
  17. * Subscribe to the store.
  18. *
  19. * @instance
  20. * @memberof Dashboard.SelectContextController
  21. **/
  22. connect() {
  23. subscription(this)
  24. this.subscribe()
  25. this.reconnect()
  26. }
  27. /**
  28. * Handles a repeated Turbo visit to the dashboard page.
  29. *
  30. * @instance
  31. * @memberof Dashboard.SelectContextController
  32. **/
  33. reconnect() {
  34. if (this.store("selectedDataVizData")) {
  35. this.storeUpdated("selectedDataVizData", this.storeIdValue)
  36. }
  37. }
  38. /**
  39. * Sets the selected class on the clicked button and updates the store with the context clicked and
  40. * the data for the context
  41. *
  42. * @instance
  43. * @memberof Dashboard.SelectContextController
  44. **/
  45. contextClicked(event) {
  46. this.buttonTargets.forEach(buttonTarget => buttonTarget.classList.remove("selected"))
  47. event.target.classList.add("selected")
  48. const buttonText = event.target.innerHTML
  49. this.editStore("contextSelected", this.contextSelected(buttonText))
  50. this.editStore("selectedContextData", this.selectContextData(this.contextSelected(buttonText)))
  51. }
  52. /**
  53. * Get the data for the selected context. Also set the value to be used on the x axis.
  54. * If there is no data for the context then return a dummy object in an array.
  55. *
  56. * @instance
  57. * @memberof Dashboard.SelectContextController
  58. **/
  59. selectContextData(context) {
  60. let selectedDataVizData = !this.store("selectedDataVizData") ? [] : this.store("selectedDataVizData")
  61. let contextData = selectedDataVizData.filter(data => data[this.contextKeyValue] === context)
  62. if(this.storeIdValue === "builds_") {
  63. if(contextData.length === 0) return [{ deploy_time: 0, build_number: 0 }]
  64. return contextData.map((data, index) => Object.assign(data, { build_number: index + 1 }))
  65. } else if (this.storeIdValue === "vitals_") {
  66. if (this.store("frameSelected") === undefined) this.editStore("frameSelected", "daily")
  67. contextData = metricsInPercentile(contextData, "data_float", 0.75)
  68. if (this.store("frameSelected") === "daily") {
  69. if(contextData.length === 0) return [{ value: 0, day: 0 }]
  70. const groupSumCount = contextData.reduce((acc , data) => {
  71. if (!acc.get(data.date)) {
  72. acc.set(
  73. data.date, { date: data.date, metric: data.metric, data_float: data.data_float, count: 1 }
  74. )
  75. return acc
  76. }
  77. const dateContent = acc.get(data.date)
  78. dateContent.data_float += data.data_float
  79. dateContent.count += 1
  80. return acc
  81. }, new Map())
  82. for (let result of groupSumCount.values()) {
  83. result.value = Math.round(((result.data_float/result.count) + Number.EPSILON) * 10000) / 10000
  84. }
  85. return [...groupSumCount.values()].map((data) => {
  86. return Object.assign(data, { day: new Date(data.date).getDate() })
  87. })
  88. } else if (this.store("frameSelected") === "frequency") {
  89. if(contextData.length === 0) return []
  90. return contextData.map(data => {
  91. return { value: data.data_float }
  92. })
  93. }
  94. }
  95. }
  96. /**
  97. * Use the button text to set the context.
  98. *
  99. * @instance
  100. * @memberof Dashboard.SelectContextController
  101. **/
  102. contextSelected(buttonText) {
  103. return buttonText.toLowerCase().replace(" ", "-")
  104. }
  105. /**
  106. * Triggered by the store whenever any store data changes. In this case it checks for
  107. * selectedDataVizData to be set and then sets production as the initially selected context
  108. * button.
  109. *
  110. * @instance
  111. * @memberof Dashboard.SelectContextController
  112. **/
  113. storeUpdated(prop, storeId) {
  114. if ((prop === "frameLoaded" || prop === "selectedDataVizData") && storeId === this.storeIdValue) {
  115. this.editStore("contextSelected", this.contextSelected(this.defaultContextValue))
  116. this.editStore("selectedContextData", this.selectContextData(this.defaultContextValue))
  117. this.buttonTargets.forEach(buttonTarget => buttonTarget.classList.remove("selected"))
  118. this.buttonTargets[0].classList.add("selected")
  119. }
  120. }
  121. /**
  122. * Unsubscribe from the store
  123. *
  124. * @instance
  125. * @memberof Dashboard.SelectContextController
  126. **/
  127. disconnect() {
  128. this.unsubscribe()
  129. }
  130. }