Commit cfd2734c authored by Tim Zallmann's avatar Tim Zallmann

Merge branch 'wc-perf-bar-download' into 'master'

Add 'Download' button to Performance Bar

Closes #28222

See merge request gitlab-org/gitlab!20205
parents d54b3423 ee612212
...@@ -80,6 +80,15 @@ export default { ...@@ -80,6 +80,15 @@ export default {
} }
return ''; return '';
}, },
downloadPath() {
const data = JSON.stringify(this.requests);
const blob = new Blob([data], { type: 'text/plain' });
return window.URL.createObjectURL(blob);
},
downloadName() {
const fileName = this.requests[0].truncatedUrl;
return `${fileName}_perf_bar_${Date.now()}.json`;
},
}, },
mounted() { mounted() {
this.currentRequest = this.requestId; this.currentRequest = this.requestId;
...@@ -121,6 +130,9 @@ export default { ...@@ -121,6 +130,9 @@ export default {
<a :href="currentRequest.details.tracing.tracing_url">{{ s__('PerformanceBar|trace') }}</a> <a :href="currentRequest.details.tracing.tracing_url">{{ s__('PerformanceBar|trace') }}</a>
</div> </div>
<add-request v-on="$listeners" /> <add-request v-on="$listeners" />
<div v-if="currentRequest.details" id="peek-download" class="view">
<a :download="downloadName" :href="downloadPath">{{ s__('PerformanceBar|Download') }}</a>
</div>
<request-selector <request-selector
v-if="currentRequest" v-if="currentRequest"
:current-request="currentRequest" :current-request="currentRequest"
......
...@@ -40,16 +40,6 @@ export default { ...@@ -40,16 +40,6 @@ export default {
}, },
}, },
methods: { methods: {
truncatedUrl(requestUrl) {
const components = requestUrl.replace(/\/$/, '').split('/');
let truncated = components[components.length - 1];
if (truncated.match(/^\d+$/)) {
truncated = `${components[components.length - 2]}/${truncated}`;
}
return truncated;
},
glEmojiTag, glEmojiTag,
}, },
}; };
...@@ -63,7 +53,7 @@ export default { ...@@ -63,7 +53,7 @@ export default {
:value="request.id" :value="request.id"
class="qa-performance-bar-request" class="qa-performance-bar-request"
> >
{{ truncatedUrl(request.url) }} {{ request.truncatedUrl }}
<span v-if="request.hasWarnings">(!)</span> <span v-if="request.hasWarnings">(!)</span>
</option> </option>
</select> </select>
......
...@@ -5,9 +5,12 @@ export default class PerformanceBarStore { ...@@ -5,9 +5,12 @@ export default class PerformanceBarStore {
addRequest(requestId, requestUrl) { addRequest(requestId, requestUrl) {
if (!this.findRequest(requestId)) { if (!this.findRequest(requestId)) {
const shortUrl = PerformanceBarStore.truncateUrl(requestUrl);
this.requests.push({ this.requests.push({
id: requestId, id: requestId,
url: requestUrl, url: requestUrl,
truncatedUrl: shortUrl,
details: {}, details: {},
hasWarnings: false, hasWarnings: false,
}); });
...@@ -36,4 +39,20 @@ export default class PerformanceBarStore { ...@@ -36,4 +39,20 @@ export default class PerformanceBarStore {
canTrackRequest(requestUrl) { canTrackRequest(requestUrl) {
return this.requests.filter(request => request.url === requestUrl).length < 2; return this.requests.filter(request => request.url === requestUrl).length < 2;
} }
static truncateUrl(requestUrl) {
const [rootAndQuery] = requestUrl.split('#');
const [root, query] = rootAndQuery.split('?');
const components = root.replace(/\/$/, '').split('/');
let truncated = components[components.length - 1];
if (truncated.match(/^\d+$/)) {
truncated = `${components[components.length - 2]}/${truncated}`;
}
if (query) {
truncated += `?${query}`;
}
return truncated;
}
} }
---
title: Add 'download' button to Performance Bar
merge_request: 20205
author: Will Chandler
type: changed
...@@ -19,6 +19,7 @@ It allows you to see (from left to right): ...@@ -19,6 +19,7 @@ It allows you to see (from left to right):
- a link to add a request's details to the performance bar; the request can be - a link to add a request's details to the performance bar; the request can be
added by its full URL (authenticated as the current user), or by the value of added by its full URL (authenticated as the current user), or by the value of
its `X-Request-Id` header its `X-Request-Id` header
- a link to download the raw JSON used to generate the Performance Bar reports
On the far right is a request selector that allows you to view the same metrics On the far right is a request selector that allows you to view the same metrics
(excluding the page timing and line profiler) for any requests made while the (excluding the page timing and line profiler) for any requests made while the
......
...@@ -12224,6 +12224,9 @@ msgstr "" ...@@ -12224,6 +12224,9 @@ msgstr ""
msgid "Performance optimization" msgid "Performance optimization"
msgstr "" msgstr ""
msgid "PerformanceBar|Download"
msgstr ""
msgid "PerformanceBar|Gitaly calls" msgid "PerformanceBar|Gitaly calls"
msgstr "" msgstr ""
......
...@@ -4,23 +4,9 @@ import { shallowMount } from '@vue/test-utils'; ...@@ -4,23 +4,9 @@ import { shallowMount } from '@vue/test-utils';
describe('request selector', () => { describe('request selector', () => {
const requests = [ const requests = [
{ {
id: '123', id: 'warningReq',
url: 'https://gitlab.com/',
hasWarnings: false,
},
{
id: '456',
url: 'https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/1',
hasWarnings: false,
},
{
id: '789',
url: 'https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/1.json?serializer=widget',
hasWarnings: false,
},
{
id: 'abc',
url: 'https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/1/discussions.json', url: 'https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/1/discussions.json',
truncatedUrl: 'discussions.json',
hasWarnings: true, hasWarnings: true,
}, },
]; ];
...@@ -28,35 +14,16 @@ describe('request selector', () => { ...@@ -28,35 +14,16 @@ describe('request selector', () => {
const wrapper = shallowMount(RequestSelector, { const wrapper = shallowMount(RequestSelector, {
propsData: { propsData: {
requests, requests,
currentRequest: requests[1], currentRequest: requests[0],
}, },
}); });
function optionText(requestId) {
return wrapper
.find(`[value='${requestId}']`)
.text()
.trim();
}
it('displays the last component of the path', () => {
expect(optionText(requests[2].id)).toEqual('1.json?serializer=widget');
});
it('keeps the last two components of the path when the last component is numeric', () => {
expect(optionText(requests[1].id)).toEqual('merge_requests/1');
});
it('ignores trailing slashes', () => {
expect(optionText(requests[0].id)).toEqual('gitlab.com');
});
it('has a warning icon if any requests have warnings', () => { it('has a warning icon if any requests have warnings', () => {
expect(wrapper.find('span > gl-emoji').element.dataset.name).toEqual('warning'); expect(wrapper.find('span > gl-emoji').element.dataset.name).toEqual('warning');
}); });
it('adds a warning glyph to requests with warnings', () => { it('adds a warning glyph to requests with warnings', () => {
const requestValue = wrapper.find('[value="abc"]').text(); const requestValue = wrapper.find('[value="warningReq"]').text();
expect(requestValue).toContain('discussions.json'); expect(requestValue).toContain('discussions.json');
expect(requestValue).toContain('(!)'); expect(requestValue).toContain('(!)');
......
import PerformanceBarStore from '~/performance_bar/stores/performance_bar_store';
describe('PerformanceBarStore', () => {
describe('truncateUrl', () => {
let store;
const findUrl = id => store.findRequest(id).truncatedUrl;
beforeEach(() => {
store = new PerformanceBarStore();
});
it('ignores trailing slashes', () => {
store.addRequest('id', 'https://gitlab.com/');
expect(findUrl('id')).toEqual('gitlab.com');
});
it('keeps the last two components of the path when the last component is numeric', () => {
store.addRequest('id', 'https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/1');
expect(findUrl('id')).toEqual('merge_requests/1');
});
it('uses the last component of the path', () => {
store.addRequest(
'id',
'https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/1.json?serializer=widget',
);
expect(findUrl('id')).toEqual('1.json?serializer=widget');
});
it('keeps query components', () => {
store.addRequest('id', 'http://localhost:3001/h5bp/html5-boilerplate/?param');
expect(findUrl('id')).toEqual('html5-boilerplate?param');
});
it('keeps components when query contains a slash', () => {
store.addRequest('id', 'http://localhost:3001/h5bp/html5-boilerplate?trunc/ated');
expect(findUrl('id')).toEqual('html5-boilerplate?trunc/ated');
});
it('ignores fragments', () => {
store.addRequest('id', 'http://localhost:3001/h5bp/html5-boilerplate/#frag/ment');
expect(findUrl('id')).toEqual('html5-boilerplate');
});
});
});
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