From 24b83ff63e7ffd3d412bc9b509102aa2c507ced1 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 4 Nov 2024 23:46:40 -0800 Subject: [PATCH] Fix milestone deadline and date related problems (#32339) Use zero instead of 9999-12-31 for deadline Fix #32291 --------- Co-authored-by: wxiaoguang Co-authored-by: Giteabot --- models/actions/schedule_spec_test.go | 8 ++- models/issues/milestone.go | 3 +- models/migrations/migrations.go | 1 + models/migrations/v1_23/v307.go | 21 ++++++++ modules/gitgraph/graph.go | 2 +- modules/gitgraph/graph_models.go | 13 ++++- modules/templates/util_date.go | 2 +- routers/api/v1/repo/issue.go | 12 ++--- routers/api/v1/repo/milestone.go | 14 +++-- routers/common/deadline.go | 31 +++++++++++ routers/web/repo/issue.go | 15 ++---- routers/web/repo/milestone.go | 21 +++----- routers/web/web.go | 2 +- services/convert/issue.go | 2 +- templates/repo/graph/commits.tmpl | 2 +- templates/repo/issue/milestone_new.tmpl | 4 +- .../repo/issue/view_content/sidebar.tmpl | 53 +++++++------------ tests/integration/api_issue_milestone_test.go | 2 + tests/integration/issue_test.go | 25 ++++----- web_src/js/features/repo-issue-sidebar.ts | 15 ++++++ web_src/js/features/repo-issue.ts | 46 ---------------- web_src/js/features/repo-milestone.ts | 16 +++--- web_src/js/index.ts | 2 - 23 files changed, 147 insertions(+), 165 deletions(-) create mode 100644 models/migrations/v1_23/v307.go create mode 100644 routers/common/deadline.go diff --git a/models/actions/schedule_spec_test.go b/models/actions/schedule_spec_test.go index 0c26fce4b2..57221461df 100644 --- a/models/actions/schedule_spec_test.go +++ b/models/actions/schedule_spec_test.go @@ -7,19 +7,17 @@ import ( "testing" "time" + "code.gitea.io/gitea/modules/test" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestActionScheduleSpec_Parse(t *testing.T) { // Mock the local timezone is not UTC - local := time.Local tz, err := time.LoadLocation("Asia/Shanghai") require.NoError(t, err) - defer func() { - time.Local = local - }() - time.Local = tz + defer test.MockVariableValue(&time.Local, tz)() now, err := time.Parse(time.RFC3339, "2024-07-31T15:47:55+08:00") require.NoError(t, err) diff --git a/models/issues/milestone.go b/models/issues/milestone.go index db0312adf0..4c9bae58f7 100644 --- a/models/issues/milestone.go +++ b/models/issues/milestone.go @@ -84,10 +84,9 @@ func (m *Milestone) BeforeUpdate() { // this object. func (m *Milestone) AfterLoad() { m.NumOpenIssues = m.NumIssues - m.NumClosedIssues - if m.DeadlineUnix.Year() == 9999 { + if m.DeadlineUnix == 0 { return } - m.DeadlineString = m.DeadlineUnix.FormatDate() if m.IsClosed { m.IsOverdue = m.ClosedDateUnix >= m.DeadlineUnix diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index ddf20d9542..41f337b838 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -364,6 +364,7 @@ func prepareMigrationTasks() []*migration { newMigration(304, "Add index for release sha1", v1_23.AddIndexForReleaseSha1), newMigration(305, "Add Repository Licenses", v1_23.AddRepositoryLicenses), newMigration(306, "Add BlockAdminMergeOverride to ProtectedBranch", v1_23.AddBlockAdminMergeOverrideBranchProtection), + newMigration(307, "Fix milestone deadline_unix when there is no due date", v1_23.FixMilestoneNoDueDate), } return preparedMigrations } diff --git a/models/migrations/v1_23/v307.go b/models/migrations/v1_23/v307.go new file mode 100644 index 0000000000..ef7f5f2c3f --- /dev/null +++ b/models/migrations/v1_23/v307.go @@ -0,0 +1,21 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_23 //nolint + +import ( + "code.gitea.io/gitea/modules/timeutil" + + "xorm.io/xorm" +) + +func FixMilestoneNoDueDate(x *xorm.Engine) error { + type Milestone struct { + DeadlineUnix timeutil.TimeStamp + } + // Wednesday, December 1, 9999 12:00:00 AM GMT+00:00 + _, err := x.Table("milestone").Where("deadline_unix > 253399622400"). + Cols("deadline_unix"). + Update(&Milestone{DeadlineUnix: 0}) + return err +} diff --git a/modules/gitgraph/graph.go b/modules/gitgraph/graph.go index 331ad6b218..7e12be030f 100644 --- a/modules/gitgraph/graph.go +++ b/modules/gitgraph/graph.go @@ -32,7 +32,7 @@ func GetCommitGraph(r *git.Repository, page, maxAllowedColors int, hidePRRefs bo graphCmd.AddArguments("--all") } - graphCmd.AddArguments("-C", "-M", "--date=iso"). + graphCmd.AddArguments("-C", "-M", "--date=iso-strict"). AddOptionFormat("-n %d", setting.UI.GraphMaxCommitNum*page). AddOptionFormat("--pretty=format:%s", format) diff --git a/modules/gitgraph/graph_models.go b/modules/gitgraph/graph_models.go index e48fef8b9d..191b0b3afc 100644 --- a/modules/gitgraph/graph_models.go +++ b/modules/gitgraph/graph_models.go @@ -8,6 +8,7 @@ import ( "context" "fmt" "strings" + "time" asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/db" @@ -192,6 +193,14 @@ var RelationCommit = &Commit{ Row: -1, } +func parseGitTime(timeStr string) time.Time { + t, err := time.Parse(time.RFC3339, timeStr) + if err != nil { + return time.Unix(0, 0) + } + return t +} + // NewCommit creates a new commit from a provided line func NewCommit(row, column int, line []byte) (*Commit, error) { data := bytes.SplitN(line, []byte("|"), 5) @@ -206,7 +215,7 @@ func NewCommit(row, column int, line []byte) (*Commit, error) { // 1 matches git log --pretty=format:%H => commit hash Rev: string(data[1]), // 2 matches git log --pretty=format:%ad => author date (format respects --date= option) - Date: string(data[2]), + Date: parseGitTime(string(data[2])), // 3 matches git log --pretty=format:%h => abbreviated commit hash ShortRev: string(data[3]), // 4 matches git log --pretty=format:%s => subject @@ -245,7 +254,7 @@ type Commit struct { Column int Refs []git.Reference Rev string - Date string + Date time.Time ShortRev string Subject string } diff --git a/modules/templates/util_date.go b/modules/templates/util_date.go index 4a794e6f30..66f83d23fe 100644 --- a/modules/templates/util_date.go +++ b/modules/templates/util_date.go @@ -27,7 +27,7 @@ func (du *DateUtils) AbsoluteShort(time any) template.HTML { // AbsoluteLong renders in "January 01, 2006" format func (du *DateUtils) AbsoluteLong(time any) template.HTML { - return dateTimeFormat("short", time) + return dateTimeFormat("long", time) } // FullTime renders in "Jan 01, 2006 20:33:44" format diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index e86fb3ccb1..cbe709c030 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -26,6 +26,7 @@ import ( "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/routers/common" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" issue_service "code.gitea.io/gitea/services/issue" @@ -1046,18 +1047,11 @@ func UpdateIssueDeadline(ctx *context.APIContext) { return } - var deadlineUnix timeutil.TimeStamp - var deadline time.Time - if form.Deadline != nil && !form.Deadline.IsZero() { - deadline = time.Date(form.Deadline.Year(), form.Deadline.Month(), form.Deadline.Day(), - 23, 59, 59, 0, time.Local) - deadlineUnix = timeutil.TimeStamp(deadline.Unix()) - } - + deadlineUnix, _ := common.ParseAPIDeadlineToEndOfDay(form.Deadline) if err := issues_model.UpdateIssueDeadline(ctx, issue, deadlineUnix, ctx.Doer); err != nil { ctx.Error(http.StatusInternalServerError, "UpdateIssueDeadline", err) return } - ctx.JSON(http.StatusCreated, api.IssueDeadline{Deadline: &deadline}) + ctx.JSON(http.StatusCreated, api.IssueDeadline{Deadline: deadlineUnix.AsTimePtr()}) } diff --git a/routers/api/v1/repo/milestone.go b/routers/api/v1/repo/milestone.go index abe9e4006a..78907c85a5 100644 --- a/routers/api/v1/repo/milestone.go +++ b/routers/api/v1/repo/milestone.go @@ -7,7 +7,6 @@ package repo import ( "net/http" "strconv" - "time" "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" @@ -16,6 +15,7 @@ import ( "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/routers/common" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) @@ -155,16 +155,16 @@ func CreateMilestone(ctx *context.APIContext) { // "$ref": "#/responses/notFound" form := web.GetForm(ctx).(*api.CreateMilestoneOption) - if form.Deadline == nil { - defaultDeadline, _ := time.ParseInLocation("2006-01-02", "9999-12-31", time.Local) - form.Deadline = &defaultDeadline + var deadlineUnix int64 + if form.Deadline != nil { + deadlineUnix = form.Deadline.Unix() } milestone := &issues_model.Milestone{ RepoID: ctx.Repo.Repository.ID, Name: form.Title, Content: form.Description, - DeadlineUnix: timeutil.TimeStamp(form.Deadline.Unix()), + DeadlineUnix: timeutil.TimeStamp(deadlineUnix), } if form.State == "closed" { @@ -225,9 +225,7 @@ func EditMilestone(ctx *context.APIContext) { if form.Description != nil { milestone.Content = *form.Description } - if form.Deadline != nil && !form.Deadline.IsZero() { - milestone.DeadlineUnix = timeutil.TimeStamp(form.Deadline.Unix()) - } + milestone.DeadlineUnix, _ = common.ParseAPIDeadlineToEndOfDay(form.Deadline) oldIsClosed := milestone.IsClosed if form.State != nil { diff --git a/routers/common/deadline.go b/routers/common/deadline.go new file mode 100644 index 0000000000..152e94597b --- /dev/null +++ b/routers/common/deadline.go @@ -0,0 +1,31 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package common + +import ( + "time" + + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/timeutil" +) + +func ParseDeadlineDateToEndOfDay(date string) (timeutil.TimeStamp, error) { + if date == "" { + return 0, nil + } + deadline, err := time.ParseInLocation("2006-01-02", date, setting.DefaultUILocation) + if err != nil { + return 0, err + } + deadline = time.Date(deadline.Year(), deadline.Month(), deadline.Day(), 23, 59, 59, 0, deadline.Location()) + return timeutil.TimeStamp(deadline.Unix()), nil +} + +func ParseAPIDeadlineToEndOfDay(t *time.Time) (timeutil.TimeStamp, error) { + if t == nil || t.IsZero() || t.Unix() == 0 { + return 0, nil + } + deadline := time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 0, setting.DefaultUILocation) + return timeutil.TimeStamp(deadline.Unix()), nil +} diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 93e2b5e748..1ee6e98afb 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -17,7 +17,6 @@ import ( "sort" "strconv" "strings" - "time" activities_model "code.gitea.io/gitea/models/activities" "code.gitea.io/gitea/models/db" @@ -45,9 +44,9 @@ import ( api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/templates/vars" - "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/routers/common" "code.gitea.io/gitea/routers/utils" shared_user "code.gitea.io/gitea/routers/web/shared/user" asymkey_service "code.gitea.io/gitea/services/asymkey" @@ -2329,7 +2328,6 @@ func UpdateIssueContent(ctx *context.Context) { // UpdateIssueDeadline updates an issue deadline func UpdateIssueDeadline(ctx *context.Context) { - form := web.GetForm(ctx).(*api.EditDeadlineOption) issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { @@ -2345,20 +2343,13 @@ func UpdateIssueDeadline(ctx *context.Context) { return } - var deadlineUnix timeutil.TimeStamp - var deadline time.Time - if form.Deadline != nil && !form.Deadline.IsZero() { - deadline = time.Date(form.Deadline.Year(), form.Deadline.Month(), form.Deadline.Day(), - 23, 59, 59, 0, time.Local) - deadlineUnix = timeutil.TimeStamp(deadline.Unix()) - } - + deadlineUnix, _ := common.ParseDeadlineDateToEndOfDay(ctx.FormString("deadline")) if err := issues_model.UpdateIssueDeadline(ctx, issue, deadlineUnix, ctx.Doer); err != nil { ctx.Error(http.StatusInternalServerError, "UpdateIssueDeadline", err.Error()) return } - ctx.JSON(http.StatusCreated, api.IssueDeadline{Deadline: &deadline}) + ctx.JSONRedirect("") } // UpdateIssueMilestone change issue's milestone diff --git a/routers/web/repo/milestone.go b/routers/web/repo/milestone.go index e4ee025875..5c0972188c 100644 --- a/routers/web/repo/milestone.go +++ b/routers/web/repo/milestone.go @@ -7,7 +7,6 @@ import ( "fmt" "net/http" "net/url" - "time" "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" @@ -16,8 +15,8 @@ import ( "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/routers/common" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/issue" @@ -134,22 +133,18 @@ func NewMilestonePost(ctx *context.Context) { return } - if len(form.Deadline) == 0 { - form.Deadline = "9999-12-31" - } - deadline, err := time.ParseInLocation("2006-01-02", form.Deadline, time.Local) + deadlineUnix, err := common.ParseDeadlineDateToEndOfDay(form.Deadline) if err != nil { ctx.Data["Err_Deadline"] = true ctx.RenderWithErr(ctx.Tr("repo.milestones.invalid_due_date_format"), tplMilestoneNew, &form) return } - deadline = time.Date(deadline.Year(), deadline.Month(), deadline.Day(), 23, 59, 59, 0, deadline.Location()) - if err = issues_model.NewMilestone(ctx, &issues_model.Milestone{ + if err := issues_model.NewMilestone(ctx, &issues_model.Milestone{ RepoID: ctx.Repo.Repository.ID, Name: form.Title, Content: form.Content, - DeadlineUnix: timeutil.TimeStamp(deadline.Unix()), + DeadlineUnix: deadlineUnix, }); err != nil { ctx.ServerError("NewMilestone", err) return @@ -194,17 +189,13 @@ func EditMilestonePost(ctx *context.Context) { return } - if len(form.Deadline) == 0 { - form.Deadline = "9999-12-31" - } - deadline, err := time.ParseInLocation("2006-01-02", form.Deadline, time.Local) + deadlineUnix, err := common.ParseDeadlineDateToEndOfDay(form.Deadline) if err != nil { ctx.Data["Err_Deadline"] = true ctx.RenderWithErr(ctx.Tr("repo.milestones.invalid_due_date_format"), tplMilestoneNew, &form) return } - deadline = time.Date(deadline.Year(), deadline.Month(), deadline.Day(), 23, 59, 59, 0, deadline.Location()) m, err := issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64(":id")) if err != nil { if issues_model.IsErrMilestoneNotExist(err) { @@ -216,7 +207,7 @@ func EditMilestonePost(ctx *context.Context) { } m.Name = form.Title m.Content = form.Content - m.DeadlineUnix = timeutil.TimeStamp(deadline.Unix()) + m.DeadlineUnix = deadlineUnix if err = issues_model.UpdateMilestone(ctx, m, m.IsClosed); err != nil { ctx.ServerError("UpdateMilestone", err) return diff --git a/routers/web/web.go b/routers/web/web.go index 69ed4bd8e4..29dd8a8edc 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1208,7 +1208,7 @@ func registerRoutes(m *web.Router) { m.Group("/{index}", func() { m.Post("/title", repo.UpdateIssueTitle) m.Post("/content", repo.UpdateIssueContent) - m.Post("/deadline", web.Bind(structs.EditDeadlineOption{}), repo.UpdateIssueDeadline) + m.Post("/deadline", repo.UpdateIssueDeadline) m.Post("/watch", repo.IssueWatch) m.Post("/ref", repo.UpdateIssueRef) m.Post("/pin", reqRepoAdmin, repo.IssuePinOrUnpin) diff --git a/services/convert/issue.go b/services/convert/issue.go index f514dc4313..e3124efd64 100644 --- a/services/convert/issue.go +++ b/services/convert/issue.go @@ -260,7 +260,7 @@ func ToAPIMilestone(m *issues_model.Milestone) *api.Milestone { if m.IsClosed { apiMilestone.Closed = m.ClosedDateUnix.AsTimePtr() } - if m.DeadlineUnix.Year() < 9999 { + if m.DeadlineUnix > 0 { apiMilestone.Deadline = m.DeadlineUnix.AsTimePtr() } return apiMilestone diff --git a/templates/repo/graph/commits.tmpl b/templates/repo/graph/commits.tmpl index 17c6cad86b..f1d0e62330 100644 --- a/templates/repo/graph/commits.tmpl +++ b/templates/repo/graph/commits.tmpl @@ -56,7 +56,7 @@ {{end}} {{end}} - + {{$userName := $commit.Commit.Author.Name}} {{if $commit.User}} {{if and $commit.User.FullName DefaultShowFullName}} diff --git a/templates/repo/issue/milestone_new.tmpl b/templates/repo/issue/milestone_new.tmpl index 9f32df00e3..736a75d73a 100644 --- a/templates/repo/issue/milestone_new.tmpl +++ b/templates/repo/issue/milestone_new.tmpl @@ -30,9 +30,9 @@
- +
diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl index 01fa433978..9c1acae0cf 100644 --- a/templates/repo/issue/view_content/sidebar.tmpl +++ b/templates/repo/issue/view_content/sidebar.tmpl @@ -358,44 +358,31 @@
{{ctx.Locale.Tr "repo.issues.due_date"}} -
-
- {{svg "octicon-x" 16 "close icon"}} - {{ctx.Locale.Tr "repo.issues.due_date_invalid"}} -
- {{if ne .Issue.DeadlineUnix 0}} -

-

-
- {{svg "octicon-calendar" 16 "tw-mr-2"}} - {{DateUtils.AbsoluteLong .Issue.DeadlineUnix}} -
-
- {{if and .HasIssuesOrPullsWritePermission (not .Repository.IsArchived)}} - {{svg "octicon-pencil" 16 "tw-mr-1"}} - {{svg "octicon-trash"}} - {{end}} -
+
+ {{if .Issue.DeadlineUnix}} +
+
+ {{svg "octicon-calendar"}} {{DateUtils.AbsoluteLong .Issue.DeadlineUnix}} +
+
+ {{if and .HasIssuesOrPullsWritePermission (not .Repository.IsArchived)}} + {{svg "octicon-pencil"}} + {{svg "octicon-trash"}} + {{end}}
-

+
{{else}} -

{{ctx.Locale.Tr "repo.issues.due_date_not_set"}}

+ {{ctx.Locale.Tr "repo.issues.due_date_not_set"}} {{end}} {{if and .HasIssuesOrPullsWritePermission (not .Repository.IsArchived)}} -
-
- {{$.CsrfTokenHtml}} - - -
-
+
+ {{$.CsrfTokenHtml}} + + +
{{end}}
diff --git a/tests/integration/api_issue_milestone_test.go b/tests/integration/api_issue_milestone_test.go index 32ac56298f..2d00752302 100644 --- a/tests/integration/api_issue_milestone_test.go +++ b/tests/integration/api_issue_milestone_test.go @@ -59,6 +59,7 @@ func TestAPIIssuesMilestone(t *testing.T) { DecodeJSON(t, resp, &apiMilestone) assert.Equal(t, "wow", apiMilestone.Title) assert.Equal(t, structs.StateClosed, apiMilestone.State) + assert.Nil(t, apiMilestone.Deadline) var apiMilestones []structs.Milestone req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/milestones?state=%s", owner.Name, repo.Name, "all")). @@ -66,6 +67,7 @@ func TestAPIIssuesMilestone(t *testing.T) { resp = MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiMilestones) assert.Len(t, apiMilestones, 4) + assert.Nil(t, apiMilestones[0].Deadline) req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/milestones/%s", owner.Name, repo.Name, apiMilestones[2].Title)). AddTokenAuth(token) diff --git a/tests/integration/issue_test.go b/tests/integration/issue_test.go index df45da84a5..4617c5f89a 100644 --- a/tests/integration/issue_test.go +++ b/tests/integration/issue_test.go @@ -657,26 +657,21 @@ func TestUpdateIssueDeadline(t *testing.T) { repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID}) owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID}) assert.NoError(t, issueBefore.LoadAttributes(db.DefaultContext)) - assert.Equal(t, int64(1019307200), int64(issueBefore.DeadlineUnix)) + assert.Equal(t, "2002-04-20", issueBefore.DeadlineUnix.FormatDate()) assert.Equal(t, api.StateOpen, issueBefore.State()) session := loginUser(t, owner.Name) + urlStr := fmt.Sprintf("%s/%s/issues/%d/deadline?_csrf=%s", owner.Name, repoBefore.Name, issueBefore.Index, GetUserCSRFToken(t, session)) - issueURL := fmt.Sprintf("%s/%s/issues/%d", owner.Name, repoBefore.Name, issueBefore.Index) - req := NewRequest(t, "GET", issueURL) - resp := session.MakeRequest(t, req, http.StatusOK) - htmlDoc := NewHTMLParser(t, resp.Body) - - urlStr := issueURL + "/deadline?_csrf=" + htmlDoc.GetCSRF() - req = NewRequestWithJSON(t, "POST", urlStr, map[string]string{ - "due_date": "2022-04-06T00:00:00.000Z", - }) - - resp = session.MakeRequest(t, req, http.StatusCreated) - var apiIssue api.IssueDeadline - DecodeJSON(t, resp, &apiIssue) + req := NewRequestWithValues(t, "POST", urlStr, map[string]string{"deadline": "2022-04-06"}) + session.MakeRequest(t, req, http.StatusOK) + issueAfter := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 10}) + assert.EqualValues(t, "2022-04-06", issueAfter.DeadlineUnix.FormatDate()) - assert.EqualValues(t, "2022-04-06", apiIssue.Deadline.Format("2006-01-02")) + req = NewRequestWithValues(t, "POST", urlStr, map[string]string{"deadline": ""}) + session.MakeRequest(t, req, http.StatusOK) + issueAfter = unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 10}) + assert.True(t, issueAfter.DeadlineUnix.IsZero()) } func TestIssueReferenceURL(t *testing.T) { diff --git a/web_src/js/features/repo-issue-sidebar.ts b/web_src/js/features/repo-issue-sidebar.ts index f33e192f29..0d30d8103c 100644 --- a/web_src/js/features/repo-issue-sidebar.ts +++ b/web_src/js/features/repo-issue-sidebar.ts @@ -3,6 +3,7 @@ import {POST} from '../modules/fetch.ts'; import {updateIssuesMeta} from './repo-common.ts'; import {svg} from '../svg.ts'; import {htmlEscape} from 'escape-goat'; +import {toggleElem} from '../utils/dom.ts'; // if there are draft comments, confirm before reloading, to avoid losing comments function reloadConfirmDraftComment() { @@ -258,8 +259,22 @@ function selectItem(select_id, input_id) { }); } +function initRepoIssueDue() { + const form = document.querySelector('.issue-due-form'); + if (!form) return; + const deadline = form.querySelector('input[name=deadline]'); + document.querySelector('.issue-due-edit')?.addEventListener('click', () => { + toggleElem(form); + }); + document.querySelector('.issue-due-remove')?.addEventListener('click', () => { + deadline.value = ''; + form.dispatchEvent(new Event('submit', {cancelable: true, bubbles: true})); + }); +} + export function initRepoIssueSidebar() { initBranchSelector(); + initRepoIssueDue(); // Init labels and assignees initListSubmits('select-label', 'labels'); diff --git a/web_src/js/features/repo-issue.ts b/web_src/js/features/repo-issue.ts index a9a65cdc81..392af776f8 100644 --- a/web_src/js/features/repo-issue.ts +++ b/web_src/js/features/repo-issue.ts @@ -43,52 +43,6 @@ export function initRepoIssueTimeTracking() { }); } -async function updateDeadline(deadlineString) { - hideElem('#deadline-err-invalid-date'); - document.querySelector('#deadline-loader')?.classList.add('is-loading'); - - let realDeadline = null; - if (deadlineString !== '') { - const newDate = Date.parse(deadlineString); - - if (Number.isNaN(newDate)) { - document.querySelector('#deadline-loader')?.classList.remove('is-loading'); - showElem('#deadline-err-invalid-date'); - return false; - } - realDeadline = new Date(newDate); - } - - try { - const response = await POST(document.querySelector('#update-issue-deadline-form').getAttribute('action'), { - data: {due_date: realDeadline}, - }); - - if (response.ok) { - window.location.reload(); - } else { - throw new Error('Invalid response'); - } - } catch (error) { - console.error(error); - document.querySelector('#deadline-loader').classList.remove('is-loading'); - showElem('#deadline-err-invalid-date'); - } -} - -export function initRepoIssueDue() { - $(document).on('click', '.issue-due-edit', () => { - toggleElem('#deadlineForm'); - }); - $(document).on('click', '.issue-due-remove', () => { - updateDeadline(''); - }); - $(document).on('submit', '.issue-due-form', () => { - updateDeadline($('#deadlineDate').val()); - return false; - }); -} - /** * @param {HTMLElement} item */ diff --git a/web_src/js/features/repo-milestone.ts b/web_src/js/features/repo-milestone.ts index ddef723b48..ee704ea2e0 100644 --- a/web_src/js/features/repo-milestone.ts +++ b/web_src/js/features/repo-milestone.ts @@ -1,11 +1,9 @@ -import $ from 'jquery'; - export function initRepoMilestone() { - // Milestones - if ($('.repository.new.milestone').length > 0) { - $('#clear-date').on('click', () => { - $('#deadline').val(''); - return false; - }); - } + const page = document.querySelector('.repository.new.milestone'); + if (!page) return; + + const deadline = page.querySelector('form input[name=deadline]'); + document.querySelector('#milestone-clear-deadline').addEventListener('click', () => { + deadline.value = ''; + }); } diff --git a/web_src/js/index.ts b/web_src/js/index.ts index 08d8997fd1..487aac97aa 100644 --- a/web_src/js/index.ts +++ b/web_src/js/index.ts @@ -25,7 +25,6 @@ import {initPdfViewer} from './render/pdf.ts'; import {initUserAuthOauth2, initUserCheckAppUrl} from './features/user-auth.ts'; import { - initRepoIssueDue, initRepoIssueReferenceRepositorySearch, initRepoIssueTimeTracking, initRepoIssueWipTitle, @@ -181,7 +180,6 @@ onDomReady(() => { initRepoEditor, initRepoGraphGit, initRepoIssueContentHistory, - initRepoIssueDue, initRepoIssueList, initRepoIssueSidebarList, initArchivedLabelHandler, -- 2.39.5