mirror of
https://github.com/go-gitea/gitea.git
synced 2025-07-18 00:01:32 -04:00
Compare commits
5 Commits
023521b016
...
a8e13e64da
Author | SHA1 | Date | |
---|---|---|---|
|
a8e13e64da | ||
|
43c136200a | ||
|
a04eeb2a54 | ||
|
e72290fd9a | ||
|
c6f5029708 |
@ -23,17 +23,15 @@ For repositories, labels can be created by going to `Issues` and clicking on `La
|
|||||||
|
|
||||||
For organizations, you can define organization-wide labels that are shared with all organization repositories, including both already-existing repositories as well as newly created ones. Organization-wide labels can be created in the organization `Settings`.
|
For organizations, you can define organization-wide labels that are shared with all organization repositories, including both already-existing repositories as well as newly created ones. Organization-wide labels can be created in the organization `Settings`.
|
||||||
|
|
||||||
Labels have a mandatory name, a mandatory color, an optional description, and must either be exclusive or not (see `Scoped labels` below).
|
Labels have a mandatory name, a mandatory color, an optional description, and must either be exclusive or not (see `Scoped Labels` below).
|
||||||
|
|
||||||
When you create a repository, you can ensure certain labels exist by using the `Issue Labels` option. This option lists a number of available label sets that are [configured globally on your instance](../customizing-gitea/#labels). Its contained labels will all be created as well while creating the repository.
|
When you create a repository, you can ensure certain labels exist by using the `Issue Labels` option. This option lists a number of available label sets that are [configured globally on your instance](../customizing-gitea/#labels). Its contained labels will all be created as well while creating the repository.
|
||||||
|
|
||||||
## Scoped Labels
|
## Scoped Labels
|
||||||
|
|
||||||
A scoped label is a label that contains `/` in its name (not at either end of the name). For example labels `kind/bug` and `kind/enhancement` both have scope `kind`. Such labels will display the scope with slightly darker color.
|
Scoped labels are used to ensure at most a single label with the same scope is assigned to an issue or pull request. For example, if labels `kind/bug` and `kind/enhancement` have the Exclusive option set, an issue can only be classified as a bug or an enhancement.
|
||||||
|
|
||||||
The scope of a label is determined based on the **last** `/`, so for example the scope of label `scope/subscope/item` is `scope/subscope`.
|
A scoped label must contain `/` in its name (not at either end of the name). The scope of a label is determined based on the **last** `/`, so for example the scope of label `scope/subscope/item` is `scope/subscope`.
|
||||||
|
|
||||||
Scoped labels can be marked as exclusive. This ensures at most a single label with the same scope is assigned to an issue or pull request. For example, if `kind/bug` and `kind/enhancement` are marked exclusive, an issue can only be classified as a bug or an enhancement.
|
|
||||||
|
|
||||||
## Filtering by Label
|
## Filtering by Label
|
||||||
|
|
||||||
|
@ -834,7 +834,7 @@ func RenderLabel(ctx context.Context, label *issues_model.Label) string {
|
|||||||
// Make scope and item background colors slightly darker and lighter respectively.
|
// Make scope and item background colors slightly darker and lighter respectively.
|
||||||
// More contrast needed with higher luminance, empirically tweaked.
|
// More contrast needed with higher luminance, empirically tweaked.
|
||||||
luminance := (0.299*r + 0.587*g + 0.114*b) / 255
|
luminance := (0.299*r + 0.587*g + 0.114*b) / 255
|
||||||
contrast := 0.01 + luminance*0.06
|
contrast := 0.01 + luminance*0.03
|
||||||
// Ensure we add the same amount of contrast also near 0 and 1.
|
// Ensure we add the same amount of contrast also near 0 and 1.
|
||||||
darken := contrast + math.Max(luminance+contrast-1.0, 0.0)
|
darken := contrast + math.Max(luminance+contrast-1.0, 0.0)
|
||||||
lighten := contrast + math.Max(contrast-luminance, 0.0)
|
lighten := contrast + math.Max(contrast-luminance, 0.0)
|
||||||
@ -859,12 +859,10 @@ func RenderLabel(ctx context.Context, label *issues_model.Label) string {
|
|||||||
|
|
||||||
return fmt.Sprintf("<span class='ui label scope-parent' title='%s'>"+
|
return fmt.Sprintf("<span class='ui label scope-parent' title='%s'>"+
|
||||||
"<div class='ui label scope-left' style='color: %s !important; background-color: %s !important'>%s</div>"+
|
"<div class='ui label scope-left' style='color: %s !important; background-color: %s !important'>%s</div>"+
|
||||||
"<div class='ui label scope-middle' style='background: linear-gradient(-80deg, %s 48%%, %s 52%% 0%%);'> </div>"+
|
|
||||||
"<div class='ui label scope-right' style='color: %s !important; background-color: %s !important''>%s</div>"+
|
"<div class='ui label scope-right' style='color: %s !important; background-color: %s !important''>%s</div>"+
|
||||||
"</span>",
|
"</span>",
|
||||||
description,
|
description,
|
||||||
textColor, scopeColor, scopeText,
|
textColor, scopeColor, scopeText,
|
||||||
itemColor, scopeColor,
|
|
||||||
textColor, itemColor, itemText)
|
textColor, itemColor, itemText)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,7 +176,7 @@ func CreateIssueAttachment(ctx *context.APIContext) {
|
|||||||
filename = query
|
filename = query
|
||||||
}
|
}
|
||||||
|
|
||||||
attachment, err := attachment.UploadAttachment(file, setting.Attachment.AllowedTypes, &repo_model.Attachment{
|
attachment, err := attachment.UploadAttachment(file, setting.Attachment.AllowedTypes, header.Size, &repo_model.Attachment{
|
||||||
Name: filename,
|
Name: filename,
|
||||||
UploaderID: ctx.Doer.ID,
|
UploaderID: ctx.Doer.ID,
|
||||||
RepoID: ctx.Repo.Repository.ID,
|
RepoID: ctx.Repo.Repository.ID,
|
||||||
|
@ -180,7 +180,7 @@ func CreateIssueCommentAttachment(ctx *context.APIContext) {
|
|||||||
filename = query
|
filename = query
|
||||||
}
|
}
|
||||||
|
|
||||||
attachment, err := attachment.UploadAttachment(file, setting.Attachment.AllowedTypes, &repo_model.Attachment{
|
attachment, err := attachment.UploadAttachment(file, setting.Attachment.AllowedTypes, header.Size, &repo_model.Attachment{
|
||||||
Name: filename,
|
Name: filename,
|
||||||
UploaderID: ctx.Doer.ID,
|
UploaderID: ctx.Doer.ID,
|
||||||
RepoID: ctx.Repo.Repository.ID,
|
RepoID: ctx.Repo.Repository.ID,
|
||||||
|
@ -194,7 +194,7 @@ func CreateReleaseAttachment(ctx *context.APIContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a new attachment and save the file
|
// Create a new attachment and save the file
|
||||||
attach, err := attachment.UploadAttachment(file, setting.Repository.Release.AllowedTypes, &repo_model.Attachment{
|
attach, err := attachment.UploadAttachment(file, setting.Repository.Release.AllowedTypes, header.Size, &repo_model.Attachment{
|
||||||
Name: filename,
|
Name: filename,
|
||||||
UploaderID: ctx.Doer.ID,
|
UploaderID: ctx.Doer.ID,
|
||||||
RepoID: release.RepoID,
|
RepoID: release.RepoID,
|
||||||
|
@ -44,7 +44,7 @@ func uploadAttachment(ctx *context.Context, repoID int64, allowedTypes string) {
|
|||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
attach, err := attachment.UploadAttachment(file, allowedTypes, &repo_model.Attachment{
|
attach, err := attachment.UploadAttachment(file, allowedTypes, header.Size, &repo_model.Attachment{
|
||||||
Name: header.Filename,
|
Name: header.Filename,
|
||||||
UploaderID: ctx.Doer.ID,
|
UploaderID: ctx.Doer.ID,
|
||||||
RepoID: repoID,
|
RepoID: repoID,
|
||||||
|
@ -113,7 +113,7 @@ func Projects(ctx *context.Context) {
|
|||||||
pager.AddParam(ctx, "state", "State")
|
pager.AddParam(ctx, "state", "State")
|
||||||
ctx.Data["Page"] = pager
|
ctx.Data["Page"] = pager
|
||||||
|
|
||||||
ctx.Data["CanWriteProjects"] = true
|
ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(unit.TypeProjects)
|
||||||
ctx.Data["IsShowClosed"] = isShowClosed
|
ctx.Data["IsShowClosed"] = isShowClosed
|
||||||
ctx.Data["IsProjectsPage"] = true
|
ctx.Data["IsProjectsPage"] = true
|
||||||
ctx.Data["SortType"] = sortType
|
ctx.Data["SortType"] = sortType
|
||||||
|
@ -19,14 +19,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// NewAttachment creates a new attachment object, but do not verify.
|
// NewAttachment creates a new attachment object, but do not verify.
|
||||||
func NewAttachment(attach *repo_model.Attachment, file io.Reader) (*repo_model.Attachment, error) {
|
func NewAttachment(attach *repo_model.Attachment, file io.Reader, size int64) (*repo_model.Attachment, error) {
|
||||||
if attach.RepoID == 0 {
|
if attach.RepoID == 0 {
|
||||||
return nil, fmt.Errorf("attachment %s should belong to a repository", attach.Name)
|
return nil, fmt.Errorf("attachment %s should belong to a repository", attach.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := db.WithTx(db.DefaultContext, func(ctx context.Context) error {
|
err := db.WithTx(db.DefaultContext, func(ctx context.Context) error {
|
||||||
attach.UUID = uuid.New().String()
|
attach.UUID = uuid.New().String()
|
||||||
size, err := storage.Attachments.Save(attach.RelativePath(), file, -1)
|
size, err := storage.Attachments.Save(attach.RelativePath(), file, size)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Create: %w", err)
|
return fmt.Errorf("Create: %w", err)
|
||||||
}
|
}
|
||||||
@ -39,7 +39,7 @@ func NewAttachment(attach *repo_model.Attachment, file io.Reader) (*repo_model.A
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UploadAttachment upload new attachment into storage and update database
|
// UploadAttachment upload new attachment into storage and update database
|
||||||
func UploadAttachment(file io.Reader, allowedTypes string, opts *repo_model.Attachment) (*repo_model.Attachment, error) {
|
func UploadAttachment(file io.Reader, allowedTypes string, fileSize int64, opts *repo_model.Attachment) (*repo_model.Attachment, error) {
|
||||||
buf := make([]byte, 1024)
|
buf := make([]byte, 1024)
|
||||||
n, _ := util.ReadAtMost(file, buf)
|
n, _ := util.ReadAtMost(file, buf)
|
||||||
buf = buf[:n]
|
buf = buf[:n]
|
||||||
@ -48,5 +48,5 @@ func UploadAttachment(file io.Reader, allowedTypes string, opts *repo_model.Atta
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewAttachment(opts, io.MultiReader(bytes.NewReader(buf), file))
|
return NewAttachment(opts, io.MultiReader(bytes.NewReader(buf), file), fileSize)
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ func TestUploadAttachment(t *testing.T) {
|
|||||||
RepoID: 1,
|
RepoID: 1,
|
||||||
UploaderID: user.ID,
|
UploaderID: user.ID,
|
||||||
Name: filepath.Base(fPath),
|
Name: filepath.Base(fPath),
|
||||||
}, f)
|
}, f, -1)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
attachment, err := repo_model.GetAttachmentByUUID(db.DefaultContext, attach.UUID)
|
attachment, err := repo_model.GetAttachmentByUUID(db.DefaultContext, attach.UUID)
|
||||||
|
@ -87,7 +87,7 @@ func (h *ReplyHandler) Handle(ctx context.Context, content *MailContent, doer *u
|
|||||||
attachmentIDs := make([]string, 0, len(content.Attachments))
|
attachmentIDs := make([]string, 0, len(content.Attachments))
|
||||||
if setting.Attachment.Enabled {
|
if setting.Attachment.Enabled {
|
||||||
for _, attachment := range content.Attachments {
|
for _, attachment := range content.Attachments {
|
||||||
a, err := attachment_service.UploadAttachment(bytes.NewReader(attachment.Content), setting.Attachment.AllowedTypes, &repo_model.Attachment{
|
a, err := attachment_service.UploadAttachment(bytes.NewReader(attachment.Content), setting.Attachment.AllowedTypes, int64(len(attachment.Content)), &repo_model.Attachment{
|
||||||
Name: attachment.Name,
|
Name: attachment.Name,
|
||||||
UploaderID: doer.ID,
|
UploaderID: doer.ID,
|
||||||
RepoID: issue.Repo.ID,
|
RepoID: issue.Repo.ID,
|
||||||
|
@ -106,11 +106,13 @@ func TestRelease_Create(t *testing.T) {
|
|||||||
IsTag: false,
|
IsTag: false,
|
||||||
}, nil, ""))
|
}, nil, ""))
|
||||||
|
|
||||||
|
testPlayload := "testtest"
|
||||||
|
|
||||||
attach, err := attachment.NewAttachment(&repo_model.Attachment{
|
attach, err := attachment.NewAttachment(&repo_model.Attachment{
|
||||||
RepoID: repo.ID,
|
RepoID: repo.ID,
|
||||||
UploaderID: user.ID,
|
UploaderID: user.ID,
|
||||||
Name: "test.txt",
|
Name: "test.txt",
|
||||||
}, strings.NewReader("testtest"))
|
}, strings.NewReader(testPlayload), int64(len([]byte(testPlayload))))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
release := repo_model.Release{
|
release := repo_model.Release{
|
||||||
@ -239,11 +241,12 @@ func TestRelease_Update(t *testing.T) {
|
|||||||
assert.Equal(t, tagName, release.TagName)
|
assert.Equal(t, tagName, release.TagName)
|
||||||
|
|
||||||
// Add new attachments
|
// Add new attachments
|
||||||
|
samplePayload := "testtest"
|
||||||
attach, err := attachment.NewAttachment(&repo_model.Attachment{
|
attach, err := attachment.NewAttachment(&repo_model.Attachment{
|
||||||
RepoID: repo.ID,
|
RepoID: repo.ID,
|
||||||
UploaderID: user.ID,
|
UploaderID: user.ID,
|
||||||
Name: "test.txt",
|
Name: "test.txt",
|
||||||
}, strings.NewReader("testtest"))
|
}, strings.NewReader(samplePayload), int64(len([]byte(samplePayload))))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.NoError(t, UpdateRelease(user, gitRepo, release, []string{attach.UUID}, nil, nil))
|
assert.NoError(t, UpdateRelease(user, gitRepo, release, []string{attach.UUID}, nil, nil))
|
||||||
|
@ -51,7 +51,7 @@
|
|||||||
{{JsPrettyNumber .NumClosedIssues}} {{$.locale.Tr "repo.issues.closed_title"}}
|
{{JsPrettyNumber .NumClosedIssues}} {{$.locale.Tr "repo.issues.closed_title"}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{{if and (or $.CanWriteIssues $.CanWritePulls) (not $.Repository.IsArchived)}}
|
{{if and $.CanWriteProjects (not $.Repository.IsArchived)}}
|
||||||
<div class="ui right operate">
|
<div class="ui right operate">
|
||||||
<a href="{{$.Link}}/{{.ID}}/edit" data-id={{.ID}} data-title={{.Title}}>{{svg "octicon-pencil"}} {{$.locale.Tr "repo.issues.label_edit"}}</a>
|
<a href="{{$.Link}}/{{.ID}}/edit" data-id={{.ID}} data-title={{.Title}}>{{svg "octicon-pencil"}} {{$.locale.Tr "repo.issues.label_edit"}}</a>
|
||||||
{{if .IsClosed}}
|
{{if .IsClosed}}
|
||||||
@ -59,7 +59,7 @@
|
|||||||
{{else}}
|
{{else}}
|
||||||
<a class="link-action" href data-url="{{$.Link}}/{{.ID}}/close">{{svg "octicon-skip"}} {{$.locale.Tr "repo.projects.close"}}</a>
|
<a class="link-action" href data-url="{{$.Link}}/{{.ID}}/close">{{svg "octicon-skip"}} {{$.locale.Tr "repo.projects.close"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
<a class="delete-button" href="#" data-url="{{$.RepoLink}}/projects/{{.ID}}/delete" data-id="{{.ID}}">{{svg "octicon-trash"}} {{$.locale.Tr "repo.issues.label_delete"}}</a>
|
<a class="delete-button" href="#" data-url="{{$.Link}}/{{.ID}}/delete" data-id="{{.ID}}">{{svg "octicon-trash"}} {{$.locale.Tr "repo.issues.label_delete"}}</a>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .Description}}
|
{{if .Description}}
|
||||||
@ -75,7 +75,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{if or .CanWriteIssues .CanWritePulls}}
|
{{if $.CanWriteProjects}}
|
||||||
<div class="ui small basic delete modal">
|
<div class="ui small basic delete modal">
|
||||||
<div class="ui icon header">
|
<div class="ui icon header">
|
||||||
{{svg "octicon-trash"}}
|
{{svg "octicon-trash"}}
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
<h2 class="project-title">{{$.Project.Title}}</h2>
|
<h2 class="project-title">{{$.Project.Title}}</h2>
|
||||||
<div class="content project-description">{{$.Project.RenderedContent|Str2html}}</div>
|
<div class="content project-description">{{$.Project.RenderedContent|Str2html}}</div>
|
||||||
</div>
|
</div>
|
||||||
{{if or $.CanWriteIssues $.CanWritePulls}}
|
{{if $.CanWriteProjects}}
|
||||||
<div class="column right aligned">
|
<div class="column right aligned">
|
||||||
<div class="ui compact right small menu">
|
<div class="ui compact right small menu">
|
||||||
<a class="item" href="{{$.Link}}/edit?redirect=project" data-id={{$.Project.ID}} data-title={{$.Project.Title}}>
|
<a class="item" href="{{$.Link}}/edit?redirect=project" data-id={{$.Project.ID}} data-title={{$.Project.Title}}>
|
||||||
@ -128,7 +128,7 @@
|
|||||||
|
|
||||||
<div class="text right actions">
|
<div class="text right actions">
|
||||||
<div class="ui cancel button">{{$.locale.Tr "settings.cancel"}}</div>
|
<div class="ui cancel button">{{$.locale.Tr "settings.cancel"}}</div>
|
||||||
<button data-url="{{$.Link}}/{{.ID}}" class="ui primary button">{{$.locale.Tr "repo.projects.column.edit"}}</button>
|
<button data-url="{{$.Link}}/{{.ID}}" class="ui primary button edit-column-button">{{$.locale.Tr "repo.projects.column.edit"}}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -256,7 +256,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{if or .CanWriteIssues .CanWritePulls}}
|
{{if .CanWriteProjects}}
|
||||||
<div class="ui small basic delete modal">
|
<div class="ui small basic delete modal">
|
||||||
<div class="ui icon header">
|
<div class="ui icon header">
|
||||||
{{svg "octicon-trash"}}
|
{{svg "octicon-trash"}}
|
||||||
|
43
templates/repo/issue/labels/labels_selector_field.tmpl
Normal file
43
templates/repo/issue/labels/labels_selector_field.tmpl
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<div class="ui {{if or (not .HasIssuesOrPullsWritePermission) .Repository.IsArchived}}disabled{{end}} floating jump select-label dropdown">
|
||||||
|
<a class="text gt-df gt-ac muted">
|
||||||
|
<strong>{{.locale.Tr "repo.issues.new.labels"}}</strong>
|
||||||
|
{{if and .HasIssuesOrPullsWritePermission (not .Repository.IsArchived)}}
|
||||||
|
{{svg "octicon-gear" 16 "gt-ml-2"}}
|
||||||
|
{{end}}
|
||||||
|
</a>
|
||||||
|
<div class="filter menu" {{if .Issue}}data-action="update" data-issue-id="{{$.Issue.ID}}" data-update-url="{{$.RepoLink}}/issues/labels"{{else}}data-id="#label_ids"{{end}}>
|
||||||
|
<div class="header" style="text-transform: none;font-size:16px;">{{.locale.Tr "repo.issues.new.add_labels_title"}}</div>
|
||||||
|
{{if or .Labels .OrgLabels}}
|
||||||
|
<div class="ui icon search input">
|
||||||
|
<i class="icon gt-df gt-ac gt-jc">{{svg "octicon-search" 16}}</i>
|
||||||
|
<input type="text" placeholder="{{.locale.Tr "repo.issues.filter_labels"}}">
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
<a class="no-select item" href="#">{{.locale.Tr "repo.issues.new.clear_labels"}}</a>
|
||||||
|
{{if or .Labels .OrgLabels}}
|
||||||
|
{{$previousExclusiveScope := "_no_scope"}}
|
||||||
|
{{range .Labels}}
|
||||||
|
{{$exclusiveScope := .ExclusiveScope}}
|
||||||
|
{{if and (ne $previousExclusiveScope "_no_scope") (ne $previousExclusiveScope $exclusiveScope)}}
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
{{end}}
|
||||||
|
{{$previousExclusiveScope = $exclusiveScope}}
|
||||||
|
<a class="{{if .IsChecked}}checked{{end}} item" href="#" data-id="{{.ID}}" data-id-selector="#label_{{.ID}}" data-scope="{{$exclusiveScope}}"><span class="octicon-check {{if not .IsChecked}}invisible{{end}}">{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}</span> {{RenderLabel $.Context .}}
|
||||||
|
{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji $.Context}}</small>{{end}}</a>
|
||||||
|
{{end}}
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
{{$previousExclusiveScope := "_no_scope"}}
|
||||||
|
{{range .OrgLabels}}
|
||||||
|
{{$exclusiveScope := .ExclusiveScope}}
|
||||||
|
{{if and (ne $previousExclusiveScope "_no_scope") (ne $previousExclusiveScope $exclusiveScope)}}
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
{{end}}
|
||||||
|
{{$previousExclusiveScope = $exclusiveScope}}
|
||||||
|
<a class="{{if .IsChecked}}checked{{end}} item" href="#" data-id="{{.ID}}" data-id-selector="#label_{{.ID}}" data-scope="{{$exclusiveScope}}"><span class="octicon-check {{if not .IsChecked}}invisible{{end}}">{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}</span> {{RenderLabel $.Context .}}
|
||||||
|
{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji $.Context}}</small>{{end}}</a>
|
||||||
|
{{end}}
|
||||||
|
{{else}}
|
||||||
|
<div class="header" style="text-transform: none;font-size:14px;">{{.locale.Tr "repo.issues.new.no_items"}}</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -36,50 +36,7 @@
|
|||||||
{{template "repo/issue/branch_selector_field" .}}
|
{{template "repo/issue/branch_selector_field" .}}
|
||||||
|
|
||||||
<input id="label_ids" name="label_ids" type="hidden" value="{{.label_ids}}">
|
<input id="label_ids" name="label_ids" type="hidden" value="{{.label_ids}}">
|
||||||
<div class="ui {{if not .HasIssuesOrPullsWritePermission}}disabled{{end}} floating jump select-label dropdown">
|
{{template "repo/issue/labels/labels_selector_field" .}}
|
||||||
<span class="text">
|
|
||||||
<strong>{{.locale.Tr "repo.issues.new.labels"}}</strong>
|
|
||||||
{{if .HasIssuesOrPullsWritePermission}}
|
|
||||||
{{svg "octicon-gear"}}
|
|
||||||
{{end}}
|
|
||||||
</span>
|
|
||||||
<div class="filter menu" data-id="#label_ids">
|
|
||||||
<div class="header" style="text-transform: none;font-size:16px;">{{.locale.Tr "repo.issues.new.add_labels_title"}}</div>
|
|
||||||
{{if or .Labels .OrgLabels}}
|
|
||||||
<div class="ui icon search input">
|
|
||||||
<i class="icon gt-df gt-ac gt-jc">{{svg "octicon-search" 16}}</i>
|
|
||||||
<input type="text" placeholder="{{.locale.Tr "repo.issues.filter_labels"}}">
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
<div class="no-select item">{{.locale.Tr "repo.issues.new.clear_labels"}}</div>
|
|
||||||
{{if or .Labels .OrgLabels}}
|
|
||||||
{{$previousExclusiveScope := "_no_scope"}}
|
|
||||||
{{range .Labels}}
|
|
||||||
{{$exclusiveScope := .ExclusiveScope}}
|
|
||||||
{{if and (ne $previousExclusiveScope "_no_scope") (ne $previousExclusiveScope $exclusiveScope)}}
|
|
||||||
<div class="ui divider"></div>
|
|
||||||
{{end}}
|
|
||||||
{{$previousExclusiveScope = $exclusiveScope}}
|
|
||||||
<a class="{{if .IsChecked}}checked{{end}} item" href="#" data-id="{{.ID}}" data-id-selector="#label_{{.ID}}" data-scope="{{$exclusiveScope}}"><span class="octicon-check {{if not .IsChecked}}invisible{{end}}">{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}</span> {{RenderLabel $.Context .}}
|
|
||||||
{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji $.Context}}</small>{{end}}</a>
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
<div class="ui divider"></div>
|
|
||||||
{{$previousExclusiveScope := "_no_scope"}}
|
|
||||||
{{range .OrgLabels}}
|
|
||||||
{{$exclusiveScope := .ExclusiveScope}}
|
|
||||||
{{if and (ne $previousExclusiveScope "_no_scope") (ne $previousExclusiveScope $exclusiveScope)}}
|
|
||||||
<div class="ui divider"></div>
|
|
||||||
{{end}}
|
|
||||||
{{$previousExclusiveScope = $exclusiveScope}}
|
|
||||||
<a class="{{if .IsChecked}}checked{{end}} item" href="#" data-id="{{.ID}}" data-id-selector="#label_{{.ID}}" data-scope="{{$exclusiveScope}}"><span class="octicon-check {{if not .IsChecked}}invisible{{end}}">{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}</span> {{RenderLabel $.Context .}}
|
|
||||||
{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji $.Context}}</small>{{end}}</a>
|
|
||||||
{{end}}
|
|
||||||
{{else}}
|
|
||||||
<div class="header" style="text-transform: none;font-size:14px;">{{.locale.Tr "repo.issues.new.no_items"}}</div>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{template "repo/issue/labels/labels_sidebar" dict "root" $}}
|
{{template "repo/issue/labels/labels_sidebar" dict "root" $}}
|
||||||
|
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
|
@ -106,49 +106,7 @@
|
|||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
<div class="ui {{if or (not .HasIssuesOrPullsWritePermission) .Repository.IsArchived}}disabled{{end}} floating jump select-label dropdown">
|
{{template "repo/issue/labels/labels_selector_field" .}}
|
||||||
<a class="text gt-df gt-ac muted">
|
|
||||||
<strong>{{.locale.Tr "repo.issues.new.labels"}}</strong>
|
|
||||||
{{if and .HasIssuesOrPullsWritePermission (not .Repository.IsArchived)}}
|
|
||||||
{{svg "octicon-gear" 16 "gt-ml-2"}}
|
|
||||||
{{end}}
|
|
||||||
</a>
|
|
||||||
<div class="filter menu" data-action="update" data-issue-id="{{$.Issue.ID}}" data-update-url="{{$.RepoLink}}/issues/labels">
|
|
||||||
<div class="header" style="text-transform: none;font-size:16px;">{{.locale.Tr "repo.issues.new.add_labels_title"}}</div>
|
|
||||||
{{if or .Labels .OrgLabels}}
|
|
||||||
<div class="ui icon search input">
|
|
||||||
<i class="icon gt-df gt-ac gt-jc">{{svg "octicon-search" 16}}</i>
|
|
||||||
<input type="text" placeholder="{{.locale.Tr "repo.issues.filter_labels"}}">
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
<a class="no-select item" href="#">{{.locale.Tr "repo.issues.new.clear_labels"}}</a>
|
|
||||||
{{if or .Labels .OrgLabels}}
|
|
||||||
{{$previousExclusiveScope := "_no_scope"}}
|
|
||||||
{{range .Labels}}
|
|
||||||
{{$exclusiveScope := .ExclusiveScope}}
|
|
||||||
{{if and (ne $previousExclusiveScope "_no_scope") (ne $previousExclusiveScope $exclusiveScope)}}
|
|
||||||
<div class="ui divider"></div>
|
|
||||||
{{end}}
|
|
||||||
{{$previousExclusiveScope = $exclusiveScope}}
|
|
||||||
<a class="{{if .IsChecked}}checked{{end}} item" href="#" data-id="{{.ID}}" data-id-selector="#label_{{.ID}}" data-scope="{{$exclusiveScope}}"><span class="octicon-check {{if not .IsChecked}}invisible{{end}}">{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}</span> {{RenderLabel $.Context .}}
|
|
||||||
{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji $.Context}}</small>{{end}}</a>
|
|
||||||
{{end}}
|
|
||||||
<div class="ui divider"></div>
|
|
||||||
{{$previousExclusiveScope := "_no_scope"}}
|
|
||||||
{{range .OrgLabels}}
|
|
||||||
{{$exclusiveScope := .ExclusiveScope}}
|
|
||||||
{{if and (ne $previousExclusiveScope "_no_scope") (ne $previousExclusiveScope $exclusiveScope)}}
|
|
||||||
<div class="ui divider"></div>
|
|
||||||
{{end}}
|
|
||||||
{{$previousExclusiveScope = $exclusiveScope}}
|
|
||||||
<a class="{{if .IsChecked}}checked{{end}} item" href="#" data-id="{{.ID}}" data-id-selector="#label_{{.ID}}" data-scope="{{$exclusiveScope}}"><span class="octicon-check {{if not .IsChecked}}invisible{{end}}">{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}</span> {{RenderLabel $.Context .}}
|
|
||||||
{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji $.Context}}</small>{{end}}</a>
|
|
||||||
{{end}}
|
|
||||||
{{else}}
|
|
||||||
<div class="header" style="text-transform: none;font-size:14px;">{{.locale.Tr "repo.issues.new.no_items"}}</div>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{template "repo/issue/labels/labels_sidebar" dict "root" $}}
|
{{template "repo/issue/labels/labels_sidebar" dict "root" $}}
|
||||||
|
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
|
@ -53,15 +53,15 @@
|
|||||||
{{JsPrettyNumber .NumClosedIssues}} {{$.locale.Tr "repo.issues.closed_title"}}
|
{{JsPrettyNumber .NumClosedIssues}} {{$.locale.Tr "repo.issues.closed_title"}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{{if and (or $.CanWriteIssues $.CanWritePulls) (not $.Repository.IsArchived)}}
|
{{if and $.CanWriteProjects (not $.Repository.IsArchived)}}
|
||||||
<div class="ui right operate">
|
<div class="ui right operate">
|
||||||
<a href="{{$.Link}}/{{.ID}}/edit" data-id={{.ID}} data-title={{.Title}}>{{svg "octicon-pencil"}} {{$.locale.Tr "repo.issues.label_edit"}}</a>
|
<a href="{{.Link}}/edit" data-id={{.ID}} data-title={{.Title}}>{{svg "octicon-pencil"}} {{$.locale.Tr "repo.issues.label_edit"}}</a>
|
||||||
{{if .IsClosed}}
|
{{if .IsClosed}}
|
||||||
<a class="link-action" href data-url="{{$.Link}}/{{.ID}}/open">{{svg "octicon-check"}} {{$.locale.Tr "repo.projects.open"}}</a>
|
<a class="link-action" href data-url="{{.Link}}/open">{{svg "octicon-check"}} {{$.locale.Tr "repo.projects.open"}}</a>
|
||||||
{{else}}
|
{{else}}
|
||||||
<a class="link-action" href data-url="{{$.Link}}/{{.ID}}/close">{{svg "octicon-skip"}} {{$.locale.Tr "repo.projects.close"}}</a>
|
<a class="link-action" href data-url="{{.Link}}/close">{{svg "octicon-skip"}} {{$.locale.Tr "repo.projects.close"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
<a class="delete-button" href="#" data-url="{{$.RepoLink}}/projects/{{.ID}}/delete" data-id="{{.ID}}">{{svg "octicon-trash"}} {{$.locale.Tr "repo.issues.label_delete"}}</a>
|
<a class="delete-button" href="#" data-url="{{.Link}}/delete" data-id="{{.ID}}">{{svg "octicon-trash"}} {{$.locale.Tr "repo.issues.label_delete"}}</a>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .Description}}
|
{{if .Description}}
|
||||||
@ -77,7 +77,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{if or .CanWriteIssues .CanWritePulls}}
|
{{if .CanWriteProjects}}
|
||||||
<div class="ui small basic delete modal">
|
<div class="ui small basic delete modal">
|
||||||
<div class="ui icon header">
|
<div class="ui icon header">
|
||||||
{{svg "octicon-trash"}}
|
{{svg "octicon-trash"}}
|
||||||
|
@ -95,39 +95,35 @@ export function initRepoProject() {
|
|||||||
$('.edit-project-board').each(function () {
|
$('.edit-project-board').each(function () {
|
||||||
const projectHeader = $(this).closest('.board-column-header');
|
const projectHeader = $(this).closest('.board-column-header');
|
||||||
const projectTitleLabel = projectHeader.find('.board-label');
|
const projectTitleLabel = projectHeader.find('.board-label');
|
||||||
const projectTitleInput = $(this).find(
|
const projectTitleInput = $(this).find('.project-board-title');
|
||||||
'.content > .form > .field > .project-board-title',
|
const projectColorInput = $(this).find('#new_board_color');
|
||||||
);
|
|
||||||
const projectColorInput = $(this).find('.content > .form > .field #new_board_color');
|
|
||||||
const boardColumn = $(this).closest('.board-column');
|
const boardColumn = $(this).closest('.board-column');
|
||||||
|
|
||||||
if (boardColumn.css('backgroundColor')) {
|
if (boardColumn.css('backgroundColor')) {
|
||||||
setLabelColor(projectHeader, rgbToHex(boardColumn.css('backgroundColor')));
|
setLabelColor(projectHeader, rgbToHex(boardColumn.css('backgroundColor')));
|
||||||
}
|
}
|
||||||
|
|
||||||
$(this)
|
$(this).find('.edit-column-button').on('click', function (e) {
|
||||||
.find('.content > .form > .actions > .red')
|
e.preventDefault();
|
||||||
.on('click', function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: $(this).data('url'),
|
url: $(this).data('url'),
|
||||||
data: JSON.stringify({title: projectTitleInput.val(), color: projectColorInput.val()}),
|
data: JSON.stringify({title: projectTitleInput.val(), color: projectColorInput.val()}),
|
||||||
headers: {
|
headers: {
|
||||||
'X-Csrf-Token': csrfToken,
|
'X-Csrf-Token': csrfToken,
|
||||||
},
|
},
|
||||||
contentType: 'application/json',
|
contentType: 'application/json',
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
}).done(() => {
|
}).done(() => {
|
||||||
projectTitleLabel.text(projectTitleInput.val());
|
projectTitleLabel.text(projectTitleInput.val());
|
||||||
projectTitleInput.closest('form').removeClass('dirty');
|
projectTitleInput.closest('form').removeClass('dirty');
|
||||||
if (projectColorInput.val()) {
|
if (projectColorInput.val()) {
|
||||||
setLabelColor(projectHeader, projectColorInput.val());
|
setLabelColor(projectHeader, projectColorInput.val());
|
||||||
}
|
}
|
||||||
boardColumn.attr('style', `background: ${projectColorInput.val()}!important`);
|
boardColumn.attr('style', `background: ${projectColorInput.val()}!important`);
|
||||||
$('.ui.modal').modal('hide');
|
$('.ui.modal').modal('hide');
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on('click', '.set-default-project-board', async function (e) {
|
$(document).on('click', '.set-default-project-board', async function (e) {
|
||||||
|
@ -2838,11 +2838,11 @@
|
|||||||
|
|
||||||
.labels-list .label {
|
.labels-list .label {
|
||||||
margin: 2px 0;
|
margin: 2px 0;
|
||||||
display: inline-block !important;
|
display: inline-flex !important;
|
||||||
line-height: 1.3em; // there is a `font-size: 1.25em` for inside emoji, so here the line-height needs to be larger slightly
|
line-height: 1.3em; // there is a `font-size: 1.25em` for inside emoji, so here the line-height needs to be larger slightly
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scoped labels with different colors on left and right, and slanted divider in the middle
|
// Scoped labels with different colors on left and right
|
||||||
.scope-parent {
|
.scope-parent {
|
||||||
background: none !important;
|
background: none !important;
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
@ -2851,23 +2851,12 @@
|
|||||||
.ui.label.scope-left {
|
.ui.label.scope-left {
|
||||||
border-bottom-right-radius: 0;
|
border-bottom-right-radius: 0;
|
||||||
border-top-right-radius: 0;
|
border-top-right-radius: 0;
|
||||||
padding-right: 0;
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui.label.scope-middle {
|
|
||||||
width: 12px;
|
|
||||||
border-radius: 0;
|
|
||||||
padding-left: 0;
|
|
||||||
padding-right: 0;
|
|
||||||
margin-left: 0;
|
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.label.scope-right {
|
.ui.label.scope-right {
|
||||||
border-bottom-left-radius: 0;
|
border-bottom-left-radius: 0;
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
padding-left: 0;
|
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user