@spinnaker/kayenta 0.0.0-2025.1-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (289) hide show
  1. package/.editorconfig +9 -0
  2. package/.eslintrc.js +1 -0
  3. package/.huskyrc +5 -0
  4. package/.lintstagedrc.json +4 -0
  5. package/.prettierignore +4 -0
  6. package/.prettierrc.js +1 -0
  7. package/LICENSE.txt +203 -0
  8. package/README.md +81 -0
  9. package/__mocks__/styleMock.js +1 -0
  10. package/__mocks__/version.json +4 -0
  11. package/babel.config.js +3 -0
  12. package/build.gradle +67 -0
  13. package/build_scripts/checkLicenses.js +79 -0
  14. package/gradle.properties +0 -0
  15. package/jest.config.js +204 -0
  16. package/jest.setup.js +5 -0
  17. package/package.json +166 -0
  18. package/rollup-plugin-angularjs-template-loader.js +82 -0
  19. package/rollup.config.js +30 -0
  20. package/src/index.ts +2 -0
  21. package/src/kayenta/actions/creators.ts +163 -0
  22. package/src/kayenta/actions/index.ts +98 -0
  23. package/src/kayenta/canary.dataSource.bridge.ts +53 -0
  24. package/src/kayenta/canary.dataSource.stub.ts +64 -0
  25. package/src/kayenta/canary.help.ts +136 -0
  26. package/src/kayenta/canary.less +168 -0
  27. package/src/kayenta/canary.settings.ts +26 -0
  28. package/src/kayenta/canary.tsx +67 -0
  29. package/src/kayenta/components/canaryScore.component.less +77 -0
  30. package/src/kayenta/components/canaryScore.component.ts +12 -0
  31. package/src/kayenta/components/canaryScore.tsx +63 -0
  32. package/src/kayenta/components/canaryScores.component.ts +20 -0
  33. package/src/kayenta/components/canaryScores.less +22 -0
  34. package/src/kayenta/components/canaryScores.tsx +163 -0
  35. package/src/kayenta/components/loadStates.tsx +52 -0
  36. package/src/kayenta/domain/ICanaryConfig.ts +57 -0
  37. package/src/kayenta/domain/ICanaryConfigSummary.ts +7 -0
  38. package/src/kayenta/domain/ICanaryConfigUpdateResponse.ts +3 -0
  39. package/src/kayenta/domain/ICanaryExecutionStatusResult.ts +72 -0
  40. package/src/kayenta/domain/ICanaryJudgeResult.ts +51 -0
  41. package/src/kayenta/domain/ICanaryJudgeResultSummary.ts +5 -0
  42. package/src/kayenta/domain/ICanaryScoreThresholds.ts +4 -0
  43. package/src/kayenta/domain/IJudge.ts +5 -0
  44. package/src/kayenta/domain/IKayentaAccount.ts +14 -0
  45. package/src/kayenta/domain/IKayentaStageConfig.ts +58 -0
  46. package/src/kayenta/domain/IMetricSetPair.ts +17 -0
  47. package/src/kayenta/domain/IMetricsServiceMetadata.ts +2 -0
  48. package/src/kayenta/domain/ISetupCanaryStage.ts +11 -0
  49. package/src/kayenta/domain/MetricClassificationLabel.ts +8 -0
  50. package/src/kayenta/domain/ScoreClassificationLabel.ts +7 -0
  51. package/src/kayenta/domain/index.ts +15 -0
  52. package/src/kayenta/edit/changeMetricGroupModal.tsx +107 -0
  53. package/src/kayenta/edit/configDetail.tsx +31 -0
  54. package/src/kayenta/edit/configDetailActionButtons.tsx +24 -0
  55. package/src/kayenta/edit/configDetailHeader.tsx +104 -0
  56. package/src/kayenta/edit/configDetailLoadStates.tsx +36 -0
  57. package/src/kayenta/edit/configDetailLoader.tsx +60 -0
  58. package/src/kayenta/edit/configJson.less +42 -0
  59. package/src/kayenta/edit/configJsonModal.tsx +158 -0
  60. package/src/kayenta/edit/configList.less +7 -0
  61. package/src/kayenta/edit/configList.tsx +57 -0
  62. package/src/kayenta/edit/copyConfigButton.tsx +34 -0
  63. package/src/kayenta/edit/createConfigButton.tsx +34 -0
  64. package/src/kayenta/edit/deleteModal.tsx +87 -0
  65. package/src/kayenta/edit/edit.tsx +24 -0
  66. package/src/kayenta/edit/editMetricEffectSizes.tsx +186 -0
  67. package/src/kayenta/edit/editMetricModal.less +9 -0
  68. package/src/kayenta/edit/editMetricModal.spec.tsx +129 -0
  69. package/src/kayenta/edit/editMetricModal.tsx +294 -0
  70. package/src/kayenta/edit/editMetricValidation.spec.ts +63 -0
  71. package/src/kayenta/edit/editMetricValidation.ts +50 -0
  72. package/src/kayenta/edit/filterTemplateSelector.less +15 -0
  73. package/src/kayenta/edit/filterTemplateSelector.spec.tsx +106 -0
  74. package/src/kayenta/edit/filterTemplateSelector.tsx +194 -0
  75. package/src/kayenta/edit/filterTemplatesValidation.spec.ts +108 -0
  76. package/src/kayenta/edit/filterTemplatesValidation.ts +95 -0
  77. package/src/kayenta/edit/footer.less +30 -0
  78. package/src/kayenta/edit/footer.tsx +12 -0
  79. package/src/kayenta/edit/groupName.tsx +80 -0
  80. package/src/kayenta/edit/groupTabs.tsx +106 -0
  81. package/src/kayenta/edit/groupWeight.tsx +80 -0
  82. package/src/kayenta/edit/groupWeights.tsx +38 -0
  83. package/src/kayenta/edit/inlineTemplateEditor.spec.tsx +42 -0
  84. package/src/kayenta/edit/inlineTemplateEditor.tsx +61 -0
  85. package/src/kayenta/edit/judgeSelect.tsx +82 -0
  86. package/src/kayenta/edit/metricConfigurerDelegator.tsx +30 -0
  87. package/src/kayenta/edit/metricList.less +21 -0
  88. package/src/kayenta/edit/metricList.tsx +215 -0
  89. package/src/kayenta/edit/metricStoreSelector.tsx +66 -0
  90. package/src/kayenta/edit/nameAndDescription.tsx +90 -0
  91. package/src/kayenta/edit/openConfigJsonModalButton.tsx +33 -0
  92. package/src/kayenta/edit/openDeleteModalButton.tsx +50 -0
  93. package/src/kayenta/edit/ownedBy.tsx +34 -0
  94. package/src/kayenta/edit/save.tsx +19 -0
  95. package/src/kayenta/edit/saveConfigButton.tsx +65 -0
  96. package/src/kayenta/edit/saveConfigError.tsx +59 -0
  97. package/src/kayenta/edit/scoring.tsx +35 -0
  98. package/src/kayenta/edit/selectConfig.tsx +10 -0
  99. package/src/kayenta/edit/validationErrors.tsx +39 -0
  100. package/src/kayenta/index.ts +6 -0
  101. package/src/kayenta/layout/addNewButton.tsx +20 -0
  102. package/src/kayenta/layout/centeredDetail.tsx +13 -0
  103. package/src/kayenta/layout/deleteButton.tsx +11 -0
  104. package/src/kayenta/layout/disableable.tsx +87 -0
  105. package/src/kayenta/layout/formList.tsx +26 -0
  106. package/src/kayenta/layout/formRow.tsx +36 -0
  107. package/src/kayenta/layout/formattedDate.tsx +14 -0
  108. package/src/kayenta/layout/index.ts +2 -0
  109. package/src/kayenta/layout/keyValueList.less +20 -0
  110. package/src/kayenta/layout/keyValueList.tsx +114 -0
  111. package/src/kayenta/layout/list.less +9 -0
  112. package/src/kayenta/layout/list.spec.tsx +83 -0
  113. package/src/kayenta/layout/list.tsx +73 -0
  114. package/src/kayenta/layout/listDetail.tsx +33 -0
  115. package/src/kayenta/layout/radioChoice.tsx +29 -0
  116. package/src/kayenta/layout/styleguide.tsx +16 -0
  117. package/src/kayenta/layout/table/index.ts +5 -0
  118. package/src/kayenta/layout/table/nativeTable.tsx +51 -0
  119. package/src/kayenta/layout/table/nativeTableHeader.tsx +26 -0
  120. package/src/kayenta/layout/table/table.tsx +56 -0
  121. package/src/kayenta/layout/table/tableColumn.ts +7 -0
  122. package/src/kayenta/layout/table/tableHeader.tsx +23 -0
  123. package/src/kayenta/layout/tabs.tsx +26 -0
  124. package/src/kayenta/layout/titledSection.less +16 -0
  125. package/src/kayenta/layout/titledSection.tsx +20 -0
  126. package/src/kayenta/layout/titledSubsection.less +11 -0
  127. package/src/kayenta/layout/titledSubsection.tsx +22 -0
  128. package/src/kayenta/manualAnalysis/ManualAnalysisModal.tsx +716 -0
  129. package/src/kayenta/metricStore/atlas/atlasMetricConfigurer.tsx +130 -0
  130. package/src/kayenta/metricStore/atlas/index.ts +8 -0
  131. package/src/kayenta/metricStore/datadog/domain/IDatadogMetricDescriptor.ts +5 -0
  132. package/src/kayenta/metricStore/datadog/index.ts +9 -0
  133. package/src/kayenta/metricStore/datadog/metricConfigurer.tsx +90 -0
  134. package/src/kayenta/metricStore/datadog/metricTypeSelector.spec.tsx +59 -0
  135. package/src/kayenta/metricStore/datadog/metricTypeSelector.tsx +73 -0
  136. package/src/kayenta/metricStore/graphite/domain/IGraphiteMetricDescriptor.ts +5 -0
  137. package/src/kayenta/metricStore/graphite/index.ts +8 -0
  138. package/src/kayenta/metricStore/graphite/metricConfigurer.tsx +54 -0
  139. package/src/kayenta/metricStore/graphite/metricTypeSelector.tsx +80 -0
  140. package/src/kayenta/metricStore/graphite/typeahead.less +3 -0
  141. package/src/kayenta/metricStore/index.ts +8 -0
  142. package/src/kayenta/metricStore/metricStoreConfig.service.ts +12 -0
  143. package/src/kayenta/metricStore/newrelic/domain/INewRelicMetricDescriptor.ts +5 -0
  144. package/src/kayenta/metricStore/newrelic/index.ts +8 -0
  145. package/src/kayenta/metricStore/newrelic/metricConfigurer.tsx +58 -0
  146. package/src/kayenta/metricStore/prometheus/domain/IPrometheusCanaryMetricSetQueryConfig.ts +14 -0
  147. package/src/kayenta/metricStore/prometheus/domain/IPrometheusMetricDescriptor.ts +5 -0
  148. package/src/kayenta/metricStore/prometheus/index.ts +12 -0
  149. package/src/kayenta/metricStore/prometheus/metricConfigurer.tsx +157 -0
  150. package/src/kayenta/metricStore/prometheus/metricTypeSelector.less +5 -0
  151. package/src/kayenta/metricStore/prometheus/metricTypeSelector.spec.tsx +62 -0
  152. package/src/kayenta/metricStore/prometheus/metricTypeSelector.tsx +144 -0
  153. package/src/kayenta/metricStore/prometheus/queryTypeSelectors.spec.ts +61 -0
  154. package/src/kayenta/metricStore/prometheus/queryTypeSelectors.ts +38 -0
  155. package/src/kayenta/metricStore/signalfx/domain/ISignalFxCanaryMetricSetQueryConfig.ts +7 -0
  156. package/src/kayenta/metricStore/signalfx/index.ts +8 -0
  157. package/src/kayenta/metricStore/signalfx/metricConfigurer.less +10 -0
  158. package/src/kayenta/metricStore/signalfx/metricConfigurer.tsx +187 -0
  159. package/src/kayenta/metricStore/stackdriver/domain/IStackdriverCanaryMetricSetQueryConfig.ts +9 -0
  160. package/src/kayenta/metricStore/stackdriver/domain/IStackdriverMetricDescriptor.ts +17 -0
  161. package/src/kayenta/metricStore/stackdriver/index.ts +12 -0
  162. package/src/kayenta/metricStore/stackdriver/metricConfigurer.tsx +144 -0
  163. package/src/kayenta/metricStore/stackdriver/metricTypeSelector.spec.tsx +92 -0
  164. package/src/kayenta/metricStore/stackdriver/metricTypeSelector.tsx +113 -0
  165. package/src/kayenta/middleware/actionInterceptor.ts +29 -0
  166. package/src/kayenta/middleware/asyncDispatch.ts +37 -0
  167. package/src/kayenta/middleware/epics.ts +211 -0
  168. package/src/kayenta/middleware/index.ts +3 -0
  169. package/src/kayenta/navigation/canary.states.stub.ts +28 -0
  170. package/src/kayenta/navigation/canary.states.ts +182 -0
  171. package/src/kayenta/reducers/app.ts +56 -0
  172. package/src/kayenta/reducers/asyncRequest.ts +5 -0
  173. package/src/kayenta/reducers/data.ts +169 -0
  174. package/src/kayenta/reducers/editingTemplate.ts +54 -0
  175. package/src/kayenta/reducers/group.ts +82 -0
  176. package/src/kayenta/reducers/index.ts +245 -0
  177. package/src/kayenta/reducers/prometheusMetricConfig.spec.ts +33 -0
  178. package/src/kayenta/reducers/prometheusMetricConfig.ts +56 -0
  179. package/src/kayenta/reducers/selectedConfig.spec.ts +190 -0
  180. package/src/kayenta/reducers/selectedConfig.ts +566 -0
  181. package/src/kayenta/reducers/selectedRun.ts +101 -0
  182. package/src/kayenta/reducers/signalFxMetricConfig.ts +36 -0
  183. package/src/kayenta/reducers/stackdriverMetricConfig.spec.ts +33 -0
  184. package/src/kayenta/reducers/stackdriverMetricConfig.ts +41 -0
  185. package/src/kayenta/reducers/templates.spec.ts +192 -0
  186. package/src/kayenta/reducers/validators.ts +118 -0
  187. package/src/kayenta/report/detail/allMetricResultsHeader.tsx +32 -0
  188. package/src/kayenta/report/detail/clickableHeader.tsx +21 -0
  189. package/src/kayenta/report/detail/colors.ts +47 -0
  190. package/src/kayenta/report/detail/detail.less +16 -0
  191. package/src/kayenta/report/detail/detail.tsx +48 -0
  192. package/src/kayenta/report/detail/detailLoader.tsx +55 -0
  193. package/src/kayenta/report/detail/graph/graph.tsx +37 -0
  194. package/src/kayenta/report/detail/graph/metricSetPairGraph.service.ts +35 -0
  195. package/src/kayenta/report/detail/graph/semiotic/boxplot.less +45 -0
  196. package/src/kayenta/report/detail/graph/semiotic/boxplot.tsx +283 -0
  197. package/src/kayenta/report/detail/graph/semiotic/chartHeader.tsx +19 -0
  198. package/src/kayenta/report/detail/graph/semiotic/chartLegend.less +26 -0
  199. package/src/kayenta/report/detail/graph/semiotic/chartLegend.tsx +42 -0
  200. package/src/kayenta/report/detail/graph/semiotic/circleIcon.tsx +16 -0
  201. package/src/kayenta/report/detail/graph/semiotic/config.less +5 -0
  202. package/src/kayenta/report/detail/graph/semiotic/config.ts +38 -0
  203. package/src/kayenta/report/detail/graph/semiotic/customAxisTickLabel.tsx +17 -0
  204. package/src/kayenta/report/detail/graph/semiotic/declarations/labella.d.ts +16 -0
  205. package/src/kayenta/report/detail/graph/semiotic/declarations/react-container-dimensions.d.ts +3 -0
  206. package/src/kayenta/report/detail/graph/semiotic/declarations/semiotic.d.ts +160 -0
  207. package/src/kayenta/report/detail/graph/semiotic/differenceArea.less +17 -0
  208. package/src/kayenta/report/detail/graph/semiotic/differenceArea.tsx +186 -0
  209. package/src/kayenta/report/detail/graph/semiotic/histogram.less +22 -0
  210. package/src/kayenta/report/detail/graph/semiotic/histogram.tsx +251 -0
  211. package/src/kayenta/report/detail/graph/semiotic/index.tsx +19 -0
  212. package/src/kayenta/report/detail/graph/semiotic/noValidDataSign.less +5 -0
  213. package/src/kayenta/report/detail/graph/semiotic/noValidDataSign.tsx +10 -0
  214. package/src/kayenta/report/detail/graph/semiotic/secondaryTSXAxis.less +6 -0
  215. package/src/kayenta/report/detail/graph/semiotic/secondaryTSXAxis.tsx +58 -0
  216. package/src/kayenta/report/detail/graph/semiotic/semiotic.service.ts +32 -0
  217. package/src/kayenta/report/detail/graph/semiotic/semioticGraph.less +53 -0
  218. package/src/kayenta/report/detail/graph/semiotic/semioticGraph.tsx +49 -0
  219. package/src/kayenta/report/detail/graph/semiotic/timeSeries.less +42 -0
  220. package/src/kayenta/report/detail/graph/semiotic/timeSeries.tsx +473 -0
  221. package/src/kayenta/report/detail/graph/semiotic/tooltip.tsx +55 -0
  222. package/src/kayenta/report/detail/graph/semiotic/utils.ts +90 -0
  223. package/src/kayenta/report/detail/graphTypeSelector.less +4 -0
  224. package/src/kayenta/report/detail/graphTypeSelector.tsx +50 -0
  225. package/src/kayenta/report/detail/groupScores.tsx +68 -0
  226. package/src/kayenta/report/detail/header.less +70 -0
  227. package/src/kayenta/report/detail/header.tsx +39 -0
  228. package/src/kayenta/report/detail/headerArrow.tsx +13 -0
  229. package/src/kayenta/report/detail/loadStates.tsx +31 -0
  230. package/src/kayenta/report/detail/metricResultActions.less +29 -0
  231. package/src/kayenta/report/detail/metricResultActions.tsx +87 -0
  232. package/src/kayenta/report/detail/metricResultClassification.tsx +22 -0
  233. package/src/kayenta/report/detail/metricResultDetail.tsx +20 -0
  234. package/src/kayenta/report/detail/metricResultDetailLayout.tsx +19 -0
  235. package/src/kayenta/report/detail/metricResultDeviation.tsx +25 -0
  236. package/src/kayenta/report/detail/metricResultStats.less +9 -0
  237. package/src/kayenta/report/detail/metricResultStats.tsx +120 -0
  238. package/src/kayenta/report/detail/metricResults.less +12 -0
  239. package/src/kayenta/report/detail/metricResults.tsx +52 -0
  240. package/src/kayenta/report/detail/metricResultsClassificationFilters.tsx +65 -0
  241. package/src/kayenta/report/detail/metricResultsColumns.tsx +27 -0
  242. package/src/kayenta/report/detail/metricResultsList.less +44 -0
  243. package/src/kayenta/report/detail/metricResultsList.tsx +120 -0
  244. package/src/kayenta/report/detail/metricSetPairLoadStates.tsx +22 -0
  245. package/src/kayenta/report/detail/multipleResultsTable.tsx +81 -0
  246. package/src/kayenta/report/detail/reportException.tsx +57 -0
  247. package/src/kayenta/report/detail/reportExplanation.less +12 -0
  248. package/src/kayenta/report/detail/reportExplanation.tsx +32 -0
  249. package/src/kayenta/report/detail/reportMetadata.tsx +167 -0
  250. package/src/kayenta/report/detail/reportScores.less +47 -0
  251. package/src/kayenta/report/detail/reportScores.tsx +80 -0
  252. package/src/kayenta/report/detail/score.tsx +33 -0
  253. package/src/kayenta/report/detail/sourceLinks.tsx +69 -0
  254. package/src/kayenta/report/list/configLink.tsx +32 -0
  255. package/src/kayenta/report/list/executionList.less +7 -0
  256. package/src/kayenta/report/list/loadStates.tsx +32 -0
  257. package/src/kayenta/report/list/pipelineLink.tsx +15 -0
  258. package/src/kayenta/report/list/reportLink.tsx +33 -0
  259. package/src/kayenta/report/list/table.tsx +309 -0
  260. package/src/kayenta/report/report.tsx +11 -0
  261. package/src/kayenta/selectors/filterTemplatesSelectors.ts +87 -0
  262. package/src/kayenta/selectors/index.ts +62 -0
  263. package/src/kayenta/service/canaryConfig.service.ts +122 -0
  264. package/src/kayenta/service/canaryRun.service.ts +60 -0
  265. package/src/kayenta/service/delegateFactory.ts +24 -0
  266. package/src/kayenta/service/metricsServiceMetadata.service.ts +9 -0
  267. package/src/kayenta/stages/kayentaStage/AnalysisType.spec.tsx +47 -0
  268. package/src/kayenta/stages/kayentaStage/AnalysisType.tsx +49 -0
  269. package/src/kayenta/stages/kayentaStage/CanaryExecutionLabel.tsx +26 -0
  270. package/src/kayenta/stages/kayentaStage/analysisType.component.ts +12 -0
  271. package/src/kayenta/stages/kayentaStage/canaryRunSummaries.component.ts +12 -0
  272. package/src/kayenta/stages/kayentaStage/canaryRunSummaries.less +5 -0
  273. package/src/kayenta/stages/kayentaStage/canaryRunSummaries.tsx +136 -0
  274. package/src/kayenta/stages/kayentaStage/forAnalysisType.component.ts +45 -0
  275. package/src/kayenta/stages/kayentaStage/kayentaStage.controller.ts +789 -0
  276. package/src/kayenta/stages/kayentaStage/kayentaStage.html +528 -0
  277. package/src/kayenta/stages/kayentaStage/kayentaStage.less +5 -0
  278. package/src/kayenta/stages/kayentaStage/kayentaStage.transformer.ts +179 -0
  279. package/src/kayenta/stages/kayentaStage/kayentaStage.ts +221 -0
  280. package/src/kayenta/stages/kayentaStage/kayentaStageConfigSection.component.ts +21 -0
  281. package/src/kayenta/stages/kayentaStage/kayentaStageExecutionDetails.controller.ts +88 -0
  282. package/src/kayenta/stages/kayentaStage/kayentaStageExecutionDetails.html +114 -0
  283. package/src/kayenta/stages/kayentaStage/kayentaStageExecutionDetails.less +6 -0
  284. package/src/kayenta/stages/kayentaStage/stageTypes.ts +5 -0
  285. package/src/kayenta/utils/duration.spec.ts +69 -0
  286. package/src/kayenta/utils/duration.ts +48 -0
  287. package/src/lazy.ts +29 -0
  288. package/src/stub.ts +60 -0
  289. package/tsconfig.json +11 -0
@@ -0,0 +1,245 @@
1
+ import * as Actions from 'kayenta/actions';
2
+ import * as Creators from 'kayenta/actions/creators';
3
+ import { CanarySettings } from 'kayenta/canary.settings';
4
+ import {
5
+ ICanaryAnalysisResult,
6
+ ICanaryJudgeConfig,
7
+ ICanaryMetricConfig,
8
+ IJudge,
9
+ KayentaAccountType,
10
+ } from 'kayenta/domain';
11
+ import { JudgeSelectRenderState } from 'kayenta/edit/judgeSelect';
12
+ import { metricResultsSelector } from 'kayenta/selectors';
13
+ import { mapStateToConfig } from 'kayenta/service/canaryConfig.service';
14
+ import { chain, isEqual } from 'lodash';
15
+ import { Action, combineReducers } from 'redux';
16
+ import { combineActions, handleActions } from 'redux-actions';
17
+
18
+ import { app, IAppState } from './app';
19
+ import { AsyncRequestState } from './asyncRequest';
20
+ import { data, IDataState } from './data';
21
+ import { ISelectedConfigState, selectedConfig } from './selectedConfig';
22
+ import { ISelectedRunState, selectedRun } from './selectedRun';
23
+ import { validationErrorsReducer } from './validators';
24
+
25
+ export interface ICanaryState {
26
+ app: IAppState;
27
+ data: IDataState;
28
+ selectedConfig: ISelectedConfigState;
29
+ selectedRun: ISelectedRunState;
30
+ }
31
+
32
+ const combined = combineReducers<ICanaryState>({
33
+ app,
34
+ configValidationErrors: () => null,
35
+ data,
36
+ selectedConfig,
37
+ selectedRun,
38
+ });
39
+
40
+ const getRenderState = (judges: IJudge[], judgeConfig: ICanaryJudgeConfig): JudgeSelectRenderState => {
41
+ if (judges.some((judge) => judge.name === judgeConfig.name)) {
42
+ if (judges.length === 1) {
43
+ return JudgeSelectRenderState.None;
44
+ } else {
45
+ return JudgeSelectRenderState.Multiple;
46
+ }
47
+ } else {
48
+ return JudgeSelectRenderState.Single;
49
+ }
50
+ };
51
+
52
+ const judgeRenderStateReducer = handleActions(
53
+ {
54
+ [combineActions(Actions.SELECT_CONFIG, Actions.UPDATE_JUDGES)]: (state: ICanaryState) => {
55
+ // At this point, we've already passed through the rest of the reducers, so
56
+ // the judge has been normalized on the state.
57
+ const {
58
+ data: { judges = [] },
59
+ selectedConfig: {
60
+ judge: { judgeConfig },
61
+ },
62
+ } = state;
63
+
64
+ if (!judgeConfig) {
65
+ return state;
66
+ } else {
67
+ return {
68
+ ...state,
69
+ selectedConfig: {
70
+ ...state.selectedConfig,
71
+ judge: {
72
+ ...state.selectedConfig.judge,
73
+ renderState: getRenderState(judges, judgeConfig),
74
+ },
75
+ },
76
+ };
77
+ }
78
+ },
79
+ },
80
+ null,
81
+ );
82
+
83
+ const isInSyncWithServerReducer = (state: ICanaryState): ICanaryState => {
84
+ return {
85
+ ...state,
86
+ selectedConfig: {
87
+ ...state.selectedConfig,
88
+ isInSyncWithServer: (() => {
89
+ const editedConfig = mapStateToConfig(state);
90
+ if (!editedConfig) {
91
+ return true;
92
+ } else {
93
+ const originalConfig = state.data.configs.find((c) => c.id === editedConfig.id);
94
+ // If we're saving the config right now, don't warn that
95
+ // the config hasn't been saved.
96
+ if (
97
+ !originalConfig &&
98
+ editedConfig.isNew &&
99
+ state.selectedConfig.save.state === AsyncRequestState.Requesting
100
+ ) {
101
+ return true;
102
+ }
103
+ return isEqual(editedConfig, originalConfig);
104
+ }
105
+ })(),
106
+ },
107
+ };
108
+ };
109
+
110
+ const resolveSelectedMetricId = (state: ICanaryState, action: Action & any): string => {
111
+ switch (action.type) {
112
+ case Actions.SELECT_REPORT_METRIC:
113
+ return action.payload.metricId;
114
+
115
+ // On report load, pick the first metric.
116
+ case Actions.LOAD_RUN_SUCCESS:
117
+ return metricResultsSelector(state).length ? metricResultsSelector(state)[0].id : null;
118
+
119
+ // On group select, pick the first metric in the group.
120
+ case Actions.SELECT_REPORT_METRIC_GROUP: {
121
+ const results = metricResultsSelector(state);
122
+ if (!results.length) {
123
+ return null;
124
+ }
125
+
126
+ const group = action.payload.group;
127
+ const filter: (r: ICanaryAnalysisResult) => boolean = group ? (r) => r.groups.includes(group) : () => true;
128
+
129
+ return results.find(filter) ? results.find(filter).id : null;
130
+ }
131
+
132
+ default:
133
+ return null;
134
+ }
135
+ };
136
+
137
+ const selectedMetricReducer = (state: ICanaryState, action: Action & any) => {
138
+ if (
139
+ ![Actions.SELECT_REPORT_METRIC, Actions.SELECT_REPORT_METRIC_GROUP, Actions.LOAD_RUN_SUCCESS].includes(action.type)
140
+ ) {
141
+ return state;
142
+ }
143
+
144
+ const id = resolveSelectedMetricId(state, action);
145
+ if (!id) {
146
+ return state;
147
+ }
148
+
149
+ // Load metric set pair.
150
+ action.asyncDispatch(
151
+ Creators.loadMetricSetPairRequest({
152
+ pairId: id,
153
+ }),
154
+ );
155
+
156
+ return {
157
+ ...state,
158
+ selectedRun: {
159
+ ...state.selectedRun,
160
+ selectedMetric: id,
161
+ metricSetPair: {
162
+ ...state.selectedRun.metricSetPair,
163
+ load: AsyncRequestState.Requesting,
164
+ },
165
+ },
166
+ };
167
+ };
168
+
169
+ // TODO(dpeach): this assumes that a config can only use one metric store.
170
+ // If that changes, then metric store handling will have to be done per metric.
171
+ const selectedMetricStoreReducer = (state: ICanaryState, action: Action & any) => {
172
+ switch (action.type) {
173
+ case Actions.SELECT_CONFIG:
174
+ case Actions.LOAD_KAYENTA_ACCOUNTS_SUCCESS: {
175
+ const stores = chain(state.data.kayentaAccounts.data)
176
+ .filter((account) => account.supportedTypes.includes(KayentaAccountType.MetricsStore))
177
+ .map((account) => account.metricsStoreType || account.type)
178
+ .uniq()
179
+ .valueOf();
180
+
181
+ let selectedStore = (state.selectedConfig.metricList || [])
182
+ .map((metric) => metric.query.type)
183
+ .find((store) => !!store);
184
+
185
+ selectedStore =
186
+ selectedStore ||
187
+ (stores.length ? (stores.includes(CanarySettings.metricStore) ? CanarySettings.metricStore : stores[0]) : null);
188
+
189
+ return {
190
+ ...state,
191
+ selectedConfig: {
192
+ ...state.selectedConfig,
193
+ selectedStore,
194
+ },
195
+ };
196
+ }
197
+
198
+ case Actions.SELECT_METRIC_STORE: {
199
+ const selectedStore: string = action.payload.store;
200
+ // Flips all metrics to use the selected metric store.
201
+ const metricUpdater = (metric: ICanaryMetricConfig): ICanaryMetricConfig => ({
202
+ ...metric,
203
+ query: { ...metric.query, type: selectedStore, serviceType: selectedStore },
204
+ });
205
+
206
+ return {
207
+ ...state,
208
+ selectedConfig: {
209
+ ...state.selectedConfig,
210
+ metricList: state.selectedConfig.metricList.map(metricUpdater),
211
+ selectedStore,
212
+ },
213
+ };
214
+ }
215
+
216
+ default:
217
+ return state;
218
+ }
219
+ };
220
+
221
+ const disableConfigEditReducer = (state: ICanaryState) => {
222
+ if (!state.selectedConfig.config) {
223
+ return state;
224
+ }
225
+
226
+ return {
227
+ ...state,
228
+ app: {
229
+ ...state.app,
230
+ disableConfigEdit: !state.selectedConfig.config.applications.includes(state.data.application.name),
231
+ },
232
+ };
233
+ };
234
+
235
+ export const rootReducer = (state: ICanaryState, action: Action & any): ICanaryState => {
236
+ return [
237
+ combined,
238
+ judgeRenderStateReducer,
239
+ selectedMetricStoreReducer,
240
+ selectedMetricReducer,
241
+ disableConfigEditReducer,
242
+ validationErrorsReducer,
243
+ isInSyncWithServerReducer,
244
+ ].reduce((s, reducer) => reducer(s, action), state);
245
+ };
@@ -0,0 +1,33 @@
1
+ import * as Actions from 'kayenta/actions';
2
+
3
+ import { prometheusMetricConfigReducer } from './prometheusMetricConfig';
4
+
5
+ describe('Reducer: prometheusMetricConfigReducer', () => {
6
+ describe('update query field', () => {
7
+ it('updates arbitrary query key/value pairs on a query', () => {
8
+ const nextState = prometheusMetricConfigReducer({ query: { resourceType: 'aws_ec2_instance' } } as any, {
9
+ type: Actions.UPDATE_PROMETHEUS_METRIC_QUERY_FIELD,
10
+ payload: { field: 'resourceType', value: 'gce_instance' },
11
+ });
12
+ expect(nextState.query.resourceType).toEqual('gce_instance');
13
+ });
14
+
15
+ it('creates key/value pair if not already extant on the query', () => {
16
+ const nextState = prometheusMetricConfigReducer({ query: {} } as any, {
17
+ type: Actions.UPDATE_PROMETHEUS_METRIC_QUERY_FIELD,
18
+ payload: { field: 'resourceType', value: 'gce_instance' },
19
+ });
20
+ expect(nextState.query.resourceType).toEqual('gce_instance');
21
+ });
22
+
23
+ it('deletes key/value pair if passed falsy value', () => {
24
+ [null, undefined, ''].forEach((falsyValue) => {
25
+ const nextState = prometheusMetricConfigReducer({ query: { resourceType: 'aws_ec2_instance' } } as any, {
26
+ type: Actions.UPDATE_PROMETHEUS_METRIC_QUERY_FIELD,
27
+ payload: { field: 'resourceType', value: falsyValue },
28
+ });
29
+ expect(nextState.query.resourceType).toBeUndefined();
30
+ });
31
+ });
32
+ });
33
+ });
@@ -0,0 +1,56 @@
1
+ import * as Actions from 'kayenta/actions';
2
+ import { IKayentaAction } from 'kayenta/actions/creators';
3
+ import { ICanaryMetricConfig } from 'kayenta/domain';
4
+ import { IUpdateListPayload, updateListReducer } from 'kayenta/layout/list';
5
+ import { IPrometheusCanaryMetricSetQueryConfig } from 'kayenta/metricStore/prometheus/domain/IPrometheusCanaryMetricSetQueryConfig';
6
+ import { omit } from 'lodash';
7
+ import { Action } from 'redux';
8
+ import { handleActions } from 'redux-actions';
9
+
10
+ const updateLabelBindingsReducer = updateListReducer();
11
+ const updateGroupByReducer = updateListReducer();
12
+
13
+ type IPrometheusMetricConfig = ICanaryMetricConfig<IPrometheusCanaryMetricSetQueryConfig>;
14
+
15
+ export const prometheusMetricConfigReducer = handleActions<IPrometheusMetricConfig, Action & any>(
16
+ {
17
+ [Actions.UPDATE_PROMETHEUS_METRIC_TYPE]: (state: IPrometheusMetricConfig, action: Action & any) => ({
18
+ ...state,
19
+ query: { ...state.query, metricName: action.payload.metricName, type: 'prometheus' },
20
+ }),
21
+ [Actions.UPDATE_PROMETHEUS_METRIC_QUERY_FIELD]: (state: IPrometheusMetricConfig, action: Action & any) => {
22
+ if (!action.payload.value) {
23
+ return {
24
+ ...state,
25
+ query: omit(state.query, action.payload.field),
26
+ };
27
+ }
28
+
29
+ return {
30
+ ...state,
31
+ query: { ...state.query, [action.payload.field]: action.payload.value },
32
+ };
33
+ },
34
+ [Actions.UPDATE_PROMETHEUS_LABEL_BINDINGS]: (
35
+ state: IPrometheusMetricConfig,
36
+ action: IKayentaAction<IUpdateListPayload>,
37
+ ) => ({
38
+ ...state,
39
+ query: {
40
+ ...state.query,
41
+ labelBindings: updateLabelBindingsReducer(state.query.labelBindings || [], action),
42
+ },
43
+ }),
44
+ [Actions.UPDATE_PROMETHEUS_GROUP_BY_FIELDS]: (
45
+ state: IPrometheusMetricConfig,
46
+ action: IKayentaAction<IUpdateListPayload>,
47
+ ) => ({
48
+ ...state,
49
+ query: {
50
+ ...state.query,
51
+ groupByFields: updateGroupByReducer(state.query.groupByFields || [], action),
52
+ },
53
+ }),
54
+ },
55
+ null,
56
+ );
@@ -0,0 +1,190 @@
1
+ import * as Actions from 'kayenta/actions/index';
2
+
3
+ import { ICanaryMetricConfig, IGroupWeights } from '../domain/ICanaryConfig';
4
+ import { IGroupState } from './group';
5
+ import {
6
+ changeMetricGroupConfirmReducer,
7
+ editGroupConfirmReducer,
8
+ ISelectedConfigState,
9
+ updateGroupWeightsReducer,
10
+ } from './selectedConfig';
11
+
12
+ describe('Reducer: editGroupConfirmReducer', () => {
13
+ const createSelectedConfigState = (groupName: string): ISelectedConfigState =>
14
+ ({
15
+ metricList: [
16
+ {
17
+ name: 'metricA',
18
+ groups: [groupName, 'groupC'],
19
+ },
20
+ ] as ICanaryMetricConfig[],
21
+ group: {
22
+ list: [groupName, 'groupC'],
23
+ groupWeights: {
24
+ [groupName]: 50,
25
+ otherGroupName: 50,
26
+ },
27
+ selected: groupName,
28
+ },
29
+ } as any); // Ignore missing fields for type ISelectedConfigState.
30
+
31
+ let state: ISelectedConfigState;
32
+
33
+ beforeEach(() => {
34
+ state = createSelectedConfigState('groupA');
35
+ });
36
+
37
+ it('ignores actions other than EDIT_GROUP_CONFIRM', () => {
38
+ expect(editGroupConfirmReducer(state, { type: 'arbitrary_action' })).toEqual(createSelectedConfigState('groupA'));
39
+ });
40
+
41
+ it('replaces a group name throughout the app state', () => {
42
+ const action = {
43
+ type: Actions.EDIT_GROUP_CONFIRM,
44
+ payload: {
45
+ group: 'groupA',
46
+ edit: 'groupB',
47
+ },
48
+ };
49
+
50
+ expect(editGroupConfirmReducer(state, action)).toEqual(createSelectedConfigState('groupB'));
51
+ });
52
+
53
+ it('ignores the updated group name if the value is JS false', () => {
54
+ const editedGroupNames = ['', null, undefined];
55
+
56
+ editedGroupNames.forEach((edited) => {
57
+ const action = {
58
+ type: Actions.EDIT_GROUP_CONFIRM,
59
+ payload: {
60
+ group: 'groupA',
61
+ edit: edited,
62
+ },
63
+ };
64
+
65
+ expect(editGroupConfirmReducer(state, action)).toEqual(createSelectedConfigState('groupA'));
66
+ });
67
+ });
68
+
69
+ it('ignores the updated group name if the group already exists', () => {
70
+ const action = {
71
+ type: Actions.EDIT_GROUP_CONFIRM,
72
+ payload: {
73
+ group: 'groupA',
74
+ edit: 'groupC',
75
+ },
76
+ };
77
+
78
+ expect(editGroupConfirmReducer(state, action)).toEqual(createSelectedConfigState('groupA'));
79
+ });
80
+ });
81
+
82
+ describe('Reducer: changeMetricGroupConfirmReducer', () => {
83
+ const createAction = (metricId: string) => ({
84
+ type: Actions.CHANGE_METRIC_GROUP_CONFIRM,
85
+ payload: {
86
+ metricId,
87
+ },
88
+ });
89
+
90
+ const createSelectedConfigState = (groups: string[], toGroup: string): ISelectedConfigState =>
91
+ ({
92
+ metricList: [
93
+ {
94
+ name: 'myMetric',
95
+ id: '1',
96
+ groups,
97
+ },
98
+ {
99
+ name: 'myOtherMetric',
100
+ id: '2',
101
+ groups: [],
102
+ },
103
+ ] as ICanaryMetricConfig[],
104
+ changeMetricGroup: {
105
+ toGroup,
106
+ },
107
+ } as any);
108
+
109
+ it("updates a metric's group, leaving other metrics's groups unchanged", () => {
110
+ const state = createSelectedConfigState(['myGroup'], 'updatedGroup');
111
+ const action = createAction('1');
112
+
113
+ const updatedState = changeMetricGroupConfirmReducer(state, action);
114
+
115
+ expect(updatedState.metricList.find((m) => m.id === '1').groups).toEqual(['updatedGroup']);
116
+
117
+ expect(updatedState.metricList.find((m) => m.id === '2').groups).toEqual([]);
118
+ });
119
+
120
+ it('handles metrics with multiple groups', () => {
121
+ let state = createSelectedConfigState(['a', 'b'], 'c');
122
+ let action = createAction('1');
123
+
124
+ let updatedState = changeMetricGroupConfirmReducer(state, action);
125
+
126
+ expect(updatedState.metricList.find((m) => m.id === '1').groups).toEqual(['c']);
127
+
128
+ state = createSelectedConfigState(['a', 'b'], 'b');
129
+ action = createAction('1');
130
+
131
+ updatedState = changeMetricGroupConfirmReducer(state, action);
132
+
133
+ expect(updatedState.metricList.find((m) => m.id === '1').groups).toEqual(['b']);
134
+ });
135
+ });
136
+
137
+ describe('Reducer: updateGroupWeightsReducer', () => {
138
+ const createAction = () => ({ type: Actions.SELECT_CONFIG });
139
+
140
+ const createSelectedConfigState = (
141
+ metricList: ICanaryMetricConfig[],
142
+ groupWeights: IGroupWeights,
143
+ ): ISelectedConfigState =>
144
+ ({
145
+ metricList,
146
+ group: {
147
+ groupWeights,
148
+ } as IGroupState,
149
+ } as any);
150
+
151
+ it('prunes weights for groups that do not exist', () => {
152
+ const metrics = [
153
+ {
154
+ name: 'metricA',
155
+ groups: ['a', 'b'],
156
+ },
157
+ {
158
+ name: 'metricB',
159
+ groups: ['c'],
160
+ },
161
+ ] as ICanaryMetricConfig[];
162
+ const weights: IGroupWeights = { a: 25, b: 25, c: 25, d: 25 };
163
+
164
+ const state = createSelectedConfigState(metrics, weights);
165
+ const action = createAction();
166
+
167
+ const updatedState = updateGroupWeightsReducer(state, action);
168
+ expect(updatedState.group.groupWeights).toEqual({ a: 25, b: 25, c: 25 });
169
+ });
170
+
171
+ it('initializes weights for groups that exist on the metrics only', () => {
172
+ const metrics = [
173
+ {
174
+ name: 'metricA',
175
+ groups: ['a'],
176
+ },
177
+ {
178
+ name: 'metricB',
179
+ groups: ['b', 'c'],
180
+ },
181
+ ] as ICanaryMetricConfig[];
182
+ const weights: IGroupWeights = { a: 50, b: 50 };
183
+
184
+ const state = createSelectedConfigState(metrics, weights);
185
+ const action = createAction();
186
+
187
+ const updatedState = updateGroupWeightsReducer(state, action);
188
+ expect(updatedState.group.groupWeights).toEqual({ a: 50, b: 50, c: 0 });
189
+ });
190
+ });