mirror of
https://github.com/go-gitea/gitea.git
synced 2025-11-08 05:02:38 +09:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
918d3d96ff | ||
|
|
92c91d7d8b | ||
|
|
9dc76b2036 | ||
|
|
802a4314ef | ||
|
|
edd4ab49c8 | ||
|
|
55e6cde7c1 | ||
|
|
729fa06468 | ||
|
|
b228a0aa44 | ||
|
|
9e7e11224f | ||
|
|
85880b2a0b | ||
|
|
211bb911e3 | ||
|
|
0554d1dd01 | ||
|
|
00e55dd223 | ||
|
|
b28c3245cc | ||
|
|
ddfb729168 | ||
|
|
6ef62e3f8e | ||
|
|
2c4f1ed13e | ||
|
|
fa3fe1e28a | ||
|
|
62f5cf4386 | ||
|
|
779d1185e7 | ||
|
|
f3d0c76afc | ||
|
|
5a4729d5e2 | ||
|
|
88a7349375 | ||
|
|
c3398906a1 | ||
|
|
330fa75945 |
30
CHANGELOG.md
30
CHANGELOG.md
@@ -4,6 +4,36 @@ This changelog goes through all the changes that have been made in each release
|
||||
without substantial changes to our git log; to see the highlights of what has
|
||||
been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||
|
||||
## [1.14.1](https://github.com/go-gitea/gitea/releases/tag/v1.14.1) - 2021-04-15
|
||||
|
||||
* BUGFIXES
|
||||
* Fix bug clone wiki (#15499) (#15502)
|
||||
* Github Migration ignore rate limit, if not enabled (#15490) (#15495)
|
||||
* Use subdir for URL (#15446) (#15493)
|
||||
* Query the DB for the hash before inserting in to email_hash (#15457) (#15491)
|
||||
* Ensure review dismissal only dismisses the correct review (#15477) (#15489)
|
||||
* Use index of the supported tags to choose user lang (#15452) (#15488)
|
||||
* Fix wrong file link in code search page (#15466) (#15486)
|
||||
* Quick template fix for built-in SSH server in admin config (#15464) (#15481)
|
||||
* Prevent superfluous response.WriteHeader (#15456) (#15476)
|
||||
* Fix ambiguous argument error on tags (#15432) (#15474)
|
||||
* Add created_unix instead of expiry to migration (#15458) (#15463)
|
||||
* Fix repository search (#15428) (#15442)
|
||||
* Prevent NPE on avatar direct rendering if federated avatars disabled (#15434) (#15439)
|
||||
* Fix wiki clone urls (#15430) (#15431)
|
||||
* Fix dingtalk icon url at webhook (#15417) (#15426)
|
||||
* Standardise icon on projects PR page (#15387) (#15408)
|
||||
* ENHANCEMENTS
|
||||
* Add option to skip LFS/attachment files for `dump` (#15407) (#15492)
|
||||
* Clone panel fixes (#15436)
|
||||
* Use semantic dropdown for code search query type (#15276) (#15364)
|
||||
* BUILD
|
||||
* Build go-git variants for windows (#15482) (#15487)
|
||||
* Lock down build-images dependencies (Partial #15479) (#15480)
|
||||
* MISC
|
||||
* Performance improvement for list pull requests (#15447) (#15500)
|
||||
* Fix potential copy lfs records failure when fork a repository (#15441) (#15485)
|
||||
|
||||
## [1.14.0](https://github.com/go-gitea/gitea/releases/tag/v1.14.0) - 2021-04-11
|
||||
|
||||
* SECURITY
|
||||
|
||||
7
Makefile
7
Makefile
@@ -577,6 +577,9 @@ release-windows: | $(DIST_DIRS)
|
||||
$(GO) install src.techknowlogick.com/xgo@latest; \
|
||||
fi
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
|
||||
ifeq (,$(findstring gogit,$(TAGS)))
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit .
|
||||
endif
|
||||
ifeq ($(CI),drone)
|
||||
cp /build/* $(DIST)/binaries
|
||||
endif
|
||||
@@ -699,8 +702,8 @@ generate-gitignore:
|
||||
GO111MODULE=on $(GO) run build/generate-gitignores.go
|
||||
|
||||
.PHONY: generate-images
|
||||
generate-images:
|
||||
npm install --no-save --no-package-lock fabric imagemin-zopfli
|
||||
generate-images: | node_modules
|
||||
npm install --no-save --no-package-lock fabric@4 imagemin-zopfli@7
|
||||
node build/generate-images.js $(TAGS)
|
||||
|
||||
.PHONY: generate-manpage
|
||||
|
||||
16
cmd/dump.go
16
cmd/dump.go
@@ -129,6 +129,14 @@ It can be used for backup and capture Gitea server image to send to maintainer`,
|
||||
Name: "skip-custom-dir",
|
||||
Usage: "Skip custom directory",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "skip-lfs-data",
|
||||
Usage: "Skip LFS data",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "skip-attachment-data",
|
||||
Usage: "Skip attachment data",
|
||||
},
|
||||
cli.GenericFlag{
|
||||
Name: "type",
|
||||
Value: outputTypeEnum,
|
||||
@@ -214,7 +222,9 @@ func runDump(ctx *cli.Context) error {
|
||||
fatal("Failed to include repositories: %v", err)
|
||||
}
|
||||
|
||||
if err := storage.LFS.IterateObjects(func(objPath string, object storage.Object) error {
|
||||
if ctx.IsSet("skip-lfs-data") && ctx.Bool("skip-lfs-data") {
|
||||
log.Info("Skip dumping LFS data")
|
||||
} else if err := storage.LFS.IterateObjects(func(objPath string, object storage.Object) error {
|
||||
info, err := object.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -313,7 +323,9 @@ func runDump(ctx *cli.Context) error {
|
||||
}
|
||||
}
|
||||
|
||||
if err := storage.Attachments.IterateObjects(func(objPath string, object storage.Object) error {
|
||||
if ctx.IsSet("skip-attachment-data") && ctx.Bool("skip-attachment-data") {
|
||||
log.Info("Skip dumping attachment data")
|
||||
} else if err := storage.Attachments.IterateObjects(func(objPath string, object storage.Object) error {
|
||||
info, err := object.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -96,6 +96,11 @@ func HashedAvatarLink(email string) string {
|
||||
// we don't care about any DB problem just return the lowerEmail
|
||||
return lowerEmail, nil
|
||||
}
|
||||
has, err := sess.Where("email = ? AND hash = ?", emailHash.Email, emailHash.Hash).Get(new(EmailHash))
|
||||
if has || err != nil {
|
||||
// Seriously we don't care about any DB problems just return the lowerEmail - we expect the transaction to fail most of the time
|
||||
return lowerEmail, nil
|
||||
}
|
||||
_, _ = sess.Insert(emailHash)
|
||||
if err := sess.Commit(); err != nil {
|
||||
// Seriously we don't care about any DB problems just return the lowerEmail - we expect the transaction to fail most of the time
|
||||
|
||||
@@ -53,6 +53,9 @@ func (issues IssueList) loadRepositories(e Engine) ([]*Repository, error) {
|
||||
|
||||
for _, issue := range issues {
|
||||
issue.Repo = repoMaps[issue.RepoID]
|
||||
if issue.PullRequest != nil {
|
||||
issue.PullRequest.BaseRepo = issue.Repo
|
||||
}
|
||||
}
|
||||
return valuesRepository(repoMaps), nil
|
||||
}
|
||||
@@ -516,6 +519,11 @@ func (issues IssueList) LoadDiscussComments() error {
|
||||
return issues.loadComments(x, builder.Eq{"comment.type": CommentTypeComment})
|
||||
}
|
||||
|
||||
// LoadPullRequests loads pull requests
|
||||
func (issues IssueList) LoadPullRequests() error {
|
||||
return issues.loadPullRequests(x)
|
||||
}
|
||||
|
||||
// GetApprovalCounts returns a map of issue ID to slice of approval counts
|
||||
// FIXME: only returns official counts due to double counting of non-official approvals
|
||||
func (issues IssueList) GetApprovalCounts() (map[int64][]*ReviewCount, error) {
|
||||
|
||||
@@ -12,9 +12,9 @@ import (
|
||||
|
||||
func addSessionTable(x *xorm.Engine) error {
|
||||
type Session struct {
|
||||
Key string `xorm:"pk CHAR(16)"`
|
||||
Data []byte `xorm:"BLOB"`
|
||||
CreatedUnix timeutil.TimeStamp
|
||||
Key string `xorm:"pk CHAR(16)"`
|
||||
Data []byte `xorm:"BLOB"`
|
||||
Expiry timeutil.TimeStamp
|
||||
}
|
||||
return x.Sync2(new(Session))
|
||||
}
|
||||
|
||||
@@ -566,7 +566,11 @@ func DismissReview(review *Review, isDismiss bool) (err error) {
|
||||
|
||||
review.Dismissed = isDismiss
|
||||
|
||||
_, err = x.Cols("dismissed").Update(review)
|
||||
if review.ID == 0 {
|
||||
return ErrReviewNotExist{}
|
||||
}
|
||||
|
||||
_, err = x.ID(review.ID).Cols("dismissed").Update(review)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -143,11 +143,57 @@ func TestGetReviewersByIssueID(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDismissReview(t *testing.T) {
|
||||
review1 := AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
|
||||
review2 := AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
|
||||
assert.NoError(t, DismissReview(review1, true))
|
||||
assert.NoError(t, DismissReview(review2, true))
|
||||
assert.NoError(t, DismissReview(review2, true))
|
||||
assert.NoError(t, DismissReview(review2, false))
|
||||
assert.NoError(t, DismissReview(review2, false))
|
||||
assert.NoError(t, PrepareTestDatabase())
|
||||
|
||||
rejectReviewExample := AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
|
||||
requestReviewExample := AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
|
||||
approveReviewExample := AssertExistsAndLoadBean(t, &Review{ID: 8}).(*Review)
|
||||
assert.False(t, rejectReviewExample.Dismissed)
|
||||
assert.False(t, requestReviewExample.Dismissed)
|
||||
assert.False(t, approveReviewExample.Dismissed)
|
||||
|
||||
assert.NoError(t, DismissReview(rejectReviewExample, true))
|
||||
rejectReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
|
||||
requestReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
|
||||
assert.True(t, rejectReviewExample.Dismissed)
|
||||
assert.False(t, requestReviewExample.Dismissed)
|
||||
|
||||
assert.NoError(t, DismissReview(requestReviewExample, true))
|
||||
rejectReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
|
||||
requestReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
|
||||
assert.True(t, rejectReviewExample.Dismissed)
|
||||
assert.False(t, requestReviewExample.Dismissed)
|
||||
assert.False(t, approveReviewExample.Dismissed)
|
||||
|
||||
assert.NoError(t, DismissReview(requestReviewExample, true))
|
||||
rejectReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
|
||||
requestReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
|
||||
assert.True(t, rejectReviewExample.Dismissed)
|
||||
assert.False(t, requestReviewExample.Dismissed)
|
||||
assert.False(t, approveReviewExample.Dismissed)
|
||||
|
||||
assert.NoError(t, DismissReview(requestReviewExample, false))
|
||||
rejectReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
|
||||
requestReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
|
||||
assert.True(t, rejectReviewExample.Dismissed)
|
||||
assert.False(t, requestReviewExample.Dismissed)
|
||||
assert.False(t, approveReviewExample.Dismissed)
|
||||
|
||||
assert.NoError(t, DismissReview(requestReviewExample, false))
|
||||
rejectReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
|
||||
requestReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
|
||||
assert.True(t, rejectReviewExample.Dismissed)
|
||||
assert.False(t, requestReviewExample.Dismissed)
|
||||
assert.False(t, approveReviewExample.Dismissed)
|
||||
|
||||
assert.NoError(t, DismissReview(rejectReviewExample, false))
|
||||
assert.False(t, rejectReviewExample.Dismissed)
|
||||
assert.False(t, requestReviewExample.Dismissed)
|
||||
assert.False(t, approveReviewExample.Dismissed)
|
||||
|
||||
assert.NoError(t, DismissReview(approveReviewExample, true))
|
||||
assert.False(t, rejectReviewExample.Dismissed)
|
||||
assert.False(t, requestReviewExample.Dismissed)
|
||||
assert.True(t, approveReviewExample.Dismissed)
|
||||
|
||||
}
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
|
||||
package context
|
||||
|
||||
import "net/http"
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// ResponseWriter represents a response writer for HTTP
|
||||
type ResponseWriter interface {
|
||||
@@ -60,8 +62,10 @@ func (r *Response) WriteHeader(statusCode int) {
|
||||
}
|
||||
r.beforeExecuted = true
|
||||
}
|
||||
r.status = statusCode
|
||||
r.ResponseWriter.WriteHeader(statusCode)
|
||||
if r.status == 0 {
|
||||
r.status = statusCode
|
||||
r.ResponseWriter.WriteHeader(statusCode)
|
||||
}
|
||||
}
|
||||
|
||||
// Flush flush cached data
|
||||
|
||||
@@ -7,6 +7,7 @@ package git
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -14,32 +15,15 @@ import (
|
||||
)
|
||||
|
||||
func TestBlob_Data(t *testing.T) {
|
||||
output := `Copyright (c) 2016 The Gitea Authors
|
||||
Copyright (c) 2015 The Gogs Authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
`
|
||||
repo, err := OpenRepository("../../.git")
|
||||
assert.NoError(t, err)
|
||||
output := "file2\n"
|
||||
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
|
||||
repo, err := OpenRepository(bareRepo1Path)
|
||||
if !assert.NoError(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
defer repo.Close()
|
||||
|
||||
testBlob, err := repo.GetBlob("a8d4b49dd073a4a38a7e58385eeff7cc52568697")
|
||||
testBlob, err := repo.GetBlob("6c493ff740f9380390d5c9ddef4af18697ac9375")
|
||||
assert.NoError(t, err)
|
||||
|
||||
r, err := testBlob.DataAsync()
|
||||
@@ -53,13 +37,14 @@ THE SOFTWARE.
|
||||
}
|
||||
|
||||
func Benchmark_Blob_Data(b *testing.B) {
|
||||
repo, err := OpenRepository("../../.git")
|
||||
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
|
||||
repo, err := OpenRepository(bareRepo1Path)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer repo.Close()
|
||||
|
||||
testBlob, err := repo.GetBlob("a8d4b49dd073a4a38a7e58385eeff7cc52568697")
|
||||
testBlob, err := repo.GetBlob("6c493ff740f9380390d5c9ddef4af18697ac9375")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -21,14 +21,7 @@ func (repo *Repository) GetBranchCommitID(name string) (string, error) {
|
||||
|
||||
// GetTagCommitID returns last commit ID string of given tag.
|
||||
func (repo *Repository) GetTagCommitID(name string) (string, error) {
|
||||
stdout, err := NewCommand("rev-list", "-n", "1", TagPrefix+name).RunInDir(repo.Path)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "unknown revision or path") {
|
||||
return "", ErrNotExist{name, ""}
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
return strings.TrimSpace(stdout), nil
|
||||
return repo.GetRefCommitID(TagPrefix + name)
|
||||
}
|
||||
|
||||
// ConvertToSHA1 returns a Hash object from a potential ID string
|
||||
|
||||
@@ -132,6 +132,11 @@ func (g *GithubDownloaderV3) sleep() {
|
||||
func (g *GithubDownloaderV3) RefreshRate() error {
|
||||
rates, _, err := g.client.RateLimits(g.ctx)
|
||||
if err != nil {
|
||||
// if rate limit is not enabled, ignore it
|
||||
if strings.Contains(err.Error(), "404") {
|
||||
g.rate = nil
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,12 @@ func ForkRepository(doer, owner *models.User, oldRepo *models.Repository, name,
|
||||
return err
|
||||
}
|
||||
|
||||
// copy lfs files failure should not be ignored
|
||||
if err := models.CopyLFS(ctx, repo, oldRepo); err != nil {
|
||||
rollbackRemoveFn()
|
||||
return err
|
||||
}
|
||||
|
||||
repoPath := models.RepoPath(owner.Name, repo.Name)
|
||||
if stdout, err := git.NewCommand(
|
||||
"clone", "--bare", oldRepoPath, repoPath).
|
||||
@@ -92,6 +98,7 @@ func ForkRepository(doer, owner *models.User, oldRepo *models.Repository, name,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// even if below operations failed, it could be ignored. And they will be retried
|
||||
ctx := models.DefaultDBContext()
|
||||
if err = repo.UpdateSize(ctx); err != nil {
|
||||
log.Error("Failed to update size for repository: %v", err)
|
||||
@@ -100,11 +107,5 @@ func ForkRepository(doer, owner *models.User, oldRepo *models.Repository, name,
|
||||
log.Error("Copy language stat from oldRepo failed")
|
||||
}
|
||||
|
||||
if err := models.CopyLFS(ctx, repo, oldRepo); err != nil {
|
||||
if errDelete := models.DeleteRepository(doer, owner.ID, repo.ID); errDelete != nil {
|
||||
log.Error("Rollback deleteRepository: %v", errDelete)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
@@ -27,8 +27,9 @@ type LangType struct {
|
||||
}
|
||||
|
||||
var (
|
||||
matcher language.Matcher
|
||||
allLangs []LangType
|
||||
matcher language.Matcher
|
||||
allLangs []LangType
|
||||
supportedTags []language.Tag
|
||||
)
|
||||
|
||||
// AllLangs returns all supported langauages
|
||||
@@ -51,12 +52,12 @@ func InitLocales() {
|
||||
}
|
||||
}
|
||||
|
||||
tags := make([]language.Tag, len(setting.Langs))
|
||||
supportedTags = make([]language.Tag, len(setting.Langs))
|
||||
for i, lang := range setting.Langs {
|
||||
tags[i] = language.Raw.Make(lang)
|
||||
supportedTags[i] = language.Raw.Make(lang)
|
||||
}
|
||||
|
||||
matcher = language.NewMatcher(tags)
|
||||
matcher = language.NewMatcher(supportedTags)
|
||||
for i := range setting.Names {
|
||||
key := "locale_" + setting.Langs[i] + ".ini"
|
||||
if err = i18n.SetMessageWithDesc(setting.Langs[i], setting.Names[i], localFiles[key]); err != nil {
|
||||
@@ -79,8 +80,9 @@ func InitLocales() {
|
||||
}
|
||||
|
||||
// Match matches accept languages
|
||||
func Match(tags ...language.Tag) (tag language.Tag, index int, c language.Confidence) {
|
||||
return matcher.Match(tags...)
|
||||
func Match(tags ...language.Tag) language.Tag {
|
||||
_, i, _ := matcher.Match(tags...)
|
||||
return supportedTags[i]
|
||||
}
|
||||
|
||||
// locale represents the information of localization.
|
||||
|
||||
@@ -38,7 +38,7 @@ func Locale(resp http.ResponseWriter, req *http.Request) translation.Locale {
|
||||
// The first element in the list is chosen to be the default language automatically.
|
||||
if len(lang) == 0 {
|
||||
tags, _, _ := language.ParseAcceptLanguage(req.Header.Get("Accept-Language"))
|
||||
tag, _, _ := translation.Match(tags...)
|
||||
tag := translation.Match(tags...)
|
||||
lang = tag.String()
|
||||
}
|
||||
|
||||
|
||||
@@ -103,9 +103,11 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
|
||||
|
||||
isWiki := false
|
||||
var unitType = models.UnitTypeCode
|
||||
var wikiRepoName string
|
||||
if strings.HasSuffix(reponame, ".wiki") {
|
||||
isWiki = true
|
||||
unitType = models.UnitTypeWiki
|
||||
wikiRepoName = reponame
|
||||
reponame = reponame[:len(reponame)-5]
|
||||
}
|
||||
|
||||
@@ -314,6 +316,11 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
|
||||
return
|
||||
}
|
||||
|
||||
if isWiki { // you cannot send wiki operation before create the repository
|
||||
ctx.HandleText(http.StatusNotFound, "Repository not found")
|
||||
return
|
||||
}
|
||||
|
||||
if owner.IsOrganization() && !setting.Repository.EnablePushCreateOrg {
|
||||
ctx.HandleText(http.StatusForbidden, "Push to create is not enabled for organizations.")
|
||||
return
|
||||
@@ -363,6 +370,9 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
|
||||
r.URL.Path = strings.ToLower(r.URL.Path) // blue: In case some repo name has upper case name
|
||||
|
||||
dir := models.RepoPath(username, reponame)
|
||||
if isWiki {
|
||||
dir = models.RepoPath(username, wikiRepoName)
|
||||
}
|
||||
|
||||
return &serviceHandler{cfg, w, r, dir, cfg.Env}
|
||||
}
|
||||
|
||||
@@ -241,14 +241,13 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
|
||||
}
|
||||
}
|
||||
|
||||
approvalCounts, err := models.IssueList(issues).GetApprovalCounts()
|
||||
var issueList = models.IssueList(issues)
|
||||
approvalCounts, err := issueList.GetApprovalCounts()
|
||||
if err != nil {
|
||||
ctx.ServerError("ApprovalCounts", err)
|
||||
return
|
||||
}
|
||||
|
||||
var commitStatus = make(map[int64]*models.CommitStatus, len(issues))
|
||||
|
||||
// Get posters.
|
||||
for i := range issues {
|
||||
// Check read status
|
||||
@@ -258,16 +257,12 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
|
||||
ctx.ServerError("GetIsRead", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if issues[i].IsPull {
|
||||
if err := issues[i].LoadPullRequest(); err != nil {
|
||||
ctx.ServerError("LoadPullRequest", err)
|
||||
return
|
||||
}
|
||||
|
||||
var statuses, _ = pull_service.GetLastCommitStatus(issues[i].PullRequest)
|
||||
commitStatus[issues[i].PullRequest.ID] = models.CalcCommitStatus(statuses)
|
||||
}
|
||||
commitStatus, err := pull_service.GetIssuesLastCommitStatus(issues)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetIssuesLastCommitStatus", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["Issues"] = issues
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
@@ -40,7 +39,7 @@ func Search(ctx *context.Context) {
|
||||
ctx.Data["Keyword"] = keyword
|
||||
ctx.Data["Language"] = language
|
||||
ctx.Data["queryType"] = queryType
|
||||
ctx.Data["SourcePath"] = path.Join(setting.AppSubURL, ctx.Repo.Repository.Owner.Name, ctx.Repo.Repository.Name)
|
||||
ctx.Data["SourcePath"] = ctx.Repo.Repository.HTMLURL()
|
||||
ctx.Data["SearchResults"] = searchResults
|
||||
ctx.Data["SearchResultLanguages"] = searchResultLanguages
|
||||
ctx.Data["RequireHighlightJS"] = true
|
||||
|
||||
@@ -7,12 +7,14 @@ package user
|
||||
import (
|
||||
"errors"
|
||||
"net/url"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
|
||||
// Avatar redirect browser to user avatar of requested size
|
||||
@@ -70,8 +72,21 @@ func AvatarByEmailHash(ctx *context.Context) {
|
||||
}
|
||||
|
||||
var avatarURL *url.URL
|
||||
avatarURL, err = models.LibravatarURL(email)
|
||||
if err != nil {
|
||||
|
||||
if setting.EnableFederatedAvatar && setting.LibravatarService != nil {
|
||||
avatarURL, err = models.LibravatarURL(email)
|
||||
if err != nil {
|
||||
avatarURL, err = url.Parse(models.DefaultAvatarLink())
|
||||
if err != nil {
|
||||
ctx.ServerError("invalid default avatar url", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
} else if !setting.DisableGravatar {
|
||||
copyOfGravatarSourceURL := *setting.GravatarSourceURL
|
||||
avatarURL = ©OfGravatarSourceURL
|
||||
avatarURL.Path = path.Join(avatarURL.Path, hash)
|
||||
} else {
|
||||
avatarURL, err = url.Parse(models.DefaultAvatarLink())
|
||||
if err != nil {
|
||||
ctx.ServerError("invalid default avatar url", err)
|
||||
|
||||
@@ -546,14 +546,14 @@ func buildIssueOverview(ctx *context.Context, unitType models.UnitType) {
|
||||
}
|
||||
|
||||
// maps pull request IDs to their CommitStatus. Will be posted to ctx.Data.
|
||||
var commitStatus = make(map[int64]*models.CommitStatus, len(issues))
|
||||
for _, issue := range issues {
|
||||
issue.Repo = showReposMap[issue.RepoID]
|
||||
}
|
||||
|
||||
if isPullList {
|
||||
var statuses, _ = pull_service.GetLastCommitStatus(issue.PullRequest)
|
||||
commitStatus[issue.PullRequest.ID] = models.CalcCommitStatus(statuses)
|
||||
}
|
||||
commitStatus, err := pull_service.GetIssuesLastCommitStatus(issues)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetIssuesLastCommitStatus", err)
|
||||
return
|
||||
}
|
||||
|
||||
// -------------------------------
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -643,33 +642,74 @@ func GetSquashMergeCommitMessages(pr *models.PullRequest) string {
|
||||
return stringBuilder.String()
|
||||
}
|
||||
|
||||
// GetLastCommitStatus returns list of commit statuses for latest commit on this pull request.
|
||||
func GetLastCommitStatus(pr *models.PullRequest) (status []*models.CommitStatus, err error) {
|
||||
if err = pr.LoadBaseRepo(); err != nil {
|
||||
// GetIssuesLastCommitStatus returns a map
|
||||
func GetIssuesLastCommitStatus(issues models.IssueList) (map[int64]*models.CommitStatus, error) {
|
||||
if err := issues.LoadPullRequests(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := issues.LoadRepositories(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
gitRepos = make(map[int64]*git.Repository)
|
||||
res = make(map[int64]*models.CommitStatus)
|
||||
err error
|
||||
)
|
||||
defer func() {
|
||||
for _, gitRepo := range gitRepos {
|
||||
gitRepo.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
for _, issue := range issues {
|
||||
if !issue.IsPull {
|
||||
continue
|
||||
}
|
||||
gitRepo, ok := gitRepos[issue.RepoID]
|
||||
if !ok {
|
||||
gitRepo, err = git.OpenRepository(issue.Repo.RepoPath())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gitRepos[issue.RepoID] = gitRepo
|
||||
}
|
||||
|
||||
status, err := getLastCommitStatus(gitRepo, issue.PullRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res[issue.PullRequest.ID] = status
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// GetLastCommitStatus returns list of commit statuses for latest commit on this pull request.
|
||||
func GetLastCommitStatus(pr *models.PullRequest) (status *models.CommitStatus, err error) {
|
||||
if err = pr.LoadBaseRepo(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer gitRepo.Close()
|
||||
|
||||
compareInfo, err := gitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.MergeBase, pr.GetGitRefName())
|
||||
return getLastCommitStatus(gitRepo, pr)
|
||||
}
|
||||
|
||||
// getLastCommitStatus get pr's last commit status. PR's last commit status is the head commit id's last commit status
|
||||
func getLastCommitStatus(gitRepo *git.Repository, pr *models.PullRequest) (status *models.CommitStatus, err error) {
|
||||
sha, err := gitRepo.GetRefCommitID(pr.GetGitRefName())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if compareInfo.Commits.Len() == 0 {
|
||||
return nil, errors.New("pull request has no commits")
|
||||
}
|
||||
|
||||
sha := compareInfo.Commits.Front().Value.(*git.Commit).ID.String()
|
||||
statusList, err := models.GetLatestCommitStatus(pr.BaseRepo.ID, sha, models.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return statusList, nil
|
||||
return models.CalcCommitStatus(statusList), nil
|
||||
}
|
||||
|
||||
// IsHeadEqualWithBranch returns if the commits of branchName are available in pull request head
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
<dd>{{if not .SSH.Disabled}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
{{if not .SSH.Disabled}}
|
||||
<dt>{{.i18n.Tr "admin.config.ssh_start_builtin_server"}}</dt>
|
||||
<dd>{{if not .SSH.StartBuiltinServer}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
<dd>{{if .SSH.StartBuiltinServer}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.ssh_domain"}}</dt>
|
||||
<dd>{{.SSH.Domain}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.ssh_port"}}</dt>
|
||||
|
||||
@@ -3,29 +3,27 @@
|
||||
{{template "explore/navbar" .}}
|
||||
<div class="ui container">
|
||||
<form class="ui form ignore-dirty" style="max-width: 100%">
|
||||
<input type="hidden" name="tab" value="{{$.TabName}}">
|
||||
<div class="ui fluid action input">
|
||||
<div class="twelve wide field">
|
||||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." autofocus>
|
||||
</div>
|
||||
<div class="two wide field mx-2">
|
||||
<select name="t">
|
||||
<option value="">{{.i18n.Tr "explore.search.fuzzy"}}</option>
|
||||
<option value="match" {{if eq .queryType "match"}}selected{{end}}>{{.i18n.Tr "explore.search.match"}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="three field">
|
||||
<button class="ui blue button">{{.i18n.Tr "explore.search"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="ui divider"></div>
|
||||
<input type="hidden" name="tab" value="{{$.TabName}}">
|
||||
<div class="ui fluid action input">
|
||||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." autofocus>
|
||||
<div class="ui dropdown selection">
|
||||
<input name="t" type="hidden" value="{{.queryType}}">{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||
<div class="text">{{.i18n.Tr (printf "explore.search.%s" (or .queryType "fuzzy"))}}</div>
|
||||
<div class="menu transition hidden" tabindex="-1" style="display: block !important;">
|
||||
<div class="item" data-value="">{{.i18n.Tr "explore.search.fuzzy"}}</div>
|
||||
<div class="item" data-value="match">{{.i18n.Tr "explore.search.match"}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui blue button">{{.i18n.Tr "explore.search"}}</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="ui divider"></div>
|
||||
|
||||
<div class="ui user list">
|
||||
{{if .SearchResults}}
|
||||
<h3>
|
||||
{{.i18n.Tr "explore.code_search_results" (.Keyword|Escape) | Str2html }}
|
||||
</h3>
|
||||
<h3>
|
||||
{{.i18n.Tr "explore.code_search_results" (.Keyword|Escape) | Str2html }}
|
||||
</h3>
|
||||
<div class="df ac fw">
|
||||
{{range $term := .SearchResultLanguages}}
|
||||
<a class="ui text-label df ac mr-1 my-1 {{if eq $.Language $term.Language}}primary {{end}}basic label" href="{{AppSubUrl}}/explore/code?q={{$.Keyword}}{{if ne $.Language $term.Language}}&l={{$term.Language}}{{end}}{{if ne $.queryType ""}}&t={{$.queryType}}{{end}}">
|
||||
@@ -35,34 +33,34 @@
|
||||
</a>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="repository search">
|
||||
{{range $result := .SearchResults}}
|
||||
{{$repo := (index $.RepoMaps .RepoID)}}
|
||||
<div class="diff-file-box diff-box file-content non-diff-file-content repo-search-result">
|
||||
<h4 class="ui top attached normal header">
|
||||
<span class="file"><a rel="nofollow" href="{{EscapePound $repo.HTMLURL}}">{{$repo.FullName}}</a> - {{.Filename}}</span>
|
||||
<a class="ui basic tiny button" rel="nofollow" href="{{EscapePound $repo.HTMLURL}}/src/commit/{{$result.CommitID}}/{{EscapePound .Filename}}">{{$.i18n.Tr "repo.diff.view_file"}}</a>
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
<div class="file-body file-code code-view">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="lines-num">
|
||||
{{range .LineNumbers}}
|
||||
<a href="{{EscapePound $repo.HTMLURL}}/src/commit/{{$result.CommitID}}/{{EscapePound $result.Filename}}#L{{.}}"><span>{{.}}</span></a>
|
||||
{{end}}
|
||||
</td>
|
||||
<td class="lines-code"><pre><code class="chroma"><ol class="linenums">{{.FormattedLines | Safe}}</ol></code></pre></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{{template "shared/searchbottom" dict "root" $ "result" .}}
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="repository search">
|
||||
{{range $result := .SearchResults}}
|
||||
{{$repo := (index $.RepoMaps .RepoID)}}
|
||||
<div class="diff-file-box diff-box file-content non-diff-file-content repo-search-result">
|
||||
<h4 class="ui top attached normal header">
|
||||
<span class="file"><a rel="nofollow" href="{{EscapePound $repo.HTMLURL}}">{{$repo.FullName}}</a> - {{.Filename}}</span>
|
||||
<a class="ui basic tiny button" rel="nofollow" href="{{EscapePound $repo.HTMLURL}}/src/commit/{{$result.CommitID}}/{{EscapePound .Filename}}">{{$.i18n.Tr "repo.diff.view_file"}}</a>
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
<div class="file-body file-code code-view">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="lines-num">
|
||||
{{range .LineNumbers}}
|
||||
<a href="{{EscapePound $repo.HTMLURL}}/src/commit/{{$result.CommitID}}/{{EscapePound $result.Filename}}#L{{.}}"><span>{{.}}</span></a>
|
||||
{{end}}
|
||||
</td>
|
||||
<td class="lines-code"><pre><code class="chroma"><ol class="linenums">{{.FormattedLines | Safe}}</ol></code></pre></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{{template "shared/searchbottom" dict "root" $ "result" .}}
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{else}}
|
||||
<div>{{$.i18n.Tr "explore.code_no_results"}}</div>
|
||||
{{end}}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
{{else if eq .HookType "discord"}}
|
||||
<img width="26" height="26" src="{{StaticUrlPrefix}}/img/discord.png">
|
||||
{{else if eq .HookType "dingtalk"}}
|
||||
<img width="26" height="26" src="{{StaticUrlPrefix}}/img/dingtalk.png">
|
||||
<img width="26" height="26" src="{{StaticUrlPrefix}}/img/dingtalk.ico">
|
||||
{{else if eq .HookType "telegram"}}
|
||||
<img width="26" height="26" src="{{StaticUrlPrefix}}/img/telegram.png">
|
||||
{{else if eq .HookType "msteams"}}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
{{if not $.DisableHTTP}}
|
||||
<button class="ui basic clone button no-transition" id="repo-clone-https" data-link="{{.CloneLink.HTTPS}}">
|
||||
<button class="ui basic clone button no-transition" id="repo-clone-https" data-link="{{if $.PageIsWiki}}{{$.WikiCloneLink.HTTPS}}{{else}}{{$.CloneLink.HTTPS}}{{end}}">
|
||||
{{if UseHTTPS}}HTTPS{{else}}HTTP{{end}}
|
||||
</button>
|
||||
{{end}}
|
||||
{{if and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH)}}
|
||||
<button class="ui basic clone button no-transition" id="repo-clone-ssh" data-link="{{.CloneLink.SSH}}">
|
||||
<button class="ui basic clone button no-transition" id="repo-clone-ssh" data-link="{{if $.PageIsWiki}}{{$.WikiCloneLink.SSH}}{{else}}{{$.CloneLink.SSH}}{{end}}">
|
||||
SSH
|
||||
</button>
|
||||
{{end}}
|
||||
{{if not $.DisableHTTP}}
|
||||
<input id="repo-clone-url" value="{{$.CloneLink.HTTPS}}" readonly>
|
||||
<input id="repo-clone-url" value="{{if $.PageIsWiki}}{{$.WikiCloneLink.HTTPS}}{{else}}{{$.CloneLink.HTTPS}}{{end}}" readonly>
|
||||
{{else if and (not .DisableSSH) (or $.IsSigned $.ExposeAnonSSH)}}
|
||||
<input id="repo-clone-url" value="{{$.CloneLink.SSH}}" readonly>
|
||||
<input id="repo-clone-url" value="{{if $.PageIsWiki}}{{$.WikiCloneLink.SSH}}{{else}}{{$.CloneLink.SSH}}{{end}}" readonly>
|
||||
{{end}}
|
||||
{{if or (not $.DisableHTTP) (and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH))}}
|
||||
<button class="ui basic icon button poping up clipboard" id="clipboard-btn" data-original="{{.i18n.Tr "repo.copy_link"}}" data-success="{{.i18n.Tr "repo.copy_link_success"}}" data-error="{{.i18n.Tr "repo.copy_link_error"}}" data-content="{{.i18n.Tr "repo.copy_link"}}" data-variation="inverted tiny" data-clipboard-target="#repo-clone-url">
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<div class="ui attached segment">
|
||||
{{template "base/alert" .}}
|
||||
|
||||
<p class="ui center">{{.i18n.Tr "repo.new_repo_helper" "/repo/migrate" | Safe}}</p>
|
||||
<p class="ui center">{{.i18n.Tr "repo.new_repo_helper" (printf "%s%s" AppSubUrl "/repo/migrate") | Safe}}</p>
|
||||
|
||||
{{if not .CanCreateRepo}}
|
||||
<div class="ui negative message">
|
||||
|
||||
@@ -110,13 +110,13 @@
|
||||
{{if eq $n 0}}
|
||||
<div class="ui action tiny input" id="clone-panel">
|
||||
{{template "repo/clone_buttons" .}}
|
||||
<div class="ui basic jump dropdown icon button poping up" data-content="{{.i18n.Tr "repo.download_archive"}}" data-variation="tiny inverted" data-position="top right">
|
||||
<button id="download-btn" class="ui basic jump dropdown icon button poping up" data-content="{{.i18n.Tr "repo.download_archive"}}" data-variation="tiny inverted" data-position="top right">
|
||||
{{svg "octicon-download"}}
|
||||
<div class="menu">
|
||||
<a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound $.BranchName}}.zip">{{svg "octicon-file-zip"}} ZIP</a>
|
||||
<a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound $.BranchName}}.tar.gz">{{svg "octicon-file-zip"}} TAR.GZ</a>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
</div>
|
||||
<div class="three wide column">
|
||||
{{if $.PageIsOrgSettingsLabels}}
|
||||
<a class="ui right open-issues" href="/issues?labels={{.ID}}">{{svg "octicon-issue-opened"}} {{$.i18n.Tr "repo.issues.label_open_issues" .NumOpenIssues}}</a>
|
||||
<a class="ui right open-issues" href="{{AppSubUrl}}/issues?labels={{.ID}}">{{svg "octicon-issue-opened"}} {{$.i18n.Tr "repo.issues.label_open_issues" .NumOpenIssues}}</a>
|
||||
{{else}}
|
||||
<a class="ui right open-issues" href="{{$.RepoLink}}/issues?labels={{.ID}}">{{svg "octicon-issue-opened"}} {{$.i18n.Tr "repo.issues.label_open_issues" .NumOpenIssues}}</a>
|
||||
{{end}}
|
||||
|
||||
@@ -158,10 +158,23 @@
|
||||
<div class="card board-card" data-issue="{{.ID}}">
|
||||
<div class="content">
|
||||
<div class="header">
|
||||
<span class="{{if .IsClosed}}red{{else}}green{{end}}">
|
||||
{{if .IsPull}}{{svg "octicon-git-merge"}}
|
||||
{{else if .IsClosed}}{{svg "octicon-issue-closed"}}
|
||||
{{else}}{{svg "octicon-issue-opened"}}
|
||||
<span>
|
||||
{{if .IsPull}}
|
||||
{{if .PullRequest.HasMerged}}
|
||||
{{svg "octicon-git-merge" 16 "text purple"}}
|
||||
{{else}}
|
||||
{{if .IsClosed}}
|
||||
{{svg "octicon-git-pull-request" 16 "text red"}}
|
||||
{{else}}
|
||||
{{svg "octicon-git-pull-request" 16 "text green"}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{else}}
|
||||
{{if .IsClosed}}
|
||||
{{svg "octicon-issue-closed" 16 "text red"}}
|
||||
{{else}}
|
||||
{{svg "octicon-issue-opened" 16 "text green"}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
</span>
|
||||
<a class="project-board-title" href="{{$.RepoLink}}/issues/{{.Index}}">#{{.Index}} {{.Title}}</a>
|
||||
|
||||
@@ -5,20 +5,16 @@
|
||||
<div class="ui repo-search">
|
||||
<form class="ui form ignore-dirty" method="get">
|
||||
<div class="ui fluid action input">
|
||||
<div class="twelve wide field">
|
||||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "repo.search.search_repo"}}">
|
||||
</div>
|
||||
<div class="two wide field">
|
||||
<select name="t">
|
||||
<option value="">{{.i18n.Tr "repo.search.fuzzy"}}</option>
|
||||
<option value="match" {{if eq .queryType "match"}}selected{{end}}>{{.i18n.Tr "repo.search.match"}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="three field">
|
||||
<button class="ui button" type="submit">
|
||||
<i class="icon df ac jc">{{svg "octicon-search" 16}}</i>
|
||||
</button>
|
||||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "repo.search.search_repo"}}">
|
||||
<div class="ui dropdown selection">
|
||||
<input name="t" type="hidden" value="{{.queryType}}">{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||
<div class="text">{{.i18n.Tr (printf "repo.search.%s" (or .queryType "fuzzy"))}}</div>
|
||||
<div class="menu transition hidden" tabindex="-1" style="display: block !important;">
|
||||
<div class="item" data-value="">{{.i18n.Tr "repo.search.fuzzy"}}</div>
|
||||
<div class="item" data-value="match">{{.i18n.Tr "repo.search.match"}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui icon button" type="submit">{{svg "octicon-search" 16}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -62,12 +62,12 @@
|
||||
{{$.i18n.Tr .GetLastEventLabelFake $timeStr (.Poster.GetDisplayName | Escape) | Safe}}
|
||||
{{end}}
|
||||
{{if and .Milestone (ne $.listType "milestone")}}
|
||||
<a class="milestone" {{if $.RepoLink}}href="{{$.RepoLink}}/milestone/{{.Milestone.ID}}"{{else}}href="{{AppSubUrl}}/{{.Repo.Owner.Name}}/{{.Repo.Name}}/milestone/{{.Milestone.ID}}"{{end}}>
|
||||
<a class="milestone" {{if $.RepoLink}}href="{{$.RepoLink}}/milestone/{{.Milestone.ID}}"{{else}}href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/milestone/{{.Milestone.ID}}"{{end}}>
|
||||
{{svg "octicon-milestone" 14 "mr-2"}}{{.Milestone.Name}}
|
||||
</a>
|
||||
{{end}}
|
||||
{{if .Ref}}
|
||||
<a class="ref" {{if $.RepoLink}}href="{{$.RepoLink}}{{index $.IssueRefURLs .ID}}"{{else}}href="{{AppSubUrl}}/{{.Repo.Owner.Name}}/{{.Repo.Name}}{{index $.IssueRefURLs .ID}}"{{end}}>
|
||||
<a class="ref" {{if $.RepoLink}}href="{{$.RepoLink}}{{index $.IssueRefURLs .ID}}"{{else}}href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{index $.IssueRefURLs .ID}}"{{end}}>
|
||||
{{svg "octicon-git-branch" 14 "mr-2"}}{{index $.IssueRefEndNames .ID}}
|
||||
</a>
|
||||
{{end}}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
{{end}}
|
||||
{{else}}
|
||||
{{if .NeedsPassword}}
|
||||
<form class="ui form" action="/user/activate" method="post">
|
||||
<form class="ui form" action="{{AppSubUrl}}/user/activate" method="post">
|
||||
<div class="required inline field">
|
||||
<label for="password">{{.i18n.Tr "password"}}</label>
|
||||
<input id="password" name="password" type="password" autocomplete="off" required>
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
</h4>
|
||||
<div class="ui attached segment repos-search">
|
||||
<div class="ui fluid right action left icon input" :class="{loading: isLoading}">
|
||||
<input @input="searchRepos(reposFilter)" v-model="searchQuery" ref="search" placeholder="{{.i18n.Tr "home.search_repos"}}">
|
||||
<input @input="changeReposFilter(reposFilter)" v-model="searchQuery" ref="search" placeholder="{{.i18n.Tr "home.search_repos"}}">
|
||||
<i class="icon df ac jc">{{svg "octicon-search" 16}}</i>
|
||||
<div class="ui dropdown icon button" title="{{.i18n.Tr "home.filter"}}">
|
||||
<i class="icon df ac jc m-0">{{svg "octicon-filter" 16}}</i>
|
||||
|
||||
@@ -3109,7 +3109,7 @@ function initVueComponents() {
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.searchRepos(this.reposFilter);
|
||||
this.changeReposFilter(this.reposFilter);
|
||||
$(this.$el).find('.poping.up').popup();
|
||||
$(this.$el).find('.dropdown').dropdown();
|
||||
this.setCheckboxes();
|
||||
|
||||
@@ -240,6 +240,15 @@ a.muted:hover,
|
||||
border-color: var(--color-primary) !important;
|
||||
}
|
||||
|
||||
/* currently used for search bar dropdowns in repo search and explore code */
|
||||
.ui.action.input:not([class*="left action"]) > .ui.dropdown.selection {
|
||||
min-width: 10em;
|
||||
|
||||
&:not(:focus):not(:hover) {
|
||||
border-right-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.ui.action.input:not([class*="left action"]) > input:focus {
|
||||
border-right-color: var(--color-primary);
|
||||
}
|
||||
|
||||
@@ -201,18 +201,25 @@
|
||||
.clone.button {
|
||||
font-size: 13px;
|
||||
padding: 7.5px 5px;
|
||||
|
||||
&:first-child {
|
||||
border-radius: var(--border-radius) 0 0 var(--border-radius);
|
||||
}
|
||||
}
|
||||
|
||||
#repo-clone-https,
|
||||
#repo-clone-ssh,
|
||||
#clipboard-btn {
|
||||
#repo-clone-ssh {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
#download-btn {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
button:first-of-type {
|
||||
border-radius: var(--border-radius) 0 0 var(--border-radius) !important;
|
||||
}
|
||||
|
||||
button:last-of-type {
|
||||
border-radius: 0 var(--border-radius) var(--border-radius) 0 !important;
|
||||
}
|
||||
|
||||
.icon.button {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user