]> source.dussan.org Git - gitea.git/commitdiff
Add UI to delete tracked times (#14100)
authorNorwin <noerw@users.noreply.github.com>
Fri, 19 Feb 2021 10:52:11 +0000 (10:52 +0000)
committerGitHub <noreply@github.com>
Fri, 19 Feb 2021 10:52:11 +0000 (12:52 +0200)
Co-authored-by: 6543 <6543@obermui.de>
13 files changed:
models/issue_comment.go
models/issue_stopwatch.go
models/issue_tracked_time.go
models/migrations/migrations.go
models/migrations/v173.go [new file with mode: 0644]
options/locale/locale_en-US.ini
routers/repo/issue.go
routers/repo/issue_timetrack.go
routers/routes/web.go
templates/repo/issue/view_content/comments.tmpl
templates/repo/issue/view_content/comments_delete_time.tmpl [new file with mode: 0644]
templates/repo/issue/view_content/sidebar.tmpl
web_src/js/index.js

index b15b5169ff4c4582b03df26613773b79c8179779..6cc03ba0e8afd5c1e89fd1340ecc8ab97ed26d87 100644 (file)
@@ -136,6 +136,8 @@ type Comment struct {
        MilestoneID      int64
        OldMilestone     *Milestone `xorm:"-"`
        Milestone        *Milestone `xorm:"-"`
+       TimeID           int64
+       Time             *TrackedTime `xorm:"-"`
        AssigneeID       int64
        RemovedAssignee  bool
        Assignee         *User `xorm:"-"`
@@ -541,6 +543,16 @@ func (c *Comment) LoadDepIssueDetails() (err error) {
        return err
 }
 
+// LoadTime loads the associated time for a CommentTypeAddTimeManual
+func (c *Comment) LoadTime() error {
+       if c.Time != nil || c.TimeID == 0 {
+               return nil
+       }
+       var err error
+       c.Time, err = GetTrackedTimeByID(c.TimeID)
+       return err
+}
+
 func (c *Comment) loadReactions(e Engine, repo *Repository) (err error) {
        if c.Reactions != nil {
                return nil
@@ -692,6 +704,7 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
                MilestoneID:      opts.MilestoneID,
                OldProjectID:     opts.OldProjectID,
                ProjectID:        opts.ProjectID,
+               TimeID:           opts.TimeID,
                RemovedAssignee:  opts.RemovedAssignee,
                AssigneeID:       opts.AssigneeID,
                AssigneeTeamID:   opts.AssigneeTeamID,
@@ -859,6 +872,7 @@ type CreateCommentOptions struct {
        MilestoneID      int64
        OldProjectID     int64
        ProjectID        int64
+       TimeID           int64
        AssigneeID       int64
        AssigneeTeamID   int64
        RemovedAssignee  bool
index a1c88503d89907e7e2796943831d5a7313700f8a..19bd4ab2c569f0a659f4d57f288fc5e80a42780e 100644 (file)
@@ -100,6 +100,7 @@ func CreateOrStopIssueStopwatch(user *User, issue *Issue) error {
                        Repo:    issue.Repo,
                        Content: SecToTime(timediff),
                        Type:    CommentTypeStopTracking,
+                       TimeID:  tt.ID,
                }); err != nil {
                        return err
                }
index 195f3e785034bad0f227af3ec6709a0ea83d01a1..9717944cbb38f2fdef0ffcf03c00a07ed022705c 100644 (file)
@@ -162,6 +162,7 @@ func AddTime(user *User, issue *Issue, amount int64, created time.Time) (*Tracke
                Doer:    user,
                Content: SecToTime(amount),
                Type:    CommentTypeAddTimeManual,
+               TimeID:  t.ID,
        }); err != nil {
                return nil, err
        }
index 740e8cb3ee977bf7f7e490178cb78f511d67ef91..4fc737e1bfe420858ff66e27e4aff84cdb30346f 100644 (file)
@@ -292,6 +292,8 @@ var migrations = []Migration{
        NewMigration("Add Sorting to ProjectBoard table", addSortingColToProjectBoard),
        // v172 -> v173
        NewMigration("Add sessions table for go-chi/session", addSessionTable),
+       // v173 -> v174
+       NewMigration("Add time_id column to Comment", addTimeIDCommentColumn),
 }
 
 // GetCurrentDBVersion returns the current db version
diff --git a/models/migrations/v173.go b/models/migrations/v173.go
new file mode 100644 (file)
index 0000000..dd45890
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2021 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package migrations
+
+import (
+       "fmt"
+
+       "xorm.io/xorm"
+)
+
+func addTimeIDCommentColumn(x *xorm.Engine) error {
+       type Comment struct {
+               TimeID int64
+       }
+
+       if err := x.Sync2(new(Comment)); err != nil {
+               return fmt.Errorf("Sync2: %v", err)
+       }
+       return nil
+}
index ec9f82ef0344f9663b963db5cb64a4af91652631..2690303253343884ed64c63073669428d798bff3 100644 (file)
@@ -1163,6 +1163,7 @@ issues.stop_tracking_history = `stopped working %s`
 issues.cancel_tracking = Discard
 issues.cancel_tracking_history = `cancelled 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`
index fa1ee9977165ac1804dab9ee9c4975932424a86a..a9459a10ed93dbe2c8ccb282384b807920d95b3e 100644 (file)
@@ -1416,6 +1416,10 @@ func ViewIssue(ctx *context.Context) {
                                ctx.ServerError("LoadPushCommits", err)
                                return
                        }
+               } else if comment.Type == models.CommentTypeAddTimeManual ||
+                       comment.Type == models.CommentTypeStopTracking {
+                       // drop error since times could be pruned from DB..
+                       _ = comment.LoadTime()
                }
        }
 
index 425f21511052611cbc28529a2a215252771ebbf0..3b13770d61dcb4b0d78ca5c589c0b4367f7a2c4c 100644 (file)
@@ -10,13 +10,13 @@ import (
 
        "code.gitea.io/gitea/models"
        "code.gitea.io/gitea/modules/context"
-       auth "code.gitea.io/gitea/modules/forms"
+       "code.gitea.io/gitea/modules/forms"
        "code.gitea.io/gitea/modules/web"
 )
 
 // AddTimeManually tracks time manually
 func AddTimeManually(c *context.Context) {
-       form := web.GetForm(c).(*auth.AddTimeManuallyForm)
+       form := web.GetForm(c).(*forms.AddTimeManuallyForm)
        issue := GetActionIssue(c)
        if c.Written() {
                return
@@ -48,3 +48,39 @@ func AddTimeManually(c *context.Context) {
 
        c.Redirect(url, http.StatusSeeOther)
 }
+
+// DeleteTime deletes tracked time
+func DeleteTime(c *context.Context) {
+       issue := GetActionIssue(c)
+       if c.Written() {
+               return
+       }
+       if !c.Repo.CanUseTimetracker(issue, c.User) {
+               c.NotFound("CanUseTimetracker", nil)
+               return
+       }
+
+       t, err := models.GetTrackedTimeByID(c.ParamsInt64(":timeid"))
+       if err != nil {
+               if models.IsErrNotExist(err) {
+                       c.NotFound("time not found", err)
+                       return
+               }
+               c.Error(http.StatusInternalServerError, "GetTrackedTimeByID", err.Error())
+               return
+       }
+
+       // only OP or admin may delete
+       if !c.IsSigned || (!c.IsUserSiteAdmin() && c.User.ID != t.UserID) {
+               c.Error(http.StatusForbidden, "not allowed")
+               return
+       }
+
+       if err = models.DeleteTime(t); err != nil {
+               c.ServerError("DeleteTime", err)
+               return
+       }
+
+       c.Flash.Success(c.Tr("repo.issues.del_time_history", models.SecToTime(t.Time)))
+       c.Redirect(issue.HTMLURL())
+}
index b3edd8f71359c5fbb332f30a52795f515294b053..dd43663e350519d818f42c1409c306b7f0ef570a 100644 (file)
@@ -723,6 +723,7 @@ func RegisterRoutes(m *web.Route) {
                                m.Combo("/comments").Post(repo.MustAllowUserComment, bindIgnErr(auth.CreateCommentForm{}), repo.NewComment)
                                m.Group("/times", func() {
                                        m.Post("/add", bindIgnErr(auth.AddTimeManuallyForm{}), repo.AddTimeManually)
+                                       m.Post("/{timeid}/delete", repo.DeleteTime)
                                        m.Group("/stopwatch", func() {
                                                m.Post("/toggle", repo.IssueStopwatch)
                                                m.Post("/cancel", repo.CancelStopwatch)
index b971c6b1ae69d282973b823288a599d69279b9ff..cfacde96486fec74f9fe79ed87c9812bc244dc7e 100644 (file)
                                <a class="author" href="{{.Poster.HomeLink}}">{{.Poster.GetDisplayName}}</a>
                                {{$.i18n.Tr "repo.issues.stop_tracking_history"  $createdStr | Safe}}
                        </span>
+                       {{ template "repo/issue/view_content/comments_delete_time" Dict "ctx" $ "comment" . }}
                        <div class="detail">
                                {{svg "octicon-clock"}}
                                <span class="text grey">{{.Content}}</span>
                                <a class="author" href="{{.Poster.HomeLink}}">{{.Poster.GetDisplayName}}</a>
                                {{$.i18n.Tr "repo.issues.add_time_history"  $createdStr | Safe}}
                        </span>
+                       {{ template "repo/issue/view_content/comments_delete_time" Dict "ctx" $ "comment" . }}
                        <div class="detail">
                                {{svg "octicon-clock"}}
                                <span class="text grey">{{.Content}}</span>
diff --git a/templates/repo/issue/view_content/comments_delete_time.tmpl b/templates/repo/issue/view_content/comments_delete_time.tmpl
new file mode 100644 (file)
index 0000000..a28d222
--- /dev/null
@@ -0,0 +1,21 @@
+{{ if .comment.Time }} {{/* compatibility with time comments made before v1.14 */}}
+       {{ if (not .comment.Time.Deleted) }}
+               {{ if (or .ctx.IsAdmin (and .ctx.IsSigned (eq .ctx.SignedUserID .comment.PosterID))) }}
+                       <span class="ui float right">
+                               <div class="ui mini modal issue-delete-time-modal" data-id="{{.comment.Time.ID}}">
+                                       <form method="POST" class="delete-time-form" action="{{.ctx.RepoLink}}/issues/{{.ctx.Issue.Index}}/times/{{.comment.TimeID}}/delete">
+                                               {{.ctx.CsrfTokenHtml}}
+                                       </form>
+                                       <div class="header">{{.ctx.i18n.Tr "repo.issues.del_time"}}</div>
+                                       <div class="actions">
+                                               <div class="ui red approve button">{{.ctx.i18n.Tr "repo.issues.context.delete"}}</div>
+                                               <div class="ui cancel button">{{.ctx.i18n.Tr "repo.issues.add_time_cancel"}}</div>
+                                       </div>
+                               </div>
+                               <button class="ui icon button compact mini issue-delete-time poping up" data-id="{{.comment.Time.ID}}" data-content="{{.ctx.i18n.Tr "repo.issues.del_time"}}" data-position="top right" data-variation="tiny inverted">
+                                       {{svg "octicon-trashcan"}}
+                               </button>
+                       </span>
+               {{end}}
+       {{end}}
+{{end}}
index 3a21a9271b2a2b264498418fef527e1e3a7dffd9..9df7d7ed44e2ed99abb79efa614267b9b4dd0037 100644 (file)
                                                        {{end}}
                                                        <div class="ui buttons two fluid">
                                                                <button class="ui button poping up issue-start-time" data-content='{{.i18n.Tr "repo.issues.start_tracking"}}' data-position="top center" data-variation="small inverted">{{.i18n.Tr "repo.issues.start_tracking_short"}}</button>
-                                                               <div class="ui mini modal">
+                                                               <div class="ui mini modal issue-start-time-modal">
                                                                        <div class="header">{{.i18n.Tr "repo.issues.add_time"}}</div>
                                                                        <div class="content">
                                                                                <form method="POST" id="add_time_manual_form" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/times/add" class="ui action input fluid">
index c67b3c809bb2f1e23703de510e2d339d0d08a526..848c88bb1f6bd8bf72ec6e55cbe3b3d688731c1a 100644 (file)
@@ -3203,12 +3203,17 @@ function initVueApp() {
 
 function initIssueTimetracking() {
   $(document).on('click', '.issue-add-time', () => {
-    $('.mini.modal').modal({
+    $('.issue-start-time-modal').modal({
       duration: 200,
       onApprove() {
         $('#add_time_manual_form').trigger('submit');
       }
     }).modal('show');
+    $('.issue-start-time-modal input').on('keydown', (e) => {
+      if ((e.keyCode || e.key) === 13) {
+        $('#add_time_manual_form').trigger('submit');
+      }
+    });
   });
   $(document).on('click', '.issue-start-time, .issue-stop-time', () => {
     $('#toggle_stopwatch_form').trigger('submit');
@@ -3216,6 +3221,15 @@ function initIssueTimetracking() {
   $(document).on('click', '.issue-cancel-time', () => {
     $('#cancel_stopwatch_form').trigger('submit');
   });
+  $(document).on('click', 'button.issue-delete-time', function () {
+    const sel = `.issue-delete-time-modal[data-id="${$(this).data('id')}"]`;
+    $(sel).modal({
+      duration: 200,
+      onApprove() {
+        $(`${sel} form`).trigger('submit');
+      }
+    }).modal('show');
+  });
 }
 
 function initFilterBranchTagDropdown(selector) {