From 6b13a226ddfc49140d58e7e88f8703ae0ed90574 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Fri, 29 Nov 2019 09:06:31 +0000 Subject: Add latest changes from gitlab-org/gitlab@master --- .../components/performance_bar_app.vue | 5 +++ app/assets/javascripts/performance_bar/index.js | 50 ++++++++++++++++++++++ .../stores/performance_bar_store.js | 10 +++++ 3 files changed, 65 insertions(+) (limited to 'app/assets/javascripts/performance_bar') diff --git a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue index a0272b148e3..d17c2f33adc 100644 --- a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue +++ b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue @@ -52,6 +52,11 @@ export default { header: s__('PerformanceBar|Redis calls'), keys: ['cmd'], }, + { + metric: 'total', + header: s__('PerformanceBar|Frontend resources'), + keys: ['name', 'size'], + }, ], data() { return { currentRequestId: '' }; diff --git a/app/assets/javascripts/performance_bar/index.js b/app/assets/javascripts/performance_bar/index.js index 735c9d804ee..2ffe07500e0 100644 --- a/app/assets/javascripts/performance_bar/index.js +++ b/app/assets/javascripts/performance_bar/index.js @@ -1,3 +1,4 @@ +/* eslint-disable @gitlab/i18n/no-non-i18n-strings */ import Vue from 'vue'; import axios from '~/lib/utils/axios_utils'; @@ -53,12 +54,61 @@ export default ({ container }) => PerformanceBarService.fetchRequestDetails(this.peekUrl, requestId) .then(res => { this.store.addRequestDetails(requestId, res.data); + + if (this.requestId === requestId) this.collectFrontendPerformanceMetrics(); }) .catch(() => // eslint-disable-next-line no-console console.warn(`Error getting performance bar results for ${requestId}`), ); }, + collectFrontendPerformanceMetrics() { + if (performance) { + const navigationEntries = performance.getEntriesByType('navigation'); + const paintEntries = performance.getEntriesByType('paint'); + const resourceEntries = performance.getEntriesByType('resource'); + + let durationString = ''; + if (navigationEntries.length > 0) { + durationString = `BE ${this.formatMs(navigationEntries[0].responseEnd)} / `; + durationString += `FCP ${this.formatMs(paintEntries[1].startTime)} / `; + durationString += `DOM ${this.formatMs(navigationEntries[0].domContentLoadedEventEnd)}`; + } + + let newEntries = resourceEntries.map(this.transformResourceEntry); + + this.updateFrontendPerformanceMetrics(durationString, newEntries); + + if ('PerformanceObserver' in window) { + // We start observing for more incoming timings + const observer = new PerformanceObserver(list => { + newEntries = newEntries.concat(list.getEntries().map(this.transformResourceEntry)); + this.updateFrontendPerformanceMetrics(durationString, newEntries); + }); + + observer.observe({ entryTypes: ['resource'] }); + } + } + }, + updateFrontendPerformanceMetrics(durationString, requestEntries) { + this.store.setRequestDetailsData(this.requestId, 'total', { + duration: durationString, + calls: requestEntries.length, + details: requestEntries, + }); + }, + transformResourceEntry(entry) { + const nf = new Intl.NumberFormat(); + return { + name: entry.name.replace(document.location.origin, ''), + duration: Math.round(entry.duration), + size: entry.transferSize ? `${nf.format(entry.transferSize)} bytes` : 'cached', + }; + }, + formatMs(msValue) { + const nf = new Intl.NumberFormat(); + return `${nf.format(Math.round(msValue))}ms`; + }, }, render(createElement) { return createElement('performance-bar-app', { diff --git a/app/assets/javascripts/performance_bar/stores/performance_bar_store.js b/app/assets/javascripts/performance_bar/stores/performance_bar_store.js index 12d0ee86218..6f443db47ed 100644 --- a/app/assets/javascripts/performance_bar/stores/performance_bar_store.js +++ b/app/assets/javascripts/performance_bar/stores/performance_bar_store.js @@ -32,6 +32,16 @@ export default class PerformanceBarStore { return request; } + setRequestDetailsData(requestId, metricKey, requestDetailsData) { + const selectedRequest = this.findRequest(requestId); + if (selectedRequest) { + selectedRequest.details = { + ...selectedRequest.details, + [metricKey]: requestDetailsData, + }; + } + } + requestsWithDetails() { return this.requests.filter(request => request.details); } -- cgit v1.2.1