зеркало из https://github.com/mozilla/treeherder.git
Bug 1831945 - Add a toggle for replicates to the CompareView. (#7703)
This commit is contained in:
Родитель
c78cd4e78d
Коммит
4d7f863362
|
@ -162,6 +162,8 @@ const compareTableControlsNode = (
|
||||||
showOnlyComparable: '0',
|
showOnlyComparable: '0',
|
||||||
showOnlyConfident: '0',
|
showOnlyConfident: '0',
|
||||||
showOnlyNoise: '0',
|
showOnlyNoise: '0',
|
||||||
|
originalProject: 'try',
|
||||||
|
newProject: 'mozilla-central',
|
||||||
filter: null,
|
filter: null,
|
||||||
}}
|
}}
|
||||||
location={{
|
location={{
|
||||||
|
@ -246,7 +248,13 @@ test('toggle all buttons should update the URL params', async () => {
|
||||||
fireEvent.click(showImportant);
|
fireEvent.click(showImportant);
|
||||||
expect(mockUpdateParams).toHaveBeenLastCalledWith(
|
expect(mockUpdateParams).toHaveBeenLastCalledWith(
|
||||||
{ page: 1, showOnlyImportant: 1 },
|
{ page: 1, showOnlyImportant: 1 },
|
||||||
['filter', 'showOnlyComparable', 'showOnlyConfident', 'showOnlyNoise'],
|
[
|
||||||
|
'filter',
|
||||||
|
'showOnlyComparable',
|
||||||
|
'showOnlyConfident',
|
||||||
|
'showOnlyNoise',
|
||||||
|
'replicates',
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
const hideUncertain = await waitFor(() =>
|
const hideUncertain = await waitFor(() =>
|
||||||
|
@ -259,7 +267,7 @@ test('toggle all buttons should update the URL params', async () => {
|
||||||
showOnlyImportant: 1,
|
showOnlyImportant: 1,
|
||||||
showOnlyConfident: 1,
|
showOnlyConfident: 1,
|
||||||
},
|
},
|
||||||
['filter', 'showOnlyComparable', 'showOnlyNoise'],
|
['filter', 'showOnlyComparable', 'showOnlyNoise', 'replicates'],
|
||||||
);
|
);
|
||||||
|
|
||||||
const showNoise = await waitFor(() => getByText(filterText.showNoise));
|
const showNoise = await waitFor(() => getByText(filterText.showNoise));
|
||||||
|
@ -271,7 +279,7 @@ test('toggle all buttons should update the URL params', async () => {
|
||||||
showOnlyConfident: 1,
|
showOnlyConfident: 1,
|
||||||
showOnlyNoise: 1,
|
showOnlyNoise: 1,
|
||||||
},
|
},
|
||||||
['filter', 'showOnlyComparable'],
|
['filter', 'showOnlyComparable', 'replicates'],
|
||||||
);
|
);
|
||||||
|
|
||||||
const hideUncomparable = await waitFor(() =>
|
const hideUncomparable = await waitFor(() =>
|
||||||
|
@ -286,6 +294,22 @@ test('toggle all buttons should update the URL params', async () => {
|
||||||
showOnlyNoise: 1,
|
showOnlyNoise: 1,
|
||||||
showOnlyComparable: 1,
|
showOnlyComparable: 1,
|
||||||
},
|
},
|
||||||
|
['filter', 'replicates'],
|
||||||
|
);
|
||||||
|
|
||||||
|
const useReplicates = await waitFor(() =>
|
||||||
|
getByText('Use replicates (try-only)'),
|
||||||
|
);
|
||||||
|
fireEvent.click(useReplicates);
|
||||||
|
expect(mockUpdateParams).toHaveBeenLastCalledWith(
|
||||||
|
{
|
||||||
|
page: 1,
|
||||||
|
showOnlyImportant: 1,
|
||||||
|
showOnlyConfident: 1,
|
||||||
|
showOnlyNoise: 1,
|
||||||
|
showOnlyComparable: 1,
|
||||||
|
replicates: 1,
|
||||||
|
},
|
||||||
['filter'],
|
['filter'],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -299,7 +323,13 @@ test('filters that are not enabled are removed from URL params', async () => {
|
||||||
fireEvent.click(showImportant);
|
fireEvent.click(showImportant);
|
||||||
expect(mockUpdateParams).toHaveBeenLastCalledWith(
|
expect(mockUpdateParams).toHaveBeenLastCalledWith(
|
||||||
{ page: 1, showOnlyImportant: 1 },
|
{ page: 1, showOnlyImportant: 1 },
|
||||||
['filter', 'showOnlyComparable', 'showOnlyConfident', 'showOnlyNoise'],
|
[
|
||||||
|
'filter',
|
||||||
|
'showOnlyComparable',
|
||||||
|
'showOnlyConfident',
|
||||||
|
'showOnlyNoise',
|
||||||
|
'replicates',
|
||||||
|
],
|
||||||
);
|
);
|
||||||
fireEvent.click(showImportant);
|
fireEvent.click(showImportant);
|
||||||
expect(mockUpdateParams).toHaveBeenLastCalledWith({ page: 1 }, [
|
expect(mockUpdateParams).toHaveBeenLastCalledWith({ page: 1 }, [
|
||||||
|
@ -308,6 +338,7 @@ test('filters that are not enabled are removed from URL params', async () => {
|
||||||
'showOnlyImportant',
|
'showOnlyImportant',
|
||||||
'showOnlyConfident',
|
'showOnlyConfident',
|
||||||
'showOnlyNoise',
|
'showOnlyNoise',
|
||||||
|
'replicates',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -624,6 +624,7 @@ class PerformanceSummary(generics.ListAPIView):
|
||||||
no_subtests = query_params.validated_data['no_subtests']
|
no_subtests = query_params.validated_data['no_subtests']
|
||||||
all_data = query_params.validated_data['all_data']
|
all_data = query_params.validated_data['all_data']
|
||||||
no_retriggers = query_params.validated_data['no_retriggers']
|
no_retriggers = query_params.validated_data['no_retriggers']
|
||||||
|
replicates = query_params.validated_data['replicates']
|
||||||
|
|
||||||
signature_data = PerformanceSignature.objects.select_related(
|
signature_data = PerformanceSignature.objects.select_related(
|
||||||
'framework', 'repository', 'platform', 'push', 'job'
|
'framework', 'repository', 'platform', 'push', 'job'
|
||||||
|
@ -707,10 +708,23 @@ class PerformanceSummary(generics.ListAPIView):
|
||||||
else:
|
else:
|
||||||
grouped_values = defaultdict(list)
|
grouped_values = defaultdict(list)
|
||||||
grouped_job_ids = defaultdict(list)
|
grouped_job_ids = defaultdict(list)
|
||||||
for signature_id, value, job_id in data.values_list('signature_id', 'value', 'job_id'):
|
if replicates:
|
||||||
if value is not None:
|
for signature_id, value, job_id, replicate_value in data.values_list(
|
||||||
grouped_values[signature_id].append(value)
|
'signature_id', 'value', 'job_id', 'performancedatumreplicate__value'
|
||||||
grouped_job_ids[signature_id].append(job_id)
|
):
|
||||||
|
if replicate_value is not None:
|
||||||
|
grouped_values[signature_id].append(replicate_value)
|
||||||
|
grouped_job_ids[signature_id].append(job_id)
|
||||||
|
elif value is not None:
|
||||||
|
grouped_values[signature_id].append(value)
|
||||||
|
grouped_job_ids[signature_id].append(job_id)
|
||||||
|
else:
|
||||||
|
for signature_id, value, job_id in data.values_list(
|
||||||
|
'signature_id', 'value', 'job_id'
|
||||||
|
):
|
||||||
|
if value is not None:
|
||||||
|
grouped_values[signature_id].append(value)
|
||||||
|
grouped_job_ids[signature_id].append(job_id)
|
||||||
|
|
||||||
# name field is created in the serializer
|
# name field is created in the serializer
|
||||||
for item in self.queryset:
|
for item in self.queryset:
|
||||||
|
|
|
@ -316,6 +316,7 @@ class PerformanceQueryParamsSerializer(serializers.Serializer):
|
||||||
signature = serializers.CharField(required=False, allow_null=True, default=None)
|
signature = serializers.CharField(required=False, allow_null=True, default=None)
|
||||||
no_subtests = serializers.BooleanField(required=False)
|
no_subtests = serializers.BooleanField(required=False)
|
||||||
all_data = OptionalBooleanField()
|
all_data = OptionalBooleanField()
|
||||||
|
replicates = OptionalBooleanField()
|
||||||
no_retriggers = OptionalBooleanField()
|
no_retriggers = OptionalBooleanField()
|
||||||
|
|
||||||
def validate(self, data):
|
def validate(self, data):
|
||||||
|
|
|
@ -603,6 +603,10 @@ li.pagination-active.active > button {
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.download-json-container .btn {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.download-json-container .download-button {
|
.download-json-container .download-button {
|
||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
color: #1f7d8e !important;
|
color: #1f7d8e !important;
|
||||||
|
|
|
@ -29,6 +29,7 @@ export default class CompareTableControls extends React.Component {
|
||||||
showImportant: convertParams(this.validated, 'showOnlyImportant'),
|
showImportant: convertParams(this.validated, 'showOnlyImportant'),
|
||||||
hideUncertain: convertParams(this.validated, 'showOnlyConfident'),
|
hideUncertain: convertParams(this.validated, 'showOnlyConfident'),
|
||||||
showNoise: convertParams(this.validated, 'showOnlyNoise'),
|
showNoise: convertParams(this.validated, 'showOnlyNoise'),
|
||||||
|
useReplicates: convertParams(this.validated, 'replicates'),
|
||||||
results: new Map(),
|
results: new Map(),
|
||||||
filteredText: this.getDefaultFilterText(this.validated),
|
filteredText: this.getDefaultFilterText(this.validated),
|
||||||
showRetriggerModal: false,
|
showRetriggerModal: false,
|
||||||
|
@ -49,6 +50,9 @@ export default class CompareTableControls extends React.Component {
|
||||||
const params = parseQueryParams(location.search);
|
const params = parseQueryParams(location.search);
|
||||||
const prevParams = parseQueryParams(prevProps.location.search);
|
const prevParams = parseQueryParams(prevProps.location.search);
|
||||||
|
|
||||||
|
if (params.replicates !== prevParams.replicates) {
|
||||||
|
window.location.reload(false);
|
||||||
|
}
|
||||||
if (prevState.countPages !== countPages) {
|
if (prevState.countPages !== countPages) {
|
||||||
this.setState({ totalPagesList: this.generatePages(countPages) });
|
this.setState({ totalPagesList: this.generatePages(countPages) });
|
||||||
}
|
}
|
||||||
|
@ -80,6 +84,13 @@ export default class CompareTableControls extends React.Component {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
updateReplicates = () => {
|
||||||
|
this.setState(
|
||||||
|
(prevState) => ({ useReplicates: !prevState.useReplicates }),
|
||||||
|
() => this.updateUrlParams(),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
filterResult = (testName, result) => {
|
filterResult = (testName, result) => {
|
||||||
const {
|
const {
|
||||||
filteredText,
|
filteredText,
|
||||||
|
@ -183,6 +194,7 @@ export default class CompareTableControls extends React.Component {
|
||||||
showImportant,
|
showImportant,
|
||||||
hideUncertain,
|
hideUncertain,
|
||||||
showNoise,
|
showNoise,
|
||||||
|
useReplicates,
|
||||||
page,
|
page,
|
||||||
} = this.state;
|
} = this.state;
|
||||||
const compareURLParams = {};
|
const compareURLParams = {};
|
||||||
|
@ -203,6 +215,9 @@ export default class CompareTableControls extends React.Component {
|
||||||
if (showNoise) compareURLParams.showOnlyNoise = 1;
|
if (showNoise) compareURLParams.showOnlyNoise = 1;
|
||||||
else paramsToRemove.push('showOnlyNoise');
|
else paramsToRemove.push('showOnlyNoise');
|
||||||
|
|
||||||
|
if (useReplicates) compareURLParams.replicates = 1;
|
||||||
|
else paramsToRemove.push('replicates');
|
||||||
|
|
||||||
compareURLParams.page = page;
|
compareURLParams.page = page;
|
||||||
updateParams(compareURLParams, paramsToRemove);
|
updateParams(compareURLParams, paramsToRemove);
|
||||||
};
|
};
|
||||||
|
@ -265,6 +280,7 @@ export default class CompareTableControls extends React.Component {
|
||||||
hideUncertain,
|
hideUncertain,
|
||||||
showImportant,
|
showImportant,
|
||||||
showNoise,
|
showNoise,
|
||||||
|
useReplicates,
|
||||||
results,
|
results,
|
||||||
showRetriggerModal,
|
showRetriggerModal,
|
||||||
currentRetriggerRow,
|
currentRetriggerRow,
|
||||||
|
@ -304,6 +320,8 @@ export default class CompareTableControls extends React.Component {
|
||||||
|
|
||||||
const viewablePagesList = this.getCurrentPages();
|
const viewablePagesList = this.getCurrentPages();
|
||||||
const hasMorePages = () => viewablePagesList.length > 0 && countPages !== 1;
|
const hasMorePages = () => viewablePagesList.length > 0 && countPages !== 1;
|
||||||
|
const hasTryProject = () =>
|
||||||
|
validated.newProject === 'try' || validated.originalProject === 'try';
|
||||||
|
|
||||||
const formattedJSONData = this.formatDownloadData(compareResults);
|
const formattedJSONData = this.formatDownloadData(compareResults);
|
||||||
|
|
||||||
|
@ -337,8 +355,19 @@ export default class CompareTableControls extends React.Component {
|
||||||
</Row>
|
</Row>
|
||||||
)
|
)
|
||||||
: null}
|
: null}
|
||||||
|
|
||||||
<div className="download-json-container">
|
<div className="download-json-container">
|
||||||
|
{hasTryProject() && (
|
||||||
|
<Button
|
||||||
|
color="darker-info"
|
||||||
|
outline
|
||||||
|
className="btn"
|
||||||
|
type="button"
|
||||||
|
onClick={this.updateReplicates}
|
||||||
|
active={useReplicates}
|
||||||
|
>
|
||||||
|
Use replicates (try-only)
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
{formattedJSONData.length > 0 && (
|
{formattedJSONData.length > 0 && (
|
||||||
<Button
|
<Button
|
||||||
className="btn download-button"
|
className="btn download-button"
|
||||||
|
|
|
@ -27,6 +27,7 @@ class CompareView extends React.PureComponent {
|
||||||
framework,
|
framework,
|
||||||
interval,
|
interval,
|
||||||
no_subtests: true,
|
no_subtests: true,
|
||||||
|
replicates: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
getQueryParams = (timeRange, framework) => {
|
getQueryParams = (timeRange, framework) => {
|
||||||
|
@ -37,6 +38,7 @@ class CompareView extends React.PureComponent {
|
||||||
newRevision,
|
newRevision,
|
||||||
newResultSet,
|
newResultSet,
|
||||||
originalResultSet,
|
originalResultSet,
|
||||||
|
replicates,
|
||||||
} = this.props.validated;
|
} = this.props.validated;
|
||||||
|
|
||||||
let originalParams;
|
let originalParams;
|
||||||
|
@ -71,6 +73,12 @@ class CompareView extends React.PureComponent {
|
||||||
|
|
||||||
const newParams = this.queryParams(newProject, interval, framework.id);
|
const newParams = this.queryParams(newProject, interval, framework.id);
|
||||||
newParams.revision = newRevision;
|
newParams.revision = newRevision;
|
||||||
|
|
||||||
|
if (replicates) {
|
||||||
|
originalParams.replicates = true;
|
||||||
|
newParams.replicates = true;
|
||||||
|
}
|
||||||
|
|
||||||
return [originalParams, newParams];
|
return [originalParams, newParams];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче