mirror of https://github.com/go-gitea/gitea
Compare commits
93 Commits
11b99774c1
...
eca8c7d4b1
Author | SHA1 | Date |
---|---|---|
Illya Marchenko | eca8c7d4b1 | |
silverwind | dcc3c17e5c | |
GiteaBot | 27861d711b | |
silverwind | c93eefb42b | |
stuzer05 | 0a8fd353ef | |
stuzer05 | 12553d7dc2 | |
stuzer05 | b97139b232 | |
stuzer05 | b452e13f35 | |
stuzer05 | e92bedc81d | |
stuzer05 | 1e22cc242f | |
stuzer05 | 93d09fa8fc | |
stuzer05 | 0820db04ed | |
stuzer05 | 09723c5e0b | |
stuzer05 | c272512d9a | |
stuzer05 | 0c4b2dfa8f | |
stuzer05 | 805af19ef1 | |
stuzer05 | bb5ca4c40b | |
stuzer05 | a737a8c10b | |
stuzer05 | 92dc2cd22c | |
stuzer05 | 39b8b1929d | |
stuzer05 | a999055954 | |
stuzer05 | a6fa4c3d04 | |
stuzer05 | 2a9009fb02 | |
stuzer05 | 3037d6cdde | |
stuzer05 | 349b959022 | |
stuzer05 | 64de74d540 | |
stuzer05 | fa662ec087 | |
stuzer05 | 62094d8cf3 | |
スツゼル | e933a89bd9 | |
stuzer05 | db49783fa8 | |
stuzer05 | a45c1e9c86 | |
stuzer05 | 721069d766 | |
stuzer05 | 3310440ed1 | |
スツゼル | 598e2d5bed | |
silverwind | b211b9e66d | |
stuzer05 | ffaa4babcb | |
stuzer05 | cef496af2a | |
stuzer05 | 015ad01513 | |
stuzer05 | 748bd67814 | |
スツゼル | 3924cb0062 | |
stuzer05 | e9afd60d6b | |
stuzer05 | 40e1373dce | |
stuzer05 | bf4fa112d0 | |
stuzer05 | fc93006f50 | |
スツゼル | 879d96f077 | |
スツゼル | fd5adc55f3 | |
stuzer05 | 57a3664eb2 | |
stuzer05 | bf323cf26c | |
スツゼル | fb8126035a | |
stuzer05 | deddce59cf | |
stuzer05 | 79e18c6711 | |
stuzer05 | 49a176d37c | |
stuzer05 | 8ef3a478aa | |
stuzer05 | 37e8e8ddaf | |
stuzer05 | e20e23b60a | |
スツゼル | 8c0bf885b2 | |
stuzer05 | b9cdc7c670 | |
stuzer05 | 7be748f63b | |
stuzer05 | 29dd61722b | |
stuzer05 | 875087061f | |
スツゼル | 775c663805 | |
stuzer05 | db3c697178 | |
stuzer05 | 5eea230714 | |
stuzer05 | 0ab85af1ce | |
stuzer05 | 5c4dc8739c | |
stuzer05 | 79f507b81f | |
stuzer05 | 7a570440f1 | |
stuzer05 | f463765fec | |
stuzer05 | e15549501d | |
stuzer05 | 1cff1a9e05 | |
stuzer05 | f7427d8b50 | |
stuzer05 | 1b7ba4189b | |
stuzer05 | 11b9719b5f | |
stuzer05 | 0f5b609f9d | |
stuzer05 | 09c05e8b76 | |
stuzer05 | d247b0ffd1 | |
stuzer05 | 870bb922cc | |
stuzer05 | b062fc9849 | |
stuzer05 | 2fc2f63c6c | |
スツゼル | 4e1aed8a61 | |
stuzer05 | f33b0a0773 | |
stuzer05 | e187364d7a | |
スツゼル | f7a4c9e0aa | |
スツゼル | 5f3edad64f | |
stuzer05 | 4be8c50a6f | |
stuzer05 | d75b7acac6 | |
stuzer05 | c248042c8e | |
stuzer05 | 7ed86ff00a | |
stuzer05 | d9446629c3 | |
stuzer05 | a8778f4db7 | |
stuzer05 | c783692f6c | |
stuzer05 | d11ba9f46c | |
stuzer05 | 1363205f29 |
5
Makefile
5
Makefile
|
@ -908,8 +908,9 @@ webpack: $(WEBPACK_DEST)
|
|||
|
||||
$(WEBPACK_DEST): $(WEBPACK_SOURCES) $(WEBPACK_CONFIGS) package-lock.json
|
||||
@$(MAKE) -s node-check node_modules
|
||||
rm -rf $(WEBPACK_DEST_ENTRIES)
|
||||
npx webpack
|
||||
@rm -rf $(WEBPACK_DEST_ENTRIES)
|
||||
@echo "Running webpack..."
|
||||
@BROWSERSLIST_IGNORE_OLD_DATA=true npx webpack
|
||||
@touch $(WEBPACK_DEST)
|
||||
|
||||
.PHONY: svg
|
||||
|
|
|
@ -112,6 +112,8 @@ const (
|
|||
|
||||
CommentTypePin // 36 pin Issue
|
||||
CommentTypeUnpin // 37 unpin Issue
|
||||
|
||||
CommentTypeChangeTimeEstimate // 38 Change time estimate
|
||||
)
|
||||
|
||||
var commentStrings = []string{
|
||||
|
@ -151,6 +153,7 @@ var commentStrings = []string{
|
|||
"change_issue_ref",
|
||||
"pull_scheduled_merge",
|
||||
"pull_cancel_scheduled_merge",
|
||||
"change_time_estimate",
|
||||
"pin",
|
||||
"unpin",
|
||||
}
|
||||
|
|
|
@ -140,6 +140,9 @@ type Issue struct {
|
|||
|
||||
// For view issue page.
|
||||
ShowRole RoleDescriptor `xorm:"-"`
|
||||
|
||||
// Time estimate
|
||||
TimeEstimate int64 `xorm:"NOT NULL DEFAULT 0"`
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -909,3 +912,33 @@ func insertIssue(ctx context.Context, issue *Issue) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ChangeIssueTimeEstimate changes the plan time of this issue, as the given user.
|
||||
func ChangeIssueTimeEstimate(issue *Issue, doer *user_model.User, timeEstimate int64) (err error) {
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer committer.Close()
|
||||
|
||||
if err = UpdateIssueCols(ctx, &Issue{ID: issue.ID, TimeEstimate: timeEstimate}, "time_estimate"); err != nil {
|
||||
return fmt.Errorf("updateIssueCols: %w", err)
|
||||
}
|
||||
|
||||
if err = issue.LoadRepo(ctx); err != nil {
|
||||
return fmt.Errorf("loadRepo: %w", err)
|
||||
}
|
||||
|
||||
opts := &CreateCommentOptions{
|
||||
Type: CommentTypeChangeTimeEstimate,
|
||||
Doer: doer,
|
||||
Repo: issue.Repo,
|
||||
Issue: issue,
|
||||
Content: fmt.Sprintf("%d", timeEstimate),
|
||||
}
|
||||
if _, err = CreateComment(ctx, opts); err != nil {
|
||||
return fmt.Errorf("createComment: %w", err)
|
||||
}
|
||||
|
||||
return committer.Commit()
|
||||
}
|
||||
|
|
|
@ -586,6 +586,8 @@ var migrations = []Migration{
|
|||
NewMigration("Add everyone_access_mode for repo_unit", v1_23.AddRepoUnitEveryoneAccessMode),
|
||||
// v298 -> v299
|
||||
NewMigration("Drop wrongly created table o_auth2_application", v1_23.DropWronglyCreatedTable),
|
||||
// v300 -> v301
|
||||
NewMigration("Add TimeEstimate to issue table", v1_23.AddTimeEstimateColumnToIssueTable),
|
||||
}
|
||||
|
||||
// GetCurrentDBVersion returns the current db version
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v1_23 //nolint
|
||||
|
||||
import (
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
func AddTimeEstimateColumnToIssueTable(x *xorm.Engine) error {
|
||||
type Issue struct {
|
||||
TimeEstimate int64 `xorm:"NOT NULL DEFAULT 0"`
|
||||
}
|
||||
|
||||
return x.Sync(new(Issue))
|
||||
}
|
|
@ -65,12 +65,14 @@ func NewFuncMap() template.FuncMap {
|
|||
|
||||
// -----------------------------------------------------------------
|
||||
// time / number / format
|
||||
"FileSize": base.FileSize,
|
||||
"CountFmt": base.FormatNumberSI,
|
||||
"TimeSince": timeutil.TimeSince,
|
||||
"TimeSinceUnix": timeutil.TimeSinceUnix,
|
||||
"DateTime": timeutil.DateTime,
|
||||
"Sec2Time": util.SecToTime,
|
||||
"FileSize": base.FileSize,
|
||||
"CountFmt": base.FormatNumberSI,
|
||||
"TimeSince": timeutil.TimeSince,
|
||||
"TimeSinceUnix": timeutil.TimeSinceUnix,
|
||||
"DateTime": timeutil.DateTime,
|
||||
"Sec2Time": util.SecToTime,
|
||||
"SecToTimeExact": util.SecToTimeExact,
|
||||
"TimeEstimateToStr": util.TimeEstimateToStr,
|
||||
"LoadTimes": func(startTime time.Time) string {
|
||||
return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms"
|
||||
},
|
||||
|
|
|
@ -66,6 +66,43 @@ func SecToTime(durationVal any) string {
|
|||
return strings.TrimRight(formattedTime, " ")
|
||||
}
|
||||
|
||||
func SecToTimeExact(duration int64, withSeconds bool) string {
|
||||
formattedTime := ""
|
||||
|
||||
// The following four variables are calculated by taking
|
||||
// into account the previously calculated variables, this avoids
|
||||
// pitfalls when using remainders. As that could lead to incorrect
|
||||
// results when the calculated number equals the quotient number.
|
||||
remainingDays := duration / (60 * 60 * 24)
|
||||
years := remainingDays / 365
|
||||
remainingDays -= years * 365
|
||||
months := remainingDays * 12 / 365
|
||||
remainingDays -= months * 365 / 12
|
||||
weeks := remainingDays / 7
|
||||
remainingDays -= weeks * 7
|
||||
days := remainingDays
|
||||
|
||||
// The following three variables are calculated without depending
|
||||
// on the previous calculated variables.
|
||||
hours := (duration / 3600) % 24
|
||||
minutes := (duration / 60) % 60
|
||||
seconds := duration % 60
|
||||
|
||||
// Show exact time information
|
||||
formattedTime = formatTime(years, "year", formattedTime)
|
||||
formattedTime = formatTime(months, "month", formattedTime)
|
||||
formattedTime = formatTime(weeks, "week", formattedTime)
|
||||
formattedTime = formatTime(days, "day", formattedTime)
|
||||
formattedTime = formatTime(hours, "hour", formattedTime)
|
||||
formattedTime = formatTime(minutes, "minute", formattedTime)
|
||||
if withSeconds {
|
||||
formattedTime = formatTime(seconds, "second", formattedTime)
|
||||
}
|
||||
|
||||
// The formatTime() function always appends a space at the end. This will be trimmed
|
||||
return strings.TrimRight(formattedTime, " ")
|
||||
}
|
||||
|
||||
// formatTime appends the given value to the existing forammattedTime. E.g:
|
||||
// formattedTime = "1 year"
|
||||
// input: value = 3, name = "month"
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
// Copyright 2022 Gitea. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
// Time estimate match regex
|
||||
rTimeEstimateOnlyHours = regexp.MustCompile(`^([\d]+)$`)
|
||||
rTimeEstimateWeeks = regexp.MustCompile(`([\d]+)w`)
|
||||
rTimeEstimateDays = regexp.MustCompile(`([\d]+)d`)
|
||||
rTimeEstimateHours = regexp.MustCompile(`([\d]+)h`)
|
||||
rTimeEstimateMinutes = regexp.MustCompile(`([\d]+)m`)
|
||||
)
|
||||
|
||||
// TimeEstimateFromStr returns time estimate in seconds from formatted string
|
||||
func TimeEstimateFromStr(timeStr string) int64 {
|
||||
timeTotal := 0
|
||||
|
||||
// If single number entered, assume hours
|
||||
timeStrMatches := rTimeEstimateOnlyHours.FindStringSubmatch(timeStr)
|
||||
if len(timeStrMatches) > 0 {
|
||||
raw, _ := strconv.Atoi(timeStrMatches[1])
|
||||
timeTotal += raw * (60 * 60)
|
||||
} else {
|
||||
// Find time weeks
|
||||
timeStrMatches = rTimeEstimateWeeks.FindStringSubmatch(timeStr)
|
||||
if len(timeStrMatches) > 0 {
|
||||
raw, _ := strconv.Atoi(timeStrMatches[1])
|
||||
timeTotal += raw * (60 * 60 * 24 * 7)
|
||||
}
|
||||
|
||||
// Find time days
|
||||
timeStrMatches = rTimeEstimateDays.FindStringSubmatch(timeStr)
|
||||
if len(timeStrMatches) > 0 {
|
||||
raw, _ := strconv.Atoi(timeStrMatches[1])
|
||||
timeTotal += raw * (60 * 60 * 24)
|
||||
}
|
||||
|
||||
// Find time hours
|
||||
timeStrMatches = rTimeEstimateHours.FindStringSubmatch(timeStr)
|
||||
if len(timeStrMatches) > 0 {
|
||||
raw, _ := strconv.Atoi(timeStrMatches[1])
|
||||
timeTotal += raw * (60 * 60)
|
||||
}
|
||||
|
||||
// Find time minutes
|
||||
timeStrMatches = rTimeEstimateMinutes.FindStringSubmatch(timeStr)
|
||||
if len(timeStrMatches) > 0 {
|
||||
raw, _ := strconv.Atoi(timeStrMatches[1])
|
||||
timeTotal += raw * (60)
|
||||
}
|
||||
}
|
||||
|
||||
return int64(timeTotal)
|
||||
}
|
||||
|
||||
// TimeEstimateStr returns formatted time estimate string from seconds (e.g. "2w 4d 12h 5m")
|
||||
func TimeEstimateToStr(amount int64) string {
|
||||
var timeParts []string
|
||||
|
||||
timeSeconds := float64(amount)
|
||||
|
||||
// Format weeks
|
||||
weeks := math.Floor(timeSeconds / (60 * 60 * 24 * 7))
|
||||
if weeks > 0 {
|
||||
timeParts = append(timeParts, fmt.Sprintf("%dw", int64(weeks)))
|
||||
}
|
||||
timeSeconds -= weeks * (60 * 60 * 24 * 7)
|
||||
|
||||
// Format days
|
||||
days := math.Floor(timeSeconds / (60 * 60 * 24))
|
||||
if days > 0 {
|
||||
timeParts = append(timeParts, fmt.Sprintf("%dd", int64(days)))
|
||||
}
|
||||
timeSeconds -= days * (60 * 60 * 24)
|
||||
|
||||
// Format hours
|
||||
hours := math.Floor(timeSeconds / (60 * 60))
|
||||
if hours > 0 {
|
||||
timeParts = append(timeParts, fmt.Sprintf("%dh", int64(hours)))
|
||||
}
|
||||
timeSeconds -= hours * (60 * 60)
|
||||
|
||||
// Format minutes
|
||||
minutes := math.Floor(timeSeconds / (60))
|
||||
if minutes > 0 {
|
||||
timeParts = append(timeParts, fmt.Sprintf("%dm", int64(minutes)))
|
||||
}
|
||||
|
||||
return strings.Join(timeParts, " ")
|
||||
}
|
|
@ -1480,6 +1480,11 @@ issues.add_assignee_at = `was assigned by <b>%s</b> %s`
|
|||
issues.remove_assignee_at = `was unassigned by <b>%s</b> %s`
|
||||
issues.remove_self_assignment = `removed their assignment %s`
|
||||
issues.change_title_at = `changed title from <b><strike>%s</strike></b> to <b>%s</b> %s`
|
||||
issues.time_estimate = `Time Estimate`
|
||||
issues.add_time_estimate = `3w 4d 12h`
|
||||
issues.change_time_estimate_at = `changed time estimate to <b>%s</b> %s`
|
||||
issues.remove_time_estimate = `removed time estimate %s`
|
||||
issues.time_estimate_invalid = `Time estimate format is invalid`
|
||||
issues.change_ref_at = `changed reference from <b><strike>%s</strike></b> to <b>%s</b> %s`
|
||||
issues.remove_ref_at = `removed reference <b>%s</b> %s`
|
||||
issues.add_ref_at = `added reference <b>%s</b> %s`
|
||||
|
@ -1650,20 +1655,20 @@ issues.start_tracking_history = `started working %s`
|
|||
issues.tracker_auto_close = Timer will be stopped automatically when this issue gets closed
|
||||
issues.tracking_already_started = `You have already started time tracking on <a href="%s">another issue</a>!`
|
||||
issues.stop_tracking = Stop Timer
|
||||
issues.stop_tracking_history = `stopped working %s`
|
||||
issues.stop_tracking_history = `worked for <b>%s</b> %s`
|
||||
issues.cancel_tracking = Discard
|
||||
issues.cancel_tracking_history = `canceled time tracking %s`
|
||||
issues.add_time = Manually Add Time
|
||||
issues.del_time = Delete this time log
|
||||
issues.add_time_short = Add Time
|
||||
issues.add_time_cancel = Cancel
|
||||
issues.add_time_history = `added spent time %s`
|
||||
issues.del_time_history= `deleted spent time %s`
|
||||
issues.add_time_history = `added spent time <b>%s</b> %s`
|
||||
issues.del_time_history= `deleted spent time <b>%s</b> %s`
|
||||
issues.add_time_hours = Hours
|
||||
issues.add_time_minutes = Minutes
|
||||
issues.add_time_sum_to_small = No time was entered.
|
||||
issues.time_spent_total = Total Time Spent
|
||||
issues.time_spent_from_all_authors = `Total Time Spent: %s`
|
||||
issues.time_spent_from_all_authors = `Total Time Spent:`
|
||||
issues.due_date = Due Date
|
||||
issues.invalid_due_date_format = "Due date format must be 'yyyy-mm-dd'."
|
||||
issues.error_modifying_due_date = "Failed to modify the due date."
|
||||
|
|
|
@ -436,6 +436,7 @@ oauth_signin_submit=Vincular conta
|
|||
oauth.signin.error=Ocorreu um erro durante o processamento do pedido de autorização. Se este erro persistir, contacte o administrador.
|
||||
oauth.signin.error.access_denied=O pedido de autorização foi negado.
|
||||
oauth.signin.error.temporarily_unavailable=A autorização falhou porque o servidor de autenticação está temporariamente indisponível. Tente mais tarde.
|
||||
oauth_callback_unable_auto_reg=O registo automático está habilitado, mas o fornecedor OAuth2 %[1]s sinalizou campos em falta: %[2]s, por isso não foi possível criar uma conta automaticamente. Crie ou vincule uma conta ou contacte o administrador do sítio.
|
||||
openid_connect_submit=Estabelecer ligação
|
||||
openid_connect_title=Estabelecer ligação a uma conta existente
|
||||
openid_connect_desc=O URI do OpenID escolhido é desconhecido. Associe-o a uma nova conta aqui.
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 67 KiB |
|
@ -13,6 +13,7 @@ import (
|
|||
"math/big"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
@ -1771,6 +1772,9 @@ func ViewIssue(ctx *context.Context) {
|
|||
comment.Content = comment.Content[1:]
|
||||
}
|
||||
}
|
||||
} else if comment.Type == issues_model.CommentTypeChangeTimeEstimate {
|
||||
timeSec, _ := util.ToInt64(comment.Content)
|
||||
comment.Content = util.SecToTimeExact(timeSec, timeSec < 60)
|
||||
}
|
||||
|
||||
if comment.Type == issues_model.CommentTypeClose || comment.Type == issues_model.CommentTypeMergePull {
|
||||
|
@ -2208,6 +2212,57 @@ func UpdateIssueTitle(ctx *context.Context) {
|
|||
})
|
||||
}
|
||||
|
||||
// UpdateIssueTimeEstimate change issue's planned time
|
||||
var (
|
||||
rTimeEstimateStr = regexp.MustCompile(`^([\d]+w)?\s?([\d]+d)?\s?([\d]+h)?\s?([\d]+m)?$`)
|
||||
rTimeEstimateStrHoursOnly = regexp.MustCompile(`^([\d]+)$`)
|
||||
)
|
||||
|
||||
func UpdateIssueTimeEstimate(ctx *context.Context) {
|
||||
issue := GetActionIssue(ctx)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
if !ctx.IsSigned || (!issue.IsPoster(ctx.Doer.ID) && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)) {
|
||||
ctx.Error(http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
url := issue.Link()
|
||||
|
||||
timeStr := ctx.FormString("time_estimate")
|
||||
|
||||
// Validate input
|
||||
if !rTimeEstimateStr.MatchString(timeStr) && !rTimeEstimateStrHoursOnly.MatchString(timeStr) {
|
||||
ctx.Flash.Error(ctx.Tr("repo.issues.time_estimate_invalid"))
|
||||
ctx.Redirect(url, http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
total := util.TimeEstimateFromStr(timeStr)
|
||||
|
||||
// User entered something wrong
|
||||
if total == 0 && len(timeStr) != 0 {
|
||||
ctx.Flash.Error(ctx.Tr("repo.issues.time_estimate_invalid"))
|
||||
ctx.Redirect(url, http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
// No time changed
|
||||
if issue.TimeEstimate == total {
|
||||
ctx.Redirect(url, http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
if err := issue_service.ChangeTimeEstimate(issue, ctx.Doer, total); err != nil {
|
||||
ctx.ServerError("ChangeTimeEstimate", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Redirect(url, http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// UpdateIssueRef change issue's ref (branch)
|
||||
func UpdateIssueRef(ctx *context.Context) {
|
||||
issue := GetActionIssue(ctx)
|
||||
|
|
|
@ -34,7 +34,7 @@ func AddTimeManually(c *context.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
total := time.Duration(form.Hours)*time.Hour + time.Duration(form.Minutes)*time.Minute
|
||||
total := util.TimeEstimateFromStr(form.TimeString)
|
||||
|
||||
if total <= 0 {
|
||||
c.Flash.Error(c.Tr("repo.issues.add_time_sum_to_small"))
|
||||
|
@ -42,7 +42,7 @@ func AddTimeManually(c *context.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
if _, err := issues_model.AddTime(c, c.Doer, issue, int64(total.Seconds()), time.Now()); err != nil {
|
||||
if _, err := issues_model.AddTime(c, c.Doer, issue, total, time.Now()); err != nil {
|
||||
c.ServerError("AddTime", err)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1202,6 +1202,7 @@ func registerRoutes(m *web.Route) {
|
|||
m.Post("/cancel", repo.CancelStopwatch)
|
||||
})
|
||||
})
|
||||
m.Post("/time_estimate", repo.UpdateIssueTimeEstimate)
|
||||
m.Post("/reactions/{action}", web.Bind(forms.ReactionForm{}), repo.ChangeIssueReaction)
|
||||
m.Post("/lock", reqRepoIssuesOrPullsWriter, web.Bind(forms.IssueLockForm{}), repo.LockIssue)
|
||||
m.Post("/unlock", reqRepoIssuesOrPullsWriter, repo.UnlockIssue)
|
||||
|
|
|
@ -76,6 +76,11 @@ func ToTimelineComment(ctx context.Context, repo *repo_model.Repository, c *issu
|
|||
// so we check for the "|" delimeter and convert new to legacy format on demand
|
||||
c.Content = util.SecToTime(c.Content[1:])
|
||||
}
|
||||
|
||||
if c.Type == issues_model.CommentTypeChangeTimeEstimate {
|
||||
timeSec, _ := util.ToInt64(c.Content)
|
||||
c.Content = util.SecToTimeExact(timeSec, timeSec < 60)
|
||||
}
|
||||
}
|
||||
|
||||
comment := &api.TimelineComment{
|
||||
|
|
|
@ -877,8 +877,7 @@ func (f *DeleteRepoFileForm) Validate(req *http.Request, errs binding.Errors) bi
|
|||
|
||||
// AddTimeManuallyForm form that adds spent time manually.
|
||||
type AddTimeManuallyForm struct {
|
||||
Hours int `binding:"Range(0,1000)"`
|
||||
Minutes int `binding:"Range(0,1000)"`
|
||||
TimeString string
|
||||
}
|
||||
|
||||
// Validate validates the fields
|
||||
|
|
|
@ -43,6 +43,7 @@ var hiddenCommentTypeGroups = hiddenCommentTypeGroupsType{
|
|||
/*14*/ issues_model.CommentTypeAddTimeManual,
|
||||
/*15*/ issues_model.CommentTypeCancelTracking,
|
||||
/*26*/ issues_model.CommentTypeDeleteTimeManual,
|
||||
/*38*/ issues_model.CommentTypeChangeTimeEstimate,
|
||||
},
|
||||
"deadline": {
|
||||
/*16*/ issues_model.CommentTypeAddedDeadline,
|
||||
|
|
|
@ -9,8 +9,6 @@ import (
|
|||
"fmt"
|
||||
"html"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -23,64 +21,11 @@ import (
|
|||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/references"
|
||||
"code.gitea.io/gitea/modules/repository"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
const (
|
||||
secondsByMinute = float64(time.Minute / time.Second) // seconds in a minute
|
||||
secondsByHour = 60 * secondsByMinute // seconds in an hour
|
||||
secondsByDay = 8 * secondsByHour // seconds in a day
|
||||
secondsByWeek = 5 * secondsByDay // seconds in a week
|
||||
secondsByMonth = 4 * secondsByWeek // seconds in a month
|
||||
)
|
||||
|
||||
var reDuration = regexp.MustCompile(`(?i)^(?:(\d+([\.,]\d+)?)(?:mo))?(?:(\d+([\.,]\d+)?)(?:w))?(?:(\d+([\.,]\d+)?)(?:d))?(?:(\d+([\.,]\d+)?)(?:h))?(?:(\d+([\.,]\d+)?)(?:m))?$`)
|
||||
|
||||
// timeLogToAmount parses time log string and returns amount in seconds
|
||||
func timeLogToAmount(str string) int64 {
|
||||
matches := reDuration.FindAllStringSubmatch(str, -1)
|
||||
if len(matches) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
match := matches[0]
|
||||
|
||||
var a int64
|
||||
|
||||
// months
|
||||
if len(match[1]) > 0 {
|
||||
mo, _ := strconv.ParseFloat(strings.Replace(match[1], ",", ".", 1), 64)
|
||||
a += int64(mo * secondsByMonth)
|
||||
}
|
||||
|
||||
// weeks
|
||||
if len(match[3]) > 0 {
|
||||
w, _ := strconv.ParseFloat(strings.Replace(match[3], ",", ".", 1), 64)
|
||||
a += int64(w * secondsByWeek)
|
||||
}
|
||||
|
||||
// days
|
||||
if len(match[5]) > 0 {
|
||||
d, _ := strconv.ParseFloat(strings.Replace(match[5], ",", ".", 1), 64)
|
||||
a += int64(d * secondsByDay)
|
||||
}
|
||||
|
||||
// hours
|
||||
if len(match[7]) > 0 {
|
||||
h, _ := strconv.ParseFloat(strings.Replace(match[7], ",", ".", 1), 64)
|
||||
a += int64(h * secondsByHour)
|
||||
}
|
||||
|
||||
// minutes
|
||||
if len(match[9]) > 0 {
|
||||
d, _ := strconv.ParseFloat(strings.Replace(match[9], ",", ".", 1), 64)
|
||||
a += int64(d * secondsByMinute)
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
func issueAddTime(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, time time.Time, timeLog string) error {
|
||||
amount := timeLogToAmount(timeLog)
|
||||
amount := util.TimeEstimateFromStr(timeLog)
|
||||
if amount == 0 {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -105,6 +105,13 @@ func ChangeTitle(ctx context.Context, issue *issues_model.Issue, doer *user_mode
|
|||
return nil
|
||||
}
|
||||
|
||||
// ChangeTimeEstimate changes the time estimate of this issue, as the given user.
|
||||
func ChangeTimeEstimate(issue *issues_model.Issue, doer *user_model.User, timeEstimate int64) (err error) {
|
||||
issue.TimeEstimate = timeEstimate
|
||||
|
||||
return issues_model.ChangeIssueTimeEstimate(issue, doer, timeEstimate)
|
||||
}
|
||||
|
||||
// ChangeIssueRef changes the branch of this issue, as the given user.
|
||||
func ChangeIssueRef(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, ref string) error {
|
||||
oldRef := issue.Ref
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
{{end -}}
|
||||
{{- range .ReviewComments}}
|
||||
<hr>
|
||||
{{$.locale.Tr "mail.issue.in_tree_path" .TreePath}}
|
||||
{{ctx.Locale.Tr "mail.issue.in_tree_path" .TreePath}}
|
||||
<div class="review">
|
||||
<pre>{{.Patch}}</pre>
|
||||
<div>{{.RenderedContent}}</div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{{if $.IsSplitStyle}}
|
||||
{{range $k, $line := $.section.Lines}}
|
||||
<tr class="{{.GetHTMLDiffLineType}}-code nl-{{$k}} ol-{{$k}}">
|
||||
<tr class="{{.GetHTMLDiffLineType}}-code nl-{{$k}} ol-{{$k}} line-expanded">
|
||||
{{if eq .GetType 4}}
|
||||
<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}">
|
||||
<div class="tw-flex">
|
||||
|
@ -26,17 +26,17 @@
|
|||
{{else}}
|
||||
{{$inlineDiff := $.section.GetComputedInlineDiffFor $line ctx.Locale}}
|
||||
<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{$.FileNameHash}}L{{$line.LeftIdx}}{{end}}"></span></td>
|
||||
<td class="blob-excerpt lines-escape lines-escape-old">{{if and $line.LeftIdx $inlineDiff.EscapeStatus.Escaped}}<button class="toggle-escape-button btn interact-bg" title="{{template "repo/diff/escape_title" dict "diff" $inlineDiff}}"></button>{{end}}</td>
|
||||
<td class="blob-excerpt lines-type-marker lines-type-marker-old">{{if $line.LeftIdx}}<span class="tw-font-mono" data-type-marker=""></span>{{end}}</td>
|
||||
<td class="blob-excerpt lines-code lines-code-old">{{/*
|
||||
<td class="lines-escape lines-escape-old">{{if and $line.LeftIdx $inlineDiff.EscapeStatus.Escaped}}<button class="toggle-escape-button btn interact-bg" title="{{template "repo/diff/escape_title" dict "diff" $inlineDiff}}"></button>{{end}}</td>
|
||||
<td class="lines-type-marker lines-type-marker-old">{{if $line.LeftIdx}}<span class="tw-font-mono" data-type-marker=""></span>{{end}}</td>
|
||||
<td class="lines-code lines-code-old">{{/*
|
||||
*/}}{{if $line.LeftIdx}}{{template "repo/diff/section_code" dict "diff" $inlineDiff}}{{else}}{{/*
|
||||
*/}}<code class="code-inner"></code>{{/*
|
||||
*/}}{{end}}{{/*
|
||||
*/}}</td>
|
||||
<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{$.FileNameHash}}R{{$line.RightIdx}}{{end}}"></span></td>
|
||||
<td class="blob-excerpt lines-escape lines-escape-new">{{if and $line.RightIdx $inlineDiff.EscapeStatus.Escaped}}<button class="toggle-escape-button btn interact-bg" title="{{template "repo/diff/escape_title" dict "diff" $inlineDiff}}"></button>{{end}}</td>
|
||||
<td class="blob-excerpt lines-type-marker lines-type-marker-new">{{if $line.RightIdx}}<span class="tw-font-mono" data-type-marker=""></span>{{end}}</td>
|
||||
<td class="blob-excerpt lines-code lines-code-new">{{/*
|
||||
<td class="lines-escape lines-escape-new">{{if and $line.RightIdx $inlineDiff.EscapeStatus.Escaped}}<button class="toggle-escape-button btn interact-bg" title="{{template "repo/diff/escape_title" dict "diff" $inlineDiff}}"></button>{{end}}</td>
|
||||
<td class="lines-type-marker lines-type-marker-new">{{if $line.RightIdx}}<span class="tw-font-mono" data-type-marker=""></span>{{end}}</td>
|
||||
<td class="lines-code lines-code-new">{{/*
|
||||
*/}}{{if $line.RightIdx}}{{template "repo/diff/section_code" dict "diff" $inlineDiff}}{{else}}{{/*
|
||||
*/}}<code class="code-inner"></code>{{/*
|
||||
*/}}{{end}}{{/*
|
||||
|
@ -46,7 +46,7 @@
|
|||
{{end}}
|
||||
{{else}}
|
||||
{{range $k, $line := $.section.Lines}}
|
||||
<tr class="{{.GetHTMLDiffLineType}}-code nl-{{$k}} ol-{{$k}}">
|
||||
<tr class="{{.GetHTMLDiffLineType}}-code nl-{{$k}} ol-{{$k}} line-expanded">
|
||||
{{if eq .GetType 4}}
|
||||
<td colspan="2" class="lines-num">
|
||||
<div class="tw-flex">
|
||||
|
@ -72,9 +72,9 @@
|
|||
<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{$.FileNameHash}}R{{$line.RightIdx}}{{end}}"></span></td>
|
||||
{{end}}
|
||||
{{$inlineDiff := $.section.GetComputedInlineDiffFor $line ctx.Locale}}
|
||||
<td class="blob-excerpt lines-escape">{{if $inlineDiff.EscapeStatus.Escaped}}<button class="toggle-escape-button btn interact-bg" title="{{template "repo/diff/escape_title" dict "diff" $inlineDiff}}"></button>{{end}}</td>
|
||||
<td class="blob-excerpt lines-type-marker"><span class="tw-font-mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span></td>
|
||||
<td class="blob-excerpt lines-code{{if (not $line.RightIdx)}} lines-code-old{{end}}"><code {{if $inlineDiff.EscapeStatus.Escaped}}class="code-inner has-escaped" title="{{template "repo/diff/escape_title" dict "diff" $inlineDiff}}"{{else}}class="code-inner"{{end}}>{{$inlineDiff.Content}}</code></td>
|
||||
<td class="lines-escape">{{if $inlineDiff.EscapeStatus.Escaped}}<button class="toggle-escape-button btn interact-bg" title="{{template "repo/diff/escape_title" dict "diff" $inlineDiff}}"></button>{{end}}</td>
|
||||
<td class="lines-type-marker"><span class="tw-font-mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span></td>
|
||||
<td class="lines-code{{if (not $line.RightIdx)}} lines-code-old{{end}}"><code {{if $inlineDiff.EscapeStatus.Escaped}}class="code-inner has-escaped" title="{{template "repo/diff/escape_title" dict "diff" $inlineDiff}}"{{else}}class="code-inner"{{end}}>{{$inlineDiff.Content}}</code></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
26 = DELETE_TIME_MANUAL, 27 = REVIEW_REQUEST, 28 = MERGE_PULL_REQUEST,
|
||||
29 = PULL_PUSH_EVENT, 30 = PROJECT_CHANGED, 31 = PROJECT_BOARD_CHANGED
|
||||
32 = DISMISSED_REVIEW, 33 = COMMENT_TYPE_CHANGE_ISSUE_REF, 34 = PR_SCHEDULE_TO_AUTO_MERGE,
|
||||
35 = CANCEL_SCHEDULED_AUTO_MERGE_PR, 36 = PIN_ISSUE, 37 = UNPIN_ISSUE -->
|
||||
35 = CANCEL_SCHEDULED_AUTO_MERGE_PR, 36 = PIN_ISSUE, 37 = UNPIN_ISSUE,
|
||||
38 = COMMENT_TYPE_CHANGE_TIME_ESTIMATE -->
|
||||
{{if eq .Type 0}}
|
||||
<div class="timeline-item comment" id="{{.HashTag}}">
|
||||
{{if .OriginalAuthor}}
|
||||
|
@ -249,18 +250,18 @@
|
|||
{{template "shared/user/avatarlink" dict "user" .Poster}}
|
||||
<span class="text grey muted-links">
|
||||
{{template "shared/user/authorlink" .Poster}}
|
||||
{{ctx.Locale.Tr "repo.issues.stop_tracking_history" $createdStr}}
|
||||
</span>
|
||||
{{template "repo/issue/view_content/comments_delete_time" dict "ctxData" $ "comment" .}}
|
||||
<div class="detail flex-text-block">
|
||||
{{svg "octicon-clock"}}
|
||||
|
||||
{{$timeStr := ""}}
|
||||
{{if .RenderedContent}}
|
||||
{{/* compatibility with time comments made before v1.21 */}}
|
||||
<span class="text grey muted-links">{{.RenderedContent}}</span>
|
||||
{{$timeStr = .RenderedContent}}
|
||||
{{else}}
|
||||
<span class="text grey muted-links">{{.Content|Sec2Time}}</span>
|
||||
{{$timeStr = .Content|Sec2Time}}
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
{{ctx.Locale.Tr "repo.issues.stop_tracking_history" $timeStr $createdStr | SafeHTML}}
|
||||
</span>
|
||||
{{template "repo/issue/view_content/comments_delete_time" dict "ctxData" $ "comment" .}}
|
||||
</div>
|
||||
{{else if eq .Type 14}}
|
||||
<div class="timeline-item event" id="{{.HashTag}}">
|
||||
|
@ -268,18 +269,18 @@
|
|||
{{template "shared/user/avatarlink" dict "user" .Poster}}
|
||||
<span class="text grey muted-links">
|
||||
{{template "shared/user/authorlink" .Poster}}
|
||||
{{ctx.Locale.Tr "repo.issues.add_time_history" $createdStr}}
|
||||
</span>
|
||||
{{template "repo/issue/view_content/comments_delete_time" dict "ctxData" $ "comment" .}}
|
||||
<div class="detail flex-text-block">
|
||||
{{svg "octicon-clock"}}
|
||||
|
||||
{{$timeStr := ""}}
|
||||
{{if .RenderedContent}}
|
||||
{{/* compatibility with time comments made before v1.21 */}}
|
||||
<span class="text grey muted-links">{{.RenderedContent}}</span>
|
||||
{{$timeStr = .RenderedContent}}
|
||||
{{else}}
|
||||
<span class="text grey muted-links">{{.Content|Sec2Time}}</span>
|
||||
{{$timeStr = .Content|Sec2Time}}
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
{{ctx.Locale.Tr "repo.issues.add_time_history" $timeStr $createdStr | SafeHTML}}
|
||||
</span>
|
||||
{{template "repo/issue/view_content/comments_delete_time" dict "ctxData" $ "comment" .}}
|
||||
</div>
|
||||
{{else if eq .Type 15}}
|
||||
<div class="timeline-item event" id="{{.HashTag}}">
|
||||
|
@ -680,6 +681,15 @@
|
|||
{{else}}{{ctx.Locale.Tr "repo.issues.unpin_comment" $createdStr}}{{end}}
|
||||
</span>
|
||||
</div>
|
||||
{{else if eq .Type 38}}
|
||||
<div class="timeline-item event" id="{{.HashTag}}">
|
||||
<span class="badge">{{svg "octicon-clock"}}</span>
|
||||
{{template "shared/user/avatarlink" dict "Context" $.Context "user" .Poster}}
|
||||
<span class="text grey muted-links">
|
||||
{{template "shared/user/authorlink" .Poster}}
|
||||
{{ctx.Locale.Tr "repo.issues.change_time_estimate_at" .Content $createdStr | SafeHTML}}
|
||||
</span>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
|
|
@ -278,8 +278,22 @@
|
|||
{{end}}
|
||||
{{if .Repository.IsTimetrackerEnabled $.Context}}
|
||||
{{if and .CanUseTimetracker (not .Repository.IsArchived)}}
|
||||
<div class="divider"></div>
|
||||
<div class="ui timetrack">
|
||||
<div class="ui divider"></div>
|
||||
<div>
|
||||
<span class="text"><strong>{{ctx.Locale.Tr "repo.issues.time_estimate"}}</strong></span>
|
||||
|
||||
<form method="post" id="set_time_estimate_form" class="gt-mt-3" action="{{.Issue.Link}}/time_estimate">
|
||||
{{$.CsrfTokenHtml}}
|
||||
<div class="ui input fluid">
|
||||
<input name="time_estimate" placeholder='{{ctx.Locale.Tr "repo.issues.add_time_estimate"}}' value="{{TimeEstimateToStr .Issue.TimeEstimate}}" data-value="{{$.Issue.TimeEstimate}}" type="text" >
|
||||
</div>
|
||||
<button class="ui fluid button green tooltip tw-mt-1">
|
||||
{{ctx.Locale.Tr "repo.issues.save"}}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
<div class="ui timetrack">
|
||||
<span class="text"><strong>{{ctx.Locale.Tr "repo.issues.tracker"}}</strong></span>
|
||||
<div class="tw-mt-2">
|
||||
<form method="post" action="{{.Issue.Link}}/times/stopwatch/toggle" id="toggle_stopwatch_form">
|
||||
|
@ -311,9 +325,8 @@
|
|||
<div class="header">{{ctx.Locale.Tr "repo.issues.add_time"}}</div>
|
||||
<div class="content">
|
||||
<form method="post" id="add_time_manual_form" action="{{.Issue.Link}}/times/add" class="ui input fluid tw-gap-2">
|
||||
{{$.CsrfTokenHtml}}
|
||||
<input placeholder='{{ctx.Locale.Tr "repo.issues.add_time_hours"}}' type="number" name="hours">
|
||||
<input placeholder='{{ctx.Locale.Tr "repo.issues.add_time_minutes"}}' type="number" name="minutes" class="ui compact">
|
||||
{{$.CsrfTokenHtml}}
|
||||
<input placeholder='{{ctx.Locale.Tr "repo.issues.add_time_estimate"}}' type="text" name="time_string">
|
||||
</form>
|
||||
</div>
|
||||
<div class="actions">
|
||||
|
@ -332,8 +345,9 @@
|
|||
{{if .WorkingUsers}}
|
||||
<div class="divider"></div>
|
||||
<div class="ui comments">
|
||||
<span class="text"><strong>{{ctx.Locale.Tr "repo.issues.time_spent_from_all_authors" ($.Issue.TotalTrackedTime | Sec2Time)}}</strong></span>
|
||||
<div>
|
||||
<div class="text"><strong>{{ctx.Locale.Tr "repo.issues.time_spent_from_all_authors" | SafeHTML}}</strong></div>
|
||||
<div>{{SecToTimeExact .Issue.TotalTrackedTime false}}</div>
|
||||
<div class="gt-mt-3">
|
||||
{{range $user, $trackedtime := .WorkingUsers}}
|
||||
<div class="comment tw-mt-2">
|
||||
<a class="avatar">
|
||||
|
|
|
@ -73,8 +73,7 @@ func testViewTimetrackingControls(t *testing.T, session *TestSession, user, repo
|
|||
htmlDoc = NewHTMLParser(t, resp.Body)
|
||||
|
||||
events = htmlDoc.doc.Find(".event > span.text")
|
||||
assert.Contains(t, events.Last().Text(), "stopped working")
|
||||
htmlDoc.AssertElement(t, ".event .detail .octicon-clock", true)
|
||||
assert.Contains(t, events.Last().Text(), "worked for ")
|
||||
} else {
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
||||
|
|
|
@ -2377,7 +2377,7 @@ tbody.commit-list {
|
|||
|
||||
.tag-code,
|
||||
.tag-code td,
|
||||
.tag-code .blob-excerpt {
|
||||
.tag-code.line-expanded {
|
||||
background-color: var(--color-box-body-highlight);
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
@ -2393,8 +2393,8 @@ tbody.commit-list {
|
|||
padding-top: 0 !important;
|
||||
}
|
||||
|
||||
.blob-excerpt {
|
||||
background-color: var(--color-secondary-alpha-30);
|
||||
.line-expanded {
|
||||
background-color: var(--color-secondary-alpha-20);
|
||||
}
|
||||
|
||||
.issue-keyword {
|
||||
|
@ -2553,11 +2553,9 @@ tbody.commit-list {
|
|||
|
||||
.code-diff-unified .add-code,
|
||||
.code-diff-unified .add-code td,
|
||||
.code-diff-split .add-code .lines-num-new,
|
||||
.code-diff-split .add-code .lines-type-marker-new,
|
||||
.code-diff-split .add-code .lines-escape-new,
|
||||
.code-diff-split .add-code .lines-code-new,
|
||||
.code-diff-split .del-code .add-code.lines-num-new,
|
||||
.code-diff-split .del-code .add-code.lines-type-marker-new,
|
||||
.code-diff-split .del-code .add-code.lines-escape-new,
|
||||
.code-diff-split .del-code .add-code.lines-code-new {
|
||||
|
@ -2565,17 +2563,33 @@ tbody.commit-list {
|
|||
border-color: var(--color-diff-added-row-border);
|
||||
}
|
||||
|
||||
.code-diff-split .del-code .lines-num-new,
|
||||
.code-diff-split .del-code .lines-type-marker-new,
|
||||
.code-diff-split .del-code .lines-code-new,
|
||||
.code-diff-split .del-code .lines-escape-new,
|
||||
.code-diff-split .add-code .lines-num-old,
|
||||
.code-diff-split .add-code .lines-escape-old,
|
||||
.code-diff-split .add-code .lines-type-marker-old,
|
||||
.code-diff-split .add-code .lines-code-old {
|
||||
background: var(--color-diff-inactive);
|
||||
}
|
||||
|
||||
.code-diff-split .add-code .lines-num.lines-num-old,
|
||||
.code-diff-split .del-code .lines-num.lines-num-new {
|
||||
background: var(--color-diff-inactive);
|
||||
}
|
||||
|
||||
.code-diff-unified .del-code .lines-num,
|
||||
.code-diff-split .del-code .lines-num {
|
||||
background: var(--color-diff-removed-linenum-bg);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.code-diff-unified .add-code .lines-num,
|
||||
.code-diff-split .add-code .lines-num,
|
||||
.code-diff-split .del-code .add-code.lines-num {
|
||||
background: var(--color-diff-added-linenum-bg);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.code-diff-split tbody tr td:nth-child(5),
|
||||
.code-diff-split tbody tr td.add-comment-right {
|
||||
border-left: 1px solid var(--color-secondary);
|
||||
|
|
|
@ -3,9 +3,10 @@
|
|||
/* red/green colorblind-friendly colors */
|
||||
/* from GitHub: --diffBlob-addition-*, --diffBlob-deletion-*, etc */
|
||||
:root {
|
||||
--color-diff-added-word-bg: #388bfd66;
|
||||
--color-diff-added-row-bg: #388bfd26;
|
||||
|
||||
--color-diff-removed-word-bg: #db6d2866;
|
||||
--color-diff-removed-row-bg: #db6d2826;
|
||||
--color-diff-added-linenum-bg: #1979fd46;
|
||||
--color-diff-added-row-bg: #1979fd20;
|
||||
--color-diff-added-word-bg: #1979fd66;
|
||||
--color-diff-removed-linenum-bg: #c8622146;
|
||||
--color-diff-removed-row-bg: #c8622120;
|
||||
--color-diff-removed-word-bg: #c8622166;
|
||||
}
|
||||
|
|
|
@ -143,14 +143,16 @@
|
|||
--color-grey-light: #818f9e;
|
||||
--color-gold: #b1983b;
|
||||
--color-white: #ffffff;
|
||||
--color-diff-removed-word-bg: #6f3333;
|
||||
--color-diff-added-word-bg: #3c653c;
|
||||
--color-diff-removed-row-bg: #3c2626;
|
||||
--color-diff-moved-row-bg: #818044;
|
||||
--color-diff-added-row-bg: #283e2d;
|
||||
--color-diff-removed-row-border: #634343;
|
||||
--color-diff-moved-row-border: #bcca6f;
|
||||
--color-diff-added-linenum-bg: #274227;
|
||||
--color-diff-added-row-bg: #203224;
|
||||
--color-diff-added-row-border: #314a37;
|
||||
--color-diff-added-word-bg: #3c653c;
|
||||
--color-diff-moved-row-bg: #818044;
|
||||
--color-diff-moved-row-border: #bcca6f;
|
||||
--color-diff-removed-linenum-bg: #482121;
|
||||
--color-diff-removed-row-bg: #301e1e;
|
||||
--color-diff-removed-row-border: #634343;
|
||||
--color-diff-removed-word-bg: #6f3333;
|
||||
--color-diff-inactive: #22282d;
|
||||
--color-error-border: #a04141;
|
||||
--color-error-bg: #522;
|
||||
|
|
|
@ -3,9 +3,10 @@
|
|||
/* red/green colorblind-friendly colors */
|
||||
/* from GitHub: --diffBlob-addition-*, --diffBlob-deletion-*, etc */
|
||||
:root {
|
||||
--color-diff-added-word-bg: #54aeff66;
|
||||
--color-diff-added-linenum-bg: #54aeff4d;
|
||||
--color-diff-added-row-bg: #ddf4ff80;
|
||||
|
||||
--color-diff-removed-word-bg: #ffb77c80;
|
||||
--color-diff-added-word-bg: #54aeff66;
|
||||
--color-diff-removed-linenum-bg: #ffb77c4d;
|
||||
--color-diff-removed-row-bg: #fff1e580;
|
||||
--color-diff-removed-word-bg: #ffb77c80;
|
||||
}
|
||||
|
|
|
@ -143,14 +143,16 @@
|
|||
--color-grey-light: #7c838a;
|
||||
--color-gold: #a1882b;
|
||||
--color-white: #ffffff;
|
||||
--color-diff-removed-word-bg: #fdb8c0;
|
||||
--color-diff-added-word-bg: #acf2bd;
|
||||
--color-diff-removed-row-bg: #ffeef0;
|
||||
--color-diff-moved-row-bg: #f1f8d1;
|
||||
--color-diff-added-linenum-bg: #d1f8d9;
|
||||
--color-diff-added-row-bg: #e6ffed;
|
||||
--color-diff-removed-row-border: #f1c0c0;
|
||||
--color-diff-moved-row-border: #d0e27f;
|
||||
--color-diff-added-row-border: #e6ffed;
|
||||
--color-diff-added-word-bg: #acf2bd;
|
||||
--color-diff-moved-row-bg: #f1f8d1;
|
||||
--color-diff-moved-row-border: #d0e27f;
|
||||
--color-diff-removed-linenum-bg: #ffcecb;
|
||||
--color-diff-removed-row-bg: #ffeef0;
|
||||
--color-diff-removed-row-border: #f1c0c0;
|
||||
--color-diff-removed-word-bg: #fdb8c0;
|
||||
--color-diff-inactive: #f0f2f4;
|
||||
--color-error-border: #e0b4b4;
|
||||
--color-error-bg: #fff6f6;
|
||||
|
|
Loading…
Reference in New Issue