From 076eaad7430dd80f202446487c99e95e8d803ab3 Mon Sep 17 00:00:00 2001 From: Gusted Date: Tue, 26 Apr 2022 20:34:30 +0000 Subject: [PATCH] Improve dashboard's repo list performance (#18963) * Improve dashboard's repo list performance - Avoid a lot of database lookups for all the repo's, by adding a undocumented "minimal" mode for this specific task, which returns the data that's only needed by this list which doesn't require any database lookups. - Makes fetching these list faster. - Less CPU overhead when a user visits home page. * Refactor javascript code + fix Fork icon - Use async in the function so we can use `await`. - Remove `archivedFilter` check for count, as it doesn't make sense to show the count of repos when you can't even see them(as they are filited away). * Add `count_only` * Remove uncessary code * Improve comment Co-authored-by: delvh * Update web_src/js/components/DashboardRepoList.js Co-authored-by: delvh * Update web_src/js/components/DashboardRepoList.js Co-authored-by: delvh * By default apply minimal mode * Remove `minimal` paramater * Refactor count header * Simplify init Co-authored-by: wxiaoguang Co-authored-by: delvh Co-authored-by: wxiaoguang Co-authored-by: zeripath --- routers/api/v1/repo/repo.go | 1 - routers/web/repo/repo.go | 38 +++++++++--------- web_src/js/components/DashboardRepoList.js | 45 ++++++++++++---------- 3 files changed, 45 insertions(+), 39 deletions(-) diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 16942dd3ba..cec4c93d19 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -218,7 +218,6 @@ func Search(ctx *context.APIContext) { } results[i] = convert.ToRepo(repo, accessMode) } - ctx.SetLinkHeader(int(count), opts.PageSize) ctx.SetTotalCountHeader(count) ctx.JSON(http.StatusOK, api.SearchResults{ diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index 60298121df..199651b2f1 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -590,26 +590,28 @@ func SearchRepo(ctx *context.Context) { return } - results := make([]*api.Repository, len(repos)) - for i, repo := range repos { - if err = repo.GetOwner(ctx); err != nil { - ctx.JSON(http.StatusInternalServerError, api.SearchError{ - OK: false, - Error: err.Error(), - }) - return - } - accessMode, err := models.AccessLevel(ctx.Doer, repo) - if err != nil { - ctx.JSON(http.StatusInternalServerError, api.SearchError{ - OK: false, - Error: err.Error(), - }) - } - results[i] = convert.ToRepo(repo, accessMode) + ctx.SetTotalCountHeader(count) + + // To improve performance when only the count is requested + if ctx.FormBool("count_only") { + return + } + + results := make([]*api.Repository, len(repos)) + for i, repo := range repos { + results[i] = &api.Repository{ + ID: repo.ID, + FullName: repo.FullName(), + Fork: repo.IsFork, + Private: repo.IsPrivate, + Template: repo.IsTemplate, + Mirror: repo.IsMirror, + Stars: repo.NumStars, + HTMLURL: repo.HTMLURL(), + Internal: !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePrivate, + } } - ctx.SetTotalCountHeader(count) ctx.JSON(http.StatusOK, api.SearchResults{ OK: true, Data: results, diff --git a/web_src/js/components/DashboardRepoList.js b/web_src/js/components/DashboardRepoList.js index e4847ec2f0..36caaf2f5b 100644 --- a/web_src/js/components/DashboardRepoList.js +++ b/web_src/js/components/DashboardRepoList.js @@ -298,36 +298,41 @@ function initVueComponents() { this.searchRepos(); }, - searchRepos() { + async searchRepos() { this.isLoading = true; - if (!this.reposTotalCount) { - const totalCountSearchURL = `${this.subUrl}/repo/search?sort=updated&order=desc&uid=${this.uid}&team_id=${this.teamId}&q=&page=1&mode=`; - $.getJSON(totalCountSearchURL, (_result, _textStatus, request) => { - this.reposTotalCount = request.getResponseHeader('X-Total-Count'); - }); - } - const searchedMode = this.repoTypes[this.reposFilter].searchMode; const searchedURL = this.searchURL; const searchedQuery = this.searchQuery; - $.getJSON(searchedURL, (result, _textStatus, request) => { - if (searchedURL === this.searchURL) { - this.repos = result.data; - const count = request.getResponseHeader('X-Total-Count'); - if (searchedQuery === '' && searchedMode === '' && this.archivedFilter === 'both') { - this.reposTotalCount = count; - } - Vue.set(this.counts, `${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`, count); - this.finalPage = Math.ceil(count / this.searchLimit); - this.updateHistory(); + let response, json; + try { + if (!this.reposTotalCount) { + const totalCountSearchURL = `${this.subUrl}/repo/search?count_only=1&uid=${this.uid}&team_id=${this.teamId}&q=&page=1&mode=`; + response = await fetch(totalCountSearchURL); + this.reposTotalCount = response.headers.get('X-Total-Count'); } - }).always(() => { + + response = await fetch(searchedURL); + json = await response.json(); + } catch { if (searchedURL === this.searchURL) { this.isLoading = false; } - }); + return; + } + + if (searchedURL === this.searchURL) { + this.repos = json.data; + const count = response.headers.get('X-Total-Count'); + if (searchedQuery === '' && searchedMode === '' && this.archivedFilter === 'both') { + this.reposTotalCount = count; + } + Vue.set(this.counts, `${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`, count); + this.finalPage = Math.ceil(count / this.searchLimit); + this.updateHistory(); + this.isLoading = false; + } }, repoIcon(repo) {