From 7c043cdb0d8c442689c0d887438680706d022e77 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 4 Mar 2024 13:36:36 +0800 Subject: [PATCH 1/5] Add cache for branch divergence on branch list page --- services/repository/branch.go | 51 ++++++++++++++++++++++++++++++----- services/repository/push.go | 3 +++ 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/services/repository/branch.go b/services/repository/branch.go index 55cedf5d84bfb..f1f4f9d69f70c 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -16,9 +16,11 @@ import ( issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/graceful" + "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/queue" @@ -99,7 +101,6 @@ func LoadBranches(ctx context.Context, repo *repo_model.Repository, gitRepo *git if err != nil { return nil, nil, 0, fmt.Errorf("loadOneBranch: %v", err) } - branches = append(branches, branch) } @@ -109,10 +110,43 @@ func LoadBranches(ctx context.Context, repo *repo_model.Repository, gitRepo *git if err != nil { return nil, nil, 0, fmt.Errorf("loadOneBranch: %v", err) } - return defaultBranch, branches, totalNumOfBranches, nil } +func getDivergenceCacheKey(repoID int64, branchName string) string { + return fmt.Sprintf("%d-%s", repoID, branchName) +} + +func getDivergenceFromCache(repoID int64, branchName string) *git.DivergeObject { + data := cache.GetCache().Get(getDivergenceCacheKey(repoID, branchName)) + res := git.DivergeObject{ + Ahead: -1, + Behind: -1, + } + s, ok := data.([]byte) + if !ok { + return &res + } + + if err := json.Unmarshal(s, &res); err != nil { + log.Error("json.UnMarshal failed: %v", err) + } + return &res +} + +func putDivergenceFromCache(repoID int64, branchName string, divergence *git.DivergeObject) { + bs, err := json.Marshal(divergence) + if err != nil { + log.Error("json.Marshal failed: %v", err) + return + } + cache.GetCache().Put(getDivergenceCacheKey(repoID, branchName), bs, 30*24*60*60) +} + +func DelDivergenceFromCache(repoID int64, branchName string) { + cache.GetCache().Delete(getDivergenceCacheKey(repoID, branchName)) +} + func loadOneBranch(ctx context.Context, repo *repo_model.Repository, dbBranch *git_model.Branch, protectedBranches *git_model.ProtectedBranchRules, repoIDToRepo map[int64]*repo_model.Repository, repoIDToGitRepo map[int64]*git.Repository, @@ -130,10 +164,15 @@ func loadOneBranch(ctx context.Context, repo *repo_model.Repository, dbBranch *g // it's not default branch if repo.DefaultBranch != dbBranch.Name && !dbBranch.IsDeleted { - var err error - divergence, err = files_service.CountDivergingCommits(ctx, repo, git.BranchPrefix+branchName) - if err != nil { - log.Error("CountDivergingCommits: %v", err) + divergence = getDivergenceFromCache(repo.ID, dbBranch.Name) + if divergence.Ahead == -1 && divergence.Behind == -1 { + var err error + divergence, err = files_service.CountDivergingCommits(ctx, repo, git.BranchPrefix+branchName) + if err != nil { + log.Error("CountDivergingCommits: %v", err) + } else { + putDivergenceFromCache(repo.ID, dbBranch.Name, divergence) + } } } diff --git a/services/repository/push.go b/services/repository/push.go index 9aaf0e1c9bcab..9e796488e8bc2 100644 --- a/services/repository/push.go +++ b/services/repository/push.go @@ -221,6 +221,9 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { } } + // delete cache for divergence + DelDivergenceFromCache(repo.ID, branch) + commits := repo_module.GitToPushCommits(l) commits.HeadCommit = repo_module.CommitToPushCommit(newCommit) From 6270922e2fbf7b76ab7a25d27ed65a57d4b943af Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 4 Mar 2024 14:22:40 +0800 Subject: [PATCH 2/5] Fix check --- services/repository/branch.go | 15 ++++++++------- services/repository/push.go | 4 +++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/services/repository/branch.go b/services/repository/branch.go index f1f4f9d69f70c..ab33ec7ed0260 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -134,17 +134,16 @@ func getDivergenceFromCache(repoID int64, branchName string) *git.DivergeObject return &res } -func putDivergenceFromCache(repoID int64, branchName string, divergence *git.DivergeObject) { +func putDivergenceFromCache(repoID int64, branchName string, divergence *git.DivergeObject) error { bs, err := json.Marshal(divergence) if err != nil { - log.Error("json.Marshal failed: %v", err) - return + return err } - cache.GetCache().Put(getDivergenceCacheKey(repoID, branchName), bs, 30*24*60*60) + return cache.GetCache().Put(getDivergenceCacheKey(repoID, branchName), bs, 30*24*60*60) } -func DelDivergenceFromCache(repoID int64, branchName string) { - cache.GetCache().Delete(getDivergenceCacheKey(repoID, branchName)) +func DelDivergenceFromCache(repoID int64, branchName string) error { + return cache.GetCache().Delete(getDivergenceCacheKey(repoID, branchName)) } func loadOneBranch(ctx context.Context, repo *repo_model.Repository, dbBranch *git_model.Branch, protectedBranches *git_model.ProtectedBranchRules, @@ -171,7 +170,9 @@ func loadOneBranch(ctx context.Context, repo *repo_model.Repository, dbBranch *g if err != nil { log.Error("CountDivergingCommits: %v", err) } else { - putDivergenceFromCache(repo.ID, dbBranch.Name, divergence) + if err = putDivergenceFromCache(repo.ID, dbBranch.Name, divergence); err != nil { + log.Error("putDivergenceFromCache: %v", err) + } } } } diff --git a/services/repository/push.go b/services/repository/push.go index 9e796488e8bc2..d6bdd0ad04ced 100644 --- a/services/repository/push.go +++ b/services/repository/push.go @@ -222,7 +222,9 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { } // delete cache for divergence - DelDivergenceFromCache(repo.ID, branch) + if err := DelDivergenceFromCache(repo.ID, branch); err != nil { + log.Error("DelDivergenceFromCache: %v", err) + } commits := repo_module.GitToPushCommits(l) commits.HeadCommit = repo_module.CommitToPushCommit(newCommit) From 9060703128dc8c368d3b66d7ad3476f8db48267e Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 8 Mar 2024 12:37:55 +0800 Subject: [PATCH 3/5] Follow wolfogre's suggestion --- services/repository/branch.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/services/repository/branch.go b/services/repository/branch.go index ab33ec7ed0260..c09583ac5c73b 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -117,7 +117,8 @@ func getDivergenceCacheKey(repoID int64, branchName string) string { return fmt.Sprintf("%d-%s", repoID, branchName) } -func getDivergenceFromCache(repoID int64, branchName string) *git.DivergeObject { +// getDivergenceFromCache gets the divergence from cache +func getDivergenceFromCache(repoID int64, branchName string) (*git.DivergeObject, bool) { data := cache.GetCache().Get(getDivergenceCacheKey(repoID, branchName)) res := git.DivergeObject{ Ahead: -1, @@ -125,13 +126,13 @@ func getDivergenceFromCache(repoID int64, branchName string) *git.DivergeObject } s, ok := data.([]byte) if !ok { - return &res + return &res, false } if err := json.Unmarshal(s, &res); err != nil { log.Error("json.UnMarshal failed: %v", err) } - return &res + return &res, true } func putDivergenceFromCache(repoID int64, branchName string, divergence *git.DivergeObject) error { @@ -163,8 +164,9 @@ func loadOneBranch(ctx context.Context, repo *repo_model.Repository, dbBranch *g // it's not default branch if repo.DefaultBranch != dbBranch.Name && !dbBranch.IsDeleted { - divergence = getDivergenceFromCache(repo.ID, dbBranch.Name) - if divergence.Ahead == -1 && divergence.Behind == -1 { + var cached bool + divergence, cached = getDivergenceFromCache(repo.ID, dbBranch.Name) + if !cached { var err error divergence, err = files_service.CountDivergingCommits(ctx, repo, git.BranchPrefix+branchName) if err != nil { From 67d0944208974dd0a247a91d3284d9c163681d80 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 8 Mar 2024 12:40:59 +0800 Subject: [PATCH 4/5] More stable --- services/repository/branch.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/repository/branch.go b/services/repository/branch.go index 2144569cde19a..9794ebc192be1 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -125,12 +125,13 @@ func getDivergenceFromCache(repoID int64, branchName string) (*git.DivergeObject Behind: -1, } s, ok := data.([]byte) - if !ok { + if !ok || len(s) == 0 { return &res, false } if err := json.Unmarshal(s, &res); err != nil { log.Error("json.UnMarshal failed: %v", err) + return &res, false } return &res, true } From 81f9a84f9fa73229b5c288f56fa6c641b94f90dd Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 8 Mar 2024 08:57:52 +0100 Subject: [PATCH 5/5] Set user's 24h preference from their current OS locale (#29651) @silverwind Can you update the issue content? Looks like we need to merge issue content and https://github.com/go-gitea/gitea/pull/29651#issuecomment-1984600844 as the commit message. --- web_src/js/components/RepoActionView.vue | 4 ++-- web_src/js/modules/tippy.js | 10 +++++++++- web_src/js/utils/time.js | 21 +++++++++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index 97cd05b45bcc4..de9625b143bab 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -3,7 +3,7 @@ import {SvgIcon} from '../svg.js'; import ActionRunStatus from './ActionRunStatus.vue'; import {createApp} from 'vue'; import {toggleElem} from '../utils/dom.js'; -import {getCurrentLocale} from '../utils.js'; +import {formatDatetime} from '../utils/time.js'; import {renderAnsi} from '../render/ansi.js'; import {POST, DELETE} from '../modules/fetch.js'; @@ -167,7 +167,7 @@ const sfc = { const logTimeStamp = document.createElement('span'); logTimeStamp.className = 'log-time-stamp'; const date = new Date(parseFloat(line.timestamp * 1000)); - const timeStamp = date.toLocaleString(getCurrentLocale(), {timeZoneName: 'short'}); + const timeStamp = formatDatetime(date); logTimeStamp.textContent = timeStamp; toggleElem(logTimeStamp, this.timeVisible['log-time-stamp']); // for "Show seconds" diff --git a/web_src/js/modules/tippy.js b/web_src/js/modules/tippy.js index 27f371fd88659..489afc0ae1cfa 100644 --- a/web_src/js/modules/tippy.js +++ b/web_src/js/modules/tippy.js @@ -1,5 +1,6 @@ import tippy, {followCursor} from 'tippy.js'; import {isDocumentFragmentOrElementNode} from '../utils/dom.js'; +import {formatDatetime} from '../utils/time.js'; const visibleInstances = new Set(); @@ -93,8 +94,15 @@ function attachTooltip(target, content = null) { } function switchTitleToTooltip(target) { - const title = target.getAttribute('title'); + let title = target.getAttribute('title'); if (title) { + // apply custom formatting to relative-time's tooltips + if (target.tagName.toLowerCase() === 'relative-time') { + const datetime = target.getAttribute('datetime'); + if (datetime) { + title = formatDatetime(new Date(datetime)); + } + } target.setAttribute('data-tooltip-content', title); target.setAttribute('aria-label', title); // keep the attribute, in case there are some other "[title]" selectors diff --git a/web_src/js/utils/time.js b/web_src/js/utils/time.js index 3284e893e1377..1848792c984c9 100644 --- a/web_src/js/utils/time.js +++ b/web_src/js/utils/time.js @@ -1,4 +1,5 @@ import dayjs from 'dayjs'; +import {getCurrentLocale} from '../utils.js'; // Returns an array of millisecond-timestamps of start-of-week days (Sundays) export function startDaysBetween(startDate, endDate) { @@ -44,3 +45,23 @@ export function fillEmptyStartDaysWithZeroes(startDays, data) { return Object.values(result); } + +let dateFormat; + +// format a Date object to document's locale, but with 24h format from user's current locale because this +// option is a personal preference of the user, not something that the document's locale should dictate. +export function formatDatetime(date) { + if (!dateFormat) { + // TODO: replace `hour12` with `Intl.Locale.prototype.getHourCycles` once there is broad browser support + dateFormat = new Intl.DateTimeFormat(getCurrentLocale(), { + day: 'numeric', + month: 'short', + year: 'numeric', + hour: 'numeric', + hour12: !Number.isInteger(Number(new Intl.DateTimeFormat([], {hour: 'numeric'}).format())), + minute: '2-digit', + timeZoneName: 'short', + }); + } + return dateFormat.format(date); +}