Skip to content

Commit 7e4e050

Browse files
authored
[#1382] Avoid rerendering tabs unnecessarily (#1390)
Tabs are destroyed and rerendered based on a key which can lead to mysterious bugs. Furthermore, tab information is passed indirectly from store to `main.js` before being passed to the tab itself. Let's - clean up the code such that tabs do not need to completely rerender when information changes. - pass the tab information directly.
1 parent aa1ba08 commit 7e4e050

File tree

4 files changed

+87
-71
lines changed

4 files changed

+87
-71
lines changed

frontend/src/index.pug

+2-8
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,8 @@ html
7878
#tabs-wrapper(ref="tabWrapper", slot="right")
7979
.tab-content.panel-padding
8080
.tab-pane
81-
v-authorship#tab-authorship(
82-
v-if="tabType === 'authorship'",
83-
v-bind:key="generateKey(tabInfo.tabAuthorship, ['author', 'repo', 'isMergeGroup'])",
84-
v-bind:info="tabInfo.tabAuthorship")
85-
v-zoom#tab-zoom(
86-
v-else-if="tabType === 'zoom'",
87-
v-bind:key="generateKey(tabInfo.tabZoom, ['zRepo', 'zAuthor', 'zFilterGroup', 'zTimeFrame'])",
88-
v-bind:info="tabInfo.tabZoom")
81+
v-authorship#tab-authorship(v-if="tabType === 'authorship'")
82+
v-zoom#tab-zoom(v-else-if="tabType === 'zoom'")
8983
#tab-empty(v-else)
9084
.title
9185
h2 Welcome to this RepoSense report!

frontend/src/static/js/main.js

+1-12
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,18 @@ window.app = new window.Vue({
2828
isLoadingOverlayEnabled: false,
2929
loadingOverlayOpacity: 1,
3030

31-
isCollapsed: false,
3231
isTabActive: true, // to force tab wrapper to load
3332

3433
tabType: 'empty',
35-
tabInfo: {},
3634
creationDate: '',
3735

3836
errorMessages: {},
3937
},
4038
watch: {
4139
'$store.state.tabZoomInfo': function () {
42-
this.tabInfo.tabZoom = Object.assign({}, this.$store.state.tabZoomInfo);
4340
this.activateTab('zoom');
4441
},
4542
'$store.state.tabAuthorshipInfo': function () {
46-
this.tabInfo.tabAuthorship = Object.assign({}, this.$store.state.tabAuthorshipInfo);
4743
this.activateTab('authorship');
4844
},
4945
'$store.state.loadingOverlayCount': function () {
@@ -107,14 +103,11 @@ window.app = new window.Vue({
107103

108104
// handle opening of sidebar //
109105
activateTab(tabName) {
110-
// changing isTabActive to trigger redrawing of component
111-
this.isTabActive = false;
112106
if (this.$refs.tabWrapper) {
113107
this.$refs.tabWrapper.scrollTop = 0;
114108
}
115109

116110
this.isTabActive = true;
117-
this.isCollapsed = false;
118111
this.tabType = tabName;
119112

120113
window.addHash('tabOpen', this.isTabActive);
@@ -135,6 +128,7 @@ window.app = new window.Vue({
135128
author: hash.tabAuthor,
136129
repo: hash.tabRepo,
137130
isMergeGroup: hash.authorshipIsMergeGroup === 'true',
131+
isRefresh: true,
138132
minDate,
139133
maxDate,
140134
};
@@ -189,11 +183,6 @@ window.app = new window.Vue({
189183
}
190184
},
191185

192-
generateKey(dataObj, keysToUse) {
193-
const picked = keysToUse.map((key) => dataObj[key]);
194-
return JSON.stringify(picked);
195-
},
196-
197186
getRepoSenseHomeLink() {
198187
const version = window.app.repoSenseVersion;
199188
if (!version) {

frontend/src/static/js/v_authorship.js

+53-31
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,29 @@ const filesSortDict = {
66
fileType: (file) => file.fileType,
77
};
88

9+
function initialState() {
10+
return {
11+
isLoaded: false,
12+
files: [],
13+
selectedFiles: [],
14+
filterType: 'checkboxes',
15+
selectedFileTypes: [],
16+
fileTypes: [],
17+
filesLinesObj: {},
18+
fileTypeBlankLinesObj: {},
19+
filesSortType: 'lineOfCode',
20+
toReverseSortFiles: true,
21+
searchBarValue: '',
22+
};
23+
}
24+
925
const repoCache = [];
1026
const minimatch = require('minimatch');
1127

1228
window.vAuthorship = {
13-
props: ['info'],
1429
template: window.$('v_authorship').innerHTML,
1530
data() {
16-
return {
17-
isLoaded: false,
18-
files: [],
19-
selectedFiles: [],
20-
filterType: 'checkboxes',
21-
selectedFileTypes: [],
22-
fileTypes: [],
23-
filesLinesObj: {},
24-
fileTypeBlankLinesObj: {},
25-
filesSortType: 'lineOfCode',
26-
toReverseSortFiles: true,
27-
searchBarValue: '',
28-
};
31+
return initialState();
2932
},
3033

3134
watch: {
@@ -49,11 +52,9 @@ window.vAuthorship = {
4952
this.updateSelectedFiles();
5053
},
5154

52-
isLoaded() {
53-
if (this.isLoaded) {
54-
this.retrieveHashes();
55-
this.setInfoHash();
56-
}
55+
authorshipOwnerWatchable() {
56+
Object.assign(this.$data, initialState());
57+
this.initiate();
5758
},
5859
},
5960

@@ -73,13 +74,12 @@ window.vAuthorship = {
7374

7475
this.toReverseSortFiles = hash.reverseAuthorshipOrder !== 'false';
7576

76-
this.selectedFileTypes = this.info.checkedFileTypes
77-
? this.info.checkedFileTypes.filter((fileType) => this.fileTypes.includes(fileType))
78-
: [];
7977
if (hash.authorshipFileTypes) {
8078
this.selectedFileTypes = hash.authorshipFileTypes
8179
.split(window.HASH_DELIMITER)
8280
.filter((fileType) => this.fileTypes.includes(fileType));
81+
} else {
82+
this.resetSelectedFileTypes();
8383
}
8484

8585
if ('authorshipFilesGlob' in hash) {
@@ -88,6 +88,12 @@ window.vAuthorship = {
8888
}
8989
},
9090

91+
resetSelectedFileTypes() {
92+
this.selectedFileTypes = this.info.checkedFileTypes
93+
? this.info.checkedFileTypes.filter((fileType) => this.fileTypes.includes(fileType))
94+
: [];
95+
},
96+
9197
setInfoHash() {
9298
const { addHash } = window;
9399
// We only set these hashes as they are propagated from summary_charts
@@ -108,7 +114,7 @@ window.vAuthorship = {
108114
window.encodeHash();
109115
},
110116

111-
initiate() {
117+
async initiate() {
112118
const repo = window.REPOS[this.info.repo];
113119

114120
this.getRepoProps(repo);
@@ -124,12 +130,19 @@ window.vAuthorship = {
124130
}
125131
repoCache.push(this.info.repo);
126132

127-
if (repo.files) {
128-
this.processFiles(repo.files);
133+
let { files } = repo;
134+
if (!files) {
135+
files = await window.api.loadAuthorship(this.info.repo);
136+
}
137+
this.processFiles(files);
138+
139+
if (this.info.isRefresh) {
140+
this.retrieveHashes();
129141
} else {
130-
window.api.loadAuthorship(this.info.repo)
131-
.then((files) => this.processFiles(files));
142+
this.resetSelectedFileTypes();
132143
}
144+
145+
this.setInfoHash();
133146
},
134147

135148
getRepoProps(repo) {
@@ -273,8 +286,7 @@ window.vAuthorship = {
273286

274287
this.fileTypeBlankLinesObj = fileTypeBlanksInfoObj;
275288
this.files = res;
276-
this.isLoaded = true;
277-
this.updateSelectedFiles();
289+
this.updateSelectedFiles(true);
278290
},
279291

280292
getContributionFromAllAuthors(contributionMap) {
@@ -309,14 +321,17 @@ window.vAuthorship = {
309321
window.encodeHash();
310322
},
311323

312-
updateSelectedFiles() {
324+
updateSelectedFiles(setIsLoaded = false) {
313325
this.$store.commit('incrementLoadingOverlayCount', 1);
314326
setTimeout(() => {
315327
this.selectedFiles = this.files.filter(
316328
(file) => this.selectedFileTypes.includes(file.fileType)
317329
&& minimatch(file.path, this.searchBarValue || '*', { matchBase: true, dot: true }),
318330
)
319331
.sort(this.sortingFunction);
332+
if (setIsLoaded) {
333+
this.isLoaded = true;
334+
}
320335
this.$store.commit('incrementLoadingOverlayCount', -1);
321336
});
322337
},
@@ -352,6 +367,10 @@ window.vAuthorship = {
352367
},
353368

354369
computed: {
370+
authorshipOwnerWatchable() {
371+
return `${this.info.author}|${this.info.repo}|${this.info.isMergeGroup}`;
372+
},
373+
355374
sortingFunction() {
356375
return (a, b) => (this.toReverseSortFiles ? -1 : 1)
357376
* window.comparator(filesSortDict[this.filesSortType])(a, b);
@@ -394,7 +413,10 @@ window.vAuthorship = {
394413
return numLinesModified;
395414
},
396415

397-
...Vuex.mapState(['fileTypeColors']),
416+
...Vuex.mapState({
417+
fileTypeColors: 'fileTypeColors',
418+
info: 'tabAuthorshipInfo',
419+
}),
398420
},
399421

400422
created() {

frontend/src/static/js/v_zoom.js

+31-20
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,28 @@
11
/* global Vuex */
22

3+
function initialState() {
4+
return {
5+
showAllCommitMessageBody: true,
6+
expandedCommitMessagesCount: this.totalCommitMessageBodyCount,
7+
commitsSortType: 'time',
8+
toReverseSortedCommits: true,
9+
isCommitsFinalized: false,
10+
selectedFileTypes: [],
11+
fileTypes: [],
12+
};
13+
}
14+
315
window.vZoom = {
4-
props: ['info'],
516
template: window.$('v_zoom').innerHTML,
617
data() {
7-
return {
8-
showAllCommitMessageBody: true,
9-
expandedCommitMessagesCount: this.totalCommitMessageBodyCount,
10-
commitsSortType: 'time',
11-
toReverseSortedCommits: true,
12-
isCommitsFinalized: false,
13-
selectedFileTypes: [],
14-
fileTypes: [],
15-
};
18+
return initialState();
1619
},
1720

1821
computed: {
22+
zoomOwnerWatchable() {
23+
return `${this.info.zRepo}|${this.info.zAuthor}|${this.info.zFilterGroup}|${this.info.zTimeFrame}`;
24+
},
25+
1926
sortingFunction() {
2027
const commitSortFunction = this.commitsSortType === 'time'
2128
? (commit) => commit.date
@@ -34,7 +41,6 @@ window.vZoom = {
3441
filteredUser.commits = zUser.commits.filter(
3542
(commit) => commit[date] >= zSince && commit[date] <= zUntil,
3643
).sort(this.sortingFunction);
37-
this.isCommitsFinalized = true;
3844

3945
return filteredUser;
4046
},
@@ -81,17 +87,20 @@ window.vZoom = {
8187
this.updateSelectedFileTypesHash();
8288
},
8389
},
84-
...Vuex.mapState(['fileTypeColors']),
90+
91+
...Vuex.mapState({
92+
fileTypeColors: 'fileTypeColors',
93+
info: 'tabZoomInfo',
94+
}),
8595
},
8696

8797
watch: {
88-
isCommitsFinalized() {
89-
if (this.isCommitsFinalized) {
90-
this.updateFileTypes();
91-
this.selectedFileTypes = this.fileTypes.slice();
92-
this.retrieveHashes();
93-
}
98+
zoomOwnerWatchable() {
99+
Object.assign(this.$data, initialState());
100+
this.initiate();
101+
this.setInfoHash();
94102
},
103+
95104
selectedFileTypes() {
96105
this.$nextTick(() => {
97106
this.updateExpandedCommitMessagesCount();
@@ -112,6 +121,9 @@ window.vZoom = {
112121
if (!this.info.zUser) { // restoring zoom tab from reloaded page
113122
this.restoreZoomTab();
114123
}
124+
125+
this.updateFileTypes();
126+
this.selectedFileTypes = this.fileTypes.slice();
115127
},
116128

117129
openSummary() {
@@ -246,8 +258,7 @@ window.vZoom = {
246258
},
247259
created() {
248260
this.initiate();
249-
},
250-
mounted() {
261+
this.retrieveHashes();
251262
this.setInfoHash();
252263
},
253264
beforeDestroy() {

0 commit comments

Comments
 (0)