Commit 025a27b1 authored by Simon Knox's avatar Simon Knox

Merge branch '238973-user-timing-webide' into 'master'

Introduce User Timing API metrics for WebIDE

See merge request gitlab-org/gitlab!43407
parents fe976e4e 8f78da10
...@@ -2,7 +2,18 @@ ...@@ -2,7 +2,18 @@
import { mapActions, mapGetters, mapState } from 'vuex'; import { mapActions, mapGetters, mapState } from 'vuex';
import { GlButton, GlLoadingIcon } from '@gitlab/ui'; import { GlButton, GlLoadingIcon } from '@gitlab/ui';
import { __ } from '~/locale'; import { __ } from '~/locale';
import {
WEBIDE_MARK_APP_START,
WEBIDE_MARK_FILE_FINISH,
WEBIDE_MARK_FILE_CLICKED,
WEBIDE_MARK_TREE_FINISH,
WEBIDE_MEASURE_TREE_FROM_REQUEST,
WEBIDE_MEASURE_FILE_FROM_REQUEST,
WEBIDE_MEASURE_FILE_AFTER_INTERACTION,
} from '~/performance_constants';
import { performanceMarkAndMeasure } from '~/performance_utils';
import { modalTypes } from '../constants'; import { modalTypes } from '../constants';
import eventHub from '../eventhub';
import FindFile from '~/vue_shared/components/file_finder/index.vue'; import FindFile from '~/vue_shared/components/file_finder/index.vue';
import NewModal from './new_dropdown/modal.vue'; import NewModal from './new_dropdown/modal.vue';
import IdeSidebar from './ide_side_bar.vue'; import IdeSidebar from './ide_side_bar.vue';
...@@ -14,6 +25,50 @@ import ErrorMessage from './error_message.vue'; ...@@ -14,6 +25,50 @@ import ErrorMessage from './error_message.vue';
import CommitEditorHeader from './commit_sidebar/editor_header.vue'; import CommitEditorHeader from './commit_sidebar/editor_header.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
const markPerformance = params => {
performanceMarkAndMeasure(params);
};
const markTreePerformance = () => {
markPerformance({
mark: WEBIDE_MARK_TREE_FINISH,
measures: [
{
name: WEBIDE_MEASURE_TREE_FROM_REQUEST,
start: undefined,
end: WEBIDE_MARK_TREE_FINISH,
},
],
});
};
const markEditorLoadPerformance = () => {
markPerformance({
mark: WEBIDE_MARK_FILE_FINISH,
measures: [
{
name: WEBIDE_MEASURE_FILE_FROM_REQUEST,
start: undefined,
end: WEBIDE_MARK_FILE_FINISH,
},
],
});
};
const markEditorInteractionPerformance = () => {
markPerformance({
mark: WEBIDE_MARK_FILE_FINISH,
measures: [
{
name: WEBIDE_MEASURE_FILE_AFTER_INTERACTION,
start: WEBIDE_MARK_FILE_CLICKED,
end: WEBIDE_MARK_FILE_FINISH,
},
],
});
};
eventHub.$on(WEBIDE_MEASURE_TREE_FROM_REQUEST, markTreePerformance);
eventHub.$on(WEBIDE_MEASURE_FILE_FROM_REQUEST, markEditorLoadPerformance);
eventHub.$on(WEBIDE_MEASURE_FILE_AFTER_INTERACTION, markEditorInteractionPerformance);
export default { export default {
components: { components: {
NewModal, NewModal,
...@@ -59,6 +114,9 @@ export default { ...@@ -59,6 +114,9 @@ export default {
if (this.themeName) if (this.themeName)
document.querySelector('.navbar-gitlab').classList.add(`theme-${this.themeName}`); document.querySelector('.navbar-gitlab').classList.add(`theme-${this.themeName}`);
}, },
beforeCreate() {
performance.mark(WEBIDE_MARK_APP_START);
},
methods: { methods: {
...mapActions(['toggleFileFinder']), ...mapActions(['toggleFileFinder']),
onBeforeUnload(e = {}) { onBeforeUnload(e = {}) {
......
...@@ -2,6 +2,13 @@ ...@@ -2,6 +2,13 @@
import { mapActions, mapGetters, mapState } from 'vuex'; import { mapActions, mapGetters, mapState } from 'vuex';
import { GlDeprecatedSkeletonLoading as GlSkeletonLoading } from '@gitlab/ui'; import { GlDeprecatedSkeletonLoading as GlSkeletonLoading } from '@gitlab/ui';
import FileTree from '~/vue_shared/components/file_tree.vue'; import FileTree from '~/vue_shared/components/file_tree.vue';
import {
WEBIDE_MARK_TREE_START,
WEBIDE_MEASURE_TREE_FROM_REQUEST,
WEBIDE_MARK_FILE_CLICKED,
} from '~/performance_constants';
import { performanceMarkAndMeasure } from '~/performance_utils';
import eventHub from '../eventhub';
import IdeFileRow from './ide_file_row.vue'; import IdeFileRow from './ide_file_row.vue';
import NavDropdown from './nav_dropdown.vue'; import NavDropdown from './nav_dropdown.vue';
...@@ -25,8 +32,21 @@ export default { ...@@ -25,8 +32,21 @@ export default {
return !this.currentTree || this.currentTree.loading; return !this.currentTree || this.currentTree.loading;
}, },
}, },
beforeCreate() {
performanceMarkAndMeasure({ mark: WEBIDE_MARK_TREE_START });
},
updated() {
if (this.currentTree?.tree?.length) {
this.$nextTick(() => {
eventHub.$emit(WEBIDE_MEASURE_TREE_FROM_REQUEST);
});
}
},
methods: { methods: {
...mapActions(['toggleTreeOpen']), ...mapActions(['toggleTreeOpen']),
clickedFile() {
performanceMarkAndMeasure({ mark: WEBIDE_MARK_FILE_CLICKED });
},
}, },
IdeFileRow, IdeFileRow,
}; };
...@@ -53,6 +73,7 @@ export default { ...@@ -53,6 +73,7 @@ export default {
:level="0" :level="0"
:file-row-component="$options.IdeFileRow" :file-row-component="$options.IdeFileRow"
@toggleTreeOpen="toggleTreeOpen" @toggleTreeOpen="toggleTreeOpen"
@clickFile="clickedFile"
/> />
</template> </template>
<div v-else class="file-row">{{ __('No files') }}</div> <div v-else class="file-row">{{ __('No files') }}</div>
......
...@@ -4,6 +4,14 @@ import { viewerInformationForPath } from '~/vue_shared/components/content_viewer ...@@ -4,6 +4,14 @@ import { viewerInformationForPath } from '~/vue_shared/components/content_viewer
import { deprecatedCreateFlash as flash } from '~/flash'; import { deprecatedCreateFlash as flash } from '~/flash';
import ContentViewer from '~/vue_shared/components/content_viewer/content_viewer.vue'; import ContentViewer from '~/vue_shared/components/content_viewer/content_viewer.vue';
import DiffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue'; import DiffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue';
import {
WEBIDE_MARK_FILE_CLICKED,
WEBIDE_MARK_FILE_START,
WEBIDE_MEASURE_FILE_AFTER_INTERACTION,
WEBIDE_MEASURE_FILE_FROM_REQUEST,
} from '~/performance_constants';
import { performanceMarkAndMeasure } from '~/performance_utils';
import eventHub from '../eventhub';
import { import {
leftSidebarViews, leftSidebarViews,
viewerTypes, viewerTypes,
...@@ -164,6 +172,9 @@ export default { ...@@ -164,6 +172,9 @@ export default {
} }
}, },
}, },
beforeCreate() {
performanceMarkAndMeasure({ mark: WEBIDE_MARK_FILE_START });
},
beforeDestroy() { beforeDestroy() {
this.editor.dispose(); this.editor.dispose();
}, },
...@@ -289,6 +300,13 @@ export default { ...@@ -289,6 +300,13 @@ export default {
}); });
this.$emit('editorSetup'); this.$emit('editorSetup');
this.$nextTick(() => {
if (performance.getEntriesByName(WEBIDE_MARK_FILE_CLICKED).length) {
eventHub.$emit(WEBIDE_MEASURE_FILE_AFTER_INTERACTION);
} else {
eventHub.$emit(WEBIDE_MEASURE_FILE_FROM_REQUEST);
}
});
}, },
refreshEditorDimensions() { refreshEditorDimensions() {
if (this.showEditor) { if (this.showEditor) {
......
...@@ -5,7 +5,7 @@ export const PERFORMANCE_TYPE_MEASURE = 'measure'; ...@@ -5,7 +5,7 @@ export const PERFORMANCE_TYPE_MEASURE = 'measure';
// SNIPPET namespace // SNIPPET namespace
// //
// marks // Marks
export const SNIPPET_MARK_VIEW_APP_START = 'snippet-view-app-start'; export const SNIPPET_MARK_VIEW_APP_START = 'snippet-view-app-start';
export const SNIPPET_MARK_EDIT_APP_START = 'snippet-edit-app-start'; export const SNIPPET_MARK_EDIT_APP_START = 'snippet-edit-app-start';
export const SNIPPET_MARK_BLOBS_CONTENT = 'snippet-blobs-content-finished'; export const SNIPPET_MARK_BLOBS_CONTENT = 'snippet-blobs-content-finished';
...@@ -13,3 +13,20 @@ export const SNIPPET_MARK_BLOBS_CONTENT = 'snippet-blobs-content-finished'; ...@@ -13,3 +13,20 @@ export const SNIPPET_MARK_BLOBS_CONTENT = 'snippet-blobs-content-finished';
// Measures // Measures
export const SNIPPET_MEASURE_BLOBS_CONTENT = 'snippet-blobs-content'; export const SNIPPET_MEASURE_BLOBS_CONTENT = 'snippet-blobs-content';
export const SNIPPET_MEASURE_BLOBS_CONTENT_WITHIN_APP = 'snippet-blobs-content-within-app'; export const SNIPPET_MEASURE_BLOBS_CONTENT_WITHIN_APP = 'snippet-blobs-content-within-app';
//
// WebIDE namespace
//
// Marks
export const WEBIDE_MARK_APP_START = 'webide-app-start';
export const WEBIDE_MARK_TREE_START = 'webide-tree-start';
export const WEBIDE_MARK_TREE_FINISH = 'webide-tree-finished';
export const WEBIDE_MARK_FILE_START = 'webide-file-start';
export const WEBIDE_MARK_FILE_CLICKED = 'webide-file-clicked';
export const WEBIDE_MARK_FILE_FINISH = 'webide-file-finished';
// Measures
export const WEBIDE_MEASURE_TREE_FROM_REQUEST = 'webide-tree-loading-from-request';
export const WEBIDE_MEASURE_FILE_FROM_REQUEST = 'webide-file-loading-from-request';
export const WEBIDE_MEASURE_FILE_AFTER_INTERACTION = 'webide-file-loading-after-interaction';
export const performanceMarkAndMeasure = ({ mark, measures = [] } = {}) => {
window.requestAnimationFrame(() => {
if (mark && !performance.getEntriesByName(mark).length) {
performance.mark(mark);
}
measures.forEach(measure => {
window.requestAnimationFrame(() =>
performance.measure(measure.name, measure.start, measure.end),
);
});
});
};
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