mirror of
https://github.com/go-gitea/gitea.git
synced 2025-07-18 00:01:32 -04:00
Compare commits
No commits in common. "2b0b56319e94b7173b566af4d082f03664853789" and "41f0668da818d3a3ae74555bfe3de375448bacf3" have entirely different histories.
2b0b56319e
...
41f0668da8
@ -12,8 +12,6 @@ import (
|
|||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
_ "code.gitea.io/gitea/cmd" // for TestPrimaryKeys
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -53,34 +51,3 @@ func TestDeleteOrphanedObjects(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, countBefore, countAfter)
|
assert.EqualValues(t, countBefore, countAfter)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPrimaryKeys(t *testing.T) {
|
|
||||||
// Some dbs require that all tables have primary keys, see
|
|
||||||
// https://github.com/go-gitea/gitea/issues/21086
|
|
||||||
// https://github.com/go-gitea/gitea/issues/16802
|
|
||||||
// To avoid creating tables without primary key again, this test will check them.
|
|
||||||
// Import "code.gitea.io/gitea/cmd" to make sure each db.RegisterModel in init functions has been called.
|
|
||||||
|
|
||||||
beans, err := db.NamesToBean()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
whitelist := map[string]string{
|
|
||||||
"the_table_name_to_skip_checking": "Write a note here to explain why",
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, bean := range beans {
|
|
||||||
table, err := db.TableInfo(bean)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if why, ok := whitelist[table.Name]; ok {
|
|
||||||
t.Logf("ignore %q because %q", table.Name, why)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if len(table.PrimaryKeys) == 0 {
|
|
||||||
t.Errorf("table %q has no primary key", table.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
1
models/fixtures/foreign_reference.yml
Normal file
1
models/fixtures/foreign_reference.yml
Normal file
@ -0,0 +1 @@
|
|||||||
|
[] # empty
|
52
models/foreignreference/error.go
Normal file
52
models/foreignreference/error.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// Copyright 2022 Gitea. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package foreignreference
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrLocalIndexNotExist represents a "LocalIndexNotExist" kind of error.
|
||||||
|
type ErrLocalIndexNotExist struct {
|
||||||
|
RepoID int64
|
||||||
|
ForeignIndex int64
|
||||||
|
Type string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrLocalIndexNotExist checks if an error is a ErrLocalIndexNotExist.
|
||||||
|
func IsErrLocalIndexNotExist(err error) bool {
|
||||||
|
_, ok := err.(ErrLocalIndexNotExist)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrLocalIndexNotExist) Error() string {
|
||||||
|
return fmt.Sprintf("repository %d has no LocalIndex for ForeignIndex %d of type %s", err.RepoID, err.ForeignIndex, err.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrLocalIndexNotExist) Unwrap() error {
|
||||||
|
return util.ErrNotExist
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrForeignIndexNotExist represents a "ForeignIndexNotExist" kind of error.
|
||||||
|
type ErrForeignIndexNotExist struct {
|
||||||
|
RepoID int64
|
||||||
|
LocalIndex int64
|
||||||
|
Type string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrForeignIndexNotExist checks if an error is a ErrForeignIndexNotExist.
|
||||||
|
func IsErrForeignIndexNotExist(err error) bool {
|
||||||
|
_, ok := err.(ErrForeignIndexNotExist)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrForeignIndexNotExist) Error() string {
|
||||||
|
return fmt.Sprintf("repository %d has no ForeignIndex for LocalIndex %d of type %s", err.RepoID, err.LocalIndex, err.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrForeignIndexNotExist) Unwrap() error {
|
||||||
|
return util.ErrNotExist
|
||||||
|
}
|
31
models/foreignreference/foreignreference.go
Normal file
31
models/foreignreference/foreignreference.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// Copyright 2022 Gitea. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package foreignreference
|
||||||
|
|
||||||
|
import (
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Type* are valid values for the Type field of ForeignReference
|
||||||
|
const (
|
||||||
|
TypeIssue = "issue"
|
||||||
|
TypePullRequest = "pull_request"
|
||||||
|
TypeComment = "comment"
|
||||||
|
TypeReview = "review"
|
||||||
|
TypeReviewComment = "review_comment"
|
||||||
|
TypeRelease = "release"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ForeignReference represents external references
|
||||||
|
type ForeignReference struct {
|
||||||
|
// RepoID is the first column in all indices. now we only need 2 indices: (repo, local) and (repo, foreign, type)
|
||||||
|
RepoID int64 `xorm:"UNIQUE(repo_foreign_type) INDEX(repo_local)" `
|
||||||
|
LocalIndex int64 `xorm:"INDEX(repo_local)"` // the resource key inside Gitea, it can be IssueIndex, or some model ID.
|
||||||
|
ForeignIndex string `xorm:"INDEX UNIQUE(repo_foreign_type)"`
|
||||||
|
Type string `xorm:"VARCHAR(16) INDEX UNIQUE(repo_foreign_type)"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
db.RegisterModel(new(ForeignReference))
|
||||||
|
}
|
@ -9,9 +9,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
"code.gitea.io/gitea/models/foreignreference"
|
||||||
"code.gitea.io/gitea/models/organization"
|
"code.gitea.io/gitea/models/organization"
|
||||||
"code.gitea.io/gitea/models/perm"
|
"code.gitea.io/gitea/models/perm"
|
||||||
access_model "code.gitea.io/gitea/models/perm/access"
|
access_model "code.gitea.io/gitea/models/perm/access"
|
||||||
@ -134,11 +136,12 @@ type Issue struct {
|
|||||||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
||||||
ClosedUnix timeutil.TimeStamp `xorm:"INDEX"`
|
ClosedUnix timeutil.TimeStamp `xorm:"INDEX"`
|
||||||
|
|
||||||
Attachments []*repo_model.Attachment `xorm:"-"`
|
Attachments []*repo_model.Attachment `xorm:"-"`
|
||||||
Comments []*Comment `xorm:"-"`
|
Comments []*Comment `xorm:"-"`
|
||||||
Reactions ReactionList `xorm:"-"`
|
Reactions ReactionList `xorm:"-"`
|
||||||
TotalTrackedTime int64 `xorm:"-"`
|
TotalTrackedTime int64 `xorm:"-"`
|
||||||
Assignees []*user_model.User `xorm:"-"`
|
Assignees []*user_model.User `xorm:"-"`
|
||||||
|
ForeignReference *foreignreference.ForeignReference `xorm:"-"`
|
||||||
|
|
||||||
// IsLocked limits commenting abilities to users on an issue
|
// IsLocked limits commenting abilities to users on an issue
|
||||||
// with write access
|
// with write access
|
||||||
@ -318,6 +321,29 @@ func (issue *Issue) loadReactions(ctx context.Context) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (issue *Issue) loadForeignReference(ctx context.Context) (err error) {
|
||||||
|
if issue.ForeignReference != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
reference := &foreignreference.ForeignReference{
|
||||||
|
RepoID: issue.RepoID,
|
||||||
|
LocalIndex: issue.Index,
|
||||||
|
Type: foreignreference.TypeIssue,
|
||||||
|
}
|
||||||
|
has, err := db.GetEngine(ctx).Get(reference)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if !has {
|
||||||
|
return foreignreference.ErrForeignIndexNotExist{
|
||||||
|
RepoID: issue.RepoID,
|
||||||
|
LocalIndex: issue.Index,
|
||||||
|
Type: foreignreference.TypeIssue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
issue.ForeignReference = reference
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// LoadMilestone load milestone of this issue.
|
// LoadMilestone load milestone of this issue.
|
||||||
func (issue *Issue) LoadMilestone(ctx context.Context) (err error) {
|
func (issue *Issue) LoadMilestone(ctx context.Context) (err error) {
|
||||||
if (issue.Milestone == nil || issue.Milestone.ID != issue.MilestoneID) && issue.MilestoneID > 0 {
|
if (issue.Milestone == nil || issue.Milestone.ID != issue.MilestoneID) && issue.MilestoneID > 0 {
|
||||||
@ -380,6 +406,10 @@ func (issue *Issue) LoadAttributes(ctx context.Context) (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err = issue.loadForeignReference(ctx); err != nil && !foreignreference.IsErrForeignIndexNotExist(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return issue.loadReactions(ctx)
|
return issue.loadReactions(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1067,6 +1097,26 @@ func GetIssueByIndex(repoID, index int64) (*Issue, error) {
|
|||||||
return issue, nil
|
return issue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetIssueByForeignIndex returns raw issue by foreign ID
|
||||||
|
func GetIssueByForeignIndex(ctx context.Context, repoID, foreignIndex int64) (*Issue, error) {
|
||||||
|
reference := &foreignreference.ForeignReference{
|
||||||
|
RepoID: repoID,
|
||||||
|
ForeignIndex: strconv.FormatInt(foreignIndex, 10),
|
||||||
|
Type: foreignreference.TypeIssue,
|
||||||
|
}
|
||||||
|
has, err := db.GetEngine(ctx).Get(reference)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if !has {
|
||||||
|
return nil, foreignreference.ErrLocalIndexNotExist{
|
||||||
|
RepoID: repoID,
|
||||||
|
ForeignIndex: foreignIndex,
|
||||||
|
Type: foreignreference.TypeIssue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return GetIssueByIndex(repoID, reference.LocalIndex)
|
||||||
|
}
|
||||||
|
|
||||||
// GetIssueWithAttrsByIndex returns issue by index in a repository.
|
// GetIssueWithAttrsByIndex returns issue by index in a repository.
|
||||||
func GetIssueWithAttrsByIndex(repoID, index int64) (*Issue, error) {
|
func GetIssueWithAttrsByIndex(repoID, index int64) (*Issue, error) {
|
||||||
issue, err := GetIssueByIndex(repoID, index)
|
issue, err := GetIssueByIndex(repoID, index)
|
||||||
|
@ -7,11 +7,13 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
"code.gitea.io/gitea/models/foreignreference"
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/organization"
|
"code.gitea.io/gitea/models/organization"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
@ -499,6 +501,38 @@ func TestCorrectIssueStats(t *testing.T) {
|
|||||||
assert.EqualValues(t, issueStats.OpenCount, issueAmount)
|
assert.EqualValues(t, issueStats.OpenCount, issueAmount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIssueForeignReference(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 4})
|
||||||
|
assert.NotEqualValues(t, issue.Index, issue.ID) // make sure they are different to avoid false positive
|
||||||
|
|
||||||
|
// it is fine for an issue to not have a foreign reference
|
||||||
|
err := issue.LoadAttributes(db.DefaultContext)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Nil(t, issue.ForeignReference)
|
||||||
|
|
||||||
|
var foreignIndex int64 = 12345
|
||||||
|
_, err = issues_model.GetIssueByForeignIndex(context.Background(), issue.RepoID, foreignIndex)
|
||||||
|
assert.True(t, foreignreference.IsErrLocalIndexNotExist(err))
|
||||||
|
|
||||||
|
err = db.Insert(db.DefaultContext, &foreignreference.ForeignReference{
|
||||||
|
LocalIndex: issue.Index,
|
||||||
|
ForeignIndex: strconv.FormatInt(foreignIndex, 10),
|
||||||
|
RepoID: issue.RepoID,
|
||||||
|
Type: foreignreference.TypeIssue,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = issue.LoadAttributes(db.DefaultContext)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.EqualValues(t, issue.ForeignReference.ForeignIndex, strconv.FormatInt(foreignIndex, 10))
|
||||||
|
|
||||||
|
found, err := issues_model.GetIssueByForeignIndex(context.Background(), issue.RepoID, foreignIndex)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, found.Index, issue.Index)
|
||||||
|
}
|
||||||
|
|
||||||
func TestMilestoneList_LoadTotalTrackedTimes(t *testing.T) {
|
func TestMilestoneList_LoadTotalTrackedTimes(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
miles := issues_model.MilestoneList{
|
miles := issues_model.MilestoneList{
|
||||||
|
@ -83,6 +83,13 @@ func insertIssue(ctx context.Context, issue *issues_model.Issue) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if issue.ForeignReference != nil {
|
||||||
|
issue.ForeignReference.LocalIndex = issue.Index
|
||||||
|
if _, err := sess.Insert(issue.ForeignReference); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,9 +4,11 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
"code.gitea.io/gitea/models/foreignreference"
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
@ -46,6 +48,7 @@ func assertCreateIssues(t *testing.T, isPull bool) {
|
|||||||
UserID: owner.ID,
|
UserID: owner.ID,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreignIndex := int64(12345)
|
||||||
title := "issuetitle1"
|
title := "issuetitle1"
|
||||||
is := &issues_model.Issue{
|
is := &issues_model.Issue{
|
||||||
RepoID: repo.ID,
|
RepoID: repo.ID,
|
||||||
@ -59,11 +62,20 @@ func assertCreateIssues(t *testing.T, isPull bool) {
|
|||||||
IsClosed: true,
|
IsClosed: true,
|
||||||
Labels: []*issues_model.Label{label},
|
Labels: []*issues_model.Label{label},
|
||||||
Reactions: []*issues_model.Reaction{reaction},
|
Reactions: []*issues_model.Reaction{reaction},
|
||||||
|
ForeignReference: &foreignreference.ForeignReference{
|
||||||
|
ForeignIndex: strconv.FormatInt(foreignIndex, 10),
|
||||||
|
RepoID: repo.ID,
|
||||||
|
Type: foreignreference.TypeIssue,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
err := InsertIssues(is)
|
err := InsertIssues(is)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
i := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{Title: title})
|
i := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{Title: title})
|
||||||
|
assert.Nil(t, i.ForeignReference)
|
||||||
|
err = i.LoadAttributes(db.DefaultContext)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, strconv.FormatInt(foreignIndex, 10), i.ForeignReference.ForeignIndex)
|
||||||
unittest.AssertExistsAndLoadBean(t, &issues_model.Reaction{Type: "heart", UserID: owner.ID, IssueID: i.ID})
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Reaction{Type: "heart", UserID: owner.ID, IssueID: i.ID})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,8 +444,6 @@ var migrations = []Migration{
|
|||||||
NewMigration("Add index for access_token", v1_19.AddIndexForAccessToken),
|
NewMigration("Add index for access_token", v1_19.AddIndexForAccessToken),
|
||||||
// v236 -> v237
|
// v236 -> v237
|
||||||
NewMigration("Create secrets table", v1_19.CreateSecretsTable),
|
NewMigration("Create secrets table", v1_19.CreateSecretsTable),
|
||||||
// v237 -> v238
|
|
||||||
NewMigration("Drop ForeignReference table", v1_19.DropForeignReferenceTable),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCurrentDBVersion returns the current db version
|
// GetCurrentDBVersion returns the current db version
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package v1_19 //nolint
|
|
||||||
|
|
||||||
import (
|
|
||||||
"xorm.io/xorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
func DropForeignReferenceTable(x *xorm.Engine) error {
|
|
||||||
// Drop the table introduced in `v211`, it's considered badly designed and doesn't look like to be used.
|
|
||||||
// See: https://github.com/go-gitea/gitea/issues/21086#issuecomment-1318217453
|
|
||||||
type ForeignReference struct{}
|
|
||||||
return x.DropTables(new(ForeignReference))
|
|
||||||
}
|
|
@ -17,6 +17,7 @@ import (
|
|||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
"code.gitea.io/gitea/models/foreignreference"
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
@ -402,6 +403,16 @@ func (g *GiteaLocalUploader) CreateIssues(issues ...*base.Issue) error {
|
|||||||
Labels: labels,
|
Labels: labels,
|
||||||
CreatedUnix: timeutil.TimeStamp(issue.Created.Unix()),
|
CreatedUnix: timeutil.TimeStamp(issue.Created.Unix()),
|
||||||
UpdatedUnix: timeutil.TimeStamp(issue.Updated.Unix()),
|
UpdatedUnix: timeutil.TimeStamp(issue.Updated.Unix()),
|
||||||
|
ForeignReference: &foreignreference.ForeignReference{
|
||||||
|
LocalIndex: issue.GetLocalIndex(),
|
||||||
|
ForeignIndex: strconv.FormatInt(issue.GetForeignIndex(), 10),
|
||||||
|
RepoID: g.repo.ID,
|
||||||
|
Type: foreignreference.TypeIssue,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if is.ForeignReference.ForeignIndex == "0" {
|
||||||
|
is.ForeignReference.ForeignIndex = strconv.FormatInt(is.Index, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := g.remapUser(issue, &is); err != nil {
|
if err := g.remapUser(issue, &is); err != nil {
|
||||||
|
@ -11,8 +11,6 @@ import (
|
|||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/tests"
|
"code.gitea.io/gitea/tests"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEmptyRepo(t *testing.T) {
|
func TestEmptyRepo(t *testing.T) {
|
||||||
@ -23,8 +21,7 @@ func TestEmptyRepo(t *testing.T) {
|
|||||||
"commit/1ae57b34ccf7e18373",
|
"commit/1ae57b34ccf7e18373",
|
||||||
"graph",
|
"graph",
|
||||||
}
|
}
|
||||||
emptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 5})
|
emptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{}, unittest.Cond("is_empty = ?", true))
|
||||||
assert.True(t, emptyRepo.IsEmpty)
|
|
||||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: emptyRepo.OwnerID})
|
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: emptyRepo.OwnerID})
|
||||||
for _, subpath := range subpaths {
|
for _, subpath := range subpaths {
|
||||||
req := NewRequestf(t, "GET", "/%s/%s/%s", owner.Name, emptyRepo.Name, subpath)
|
req := NewRequestf(t, "GET", "/%s/%s/%s", owner.Name, emptyRepo.Name, subpath)
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
import {CalendarHeatmap} from 'vue3-calendar-heatmap';
|
import {CalendarHeatmap} from 'vue3-calendar-heatmap';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
name: 'ActivityHeatmap',
|
||||||
components: {CalendarHeatmap},
|
components: {CalendarHeatmap},
|
||||||
props: {
|
props: {
|
||||||
values: {
|
values: {
|
||||||
|
@ -46,13 +46,19 @@ const luminance = (colorString) => {
|
|||||||
const luminanceThreshold = 0.179;
|
const luminanceThreshold = 0.179;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {SvgIcon},
|
name: 'ContextPopup',
|
||||||
|
|
||||||
|
components: {
|
||||||
|
SvgIcon,
|
||||||
|
},
|
||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
loading: false,
|
loading: false,
|
||||||
issue: null,
|
issue: null,
|
||||||
i18nErrorOccurred: i18n.error_occurred,
|
i18nErrorOccurred: i18n.error_occurred,
|
||||||
i18nErrorMessage: null,
|
i18nErrorMessage: null,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
createdAt() {
|
createdAt() {
|
||||||
return new Date(this.issue.created_at).toLocaleDateString(undefined, {year: 'numeric', month: 'short', day: 'numeric'});
|
return new Date(this.issue.created_at).toLocaleDateString(undefined, {year: 'numeric', month: 'short', day: 'numeric'});
|
||||||
@ -101,6 +107,7 @@ export default {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$refs.root.addEventListener('us-load-context-popup', (e) => {
|
this.$refs.root.addEventListener('us-load-context-popup', (e) => {
|
||||||
const data = e.detail;
|
const data = e.detail;
|
||||||
@ -109,6 +116,7 @@ export default {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
load(data) {
|
load(data) {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
@ -27,9 +27,12 @@ import {doLoadMoreFiles} from '../features/repo-diff.js';
|
|||||||
const {pageData} = window.config;
|
const {pageData} = window.config;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
name: 'DiffFileList',
|
||||||
|
|
||||||
data: () => {
|
data: () => {
|
||||||
return pageData.diffFileInfo;
|
return pageData.diffFileInfo;
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
fileListIsVisible(newValue) {
|
fileListIsVisible(newValue) {
|
||||||
if (newValue === true) {
|
if (newValue === true) {
|
||||||
@ -41,12 +44,15 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
document.getElementById('show-file-list-btn').addEventListener('click', this.toggleFileList);
|
document.getElementById('show-file-list-btn').addEventListener('click', this.toggleFileList);
|
||||||
},
|
},
|
||||||
|
|
||||||
unmounted() {
|
unmounted() {
|
||||||
document.getElementById('show-file-list-btn').removeEventListener('click', this.toggleFileList);
|
document.getElementById('show-file-list-btn').removeEventListener('click', this.toggleFileList);
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
toggleFileList() {
|
toggleFileList() {
|
||||||
this.fileListIsVisible = !this.fileListIsVisible;
|
this.fileListIsVisible = !this.fileListIsVisible;
|
||||||
|
@ -21,12 +21,15 @@ const {pageData} = window.config;
|
|||||||
const LOCAL_STORAGE_KEY = 'diff_file_tree_visible';
|
const LOCAL_STORAGE_KEY = 'diff_file_tree_visible';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
name: 'DiffFileTree',
|
||||||
components: {DiffFileTreeItem},
|
components: {DiffFileTreeItem},
|
||||||
|
|
||||||
data: () => {
|
data: () => {
|
||||||
const fileTreeIsVisible = localStorage.getItem(LOCAL_STORAGE_KEY) === 'true';
|
const fileTreeIsVisible = localStorage.getItem(LOCAL_STORAGE_KEY) === 'true';
|
||||||
pageData.diffFileInfo.fileTreeIsVisible = fileTreeIsVisible;
|
pageData.diffFileInfo.fileTreeIsVisible = fileTreeIsVisible;
|
||||||
return pageData.diffFileInfo;
|
return pageData.diffFileInfo;
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
fileTree() {
|
fileTree() {
|
||||||
const result = [];
|
const result = [];
|
||||||
@ -91,6 +94,7 @@ export default {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
// ensure correct buttons when we are mounted to the dom
|
// ensure correct buttons when we are mounted to the dom
|
||||||
this.adjustToggleButton(this.fileTreeIsVisible);
|
this.adjustToggleButton(this.fileTreeIsVisible);
|
||||||
@ -121,7 +125,7 @@ export default {
|
|||||||
doLoadMoreFiles(this.link, this.diffEnd, () => {
|
doLoadMoreFiles(this.link, this.diffEnd, () => {
|
||||||
this.isLoadingNewData = false;
|
this.isLoadingNewData = false;
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -43,7 +43,11 @@
|
|||||||
import {SvgIcon} from '../svg.js';
|
import {SvgIcon} from '../svg.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {SvgIcon},
|
name: 'DiffFileTreeItem',
|
||||||
|
components: {
|
||||||
|
SvgIcon,
|
||||||
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
item: {
|
item: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@ -55,6 +59,7 @@ export default {
|
|||||||
default: true
|
default: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
collapsed: false,
|
collapsed: false,
|
||||||
}),
|
}),
|
||||||
|
@ -111,7 +111,11 @@ import {SvgIcon} from '../svg.js';
|
|||||||
const {csrfToken, pageData} = window.config;
|
const {csrfToken, pageData} = window.config;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {SvgIcon},
|
name: 'PullRequestMergeForm',
|
||||||
|
components: {
|
||||||
|
SvgIcon,
|
||||||
|
},
|
||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
csrfToken,
|
csrfToken,
|
||||||
mergeForm: pageData.pullRequestMergeForm,
|
mergeForm: pageData.pullRequestMergeForm,
|
||||||
@ -133,17 +137,20 @@ export default {
|
|||||||
showMergeStyleMenu: false,
|
showMergeStyleMenu: false,
|
||||||
showActionForm: false,
|
showActionForm: false,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
mergeButtonStyleClass() {
|
mergeButtonStyleClass() {
|
||||||
if (this.mergeForm.allOverridableChecksOk) return 'green';
|
if (this.mergeForm.allOverridableChecksOk) return 'green';
|
||||||
return this.autoMergeWhenSucceed ? 'blue' : 'red';
|
return this.autoMergeWhenSucceed ? 'blue' : 'red';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
mergeStyle(val) {
|
mergeStyle(val) {
|
||||||
this.mergeStyleDetail = this.mergeForm.mergeStyles.find((e) => e.name === val);
|
this.mergeStyleDetail = this.mergeForm.mergeStyles.find((e) => e.name === val);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
this.mergeStyleAllowedCount = this.mergeForm.mergeStyles.reduce((v, msd) => v + (msd.allowed ? 1 : 0), 0);
|
this.mergeStyleAllowedCount = this.mergeForm.mergeStyles.reduce((v, msd) => v + (msd.allowed ? 1 : 0), 0);
|
||||||
|
|
||||||
@ -151,12 +158,15 @@ export default {
|
|||||||
if (!mergeStyle) mergeStyle = this.mergeForm.mergeStyles.find((e) => e.allowed)?.name;
|
if (!mergeStyle) mergeStyle = this.mergeForm.mergeStyles.find((e) => e.allowed)?.name;
|
||||||
this.switchMergeStyle(mergeStyle, !this.mergeForm.canMergeNow);
|
this.switchMergeStyle(mergeStyle, !this.mergeForm.canMergeNow);
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
document.addEventListener('mouseup', this.hideMergeStyleMenu);
|
document.addEventListener('mouseup', this.hideMergeStyleMenu);
|
||||||
},
|
},
|
||||||
|
|
||||||
unmounted() {
|
unmounted() {
|
||||||
document.removeEventListener('mouseup', this.hideMergeStyleMenu);
|
document.removeEventListener('mouseup', this.hideMergeStyleMenu);
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
hideMergeStyleMenu() {
|
hideMergeStyleMenu() {
|
||||||
this.showMergeStyleMenu = false;
|
this.showMergeStyleMenu = false;
|
||||||
|
@ -44,7 +44,7 @@ function fallbackCopyToClipboard(text) {
|
|||||||
|
|
||||||
// For all DOM elements with [data-clipboard-target] or [data-clipboard-text],
|
// For all DOM elements with [data-clipboard-target] or [data-clipboard-text],
|
||||||
// this copy-to-clipboard will work for them
|
// this copy-to-clipboard will work for them
|
||||||
export function initGlobalCopyToClipboardListener() {
|
export default function initGlobalCopyToClipboardListener() {
|
||||||
document.addEventListener('click', (e) => {
|
document.addEventListener('click', (e) => {
|
||||||
let target = e.target;
|
let target = e.target;
|
||||||
// in case <button data-clipboard-text><svg></button>, so we just search
|
// in case <button data-clipboard-text><svg></button>, so we just search
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export async function createColorPicker($els) {
|
export default async function createColorPicker($els) {
|
||||||
if (!$els || !$els.length) return;
|
if (!$els || !$els.length) return;
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import 'jquery.are-you-sure';
|
import 'jquery.are-you-sure';
|
||||||
import {mqBinarySearch} from '../utils.js';
|
import {mqBinarySearch} from '../utils.js';
|
||||||
import {createDropzone} from './dropzone.js';
|
import createDropzone from './dropzone.js';
|
||||||
import {initCompColorPicker} from './comp/ColorPicker.js';
|
import {initCompColorPicker} from './comp/ColorPicker.js';
|
||||||
import {showGlobalErrorMessage} from '../bootstrap.js';
|
import {showGlobalErrorMessage} from '../bootstrap.js';
|
||||||
import {attachDropdownAria} from './aria.js';
|
import {attachDropdownAria} from './aria.js';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import {createColorPicker} from '../colorpicker.js';
|
import createColorPicker from '../colorpicker.js';
|
||||||
|
|
||||||
export function initCompColorPicker() {
|
export function initCompColorPicker() {
|
||||||
createColorPicker($('.color-picker'));
|
createColorPicker($('.color-picker'));
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import {attachTribute} from '../tribute.js';
|
import attachTribute from '../tribute.js';
|
||||||
import {handleGlobalEnterQuickSubmit} from './QuickSubmit.js';
|
import {handleGlobalEnterQuickSubmit} from './QuickSubmit.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,6 +2,7 @@ import $ from 'jquery';
|
|||||||
import {htmlEscape} from 'escape-goat';
|
import {htmlEscape} from 'escape-goat';
|
||||||
|
|
||||||
const {appSubUrl} = window.config;
|
const {appSubUrl} = window.config;
|
||||||
|
|
||||||
const looksLikeEmailAddressCheck = /^\S+@\S+$/;
|
const looksLikeEmailAddressCheck = /^\S+@\S+$/;
|
||||||
|
|
||||||
export function initCompSearchUserBox() {
|
export function initCompSearchUserBox() {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
|
|
||||||
const {csrfToken} = window.config;
|
const {csrfToken} = window.config;
|
||||||
|
|
||||||
export function initCompWebHookEditor() {
|
export function initCompWebHookEditor() {
|
||||||
|
@ -4,7 +4,7 @@ import ContextPopup from '../components/ContextPopup.vue';
|
|||||||
import {parseIssueHref} from '../utils.js';
|
import {parseIssueHref} from '../utils.js';
|
||||||
import {createTippy} from '../modules/tippy.js';
|
import {createTippy} from '../modules/tippy.js';
|
||||||
|
|
||||||
export function initContextPopups() {
|
export default function initContextPopups() {
|
||||||
const refIssues = $('.ref-issue');
|
const refIssues = $('.ref-issue');
|
||||||
if (!refIssues.length) return;
|
if (!refIssues.length) return;
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import {copyToClipboard} from './clipboard.js';
|
import {copyToClipboard} from './clipboard.js';
|
||||||
import {showTemporaryTooltip} from '../modules/tippy.js';
|
import {showTemporaryTooltip} from '../modules/tippy.js';
|
||||||
import {convertImage} from '../utils.js';
|
import {convertImage} from '../utils.js';
|
||||||
|
|
||||||
const {i18n} = window.config;
|
const {i18n} = window.config;
|
||||||
|
|
||||||
async function doCopy(content, btn) {
|
async function doCopy(content, btn) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export async function createDropzone(el, opts) {
|
export default async function createDropzone(el, opts) {
|
||||||
const [{Dropzone}] = await Promise.all([
|
const [{Dropzone}] = await Promise.all([
|
||||||
import(/* webpackChunkName: "dropzone" */'dropzone'),
|
import(/* webpackChunkName: "dropzone" */'dropzone'),
|
||||||
import(/* webpackChunkName: "dropzone" */'dropzone/dist/dropzone.css'),
|
import(/* webpackChunkName: "dropzone" */'dropzone/dist/dropzone.css'),
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import emojis from '../../../assets/emoji.json';
|
import emojis from '../../../assets/emoji.json';
|
||||||
|
|
||||||
const {assetUrlPrefix, customEmojis} = window.config;
|
const {assetUrlPrefix} = window.config;
|
||||||
|
const {customEmojis} = window.config;
|
||||||
|
|
||||||
const tempMap = {...customEmojis};
|
const tempMap = {...customEmojis};
|
||||||
for (const {emoji, aliases} of emojis) {
|
for (const {emoji, aliases} of emojis) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import {svg} from '../svg.js';
|
import {svg} from '../svg.js';
|
||||||
|
|
||||||
|
|
||||||
// Hides the file if newFold is true, and shows it otherwise. The actual hiding is performed using CSS.
|
// Hides the file if newFold is true, and shows it otherwise. The actual hiding is performed using CSS.
|
||||||
//
|
//
|
||||||
// The fold arrow is the icon displayed on the upper left of the file box, especially intended for components having the 'fold-file' class.
|
// The fold arrow is the icon displayed on the upper left of the file box, especially intended for components having the 'fold-file' class.
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import {prettyNumber} from '../utils.js';
|
import {prettyNumber} from '../utils.js';
|
||||||
|
|
||||||
const {lang} = document.documentElement;
|
const {lang} = document.documentElement;
|
||||||
|
|
||||||
const dateFormatter = new Intl.DateTimeFormat(lang, {year: 'numeric', month: 'long', day: 'numeric'});
|
const dateFormatter = new Intl.DateTimeFormat(lang, {year: 'numeric', month: 'long', day: 'numeric'});
|
||||||
const shortDateFormatter = new Intl.DateTimeFormat(lang, {year: 'numeric', month: 'short', day: 'numeric'});
|
const shortDateFormatter = new Intl.DateTimeFormat(lang, {year: 'numeric', month: 'short', day: 'numeric'});
|
||||||
const dateTimeFormatter = new Intl.DateTimeFormat(lang, {year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric'});
|
const dateTimeFormatter = new Intl.DateTimeFormat(lang, {year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric'});
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import {createApp} from 'vue';
|
import {createApp} from 'vue';
|
||||||
import ActivityHeatmap from '../components/ActivityHeatmap.vue';
|
import ActivityHeatmap from '../components/ActivityHeatmap.vue';
|
||||||
import {translateMonth, translateDay} from '../utils.js';
|
import {translateMonth, translateDay} from '../utils.js';
|
||||||
|
export default function initHeatmap() {
|
||||||
export function initHeatmap() {
|
|
||||||
const el = document.getElementById('user-heatmap');
|
const el = document.getElementById('user-heatmap');
|
||||||
if (!el) return;
|
if (!el) return;
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ function getDefaultSvgBoundsIfUndefined(svgXml, src) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initImageDiff() {
|
export default function initImageDiff() {
|
||||||
function createContext(image1, image2) {
|
function createContext(image1, image2) {
|
||||||
const size1 = {
|
const size1 = {
|
||||||
width: image1 && image1.width || 0,
|
width: image1 && image1.width || 0,
|
||||||
|
@ -2,7 +2,7 @@ import {createApp} from 'vue';
|
|||||||
import DiffFileTree from '../components/DiffFileTree.vue';
|
import DiffFileTree from '../components/DiffFileTree.vue';
|
||||||
import DiffFileList from '../components/DiffFileList.vue';
|
import DiffFileList from '../components/DiffFileList.vue';
|
||||||
|
|
||||||
export function initDiffFileTree() {
|
export default function initDiffFileTree() {
|
||||||
const el = document.getElementById('diff-file-tree');
|
const el = document.getElementById('diff-file-tree');
|
||||||
if (!el) return;
|
if (!el) return;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import {svg} from '../svg.js';
|
|
||||||
|
|
||||||
|
import {svg} from '../svg.js';
|
||||||
const {csrf} = window.config;
|
const {csrf} = window.config;
|
||||||
|
|
||||||
const threshold = 50;
|
const threshold = 50;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
|
|
||||||
export function initRepoGraphGit() {
|
export default function initRepoGraphGit() {
|
||||||
const graphContainer = document.getElementById('git-graph-container');
|
const graphContainer = document.getElementById('git-graph-container');
|
||||||
if (!graphContainer) return;
|
if (!graphContainer) return;
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import {createApp} from 'vue';
|
import {createApp} from 'vue';
|
||||||
import PullRequestMergeForm from '../components/PullRequestMergeForm.vue';
|
import PullRequestMergeForm from '../components/PullRequestMergeForm.vue';
|
||||||
|
|
||||||
export function initRepoPullRequestMergeForm() {
|
export default function initPullRequestMergeForm() {
|
||||||
const el = document.getElementById('pull-request-merge-form');
|
const el = document.getElementById('pull-request-merge-form');
|
||||||
if (!el) return;
|
if (!el) return;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import {htmlEscape} from 'escape-goat';
|
import {htmlEscape} from 'escape-goat';
|
||||||
import {attachTribute} from './tribute.js';
|
import attachTribute from './tribute.js';
|
||||||
import {createCommentEasyMDE, getAttachedEasyMDE} from './comp/EasyMDE.js';
|
import {createCommentEasyMDE, getAttachedEasyMDE} from './comp/EasyMDE.js';
|
||||||
import {initEasyMDEImagePaste} from './comp/ImagePaste.js';
|
import {initEasyMDEImagePaste} from './comp/ImagePaste.js';
|
||||||
import {initCompMarkupContentPreviewTab} from './comp/MarkupContentPreview.js';
|
import {initCompMarkupContentPreviewTab} from './comp/MarkupContentPreview.js';
|
||||||
|
@ -3,28 +3,33 @@ import {createCommentEasyMDE, getAttachedEasyMDE} from './comp/EasyMDE.js';
|
|||||||
import {initCompMarkupContentPreviewTab} from './comp/MarkupContentPreview.js';
|
import {initCompMarkupContentPreviewTab} from './comp/MarkupContentPreview.js';
|
||||||
import {initEasyMDEImagePaste} from './comp/ImagePaste.js';
|
import {initEasyMDEImagePaste} from './comp/ImagePaste.js';
|
||||||
import {
|
import {
|
||||||
initRepoIssueBranchSelect, initRepoIssueCodeCommentCancel, initRepoIssueCommentDelete,
|
initRepoIssueBranchSelect, initRepoIssueCodeCommentCancel,
|
||||||
initRepoIssueComments, initRepoIssueDependencyDelete, initRepoIssueReferenceIssue,
|
initRepoIssueCommentDelete,
|
||||||
initRepoIssueStatusButton, initRepoIssueTitleEdit, initRepoIssueWipToggle,
|
initRepoIssueComments, initRepoIssueDependencyDelete,
|
||||||
initRepoPullRequestUpdate, updateIssuesMeta,
|
initRepoIssueReferenceIssue, initRepoIssueStatusButton,
|
||||||
|
initRepoIssueTitleEdit,
|
||||||
|
initRepoIssueWipToggle, initRepoPullRequestUpdate,
|
||||||
|
updateIssuesMeta,
|
||||||
} from './repo-issue.js';
|
} from './repo-issue.js';
|
||||||
import {initUnicodeEscapeButton} from './repo-unicode-escape.js';
|
import {initUnicodeEscapeButton} from './repo-unicode-escape.js';
|
||||||
import {svg} from '../svg.js';
|
import {svg} from '../svg.js';
|
||||||
import {htmlEscape} from 'escape-goat';
|
import {htmlEscape} from 'escape-goat';
|
||||||
import {initRepoBranchTagDropdown} from '../components/RepoBranchTagDropdown.js';
|
import {initRepoBranchTagDropdown} from '../components/RepoBranchTagDropdown.js';
|
||||||
import {
|
import {
|
||||||
initRepoCloneLink, initRepoCommonBranchOrTagDropdown, initRepoCommonFilterSearchDropdown,
|
initRepoCloneLink,
|
||||||
|
initRepoCommonBranchOrTagDropdown,
|
||||||
|
initRepoCommonFilterSearchDropdown,
|
||||||
initRepoCommonLanguageStats,
|
initRepoCommonLanguageStats,
|
||||||
} from './repo-common.js';
|
} from './repo-common.js';
|
||||||
import {initCitationFileCopyContent} from './citation.js';
|
import {initCitationFileCopyContent} from './citation.js';
|
||||||
import {initCompLabelEdit} from './comp/LabelEdit.js';
|
import {initCompLabelEdit} from './comp/LabelEdit.js';
|
||||||
import {initRepoDiffConversationNav} from './repo-diff.js';
|
import {initRepoDiffConversationNav} from './repo-diff.js';
|
||||||
import {attachTribute} from './tribute.js';
|
import attachTribute from './tribute.js';
|
||||||
import {createDropzone} from './dropzone.js';
|
import createDropzone from './dropzone.js';
|
||||||
import {initCommentContent, initMarkupContent} from '../markup/content.js';
|
import {initCommentContent, initMarkupContent} from '../markup/content.js';
|
||||||
import {initCompReactionSelector} from './comp/ReactionSelector.js';
|
import {initCompReactionSelector} from './comp/ReactionSelector.js';
|
||||||
import {initRepoSettingBranches} from './repo-settings.js';
|
import {initRepoSettingBranches} from './repo-settings.js';
|
||||||
import {initRepoPullRequestMergeForm} from './repo-issue-pr-form.js';
|
import initRepoPullRequestMergeForm from './repo-issue-pr-form.js';
|
||||||
|
|
||||||
const {csrfToken} = window.config;
|
const {csrfToken} = window.config;
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ const $lfsSettings = $('#lfs_settings');
|
|||||||
const $lfsEndpoint = $('#lfs_endpoint');
|
const $lfsEndpoint = $('#lfs_endpoint');
|
||||||
const $items = $('#migrate_items').find('input[type=checkbox]');
|
const $items = $('#migrate_items').find('input[type=checkbox]');
|
||||||
|
|
||||||
export function initRepoMigration() {
|
export default function initRepoMigration() {
|
||||||
checkAuth();
|
checkAuth();
|
||||||
setLFSSettingsVisibility();
|
setLFSSettingsVisibility();
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ async function initRepoProjectSortable() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initRepoProject() {
|
export default function initRepoProject() {
|
||||||
if (!$('.repository.projects').length) {
|
if (!$('.repository.projects').length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import {attachTribute} from './tribute.js';
|
import attachTribute from './tribute.js';
|
||||||
import {initCompMarkupContentPreviewTab} from './comp/MarkupContentPreview.js';
|
import {initCompMarkupContentPreviewTab} from './comp/MarkupContentPreview.js';
|
||||||
import {initEasyMDEImagePaste} from './comp/ImagePaste.js';
|
import {initEasyMDEImagePaste} from './comp/ImagePaste.js';
|
||||||
import {createCommentEasyMDE} from './comp/EasyMDE.js';
|
import {createCommentEasyMDE} from './comp/EasyMDE.js';
|
||||||
|
@ -35,7 +35,7 @@ async function checkCacheValidity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function initServiceWorker() {
|
export default async function initServiceWorker() {
|
||||||
if (!('serviceWorker' in navigator)) return;
|
if (!('serviceWorker' in navigator)) return;
|
||||||
|
|
||||||
if (useServiceWorker) {
|
if (useServiceWorker) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export function initTableSort() {
|
export default function initTableSort() {
|
||||||
for (const header of document.querySelectorAll('th[data-sortt-asc]') || []) {
|
for (const header of document.querySelectorAll('th[data-sortt-asc]') || []) {
|
||||||
const sorttAsc = header.getAttribute('data-sortt-asc');
|
const sorttAsc = header.getAttribute('data-sortt-asc');
|
||||||
const sorttDesc = header.getAttribute('data-sortt-desc');
|
const sorttDesc = header.getAttribute('data-sortt-desc');
|
||||||
|
@ -49,7 +49,7 @@ function makeCollections({mentions, emoji}) {
|
|||||||
return collections;
|
return collections;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function attachTribute(elementOrNodeList, {mentions, emoji} = {}) {
|
export default async function attachTribute(elementOrNodeList, {mentions, emoji} = {}) {
|
||||||
if (!window.config.requireTribute || !elementOrNodeList) return;
|
if (!window.config.requireTribute || !elementOrNodeList) return;
|
||||||
const nodes = Array.from('length' in elementOrNodeList ? elementOrNodeList : [elementOrNodeList]);
|
const nodes = Array.from('length' in elementOrNodeList ? elementOrNodeList : [elementOrNodeList]);
|
||||||
if (!nodes.length) return;
|
if (!nodes.length) return;
|
||||||
|
@ -6,16 +6,16 @@ import {initVueEnv} from './components/VueComponentLoader.js';
|
|||||||
import {initRepoActivityTopAuthorsChart} from './components/RepoActivityTopAuthors.vue';
|
import {initRepoActivityTopAuthorsChart} from './components/RepoActivityTopAuthors.vue';
|
||||||
import {initDashboardRepoList} from './components/DashboardRepoList.js';
|
import {initDashboardRepoList} from './components/DashboardRepoList.js';
|
||||||
|
|
||||||
import {attachTribute} from './features/tribute.js';
|
import attachTribute from './features/tribute.js';
|
||||||
import {initGlobalCopyToClipboardListener} from './features/clipboard.js';
|
import initGlobalCopyToClipboardListener from './features/clipboard.js';
|
||||||
import {initContextPopups} from './features/contextpopup.js';
|
import initContextPopups from './features/contextpopup.js';
|
||||||
import {initRepoGraphGit} from './features/repo-graph.js';
|
import initRepoGraphGit from './features/repo-graph.js';
|
||||||
import {initHeatmap} from './features/heatmap.js';
|
import initHeatmap from './features/heatmap.js';
|
||||||
import {initImageDiff} from './features/imagediff.js';
|
import initImageDiff from './features/imagediff.js';
|
||||||
import {initRepoMigration} from './features/repo-migration.js';
|
import initRepoMigration from './features/repo-migration.js';
|
||||||
import {initRepoProject} from './features/repo-projects.js';
|
import initRepoProject from './features/repo-projects.js';
|
||||||
import {initServiceWorker} from './features/serviceworker.js';
|
import initServiceWorker from './features/serviceworker.js';
|
||||||
import {initTableSort} from './features/tablesort.js';
|
import initTableSort from './features/tablesort.js';
|
||||||
import {initAdminUserListSearchForm} from './features/admin/users.js';
|
import {initAdminUserListSearchForm} from './features/admin/users.js';
|
||||||
import {initAdminConfigs} from './features/admin/config.js';
|
import {initAdminConfigs} from './features/admin/config.js';
|
||||||
import {initMarkupAnchors} from './markup/anchors.js';
|
import {initMarkupAnchors} from './markup/anchors.js';
|
||||||
@ -24,7 +24,7 @@ import {initRepoIssueContentHistory} from './features/repo-issue-content.js';
|
|||||||
import {initStopwatch} from './features/stopwatch.js';
|
import {initStopwatch} from './features/stopwatch.js';
|
||||||
import {initFindFileInRepo} from './features/repo-findfile.js';
|
import {initFindFileInRepo} from './features/repo-findfile.js';
|
||||||
import {initCommentContent, initMarkupContent} from './markup/content.js';
|
import {initCommentContent, initMarkupContent} from './markup/content.js';
|
||||||
import {initDiffFileTree} from './features/repo-diff-filetree.js';
|
import initDiffFileTree from './features/repo-diff-filetree.js';
|
||||||
|
|
||||||
import {initUserAuthLinkAccountView, initUserAuthOauth2} from './features/user-auth.js';
|
import {initUserAuthLinkAccountView, initUserAuthOauth2} from './features/user-auth.js';
|
||||||
import {
|
import {
|
||||||
|
@ -26,6 +26,7 @@ import octiconSidebarExpand from '../../public/img/svg/octicon-sidebar-expand.sv
|
|||||||
import octiconTriangleDown from '../../public/img/svg/octicon-triangle-down.svg';
|
import octiconTriangleDown from '../../public/img/svg/octicon-triangle-down.svg';
|
||||||
import octiconX from '../../public/img/svg/octicon-x.svg';
|
import octiconX from '../../public/img/svg/octicon-x.svg';
|
||||||
|
|
||||||
|
|
||||||
export const svgs = {
|
export const svgs = {
|
||||||
'octicon-chevron-down': octiconChevronDown,
|
'octicon-chevron-down': octiconChevronDown,
|
||||||
'octicon-chevron-right': octiconChevronRight,
|
'octicon-chevron-right': octiconChevronRight,
|
||||||
@ -56,6 +57,7 @@ export const svgs = {
|
|||||||
'octicon-x': octiconX,
|
'octicon-x': octiconX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const parser = new DOMParser();
|
const parser = new DOMParser();
|
||||||
const serializer = new XMLSerializer();
|
const serializer = new XMLSerializer();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user