mirror of
https://github.com/go-gitea/gitea
synced 2025-01-09 21:16:01 +01:00
Merge branch 'main' into lunny/refactor_getpatch
This commit is contained in:
commit
72f6e28f7f
8
go.mod
8
go.mod
@ -121,13 +121,13 @@ require (
|
||||
github.com/yuin/goldmark v1.7.8
|
||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
|
||||
github.com/yuin/goldmark-meta v1.1.0
|
||||
golang.org/x/crypto v0.28.0
|
||||
golang.org/x/crypto v0.31.0
|
||||
golang.org/x/image v0.21.0
|
||||
golang.org/x/net v0.30.0
|
||||
golang.org/x/oauth2 v0.23.0
|
||||
golang.org/x/sync v0.8.0
|
||||
golang.org/x/sys v0.26.0
|
||||
golang.org/x/text v0.19.0
|
||||
golang.org/x/sync v0.10.0
|
||||
golang.org/x/sys v0.28.0
|
||||
golang.org/x/text v0.21.0
|
||||
golang.org/x/tools v0.26.0
|
||||
google.golang.org/grpc v1.67.1
|
||||
google.golang.org/protobuf v1.35.1
|
||||
|
15
go.sum
15
go.sum
@ -893,8 +893,9 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
|
||||
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
|
||||
golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s=
|
||||
@ -946,8 +947,9 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181221143128-b4a75ba826a6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@ -982,8 +984,9 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@ -996,8 +999,9 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
|
||||
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
|
||||
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
|
||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@ -1009,8 +1013,9 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
||||
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
@ -23,7 +23,7 @@ import (
|
||||
const (
|
||||
issueIndexerAnalyzer = "issueIndexer"
|
||||
issueIndexerDocType = "issueIndexerDocType"
|
||||
issueIndexerLatestVersion = 4
|
||||
issueIndexerLatestVersion = 5
|
||||
)
|
||||
|
||||
const unicodeNormalizeName = "unicodeNormalize"
|
||||
@ -75,6 +75,7 @@ func generateIssueIndexMapping() (mapping.IndexMapping, error) {
|
||||
|
||||
docMapping.AddFieldMappingsAt("is_pull", boolFieldMapping)
|
||||
docMapping.AddFieldMappingsAt("is_closed", boolFieldMapping)
|
||||
docMapping.AddFieldMappingsAt("is_archived", boolFieldMapping)
|
||||
docMapping.AddFieldMappingsAt("label_ids", numberFieldMapping)
|
||||
docMapping.AddFieldMappingsAt("no_label", boolFieldMapping)
|
||||
docMapping.AddFieldMappingsAt("milestone_id", numberFieldMapping)
|
||||
@ -185,6 +186,9 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
|
||||
if options.IsClosed.Has() {
|
||||
queries = append(queries, inner_bleve.BoolFieldQuery(options.IsClosed.Value(), "is_closed"))
|
||||
}
|
||||
if options.IsArchived.Has() {
|
||||
queries = append(queries, inner_bleve.BoolFieldQuery(options.IsArchived.Value(), "is_archived"))
|
||||
}
|
||||
|
||||
if options.NoLabelOnly {
|
||||
queries = append(queries, inner_bleve.BoolFieldQuery(true, "no_label"))
|
||||
|
@ -72,7 +72,7 @@ func ToDBOptions(ctx context.Context, options *internal.SearchOptions) (*issue_m
|
||||
UpdatedAfterUnix: options.UpdatedAfterUnix.Value(),
|
||||
UpdatedBeforeUnix: options.UpdatedBeforeUnix.Value(),
|
||||
PriorityRepoID: 0,
|
||||
IsArchived: optional.None[bool](),
|
||||
IsArchived: options.IsArchived,
|
||||
Org: nil,
|
||||
Team: nil,
|
||||
User: nil,
|
||||
|
@ -16,6 +16,7 @@ func ToSearchOptions(keyword string, opts *issues_model.IssuesOptions) *SearchOp
|
||||
AllPublic: opts.AllPublic,
|
||||
IsPull: opts.IsPull,
|
||||
IsClosed: opts.IsClosed,
|
||||
IsArchived: opts.IsArchived,
|
||||
}
|
||||
|
||||
if len(opts.LabelIDs) == 1 && opts.LabelIDs[0] == 0 {
|
||||
|
@ -18,7 +18,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
issueIndexerLatestVersion = 1
|
||||
issueIndexerLatestVersion = 2
|
||||
// multi-match-types, currently only 2 types are used
|
||||
// Reference: https://www.elastic.co/guide/en/elasticsearch/reference/7.0/query-dsl-multi-match-query.html#multi-match-types
|
||||
esMultiMatchTypeBestFields = "best_fields"
|
||||
@ -58,6 +58,7 @@ const (
|
||||
|
||||
"is_pull": { "type": "boolean", "index": true },
|
||||
"is_closed": { "type": "boolean", "index": true },
|
||||
"is_archived": { "type": "boolean", "index": true },
|
||||
"label_ids": { "type": "integer", "index": true },
|
||||
"no_label": { "type": "boolean", "index": true },
|
||||
"milestone_id": { "type": "integer", "index": true },
|
||||
@ -168,6 +169,9 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
|
||||
if options.IsClosed.Has() {
|
||||
query.Must(elastic.NewTermQuery("is_closed", options.IsClosed.Value()))
|
||||
}
|
||||
if options.IsArchived.Has() {
|
||||
query.Must(elastic.NewTermQuery("is_archived", options.IsArchived.Value()))
|
||||
}
|
||||
|
||||
if options.NoLabelOnly {
|
||||
query.Must(elastic.NewTermQuery("no_label", true))
|
||||
|
@ -37,6 +37,7 @@ func TestDBSearchIssues(t *testing.T) {
|
||||
t.Run("search issues by ID", searchIssueByID)
|
||||
t.Run("search issues is pr", searchIssueIsPull)
|
||||
t.Run("search issues is closed", searchIssueIsClosed)
|
||||
t.Run("search issues is archived", searchIssueIsArchived)
|
||||
t.Run("search issues by milestone", searchIssueByMilestoneID)
|
||||
t.Run("search issues by label", searchIssueByLabelID)
|
||||
t.Run("search issues by time", searchIssueByTime)
|
||||
@ -298,6 +299,33 @@ func searchIssueIsClosed(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func searchIssueIsArchived(t *testing.T) {
|
||||
tests := []struct {
|
||||
opts SearchOptions
|
||||
expectedIDs []int64
|
||||
}{
|
||||
{
|
||||
SearchOptions{
|
||||
IsArchived: optional.Some(false),
|
||||
},
|
||||
[]int64{22, 21, 17, 16, 15, 13, 12, 11, 20, 6, 5, 19, 18, 10, 7, 4, 9, 8, 3, 2, 1},
|
||||
},
|
||||
{
|
||||
SearchOptions{
|
||||
IsArchived: optional.Some(true),
|
||||
},
|
||||
[]int64{14},
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
assert.Equal(t, test.expectedIDs, issueIDs)
|
||||
}
|
||||
}
|
||||
|
||||
func searchIssueByMilestoneID(t *testing.T) {
|
||||
tests := []struct {
|
||||
opts SearchOptions
|
||||
|
@ -25,6 +25,7 @@ type IndexerData struct {
|
||||
// Fields used for filtering
|
||||
IsPull bool `json:"is_pull"`
|
||||
IsClosed bool `json:"is_closed"`
|
||||
IsArchived bool `json:"is_archived"`
|
||||
LabelIDs []int64 `json:"label_ids"`
|
||||
NoLabel bool `json:"no_label"` // True if LabelIDs is empty
|
||||
MilestoneID int64 `json:"milestone_id"`
|
||||
@ -83,6 +84,7 @@ type SearchOptions struct {
|
||||
|
||||
IsPull optional.Option[bool] // if the issues is a pull request
|
||||
IsClosed optional.Option[bool] // if the issues is closed
|
||||
IsArchived optional.Option[bool] // if the repo is archived
|
||||
|
||||
IncludedLabelIDs []int64 // labels the issues have
|
||||
ExcludedLabelIDs []int64 // labels the issues don't have
|
||||
|
@ -18,7 +18,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
issueIndexerLatestVersion = 3
|
||||
issueIndexerLatestVersion = 4
|
||||
|
||||
// TODO: make this configurable if necessary
|
||||
maxTotalHits = 10000
|
||||
@ -61,6 +61,7 @@ func NewIndexer(url, apiKey, indexerName string) *Indexer {
|
||||
"is_public",
|
||||
"is_pull",
|
||||
"is_closed",
|
||||
"is_archived",
|
||||
"label_ids",
|
||||
"no_label",
|
||||
"milestone_id",
|
||||
@ -145,6 +146,9 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
|
||||
if options.IsClosed.Has() {
|
||||
query.And(inner_meilisearch.NewFilterEq("is_closed", options.IsClosed.Value()))
|
||||
}
|
||||
if options.IsArchived.Has() {
|
||||
query.And(inner_meilisearch.NewFilterEq("is_archived", options.IsArchived.Value()))
|
||||
}
|
||||
|
||||
if options.NoLabelOnly {
|
||||
query.And(inner_meilisearch.NewFilterEq("no_label", true))
|
||||
|
@ -101,6 +101,7 @@ func getIssueIndexerData(ctx context.Context, issueID int64) (*internal.IndexerD
|
||||
Comments: comments,
|
||||
IsPull: issue.IsPull,
|
||||
IsClosed: issue.IsClosed,
|
||||
IsArchived: issue.Repo.IsArchived,
|
||||
LabelIDs: labels,
|
||||
NoLabel: len(labels) == 0,
|
||||
MilestoneID: issue.MilestoneID,
|
||||
|
@ -358,6 +358,7 @@ func CommonRoutes() *web.Router {
|
||||
r.Get("/PACKAGES", cran.EnumerateSourcePackages)
|
||||
r.Get("/PACKAGES{format}", cran.EnumerateSourcePackages)
|
||||
r.Get("/{filename}", cran.DownloadSourcePackageFile)
|
||||
r.Get("/Archive/{packagename}/{filename}", cran.DownloadSourcePackageFile)
|
||||
})
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), cran.UploadSourcePackageFile)
|
||||
})
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/indexer/code"
|
||||
issue_indexer "code.gitea.io/gitea/modules/indexer/issues"
|
||||
"code.gitea.io/gitea/modules/indexer/stats"
|
||||
"code.gitea.io/gitea/modules/lfs"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
@ -905,6 +906,9 @@ func SettingsPost(ctx *context.Context) {
|
||||
log.Error("CleanRepoScheduleTasks for archived repo %s/%s: %v", ctx.Repo.Owner.Name, repo.Name, err)
|
||||
}
|
||||
|
||||
// update issue indexer
|
||||
issue_indexer.UpdateRepoIndexer(ctx, repo.ID)
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("repo.settings.archive.success"))
|
||||
|
||||
log.Trace("Repository was archived: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
||||
@ -929,6 +933,9 @@ func SettingsPost(ctx *context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// update issue indexer
|
||||
issue_indexer.UpdateRepoIndexer(ctx, repo.ID)
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("repo.settings.unarchive.success"))
|
||||
|
||||
log.Trace("Repository was un-archived: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
||||
|
@ -74,9 +74,9 @@ func prepareOpenWithEditorApps(ctx *context.Context) {
|
||||
schema, _, _ := strings.Cut(app.OpenURL, ":")
|
||||
var iconHTML template.HTML
|
||||
if schema == "vscode" || schema == "vscodium" || schema == "jetbrains" {
|
||||
iconHTML = svg.RenderHTML(fmt.Sprintf("gitea-%s", schema), 16, "tw-mr-2")
|
||||
iconHTML = svg.RenderHTML(fmt.Sprintf("gitea-%s", schema), 16)
|
||||
} else {
|
||||
iconHTML = svg.RenderHTML("gitea-git", 16, "tw-mr-2") // TODO: it could support user's customized icon in the future
|
||||
iconHTML = svg.RenderHTML("gitea-git", 16) // TODO: it could support user's customized icon in the future
|
||||
}
|
||||
tmplApps = append(tmplApps, map[string]any{
|
||||
"DisplayName": app.DisplayName,
|
||||
|
@ -1,15 +1,13 @@
|
||||
<!-- there is always at least one button (by context/repo.go) -->
|
||||
{{if $.CloneButtonShowHTTPS}}
|
||||
<button class="ui small button" id="repo-clone-https" data-link="{{$.CloneButtonOriginLink.HTTPS}}">
|
||||
HTTPS
|
||||
</button>
|
||||
{{end}}
|
||||
{{if $.CloneButtonShowSSH}}
|
||||
<button class="ui small button" id="repo-clone-ssh" data-link="{{$.CloneButtonOriginLink.SSH}}">
|
||||
SSH
|
||||
</button>
|
||||
{{end}}
|
||||
<input id="repo-clone-url" size="10" class="js-clone-url" value="{{$.CloneButtonOriginLink.HTTPS}}" readonly>
|
||||
<button class="ui small icon button" id="clipboard-btn" data-tooltip-content="{{ctx.Locale.Tr "copy_url"}}" data-clipboard-target="#repo-clone-url" aria-label="{{ctx.Locale.Tr "copy_url"}}">
|
||||
<!-- there is always at least one button (guaranteed by context/repo.go) -->
|
||||
<div class="ui action small input clone-buttons-combo">
|
||||
{{if $.CloneButtonShowHTTPS}}
|
||||
<button class="ui small button repo-clone-https" data-link="{{$.CloneButtonOriginLink.HTTPS}}">HTTPS</button>
|
||||
{{end}}
|
||||
{{if $.CloneButtonShowSSH}}
|
||||
<button class="ui small button repo-clone-ssh" data-link="{{$.CloneButtonOriginLink.SSH}}">SSH</button>
|
||||
{{end}}
|
||||
<input size="10" class="repo-clone-url js-clone-url" value="{{$.CloneButtonOriginLink.HTTPS}}" readonly>
|
||||
<button class="ui small icon button" data-clipboard-target=".repo-clone-url" data-tooltip-content="{{ctx.Locale.Tr "copy_url"}}">
|
||||
{{svg "octicon-copy" 14}}
|
||||
</button>
|
||||
</button>
|
||||
</div>
|
||||
|
44
templates/repo/clone_panel.tmpl
Normal file
44
templates/repo/clone_panel.tmpl
Normal file
@ -0,0 +1,44 @@
|
||||
<button class="ui green button js-btn-clone-panel">
|
||||
<span>{{svg "octicon-code" 16}} Code</span>
|
||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||
</button>
|
||||
<div class="clone-panel-popup tippy-target">
|
||||
<div class="flex-text-block clone-panel-field">{{svg "octicon-terminal"}} Clone</div>
|
||||
|
||||
<div class="clone-panel-tab">
|
||||
<!-- there is always at least one button (guaranteed by context/repo.go) -->
|
||||
{{if $.CloneButtonShowHTTPS}}
|
||||
<button class="item repo-clone-https" data-link="{{$.CloneButtonOriginLink.HTTPS}}">HTTPS</button>
|
||||
{{end}}
|
||||
{{if $.CloneButtonShowSSH}}
|
||||
<button class="item repo-clone-ssh" data-link="{{$.CloneButtonOriginLink.SSH}}">SSH</button>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="clone-panel-field">
|
||||
<div class="ui input tiny action">
|
||||
<input size="30" class="repo-clone-url js-clone-url" value="{{$.CloneButtonOriginLink.HTTPS}}" readonly>
|
||||
<div class="ui small compact icon button" data-clipboard-target=".js-clone-url" data-tooltip-content="{{ctx.Locale.Tr "copy_url"}}">
|
||||
{{svg "octicon-copy" 14}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{if not .PageIsWiki}}
|
||||
<div class="flex-items-block clone-panel-list">
|
||||
{{range .OpenWithEditorApps}}
|
||||
<a class="item muted js-clone-url-editor" data-href-template="{{.OpenURL}}">{{.IconHTML}}{{ctx.Locale.Tr "repo.open_with_editor" .DisplayName}}</a>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
{{if and (not $.DisableDownloadSourceArchives) $.RefName}}
|
||||
<div class="divider"></div>
|
||||
<div class="flex-items-block clone-panel-list">
|
||||
<a class="item muted archive-link" href="{{$.RepoLink}}/archive/{{PathEscapeSegments $.RefName}}.zip" rel="nofollow">{{svg "octicon-file-zip"}} {{ctx.Locale.Tr "repo.download_zip"}}</a>
|
||||
<a class="item muted archive-link" href="{{$.RepoLink}}/archive/{{PathEscapeSegments $.RefName}}.tar.gz" rel="nofollow">{{svg "octicon-file-zip"}} {{ctx.Locale.Tr "repo.download_tar"}}</a>
|
||||
<a class="item muted archive-link" href="{{$.RepoLink}}/archive/{{PathEscapeSegments $.RefName}}.bundle" rel="nofollow">{{svg "octicon-package"}} {{ctx.Locale.Tr "repo.download_bundle"}}</a>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
@ -1,50 +0,0 @@
|
||||
<script>
|
||||
// synchronously set clone button states and urls here to avoid flickering
|
||||
// on page load. initRepoCloneLink calls this when proto changes.
|
||||
// this applies the protocol-dependant clone url to all elements with the
|
||||
// `js-clone-url` and `js-clone-url-vsc` classes.
|
||||
// TODO: This localStorage setting should be moved to backend user config
|
||||
// so it's available during rendering, then this inline script can be removed.
|
||||
(window.updateCloneStates = function() {
|
||||
const httpsBtn = document.getElementById('repo-clone-https');
|
||||
const sshBtn = document.getElementById('repo-clone-ssh');
|
||||
const value = localStorage.getItem('repo-clone-protocol') || 'https';
|
||||
const isSSH = value === 'ssh' && sshBtn || value !== 'ssh' && !httpsBtn;
|
||||
|
||||
if (httpsBtn) {
|
||||
httpsBtn.textContent = window.origin.split(':')[0].toUpperCase();
|
||||
httpsBtn.classList.toggle('primary', !isSSH);
|
||||
httpsBtn.classList.toggle('basic', isSSH);
|
||||
}
|
||||
if (sshBtn) {
|
||||
sshBtn.classList.toggle('primary', isSSH);
|
||||
sshBtn.classList.toggle('basic', !isSSH);
|
||||
}
|
||||
|
||||
const btn = isSSH ? sshBtn : httpsBtn;
|
||||
if (!btn) return;
|
||||
|
||||
// NOTE: Keep this function in sync with the one in the js folder
|
||||
function toOriginUrl(urlStr) {
|
||||
try {
|
||||
if (urlStr.startsWith('http://') || urlStr.startsWith('https://') || urlStr.startsWith('/')) {
|
||||
const {origin, protocol, hostname, port} = window.location;
|
||||
const url = new URL(urlStr, origin);
|
||||
url.protocol = protocol;
|
||||
url.hostname = hostname;
|
||||
url.port = port || (protocol === 'https:' ? '443' : '80');
|
||||
return url.toString();
|
||||
}
|
||||
} catch {}
|
||||
return urlStr;
|
||||
}
|
||||
const link = toOriginUrl(btn.getAttribute('data-link'));
|
||||
|
||||
for (const el of document.getElementsByClassName('js-clone-url')) {
|
||||
el[el.nodeName === 'INPUT' ? 'value' : 'textContent'] = link;
|
||||
}
|
||||
for (const el of document.getElementsByClassName('js-clone-url-editor')) {
|
||||
el.href = el.getAttribute('data-href-template').replace('{url}', encodeURIComponent(link));
|
||||
}
|
||||
})();
|
||||
</script>
|
@ -37,11 +37,9 @@
|
||||
</a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
<div class="clone-panel ui action small input tw-flex-1">
|
||||
{{template "repo/clone_buttons" .}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{if not .Repository.IsArchived}}
|
||||
<div class="divider tw-my-0"></div>
|
||||
@ -73,7 +71,6 @@ git push -u origin {{.Repository.DefaultBranch}}</code></pre>
|
||||
{{ctx.Locale.Tr "repo.empty_message"}}
|
||||
</div>
|
||||
{{end}}
|
||||
{{template "repo/clone_script" .}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -102,27 +102,10 @@
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
{{/* by default, the row-right flex grows, but on non-root tree path, it should not because the row-left might contain a long path */}}
|
||||
<div class="repo-button-row-right {{if not $isTreePathRoot}}tw-flex-grow-0{{end}}">
|
||||
<div class="repo-button-row-right">
|
||||
<!-- Only show clone panel in repository home page -->
|
||||
{{if $isTreePathRoot}}
|
||||
<div class="clone-panel ui action tiny input">
|
||||
{{template "repo/clone_buttons" .}}
|
||||
<button class="ui small jump dropdown icon button" data-tooltip-content="{{ctx.Locale.Tr "repo.more_operations"}}">
|
||||
{{svg "octicon-kebab-horizontal"}}
|
||||
<div class="menu">
|
||||
{{if not $.DisableDownloadSourceArchives}}
|
||||
<a class="item archive-link" href="{{$.RepoLink}}/archive/{{PathEscapeSegments $.RefName}}.zip" rel="nofollow">{{svg "octicon-file-zip" 16 "tw-mr-2"}}{{ctx.Locale.Tr "repo.download_zip"}}</a>
|
||||
<a class="item archive-link" href="{{$.RepoLink}}/archive/{{PathEscapeSegments $.RefName}}.tar.gz" rel="nofollow">{{svg "octicon-file-zip" 16 "tw-mr-2"}}{{ctx.Locale.Tr "repo.download_tar"}}</a>
|
||||
<a class="item archive-link" href="{{$.RepoLink}}/archive/{{PathEscapeSegments $.RefName}}.bundle" rel="nofollow">{{svg "octicon-package" 16 "tw-mr-2"}}{{ctx.Locale.Tr "repo.download_bundle"}}</a>
|
||||
{{end}}
|
||||
{{range .OpenWithEditorApps}}
|
||||
<a class="item js-clone-url-editor" data-href-template="{{.OpenURL}}">{{.IconHTML}}{{ctx.Locale.Tr "repo.open_with_editor" .DisplayName}}</a>
|
||||
{{end}}
|
||||
</div>
|
||||
</button>
|
||||
{{template "repo/clone_script" .}}{{/* the script will update `.js-clone-url` and related elements */}}
|
||||
</div>
|
||||
{{template "repo/clone_panel" .}}
|
||||
{{end}}
|
||||
{{if and (not $isTreePathRoot) (not .IsViewFile) (not .IsBlame)}}{{/* IsViewDirectory (not home), TODO: split the templates, avoid using "if" tricks */}}
|
||||
<a class="ui button" href="{{.RepoLink}}/commits/{{.BranchNameSubURL}}/{{.TreePath | PathEscapeSegments}}">
|
||||
@ -140,6 +123,9 @@
|
||||
{{template "repo/code/upstream_diverging_info" .}}
|
||||
{{end}}
|
||||
{{template "repo/view_list" .}}
|
||||
{{if and .ReadmeExist (or .IsMarkup .IsPlainText)}}
|
||||
{{template "repo/view_file" .}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
{{if not .LatestCommit}}
|
||||
<div class="ui active tiny slow centered inline">…</div>
|
||||
…
|
||||
{{else}}
|
||||
{{if .LatestCommitUser}}
|
||||
{{ctx.AvatarUtils.Avatar .LatestCommitUser 24 "tw-mr-1"}}
|
||||
|
@ -1,29 +1,20 @@
|
||||
<table id="repo-files-table" class="ui single line fixed table tw-mt-0" {{if .HasFilesWithoutLatestCommit}}hx-indicator="tr.notready td.message span" hx-trigger="load" hx-swap="morph" hx-post="{{.LastCommitLoaderURL}}"{{end}}>
|
||||
<thead>
|
||||
<tr class="commit-list">
|
||||
<th class="tw-overflow-hidden" colspan="2">
|
||||
<div class="tw-flex">
|
||||
<div class="latest-commit">
|
||||
{{template "repo/latest_commit" .}}
|
||||
{{/* use grid layout, still use the old ID because there are many other CSS styles depending on this ID */}}
|
||||
<div id="repo-files-table" {{if .HasFilesWithoutLatestCommit}}hx-indicator="#repo-files-table .repo-file-cell.message" hx-trigger="load" hx-swap="morph" hx-post="{{.LastCommitLoaderURL}}"{{end}}>
|
||||
<div class="repo-file-line">
|
||||
<div class="latest-commit">{{template "repo/latest_commit" .}}</div>
|
||||
<div>{{if and .LatestCommit .LatestCommit.Committer}}{{DateUtils.TimeSince .LatestCommit.Committer.When}}{{end}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</th>
|
||||
<th class="text grey right age">{{if .LatestCommit}}{{if .LatestCommit.Committer}}{{DateUtils.TimeSince .LatestCommit.Committer.When}}{{end}}{{end}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{if .HasParentPath}}
|
||||
<tr class="has-parent">
|
||||
<td colspan="3">{{svg "octicon-reply"}}<a class="muted" href="{{.BranchLink}}{{if .ParentPath}}{{PathEscapeSegments .ParentPath}}{{end}}">..</a></td>
|
||||
</tr>
|
||||
<div class="repo-file-line">
|
||||
{{svg "octicon-reply"}} <a class="muted" href="{{.BranchLink}}{{if .ParentPath}}{{PathEscapeSegments .ParentPath}}{{end}}">..</a>
|
||||
</div>
|
||||
{{end}}
|
||||
{{range $item := .Files}}
|
||||
<div class="repo-file-item">
|
||||
{{$entry := $item.Entry}}
|
||||
{{$commit := $item.Commit}}
|
||||
{{$subModuleFile := $item.SubModuleFile}}
|
||||
<tr data-entryname="{{$entry.Name}}" data-ready="{{if $commit}}true{{else}}false{{end}}" class="{{if not $commit}}not{{end}}ready entry">
|
||||
<td class="name four wide">
|
||||
<span class="truncate">
|
||||
<div class="repo-file-cell name {{if not $commit}}notready{{end}}">
|
||||
{{if $entry.IsSubModule}}
|
||||
{{svg "octicon-file-submodule"}}
|
||||
{{$refURL := $subModuleFile.RefURL AppUrl $.Repository.FullName $.SSHDomain}} {{/* FIXME: the usage of AppUrl seems incorrect, it would be fixed in the future, use AppSubUrl instead */}}
|
||||
@ -51,23 +42,16 @@
|
||||
<a class="muted" href="{{$.TreeLink}}/{{PathEscapeSegments $entry.Name}}" title="{{$entry.Name}}">{{$entry.Name}}</a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</span>
|
||||
</td>
|
||||
<td class="message nine wide">
|
||||
<span class="truncate">
|
||||
</div>
|
||||
<div class="repo-file-cell message loading-icon-2px">
|
||||
{{if $commit}}
|
||||
{{$commitLink := printf "%s/commit/%s" $.RepoLink (PathEscape $commit.ID.String)}}
|
||||
{{ctx.RenderUtils.RenderCommitMessageLinkSubject $commit.Message $commitLink ($.Repository.ComposeMetas ctx)}}
|
||||
{{else}}
|
||||
<div class="ui active tiny slow centered inline"></div>
|
||||
… {{/* will be loaded again by LastCommitLoaderURL */}}
|
||||
{{end}}
|
||||
</span>
|
||||
</td>
|
||||
<td class="text right age three wide">{{if $commit}}{{DateUtils.TimeSince $commit.Committer.When}}{{end}}</td>
|
||||
</tr>
|
||||
</div>
|
||||
<div class="repo-file-cell age">{{if $commit}}{{DateUtils.TimeSince $commit.Committer.When}}{{end}}</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{if and .ReadmeExist (or .IsMarkup .IsPlainText)}}
|
||||
{{template "repo/view_file" .}}
|
||||
{{end}}
|
||||
</div>
|
||||
|
@ -15,10 +15,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui eight wide column text right">
|
||||
<div class="clone-panel ui action small input">
|
||||
{{template "repo/clone_buttons" .}}
|
||||
{{template "repo/clone_script" .}}
|
||||
</div>
|
||||
{{template "repo/clone_panel" .}}
|
||||
</div>
|
||||
</div>
|
||||
<h2 class="ui top header">{{ctx.Locale.Tr "repo.wiki.wiki_page_revisions"}}</h2>
|
||||
|
@ -4,7 +4,7 @@
|
||||
{{$title := .title}}
|
||||
<div class="ui container">
|
||||
<div class="repo-button-row">
|
||||
<div class="tw-flex tw-items-center">
|
||||
<div class="flex-text-block tw-flex-1">
|
||||
<div class="ui floating filter dropdown" data-no-results="{{ctx.Locale.Tr "no_results_found"}}">
|
||||
<div class="ui basic small button">
|
||||
<span class="text">
|
||||
@ -28,10 +28,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clone-panel ui action small input">
|
||||
{{template "repo/clone_buttons" .}}
|
||||
{{template "repo/clone_script" .}}
|
||||
</div>
|
||||
{{template "repo/clone_panel" .}}
|
||||
</div>
|
||||
<div class="ui dividing header">
|
||||
<div class="flex-text-block tw-flex-wrap tw-justify-end">
|
||||
@ -45,7 +42,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-text-block tw-flex-wrap tw-justify-end">
|
||||
<div class="repo-button-row">
|
||||
{{if .EscapeStatus.Escaped}}
|
||||
<a class="ui small button unescape-button tw-m-0 tw-hidden">{{ctx.Locale.Tr "repo.unescape_control_characters"}}</a>
|
||||
<a class="ui small button escape-button tw-m-0">{{ctx.Locale.Tr "repo.escape_control_characters"}}</a>
|
||||
|
@ -115,6 +115,14 @@ func TestPackageCran(t *testing.T) {
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
})
|
||||
|
||||
t.Run("DownloadArchived", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/src/contrib/Archive/%s/%s_%s.tar.gz", url, packageName, packageName, packageVersion)).
|
||||
AddBasicAuth(user.Name)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
})
|
||||
|
||||
t.Run("Enumerate", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
|
@ -49,7 +49,7 @@ func testViewRepo(t *testing.T) {
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
files := htmlDoc.doc.Find("#repo-files-table > TBODY > TR")
|
||||
files := htmlDoc.doc.Find("#repo-files-table .repo-file-item")
|
||||
|
||||
type file struct {
|
||||
fileName string
|
||||
@ -61,7 +61,7 @@ func testViewRepo(t *testing.T) {
|
||||
var items []file
|
||||
|
||||
files.Each(func(i int, s *goquery.Selection) {
|
||||
tds := s.Find("td")
|
||||
tds := s.Find(".repo-file-cell")
|
||||
var f file
|
||||
tds.Each(func(i int, s *goquery.Selection) {
|
||||
if i == 0 {
|
||||
@ -127,10 +127,10 @@ func TestViewRepo1CloneLinkAnonymous(t *testing.T) {
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
link, exists := htmlDoc.doc.Find("#repo-clone-https").Attr("data-link")
|
||||
link, exists := htmlDoc.doc.Find(".repo-clone-https").Attr("data-link")
|
||||
assert.True(t, exists, "The template has changed")
|
||||
assert.Equal(t, setting.AppURL+"user2/repo1.git", link)
|
||||
_, exists = htmlDoc.doc.Find("#repo-clone-ssh").Attr("data-link")
|
||||
_, exists = htmlDoc.doc.Find(".repo-clone-ssh").Attr("data-link")
|
||||
assert.False(t, exists)
|
||||
}
|
||||
|
||||
@ -143,10 +143,10 @@ func TestViewRepo1CloneLinkAuthorized(t *testing.T) {
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
link, exists := htmlDoc.doc.Find("#repo-clone-https").Attr("data-link")
|
||||
link, exists := htmlDoc.doc.Find(".repo-clone-https").Attr("data-link")
|
||||
assert.True(t, exists, "The template has changed")
|
||||
assert.Equal(t, setting.AppURL+"user2/repo1.git", link)
|
||||
link, exists = htmlDoc.doc.Find("#repo-clone-ssh").Attr("data-link")
|
||||
link, exists = htmlDoc.doc.Find(".repo-clone-ssh").Attr("data-link")
|
||||
assert.True(t, exists, "The template has changed")
|
||||
sshURL := fmt.Sprintf("ssh://%s@%s:%d/user2/repo1.git", setting.SSH.User, setting.SSH.Domain, setting.SSH.Port)
|
||||
assert.Equal(t, sshURL, link)
|
||||
@ -161,7 +161,7 @@ func TestViewRepoWithSymlinks(t *testing.T) {
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
files := htmlDoc.doc.Find("#repo-files-table > TBODY > TR > TD.name > SPAN.truncate")
|
||||
files := htmlDoc.doc.Find("#repo-files-table .repo-file-cell.name")
|
||||
items := files.Map(func(i int, s *goquery.Selection) string {
|
||||
cls, _ := s.Find("SVG").Attr("class")
|
||||
file := strings.Trim(s.Find("A").Text(), " \t\n")
|
||||
|
@ -66,7 +66,10 @@
|
||||
@import "./repo/wiki.css";
|
||||
@import "./repo/header.css";
|
||||
@import "./repo/home.css";
|
||||
@import "./repo/home-file-list.css";
|
||||
@import "./repo/reactions.css";
|
||||
@import "./repo/clone.css";
|
||||
@import "./repo/commit-sign.css";
|
||||
|
||||
@import "./editor/fileeditor.css";
|
||||
@import "./editor/combomarkdowneditor.css";
|
||||
|
@ -101,42 +101,6 @@
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.repository .clone-panel {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.repository.wiki .clone-panel {
|
||||
flex: 0;
|
||||
}
|
||||
|
||||
.repository.wiki .clone-panel input {
|
||||
width: 20ch;
|
||||
}
|
||||
|
||||
.repository .clone-panel #repo-clone-url {
|
||||
border-radius: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.repository .ui.action.input.clone-panel > button + button,
|
||||
.repository .ui.action.input.clone-panel > button + input {
|
||||
margin-left: -1px; /* make the borders overlap to avoid double borders */
|
||||
}
|
||||
|
||||
.repository .clone-panel > button:first-of-type {
|
||||
border-radius: var(--border-radius) 0 0 var(--border-radius) !important;
|
||||
}
|
||||
|
||||
.repository .clone-panel > button:last-of-type {
|
||||
border-radius: 0 var(--border-radius) var(--border-radius) 0 !important;
|
||||
}
|
||||
|
||||
.repository .clone-panel .dropdown .menu {
|
||||
right: 0 !important;
|
||||
left: auto !important;
|
||||
}
|
||||
|
||||
.repository .repo-description {
|
||||
font-size: 16px;
|
||||
margin-bottom: 5px;
|
||||
@ -177,138 +141,6 @@ td .commit-summary {
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
/* this is what limits the commit table width to a value that works on all viewport sizes */
|
||||
#repo-files-table th:first-of-type {
|
||||
max-width: calc(calc(min(100vw, 1280px)) - 145px - calc(2 * var(--page-margin-x)));
|
||||
}
|
||||
|
||||
.repository.file.list #repo-files-table thead th {
|
||||
font-weight: var(--font-weight-normal);
|
||||
}
|
||||
|
||||
.repository.file.list #repo-files-table tbody .svg {
|
||||
margin-left: 3px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.repository.file.list #repo-files-table tbody .svg.octicon-reply {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.repository.file.list #repo-files-table tbody .svg.octicon-file-directory-fill,
|
||||
.repository.file.list #repo-files-table tbody .svg.octicon-file-submodule {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.repository.file.list #repo-files-table tbody .svg.octicon-file,
|
||||
.repository.file.list #repo-files-table tbody .svg.octicon-file-symlink-file,
|
||||
.repository.file.list #repo-files-table tbody .svg.octicon-file-directory-symlink {
|
||||
color: var(--color-secondary-dark-7);
|
||||
}
|
||||
|
||||
.repository.file.list #repo-files-table td {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
overflow: initial;
|
||||
}
|
||||
|
||||
.repository.file.list #repo-files-table td.name {
|
||||
width: 33%;
|
||||
max-width: calc(100vw - 140px);
|
||||
}
|
||||
|
||||
@media (min-width: 1201px) {
|
||||
.repository.file.list #repo-files-table td.name {
|
||||
max-width: 150px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) and (max-width: 1200px) {
|
||||
.repository.file.list #repo-files-table td.name {
|
||||
max-width: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) and (max-width: 991.98px) {
|
||||
.repository.file.list #repo-files-table td.name {
|
||||
max-width: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
.repository.file.list #repo-files-table td.message {
|
||||
color: var(--color-text-light-1);
|
||||
width: 66%;
|
||||
}
|
||||
|
||||
@media (min-width: 1201px) {
|
||||
.repository.file.list #repo-files-table td.message {
|
||||
max-width: 400px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) and (max-width: 1200px) {
|
||||
.repository.file.list #repo-files-table td.message {
|
||||
max-width: 350px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) and (max-width: 991.98px) {
|
||||
.repository.file.list #repo-files-table td.message {
|
||||
max-width: 250px;
|
||||
}
|
||||
}
|
||||
|
||||
.repository.file.list #repo-files-table td.age {
|
||||
color: var(--color-text-light-1);
|
||||
}
|
||||
|
||||
.repository.file.list #repo-files-table td .truncate {
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.repository.file.list #repo-files-table td a {
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.repository.file.list #repo-files-table td .at {
|
||||
margin-left: 3px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.repository.file.list #repo-files-table td > * {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.repository.file.list #repo-files-table td.message .isSigned {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.repository.file.list #repo-files-table tr:last-of-type td:first-child {
|
||||
border-bottom-left-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.repository.file.list #repo-files-table tr:last-of-type td:last-child {
|
||||
border-bottom-right-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.repository.file.list #repo-files-table tr:hover {
|
||||
background-color: var(--color-hover);
|
||||
}
|
||||
|
||||
.repository.file.list #repo-files-table tr.has-parent a {
|
||||
display: inline-block;
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
width: calc(100% - 1.25rem);
|
||||
}
|
||||
|
||||
.repository.file.list .non-diff-file-content .header .icon {
|
||||
font-size: 1em;
|
||||
}
|
||||
@ -787,47 +619,6 @@ td .commit-summary {
|
||||
height: 30px !important;
|
||||
}
|
||||
|
||||
.singular-commit .shabox .sha.label {
|
||||
margin: 0;
|
||||
border: 1px solid var(--color-light-border);
|
||||
}
|
||||
|
||||
.singular-commit .shabox .sha.label.isSigned.isWarning {
|
||||
border: 1px solid var(--color-red-badge);
|
||||
background: var(--color-red-badge-bg);
|
||||
}
|
||||
|
||||
.singular-commit .shabox .sha.label.isSigned.isWarning:hover {
|
||||
background: var(--color-red-badge-hover-bg) !important;
|
||||
}
|
||||
|
||||
.singular-commit .shabox .sha.label.isSigned.isVerified {
|
||||
border: 1px solid var(--color-green-badge);
|
||||
background: var(--color-green-badge-bg);
|
||||
}
|
||||
|
||||
.singular-commit .shabox .sha.label.isSigned.isVerified:hover {
|
||||
background: var(--color-green-badge-hover-bg) !important;
|
||||
}
|
||||
|
||||
.singular-commit .shabox .sha.label.isSigned.isVerifiedUntrusted {
|
||||
border: 1px solid var(--color-yellow-badge);
|
||||
background: var(--color-yellow-badge-bg);
|
||||
}
|
||||
|
||||
.singular-commit .shabox .sha.label.isSigned.isVerifiedUntrusted:hover {
|
||||
background: var(--color-yellow-badge-hover-bg) !important;
|
||||
}
|
||||
|
||||
.singular-commit .shabox .sha.label.isSigned.isVerifiedUnmatched {
|
||||
border: 1px solid var(--color-orange-badge);
|
||||
background: var(--color-orange-badge-bg);
|
||||
}
|
||||
|
||||
.singular-commit .shabox .sha.label.isSigned.isVerifiedUnmatched:hover {
|
||||
background: var(--color-orange-badge-hover-bg) !important;
|
||||
}
|
||||
|
||||
.repository.view.issue .comment-list .timeline-item.event > .commit-status-link {
|
||||
float: right;
|
||||
margin-right: 8px;
|
||||
@ -1162,151 +953,6 @@ td .commit-summary {
|
||||
background-color: var(--color-light) !important;
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label,
|
||||
.repository #repo-files-table .sha.label,
|
||||
.repository #repo-file-commit-box .sha.label,
|
||||
.repository #rev-list .sha.label,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label {
|
||||
border: 1px solid var(--color-light-border);
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label .detail.icon,
|
||||
.repository #repo-files-table .sha.label .detail.icon,
|
||||
.repository #repo-file-commit-box .sha.label .detail.icon,
|
||||
.repository #rev-list .sha.label .detail.icon,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label .detail.icon {
|
||||
background: var(--color-light);
|
||||
margin: -6px -10px -4px 0;
|
||||
padding: 5px 4px 5px 6px;
|
||||
border-left: 1px solid var(--color-light-border);
|
||||
border-top: 0;
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label .detail.icon .svg,
|
||||
.repository #repo-files-table .sha.label .detail.icon .svg,
|
||||
.repository #repo-file-commit-box .sha.label .detail.icon .svg,
|
||||
.repository #rev-list .sha.label .detail.icon .svg,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label .detail.icon .svg {
|
||||
margin: 0 0.25em 0 0;
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label .detail.icon > div,
|
||||
.repository #repo-files-table .sha.label .detail.icon > div,
|
||||
.repository #repo-file-commit-box .sha.label .detail.icon > div,
|
||||
.repository #rev-list .sha.label .detail.icon > div,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label .detail.icon > div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label.isSigned.isWarning,
|
||||
.repository #repo-files-table .sha.label.isSigned.isWarning,
|
||||
.repository #repo-file-commit-box .sha.label.isSigned.isWarning,
|
||||
.repository #rev-list .sha.label.isSigned.isWarning,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label.isSigned.isWarning {
|
||||
border: 1px solid var(--color-red-badge);
|
||||
background: var(--color-red-badge-bg);
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label.isSigned.isWarning .detail.icon,
|
||||
.repository #repo-files-table .sha.label.isSigned.isWarning .detail.icon,
|
||||
.repository #repo-file-commit-box .sha.label.isSigned.isWarning .detail.icon,
|
||||
.repository #rev-list .sha.label.isSigned.isWarning .detail.icon,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label.isSigned.isWarning .detail.icon {
|
||||
border-left: 1px solid var(--color-red-badge);
|
||||
color: var(--color-red-badge);
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label.isSigned.isWarning:hover,
|
||||
.repository #repo-files-table .sha.label.isSigned.isWarning:hover,
|
||||
.repository #repo-file-commit-box .sha.label.isSigned.isWarning:hover,
|
||||
.repository #rev-list .sha.label.isSigned.isWarning:hover,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label.isSigned.isWarning:hover {
|
||||
background: var(--color-red-badge-hover-bg) !important;
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label.isSigned.isVerified,
|
||||
.repository #repo-files-table .sha.label.isSigned.isVerified,
|
||||
.repository #repo-file-commit-box .sha.label.isSigned.isVerified,
|
||||
.repository #rev-list .sha.label.isSigned.isVerified,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label.isSigned.isVerified {
|
||||
border: 1px solid var(--color-green-badge);
|
||||
background: var(--color-green-badge-bg);
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label.isSigned.isVerified .detail.icon,
|
||||
.repository #repo-files-table .sha.label.isSigned.isVerified .detail.icon,
|
||||
.repository #repo-file-commit-box .sha.label.isSigned.isVerified .detail.icon,
|
||||
.repository #rev-list .sha.label.isSigned.isVerified .detail.icon,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label.isSigned.isVerified .detail.icon {
|
||||
border-left: 1px solid var(--color-green-badge);
|
||||
color: var(--color-green-badge);
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label.isSigned.isVerified:hover,
|
||||
.repository #repo-files-table .sha.label.isSigned.isVerified:hover,
|
||||
.repository #repo-file-commit-box .sha.label.isSigned.isVerified:hover,
|
||||
.repository #rev-list .sha.label.isSigned.isVerified:hover,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label.isSigned.isVerified:hover {
|
||||
background: var(--color-green-badge-hover-bg) !important;
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label.isSigned.isVerifiedUntrusted,
|
||||
.repository #repo-files-table .sha.label.isSigned.isVerifiedUntrusted,
|
||||
.repository #repo-file-commit-box .sha.label.isSigned.isVerifiedUntrusted,
|
||||
.repository #rev-list .sha.label.isSigned.isVerifiedUntrusted,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label.isSigned.isVerifiedUntrusted {
|
||||
border: 1px solid var(--color-yellow-badge);
|
||||
background: var(--color-yellow-badge-bg);
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label.isSigned.isVerifiedUntrusted .detail.icon,
|
||||
.repository #repo-files-table .sha.label.isSigned.isVerifiedUntrusted .detail.icon,
|
||||
.repository #repo-file-commit-box .sha.label.isSigned.isVerifiedUntrusted .detail.icon,
|
||||
.repository #rev-list .sha.label.isSigned.isVerifiedUntrusted .detail.icon,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label.isSigned.isVerifiedUntrusted .detail.icon {
|
||||
border-left: 1px solid var(--color-yellow-badge);
|
||||
color: var(--color-yellow-badge);
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label.isSigned.isVerifiedUntrusted:hover,
|
||||
.repository #repo-files-table .sha.label.isSigned.isVerifiedUntrusted:hover,
|
||||
.repository #repo-file-commit-box .sha.label.isSigned.isVerifiedUntrusted:hover,
|
||||
.repository #rev-list .sha.label.isSigned.isVerifiedUntrusted:hover,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label.isSigned.isVerifiedUntrusted:hover {
|
||||
background: var(--color-yellow-badge-hover-bg) !important;
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label.isSigned.isVerifiedUnmatched,
|
||||
.repository #repo-files-table .sha.label.isSigned.isVerifiedUnmatched,
|
||||
.repository #repo-file-commit-box .sha.label.isSigned.isVerifiedUnmatched,
|
||||
.repository #rev-list .sha.label.isSigned.isVerifiedUnmatched,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label.isSigned.isVerifiedUnmatched {
|
||||
border: 1px solid var(--color-orange-badge);
|
||||
background: var(--color-orange-badge-bg);
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label.isSigned.isVerifiedUnmatched .detail.icon,
|
||||
.repository #repo-files-table .sha.label.isSigned.isVerifiedUnmatched .detail.icon,
|
||||
.repository #repo-file-commit-box .sha.label.isSigned.isVerifiedUnmatched .detail.icon,
|
||||
.repository #rev-list .sha.label.isSigned.isVerifiedUnmatched .detail.icon,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label.isSigned.isVerifiedUnmatched .detail.icon {
|
||||
border-left: 1px solid var(--color-orange-badge);
|
||||
color: var(--color-orange-badge);
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label.isSigned.isVerifiedUnmatched:hover,
|
||||
.repository #repo-files-table .sha.label.isSigned.isVerifiedUnmatched:hover,
|
||||
.repository #repo-file-commit-box .sha.label.isSigned.isVerifiedUnmatched:hover,
|
||||
.repository #rev-list .sha.label.isSigned.isVerifiedUnmatched:hover,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label.isSigned.isVerifiedUnmatched:hover {
|
||||
background: var(--color-orange-badge-hover-bg) !important;
|
||||
}
|
||||
|
||||
.repository .data-table {
|
||||
width: 100%;
|
||||
}
|
||||
@ -1615,14 +1261,6 @@ td .commit-summary {
|
||||
font-weight: var(--font-weight-normal);
|
||||
}
|
||||
|
||||
.repository.quickstart .guide #repo-clone-url {
|
||||
border-radius: 0;
|
||||
padding: 5px 10px;
|
||||
font-size: 1.2em;
|
||||
line-height: 1.4;
|
||||
flex: 1
|
||||
}
|
||||
|
||||
.empty-placeholder {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -1678,92 +1316,6 @@ td .commit-summary {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isWarning {
|
||||
border-left: 1px solid var(--color-error-border);
|
||||
border-right: 1px solid var(--color-error-border);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isWarning.top,
|
||||
.repository .ui.attached.isSigned.isWarning.message {
|
||||
border-top: 1px solid var(--color-error-border);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isWarning.message {
|
||||
box-shadow: none;
|
||||
background-color: var(--color-error-bg);
|
||||
color: var(--color-error-text);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isWarning.message .ui.text {
|
||||
color: var(--color-error-text);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isWarning:last-child,
|
||||
.repository .ui.attached.isSigned.isWarning.bottom {
|
||||
border-bottom: 1px solid var(--color-error-border);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isVerified {
|
||||
border-left: 1px solid var(--color-success-border);
|
||||
border-right: 1px solid var(--color-success-border);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isVerified.top,
|
||||
.repository .ui.attached.isSigned.isVerified.message {
|
||||
border-top: 1px solid var(--color-success-border);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isVerified.message {
|
||||
box-shadow: none;
|
||||
background-color: var(--color-success-bg);
|
||||
color: var(--color-success-text);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isVerified.message .pull-right {
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isVerified.message .ui.text {
|
||||
color: var(--color-success-text);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isVerified:last-child,
|
||||
.repository .ui.attached.isSigned.isVerified.bottom {
|
||||
border-bottom: 1px solid var(--color-success-border);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isVerifiedUntrusted,
|
||||
.repository .ui.attached.isSigned.isVerifiedUnmatched {
|
||||
border-left: 1px solid var(--color-warning-border);
|
||||
border-right: 1px solid var(--color-warning-border);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isVerifiedUntrusted.top,
|
||||
.repository .ui.attached.isSigned.isVerifiedUnmatched.top,
|
||||
.repository .ui.attached.isSigned.isVerifiedUntrusted.message,
|
||||
.repository .ui.attached.isSigned.isVerifiedUnmatched.message {
|
||||
border-top: 1px solid var(--color-warning-border);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isVerifiedUntrusted.message,
|
||||
.repository .ui.attached.isSigned.isVerifiedUnmatched.message {
|
||||
box-shadow: none;
|
||||
background-color: var(--color-warning-bg);
|
||||
color: var(--color-warning-text);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isVerifiedUntrusted.message .ui.text,
|
||||
.repository .ui.attached.isSigned.isVerifiedUnmatched.message .ui.text {
|
||||
color: var(--color-warning-text);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isVerifiedUntrusted:last-child,
|
||||
.repository .ui.attached.isSigned.isVerifiedUnmatched:last-child,
|
||||
.repository .ui.attached.isSigned.isVerifiedUntrusted.bottom,
|
||||
.repository .ui.attached.isSigned.isVerifiedUnmatched.bottom {
|
||||
border-bottom: 1px solid var(--color-warning-border);
|
||||
}
|
||||
|
||||
.repository .ui.fluid.action.input .ui.search.action.input {
|
||||
flex: auto;
|
||||
}
|
||||
@ -1782,7 +1334,7 @@ td .commit-summary {
|
||||
|
||||
.repository .repository-summary .sub-menu .item {
|
||||
flex: 1;
|
||||
height: 30px;
|
||||
height: 33px; /* match search bar height, need to be improved in the future to use some consistent methods */
|
||||
line-height: var(--line-height-default);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -2110,26 +1662,18 @@ td .commit-summary {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.repo-button-row-left,
|
||||
.repo-button-row-right {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.repo-button-row-right {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.repository:not(.wiki) .repo-button-row {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
.repo-button-row-left {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.repo-button-row .button {
|
||||
@ -2143,16 +1687,6 @@ td .commit-summary {
|
||||
padding-right: 22px !important; /* normal buttons have !important paddings, so we need to override it for dropdown (Add File) icons */
|
||||
}
|
||||
|
||||
.repo-button-row input {
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.repo-button-row-left {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
tbody.commit-list {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
@ -2178,11 +1712,6 @@ tbody.commit-list {
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
/* but in the repo-files-table we cannot */
|
||||
#repo-files-table .commit-list .message-wrapper {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
tr.commit-list {
|
||||
width: 100%;
|
||||
@ -2578,25 +2107,6 @@ tbody.commit-list {
|
||||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
.repository.file.list #repo-files-table .entry,
|
||||
.repository.file.list #repo-files-table .commit-list {
|
||||
align-items: center;
|
||||
display: flex !important;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
.repository.file.list #repo-files-table .entry td.age,
|
||||
.repository.file.list #repo-files-table .commit-list td.age,
|
||||
.repository.file.list #repo-files-table .entry th.age,
|
||||
.repository.file.list #repo-files-table .commit-list th.age {
|
||||
margin-left: auto;
|
||||
}
|
||||
.repository.file.list #repo-files-table .entry td.message,
|
||||
.repository.file.list #repo-files-table .commit-list td.message,
|
||||
.repository.file.list #repo-files-table .entry span.commit-summary,
|
||||
.repository.file.list #repo-files-table .commit-list tr span.commit-summary {
|
||||
display: none !important;
|
||||
}
|
||||
.repository.view.issue .comment-list .timeline,
|
||||
.repository.view.issue .comment-list .timeline-item {
|
||||
margin-left: 0;
|
||||
|
32
web_src/css/repo/clone.css
Normal file
32
web_src/css/repo/clone.css
Normal file
@ -0,0 +1,32 @@
|
||||
/* only used by "repo/empty.tmpl" */
|
||||
.clone-buttons-combo {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.clone-buttons-combo input {
|
||||
border-left: none !important;
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
/* used by the clone-panel popup */
|
||||
.clone-panel-field,
|
||||
.clone-panel-list {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.clone-panel-tab .item {
|
||||
padding: 5px 10px;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.clone-panel-tab .item.active {
|
||||
border-bottom: 3px solid var(--color-secondary);
|
||||
}
|
||||
|
||||
.clone-panel-tab + .divider {
|
||||
margin: -1px 0 0;
|
||||
}
|
||||
|
||||
.clone-panel-list .item {
|
||||
margin: 5px 0;
|
||||
}
|
272
web_src/css/repo/commit-sign.css
Normal file
272
web_src/css/repo/commit-sign.css
Normal file
@ -0,0 +1,272 @@
|
||||
|
||||
.repository .ui.attached.isSigned.isWarning {
|
||||
border-left: 1px solid var(--color-error-border);
|
||||
border-right: 1px solid var(--color-error-border);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isWarning.top,
|
||||
.repository .ui.attached.isSigned.isWarning.message {
|
||||
border-top: 1px solid var(--color-error-border);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isWarning.message {
|
||||
box-shadow: none;
|
||||
background-color: var(--color-error-bg);
|
||||
color: var(--color-error-text);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isWarning.message .ui.text {
|
||||
color: var(--color-error-text);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isWarning:last-child,
|
||||
.repository .ui.attached.isSigned.isWarning.bottom {
|
||||
border-bottom: 1px solid var(--color-error-border);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isVerified {
|
||||
border-left: 1px solid var(--color-success-border);
|
||||
border-right: 1px solid var(--color-success-border);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isVerified.top,
|
||||
.repository .ui.attached.isSigned.isVerified.message {
|
||||
border-top: 1px solid var(--color-success-border);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isVerified.message {
|
||||
box-shadow: none;
|
||||
background-color: var(--color-success-bg);
|
||||
color: var(--color-success-text);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isVerified.message .pull-right {
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isVerified.message .ui.text {
|
||||
color: var(--color-success-text);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isVerified:last-child,
|
||||
.repository .ui.attached.isSigned.isVerified.bottom {
|
||||
border-bottom: 1px solid var(--color-success-border);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isVerifiedUntrusted,
|
||||
.repository .ui.attached.isSigned.isVerifiedUnmatched {
|
||||
border-left: 1px solid var(--color-warning-border);
|
||||
border-right: 1px solid var(--color-warning-border);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isVerifiedUntrusted.top,
|
||||
.repository .ui.attached.isSigned.isVerifiedUnmatched.top,
|
||||
.repository .ui.attached.isSigned.isVerifiedUntrusted.message,
|
||||
.repository .ui.attached.isSigned.isVerifiedUnmatched.message {
|
||||
border-top: 1px solid var(--color-warning-border);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isVerifiedUntrusted.message,
|
||||
.repository .ui.attached.isSigned.isVerifiedUnmatched.message {
|
||||
box-shadow: none;
|
||||
background-color: var(--color-warning-bg);
|
||||
color: var(--color-warning-text);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isVerifiedUntrusted.message .ui.text,
|
||||
.repository .ui.attached.isSigned.isVerifiedUnmatched.message .ui.text {
|
||||
color: var(--color-warning-text);
|
||||
}
|
||||
|
||||
.repository .ui.attached.isSigned.isVerifiedUntrusted:last-child,
|
||||
.repository .ui.attached.isSigned.isVerifiedUnmatched:last-child,
|
||||
.repository .ui.attached.isSigned.isVerifiedUntrusted.bottom,
|
||||
.repository .ui.attached.isSigned.isVerifiedUnmatched.bottom {
|
||||
border-bottom: 1px solid var(--color-warning-border);
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label,
|
||||
.repository #repo-files-table .sha.label,
|
||||
.repository #repo-file-commit-box .sha.label,
|
||||
.repository #rev-list .sha.label,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label {
|
||||
border: 1px solid var(--color-light-border);
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label .detail.icon,
|
||||
.repository #repo-files-table .sha.label .detail.icon,
|
||||
.repository #repo-file-commit-box .sha.label .detail.icon,
|
||||
.repository #rev-list .sha.label .detail.icon,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label .detail.icon {
|
||||
background: var(--color-light);
|
||||
margin: -6px -10px -4px 0;
|
||||
padding: 5px 4px 5px 6px;
|
||||
border-left: 1px solid var(--color-light-border);
|
||||
border-top: 0;
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label .detail.icon .svg,
|
||||
.repository #repo-files-table .sha.label .detail.icon .svg,
|
||||
.repository #repo-file-commit-box .sha.label .detail.icon .svg,
|
||||
.repository #rev-list .sha.label .detail.icon .svg,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label .detail.icon .svg {
|
||||
margin: 0 0.25em 0 0;
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label .detail.icon > div,
|
||||
.repository #repo-files-table .sha.label .detail.icon > div,
|
||||
.repository #repo-file-commit-box .sha.label .detail.icon > div,
|
||||
.repository #rev-list .sha.label .detail.icon > div,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label .detail.icon > div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label.isSigned.isWarning,
|
||||
.repository #repo-files-table .sha.label.isSigned.isWarning,
|
||||
.repository #repo-file-commit-box .sha.label.isSigned.isWarning,
|
||||
.repository #rev-list .sha.label.isSigned.isWarning,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label.isSigned.isWarning {
|
||||
border: 1px solid var(--color-red-badge);
|
||||
background: var(--color-red-badge-bg);
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label.isSigned.isWarning .detail.icon,
|
||||
.repository #repo-files-table .sha.label.isSigned.isWarning .detail.icon,
|
||||
.repository #repo-file-commit-box .sha.label.isSigned.isWarning .detail.icon,
|
||||
.repository #rev-list .sha.label.isSigned.isWarning .detail.icon,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label.isSigned.isWarning .detail.icon {
|
||||
border-left: 1px solid var(--color-red-badge);
|
||||
color: var(--color-red-badge);
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label.isSigned.isWarning:hover,
|
||||
.repository #repo-files-table .sha.label.isSigned.isWarning:hover,
|
||||
.repository #repo-file-commit-box .sha.label.isSigned.isWarning:hover,
|
||||
.repository #rev-list .sha.label.isSigned.isWarning:hover,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label.isSigned.isWarning:hover {
|
||||
background: var(--color-red-badge-hover-bg) !important;
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label.isSigned.isVerified,
|
||||
.repository #repo-files-table .sha.label.isSigned.isVerified,
|
||||
.repository #repo-file-commit-box .sha.label.isSigned.isVerified,
|
||||
.repository #rev-list .sha.label.isSigned.isVerified,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label.isSigned.isVerified {
|
||||
border: 1px solid var(--color-green-badge);
|
||||
background: var(--color-green-badge-bg);
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label.isSigned.isVerified .detail.icon,
|
||||
.repository #repo-files-table .sha.label.isSigned.isVerified .detail.icon,
|
||||
.repository #repo-file-commit-box .sha.label.isSigned.isVerified .detail.icon,
|
||||
.repository #rev-list .sha.label.isSigned.isVerified .detail.icon,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label.isSigned.isVerified .detail.icon {
|
||||
border-left: 1px solid var(--color-green-badge);
|
||||
color: var(--color-green-badge);
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label.isSigned.isVerified:hover,
|
||||
.repository #repo-files-table .sha.label.isSigned.isVerified:hover,
|
||||
.repository #repo-file-commit-box .sha.label.isSigned.isVerified:hover,
|
||||
.repository #rev-list .sha.label.isSigned.isVerified:hover,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label.isSigned.isVerified:hover {
|
||||
background: var(--color-green-badge-hover-bg) !important;
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label.isSigned.isVerifiedUntrusted,
|
||||
.repository #repo-files-table .sha.label.isSigned.isVerifiedUntrusted,
|
||||
.repository #repo-file-commit-box .sha.label.isSigned.isVerifiedUntrusted,
|
||||
.repository #rev-list .sha.label.isSigned.isVerifiedUntrusted,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label.isSigned.isVerifiedUntrusted {
|
||||
border: 1px solid var(--color-yellow-badge);
|
||||
background: var(--color-yellow-badge-bg);
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label.isSigned.isVerifiedUntrusted .detail.icon,
|
||||
.repository #repo-files-table .sha.label.isSigned.isVerifiedUntrusted .detail.icon,
|
||||
.repository #repo-file-commit-box .sha.label.isSigned.isVerifiedUntrusted .detail.icon,
|
||||
.repository #rev-list .sha.label.isSigned.isVerifiedUntrusted .detail.icon,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label.isSigned.isVerifiedUntrusted .detail.icon {
|
||||
border-left: 1px solid var(--color-yellow-badge);
|
||||
color: var(--color-yellow-badge);
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label.isSigned.isVerifiedUntrusted:hover,
|
||||
.repository #repo-files-table .sha.label.isSigned.isVerifiedUntrusted:hover,
|
||||
.repository #repo-file-commit-box .sha.label.isSigned.isVerifiedUntrusted:hover,
|
||||
.repository #rev-list .sha.label.isSigned.isVerifiedUntrusted:hover,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label.isSigned.isVerifiedUntrusted:hover {
|
||||
background: var(--color-yellow-badge-hover-bg) !important;
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label.isSigned.isVerifiedUnmatched,
|
||||
.repository #repo-files-table .sha.label.isSigned.isVerifiedUnmatched,
|
||||
.repository #repo-file-commit-box .sha.label.isSigned.isVerifiedUnmatched,
|
||||
.repository #rev-list .sha.label.isSigned.isVerifiedUnmatched,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label.isSigned.isVerifiedUnmatched {
|
||||
border: 1px solid var(--color-orange-badge);
|
||||
background: var(--color-orange-badge-bg);
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label.isSigned.isVerifiedUnmatched .detail.icon,
|
||||
.repository #repo-files-table .sha.label.isSigned.isVerifiedUnmatched .detail.icon,
|
||||
.repository #repo-file-commit-box .sha.label.isSigned.isVerifiedUnmatched .detail.icon,
|
||||
.repository #rev-list .sha.label.isSigned.isVerifiedUnmatched .detail.icon,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label.isSigned.isVerifiedUnmatched .detail.icon {
|
||||
border-left: 1px solid var(--color-orange-badge);
|
||||
color: var(--color-orange-badge);
|
||||
}
|
||||
|
||||
.repository #commits-table td.sha .sha.label.isSigned.isVerifiedUnmatched:hover,
|
||||
.repository #repo-files-table .sha.label.isSigned.isVerifiedUnmatched:hover,
|
||||
.repository #repo-file-commit-box .sha.label.isSigned.isVerifiedUnmatched:hover,
|
||||
.repository #rev-list .sha.label.isSigned.isVerifiedUnmatched:hover,
|
||||
.repository .timeline-item.commits-list .singular-commit .sha.label.isSigned.isVerifiedUnmatched:hover {
|
||||
background: var(--color-orange-badge-hover-bg) !important;
|
||||
}
|
||||
|
||||
.singular-commit .shabox .sha.label {
|
||||
margin: 0;
|
||||
border: 1px solid var(--color-light-border);
|
||||
}
|
||||
|
||||
.singular-commit .shabox .sha.label.isSigned.isWarning {
|
||||
border: 1px solid var(--color-red-badge);
|
||||
background: var(--color-red-badge-bg);
|
||||
}
|
||||
|
||||
.singular-commit .shabox .sha.label.isSigned.isWarning:hover {
|
||||
background: var(--color-red-badge-hover-bg) !important;
|
||||
}
|
||||
|
||||
.singular-commit .shabox .sha.label.isSigned.isVerified {
|
||||
border: 1px solid var(--color-green-badge);
|
||||
background: var(--color-green-badge-bg);
|
||||
}
|
||||
|
||||
.singular-commit .shabox .sha.label.isSigned.isVerified:hover {
|
||||
background: var(--color-green-badge-hover-bg) !important;
|
||||
}
|
||||
|
||||
.singular-commit .shabox .sha.label.isSigned.isVerifiedUntrusted {
|
||||
border: 1px solid var(--color-yellow-badge);
|
||||
background: var(--color-yellow-badge-bg);
|
||||
}
|
||||
|
||||
.singular-commit .shabox .sha.label.isSigned.isVerifiedUntrusted:hover {
|
||||
background: var(--color-yellow-badge-hover-bg) !important;
|
||||
}
|
||||
|
||||
.singular-commit .shabox .sha.label.isSigned.isVerifiedUnmatched {
|
||||
border: 1px solid var(--color-orange-badge);
|
||||
background: var(--color-orange-badge-bg);
|
||||
}
|
||||
|
||||
.singular-commit .shabox .sha.label.isSigned.isVerifiedUnmatched:hover {
|
||||
background: var(--color-orange-badge-hover-bg) !important;
|
||||
}
|
70
web_src/css/repo/home-file-list.css
Normal file
70
web_src/css/repo/home-file-list.css
Normal file
@ -0,0 +1,70 @@
|
||||
#repo-files-table {
|
||||
width: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
border: 1px solid var(--color-light-border);
|
||||
border-radius: var(--border-radius);
|
||||
margin: 10px 0; /* match the "clone-panel-popup" margin to avoid "visual double-border" */
|
||||
}
|
||||
|
||||
#repo-files-table .svg.octicon-file-directory-fill,
|
||||
#repo-files-table .svg.octicon-file-submodule {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
#repo-files-table .svg.octicon-file,
|
||||
#repo-files-table .svg.octicon-file-symlink-file,
|
||||
#repo-files-table .svg.octicon-file-directory-symlink {
|
||||
color: var(--color-secondary-dark-7);
|
||||
}
|
||||
|
||||
#repo-files-table .repo-file-item {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
#repo-files-table .repo-file-item:hover > .repo-file-cell {
|
||||
background: var(--color-hover);
|
||||
}
|
||||
|
||||
#repo-files-table .repo-file-line,
|
||||
#repo-files-table .repo-file-cell {
|
||||
border-top: 1px solid var(--color-light-border);
|
||||
padding: 6px 10px;
|
||||
}
|
||||
|
||||
#repo-files-table .repo-file-line:first-child {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
#repo-files-table .repo-file-line {
|
||||
grid-column: 1 / span 3;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5em;
|
||||
padding: 6px 10px;
|
||||
}
|
||||
|
||||
#repo-files-table .repo-file-cell.name {
|
||||
max-width: 300px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
#repo-files-table .repo-file-cell.message {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: var(--color-text-light-1);
|
||||
}
|
||||
|
||||
#repo-files-table .repo-file-cell.age {
|
||||
white-space: nowrap;
|
||||
color: var(--color-text-light-1);
|
||||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
#repo-files-table .repo-file-cell.name {
|
||||
max-width: 150px;
|
||||
}
|
||||
}
|
@ -59,9 +59,6 @@
|
||||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
.repository.wiki .clone-panel #repo-clone-url {
|
||||
width: 160px;
|
||||
}
|
||||
.repository.wiki .wiki-content-main.with-sidebar,
|
||||
.repository.wiki .wiki-content-sidebar {
|
||||
float: none;
|
||||
|
@ -11,7 +11,7 @@ function initRepoCreateBranchButton() {
|
||||
for (const el of document.querySelectorAll('.show-create-branch-modal')) {
|
||||
el.addEventListener('click', () => {
|
||||
const modalFormName = el.getAttribute('data-modal-form') || '#create-branch-form';
|
||||
const modalForm = document.querySelector(modalFormName);
|
||||
const modalForm = document.querySelector<HTMLFormElement>(modalFormName);
|
||||
if (!modalForm) return;
|
||||
modalForm.action = `${modalForm.getAttribute('data-base-action')}${el.getAttribute('data-branch-from-urlcomponent')}`;
|
||||
|
||||
@ -29,7 +29,7 @@ function initRepoRenameBranchButton() {
|
||||
const target = el.getAttribute('data-modal');
|
||||
const modal = document.querySelector(target);
|
||||
const oldBranchName = el.getAttribute('data-old-branch-name');
|
||||
modal.querySelector('input[name=from]').value = oldBranchName;
|
||||
modal.querySelector<HTMLInputElement>('input[name=from]').value = oldBranchName;
|
||||
|
||||
// display the warning that the branch which is chosen is the default branch
|
||||
const warn = modal.querySelector('.default-branch-warning');
|
||||
|
@ -8,7 +8,7 @@ import {toAbsoluteUrl} from '../utils.ts';
|
||||
export const singleAnchorRegex = /^#(L|n)([1-9][0-9]*)$/;
|
||||
export const rangeAnchorRegex = /^#(L[1-9][0-9]*)-(L[1-9][0-9]*)$/;
|
||||
|
||||
function changeHash(hash) {
|
||||
function changeHash(hash: string) {
|
||||
if (window.history.pushState) {
|
||||
window.history.pushState(null, null, hash);
|
||||
} else {
|
||||
@ -24,7 +24,7 @@ function getLineEls() {
|
||||
return document.querySelectorAll(`.code-view td.lines-code${isBlame() ? '.blame-code' : ''}`);
|
||||
}
|
||||
|
||||
function selectRange($linesEls, $selectionEndEl, $selectionStartEls) {
|
||||
function selectRange($linesEls, $selectionEndEl, $selectionStartEls?) {
|
||||
for (const el of $linesEls) {
|
||||
el.closest('tr').classList.remove('active');
|
||||
}
|
||||
@ -34,7 +34,7 @@ function selectRange($linesEls, $selectionEndEl, $selectionStartEls) {
|
||||
const copyPermalink = document.querySelector('a.copy-line-permalink');
|
||||
const viewGitBlame = document.querySelector('a.view_git_blame');
|
||||
|
||||
const updateIssueHref = function (anchor) {
|
||||
const updateIssueHref = function (anchor: string) {
|
||||
if (!refInNewIssue) return;
|
||||
const urlIssueNew = refInNewIssue.getAttribute('data-url-issue-new');
|
||||
const urlParamBodyLink = refInNewIssue.getAttribute('data-url-param-body-link');
|
||||
@ -42,7 +42,7 @@ function selectRange($linesEls, $selectionEndEl, $selectionStartEls) {
|
||||
refInNewIssue.setAttribute('href', `${urlIssueNew}?body=${encodeURIComponent(issueContent)}`);
|
||||
};
|
||||
|
||||
const updateViewGitBlameFragment = function (anchor) {
|
||||
const updateViewGitBlameFragment = function (anchor: string) {
|
||||
if (!viewGitBlame) return;
|
||||
let href = viewGitBlame.getAttribute('href');
|
||||
href = `${href.replace(/#L\d+$|#L\d+-L\d+$/, '')}`;
|
||||
@ -52,7 +52,7 @@ function selectRange($linesEls, $selectionEndEl, $selectionStartEls) {
|
||||
viewGitBlame.setAttribute('href', href);
|
||||
};
|
||||
|
||||
const updateCopyPermalinkUrl = function (anchor) {
|
||||
const updateCopyPermalinkUrl = function (anchor: string) {
|
||||
if (!copyPermalink) return;
|
||||
let link = copyPermalink.getAttribute('data-url');
|
||||
link = `${link.replace(/#L\d+$|#L\d+-L\d+$/, '')}#${anchor}`;
|
||||
@ -142,13 +142,7 @@ export function initRepoCodeView() {
|
||||
});
|
||||
}
|
||||
selectRange($(linesEls), $(selectedEls), from ? $(from) : null);
|
||||
|
||||
if (window.getSelection) {
|
||||
window.getSelection().removeAllRanges();
|
||||
} else {
|
||||
document.selection.empty();
|
||||
}
|
||||
|
||||
showLineButton();
|
||||
});
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
import $ from 'jquery';
|
||||
import {hideElem, queryElems, showElem} from '../utils/dom.ts';
|
||||
import {queryElems} from '../utils/dom.ts';
|
||||
import {POST} from '../modules/fetch.ts';
|
||||
import {showErrorToast} from '../modules/toast.ts';
|
||||
import {sleep} from '../utils.ts';
|
||||
import RepoActivityTopAuthors from '../components/RepoActivityTopAuthors.vue';
|
||||
import {createApp} from 'vue';
|
||||
import {toOriginUrl} from '../utils/url.ts';
|
||||
import {createTippy} from '../modules/tippy.ts';
|
||||
|
||||
async function onDownloadArchive(e) {
|
||||
e.preventDefault();
|
||||
@ -41,54 +42,69 @@ export function initRepoActivityTopAuthorsChart() {
|
||||
}
|
||||
}
|
||||
|
||||
export function initRepoCloneLink() {
|
||||
const $repoCloneSsh = $('#repo-clone-ssh');
|
||||
const $repoCloneHttps = $('#repo-clone-https');
|
||||
const $inputLink = $('#repo-clone-url');
|
||||
function initCloneSchemeUrlSelection(parent: Element) {
|
||||
const elCloneUrlInput = parent.querySelector<HTMLInputElement>('.repo-clone-url');
|
||||
|
||||
if ((!$repoCloneSsh.length && !$repoCloneHttps.length) || !$inputLink.length) {
|
||||
return;
|
||||
const tabSsh = parent.querySelector('.repo-clone-ssh');
|
||||
const tabHttps = parent.querySelector('.repo-clone-https');
|
||||
const updateClonePanelUi = function() {
|
||||
const scheme = localStorage.getItem('repo-clone-protocol') || 'https';
|
||||
const isSSH = scheme === 'ssh' && Boolean(tabSsh) || scheme !== 'ssh' && !tabHttps;
|
||||
if (tabHttps) {
|
||||
tabHttps.textContent = window.origin.split(':')[0].toUpperCase(); // show "HTTP" or "HTTPS"
|
||||
tabHttps.classList.toggle('active', !isSSH);
|
||||
}
|
||||
if (tabSsh) {
|
||||
tabSsh.classList.toggle('active', isSSH);
|
||||
}
|
||||
|
||||
$repoCloneSsh.on('click', () => {
|
||||
const tab = isSSH ? tabSsh : tabHttps;
|
||||
if (!tab) return;
|
||||
const link = toOriginUrl(tab.getAttribute('data-link'));
|
||||
|
||||
for (const el of document.querySelectorAll('.js-clone-url')) {
|
||||
if (el.nodeName === 'INPUT') {
|
||||
(el as HTMLInputElement).value = link;
|
||||
} else {
|
||||
el.textContent = link;
|
||||
}
|
||||
}
|
||||
for (const el of parent.querySelectorAll<HTMLAnchorElement>('.js-clone-url-editor')) {
|
||||
el.href = el.getAttribute('data-href-template').replace('{url}', encodeURIComponent(link));
|
||||
}
|
||||
};
|
||||
|
||||
updateClonePanelUi();
|
||||
|
||||
tabSsh.addEventListener('click', () => {
|
||||
localStorage.setItem('repo-clone-protocol', 'ssh');
|
||||
window.updateCloneStates();
|
||||
updateClonePanelUi();
|
||||
});
|
||||
$repoCloneHttps.on('click', () => {
|
||||
tabHttps.addEventListener('click', () => {
|
||||
localStorage.setItem('repo-clone-protocol', 'https');
|
||||
window.updateCloneStates();
|
||||
updateClonePanelUi();
|
||||
});
|
||||
|
||||
$inputLink.on('focus', () => {
|
||||
$inputLink.trigger('select');
|
||||
elCloneUrlInput.addEventListener('focus', () => {
|
||||
elCloneUrlInput.select();
|
||||
});
|
||||
}
|
||||
|
||||
export function initRepoCommonBranchOrTagDropdown(selector) {
|
||||
$(selector).each(function () {
|
||||
const $dropdown = $(this);
|
||||
$dropdown.find('.reference.column').on('click', function () {
|
||||
hideElem($dropdown.find('.scrolling.reference-list-menu'));
|
||||
showElem($($(this).data('target')));
|
||||
return false;
|
||||
});
|
||||
function initClonePanelButton(btn: HTMLButtonElement) {
|
||||
const elPanel = btn.nextElementSibling;
|
||||
// "init" must be before the "createTippy" otherwise the "tippy-target" will be removed from the document
|
||||
initCloneSchemeUrlSelection(elPanel);
|
||||
createTippy(btn, {
|
||||
content: elPanel,
|
||||
trigger: 'click',
|
||||
placement: 'bottom-end',
|
||||
interactive: true,
|
||||
hideOnClick: true,
|
||||
});
|
||||
}
|
||||
|
||||
export function initRepoCommonFilterSearchDropdown(selector) {
|
||||
const $dropdown = $(selector);
|
||||
if (!$dropdown.length) return;
|
||||
|
||||
$dropdown.dropdown({
|
||||
fullTextSearch: 'exact',
|
||||
selectOnKeydown: false,
|
||||
onChange(_text, _value, $choice) {
|
||||
if ($choice[0].getAttribute('data-url')) {
|
||||
window.location.href = $choice[0].getAttribute('data-url');
|
||||
}
|
||||
},
|
||||
message: {noResults: $dropdown[0].getAttribute('data-no-results')},
|
||||
});
|
||||
export function initRepoCloneButtons() {
|
||||
queryElems(document, '.js-btn-clone-panel', initClonePanelButton);
|
||||
queryElems(document, '.clone-buttons-combo', initCloneSchemeUrlSelection);
|
||||
}
|
||||
|
||||
export async function updateIssuesMeta(url, action, issue_ids, id) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {hideElem, showElem, toggleElem} from '../utils/dom.ts';
|
||||
import {GET} from '../modules/fetch.ts';
|
||||
|
||||
async function loadBranchesAndTags(area, loadingButton) {
|
||||
async function loadBranchesAndTags(area: Element, loadingButton: Element) {
|
||||
loadingButton.classList.add('disabled');
|
||||
try {
|
||||
const res = await GET(loadingButton.getAttribute('data-fetch-url'));
|
||||
@ -15,7 +15,7 @@ async function loadBranchesAndTags(area, loadingButton) {
|
||||
}
|
||||
}
|
||||
|
||||
function addTags(area, tags) {
|
||||
function addTags(area: Element, tags: Array<Record<string, any>>) {
|
||||
const tagArea = area.querySelector('.tag-area');
|
||||
toggleElem(tagArea.parentElement, tags.length > 0);
|
||||
for (const tag of tags) {
|
||||
@ -23,7 +23,7 @@ function addTags(area, tags) {
|
||||
}
|
||||
}
|
||||
|
||||
function addBranches(area, branches, defaultBranch) {
|
||||
function addBranches(area: Element, branches: Array<Record<string, any>>, defaultBranch: string) {
|
||||
const defaultBranchTooltip = area.getAttribute('data-text-default-branch-tooltip');
|
||||
const branchArea = area.querySelector('.branch-area');
|
||||
toggleElem(branchArea.parentElement, branches.length > 0);
|
||||
@ -33,7 +33,7 @@ function addBranches(area, branches, defaultBranch) {
|
||||
}
|
||||
}
|
||||
|
||||
function addLink(parent, href, text, tooltip) {
|
||||
function addLink(parent: Element, href: string, text: string, tooltip?: string) {
|
||||
const link = document.createElement('a');
|
||||
link.classList.add('muted', 'tw-px-1');
|
||||
link.href = href;
|
||||
|
@ -22,7 +22,7 @@ export function initRepoGraphGit() {
|
||||
for (const link of document.querySelectorAll('.pagination a')) {
|
||||
const href = link.getAttribute('href');
|
||||
if (!href) continue;
|
||||
const url = new URL(href, window.location);
|
||||
const url = new URL(href, window.location.href);
|
||||
const params = url.searchParams;
|
||||
params.set('mode', 'monochrome');
|
||||
url.search = `?${params.toString()}`;
|
||||
@ -38,7 +38,7 @@ export function initRepoGraphGit() {
|
||||
for (const link of document.querySelectorAll('.pagination a')) {
|
||||
const href = link.getAttribute('href');
|
||||
if (!href) continue;
|
||||
const url = new URL(href, window.location);
|
||||
const url = new URL(href, window.location.href);
|
||||
const params = url.searchParams;
|
||||
params.delete('mode');
|
||||
url.search = `?${params.toString()}`;
|
||||
@ -53,7 +53,7 @@ export function initRepoGraphGit() {
|
||||
window.history.replaceState({}, '', window.location.pathname);
|
||||
}
|
||||
});
|
||||
const url = new URL(window.location);
|
||||
const url = new URL(window.location.href);
|
||||
const params = url.searchParams;
|
||||
const updateGraph = () => {
|
||||
const queryString = params.toString();
|
||||
@ -103,7 +103,7 @@ export function initRepoGraphGit() {
|
||||
},
|
||||
onAdd(toAdd) {
|
||||
if (toAdd === '...flow-hide-pr-refs') {
|
||||
params.set('hide-pr-refs', true);
|
||||
params.set('hide-pr-refs', 'true');
|
||||
} else {
|
||||
params.append('branch', toAdd);
|
||||
}
|
||||
@ -111,7 +111,7 @@ export function initRepoGraphGit() {
|
||||
},
|
||||
});
|
||||
|
||||
graphContainer.addEventListener('mouseenter', (e) => {
|
||||
graphContainer.addEventListener('mouseenter', (e: MouseEvent & {target: HTMLElement}) => {
|
||||
if (e.target.matches('#rev-list li')) {
|
||||
const flow = e.target.getAttribute('data-flow');
|
||||
if (flow === '0') return;
|
||||
@ -132,7 +132,7 @@ export function initRepoGraphGit() {
|
||||
}
|
||||
});
|
||||
|
||||
graphContainer.addEventListener('mouseleave', (e) => {
|
||||
graphContainer.addEventListener('mouseleave', (e: MouseEvent & {target: HTMLElement}) => {
|
||||
if (e.target.matches('#rev-list li')) {
|
||||
const flow = e.target.getAttribute('data-flow');
|
||||
if (flow === '0') return;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {stripTags} from '../utils.ts';
|
||||
import {hideElem, queryElemChildren, showElem} from '../utils/dom.ts';
|
||||
import {POST} from '../modules/fetch.ts';
|
||||
import {showErrorToast} from '../modules/toast.ts';
|
||||
import {showErrorToast, type Toast} from '../modules/toast.ts';
|
||||
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
||||
|
||||
const {appSubUrl} = window.config;
|
||||
@ -13,7 +13,7 @@ export function initRepoTopicBar() {
|
||||
const editDiv = document.querySelector('#topic_edit');
|
||||
const viewDiv = document.querySelector('#repo-topics');
|
||||
const topicDropdown = editDiv.querySelector('.ui.dropdown');
|
||||
let lastErrorToast;
|
||||
let lastErrorToast: Toast;
|
||||
|
||||
mgrBtn.addEventListener('click', () => {
|
||||
hideElem(viewDiv);
|
||||
|
@ -1,7 +1,7 @@
|
||||
export function initRepoPullRequestCommitStatus() {
|
||||
for (const btn of document.querySelectorAll('.commit-status-hide-checks')) {
|
||||
const panel = btn.closest('.commit-status-panel');
|
||||
const list = panel.querySelector('.commit-status-list');
|
||||
const list = panel.querySelector<HTMLElement>('.commit-status-list');
|
||||
btn.addEventListener('click', () => {
|
||||
list.style.maxHeight = list.style.maxHeight ? '' : '0px'; // toggle
|
||||
btn.textContent = btn.getAttribute(list.style.maxHeight ? 'data-show-all' : 'data-hide-all');
|
||||
|
@ -124,7 +124,7 @@ export function initRepoIssueFilterItemLabel() {
|
||||
|
||||
export function initRepoIssueCommentDelete() {
|
||||
// Delete comment
|
||||
document.addEventListener('click', async (e) => {
|
||||
document.addEventListener('click', async (e: MouseEvent & {target: HTMLElement}) => {
|
||||
if (!e.target.matches('.delete-comment')) return;
|
||||
e.preventDefault();
|
||||
|
||||
@ -143,7 +143,7 @@ export function initRepoIssueCommentDelete() {
|
||||
const counter = document.querySelector('#review-box .review-comments-counter');
|
||||
let num = parseInt(counter?.getAttribute('data-pending-comment-number')) - 1 || 0;
|
||||
num = Math.max(num, 0);
|
||||
counter.setAttribute('data-pending-comment-number', num);
|
||||
counter.setAttribute('data-pending-comment-number', String(num));
|
||||
counter.textContent = String(num);
|
||||
}
|
||||
|
||||
@ -199,7 +199,7 @@ export function initRepoIssueDependencyDelete() {
|
||||
|
||||
export function initRepoIssueCodeCommentCancel() {
|
||||
// Cancel inline code comment
|
||||
document.addEventListener('click', (e) => {
|
||||
document.addEventListener('click', (e: MouseEvent & {target: HTMLElement}) => {
|
||||
if (!e.target.matches('.cancel-code-comment')) return;
|
||||
|
||||
const form = e.target.closest('form');
|
||||
@ -268,12 +268,14 @@ export function initRepoPullRequestMergeInstruction() {
|
||||
export function initRepoPullRequestAllowMaintainerEdit() {
|
||||
const wrapper = document.querySelector('#allow-edits-from-maintainers');
|
||||
if (!wrapper) return;
|
||||
const checkbox = wrapper.querySelector('input[type="checkbox"]');
|
||||
const checkbox = wrapper.querySelector<HTMLInputElement>('input[type="checkbox"]');
|
||||
checkbox.addEventListener('input', async () => {
|
||||
const url = `${wrapper.getAttribute('data-url')}/set_allow_maintainer_edit`;
|
||||
wrapper.classList.add('is-loading');
|
||||
try {
|
||||
const resp = await POST(url, {data: new URLSearchParams({allow_maintainer_edit: checkbox.checked})});
|
||||
const resp = await POST(url, {data: new URLSearchParams({
|
||||
allow_maintainer_edit: String(checkbox.checked),
|
||||
})});
|
||||
if (!resp.ok) {
|
||||
throw new Error('Failed to update maintainer edit permission');
|
||||
}
|
||||
@ -322,7 +324,7 @@ export function initRepoIssueWipTitle() {
|
||||
|
||||
const $issueTitle = $('#issue_title');
|
||||
$issueTitle.trigger('focus');
|
||||
const value = $issueTitle.val().trim().toUpperCase();
|
||||
const value = ($issueTitle.val() as string).trim().toUpperCase();
|
||||
|
||||
const wipPrefixes = $('.title_wip_desc').data('wip-prefixes');
|
||||
for (const prefix of wipPrefixes) {
|
||||
@ -338,7 +340,7 @@ export function initRepoIssueWipTitle() {
|
||||
export function initRepoIssueComments() {
|
||||
if (!$('.repository.view.issue .timeline').length) return;
|
||||
|
||||
document.addEventListener('click', (e) => {
|
||||
document.addEventListener('click', (e: MouseEvent & {target: HTMLElement}) => {
|
||||
const urlTarget = document.querySelector(':target');
|
||||
if (!urlTarget) return;
|
||||
|
||||
@ -490,7 +492,7 @@ export function initRepoPullRequestReview() {
|
||||
|
||||
export function initRepoIssueReferenceIssue() {
|
||||
// Reference issue
|
||||
$(document).on('click', '.reference-issue', function (event) {
|
||||
$(document).on('click', '.reference-issue', function (e) {
|
||||
const target = this.getAttribute('data-target');
|
||||
const content = document.querySelector(`#${target}`)?.textContent ?? '';
|
||||
const poster = this.getAttribute('data-poster-username');
|
||||
@ -500,7 +502,7 @@ export function initRepoIssueReferenceIssue() {
|
||||
const textarea = modal.querySelector('textarea[name="content"]');
|
||||
textarea.value = `${content}\n\n_Originally posted by @${poster} in ${reference}_`;
|
||||
$(modal).modal('show');
|
||||
event.preventDefault();
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
|
||||
@ -584,7 +586,7 @@ export function initRepoIssueTitleEdit() {
|
||||
}
|
||||
|
||||
export function initRepoIssueBranchSelect() {
|
||||
document.querySelector('#branch-select')?.addEventListener('click', (e) => {
|
||||
document.querySelector('#branch-select')?.addEventListener('click', (e: MouseEvent & {target: HTMLElement}) => {
|
||||
const el = e.target.closest('.item[data-branch]');
|
||||
if (!el) return;
|
||||
const pullTargetBranch = document.querySelector('#pull-target-branch');
|
||||
|
@ -8,9 +8,7 @@ import {
|
||||
} from './repo-issue.ts';
|
||||
import {initUnicodeEscapeButton} from './repo-unicode-escape.ts';
|
||||
import {initRepoBranchTagSelector} from '../components/RepoBranchTagSelector.vue';
|
||||
import {
|
||||
initRepoCloneLink, initRepoCommonBranchOrTagDropdown, initRepoCommonFilterSearchDropdown,
|
||||
} from './repo-common.ts';
|
||||
import {initRepoCloneButtons} from './repo-common.ts';
|
||||
import {initCitationFileCopyContent} from './citation.ts';
|
||||
import {initCompLabelEdit} from './comp/LabelEdit.ts';
|
||||
import {initRepoDiffConversationNav} from './repo-diff.ts';
|
||||
@ -36,6 +34,33 @@ export function initBranchSelectorTabs() {
|
||||
});
|
||||
}
|
||||
|
||||
function initRepoCommonBranchOrTagDropdown(selector: string) {
|
||||
$(selector).each(function () {
|
||||
const $dropdown = $(this);
|
||||
$dropdown.find('.reference.column').on('click', function () {
|
||||
hideElem($dropdown.find('.scrolling.reference-list-menu'));
|
||||
showElem($($(this).data('target')));
|
||||
return false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function initRepoCommonFilterSearchDropdown(selector: string) {
|
||||
const $dropdown = $(selector);
|
||||
if (!$dropdown.length) return;
|
||||
|
||||
$dropdown.dropdown({
|
||||
fullTextSearch: 'exact',
|
||||
selectOnKeydown: false,
|
||||
onChange(_text, _value, $choice) {
|
||||
if ($choice[0].getAttribute('data-url')) {
|
||||
window.location.href = $choice[0].getAttribute('data-url');
|
||||
}
|
||||
},
|
||||
message: {noResults: $dropdown[0].getAttribute('data-no-results')},
|
||||
});
|
||||
}
|
||||
|
||||
export function initRepository() {
|
||||
if (!$('.page-content.repository').length) return;
|
||||
|
||||
@ -54,7 +79,7 @@ export function initRepository() {
|
||||
initRepoCommonFilterSearchDropdown('.choose.branch .dropdown');
|
||||
}
|
||||
|
||||
initRepoCloneLink();
|
||||
initRepoCloneButtons();
|
||||
initCitationFileCopyContent();
|
||||
initRepoSettings();
|
||||
|
||||
|
@ -1,14 +1,14 @@
|
||||
import {hideElem, showElem, toggleElem} from '../utils/dom.ts';
|
||||
|
||||
const service = document.querySelector('#service_type');
|
||||
const user = document.querySelector('#auth_username');
|
||||
const pass = document.querySelector('#auth_password');
|
||||
const token = document.querySelector('#auth_token');
|
||||
const mirror = document.querySelector('#mirror');
|
||||
const lfs = document.querySelector('#lfs');
|
||||
const lfsSettings = document.querySelector('#lfs_settings');
|
||||
const lfsEndpoint = document.querySelector('#lfs_endpoint');
|
||||
const items = document.querySelectorAll('#migrate_items input[type=checkbox]');
|
||||
const service = document.querySelector<HTMLInputElement>('#service_type');
|
||||
const user = document.querySelector<HTMLInputElement>('#auth_username');
|
||||
const pass = document.querySelector<HTMLInputElement>('#auth_password');
|
||||
const token = document.querySelector<HTMLInputElement>('#auth_token');
|
||||
const mirror = document.querySelector<HTMLInputElement>('#mirror');
|
||||
const lfs = document.querySelector<HTMLInputElement>('#lfs');
|
||||
const lfsSettings = document.querySelector<HTMLElement>('#lfs_settings');
|
||||
const lfsEndpoint = document.querySelector<HTMLElement>('#lfs_endpoint');
|
||||
const items = document.querySelectorAll<HTMLInputElement>('#migrate_items input[type=checkbox]');
|
||||
|
||||
export function initRepoMigration() {
|
||||
checkAuth();
|
||||
@ -25,11 +25,11 @@ export function initRepoMigration() {
|
||||
});
|
||||
lfs?.addEventListener('change', setLFSSettingsVisibility);
|
||||
|
||||
const cloneAddr = document.querySelector('#clone_addr');
|
||||
const cloneAddr = document.querySelector<HTMLInputElement>('#clone_addr');
|
||||
cloneAddr?.addEventListener('change', () => {
|
||||
const repoName = document.querySelector('#repo_name');
|
||||
const repoName = document.querySelector<HTMLInputElement>('#repo_name');
|
||||
if (cloneAddr.value && !repoName?.value) { // Only modify if repo_name input is blank
|
||||
repoName.value = cloneAddr.value.match(/^(.*\/)?((.+?)(\.git)?)$/)[3];
|
||||
repoName.value = /^(.*\/)?((.+?)(\.git)?)$/.exec(cloneAddr.value)[3];
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -41,8 +41,8 @@ function checkAuth() {
|
||||
checkItems(serviceType !== 1);
|
||||
}
|
||||
|
||||
function checkItems(tokenAuth) {
|
||||
let enableItems;
|
||||
function checkItems(tokenAuth: boolean) {
|
||||
let enableItems = false;
|
||||
if (tokenAuth) {
|
||||
enableItems = token?.value !== '';
|
||||
} else {
|
||||
|
@ -7,7 +7,7 @@ export function initRepoNew() {
|
||||
const gitignores = $('input[name="gitignores"]').val();
|
||||
const license = $('input[name="license"]').val();
|
||||
if (gitignores || license) {
|
||||
document.querySelector('input[name="auto_init"]').checked = true;
|
||||
document.querySelector<HTMLInputElement>('input[name="auto_init"]').checked = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ async function createNewColumn(url, columnTitle, projectColorInput) {
|
||||
}
|
||||
}
|
||||
|
||||
async function moveIssue({item, from, to, oldIndex}) {
|
||||
async function moveIssue({item, from, to, oldIndex}: {item: HTMLElement, from: HTMLElement, to: HTMLElement, oldIndex: number}) {
|
||||
const columnCards = to.querySelectorAll('.issue-card');
|
||||
updateIssueCount(from);
|
||||
updateIssueCount(to);
|
||||
@ -97,14 +97,14 @@ export function initRepoProject() {
|
||||
return;
|
||||
}
|
||||
|
||||
const _promise = initRepoProjectSortable();
|
||||
initRepoProjectSortable(); // no await
|
||||
|
||||
for (const modal of document.querySelectorAll('.edit-project-column-modal')) {
|
||||
const projectHeader = modal.closest('.project-column-header');
|
||||
const projectTitleLabel = projectHeader?.querySelector('.project-column-title-label');
|
||||
const projectTitleInput = modal.querySelector('.project-column-title-input');
|
||||
const projectColorInput = modal.querySelector('#new_project_column_color');
|
||||
const boardColumn = modal.closest('.project-column');
|
||||
const projectHeader = modal.closest<HTMLElement>('.project-column-header');
|
||||
const projectTitleLabel = projectHeader?.querySelector<HTMLElement>('.project-column-title-label');
|
||||
const projectTitleInput = modal.querySelector<HTMLInputElement>('.project-column-title-input');
|
||||
const projectColorInput = modal.querySelector<HTMLInputElement>('#new_project_column_color');
|
||||
const boardColumn = modal.closest<HTMLElement>('.project-column');
|
||||
modal.querySelector('.edit-project-column-button')?.addEventListener('click', async function (e) {
|
||||
e.preventDefault();
|
||||
try {
|
||||
@ -119,7 +119,7 @@ export function initRepoProject() {
|
||||
} finally {
|
||||
projectTitleLabel.textContent = projectTitleInput?.value;
|
||||
projectTitleInput.closest('form')?.classList.remove('dirty');
|
||||
const dividers = boardColumn.querySelectorAll(':scope > .divider');
|
||||
const dividers = boardColumn.querySelectorAll<HTMLElement>(':scope > .divider');
|
||||
if (projectColorInput.value) {
|
||||
const color = contrastColor(projectColorInput.value);
|
||||
boardColumn.style.setProperty('background', projectColorInput.value, 'important');
|
||||
|
@ -1,11 +1,11 @@
|
||||
import {hideElem, showElem} from '../utils/dom.ts';
|
||||
|
||||
export function initRepoRelease() {
|
||||
document.addEventListener('click', (e) => {
|
||||
document.addEventListener('click', (e: MouseEvent & {target: HTMLElement}) => {
|
||||
if (e.target.matches('.remove-rel-attach')) {
|
||||
const uuid = e.target.getAttribute('data-uuid');
|
||||
const id = e.target.getAttribute('data-id');
|
||||
document.querySelector(`input[name='attachment-del-${uuid}']`).value = 'true';
|
||||
document.querySelector<HTMLInputElement>(`input[name='attachment-del-${uuid}']`).value = 'true';
|
||||
hideElem(`#attachment-${id}`);
|
||||
}
|
||||
});
|
||||
@ -28,8 +28,8 @@ function initTagNameEditor() {
|
||||
const newTagHelperText = el.getAttribute('data-tag-helper-new');
|
||||
const existingTagHelperText = el.getAttribute('data-tag-helper-existing');
|
||||
|
||||
const tagNameInput = document.querySelector('#tag-name');
|
||||
const hideTargetInput = function(tagNameInput) {
|
||||
const tagNameInput = document.querySelector<HTMLInputElement>('#tag-name');
|
||||
const hideTargetInput = function(tagNameInput: HTMLInputElement) {
|
||||
const value = tagNameInput.value;
|
||||
const tagHelper = document.querySelector('#tag-helper');
|
||||
if (existingTags.includes(value)) {
|
||||
@ -42,7 +42,7 @@ function initTagNameEditor() {
|
||||
}
|
||||
};
|
||||
hideTargetInput(tagNameInput); // update on page load because the input may have a value
|
||||
tagNameInput.addEventListener('input', (e) => {
|
||||
tagNameInput.addEventListener('input', (e: InputEvent & {target: HTMLInputElement}) => {
|
||||
hideTargetInput(e.target);
|
||||
});
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
export function initRepositorySearch() {
|
||||
const repositorySearchForm = document.querySelector('#repo-search-form');
|
||||
const repositorySearchForm = document.querySelector<HTMLFormElement>('#repo-search-form');
|
||||
if (!repositorySearchForm) return;
|
||||
|
||||
repositorySearchForm.addEventListener('change', (e) => {
|
||||
repositorySearchForm.addEventListener('change', (e: Event & {target: HTMLFormElement}) => {
|
||||
e.preventDefault();
|
||||
|
||||
const formData = new FormData(repositorySearchForm);
|
||||
|
@ -73,7 +73,7 @@ function initRepoSettingsSearchTeamBox() {
|
||||
function initRepoSettingsGitHook() {
|
||||
if (!$('.edit.githook').length) return;
|
||||
const filename = document.querySelector('.hook-filename').textContent;
|
||||
createMonaco($('#content')[0], filename, {language: 'shell'});
|
||||
createMonaco($('#content')[0] as HTMLTextAreaElement, filename, {language: 'shell'});
|
||||
}
|
||||
|
||||
function initRepoSettingsBranches() {
|
||||
@ -99,7 +99,7 @@ function initRepoSettingsBranches() {
|
||||
|
||||
// show the `Matched` mark for the status checks that match the pattern
|
||||
const markMatchedStatusChecks = () => {
|
||||
const patterns = (document.querySelector('#status_check_contexts').value || '').split(/[\r\n]+/);
|
||||
const patterns = (document.querySelector<HTMLTextAreaElement>('#status_check_contexts').value || '').split(/[\r\n]+/);
|
||||
const validPatterns = patterns.map((item) => item.trim()).filter(Boolean);
|
||||
const marks = document.querySelectorAll('.status-check-matched-mark');
|
||||
|
||||
@ -122,7 +122,7 @@ function initRepoSettingsBranches() {
|
||||
function initRepoSettingsOptions() {
|
||||
if ($('.repository.settings.options').length > 0) {
|
||||
// Enable or select internal/external wiki system and issue tracker.
|
||||
$('.enable-system').on('change', function () {
|
||||
$('.enable-system').on('change', function (this: HTMLInputElement) {
|
||||
if (this.checked) {
|
||||
$($(this).data('target')).removeClass('disabled');
|
||||
if (!$(this).data('context')) $($(this).data('context')).addClass('disabled');
|
||||
@ -131,7 +131,7 @@ function initRepoSettingsOptions() {
|
||||
if (!$(this).data('context')) $($(this).data('context')).removeClass('disabled');
|
||||
}
|
||||
});
|
||||
$('.enable-system-radio').on('change', function () {
|
||||
$('.enable-system-radio').on('change', function (this: HTMLInputElement) {
|
||||
if (this.value === 'false') {
|
||||
$($(this).data('target')).addClass('disabled');
|
||||
if ($(this).data('context') !== undefined) $($(this).data('context')).removeClass('disabled');
|
||||
|
@ -2,7 +2,7 @@ export function initSshKeyFormParser() {
|
||||
// Parse SSH Key
|
||||
document.querySelector('#ssh-key-content')?.addEventListener('input', function () {
|
||||
const arrays = this.value.split(' ');
|
||||
const title = document.querySelector('#ssh-key-title');
|
||||
const title = document.querySelector<HTMLInputElement>('#ssh-key-title');
|
||||
if (!title.value && arrays.length === 3 && arrays[2] !== '') {
|
||||
title.value = arrays[2];
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ function tableSort(normSort, revSort, isDefault) {
|
||||
if (!normSort) return false;
|
||||
if (!revSort) revSort = '';
|
||||
|
||||
const url = new URL(window.location);
|
||||
const url = new URL(window.location.href);
|
||||
let urlSort = url.searchParams.get('sort');
|
||||
if (!urlSort && isDefault) urlSort = normSort;
|
||||
|
||||
|
@ -48,7 +48,7 @@ function makeCollections({mentions, emoji}) {
|
||||
return collections;
|
||||
}
|
||||
|
||||
export async function attachTribute(element, {mentions, emoji} = {}) {
|
||||
export async function attachTribute(element, {mentions, emoji}) {
|
||||
const {default: Tribute} = await import(/* webpackChunkName: "tribute" */'tributejs');
|
||||
const collections = makeCollections({mentions, emoji});
|
||||
const tribute = new Tribute({collection: collections, noMatchTemplate: ''});
|
||||
|
2
web_src/js/globals.d.ts
vendored
2
web_src/js/globals.d.ts
vendored
@ -33,6 +33,7 @@ interface JQuery {
|
||||
modal: any; // fomantic
|
||||
tab: any; // fomantic
|
||||
transition: any, // fomantic
|
||||
search: any, // fomantic
|
||||
}
|
||||
|
||||
interface JQueryStatic {
|
||||
@ -62,4 +63,5 @@ interface Window {
|
||||
turnstile: any,
|
||||
hcaptcha: any,
|
||||
codeEditors: any[],
|
||||
updateCloneStates: () => void,
|
||||
}
|
||||
|
@ -5,6 +5,9 @@ import Toastify from 'toastify-js'; // don't use "async import", because when ne
|
||||
import type {Intent} from '../types.ts';
|
||||
import type {SvgName} from '../svg.ts';
|
||||
import type {Options} from 'toastify-js';
|
||||
import type StartToastifyInstance from 'toastify-js';
|
||||
|
||||
export type Toast = ReturnType<typeof StartToastifyInstance>;
|
||||
|
||||
type ToastLevels = {
|
||||
[intent in Intent]: {
|
||||
@ -38,7 +41,7 @@ type ToastOpts = {
|
||||
} & Options;
|
||||
|
||||
// See https://github.com/apvarun/toastify-js#api for options
|
||||
function showToast(message: string, level: Intent, {gravity, position, duration, useHtmlBody, preventDuplicates = true, ...other}: ToastOpts = {}) {
|
||||
function showToast(message: string, level: Intent, {gravity, position, duration, useHtmlBody, preventDuplicates = true, ...other}: ToastOpts = {}): Toast {
|
||||
const body = useHtmlBody ? String(message) : htmlEscape(message);
|
||||
const key = `${level}-${body}`;
|
||||
|
||||
@ -75,14 +78,14 @@ function showToast(message: string, level: Intent, {gravity, position, duration,
|
||||
return toast;
|
||||
}
|
||||
|
||||
export function showInfoToast(message: string, opts?: ToastOpts) {
|
||||
export function showInfoToast(message: string, opts?: ToastOpts): Toast {
|
||||
return showToast(message, 'info', opts);
|
||||
}
|
||||
|
||||
export function showWarningToast(message: string, opts?: ToastOpts) {
|
||||
export function showWarningToast(message: string, opts?: ToastOpts): Toast {
|
||||
return showToast(message, 'warning', opts);
|
||||
}
|
||||
|
||||
export function showErrorToast(message: string, opts?: ToastOpts) {
|
||||
export function showErrorToast(message: string, opts?: ToastOpts): Toast {
|
||||
return showToast(message, 'error', opts);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {pathEscapeSegments, isUrl} from './url.ts';
|
||||
import {pathEscapeSegments, isUrl, toOriginUrl} from './url.ts';
|
||||
|
||||
test('pathEscapeSegments', () => {
|
||||
expect(pathEscapeSegments('a/b/c')).toEqual('a/b/c');
|
||||
@ -11,3 +11,19 @@ test('isUrl', () => {
|
||||
expect(isUrl('https://example.com/index.html')).toEqual(true);
|
||||
expect(isUrl('/index.html')).toEqual(false);
|
||||
});
|
||||
|
||||
test('toOriginUrl', () => {
|
||||
const oldLocation = String(window.location);
|
||||
for (const origin of ['https://example.com', 'https://example.com:3000']) {
|
||||
window.location.assign(`${origin}/`);
|
||||
expect(toOriginUrl('/')).toEqual(`${origin}/`);
|
||||
expect(toOriginUrl('/org/repo.git')).toEqual(`${origin}/org/repo.git`);
|
||||
expect(toOriginUrl('https://another.com')).toEqual(`${origin}/`);
|
||||
expect(toOriginUrl('https://another.com/')).toEqual(`${origin}/`);
|
||||
expect(toOriginUrl('https://another.com/org/repo.git')).toEqual(`${origin}/org/repo.git`);
|
||||
expect(toOriginUrl('https://another.com:4000')).toEqual(`${origin}/`);
|
||||
expect(toOriginUrl('https://another.com:4000/')).toEqual(`${origin}/`);
|
||||
expect(toOriginUrl('https://another.com:4000/org/repo.git')).toEqual(`${origin}/org/repo.git`);
|
||||
}
|
||||
window.location.assign(oldLocation);
|
||||
});
|
||||
|
@ -13,3 +13,19 @@ export function isUrl(url: string): boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert an absolute or relative URL to an absolute URL with the current origin. It only
|
||||
// processes absolute HTTP/HTTPS URLs or relative URLs like '/xxx' or '//host/xxx'.
|
||||
export function toOriginUrl(urlStr: string) {
|
||||
try {
|
||||
if (urlStr.startsWith('http://') || urlStr.startsWith('https://') || urlStr.startsWith('/')) {
|
||||
const {origin, protocol, hostname, port} = window.location;
|
||||
const url = new URL(urlStr, origin);
|
||||
url.protocol = protocol;
|
||||
url.hostname = hostname;
|
||||
url.port = port || (protocol === 'https:' ? '443' : '80');
|
||||
return url.toString();
|
||||
}
|
||||
} catch {}
|
||||
return urlStr;
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
import {toOriginUrl} from './origin-url.ts';
|
||||
|
||||
test('toOriginUrl', () => {
|
||||
const oldLocation = String(window.location);
|
||||
for (const origin of ['https://example.com', 'https://example.com:3000']) {
|
||||
window.location.assign(`${origin}/`);
|
||||
expect(toOriginUrl('/')).toEqual(`${origin}/`);
|
||||
expect(toOriginUrl('/org/repo.git')).toEqual(`${origin}/org/repo.git`);
|
||||
expect(toOriginUrl('https://another.com')).toEqual(`${origin}/`);
|
||||
expect(toOriginUrl('https://another.com/')).toEqual(`${origin}/`);
|
||||
expect(toOriginUrl('https://another.com/org/repo.git')).toEqual(`${origin}/org/repo.git`);
|
||||
expect(toOriginUrl('https://another.com:4000')).toEqual(`${origin}/`);
|
||||
expect(toOriginUrl('https://another.com:4000/')).toEqual(`${origin}/`);
|
||||
expect(toOriginUrl('https://another.com:4000/org/repo.git')).toEqual(`${origin}/org/repo.git`);
|
||||
}
|
||||
window.location.assign(oldLocation);
|
||||
});
|
@ -1,19 +1,4 @@
|
||||
// Convert an absolute or relative URL to an absolute URL with the current origin. It only
|
||||
// processes absolute HTTP/HTTPS URLs or relative URLs like '/xxx' or '//host/xxx'.
|
||||
// NOTE: Keep this function in sync with clone_script.tmpl
|
||||
export function toOriginUrl(urlStr: string) {
|
||||
try {
|
||||
if (urlStr.startsWith('http://') || urlStr.startsWith('https://') || urlStr.startsWith('/')) {
|
||||
const {origin, protocol, hostname, port} = window.location;
|
||||
const url = new URL(urlStr, origin);
|
||||
url.protocol = protocol;
|
||||
url.hostname = hostname;
|
||||
url.port = port || (protocol === 'https:' ? '443' : '80');
|
||||
return url.toString();
|
||||
}
|
||||
} catch {}
|
||||
return urlStr;
|
||||
}
|
||||
import {toOriginUrl} from '../utils/url.ts';
|
||||
|
||||
window.customElements.define('origin-url', class extends HTMLElement {
|
||||
connectedCallback() {
|
||||
|
Loading…
Reference in New Issue
Block a user