-
@@ -64,41 +15,133 @@ exports[`App CompareResults or CompareOverTime loader Should render an error pag
class="MuiGrid-root MuiGrid-direction-xs-row header-container container_fjtw4pp css-k4qgqg-MuiGrid-root"
>
+
-
@@ -327,41 +321,133 @@ exports[`App CompareResults or CompareOverTime loader Should render an error pag
class="MuiGrid-root MuiGrid-direction-xs-row header-container container_fjtw4pp css-k4qgqg-MuiGrid-root"
>
+
-
@@ -485,41 +522,133 @@ exports[`App CompareResults or CompareOverTime loader Should render an error pag
class="MuiGrid-root MuiGrid-direction-xs-row header-container container_fjtw4pp css-k4qgqg-MuiGrid-root"
>
+
{
});
});
+describe('getLatestCommitMessage with no newline Helper', () => {
+ it('correctly returns latest commit message when newline is missing', () => {
+ const { testData } = getTestData();
+
+ const commitMessage = getLatestCommitMessage(testData[6]);
+
+ expect(commitMessage).toBe('Commit message with no newline at the end');
+ });
+});
+
describe('formateDate Helper', () => {
it('correctly formats date', () => {
const timestamp = 1649883600;
diff --git a/src/__tests__/utils/fixtures.ts b/src/__tests__/utils/fixtures.ts
index 1b1fd6229..8ed43150c 100644
--- a/src/__tests__/utils/fixtures.ts
+++ b/src/__tests__/utils/fixtures.ts
@@ -123,6 +123,30 @@ const getTestData = () => {
push_timestamp: 1649808222,
repository_id: 77,
},
+ {
+ id: 7,
+ revision: 'spamspamspamspamandeggs',
+ author: 'grahamchapman@python.com',
+ revisions: [
+ {
+ result_set_id: 7,
+ repository_id: 77,
+ revision: 'spam',
+ author: 'grahamchapman@python.com',
+ comments: 'Commit message with no newline at the end',
+ },
+ {
+ result_set_id: 7,
+ repository_id: 77,
+ revision: 'spam',
+ author: 'grahamchapman@python.com',
+ comments: 'It got better...',
+ },
+ ],
+ revision_count: 1,
+ push_timestamp: 1649808000,
+ repository_id: 77,
+ },
];
const testCompareData: CompareResultsItem[] = [
diff --git a/src/common/constants.ts b/src/common/constants.ts
index d1f24af96..d3809f23b 100644
--- a/src/common/constants.ts
+++ b/src/common/constants.ts
@@ -325,12 +325,8 @@ export const platformMap: Record
= {
export const MANN_WHITNEY_U = 'mann-whitney-u' as TestVersion;
export const STUDENT_T = 'student-t' as TestVersion;
-export const tooltipEffectSize =
- 'An improvement or regression being shown here means that the effect size is meaningful, and the difference has a significant p-value.';
export const tooltipSignificance =
'Significance of the comparison as determined by a Mann Whitney U test. A significant comparison has a p-value of less than 0.05.';
-export const tooltipCliffsDelta =
- 'Cliff’s Delta quantifies the magnitude of the difference between Base and New values.';
export const tooltipStatusMannWhitney =
'An improvement or regression being shown here means that the effect size is meaningful, and the difference has a significant p-value.';
export const tooltipTotalRuns =
diff --git a/src/common/testVersions/index.ts b/src/common/testVersions/index.ts
new file mode 100644
index 000000000..8c61c882e
--- /dev/null
+++ b/src/common/testVersions/index.ts
@@ -0,0 +1,34 @@
+import type { ReactNode } from 'react';
+
+import { mannWhitneyStrategy } from './mannWhitney';
+import { studentTStrategy } from './studentT';
+import { CombinedResultsItemType } from '../../types/state';
+import { TableConfig, TestVersion } from '../../types/types';
+
+export interface TestVersionStrategy {
+ getColumns(isSubtestTable: boolean): TableConfig;
+ getAvgValues(result: CombinedResultsItemType): {
+ baseAvg: number | null;
+ newAvg: number | null;
+ };
+ renderColumns(result: CombinedResultsItemType): ReactNode;
+}
+
+// Registry mapping each TestVersion to its concrete strategy.
+// To add a new test version: create a strategy file, add it here,
+// and extend the TestVersion union type in types/types.ts.
+const registry: Record = {
+ 'student-t': studentTStrategy,
+ 'mann-whitney-u': mannWhitneyStrategy,
+};
+
+export function getStrategy(testVersion: TestVersion): TestVersionStrategy {
+ return registry[testVersion];
+}
+
+export function getColumnsForVersion(
+ testVersion: TestVersion,
+ isSubtestTable: boolean,
+): TableConfig {
+ return registry[testVersion].getColumns(isSubtestTable);
+}
diff --git a/src/common/testVersions/mannWhitney.tsx b/src/common/testVersions/mannWhitney.tsx
new file mode 100644
index 000000000..2d3a404c0
--- /dev/null
+++ b/src/common/testVersions/mannWhitney.tsx
@@ -0,0 +1,250 @@
+import ThumbDownIcon from '@mui/icons-material/ThumbDown';
+import ThumbUpIcon from '@mui/icons-material/ThumbUp';
+import Box from '@mui/material/Box';
+
+import {
+ CombinedResultsItemType,
+ MannWhitneyResultsItem,
+} from '../../types/state';
+import { TableConfig } from '../../types/types';
+import { capitalize } from '../../utils/helpers';
+import { getPlatformShortName } from '../../utils/platform';
+import { determineStatusHintClass } from '../../utils/revisionRowHelpers';
+import { defaultSortFunction } from '../../utils/sortFunctions';
+import {
+ tooltipBaseMean,
+ tooltipNewMean,
+ tooltipSignificance,
+ tooltipStatusMannWhitney,
+ tooltipTotalRuns,
+} from '../constants';
+
+const tooltipCliffsDelta = (
+
+
+ Cliff's Delta
+ {' '}
+ quantifies the magnitude of the difference between Base and New values.
+ Anything beyond ±0.47 is considered a large difference while anything below
+ ±0.15 is negligible. A negative value means a New value is consistently
+ larger than a Base value.
+
+);
+
+const tooltipEffectSize = (
+
+
+ The Common Language Effect Size (CLES)
+ {' '}
+ is a percentage, from 0% to 100%, providing a clearer indication of how
+ large or meaningful the change is. An improvement or regression being shown
+ here means that the effect size is meaningful. If the effect size is close
+ to 50%, the distributions are probably identical, if not, they probably
+ differ. The sign of the Cliff's delta is also important, as it
+ indicates the direction of the change. If shifted to the left, it's
+ negative; to the right, it's positive. Pair this with higher is better
+ or lower is better to understand whether the change is an improvement or
+ regression. For example, given a Cliff's delta of 0.54 and CLES of 77%,
+ there's a 77% chance a value from new is lower than a value from old
+ (lower is better).
+
+);
+
+const PLATFORM_FILTER_VALUES = [
+ { label: 'Windows', key: 'windows' },
+ { label: 'macOS', key: 'osx' },
+ { label: 'Linux', key: 'linux' },
+ { label: 'Android', key: 'android' },
+ { label: 'iOS', key: 'ios' },
+];
+
+export const mannWhitneyStrategy = {
+ getColumns(isSubtestTable: boolean): TableConfig {
+ const platformConfig = isSubtestTable
+ ? {
+ name: 'Subtests',
+ key: 'subtests',
+ gridWidth: '1.5fr',
+ sortFunction: defaultSortFunction,
+ }
+ : {
+ name: 'Platform',
+ filter: true,
+ key: 'platform',
+ gridWidth: '1.5fr',
+ possibleValues: PLATFORM_FILTER_VALUES,
+ matchesFunction(result: MannWhitneyResultsItem, valueKey: string) {
+ const label = this.possibleValues.find(
+ ({ key }) => key === valueKey,
+ )?.label;
+ return getPlatformShortName(result.platform) === label;
+ },
+ };
+
+ const colWidthMultiply = isSubtestTable ? 1 : 2.5;
+
+ return [
+ platformConfig,
+ {
+ name: 'Base',
+ key: 'base',
+ gridWidth: '.75fr',
+ tooltip: tooltipBaseMean,
+ },
+ { key: 'comparisonSign', gridWidth: '0.25fr' },
+ { name: 'New', key: 'new', gridWidth: '.75fr', tooltip: tooltipNewMean },
+ {
+ name: 'Status',
+ filter: true,
+ key: 'status',
+ gridWidth: '1.25fr',
+ possibleValues: [
+ { label: 'No changes', key: 'none' },
+ { label: 'Improvement', key: 'improvement' },
+ { label: 'Regression', key: 'regression' },
+ ],
+ matchesFunction(result: MannWhitneyResultsItem, valueKey: string) {
+ switch (valueKey) {
+ case 'improvement':
+ return result.direction_of_change === 'improvement';
+ case 'regression':
+ return result.direction_of_change === 'regression';
+ default:
+ return (
+ !result.direction_of_change ||
+ result.direction_of_change === 'no change'
+ );
+ }
+ },
+ tooltip: tooltipStatusMannWhitney,
+ },
+ {
+ name: "Cliff's Delta",
+ key: 'delta',
+ gridWidth: '1.25fr',
+ sortFunction(
+ resultA: MannWhitneyResultsItem,
+ resultB: MannWhitneyResultsItem,
+ ) {
+ return (
+ Math.abs(resultA.cliffs_delta) - Math.abs(resultB.cliffs_delta)
+ );
+ },
+ tooltip: tooltipCliffsDelta,
+ },
+ {
+ name: 'Significance',
+ key: 'significance',
+ filter: true,
+ gridWidth: '1.5fr',
+ tooltip: tooltipSignificance,
+ possibleValues: [
+ { label: 'Significant', key: 'significant' },
+ { label: 'Not Significant', key: 'not significant' },
+ ],
+ matchesFunction(result: MannWhitneyResultsItem, valueKey: string) {
+ const label = this.possibleValues.find(
+ ({ key }) => key === valueKey?.toLowerCase(),
+ )?.label;
+ return (
+ result.mann_whitney_test?.interpretation === label?.toLowerCase()
+ );
+ },
+ sortFunction(
+ resultA: MannWhitneyResultsItem,
+ resultB: MannWhitneyResultsItem,
+ ) {
+ return (
+ Math.abs(resultA.mann_whitney_test?.pvalue ?? 0) -
+ Math.abs(resultB.mann_whitney_test?.pvalue ?? 0)
+ );
+ },
+ },
+ {
+ name: 'Effect Size (%)',
+ key: 'effects',
+ gridWidth: '1.25fr',
+ sortFunction(
+ resultA: MannWhitneyResultsItem,
+ resultB: MannWhitneyResultsItem,
+ ) {
+ return (
+ Math.abs(resultA.cles?.cles ?? 0) -
+ Math.abs(resultB.cles?.cles ?? 0)
+ );
+ },
+ tooltip: tooltipEffectSize,
+ },
+ {
+ name: 'Total Runs',
+ key: 'runs',
+ gridWidth: '1fr',
+ tooltip: tooltipTotalRuns,
+ },
+ { key: 'buttons', gridWidth: `calc(${colWidthMultiply} * 34px)` },
+ { key: 'expand', gridWidth: '34px' },
+ ] as TableConfig;
+ },
+
+ getAvgValues(result: CombinedResultsItemType) {
+ const resultItem = result as MannWhitneyResultsItem;
+ return {
+ baseAvg: resultItem.base_standard_stats?.mean ?? null,
+ newAvg: resultItem.new_standard_stats?.mean ?? null,
+ };
+ },
+
+ renderColumns(result: CombinedResultsItemType) {
+ const { cliffs_delta, direction_of_change, mann_whitney_test, cles } =
+ result as MannWhitneyResultsItem;
+ const clesValue = cles?.cles ? `${(cles.cles * 100).toFixed(2)} %` : '-';
+
+ return (
+ <>
+
+
+ {direction_of_change === 'improvement' ? (
+
+ ) : null}
+ {direction_of_change === 'regression' ? (
+
+ ) : null}
+ {capitalize(direction_of_change ?? '')}
+
+
+
+ {cliffs_delta || '-'}
+
+
+ {mann_whitney_test?.interpretation
+ ? capitalize(mann_whitney_test.interpretation)
+ : '-'}
+
+
+ {clesValue}
+
+ >
+ );
+ },
+};
diff --git a/src/common/testVersions/studentT.tsx b/src/common/testVersions/studentT.tsx
new file mode 100644
index 000000000..7e79fffae
--- /dev/null
+++ b/src/common/testVersions/studentT.tsx
@@ -0,0 +1,191 @@
+import DragHandleIcon from '@mui/icons-material/DragHandle';
+import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
+import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp';
+import ThumbDownIcon from '@mui/icons-material/ThumbDown';
+import ThumbUpIcon from '@mui/icons-material/ThumbUp';
+import Box from '@mui/material/Box';
+
+import { CombinedResultsItemType, CompareResultsItem } from '../../types/state';
+import { TableConfig } from '../../types/types';
+import { getPlatformShortName } from '../../utils/platform';
+import {
+ determineStatus,
+ determineStatusHintClass,
+} from '../../utils/revisionRowHelpers';
+import { defaultSortSubtestFunction } from '../../utils/sortFunctions';
+import {
+ tooltipBaseMean,
+ tooltipConfidence,
+ tooltipDelta,
+ tooltipNewMean,
+ tooltipTotalRuns,
+} from '../constants';
+
+const PLATFORM_FILTER_VALUES = [
+ { label: 'Windows', key: 'windows' },
+ { label: 'macOS', key: 'osx' },
+ { label: 'Linux', key: 'linux' },
+ { label: 'Android', key: 'android' },
+ { label: 'iOS', key: 'ios' },
+];
+
+const confidenceIcons: Record<'Low' | 'Medium' | 'High', React.ReactNode> = {
+ Low: ,
+ Medium: ,
+ High: ,
+};
+
+export const studentTStrategy = {
+ getColumns(isSubtestTable: boolean): TableConfig {
+ const platformConfig = isSubtestTable
+ ? {
+ name: 'Subtests',
+ key: 'subtests',
+ gridWidth: '3fr',
+ sortFunction: defaultSortSubtestFunction,
+ }
+ : {
+ name: 'Platform',
+ filter: true,
+ key: 'platform',
+ gridWidth: '2fr',
+ possibleValues: PLATFORM_FILTER_VALUES,
+ matchesFunction(result: CompareResultsItem, valueKey: string) {
+ const label = this.possibleValues.find(
+ ({ key }) => key === valueKey,
+ )?.label;
+ return getPlatformShortName(result.platform) === label;
+ },
+ };
+
+ const colWidthMultiply = isSubtestTable ? 1 : 3.5;
+ const confidenceGridWidth = isSubtestTable ? '1.8fr' : '1.5fr';
+
+ return [
+ platformConfig,
+ { name: 'Base', key: 'base', gridWidth: '1fr', tooltip: tooltipBaseMean },
+ { key: 'comparisonSign', gridWidth: '0.2fr' },
+ { name: 'New', key: 'new', gridWidth: '1fr', tooltip: tooltipNewMean },
+ {
+ name: 'Status',
+ filter: true,
+ key: 'status',
+ gridWidth: '1.5fr',
+ possibleValues: [
+ { label: 'No changes', key: 'none' },
+ { label: 'Improvement', key: 'improvement' },
+ { label: 'Regression', key: 'regression' },
+ ],
+ matchesFunction(result: CompareResultsItem, valueKey: string) {
+ switch (valueKey) {
+ case 'improvement':
+ return result.is_improvement;
+ case 'regression':
+ return result.is_regression;
+ default:
+ return !result.is_improvement && !result.is_regression;
+ }
+ },
+ },
+ {
+ name: 'Delta',
+ key: 'delta',
+ gridWidth: '1fr',
+ sortFunction(resultA: CompareResultsItem, resultB: CompareResultsItem) {
+ return (
+ Math.abs(resultA.delta_percentage) -
+ Math.abs(resultB.delta_percentage)
+ );
+ },
+ tooltip: tooltipDelta,
+ },
+ {
+ name: 'Confidence',
+ filter: true,
+ key: 'confidence',
+ gridWidth: confidenceGridWidth,
+ tooltip: tooltipConfidence,
+ possibleValues: [
+ { label: 'No value', key: 'none' },
+ { label: 'Low', key: 'low' },
+ { label: 'Medium', key: 'medium' },
+ { label: 'High', key: 'high' },
+ ],
+ matchesFunction(result: CompareResultsItem, valueKey: string) {
+ switch (valueKey) {
+ case 'none':
+ return !result.confidence_text;
+ default: {
+ const label = this.possibleValues.find(
+ ({ key }) => key === valueKey,
+ )?.label;
+ return result.confidence_text === label;
+ }
+ }
+ },
+ sortFunction(resultA: CompareResultsItem, resultB: CompareResultsItem) {
+ const confidenceA =
+ resultA.confidence_text && resultA.confidence !== null
+ ? resultA.confidence
+ : -1;
+ const confidenceB =
+ resultB.confidence_text && resultB.confidence !== null
+ ? resultB.confidence
+ : -1;
+ return confidenceA - confidenceB;
+ },
+ },
+ {
+ name: 'Total Runs',
+ key: 'runs',
+ gridWidth: '1fr',
+ tooltip: tooltipTotalRuns,
+ },
+ { key: 'buttons', gridWidth: `calc(${colWidthMultiply} * 34px)` },
+ { key: 'expand', gridWidth: '34px' },
+ ] as TableConfig;
+ },
+
+ getAvgValues(result: CombinedResultsItemType) {
+ const resultItem = result as CompareResultsItem;
+ return {
+ baseAvg: resultItem.base_avg_value,
+ newAvg: resultItem.new_avg_value,
+ };
+ },
+
+ renderColumns(result: CombinedResultsItemType) {
+ const {
+ is_improvement: improvement,
+ is_regression: regression,
+ confidence_text: confidenceText,
+ delta_percentage: deltaPercent,
+ } = result as CompareResultsItem;
+
+ return (
+ <>
+
+
+ {improvement ? : null}
+ {regression ? : null}
+ {determineStatus(!!improvement, !!regression)}
+
+
+ {` ${deltaPercent} % `}
+
+ {confidenceText && confidenceIcons[confidenceText]}
+ {confidenceText || '-'}
+
+ >
+ );
+ },
+};
diff --git a/src/components/App.tsx b/src/components/App.tsx
index e02ae29fc..4768399c2 100644
--- a/src/components/App.tsx
+++ b/src/components/App.tsx
@@ -1,8 +1,6 @@
import React, { useState, useMemo } from 'react';
-import Alert from '@mui/material/Alert';
import CssBaseline from '@mui/material/CssBaseline';
-import Link from '@mui/material/Link';
import { ThemeProvider } from '@mui/material/styles';
import { SnackbarProvider } from 'notistack';
import {
@@ -14,7 +12,6 @@ import { RouterProvider } from 'react-router/dom';
import { useAppSelector } from '../hooks/app';
import { Strings } from '../resources/Strings';
-import { Banner } from '../styles/Banner';
import getProtocolTheme from '../theme/protocolTheme';
import { loader as hashToCommitLoader } from './CompareResults/hashToCommitLoader';
import { loader as landoToCommitLoader } from './CompareResults/landoToCommitLoader';
@@ -33,18 +30,6 @@ import SnackbarCloseButton from './Shared/SnackbarCloseButton';
import { loader as authenticationLoader } from './TaskclusterAuth/loader';
import TaskclusterCallback from './TaskclusterAuth/TaskclusterCallback';
-const strings: InfoStrings = {
- text: Strings.components.topBanner.text,
- linkText: Strings.components.topBanner.linkText,
- href: Strings.components.topBanner.href,
-};
-
-const contact: InfoStrings = {
- text: Strings.components.contact.text,
- linkText: Strings.components.contact.linkText,
- href: Strings.components.contact.href,
-};
-
type DivProps = React.HTMLProps;
const AlertContainer = React.forwardRef(
@@ -167,20 +152,6 @@ function App() {
)}
>
-
-
- {strings.text}{' '}
-
- {strings.linkText}
-
- {'. '}
- {contact.text}{' '}
-
- {contact.linkText}
-
- .
-
-
) : null}
@@ -188,10 +159,4 @@ function App() {
);
}
-interface InfoStrings {
- text: string;
- linkText: string;
- href: string;
-}
-
export default App;
diff --git a/src/components/CompareResults/ResultsMain.tsx b/src/components/CompareResults/ResultsMain.tsx
index f230f5198..85fbfb933 100644
--- a/src/components/CompareResults/ResultsMain.tsx
+++ b/src/components/CompareResults/ResultsMain.tsx
@@ -10,6 +10,7 @@ import { style } from 'typestyle';
import type { LoaderReturnValue } from './loader';
import type { LoaderReturnValue as OverTimeLoaderReturnValue } from './overTimeLoader';
import ResultsTable from './ResultsTable';
+import { STUDENT_T, MANN_WHITNEY_U } from '../../common/constants';
import { useAppSelector } from '../../hooks/app';
import useRawSearchParams from '../../hooks/useRawSearchParams';
import { Strings } from '../../resources/Strings';
@@ -180,13 +181,15 @@ function ResultsMain() {
{subtitles[loaderData.view]}
-
-
-
+ {testVersion === STUDENT_T && (
+
+
+
+ )}
- {testWarnings[testVersion] ?? testWarnings['mann-whitney-u']}
+ {testWarnings[testVersion] ?? testWarnings[MANN_WHITNEY_U]}
diff --git a/src/components/CompareResults/RevisionRow.tsx b/src/components/CompareResults/RevisionRow.tsx
index e85098efd..e0650be6a 100644
--- a/src/components/CompareResults/RevisionRow.tsx
+++ b/src/components/CompareResults/RevisionRow.tsx
@@ -1,13 +1,8 @@
import { useId, useState, type ReactNode } from 'react';
import AppleIcon from '@mui/icons-material/Apple';
-import DragHandleIcon from '@mui/icons-material/DragHandle';
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
-import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
-import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp';
-import ThumbDownIcon from '@mui/icons-material/ThumbDown';
-import ThumbUpIcon from '@mui/icons-material/ThumbUp';
import TimelineIcon from '@mui/icons-material/Timeline';
import { IconButton, Box } from '@mui/material';
import Tooltip from '@mui/material/Tooltip';
@@ -15,23 +10,17 @@ import { style } from 'typestyle';
import { RetriggerButton } from './Retrigger/RetriggerButton';
import RevisionRowExpandable from './RevisionRowExpandable';
-import {
- compareView,
- compareOverTimeView,
- MANN_WHITNEY_U,
- STUDENT_T,
-} from '../../common/constants';
+import { compareView, compareOverTimeView } from '../../common/constants';
+import { getStrategy } from '../../common/testVersions';
import { Strings } from '../../resources/Strings';
import { FontSize, Spacing } from '../../styles';
import type {
CombinedResultsItemType,
CompareResultsItem,
- MannWhitneyResultsItem,
PlatformShortName,
} from '../../types/state';
import { TestVersion } from '../../types/types';
import { formatNumber } from '../../utils/format';
-import { capitalize } from '../../utils/helpers';
import {
getPlatformShortName,
getPlatformAndVersion,
@@ -131,18 +120,6 @@ const revisionRow = style({
},
});
-function determineStatus(improvement: boolean, regression: boolean) {
- if (improvement) return 'Improvement';
- if (regression) return 'Regression';
- return '-';
-}
-
-function determineStatusHintClass(improvement: boolean, regression: boolean) {
- if (improvement) return 'status-hint-improvement';
- if (regression) return 'status-hint-regression';
- return '';
-}
-
function determineSign(baseMedianValue: number, newMedianValue: number) {
if (baseMedianValue > newMedianValue) return '>';
if (baseMedianValue < newMedianValue) return '<';
@@ -158,12 +135,6 @@ const platformIcons: Record = {
Unspecified: '',
};
-const confidenceIcons = {
- Low: ,
- Medium: ,
- High: ,
-};
-
const getSubtestsCompareWithBaseLink = (
result: CombinedResultsItemType,
testVersion: TestVersion,
@@ -217,95 +188,6 @@ const getSubtestsCompareOverTimeLink = (
return `/subtests-compare-over-time-results?${params.toString()}`;
};
-export const renderDifferingTestVersionColumns = (
- testVersion: TestVersion,
- result: CombinedResultsItemType,
-) => {
- if (testVersion === MANN_WHITNEY_U) {
- const { cliffs_delta, direction_of_change, mann_whitney_test, cles } =
- result as MannWhitneyResultsItem;
- const clesValue = cles?.cles ? `${(cles?.cles * 100).toFixed(2)} %` : '-';
- return (
- <>
-
-
- {direction_of_change === 'improvement' ? (
-
- ) : null}
- {direction_of_change === 'regression' ? (
-
- ) : null}
- {capitalize(direction_of_change ?? '')}
-
-
-
- {' '}
- {cliffs_delta || '-'}
-
-
- {mann_whitney_test?.interpretation
- ? capitalize(mann_whitney_test?.interpretation)
- : '-'}
-
-
- {clesValue}
-
- >
- );
- } else {
- const {
- is_improvement: improvement,
- is_regression: regression,
- confidence_text: confidenceText,
- delta_percentage: deltaPercent,
- } = result as CompareResultsItem;
- return (
- <>
-
-
- {improvement ? : null}
- {regression ? : null}
- {determineStatus(!!improvement, !!regression)}
-
-
-
- {' '}
- {` ${deltaPercent} % `}
-
-
- {confidenceText && confidenceIcons[confidenceText]}
- {confidenceText || '-'}
-
- >
- );
- }
-};
-
function RevisionRow(props: RevisionRowProps) {
const id = useId();
@@ -330,14 +212,9 @@ function RevisionRow(props: RevisionRowProps) {
? baseRunsReplicates.length
: baseRuns.length;
const newRunsCount = replicates ? newRunsReplicates.length : newRuns.length;
- const baseAvgValue =
- testVersion === MANN_WHITNEY_U
- ? ((result as MannWhitneyResultsItem).base_standard_stats?.mean ?? null)
- : (result as CompareResultsItem).base_avg_value;
- const newAvgValue =
- testVersion === MANN_WHITNEY_U
- ? ((result as MannWhitneyResultsItem).new_standard_stats?.mean ?? null)
- : (result as CompareResultsItem).new_avg_value;
+ const strategy = getStrategy(testVersion);
+ const { baseAvg: baseAvgValue, newAvg: newAvgValue } =
+ strategy.getAvgValues(result);
const [expanded, setExpanded] = useState(false);
const toggleIsExpanded = () => {
@@ -395,7 +272,7 @@ function RevisionRow(props: RevisionRowProps) {
({newApp})
)}
- {renderDifferingTestVersionColumns(testVersion ?? STUDENT_T, result)}
+ {strategy.renderColumns(result)}
-
-
-
+ {testVersion === STUDENT_T && (
+
+
+
+ )}
{displayMannWhitneyUWarning && (
{Strings.components.mannWhitneyUWarning.text}{' '}
diff --git a/src/components/CompareResults/SubtestsResults/SubtestsRevisionHeader.tsx b/src/components/CompareResults/SubtestsResults/SubtestsRevisionHeader.tsx
index 1c84ecbbb..179aeef31 100644
--- a/src/components/CompareResults/SubtestsResults/SubtestsRevisionHeader.tsx
+++ b/src/components/CompareResults/SubtestsResults/SubtestsRevisionHeader.tsx
@@ -1,7 +1,7 @@
import { type ReactNode } from 'react';
import AppleIcon from '@mui/icons-material/Apple';
-import { Link } from '@mui/material';
+import { Box, Link } from '@mui/material';
import Tooltip from '@mui/material/Tooltip';
import { useLoaderData } from 'react-router';
import { style } from 'typestyle';
@@ -173,14 +173,34 @@ function SubtestsRevisionHeader(props: SubtestsRevisionHeaderProps) {
-
+
{header.option_name}
{extraOptions.map((option, index) => (
{option}
))}
-
+
);
}
diff --git a/src/components/CompareResults/TableHeader.tsx b/src/components/CompareResults/TableHeader.tsx
index 9d597b329..94ea349c9 100644
--- a/src/components/CompareResults/TableHeader.tsx
+++ b/src/components/CompareResults/TableHeader.tsx
@@ -76,7 +76,7 @@ type FilterableColumnHeaderProps = {
checkedValues?: Set