Merge branch 'main' into add-repo-license-display
2
go.mod
@ -3,7 +3,7 @@ module code.gitea.io/gitea
|
|||||||
go 1.20
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
code.gitea.io/actions-proto-go v0.2.1
|
code.gitea.io/actions-proto-go v0.3.0
|
||||||
code.gitea.io/gitea-vet v0.2.2
|
code.gitea.io/gitea-vet v0.2.2
|
||||||
code.gitea.io/sdk/gitea v0.15.1
|
code.gitea.io/sdk/gitea v0.15.1
|
||||||
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570
|
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570
|
||||||
|
4
go.sum
@ -40,8 +40,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
|
|||||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||||
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
||||||
code.gitea.io/actions-proto-go v0.2.1 h1:ToMN/8thz2q10TuCq8dL2d8mI+/pWpJcHCvG+TELwa0=
|
code.gitea.io/actions-proto-go v0.3.0 h1:9Tvg8+TaaCXPKi6EnWl9vVgs2VZsj1Cs5afnsHa4AmM=
|
||||||
code.gitea.io/actions-proto-go v0.2.1/go.mod h1:00ys5QDo1iHN1tHNvvddAcy2W/g+425hQya1cCSvq9A=
|
code.gitea.io/actions-proto-go v0.3.0/go.mod h1:00ys5QDo1iHN1tHNvvddAcy2W/g+425hQya1cCSvq9A=
|
||||||
code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE=
|
code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE=
|
||||||
code.gitea.io/gitea-vet v0.2.2 h1:TEOV/Glf38iGmKzKP0EB++Z5OSL4zGg3RrAvlwaMuvk=
|
code.gitea.io/gitea-vet v0.2.2 h1:TEOV/Glf38iGmKzKP0EB++Z5OSL4zGg3RrAvlwaMuvk=
|
||||||
code.gitea.io/gitea-vet v0.2.2/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE=
|
code.gitea.io/gitea-vet v0.2.2/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE=
|
||||||
|
@ -43,10 +43,8 @@ type ActionRunner struct {
|
|||||||
LastOnline timeutil.TimeStamp `xorm:"index"`
|
LastOnline timeutil.TimeStamp `xorm:"index"`
|
||||||
LastActive timeutil.TimeStamp `xorm:"index"`
|
LastActive timeutil.TimeStamp `xorm:"index"`
|
||||||
|
|
||||||
// Store OS and Artch.
|
// Store labels defined in state file (default: .runner file) of `act_runner`
|
||||||
AgentLabels []string
|
AgentLabels []string `xorm:"TEXT"`
|
||||||
// Store custom labes use defined.
|
|
||||||
CustomLabels []string
|
|
||||||
|
|
||||||
Created timeutil.TimeStamp `xorm:"created"`
|
Created timeutil.TimeStamp `xorm:"created"`
|
||||||
Updated timeutil.TimeStamp `xorm:"updated"`
|
Updated timeutil.TimeStamp `xorm:"updated"`
|
||||||
@ -104,11 +102,6 @@ func (r *ActionRunner) IsOnline() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// AllLabels returns agent and custom labels
|
|
||||||
func (r *ActionRunner) AllLabels() []string {
|
|
||||||
return append(r.AgentLabels, r.CustomLabels...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Editable checks if the runner is editable by the user
|
// Editable checks if the runner is editable by the user
|
||||||
func (r *ActionRunner) Editable(ownerID, repoID int64) bool {
|
func (r *ActionRunner) Editable(ownerID, repoID int64) bool {
|
||||||
if ownerID == 0 && repoID == 0 {
|
if ownerID == 0 && repoID == 0 {
|
||||||
|
@ -241,11 +241,9 @@ func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask
|
|||||||
|
|
||||||
// TODO: a more efficient way to filter labels
|
// TODO: a more efficient way to filter labels
|
||||||
var job *ActionRunJob
|
var job *ActionRunJob
|
||||||
labels := runner.AgentLabels
|
log.Trace("runner labels: %v", runner.AgentLabels)
|
||||||
labels = append(labels, runner.CustomLabels...)
|
|
||||||
log.Trace("runner labels: %v", labels)
|
|
||||||
for _, v := range jobs {
|
for _, v := range jobs {
|
||||||
if isSubset(labels, v.RunsOn) {
|
if isSubset(runner.AgentLabels, v.RunsOn) {
|
||||||
job = v
|
job = v
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -920,7 +920,7 @@ func PullRequestCodeOwnersReview(ctx context.Context, pull *Issue, pr *PullReque
|
|||||||
var data string
|
var data string
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
if blob, err := commit.GetBlobByPath(file); err == nil {
|
if blob, err := commit.GetBlobByPath(file); err == nil {
|
||||||
data, err = blob.GetBlobContent()
|
data, err = blob.GetBlobContent(setting.UI.MaxDisplayFileSize)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"code.gitea.io/gitea/models/migrations/v1_18"
|
"code.gitea.io/gitea/models/migrations/v1_18"
|
||||||
"code.gitea.io/gitea/models/migrations/v1_19"
|
"code.gitea.io/gitea/models/migrations/v1_19"
|
||||||
"code.gitea.io/gitea/models/migrations/v1_20"
|
"code.gitea.io/gitea/models/migrations/v1_20"
|
||||||
|
"code.gitea.io/gitea/models/migrations/v1_21"
|
||||||
"code.gitea.io/gitea/models/migrations/v1_6"
|
"code.gitea.io/gitea/models/migrations/v1_6"
|
||||||
"code.gitea.io/gitea/models/migrations/v1_7"
|
"code.gitea.io/gitea/models/migrations/v1_7"
|
||||||
"code.gitea.io/gitea/models/migrations/v1_8"
|
"code.gitea.io/gitea/models/migrations/v1_8"
|
||||||
@ -497,7 +498,12 @@ var migrations = []Migration{
|
|||||||
NewMigration("Add PinOrder Column", v1_20.AddPinOrderToIssue),
|
NewMigration("Add PinOrder Column", v1_20.AddPinOrderToIssue),
|
||||||
// v259 -> 260
|
// v259 -> 260
|
||||||
NewMigration("Convert scoped access tokens", v1_20.ConvertScopedAccessTokens),
|
NewMigration("Convert scoped access tokens", v1_20.ConvertScopedAccessTokens),
|
||||||
// v260 -> 261
|
|
||||||
|
// Gitea 1.21.0 ends at 260
|
||||||
|
|
||||||
|
// v260 -> v261
|
||||||
|
NewMigration("Add label column to action_run table, and combine labels", v1_21.DropCustomLabelsColumnToActRunner),
|
||||||
|
// v261 -> 262
|
||||||
NewMigration("Add Repository Licenses", v1_20.AddRepositoryLicenses),
|
NewMigration("Add Repository Licenses", v1_20.AddRepositoryLicenses),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
14
models/migrations/v1_21/main_test.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package v1_21 //nolint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/migrations/base"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
base.MainTest(m)
|
||||||
|
}
|
26
models/migrations/v1_21/v260.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package v1_21 //nolint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"code.gitea.io/gitea/models/migrations/base"
|
||||||
|
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DropCustomLabelsColumnToActRunner(x *xorm.Engine) error {
|
||||||
|
sess := x.NewSession()
|
||||||
|
defer sess.Close()
|
||||||
|
|
||||||
|
if err := sess.Begin(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// drop "custom_labels" cols
|
||||||
|
if err := base.DropTableColumns(sess, "action_runner", "custom_labels"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return sess.Commit()
|
||||||
|
}
|
@ -20,17 +20,18 @@ func (b *Blob) Name() string {
|
|||||||
return b.name
|
return b.name
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlobContent Gets the content of the blob as raw text
|
// GetBlobContent Gets the limited content of the blob as raw text
|
||||||
func (b *Blob) GetBlobContent() (string, error) {
|
func (b *Blob) GetBlobContent(limit int64) (string, error) {
|
||||||
|
if limit <= 0 {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
dataRc, err := b.DataAsync()
|
dataRc, err := b.DataAsync()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
defer dataRc.Close()
|
defer dataRc.Close()
|
||||||
buf := make([]byte, 1024)
|
buf, err := util.ReadWithLimit(dataRc, int(limit))
|
||||||
n, _ := util.ReadAtMost(dataRc, buf)
|
return string(buf), err
|
||||||
buf = buf[:n]
|
|
||||||
return string(buf), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlobAll Gets the all content of the blob as bytes
|
// GetBlobAll Gets the all content of the blob as bytes
|
||||||
|
@ -163,6 +163,7 @@ func (ref RefName) ShortName() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RefGroup returns the group type of the reference
|
// RefGroup returns the group type of the reference
|
||||||
|
// Using the name of the directory under .git/refs
|
||||||
func (ref RefName) RefGroup() string {
|
func (ref RefName) RefGroup() string {
|
||||||
if ref.IsBranch() {
|
if ref.IsBranch() {
|
||||||
return "heads"
|
return "heads"
|
||||||
@ -182,6 +183,19 @@ func (ref RefName) RefGroup() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RefType returns the simple ref type of the reference, e.g. branch, tag
|
||||||
|
// It's differrent from RefGroup, which is using the name of the directory under .git/refs
|
||||||
|
// Here we using branch but not heads, using tag but not tags
|
||||||
|
func (ref RefName) RefType() string {
|
||||||
|
var refType string
|
||||||
|
if ref.IsBranch() {
|
||||||
|
refType = "branch"
|
||||||
|
} else if ref.IsTag() {
|
||||||
|
refType = "tag"
|
||||||
|
}
|
||||||
|
return refType
|
||||||
|
}
|
||||||
|
|
||||||
// RefURL returns the absolute URL for a ref in a repository
|
// RefURL returns the absolute URL for a ref in a repository
|
||||||
func RefURL(repoURL, ref string) string {
|
func RefURL(repoURL, ref string) string {
|
||||||
refFullName := RefName(ref)
|
refFullName := RefName(ref)
|
||||||
|
@ -76,7 +76,8 @@ func IsSummary(node ast.Node) bool {
|
|||||||
// TaskCheckBoxListItem is a block that represents a list item of a markdown block with a checkbox
|
// TaskCheckBoxListItem is a block that represents a list item of a markdown block with a checkbox
|
||||||
type TaskCheckBoxListItem struct {
|
type TaskCheckBoxListItem struct {
|
||||||
*ast.ListItem
|
*ast.ListItem
|
||||||
IsChecked bool
|
IsChecked bool
|
||||||
|
SourcePosition int
|
||||||
}
|
}
|
||||||
|
|
||||||
// KindTaskCheckBoxListItem is the NodeKind for TaskCheckBoxListItem
|
// KindTaskCheckBoxListItem is the NodeKind for TaskCheckBoxListItem
|
||||||
@ -86,6 +87,7 @@ var KindTaskCheckBoxListItem = ast.NewNodeKind("TaskCheckBoxListItem")
|
|||||||
func (n *TaskCheckBoxListItem) Dump(source []byte, level int) {
|
func (n *TaskCheckBoxListItem) Dump(source []byte, level int) {
|
||||||
m := map[string]string{}
|
m := map[string]string{}
|
||||||
m["IsChecked"] = strconv.FormatBool(n.IsChecked)
|
m["IsChecked"] = strconv.FormatBool(n.IsChecked)
|
||||||
|
m["SourcePosition"] = strconv.FormatInt(int64(n.SourcePosition), 10)
|
||||||
ast.DumpHelper(n, source, level, m, nil)
|
ast.DumpHelper(n, source, level, m, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,6 +177,11 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa
|
|||||||
newChild := NewTaskCheckBoxListItem(listItem)
|
newChild := NewTaskCheckBoxListItem(listItem)
|
||||||
newChild.IsChecked = taskCheckBox.IsChecked
|
newChild.IsChecked = taskCheckBox.IsChecked
|
||||||
newChild.SetAttributeString("class", []byte("task-list-item"))
|
newChild.SetAttributeString("class", []byte("task-list-item"))
|
||||||
|
segments := newChild.FirstChild().Lines()
|
||||||
|
if segments.Len() > 0 {
|
||||||
|
segment := segments.At(0)
|
||||||
|
newChild.SourcePosition = rc.metaLength + segment.Start
|
||||||
|
}
|
||||||
v.AppendChild(v, newChild)
|
v.AppendChild(v, newChild)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -457,12 +462,7 @@ func (r *HTMLRenderer) renderTaskCheckBoxListItem(w util.BufWriter, source []byt
|
|||||||
} else {
|
} else {
|
||||||
_, _ = w.WriteString("<li>")
|
_, _ = w.WriteString("<li>")
|
||||||
}
|
}
|
||||||
_, _ = w.WriteString(`<input type="checkbox" disabled=""`)
|
fmt.Fprintf(w, `<input type="checkbox" disabled="" data-source-position="%d"`, n.SourcePosition)
|
||||||
segments := node.FirstChild().Lines()
|
|
||||||
if segments.Len() > 0 {
|
|
||||||
segment := segments.At(0)
|
|
||||||
_, _ = w.WriteString(fmt.Sprintf(` data-source-position="%d"`, segment.Start))
|
|
||||||
}
|
|
||||||
if n.IsChecked {
|
if n.IsChecked {
|
||||||
_, _ = w.WriteString(` checked=""`)
|
_, _ = w.WriteString(` checked=""`)
|
||||||
}
|
}
|
||||||
|
@ -178,6 +178,9 @@ func actualRender(ctx *markup.RenderContext, input io.Reader, output io.Writer)
|
|||||||
}
|
}
|
||||||
buf = giteautil.NormalizeEOL(buf)
|
buf = giteautil.NormalizeEOL(buf)
|
||||||
|
|
||||||
|
// Preserve original length.
|
||||||
|
bufWithMetadataLength := len(buf)
|
||||||
|
|
||||||
rc := &RenderConfig{
|
rc := &RenderConfig{
|
||||||
Meta: renderMetaModeFromString(string(ctx.RenderMetaAs)),
|
Meta: renderMetaModeFromString(string(ctx.RenderMetaAs)),
|
||||||
Icon: "table",
|
Icon: "table",
|
||||||
@ -185,6 +188,12 @@ func actualRender(ctx *markup.RenderContext, input io.Reader, output io.Writer)
|
|||||||
}
|
}
|
||||||
buf, _ = ExtractMetadataBytes(buf, rc)
|
buf, _ = ExtractMetadataBytes(buf, rc)
|
||||||
|
|
||||||
|
metaLength := bufWithMetadataLength - len(buf)
|
||||||
|
if metaLength < 0 {
|
||||||
|
metaLength = 0
|
||||||
|
}
|
||||||
|
rc.metaLength = metaLength
|
||||||
|
|
||||||
pc.Set(renderConfigKey, rc)
|
pc.Set(renderConfigKey, rc)
|
||||||
|
|
||||||
if err := converter.Convert(buf, lw, parser.WithContext(pc)); err != nil {
|
if err := converter.Convert(buf, lw, parser.WithContext(pc)); err != nil {
|
||||||
|
@ -520,3 +520,40 @@ func TestMathBlock(t *testing.T) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTaskList(t *testing.T) {
|
||||||
|
testcases := []struct {
|
||||||
|
testcase string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
// data-source-position should take into account YAML frontmatter.
|
||||||
|
`---
|
||||||
|
foo: bar
|
||||||
|
---
|
||||||
|
- [ ] task 1`,
|
||||||
|
`<details><summary><i class="icon table"></i></summary><table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>foo</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>bar</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</details><ul>
|
||||||
|
<li class="task-list-item"><input type="checkbox" disabled="" data-source-position="19"/>task 1</li>
|
||||||
|
</ul>
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testcases {
|
||||||
|
res, err := RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase)
|
||||||
|
assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase)
|
||||||
|
assert.Equal(t, test.expected, res, "Unexpected result in testcase %q", test.testcase)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -20,6 +20,9 @@ type RenderConfig struct {
|
|||||||
TOC string // "false": hide, "side"/empty: in sidebar, "main"/"true": in main view
|
TOC string // "false": hide, "side"/empty: in sidebar, "main"/"true": in main view
|
||||||
Lang string
|
Lang string
|
||||||
yamlNode *yaml.Node
|
yamlNode *yaml.Node
|
||||||
|
|
||||||
|
// Used internally. Cannot be controlled by frontmatter.
|
||||||
|
metaLength int
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderMetaModeFromString(s string) markup.RenderMetaMode {
|
func renderMetaModeFromString(s string) markup.RenderMetaMode {
|
||||||
|
@ -62,5 +62,5 @@ func RenderHTML(icon string, others ...interface{}) template.HTML {
|
|||||||
}
|
}
|
||||||
return template.HTML(svgStr)
|
return template.HTML(svgStr)
|
||||||
}
|
}
|
||||||
return template.HTML("")
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,14 @@
|
|||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReadAtMost reads at most len(buf) bytes from r into buf.
|
// ReadAtMost reads at most len(buf) bytes from r into buf.
|
||||||
// It returns the number of bytes copied. n is only less than len(buf) if r provides fewer bytes.
|
// It returns the number of bytes copied. n is only less than len(buf) if r provides fewer bytes.
|
||||||
// If EOF occurs while reading, err will be nil.
|
// If EOF or ErrUnexpectedEOF occurs while reading, err will be nil.
|
||||||
func ReadAtMost(r io.Reader, buf []byte) (n int, err error) {
|
func ReadAtMost(r io.Reader, buf []byte) (n int, err error) {
|
||||||
n, err = io.ReadFull(r, buf)
|
n, err = io.ReadFull(r, buf)
|
||||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||||
@ -19,6 +20,42 @@ func ReadAtMost(r io.Reader, buf []byte) (n int, err error) {
|
|||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReadWithLimit reads at most "limit" bytes from r into buf.
|
||||||
|
// If EOF or ErrUnexpectedEOF occurs while reading, err will be nil.
|
||||||
|
func ReadWithLimit(r io.Reader, n int) (buf []byte, err error) {
|
||||||
|
return readWithLimit(r, 1024, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func readWithLimit(r io.Reader, batch, limit int) ([]byte, error) {
|
||||||
|
if limit <= batch {
|
||||||
|
buf := make([]byte, limit)
|
||||||
|
n, err := ReadAtMost(r, buf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return buf[:n], nil
|
||||||
|
}
|
||||||
|
res := bytes.NewBuffer(make([]byte, 0, batch))
|
||||||
|
bufFix := make([]byte, batch)
|
||||||
|
eof := false
|
||||||
|
for res.Len() < limit && !eof {
|
||||||
|
bufTmp := bufFix
|
||||||
|
if res.Len()+batch > limit {
|
||||||
|
bufTmp = bufFix[:limit-res.Len()]
|
||||||
|
}
|
||||||
|
n, err := io.ReadFull(r, bufTmp)
|
||||||
|
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||||
|
eof = true
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if _, err = res.Write(bufTmp[:n]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
// ErrNotEmpty is an error reported when there is a non-empty reader
|
// ErrNotEmpty is an error reported when there is a non-empty reader
|
||||||
var ErrNotEmpty = errors.New("not-empty")
|
var ErrNotEmpty = errors.New("not-empty")
|
||||||
|
|
||||||
|
66
modules/util/io_test.go
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
type readerWithError struct {
|
||||||
|
buf *bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *readerWithError) Read(p []byte) (n int, err error) {
|
||||||
|
if r.buf.Len() < 2 {
|
||||||
|
return 0, errors.New("test error")
|
||||||
|
}
|
||||||
|
return r.buf.Read(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadWithLimit(t *testing.T) {
|
||||||
|
bs := []byte("0123456789abcdef")
|
||||||
|
|
||||||
|
// normal test
|
||||||
|
buf, err := readWithLimit(bytes.NewBuffer(bs), 5, 2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, []byte("01"), buf)
|
||||||
|
|
||||||
|
buf, err = readWithLimit(bytes.NewBuffer(bs), 5, 5)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, []byte("01234"), buf)
|
||||||
|
|
||||||
|
buf, err = readWithLimit(bytes.NewBuffer(bs), 5, 6)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, []byte("012345"), buf)
|
||||||
|
|
||||||
|
buf, err = readWithLimit(bytes.NewBuffer(bs), 5, len(bs))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, []byte("0123456789abcdef"), buf)
|
||||||
|
|
||||||
|
buf, err = readWithLimit(bytes.NewBuffer(bs), 5, 100)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, []byte("0123456789abcdef"), buf)
|
||||||
|
|
||||||
|
// test with error
|
||||||
|
buf, err = readWithLimit(&readerWithError{bytes.NewBuffer(bs)}, 5, 10)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, []byte("0123456789"), buf)
|
||||||
|
|
||||||
|
buf, err = readWithLimit(&readerWithError{bytes.NewBuffer(bs)}, 5, 100)
|
||||||
|
assert.ErrorContains(t, err, "test error")
|
||||||
|
assert.Empty(t, buf)
|
||||||
|
|
||||||
|
// test public function
|
||||||
|
buf, err = ReadWithLimit(bytes.NewBuffer(bs), 2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, []byte("01"), buf)
|
||||||
|
|
||||||
|
buf, err = ReadWithLimit(bytes.NewBuffer(bs), 9999999)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, []byte("0123456789abcdef"), buf)
|
||||||
|
}
|
@ -811,7 +811,10 @@ repo_and_org_access = Repository and Organization Access
|
|||||||
permissions_public_only = Public only
|
permissions_public_only = Public only
|
||||||
permissions_access_all = All (public, private, and limited)
|
permissions_access_all = All (public, private, and limited)
|
||||||
select_permissions = Select permissions
|
select_permissions = Select permissions
|
||||||
scoped_token_desc = Selected token scopes limit authentication only to the corresponding <a %s>API</a> routes. Read the <a %s>documentation</a> for more information.
|
permission_no_access = No Access
|
||||||
|
permission_read = Read
|
||||||
|
permission_write = Read and Write
|
||||||
|
access_token_desc = Selected token permissions limit authorization only to the corresponding <a %s>API</a> routes. Read the <a %s>documentation</a> for more information.
|
||||||
at_least_one_permission = You must select at least one permission to create a token
|
at_least_one_permission = You must select at least one permission to create a token
|
||||||
permissions_list = Permissions:
|
permissions_list = Permissions:
|
||||||
|
|
||||||
@ -3424,11 +3427,9 @@ runners.owner_type = Type
|
|||||||
runners.description = Description
|
runners.description = Description
|
||||||
runners.labels = Labels
|
runners.labels = Labels
|
||||||
runners.last_online = Last Online Time
|
runners.last_online = Last Online Time
|
||||||
runners.agent_labels = Agent Labels
|
|
||||||
runners.custom_labels = Custom Labels
|
|
||||||
runners.custom_labels_helper = Custom labels are labels that are added manually by an administrator. A comma separates labels, whitespace at the start and end of each label is ignored.
|
|
||||||
runners.runner_title = Runner
|
runners.runner_title = Runner
|
||||||
runners.task_list = Recent tasks on this runner
|
runners.task_list = Recent tasks on this runner
|
||||||
|
runners.task_list.no_tasks = There is no task yet.
|
||||||
runners.task_list.run = Run
|
runners.task_list.run = Run
|
||||||
runners.task_list.status = Status
|
runners.task_list.status = Status
|
||||||
runners.task_list.repository = Repository
|
runners.task_list.repository = Repository
|
||||||
|
@ -357,7 +357,7 @@ hi_user_x=Cześć <b>%s</b>,
|
|||||||
|
|
||||||
activate_account=Aktywuj swoje konto
|
activate_account=Aktywuj swoje konto
|
||||||
activate_account.title=%s, proszę aktywuj swoje konto
|
activate_account.title=%s, proszę aktywuj swoje konto
|
||||||
activate_account.text_1=Cześć <b>%[1]s</b>, dziękujemy za rejestrację na %[2]!
|
activate_account.text_1=Cześć <b>%[1]s</b>, dziękujemy za rejestrację na %[2]s!
|
||||||
activate_account.text_2=Kliknij poniższy link, aby aktywować swoje konto w ciągu <b>%s</b>:
|
activate_account.text_2=Kliknij poniższy link, aby aktywować swoje konto w ciągu <b>%s</b>:
|
||||||
|
|
||||||
activate_email=Potwierdź swój adres e-mail
|
activate_email=Potwierdź swój adres e-mail
|
||||||
|
@ -1288,7 +1288,7 @@ projects.column.edit_title=Nome
|
|||||||
projects.column.new_title=Nome
|
projects.column.new_title=Nome
|
||||||
projects.column.new_submit=Criar coluna
|
projects.column.new_submit=Criar coluna
|
||||||
projects.column.new=Nova coluna
|
projects.column.new=Nova coluna
|
||||||
projects.column.set_default=Pôr como predefinida
|
projects.column.set_default=Tornar predefinida
|
||||||
projects.column.set_default_desc=Definir esta coluna como a predefinida para questões e pedidos de integração não categorizados
|
projects.column.set_default_desc=Definir esta coluna como a predefinida para questões e pedidos de integração não categorizados
|
||||||
projects.column.unset_default=Deixar de ser a predefinida
|
projects.column.unset_default=Deixar de ser a predefinida
|
||||||
projects.column.unset_default_desc=Faz com que esta coluna deixe de ser a predefinida
|
projects.column.unset_default_desc=Faz com que esta coluna deixe de ser a predefinida
|
||||||
|
@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 18" class="svg gitea-azureadv2" width="16" height="16" aria-hidden="true"><defs><linearGradient id="gitea-azureadv2__a" x1="13.25" x2="8.62" y1="13.02" y2="4.25" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1988d9"/><stop offset=".9" stop-color="#54aef0"/></linearGradient><linearGradient id="gitea-azureadv2__b" x1="11.26" x2="14.46" y1="10.47" y2="15.99" gradientUnits="userSpaceOnUse"><stop offset=".1" stop-color="#54aef0"/><stop offset=".29" stop-color="#4fabee"/><stop offset=".51" stop-color="#41a2e9"/><stop offset=".74" stop-color="#2a93e0"/><stop offset=".88" stop-color="#1988d9"/></linearGradient></defs><path fill="#50e6ff" d="m1.01 10.19 7.92 5.14 8.06-5.16L18 11.35l-9.07 5.84L0 11.35l1.01-1.16z"/><path fill="#fff" d="M1.61 9.53 8.93.81l7.47 8.73-7.47 4.72-7.32-4.73z"/><path fill="#50e6ff" d="M8.93.81v13.45L1.61 9.53 8.93.81z"/><path fill="url(#gitea-azureadv2__a)" d="M8.93.81v13.45l7.47-4.72L8.93.81z"/><path fill="#53b1e0" d="m8.93 7.76 7.47 1.78-7.47 4.72v-6.5z"/><path fill="#9cebff" d="M8.93 14.26 1.61 9.53l7.32-1.77v6.5z"/><path fill="url(#gitea-azureadv2__b)" d="M8.93 17.19 18 11.35l-1.01-1.18-8.06 5.16v1.86z"/></svg>
|
|
Before Width: | Height: | Size: 1.2 KiB |
@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640" class="svg gitea-gitea" width="16" height="16" aria-hidden="true"><path fill="#fff" d="m395.9 484.2-126.9-61c-12.5-6-17.9-21.2-11.8-33.8l61-126.9c6-12.5 21.2-17.9 33.8-11.8 17.2 8.3 27.1 13 27.1 13l-.1-109.2 16.7-.1.1 117.1s57.4 24.2 83.1 40.1c3.7 2.3 10.2 6.8 12.9 14.4 2.1 6.1 2 13.1-1 19.3l-61 126.9c-6.2 12.7-21.4 18.1-33.9 12z"/><g fill="#609926"><path d="M622.7 149.8c-4.1-4.1-9.6-4-9.6-4s-117.2 6.6-177.9 8c-13.3.3-26.5.6-39.6.7v117.2c-5.5-2.6-11.1-5.3-16.6-7.9 0-36.4-.1-109.2-.1-109.2-29 .4-89.2-2.2-89.2-2.2s-141.4-7.1-156.8-8.5c-9.8-.6-22.5-2.1-39 1.5-8.7 1.8-33.5 7.4-53.8 26.9C-4.9 212.4 6.6 276.2 8 285.8c1.7 11.7 6.9 44.2 31.7 72.5 45.8 56.1 144.4 54.8 144.4 54.8s12.1 28.9 30.6 55.5c25 33.1 50.7 58.9 75.7 62 63 0 188.9-.1 188.9-.1s12 .1 28.3-10.3c14-8.5 26.5-23.4 26.5-23.4S547 483 565 451.5c5.5-9.7 10.1-19.1 14.1-28 0 0 55.2-117.1 55.2-231.1-1.1-34.5-9.6-40.6-11.6-42.6zM125.6 353.9c-25.9-8.5-36.9-18.7-36.9-18.7S69.6 321.8 60 295.4c-16.5-44.2-1.4-71.2-1.4-71.2s8.4-22.5 38.5-30c13.8-3.7 31-3.1 31-3.1s7.1 59.4 15.7 94.2c7.2 29.2 24.8 77.7 24.8 77.7s-26.1-3.1-43-9.1zm300.3 107.6s-6.1 14.5-19.6 15.4c-5.8.4-10.3-1.2-10.3-1.2s-.3-.1-5.3-2.1l-112.9-55s-10.9-5.7-12.8-15.6c-2.2-8.1 2.7-18.1 2.7-18.1L322 273s4.8-9.7 12.2-13c.6-.3 2.3-1 4.5-1.5 8.1-2.1 18 2.8 18 2.8L467.4 315s12.6 5.7 15.3 16.2c1.9 7.4-.5 14-1.8 17.2-6.3 15.4-55 113.1-55 113.1z"/><path d="M326.8 380.1c-8.2.1-15.4 5.8-17.3 13.8-1.9 8 2 16.3 9.1 20 7.7 4 17.5 1.8 22.7-5.4 5.1-7.1 4.3-16.9-1.8-23.1l24-49.1c1.5.1 3.7.2 6.2-.5 4.1-.9 7.1-3.6 7.1-3.6 4.2 1.8 8.6 3.8 13.2 6.1 4.8 2.4 9.3 4.9 13.4 7.3.9.5 1.8 1.1 2.8 1.9 1.6 1.3 3.4 3.1 4.7 5.5 1.9 5.5-1.9 14.9-1.9 14.9-2.3 7.6-18.4 40.6-18.4 40.6-8.1-.2-15.3 5-17.7 12.5-2.6 8.1 1.1 17.3 8.9 21.3 7.8 4 17.4 1.7 22.5-5.3 5-6.8 4.6-16.3-1.1-22.6 1.9-3.7 3.7-7.4 5.6-11.3 5-10.4 13.5-30.4 13.5-30.4.9-1.7 5.7-10.3 2.7-21.3-2.5-11.4-12.6-16.7-12.6-16.7-12.2-7.9-29.2-15.2-29.2-15.2s0-4.1-1.1-7.1c-1.1-3.1-2.8-5.1-3.9-6.3 4.7-9.7 9.4-19.3 14.1-29-4.1-2-8.1-4-12.2-6.1-4.8 9.8-9.7 19.7-14.5 29.5-6.7-.1-12.9 3.5-16.1 9.4-3.4 6.3-2.7 14.1 1.9 19.8l-24.6 50.4z"/></g></svg>
|
|
Before Width: | Height: | Size: 2.1 KiB |
@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" class="svg octicon-mark-github" width="16" height="16" aria-hidden="true"><path d="M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z"/></svg>
|
|
Before Width: | Height: | Size: 723 B |
@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" class="svg gitea-gitlab" width="16" height="16" aria-hidden="true"><path fill="#E24329" d="m31.462 12.779-.045-.115-4.35-11.35a1.137 1.137 0 0 0-.447-.541 1.163 1.163 0 0 0-1.343.071c-.187.15-.322.356-.386.587l-2.94 9.001h-11.9l-2.941-9a1.138 1.138 0 0 0-1.045-.84 1.153 1.153 0 0 0-1.13.72L.579 12.68l-.045.113a8.09 8.09 0 0 0 2.68 9.34l.016.012.038.03 6.635 4.967 3.28 2.484 1.994 1.51a1.35 1.35 0 0 0 1.627 0l1.994-1.51 3.282-2.484 6.673-4.997.018-.013a8.088 8.088 0 0 0 2.69-9.352Z"/><path fill="#FC6D26" d="m31.462 12.779-.045-.115a14.748 14.748 0 0 0-5.856 2.634l-9.553 7.24A11225.6 11225.6 0 0 0 22.1 27.14l6.673-4.997.019-.013a8.09 8.09 0 0 0 2.67-9.352Z"/><path fill="#FCA326" d="m9.908 27.14 3.275 2.485 1.994 1.51a1.35 1.35 0 0 0 1.627 0l1.994-1.51 3.282-2.484s-2.835-2.14-6.092-4.603l-6.08 4.603Z"/><path fill="#FC6D26" d="M6.435 15.305A14.712 14.712 0 0 0 .58 12.672l-.045.113a8.09 8.09 0 0 0 2.68 9.347l.016.012.038.03 6.635 4.967 6.105-4.603-9.573-7.233Z"/></svg>
|
|
Before Width: | Height: | Size: 1.0 KiB |
1
public/img/svg/gitea-azuread.svg
generated
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="gitea-azuread__svg gitea-azuread__gitea-azuread svg gitea-azuread" viewBox="0 0 18 18" width="16" height="16"><defs><linearGradient id="gitea-azuread__a" x1="13.25" x2="8.62" y1="13.02" y2="4.25" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1988d9"/><stop offset=".9" stop-color="#54aef0"/></linearGradient><linearGradient id="gitea-azuread__b" x1="11.26" x2="14.46" y1="10.47" y2="15.99" gradientUnits="userSpaceOnUse"><stop offset=".1" stop-color="#54aef0"/><stop offset=".29" stop-color="#4fabee"/><stop offset=".51" stop-color="#41a2e9"/><stop offset=".74" stop-color="#2a93e0"/><stop offset=".88" stop-color="#1988d9"/></linearGradient></defs><path fill="#50e6ff" d="m1.01 10.19 7.92 5.14 8.06-5.16L18 11.35l-9.07 5.84L0 11.35l1.01-1.16z"/><path fill="#fff" d="M1.61 9.53 8.93.81l7.47 8.73-7.47 4.72-7.32-4.73z"/><path fill="#50e6ff" d="M8.93.81v13.45L1.61 9.53 8.93.81z"/><path fill="url(#gitea-azuread__a)" d="M8.93.81v13.45l7.47-4.72L8.93.81z"/><path fill="#53b1e0" d="m8.93 7.76 7.47 1.78-7.47 4.72v-6.5z"/><path fill="#9cebff" d="M8.93 14.26 1.61 9.53l7.32-1.77v6.5z"/><path fill="url(#gitea-azuread__b)" d="M8.93 17.19 18 11.35l-1.01-1.18-8.06 5.16v1.86z"/></svg>
|
After Width: | Height: | Size: 1.2 KiB |
1
public/img/svg/gitea-azureadv2.svg
generated
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="gitea-azureadv2__svg gitea-azureadv2__gitea-azuread svg gitea-azureadv2" viewBox="0 0 18 18" width="16" height="16"><defs><linearGradient id="gitea-azureadv2__a" x1="13.25" x2="8.62" y1="13.02" y2="4.25" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1988d9"/><stop offset=".9" stop-color="#54aef0"/></linearGradient><linearGradient id="gitea-azureadv2__b" x1="11.26" x2="14.46" y1="10.47" y2="15.99" gradientUnits="userSpaceOnUse"><stop offset=".1" stop-color="#54aef0"/><stop offset=".29" stop-color="#4fabee"/><stop offset=".51" stop-color="#41a2e9"/><stop offset=".74" stop-color="#2a93e0"/><stop offset=".88" stop-color="#1988d9"/></linearGradient></defs><path fill="#50e6ff" d="m1.01 10.19 7.92 5.14 8.06-5.16L18 11.35l-9.07 5.84L0 11.35l1.01-1.16z"/><path fill="#fff" d="M1.61 9.53 8.93.81l7.47 8.73-7.47 4.72-7.32-4.73z"/><path fill="#50e6ff" d="M8.93.81v13.45L1.61 9.53 8.93.81z"/><path fill="url(#gitea-azureadv2__a)" d="M8.93.81v13.45l7.47-4.72L8.93.81z"/><path fill="#53b1e0" d="m8.93 7.76 7.47 1.78-7.47 4.72v-6.5z"/><path fill="#9cebff" d="M8.93 14.26 1.61 9.53l7.32-1.77v6.5z"/><path fill="url(#gitea-azureadv2__b)" d="M8.93 17.19 18 11.35l-1.01-1.18-8.06 5.16v1.86z"/></svg>
|
After Width: | Height: | Size: 1.2 KiB |
1
public/img/svg/gitea-bitbucket.svg
generated
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="gitea-bitbucket__svg gitea-bitbucket__gitea-bitbucket svg gitea-bitbucket" preserveAspectRatio="xMinYMin meet" viewBox="0 0 256 295" width="16" height="16"><g fill="#205081"><path d="M128 0C57.732 0 .012 18.822.012 42.663c0 6.274 15.057 95.364 21.331 130.498 2.51 16.312 43.918 38.898 106.657 38.898 62.74 0 102.893-22.586 106.657-38.898 6.274-35.134 21.331-124.224 21.331-130.498C254.734 18.822 198.268 0 128 0zm0 183.199c-22.586 0-40.153-17.567-40.153-40.153s17.567-40.153 40.153-40.153 40.153 17.567 40.153 40.153c0 21.331-17.567 40.153-40.153 40.153zm0-127.988c-45.172 0-81.561-7.53-81.561-17.567 0-10.039 36.389-17.567 81.561-17.567 45.172 0 81.561 7.528 81.561 17.567 0 10.038-36.389 17.567-81.561 17.567z"/><path d="M220.608 207.04c-2.51 0-3.764 1.255-3.764 1.255s-31.37 25.096-87.835 25.096c-56.466 0-87.835-25.096-87.835-25.096s-2.51-1.255-3.765-1.255c-2.51 0-5.019 1.255-5.019 5.02v1.254c5.02 26.35 8.784 45.172 8.784 47.682 3.764 18.822 41.408 33.88 86.58 33.88s82.816-15.058 86.58-33.88c0-2.51 3.765-21.332 8.784-47.682v-1.255c1.255-2.51 0-5.019-2.51-5.019z"/><circle cx="128" cy="141.791" r="20.077"/></g></svg>
|
After Width: | Height: | Size: 1.2 KiB |
1
public/img/svg/gitea-discord.svg
generated
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="gitea-discord__svg gitea-discord__gitea-discord svg gitea-discord" preserveAspectRatio="xMidYMid" viewBox="0 0 256 293" width="16" height="16"><path fill="#7289DA" d="M226.011 0H29.99C13.459 0 0 13.458 0 30.135v197.778c0 16.677 13.458 30.135 29.989 30.135h165.888l-7.754-27.063 18.725 17.408 17.7 16.384L256 292.571V30.135C256 13.458 242.542 0 226.011 0zm-56.466 191.05s-5.266-6.291-9.655-11.85c19.164-5.413 26.478-17.408 26.478-17.408-5.998 3.95-11.703 6.73-16.823 8.63-7.314 3.073-14.336 5.12-21.211 6.291-14.044 2.633-26.917 1.902-37.888-.146-8.339-1.61-15.507-3.95-21.504-6.29-3.365-1.317-7.022-2.926-10.68-4.974-.438-.293-.877-.439-1.316-.732a2.022 2.022 0 0 1-.585-.438c-2.633-1.463-4.096-2.487-4.096-2.487s7.022 11.703 25.6 17.261c-4.388 5.56-9.801 12.142-9.801 12.142-32.33-1.024-44.617-22.235-44.617-22.235 0-47.104 21.065-85.285 21.065-85.285 21.065-15.799 41.106-15.36 41.106-15.36l1.463 1.756C80.75 77.53 68.608 89.088 68.608 89.088s3.218-1.755 8.63-4.242c15.653-6.876 28.088-8.777 33.208-9.216.877-.147 1.609-.293 2.487-.293a123.776 123.776 0 0 1 29.55-.292c13.896 1.609 28.818 5.705 44.031 14.043 0 0-11.556-10.971-36.425-18.578l2.048-2.34s20.041-.44 41.106 15.36c0 0 21.066 38.18 21.066 85.284 0 0-12.435 21.211-44.764 22.235zm-68.023-68.316c-8.338 0-14.92 7.314-14.92 16.237 0 8.924 6.728 16.238 14.92 16.238 8.339 0 14.921-7.314 14.921-16.238.147-8.923-6.582-16.237-14.92-16.237m53.394 0c-8.339 0-14.922 7.314-14.922 16.237 0 8.924 6.73 16.238 14.922 16.238 8.338 0 14.92-7.314 14.92-16.238 0-8.923-6.582-16.237-14.92-16.237"/></svg>
|
After Width: | Height: | Size: 1.6 KiB |
1
public/img/svg/gitea-dropbox.svg
generated
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="gitea-dropbox__svg gitea-dropbox__gitea-dropbox svg gitea-dropbox" viewBox="25 24.999 850 790.592" width="16" height="16"><g fill="#007ee5"><path d="M275.037 24.999 25 188.255l172.886 138.448L450 171.023zM25 465.16l250.037 163.256L450 482.374l-252.114-155.67zm425 17.214 174.963 146.042L875 465.16 702.114 326.703z"/><path d="M875 188.255 624.963 24.999 450 171.024l252.114 155.68zM450.513 513.797l-175.476 145.61-75.09-49.028v54.959L450.513 815.59 701.08 665.338v-54.96l-75.09 49.029z"/></g></svg>
|
After Width: | Height: | Size: 564 B |
1
public/img/svg/gitea-facebook.svg
generated
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="gitea-facebook__svg gitea-facebook__gitea-facebook svg gitea-facebook" style="shape-rendering:geometricPrecision;text-rendering:geometricPrecision;image-rendering:optimizeQuality;fill-rule:evenodd;clip-rule:evenodd" viewBox="0 0 128 128" width="16" height="16"><path fill="#395b97" d="M93.5 8.5c-1.452.802-3.118 1.302-5 1.5L10 88.5c-.198 1.882-.698 3.548-1.5 5a551.581 551.581 0 0 1-.5-56c2.5-17.167 12.333-27 29.5-29.5a551.581 551.581 0 0 1 56 .5Z" style="opacity:.995"/><path fill="#366098" d="M93.5 8.5c15.888 4.225 24.555 14.558 26 31a676.749 676.749 0 0 0-1.5 37l-35 35a32.438 32.438 0 0 0-.5 8 441.615 441.615 0 0 1-1-42h14a379.883 379.883 0 0 0 3-17h-17c-2.5-13.83 3.166-19.83 17-18v-16c-25.755-3.243-36.755 8.09-33 34h-14v17h14v42c-9.34.166-18.673 0-28-.5-15.451-1.953-25.118-10.453-29-25.5.802-1.452 1.302-3.118 1.5-5L88.5 10c1.882-.198 3.548-.698 5-1.5Z" style="opacity:.976"/><path fill="#346499" d="M119.5 39.5c.167 16.67 0 33.337-.5 50-3.622 20.245-15.788 30.245-36.5 30a32.438 32.438 0 0 1 .5-8l35-35c.169-12.507.669-24.84 1.5-37Z" style="opacity:.918"/></svg>
|
After Width: | Height: | Size: 1.1 KiB |
1
public/img/svg/gitea-google.svg
generated
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" class="gitea-google__svg gitea-google__gitea-google svg gitea-google" viewBox="0 0 48 48" width="16" height="16"><defs><path id="gitea-google__a" d="M44.5 20H24v8.5h11.8C34.7 33.9 30.1 37 24 37c-7.2 0-13-5.8-13-13s5.8-13 13-13c3.1 0 5.9 1.1 8.1 2.9l6.4-6.4C34.6 4.1 29.6 2 24 2 11.8 2 2 11.8 2 24s9.8 22 22 22c11 0 21-8 21-22 0-1.3-.2-2.7-.5-4z"/></defs><clipPath id="gitea-google__b"><use xlink:href="#gitea-google__a" overflow="visible"/></clipPath><path fill="#FBBC05" d="M0 37V11l17 13z" clip-path="url(#gitea-google__b)"/><path fill="#EA4335" d="m0 11 17 13 7-6.1L48 14V0H0z" clip-path="url(#gitea-google__b)"/><path fill="#34A853" d="m0 37 30-23 7.9 1L48 0v48H0z" clip-path="url(#gitea-google__b)"/><path fill="#4285F4" d="M48 48 17 24l-4-3 35-10z" clip-path="url(#gitea-google__b)"/></svg>
|
After Width: | Height: | Size: 898 B |
1
public/img/svg/gitea-mastodon.svg
generated
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="gitea-mastodon__svg gitea-mastodon__gitea-mastodon svg gitea-mastodon" viewBox="-0.41 0.22 747.62 801.45" width="16" height="16"><path fill="#3088d4" d="M729.94 479.5c-10.96 56.4-98.17 118.12-198.34 130.08-52.23 6.23-103.66 11.96-158.49 9.44-89.68-4.1-160.45-21.4-160.45-21.4 0 8.73.54 17.04 1.62 24.81 11.66 88.52 87.76 93.82 159.84 96.29 72.76 2.49 137.55-17.94 137.55-17.94l2.99 65.79s-50.89 27.32-141.55 32.35c-50 2.75-112.07-1.26-184.37-20.39C31.94 737.02 4.97 569.86.85 400.26-.41 349.9.37 302.42.37 262.7.37 89.27 113.99 38.44 113.99 38.44 171.28 12.12 269.59 1.06 371.79.22h2.52c102.19.84 200.57 11.9 257.86 38.22 0 0 113.62 50.83 113.62 224.26 0 0 1.42 127.96-15.85 216.8"/><path fill="#fff" d="M611.77 276.16v209.99h-83.2V282.33c0-42.97-18.07-64.77-54.23-64.77-39.98 0-60.01 25.86-60.01 77.02v111.57h-82.71V294.58c0-51.16-20.04-77.02-60.01-77.02-36.16 0-54.24 21.8-54.24 64.77v203.82h-83.19V276.16c0-42.92 10.93-77.03 32.88-102.26 22.63-25.23 52.27-38.17 89.07-38.17 42.57 0 74.81 16.37 96.12 49.1l20.72 34.74 20.73-34.74c21.31-32.73 53.55-49.1 96.12-49.1 36.79 0 66.44 12.94 89.07 38.17 21.95 25.23 32.88 59.34 32.88 102.26z"/></svg>
|
After Width: | Height: | Size: 1.2 KiB |
1
public/img/svg/gitea-microsoftonline.svg
generated
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="gitea-microsoftonline__svg gitea-microsoftonline__gitea-microsoftonline svg gitea-microsoftonline" viewBox="0 0 2075 2499.8" width="16" height="16"><path fill="#eb3c00" d="M0 2016.6V496.8L1344.4 0 2075 233.7v2045.9l-730.6 220.3L0 2016.6l1344.4 161.8V409.2L467.6 613.8v1198.3z"/></svg>
|
After Width: | Height: | Size: 350 B |
1
public/img/svg/gitea-nextcloud.svg
generated
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="gitea-nextcloud__svg gitea-nextcloud__gitea-nextcloud svg gitea-nextcloud" style="shape-rendering:geometricPrecision;text-rendering:geometricPrecision;image-rendering:optimizeQuality;fill-rule:evenodd;clip-rule:evenodd" viewBox="0 0 128 128" width="16" height="16"><path fill="#0382c9" d="M12.5-.5h102a796.486 796.486 0 0 0 7 4.5 68.97 68.97 0 0 1 6 8.5v102a785.54 785.54 0 0 0-4.5 7 68.927 68.927 0 0 1-8.5 6h-102a779.088 779.088 0 0 0-7-4.5 68.94 68.94 0 0 1-6-8.5v-102a789.852 789.852 0 0 0 4.5-7 68.982 68.982 0 0 1 8.5-6Z" style="opacity:.997"/><path fill="#fafcfe" d="M55.5 37.5c16.649-2.824 28.149 3.51 34.5 19 6.704-10.658 15.537-12.825 26.5-6.5 9.555 10.007 9.222 19.673-1 29-10.492 5.063-18.992 2.897-25.5-6.5C83.734 86.553 72.9 92.72 57.5 91c-9.864-2.843-16.697-9.01-20.5-18.5-6.582 9.277-15.082 11.444-25.5 6.5-10.222-9.327-10.555-18.993-1-29 10.809-5.923 19.642-3.756 26.5 6.5 3.713-8.878 9.88-15.211 18.5-19Z" style="opacity:1"/><path fill="#0b83c9" d="M58.5 47.5c17.163-.677 23.996 7.323 20.5 24-6.538 9.38-15.038 11.546-25.5 6.5-10.605-12.356-8.939-22.523 5-30.5Z" style="opacity:1"/><path fill="#1986cb" d="M18.5 56.5c7.7-.138 10.867 3.529 9.5 11-4.041 4.813-8.375 5.146-13 1-1.407-4.857-.24-8.857 3.5-12Z" style="opacity:1"/><path fill="#2088cb" d="M103.5 56.5c7.801.619 10.635 4.619 8.5 12-4.709 4.27-9.042 3.936-13-1-1.607-5.062-.107-8.728 4.5-11Z" style="opacity:1"/></svg>
|
After Width: | Height: | Size: 1.4 KiB |
1
public/img/svg/gitea-twitter.svg
generated
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" aria-hidden="true" class="gitea-twitter__svg gitea-twitter__gitea-twitter svg gitea-twitter" clip-rule="evenodd" viewBox="-89.009 -46.884 643.937 446.884" width="16" height="16"><path fill="#1da1f2" fill-rule="nonzero" d="M154.729 400c185.669 0 287.205-153.876 287.205-287.312 0-4.37-.089-8.72-.286-13.052A205.304 205.304 0 0 0 492 47.346c-18.087 8.044-37.55 13.458-57.968 15.899 20.841-12.501 36.84-32.278 44.389-55.852a202.42 202.42 0 0 1-64.098 24.511C395.903 12.276 369.679 0 340.641 0c-55.744 0-100.948 45.222-100.948 100.965 0 7.925.887 15.631 2.619 23.025-83.895-4.223-158.287-44.405-208.074-105.504A100.739 100.739 0 0 0 20.57 69.24c0 35.034 17.82 65.961 44.92 84.055a100.172 100.172 0 0 1-45.716-12.63c-.015.424-.015.837-.015 1.29 0 48.903 34.794 89.734 80.982 98.986a101.036 101.036 0 0 1-26.617 3.553c-6.493 0-12.821-.639-18.971-1.82 12.851 40.122 50.115 69.319 94.296 70.135-34.549 27.089-78.07 43.224-125.371 43.224A204.9 204.9 0 0 1 0 354.634c44.674 28.645 97.72 45.359 154.734 45.359"/></svg>
|
After Width: | Height: | Size: 1.1 KiB |
1
public/img/svg/gitea-yandex.svg
generated
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="gitea-yandex__svg gitea-yandex__gitea-yandex svg gitea-yandex" viewBox="0 0 64 64" width="16" height="16"><path fill="#e52620" d="M49.07 0c.524.405.262.88.095 1.333l-6.643 18.095-8.047 22.12a4.21 4.21 0 0 0-.262 1.429v19.81c0 1.2-.024 1.2-1.214 1.2-1.238 0-2.476-.048-3.714.024-.786.024-1.07-.238-1.048-1.024l.024-7.333V42.928c0-.5-.07-1.048-.262-1.524L14.976 7.333c-.095-.262-.238-.476-.357-.714v-.5c.38-.12.762-.3 1.143-.3l4.12-.024s1.357 0 1.81 1.286l9.7 27.31.405.976.333-1.095 1.905-6.976 8.5-26.31c.12-.333.405-.62.62-.93L49.07 0z"/></svg>
|
After Width: | Height: | Size: 611 B |
@ -21,11 +21,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
uuidHeaderKey = "x-runner-uuid"
|
uuidHeaderKey = "x-runner-uuid"
|
||||||
tokenHeaderKey = "x-runner-token"
|
tokenHeaderKey = "x-runner-token"
|
||||||
|
// Deprecated: will be removed after Gitea 1.20 released.
|
||||||
versionHeaderKey = "x-runner-version"
|
versionHeaderKey = "x-runner-version"
|
||||||
|
|
||||||
versionUnknown = "Unknown"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var withRunner = connect.WithInterceptors(connect.UnaryInterceptorFunc(func(unaryFunc connect.UnaryFunc) connect.UnaryFunc {
|
var withRunner = connect.WithInterceptors(connect.UnaryInterceptorFunc(func(unaryFunc connect.UnaryFunc) connect.UnaryFunc {
|
||||||
@ -36,11 +35,9 @@ var withRunner = connect.WithInterceptors(connect.UnaryInterceptorFunc(func(unar
|
|||||||
}
|
}
|
||||||
uuid := request.Header().Get(uuidHeaderKey)
|
uuid := request.Header().Get(uuidHeaderKey)
|
||||||
token := request.Header().Get(tokenHeaderKey)
|
token := request.Header().Get(tokenHeaderKey)
|
||||||
|
// TODO: version will be removed from request header after Gitea 1.20 released.
|
||||||
|
// And Gitea will not try to read version from reuqest header
|
||||||
version := request.Header().Get(versionHeaderKey)
|
version := request.Header().Get(versionHeaderKey)
|
||||||
if util.IsEmptyString(version) {
|
|
||||||
version = versionUnknown
|
|
||||||
}
|
|
||||||
version, _ = util.SplitStringAtByteN(version, 64)
|
|
||||||
|
|
||||||
runner, err := actions_model.GetRunnerByUUID(ctx, uuid)
|
runner, err := actions_model.GetRunnerByUUID(ctx, uuid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -54,7 +51,11 @@ var withRunner = connect.WithInterceptors(connect.UnaryInterceptorFunc(func(unar
|
|||||||
}
|
}
|
||||||
|
|
||||||
cols := []string{"last_online"}
|
cols := []string{"last_online"}
|
||||||
if runner.Version != version {
|
|
||||||
|
// TODO: version will be removed from request header after Gitea 1.20 released.
|
||||||
|
// And Gitea will not try to read version from reuqest header
|
||||||
|
version, _ = util.SplitStringAtByteN(version, 64)
|
||||||
|
if !util.IsEmptyString(version) && runner.Version != version {
|
||||||
runner.Version = version
|
runner.Version = version
|
||||||
cols = append(cols, "version")
|
cols = append(cols, "version")
|
||||||
}
|
}
|
||||||
|
@ -54,15 +54,23 @@ func (s *Service) Register(
|
|||||||
return nil, errors.New("runner token has already been activated")
|
return nil, errors.New("runner token has already been activated")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
labels := req.Msg.Labels
|
||||||
|
// TODO: agent_labels should be removed from pb after Gitea 1.20 released.
|
||||||
|
// Old version runner's agent_labels slice is not empty and labels slice is empty.
|
||||||
|
// And due to compatibility with older versions, it is temporarily marked as Deprecated in pb, so use `//nolint` here.
|
||||||
|
if len(req.Msg.AgentLabels) > 0 && len(req.Msg.Labels) == 0 { //nolint:staticcheck
|
||||||
|
labels = req.Msg.AgentLabels //nolint:staticcheck
|
||||||
|
}
|
||||||
|
|
||||||
// create new runner
|
// create new runner
|
||||||
name, _ := util.SplitStringAtByteN(req.Msg.Name, 255)
|
name, _ := util.SplitStringAtByteN(req.Msg.Name, 255)
|
||||||
runner := &actions_model.ActionRunner{
|
runner := &actions_model.ActionRunner{
|
||||||
UUID: gouuid.New().String(),
|
UUID: gouuid.New().String(),
|
||||||
Name: name,
|
Name: name,
|
||||||
OwnerID: runnerToken.OwnerID,
|
OwnerID: runnerToken.OwnerID,
|
||||||
RepoID: runnerToken.RepoID,
|
RepoID: runnerToken.RepoID,
|
||||||
AgentLabels: req.Msg.AgentLabels,
|
Version: req.Msg.Version,
|
||||||
CustomLabels: req.Msg.CustomLabels,
|
AgentLabels: labels,
|
||||||
}
|
}
|
||||||
if err := runner.GenerateToken(); err != nil {
|
if err := runner.GenerateToken(); err != nil {
|
||||||
return nil, errors.New("can't generate token")
|
return nil, errors.New("can't generate token")
|
||||||
@ -81,18 +89,41 @@ func (s *Service) Register(
|
|||||||
|
|
||||||
res := connect.NewResponse(&runnerv1.RegisterResponse{
|
res := connect.NewResponse(&runnerv1.RegisterResponse{
|
||||||
Runner: &runnerv1.Runner{
|
Runner: &runnerv1.Runner{
|
||||||
Id: runner.ID,
|
Id: runner.ID,
|
||||||
Uuid: runner.UUID,
|
Uuid: runner.UUID,
|
||||||
Token: runner.Token,
|
Token: runner.Token,
|
||||||
Name: runner.Name,
|
Name: runner.Name,
|
||||||
AgentLabels: runner.AgentLabels,
|
Version: runner.Version,
|
||||||
CustomLabels: runner.CustomLabels,
|
Labels: runner.AgentLabels,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) Declare(
|
||||||
|
ctx context.Context,
|
||||||
|
req *connect.Request[runnerv1.DeclareRequest],
|
||||||
|
) (*connect.Response[runnerv1.DeclareResponse], error) {
|
||||||
|
runner := GetRunner(ctx)
|
||||||
|
runner.AgentLabels = req.Msg.Labels
|
||||||
|
runner.Version = req.Msg.Version
|
||||||
|
if err := actions_model.UpdateRunner(ctx, runner, "agent_labels", "version"); err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "update runner: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return connect.NewResponse(&runnerv1.DeclareResponse{
|
||||||
|
Runner: &runnerv1.Runner{
|
||||||
|
Id: runner.ID,
|
||||||
|
Uuid: runner.UUID,
|
||||||
|
Token: runner.Token,
|
||||||
|
Name: runner.Name,
|
||||||
|
Version: runner.Version,
|
||||||
|
Labels: runner.AgentLabels,
|
||||||
|
},
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
// FetchTask assigns a task to the runner
|
// FetchTask assigns a task to the runner
|
||||||
func (s *Service) FetchTask(
|
func (s *Service) FetchTask(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
|
@ -98,8 +98,8 @@ func generateTaskContext(t *actions_model.ActionTask) *structpb.Struct {
|
|||||||
baseRef = pullPayload.PullRequest.Base.Ref
|
baseRef = pullPayload.PullRequest.Base.Ref
|
||||||
headRef = pullPayload.PullRequest.Head.Ref
|
headRef = pullPayload.PullRequest.Head.Ref
|
||||||
}
|
}
|
||||||
|
|
||||||
refName := git.RefName(t.Job.Run.Ref)
|
refName := git.RefName(t.Job.Run.Ref)
|
||||||
refType := refName.RefGroup()
|
|
||||||
|
|
||||||
taskContext, err := structpb.NewStruct(map[string]interface{}{
|
taskContext, err := structpb.NewStruct(map[string]interface{}{
|
||||||
// standard contexts, see https://docs.github.com/en/actions/learn-github-actions/contexts#github-context
|
// standard contexts, see https://docs.github.com/en/actions/learn-github-actions/contexts#github-context
|
||||||
@ -121,7 +121,7 @@ func generateTaskContext(t *actions_model.ActionTask) *structpb.Struct {
|
|||||||
"ref": t.Job.Run.Ref, // string, The fully-formed ref of the branch or tag that triggered the workflow run. For workflows triggered by push, this is the branch or tag ref that was pushed. For workflows triggered by pull_request, this is the pull request merge branch. For workflows triggered by release, this is the release tag created. For other triggers, this is the branch or tag ref that triggered the workflow run. This is only set if a branch or tag is available for the event type. The ref given is fully-formed, meaning that for branches the format is refs/heads/<branch_name>, for pull requests it is refs/pull/<pr_number>/merge, and for tags it is refs/tags/<tag_name>. For example, refs/heads/feature-branch-1.
|
"ref": t.Job.Run.Ref, // string, The fully-formed ref of the branch or tag that triggered the workflow run. For workflows triggered by push, this is the branch or tag ref that was pushed. For workflows triggered by pull_request, this is the pull request merge branch. For workflows triggered by release, this is the release tag created. For other triggers, this is the branch or tag ref that triggered the workflow run. This is only set if a branch or tag is available for the event type. The ref given is fully-formed, meaning that for branches the format is refs/heads/<branch_name>, for pull requests it is refs/pull/<pr_number>/merge, and for tags it is refs/tags/<tag_name>. For example, refs/heads/feature-branch-1.
|
||||||
"ref_name": refName.String(), // string, The short ref name of the branch or tag that triggered the workflow run. This value matches the branch or tag name shown on GitHub. For example, feature-branch-1.
|
"ref_name": refName.String(), // string, The short ref name of the branch or tag that triggered the workflow run. This value matches the branch or tag name shown on GitHub. For example, feature-branch-1.
|
||||||
"ref_protected": false, // boolean, true if branch protections are configured for the ref that triggered the workflow run.
|
"ref_protected": false, // boolean, true if branch protections are configured for the ref that triggered the workflow run.
|
||||||
"ref_type": refType, // string, The type of ref that triggered the workflow run. Valid values are branch or tag.
|
"ref_type": refName.RefType(), // string, The type of ref that triggered the workflow run. Valid values are branch or tag.
|
||||||
"path": "", // string, Path on the runner to the file that sets system PATH variables from workflow commands. This file is unique to the current step and is a different file for each step in a job. For more information, see "Workflow commands for GitHub Actions."
|
"path": "", // string, Path on the runner to the file that sets system PATH variables from workflow commands. This file is unique to the current step and is a different file for each step in a job. For more information, see "Workflow commands for GitHub Actions."
|
||||||
"repository": t.Job.Run.Repo.OwnerName + "/" + t.Job.Run.Repo.Name, // string, The owner and repository name. For example, Codertocat/Hello-World.
|
"repository": t.Job.Run.Repo.OwnerName + "/" + t.Job.Run.Repo.Name, // string, The owner and repository name. For example, Codertocat/Hello-World.
|
||||||
"repository_owner": t.Job.Run.Repo.OwnerName, // string, The repository owner's name. For example, Codertocat.
|
"repository_owner": t.Job.Run.Repo.OwnerName, // string, The repository owner's name. For example, Codertocat.
|
||||||
|
@ -84,7 +84,6 @@ func List(ctx *context.Context) {
|
|||||||
allRunnerLabels := make(container.Set[string])
|
allRunnerLabels := make(container.Set[string])
|
||||||
for _, r := range runners {
|
for _, r := range runners {
|
||||||
allRunnerLabels.AddMultiple(r.AgentLabels...)
|
allRunnerLabels.AddMultiple(r.AgentLabels...)
|
||||||
allRunnerLabels.AddMultiple(r.CustomLabels...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
workflows = make([]Workflow, 0, len(entries))
|
workflows = make([]Workflow, 0, len(entries))
|
||||||
|
@ -247,7 +247,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
|
|||||||
ctx.Data["FileError"] = ctx.Locale.Tr("actions.runs.invalid_workflow_helper", workFlowErr.Error())
|
ctx.Data["FileError"] = ctx.Locale.Tr("actions.runs.invalid_workflow_helper", workFlowErr.Error())
|
||||||
}
|
}
|
||||||
} else if util.SliceContains([]string{"CODEOWNERS", "docs/CODEOWNERS", ".gitea/CODEOWNERS"}, ctx.Repo.TreePath) {
|
} else if util.SliceContains([]string{"CODEOWNERS", "docs/CODEOWNERS", ".gitea/CODEOWNERS"}, ctx.Repo.TreePath) {
|
||||||
if data, err := blob.GetBlobContent(); err == nil {
|
if data, err := blob.GetBlobContent(setting.UI.MaxDisplayFileSize); err == nil {
|
||||||
_, warnings := issue_model.GetCodeOwnersFromContent(ctx, data)
|
_, warnings := issue_model.GetCodeOwnersFromContent(ctx, data)
|
||||||
if len(warnings) > 0 {
|
if len(warnings) > 0 {
|
||||||
ctx.Data["FileWarning"] = strings.Join(warnings, "\n")
|
ctx.Data["FileWarning"] = strings.Join(warnings, "\n")
|
||||||
|
@ -6,7 +6,6 @@ package actions
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
|
||||||
|
|
||||||
actions_model "code.gitea.io/gitea/models/actions"
|
actions_model "code.gitea.io/gitea/models/actions"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
@ -126,9 +125,8 @@ func RunnerDetailsEditPost(ctx *context.Context, runnerID, ownerID, repoID int64
|
|||||||
|
|
||||||
form := web.GetForm(ctx).(*forms.EditRunnerForm)
|
form := web.GetForm(ctx).(*forms.EditRunnerForm)
|
||||||
runner.Description = form.Description
|
runner.Description = form.Description
|
||||||
runner.CustomLabels = splitLabels(form.CustomLabels)
|
|
||||||
|
|
||||||
err = actions_model.UpdateRunner(ctx, runner, "description", "custom_labels")
|
err = actions_model.UpdateRunner(ctx, runner, "description")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("RunnerDetailsEditPost.UpdateRunner failed: %v, url: %s", err, ctx.Req.URL)
|
log.Warn("RunnerDetailsEditPost.UpdateRunner failed: %v, url: %s", err, ctx.Req.URL)
|
||||||
ctx.Flash.Warning(ctx.Tr("actions.runners.update_runner_failed"))
|
ctx.Flash.Warning(ctx.Tr("actions.runners.update_runner_failed"))
|
||||||
@ -176,11 +174,3 @@ func RunnerDeletePost(ctx *context.Context, runnerID int64,
|
|||||||
"redirect": successRedirectTo,
|
"redirect": successRedirectTo,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func splitLabels(s string) []string {
|
|
||||||
labels := strings.Split(s, ",")
|
|
||||||
for i, v := range labels {
|
|
||||||
labels[i] = strings.TrimSpace(v)
|
|
||||||
}
|
|
||||||
return labels
|
|
||||||
}
|
|
||||||
|
@ -107,7 +107,7 @@ func Profile(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
blob, err := commit.GetBlobByPath("README.md")
|
blob, err := commit.GetBlobByPath("README.md")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
bytes, err := blob.GetBlobContent()
|
bytes, err := blob.GetBlobContent(setting.UI.MaxDisplayFileSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetBlobContent", err)
|
ctx.ServerError("GetBlobContent", err)
|
||||||
return
|
return
|
||||||
|
@ -384,7 +384,7 @@ func (n *actionsNotifier) NotifyCreateRef(ctx context.Context, pusher *user_mode
|
|||||||
WithPayload(&api.CreatePayload{
|
WithPayload(&api.CreatePayload{
|
||||||
Ref: refFullName.ShortName(),
|
Ref: refFullName.ShortName(),
|
||||||
Sha: refID,
|
Sha: refID,
|
||||||
RefType: refFullName.RefGroup(),
|
RefType: refFullName.RefType(),
|
||||||
Repo: apiRepo,
|
Repo: apiRepo,
|
||||||
Sender: apiPusher,
|
Sender: apiPusher,
|
||||||
}).
|
}).
|
||||||
@ -401,7 +401,7 @@ func (n *actionsNotifier) NotifyDeleteRef(ctx context.Context, pusher *user_mode
|
|||||||
WithRef(refFullName.ShortName()). // FIXME: should we use a full ref name
|
WithRef(refFullName.ShortName()). // FIXME: should we use a full ref name
|
||||||
WithPayload(&api.DeletePayload{
|
WithPayload(&api.DeletePayload{
|
||||||
Ref: refFullName.ShortName(),
|
Ref: refFullName.ShortName(),
|
||||||
RefType: refFullName.RefGroup(),
|
RefType: refFullName.RefType(),
|
||||||
PusherType: api.PusherTypeUser,
|
PusherType: api.PusherTypeUser,
|
||||||
Repo: apiRepo,
|
Repo: apiRepo,
|
||||||
Sender: apiPusher,
|
Sender: apiPusher,
|
||||||
|
@ -5,6 +5,9 @@ package oauth2
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"html"
|
||||||
|
"html/template"
|
||||||
"net/url"
|
"net/url"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
@ -19,7 +22,7 @@ import (
|
|||||||
type Provider interface {
|
type Provider interface {
|
||||||
Name() string
|
Name() string
|
||||||
DisplayName() string
|
DisplayName() string
|
||||||
IconURL() string
|
IconHTML() template.HTML
|
||||||
CustomURLSettings() *CustomURLSettings
|
CustomURLSettings() *CustomURLSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,7 +38,7 @@ type GothProvider interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AuthSourceProvider provides a provider for an AuthSource. Multiple auth sources could use the same registered GothProvider
|
// AuthSourceProvider provides a provider for an AuthSource. Multiple auth sources could use the same registered GothProvider
|
||||||
// So each auth source should have its own DisplayName and IconURL for display.
|
// So each auth source should have its own DisplayName and IconHTML for display.
|
||||||
// The Name is the GothProvider's name, to help to find the GothProvider to sign in.
|
// The Name is the GothProvider's name, to help to find the GothProvider to sign in.
|
||||||
// The DisplayName is the auth source config's name, site admin set it on the admin page, the IconURL can also be set there.
|
// The DisplayName is the auth source config's name, site admin set it on the admin page, the IconURL can also be set there.
|
||||||
type AuthSourceProvider struct {
|
type AuthSourceProvider struct {
|
||||||
@ -51,11 +54,14 @@ func (p *AuthSourceProvider) DisplayName() string {
|
|||||||
return p.sourceName
|
return p.sourceName
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *AuthSourceProvider) IconURL() string {
|
func (p *AuthSourceProvider) IconHTML() template.HTML {
|
||||||
if p.iconURL != "" {
|
if p.iconURL != "" {
|
||||||
return p.iconURL
|
img := fmt.Sprintf(`<img class="gt-mr-3" width="20" height="20" src="%s" alt="%s">`,
|
||||||
|
html.EscapeString(p.iconURL), html.EscapeString(p.DisplayName()),
|
||||||
|
)
|
||||||
|
return template.HTML(img)
|
||||||
}
|
}
|
||||||
return p.GothProvider.IconURL()
|
return p.GothProvider.IconHTML()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Providers contains the map of registered OAuth2 providers in Gitea (based on goth)
|
// Providers contains the map of registered OAuth2 providers in Gitea (based on goth)
|
||||||
|
@ -3,7 +3,12 @@
|
|||||||
|
|
||||||
package oauth2
|
package oauth2
|
||||||
|
|
||||||
import "code.gitea.io/gitea/modules/setting"
|
import (
|
||||||
|
"html/template"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/svg"
|
||||||
|
)
|
||||||
|
|
||||||
// BaseProvider represents a common base for Provider
|
// BaseProvider represents a common base for Provider
|
||||||
type BaseProvider struct {
|
type BaseProvider struct {
|
||||||
@ -21,14 +26,21 @@ func (b *BaseProvider) DisplayName() string {
|
|||||||
return b.displayName
|
return b.displayName
|
||||||
}
|
}
|
||||||
|
|
||||||
// IconURL returns an icon path for this provider
|
// IconHTML returns icon HTML for this provider
|
||||||
// Use svg for default icons, providers_openid has its own IconURL function
|
func (b *BaseProvider) IconHTML() template.HTML {
|
||||||
func (b *BaseProvider) IconURL() string {
|
svgName := "gitea-" + b.name
|
||||||
name := b.name
|
switch b.name {
|
||||||
if b.name == "gplus" {
|
case "gplus":
|
||||||
name = "google"
|
svgName = "gitea-google"
|
||||||
|
case "github":
|
||||||
|
svgName = "octicon-mark-github"
|
||||||
}
|
}
|
||||||
return setting.AppSubURL + "/assets/img/auth/" + name + ".svg"
|
svgHTML := svg.RenderHTML(svgName, 20, "gt-mr-3")
|
||||||
|
if svgHTML == "" {
|
||||||
|
log.Error("No SVG icon for oauth2 provider %q", b.name)
|
||||||
|
svgHTML = svg.RenderHTML("gitea-openid", 20, "gt-mr-3")
|
||||||
|
}
|
||||||
|
return svgHTML
|
||||||
}
|
}
|
||||||
|
|
||||||
// CustomURLSettings returns the custom url settings for this provider
|
// CustomURLSettings returns the custom url settings for this provider
|
||||||
|
@ -4,8 +4,11 @@
|
|||||||
package oauth2
|
package oauth2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"html/template"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/svg"
|
||||||
|
|
||||||
"github.com/markbates/goth"
|
"github.com/markbates/goth"
|
||||||
"github.com/markbates/goth/providers/openidConnect"
|
"github.com/markbates/goth/providers/openidConnect"
|
||||||
@ -24,9 +27,9 @@ func (o *OpenIDProvider) DisplayName() string {
|
|||||||
return "OpenID Connect"
|
return "OpenID Connect"
|
||||||
}
|
}
|
||||||
|
|
||||||
// IconURL returns an icon path for this provider
|
// IconHTML returns icon HTML for this provider
|
||||||
func (o *OpenIDProvider) IconURL() string {
|
func (o *OpenIDProvider) IconHTML() template.HTML {
|
||||||
return setting.AppSubURL + "/assets/img/svg/gitea-openid.svg"
|
return svg.RenderHTML("gitea-openid", 20, "gt-mr-3")
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateGothProvider creates a GothProvider from this Provider
|
// CreateGothProvider creates a GothProvider from this Provider
|
||||||
|
@ -14,8 +14,7 @@ import (
|
|||||||
|
|
||||||
// EditRunnerForm form for admin to create runner
|
// EditRunnerForm form for admin to create runner
|
||||||
type EditRunnerForm struct {
|
type EditRunnerForm struct {
|
||||||
Description string
|
Description string
|
||||||
CustomLabels string // comma-separated
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates form fields
|
// Validate validates form fields
|
||||||
|
@ -203,7 +203,7 @@ func GetContents(ctx context.Context, repo *repo_model.Repository, treePath, ref
|
|||||||
} else if entry.IsLink() {
|
} else if entry.IsLink() {
|
||||||
contentsResponse.Type = string(ContentTypeLink)
|
contentsResponse.Type = string(ContentTypeLink)
|
||||||
// The target of a symlink file is the content of the file
|
// The target of a symlink file is the content of the file
|
||||||
targetFromContent, err := entry.Blob().GetBlobContent()
|
targetFromContent, err := entry.Blob().GetBlobContent(1024)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -755,7 +755,7 @@ func (m *webhookNotifier) NotifyCreateRef(ctx context.Context, pusher *user_mode
|
|||||||
if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventCreate, &api.CreatePayload{
|
if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventCreate, &api.CreatePayload{
|
||||||
Ref: refName, // FIXME: should it be a full ref name?
|
Ref: refName, // FIXME: should it be a full ref name?
|
||||||
Sha: refID,
|
Sha: refID,
|
||||||
RefType: refFullName.RefGroup(),
|
RefType: refFullName.RefType(),
|
||||||
Repo: apiRepo,
|
Repo: apiRepo,
|
||||||
Sender: apiPusher,
|
Sender: apiPusher,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
@ -791,12 +791,12 @@ func (m *webhookNotifier) NotifyDeleteRef(ctx context.Context, pusher *user_mode
|
|||||||
|
|
||||||
if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventDelete, &api.DeletePayload{
|
if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventDelete, &api.DeletePayload{
|
||||||
Ref: refName, // FIXME: should it be a full ref name?
|
Ref: refName, // FIXME: should it be a full ref name?
|
||||||
RefType: refFullName.RefGroup(),
|
RefType: refFullName.RefType(),
|
||||||
PusherType: api.PusherTypeUser,
|
PusherType: api.PusherTypeUser,
|
||||||
Repo: apiRepo,
|
Repo: apiRepo,
|
||||||
Sender: apiPusher,
|
Sender: apiPusher,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
log.Error("PrepareWebhooks.(delete %s): %v", refFullName.RefGroup(), err)
|
log.Error("PrepareWebhooks.(delete %s): %v", refFullName.RefType(), err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +186,7 @@
|
|||||||
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<button class="ui green button">{{$.locale.Tr "settings.update_avatar"}}</button>
|
<button class="ui green button">{{$.locale.Tr "settings.update_avatar"}}</button>
|
||||||
<a class="ui red button delete-post" data-request-url="{{.Link}}/avatar/delete" data-done-url="{{.Link}}">{{$.locale.Tr "settings.delete_current_avatar"}}</a>{{/* TODO: Convert links without href to buttons for a11y */}}
|
<button class="ui red button link-action" data-url="{{.Link}}/avatar/delete" data-redirect="{{.Link}}">{{$.locale.Tr "settings.delete_current_avatar"}}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -32,11 +32,13 @@ If you introduce mistakes in it, Gitea JavaScript code wouldn't run correctly.
|
|||||||
mermaidMaxSourceCharacters: {{MermaidMaxSourceCharacters}},
|
mermaidMaxSourceCharacters: {{MermaidMaxSourceCharacters}},
|
||||||
{{/* this global i18n object should only contain general texts. for specialized texts, it should be provided inside the related modules by: (1) API response (2) HTML data-attribute (3) PageData */}}
|
{{/* this global i18n object should only contain general texts. for specialized texts, it should be provided inside the related modules by: (1) API response (2) HTML data-attribute (3) PageData */}}
|
||||||
i18n: {
|
i18n: {
|
||||||
copy_success: '{{.locale.Tr "copy_success"}}',
|
copy_success: {{.locale.Tr "copy_success"}},
|
||||||
copy_error: '{{.locale.Tr "copy_error"}}',
|
copy_error: {{.locale.Tr "copy_error"}},
|
||||||
error_occurred: '{{.locale.Tr "error.occurred"}}',
|
error_occurred: {{.locale.Tr "error.occurred"}},
|
||||||
network_error: '{{.locale.Tr "error.network_error"}}',
|
network_error: {{.locale.Tr "error.network_error"}},
|
||||||
remove_label_str: '{{.locale.Tr "remove_label_str"}}',
|
remove_label_str: {{.locale.Tr "remove_label_str"}},
|
||||||
|
modal_confirm: {{.locale.Tr "modal.confirm"}},
|
||||||
|
modal_cancel: {{.locale.Tr "modal.cancel"}},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
{{/* in case some pages don't render the pageData, we make sure it is an object to prevent null access */}}
|
{{/* in case some pages don't render the pageData, we make sure it is an object to prevent null access */}}
|
||||||
|
@ -90,7 +90,7 @@
|
|||||||
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<button class="ui green button">{{$.locale.Tr "settings.update_avatar"}}</button>
|
<button class="ui green button">{{$.locale.Tr "settings.update_avatar"}}</button>
|
||||||
<a class="ui red button delete-post" data-request-url="{{.Link}}/avatar/delete" data-done-url="{{.Link}}">{{$.locale.Tr "settings.delete_current_avatar"}}</a>
|
<button class="ui red button link-action" data-url="{{.Link}}/avatar/delete" data-redirect="{{.Link}}">{{$.locale.Tr "settings.delete_current_avatar"}}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -9,14 +9,12 @@
|
|||||||
{{template "org/team/navbar" .}}
|
{{template "org/team/navbar" .}}
|
||||||
{{if .IsOrganizationOwner}}
|
{{if .IsOrganizationOwner}}
|
||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
<form class="ui form ignore-dirty" id="add-member-form" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/add" method="post">
|
<form class="ui form ignore-dirty gt-df gt-fw gt-gap-3" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/add" method="post">
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
<input type="hidden" name="uid" value="{{.SignedUser.ID}}">
|
<input type="hidden" name="uid" value="{{.SignedUser.ID}}">
|
||||||
<div class="inline field ui left">
|
<div id="search-user-box" class="ui search gt-mr-3"{{if .IsEmailInviteEnabled}} data-allow-email="true" data-allow-email-description="{{.locale.Tr "org.teams.invite_team_member" $.Team.Name}}"{{end}}>
|
||||||
<div id="search-user-box" class="ui search"{{if .IsEmailInviteEnabled}} data-allow-email="true" data-allow-email-description="{{.locale.Tr "org.teams.invite_team_member" $.Team.Name}}"{{end}}>
|
<div class="ui input">
|
||||||
<div class="ui input">
|
<input class="prompt" name="uname" placeholder="{{.locale.Tr "repo.settings.search_user_placeholder"}}" autocomplete="off" required>
|
||||||
<input class="prompt" name="uname" placeholder="{{.locale.Tr "repo.settings.search_user_placeholder"}}" autocomplete="off" required>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="ui green button">{{.locale.Tr "org.teams.add_team_member"}}</button>
|
<button class="ui green button">{{.locale.Tr "org.teams.add_team_member"}}</button>
|
||||||
|
@ -9,25 +9,19 @@
|
|||||||
{{template "org/team/navbar" .}}
|
{{template "org/team/navbar" .}}
|
||||||
{{$canAddRemove := and $.IsOrganizationOwner (not $.Team.IncludesAllRepositories)}}
|
{{$canAddRemove := and $.IsOrganizationOwner (not $.Team.IncludesAllRepositories)}}
|
||||||
{{if $canAddRemove}}
|
{{if $canAddRemove}}
|
||||||
<div class="ui attached segment" id="repo-top-segment">
|
<div class="ui attached segment gt-df gt-fw gt-gap-3">
|
||||||
<div class="inline ui field left">
|
<form class="ui form ignore-dirty gt-f1 gt-dif" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/repo/add" method="post">
|
||||||
<form class="ui form ignore-dirty" id="add-repo-form" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/repo/add" method="post">
|
{{.CsrfTokenHtml}}
|
||||||
{{.CsrfTokenHtml}}
|
<div id="search-repo-box" data-uid="{{.Org.ID}}" class="ui search">
|
||||||
<div class="inline field ui left">
|
<div class="ui input">
|
||||||
<div id="search-repo-box" data-uid="{{.Org.ID}}" class="ui search">
|
<input class="prompt" name="repo_name" placeholder="{{.locale.Tr "org.teams.search_repo_placeholder"}}" autocomplete="off" required>
|
||||||
<div class="ui input">
|
|
||||||
<input class="prompt" name="repo_name" placeholder="{{.locale.Tr "org.teams.search_repo_placeholder"}}" autocomplete="off" required>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<button class="ui green button">{{.locale.Tr "add"}}</button>
|
</div>
|
||||||
</form>
|
<button class="ui green button gt-ml-3">{{.locale.Tr "add"}}</button>
|
||||||
</div>
|
</form>
|
||||||
<div class="inline ui field right">
|
<div class="gt-dib">
|
||||||
<form class="ui form" id="repo-multiple-form" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/repositories" method="post">
|
<button class="ui green button link-action" data-modal-confirm="{{.locale.Tr "org.teams.add_all_repos_desc"}}" data-url="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/repo/addall">{{.locale.Tr "add_all"}}</button>
|
||||||
<button class="ui green button add-all-button" data-modal-id="org-team-add-all-repo" data-url="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/repo/addall">{{.locale.Tr "add_all"}}</button>
|
<button class="ui red button link-action" data-modal-confirm="{{.locale.Tr "org.teams.remove_all_repos_desc"}}" data-url="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/repo/removeall">{{.locale.Tr "remove_all"}}</button>
|
||||||
<button class="ui red button delete-button" data-modal-id="org-team-remove-all-repo" data-url="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/repo/removeall">{{.locale.Tr "remove_all"}}</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
@ -64,26 +58,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui g-modal-confirm delete modal" id="org-team-remove-all-repo">
|
|
||||||
<div class="header">
|
|
||||||
{{svg "octicon-trash"}}
|
|
||||||
{{.locale.Tr "org.teams.remove_all_repos_title"}}
|
|
||||||
</div>
|
|
||||||
<div class="content">
|
|
||||||
<p>{{.locale.Tr "org.teams.remove_all_repos_desc"}}</p>
|
|
||||||
</div>
|
|
||||||
{{template "base/modal_actions_confirm" .}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="ui g-modal-confirm addall modal" id="org-team-add-all-repo">
|
|
||||||
<div class="header">
|
|
||||||
{{svg "octicon-globe"}}
|
|
||||||
{{.locale.Tr "org.teams.add_all_repos_title"}}
|
|
||||||
</div>
|
|
||||||
<div class="content">
|
|
||||||
<p>{{.locale.Tr "org.teams.add_all_repos_desc"}}</p>
|
|
||||||
</div>
|
|
||||||
{{template "base/modal_actions_confirm" .}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{template "base/footer" .}}
|
{{template "base/footer" .}}
|
||||||
|
@ -165,7 +165,7 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
{{if and $.IsWriter (not $.IsMirror) (not $.Repository.IsArchived) (not .IsProtected)}}
|
{{if and $.IsWriter (not $.IsMirror) (not $.Repository.IsArchived) (not .IsProtected)}}
|
||||||
{{if .IsDeleted}}
|
{{if .IsDeleted}}
|
||||||
<button class="btn interact-bg gt-p-3 undo-button" data-url="{{$.Link}}/restore?branch_id={{.DeletedBranch.ID}}&name={{.DeletedBranch.Name}}&page={{$.Page.Paginater.Current}}" data-tooltip-content="{{$.locale.Tr "repo.branch.restore" (.Name)}}">
|
<button class="btn interact-bg gt-p-3 link-action restore-branch-button" data-url="{{$.Link}}/restore?branch_id={{.DeletedBranch.ID}}&name={{.DeletedBranch.Name}}&page={{$.Page.Paginater.Current}}" data-tooltip-content="{{$.locale.Tr "repo.branch.restore" (.Name)}}">
|
||||||
<span class="text blue">
|
<span class="text blue">
|
||||||
{{svg "octicon-reply"}}
|
{{svg "octicon-reply"}}
|
||||||
</span>
|
</span>
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
|
|
||||||
<div class="text right actions">
|
<div class="text right actions">
|
||||||
<button class="ui cancel button">{{$.locale.Tr "settings.cancel"}}</button>
|
<button class="ui cancel button">{{$.locale.Tr "settings.cancel"}}</button>
|
||||||
<button data-url="{{$.RepoLink}}/projects/{{$.Project.ID}}" class="ui primary button" id="new_board_submit">{{$.locale.Tr "repo.projects.column.new_submit"}}</button>
|
<button data-url="{{$.RepoLink}}/projects/{{$.Project.ID}}" class="ui primary button disabled" id="new_board_submit">{{$.locale.Tr "repo.projects.column.new_submit"}}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -61,7 +61,7 @@
|
|||||||
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<button class="ui green button">{{$.locale.Tr "settings.update_avatar"}}</button>
|
<button class="ui green button">{{$.locale.Tr "settings.update_avatar"}}</button>
|
||||||
<a class="ui red button delete-post" data-request-url="{{.Link}}/avatar/delete" data-done-url="{{.Link}}">{{$.locale.Tr "settings.delete_current_avatar"}}</a>
|
<button class="ui red button link-action" data-url="{{.Link}}/avatar/delete" data-redirect="{{.Link}}">{{$.locale.Tr "settings.delete_current_avatar"}}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
@ -13,10 +13,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="field gt-dib gt-mr-4">
|
<div class="field gt-dib gt-mr-4">
|
||||||
<label>{{.locale.Tr "actions.runners.last_online"}}</label>
|
<label>{{.locale.Tr "actions.runners.last_online"}}</label>
|
||||||
<span>{{if .LastOnline}}{{TimeSinceUnix .LastOnline $.locale}}{{else}}{{$.locale.Tr "never"}}{{end}}</span>
|
<span>{{if .Runner.LastOnline}}{{TimeSinceUnix .Runner.LastOnline $.locale}}{{else}}{{$.locale.Tr "never"}}{{end}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="field gt-dib gt-mr-4">
|
<div class="field gt-dib gt-mr-4">
|
||||||
<label>{{.locale.Tr "actions.runners.agent_labels"}}</label>
|
<label>{{.locale.Tr "actions.runners.labels"}}</label>
|
||||||
<span>
|
<span>
|
||||||
{{range .Runner.AgentLabels}}
|
{{range .Runner.AgentLabels}}
|
||||||
<span>{{.}}</span>
|
<span>{{.}}</span>
|
||||||
@ -35,11 +35,6 @@
|
|||||||
<label for="description">{{.locale.Tr "actions.runners.description"}}</label>
|
<label for="description">{{.locale.Tr "actions.runners.description"}}</label>
|
||||||
<input id="description" name="description" value="{{.Runner.Description}}">
|
<input id="description" name="description" value="{{.Runner.Description}}">
|
||||||
</div>
|
</div>
|
||||||
<div class="field" data-tooltip-content="Labels are comma-separated. Whitespace at the beginning, end, and around the commas are ignored.">
|
|
||||||
<label for="custom_labels">{{.locale.Tr "actions.runners.custom_labels"}}</label>
|
|
||||||
<input id="custom_labels" name="custom_labels" value="{{StringUtils.Join .Runner.CustomLabels `,`}}">
|
|
||||||
<p class="help">{{.locale.Tr "actions.runners.custom_labels_helper"}}</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
|
|
||||||
@ -81,7 +76,7 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
{{if not .Tasks}}
|
{{if not .Tasks}}
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="5">{{.locale.Tr "runners.task_list.no_tasks"}}</td>
|
<td colspan="5">{{.locale.Tr "actions.runners.task_list.no_tasks"}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{end}}
|
{{end}}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -67,7 +67,7 @@
|
|||||||
<td>{{if .Version}}{{.Version}}{{else}}{{$.locale.Tr "unknown"}}{{end}}</td>
|
<td>{{if .Version}}{{.Version}}{{else}}{{$.locale.Tr "unknown"}}{{end}}</td>
|
||||||
<td><span data-tooltip-content="{{.BelongsToOwnerName}}">{{.BelongsToOwnerType.LocaleString $.locale}}<span></td>
|
<td><span data-tooltip-content="{{.BelongsToOwnerName}}">{{.BelongsToOwnerType.LocaleString $.locale}}<span></td>
|
||||||
<td class="runner-tags">
|
<td class="runner-tags">
|
||||||
{{range .AllLabels}}<span class="ui label">{{.}}</span>{{end}}
|
{{range .AgentLabels}}<span class="ui label">{{.}}</span>{{end}}
|
||||||
</td>
|
</td>
|
||||||
<td>{{if .LastOnline}}{{TimeSinceUnix .LastOnline $.locale}}{{else}}{{$.locale.Tr "never"}}{{end}}</td>
|
<td>{{if .LastOnline}}{{TimeSinceUnix .LastOnline $.locale}}{{else}}{{$.locale.Tr "never"}}{{end}}</td>
|
||||||
<td class="runner-ops">
|
<td class="runner-ops">
|
||||||
|
@ -53,16 +53,16 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if and .OrderedOAuth2Names .OAuth2Providers}}
|
{{if and .OrderedOAuth2Names .OAuth2Providers}}
|
||||||
<div id="oauth2-login-navigator">
|
<div class="ui horizontal divider">
|
||||||
|
{{.locale.Tr "sign_in_or"}}
|
||||||
|
</div>
|
||||||
|
<div id="oauth2-login-navigator" class="gt-py-2">
|
||||||
<div class="gt-df gt-fc gt-jc">
|
<div class="gt-df gt-fc gt-jc">
|
||||||
<div class="ui horizontal divider">
|
|
||||||
{{.locale.Tr "sign_in_or"}}
|
|
||||||
</div>
|
|
||||||
<div id="oauth2-login-navigator-inner" class="gt-df gt-fc gt-fw gt-ac gt-gap-3">
|
<div id="oauth2-login-navigator-inner" class="gt-df gt-fc gt-fw gt-ac gt-gap-3">
|
||||||
{{range $key := .OrderedOAuth2Names}}
|
{{range $key := .OrderedOAuth2Names}}
|
||||||
{{$provider := index $.OAuth2Providers $key}}
|
{{$provider := index $.OAuth2Providers $key}}
|
||||||
<a class="{{$provider.Name}} ui button gt-df gt-ac gt-jc gt-py-3 oauth-login-link" href="{{AppSubUrl}}/user/oauth2/{{$key}}">
|
<a class="{{$provider.Name}} ui button gt-df gt-ac gt-jc gt-py-3 oauth-login-link" href="{{AppSubUrl}}/user/oauth2/{{$key}}">
|
||||||
<img class="gt-mr-3" width="20" height="20" src="{{$provider.IconURL}}" alt="{{$provider.DisplayName}}">
|
{{$provider.IconHTML}}
|
||||||
{{$.locale.Tr "sign_in_with_provider" $provider.DisplayName}}
|
{{$.locale.Tr "sign_in_with_provider" $provider.DisplayName}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -69,20 +69,17 @@
|
|||||||
<summary class="gt-pb-4 gt-pl-2">
|
<summary class="gt-pb-4 gt-pl-2">
|
||||||
{{.locale.Tr "settings.select_permissions"}}
|
{{.locale.Tr "settings.select_permissions"}}
|
||||||
</summary>
|
</summary>
|
||||||
<div class="activity meta">
|
<p class="activity meta">
|
||||||
<i>{{$.locale.Tr "settings.scoped_token_desc" (printf `href="/api/swagger" target="_blank"`) (printf `href="https://docs.gitea.com/development/oauth2-provider#scopes" target="_blank"`) | Str2html}}</i>
|
<i>{{$.locale.Tr "settings.access_token_desc" (printf `href="/api/swagger" target="_blank"`) (printf `href="https://docs.gitea.com/development/oauth2-provider#scopes" target="_blank"`) | Str2html}}</i>
|
||||||
|
</p>
|
||||||
|
<div class="scoped-access-token-mount">
|
||||||
|
<scoped-access-token-selector
|
||||||
|
:is-admin="{{if .IsAdmin}}true{{else}}false{{end}}"
|
||||||
|
no-access-label="{{.locale.Tr "settings.permission_no_access"}}"
|
||||||
|
read-label="{{.locale.Tr "settings.permission_read"}}"
|
||||||
|
write-label="{{.locale.Tr "settings.permission_write"}}"
|
||||||
|
></scoped-access-token-selector>
|
||||||
</div>
|
</div>
|
||||||
<scoped-access-token-category category="activitypub"></scoped-access-token-category>
|
|
||||||
{{if .IsAdmin}}
|
|
||||||
<scoped-access-token-category category="admin"></scoped-access-token-category>
|
|
||||||
{{end}}
|
|
||||||
<scoped-access-token-category category="issue"></scoped-access-token-category>
|
|
||||||
<scoped-access-token-category category="misc"></scoped-access-token-category>
|
|
||||||
<scoped-access-token-category category="notification"></scoped-access-token-category>
|
|
||||||
<scoped-access-token-category category="organization"></scoped-access-token-category>
|
|
||||||
<scoped-access-token-category category="package"></scoped-access-token-category>
|
|
||||||
<scoped-access-token-category category="repository"></scoped-access-token-category>
|
|
||||||
<scoped-access-token-category category="user"></scoped-access-token-category>
|
|
||||||
</details>
|
</details>
|
||||||
<div id="scoped-access-warning" class="ui warning message center gt-db gt-hidden">
|
<div id="scoped-access-warning" class="ui warning message center gt-db gt-hidden">
|
||||||
{{.locale.Tr "settings.at_least_one_permission"}}
|
{{.locale.Tr "settings.at_least_one_permission"}}
|
||||||
|
@ -125,7 +125,7 @@
|
|||||||
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<button class="ui green button">{{$.locale.Tr "settings.update_avatar"}}</button>
|
<button class="ui green button">{{$.locale.Tr "settings.update_avatar"}}</button>
|
||||||
<button class="ui red button delete-post" data-request-url="{{.Link}}/avatar/delete" data-done-url="{{.Link}}">{{$.locale.Tr "settings.delete_current_avatar"}}</button>
|
<button class="ui red button link-action" data-url="{{.Link}}/avatar/delete" data-redirect="{{.Link}}">{{$.locale.Tr "settings.delete_current_avatar"}}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
{{range $key := .OrderedOAuth2Names}}
|
{{range $key := .OrderedOAuth2Names}}
|
||||||
{{$provider := index $.OAuth2Providers $key}}
|
{{$provider := index $.OAuth2Providers $key}}
|
||||||
<a class="item" href="{{AppSubUrl}}/user/oauth2/{{$key}}">
|
<a class="item" href="{{AppSubUrl}}/user/oauth2/{{$key}}">
|
||||||
<img class="gt-mr-3" width="20" height="20" src="{{$provider.IconURL}}" alt="{{$provider.DisplayName}}">
|
{{$provider.IconHTML}}
|
||||||
{{$provider.DisplayName}}
|
{{$provider.DisplayName}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -88,7 +88,7 @@ func testPackageCargo(t *testing.T, _ *neturl.URL) {
|
|||||||
blob, err := commit.GetBlobByPath(path)
|
blob, err := commit.GetBlobByPath(path)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
content, err := blob.GetBlobContent()
|
content, err := blob.GetBlobContent(1024)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
return content
|
return content
|
||||||
|
@ -34,7 +34,7 @@ func TestDeleteBranch(t *testing.T) {
|
|||||||
func TestUndoDeleteBranch(t *testing.T) {
|
func TestUndoDeleteBranch(t *testing.T) {
|
||||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||||
deleteBranch(t)
|
deleteBranch(t)
|
||||||
htmlDoc, name := branchAction(t, ".undo-button")
|
htmlDoc, name := branchAction(t, ".restore-branch-button")
|
||||||
assert.Contains(t,
|
assert.Contains(t,
|
||||||
htmlDoc.doc.Find(".ui.positive.message").Text(),
|
htmlDoc.doc.Find(".ui.positive.message").Text(),
|
||||||
translation.NewLocale("en-US").Tr("repo.branch.restore_success", name),
|
translation.NewLocale("en-US").Tr("repo.branch.restore_success", name),
|
||||||
|
@ -266,19 +266,11 @@ body {
|
|||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
background-color: var(--color-body);
|
background-color: var(--color-body);
|
||||||
tab-size: var(--tab-size);
|
tab-size: var(--tab-size);
|
||||||
overflow-y: auto;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
@supports (overflow: overlay) {
|
|
||||||
body {
|
|
||||||
overflow: overlay; /* stylelint-disable-line */
|
|
||||||
scrollbar-gutter: stable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
table {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
}
|
}
|
||||||
@ -910,7 +902,7 @@ img.ui.avatar,
|
|||||||
/* overwrite semantic width of containers inside the main page content div (div with class "page-content") */
|
/* overwrite semantic width of containers inside the main page content div (div with class "page-content") */
|
||||||
.page-content .ui.ui.ui.container:not(.fluid) {
|
.page-content .ui.ui.ui.container:not(.fluid) {
|
||||||
width: 1280px;
|
width: 1280px;
|
||||||
max-width: calc(100vw - 64px);
|
max-width: calc(100% - 64px);
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
}
|
}
|
||||||
@ -922,8 +914,7 @@ img.ui.avatar,
|
|||||||
/* enable fluid page widths for medium size viewports */
|
/* enable fluid page widths for medium size viewports */
|
||||||
@media (min-width: 768px) and (max-width: 1200px) {
|
@media (min-width: 768px) and (max-width: 1200px) {
|
||||||
.page-content .ui.ui.ui.container:not(.fluid) {
|
.page-content .ui.ui.ui.container:not(.fluid) {
|
||||||
width: calc(100vw - 32px);
|
max-width: calc(100% - 32px);
|
||||||
max-width: calc(100vw - 32px);
|
|
||||||
}
|
}
|
||||||
.ui.container.fluid.padded {
|
.ui.container.fluid.padded {
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
@ -932,8 +923,7 @@ img.ui.avatar,
|
|||||||
|
|
||||||
@media (max-width: 767.98px) {
|
@media (max-width: 767.98px) {
|
||||||
.page-content .ui.ui.ui.container:not(.fluid) {
|
.page-content .ui.ui.ui.container:not(.fluid) {
|
||||||
width: calc(100vw - 16px);
|
max-width: calc(100% - 16px);
|
||||||
max-width: calc(100vw - 16px);
|
|
||||||
}
|
}
|
||||||
.ui.container.fluid.padded {
|
.ui.container.fluid.padded {
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
@ -945,7 +935,6 @@ img.ui.avatar,
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
background: var(--color-nav-bg);
|
background: var(--color-nav-bg);
|
||||||
border-bottom: 1px solid var(--color-secondary);
|
border-bottom: 1px solid var(--color-secondary);
|
||||||
width: 100vw;
|
|
||||||
min-height: 52px;
|
min-height: 52px;
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
@import "./modules/normalize.css";
|
@import "./modules/normalize.css";
|
||||||
@import "./modules/animations.css";
|
@import "./modules/animations.css";
|
||||||
@import "./modules/button.css";
|
@import "./modules/button.css";
|
||||||
|
@import "./modules/select.css";
|
||||||
@import "./modules/tippy.css";
|
@import "./modules/tippy.css";
|
||||||
@import "./modules/modal.css";
|
@import "./modules/modal.css";
|
||||||
@import "./modules/breadcrumb.css";
|
@import "./modules/breadcrumb.css";
|
||||||
|
25
web_src/css/modules/select.css
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
.gitea-select {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gitea-select select {
|
||||||
|
appearance: none; /* hide default triangle */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ::before and ::after pseudo elements don't work on select elements,
|
||||||
|
so we need to put it on the parent. */
|
||||||
|
.gitea-select::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 12px;
|
||||||
|
right: 8px;
|
||||||
|
pointer-events: none;
|
||||||
|
content: '';
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
mask-size: cover;
|
||||||
|
-webkit-mask-size: cover;
|
||||||
|
mask-image: var(--octicon-chevron-right);
|
||||||
|
-webkit-mask-image: var(--octicon-chevron-right);
|
||||||
|
transform: rotate(90deg); /* point the chevron down */
|
||||||
|
background: currentcolor;
|
||||||
|
}
|
@ -205,29 +205,6 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.organization.teams #add-repo-form input,
|
|
||||||
.organization.teams #repo-multiple-form input,
|
|
||||||
.organization.teams #add-member-form input {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.organization.teams #add-repo-form .ui.button,
|
|
||||||
.organization.teams #repo-multiple-form .ui.button,
|
|
||||||
.organization.teams #add-member-form .ui.button {
|
|
||||||
margin-left: 5px;
|
|
||||||
margin-top: -3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.organization.teams #repo-top-segment {
|
|
||||||
height: 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 767.98px) {
|
|
||||||
.organization.teams #repo-top-segment {
|
|
||||||
height: 100px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.org-team-navbar .active.item {
|
.org-team-navbar .active.item {
|
||||||
background: var(--color-box-body) !important;
|
background: var(--color-box-body) !important;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
audit=false
|
audit=false
|
||||||
fund=false
|
fund=false
|
||||||
update-notifier=false
|
update-notifier=false
|
||||||
package-lock=false
|
package-lock=true
|
||||||
|
save-exact=true
|
||||||
|
lockfile-version=3
|
||||||
optional=false
|
optional=false
|
||||||
|
@ -8,3 +8,4 @@
|
|||||||
@variationPopupTooltip: false;
|
@variationPopupTooltip: false;
|
||||||
@linkHoverUnderline: underline;
|
@linkHoverUnderline: underline;
|
||||||
@variationButtonSocial: false;
|
@variationButtonSocial: false;
|
||||||
|
@pageOverflowX: visible;
|
||||||
|
2
web_src/fomantic/build/semantic.css
generated
@ -24658,7 +24658,7 @@ html {
|
|||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
overflow-x: hidden;
|
overflow-x: visible;
|
||||||
min-width: 320px;
|
min-width: 320px;
|
||||||
background: #FFFFFF;
|
background: #FFFFFF;
|
||||||
font-family: var(--fonts-regular);
|
font-family: var(--fonts-regular);
|
||||||
|
7337
web_src/fomantic/package-lock.json
generated
Normal file
@ -1,97 +1,100 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="scoped-access-token-category">
|
<div v-for="category in categories" :key="category" class="field gt-pl-2 gt-pb-2 access-token-category">
|
||||||
<div class="field gt-pl-2">
|
<label class="category-label" :for="'access-token-scope-' + category">
|
||||||
<label class="checkbox-label">
|
{{ category }}
|
||||||
<input
|
</label>
|
||||||
ref="category"
|
<div class="gitea-select">
|
||||||
v-model="categorySelected"
|
<select
|
||||||
class="scope-checkbox scoped-access-token-input"
|
class="ui selection access-token-select"
|
||||||
type="checkbox"
|
name="scope"
|
||||||
name="scope"
|
:id="'access-token-scope-' + category"
|
||||||
:value="'write:' + category"
|
>
|
||||||
@input="onCategoryInput"
|
<option value="">
|
||||||
>
|
{{ noAccessLabel }}
|
||||||
{{ category }}
|
</option>
|
||||||
</label>
|
<option :value="'read:' + category">
|
||||||
</div>
|
{{ readLabel }}
|
||||||
<div class="field gt-pl-4">
|
</option>
|
||||||
<div class="inline field">
|
<option :value="'write:' + category">
|
||||||
<label class="checkbox-label">
|
{{ writeLabel }}
|
||||||
<input
|
</option>
|
||||||
ref="read"
|
</select>
|
||||||
v-model="readSelected"
|
|
||||||
:disabled="disableIndividual || writeSelected"
|
|
||||||
class="scope-checkbox scoped-access-token-input"
|
|
||||||
type="checkbox"
|
|
||||||
name="scope"
|
|
||||||
:value="'read:' + category"
|
|
||||||
@input="onIndividualInput"
|
|
||||||
>
|
|
||||||
read:{{ category }}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="inline field">
|
|
||||||
<label class="checkbox-label">
|
|
||||||
<input
|
|
||||||
ref="write"
|
|
||||||
v-model="writeSelected"
|
|
||||||
:disabled="disableIndividual"
|
|
||||||
class="scope-checkbox scoped-access-token-input"
|
|
||||||
type="checkbox"
|
|
||||||
name="scope"
|
|
||||||
:value="'write:' + category"
|
|
||||||
@input="onIndividualInput"
|
|
||||||
>
|
|
||||||
write:{{ category }}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {createApp} from 'vue';
|
import {createApp} from 'vue';
|
||||||
import {showElem} from '../utils/dom.js';
|
import {hideElem, showElem} from '../utils/dom.js';
|
||||||
|
|
||||||
const sfc = {
|
const sfc = {
|
||||||
props: {
|
props: {
|
||||||
category: {
|
isAdmin: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
noAccessLabel: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
readLabel: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
writeLabel: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
data: () => ({
|
computed: {
|
||||||
categorySelected: false,
|
categories() {
|
||||||
disableIndividual: false,
|
const categories = [
|
||||||
readSelected: false,
|
'activitypub',
|
||||||
writeSelected: false,
|
];
|
||||||
}),
|
if (this.isAdmin) {
|
||||||
|
categories.push('admin');
|
||||||
|
}
|
||||||
|
categories.push(
|
||||||
|
'issue',
|
||||||
|
'misc',
|
||||||
|
'notification',
|
||||||
|
'organization',
|
||||||
|
'package',
|
||||||
|
'repository',
|
||||||
|
'user');
|
||||||
|
return categories;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
document.getElementById('scoped-access-submit').addEventListener('click', this.onClickSubmit);
|
||||||
|
},
|
||||||
|
|
||||||
|
unmounted() {
|
||||||
|
document.getElementById('scoped-access-submit').removeEventListener('click', this.onClickSubmit);
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
/**
|
onClickSubmit(e) {
|
||||||
* When entire category is toggled
|
|
||||||
* @param {Event} e
|
|
||||||
*/
|
|
||||||
onCategoryInput(e) {
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.disableIndividual = this.$refs.category.checked;
|
|
||||||
this.writeSelected = this.$refs.category.checked;
|
|
||||||
this.readSelected = this.$refs.category.checked;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
const warningEl = document.getElementById('scoped-access-warning');
|
||||||
* When an individual level of category is toggled
|
// check that at least one scope has been selected
|
||||||
* @param {Event} e
|
for (const el of document.getElementsByClassName('access-token-select')) {
|
||||||
*/
|
if (el.value) {
|
||||||
onIndividualInput(e) {
|
// Hide the error if it was visible from previous attempt.
|
||||||
e.preventDefault();
|
hideElem(warningEl);
|
||||||
if (this.$refs.write.checked) {
|
// Submit the form.
|
||||||
this.readSelected = true;
|
document.getElementById('scoped-access-form').submit();
|
||||||
|
// Don't show the warning.
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.categorySelected = this.$refs.write.checked;
|
// no scopes selected, show validation error
|
||||||
},
|
showElem(warningEl);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default sfc;
|
export default sfc;
|
||||||
@ -100,39 +103,11 @@ export default sfc;
|
|||||||
* Initialize category toggle sections
|
* Initialize category toggle sections
|
||||||
*/
|
*/
|
||||||
export function initScopedAccessTokenCategories() {
|
export function initScopedAccessTokenCategories() {
|
||||||
for (const el of document.getElementsByTagName('scoped-access-token-category')) {
|
for (const el of document.getElementsByClassName('scoped-access-token-mount')) {
|
||||||
const category = el.getAttribute('category');
|
createApp({})
|
||||||
createApp(sfc, {
|
.component('scoped-access-token-selector', sfc)
|
||||||
category,
|
.mount(el);
|
||||||
}).mount(el);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('scoped-access-submit')?.addEventListener('click', (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
// check that at least one scope has been selected
|
|
||||||
for (const el of document.getElementsByClassName('scoped-access-token-input')) {
|
|
||||||
if (el.checked) {
|
|
||||||
document.getElementById('scoped-access-form').submit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// no scopes selected, show validation error
|
|
||||||
showElem(document.getElementById('scoped-access-warning'));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.scoped-access-token-category {
|
|
||||||
padding-top: 10px;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.checkbox-label {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.scope-checkbox {
|
|
||||||
margin: 4px 5px 0 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@ -8,7 +8,7 @@ import {svg} from '../svg.js';
|
|||||||
import {hideElem, showElem, toggleElem} from '../utils/dom.js';
|
import {hideElem, showElem, toggleElem} from '../utils/dom.js';
|
||||||
import {htmlEscape} from 'escape-goat';
|
import {htmlEscape} from 'escape-goat';
|
||||||
|
|
||||||
const {appUrl, csrfToken} = window.config;
|
const {appUrl, csrfToken, i18n} = window.config;
|
||||||
|
|
||||||
export function initGlobalFormDirtyLeaveConfirm() {
|
export function initGlobalFormDirtyLeaveConfirm() {
|
||||||
// Warn users that try to leave a page after entering data into a form.
|
// Warn users that try to leave a page after entering data into a form.
|
||||||
@ -172,6 +172,62 @@ export function initGlobalDropzone() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function linkAction(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
// A "link-action" can post AJAX request to its "data-url"
|
||||||
|
// Then the browser is redirect to: the "redirect" in response, or "data-redirect" attribute, or current URL by reloading.
|
||||||
|
// If the "link-action" has "data-modal-confirm(-html)" attribute, a confirm modal dialog will be shown before taking action.
|
||||||
|
|
||||||
|
const $this = $(e.target);
|
||||||
|
const redirect = $this.attr('data-redirect');
|
||||||
|
|
||||||
|
const request = () => {
|
||||||
|
$this.prop('disabled', true);
|
||||||
|
$.post($this.attr('data-url'), {
|
||||||
|
_csrf: csrfToken
|
||||||
|
}).done((data) => {
|
||||||
|
if (data && data.redirect) {
|
||||||
|
window.location.href = data.redirect;
|
||||||
|
} else if (redirect) {
|
||||||
|
window.location.href = redirect;
|
||||||
|
} else {
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
}).always(() => {
|
||||||
|
$this.prop('disabled', false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const modalConfirmHtml = htmlEscape($this.attr('data-modal-confirm') || '');
|
||||||
|
if (!modalConfirmHtml) {
|
||||||
|
request();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const okButtonColor = $this.hasClass('red') || $this.hasClass('yellow') || $this.hasClass('orange') || $this.hasClass('negative') ? 'orange' : 'green';
|
||||||
|
|
||||||
|
const $modal = $(`
|
||||||
|
<div class="ui g-modal-confirm modal">
|
||||||
|
<div class="content">${modalConfirmHtml}</div>
|
||||||
|
<div class="actions">
|
||||||
|
<button class="ui basic cancel button">${svg('octicon-x')} ${i18n.modal_cancel}</button>
|
||||||
|
<button class="ui ${okButtonColor} ok button">${svg('octicon-check')} ${i18n.modal_confirm}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
|
||||||
|
$modal.appendTo(document.body);
|
||||||
|
$modal.modal({
|
||||||
|
onApprove() {
|
||||||
|
request();
|
||||||
|
},
|
||||||
|
onHidden() {
|
||||||
|
$modal.remove();
|
||||||
|
},
|
||||||
|
}).modal('show');
|
||||||
|
}
|
||||||
|
|
||||||
export function initGlobalLinkActions() {
|
export function initGlobalLinkActions() {
|
||||||
function showDeletePopup(e) {
|
function showDeletePopup(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -217,75 +273,9 @@ export function initGlobalLinkActions() {
|
|||||||
}).modal('show');
|
}).modal('show');
|
||||||
}
|
}
|
||||||
|
|
||||||
function showAddAllPopup(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
const $this = $(this);
|
|
||||||
let filter = '';
|
|
||||||
if ($this.attr('data-modal-id')) {
|
|
||||||
filter += `#${$this.attr('data-modal-id')}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dialog = $(`.addall.modal${filter}`);
|
|
||||||
dialog.find('.name').text($this.data('name'));
|
|
||||||
|
|
||||||
dialog.modal({
|
|
||||||
closable: false,
|
|
||||||
onApprove() {
|
|
||||||
if ($this.data('type') === 'form') {
|
|
||||||
$($this.data('form')).trigger('submit');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$.post($this.data('url'), {
|
|
||||||
_csrf: csrfToken,
|
|
||||||
id: $this.data('id')
|
|
||||||
}).done((data) => {
|
|
||||||
window.location.href = data.redirect;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}).modal('show');
|
|
||||||
}
|
|
||||||
|
|
||||||
function linkAction(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
const $this = $(this);
|
|
||||||
const redirect = $this.data('redirect');
|
|
||||||
$this.prop('disabled', true);
|
|
||||||
$.post($this.data('url'), {
|
|
||||||
_csrf: csrfToken
|
|
||||||
}).done((data) => {
|
|
||||||
if (data.redirect) {
|
|
||||||
window.location.href = data.redirect;
|
|
||||||
} else if (redirect) {
|
|
||||||
window.location.href = redirect;
|
|
||||||
} else {
|
|
||||||
window.location.reload();
|
|
||||||
}
|
|
||||||
}).always(() => {
|
|
||||||
$this.prop('disabled', false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helpers.
|
// Helpers.
|
||||||
$('.delete-button').on('click', showDeletePopup);
|
$('.delete-button').on('click', showDeletePopup);
|
||||||
$('.link-action').on('click', linkAction);
|
$('.link-action').on('click', linkAction);
|
||||||
|
|
||||||
// FIXME: this function is only used once, and not common, not well designed. should be refactored later
|
|
||||||
$('.add-all-button').on('click', showAddAllPopup);
|
|
||||||
|
|
||||||
// FIXME: this is only used once, and should be replace with `link-action` instead
|
|
||||||
$('.undo-button').on('click', function () {
|
|
||||||
const $this = $(this);
|
|
||||||
$this.prop('disabled', true);
|
|
||||||
$.post($this.data('url'), {
|
|
||||||
_csrf: csrfToken,
|
|
||||||
id: $this.data('id')
|
|
||||||
}).done((data) => {
|
|
||||||
window.location.href = data.redirect;
|
|
||||||
}).always(() => {
|
|
||||||
$this.prop('disabled', false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initGlobalButtons() {
|
export function initGlobalButtons() {
|
||||||
@ -346,16 +336,6 @@ export function initGlobalButtons() {
|
|||||||
initCompColorPicker();
|
initCompColorPicker();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.delete-post.button').on('click', function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
const $this = $(this);
|
|
||||||
$.post($this.attr('data-request-url'), {
|
|
||||||
_csrf: csrfToken
|
|
||||||
}).done(() => {
|
|
||||||
window.location.href = $this.attr('data-done-url');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -9,6 +9,21 @@ function updateIssueCount(cards) {
|
|||||||
parent.getElementsByClassName('board-card-cnt')[0].textContent = cnt;
|
parent.getElementsByClassName('board-card-cnt')[0].textContent = cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createNewBoard(url, boardTitle, projectColorInput) {
|
||||||
|
$.ajax({
|
||||||
|
url,
|
||||||
|
data: JSON.stringify({title: boardTitle.val(), color: projectColorInput.val()}),
|
||||||
|
headers: {
|
||||||
|
'X-Csrf-Token': csrfToken,
|
||||||
|
},
|
||||||
|
contentType: 'application/json',
|
||||||
|
method: 'POST',
|
||||||
|
}).done(() => {
|
||||||
|
boardTitle.closest('form').removeClass('dirty');
|
||||||
|
window.location.reload();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function moveIssue({item, from, to, oldIndex}) {
|
function moveIssue({item, from, to, oldIndex}) {
|
||||||
const columnCards = to.getElementsByClassName('board-card');
|
const columnCards = to.getElementsByClassName('board-card');
|
||||||
updateIssueCount(from);
|
updateIssueCount(from);
|
||||||
@ -17,8 +32,8 @@ function moveIssue({item, from, to, oldIndex}) {
|
|||||||
const columnSorting = {
|
const columnSorting = {
|
||||||
issues: Array.from(columnCards, (card, i) => ({
|
issues: Array.from(columnCards, (card, i) => ({
|
||||||
issueID: parseInt($(card).attr('data-issue')),
|
issueID: parseInt($(card).attr('data-issue')),
|
||||||
sorting: i
|
sorting: i,
|
||||||
}))
|
})),
|
||||||
};
|
};
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
@ -31,7 +46,7 @@ function moveIssue({item, from, to, oldIndex}) {
|
|||||||
type: 'POST',
|
type: 'POST',
|
||||||
error: () => {
|
error: () => {
|
||||||
from.insertBefore(item, from.children[oldIndex]);
|
from.insertBefore(item, from.children[oldIndex]);
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,24 +183,29 @@ export function initRepoProject() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#new_board_submit').on('click', function (e) {
|
$('#new_board_submit').on('click', (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const boardTitle = $('#new_board');
|
const boardTitle = $('#new_board');
|
||||||
const projectColorInput = $('#new_board_color_picker');
|
const projectColorInput = $('#new_board_color_picker');
|
||||||
|
if (!boardTitle.val()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const url = $(this).data('url');
|
||||||
|
createNewBoard(url, boardTitle, projectColorInput);
|
||||||
|
});
|
||||||
|
|
||||||
$.ajax({
|
$('.new-board').on('input keyup', (e) => {
|
||||||
url: $(this).data('url'),
|
const boardTitle = $('#new_board');
|
||||||
data: JSON.stringify({title: boardTitle.val(), color: projectColorInput.val()}),
|
const projectColorInput = $('#new_board_color_picker');
|
||||||
headers: {
|
if (!boardTitle.val()) {
|
||||||
'X-Csrf-Token': csrfToken,
|
$('#new_board_submit').addClass('disabled');
|
||||||
},
|
return;
|
||||||
contentType: 'application/json',
|
}
|
||||||
method: 'POST',
|
$('#new_board_submit').removeClass('disabled');
|
||||||
}).done(() => {
|
if (e.key === 'Enter') {
|
||||||
boardTitle.closest('form').removeClass('dirty');
|
const url = $(this).data('url');
|
||||||
window.location.reload();
|
createNewBoard(url, boardTitle, projectColorInput);
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,14 @@ export function initMarkupTasklist() {
|
|||||||
|
|
||||||
const encoder = new TextEncoder();
|
const encoder = new TextEncoder();
|
||||||
const buffer = encoder.encode(oldContent);
|
const buffer = encoder.encode(oldContent);
|
||||||
|
// Indexes may fall off the ends and return undefined.
|
||||||
|
if (buffer[position - 1] !== '['.codePointAt(0) ||
|
||||||
|
buffer[position] !== ' '.codePointAt(0) && buffer[position] !== 'x'.codePointAt(0) ||
|
||||||
|
buffer[position + 1] !== ']'.codePointAt(0)) {
|
||||||
|
// Position is probably wrong. Revert and don't allow change.
|
||||||
|
checkbox.checked = !checkbox.checked;
|
||||||
|
throw new Error(`Expected position to be space or x and surrounded by brackets, but it's not: position=${position}`);
|
||||||
|
}
|
||||||
buffer.set(encoder.encode(checkboxCharacter), position);
|
buffer.set(encoder.encode(checkboxCharacter), position);
|
||||||
const newContent = new TextDecoder().decode(buffer);
|
const newContent = new TextDecoder().decode(buffer);
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
1
web_src/svg/gitea-azureadv2.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 18" class="svg gitea-azuread" width="16" height="16" aria-hidden="true"><defs><linearGradient id="gitea-azuread__a" x1="13.25" x2="8.62" y1="13.02" y2="4.25" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1988d9"/><stop offset=".9" stop-color="#54aef0"/></linearGradient><linearGradient id="gitea-azuread__b" x1="11.26" x2="14.46" y1="10.47" y2="15.99" gradientUnits="userSpaceOnUse"><stop offset=".1" stop-color="#54aef0"/><stop offset=".29" stop-color="#4fabee"/><stop offset=".51" stop-color="#41a2e9"/><stop offset=".74" stop-color="#2a93e0"/><stop offset=".88" stop-color="#1988d9"/></linearGradient></defs><path fill="#50e6ff" d="m1.01 10.19 7.92 5.14 8.06-5.16L18 11.35l-9.07 5.84L0 11.35l1.01-1.16z"/><path fill="#fff" d="M1.61 9.53 8.93.81l7.47 8.73-7.47 4.72-7.32-4.73z"/><path fill="#50e6ff" d="M8.93.81v13.45L1.61 9.53 8.93.81z"/><path fill="url(#gitea-azuread__a)" d="M8.93.81v13.45l7.47-4.72L8.93.81z"/><path fill="#53b1e0" d="m8.93 7.76 7.47 1.78-7.47 4.72v-6.5z"/><path fill="#9cebff" d="M8.93 14.26 1.61 9.53l7.32-1.77v6.5z"/><path fill="url(#gitea-azuread__b)" d="M8.93 17.19 18 11.35l-1.01-1.18-8.06 5.16v1.86z"/></svg>
|
After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 516 B After Width: | Height: | Size: 516 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 853 B After Width: | Height: | Size: 853 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 278 B After Width: | Height: | Size: 278 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 566 B After Width: | Height: | Size: 566 B |