mirror of
https://github.com/go-gitea/gitea
synced 2025-02-08 15:54:43 +00:00
Merge branch 'main' into lunny/issue_dev
This commit is contained in:
commit
d869d3286f
@ -524,6 +524,7 @@ rules:
|
|||||||
no-jquery/no-data: [0]
|
no-jquery/no-data: [0]
|
||||||
no-jquery/no-deferred: [2]
|
no-jquery/no-deferred: [2]
|
||||||
no-jquery/no-delegate: [2]
|
no-jquery/no-delegate: [2]
|
||||||
|
no-jquery/no-done-fail: [2]
|
||||||
no-jquery/no-each-collection: [0]
|
no-jquery/no-each-collection: [0]
|
||||||
no-jquery/no-each-util: [0]
|
no-jquery/no-each-util: [0]
|
||||||
no-jquery/no-each: [0]
|
no-jquery/no-each: [0]
|
||||||
@ -538,6 +539,7 @@ rules:
|
|||||||
no-jquery/no-find-util: [2]
|
no-jquery/no-find-util: [2]
|
||||||
no-jquery/no-find: [0]
|
no-jquery/no-find: [0]
|
||||||
no-jquery/no-fx-interval: [2]
|
no-jquery/no-fx-interval: [2]
|
||||||
|
no-jquery/no-fx: [2]
|
||||||
no-jquery/no-global-eval: [2]
|
no-jquery/no-global-eval: [2]
|
||||||
no-jquery/no-global-selector: [0]
|
no-jquery/no-global-selector: [0]
|
||||||
no-jquery/no-grep: [2]
|
no-jquery/no-grep: [2]
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -28,6 +28,7 @@ _testmain.go
|
|||||||
*.exe
|
*.exe
|
||||||
*.test
|
*.test
|
||||||
*.prof
|
*.prof
|
||||||
|
*.tsbuildInfo
|
||||||
|
|
||||||
*coverage.out
|
*coverage.out
|
||||||
coverage.all
|
coverage.all
|
||||||
|
@ -114,6 +114,8 @@ const (
|
|||||||
|
|
||||||
CommentTypePin // 36 pin Issue
|
CommentTypePin // 36 pin Issue
|
||||||
CommentTypeUnpin // 37 unpin Issue
|
CommentTypeUnpin // 37 unpin Issue
|
||||||
|
|
||||||
|
CommentTypeChangeTimeEstimate // 38 Change time estimate
|
||||||
)
|
)
|
||||||
|
|
||||||
var commentStrings = []string{
|
var commentStrings = []string{
|
||||||
@ -155,6 +157,7 @@ var commentStrings = []string{
|
|||||||
"pull_cancel_scheduled_merge",
|
"pull_cancel_scheduled_merge",
|
||||||
"pin",
|
"pin",
|
||||||
"unpin",
|
"unpin",
|
||||||
|
"change_time_estimate",
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t CommentType) String() string {
|
func (t CommentType) String() string {
|
||||||
|
@ -147,6 +147,9 @@ type Issue struct {
|
|||||||
|
|
||||||
// For view issue page.
|
// For view issue page.
|
||||||
ShowRole RoleDescriptor `xorm:"-"`
|
ShowRole RoleDescriptor `xorm:"-"`
|
||||||
|
|
||||||
|
// Time estimate
|
||||||
|
TimeEstimate int64 `xorm:"NOT NULL DEFAULT 0"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -934,3 +937,28 @@ func insertIssue(ctx context.Context, issue *Issue) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ChangeIssueTimeEstimate changes the plan time of this issue, as the given user.
|
||||||
|
func ChangeIssueTimeEstimate(ctx context.Context, issue *Issue, doer *user_model.User, timeEstimate int64) error {
|
||||||
|
return db.WithTx(ctx, func(ctx context.Context) error {
|
||||||
|
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 nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -368,7 +368,8 @@ func prepareMigrationTasks() []*migration {
|
|||||||
newMigration(308, "Add index(user_id, is_deleted) for action table", v1_23.AddNewIndexForUserDashboard),
|
newMigration(308, "Add index(user_id, is_deleted) for action table", v1_23.AddNewIndexForUserDashboard),
|
||||||
newMigration(309, "Improve Notification table indices", v1_23.ImproveNotificationTableIndices),
|
newMigration(309, "Improve Notification table indices", v1_23.ImproveNotificationTableIndices),
|
||||||
newMigration(310, "Add Priority to ProtectedBranch", v1_23.AddPriorityToProtectedBranch),
|
newMigration(310, "Add Priority to ProtectedBranch", v1_23.AddPriorityToProtectedBranch),
|
||||||
newMigration(311, "Add table issue_dev_link", v1_23.CreateTableIssueDevLink),
|
newMigration(311, "Add TimeEstimate to Issue table", v1_23.AddTimeEstimateColumnToIssueTable),
|
||||||
|
newMigration(312, "Add table issue_dev_link", v1_23.CreateTableIssueDevLink),
|
||||||
}
|
}
|
||||||
return preparedMigrations
|
return preparedMigrations
|
||||||
}
|
}
|
||||||
|
@ -4,19 +4,13 @@
|
|||||||
package v1_23 //nolint
|
package v1_23 //nolint
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
|
||||||
|
|
||||||
"xorm.io/xorm"
|
"xorm.io/xorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CreateTableIssueDevLink(x *xorm.Engine) error {
|
func AddTimeEstimateColumnToIssueTable(x *xorm.Engine) error {
|
||||||
type IssueDevLink struct {
|
type Issue struct {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
TimeEstimate int64 `xorm:"NOT NULL DEFAULT 0"`
|
||||||
IssueID int64 `xorm:"INDEX"`
|
|
||||||
LinkType int
|
|
||||||
LinkedRepoID int64 `xorm:"INDEX"` // it can link to self repo or other repo
|
|
||||||
LinkIndex string // branch name, pull request number or commit sha
|
|
||||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
|
|
||||||
}
|
}
|
||||||
return x.Sync(new(IssueDevLink))
|
|
||||||
|
return x.Sync(new(Issue))
|
||||||
}
|
}
|
||||||
|
22
models/migrations/v1_23/v312.go
Normal file
22
models/migrations/v1_23/v312.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// 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 CreateTableIssueDevLink(x *xorm.Engine) error {
|
||||||
|
type IssueDevLink struct {
|
||||||
|
ID int64 `xorm:"pk autoincr"`
|
||||||
|
IssueID int64 `xorm:"INDEX"`
|
||||||
|
LinkType int
|
||||||
|
LinkedRepoID int64 `xorm:"INDEX"` // it can link to self repo or other repo
|
||||||
|
LinkIndex string // branch name, pull request number or commit sha
|
||||||
|
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
|
||||||
|
}
|
||||||
|
return x.Sync(new(IssueDevLink))
|
||||||
|
}
|
@ -70,6 +70,9 @@ func NewFuncMap() template.FuncMap {
|
|||||||
"FileSize": base.FileSize,
|
"FileSize": base.FileSize,
|
||||||
"CountFmt": base.FormatNumberSI,
|
"CountFmt": base.FormatNumberSI,
|
||||||
"Sec2Time": util.SecToTime,
|
"Sec2Time": util.SecToTime,
|
||||||
|
|
||||||
|
"TimeEstimateString": timeEstimateString,
|
||||||
|
|
||||||
"LoadTimes": func(startTime time.Time) string {
|
"LoadTimes": func(startTime time.Time) string {
|
||||||
return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms"
|
return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms"
|
||||||
},
|
},
|
||||||
@ -282,6 +285,14 @@ func userThemeName(user *user_model.User) string {
|
|||||||
return setting.UI.DefaultTheme
|
return setting.UI.DefaultTheme
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func timeEstimateString(timeSec any) string {
|
||||||
|
v, _ := util.ToInt64(timeSec)
|
||||||
|
if v == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return util.TimeEstimateString(v)
|
||||||
|
}
|
||||||
|
|
||||||
func panicIfDevOrTesting() {
|
func panicIfDevOrTesting() {
|
||||||
if !setting.IsProd || setting.IsInTesting {
|
if !setting.IsProd || setting.IsInTesting {
|
||||||
panic("legacy template functions are for backward compatibility only, do not use them in new code")
|
panic("legacy template functions are for backward compatibility only, do not use them in new code")
|
||||||
|
85
modules/util/time_str.go
Normal file
85
modules/util/time_str.go
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
// Copyright 2024 Gitea. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type timeStrGlobalVarsType struct {
|
||||||
|
units []struct {
|
||||||
|
name string
|
||||||
|
num int64
|
||||||
|
}
|
||||||
|
re *regexp.Regexp
|
||||||
|
}
|
||||||
|
|
||||||
|
// When tracking working time, only hour/minute/second units are accurate and could be used.
|
||||||
|
// For other units like "day", it depends on "how many working hours in a day": 6 or 7 or 8?
|
||||||
|
// So at the moment, we only support hour/minute/second units.
|
||||||
|
// In the future, it could be some configurable options to help users
|
||||||
|
// to convert the working time to different units.
|
||||||
|
|
||||||
|
var timeStrGlobalVars = sync.OnceValue[*timeStrGlobalVarsType](func() *timeStrGlobalVarsType {
|
||||||
|
v := &timeStrGlobalVarsType{}
|
||||||
|
v.re = regexp.MustCompile(`(?i)(\d+)\s*([hms])`)
|
||||||
|
v.units = []struct {
|
||||||
|
name string
|
||||||
|
num int64
|
||||||
|
}{
|
||||||
|
{"h", 60 * 60},
|
||||||
|
{"m", 60},
|
||||||
|
{"s", 1},
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
})
|
||||||
|
|
||||||
|
func TimeEstimateParse(timeStr string) (int64, error) {
|
||||||
|
if timeStr == "" {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
var total int64
|
||||||
|
matches := timeStrGlobalVars().re.FindAllStringSubmatchIndex(timeStr, -1)
|
||||||
|
if len(matches) == 0 {
|
||||||
|
return 0, fmt.Errorf("invalid time string: %s", timeStr)
|
||||||
|
}
|
||||||
|
if matches[0][0] != 0 || matches[len(matches)-1][1] != len(timeStr) {
|
||||||
|
return 0, fmt.Errorf("invalid time string: %s", timeStr)
|
||||||
|
}
|
||||||
|
for _, match := range matches {
|
||||||
|
amount, err := strconv.ParseInt(timeStr[match[2]:match[3]], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("invalid time string: %v", err)
|
||||||
|
}
|
||||||
|
unit := timeStr[match[4]:match[5]]
|
||||||
|
found := false
|
||||||
|
for _, u := range timeStrGlobalVars().units {
|
||||||
|
if strings.ToLower(unit) == u.name {
|
||||||
|
total += amount * u.num
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
return 0, fmt.Errorf("invalid time unit: %s", unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return total, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TimeEstimateString(amount int64) string {
|
||||||
|
var timeParts []string
|
||||||
|
for _, u := range timeStrGlobalVars().units {
|
||||||
|
if amount >= u.num {
|
||||||
|
num := amount / u.num
|
||||||
|
amount %= u.num
|
||||||
|
timeParts = append(timeParts, fmt.Sprintf("%d%s", num, u.name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.Join(timeParts, " ")
|
||||||
|
}
|
55
modules/util/time_str_test.go
Normal file
55
modules/util/time_str_test.go
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
// Copyright 2024 Gitea. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTimeStr(t *testing.T) {
|
||||||
|
t.Run("Parse", func(t *testing.T) {
|
||||||
|
// Test TimeEstimateParse
|
||||||
|
tests := []struct {
|
||||||
|
input string
|
||||||
|
output int64
|
||||||
|
err bool
|
||||||
|
}{
|
||||||
|
{"1h", 3600, false},
|
||||||
|
{"1m", 60, false},
|
||||||
|
{"1s", 1, false},
|
||||||
|
{"1h 1m 1s", 3600 + 60 + 1, false},
|
||||||
|
{"1d1x", 0, true},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.input, func(t *testing.T) {
|
||||||
|
output, err := TimeEstimateParse(test.input)
|
||||||
|
if test.err {
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
} else {
|
||||||
|
assert.Nil(t, err)
|
||||||
|
}
|
||||||
|
assert.Equal(t, test.output, output)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("String", func(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
input int64
|
||||||
|
output string
|
||||||
|
}{
|
||||||
|
{3600, "1h"},
|
||||||
|
{60, "1m"},
|
||||||
|
{1, "1s"},
|
||||||
|
{3600 + 1, "1h 1s"},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.output, func(t *testing.T) {
|
||||||
|
output := TimeEstimateString(test.input)
|
||||||
|
assert.Equal(t, test.output, output)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
@ -1681,27 +1681,34 @@ issues.comment_on_locked = You cannot comment on a locked issue.
|
|||||||
issues.delete = Delete
|
issues.delete = Delete
|
||||||
issues.delete.title = Delete this issue?
|
issues.delete.title = Delete this issue?
|
||||||
issues.delete.text = Do you really want to delete this issue? (This will permanently remove all content. Consider closing it instead, if you intend to keep it archived)
|
issues.delete.text = Do you really want to delete this issue? (This will permanently remove all content. Consider closing it instead, if you intend to keep it archived)
|
||||||
|
|
||||||
issues.tracker = Time Tracker
|
issues.tracker = Time Tracker
|
||||||
issues.start_tracking_short = Start Timer
|
issues.timetracker_timer_start = Start timer
|
||||||
issues.start_tracking = Start Time Tracking
|
issues.timetracker_timer_stop = Stop timer
|
||||||
issues.start_tracking_history = `started working %s`
|
issues.timetracker_timer_discard = Discard timer
|
||||||
|
issues.timetracker_timer_manually_add = Add Time
|
||||||
|
|
||||||
|
issues.time_estimate_placeholder = 1h 2m
|
||||||
|
issues.time_estimate_set = Set estimated time
|
||||||
|
issues.time_estimate_display = Estimate: %s
|
||||||
|
issues.change_time_estimate_at = changed time estimate to <b>%s</b> %s
|
||||||
|
issues.remove_time_estimate_at = removed time estimate %s
|
||||||
|
issues.time_estimate_invalid = Time estimate format is invalid
|
||||||
|
issues.start_tracking_history = started working %s
|
||||||
issues.tracker_auto_close = Timer will be stopped automatically when this issue gets closed
|
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.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 = worked for <b>%s</b> %s
|
||||||
issues.stop_tracking_history = `stopped working %s`
|
|
||||||
issues.cancel_tracking = Discard
|
|
||||||
issues.cancel_tracking_history = `canceled time tracking %s`
|
issues.cancel_tracking_history = `canceled time tracking %s`
|
||||||
issues.add_time = Manually Add Time
|
|
||||||
issues.del_time = Delete this time log
|
issues.del_time = Delete this time log
|
||||||
issues.add_time_short = Add Time
|
issues.add_time_history = added spent time <b>%s</b> %s
|
||||||
issues.add_time_cancel = Cancel
|
|
||||||
issues.add_time_history = `added spent time %s`
|
|
||||||
issues.del_time_history= `deleted spent time %s`
|
issues.del_time_history= `deleted spent time %s`
|
||||||
|
issues.add_time_manually = Manually Add Time
|
||||||
issues.add_time_hours = Hours
|
issues.add_time_hours = Hours
|
||||||
issues.add_time_minutes = Minutes
|
issues.add_time_minutes = Minutes
|
||||||
issues.add_time_sum_to_small = No time was entered.
|
issues.add_time_sum_to_small = No time was entered.
|
||||||
issues.time_spent_total = Total Time Spent
|
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: %s`
|
||||||
|
|
||||||
issues.due_date = Due Date
|
issues.due_date = Due Date
|
||||||
issues.invalid_due_date_format = "Due date format must be 'yyyy-mm-dd'."
|
issues.invalid_due_date_format = "Due date format must be 'yyyy-mm-dd'."
|
||||||
issues.error_modifying_due_date = "Failed to modify the due date."
|
issues.error_modifying_due_date = "Failed to modify the due date."
|
||||||
|
1600
package-lock.json
generated
1600
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
62
package.json
62
package.json
@ -12,15 +12,15 @@
|
|||||||
"@github/relative-time-element": "4.4.3",
|
"@github/relative-time-element": "4.4.3",
|
||||||
"@github/text-expander-element": "2.8.0",
|
"@github/text-expander-element": "2.8.0",
|
||||||
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
|
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
|
||||||
"@primer/octicons": "19.12.0",
|
"@primer/octicons": "19.13.0",
|
||||||
"@silverwind/vue3-calendar-heatmap": "2.0.6",
|
"@silverwind/vue3-calendar-heatmap": "2.0.6",
|
||||||
"add-asset-webpack-plugin": "3.0.0",
|
"add-asset-webpack-plugin": "3.0.0",
|
||||||
"ansi_up": "6.0.2",
|
"ansi_up": "6.0.2",
|
||||||
"asciinema-player": "3.8.1",
|
"asciinema-player": "3.8.1",
|
||||||
"chart.js": "4.4.6",
|
"chart.js": "4.4.7",
|
||||||
"chartjs-adapter-dayjs-4": "1.0.4",
|
"chartjs-adapter-dayjs-4": "1.0.4",
|
||||||
"chartjs-plugin-zoom": "2.0.1",
|
"chartjs-plugin-zoom": "2.2.0",
|
||||||
"clippie": "4.1.3",
|
"clippie": "4.1.4",
|
||||||
"cropperjs": "1.6.2",
|
"cropperjs": "1.6.2",
|
||||||
"css-loader": "7.1.2",
|
"css-loader": "7.1.2",
|
||||||
"dayjs": "1.11.13",
|
"dayjs": "1.11.13",
|
||||||
@ -34,7 +34,7 @@
|
|||||||
"jquery": "3.7.1",
|
"jquery": "3.7.1",
|
||||||
"katex": "0.16.11",
|
"katex": "0.16.11",
|
||||||
"license-checker-webpack-plugin": "0.2.1",
|
"license-checker-webpack-plugin": "0.2.1",
|
||||||
"mermaid": "11.4.0",
|
"mermaid": "11.4.1",
|
||||||
"mini-css-extract-plugin": "2.9.2",
|
"mini-css-extract-plugin": "2.9.2",
|
||||||
"minimatch": "10.0.1",
|
"minimatch": "10.0.1",
|
||||||
"monaco-editor": "0.52.0",
|
"monaco-editor": "0.52.0",
|
||||||
@ -44,32 +44,32 @@
|
|||||||
"postcss": "8.4.49",
|
"postcss": "8.4.49",
|
||||||
"postcss-loader": "8.1.1",
|
"postcss-loader": "8.1.1",
|
||||||
"postcss-nesting": "13.0.1",
|
"postcss-nesting": "13.0.1",
|
||||||
"sortablejs": "1.15.3",
|
"sortablejs": "1.15.6",
|
||||||
"swagger-ui-dist": "5.18.2",
|
"swagger-ui-dist": "5.18.2",
|
||||||
"tailwindcss": "3.4.14",
|
"tailwindcss": "3.4.16",
|
||||||
"throttle-debounce": "5.0.2",
|
"throttle-debounce": "5.0.2",
|
||||||
"tinycolor2": "1.6.0",
|
"tinycolor2": "1.6.0",
|
||||||
"tippy.js": "6.3.7",
|
"tippy.js": "6.3.7",
|
||||||
"toastify-js": "1.12.0",
|
"toastify-js": "1.12.0",
|
||||||
"tributejs": "5.1.3",
|
"tributejs": "5.1.3",
|
||||||
"typescript": "5.6.3",
|
"typescript": "5.7.2",
|
||||||
"uint8-to-base64": "0.2.0",
|
"uint8-to-base64": "0.2.0",
|
||||||
"vanilla-colorful": "0.7.2",
|
"vanilla-colorful": "0.7.2",
|
||||||
"vue": "3.5.12",
|
"vue": "3.5.13",
|
||||||
"vue-bar-graph": "2.1.0",
|
"vue-bar-graph": "2.2.0",
|
||||||
"vue-chartjs": "5.3.2",
|
"vue-chartjs": "5.3.2",
|
||||||
"vue-loader": "17.4.2",
|
"vue-loader": "17.4.2",
|
||||||
"webpack": "5.96.1",
|
"webpack": "5.97.0",
|
||||||
"webpack-cli": "5.1.4",
|
"webpack-cli": "5.1.4",
|
||||||
"wrap-ansi": "9.0.0"
|
"wrap-ansi": "9.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint-community/eslint-plugin-eslint-comments": "4.4.1",
|
"@eslint-community/eslint-plugin-eslint-comments": "4.4.1",
|
||||||
"@playwright/test": "1.48.2",
|
"@playwright/test": "1.49.0",
|
||||||
"@stoplight/spectral-cli": "6.14.0",
|
"@stoplight/spectral-cli": "6.14.2",
|
||||||
"@stylistic/eslint-plugin-js": "2.10.1",
|
"@stylistic/eslint-plugin-js": "2.11.0",
|
||||||
"@stylistic/stylelint-plugin": "3.1.1",
|
"@stylistic/stylelint-plugin": "3.1.1",
|
||||||
"@types/dropzone": "5.7.8",
|
"@types/dropzone": "5.7.9",
|
||||||
"@types/jquery": "3.5.32",
|
"@types/jquery": "3.5.32",
|
||||||
"@types/katex": "0.16.7",
|
"@types/katex": "0.16.7",
|
||||||
"@types/license-checker-webpack-plugin": "0.2.4",
|
"@types/license-checker-webpack-plugin": "0.2.4",
|
||||||
@ -79,38 +79,38 @@
|
|||||||
"@types/throttle-debounce": "5.0.2",
|
"@types/throttle-debounce": "5.0.2",
|
||||||
"@types/tinycolor2": "1.4.6",
|
"@types/tinycolor2": "1.4.6",
|
||||||
"@types/toastify-js": "1.12.3",
|
"@types/toastify-js": "1.12.3",
|
||||||
"@typescript-eslint/eslint-plugin": "8.14.0",
|
"@typescript-eslint/eslint-plugin": "8.17.0",
|
||||||
"@typescript-eslint/parser": "8.14.0",
|
"@typescript-eslint/parser": "8.17.0",
|
||||||
"@vitejs/plugin-vue": "5.1.5",
|
"@vitejs/plugin-vue": "5.2.1",
|
||||||
"eslint": "8.57.0",
|
"eslint": "8.57.0",
|
||||||
"eslint-import-resolver-typescript": "3.6.3",
|
"eslint-import-resolver-typescript": "3.7.0",
|
||||||
"eslint-plugin-array-func": "4.0.0",
|
"eslint-plugin-array-func": "4.0.0",
|
||||||
"eslint-plugin-github": "5.0.2",
|
"eslint-plugin-github": "5.1.3",
|
||||||
"eslint-plugin-i": "2.29.1",
|
"eslint-plugin-i": "2.29.1",
|
||||||
"eslint-plugin-no-jquery": "3.0.2",
|
"eslint-plugin-no-jquery": "3.1.0",
|
||||||
"eslint-plugin-no-use-extend-native": "0.5.0",
|
"eslint-plugin-no-use-extend-native": "0.5.0",
|
||||||
"eslint-plugin-playwright": "2.0.1",
|
"eslint-plugin-playwright": "2.1.0",
|
||||||
"eslint-plugin-regexp": "2.6.0",
|
"eslint-plugin-regexp": "2.7.0",
|
||||||
"eslint-plugin-sonarjs": "2.0.4",
|
"eslint-plugin-sonarjs": "2.0.4",
|
||||||
"eslint-plugin-unicorn": "56.0.0",
|
"eslint-plugin-unicorn": "56.0.1",
|
||||||
"eslint-plugin-vitest": "0.4.1",
|
"eslint-plugin-vitest": "0.4.1",
|
||||||
"eslint-plugin-vitest-globals": "1.5.0",
|
"eslint-plugin-vitest-globals": "1.5.0",
|
||||||
"eslint-plugin-vue": "9.31.0",
|
"eslint-plugin-vue": "9.32.0",
|
||||||
"eslint-plugin-vue-scoped-css": "2.8.1",
|
"eslint-plugin-vue-scoped-css": "2.9.0",
|
||||||
"eslint-plugin-wc": "2.2.0",
|
"eslint-plugin-wc": "2.2.0",
|
||||||
"happy-dom": "15.11.3",
|
"happy-dom": "15.11.7",
|
||||||
"markdownlint-cli": "0.42.0",
|
"markdownlint-cli": "0.43.0",
|
||||||
"nolyfill": "1.0.42",
|
"nolyfill": "1.0.42",
|
||||||
"postcss-html": "1.7.0",
|
"postcss-html": "1.7.0",
|
||||||
"stylelint": "16.10.0",
|
"stylelint": "16.11.0",
|
||||||
"stylelint-declaration-block-no-ignored-properties": "2.8.0",
|
"stylelint-declaration-block-no-ignored-properties": "2.8.0",
|
||||||
"stylelint-declaration-strict-value": "1.10.6",
|
"stylelint-declaration-strict-value": "1.10.6",
|
||||||
"stylelint-value-no-unknown-custom-properties": "6.0.1",
|
"stylelint-value-no-unknown-custom-properties": "6.0.1",
|
||||||
"svgo": "3.3.2",
|
"svgo": "3.3.2",
|
||||||
"type-fest": "4.26.1",
|
"type-fest": "4.30.0",
|
||||||
"updates": "16.4.0",
|
"updates": "16.4.0",
|
||||||
"vite-string-plugin": "1.3.4",
|
"vite-string-plugin": "1.3.4",
|
||||||
"vitest": "2.1.4",
|
"vitest": "2.1.8",
|
||||||
"vue-tsc": "2.1.10"
|
"vue-tsc": "2.1.10"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
|
106
poetry.lock
generated
106
poetry.lock
generated
@ -42,33 +42,33 @@ six = ">=1.13.0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "djlint"
|
name = "djlint"
|
||||||
version = "1.36.1"
|
version = "1.36.3"
|
||||||
description = "HTML Template Linter and Formatter"
|
description = "HTML Template Linter and Formatter"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.9"
|
python-versions = ">=3.9"
|
||||||
files = [
|
files = [
|
||||||
{file = "djlint-1.36.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef40527fd6cd82cdd18f65a6bf5b486b767d2386f6c21f2ebd60e5d88f487fe8"},
|
{file = "djlint-1.36.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2ae7c620b58e16d6bf003bd7de3f71376a7a3daa79dc02e77f3726d5a75243f2"},
|
||||||
{file = "djlint-1.36.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4712de3dea172000a098da6a0cd709d158909b4964ba0f68bee584cef18b4878"},
|
{file = "djlint-1.36.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e155ce0970d4a28d0a2e9f2e106733a2ad05910eee90e056b056d48049e4a97b"},
|
||||||
{file = "djlint-1.36.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63d01c1425170b7059d68a3b01709e1c31d2cd6520a1eb0166e6670fd250518a"},
|
{file = "djlint-1.36.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e8bb0406e60cc696806aa6226df137618f3889c72f2dbdfa76c908c99151579"},
|
||||||
{file = "djlint-1.36.1-cp310-cp310-win_amd64.whl", hash = "sha256:65585a97d3a37760b4c1fbd089a3573506ad0ab2885119322a66231f911d113f"},
|
{file = "djlint-1.36.3-cp310-cp310-win_amd64.whl", hash = "sha256:76d32faf988ad58ef2e7a11d04046fc984b98391761bf1b61f9a6044da53d414"},
|
||||||
{file = "djlint-1.36.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:607437a0a230462916858c269bc5dfd15ff71b27d15dfd1ad6e96b3da9cbd8f6"},
|
{file = "djlint-1.36.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:32f7a5834000fff22e94d1d35f95aaf2e06f2af2cae18af0ed2a4e215d60e730"},
|
||||||
{file = "djlint-1.36.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8ddc9ae6b83b288465f6685b24797adbde79952d6e1a5276026e5ef479bac76f"},
|
{file = "djlint-1.36.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3eb1b9c0be499e63e8822a051e7e55f188ff1ab8172a85d338a8ae21c872060e"},
|
||||||
{file = "djlint-1.36.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:001e5124b0ebab60a2044134abd11ff11dee772e7c3caaa2c8d12eb5d3b1f1dc"},
|
{file = "djlint-1.36.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c2e0dd1f26eb472b8c84eb70d6482877b6497a1fd031d7534864088f016d5ea"},
|
||||||
{file = "djlint-1.36.1-cp311-cp311-win_amd64.whl", hash = "sha256:095d62f3cabbac08683c51c1d9dacab522b54437a2a317df9e134599360f7b89"},
|
{file = "djlint-1.36.3-cp311-cp311-win_amd64.whl", hash = "sha256:a06b531ab9d049c46ad4d2365d1857004a1a9dd0c23c8eae94aa0d233c6ec00d"},
|
||||||
{file = "djlint-1.36.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:210f319c2d22489aebc0e9c1acd5015ca3892b66fa35647344511b3c03fcbe82"},
|
{file = "djlint-1.36.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e66361a865e5e5a4bbcb40f56af7f256fd02cbf9d48b763a40172749cc294084"},
|
||||||
{file = "djlint-1.36.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7aa3db13d7702c35f4e408325061d9d4e84d006c99bb3e55fddf2b2543736923"},
|
{file = "djlint-1.36.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:36e102b80d83e9ac2e6be9a9ded32fb925945f6dbc7a7156e4415de1b0aa0dba"},
|
||||||
{file = "djlint-1.36.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2f907e97f4d67f4423dc71671592891cfd9cd311aeef14db25633f292dbf7048"},
|
{file = "djlint-1.36.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ac4b7370d80bd82281e57a470de8923ac494ffb571b89d8787cef57c738c69a"},
|
||||||
{file = "djlint-1.36.1-cp312-cp312-win_amd64.whl", hash = "sha256:abadf6b61dc53d81710f230542f57f2d470b7503cd3108ad8a0113271c0514dd"},
|
{file = "djlint-1.36.3-cp312-cp312-win_amd64.whl", hash = "sha256:107cc56bbef13d60cc0ae774a4d52881bf98e37c02412e573827a3e549217e3a"},
|
||||||
{file = "djlint-1.36.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7f31646435385eec1d4b03dad7bebb5e4078d9893c60d490a685535bd6303c83"},
|
{file = "djlint-1.36.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2a9f51971d6e63c41ea9b3831c928e1f21ae6fe57e87a3452cfe672d10232433"},
|
||||||
{file = "djlint-1.36.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4399477ac51f9c8147eedbef70aa8465eccba6759d875d1feec6782744aa168a"},
|
{file = "djlint-1.36.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:080c98714b55d8f0fef5c42beaee8247ebb2e3d46b0936473bd6c47808bb6302"},
|
||||||
{file = "djlint-1.36.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f08c217b17d3ae3c0e3b5fff57fb708029cceda6e232f5a54ff1b3aeb43a7540"},
|
{file = "djlint-1.36.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f65a80e0b5cb13d357ea51ca6570b34c2d9d18974c1e57142de760ea27d49ed0"},
|
||||||
{file = "djlint-1.36.1-cp313-cp313-win_amd64.whl", hash = "sha256:1577490802ca4697af3488ed13066c9214ef0f625a96aa20d4f297e37aa19303"},
|
{file = "djlint-1.36.3-cp313-cp313-win_amd64.whl", hash = "sha256:95ef6b67ef7f2b90d9434bba37d572031079001dc8524add85c00ef0386bda1e"},
|
||||||
{file = "djlint-1.36.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3ae356faf8180c7629ca705b7b9d8c9269b2c53273a1887a438a21b8fa263588"},
|
{file = "djlint-1.36.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8e2317a32094d525bc41cd11c8dc064bf38d1b442c99cc3f7c4a2616b5e6ce6e"},
|
||||||
{file = "djlint-1.36.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2237ac5cecd2524960e1684f64ce358624b0d769b7404e5aad415750ad00edc9"},
|
{file = "djlint-1.36.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e82266c28793cd15f97b93535d72bfbc77306eaaf6b210dd90910383a814ee6c"},
|
||||||
{file = "djlint-1.36.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:02c22352a49c053ff6260428ed571afb783011d20afc98b44bbe1dd2fa2d5418"},
|
{file = "djlint-1.36.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01b2101c2d1b079e8d545e6d9d03487fcca14d2371e44cbfdedee15b0bf4567c"},
|
||||||
{file = "djlint-1.36.1-cp39-cp39-win_amd64.whl", hash = "sha256:99a2debeea2e931b68360306fdbf13861e3d6f96037a9d882f3d4d5e44fdc319"},
|
{file = "djlint-1.36.3-cp39-cp39-win_amd64.whl", hash = "sha256:15cde63ef28beb5194ff4137883025f125676ece1b574b64a3e1c6daed734639"},
|
||||||
{file = "djlint-1.36.1-py3-none-any.whl", hash = "sha256:950782b396dd82b74622c09d7e4c52328e56a3b03c8ac790c319708e5caa0686"},
|
{file = "djlint-1.36.3-py3-none-any.whl", hash = "sha256:0c05cd5b76785de2c41a2420c06ffd112800bfc0f9c0f399cc7cea7c42557f4c"},
|
||||||
{file = "djlint-1.36.1.tar.gz", hash = "sha256:f7260637ed72c270fa6dd4a87628e1a21c49b24a46df52e4e26f44d4934fb97c"},
|
{file = "djlint-1.36.3.tar.gz", hash = "sha256:d85735da34bc7ac93ad8ef9b4822cc2a23d5f0ce33f25438737b8dca1d404f78"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -109,13 +109,13 @@ six = ">=1.13.0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "json5"
|
name = "json5"
|
||||||
version = "0.9.28"
|
version = "0.10.0"
|
||||||
description = "A Python implementation of the JSON5 data format."
|
description = "A Python implementation of the JSON5 data format."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8.0"
|
python-versions = ">=3.8.0"
|
||||||
files = [
|
files = [
|
||||||
{file = "json5-0.9.28-py3-none-any.whl", hash = "sha256:29c56f1accdd8bc2e037321237662034a7e07921e2b7223281a5ce2c46f0c4df"},
|
{file = "json5-0.10.0-py3-none-any.whl", hash = "sha256:19b23410220a7271e8377f81ba8aacba2fdd56947fbb137ee5977cbe1f5e8dfa"},
|
||||||
{file = "json5-0.9.28.tar.gz", hash = "sha256:1f82f36e615bc5b42f1bbd49dbc94b12563c56408c6ffa06414ea310890e9a6e"},
|
{file = "json5-0.10.0.tar.gz", hash = "sha256:e66941c8f0a02026943c52c2eb34ebeb2a6f819a0be05920a6f5243cd30fd559"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
@ -299,42 +299,72 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "six"
|
name = "six"
|
||||||
version = "1.16.0"
|
version = "1.17.0"
|
||||||
description = "Python 2 and 3 compatibility utilities"
|
description = "Python 2 and 3 compatibility utilities"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
|
||||||
files = [
|
files = [
|
||||||
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
|
{file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"},
|
||||||
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
|
{file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tomli"
|
name = "tomli"
|
||||||
version = "2.1.0"
|
version = "2.2.1"
|
||||||
description = "A lil' TOML parser"
|
description = "A lil' TOML parser"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "tomli-2.1.0-py3-none-any.whl", hash = "sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391"},
|
{file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"},
|
||||||
{file = "tomli-2.1.0.tar.gz", hash = "sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8"},
|
{file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"},
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"},
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"},
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"},
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"},
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"},
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"},
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"},
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"},
|
||||||
|
{file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"},
|
||||||
|
{file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tqdm"
|
name = "tqdm"
|
||||||
version = "4.67.0"
|
version = "4.67.1"
|
||||||
description = "Fast, Extensible Progress Meter"
|
description = "Fast, Extensible Progress Meter"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
{file = "tqdm-4.67.0-py3-none-any.whl", hash = "sha256:0cd8af9d56911acab92182e88d763100d4788bdf421d251616040cc4d44863be"},
|
{file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"},
|
||||||
{file = "tqdm-4.67.0.tar.gz", hash = "sha256:fe5a6f95e6fe0b9755e9469b77b9c3cf850048224ecaa8293d7d2d31f97d869a"},
|
{file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"]
|
dev = ["nbval", "pytest (>=6)", "pytest-asyncio (>=0.24)", "pytest-cov", "pytest-timeout"]
|
||||||
discord = ["requests"]
|
discord = ["requests"]
|
||||||
notebook = ["ipywidgets (>=6)"]
|
notebook = ["ipywidgets (>=6)"]
|
||||||
slack = ["slack-sdk"]
|
slack = ["slack-sdk"]
|
||||||
@ -361,4 +391,4 @@ dev = ["doc8", "flake8", "flake8-import-order", "rstcheck[sphinx]", "sphinx"]
|
|||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.10"
|
python-versions = "^3.10"
|
||||||
content-hash = "5cb350262cf59a02e2e4a08f10fde820cd5bf72c3c7b70ae20f6dd990380d099"
|
content-hash = "01b1e2f910276dd20a70ebb665c83415c37531709d90874f5b7a86a5305e2369"
|
||||||
|
1
public/assets/img/svg/octicon-sparkles-fill.svg
generated
Normal file
1
public/assets/img/svg/octicon-sparkles-fill.svg
generated
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" class="svg octicon-sparkles-fill" width="16" height="16" aria-hidden="true"><path d="M9.6 2.279a.426.426 0 0 1 .8 0l.407 1.112a6.39 6.39 0 0 0 3.802 3.802l1.112.407a.426.426 0 0 1 0 .8l-1.112.407a6.39 6.39 0 0 0-3.802 3.802l-.407 1.112a.426.426 0 0 1-.8 0l-.407-1.112a6.39 6.39 0 0 0-3.802-3.802L4.279 8.4a.426.426 0 0 1 0-.8l1.112-.407a6.39 6.39 0 0 0 3.802-3.802zm-4.267 8.837a.178.178 0 0 1 .334 0l.169.464a2.66 2.66 0 0 0 1.584 1.584l.464.169a.178.178 0 0 1 0 .334l-.464.169a2.66 2.66 0 0 0-1.584 1.584l-.169.464a.178.178 0 0 1-.334 0l-.169-.464a2.66 2.66 0 0 0-1.584-1.584l-.464-.169a.178.178 0 0 1 0-.334l.464-.169a2.66 2.66 0 0 0 1.584-1.584zM2.8.14a.213.213 0 0 1 .4 0l.203.556a3.2 3.2 0 0 0 1.901 1.901l.556.203a.213.213 0 0 1 0 .4l-.556.203a3.2 3.2 0 0 0-1.901 1.901L3.2 5.86a.213.213 0 0 1-.4 0l-.203-.556A3.2 3.2 0 0 0 .696 3.403L.14 3.2a.213.213 0 0 1 0-.4l.556-.203A3.2 3.2 0 0 0 2.597.696z"/></svg>
|
After Width: | Height: | Size: 973 B |
@ -5,7 +5,7 @@ package-mode = false
|
|||||||
python = "^3.10"
|
python = "^3.10"
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
djlint = "1.36.1"
|
djlint = "1.36.3"
|
||||||
yamllint = "1.35.1"
|
yamllint = "1.35.1"
|
||||||
|
|
||||||
[tool.djlint]
|
[tool.djlint]
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
package repo
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
@ -40,8 +39,7 @@ func IssueStopwatch(c *context.Context) {
|
|||||||
c.Flash.Success(c.Tr("repo.issues.tracker_auto_close"))
|
c.Flash.Success(c.Tr("repo.issues.tracker_auto_close"))
|
||||||
}
|
}
|
||||||
|
|
||||||
url := issue.Link()
|
c.JSONRedirect("")
|
||||||
c.Redirect(url, http.StatusSeeOther)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CancelStopwatch cancel the stopwatch
|
// CancelStopwatch cancel the stopwatch
|
||||||
@ -72,8 +70,7 @@ func CancelStopwatch(c *context.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
url := issue.Link()
|
c.JSONRedirect("")
|
||||||
c.Redirect(url, http.StatusSeeOther)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetActiveStopwatch is the middleware that sets .ActiveStopwatch on context
|
// GetActiveStopwatch is the middleware that sets .ActiveStopwatch on context
|
||||||
|
@ -5,6 +5,7 @@ package repo
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
@ -13,6 +14,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/web"
|
"code.gitea.io/gitea/modules/web"
|
||||||
"code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
"code.gitea.io/gitea/services/forms"
|
"code.gitea.io/gitea/services/forms"
|
||||||
|
issue_service "code.gitea.io/gitea/services/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddTimeManually tracks time manually
|
// AddTimeManually tracks time manually
|
||||||
@ -26,19 +28,16 @@ func AddTimeManually(c *context.Context) {
|
|||||||
c.NotFound("CanUseTimetracker", nil)
|
c.NotFound("CanUseTimetracker", nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
url := issue.Link()
|
|
||||||
|
|
||||||
if c.HasError() {
|
if c.HasError() {
|
||||||
c.Flash.Error(c.GetErrMsg())
|
c.JSONError(c.GetErrMsg())
|
||||||
c.Redirect(url)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
total := time.Duration(form.Hours)*time.Hour + time.Duration(form.Minutes)*time.Minute
|
total := time.Duration(form.Hours)*time.Hour + time.Duration(form.Minutes)*time.Minute
|
||||||
|
|
||||||
if total <= 0 {
|
if total <= 0 {
|
||||||
c.Flash.Error(c.Tr("repo.issues.add_time_sum_to_small"))
|
c.JSONError(c.Tr("repo.issues.add_time_sum_to_small"))
|
||||||
c.Redirect(url, http.StatusSeeOther)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +46,7 @@ func AddTimeManually(c *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Redirect(url, http.StatusSeeOther)
|
c.JSONRedirect("")
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteTime deletes tracked time
|
// DeleteTime deletes tracked time
|
||||||
@ -83,5 +82,38 @@ func DeleteTime(c *context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.Flash.Success(c.Tr("repo.issues.del_time_history", util.SecToTime(t.Time)))
|
c.Flash.Success(c.Tr("repo.issues.del_time_history", util.SecToTime(t.Time)))
|
||||||
c.Redirect(issue.Link())
|
c.JSONRedirect("")
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
timeStr := strings.TrimSpace(ctx.FormString("time_estimate"))
|
||||||
|
|
||||||
|
total, err := util.TimeEstimateParse(timeStr)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSONError(ctx.Tr("repo.issues.time_estimate_invalid"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// No time changed
|
||||||
|
if issue.TimeEstimate == total {
|
||||||
|
ctx.JSONRedirect("")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := issue_service.ChangeTimeEstimate(ctx, issue, ctx.Doer, total); err != nil {
|
||||||
|
ctx.ServerError("ChangeTimeEstimate", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSONRedirect("")
|
||||||
}
|
}
|
||||||
|
@ -1235,6 +1235,7 @@ func registerRoutes(m *web.Router) {
|
|||||||
m.Post("/cancel", repo.CancelStopwatch)
|
m.Post("/cancel", repo.CancelStopwatch)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
m.Post("/time_estimate", repo.UpdateIssueTimeEstimate)
|
||||||
m.Post("/reactions/{action}", web.Bind(forms.ReactionForm{}), repo.ChangeIssueReaction)
|
m.Post("/reactions/{action}", web.Bind(forms.ReactionForm{}), repo.ChangeIssueReaction)
|
||||||
m.Post("/lock", reqRepoIssuesOrPullsWriter, web.Bind(forms.IssueLockForm{}), repo.LockIssue)
|
m.Post("/lock", reqRepoIssuesOrPullsWriter, web.Bind(forms.IssueLockForm{}), repo.LockIssue)
|
||||||
m.Post("/unlock", reqRepoIssuesOrPullsWriter, repo.UnlockIssue)
|
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 "|" delimiter and convert new to legacy format on demand
|
// so we check for the "|" delimiter and convert new to legacy format on demand
|
||||||
c.Content = util.SecToTime(c.Content[1:])
|
c.Content = util.SecToTime(c.Content[1:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.Type == issues_model.CommentTypeChangeTimeEstimate {
|
||||||
|
timeSec, _ := util.ToInt64(c.Content)
|
||||||
|
c.Content = util.TimeEstimateString(timeSec)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
comment := &api.TimelineComment{
|
comment := &api.TimelineComment{
|
||||||
|
@ -43,6 +43,7 @@ var hiddenCommentTypeGroups = hiddenCommentTypeGroupsType{
|
|||||||
/*14*/ issues_model.CommentTypeAddTimeManual,
|
/*14*/ issues_model.CommentTypeAddTimeManual,
|
||||||
/*15*/ issues_model.CommentTypeCancelTracking,
|
/*15*/ issues_model.CommentTypeCancelTracking,
|
||||||
/*26*/ issues_model.CommentTypeDeleteTimeManual,
|
/*26*/ issues_model.CommentTypeDeleteTimeManual,
|
||||||
|
/*38*/ issues_model.CommentTypeChangeTimeEstimate,
|
||||||
},
|
},
|
||||||
"deadline": {
|
"deadline": {
|
||||||
/*16*/ issues_model.CommentTypeAddedDeadline,
|
/*16*/ issues_model.CommentTypeAddedDeadline,
|
||||||
|
@ -105,6 +105,13 @@ func ChangeTitle(ctx context.Context, issue *issues_model.Issue, doer *user_mode
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ChangeTimeEstimate changes the time estimate of this issue, as the given user.
|
||||||
|
func ChangeTimeEstimate(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, timeEstimate int64) (err error) {
|
||||||
|
issue.TimeEstimate = timeEstimate
|
||||||
|
|
||||||
|
return issues_model.ChangeIssueTimeEstimate(ctx, issue, doer, timeEstimate)
|
||||||
|
}
|
||||||
|
|
||||||
// ChangeIssueRef changes the branch of this issue, as the given user.
|
// 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 {
|
func ChangeIssueRef(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, ref string) error {
|
||||||
oldRef := issue.Ref
|
oldRef := issue.Ref
|
||||||
|
@ -1,60 +1,78 @@
|
|||||||
{{if .Repository.IsTimetrackerEnabled ctx}}
|
{{if .Repository.IsTimetrackerEnabled ctx}}
|
||||||
{{if and .CanUseTimetracker (not .Repository.IsArchived)}}
|
{{if and .CanUseTimetracker (not .Repository.IsArchived)}}
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
<div class="ui timetrack">
|
<div>
|
||||||
<span class="text"><strong>{{ctx.Locale.Tr "repo.issues.tracker"}}</strong></span>
|
<div class="ui dropdown jump">
|
||||||
<div class="tw-mt-2">
|
<a class="text muted">
|
||||||
<form method="post" action="{{.Issue.Link}}/times/stopwatch/toggle" id="toggle_stopwatch_form">
|
<strong>{{ctx.Locale.Tr "repo.issues.tracker"}}</strong> {{svg "octicon-gear"}}
|
||||||
{{$.CsrfTokenHtml}}
|
{{if $.IsStopwatchRunning}}{{svg "octicon-stopwatch"}}{{end}}
|
||||||
</form>
|
</a>
|
||||||
<form method="post" action="{{.Issue.Link}}/times/stopwatch/cancel" id="cancel_stopwatch_form">
|
<div class="menu">
|
||||||
{{$.CsrfTokenHtml}}
|
<a class="item issue-set-time-estimate show-modal" data-modal="#issue-time-set-estimate-modal">
|
||||||
</form>
|
{{svg "octicon-pencil"}} {{ctx.Locale.Tr "repo.issues.time_estimate_set"}}
|
||||||
{{if $.IsStopwatchRunning}}
|
</a>
|
||||||
<button class="ui fluid button issue-stop-time">
|
<div class="divider"></div>
|
||||||
{{svg "octicon-stopwatch" 16 "tw-mr-2"}}
|
{{if $.IsStopwatchRunning}}
|
||||||
{{ctx.Locale.Tr "repo.issues.stop_tracking"}}
|
<a class="item issue-stop-time link-action" data-url="{{.Issue.Link}}/times/stopwatch/toggle">
|
||||||
</button>
|
{{svg "octicon-stopwatch"}} {{ctx.Locale.Tr "repo.issues.timetracker_timer_stop"}}
|
||||||
<button class="ui fluid button issue-cancel-time tw-mt-2">
|
</a>
|
||||||
{{svg "octicon-trash" 16 "tw-mr-2"}}
|
<a class="item issue-cancel-time link-action" data-url="{{.Issue.Link}}/times/stopwatch/cancel">
|
||||||
{{ctx.Locale.Tr "repo.issues.cancel_tracking"}}
|
{{svg "octicon-trash"}} {{ctx.Locale.Tr "repo.issues.timetracker_timer_discard"}}
|
||||||
</button>
|
</a>
|
||||||
{{else}}
|
{{else}}
|
||||||
{{if .HasUserStopwatch}}
|
<a class="item issue-start-time link-action" data-url="{{.Issue.Link}}/times/stopwatch/toggle">
|
||||||
<div class="ui warning message">
|
{{svg "octicon-stopwatch"}} {{ctx.Locale.Tr "repo.issues.timetracker_timer_start"}}
|
||||||
{{ctx.Locale.Tr "repo.issues.tracking_already_started" .OtherStopwatchURL}}
|
</a>
|
||||||
</div>
|
<a class="item issue-add-time show-modal" data-modal="#issue-time-manually-add-modal">
|
||||||
|
{{svg "octicon-plus"}} {{ctx.Locale.Tr "repo.issues.timetracker_timer_manually_add"}}
|
||||||
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
<button class="ui fluid button issue-start-time" data-tooltip-content='{{ctx.Locale.Tr "repo.issues.start_tracking"}}'>
|
</div>
|
||||||
{{svg "octicon-stopwatch" 16 "tw-mr-2"}}
|
</div>
|
||||||
{{ctx.Locale.Tr "repo.issues.start_tracking_short"}}
|
|
||||||
</button>
|
{{if and (not $.IsStopwatchRunning) .HasUserStopwatch}}
|
||||||
<div class="ui mini modal issue-start-time-modal">
|
<div class="ui warning message">{{ctx.Locale.Tr "repo.issues.tracking_already_started" .OtherStopwatchURL}}</div>
|
||||||
<div class="header">{{ctx.Locale.Tr "repo.issues.add_time"}}</div>
|
{{end}}
|
||||||
<div class="content">
|
|
||||||
<form method="post" id="add_time_manual_form" action="{{.Issue.Link}}/times/add" class="ui input fluid tw-gap-2">
|
{{if .Issue.TimeEstimate}}
|
||||||
{{$.CsrfTokenHtml}}
|
<div class="tw-my-2">{{ctx.Locale.Tr "repo.issues.time_estimate_display" (TimeEstimateString .Issue.TimeEstimate)}}</div>
|
||||||
<input placeholder='{{ctx.Locale.Tr "repo.issues.add_time_hours"}}' type="number" name="hours">
|
{{end}}
|
||||||
<input placeholder='{{ctx.Locale.Tr "repo.issues.add_time_minutes"}}' type="number" name="minutes" class="ui compact">
|
|
||||||
</form>
|
{{/* set time estimate modal */}}
|
||||||
</div>
|
<div class="ui mini modal" id="issue-time-set-estimate-modal">
|
||||||
|
<div class="header">{{ctx.Locale.Tr "repo.issues.time_estimate_set"}}</div>
|
||||||
|
<form method="post" class="ui form form-fetch-action" action="{{.Issue.Link}}/time_estimate">
|
||||||
|
<div class="content">
|
||||||
|
{{$.CsrfTokenHtml}}
|
||||||
|
<input name="time_estimate" placeholder="{{ctx.Locale.Tr "repo.issues.time_estimate_placeholder"}}" value="{{TimeEstimateString .Issue.TimeEstimate}}">
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<button class="ui primary approve button">{{ctx.Locale.Tr "repo.issues.add_time_short"}}</button>
|
<button class="ui cancel button">{{ctx.Locale.Tr "cancel"}}</button>
|
||||||
<button class="ui cancel button">{{ctx.Locale.Tr "repo.issues.add_time_cancel"}}</button>
|
<button class="ui primary button">{{ctx.Locale.Tr "repo.issues.save"}}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="ui fluid button issue-add-time tw-mt-2" data-tooltip-content='{{ctx.Locale.Tr "repo.issues.add_time"}}'>
|
</form>
|
||||||
{{svg "octicon-plus" 16 "tw-mr-2"}}
|
</div>
|
||||||
{{ctx.Locale.Tr "repo.issues.add_time_short"}}
|
|
||||||
</button>
|
{{/* manually add time modal */}}
|
||||||
{{end}}
|
<div class="ui mini modal" id="issue-time-manually-add-modal">
|
||||||
|
<div class="header">{{ctx.Locale.Tr "repo.issues.add_time_manually"}}</div>
|
||||||
|
<form method="post" class="ui form form-fetch-action" action="{{.Issue.Link}}/times/add">
|
||||||
|
<div class="content flex-text-block">
|
||||||
|
{{$.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">
|
||||||
|
</div>
|
||||||
|
<div class="actions">
|
||||||
|
<button class="ui cancel button">{{ctx.Locale.Tr "cancel"}}</button>
|
||||||
|
<button class="ui primary button">{{ctx.Locale.Tr "repo.issues.timetracker_timer_manually_add"}}</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .WorkingUsers}}
|
{{if .WorkingUsers}}
|
||||||
<div class="divider"></div>
|
<div class="ui comments tw-mt-2">
|
||||||
<div class="ui comments">
|
{{ctx.Locale.Tr "repo.issues.time_spent_from_all_authors" ($.Issue.TotalTrackedTime | Sec2Time)}}
|
||||||
<span class="text"><strong>{{ctx.Locale.Tr "repo.issues.time_spent_from_all_authors" ($.Issue.TotalTrackedTime | Sec2Time)}}</strong></span>
|
|
||||||
<div>
|
<div>
|
||||||
{{range $user, $trackedtime := .WorkingUsers}}
|
{{range $user, $trackedtime := .WorkingUsers}}
|
||||||
<div class="comment tw-mt-2">
|
<div class="comment tw-mt-2">
|
||||||
|
@ -12,7 +12,8 @@
|
|||||||
26 = DELETE_TIME_MANUAL, 27 = REVIEW_REQUEST, 28 = MERGE_PULL_REQUEST,
|
26 = DELETE_TIME_MANUAL, 27 = REVIEW_REQUEST, 28 = MERGE_PULL_REQUEST,
|
||||||
29 = PULL_PUSH_EVENT, 30 = PROJECT_CHANGED, 31 = PROJECT_BOARD_CHANGED
|
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,
|
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}}
|
{{if eq .Type 0}}
|
||||||
<div class="timeline-item comment" id="{{.HashTag}}">
|
<div class="timeline-item comment" id="{{.HashTag}}">
|
||||||
{{if .OriginalAuthor}}
|
{{if .OriginalAuthor}}
|
||||||
@ -250,18 +251,11 @@
|
|||||||
{{template "shared/user/avatarlink" dict "user" .Poster}}
|
{{template "shared/user/avatarlink" dict "user" .Poster}}
|
||||||
<span class="text grey muted-links">
|
<span class="text grey muted-links">
|
||||||
{{template "shared/user/authorlink" .Poster}}
|
{{template "shared/user/authorlink" .Poster}}
|
||||||
{{ctx.Locale.Tr "repo.issues.stop_tracking_history" $createdStr}}
|
{{$timeStr := .RenderedContent}} {{/* compatibility with time comments made before v1.21 */}}
|
||||||
|
{{if not $timeStr}}{{$timeStr = .Content|Sec2Time}}{{end}}
|
||||||
|
{{ctx.Locale.Tr "repo.issues.stop_tracking_history" $timeStr $createdStr}}
|
||||||
</span>
|
</span>
|
||||||
{{template "repo/issue/view_content/comments_delete_time" dict "ctxData" $ "comment" .}}
|
{{template "repo/issue/view_content/comments_delete_time" dict "ctxData" $ "comment" .}}
|
||||||
<div class="detail flex-text-block">
|
|
||||||
{{svg "octicon-clock"}}
|
|
||||||
{{if .RenderedContent}}
|
|
||||||
{{/* compatibility with time comments made before v1.21 */}}
|
|
||||||
<span class="text grey muted-links">{{.RenderedContent}}</span>
|
|
||||||
{{else}}
|
|
||||||
<span class="text grey muted-links">{{.Content|Sec2Time}}</span>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{{else if eq .Type 14}}
|
{{else if eq .Type 14}}
|
||||||
<div class="timeline-item event" id="{{.HashTag}}">
|
<div class="timeline-item event" id="{{.HashTag}}">
|
||||||
@ -269,18 +263,11 @@
|
|||||||
{{template "shared/user/avatarlink" dict "user" .Poster}}
|
{{template "shared/user/avatarlink" dict "user" .Poster}}
|
||||||
<span class="text grey muted-links">
|
<span class="text grey muted-links">
|
||||||
{{template "shared/user/authorlink" .Poster}}
|
{{template "shared/user/authorlink" .Poster}}
|
||||||
{{ctx.Locale.Tr "repo.issues.add_time_history" $createdStr}}
|
{{$timeStr := .RenderedContent}} {{/* compatibility with time comments made before v1.21 */}}
|
||||||
|
{{if not $timeStr}}{{$timeStr = .Content|Sec2Time}}{{end}}
|
||||||
|
{{ctx.Locale.Tr "repo.issues.add_time_history" $timeStr $createdStr}}
|
||||||
</span>
|
</span>
|
||||||
{{template "repo/issue/view_content/comments_delete_time" dict "ctxData" $ "comment" .}}
|
{{template "repo/issue/view_content/comments_delete_time" dict "ctxData" $ "comment" .}}
|
||||||
<div class="detail flex-text-block">
|
|
||||||
{{svg "octicon-clock"}}
|
|
||||||
{{if .RenderedContent}}
|
|
||||||
{{/* compatibility with time comments made before v1.21 */}}
|
|
||||||
<span class="text grey muted-links">{{.RenderedContent}}</span>
|
|
||||||
{{else}}
|
|
||||||
<span class="text grey muted-links">{{.Content|Sec2Time}}</span>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{{else if eq .Type 15}}
|
{{else if eq .Type 15}}
|
||||||
<div class="timeline-item event" id="{{.HashTag}}">
|
<div class="timeline-item event" id="{{.HashTag}}">
|
||||||
@ -703,6 +690,20 @@
|
|||||||
{{else}}{{ctx.Locale.Tr "repo.issues.unpin_comment" $createdStr}}{{end}}
|
{{else}}{{ctx.Locale.Tr "repo.issues.unpin_comment" $createdStr}}{{end}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</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}}
|
||||||
|
{{$timeStr := .Content|TimeEstimateString}}
|
||||||
|
{{if $timeStr}}
|
||||||
|
{{ctx.Locale.Tr "repo.issues.change_time_estimate_at" $timeStr $createdStr}}
|
||||||
|
{{else}}
|
||||||
|
{{ctx.Locale.Tr "repo.issues.remove_time_estimate_at" $createdStr}}
|
||||||
|
{{end}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -2,14 +2,10 @@
|
|||||||
{{if (not .comment.Time.Deleted)}}
|
{{if (not .comment.Time.Deleted)}}
|
||||||
{{if (or .ctxData.IsAdmin (and .ctxData.IsSigned (eq .ctxData.SignedUserID .comment.PosterID)))}}
|
{{if (or .ctxData.IsAdmin (and .ctxData.IsSigned (eq .ctxData.SignedUserID .comment.PosterID)))}}
|
||||||
<span class="tw-float-right">
|
<span class="tw-float-right">
|
||||||
<div class="ui mini modal issue-delete-time-modal" data-id="{{.comment.Time.ID}}">
|
<button class="ui icon button compact mini link-action" data-tooltip-content="{{ctx.Locale.Tr "repo.issues.del_time"}}"
|
||||||
<form method="post" class="delete-time-form" action="{{.ctxData.RepoLink}}/issues/{{.ctxData.Issue.Index}}/times/{{.comment.TimeID}}/delete">
|
data-url="{{.ctxData.RepoLink}}/issues/{{.ctxData.Issue.Index}}/times/{{.comment.TimeID}}/delete?id={{.comment.Time.ID}}"
|
||||||
{{.ctxData.CsrfTokenHtml}}
|
data-modal-confirm="{{ctx.Locale.Tr "repo.issues.del_time"}}"
|
||||||
</form>
|
>
|
||||||
<div class="header">{{ctx.Locale.Tr "repo.issues.del_time"}}</div>
|
|
||||||
{{template "base/modal_actions_confirm"}}
|
|
||||||
</div>
|
|
||||||
<button class="ui icon button compact mini issue-delete-time" data-id="{{.comment.Time.ID}}" data-tooltip-content="{{ctx.Locale.Tr "repo.issues.del_time"}}">
|
|
||||||
{{svg "octicon-trash"}}
|
{{svg "octicon-trash"}}
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
|
@ -53,20 +53,18 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
<label>{{ctx.Locale.Tr "repo.fork_branch"}}</label>
|
<label>{{ctx.Locale.Tr "repo.fork_branch"}}</label>
|
||||||
<div class="ui selection dropdown">
|
<div class="ui selection dropdown ellipsis-items-nowrap">
|
||||||
<input type="hidden" id="fork_single_branch" name="fork_single_branch" value="" required>
|
<input type="hidden" id="fork_single_branch" name="fork_single_branch" value="" required>
|
||||||
<span class="text truncated-item-container" data-value="" title="{{ctx.Locale.Tr "repo.all_branches"}}">
|
<div class="text" title="{{ctx.Locale.Tr "repo.all_branches"}}">
|
||||||
<span class="truncated-item-name">{{ctx.Locale.Tr "repo.all_branches"}}</span>
|
<span class="truncated-item-name">{{ctx.Locale.Tr "repo.all_branches"}}</span>
|
||||||
</span>
|
</div>
|
||||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<div class="item truncated-item-container" data-value="" title="{{ctx.Locale.Tr "repo.all_branches"}}">
|
<div class="item" data-value="" title="{{ctx.Locale.Tr "repo.all_branches"}}">
|
||||||
<span class="truncated-item-name">{{ctx.Locale.Tr "repo.all_branches"}}</span>
|
{{ctx.Locale.Tr "repo.all_branches"}}
|
||||||
</div>
|
</div>
|
||||||
{{range .Branches}}
|
{{range .Branches}}
|
||||||
<div class="item truncated-item-container" data-value="{{.}}" title="{{.}}">
|
<div class="item" data-value="{{.}}" title="{{.}}">{{.}}</div>
|
||||||
<span class="truncated-item-name">{{.}}</span>
|
|
||||||
</div>
|
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -24,15 +24,9 @@ func NewHTMLParser(t testing.TB, body *bytes.Buffer) *HTMLDoc {
|
|||||||
return &HTMLDoc{doc: doc}
|
return &HTMLDoc{doc: doc}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetInputValueByID for get input value by id
|
|
||||||
func (doc *HTMLDoc) GetInputValueByID(id string) string {
|
|
||||||
text, _ := doc.doc.Find("#" + id).Attr("value")
|
|
||||||
return text
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetInputValueByName for get input value by name
|
// GetInputValueByName for get input value by name
|
||||||
func (doc *HTMLDoc) GetInputValueByName(name string) string {
|
func (doc *HTMLDoc) GetInputValueByName(name string) string {
|
||||||
text, _ := doc.doc.Find("input[name=\"" + name + "\"]").Attr("value")
|
text, _ := doc.doc.Find(`input[name="` + name + `"]`).Attr("value")
|
||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/test"
|
|
||||||
"code.gitea.io/gitea/tests"
|
"code.gitea.io/gitea/tests"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -17,22 +16,24 @@ import (
|
|||||||
|
|
||||||
func TestViewTimetrackingControls(t *testing.T) {
|
func TestViewTimetrackingControls(t *testing.T) {
|
||||||
defer tests.PrepareTestEnv(t)()
|
defer tests.PrepareTestEnv(t)()
|
||||||
session := loginUser(t, "user2")
|
|
||||||
testViewTimetrackingControls(t, session, "user2", "repo1", "1", true)
|
|
||||||
// user2/repo1
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNotViewTimetrackingControls(t *testing.T) {
|
t.Run("Exist", func(t *testing.T) {
|
||||||
defer tests.PrepareTestEnv(t)()
|
defer tests.PrintCurrentTest(t)()
|
||||||
session := loginUser(t, "user5")
|
session := loginUser(t, "user2")
|
||||||
testViewTimetrackingControls(t, session, "user2", "repo1", "1", false)
|
testViewTimetrackingControls(t, session, "user2", "repo1", "1", true)
|
||||||
// user2/repo1
|
})
|
||||||
}
|
|
||||||
|
|
||||||
func TestViewTimetrackingControlsDisabled(t *testing.T) {
|
t.Run("Non-exist", func(t *testing.T) {
|
||||||
defer tests.PrepareTestEnv(t)()
|
defer tests.PrintCurrentTest(t)()
|
||||||
session := loginUser(t, "user2")
|
session := loginUser(t, "user5")
|
||||||
testViewTimetrackingControls(t, session, "org3", "repo3", "1", false)
|
testViewTimetrackingControls(t, session, "user2", "repo1", "1", false)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Disabled", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
session := loginUser(t, "user2")
|
||||||
|
testViewTimetrackingControls(t, session, "org3", "repo3", "1", false)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func testViewTimetrackingControls(t *testing.T, session *TestSession, user, repo, issue string, canTrackTime bool) {
|
func testViewTimetrackingControls(t *testing.T, session *TestSession, user, repo, issue string, canTrackTime bool) {
|
||||||
@ -41,40 +42,40 @@ func testViewTimetrackingControls(t *testing.T, session *TestSession, user, repo
|
|||||||
|
|
||||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||||
|
|
||||||
htmlDoc.AssertElement(t, ".timetrack .issue-start-time", canTrackTime)
|
htmlDoc.AssertElement(t, ".issue-start-time", canTrackTime)
|
||||||
htmlDoc.AssertElement(t, ".timetrack .issue-add-time", canTrackTime)
|
htmlDoc.AssertElement(t, ".issue-add-time", canTrackTime)
|
||||||
|
|
||||||
req = NewRequestWithValues(t, "POST", path.Join(user, repo, "issues", issue, "times", "stopwatch", "toggle"), map[string]string{
|
issueLink := path.Join(user, repo, "issues", issue)
|
||||||
|
req = NewRequestWithValues(t, "POST", path.Join(issueLink, "times", "stopwatch", "toggle"), map[string]string{
|
||||||
"_csrf": htmlDoc.GetCSRF(),
|
"_csrf": htmlDoc.GetCSRF(),
|
||||||
})
|
})
|
||||||
if canTrackTime {
|
if canTrackTime {
|
||||||
resp = session.MakeRequest(t, req, http.StatusSeeOther)
|
session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
req = NewRequest(t, "GET", test.RedirectURL(resp))
|
req = NewRequest(t, "GET", issueLink)
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||||
htmlDoc = NewHTMLParser(t, resp.Body)
|
htmlDoc = NewHTMLParser(t, resp.Body)
|
||||||
|
|
||||||
events := htmlDoc.doc.Find(".event > span.text")
|
events := htmlDoc.doc.Find(".event > span.text")
|
||||||
assert.Contains(t, events.Last().Text(), "started working")
|
assert.Contains(t, events.Last().Text(), "started working")
|
||||||
|
|
||||||
htmlDoc.AssertElement(t, ".timetrack .issue-stop-time", true)
|
htmlDoc.AssertElement(t, ".issue-stop-time", true)
|
||||||
htmlDoc.AssertElement(t, ".timetrack .issue-cancel-time", true)
|
htmlDoc.AssertElement(t, ".issue-cancel-time", true)
|
||||||
|
|
||||||
// Sleep for 1 second to not get wrong order for stopping timer
|
// Sleep for 1 second to not get wrong order for stopping timer
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
req = NewRequestWithValues(t, "POST", path.Join(user, repo, "issues", issue, "times", "stopwatch", "toggle"), map[string]string{
|
req = NewRequestWithValues(t, "POST", path.Join(issueLink, "times", "stopwatch", "toggle"), map[string]string{
|
||||||
"_csrf": htmlDoc.GetCSRF(),
|
"_csrf": htmlDoc.GetCSRF(),
|
||||||
})
|
})
|
||||||
resp = session.MakeRequest(t, req, http.StatusSeeOther)
|
session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
req = NewRequest(t, "GET", test.RedirectURL(resp))
|
req = NewRequest(t, "GET", issueLink)
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||||
htmlDoc = NewHTMLParser(t, resp.Body)
|
htmlDoc = NewHTMLParser(t, resp.Body)
|
||||||
|
|
||||||
events = htmlDoc.doc.Find(".event > span.text")
|
events = htmlDoc.doc.Find(".event > span.text")
|
||||||
assert.Contains(t, events.Last().Text(), "stopped working")
|
assert.Contains(t, events.Last().Text(), "worked for ")
|
||||||
htmlDoc.AssertElement(t, ".event .detail .octicon-clock", true)
|
|
||||||
} else {
|
} else {
|
||||||
session.MakeRequest(t, req, http.StatusNotFound)
|
session.MakeRequest(t, req, http.StatusNotFound)
|
||||||
}
|
}
|
||||||
|
@ -11,37 +11,6 @@ import {initRepoIssueSidebar} from './repo-issue-sidebar.ts';
|
|||||||
|
|
||||||
const {appSubUrl} = window.config;
|
const {appSubUrl} = window.config;
|
||||||
|
|
||||||
export function initRepoIssueTimeTracking() {
|
|
||||||
$(document).on('click', '.issue-add-time', () => {
|
|
||||||
$('.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.key === 'Enter') {
|
|
||||||
$('#add_time_manual_form').trigger('submit');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
$(document).on('click', '.issue-start-time, .issue-stop-time', () => {
|
|
||||||
$('#toggle_stopwatch_form').trigger('submit');
|
|
||||||
});
|
|
||||||
$(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');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {HTMLElement} item
|
* @param {HTMLElement} item
|
||||||
*/
|
*/
|
||||||
|
@ -26,7 +26,6 @@ import {initPdfViewer} from './render/pdf.ts';
|
|||||||
import {initUserAuthOauth2, initUserCheckAppUrl} from './features/user-auth.ts';
|
import {initUserAuthOauth2, initUserCheckAppUrl} from './features/user-auth.ts';
|
||||||
import {
|
import {
|
||||||
initRepoIssueReferenceRepositorySearch,
|
initRepoIssueReferenceRepositorySearch,
|
||||||
initRepoIssueTimeTracking,
|
|
||||||
initRepoIssueWipTitle,
|
initRepoIssueWipTitle,
|
||||||
initRepoPullRequestMergeInstruction,
|
initRepoPullRequestMergeInstruction,
|
||||||
initRepoPullRequestAllowMaintainerEdit,
|
initRepoPullRequestAllowMaintainerEdit,
|
||||||
@ -184,7 +183,6 @@ onDomReady(() => {
|
|||||||
initRepoIssueList,
|
initRepoIssueList,
|
||||||
initRepoIssueSidebarList,
|
initRepoIssueSidebarList,
|
||||||
initRepoIssueReferenceRepositorySearch,
|
initRepoIssueReferenceRepositorySearch,
|
||||||
initRepoIssueTimeTracking,
|
|
||||||
initRepoIssueWipTitle,
|
initRepoIssueWipTitle,
|
||||||
initRepoMigration,
|
initRepoMigration,
|
||||||
initRepoMigrationStatusChecker,
|
initRepoMigrationStatusChecker,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user