@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.
- package/.editorconfig +9 -0
- package/.eslintrc.js +1 -0
- package/.huskyrc +5 -0
- package/.lintstagedrc.json +4 -0
- package/.prettierignore +4 -0
- package/.prettierrc.js +1 -0
- package/LICENSE.txt +203 -0
- package/README.md +81 -0
- package/__mocks__/styleMock.js +1 -0
- package/__mocks__/version.json +4 -0
- package/babel.config.js +3 -0
- package/build.gradle +67 -0
- package/build_scripts/checkLicenses.js +79 -0
- package/gradle.properties +0 -0
- package/jest.config.js +204 -0
- package/jest.setup.js +5 -0
- package/package.json +166 -0
- package/rollup-plugin-angularjs-template-loader.js +82 -0
- package/rollup.config.js +30 -0
- package/src/index.ts +2 -0
- package/src/kayenta/actions/creators.ts +163 -0
- package/src/kayenta/actions/index.ts +98 -0
- package/src/kayenta/canary.dataSource.bridge.ts +53 -0
- package/src/kayenta/canary.dataSource.stub.ts +64 -0
- package/src/kayenta/canary.help.ts +136 -0
- package/src/kayenta/canary.less +168 -0
- package/src/kayenta/canary.settings.ts +26 -0
- package/src/kayenta/canary.tsx +67 -0
- package/src/kayenta/components/canaryScore.component.less +77 -0
- package/src/kayenta/components/canaryScore.component.ts +12 -0
- package/src/kayenta/components/canaryScore.tsx +63 -0
- package/src/kayenta/components/canaryScores.component.ts +20 -0
- package/src/kayenta/components/canaryScores.less +22 -0
- package/src/kayenta/components/canaryScores.tsx +163 -0
- package/src/kayenta/components/loadStates.tsx +52 -0
- package/src/kayenta/domain/ICanaryConfig.ts +57 -0
- package/src/kayenta/domain/ICanaryConfigSummary.ts +7 -0
- package/src/kayenta/domain/ICanaryConfigUpdateResponse.ts +3 -0
- package/src/kayenta/domain/ICanaryExecutionStatusResult.ts +72 -0
- package/src/kayenta/domain/ICanaryJudgeResult.ts +51 -0
- package/src/kayenta/domain/ICanaryJudgeResultSummary.ts +5 -0
- package/src/kayenta/domain/ICanaryScoreThresholds.ts +4 -0
- package/src/kayenta/domain/IJudge.ts +5 -0
- package/src/kayenta/domain/IKayentaAccount.ts +14 -0
- package/src/kayenta/domain/IKayentaStageConfig.ts +58 -0
- package/src/kayenta/domain/IMetricSetPair.ts +17 -0
- package/src/kayenta/domain/IMetricsServiceMetadata.ts +2 -0
- package/src/kayenta/domain/ISetupCanaryStage.ts +11 -0
- package/src/kayenta/domain/MetricClassificationLabel.ts +8 -0
- package/src/kayenta/domain/ScoreClassificationLabel.ts +7 -0
- package/src/kayenta/domain/index.ts +15 -0
- package/src/kayenta/edit/changeMetricGroupModal.tsx +107 -0
- package/src/kayenta/edit/configDetail.tsx +31 -0
- package/src/kayenta/edit/configDetailActionButtons.tsx +24 -0
- package/src/kayenta/edit/configDetailHeader.tsx +104 -0
- package/src/kayenta/edit/configDetailLoadStates.tsx +36 -0
- package/src/kayenta/edit/configDetailLoader.tsx +60 -0
- package/src/kayenta/edit/configJson.less +42 -0
- package/src/kayenta/edit/configJsonModal.tsx +158 -0
- package/src/kayenta/edit/configList.less +7 -0
- package/src/kayenta/edit/configList.tsx +57 -0
- package/src/kayenta/edit/copyConfigButton.tsx +34 -0
- package/src/kayenta/edit/createConfigButton.tsx +34 -0
- package/src/kayenta/edit/deleteModal.tsx +87 -0
- package/src/kayenta/edit/edit.tsx +24 -0
- package/src/kayenta/edit/editMetricEffectSizes.tsx +186 -0
- package/src/kayenta/edit/editMetricModal.less +9 -0
- package/src/kayenta/edit/editMetricModal.spec.tsx +129 -0
- package/src/kayenta/edit/editMetricModal.tsx +294 -0
- package/src/kayenta/edit/editMetricValidation.spec.ts +63 -0
- package/src/kayenta/edit/editMetricValidation.ts +50 -0
- package/src/kayenta/edit/filterTemplateSelector.less +15 -0
- package/src/kayenta/edit/filterTemplateSelector.spec.tsx +106 -0
- package/src/kayenta/edit/filterTemplateSelector.tsx +194 -0
- package/src/kayenta/edit/filterTemplatesValidation.spec.ts +108 -0
- package/src/kayenta/edit/filterTemplatesValidation.ts +95 -0
- package/src/kayenta/edit/footer.less +30 -0
- package/src/kayenta/edit/footer.tsx +12 -0
- package/src/kayenta/edit/groupName.tsx +80 -0
- package/src/kayenta/edit/groupTabs.tsx +106 -0
- package/src/kayenta/edit/groupWeight.tsx +80 -0
- package/src/kayenta/edit/groupWeights.tsx +38 -0
- package/src/kayenta/edit/inlineTemplateEditor.spec.tsx +42 -0
- package/src/kayenta/edit/inlineTemplateEditor.tsx +61 -0
- package/src/kayenta/edit/judgeSelect.tsx +82 -0
- package/src/kayenta/edit/metricConfigurerDelegator.tsx +30 -0
- package/src/kayenta/edit/metricList.less +21 -0
- package/src/kayenta/edit/metricList.tsx +215 -0
- package/src/kayenta/edit/metricStoreSelector.tsx +66 -0
- package/src/kayenta/edit/nameAndDescription.tsx +90 -0
- package/src/kayenta/edit/openConfigJsonModalButton.tsx +33 -0
- package/src/kayenta/edit/openDeleteModalButton.tsx +50 -0
- package/src/kayenta/edit/ownedBy.tsx +34 -0
- package/src/kayenta/edit/save.tsx +19 -0
- package/src/kayenta/edit/saveConfigButton.tsx +65 -0
- package/src/kayenta/edit/saveConfigError.tsx +59 -0
- package/src/kayenta/edit/scoring.tsx +35 -0
- package/src/kayenta/edit/selectConfig.tsx +10 -0
- package/src/kayenta/edit/validationErrors.tsx +39 -0
- package/src/kayenta/index.ts +6 -0
- package/src/kayenta/layout/addNewButton.tsx +20 -0
- package/src/kayenta/layout/centeredDetail.tsx +13 -0
- package/src/kayenta/layout/deleteButton.tsx +11 -0
- package/src/kayenta/layout/disableable.tsx +87 -0
- package/src/kayenta/layout/formList.tsx +26 -0
- package/src/kayenta/layout/formRow.tsx +36 -0
- package/src/kayenta/layout/formattedDate.tsx +14 -0
- package/src/kayenta/layout/index.ts +2 -0
- package/src/kayenta/layout/keyValueList.less +20 -0
- package/src/kayenta/layout/keyValueList.tsx +114 -0
- package/src/kayenta/layout/list.less +9 -0
- package/src/kayenta/layout/list.spec.tsx +83 -0
- package/src/kayenta/layout/list.tsx +73 -0
- package/src/kayenta/layout/listDetail.tsx +33 -0
- package/src/kayenta/layout/radioChoice.tsx +29 -0
- package/src/kayenta/layout/styleguide.tsx +16 -0
- package/src/kayenta/layout/table/index.ts +5 -0
- package/src/kayenta/layout/table/nativeTable.tsx +51 -0
- package/src/kayenta/layout/table/nativeTableHeader.tsx +26 -0
- package/src/kayenta/layout/table/table.tsx +56 -0
- package/src/kayenta/layout/table/tableColumn.ts +7 -0
- package/src/kayenta/layout/table/tableHeader.tsx +23 -0
- package/src/kayenta/layout/tabs.tsx +26 -0
- package/src/kayenta/layout/titledSection.less +16 -0
- package/src/kayenta/layout/titledSection.tsx +20 -0
- package/src/kayenta/layout/titledSubsection.less +11 -0
- package/src/kayenta/layout/titledSubsection.tsx +22 -0
- package/src/kayenta/manualAnalysis/ManualAnalysisModal.tsx +716 -0
- package/src/kayenta/metricStore/atlas/atlasMetricConfigurer.tsx +130 -0
- package/src/kayenta/metricStore/atlas/index.ts +8 -0
- package/src/kayenta/metricStore/datadog/domain/IDatadogMetricDescriptor.ts +5 -0
- package/src/kayenta/metricStore/datadog/index.ts +9 -0
- package/src/kayenta/metricStore/datadog/metricConfigurer.tsx +90 -0
- package/src/kayenta/metricStore/datadog/metricTypeSelector.spec.tsx +59 -0
- package/src/kayenta/metricStore/datadog/metricTypeSelector.tsx +73 -0
- package/src/kayenta/metricStore/graphite/domain/IGraphiteMetricDescriptor.ts +5 -0
- package/src/kayenta/metricStore/graphite/index.ts +8 -0
- package/src/kayenta/metricStore/graphite/metricConfigurer.tsx +54 -0
- package/src/kayenta/metricStore/graphite/metricTypeSelector.tsx +80 -0
- package/src/kayenta/metricStore/graphite/typeahead.less +3 -0
- package/src/kayenta/metricStore/index.ts +8 -0
- package/src/kayenta/metricStore/metricStoreConfig.service.ts +12 -0
- package/src/kayenta/metricStore/newrelic/domain/INewRelicMetricDescriptor.ts +5 -0
- package/src/kayenta/metricStore/newrelic/index.ts +8 -0
- package/src/kayenta/metricStore/newrelic/metricConfigurer.tsx +58 -0
- package/src/kayenta/metricStore/prometheus/domain/IPrometheusCanaryMetricSetQueryConfig.ts +14 -0
- package/src/kayenta/metricStore/prometheus/domain/IPrometheusMetricDescriptor.ts +5 -0
- package/src/kayenta/metricStore/prometheus/index.ts +12 -0
- package/src/kayenta/metricStore/prometheus/metricConfigurer.tsx +157 -0
- package/src/kayenta/metricStore/prometheus/metricTypeSelector.less +5 -0
- package/src/kayenta/metricStore/prometheus/metricTypeSelector.spec.tsx +62 -0
- package/src/kayenta/metricStore/prometheus/metricTypeSelector.tsx +144 -0
- package/src/kayenta/metricStore/prometheus/queryTypeSelectors.spec.ts +61 -0
- package/src/kayenta/metricStore/prometheus/queryTypeSelectors.ts +38 -0
- package/src/kayenta/metricStore/signalfx/domain/ISignalFxCanaryMetricSetQueryConfig.ts +7 -0
- package/src/kayenta/metricStore/signalfx/index.ts +8 -0
- package/src/kayenta/metricStore/signalfx/metricConfigurer.less +10 -0
- package/src/kayenta/metricStore/signalfx/metricConfigurer.tsx +187 -0
- package/src/kayenta/metricStore/stackdriver/domain/IStackdriverCanaryMetricSetQueryConfig.ts +9 -0
- package/src/kayenta/metricStore/stackdriver/domain/IStackdriverMetricDescriptor.ts +17 -0
- package/src/kayenta/metricStore/stackdriver/index.ts +12 -0
- package/src/kayenta/metricStore/stackdriver/metricConfigurer.tsx +144 -0
- package/src/kayenta/metricStore/stackdriver/metricTypeSelector.spec.tsx +92 -0
- package/src/kayenta/metricStore/stackdriver/metricTypeSelector.tsx +113 -0
- package/src/kayenta/middleware/actionInterceptor.ts +29 -0
- package/src/kayenta/middleware/asyncDispatch.ts +37 -0
- package/src/kayenta/middleware/epics.ts +211 -0
- package/src/kayenta/middleware/index.ts +3 -0
- package/src/kayenta/navigation/canary.states.stub.ts +28 -0
- package/src/kayenta/navigation/canary.states.ts +182 -0
- package/src/kayenta/reducers/app.ts +56 -0
- package/src/kayenta/reducers/asyncRequest.ts +5 -0
- package/src/kayenta/reducers/data.ts +169 -0
- package/src/kayenta/reducers/editingTemplate.ts +54 -0
- package/src/kayenta/reducers/group.ts +82 -0
- package/src/kayenta/reducers/index.ts +245 -0
- package/src/kayenta/reducers/prometheusMetricConfig.spec.ts +33 -0
- package/src/kayenta/reducers/prometheusMetricConfig.ts +56 -0
- package/src/kayenta/reducers/selectedConfig.spec.ts +190 -0
- package/src/kayenta/reducers/selectedConfig.ts +566 -0
- package/src/kayenta/reducers/selectedRun.ts +101 -0
- package/src/kayenta/reducers/signalFxMetricConfig.ts +36 -0
- package/src/kayenta/reducers/stackdriverMetricConfig.spec.ts +33 -0
- package/src/kayenta/reducers/stackdriverMetricConfig.ts +41 -0
- package/src/kayenta/reducers/templates.spec.ts +192 -0
- package/src/kayenta/reducers/validators.ts +118 -0
- package/src/kayenta/report/detail/allMetricResultsHeader.tsx +32 -0
- package/src/kayenta/report/detail/clickableHeader.tsx +21 -0
- package/src/kayenta/report/detail/colors.ts +47 -0
- package/src/kayenta/report/detail/detail.less +16 -0
- package/src/kayenta/report/detail/detail.tsx +48 -0
- package/src/kayenta/report/detail/detailLoader.tsx +55 -0
- package/src/kayenta/report/detail/graph/graph.tsx +37 -0
- package/src/kayenta/report/detail/graph/metricSetPairGraph.service.ts +35 -0
- package/src/kayenta/report/detail/graph/semiotic/boxplot.less +45 -0
- package/src/kayenta/report/detail/graph/semiotic/boxplot.tsx +283 -0
- package/src/kayenta/report/detail/graph/semiotic/chartHeader.tsx +19 -0
- package/src/kayenta/report/detail/graph/semiotic/chartLegend.less +26 -0
- package/src/kayenta/report/detail/graph/semiotic/chartLegend.tsx +42 -0
- package/src/kayenta/report/detail/graph/semiotic/circleIcon.tsx +16 -0
- package/src/kayenta/report/detail/graph/semiotic/config.less +5 -0
- package/src/kayenta/report/detail/graph/semiotic/config.ts +38 -0
- package/src/kayenta/report/detail/graph/semiotic/customAxisTickLabel.tsx +17 -0
- package/src/kayenta/report/detail/graph/semiotic/declarations/labella.d.ts +16 -0
- package/src/kayenta/report/detail/graph/semiotic/declarations/react-container-dimensions.d.ts +3 -0
- package/src/kayenta/report/detail/graph/semiotic/declarations/semiotic.d.ts +160 -0
- package/src/kayenta/report/detail/graph/semiotic/differenceArea.less +17 -0
- package/src/kayenta/report/detail/graph/semiotic/differenceArea.tsx +186 -0
- package/src/kayenta/report/detail/graph/semiotic/histogram.less +22 -0
- package/src/kayenta/report/detail/graph/semiotic/histogram.tsx +251 -0
- package/src/kayenta/report/detail/graph/semiotic/index.tsx +19 -0
- package/src/kayenta/report/detail/graph/semiotic/noValidDataSign.less +5 -0
- package/src/kayenta/report/detail/graph/semiotic/noValidDataSign.tsx +10 -0
- package/src/kayenta/report/detail/graph/semiotic/secondaryTSXAxis.less +6 -0
- package/src/kayenta/report/detail/graph/semiotic/secondaryTSXAxis.tsx +58 -0
- package/src/kayenta/report/detail/graph/semiotic/semiotic.service.ts +32 -0
- package/src/kayenta/report/detail/graph/semiotic/semioticGraph.less +53 -0
- package/src/kayenta/report/detail/graph/semiotic/semioticGraph.tsx +49 -0
- package/src/kayenta/report/detail/graph/semiotic/timeSeries.less +42 -0
- package/src/kayenta/report/detail/graph/semiotic/timeSeries.tsx +473 -0
- package/src/kayenta/report/detail/graph/semiotic/tooltip.tsx +55 -0
- package/src/kayenta/report/detail/graph/semiotic/utils.ts +90 -0
- package/src/kayenta/report/detail/graphTypeSelector.less +4 -0
- package/src/kayenta/report/detail/graphTypeSelector.tsx +50 -0
- package/src/kayenta/report/detail/groupScores.tsx +68 -0
- package/src/kayenta/report/detail/header.less +70 -0
- package/src/kayenta/report/detail/header.tsx +39 -0
- package/src/kayenta/report/detail/headerArrow.tsx +13 -0
- package/src/kayenta/report/detail/loadStates.tsx +31 -0
- package/src/kayenta/report/detail/metricResultActions.less +29 -0
- package/src/kayenta/report/detail/metricResultActions.tsx +87 -0
- package/src/kayenta/report/detail/metricResultClassification.tsx +22 -0
- package/src/kayenta/report/detail/metricResultDetail.tsx +20 -0
- package/src/kayenta/report/detail/metricResultDetailLayout.tsx +19 -0
- package/src/kayenta/report/detail/metricResultDeviation.tsx +25 -0
- package/src/kayenta/report/detail/metricResultStats.less +9 -0
- package/src/kayenta/report/detail/metricResultStats.tsx +120 -0
- package/src/kayenta/report/detail/metricResults.less +12 -0
- package/src/kayenta/report/detail/metricResults.tsx +52 -0
- package/src/kayenta/report/detail/metricResultsClassificationFilters.tsx +65 -0
- package/src/kayenta/report/detail/metricResultsColumns.tsx +27 -0
- package/src/kayenta/report/detail/metricResultsList.less +44 -0
- package/src/kayenta/report/detail/metricResultsList.tsx +120 -0
- package/src/kayenta/report/detail/metricSetPairLoadStates.tsx +22 -0
- package/src/kayenta/report/detail/multipleResultsTable.tsx +81 -0
- package/src/kayenta/report/detail/reportException.tsx +57 -0
- package/src/kayenta/report/detail/reportExplanation.less +12 -0
- package/src/kayenta/report/detail/reportExplanation.tsx +32 -0
- package/src/kayenta/report/detail/reportMetadata.tsx +167 -0
- package/src/kayenta/report/detail/reportScores.less +47 -0
- package/src/kayenta/report/detail/reportScores.tsx +80 -0
- package/src/kayenta/report/detail/score.tsx +33 -0
- package/src/kayenta/report/detail/sourceLinks.tsx +69 -0
- package/src/kayenta/report/list/configLink.tsx +32 -0
- package/src/kayenta/report/list/executionList.less +7 -0
- package/src/kayenta/report/list/loadStates.tsx +32 -0
- package/src/kayenta/report/list/pipelineLink.tsx +15 -0
- package/src/kayenta/report/list/reportLink.tsx +33 -0
- package/src/kayenta/report/list/table.tsx +309 -0
- package/src/kayenta/report/report.tsx +11 -0
- package/src/kayenta/selectors/filterTemplatesSelectors.ts +87 -0
- package/src/kayenta/selectors/index.ts +62 -0
- package/src/kayenta/service/canaryConfig.service.ts +122 -0
- package/src/kayenta/service/canaryRun.service.ts +60 -0
- package/src/kayenta/service/delegateFactory.ts +24 -0
- package/src/kayenta/service/metricsServiceMetadata.service.ts +9 -0
- package/src/kayenta/stages/kayentaStage/AnalysisType.spec.tsx +47 -0
- package/src/kayenta/stages/kayentaStage/AnalysisType.tsx +49 -0
- package/src/kayenta/stages/kayentaStage/CanaryExecutionLabel.tsx +26 -0
- package/src/kayenta/stages/kayentaStage/analysisType.component.ts +12 -0
- package/src/kayenta/stages/kayentaStage/canaryRunSummaries.component.ts +12 -0
- package/src/kayenta/stages/kayentaStage/canaryRunSummaries.less +5 -0
- package/src/kayenta/stages/kayentaStage/canaryRunSummaries.tsx +136 -0
- package/src/kayenta/stages/kayentaStage/forAnalysisType.component.ts +45 -0
- package/src/kayenta/stages/kayentaStage/kayentaStage.controller.ts +789 -0
- package/src/kayenta/stages/kayentaStage/kayentaStage.html +528 -0
- package/src/kayenta/stages/kayentaStage/kayentaStage.less +5 -0
- package/src/kayenta/stages/kayentaStage/kayentaStage.transformer.ts +179 -0
- package/src/kayenta/stages/kayentaStage/kayentaStage.ts +221 -0
- package/src/kayenta/stages/kayentaStage/kayentaStageConfigSection.component.ts +21 -0
- package/src/kayenta/stages/kayentaStage/kayentaStageExecutionDetails.controller.ts +88 -0
- package/src/kayenta/stages/kayentaStage/kayentaStageExecutionDetails.html +114 -0
- package/src/kayenta/stages/kayentaStage/kayentaStageExecutionDetails.less +6 -0
- package/src/kayenta/stages/kayentaStage/stageTypes.ts +5 -0
- package/src/kayenta/utils/duration.spec.ts +69 -0
- package/src/kayenta/utils/duration.ts +48 -0
- package/src/lazy.ts +29 -0
- package/src/stub.ts +60 -0
- package/tsconfig.json +11 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import * as Creators from 'kayenta/actions/creators';
|
|
2
|
+
import { ICanaryState } from 'kayenta/reducers';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { connect, Dispatch } from 'react-redux';
|
|
5
|
+
|
|
6
|
+
import { GraphType } from './graph/metricSetPairGraph.service';
|
|
7
|
+
|
|
8
|
+
import './graphTypeSelector.less';
|
|
9
|
+
|
|
10
|
+
interface IGraphTypeSelectorStateProps {
|
|
11
|
+
selected: GraphType;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface IGraphTypeSelectorDispatchProps {
|
|
15
|
+
selectGraphType: (type: GraphType) => void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const GraphTypeSelector = ({
|
|
19
|
+
selected,
|
|
20
|
+
selectGraphType,
|
|
21
|
+
}: IGraphTypeSelectorStateProps & IGraphTypeSelectorDispatchProps) => {
|
|
22
|
+
return (
|
|
23
|
+
<ul className="list-inline graph-type-selector">
|
|
24
|
+
<li>
|
|
25
|
+
<label className="label uppercase color-text-primary" style={{ paddingLeft: 0 }}>
|
|
26
|
+
Graph:
|
|
27
|
+
</label>
|
|
28
|
+
</li>
|
|
29
|
+
{Object.values(GraphType).map((type) => (
|
|
30
|
+
<li
|
|
31
|
+
style={selected === type ? { textDecoration: 'underline' } : null}
|
|
32
|
+
key={type}
|
|
33
|
+
onClick={() => selectGraphType(type)}
|
|
34
|
+
>
|
|
35
|
+
<a className="small clickable">{type}</a>
|
|
36
|
+
</li>
|
|
37
|
+
))}
|
|
38
|
+
</ul>
|
|
39
|
+
);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const mapStateToProps = (state: ICanaryState): IGraphTypeSelectorStateProps => ({
|
|
43
|
+
selected: state.selectedRun.graphType,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const mapDispatchToProps = (dispatch: Dispatch<ICanaryState>): IGraphTypeSelectorDispatchProps => ({
|
|
47
|
+
selectGraphType: (type: GraphType) => dispatch(Creators.selectGraphType({ type })),
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
export default connect(mapStateToProps, mapDispatchToProps)(GraphTypeSelector);
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import classNames from 'classnames';
|
|
2
|
+
import * as Creators from 'kayenta/actions/creators';
|
|
3
|
+
import { ICanaryJudgeGroupScore, ICanaryScoreThresholds, IGroupWeights } from 'kayenta/domain';
|
|
4
|
+
import { ICanaryState } from 'kayenta/reducers';
|
|
5
|
+
import { canaryExecutionRequestSelector, serializedGroupWeightsSelector } from 'kayenta/selectors';
|
|
6
|
+
import * as React from 'react';
|
|
7
|
+
import { connect, Dispatch } from 'react-redux';
|
|
8
|
+
|
|
9
|
+
import ClickableHeader from './clickableHeader';
|
|
10
|
+
import { mapGroupToColor } from './colors';
|
|
11
|
+
|
|
12
|
+
export interface IGroupScoresOwnProps {
|
|
13
|
+
groups: ICanaryJudgeGroupScore[];
|
|
14
|
+
className?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface IGroupScoresStateProps {
|
|
18
|
+
groupWeights: IGroupWeights;
|
|
19
|
+
scoreThresholds: ICanaryScoreThresholds;
|
|
20
|
+
selectedGroup: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface IGroupScoresDispatchProps {
|
|
24
|
+
select: (event: any) => void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/*
|
|
28
|
+
* Renders list of group scores.
|
|
29
|
+
* */
|
|
30
|
+
const GroupScores = ({
|
|
31
|
+
groups,
|
|
32
|
+
groupWeights,
|
|
33
|
+
scoreThresholds,
|
|
34
|
+
className,
|
|
35
|
+
select,
|
|
36
|
+
selectedGroup,
|
|
37
|
+
}: IGroupScoresOwnProps & IGroupScoresDispatchProps & IGroupScoresStateProps) => (
|
|
38
|
+
<section className={classNames('horizontal', className)}>
|
|
39
|
+
{groups.map((g) => (
|
|
40
|
+
<ClickableHeader
|
|
41
|
+
key={g.name}
|
|
42
|
+
style={{
|
|
43
|
+
width: `${groupWeights[g.name]}%`, // TODO: at some point (around 4%), the group name doesn't fit.
|
|
44
|
+
backgroundColor: mapGroupToColor(g, scoreThresholds),
|
|
45
|
+
}}
|
|
46
|
+
onClick={() => select(g.name)}
|
|
47
|
+
label={g.name}
|
|
48
|
+
className={classNames('report-score', { active: g.name === selectedGroup })}
|
|
49
|
+
/>
|
|
50
|
+
))}
|
|
51
|
+
</section>
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const mapStateToProps = (state: ICanaryState): IGroupScoresStateProps => ({
|
|
55
|
+
selectedGroup: state.selectedRun.selectedGroup,
|
|
56
|
+
groupWeights: serializedGroupWeightsSelector(state),
|
|
57
|
+
scoreThresholds: canaryExecutionRequestSelector(state).thresholds,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const mapDispatchToProps = (
|
|
61
|
+
dispatch: Dispatch<ICanaryState>,
|
|
62
|
+
ownProps: IGroupScoresOwnProps,
|
|
63
|
+
): IGroupScoresOwnProps & IGroupScoresDispatchProps => ({
|
|
64
|
+
select: (group: string) => dispatch(Creators.selectReportMetricGroup({ group })),
|
|
65
|
+
...ownProps,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
export default connect(mapStateToProps, mapDispatchToProps)(GroupScores);
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
.report-header {
|
|
2
|
+
margin-bottom: 10px;
|
|
3
|
+
align-items: center;
|
|
4
|
+
|
|
5
|
+
h1 {
|
|
6
|
+
flex: 1 0 200px;
|
|
7
|
+
align-items: center;
|
|
8
|
+
margin: 0;
|
|
9
|
+
padding: 0;
|
|
10
|
+
word-break: break-all;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.report-score-wrapper {
|
|
14
|
+
padding: 5px 20px 0 0;
|
|
15
|
+
margin-left: 15px;
|
|
16
|
+
border-right: 1px solid var(--color-titanium);
|
|
17
|
+
text-align: center;
|
|
18
|
+
flex: 0 0 200px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.report-metadata {
|
|
22
|
+
flex: 0 1 auto;
|
|
23
|
+
display: flex;
|
|
24
|
+
overflow: hidden;
|
|
25
|
+
padding-left: 20px;
|
|
26
|
+
padding-top: 10px;
|
|
27
|
+
width: 100%;
|
|
28
|
+
|
|
29
|
+
.group {
|
|
30
|
+
flex: 1 1 200px;
|
|
31
|
+
margin-right: 20px;
|
|
32
|
+
overflow: hidden;
|
|
33
|
+
|
|
34
|
+
&.group-time {
|
|
35
|
+
flex: 0 0 150px;
|
|
36
|
+
}
|
|
37
|
+
&.group-threshold {
|
|
38
|
+
flex: 0 0 80px;
|
|
39
|
+
}
|
|
40
|
+
&.group-source {
|
|
41
|
+
flex: 0 0 64px;
|
|
42
|
+
margin-right: 0;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
ul {
|
|
47
|
+
margin-bottom: 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.label {
|
|
51
|
+
padding-left: 0;
|
|
52
|
+
&.label-lg {
|
|
53
|
+
font-size: 85%;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.kayenta-scope {
|
|
59
|
+
width: 100%;
|
|
60
|
+
overflow: hidden;
|
|
61
|
+
white-space: nowrap;
|
|
62
|
+
text-overflow: ellipsis;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.popover {
|
|
67
|
+
.kayenta-scope {
|
|
68
|
+
word-break: break-all;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { UISref } from '@uirouter/react';
|
|
2
|
+
import { ICanaryJudgeScore } from 'kayenta/domain/ICanaryJudgeResult';
|
|
3
|
+
import { ICanaryState } from 'kayenta/reducers';
|
|
4
|
+
import { judgeResultSelector, serializedCanaryConfigSelector } from 'kayenta/selectors';
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
import { connect } from 'react-redux';
|
|
7
|
+
|
|
8
|
+
import ReportMetadata from './reportMetadata';
|
|
9
|
+
import ReportScore from './score';
|
|
10
|
+
|
|
11
|
+
import './header.less';
|
|
12
|
+
|
|
13
|
+
export interface IReportHeaderStateProps {
|
|
14
|
+
id: string;
|
|
15
|
+
name: string;
|
|
16
|
+
score: ICanaryJudgeScore;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const ReportHeader = ({ id, name, score }: IReportHeaderStateProps) => (
|
|
20
|
+
<section className="horizontal report-header">
|
|
21
|
+
<div className="report-score-wrapper">
|
|
22
|
+
<ReportScore score={score} showClassification={true} />
|
|
23
|
+
<h1 className="heading-2 color-text-primary">
|
|
24
|
+
<UISref to="^.^.canaryConfig.configDetail" params={{ id }}>
|
|
25
|
+
<a className="clickable color-text-primary"> {name}</a>
|
|
26
|
+
</UISref>
|
|
27
|
+
</h1>
|
|
28
|
+
</div>
|
|
29
|
+
<ReportMetadata />
|
|
30
|
+
</section>
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const mapStateToProps = (state: ICanaryState): IReportHeaderStateProps => ({
|
|
34
|
+
id: serializedCanaryConfigSelector(state).id,
|
|
35
|
+
name: serializedCanaryConfigSelector(state).name,
|
|
36
|
+
score: judgeResultSelector(state).score,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
export default connect(mapStateToProps)(ReportHeader);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import classNames from 'classnames';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
const ARROW_CLASS = 'arrow-down';
|
|
5
|
+
|
|
6
|
+
export interface IHeaderArrowProps {
|
|
7
|
+
arrowColor: string;
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default ({ arrowColor, className }: IHeaderArrowProps) => (
|
|
12
|
+
<div className={classNames(ARROW_CLASS, className)} style={{ borderTopColor: arrowColor }} />
|
|
13
|
+
);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import LoadStatesBuilder from 'kayenta/components/loadStates';
|
|
2
|
+
import CenteredDetail from 'kayenta/layout/centeredDetail';
|
|
3
|
+
import { ICanaryState } from 'kayenta/reducers';
|
|
4
|
+
import { AsyncRequestState } from 'kayenta/reducers/asyncRequest';
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
import { connect } from 'react-redux';
|
|
7
|
+
|
|
8
|
+
import ReportDetail from './detail';
|
|
9
|
+
|
|
10
|
+
interface IReportLoadStatesStateProps {
|
|
11
|
+
loadState: AsyncRequestState;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const ReportLoadStates = ({ loadState }: IReportLoadStatesStateProps) => {
|
|
15
|
+
const LoadStates = new LoadStatesBuilder()
|
|
16
|
+
.onFulfilled(<ReportDetail />)
|
|
17
|
+
.onFailed(
|
|
18
|
+
<CenteredDetail>
|
|
19
|
+
<h3 className="heading-3">Could not load canary report.</h3>
|
|
20
|
+
</CenteredDetail>,
|
|
21
|
+
)
|
|
22
|
+
.build();
|
|
23
|
+
|
|
24
|
+
return <LoadStates state={loadState} />;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const mapStateToProps = (state: ICanaryState) => ({
|
|
28
|
+
loadState: state.selectedRun.load,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export default connect(mapStateToProps)(ReportLoadStates);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
.metric-result-actions {
|
|
2
|
+
.actions-layout {
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: row;
|
|
5
|
+
justify-content: flex-end;
|
|
6
|
+
margin: 12px 4px;
|
|
7
|
+
}
|
|
8
|
+
.action {
|
|
9
|
+
padding-left: 8px;
|
|
10
|
+
}
|
|
11
|
+
.copy-button-container {
|
|
12
|
+
display: flex;
|
|
13
|
+
flex-direction: row;
|
|
14
|
+
align-items: center;
|
|
15
|
+
position: relative;
|
|
16
|
+
.clipboard-btn {
|
|
17
|
+
width: 100%;
|
|
18
|
+
height: 100%;
|
|
19
|
+
opacity: 0;
|
|
20
|
+
z-index: 2;
|
|
21
|
+
position: absolute;
|
|
22
|
+
}
|
|
23
|
+
.copy-button {
|
|
24
|
+
.copy-icon {
|
|
25
|
+
top: -1px;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { CanarySettings } from 'kayenta/canary.settings';
|
|
2
|
+
import { ICanaryMetricConfig } from 'kayenta/domain/ICanaryConfig';
|
|
3
|
+
import { IMetricSetPair } from 'kayenta/domain/IMetricSetPair';
|
|
4
|
+
import metricStoreConfigStore from 'kayenta/metricStore/metricStoreConfig.service';
|
|
5
|
+
import { ICanaryState } from 'kayenta/reducers';
|
|
6
|
+
import { selectedMetricConfigSelector } from 'kayenta/selectors';
|
|
7
|
+
import * as React from 'react';
|
|
8
|
+
import { connect } from 'react-redux';
|
|
9
|
+
|
|
10
|
+
import { CopyToClipboard } from '@spinnaker/core';
|
|
11
|
+
|
|
12
|
+
import './metricResultActions.less';
|
|
13
|
+
|
|
14
|
+
export interface IMetricResultStatsStateProps {
|
|
15
|
+
metricConfig: ICanaryMetricConfig;
|
|
16
|
+
metricSetPair: IMetricSetPair;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const buildAtlasGraphUrl = (metricSetPair: IMetricSetPair) => {
|
|
20
|
+
const { attributes, scopes, values, tags } = metricSetPair;
|
|
21
|
+
const { atlasGraphBaseUrl } = CanarySettings;
|
|
22
|
+
let legendTags = '';
|
|
23
|
+
if (Object.keys(tags).length) {
|
|
24
|
+
legendTags = ` (${Object.keys(tags)
|
|
25
|
+
.map((tag) => `$${tag}`)
|
|
26
|
+
.join('|')})`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// TODO: If the control and experiment have different baseURLs, generate two links instead of a combined one.
|
|
30
|
+
const backend = encodeURIComponent(attributes.control.baseURL);
|
|
31
|
+
const experimentQuery = encodeURIComponent(attributes.experiment.query);
|
|
32
|
+
const controlQuery = encodeURIComponent(attributes.control.query);
|
|
33
|
+
const query = `${experimentQuery},Canary${legendTags},:legend,:freeze,${controlQuery},Baseline${legendTags},:legend`;
|
|
34
|
+
|
|
35
|
+
const startTime = Math.min(scopes.control.startTimeMillis, scopes.experiment.startTimeMillis);
|
|
36
|
+
const controlEndTime = scopes.control.startTimeMillis + values.control.length * scopes.control.stepMillis;
|
|
37
|
+
const experimentEndTime = scopes.experiment.startTimeMillis + values.experiment.length * scopes.experiment.stepMillis;
|
|
38
|
+
const endTime = Math.max(controlEndTime, experimentEndTime);
|
|
39
|
+
|
|
40
|
+
return `${atlasGraphBaseUrl}?backend=${backend}&g.q=${query}&g.s=${startTime}&g.e=${endTime}&g.w=651&mode=png&axis=0`;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const MetricResultActions = ({ metricSetPair, metricConfig }: IMetricResultStatsStateProps) => {
|
|
44
|
+
const atlasURL = buildAtlasGraphUrl(metricSetPair);
|
|
45
|
+
const atlasQuery = metricStoreConfigStore.getDelegate(metricConfig.query.type).queryFinder(metricConfig);
|
|
46
|
+
|
|
47
|
+
// Mask CopyToClipboard component as a larger button, fire event when clicked
|
|
48
|
+
const copyToClipboard = (
|
|
49
|
+
<div className="copy-button-container">
|
|
50
|
+
<CopyToClipboard displayText={false} text={atlasQuery} toolTip={null} />
|
|
51
|
+
<button className="primary copy-button" key="copy-link">
|
|
52
|
+
<i className="glyphicon glyphicon-copy copy-icon" />
|
|
53
|
+
Copy metric query
|
|
54
|
+
</button>
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const openAtlas = (
|
|
59
|
+
<a href={atlasURL} target="_blank">
|
|
60
|
+
<button className="primary">
|
|
61
|
+
<i className="fas fa-chart-line" />
|
|
62
|
+
Explore more data in Atlas
|
|
63
|
+
</button>
|
|
64
|
+
</a>
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
const actions = [copyToClipboard, openAtlas].map((action, i) => {
|
|
68
|
+
return (
|
|
69
|
+
<li className="action" key={i}>
|
|
70
|
+
{action}
|
|
71
|
+
</li>
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<div className="metric-result-actions">
|
|
77
|
+
<ul className="actions-layout list-inline">{actions}</ul>
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const mapStateToProps = (state: ICanaryState): IMetricResultStatsStateProps => ({
|
|
83
|
+
metricConfig: selectedMetricConfigSelector(state),
|
|
84
|
+
metricSetPair: state.selectedRun.metricSetPair.pair,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
export default connect(mapStateToProps)(MetricResultActions);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import classNames from 'classnames';
|
|
2
|
+
import { MetricClassificationLabel } from 'kayenta/domain/MetricClassificationLabel';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
|
|
5
|
+
import { mapMetricClassificationToColor } from './colors';
|
|
6
|
+
|
|
7
|
+
interface IMetricResultClassificationProps {
|
|
8
|
+
classification: MetricClassificationLabel;
|
|
9
|
+
className?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const buildStyle = (classification: MetricClassificationLabel) => ({
|
|
13
|
+
backgroundColor: mapMetricClassificationToColor(classification),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const TEXT_COLOR = 'var(--color-text-on-dark)';
|
|
17
|
+
|
|
18
|
+
export default ({ classification, className }: IMetricResultClassificationProps) => (
|
|
19
|
+
<div className={classNames('pill', 'metric-result-classification', className)} style={buildStyle(classification)}>
|
|
20
|
+
<span style={{ color: TEXT_COLOR }}>{classification}</span>
|
|
21
|
+
</div>
|
|
22
|
+
);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ICanaryAnalysisResult } from 'kayenta/domain/ICanaryJudgeResult';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
import MetricSetPairLoadStates from './metricSetPairLoadStates';
|
|
5
|
+
|
|
6
|
+
export interface IMetricResultDetailProps {
|
|
7
|
+
result: ICanaryAnalysisResult;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
* Top-level component for the metric result detail - i.e., the right side of the
|
|
12
|
+
* screen that opens when you click on a metric result.
|
|
13
|
+
* */
|
|
14
|
+
export default ({ result }: IMetricResultDetailProps) => {
|
|
15
|
+
if (result) {
|
|
16
|
+
return <MetricSetPairLoadStates />;
|
|
17
|
+
} else {
|
|
18
|
+
return <h3 className="heading-3 text-center">Select a metric result.</h3>;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import Graph from './graph/graph';
|
|
4
|
+
import GraphTypeSelector from './graphTypeSelector';
|
|
5
|
+
import MetricResultActions from './metricResultActions';
|
|
6
|
+
import MetricResultStats from './metricResultStats';
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
* Responsible for layout of the metric result detail view after the metric set
|
|
10
|
+
* pair for the result has loaded successfully.
|
|
11
|
+
* */
|
|
12
|
+
export default () => (
|
|
13
|
+
<section className="vertical flex-1 sp-padding-xl-bottom" style={{ overflowY: 'auto' }}>
|
|
14
|
+
<GraphTypeSelector />
|
|
15
|
+
<Graph />
|
|
16
|
+
<MetricResultActions />
|
|
17
|
+
<MetricResultStats />
|
|
18
|
+
</section>
|
|
19
|
+
);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
interface IMetricResultDeviationProps {
|
|
4
|
+
className?: string;
|
|
5
|
+
ratio: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const formatDeviationAsPercentage = (ratio: number) => {
|
|
9
|
+
if (typeof ratio !== 'number') {
|
|
10
|
+
return 'N/A';
|
|
11
|
+
} else if (ratio === 1) {
|
|
12
|
+
return '0%';
|
|
13
|
+
} else if (ratio < 1) {
|
|
14
|
+
return ((ratio - 1) * 100).toFixed(1) + '%';
|
|
15
|
+
} else {
|
|
16
|
+
return '+' + ((ratio - 1) * 100).toFixed(1) + '%';
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default ({ ratio, className }: IMetricResultDeviationProps) =>
|
|
21
|
+
ratio && (
|
|
22
|
+
<span className={className} style={{ color: 'var(--color-text-caption' }}>
|
|
23
|
+
{formatDeviationAsPercentage(ratio)}
|
|
24
|
+
</span>
|
|
25
|
+
);
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { ICanaryAnalysisResultsStats } from 'kayenta/domain';
|
|
2
|
+
import { ICanaryMetricConfig } from 'kayenta/domain/ICanaryConfig';
|
|
3
|
+
import { ICanaryExecutionStatusResult } from 'kayenta/domain/ICanaryExecutionStatusResult';
|
|
4
|
+
import { IMetricSetPair } from 'kayenta/domain/IMetricSetPair';
|
|
5
|
+
import FormattedDate from 'kayenta/layout/formattedDate';
|
|
6
|
+
import { ITableColumn, NativeTable } from 'kayenta/layout/table';
|
|
7
|
+
import { ICanaryState } from 'kayenta/reducers';
|
|
8
|
+
import { runSelector, selectedMetricConfigSelector } from 'kayenta/selectors';
|
|
9
|
+
import { round } from 'lodash';
|
|
10
|
+
import * as React from 'react';
|
|
11
|
+
import { connect } from 'react-redux';
|
|
12
|
+
|
|
13
|
+
import './metricResultStats.less';
|
|
14
|
+
|
|
15
|
+
export interface IMetricResultStatsStateProps {
|
|
16
|
+
metricConfig: ICanaryMetricConfig;
|
|
17
|
+
metricSetPair: IMetricSetPair;
|
|
18
|
+
run: ICanaryExecutionStatusResult;
|
|
19
|
+
service: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const getStats = (run: ICanaryExecutionStatusResult, id: string, target: string): ICanaryAnalysisResultsStats => {
|
|
23
|
+
const result = run.result.judgeResult.results.find((r) => r.id === id);
|
|
24
|
+
if (target === 'experiment') {
|
|
25
|
+
return result.experimentMetadata.stats;
|
|
26
|
+
} else if (target === 'control') {
|
|
27
|
+
return result.controlMetadata.stats;
|
|
28
|
+
} else {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
interface IResultMetadataRow {
|
|
34
|
+
label: string;
|
|
35
|
+
getContent: () => JSX.Element;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const ResultMetadataRow = ({ row }: { row: IResultMetadataRow }) => {
|
|
39
|
+
if (!row.getContent()) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<div>
|
|
45
|
+
<label className="label uppercase color-text-primary">{row.label}</label>
|
|
46
|
+
{row.getContent()}
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const MetricResultStats = ({ metricConfig, metricSetPair, run }: IMetricResultStatsStateProps) => {
|
|
52
|
+
const tableColumns: Array<ITableColumn<string>> = [
|
|
53
|
+
{
|
|
54
|
+
getContent: (target) => <span>{target === 'control' ? 'Baseline' : 'Canary'}</span>,
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
label: 'start',
|
|
58
|
+
getContent: (target) => <FormattedDate dateIso={metricSetPair.scopes[target].startTimeIso} />,
|
|
59
|
+
hide: () => {
|
|
60
|
+
const request = run.canaryExecutionRequest;
|
|
61
|
+
const configuredControlStart = request.scopes[metricConfig.scopeName].controlScope.start;
|
|
62
|
+
const actualControlStart = metricSetPair.scopes.control.startTimeIso;
|
|
63
|
+
|
|
64
|
+
const configuredExperimentStart = request.scopes[metricConfig.scopeName].experimentScope.start;
|
|
65
|
+
const actualExperimentStart = metricSetPair.scopes.experiment.startTimeIso;
|
|
66
|
+
|
|
67
|
+
return configuredControlStart === actualControlStart && configuredExperimentStart === actualExperimentStart;
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
label: 'count',
|
|
72
|
+
getContent: (target) => <span>{getStats(run, metricSetPair.id, target).count}</span>,
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
label: 'avg',
|
|
76
|
+
getContent: (target) => <span>{round(getStats(run, metricSetPair.id, target).mean, 3)}</span>,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
label: 'max',
|
|
80
|
+
getContent: (target) => <span>{round(getStats(run, metricSetPair.id, target).max, 3)}</span>,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
label: 'min',
|
|
84
|
+
getContent: (target) => <span>{round(getStats(run, metricSetPair.id, target).min, 3)}</span>,
|
|
85
|
+
},
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
const metadataRows: IResultMetadataRow[] = [
|
|
89
|
+
{
|
|
90
|
+
label: 'classification reason',
|
|
91
|
+
getContent: () => {
|
|
92
|
+
const result = run.result.judgeResult.results.find((r) => r.id === metricSetPair.id);
|
|
93
|
+
|
|
94
|
+
if (!result.classificationReason) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return <p>{result.classificationReason}</p>;
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
];
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<div className="metric-stats vertical">
|
|
105
|
+
{metadataRows.map((row) => (
|
|
106
|
+
<ResultMetadataRow row={row} key={row.label} />
|
|
107
|
+
))}
|
|
108
|
+
<NativeTable columns={tableColumns} rows={['control', 'experiment']} rowKey={(row) => row} />
|
|
109
|
+
</div>
|
|
110
|
+
);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const mapStateToProps = (state: ICanaryState): IMetricResultStatsStateProps => ({
|
|
114
|
+
metricConfig: selectedMetricConfigSelector(state),
|
|
115
|
+
metricSetPair: state.selectedRun.metricSetPair.pair,
|
|
116
|
+
run: runSelector(state),
|
|
117
|
+
service: selectedMetricConfigSelector(state).query.type,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
export default connect(mapStateToProps)(MetricResultStats);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ICanaryAnalysisResult } from 'kayenta/domain/ICanaryJudgeResult';
|
|
2
|
+
import { ICanaryState } from 'kayenta/reducers';
|
|
3
|
+
import { judgeResultSelector } from 'kayenta/selectors';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import { connect } from 'react-redux';
|
|
6
|
+
|
|
7
|
+
import ListDetail from '../../layout/listDetail';
|
|
8
|
+
import MetricResultDetail from './metricResultDetail';
|
|
9
|
+
import MetricResultsList from './metricResultsList';
|
|
10
|
+
|
|
11
|
+
import './metricResults.less';
|
|
12
|
+
|
|
13
|
+
interface IMetricResultsStateProps {
|
|
14
|
+
metricResults: ICanaryAnalysisResult[];
|
|
15
|
+
selectedMetricResult: ICanaryAnalysisResult;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const MetricResults = ({ metricResults, selectedMetricResult }: IMetricResultsStateProps) => {
|
|
19
|
+
const list = <MetricResultsList results={metricResults} />;
|
|
20
|
+
const detail = <MetricResultDetail result={selectedMetricResult} />;
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<ListDetail
|
|
24
|
+
list={list}
|
|
25
|
+
listClass="vertical"
|
|
26
|
+
listWidth={5}
|
|
27
|
+
detail={detail}
|
|
28
|
+
detailClass="vertical"
|
|
29
|
+
detailWidth={9}
|
|
30
|
+
className="metric-results flex-1"
|
|
31
|
+
/>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const mapStateToProps = (state: ICanaryState): IMetricResultsStateProps => {
|
|
36
|
+
const {
|
|
37
|
+
selectedRun: { selectedGroup, selectedMetric },
|
|
38
|
+
} = state;
|
|
39
|
+
const result = judgeResultSelector(state);
|
|
40
|
+
|
|
41
|
+
// Build list of metric results to render.
|
|
42
|
+
const filter: (r: ICanaryAnalysisResult) => boolean = selectedGroup
|
|
43
|
+
? (r) => r.groups.includes(selectedGroup)
|
|
44
|
+
: () => true;
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
metricResults: Object.values(result.results).filter(filter),
|
|
48
|
+
selectedMetricResult: Object.values(result.results).find((r) => r.id === selectedMetric),
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export default connect(mapStateToProps)(MetricResults);
|