mirror of
https://github.com/go-gitea/gitea.git
synced 2025-08-13 00:03:31 -04:00
Compare commits
7 Commits
d11133b836
...
7ad5031328
Author | SHA1 | Date | |
---|---|---|---|
|
7ad5031328 | ||
|
61b495e5ab | ||
|
a3d9f0d915 | ||
|
4daea7c603 | ||
|
a21ca9b5a5 | ||
|
e80466f734 | ||
|
ad4e902d5a |
@ -397,36 +397,16 @@ func GetLatestCommitStatusForRepoCommitIDs(ctx context.Context, repoID int64, co
|
|||||||
|
|
||||||
// FindRepoRecentCommitStatusContexts returns repository's recent commit status contexts
|
// FindRepoRecentCommitStatusContexts returns repository's recent commit status contexts
|
||||||
func FindRepoRecentCommitStatusContexts(ctx context.Context, repoID int64, before time.Duration) ([]string, error) {
|
func FindRepoRecentCommitStatusContexts(ctx context.Context, repoID int64, before time.Duration) ([]string, error) {
|
||||||
type result struct {
|
|
||||||
Index int64
|
|
||||||
SHA string
|
|
||||||
}
|
|
||||||
getBase := func() *xorm.Session {
|
|
||||||
return db.GetEngine(ctx).Table(&CommitStatus{}).Where("repo_id = ?", repoID)
|
|
||||||
}
|
|
||||||
|
|
||||||
start := timeutil.TimeStampNow().AddDuration(-before)
|
start := timeutil.TimeStampNow().AddDuration(-before)
|
||||||
results := make([]result, 0, 10)
|
|
||||||
|
|
||||||
sess := getBase().And("updated_unix >= ?", start).
|
var contexts []string
|
||||||
Select("max( `index` ) as `index`, sha").
|
if err := db.GetEngine(ctx).Table("commit_status").
|
||||||
GroupBy("context_hash, sha").OrderBy("max( `index` ) desc")
|
Where("repo_id = ?", repoID).And("updated_unix >= ?", start).
|
||||||
|
Cols("context").Distinct().Find(&contexts); err != nil {
|
||||||
err := sess.Find(&results)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
contexts := make([]string, 0, len(results))
|
return contexts, nil
|
||||||
if len(results) == 0 {
|
|
||||||
return contexts, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
conds := make([]builder.Cond, 0, len(results))
|
|
||||||
for _, result := range results {
|
|
||||||
conds = append(conds, builder.Eq{"`index`": result.Index, "sha": result.SHA})
|
|
||||||
}
|
|
||||||
return contexts, getBase().And(builder.Or(conds...)).Select("context").Find(&contexts)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCommitStatusOptions holds options for creating a CommitStatus
|
// NewCommitStatusOptions holds options for creating a CommitStatus
|
||||||
|
@ -5,11 +5,15 @@ package git_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
git_model "code.gitea.io/gitea/models/git"
|
git_model "code.gitea.io/gitea/models/git"
|
||||||
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"
|
||||||
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/gitrepo"
|
||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -175,3 +179,55 @@ func Test_CalcCommitStatus(t *testing.T) {
|
|||||||
assert.Equal(t, kase.expected, git_model.CalcCommitStatus(kase.statuses))
|
assert.Equal(t, kase.expected, git_model.CalcCommitStatus(kase.statuses))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFindRepoRecentCommitStatusContexts(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
|
||||||
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
|
gitRepo, err := gitrepo.OpenRepository(git.DefaultContext, repo2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer gitRepo.Close()
|
||||||
|
|
||||||
|
commit, err := gitRepo.GetBranchCommit(repo2.DefaultBranch)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
_, err := db.DeleteByBean(db.DefaultContext, &git_model.CommitStatus{
|
||||||
|
RepoID: repo2.ID,
|
||||||
|
CreatorID: user2.ID,
|
||||||
|
SHA: commit.ID.String(),
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = git_model.NewCommitStatus(db.DefaultContext, git_model.NewCommitStatusOptions{
|
||||||
|
Repo: repo2,
|
||||||
|
Creator: user2,
|
||||||
|
SHA: commit.ID,
|
||||||
|
CommitStatus: &git_model.CommitStatus{
|
||||||
|
State: structs.CommitStatusFailure,
|
||||||
|
TargetURL: "https://example.com/tests/",
|
||||||
|
Context: "compliance/lint-backend",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = git_model.NewCommitStatus(db.DefaultContext, git_model.NewCommitStatusOptions{
|
||||||
|
Repo: repo2,
|
||||||
|
Creator: user2,
|
||||||
|
SHA: commit.ID,
|
||||||
|
CommitStatus: &git_model.CommitStatus{
|
||||||
|
State: structs.CommitStatusSuccess,
|
||||||
|
TargetURL: "https://example.com/tests/",
|
||||||
|
Context: "compliance/lint-backend",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
contexts, err := git_model.FindRepoRecentCommitStatusContexts(db.DefaultContext, repo2.ID, time.Hour)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if assert.Len(t, contexts, 1) {
|
||||||
|
assert.Equal(t, "compliance/lint-backend", contexts[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -34,7 +34,7 @@ func TestXRef_AddCrossReferences(t *testing.T) {
|
|||||||
|
|
||||||
// Comment on PR to reopen issue #1
|
// Comment on PR to reopen issue #1
|
||||||
content = fmt.Sprintf("content2, reopens #%d", itarget.Index)
|
content = fmt.Sprintf("content2, reopens #%d", itarget.Index)
|
||||||
c := testCreateComment(t, 1, 2, pr.ID, content)
|
c := testCreateComment(t, 2, pr.ID, content)
|
||||||
ref = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: pr.ID, RefCommentID: c.ID})
|
ref = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: pr.ID, RefCommentID: c.ID})
|
||||||
assert.Equal(t, issues_model.CommentTypeCommentRef, ref.Type)
|
assert.Equal(t, issues_model.CommentTypeCommentRef, ref.Type)
|
||||||
assert.Equal(t, pr.RepoID, ref.RefRepoID)
|
assert.Equal(t, pr.RepoID, ref.RefRepoID)
|
||||||
@ -104,18 +104,18 @@ func TestXRef_ResolveCrossReferences(t *testing.T) {
|
|||||||
pr := testCreatePR(t, 1, 2, "titlepr", fmt.Sprintf("closes #%d", i1.Index))
|
pr := testCreatePR(t, 1, 2, "titlepr", fmt.Sprintf("closes #%d", i1.Index))
|
||||||
rp := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i1.ID, RefIssueID: pr.Issue.ID, RefCommentID: 0})
|
rp := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i1.ID, RefIssueID: pr.Issue.ID, RefCommentID: 0})
|
||||||
|
|
||||||
c1 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("closes #%d", i2.Index))
|
c1 := testCreateComment(t, 2, pr.Issue.ID, fmt.Sprintf("closes #%d", i2.Index))
|
||||||
r1 := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i2.ID, RefIssueID: pr.Issue.ID, RefCommentID: c1.ID})
|
r1 := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i2.ID, RefIssueID: pr.Issue.ID, RefCommentID: c1.ID})
|
||||||
|
|
||||||
// Must be ignored
|
// Must be ignored
|
||||||
c2 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("mentions #%d", i2.Index))
|
c2 := testCreateComment(t, 2, pr.Issue.ID, fmt.Sprintf("mentions #%d", i2.Index))
|
||||||
unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i2.ID, RefIssueID: pr.Issue.ID, RefCommentID: c2.ID})
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i2.ID, RefIssueID: pr.Issue.ID, RefCommentID: c2.ID})
|
||||||
|
|
||||||
// Must be superseded by c4/r4
|
// Must be superseded by c4/r4
|
||||||
c3 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("reopens #%d", i3.Index))
|
c3 := testCreateComment(t, 2, pr.Issue.ID, fmt.Sprintf("reopens #%d", i3.Index))
|
||||||
unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i3.ID, RefIssueID: pr.Issue.ID, RefCommentID: c3.ID})
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i3.ID, RefIssueID: pr.Issue.ID, RefCommentID: c3.ID})
|
||||||
|
|
||||||
c4 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("closes #%d", i3.Index))
|
c4 := testCreateComment(t, 2, pr.Issue.ID, fmt.Sprintf("closes #%d", i3.Index))
|
||||||
r4 := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i3.ID, RefIssueID: pr.Issue.ID, RefCommentID: c4.ID})
|
r4 := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i3.ID, RefIssueID: pr.Issue.ID, RefCommentID: c4.ID})
|
||||||
|
|
||||||
refs, err := pr.ResolveCrossReferences(db.DefaultContext)
|
refs, err := pr.ResolveCrossReferences(db.DefaultContext)
|
||||||
@ -168,7 +168,7 @@ func testCreatePR(t *testing.T, repo, doer int64, title, content string) *issues
|
|||||||
return pr
|
return pr
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCreateComment(t *testing.T, repo, doer, issue int64, content string) *issues_model.Comment {
|
func testCreateComment(t *testing.T, doer, issue int64, content string) *issues_model.Comment {
|
||||||
d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer})
|
d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer})
|
||||||
i := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issue})
|
i := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issue})
|
||||||
c := &issues_model.Comment{Type: issues_model.CommentTypeComment, PosterID: doer, Poster: d, IssueID: issue, Issue: i, Content: content}
|
c := &issues_model.Comment{Type: issues_model.CommentTypeComment, PosterID: doer, Poster: d, IssueID: issue, Issue: i, Content: content}
|
||||||
|
@ -291,15 +291,15 @@ func TestAccessibleReposEnv_CountRepos(t *testing.T) {
|
|||||||
func TestAccessibleReposEnv_RepoIDs(t *testing.T) {
|
func TestAccessibleReposEnv_RepoIDs(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
|
org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
|
||||||
testSuccess := func(userID, _, pageSize int64, expectedRepoIDs []int64) {
|
testSuccess := func(userID int64, expectedRepoIDs []int64) {
|
||||||
env, err := organization.AccessibleReposEnv(db.DefaultContext, org, userID)
|
env, err := organization.AccessibleReposEnv(db.DefaultContext, org, userID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
repoIDs, err := env.RepoIDs(1, 100)
|
repoIDs, err := env.RepoIDs(1, 100)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, expectedRepoIDs, repoIDs)
|
assert.Equal(t, expectedRepoIDs, repoIDs)
|
||||||
}
|
}
|
||||||
testSuccess(2, 1, 100, []int64{3, 5, 32})
|
testSuccess(2, []int64{3, 5, 32})
|
||||||
testSuccess(4, 0, 100, []int64{3, 32})
|
testSuccess(4, []int64{3, 32})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAccessibleReposEnv_Repos(t *testing.T) {
|
func TestAccessibleReposEnv_Repos(t *testing.T) {
|
||||||
|
@ -208,14 +208,14 @@ func detectMatched(gitRepo *git.Repository, commit *git.Commit, triggedEvent web
|
|||||||
webhook_module.HookEventIssueAssign,
|
webhook_module.HookEventIssueAssign,
|
||||||
webhook_module.HookEventIssueLabel,
|
webhook_module.HookEventIssueLabel,
|
||||||
webhook_module.HookEventIssueMilestone:
|
webhook_module.HookEventIssueMilestone:
|
||||||
return matchIssuesEvent(commit, payload.(*api.IssuePayload), evt)
|
return matchIssuesEvent(payload.(*api.IssuePayload), evt)
|
||||||
|
|
||||||
case // issue_comment
|
case // issue_comment
|
||||||
webhook_module.HookEventIssueComment,
|
webhook_module.HookEventIssueComment,
|
||||||
// `pull_request_comment` is same as `issue_comment`
|
// `pull_request_comment` is same as `issue_comment`
|
||||||
// See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_comment-use-issue_comment
|
// See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_comment-use-issue_comment
|
||||||
webhook_module.HookEventPullRequestComment:
|
webhook_module.HookEventPullRequestComment:
|
||||||
return matchIssueCommentEvent(commit, payload.(*api.IssueCommentPayload), evt)
|
return matchIssueCommentEvent(payload.(*api.IssueCommentPayload), evt)
|
||||||
|
|
||||||
case // pull_request
|
case // pull_request
|
||||||
webhook_module.HookEventPullRequest,
|
webhook_module.HookEventPullRequest,
|
||||||
@ -229,19 +229,19 @@ func detectMatched(gitRepo *git.Repository, commit *git.Commit, triggedEvent web
|
|||||||
case // pull_request_review
|
case // pull_request_review
|
||||||
webhook_module.HookEventPullRequestReviewApproved,
|
webhook_module.HookEventPullRequestReviewApproved,
|
||||||
webhook_module.HookEventPullRequestReviewRejected:
|
webhook_module.HookEventPullRequestReviewRejected:
|
||||||
return matchPullRequestReviewEvent(commit, payload.(*api.PullRequestPayload), evt)
|
return matchPullRequestReviewEvent(payload.(*api.PullRequestPayload), evt)
|
||||||
|
|
||||||
case // pull_request_review_comment
|
case // pull_request_review_comment
|
||||||
webhook_module.HookEventPullRequestReviewComment:
|
webhook_module.HookEventPullRequestReviewComment:
|
||||||
return matchPullRequestReviewCommentEvent(commit, payload.(*api.PullRequestPayload), evt)
|
return matchPullRequestReviewCommentEvent(payload.(*api.PullRequestPayload), evt)
|
||||||
|
|
||||||
case // release
|
case // release
|
||||||
webhook_module.HookEventRelease:
|
webhook_module.HookEventRelease:
|
||||||
return matchReleaseEvent(commit, payload.(*api.ReleasePayload), evt)
|
return matchReleaseEvent(payload.(*api.ReleasePayload), evt)
|
||||||
|
|
||||||
case // registry_package
|
case // registry_package
|
||||||
webhook_module.HookEventPackage:
|
webhook_module.HookEventPackage:
|
||||||
return matchPackageEvent(commit, payload.(*api.PackagePayload), evt)
|
return matchPackageEvent(payload.(*api.PackagePayload), evt)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log.Warn("unsupported event %q", triggedEvent)
|
log.Warn("unsupported event %q", triggedEvent)
|
||||||
@ -347,7 +347,7 @@ func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobpa
|
|||||||
return matchTimes == len(evt.Acts())
|
return matchTimes == len(evt.Acts())
|
||||||
}
|
}
|
||||||
|
|
||||||
func matchIssuesEvent(commit *git.Commit, issuePayload *api.IssuePayload, evt *jobparser.Event) bool {
|
func matchIssuesEvent(issuePayload *api.IssuePayload, evt *jobparser.Event) bool {
|
||||||
// with no special filter parameters
|
// with no special filter parameters
|
||||||
if len(evt.Acts()) == 0 {
|
if len(evt.Acts()) == 0 {
|
||||||
return true
|
return true
|
||||||
@ -495,7 +495,7 @@ func matchPullRequestEvent(gitRepo *git.Repository, commit *git.Commit, prPayloa
|
|||||||
return activityTypeMatched && matchTimes == len(evt.Acts())
|
return activityTypeMatched && matchTimes == len(evt.Acts())
|
||||||
}
|
}
|
||||||
|
|
||||||
func matchIssueCommentEvent(commit *git.Commit, issueCommentPayload *api.IssueCommentPayload, evt *jobparser.Event) bool {
|
func matchIssueCommentEvent(issueCommentPayload *api.IssueCommentPayload, evt *jobparser.Event) bool {
|
||||||
// with no special filter parameters
|
// with no special filter parameters
|
||||||
if len(evt.Acts()) == 0 {
|
if len(evt.Acts()) == 0 {
|
||||||
return true
|
return true
|
||||||
@ -527,7 +527,7 @@ func matchIssueCommentEvent(commit *git.Commit, issueCommentPayload *api.IssueCo
|
|||||||
return matchTimes == len(evt.Acts())
|
return matchTimes == len(evt.Acts())
|
||||||
}
|
}
|
||||||
|
|
||||||
func matchPullRequestReviewEvent(commit *git.Commit, prPayload *api.PullRequestPayload, evt *jobparser.Event) bool {
|
func matchPullRequestReviewEvent(prPayload *api.PullRequestPayload, evt *jobparser.Event) bool {
|
||||||
// with no special filter parameters
|
// with no special filter parameters
|
||||||
if len(evt.Acts()) == 0 {
|
if len(evt.Acts()) == 0 {
|
||||||
return true
|
return true
|
||||||
@ -576,7 +576,7 @@ func matchPullRequestReviewEvent(commit *git.Commit, prPayload *api.PullRequestP
|
|||||||
return matchTimes == len(evt.Acts())
|
return matchTimes == len(evt.Acts())
|
||||||
}
|
}
|
||||||
|
|
||||||
func matchPullRequestReviewCommentEvent(commit *git.Commit, prPayload *api.PullRequestPayload, evt *jobparser.Event) bool {
|
func matchPullRequestReviewCommentEvent(prPayload *api.PullRequestPayload, evt *jobparser.Event) bool {
|
||||||
// with no special filter parameters
|
// with no special filter parameters
|
||||||
if len(evt.Acts()) == 0 {
|
if len(evt.Acts()) == 0 {
|
||||||
return true
|
return true
|
||||||
@ -625,7 +625,7 @@ func matchPullRequestReviewCommentEvent(commit *git.Commit, prPayload *api.PullR
|
|||||||
return matchTimes == len(evt.Acts())
|
return matchTimes == len(evt.Acts())
|
||||||
}
|
}
|
||||||
|
|
||||||
func matchReleaseEvent(commit *git.Commit, payload *api.ReleasePayload, evt *jobparser.Event) bool {
|
func matchReleaseEvent(payload *api.ReleasePayload, evt *jobparser.Event) bool {
|
||||||
// with no special filter parameters
|
// with no special filter parameters
|
||||||
if len(evt.Acts()) == 0 {
|
if len(evt.Acts()) == 0 {
|
||||||
return true
|
return true
|
||||||
@ -662,7 +662,7 @@ func matchReleaseEvent(commit *git.Commit, payload *api.ReleasePayload, evt *job
|
|||||||
return matchTimes == len(evt.Acts())
|
return matchTimes == len(evt.Acts())
|
||||||
}
|
}
|
||||||
|
|
||||||
func matchPackageEvent(commit *git.Commit, payload *api.PackagePayload, evt *jobparser.Event) bool {
|
func matchPackageEvent(payload *api.PackagePayload, evt *jobparser.Event) bool {
|
||||||
// with no special filter parameters
|
// with no special filter parameters
|
||||||
if len(evt.Acts()) == 0 {
|
if len(evt.Acts()) == 0 {
|
||||||
return true
|
return true
|
||||||
|
@ -29,7 +29,7 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath
|
|||||||
var revs map[string]*Commit
|
var revs map[string]*Commit
|
||||||
if commit.repo.LastCommitCache != nil {
|
if commit.repo.LastCommitCache != nil {
|
||||||
var unHitPaths []string
|
var unHitPaths []string
|
||||||
revs, unHitPaths, err = getLastCommitForPathsByCache(ctx, commit.ID.String(), treePath, entryPaths, commit.repo.LastCommitCache)
|
revs, unHitPaths, err = getLastCommitForPathsByCache(commit.ID.String(), treePath, entryPaths, commit.repo.LastCommitCache)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -97,7 +97,7 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath
|
|||||||
return commitsInfo, treeCommit, nil
|
return commitsInfo, treeCommit, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLastCommitForPathsByCache(ctx context.Context, commitID, treePath string, paths []string, cache *LastCommitCache) (map[string]*Commit, []string, error) {
|
func getLastCommitForPathsByCache(commitID, treePath string, paths []string, cache *LastCommitCache) (map[string]*Commit, []string, error) {
|
||||||
var unHitEntryPaths []string
|
var unHitEntryPaths []string
|
||||||
results := make(map[string]*Commit)
|
results := make(map[string]*Commit)
|
||||||
for _, p := range paths {
|
for _, p := range paths {
|
||||||
|
@ -18,7 +18,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ParseTreeEntries parses the output of a `git ls-tree -l` command.
|
// ParseTreeEntries parses the output of a `git ls-tree -l` command.
|
||||||
func ParseTreeEntries(h ObjectFormat, data []byte) ([]*TreeEntry, error) {
|
func ParseTreeEntries(data []byte) ([]*TreeEntry, error) {
|
||||||
return parseTreeEntries(data, nil)
|
return parseTreeEntries(data, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ func TestParseTreeEntries(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
entries, err := ParseTreeEntries(Sha1ObjectFormat, []byte(testCase.Input))
|
entries, err := ParseTreeEntries([]byte(testCase.Input))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
if len(entries) > 1 {
|
if len(entries) > 1 {
|
||||||
fmt.Println(testCase.Expected[0].ID)
|
fmt.Println(testCase.Expected[0].ID)
|
||||||
|
@ -17,13 +17,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ParseTreeEntries parses the output of a `git ls-tree -l` command.
|
// ParseTreeEntries parses the output of a `git ls-tree -l` command.
|
||||||
func ParseTreeEntries(objectFormat ObjectFormat, data []byte) ([]*TreeEntry, error) {
|
func ParseTreeEntries(data []byte) ([]*TreeEntry, error) {
|
||||||
return parseTreeEntries(objectFormat, data, nil)
|
return parseTreeEntries(data, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
var sepSpace = []byte{' '}
|
var sepSpace = []byte{' '}
|
||||||
|
|
||||||
func parseTreeEntries(objectFormat ObjectFormat, data []byte, ptree *Tree) ([]*TreeEntry, error) {
|
func parseTreeEntries(data []byte, ptree *Tree) ([]*TreeEntry, error) {
|
||||||
var err error
|
var err error
|
||||||
entries := make([]*TreeEntry, 0, bytes.Count(data, []byte{'\n'})+1)
|
entries := make([]*TreeEntry, 0, bytes.Count(data, []byte{'\n'})+1)
|
||||||
for pos := 0; pos < len(data); {
|
for pos := 0; pos < len(data); {
|
||||||
|
@ -12,8 +12,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestParseTreeEntriesLong(t *testing.T) {
|
func TestParseTreeEntriesLong(t *testing.T) {
|
||||||
objectFormat := Sha1ObjectFormat
|
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
Input string
|
Input string
|
||||||
Expected []*TreeEntry
|
Expected []*TreeEntry
|
||||||
@ -56,7 +54,7 @@ func TestParseTreeEntriesLong(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
entries, err := ParseTreeEntries(objectFormat, []byte(testCase.Input))
|
entries, err := ParseTreeEntries([]byte(testCase.Input))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, entries, len(testCase.Expected))
|
assert.Len(t, entries, len(testCase.Expected))
|
||||||
for i, entry := range entries {
|
for i, entry := range entries {
|
||||||
@ -66,8 +64,6 @@ func TestParseTreeEntriesLong(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestParseTreeEntriesShort(t *testing.T) {
|
func TestParseTreeEntriesShort(t *testing.T) {
|
||||||
objectFormat := Sha1ObjectFormat
|
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
Input string
|
Input string
|
||||||
Expected []*TreeEntry
|
Expected []*TreeEntry
|
||||||
@ -91,7 +87,7 @@ func TestParseTreeEntriesShort(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
entries, err := ParseTreeEntries(objectFormat, []byte(testCase.Input))
|
entries, err := ParseTreeEntries([]byte(testCase.Input))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, entries, len(testCase.Expected))
|
assert.Len(t, entries, len(testCase.Expected))
|
||||||
for i, entry := range entries {
|
for i, entry := range entries {
|
||||||
@ -102,7 +98,7 @@ func TestParseTreeEntriesShort(t *testing.T) {
|
|||||||
|
|
||||||
func TestParseTreeEntriesInvalid(t *testing.T) {
|
func TestParseTreeEntriesInvalid(t *testing.T) {
|
||||||
// there was a panic: "runtime error: slice bounds out of range" when the input was invalid: #20315
|
// there was a panic: "runtime error: slice bounds out of range" when the input was invalid: #20315
|
||||||
entries, err := ParseTreeEntries(Sha1ObjectFormat, []byte("100644 blob ea0d83c9081af9500ac9f804101b3fd0a5c293af"))
|
entries, err := ParseTreeEntries([]byte("100644 blob ea0d83c9081af9500ac9f804101b3fd0a5c293af"))
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Len(t, entries, 0)
|
assert.Len(t, entries, 0)
|
||||||
}
|
}
|
||||||
|
@ -77,11 +77,8 @@ func (t *Tree) ListEntries() (Entries, error) {
|
|||||||
return nil, runErr
|
return nil, runErr
|
||||||
}
|
}
|
||||||
|
|
||||||
objectFormat, err := t.repo.GetObjectFormat()
|
var err error
|
||||||
if err != nil {
|
t.entries, err = parseTreeEntries(stdout, t)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
t.entries, err = parseTreeEntries(objectFormat, stdout, t)
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.entriesParsed = true
|
t.entriesParsed = true
|
||||||
}
|
}
|
||||||
@ -104,11 +101,8 @@ func (t *Tree) listEntriesRecursive(extraArgs TrustedCmdArgs) (Entries, error) {
|
|||||||
return nil, runErr
|
return nil, runErr
|
||||||
}
|
}
|
||||||
|
|
||||||
objectFormat, err := t.repo.GetObjectFormat()
|
var err error
|
||||||
if err != nil {
|
t.entriesRecursive, err = parseTreeEntries(stdout, t)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
t.entriesRecursive, err = parseTreeEntries(objectFormat, stdout, t)
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.entriesRecursiveParsed = true
|
t.entriesRecursiveParsed = true
|
||||||
}
|
}
|
||||||
|
@ -62,8 +62,8 @@ func isIndexable(entry *git.TreeEntry) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parseGitLsTreeOutput parses the output of a `git ls-tree -r --full-name` command
|
// parseGitLsTreeOutput parses the output of a `git ls-tree -r --full-name` command
|
||||||
func parseGitLsTreeOutput(objectFormat git.ObjectFormat, stdout []byte) ([]internal.FileUpdate, error) {
|
func parseGitLsTreeOutput(stdout []byte) ([]internal.FileUpdate, error) {
|
||||||
entries, err := git.ParseTreeEntries(objectFormat, stdout)
|
entries, err := git.ParseTreeEntries(stdout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -91,10 +91,8 @@ func genesisChanges(ctx context.Context, repo *repo_model.Repository, revision s
|
|||||||
return nil, runErr
|
return nil, runErr
|
||||||
}
|
}
|
||||||
|
|
||||||
objectFormat := git.ObjectFormatFromName(repo.ObjectFormatName)
|
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
changes.Updates, err = parseGitLsTreeOutput(objectFormat, stdout)
|
changes.Updates, err = parseGitLsTreeOutput(stdout)
|
||||||
return &changes, err
|
return &changes, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,8 +170,6 @@ func nonGenesisChanges(ctx context.Context, repo *repo_model.Repository, revisio
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
objectFormat := git.ObjectFormatFromName(repo.ObjectFormatName)
|
changes.Updates, err = parseGitLsTreeOutput(lsTreeStdout)
|
||||||
|
|
||||||
changes.Updates, err = parseGitLsTreeOutput(objectFormat, lsTreeStdout)
|
|
||||||
return &changes, err
|
return &changes, err
|
||||||
}
|
}
|
||||||
|
@ -65,11 +65,11 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa
|
|||||||
case *ast.Paragraph:
|
case *ast.Paragraph:
|
||||||
g.applyElementDir(v)
|
g.applyElementDir(v)
|
||||||
case *ast.Image:
|
case *ast.Image:
|
||||||
g.transformImage(ctx, v, reader)
|
g.transformImage(ctx, v)
|
||||||
case *ast.Link:
|
case *ast.Link:
|
||||||
g.transformLink(ctx, v, reader)
|
g.transformLink(ctx, v)
|
||||||
case *ast.List:
|
case *ast.List:
|
||||||
g.transformList(ctx, v, reader, rc)
|
g.transformList(ctx, v, rc)
|
||||||
case *ast.Text:
|
case *ast.Text:
|
||||||
if v.SoftLineBreak() && !v.HardLineBreak() {
|
if v.SoftLineBreak() && !v.HardLineBreak() {
|
||||||
if ctx.Metas["mode"] != "document" {
|
if ctx.Metas["mode"] != "document" {
|
||||||
|
@ -68,7 +68,7 @@ func cssColorHandler(value string) bool {
|
|||||||
return css.HSLA.MatchString(value)
|
return css.HSLA.MatchString(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *ASTTransformer) transformCodeSpan(ctx *markup.RenderContext, v *ast.CodeSpan, reader text.Reader) {
|
func (g *ASTTransformer) transformCodeSpan(_ *markup.RenderContext, v *ast.CodeSpan, reader text.Reader) {
|
||||||
colorContent := v.Text(reader.Source())
|
colorContent := v.Text(reader.Source())
|
||||||
if cssColorHandler(string(colorContent)) {
|
if cssColorHandler(string(colorContent)) {
|
||||||
v.AppendChild(v, NewColorPreview(colorContent))
|
v.AppendChild(v, NewColorPreview(colorContent))
|
||||||
|
@ -13,7 +13,7 @@ import (
|
|||||||
"github.com/yuin/goldmark/util"
|
"github.com/yuin/goldmark/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (g *ASTTransformer) transformHeading(ctx *markup.RenderContext, v *ast.Heading, reader text.Reader, tocList *[]markup.Header) {
|
func (g *ASTTransformer) transformHeading(_ *markup.RenderContext, v *ast.Heading, reader text.Reader, tocList *[]markup.Header) {
|
||||||
for _, attr := range v.Attributes() {
|
for _, attr := range v.Attributes() {
|
||||||
if _, ok := attr.Value.([]byte); !ok {
|
if _, ok := attr.Value.([]byte); !ok {
|
||||||
v.SetAttribute(attr.Name, []byte(fmt.Sprintf("%v", attr.Value)))
|
v.SetAttribute(attr.Name, []byte(fmt.Sprintf("%v", attr.Value)))
|
||||||
|
@ -10,10 +10,9 @@ import (
|
|||||||
giteautil "code.gitea.io/gitea/modules/util"
|
giteautil "code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"github.com/yuin/goldmark/ast"
|
"github.com/yuin/goldmark/ast"
|
||||||
"github.com/yuin/goldmark/text"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (g *ASTTransformer) transformImage(ctx *markup.RenderContext, v *ast.Image, reader text.Reader) {
|
func (g *ASTTransformer) transformImage(ctx *markup.RenderContext, v *ast.Image) {
|
||||||
// Images need two things:
|
// Images need two things:
|
||||||
//
|
//
|
||||||
// 1. Their src needs to munged to be a real value
|
// 1. Their src needs to munged to be a real value
|
||||||
|
@ -10,10 +10,9 @@ import (
|
|||||||
giteautil "code.gitea.io/gitea/modules/util"
|
giteautil "code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"github.com/yuin/goldmark/ast"
|
"github.com/yuin/goldmark/ast"
|
||||||
"github.com/yuin/goldmark/text"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (g *ASTTransformer) transformLink(ctx *markup.RenderContext, v *ast.Link, reader text.Reader) {
|
func (g *ASTTransformer) transformLink(ctx *markup.RenderContext, v *ast.Link) {
|
||||||
// Links need their href to munged to be a real value
|
// Links need their href to munged to be a real value
|
||||||
link := v.Destination
|
link := v.Destination
|
||||||
isAnchorFragment := len(link) > 0 && link[0] == '#'
|
isAnchorFragment := len(link) > 0 && link[0] == '#'
|
||||||
|
@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/yuin/goldmark/ast"
|
"github.com/yuin/goldmark/ast"
|
||||||
east "github.com/yuin/goldmark/extension/ast"
|
east "github.com/yuin/goldmark/extension/ast"
|
||||||
"github.com/yuin/goldmark/renderer/html"
|
"github.com/yuin/goldmark/renderer/html"
|
||||||
"github.com/yuin/goldmark/text"
|
|
||||||
"github.com/yuin/goldmark/util"
|
"github.com/yuin/goldmark/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -50,7 +49,7 @@ func (r *HTMLRenderer) renderTaskCheckBox(w util.BufWriter, source []byte, node
|
|||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *ASTTransformer) transformList(ctx *markup.RenderContext, v *ast.List, reader text.Reader, rc *RenderConfig) {
|
func (g *ASTTransformer) transformList(_ *markup.RenderContext, v *ast.List, rc *RenderConfig) {
|
||||||
if v.HasChildren() {
|
if v.HasChildren() {
|
||||||
children := make([]ast.Node, 0, v.ChildCount())
|
children := make([]ast.Node, 0, v.ChildCount())
|
||||||
child := v.FirstChild()
|
child := v.FirstChild()
|
||||||
|
@ -54,7 +54,7 @@ func (r *stripRenderer) Render(w io.Writer, source []byte, doc ast.Node) error {
|
|||||||
}
|
}
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
case *ast.Link:
|
case *ast.Link:
|
||||||
r.processLink(w, v.Destination)
|
r.processLink(v.Destination)
|
||||||
return ast.WalkSkipChildren, nil
|
return ast.WalkSkipChildren, nil
|
||||||
case *ast.AutoLink:
|
case *ast.AutoLink:
|
||||||
// This could be a reference to an issue or pull - if so convert it
|
// This could be a reference to an issue or pull - if so convert it
|
||||||
@ -124,7 +124,7 @@ func (r *stripRenderer) processAutoLink(w io.Writer, link []byte) {
|
|||||||
_, _ = w.Write([]byte(parts[4]))
|
_, _ = w.Write([]byte(parts[4]))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *stripRenderer) processLink(w io.Writer, link []byte) {
|
func (r *stripRenderer) processLink(link []byte) {
|
||||||
// Links are processed out of band
|
// Links are processed out of band
|
||||||
r.links = append(r.links, string(link))
|
r.links = append(r.links, string(link))
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ func TestOption(t *testing.T) {
|
|||||||
assert.Equal(t, int(0), none.Value())
|
assert.Equal(t, int(0), none.Value())
|
||||||
assert.Equal(t, int(1), none.ValueOrDefault(1))
|
assert.Equal(t, int(1), none.ValueOrDefault(1))
|
||||||
|
|
||||||
some := optional.Some[int](1)
|
some := optional.Some(1)
|
||||||
assert.True(t, some.Has())
|
assert.True(t, some.Has())
|
||||||
assert.Equal(t, int(1), some.Value())
|
assert.Equal(t, int(1), some.Value())
|
||||||
assert.Equal(t, int(1), some.ValueOrDefault(2))
|
assert.Equal(t, int(1), some.ValueOrDefault(2))
|
||||||
|
@ -78,6 +78,7 @@ type PackageMetadataVersion struct {
|
|||||||
Repository Repository `json:"repository,omitempty"`
|
Repository Repository `json:"repository,omitempty"`
|
||||||
Keywords []string `json:"keywords,omitempty"`
|
Keywords []string `json:"keywords,omitempty"`
|
||||||
Dependencies map[string]string `json:"dependencies,omitempty"`
|
Dependencies map[string]string `json:"dependencies,omitempty"`
|
||||||
|
BundleDependencies []string `json:"bundleDependencies,omitempty"`
|
||||||
DevDependencies map[string]string `json:"devDependencies,omitempty"`
|
DevDependencies map[string]string `json:"devDependencies,omitempty"`
|
||||||
PeerDependencies map[string]string `json:"peerDependencies,omitempty"`
|
PeerDependencies map[string]string `json:"peerDependencies,omitempty"`
|
||||||
Bin map[string]string `json:"bin,omitempty"`
|
Bin map[string]string `json:"bin,omitempty"`
|
||||||
@ -218,6 +219,7 @@ func ParsePackage(r io.Reader) (*Package, error) {
|
|||||||
ProjectURL: meta.Homepage,
|
ProjectURL: meta.Homepage,
|
||||||
Keywords: meta.Keywords,
|
Keywords: meta.Keywords,
|
||||||
Dependencies: meta.Dependencies,
|
Dependencies: meta.Dependencies,
|
||||||
|
BundleDependencies: meta.BundleDependencies,
|
||||||
DevelopmentDependencies: meta.DevDependencies,
|
DevelopmentDependencies: meta.DevDependencies,
|
||||||
PeerDependencies: meta.PeerDependencies,
|
PeerDependencies: meta.PeerDependencies,
|
||||||
OptionalDependencies: meta.OptionalDependencies,
|
OptionalDependencies: meta.OptionalDependencies,
|
||||||
|
@ -16,6 +16,7 @@ type Metadata struct {
|
|||||||
ProjectURL string `json:"project_url,omitempty"`
|
ProjectURL string `json:"project_url,omitempty"`
|
||||||
Keywords []string `json:"keywords,omitempty"`
|
Keywords []string `json:"keywords,omitempty"`
|
||||||
Dependencies map[string]string `json:"dependencies,omitempty"`
|
Dependencies map[string]string `json:"dependencies,omitempty"`
|
||||||
|
BundleDependencies []string `json:"bundleDependencies,omitempty"`
|
||||||
DevelopmentDependencies map[string]string `json:"development_dependencies,omitempty"`
|
DevelopmentDependencies map[string]string `json:"development_dependencies,omitempty"`
|
||||||
PeerDependencies map[string]string `json:"peer_dependencies,omitempty"`
|
PeerDependencies map[string]string `json:"peer_dependencies,omitempty"`
|
||||||
OptionalDependencies map[string]string `json:"optional_dependencies,omitempty"`
|
OptionalDependencies map[string]string `json:"optional_dependencies,omitempty"`
|
||||||
|
@ -38,12 +38,12 @@ func loadIncomingEmailFrom(rootCfg ConfigProvider) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := checkReplyToAddress(IncomingEmail.ReplyToAddress); err != nil {
|
if err := checkReplyToAddress(); err != nil {
|
||||||
log.Fatal("Invalid incoming_mail.REPLY_TO_ADDRESS (%s): %v", IncomingEmail.ReplyToAddress, err)
|
log.Fatal("Invalid incoming_mail.REPLY_TO_ADDRESS (%s): %v", IncomingEmail.ReplyToAddress, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkReplyToAddress(address string) error {
|
func checkReplyToAddress() error {
|
||||||
parsed, err := mail.ParseAddress(IncomingEmail.ReplyToAddress)
|
parsed, err := mail.ParseAddress(IncomingEmail.ReplyToAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -97,7 +97,7 @@ func getStorage(rootCfg ConfigProvider, name, typ string, sec ConfigSection) (*S
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
overrideSec := getStorageOverrideSection(rootCfg, targetSec, sec, tp, name)
|
overrideSec := getStorageOverrideSection(rootCfg, sec, tp, name)
|
||||||
|
|
||||||
targetType := targetSec.Key("STORAGE_TYPE").String()
|
targetType := targetSec.Key("STORAGE_TYPE").String()
|
||||||
switch targetType {
|
switch targetType {
|
||||||
@ -189,7 +189,7 @@ func getStorageTargetSection(rootCfg ConfigProvider, name, typ string, sec Confi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getStorageOverrideSection override section will be read SERVE_DIRECT, PATH, MINIO_BASE_PATH, MINIO_BUCKET to override the targetsec when possible
|
// getStorageOverrideSection override section will be read SERVE_DIRECT, PATH, MINIO_BASE_PATH, MINIO_BUCKET to override the targetsec when possible
|
||||||
func getStorageOverrideSection(rootConfig ConfigProvider, targetSec, sec ConfigSection, targetSecType targetSecType, name string) ConfigSection {
|
func getStorageOverrideSection(rootConfig ConfigProvider, sec ConfigSection, targetSecType targetSecType, name string) ConfigSection {
|
||||||
if targetSecType == targetSecIsSec {
|
if targetSecType == targetSecIsSec {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -121,29 +121,25 @@ func RenderIssueTitle(ctx context.Context, text string, metas map[string]string)
|
|||||||
// RenderLabel renders a label
|
// RenderLabel renders a label
|
||||||
// locale is needed due to an import cycle with our context providing the `Tr` function
|
// locale is needed due to an import cycle with our context providing the `Tr` function
|
||||||
func RenderLabel(ctx context.Context, locale translation.Locale, label *issues_model.Label) template.HTML {
|
func RenderLabel(ctx context.Context, locale translation.Locale, label *issues_model.Label) template.HTML {
|
||||||
var (
|
var extraCSSClasses string
|
||||||
archivedCSSClass string
|
textColor := util.ContrastColor(label.Color)
|
||||||
textColor = util.ContrastColor(label.Color)
|
labelScope := label.ExclusiveScope()
|
||||||
labelScope = label.ExclusiveScope()
|
descriptionText := emoji.ReplaceAliases(label.Description)
|
||||||
)
|
|
||||||
|
|
||||||
description := emoji.ReplaceAliases(template.HTMLEscapeString(label.Description))
|
|
||||||
|
|
||||||
if label.IsArchived() {
|
if label.IsArchived() {
|
||||||
archivedCSSClass = "archived-label"
|
extraCSSClasses = "archived-label"
|
||||||
description = fmt.Sprintf("(%s) %s", locale.TrString("archived"), description)
|
descriptionText = fmt.Sprintf("(%s) %s", locale.TrString("archived"), descriptionText)
|
||||||
}
|
}
|
||||||
|
|
||||||
if labelScope == "" {
|
if labelScope == "" {
|
||||||
// Regular label
|
// Regular label
|
||||||
s := fmt.Sprintf("<div class='ui label %s' style='color: %s !important; background-color: %s !important;' data-tooltip-content title='%s'>%s</div>",
|
return HTMLFormat(`<div class="ui label %s" style="color: %s !important; background-color: %s !important;" data-tooltip-content title="%s">%s</div>`,
|
||||||
archivedCSSClass, textColor, label.Color, description, RenderEmoji(ctx, label.Name))
|
extraCSSClasses, textColor, label.Color, descriptionText, RenderEmoji(ctx, label.Name))
|
||||||
return template.HTML(s)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scoped label
|
// Scoped label
|
||||||
scopeText := RenderEmoji(ctx, labelScope)
|
scopeHTML := RenderEmoji(ctx, labelScope)
|
||||||
itemText := RenderEmoji(ctx, label.Name[len(labelScope)+1:])
|
itemHTML := RenderEmoji(ctx, label.Name[len(labelScope)+1:])
|
||||||
|
|
||||||
// Make scope and item background colors slightly darker and lighter respectively.
|
// Make scope and item background colors slightly darker and lighter respectively.
|
||||||
// More contrast needed with higher luminance, empirically tweaked.
|
// More contrast needed with higher luminance, empirically tweaked.
|
||||||
@ -171,14 +167,13 @@ func RenderLabel(ctx context.Context, locale translation.Locale, label *issues_m
|
|||||||
itemColor := "#" + hex.EncodeToString(itemBytes)
|
itemColor := "#" + hex.EncodeToString(itemBytes)
|
||||||
scopeColor := "#" + hex.EncodeToString(scopeBytes)
|
scopeColor := "#" + hex.EncodeToString(scopeBytes)
|
||||||
|
|
||||||
s := fmt.Sprintf("<span class='ui label %s scope-parent' data-tooltip-content title='%s'>"+
|
return HTMLFormat(`<span class="ui label %s scope-parent" data-tooltip-content title="%s">`+
|
||||||
"<div class='ui label scope-left' style='color: %s !important; background-color: %s !important'>%s</div>"+
|
`<div class="ui label scope-left" style="color: %s !important; background-color: %s !important">%s</div>`+
|
||||||
"<div class='ui label scope-right' style='color: %s !important; background-color: %s !important'>%s</div>"+
|
`<div class="ui label scope-right" style="color: %s !important; background-color: %s !important">%s</div>`+
|
||||||
"</span>",
|
`</span>`,
|
||||||
archivedCSSClass, description,
|
extraCSSClasses, descriptionText,
|
||||||
textColor, scopeColor, scopeText,
|
textColor, scopeColor, scopeHTML,
|
||||||
textColor, itemColor, itemText)
|
textColor, itemColor, itemHTML)
|
||||||
return template.HTML(s)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenderEmoji renders html text with emoji post processors
|
// RenderEmoji renders html text with emoji post processors
|
||||||
|
@ -3495,6 +3495,7 @@ npm.install = To install the package using npm, run the following command:
|
|||||||
npm.install2 = or add it to the package.json file:
|
npm.install2 = or add it to the package.json file:
|
||||||
npm.dependencies = Dependencies
|
npm.dependencies = Dependencies
|
||||||
npm.dependencies.development = Development Dependencies
|
npm.dependencies.development = Development Dependencies
|
||||||
|
npm.dependencies.bundle = Bundled Dependencies
|
||||||
npm.dependencies.peer = Peer Dependencies
|
npm.dependencies.peer = Peer Dependencies
|
||||||
npm.dependencies.optional = Optional Dependencies
|
npm.dependencies.optional = Optional Dependencies
|
||||||
npm.details.tag = Tag
|
npm.details.tag = Tag
|
||||||
|
@ -64,6 +64,7 @@ func createPackageMetadataVersion(registryURL string, pd *packages_model.Package
|
|||||||
Homepage: metadata.ProjectURL,
|
Homepage: metadata.ProjectURL,
|
||||||
License: metadata.License,
|
License: metadata.License,
|
||||||
Dependencies: metadata.Dependencies,
|
Dependencies: metadata.Dependencies,
|
||||||
|
BundleDependencies: metadata.BundleDependencies,
|
||||||
DevDependencies: metadata.DevelopmentDependencies,
|
DevDependencies: metadata.DevelopmentDependencies,
|
||||||
PeerDependencies: metadata.PeerDependencies,
|
PeerDependencies: metadata.PeerDependencies,
|
||||||
OptionalDependencies: metadata.OptionalDependencies,
|
OptionalDependencies: metadata.OptionalDependencies,
|
||||||
|
@ -67,7 +67,7 @@ func AddUserBadges(ctx *context.APIContext) {
|
|||||||
// "$ref": "#/responses/forbidden"
|
// "$ref": "#/responses/forbidden"
|
||||||
|
|
||||||
form := web.GetForm(ctx).(*api.UserBadgeOption)
|
form := web.GetForm(ctx).(*api.UserBadgeOption)
|
||||||
badges := prepareBadgesForReplaceOrAdd(ctx, *form)
|
badges := prepareBadgesForReplaceOrAdd(*form)
|
||||||
|
|
||||||
if err := user_model.AddUserBadges(ctx, ctx.ContextUser, badges); err != nil {
|
if err := user_model.AddUserBadges(ctx, ctx.ContextUser, badges); err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "ReplaceUserBadges", err)
|
ctx.Error(http.StatusInternalServerError, "ReplaceUserBadges", err)
|
||||||
@ -103,7 +103,7 @@ func DeleteUserBadges(ctx *context.APIContext) {
|
|||||||
// "$ref": "#/responses/validationError"
|
// "$ref": "#/responses/validationError"
|
||||||
|
|
||||||
form := web.GetForm(ctx).(*api.UserBadgeOption)
|
form := web.GetForm(ctx).(*api.UserBadgeOption)
|
||||||
badges := prepareBadgesForReplaceOrAdd(ctx, *form)
|
badges := prepareBadgesForReplaceOrAdd(*form)
|
||||||
|
|
||||||
if err := user_model.RemoveUserBadges(ctx, ctx.ContextUser, badges); err != nil {
|
if err := user_model.RemoveUserBadges(ctx, ctx.ContextUser, badges); err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "ReplaceUserBadges", err)
|
ctx.Error(http.StatusInternalServerError, "ReplaceUserBadges", err)
|
||||||
@ -113,7 +113,7 @@ func DeleteUserBadges(ctx *context.APIContext) {
|
|||||||
ctx.Status(http.StatusNoContent)
|
ctx.Status(http.StatusNoContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareBadgesForReplaceOrAdd(ctx *context.APIContext, form api.UserBadgeOption) []*user_model.Badge {
|
func prepareBadgesForReplaceOrAdd(form api.UserBadgeOption) []*user_model.Badge {
|
||||||
badges := make([]*user_model.Badge, len(form.BadgeSlugs))
|
badges := make([]*user_model.Badge, len(form.BadgeSlugs))
|
||||||
for i, badge := range form.BadgeSlugs {
|
for i, badge := range form.BadgeSlugs {
|
||||||
badges[i] = &user_model.Badge{
|
badges[i] = &user_model.Badge{
|
||||||
|
@ -180,7 +180,7 @@ func Migrate(ctx *context.APIContext) {
|
|||||||
Status: repo_model.RepositoryBeingMigrated,
|
Status: repo_model.RepositoryBeingMigrated,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handleMigrateError(ctx, repoOwner, remoteAddr, err)
|
handleMigrateError(ctx, repoOwner, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,7 +207,7 @@ func Migrate(ctx *context.APIContext) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
if repo, err = migrations.MigrateRepository(graceful.GetManager().HammerContext(), ctx.Doer, repoOwner.Name, opts, nil); err != nil {
|
if repo, err = migrations.MigrateRepository(graceful.GetManager().HammerContext(), ctx.Doer, repoOwner.Name, opts, nil); err != nil {
|
||||||
handleMigrateError(ctx, repoOwner, remoteAddr, err)
|
handleMigrateError(ctx, repoOwner, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +215,7 @@ func Migrate(ctx *context.APIContext) {
|
|||||||
ctx.JSON(http.StatusCreated, convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeAdmin}))
|
ctx.JSON(http.StatusCreated, convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeAdmin}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMigrateError(ctx *context.APIContext, repoOwner *user_model.User, remoteAddr string, err error) {
|
func handleMigrateError(ctx *context.APIContext, repoOwner *user_model.User, err error) {
|
||||||
switch {
|
switch {
|
||||||
case repo_model.IsErrRepoAlreadyExist(err):
|
case repo_model.IsErrRepoAlreadyExist(err):
|
||||||
ctx.Error(http.StatusConflict, "", "The repository with the same name already exists.")
|
ctx.Error(http.StatusConflict, "", "The repository with the same name already exists.")
|
||||||
|
@ -121,9 +121,9 @@ func HookPreReceive(ctx *gitea_context.PrivateContext) {
|
|||||||
case refFullName.IsBranch():
|
case refFullName.IsBranch():
|
||||||
preReceiveBranch(ourCtx, oldCommitID, newCommitID, refFullName)
|
preReceiveBranch(ourCtx, oldCommitID, newCommitID, refFullName)
|
||||||
case refFullName.IsTag():
|
case refFullName.IsTag():
|
||||||
preReceiveTag(ourCtx, oldCommitID, newCommitID, refFullName)
|
preReceiveTag(ourCtx, refFullName)
|
||||||
case git.DefaultFeatures.SupportProcReceive && refFullName.IsFor():
|
case git.DefaultFeatures.SupportProcReceive && refFullName.IsFor():
|
||||||
preReceiveFor(ourCtx, oldCommitID, newCommitID, refFullName)
|
preReceiveFor(ourCtx, refFullName)
|
||||||
default:
|
default:
|
||||||
ourCtx.AssertCanWriteCode()
|
ourCtx.AssertCanWriteCode()
|
||||||
}
|
}
|
||||||
@ -368,7 +368,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func preReceiveTag(ctx *preReceiveContext, oldCommitID, newCommitID string, refFullName git.RefName) {
|
func preReceiveTag(ctx *preReceiveContext, refFullName git.RefName) {
|
||||||
if !ctx.AssertCanWriteCode() {
|
if !ctx.AssertCanWriteCode() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -404,7 +404,7 @@ func preReceiveTag(ctx *preReceiveContext, oldCommitID, newCommitID string, refF
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func preReceiveFor(ctx *preReceiveContext, oldCommitID, newCommitID string, refFullName git.RefName) {
|
func preReceiveFor(ctx *preReceiveContext, refFullName git.RefName) {
|
||||||
if !ctx.AssertCreatePullRequest() {
|
if !ctx.AssertCreatePullRequest() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -159,7 +159,7 @@ func DashboardPost(ctx *context.Context) {
|
|||||||
switch form.Op {
|
switch form.Op {
|
||||||
case "sync_repo_branches":
|
case "sync_repo_branches":
|
||||||
go func() {
|
go func() {
|
||||||
if err := repo_service.AddAllRepoBranchesToSyncQueue(graceful.GetManager().ShutdownContext(), ctx.Doer.ID); err != nil {
|
if err := repo_service.AddAllRepoBranchesToSyncQueue(graceful.GetManager().ShutdownContext()); err != nil {
|
||||||
log.Error("AddAllRepoBranchesToSyncQueue: %v: %v", ctx.Doer.ID, err)
|
log.Error("AddAllRepoBranchesToSyncQueue: %v: %v", ctx.Doer.ID, err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -279,7 +279,7 @@ func GetFeedType(name string, req *http.Request) (bool, string, string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// feedActionsToFeedItems convert gitea's Repo's Releases to feeds Item
|
// feedActionsToFeedItems convert gitea's Repo's Releases to feeds Item
|
||||||
func releasesToFeedItems(ctx *context.Context, releases []*repo_model.Release, isReleasesOnly bool) (items []*feeds.Item, err error) {
|
func releasesToFeedItems(ctx *context.Context, releases []*repo_model.Release) (items []*feeds.Item, err error) {
|
||||||
for _, rel := range releases {
|
for _, rel := range releases {
|
||||||
err := rel.LoadAttributes(ctx)
|
err := rel.LoadAttributes(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -42,7 +42,7 @@ func ShowReleaseFeed(ctx *context.Context, repo *repo_model.Repository, isReleas
|
|||||||
Created: time.Now(),
|
Created: time.Now(),
|
||||||
}
|
}
|
||||||
|
|
||||||
feed.Items, err = releasesToFeedItems(ctx, releases, isReleasesOnly)
|
feed.Items, err = releasesToFeedItems(ctx, releases)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("releasesToFeedItems", err)
|
ctx.ServerError("releasesToFeedItems", err)
|
||||||
return
|
return
|
||||||
|
@ -419,11 +419,9 @@ func DiffPreviewPost(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if diff.NumFiles == 0 {
|
if diff.NumFiles != 0 {
|
||||||
ctx.PlainText(http.StatusOK, ctx.Locale.TrString("repo.editor.no_changes_to_show"))
|
ctx.Data["File"] = diff.Files[0]
|
||||||
return
|
|
||||||
}
|
}
|
||||||
ctx.Data["File"] = diff.Files[0]
|
|
||||||
|
|
||||||
ctx.HTML(http.StatusOK, tplEditDiffPreview)
|
ctx.HTML(http.StatusOK, tplEditDiffPreview)
|
||||||
}
|
}
|
||||||
|
@ -2177,7 +2177,10 @@ func GetIssueInfo(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.JSON(http.StatusOK, convert.ToIssue(ctx, ctx.Doer, issue))
|
ctx.JSON(http.StatusOK, map[string]any{
|
||||||
|
"convertedIssue": convert.ToIssue(ctx, ctx.Doer, issue),
|
||||||
|
"renderedLabels": templates.RenderLabels(ctx, ctx.Locale, issue.Labels, ctx.Repo.RepoLink, issue),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateIssueTitle change issue's title
|
// UpdateIssueTitle change issue's title
|
||||||
|
@ -86,7 +86,7 @@ func Search(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Data["CodeIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
|
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
|
||||||
ctx.Data["Repo"] = ctx.Repo.Repository
|
ctx.Data["Repo"] = ctx.Repo.Repository
|
||||||
ctx.Data["SearchResults"] = searchResults
|
ctx.Data["SearchResults"] = searchResults
|
||||||
ctx.Data["SearchResultLanguages"] = searchResultLanguages
|
ctx.Data["SearchResultLanguages"] = searchResultLanguages
|
||||||
|
@ -65,7 +65,7 @@ func SettingsCtxData(ctx *context.Context) {
|
|||||||
signing, _ := asymkey_service.SigningKey(ctx, ctx.Repo.Repository.RepoPath())
|
signing, _ := asymkey_service.SigningKey(ctx, ctx.Repo.Repository.RepoPath())
|
||||||
ctx.Data["SigningKeyAvailable"] = len(signing) > 0
|
ctx.Data["SigningKeyAvailable"] = len(signing) > 0
|
||||||
ctx.Data["SigningSettings"] = setting.Repository.Signing
|
ctx.Data["SigningSettings"] = setting.Repository.Signing
|
||||||
ctx.Data["CodeIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
|
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
|
||||||
|
|
||||||
if ctx.Doer.IsAdmin {
|
if ctx.Doer.IsAdmin {
|
||||||
if setting.Indexer.RepoIndexerEnabled {
|
if setting.Indexer.RepoIndexerEnabled {
|
||||||
@ -110,7 +110,7 @@ func SettingsPost(ctx *context.Context) {
|
|||||||
signing, _ := asymkey_service.SigningKey(ctx, ctx.Repo.Repository.RepoPath())
|
signing, _ := asymkey_service.SigningKey(ctx, ctx.Repo.Repository.RepoPath())
|
||||||
ctx.Data["SigningKeyAvailable"] = len(signing) > 0
|
ctx.Data["SigningKeyAvailable"] = len(signing) > 0
|
||||||
ctx.Data["SigningSettings"] = setting.Repository.Signing
|
ctx.Data["SigningSettings"] = setting.Repository.Signing
|
||||||
ctx.Data["CodeIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
|
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
|
||||||
|
|
||||||
repo := ctx.Repo.Repository
|
repo := ctx.Repo.Repository
|
||||||
|
|
||||||
|
@ -787,7 +787,7 @@ func (rt RepoRefType) RefTypeIncludesTags() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRefNameFromPath(ctx *Base, repo *Repository, path string, isExist func(string) bool) string {
|
func getRefNameFromPath(repo *Repository, path string, isExist func(string) bool) string {
|
||||||
refName := ""
|
refName := ""
|
||||||
parts := strings.Split(path, "/")
|
parts := strings.Split(path, "/")
|
||||||
for i, part := range parts {
|
for i, part := range parts {
|
||||||
@ -823,7 +823,7 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string {
|
|||||||
repo.TreePath = path
|
repo.TreePath = path
|
||||||
return repo.Repository.DefaultBranch
|
return repo.Repository.DefaultBranch
|
||||||
case RepoRefBranch:
|
case RepoRefBranch:
|
||||||
ref := getRefNameFromPath(ctx, repo, path, repo.GitRepo.IsBranchExist)
|
ref := getRefNameFromPath(repo, path, repo.GitRepo.IsBranchExist)
|
||||||
if len(ref) == 0 {
|
if len(ref) == 0 {
|
||||||
// check if ref is HEAD
|
// check if ref is HEAD
|
||||||
parts := strings.Split(path, "/")
|
parts := strings.Split(path, "/")
|
||||||
@ -833,7 +833,7 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// maybe it's a renamed branch
|
// maybe it's a renamed branch
|
||||||
return getRefNameFromPath(ctx, repo, path, func(s string) bool {
|
return getRefNameFromPath(repo, path, func(s string) bool {
|
||||||
b, exist, err := git_model.FindRenamedBranch(ctx, repo.Repository.ID, s)
|
b, exist, err := git_model.FindRenamedBranch(ctx, repo.Repository.ID, s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("FindRenamedBranch: %v", err)
|
log.Error("FindRenamedBranch: %v", err)
|
||||||
@ -853,7 +853,7 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string {
|
|||||||
|
|
||||||
return ref
|
return ref
|
||||||
case RepoRefTag:
|
case RepoRefTag:
|
||||||
return getRefNameFromPath(ctx, repo, path, repo.GitRepo.IsTagExist)
|
return getRefNameFromPath(repo, path, repo.GitRepo.IsTagExist)
|
||||||
case RepoRefCommit:
|
case RepoRefCommit:
|
||||||
parts := strings.Split(path, "/")
|
parts := strings.Split(path, "/")
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ type commonStorageCheckOptions struct {
|
|||||||
name string
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
func commonCheckStorage(ctx context.Context, logger log.Logger, autofix bool, opts *commonStorageCheckOptions) error {
|
func commonCheckStorage(logger log.Logger, autofix bool, opts *commonStorageCheckOptions) error {
|
||||||
totalCount, orphanedCount := 0, 0
|
totalCount, orphanedCount := 0, 0
|
||||||
totalSize, orphanedSize := int64(0), int64(0)
|
totalSize, orphanedSize := int64(0), int64(0)
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ func checkStorage(opts *checkStorageOptions) func(ctx context.Context, logger lo
|
|||||||
}
|
}
|
||||||
|
|
||||||
if opts.Attachments || opts.All {
|
if opts.Attachments || opts.All {
|
||||||
if err := commonCheckStorage(ctx, logger, autofix,
|
if err := commonCheckStorage(logger, autofix,
|
||||||
&commonStorageCheckOptions{
|
&commonStorageCheckOptions{
|
||||||
storer: storage.Attachments,
|
storer: storage.Attachments,
|
||||||
isOrphaned: func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) {
|
isOrphaned: func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) {
|
||||||
@ -116,7 +116,7 @@ func checkStorage(opts *checkStorageOptions) func(ctx context.Context, logger lo
|
|||||||
logger.Info("LFS isn't enabled (skipped)")
|
logger.Info("LFS isn't enabled (skipped)")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if err := commonCheckStorage(ctx, logger, autofix,
|
if err := commonCheckStorage(logger, autofix,
|
||||||
&commonStorageCheckOptions{
|
&commonStorageCheckOptions{
|
||||||
storer: storage.LFS,
|
storer: storage.LFS,
|
||||||
isOrphaned: func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) {
|
isOrphaned: func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) {
|
||||||
@ -132,7 +132,7 @@ func checkStorage(opts *checkStorageOptions) func(ctx context.Context, logger lo
|
|||||||
}
|
}
|
||||||
|
|
||||||
if opts.Avatars || opts.All {
|
if opts.Avatars || opts.All {
|
||||||
if err := commonCheckStorage(ctx, logger, autofix,
|
if err := commonCheckStorage(logger, autofix,
|
||||||
&commonStorageCheckOptions{
|
&commonStorageCheckOptions{
|
||||||
storer: storage.Avatars,
|
storer: storage.Avatars,
|
||||||
isOrphaned: func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) {
|
isOrphaned: func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) {
|
||||||
@ -146,7 +146,7 @@ func checkStorage(opts *checkStorageOptions) func(ctx context.Context, logger lo
|
|||||||
}
|
}
|
||||||
|
|
||||||
if opts.RepoAvatars || opts.All {
|
if opts.RepoAvatars || opts.All {
|
||||||
if err := commonCheckStorage(ctx, logger, autofix,
|
if err := commonCheckStorage(logger, autofix,
|
||||||
&commonStorageCheckOptions{
|
&commonStorageCheckOptions{
|
||||||
storer: storage.RepoAvatars,
|
storer: storage.RepoAvatars,
|
||||||
isOrphaned: func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) {
|
isOrphaned: func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) {
|
||||||
@ -160,7 +160,7 @@ func checkStorage(opts *checkStorageOptions) func(ctx context.Context, logger lo
|
|||||||
}
|
}
|
||||||
|
|
||||||
if opts.RepoArchives || opts.All {
|
if opts.RepoArchives || opts.All {
|
||||||
if err := commonCheckStorage(ctx, logger, autofix,
|
if err := commonCheckStorage(logger, autofix,
|
||||||
&commonStorageCheckOptions{
|
&commonStorageCheckOptions{
|
||||||
storer: storage.RepoArchives,
|
storer: storage.RepoArchives,
|
||||||
isOrphaned: func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) {
|
isOrphaned: func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) {
|
||||||
@ -182,7 +182,7 @@ func checkStorage(opts *checkStorageOptions) func(ctx context.Context, logger lo
|
|||||||
logger.Info("Packages isn't enabled (skipped)")
|
logger.Info("Packages isn't enabled (skipped)")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if err := commonCheckStorage(ctx, logger, autofix,
|
if err := commonCheckStorage(logger, autofix,
|
||||||
&commonStorageCheckOptions{
|
&commonStorageCheckOptions{
|
||||||
storer: storage.Packages,
|
storer: storage.Packages,
|
||||||
isOrphaned: func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) {
|
isOrphaned: func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) {
|
||||||
|
@ -977,25 +977,24 @@ func (g *GiteaLocalUploader) Finish() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *GiteaLocalUploader) remapUser(source user_model.ExternalUserMigrated, target user_model.ExternalUserRemappable) error {
|
func (g *GiteaLocalUploader) remapUser(source user_model.ExternalUserMigrated, target user_model.ExternalUserRemappable) error {
|
||||||
var userid int64
|
var userID int64
|
||||||
var err error
|
var err error
|
||||||
if g.sameApp {
|
if g.sameApp {
|
||||||
userid, err = g.remapLocalUser(source, target)
|
userID, err = g.remapLocalUser(source)
|
||||||
} else {
|
} else {
|
||||||
userid, err = g.remapExternalUser(source, target)
|
userID, err = g.remapExternalUser(source)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if userid > 0 {
|
if userID > 0 {
|
||||||
return target.RemapExternalUser("", 0, userid)
|
return target.RemapExternalUser("", 0, userID)
|
||||||
}
|
}
|
||||||
return target.RemapExternalUser(source.GetExternalName(), source.GetExternalID(), g.doer.ID)
|
return target.RemapExternalUser(source.GetExternalName(), source.GetExternalID(), g.doer.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GiteaLocalUploader) remapLocalUser(source user_model.ExternalUserMigrated, target user_model.ExternalUserRemappable) (int64, error) {
|
func (g *GiteaLocalUploader) remapLocalUser(source user_model.ExternalUserMigrated) (int64, error) {
|
||||||
userid, ok := g.userMap[source.GetExternalID()]
|
userid, ok := g.userMap[source.GetExternalID()]
|
||||||
if !ok {
|
if !ok {
|
||||||
name, err := user_model.GetUserNameByID(g.ctx, source.GetExternalID())
|
name, err := user_model.GetUserNameByID(g.ctx, source.GetExternalID())
|
||||||
@ -1013,7 +1012,7 @@ func (g *GiteaLocalUploader) remapLocalUser(source user_model.ExternalUserMigrat
|
|||||||
return userid, nil
|
return userid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GiteaLocalUploader) remapExternalUser(source user_model.ExternalUserMigrated, target user_model.ExternalUserRemappable) (userid int64, err error) {
|
func (g *GiteaLocalUploader) remapExternalUser(source user_model.ExternalUserMigrated) (userid int64, err error) {
|
||||||
userid, ok := g.userMap[source.GetExternalID()]
|
userid, ok := g.userMap[source.GetExternalID()]
|
||||||
if !ok {
|
if !ok {
|
||||||
userid, err = user_model.GetUserIDByExternalUserID(g.ctx, g.gitServiceType.Name(), fmt.Sprintf("%d", source.GetExternalID()))
|
userid, err = user_model.GetUserIDByExternalUserID(g.ctx, g.gitServiceType.Name(), fmt.Sprintf("%d", source.GetExternalID()))
|
||||||
|
@ -90,7 +90,7 @@ func Update(ctx context.Context, pullLimit, pushLimit int) error {
|
|||||||
|
|
||||||
pullMirrorsRequested := 0
|
pullMirrorsRequested := 0
|
||||||
if pullLimit != 0 {
|
if pullLimit != 0 {
|
||||||
if err := repo_model.MirrorsIterate(ctx, pullLimit, func(idx int, bean any) error {
|
if err := repo_model.MirrorsIterate(ctx, pullLimit, func(_ int, bean any) error {
|
||||||
if err := handler(bean); err != nil {
|
if err := handler(bean); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ var ErrSubmitReviewOnClosedPR = errors.New("can't submit review for a closed or
|
|||||||
|
|
||||||
// checkInvalidation checks if the line of code comment got changed by another commit.
|
// checkInvalidation checks if the line of code comment got changed by another commit.
|
||||||
// If the line got changed the comment is going to be invalidated.
|
// If the line got changed the comment is going to be invalidated.
|
||||||
func checkInvalidation(ctx context.Context, c *issues_model.Comment, doer *user_model.User, repo *git.Repository, branch string) error {
|
func checkInvalidation(ctx context.Context, c *issues_model.Comment, repo *git.Repository, branch string) error {
|
||||||
// FIXME differentiate between previous and proposed line
|
// FIXME differentiate between previous and proposed line
|
||||||
commit, err := repo.LineBlame(branch, repo.Path, c.TreePath, uint(c.UnsignedLine()))
|
commit, err := repo.LineBlame(branch, repo.Path, c.TreePath, uint(c.UnsignedLine()))
|
||||||
if err != nil && (strings.Contains(err.Error(), "fatal: no such path") || notEnoughLines.MatchString(err.Error())) {
|
if err != nil && (strings.Contains(err.Error(), "fatal: no such path") || notEnoughLines.MatchString(err.Error())) {
|
||||||
@ -83,7 +83,7 @@ func InvalidateCodeComments(ctx context.Context, prs issues_model.PullRequestLis
|
|||||||
return fmt.Errorf("find code comments: %v", err)
|
return fmt.Errorf("find code comments: %v", err)
|
||||||
}
|
}
|
||||||
for _, comment := range codeComments {
|
for _, comment := range codeComments {
|
||||||
if err := checkInvalidation(ctx, comment, doer, repo, branch); err != nil {
|
if err := checkInvalidation(ctx, comment, repo, branch); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ func Update(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.
|
|||||||
go AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false, "", "")
|
go AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false, "", "")
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return updateHeadByRebaseOnToBase(ctx, pr, doer, message)
|
return updateHeadByRebaseOnToBase(ctx, pr, doer)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := pr.LoadBaseRepo(ctx); err != nil {
|
if err := pr.LoadBaseRepo(ctx); err != nil {
|
||||||
|
@ -18,7 +18,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// updateHeadByRebaseOnToBase handles updating a PR's head branch by rebasing it on the PR current base branch
|
// updateHeadByRebaseOnToBase handles updating a PR's head branch by rebasing it on the PR current base branch
|
||||||
func updateHeadByRebaseOnToBase(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User, message string) error {
|
func updateHeadByRebaseOnToBase(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User) error {
|
||||||
// "Clone" base repo and add the cache headers for the head repo and branch
|
// "Clone" base repo and add the cache headers for the head repo and branch
|
||||||
mergeCtx, cancel, err := createTemporaryRepoForMerge(ctx, pr, doer, "")
|
mergeCtx, cancel, err := createTemporaryRepoForMerge(ctx, pr, doer, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -80,7 +80,7 @@ func AdoptRepository(ctx context.Context, doer, u *user_model.User, opts CreateR
|
|||||||
return fmt.Errorf("getRepositoryByID: %w", err)
|
return fmt.Errorf("getRepositoryByID: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := adoptRepository(ctx, repoPath, doer, repo, opts.DefaultBranch); err != nil {
|
if err := adoptRepository(ctx, repoPath, repo, opts.DefaultBranch); err != nil {
|
||||||
return fmt.Errorf("createDelegateHooks: %w", err)
|
return fmt.Errorf("createDelegateHooks: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +111,7 @@ func AdoptRepository(ctx context.Context, doer, u *user_model.User, opts CreateR
|
|||||||
return repo, nil
|
return repo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func adoptRepository(ctx context.Context, repoPath string, u *user_model.User, repo *repo_model.Repository, defaultBranch string) (err error) {
|
func adoptRepository(ctx context.Context, repoPath string, repo *repo_model.Repository, defaultBranch string) (err error) {
|
||||||
isExist, err := util.IsExist(repoPath)
|
isExist, err := util.IsExist(repoPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Unable to check if %s exists. Error: %v", repoPath, err)
|
log.Error("Unable to check if %s exists. Error: %v", repoPath, err)
|
||||||
|
@ -527,7 +527,7 @@ func handlerBranchSync(items ...*BranchSyncOptions) []*BranchSyncOptions {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addRepoToBranchSyncQueue(repoID, doerID int64) error {
|
func addRepoToBranchSyncQueue(repoID int64) error {
|
||||||
return branchSyncQueue.Push(&BranchSyncOptions{
|
return branchSyncQueue.Push(&BranchSyncOptions{
|
||||||
RepoID: repoID,
|
RepoID: repoID,
|
||||||
})
|
})
|
||||||
@ -543,9 +543,9 @@ func initBranchSyncQueue(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddAllRepoBranchesToSyncQueue(ctx context.Context, doerID int64) error {
|
func AddAllRepoBranchesToSyncQueue(ctx context.Context) error {
|
||||||
if err := db.Iterate(ctx, builder.Eq{"is_empty": false}, func(ctx context.Context, repo *repo_model.Repository) error {
|
if err := db.Iterate(ctx, builder.Eq{"is_empty": false}, func(ctx context.Context, repo *repo_model.Repository) error {
|
||||||
return addRepoToBranchSyncQueue(repo.ID, doerID)
|
return addRepoToBranchSyncQueue(repo.ID)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return fmt.Errorf("run sync all branches failed: %v", err)
|
return fmt.Errorf("run sync all branches failed: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -211,7 +211,7 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, file := range opts.Files {
|
for _, file := range opts.Files {
|
||||||
if err := handleCheckErrors(file, commit, opts, repo); err != nil {
|
if err := handleCheckErrors(file, commit, opts); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -277,7 +277,7 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handles the check for various issues for ChangeRepoFiles
|
// handles the check for various issues for ChangeRepoFiles
|
||||||
func handleCheckErrors(file *ChangeRepoFile, commit *git.Commit, opts *ChangeRepoFilesOptions, repo *repo_model.Repository) error {
|
func handleCheckErrors(file *ChangeRepoFile, commit *git.Commit, opts *ChangeRepoFilesOptions) error {
|
||||||
if file.Operation == "update" || file.Operation == "delete" {
|
if file.Operation == "update" || file.Operation == "delete" {
|
||||||
fromEntry, err := commit.GetTreeEntryByPath(file.Options.fromTreePath)
|
fromEntry, err := commit.GetTreeEntryByPath(file.Options.fromTreePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -35,7 +35,7 @@ func TestUpdateUser(t *testing.T) {
|
|||||||
Description: optional.Some("description"),
|
Description: optional.Some("description"),
|
||||||
AllowGitHook: optional.Some(true),
|
AllowGitHook: optional.Some(true),
|
||||||
AllowImportLocal: optional.Some(true),
|
AllowImportLocal: optional.Some(true),
|
||||||
MaxRepoCreation: optional.Some[int](10),
|
MaxRepoCreation: optional.Some(10),
|
||||||
IsRestricted: optional.Some(true),
|
IsRestricted: optional.Some(true),
|
||||||
IsActive: optional.Some(false),
|
IsActive: optional.Some(false),
|
||||||
IsAdmin: optional.Some(true),
|
IsAdmin: optional.Some(true),
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<div class="ui ten wide column">
|
<div class="ui ten wide column">
|
||||||
{{template "org/team/navbar" .}}
|
{{template "org/team/navbar" .}}
|
||||||
{{if .IsOrganizationOwner}}
|
{{if .IsOrganizationOwner}}
|
||||||
<div class="ui attached segment">
|
<div class="ui top attached segment">
|
||||||
<form class="ui form ignore-dirty tw-flex tw-flex-wrap tw-gap-2" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/add" method="post">
|
<form class="ui form ignore-dirty tw-flex tw-flex-wrap tw-gap-2" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/add" method="post">
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
<input type="hidden" name="uid" value="{{.SignedUser.ID}}">
|
<input type="hidden" name="uid" value="{{.SignedUser.ID}}">
|
||||||
@ -21,7 +21,7 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
<div class="ui attached segment">
|
<div class="ui{{if not .IsOrganizationOwner}} top{{end}} attached segment">
|
||||||
<div class="flex-list">
|
<div class="flex-list">
|
||||||
{{range .Team.Members}}
|
{{range .Team.Members}}
|
||||||
<div class="flex-item tw-items-center">
|
<div class="flex-item tw-items-center">
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<div class="ui top attached tabular menu org-team-navbar">
|
<div class="ui compact small menu small-menu-items org-team-navbar">
|
||||||
<a class="item{{if .PageIsOrgTeamMembers}} active{{end}}" href="{{.OrgLink}}/teams/{{.Team.LowerName | PathEscape}}">{{svg "octicon-person"}} <strong>{{.Team.NumMembers}}</strong> {{ctx.Locale.Tr "org.lower_members"}}</a>
|
<a class="item{{if .PageIsOrgTeamMembers}} active{{end}}" href="{{.OrgLink}}/teams/{{.Team.LowerName | PathEscape}}">{{svg "octicon-person"}} <strong>{{.Team.NumMembers}}</strong> {{ctx.Locale.Tr "org.lower_members"}}</a>
|
||||||
<a class="item{{if .PageIsOrgTeamRepos}} active{{end}}" href="{{.OrgLink}}/teams/{{.Team.LowerName | PathEscape}}/repositories">{{svg "octicon-repo"}} <strong>{{.Team.NumRepos}}</strong> {{ctx.Locale.Tr "org.lower_repositories"}}</a>
|
<a class="item{{if .PageIsOrgTeamRepos}} active{{end}}" href="{{.OrgLink}}/teams/{{.Team.LowerName | PathEscape}}/repositories">{{svg "octicon-repo"}} <strong>{{.Team.NumRepos}}</strong> {{ctx.Locale.Tr "org.lower_repositories"}}</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
<div class="ui attached segment">
|
<div class="ui{{if not $canAddRemove}} top{{end}} attached segment">
|
||||||
<div class="flex-list">
|
<div class="flex-list">
|
||||||
{{range .Team.Repos}}
|
{{range .Team.Repos}}
|
||||||
<div class="flex-item tw-items-center">
|
<div class="flex-item tw-items-center">
|
||||||
|
@ -45,6 +45,15 @@
|
|||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
{{if .PackageDescriptor.Metadata.BundleDependencies}}
|
||||||
|
<h4 class="ui top attached header">{{ctx.Locale.Tr "packages.npm.dependencies.bundle"}}</h4>
|
||||||
|
<div class="ui attached segment">
|
||||||
|
{{range .PackageDescriptor.Metadata.BundleDependencies}}
|
||||||
|
{{.}}
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{if .PackageDescriptor.Metadata.Keywords}}
|
{{if .PackageDescriptor.Metadata.Keywords}}
|
||||||
<h4 class="ui top attached header">{{ctx.Locale.Tr "packages.keywords"}}</h4>
|
<h4 class="ui top attached header">{{ctx.Locale.Tr "packages.keywords"}}</h4>
|
||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
|
@ -139,7 +139,7 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
{{template "repo/commit_load_branches_and_tags" .}}
|
{{template "repo/commit_load_branches_and_tags" .}}
|
||||||
</div>
|
</div>
|
||||||
<div class="ui attached segment tw-flex tw-items-center tw-justify-between tw-py-1 commit-header-row tw-flex-wrap {{$class}}">
|
<div class="ui{{if not .Commit.Signature}} bottom{{end}} attached segment tw-flex tw-items-center tw-justify-between tw-py-1 commit-header-row tw-flex-wrap {{$class}}">
|
||||||
<div class="tw-flex tw-items-center author">
|
<div class="tw-flex tw-items-center author">
|
||||||
{{if .Author}}
|
{{if .Author}}
|
||||||
{{ctx.AvatarUtils.Avatar .Author 28 "tw-mr-2"}}
|
{{ctx.AvatarUtils.Avatar .Author 28 "tw-mr-2"}}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
{{if .File}}
|
||||||
<div class="diff-file-box">
|
<div class="diff-file-box">
|
||||||
<div class="ui attached table segment">
|
<div class="ui attached table segment">
|
||||||
<div class="file-body file-code code-diff code-diff-unified unicode-escaped">
|
<div class="file-body file-code code-diff code-diff-unified unicode-escaped">
|
||||||
@ -9,3 +10,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<div class="tw-p-6 tw-text-center">
|
||||||
|
{{ctx.Locale.Tr "repo.editor.no_changes_to_show"}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
@ -26,14 +26,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui top attached tabular menu" data-write="write" data-preview="preview" data-diff="diff">
|
<div class="ui compact small menu small-menu-items repo-editor-menu">
|
||||||
<a class="active item" data-tab="write">{{svg "octicon-code"}} {{if .IsNewFile}}{{ctx.Locale.Tr "repo.editor.new_file"}}{{else}}{{ctx.Locale.Tr "repo.editor.edit_file"}}{{end}}</a>
|
<a class="active item" data-tab="write">{{svg "octicon-code"}} {{if .IsNewFile}}{{ctx.Locale.Tr "repo.editor.new_file"}}{{else}}{{ctx.Locale.Tr "repo.editor.edit_file"}}{{end}}</a>
|
||||||
<a class="item" data-tab="preview" data-url="{{.Repository.Link}}/markup" data-context="{{.RepoLink}}/src/{{.BranchNameSubURL}}" data-markup-mode="file">{{svg "octicon-eye"}} {{ctx.Locale.Tr "preview"}}</a>
|
<a class="item" data-tab="preview" data-url="{{.Repository.Link}}/markup" data-context="{{.RepoLink}}/src/{{.BranchNameSubURL}}" data-markup-mode="file">{{svg "octicon-eye"}} {{ctx.Locale.Tr "preview"}}</a>
|
||||||
{{if not .IsNewFile}}
|
{{if not .IsNewFile}}
|
||||||
<a class="item" data-tab="diff" hx-params="context,content" hx-vals='{"context":"{{.BranchLink}}"}' hx-include="#edit_area" hx-swap="innerHTML" hx-target=".tab[data-tab='diff']" hx-indicator=".tab[data-tab='diff']" hx-post="{{.RepoLink}}/_preview/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">{{svg "octicon-diff"}} {{ctx.Locale.Tr "repo.editor.preview_changes"}}</a>
|
<a class="item" data-tab="diff" hx-params="context,content" hx-vals='{"context":"{{.BranchLink}}"}' hx-include="#edit_area" hx-swap="innerHTML" hx-target=".tab[data-tab='diff']" hx-indicator=".tab[data-tab='diff']" hx-post="{{.RepoLink}}/_preview/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">{{svg "octicon-diff"}} {{ctx.Locale.Tr "repo.editor.preview_changes"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="ui bottom attached active tab segment" data-tab="write">
|
<div class="ui active tab segment tw-rounded" data-tab="write">
|
||||||
<textarea id="edit_area" name="content" class="tw-hidden" data-id="repo-{{.Repository.Name}}-{{.TreePath}}"
|
<textarea id="edit_area" name="content" class="tw-hidden" data-id="repo-{{.Repository.Name}}-{{.TreePath}}"
|
||||||
data-url="{{.Repository.Link}}/markup"
|
data-url="{{.Repository.Link}}/markup"
|
||||||
data-context="{{.RepoLink}}"
|
data-context="{{.RepoLink}}"
|
||||||
@ -41,10 +41,10 @@
|
|||||||
data-line-wrap-extensions="{{.LineWrapExtensions}}">{{.FileContent}}</textarea>
|
data-line-wrap-extensions="{{.LineWrapExtensions}}">{{.FileContent}}</textarea>
|
||||||
<div class="editor-loading is-loading"></div>
|
<div class="editor-loading is-loading"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui bottom attached tab segment markup" data-tab="preview">
|
<div class="ui tab segment markup tw-rounded" data-tab="preview">
|
||||||
{{ctx.Locale.Tr "loading"}}
|
{{ctx.Locale.Tr "loading"}}
|
||||||
</div>
|
</div>
|
||||||
<div class="ui bottom attached tab segment diff edit-diff" data-tab="diff">
|
<div class="ui tab segment diff edit-diff" data-tab="diff">
|
||||||
<div class="tw-p-16"></div>
|
<div class="tw-p-16"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,10 +19,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui top attached tabular menu" data-write="write">
|
<div class="ui compact small menu small-menu-items repo-editor-menu">
|
||||||
<a class="active item" data-tab="write">{{svg "octicon-code" 16 "tw-mr-1"}}{{ctx.Locale.Tr "repo.editor.new_patch"}}</a>
|
<a class="active item" data-tab="write">{{svg "octicon-code" 16 "tw-mr-1"}}{{ctx.Locale.Tr "repo.editor.new_patch"}}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui bottom attached active tab segment" data-tab="write">
|
<div class="ui active tab segment tw-rounded tw-p-0" data-tab="write">
|
||||||
<textarea id="edit_area" name="content" class="tw-hidden" data-id="repo-{{.Repository.Name}}-patch"
|
<textarea id="edit_area" name="content" class="tw-hidden" data-id="repo-{{.Repository.Name}}-patch"
|
||||||
data-context="{{.RepoLink}}"
|
data-context="{{.RepoLink}}"
|
||||||
data-line-wrap-extensions="{{.LineWrapExtensions}}">
|
data-line-wrap-extensions="{{.LineWrapExtensions}}">
|
||||||
|
@ -1,24 +1,21 @@
|
|||||||
<div class="ui centered grid">
|
<div class="ui centered grid">
|
||||||
<div class="twelve wide computer column">
|
<div class="twelve wide computer column">
|
||||||
<div class="ui attached left aligned segment">
|
<p>{{ctx.Locale.Tr "repo.issues.label_templates.info"}}</p>
|
||||||
<p>{{ctx.Locale.Tr "repo.issues.label_templates.info"}}</p>
|
<form class="ui form center" action="{{.Link}}/initialize" method="post">
|
||||||
<br>
|
{{.CsrfTokenHtml}}
|
||||||
<form class="ui form center" action="{{.Link}}/initialize" method="post">
|
<div class="field">
|
||||||
{{.CsrfTokenHtml}}
|
<div class="ui selection dropdown">
|
||||||
<div class="field">
|
<input type="hidden" name="template_name" value="Default">
|
||||||
<div class="ui selection dropdown">
|
<div class="default text">{{ctx.Locale.Tr "repo.issues.label_templates.helper"}}</div>
|
||||||
<input type="hidden" name="template_name" value="Default">
|
<div class="menu">
|
||||||
<div class="default text">{{ctx.Locale.Tr "repo.issues.label_templates.helper"}}</div>
|
{{range .LabelTemplateFiles}}
|
||||||
<div class="menu">
|
<div class="item" data-value="{{.DisplayName}}">{{.DisplayName}}<br><i>({{.Description}})</i></div>
|
||||||
{{range .LabelTemplateFiles}}
|
{{end}}
|
||||||
<div class="item" data-value="{{.DisplayName}}">{{.DisplayName}}<br><i>({{.Description}})</i></div>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
{{svg "octicon-triangle-down" 18 "dropdown icon"}}
|
|
||||||
</div>
|
</div>
|
||||||
|
{{svg "octicon-triangle-down" 18 "dropdown icon"}}
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="ui primary button">{{ctx.Locale.Tr "repo.issues.label_templates.use"}}</button>
|
</div>
|
||||||
</form>
|
<button type="submit" class="ui primary button">{{ctx.Locale.Tr "repo.issues.label_templates.use"}}</button>
|
||||||
</div>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -739,7 +739,7 @@
|
|||||||
<form class="ui form" method="post">
|
<form class="ui form" method="post">
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
<input type="hidden" name="action" value="admin_index">
|
<input type="hidden" name="action" value="admin_index">
|
||||||
{{if .CodeIndexerEnabled}}
|
{{if .IsRepoIndexerEnabled}}
|
||||||
<h4 class="ui header">{{ctx.Locale.Tr "repo.settings.admin_code_indexer"}}</h4>
|
<h4 class="ui header">{{ctx.Locale.Tr "repo.settings.admin_code_indexer"}}</h4>
|
||||||
<div class="inline fields">
|
<div class="inline fields">
|
||||||
<label>{{ctx.Locale.Tr "repo.settings.admin_indexer_commit_sha"}}</label>
|
<label>{{ctx.Locale.Tr "repo.settings.admin_indexer_commit_sha"}}</label>
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
<div class="ui container">
|
<div class="ui container">
|
||||||
{{template "base/alert" .}}
|
{{template "base/alert" .}}
|
||||||
{{template "repo/release_tag_header" .}}
|
{{template "repo/release_tag_header" .}}
|
||||||
|
{{if .Releases}}
|
||||||
<h4 class="ui top attached header">
|
<h4 class="ui top attached header">
|
||||||
<div class="five wide column tw-flex tw-items-center">
|
<div class="five wide column tw-flex tw-items-center">
|
||||||
{{svg "octicon-tag" 16 "tw-mr-1"}}{{ctx.Locale.Tr "repo.release.tags"}}
|
{{svg "octicon-tag" 16 "tw-mr-1"}}{{ctx.Locale.Tr "repo.release.tags"}}
|
||||||
@ -57,6 +58,7 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{template "base/paginate" .}}
|
{{template "base/paginate" .}}
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<p>{{ctx.Locale.Tr "search.code_search_unavailable"}}</p>
|
<p>{{ctx.Locale.Tr "search.code_search_unavailable"}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
{{if not .CodeIndexerEnabled}}
|
{{if not .IsRepoIndexerEnabled}}
|
||||||
<div class="ui message">
|
<div class="ui message">
|
||||||
<p>{{ctx.Locale.Tr "search.code_search_by_git_grep"}}</p>
|
<p>{{ctx.Locale.Tr "search.code_search_by_git_grep"}}</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{{template "base/head" .}}
|
{{template "base/head" .}}
|
||||||
<div role="main" aria-label="{{.Title}}" class="page-content user notification">
|
<div role="main" aria-label="{{.Title}}" class="page-content user notification">
|
||||||
<div class="ui container">
|
<div class="ui container">
|
||||||
<div class="ui top attached tabular menu">
|
<div class="ui compact small menu small-menu-items">
|
||||||
<a href="{{AppSubUrl}}/notifications/subscriptions" class="{{if eq .Status 1}}active {{end}}item">
|
<a href="{{AppSubUrl}}/notifications/subscriptions" class="{{if eq .Status 1}}active {{end}}item">
|
||||||
{{ctx.Locale.Tr "notification.subscriptions"}}
|
{{ctx.Locale.Tr "notification.subscriptions"}}
|
||||||
</a>
|
</a>
|
||||||
@ -9,7 +9,7 @@
|
|||||||
{{ctx.Locale.Tr "notification.watching"}}
|
{{ctx.Locale.Tr "notification.watching"}}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui bottom attached active tab segment">
|
<div class="ui top attached segment">
|
||||||
{{if eq .Status 1}}
|
{{if eq .Status 1}}
|
||||||
<div class="tw-flex tw-justify-between">
|
<div class="tw-flex tw-justify-between">
|
||||||
<div class="tw-flex">
|
<div class="tw-flex">
|
||||||
|
@ -111,7 +111,7 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui attached bottom segment">
|
<div class="ui bottom attached segment">
|
||||||
<form class="ui form" action="{{AppSubUrl}}/user/settings/account/email" method="post">
|
<form class="ui form" action="{{AppSubUrl}}/user/settings/account/email" method="post">
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
<div class="required field {{if .Err_Email}}error{{end}}">
|
<div class="required field {{if .Err_Email}}error{{end}}">
|
||||||
|
@ -49,7 +49,7 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui attached bottom segment">
|
<div class="ui bottom attached segment">
|
||||||
<h5 class="ui top header">
|
<h5 class="ui top header">
|
||||||
{{ctx.Locale.Tr "settings.generate_new_token"}}
|
{{ctx.Locale.Tr "settings.generate_new_token"}}
|
||||||
</h5>
|
</h5>
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui attached bottom segment">
|
<div class="ui bottom attached segment">
|
||||||
<form class="ui form ignore-dirty" action="{{.FormActionPath}}" method="post">
|
<form class="ui form ignore-dirty" action="{{.FormActionPath}}" method="post">
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
<div class="field {{if .Err_AppName}}error{{end}}">
|
<div class="field {{if .Err_AppName}}error{{end}}">
|
||||||
|
@ -47,7 +47,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui attached bottom segment">
|
<div class="ui bottom attached segment">
|
||||||
<h5 class="ui top header">
|
<h5 class="ui top header">
|
||||||
{{ctx.Locale.Tr "settings.create_oauth2_application"}}
|
{{ctx.Locale.Tr "settings.create_oauth2_application"}}
|
||||||
</h5>
|
</h5>
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui attached bottom segment">
|
<div class="ui bottom attached segment">
|
||||||
<form class="ui form" action="{{AppSubUrl}}/user/settings/security/openid" method="post">
|
<form class="ui form" action="{{AppSubUrl}}/user/settings/security/openid" method="post">
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
<div class="required field {{if .Err_OpenID}}error{{end}}">
|
<div class="required field {{if .Err_OpenID}}error{{end}}">
|
||||||
|
@ -169,7 +169,7 @@ nwIDAQAB
|
|||||||
assert.Nil(t, u)
|
assert.Nil(t, u)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
signRequest := func(t *testing.T, rw *RequestWrapper, version string) {
|
signRequest := func(rw *RequestWrapper, version string) {
|
||||||
req := rw.Request
|
req := rw.Request
|
||||||
username := req.Header.Get("X-Ops-Userid")
|
username := req.Header.Get("X-Ops-Userid")
|
||||||
if version != "1.0" && version != "1.3" {
|
if version != "1.0" && version != "1.3" {
|
||||||
@ -255,7 +255,7 @@ nwIDAQAB
|
|||||||
t.Run(v, func(t *testing.T) {
|
t.Run(v, func(t *testing.T) {
|
||||||
defer tests.PrintCurrentTest(t)()
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
signRequest(t, req, v)
|
signRequest(req, v)
|
||||||
u, err = auth.Verify(req.Request, nil, nil, nil)
|
u, err = auth.Verify(req.Request, nil, nil, nil)
|
||||||
assert.NotNil(t, u)
|
assert.NotNil(t, u)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -77,7 +77,7 @@ func TestAPIListReleases(t *testing.T) {
|
|||||||
testFilterByLen(true, url.Values{"draft": {"true"}, "pre-release": {"true"}}, 0, "there is no pre-release draft")
|
testFilterByLen(true, url.Values{"draft": {"true"}, "pre-release": {"true"}}, 0, "there is no pre-release draft")
|
||||||
}
|
}
|
||||||
|
|
||||||
func createNewReleaseUsingAPI(t *testing.T, session *TestSession, token string, owner *user_model.User, repo *repo_model.Repository, name, target, title, desc string) *api.Release {
|
func createNewReleaseUsingAPI(t *testing.T, token string, owner *user_model.User, repo *repo_model.Repository, name, target, title, desc string) *api.Release {
|
||||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases", owner.Name, repo.Name)
|
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases", owner.Name, repo.Name)
|
||||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateReleaseOption{
|
req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateReleaseOption{
|
||||||
TagName: name,
|
TagName: name,
|
||||||
@ -120,7 +120,7 @@ func TestAPICreateAndUpdateRelease(t *testing.T) {
|
|||||||
target, err := gitRepo.GetTagCommitID("v0.0.1")
|
target, err := gitRepo.GetTagCommitID("v0.0.1")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
newRelease := createNewReleaseUsingAPI(t, session, token, owner, repo, "v0.0.1", target, "v0.0.1", "test")
|
newRelease := createNewReleaseUsingAPI(t, token, owner, repo, "v0.0.1", target, "v0.0.1", "test")
|
||||||
|
|
||||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases/%d", owner.Name, repo.Name, newRelease.ID)
|
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases/%d", owner.Name, repo.Name, newRelease.ID)
|
||||||
req := NewRequest(t, "GET", urlStr).
|
req := NewRequest(t, "GET", urlStr).
|
||||||
@ -162,7 +162,7 @@ func TestAPICreateReleaseToDefaultBranch(t *testing.T) {
|
|||||||
session := loginUser(t, owner.LowerName)
|
session := loginUser(t, owner.LowerName)
|
||||||
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
|
||||||
|
|
||||||
createNewReleaseUsingAPI(t, session, token, owner, repo, "v0.0.1", "", "v0.0.1", "test")
|
createNewReleaseUsingAPI(t, token, owner, repo, "v0.0.1", "", "v0.0.1", "test")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAPICreateReleaseToDefaultBranchOnExistingTag(t *testing.T) {
|
func TestAPICreateReleaseToDefaultBranchOnExistingTag(t *testing.T) {
|
||||||
@ -180,7 +180,7 @@ func TestAPICreateReleaseToDefaultBranchOnExistingTag(t *testing.T) {
|
|||||||
err = gitRepo.CreateTag("v0.0.1", "master")
|
err = gitRepo.CreateTag("v0.0.1", "master")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
createNewReleaseUsingAPI(t, session, token, owner, repo, "v0.0.1", "", "v0.0.1", "test")
|
createNewReleaseUsingAPI(t, token, owner, repo, "v0.0.1", "", "v0.0.1", "test")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAPIGetLatestRelease(t *testing.T) {
|
func TestAPIGetLatestRelease(t *testing.T) {
|
||||||
@ -232,7 +232,7 @@ func TestAPIDeleteReleaseByTagName(t *testing.T) {
|
|||||||
session := loginUser(t, owner.LowerName)
|
session := loginUser(t, owner.LowerName)
|
||||||
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
|
||||||
|
|
||||||
createNewReleaseUsingAPI(t, session, token, owner, repo, "release-tag", "", "Release Tag", "test")
|
createNewReleaseUsingAPI(t, token, owner, repo, "release-tag", "", "Release Tag", "test")
|
||||||
|
|
||||||
// delete release
|
// delete release
|
||||||
req := NewRequestf(t, http.MethodDelete, fmt.Sprintf("/api/v1/repos/%s/%s/releases/tags/release-tag", owner.Name, repo.Name)).
|
req := NewRequestf(t, http.MethodDelete, fmt.Sprintf("/api/v1/repos/%s/%s/releases/tags/release-tag", owner.Name, repo.Name)).
|
||||||
@ -258,7 +258,7 @@ func TestAPIUploadAssetRelease(t *testing.T) {
|
|||||||
session := loginUser(t, owner.LowerName)
|
session := loginUser(t, owner.LowerName)
|
||||||
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
|
||||||
|
|
||||||
r := createNewReleaseUsingAPI(t, session, token, owner, repo, "release-tag", "", "Release Tag", "test")
|
r := createNewReleaseUsingAPI(t, token, owner, repo, "release-tag", "", "Release Tag", "test")
|
||||||
|
|
||||||
filename := "image.png"
|
filename := "image.png"
|
||||||
buff := generateImg()
|
buff := generateImg()
|
||||||
|
@ -80,7 +80,7 @@ func TestAPIDeleteTagByName(t *testing.T) {
|
|||||||
_ = MakeRequest(t, req, http.StatusNoContent)
|
_ = MakeRequest(t, req, http.StatusNoContent)
|
||||||
|
|
||||||
// Make sure that actual releases can't be deleted outright
|
// Make sure that actual releases can't be deleted outright
|
||||||
createNewReleaseUsingAPI(t, session, token, owner, repo, "release-tag", "", "Release Tag", "test")
|
createNewReleaseUsingAPI(t, token, owner, repo, "release-tag", "", "Release Tag", "test")
|
||||||
|
|
||||||
req = NewRequest(t, http.MethodDelete, fmt.Sprintf("/api/v1/repos/%s/%s/tags/release-tag", owner.Name, repo.Name)).
|
req = NewRequest(t, http.MethodDelete, fmt.Sprintf("/api/v1/repos/%s/%s/tags/release-tag", owner.Name, repo.Name)).
|
||||||
AddTokenAuth(token)
|
AddTokenAuth(token)
|
||||||
|
@ -6,6 +6,7 @@ package integration
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
@ -573,10 +574,14 @@ func TestGetIssueInfo(t *testing.T) {
|
|||||||
urlStr := fmt.Sprintf("/%s/%s/issues/%d/info", owner.Name, repo.Name, issue.Index)
|
urlStr := fmt.Sprintf("/%s/%s/issues/%d/info", owner.Name, repo.Name, issue.Index)
|
||||||
req := NewRequest(t, "GET", urlStr)
|
req := NewRequest(t, "GET", urlStr)
|
||||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
var apiIssue api.Issue
|
var respStruct struct {
|
||||||
DecodeJSON(t, resp, &apiIssue)
|
ConvertedIssue api.Issue
|
||||||
|
RenderedLabels template.HTML
|
||||||
|
}
|
||||||
|
DecodeJSON(t, resp, &respStruct)
|
||||||
|
|
||||||
assert.EqualValues(t, issue.ID, apiIssue.ID)
|
assert.EqualValues(t, issue.ID, respStruct.ConvertedIssue.ID)
|
||||||
|
assert.Contains(t, string(respStruct.RenderedLabels), `"labels-list"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateIssueDeadline(t *testing.T) {
|
func TestUpdateIssueDeadline(t *testing.T) {
|
||||||
|
@ -17,7 +17,7 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func resultFilenames(t testing.TB, doc *HTMLDoc) []string {
|
func resultFilenames(doc *HTMLDoc) []string {
|
||||||
filenameSelections := doc.doc.Find(".repository.search").Find(".repo-search-result").Find(".header").Find("span.file")
|
filenameSelections := doc.doc.Find(".repository.search").Find(".repo-search-result").Find(".header").Find("span.file")
|
||||||
result := make([]string, filenameSelections.Length())
|
result := make([]string, filenameSelections.Length())
|
||||||
filenameSelections.Each(func(i int, selection *goquery.Selection) {
|
filenameSelections.Each(func(i int, selection *goquery.Selection) {
|
||||||
@ -56,6 +56,6 @@ func testSearch(t *testing.T, url string, expected []string) {
|
|||||||
req := NewRequest(t, "GET", url)
|
req := NewRequest(t, "GET", url)
|
||||||
resp := MakeRequest(t, req, http.StatusOK)
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
filenames := resultFilenames(t, NewHTMLParser(t, resp.Body))
|
filenames := resultFilenames(NewHTMLParser(t, resp.Body))
|
||||||
assert.EqualValues(t, expected, filenames)
|
assert.EqualValues(t, expected, filenames)
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ func getDeleteRepoFilesOptions(repo *repo_model.Repository) *files_service.Chang
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getExpectedFileResponseForRepofilesDelete(u *url.URL) *api.FileResponse {
|
func getExpectedFileResponseForRepofilesDelete() *api.FileResponse {
|
||||||
// Just returns fields that don't change, i.e. fields with commit SHAs and dates can't be determined
|
// Just returns fields that don't change, i.e. fields with commit SHAs and dates can't be determined
|
||||||
return &api.FileResponse{
|
return &api.FileResponse{
|
||||||
Content: nil,
|
Content: nil,
|
||||||
@ -418,7 +418,7 @@ func testDeleteRepoFiles(t *testing.T, u *url.URL) {
|
|||||||
t.Run("Delete README.md file", func(t *testing.T) {
|
t.Run("Delete README.md file", func(t *testing.T) {
|
||||||
filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts)
|
filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
expectedFileResponse := getExpectedFileResponseForRepofilesDelete(u)
|
expectedFileResponse := getExpectedFileResponseForRepofilesDelete()
|
||||||
assert.NotNil(t, filesResponse)
|
assert.NotNil(t, filesResponse)
|
||||||
assert.Nil(t, filesResponse.Files[0])
|
assert.Nil(t, filesResponse.Files[0])
|
||||||
assert.EqualValues(t, expectedFileResponse.Commit.Message, filesResponse.Commit.Message)
|
assert.EqualValues(t, expectedFileResponse.Commit.Message, filesResponse.Commit.Message)
|
||||||
@ -460,7 +460,7 @@ func testDeleteRepoFilesWithoutBranchNames(t *testing.T, u *url.URL) {
|
|||||||
t.Run("Delete README.md without Branch Name", func(t *testing.T) {
|
t.Run("Delete README.md without Branch Name", func(t *testing.T) {
|
||||||
filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts)
|
filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
expectedFileResponse := getExpectedFileResponseForRepofilesDelete(u)
|
expectedFileResponse := getExpectedFileResponseForRepofilesDelete()
|
||||||
assert.NotNil(t, filesResponse)
|
assert.NotNil(t, filesResponse)
|
||||||
assert.Nil(t, filesResponse.Files[0])
|
assert.Nil(t, filesResponse.Files[0])
|
||||||
assert.EqualValues(t, expectedFileResponse.Commit.Message, filesResponse.Commit.Message)
|
assert.EqualValues(t, expectedFileResponse.Commit.Message, filesResponse.Commit.Message)
|
||||||
|
@ -680,10 +680,6 @@ input:-webkit-autofill:active,
|
|||||||
box-shadow: 0 6px 18px var(--color-shadow) !important;
|
box-shadow: 0 6px 18px var(--color-shadow) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.dimmer {
|
|
||||||
background: var(--color-overlay-backdrop);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui.dropdown .menu > .header {
|
.ui.dropdown .menu > .header {
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,11 @@
|
|||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.monaco-editor,
|
||||||
|
.monaco-editor .overflow-guard {
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
}
|
||||||
|
|
||||||
/* these seem unthemeable */
|
/* these seem unthemeable */
|
||||||
.monaco-scrollable-element > .scrollbar > .slider {
|
.monaco-scrollable-element > .scrollbar > .slider {
|
||||||
background: var(--color-primary) !important;
|
background: var(--color-primary) !important;
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
@import "./modules/table.css";
|
@import "./modules/table.css";
|
||||||
@import "./modules/card.css";
|
@import "./modules/card.css";
|
||||||
@import "./modules/checkbox.css";
|
@import "./modules/checkbox.css";
|
||||||
|
@import "./modules/dimmer.css";
|
||||||
@import "./modules/modal.css";
|
@import "./modules/modal.css";
|
||||||
|
|
||||||
@import "./modules/select.css";
|
@import "./modules/select.css";
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
border: 1px solid var(--color-secondary);
|
border: 1px solid var(--color-secondary);
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
|
border-radius: var(--border-radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.card {
|
.ui.card {
|
||||||
|
30
web_src/css/modules/dimmer.css
Normal file
30
web_src/css/modules/dimmer.css
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/* These are the remnants of the fomantic dimmer module */
|
||||||
|
|
||||||
|
.ui.dimmer {
|
||||||
|
position: fixed;
|
||||||
|
display: none;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: var(--color-overlay-backdrop);
|
||||||
|
opacity: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
overflow-y: auto;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 8px 0;
|
||||||
|
animation-name: fadein;
|
||||||
|
animation-duration: .2s;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui.active.dimmer {
|
||||||
|
display: flex;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui.dimmer > * {
|
||||||
|
position: static;
|
||||||
|
margin-top: auto !important;
|
||||||
|
margin-bottom: auto !important;
|
||||||
|
}
|
@ -799,3 +799,23 @@
|
|||||||
.ui.segment .ui.tabular.menu .active.item:hover {
|
.ui.segment .ui.tabular.menu .active.item:hover {
|
||||||
background: var(--color-box-body);
|
background: var(--color-box-body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.small-menu-items {
|
||||||
|
min-height: 35.4px !important; /* match .small.button in height */
|
||||||
|
background: none !important; /* fomantic sets a color here which does not play well with active transparent color on the item, so unset and set the colors on the item */
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small-menu-items .item {
|
||||||
|
background: var(--color-menu) !important;
|
||||||
|
padding-top: 6px !important;
|
||||||
|
padding-bottom: 6px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small-menu-items .item:hover {
|
||||||
|
background: var(--color-hover) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small-menu-items .item.active {
|
||||||
|
background: var(--color-active) !important;
|
||||||
|
}
|
||||||
|
@ -54,6 +54,7 @@ These inconsistent layouts should be refactored to simple ones.
|
|||||||
.ui.modal form > .content {
|
.ui.modal form > .content {
|
||||||
padding: 1.5em;
|
padding: 1.5em;
|
||||||
background: var(--color-body);
|
background: var(--color-body);
|
||||||
|
border-radius: 0 0 var(--border-radius) var(--border-radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.modal > .actions,
|
.ui.modal > .actions,
|
||||||
@ -63,6 +64,7 @@ These inconsistent layouts should be refactored to simple ones.
|
|||||||
border-color: var(--color-secondary);
|
border-color: var(--color-secondary);
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
border-radius: 0 0 var(--border-radius) var(--border-radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.modal .content > .actions {
|
.ui.modal .content > .actions {
|
||||||
|
@ -152,7 +152,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ui.attached.segment:has(+ .ui[class*="top attached"].header),
|
.ui.attached.segment:has(+ .ui[class*="top attached"].header),
|
||||||
.ui.attached.segment:last-child {
|
.ui.attached.segment:last-child,
|
||||||
|
.ui.segment:has(+ .ui.segment:not(.attached)),
|
||||||
|
.ui.attached.segment:has(+ .ui.modal) {
|
||||||
border-radius: 0 0 0.28571429rem 0.28571429rem;
|
border-radius: 0 0 0.28571429rem 0.28571429rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,6 +168,10 @@
|
|||||||
.ui.segment[class*="top attached"]:first-child {
|
.ui.segment[class*="top attached"]:first-child {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
.ui[class*="top attached"].segment:last-child {
|
||||||
|
border-top-left-radius: 0.28571429rem;
|
||||||
|
border-top-right-radius: 0.28571429rem;
|
||||||
|
}
|
||||||
|
|
||||||
.ui.segment[class*="bottom attached"] {
|
.ui.segment[class*="bottom attached"] {
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
@ -1586,6 +1586,7 @@ td .commit-summary {
|
|||||||
|
|
||||||
.repository .diff-file-box .file-body.file-code {
|
.repository .diff-file-box .file-body.file-code {
|
||||||
background: var(--color-code-bg);
|
background: var(--color-code-bg);
|
||||||
|
border-radius: var(--border-radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
.repository .diff-file-box .file-body.file-code .lines-num {
|
.repository .diff-file-box .file-body.file-code .lines-num {
|
||||||
@ -2382,6 +2383,22 @@ tbody.commit-list {
|
|||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* fix bottom border radius on diff files */
|
||||||
|
.diff-file-body tr.tag-code:last-child {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
.diff-file-body tr.tag-code:last-child > td {
|
||||||
|
background: var(--color-box-body-highlight);
|
||||||
|
}
|
||||||
|
.diff-file-body tr.tag-code:last-child td:first-child,
|
||||||
|
.diff-file-body tr.tag-code:last-child td:first-child * {
|
||||||
|
border-bottom-left-radius: 3px;
|
||||||
|
}
|
||||||
|
.diff-file-body tr.tag-code:last-child td:last-child,
|
||||||
|
.diff-file-body tr.tag-code:last-child td:last-child * {
|
||||||
|
border-bottom-right-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
.resolved-placeholder {
|
.resolved-placeholder {
|
||||||
font-weight: var(--font-weight-normal) !important;
|
font-weight: var(--font-weight-normal) !important;
|
||||||
border: 1px solid var(--color-secondary) !important;
|
border: 1px solid var(--color-secondary) !important;
|
||||||
@ -2491,6 +2508,7 @@ tbody.commit-list {
|
|||||||
|
|
||||||
.diff-file-header {
|
.diff-file-header {
|
||||||
padding: 5px 8px !important;
|
padding: 5px 8px !important;
|
||||||
|
box-shadow: 0 -1px 0 1px var(--color-body); /* prevent borders being visible behind top corners when sticky and scrolled */
|
||||||
}
|
}
|
||||||
|
|
||||||
.diff-file-box[data-folded="true"] .diff-file-body {
|
.diff-file-box[data-folded="true"] .diff-file-body {
|
||||||
|
@ -25,25 +25,6 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.small-menu-items {
|
|
||||||
min-height: 35.4px !important; /* match .small.button in height */
|
|
||||||
background: none !important; /* fomantic sets a color here which does not play well with active transparent color on the item, so unset and set the colors on the item */
|
|
||||||
}
|
|
||||||
|
|
||||||
.small-menu-items .item {
|
|
||||||
background: var(--color-menu) !important;
|
|
||||||
padding-top: 6px !important;
|
|
||||||
padding-bottom: 6px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.small-menu-items .item:hover {
|
|
||||||
background: var(--color-hover) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.small-menu-items .item.active {
|
|
||||||
background: var(--color-active) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 767.98px) {
|
@media (max-width: 767.98px) {
|
||||||
.list-header-search {
|
.list-header-search {
|
||||||
order: 0;
|
order: 0;
|
||||||
|
357
web_src/fomantic/build/semantic.css
generated
357
web_src/fomantic/build/semantic.css
generated
@ -8,363 +8,6 @@
|
|||||||
* http://opensource.org/licenses/MIT
|
* http://opensource.org/licenses/MIT
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
/*!
|
|
||||||
* # Fomantic-UI - Dimmer
|
|
||||||
* http://github.com/fomantic/Fomantic-UI/
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Released under the MIT license
|
|
||||||
* http://opensource.org/licenses/MIT
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*******************************
|
|
||||||
Dimmer
|
|
||||||
*******************************/
|
|
||||||
|
|
||||||
.dimmable:not(body) {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui.dimmer {
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
top: 0 !important;
|
|
||||||
left: 0 !important;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
text-align: center;
|
|
||||||
vertical-align: middle;
|
|
||||||
padding: 1em;
|
|
||||||
background: rgba(0, 0, 0, 0.85);
|
|
||||||
opacity: 0;
|
|
||||||
line-height: 1;
|
|
||||||
animation-fill-mode: both;
|
|
||||||
animation-duration: 0.5s;
|
|
||||||
transition: background-color 0.5s linear;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
will-change: opacity;
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Dimmer Content */
|
|
||||||
|
|
||||||
.ui.dimmer > .content {
|
|
||||||
-webkit-user-select: text;
|
|
||||||
-moz-user-select: text;
|
|
||||||
user-select: text;
|
|
||||||
color: #FFFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Loose Coupling */
|
|
||||||
|
|
||||||
.ui.segment > .ui.dimmer:not(.page) {
|
|
||||||
border-radius: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Scrollbars */
|
|
||||||
|
|
||||||
/*******************************
|
|
||||||
States
|
|
||||||
*******************************/
|
|
||||||
|
|
||||||
/* Animating */
|
|
||||||
|
|
||||||
.animating.dimmable:not(body),
|
|
||||||
.dimmed.dimmable:not(body) {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Animating / Active / Visible */
|
|
||||||
|
|
||||||
.dimmed.dimmable > .ui.animating.dimmer,
|
|
||||||
.dimmed.dimmable > .ui.visible.dimmer,
|
|
||||||
.ui.active.dimmer {
|
|
||||||
display: flex;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Disabled */
|
|
||||||
|
|
||||||
.ui.disabled.dimmer {
|
|
||||||
width: 0 !important;
|
|
||||||
height: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************
|
|
||||||
Variations
|
|
||||||
*******************************/
|
|
||||||
|
|
||||||
/*--------------
|
|
||||||
Legacy
|
|
||||||
---------------*/
|
|
||||||
|
|
||||||
/* Animating / Active / Visible */
|
|
||||||
|
|
||||||
.dimmed.dimmable > .ui.animating.legacy.dimmer,
|
|
||||||
.dimmed.dimmable > .ui.visible.legacy.dimmer,
|
|
||||||
.ui.active.legacy.dimmer {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--------------
|
|
||||||
Alignment
|
|
||||||
---------------*/
|
|
||||||
|
|
||||||
.ui[class*="top aligned"].dimmer {
|
|
||||||
justify-content: flex-start;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui[class*="bottom aligned"].dimmer {
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--------------
|
|
||||||
Page
|
|
||||||
---------------*/
|
|
||||||
|
|
||||||
.ui.page.dimmer {
|
|
||||||
position: fixed;
|
|
||||||
transform-style: '';
|
|
||||||
perspective: 2000px;
|
|
||||||
transform-origin: center center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui.page.dimmer.modals {
|
|
||||||
-moz-perspective: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.animating.in.dimmable,
|
|
||||||
body.dimmed.dimmable {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.dimmable > .dimmer {
|
|
||||||
position: fixed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--------------
|
|
||||||
Blurring
|
|
||||||
---------------*/
|
|
||||||
|
|
||||||
.blurring.dimmable > :not(.dimmer) {
|
|
||||||
filter: initial;
|
|
||||||
transition: 800ms filter ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.blurring.dimmed.dimmable > :not(.dimmer):not(.popup) {
|
|
||||||
filter: blur(5px) grayscale(0.7);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Dimmer Color */
|
|
||||||
|
|
||||||
.blurring.dimmable > .dimmer {
|
|
||||||
background: rgba(0, 0, 0, 0.6);
|
|
||||||
}
|
|
||||||
|
|
||||||
.blurring.dimmable > .inverted.dimmer {
|
|
||||||
background: rgba(255, 255, 255, 0.6);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--------------
|
|
||||||
Aligned
|
|
||||||
---------------*/
|
|
||||||
|
|
||||||
.ui.dimmer > .top.aligned.content > * {
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui.dimmer > .bottom.aligned.content > * {
|
|
||||||
vertical-align: bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--------------
|
|
||||||
Shades
|
|
||||||
---------------*/
|
|
||||||
|
|
||||||
.medium.medium.medium.medium.medium.dimmer {
|
|
||||||
background: rgba(0, 0, 0, 0.65);
|
|
||||||
}
|
|
||||||
|
|
||||||
.light.light.light.light.light.dimmer {
|
|
||||||
background: rgba(0, 0, 0, 0.45);
|
|
||||||
}
|
|
||||||
|
|
||||||
.very.light.light.light.light.dimmer {
|
|
||||||
background: rgba(0, 0, 0, 0.25);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--------------
|
|
||||||
Simple
|
|
||||||
---------------*/
|
|
||||||
|
|
||||||
/* Displays without javascript */
|
|
||||||
|
|
||||||
.ui.simple.dimmer {
|
|
||||||
display: block;
|
|
||||||
overflow: hidden;
|
|
||||||
opacity: 0;
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
z-index: -100;
|
|
||||||
background: rgba(0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
.dimmed.dimmable > .ui.simple.dimmer {
|
|
||||||
overflow: visible;
|
|
||||||
opacity: 1;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background: rgba(0, 0, 0, 0.85);
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui.simple.inverted.dimmer {
|
|
||||||
background: rgba(255, 255, 255, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
.dimmed.dimmable > .ui.simple.inverted.dimmer {
|
|
||||||
background: rgba(255, 255, 255, 0.85);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--------------
|
|
||||||
Partially
|
|
||||||
----------------*/
|
|
||||||
|
|
||||||
.ui[class*="top dimmer"],
|
|
||||||
.ui[class*="center dimmer"],
|
|
||||||
.ui[class*="bottom dimmer"] {
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui[class*="bottom dimmer"] {
|
|
||||||
top: auto !important;
|
|
||||||
bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui[class*="center dimmer"] {
|
|
||||||
top: 50% !important;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
-webkit-transform: translateY(calc(-50% - 0.5px));
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui.segment > .ui.ui[class*="top dimmer"] {
|
|
||||||
border-bottom-left-radius: 0;
|
|
||||||
border-bottom-right-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui.segment > .ui.ui[class*="center dimmer"] {
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui.segment > .ui.ui[class*="bottom dimmer"] {
|
|
||||||
border-top-left-radius: 0;
|
|
||||||
border-top-right-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui[class*="center dimmer"].transition[class*="fade up"].in {
|
|
||||||
animation-name: fadeInUpCenter;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui[class*="center dimmer"].transition[class*="fade down"].in {
|
|
||||||
animation-name: fadeInDownCenter;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui[class*="center dimmer"].transition[class*="fade up"].out {
|
|
||||||
animation-name: fadeOutUpCenter;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui[class*="center dimmer"].transition[class*="fade down"].out {
|
|
||||||
animation-name: fadeOutDownCenter;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui[class*="center dimmer"].bounce.transition {
|
|
||||||
animation-name: bounceCenter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeInUpCenter {
|
|
||||||
0% {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(-40%);
|
|
||||||
-webkit-transform: translateY(calc(-40% - 0.5px));
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
-webkit-transform: translateY(calc(-50% - 0.5px));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeInDownCenter {
|
|
||||||
0% {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(-60%);
|
|
||||||
-webkit-transform: translateY(calc(-60% - 0.5px));
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
-webkit-transform: translateY(calc(-50% - 0.5px));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeOutUpCenter {
|
|
||||||
0% {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
-webkit-transform: translateY(calc(-50% - 0.5px));
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(-45%);
|
|
||||||
-webkit-transform: translateY(calc(-45% - 0.5px));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeOutDownCenter {
|
|
||||||
0% {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
-webkit-transform: translateY(calc(-50% - 0.5px));
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(-55%);
|
|
||||||
-webkit-transform: translateY(calc(-55% - 0.5px));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes bounceCenter {
|
|
||||||
0%, 20%, 50%, 80%, 100% {
|
|
||||||
transform: translateY(-50%);
|
|
||||||
-webkit-transform: translateY(calc(-50% - 0.5px));
|
|
||||||
}
|
|
||||||
|
|
||||||
40% {
|
|
||||||
transform: translateY(calc(-50% - 30px));
|
|
||||||
}
|
|
||||||
|
|
||||||
60% {
|
|
||||||
transform: translateY(calc(-50% - 15px));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************
|
|
||||||
Theme Overrides
|
|
||||||
*******************************/
|
|
||||||
|
|
||||||
/*******************************
|
|
||||||
User Overrides
|
|
||||||
*******************************/
|
|
||||||
/*!
|
/*!
|
||||||
* # Fomantic-UI - Dropdown
|
* # Fomantic-UI - Dropdown
|
||||||
* http://github.com/fomantic/Fomantic-UI/
|
* http://github.com/fomantic/Fomantic-UI/
|
||||||
|
754
web_src/fomantic/build/semantic.js
generated
754
web_src/fomantic/build/semantic.js
generated
@ -1184,760 +1184,6 @@ $.api.settings = {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
})( jQuery, window, document );
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* # Fomantic-UI - Dimmer
|
|
||||||
* http://github.com/fomantic/Fomantic-UI/
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Released under the MIT license
|
|
||||||
* http://opensource.org/licenses/MIT
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
;(function ($, window, document, undefined) {
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
$.isFunction = $.isFunction || function(obj) {
|
|
||||||
return typeof obj === "function" && typeof obj.nodeType !== "number";
|
|
||||||
};
|
|
||||||
|
|
||||||
window = (typeof window != 'undefined' && window.Math == Math)
|
|
||||||
? window
|
|
||||||
: (typeof self != 'undefined' && self.Math == Math)
|
|
||||||
? self
|
|
||||||
: Function('return this')()
|
|
||||||
;
|
|
||||||
|
|
||||||
$.fn.dimmer = function(parameters) {
|
|
||||||
var
|
|
||||||
$allModules = $(this),
|
|
||||||
|
|
||||||
time = new Date().getTime(),
|
|
||||||
performance = [],
|
|
||||||
|
|
||||||
query = arguments[0],
|
|
||||||
methodInvoked = (typeof query == 'string'),
|
|
||||||
queryArguments = [].slice.call(arguments, 1),
|
|
||||||
|
|
||||||
returnedValue
|
|
||||||
;
|
|
||||||
|
|
||||||
$allModules
|
|
||||||
.each(function() {
|
|
||||||
var
|
|
||||||
settings = ( $.isPlainObject(parameters) )
|
|
||||||
? $.extend(true, {}, $.fn.dimmer.settings, parameters)
|
|
||||||
: $.extend({}, $.fn.dimmer.settings),
|
|
||||||
|
|
||||||
selector = settings.selector,
|
|
||||||
namespace = settings.namespace,
|
|
||||||
className = settings.className,
|
|
||||||
error = settings.error,
|
|
||||||
|
|
||||||
eventNamespace = '.' + namespace,
|
|
||||||
moduleNamespace = 'module-' + namespace,
|
|
||||||
moduleSelector = $allModules.selector || '',
|
|
||||||
|
|
||||||
clickEvent = "click", unstableClickEvent = ('ontouchstart' in document.documentElement)
|
|
||||||
? 'touchstart'
|
|
||||||
: 'click',
|
|
||||||
|
|
||||||
$module = $(this),
|
|
||||||
$dimmer,
|
|
||||||
$dimmable,
|
|
||||||
|
|
||||||
element = this,
|
|
||||||
instance = $module.data(moduleNamespace),
|
|
||||||
module
|
|
||||||
;
|
|
||||||
|
|
||||||
module = {
|
|
||||||
|
|
||||||
preinitialize: function() {
|
|
||||||
if( module.is.dimmer() ) {
|
|
||||||
|
|
||||||
$dimmable = $module.parent();
|
|
||||||
$dimmer = $module;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$dimmable = $module;
|
|
||||||
if( module.has.dimmer() ) {
|
|
||||||
if(settings.dimmerName) {
|
|
||||||
$dimmer = $dimmable.find(selector.dimmer).filter('.' + settings.dimmerName);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$dimmer = $dimmable.find(selector.dimmer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$dimmer = module.create();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
initialize: function() {
|
|
||||||
module.debug('Initializing dimmer', settings);
|
|
||||||
|
|
||||||
module.bind.events();
|
|
||||||
module.set.dimmable();
|
|
||||||
module.instantiate();
|
|
||||||
},
|
|
||||||
|
|
||||||
instantiate: function() {
|
|
||||||
module.verbose('Storing instance of module', module);
|
|
||||||
instance = module;
|
|
||||||
$module
|
|
||||||
.data(moduleNamespace, instance)
|
|
||||||
;
|
|
||||||
},
|
|
||||||
|
|
||||||
destroy: function() {
|
|
||||||
module.verbose('Destroying previous module', $dimmer);
|
|
||||||
module.unbind.events();
|
|
||||||
module.remove.variation();
|
|
||||||
$dimmable
|
|
||||||
.off(eventNamespace)
|
|
||||||
;
|
|
||||||
},
|
|
||||||
|
|
||||||
bind: {
|
|
||||||
events: function() {
|
|
||||||
if(settings.on == 'hover') {
|
|
||||||
$dimmable
|
|
||||||
.on('mouseenter' + eventNamespace, module.show)
|
|
||||||
.on('mouseleave' + eventNamespace, module.hide)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
else if(settings.on == 'click') {
|
|
||||||
$dimmable
|
|
||||||
.on(clickEvent + eventNamespace, module.toggle)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
if( module.is.page() ) {
|
|
||||||
module.debug('Setting as a page dimmer', $dimmable);
|
|
||||||
module.set.pageDimmer();
|
|
||||||
}
|
|
||||||
|
|
||||||
if( module.is.closable() ) {
|
|
||||||
module.verbose('Adding dimmer close event', $dimmer);
|
|
||||||
$dimmable
|
|
||||||
.on(clickEvent + eventNamespace, selector.dimmer, module.event.click)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
unbind: {
|
|
||||||
events: function() {
|
|
||||||
$module
|
|
||||||
.removeData(moduleNamespace)
|
|
||||||
;
|
|
||||||
$dimmable
|
|
||||||
.off(eventNamespace)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
event: {
|
|
||||||
click: function(event) {
|
|
||||||
module.verbose('Determining if event occured on dimmer', event);
|
|
||||||
if( $dimmer.find(event.target).length === 0 || $(event.target).is(selector.content) ) {
|
|
||||||
module.hide();
|
|
||||||
event.stopImmediatePropagation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
addContent: function(element) {
|
|
||||||
var
|
|
||||||
$content = $(element)
|
|
||||||
;
|
|
||||||
module.debug('Add content to dimmer', $content);
|
|
||||||
if($content.parent()[0] !== $dimmer[0]) {
|
|
||||||
$content.detach().appendTo($dimmer);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
create: function() {
|
|
||||||
var
|
|
||||||
$element = $( settings.template.dimmer(settings) )
|
|
||||||
;
|
|
||||||
if(settings.dimmerName) {
|
|
||||||
module.debug('Creating named dimmer', settings.dimmerName);
|
|
||||||
$element.addClass(settings.dimmerName);
|
|
||||||
}
|
|
||||||
$element
|
|
||||||
.appendTo($dimmable)
|
|
||||||
;
|
|
||||||
return $element;
|
|
||||||
},
|
|
||||||
|
|
||||||
show: function(callback) {
|
|
||||||
callback = $.isFunction(callback)
|
|
||||||
? callback
|
|
||||||
: function(){}
|
|
||||||
;
|
|
||||||
module.debug('Showing dimmer', $dimmer, settings);
|
|
||||||
module.set.variation();
|
|
||||||
if( (!module.is.dimmed() || module.is.animating()) && module.is.enabled() ) {
|
|
||||||
module.animate.show(callback);
|
|
||||||
settings.onShow.call(element);
|
|
||||||
settings.onChange.call(element);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
module.debug('Dimmer is already shown or disabled');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
hide: function(callback) {
|
|
||||||
callback = $.isFunction(callback)
|
|
||||||
? callback
|
|
||||||
: function(){}
|
|
||||||
;
|
|
||||||
if( module.is.dimmed() || module.is.animating() ) {
|
|
||||||
module.debug('Hiding dimmer', $dimmer);
|
|
||||||
module.animate.hide(callback);
|
|
||||||
settings.onHide.call(element);
|
|
||||||
settings.onChange.call(element);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
module.debug('Dimmer is not visible');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
toggle: function() {
|
|
||||||
module.verbose('Toggling dimmer visibility', $dimmer);
|
|
||||||
if( !module.is.dimmed() ) {
|
|
||||||
module.show();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ( module.is.closable() ) {
|
|
||||||
module.hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
animate: {
|
|
||||||
show: function(callback) {
|
|
||||||
callback = $.isFunction(callback)
|
|
||||||
? callback
|
|
||||||
: function(){}
|
|
||||||
;
|
|
||||||
if(settings.useCSS && $.fn.transition !== undefined && $dimmer.transition('is supported')) {
|
|
||||||
if(settings.useFlex) {
|
|
||||||
module.debug('Using flex dimmer');
|
|
||||||
module.remove.legacy();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
module.debug('Using legacy non-flex dimmer');
|
|
||||||
module.set.legacy();
|
|
||||||
}
|
|
||||||
if(settings.opacity !== 'auto') {
|
|
||||||
module.set.opacity();
|
|
||||||
}
|
|
||||||
$dimmer
|
|
||||||
.transition({
|
|
||||||
displayType : settings.useFlex
|
|
||||||
? 'flex'
|
|
||||||
: 'block',
|
|
||||||
animation : settings.transition + ' in',
|
|
||||||
queue : false,
|
|
||||||
duration : module.get.duration(),
|
|
||||||
useFailSafe : true,
|
|
||||||
onStart : function() {
|
|
||||||
module.set.dimmed();
|
|
||||||
},
|
|
||||||
onComplete : function() {
|
|
||||||
module.set.active();
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
module.verbose('Showing dimmer animation with javascript');
|
|
||||||
module.set.dimmed();
|
|
||||||
if(settings.opacity == 'auto') {
|
|
||||||
settings.opacity = 0.8;
|
|
||||||
}
|
|
||||||
$dimmer
|
|
||||||
.stop()
|
|
||||||
.css({
|
|
||||||
opacity : 0,
|
|
||||||
width : '100%',
|
|
||||||
height : '100%'
|
|
||||||
})
|
|
||||||
.fadeTo(module.get.duration(), settings.opacity, function() {
|
|
||||||
$dimmer.removeAttr('style');
|
|
||||||
module.set.active();
|
|
||||||
callback();
|
|
||||||
})
|
|
||||||
;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
hide: function(callback) {
|
|
||||||
callback = $.isFunction(callback)
|
|
||||||
? callback
|
|
||||||
: function(){}
|
|
||||||
;
|
|
||||||
if(settings.useCSS && $.fn.transition !== undefined && $dimmer.transition('is supported')) {
|
|
||||||
module.verbose('Hiding dimmer with css');
|
|
||||||
$dimmer
|
|
||||||
.transition({
|
|
||||||
displayType : settings.useFlex
|
|
||||||
? 'flex'
|
|
||||||
: 'block',
|
|
||||||
animation : settings.transition + ' out',
|
|
||||||
queue : false,
|
|
||||||
duration : module.get.duration(),
|
|
||||||
useFailSafe : true,
|
|
||||||
onComplete : function() {
|
|
||||||
module.remove.dimmed();
|
|
||||||
module.remove.variation();
|
|
||||||
module.remove.active();
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
module.verbose('Hiding dimmer with javascript');
|
|
||||||
$dimmer
|
|
||||||
.stop()
|
|
||||||
.fadeOut(module.get.duration(), function() {
|
|
||||||
module.remove.dimmed();
|
|
||||||
module.remove.active();
|
|
||||||
$dimmer.removeAttr('style');
|
|
||||||
callback();
|
|
||||||
})
|
|
||||||
;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
get: {
|
|
||||||
dimmer: function() {
|
|
||||||
return $dimmer;
|
|
||||||
},
|
|
||||||
duration: function() {
|
|
||||||
if(typeof settings.duration == 'object') {
|
|
||||||
if( module.is.active() ) {
|
|
||||||
return settings.duration.hide;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return settings.duration.show;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return settings.duration;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
has: {
|
|
||||||
dimmer: function() {
|
|
||||||
if(settings.dimmerName) {
|
|
||||||
return ($module.find(selector.dimmer).filter('.' + settings.dimmerName).length > 0);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return ( $module.find(selector.dimmer).length > 0 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
is: {
|
|
||||||
active: function() {
|
|
||||||
return $dimmer.hasClass(className.active);
|
|
||||||
},
|
|
||||||
animating: function() {
|
|
||||||
return ( $dimmer.is(':animated') || $dimmer.hasClass(className.animating) );
|
|
||||||
},
|
|
||||||
closable: function() {
|
|
||||||
if(settings.closable == 'auto') {
|
|
||||||
if(settings.on == 'hover') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return settings.closable;
|
|
||||||
},
|
|
||||||
dimmer: function() {
|
|
||||||
return $module.hasClass(className.dimmer);
|
|
||||||
},
|
|
||||||
dimmable: function() {
|
|
||||||
return $module.hasClass(className.dimmable);
|
|
||||||
},
|
|
||||||
dimmed: function() {
|
|
||||||
return $dimmable.hasClass(className.dimmed);
|
|
||||||
},
|
|
||||||
disabled: function() {
|
|
||||||
return $dimmable.hasClass(className.disabled);
|
|
||||||
},
|
|
||||||
enabled: function() {
|
|
||||||
return !module.is.disabled();
|
|
||||||
},
|
|
||||||
page: function () {
|
|
||||||
return $dimmable.is('body');
|
|
||||||
},
|
|
||||||
pageDimmer: function() {
|
|
||||||
return $dimmer.hasClass(className.pageDimmer);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
can: {
|
|
||||||
show: function() {
|
|
||||||
return !$dimmer.hasClass(className.disabled);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
set: {
|
|
||||||
opacity: function(opacity) {
|
|
||||||
var
|
|
||||||
color = $dimmer.css('background-color'),
|
|
||||||
colorArray = color.split(','),
|
|
||||||
isRGB = (colorArray && colorArray.length >= 3)
|
|
||||||
;
|
|
||||||
opacity = settings.opacity === 0 ? 0 : settings.opacity || opacity;
|
|
||||||
if(isRGB) {
|
|
||||||
colorArray[2] = colorArray[2].replace(')','');
|
|
||||||
colorArray[3] = opacity + ')';
|
|
||||||
color = colorArray.join(',');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
color = 'rgba(0, 0, 0, ' + opacity + ')';
|
|
||||||
}
|
|
||||||
module.debug('Setting opacity to', opacity);
|
|
||||||
$dimmer.css('background-color', color);
|
|
||||||
},
|
|
||||||
legacy: function() {
|
|
||||||
$dimmer.addClass(className.legacy);
|
|
||||||
},
|
|
||||||
active: function() {
|
|
||||||
$dimmer.addClass(className.active);
|
|
||||||
},
|
|
||||||
dimmable: function() {
|
|
||||||
$dimmable.addClass(className.dimmable);
|
|
||||||
},
|
|
||||||
dimmed: function() {
|
|
||||||
$dimmable.addClass(className.dimmed);
|
|
||||||
},
|
|
||||||
pageDimmer: function() {
|
|
||||||
$dimmer.addClass(className.pageDimmer);
|
|
||||||
},
|
|
||||||
disabled: function() {
|
|
||||||
$dimmer.addClass(className.disabled);
|
|
||||||
},
|
|
||||||
variation: function(variation) {
|
|
||||||
variation = variation || settings.variation;
|
|
||||||
if(variation) {
|
|
||||||
$dimmer.addClass(variation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
remove: {
|
|
||||||
active: function() {
|
|
||||||
$dimmer
|
|
||||||
.removeClass(className.active)
|
|
||||||
;
|
|
||||||
},
|
|
||||||
legacy: function() {
|
|
||||||
$dimmer.removeClass(className.legacy);
|
|
||||||
},
|
|
||||||
dimmed: function() {
|
|
||||||
$dimmable.removeClass(className.dimmed);
|
|
||||||
},
|
|
||||||
disabled: function() {
|
|
||||||
$dimmer.removeClass(className.disabled);
|
|
||||||
},
|
|
||||||
variation: function(variation) {
|
|
||||||
variation = variation || settings.variation;
|
|
||||||
if(variation) {
|
|
||||||
$dimmer.removeClass(variation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
setting: function(name, value) {
|
|
||||||
module.debug('Changing setting', name, value);
|
|
||||||
if( $.isPlainObject(name) ) {
|
|
||||||
$.extend(true, settings, name);
|
|
||||||
}
|
|
||||||
else if(value !== undefined) {
|
|
||||||
if($.isPlainObject(settings[name])) {
|
|
||||||
$.extend(true, settings[name], value);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
settings[name] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return settings[name];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
internal: function(name, value) {
|
|
||||||
if( $.isPlainObject(name) ) {
|
|
||||||
$.extend(true, module, name);
|
|
||||||
}
|
|
||||||
else if(value !== undefined) {
|
|
||||||
module[name] = value;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return module[name];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
debug: function() {
|
|
||||||
if(!settings.silent && settings.debug) {
|
|
||||||
if(settings.performance) {
|
|
||||||
module.performance.log(arguments);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
|
|
||||||
module.debug.apply(console, arguments);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
verbose: function() {
|
|
||||||
if(!settings.silent && settings.verbose && settings.debug) {
|
|
||||||
if(settings.performance) {
|
|
||||||
module.performance.log(arguments);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
|
|
||||||
module.verbose.apply(console, arguments);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error: function() {
|
|
||||||
if(!settings.silent) {
|
|
||||||
module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
|
|
||||||
module.error.apply(console, arguments);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
performance: {
|
|
||||||
log: function(message) {
|
|
||||||
var
|
|
||||||
currentTime,
|
|
||||||
executionTime,
|
|
||||||
previousTime
|
|
||||||
;
|
|
||||||
if(settings.performance) {
|
|
||||||
currentTime = new Date().getTime();
|
|
||||||
previousTime = time || currentTime;
|
|
||||||
executionTime = currentTime - previousTime;
|
|
||||||
time = currentTime;
|
|
||||||
performance.push({
|
|
||||||
'Name' : message[0],
|
|
||||||
'Arguments' : [].slice.call(message, 1) || '',
|
|
||||||
'Element' : element,
|
|
||||||
'Execution Time' : executionTime
|
|
||||||
});
|
|
||||||
}
|
|
||||||
clearTimeout(module.performance.timer);
|
|
||||||
module.performance.timer = setTimeout(module.performance.display, 500);
|
|
||||||
},
|
|
||||||
display: function() {
|
|
||||||
var
|
|
||||||
title = settings.name + ':',
|
|
||||||
totalTime = 0
|
|
||||||
;
|
|
||||||
time = false;
|
|
||||||
clearTimeout(module.performance.timer);
|
|
||||||
$.each(performance, function(index, data) {
|
|
||||||
totalTime += data['Execution Time'];
|
|
||||||
});
|
|
||||||
title += ' ' + totalTime + 'ms';
|
|
||||||
if(moduleSelector) {
|
|
||||||
title += ' \'' + moduleSelector + '\'';
|
|
||||||
}
|
|
||||||
if($allModules.length > 1) {
|
|
||||||
title += ' ' + '(' + $allModules.length + ')';
|
|
||||||
}
|
|
||||||
if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
|
|
||||||
console.groupCollapsed(title);
|
|
||||||
if(console.table) {
|
|
||||||
console.table(performance);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$.each(performance, function(index, data) {
|
|
||||||
console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
console.groupEnd();
|
|
||||||
}
|
|
||||||
performance = [];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
invoke: function(query, passedArguments, context) {
|
|
||||||
var
|
|
||||||
object = instance,
|
|
||||||
maxDepth,
|
|
||||||
found,
|
|
||||||
response
|
|
||||||
;
|
|
||||||
passedArguments = passedArguments || queryArguments;
|
|
||||||
context = element || context;
|
|
||||||
if(typeof query == 'string' && object !== undefined) {
|
|
||||||
query = query.split(/[\. ]/);
|
|
||||||
maxDepth = query.length - 1;
|
|
||||||
$.each(query, function(depth, value) {
|
|
||||||
var camelCaseValue = (depth != maxDepth)
|
|
||||||
? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
|
|
||||||
: query
|
|
||||||
;
|
|
||||||
if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
|
|
||||||
object = object[camelCaseValue];
|
|
||||||
}
|
|
||||||
else if( object[camelCaseValue] !== undefined ) {
|
|
||||||
found = object[camelCaseValue];
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
|
|
||||||
object = object[value];
|
|
||||||
}
|
|
||||||
else if( object[value] !== undefined ) {
|
|
||||||
found = object[value];
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
module.error(error.method, query);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if ( $.isFunction( found ) ) {
|
|
||||||
response = found.apply(context, passedArguments);
|
|
||||||
}
|
|
||||||
else if(found !== undefined) {
|
|
||||||
response = found;
|
|
||||||
}
|
|
||||||
if(Array.isArray(returnedValue)) {
|
|
||||||
returnedValue.push(response);
|
|
||||||
}
|
|
||||||
else if(returnedValue !== undefined) {
|
|
||||||
returnedValue = [returnedValue, response];
|
|
||||||
}
|
|
||||||
else if(response !== undefined) {
|
|
||||||
returnedValue = response;
|
|
||||||
}
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.preinitialize();
|
|
||||||
|
|
||||||
if(methodInvoked) {
|
|
||||||
if(instance === undefined) {
|
|
||||||
module.initialize();
|
|
||||||
}
|
|
||||||
module.invoke(query);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(instance !== undefined) {
|
|
||||||
instance.invoke('destroy');
|
|
||||||
}
|
|
||||||
module.initialize();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
return (returnedValue !== undefined)
|
|
||||||
? returnedValue
|
|
||||||
: this
|
|
||||||
;
|
|
||||||
};
|
|
||||||
|
|
||||||
$.fn.dimmer.settings = {
|
|
||||||
|
|
||||||
name : 'Dimmer',
|
|
||||||
namespace : 'dimmer',
|
|
||||||
|
|
||||||
silent : false,
|
|
||||||
debug : false,
|
|
||||||
verbose : false,
|
|
||||||
performance : true,
|
|
||||||
|
|
||||||
// whether should use flex layout
|
|
||||||
useFlex : true,
|
|
||||||
|
|
||||||
// name to distinguish between multiple dimmers in context
|
|
||||||
dimmerName : false,
|
|
||||||
|
|
||||||
// whether to add a variation type
|
|
||||||
variation : false,
|
|
||||||
|
|
||||||
// whether to bind close events
|
|
||||||
closable : 'auto',
|
|
||||||
|
|
||||||
// whether to use css animations
|
|
||||||
useCSS : true,
|
|
||||||
|
|
||||||
// css animation to use
|
|
||||||
transition : 'fade',
|
|
||||||
|
|
||||||
// event to bind to
|
|
||||||
on : false,
|
|
||||||
|
|
||||||
// overriding opacity value
|
|
||||||
opacity : 'auto',
|
|
||||||
|
|
||||||
// transition durations
|
|
||||||
duration : {
|
|
||||||
show : 500,
|
|
||||||
hide : 500
|
|
||||||
},
|
|
||||||
// whether the dynamically created dimmer should have a loader
|
|
||||||
displayLoader: false,
|
|
||||||
loaderText : false,
|
|
||||||
loaderVariation : '',
|
|
||||||
|
|
||||||
onChange : function(){},
|
|
||||||
onShow : function(){},
|
|
||||||
onHide : function(){},
|
|
||||||
|
|
||||||
error : {
|
|
||||||
method : 'The method you called is not defined.'
|
|
||||||
},
|
|
||||||
|
|
||||||
className : {
|
|
||||||
active : 'active',
|
|
||||||
animating : 'animating',
|
|
||||||
dimmable : 'dimmable',
|
|
||||||
dimmed : 'dimmed',
|
|
||||||
dimmer : 'dimmer',
|
|
||||||
disabled : 'disabled',
|
|
||||||
hide : 'hide',
|
|
||||||
legacy : 'legacy',
|
|
||||||
pageDimmer : 'page',
|
|
||||||
show : 'show',
|
|
||||||
loader : 'ui loader'
|
|
||||||
},
|
|
||||||
|
|
||||||
selector: {
|
|
||||||
dimmer : '> .ui.dimmer',
|
|
||||||
content : '.ui.dimmer > .content, .ui.dimmer > .content > .center'
|
|
||||||
},
|
|
||||||
|
|
||||||
template: {
|
|
||||||
dimmer: function(settings) {
|
|
||||||
var d = $('<div/>').addClass('ui dimmer'),l;
|
|
||||||
if(settings.displayLoader) {
|
|
||||||
l = $('<div/>')
|
|
||||||
.addClass(settings.className.loader)
|
|
||||||
.addClass(settings.loaderVariation);
|
|
||||||
if(!!settings.loaderText){
|
|
||||||
l.text(settings.loaderText);
|
|
||||||
l.addClass('text');
|
|
||||||
}
|
|
||||||
d.append(l);
|
|
||||||
}
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
})( jQuery, window, document );
|
})( jQuery, window, document );
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
"admin": false,
|
"admin": false,
|
||||||
"components": [
|
"components": [
|
||||||
"api",
|
"api",
|
||||||
"dimmer",
|
|
||||||
"dropdown",
|
"dropdown",
|
||||||
"form",
|
"form",
|
||||||
"modal",
|
"modal",
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
import {SvgIcon} from '../svg.js';
|
import {SvgIcon} from '../svg.js';
|
||||||
import {contrastColor} from '../utils/color.js';
|
|
||||||
import {GET} from '../modules/fetch.js';
|
import {GET} from '../modules/fetch.js';
|
||||||
|
|
||||||
const {appSubUrl, i18n} = window.config;
|
const {appSubUrl, i18n} = window.config;
|
||||||
@ -10,6 +9,7 @@ export default {
|
|||||||
data: () => ({
|
data: () => ({
|
||||||
loading: false,
|
loading: false,
|
||||||
issue: null,
|
issue: null,
|
||||||
|
renderedLabels: '',
|
||||||
i18nErrorOccurred: i18n.error_occurred,
|
i18nErrorOccurred: i18n.error_occurred,
|
||||||
i18nErrorMessage: null,
|
i18nErrorMessage: null,
|
||||||
}),
|
}),
|
||||||
@ -56,14 +56,6 @@ export default {
|
|||||||
}
|
}
|
||||||
return 'red'; // Closed Issue
|
return 'red'; // Closed Issue
|
||||||
},
|
},
|
||||||
|
|
||||||
labels() {
|
|
||||||
return this.issue.labels.map((label) => ({
|
|
||||||
name: label.name,
|
|
||||||
color: `#${label.color}`,
|
|
||||||
textColor: contrastColor(`#${label.color}`),
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$refs.root.addEventListener('ce-load-context-popup', (e) => {
|
this.$refs.root.addEventListener('ce-load-context-popup', (e) => {
|
||||||
@ -79,13 +71,14 @@ export default {
|
|||||||
this.i18nErrorMessage = null;
|
this.i18nErrorMessage = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await GET(`${appSubUrl}/${data.owner}/${data.repo}/issues/${data.index}/info`);
|
const response = await GET(`${appSubUrl}/${data.owner}/${data.repo}/issues/${data.index}/info`); // backend: GetIssueInfo
|
||||||
const respJson = await response.json();
|
const respJson = await response.json();
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
this.i18nErrorMessage = respJson.message ?? i18n.network_error;
|
this.i18nErrorMessage = respJson.message ?? i18n.network_error;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.issue = respJson;
|
this.issue = respJson.convertedIssue;
|
||||||
|
this.renderedLabels = respJson.renderedLabels;
|
||||||
} catch {
|
} catch {
|
||||||
this.i18nErrorMessage = i18n.network_error;
|
this.i18nErrorMessage = i18n.network_error;
|
||||||
} finally {
|
} finally {
|
||||||
@ -102,16 +95,8 @@ export default {
|
|||||||
<p><small>{{ issue.repository.full_name }} on {{ createdAt }}</small></p>
|
<p><small>{{ issue.repository.full_name }} on {{ createdAt }}</small></p>
|
||||||
<p><svg-icon :name="icon" :class="['text', color]"/> <strong>{{ issue.title }}</strong> #{{ issue.number }}</p>
|
<p><svg-icon :name="icon" :class="['text', color]"/> <strong>{{ issue.title }}</strong> #{{ issue.number }}</p>
|
||||||
<p>{{ body }}</p>
|
<p>{{ body }}</p>
|
||||||
<div class="labels-list">
|
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||||
<div
|
<div v-html="renderedLabels"/>
|
||||||
v-for="label in labels"
|
|
||||||
:key="label.name"
|
|
||||||
class="ui label"
|
|
||||||
:style="{ color: label.textColor, backgroundColor: label.color }"
|
|
||||||
>
|
|
||||||
{{ label.name }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!loading && issue === null">
|
<div v-if="!loading && issue === null">
|
||||||
<p><small>{{ i18nErrorOccurred }}</small></p>
|
<p><small>{{ i18nErrorOccurred }}</small></p>
|
||||||
|
@ -98,6 +98,7 @@ export async function createMonaco(textarea, filename, editorOpts) {
|
|||||||
'input.foreground': getColor('--color-input-text'),
|
'input.foreground': getColor('--color-input-text'),
|
||||||
'scrollbar.shadow': getColor('--color-shadow'),
|
'scrollbar.shadow': getColor('--color-shadow'),
|
||||||
'progressBar.background': getColor('--color-primary'),
|
'progressBar.background': getColor('--color-primary'),
|
||||||
|
'focusBorder': '#0000', // prevent blue border
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ export function initCommonIssueListQuickGoto() {
|
|||||||
// try to check whether the parsed goto link is valid
|
// try to check whether the parsed goto link is valid
|
||||||
let targetUrl = parseIssueListQuickGotoLink(repoLink, searchText);
|
let targetUrl = parseIssueListQuickGotoLink(repoLink, searchText);
|
||||||
if (targetUrl) {
|
if (targetUrl) {
|
||||||
const res = await GET(`${targetUrl}/info`);
|
const res = await GET(`${targetUrl}/info`); // backend: GetIssueInfo, it only checks whether the issue exists by status code
|
||||||
if (res.status !== 200) targetUrl = '';
|
if (res.status !== 200) targetUrl = '';
|
||||||
}
|
}
|
||||||
// if the input value has changed, then ignore the result
|
// if the input value has changed, then ignore the result
|
||||||
|
@ -7,9 +7,9 @@ import {attachRefIssueContextPopup} from './contextpopup.js';
|
|||||||
import {POST} from '../modules/fetch.js';
|
import {POST} from '../modules/fetch.js';
|
||||||
|
|
||||||
function initEditPreviewTab($form) {
|
function initEditPreviewTab($form) {
|
||||||
const $tabMenu = $form.find('.tabular.menu');
|
const $tabMenu = $form.find('.repo-editor-menu');
|
||||||
$tabMenu.find('.item').tab();
|
$tabMenu.find('.item').tab();
|
||||||
const $previewTab = $tabMenu.find(`.item[data-tab="${$tabMenu.data('preview')}"]`);
|
const $previewTab = $tabMenu.find('a[data-tab="preview"]');
|
||||||
if ($previewTab.length) {
|
if ($previewTab.length) {
|
||||||
$previewTab.on('click', async function () {
|
$previewTab.on('click', async function () {
|
||||||
const $this = $(this);
|
const $this = $(this);
|
||||||
@ -24,13 +24,15 @@ function initEditPreviewTab($form) {
|
|||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('mode', mode);
|
formData.append('mode', mode);
|
||||||
formData.append('context', context);
|
formData.append('context', context);
|
||||||
formData.append('text', $form.find(`.tab[data-tab="${$tabMenu.data('write')}"] textarea`).val());
|
formData.append('text', $form.find('.tab[data-tab="write"] textarea').val());
|
||||||
formData.append('file_path', $treePathEl.val());
|
formData.append('file_path', $treePathEl.val());
|
||||||
try {
|
try {
|
||||||
const response = await POST($this.data('url'), {data: formData});
|
const response = await POST($this.data('url'), {data: formData});
|
||||||
const data = await response.text();
|
const data = await response.text();
|
||||||
const $previewPanel = $form.find(`.tab[data-tab="${$tabMenu.data('preview')}"]`);
|
const $previewPanel = $form.find('.tab[data-tab="preview"]');
|
||||||
renderPreviewPanelContent($previewPanel, data);
|
if ($previewPanel.length) {
|
||||||
|
renderPreviewPanelContent($previewPanel, data);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error:', error);
|
console.error('Error:', error);
|
||||||
}
|
}
|
||||||
@ -175,10 +177,10 @@ export function initRepoEditor() {
|
|||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function renderPreviewPanelContent($panelPreviewer, data) {
|
export function renderPreviewPanelContent($previewPanel, data) {
|
||||||
$panelPreviewer.html(data);
|
$previewPanel.html(data);
|
||||||
initMarkupContent();
|
initMarkupContent();
|
||||||
|
|
||||||
const $refIssues = $panelPreviewer.find('p .ref-issue');
|
const $refIssues = $previewPanel.find('p .ref-issue');
|
||||||
attachRefIssueContextPopup($refIssues);
|
attachRefIssueContextPopup($refIssues);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import {initAriaFormFieldPatch} from './fomantic/form.js';
|
|||||||
import {initAriaDropdownPatch} from './fomantic/dropdown.js';
|
import {initAriaDropdownPatch} from './fomantic/dropdown.js';
|
||||||
import {initAriaModalPatch} from './fomantic/modal.js';
|
import {initAriaModalPatch} from './fomantic/modal.js';
|
||||||
import {initFomanticTransition} from './fomantic/transition.js';
|
import {initFomanticTransition} from './fomantic/transition.js';
|
||||||
|
import {initFomanticDimmer} from './fomantic/dimmer.js';
|
||||||
import {svg} from '../svg.js';
|
import {svg} from '../svg.js';
|
||||||
|
|
||||||
export const fomanticMobileScreen = window.matchMedia('only screen and (max-width: 767.98px)');
|
export const fomanticMobileScreen = window.matchMedia('only screen and (max-width: 767.98px)');
|
||||||
@ -24,6 +25,7 @@ export function initGiteaFomantic() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
initFomanticTransition();
|
initFomanticTransition();
|
||||||
|
initFomanticDimmer();
|
||||||
initFomanticApiPatch();
|
initFomanticApiPatch();
|
||||||
|
|
||||||
// Use the patches to improve accessibility, these patches are designed to be as independent as possible, make it easy to modify or remove in the future.
|
// Use the patches to improve accessibility, these patches are designed to be as independent as possible, make it easy to modify or remove in the future.
|
||||||
|
29
web_src/js/modules/fomantic/dimmer.js
Normal file
29
web_src/js/modules/fomantic/dimmer.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import $ from 'jquery';
|
||||||
|
import {queryElemChildren} from '../../utils/dom.js';
|
||||||
|
|
||||||
|
export function initFomanticDimmer() {
|
||||||
|
// stand-in for removed dimmer module
|
||||||
|
$.fn.dimmer = function (arg0, $el) {
|
||||||
|
if (arg0 === 'add content') {
|
||||||
|
const existingDimmer = document.querySelector('body > .ui.dimmer');
|
||||||
|
if (existingDimmer) {
|
||||||
|
queryElemChildren(existingDimmer, '*', (el) => el.remove());
|
||||||
|
this._dimmer = existingDimmer;
|
||||||
|
} else {
|
||||||
|
this._dimmer = document.createElement('div');
|
||||||
|
this._dimmer.classList.add('ui', 'dimmer');
|
||||||
|
document.body.append(this._dimmer);
|
||||||
|
}
|
||||||
|
this._dimmer.append($el[0]);
|
||||||
|
} else if (arg0 === 'get dimmer') {
|
||||||
|
return $(this._dimmer);
|
||||||
|
} else if (arg0 === 'show') {
|
||||||
|
this._dimmer.classList.add('active');
|
||||||
|
document.body.classList.add('tw-overflow-hidden');
|
||||||
|
} else if (arg0 === 'hide') {
|
||||||
|
this._dimmer.classList.remove('active');
|
||||||
|
document.body.classList.remove('tw-overflow-hidden');
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user