Commit 89d438d4 authored by Quang-Minh Nguyen's avatar Quang-Minh Nguyen

Address code review feedback

Issue https://gitlab.com/gitlab-org/gitlab/-/issues/324649
parent d38671b9
...@@ -2,11 +2,9 @@ ...@@ -2,11 +2,9 @@
import { GlButton, GlModal, GlModalDirective, GlSegmentedControl } from '@gitlab/ui'; import { GlButton, GlModal, GlModalDirective, GlSegmentedControl } from '@gitlab/ui';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import { sortOrders, sortOrderOptions } from '../constants';
import RequestWarning from './request_warning.vue'; import RequestWarning from './request_warning.vue';
export const SortOrderDuration = 'SortOrderDuration';
export const SortOrderChronological = 'SortOrderChronological';
export default { export default {
components: { components: {
RequestWarning, RequestWarning,
...@@ -45,7 +43,7 @@ export default { ...@@ -45,7 +43,7 @@ export default {
data() { data() {
return { return {
openedBacktraces: [], openedBacktraces: [],
sortOrder: SortOrderDuration, sortOrder: sortOrders.DURATION,
}; };
}, },
computed: { computed: {
...@@ -56,15 +54,11 @@ export default { ...@@ -56,15 +54,11 @@ export default {
return this.currentRequest.details[this.metric]; return this.currentRequest.details[this.metric];
}, },
metricDetailsSummary() { metricDetailsSummary() {
let summary = { return {
[s__('PerformanceBar|Total')]: this.metricDetails.calls, [s__('Total')]: this.metricDetails.calls,
[s__('PerformanceBar|Total duration')]: this.metricDetails.duration, [s__('PerformanceBar|Total duration')]: this.metricDetails.duration,
...(this.metricDetails.summary || {}),
}; };
if (this.metricDetails.summary) {
summary = { ...summary, ...this.metricDetails.summary };
}
return summary;
}, },
metricDetailsLabel() { metricDetailsLabel() {
if (this.metricDetails.duration && this.metricDetails.calls) { if (this.metricDetails.duration && this.metricDetails.calls) {
...@@ -82,17 +76,14 @@ export default { ...@@ -82,17 +76,14 @@ export default {
); );
}, },
detailsList() { detailsList() {
const list = this.metricDetails.details return this.metricDetails.details.map((item, index) => ({ ...item, id: index }));
.slice() },
.map((item, index) => ({ ...item, id: index })); sortedList() {
if (this.sortOrder === sortOrders.CHRONOLOGICAL) {
if (this.sortOrder === SortOrderDuration) { return this.detailsList.slice().sort(this.sortDetailChronologically);
return list.sort((a, b) => (a.duration < b.duration ? 1 : -1));
} else if (this.sortOrder === SortOrderChronological) {
return list.sort((a, b) => (a.start < b.start ? -1 : 1));
} }
return list; return this.detailsList.slice().sort(this.sortDetailByDuration);
}, },
warnings() { warnings() {
return this.metricDetails.warnings || []; return this.metricDetails.warnings || [];
...@@ -123,11 +114,14 @@ export default { ...@@ -123,11 +114,14 @@ export default {
changeSortOrder(order) { changeSortOrder(order) {
this.sortOrder = order; this.sortOrder = order;
}, },
sortDetailByDuration(a, b) {
return a.duration < b.duration ? 1 : -1;
},
sortDetailChronologically(a, b) {
return a.start < b.start ? -1 : 1;
},
}, },
sortOrders: [ sortOrderOptions,
{ value: SortOrderDuration, text: s__('PerformanceBar|Sort by duration') },
{ value: SortOrderChronological, text: s__('PerformanceBar|Sort chronologically') },
],
}; };
</script> </script>
<template> <template>
...@@ -148,29 +142,25 @@ export default { ...@@ -148,29 +142,25 @@ export default {
<gl-modal :modal-id="modalId" :title="header" size="lg" footer-class="d-none" scrollable> <gl-modal :modal-id="modalId" :title="header" size="lg" footer-class="d-none" scrollable>
<div class="gl-display-flex gl-align-items-center gl-justify-content-space-between"> <div class="gl-display-flex gl-align-items-center gl-justify-content-space-between">
<div class="gl-display-flex gl-align-items-center" data-testid="performance-bar-summary"> <div class="gl-display-flex gl-align-items-center" data-testid="performance-bar-summary">
<div <div v-for="(value, name) in metricDetailsSummary" :key="name" class="gl-pr-8">
v-for="(value, name) in metricDetailsSummary" <div v-if="value" data-testid="performance-bar-summary-item">
v-if="value" <div>{{ name }}</div>
:key="name" <div class="gl-font-size-h1 gl-font-weight-bold">{{ value }}</div>
class="gl-pr-8" </div>
data-testid="performance-bar-summary-item"
>
<div>{{ name }}</div>
<div class="gl-font-size-h1 gl-font-weight-bold">{{ value }}</div>
</div> </div>
</div> </div>
<gl-segmented-control <gl-segmented-control
v-if="displaySortOrder" v-if="displaySortOrder"
data-testid="performance-bar-sort-order" data-testid="performance-bar-sort-order"
:options="$options.sortOrders" :options="$options.sortOrderOptions"
:checked="sortOrder" :checked="sortOrder"
@input="changeSortOrder" @input="changeSortOrder"
/> />
</div> </div>
<hr /> <hr />
<table class="table gl-table"> <table class="table gl-table">
<template v-if="detailsList.length"> <template v-if="sortedList.length">
<tr v-for="item in detailsList" :key="item.id"> <tr v-for="item in sortedList" :key="item.id">
<td data-testid="performance-item-duration"> <td data-testid="performance-item-duration">
<span v-if="item.duration">{{ <span v-if="item.duration">{{
sprintf(__('%{duration}ms'), { duration: item.duration }) sprintf(__('%{duration}ms'), { duration: item.duration })
...@@ -198,7 +188,7 @@ export default { ...@@ -198,7 +188,7 @@ export default {
@click="toggleBacktrace(item.id)" @click="toggleBacktrace(item.id)"
/> />
</div> </div>
<pre v-if="itemHasOpenedBacktrace(item.id)" class="backtrace-row mt-2">{{ <pre v-if="itemHasOpenedBacktrace(item.id)" class="backtrace-row gl-mt-3">{{
item.backtrace item.backtrace
}}</pre> }}</pre>
</div> </div>
...@@ -207,7 +197,7 @@ export default { ...@@ -207,7 +197,7 @@ export default {
</template> </template>
<template v-else> <template v-else>
<tr> <tr>
<td> <td data-testid="performance-bar-empty-detail-notice">
{{ sprintf(__('No %{header} for this request.'), { header: header.toLowerCase() }) }} {{ sprintf(__('No %{header} for this request.'), { header: header.toLowerCase() }) }}
</td> </td>
</tr> </tr>
......
...@@ -166,9 +166,9 @@ export default { ...@@ -166,9 +166,9 @@ export default {
s__('PerformanceBar|Download') s__('PerformanceBar|Download')
}}</a> }}</a>
</div> </div>
<div v-if="statsUrl" id="peek-stats" class="view"> <a v-if="statsUrl" class="gl-text-blue-300 view" :href="statsUrl">{{
<a class="gl-text-blue-300" :href="statsUrl">{{ s__('PerformanceBar|Stats') }}</a> s__('PerformanceBar|Stats')
</div> }}</a>
<request-selector <request-selector
v-if="currentRequest" v-if="currentRequest"
:current-request="currentRequest" :current-request="currentRequest"
......
import { s__ } from '~/locale';
export const sortOrders = {
DURATION: 'duration',
CHRONOLOGICAL: 'chronological',
};
export const sortOrderOptions = [
{
value: sortOrders.DURATION,
text: s__('PerformanceBar|Sort by duration'),
},
{
value: sortOrders.CHRONOLOGICAL,
text: s__('PerformanceBar|Sort chronologically'),
},
];
--- ---
title: Improve the performance bar title: Allow details to be sorted chronologically in the performance bar
merge_request: 56830 merge_request: 56830
author: author:
type: changed type: changed
...@@ -22213,9 +22213,6 @@ msgstr "" ...@@ -22213,9 +22213,6 @@ msgstr ""
msgid "PerformanceBar|Stats" msgid "PerformanceBar|Stats"
msgstr "" msgstr ""
msgid "PerformanceBar|Total"
msgstr ""
msgid "PerformanceBar|Total duration" msgid "PerformanceBar|Total duration"
msgstr "" msgstr ""
......
...@@ -2,35 +2,39 @@ import { shallowMount } from '@vue/test-utils'; ...@@ -2,35 +2,39 @@ import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue'; import { nextTick } from 'vue';
import { trimText } from 'helpers/text_helper'; import { trimText } from 'helpers/text_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import DetailedMetric, { import DetailedMetric from '~/performance_bar/components/detailed_metric.vue';
SortOrderDuration,
SortOrderChronological,
} from '~/performance_bar/components/detailed_metric.vue';
import RequestWarning from '~/performance_bar/components/request_warning.vue'; import RequestWarning from '~/performance_bar/components/request_warning.vue';
import { sortOrders } from '~/performance_bar/constants';
describe('detailedMetric', () => { describe('detailedMetric', () => {
let wrapper; let wrapper;
const createComponent = (props) => { const defaultProps = {
currentRequest: {},
metric: 'gitaly',
header: 'Gitaly calls',
keys: ['feature', 'request'],
};
const createComponent = (props = {}) => {
wrapper = extendedWrapper( wrapper = extendedWrapper(
shallowMount(DetailedMetric, { shallowMount(DetailedMetric, {
propsData: { propsData: { ...defaultProps, ...props },
...props,
},
}), }),
); );
}; };
const findAllTraceBlocks = () => wrapper.findAll('pre'); const findAllTraceBlocks = () => wrapper.findAll('pre');
const findTraceBlockAtIndex = (index) => findAllTraceBlocks().at(index); const findTraceBlockAtIndex = (index) => findAllTraceBlocks().at(index);
const findExpandBacktraceBtns = () => wrapper.findAll('[data-testid="backtrace-expand-btn"]'); const findExpandBacktraceBtns = () => wrapper.findAllByTestId('backtrace-expand-btn');
const findExpandedBacktraceBtnAtIndex = (index) => findExpandBacktraceBtns().at(index); const findExpandedBacktraceBtnAtIndex = (index) => findExpandBacktraceBtns().at(index);
const findDetailsLabel = () => wrapper.findByTestId('performance-bar-details-label'); const findDetailsLabel = () => wrapper.findByTestId('performance-bar-details-label');
const findSortOrderSwitcher = () => wrapper.findByTestId('performance-bar-sort-order'); const findSortOrderSwitcher = () => wrapper.findByTestId('performance-bar-sort-order');
const findEmptyDetailNotice = () => wrapper.findByTestId('performance-bar-empty-detail-notice');
const findAllDetailDurations = () => const findAllDetailDurations = () =>
wrapper.findAll('[data-testid="performance-item-duration"]').wrappers.map((w) => w.text()); wrapper.findAllByTestId('performance-item-duration').wrappers.map((w) => w.text());
const findAllSummaryItems = () => const findAllSummaryItems = () =>
wrapper.findAll('[data-testid="performance-bar-summary-item"]').wrappers.map((w) => w.text()); wrapper.findAllByTestId('performance-bar-summary-item').wrappers.map((w) => w.text());
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
...@@ -38,13 +42,7 @@ describe('detailedMetric', () => { ...@@ -38,13 +42,7 @@ describe('detailedMetric', () => {
describe('when the current request has no details', () => { describe('when the current request has no details', () => {
beforeEach(() => { beforeEach(() => {
createComponent({ createComponent();
currentRequest: {},
metric: 'gitaly',
header: 'Gitaly calls',
details: 'details',
keys: ['feature', 'request'],
});
}); });
it('does not render the element', () => { it('does not render the element', () => {
...@@ -76,18 +74,15 @@ describe('detailedMetric', () => { ...@@ -76,18 +74,15 @@ describe('detailedMetric', () => {
}, },
}, },
}, },
metric: 'gitaly',
header: 'Gitaly calls',
keys: ['feature', 'request'],
}); });
}); });
it('displays an empty title', () => { it('displays an empty title', () => {
expect(findDetailsLabel().text()).toContain('0'); expect(findDetailsLabel().text()).toBe('0');
}); });
it('displays an empty modal', () => { it('displays an empty modal', () => {
expect(wrapper.text().replace(/\s+/g, ' ')).toContain('No gitaly calls for this request'); expect(findEmptyDetailNotice().text()).toContain('No gitaly calls for this request');
}); });
it('does not display sort by switcher', () => { it('does not display sort by switcher', () => {
...@@ -112,9 +107,6 @@ describe('detailedMetric', () => { ...@@ -112,9 +107,6 @@ describe('detailedMetric', () => {
}, },
}, },
}, },
metric: 'gitaly',
header: 'Gitaly calls',
keys: ['feature', 'request'],
}); });
}); });
...@@ -141,14 +133,11 @@ describe('detailedMetric', () => { ...@@ -141,14 +133,11 @@ describe('detailedMetric', () => {
}, },
}, },
}, },
metric: 'gitaly',
header: 'Gitaly calls',
keys: ['feature', 'request'],
}); });
}); });
it('displays details header', () => { it('displays details header', () => {
expect(findDetailsLabel().text()).toContain('123ms / 456'); expect(findDetailsLabel().text()).toBe('123ms / 456');
}); });
it('displays a basic summary section', () => { it('displays a basic summary section', () => {
...@@ -156,11 +145,7 @@ describe('detailedMetric', () => { ...@@ -156,11 +145,7 @@ describe('detailedMetric', () => {
}); });
it('sorts the details by descending duration order', () => { it('sorts the details by descending duration order', () => {
expect( expect(findAllDetailDurations()).toEqual(['100ms', '23ms']);
wrapper
.findAll('[data-testid="performance-item-duration"]')
.wrappers.map((w) => w.text()),
).toEqual(['100ms', '23ms']);
}); });
it('does not display sort by switcher', () => { it('does not display sort by switcher', () => {
...@@ -275,10 +260,10 @@ describe('detailedMetric', () => { ...@@ -275,10 +260,10 @@ describe('detailedMetric', () => {
}); });
it('allows switch sorting orders', async () => { it('allows switch sorting orders', async () => {
findSortOrderSwitcher().vm.$emit('input', SortOrderChronological); findSortOrderSwitcher().vm.$emit('input', sortOrders.CHRONOLOGICAL);
await nextTick(); await nextTick();
expect(findAllDetailDurations()).toEqual(['23ms', '100ms', '75ms']); expect(findAllDetailDurations()).toEqual(['23ms', '100ms', '75ms']);
findSortOrderSwitcher().vm.$emit('input', SortOrderDuration); findSortOrderSwitcher().vm.$emit('input', sortOrders.DURATION);
await nextTick(); await nextTick();
expect(findAllDetailDurations()).toEqual(['100ms', '75ms', '23ms']); expect(findAllDetailDurations()).toEqual(['100ms', '75ms', '23ms']);
}); });
...@@ -296,10 +281,7 @@ describe('detailedMetric', () => { ...@@ -296,10 +281,7 @@ describe('detailedMetric', () => {
}, },
}, },
}, },
metric: 'gitaly',
title: 'custom', title: 'custom',
header: 'Gitaly calls',
keys: ['feature', 'request'],
}); });
}); });
...@@ -326,7 +308,7 @@ describe('detailedMetric', () => { ...@@ -326,7 +308,7 @@ describe('detailedMetric', () => {
}); });
it('displays calls in the label', () => { it('displays calls in the label', () => {
expect(findDetailsLabel().text()).toContain('456'); expect(findDetailsLabel().text()).toBe('456');
}); });
it('displays a basic summary section', () => { it('displays a basic summary section', () => {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment