mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-11-25 08:59:31 -05:00
Add label descriptions (#3662)
* Add label descriptions * Add default descriptions to label template
This commit is contained in:
parent
ad33730dca
commit
c0d41b1b77
14 changed files with 109 additions and 34 deletions
|
@ -19,22 +19,24 @@ import (
|
||||||
var labelColorPattern = regexp.MustCompile("#([a-fA-F0-9]{6})")
|
var labelColorPattern = regexp.MustCompile("#([a-fA-F0-9]{6})")
|
||||||
|
|
||||||
// GetLabelTemplateFile loads the label template file by given name,
|
// GetLabelTemplateFile loads the label template file by given name,
|
||||||
// then parses and returns a list of name-color pairs.
|
// then parses and returns a list of name-color pairs and optionally description.
|
||||||
func GetLabelTemplateFile(name string) ([][2]string, error) {
|
func GetLabelTemplateFile(name string) ([][3]string, error) {
|
||||||
data, err := getRepoInitFile("label", name)
|
data, err := getRepoInitFile("label", name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("getRepoInitFile: %v", err)
|
return nil, fmt.Errorf("getRepoInitFile: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lines := strings.Split(string(data), "\n")
|
lines := strings.Split(string(data), "\n")
|
||||||
list := make([][2]string, 0, len(lines))
|
list := make([][3]string, 0, len(lines))
|
||||||
for i := 0; i < len(lines); i++ {
|
for i := 0; i < len(lines); i++ {
|
||||||
line := strings.TrimSpace(lines[i])
|
line := strings.TrimSpace(lines[i])
|
||||||
if len(line) == 0 {
|
if len(line) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
fields := strings.SplitN(line, " ", 2)
|
parts := strings.SplitN(line, ";", 2)
|
||||||
|
|
||||||
|
fields := strings.SplitN(parts[0], " ", 2)
|
||||||
if len(fields) != 2 {
|
if len(fields) != 2 {
|
||||||
return nil, fmt.Errorf("line is malformed: %s", line)
|
return nil, fmt.Errorf("line is malformed: %s", line)
|
||||||
}
|
}
|
||||||
|
@ -43,8 +45,14 @@ func GetLabelTemplateFile(name string) ([][2]string, error) {
|
||||||
return nil, fmt.Errorf("bad HTML color code in line: %s", line)
|
return nil, fmt.Errorf("bad HTML color code in line: %s", line)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var description string
|
||||||
|
|
||||||
|
if len(parts) > 1 {
|
||||||
|
description = strings.TrimSpace(parts[1])
|
||||||
|
}
|
||||||
|
|
||||||
fields[1] = strings.TrimSpace(fields[1])
|
fields[1] = strings.TrimSpace(fields[1])
|
||||||
list = append(list, [2]string{fields[1], fields[0]})
|
list = append(list, [3]string{fields[1], fields[0], description})
|
||||||
}
|
}
|
||||||
|
|
||||||
return list, nil
|
return list, nil
|
||||||
|
@ -55,6 +63,7 @@ type Label struct {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
RepoID int64 `xorm:"INDEX"`
|
RepoID int64 `xorm:"INDEX"`
|
||||||
Name string
|
Name string
|
||||||
|
Description string
|
||||||
Color string `xorm:"VARCHAR(7)"`
|
Color string `xorm:"VARCHAR(7)"`
|
||||||
NumIssues int
|
NumIssues int
|
||||||
NumClosedIssues int
|
NumClosedIssues int
|
||||||
|
|
|
@ -168,6 +168,8 @@ var migrations = []Migration{
|
||||||
NewMigration("remove is_owner, num_teams columns from org_user", removeIsOwnerColumnFromOrgUser),
|
NewMigration("remove is_owner, num_teams columns from org_user", removeIsOwnerColumnFromOrgUser),
|
||||||
// v57 -> v58
|
// v57 -> v58
|
||||||
NewMigration("add closed_unix column for issues", addIssueClosedTime),
|
NewMigration("add closed_unix column for issues", addIssueClosedTime),
|
||||||
|
// v58 -> v59
|
||||||
|
NewMigration("add label descriptions", addLabelsDescriptions),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Migrate database to current version
|
// Migrate database to current version
|
||||||
|
|
22
models/migrations/v58.go
Normal file
22
models/migrations/v58.go
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/go-xorm/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func addLabelsDescriptions(x *xorm.Engine) error {
|
||||||
|
type Label struct {
|
||||||
|
Description string
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := x.Sync2(new(Label)); err != nil {
|
||||||
|
return fmt.Errorf("Sync2: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -310,9 +310,10 @@ func (f *CreateMilestoneForm) Validate(ctx *macaron.Context, errs binding.Errors
|
||||||
|
|
||||||
// CreateLabelForm form for creating label
|
// CreateLabelForm form for creating label
|
||||||
type CreateLabelForm struct {
|
type CreateLabelForm struct {
|
||||||
ID int64
|
ID int64
|
||||||
Title string `binding:"Required;MaxSize(50)" locale:"repo.issues.label_name"`
|
Title string `binding:"Required;MaxSize(50)" locale:"repo.issues.label_title"`
|
||||||
Color string `binding:"Required;Size(7)" locale:"repo.issues.label_color"`
|
Description string `binding:"MaxSize(200)" locale:"repo.issues.label_description"`
|
||||||
|
Color string `binding:"Required;Size(7)" locale:"repo.issues.label_color"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ee0701 bug
|
#ee0701 bug ; Something is not working
|
||||||
#cccccc duplicate
|
#cccccc duplicate ; This issue or pull request already exists
|
||||||
#84b6eb enhancement
|
#84b6eb enhancement ; New feature
|
||||||
#128a0c help wanted
|
#128a0c help wanted ; Need some help
|
||||||
#e6e6e6 invalid
|
#e6e6e6 invalid ; Something is wrong
|
||||||
#cc317c question
|
#cc317c question ; More information is needed
|
||||||
#ffffff wontfix
|
#ffffff wontfix ; This won't be fixed
|
||||||
|
|
|
@ -627,6 +627,7 @@ issues.no_ref = No Branch/Tag Specified
|
||||||
issues.create = Create Issue
|
issues.create = Create Issue
|
||||||
issues.new_label = New Label
|
issues.new_label = New Label
|
||||||
issues.new_label_placeholder = Label name…
|
issues.new_label_placeholder = Label name…
|
||||||
|
issues.new_label_desc_placeholder = Description…
|
||||||
issues.create_label = Create Label
|
issues.create_label = Create Label
|
||||||
issues.label_templates.title = Load a predefined set of labels
|
issues.label_templates.title = Load a predefined set of labels
|
||||||
issues.label_templates.info = There are not any labels yet. You can click on the "New Label" button above to create one or use a predefined set below.
|
issues.label_templates.info = There are not any labels yet. You can click on the "New Label" button above to create one or use a predefined set below.
|
||||||
|
@ -697,6 +698,7 @@ issues.edit = Edit
|
||||||
issues.cancel = Cancel
|
issues.cancel = Cancel
|
||||||
issues.save = Save
|
issues.save = Save
|
||||||
issues.label_title = Label name
|
issues.label_title = Label name
|
||||||
|
issues.label_description = Label description
|
||||||
issues.label_color = Label color
|
issues.label_color = Label color
|
||||||
issues.label_count = %d labels
|
issues.label_count = %d labels
|
||||||
issues.label_open_issues = %d open issues
|
issues.label_open_issues = %d open issues
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -491,6 +491,7 @@ function initRepository() {
|
||||||
$('.edit-label-button').click(function () {
|
$('.edit-label-button').click(function () {
|
||||||
$('#label-modal-id').val($(this).data('id'));
|
$('#label-modal-id').val($(this).data('id'));
|
||||||
$('.edit-label .new-label-input').val($(this).data('title'));
|
$('.edit-label .new-label-input').val($(this).data('title'));
|
||||||
|
$('.edit-label .new-label-desc-input').val($(this).data('description'));
|
||||||
$('.edit-label .color-picker').val($(this).data('color'));
|
$('.edit-label .color-picker').val($(this).data('color'));
|
||||||
$('.minicolors-swatch-color').css("background-color", $(this).data('color'));
|
$('.minicolors-swatch-color').css("background-color", $(this).data('color'));
|
||||||
$('.edit-label.modal').modal({
|
$('.edit-label.modal').modal({
|
||||||
|
|
|
@ -134,6 +134,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.select-label {
|
||||||
|
.item {
|
||||||
|
max-width: 250px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.desc {
|
||||||
|
padding-left: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.ui.tabs {
|
.ui.tabs {
|
||||||
&.container {
|
&.container {
|
||||||
margin-top: 14px;
|
margin-top: 14px;
|
||||||
|
|
|
@ -42,9 +42,10 @@ func InitializeLabels(ctx *context.Context, form auth.InitializeLabelsForm) {
|
||||||
labels := make([]*models.Label, len(list))
|
labels := make([]*models.Label, len(list))
|
||||||
for i := 0; i < len(list); i++ {
|
for i := 0; i < len(list); i++ {
|
||||||
labels[i] = &models.Label{
|
labels[i] = &models.Label{
|
||||||
RepoID: ctx.Repo.Repository.ID,
|
RepoID: ctx.Repo.Repository.ID,
|
||||||
Name: list[i][0],
|
Name: list[i][0],
|
||||||
Color: list[i][1],
|
Description: list[i][2],
|
||||||
|
Color: list[i][1],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := models.NewLabels(labels...); err != nil {
|
if err := models.NewLabels(labels...); err != nil {
|
||||||
|
@ -81,9 +82,10 @@ func NewLabel(ctx *context.Context, form auth.CreateLabelForm) {
|
||||||
}
|
}
|
||||||
|
|
||||||
l := &models.Label{
|
l := &models.Label{
|
||||||
RepoID: ctx.Repo.Repository.ID,
|
RepoID: ctx.Repo.Repository.ID,
|
||||||
Name: form.Title,
|
Name: form.Title,
|
||||||
Color: form.Color,
|
Description: form.Description,
|
||||||
|
Color: form.Color,
|
||||||
}
|
}
|
||||||
if err := models.NewLabel(l); err != nil {
|
if err := models.NewLabel(l); err != nil {
|
||||||
ctx.ServerError("NewLabel", err)
|
ctx.ServerError("NewLabel", err)
|
||||||
|
@ -106,6 +108,7 @@ func UpdateLabel(ctx *context.Context, form auth.CreateLabelForm) {
|
||||||
}
|
}
|
||||||
|
|
||||||
l.Name = form.Title
|
l.Name = form.Title
|
||||||
|
l.Description = form.Description
|
||||||
l.Color = form.Color
|
l.Color = form.Color
|
||||||
if err := models.UpdateLabel(l); err != nil {
|
if err := models.UpdateLabel(l); err != nil {
|
||||||
ctx.ServerError("UpdateLabel", err)
|
ctx.ServerError("UpdateLabel", err)
|
||||||
|
|
|
@ -14,11 +14,16 @@
|
||||||
<form class="ui form" action="{{$.RepoLink}}/labels/new" method="post">
|
<form class="ui form" action="{{$.RepoLink}}/labels/new" method="post">
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
<div class="ui grid">
|
<div class="ui grid">
|
||||||
<div class="five wide column">
|
<div class="three wide column">
|
||||||
<div class="ui small input">
|
<div class="ui small input">
|
||||||
<input class="new-label-input" name="title" placeholder="{{.i18n.Tr "repo.issues.new_label_placeholder"}}" autofocus required>
|
<input class="new-label-input" name="title" placeholder="{{.i18n.Tr "repo.issues.new_label_placeholder"}}" autofocus required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="five wide column">
|
||||||
|
<div class="ui small fluid input">
|
||||||
|
<input class="new-label-desc-input" name="description" placeholder="{{.i18n.Tr "repo.issues.new_label_desc_placeholder"}}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="color picker column">
|
<div class="color picker column">
|
||||||
<input class="color-picker" name="color" value="#70c24a" required>
|
<input class="color-picker" name="color" value="#70c24a" required>
|
||||||
</div>
|
</div>
|
||||||
|
@ -85,14 +90,27 @@
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
|
||||||
{{range .Labels}}
|
{{range .Labels}}
|
||||||
<li class="item">
|
<li class="item">
|
||||||
<div class="ui label" style="color: {{.ForegroundColor}}; background-color: {{.Color}}"><i class="octicon octicon-tag"></i> {{.Name}}</div>
|
<div class="ui grid">
|
||||||
{{if $.IsRepositoryWriter}}
|
<div class="three wide column">
|
||||||
<a class="ui right delete-button" href="#" data-url="{{$.RepoLink}}/labels/delete" data-id="{{.ID}}"><i class="octicon octicon-trashcan"></i> {{$.i18n.Tr "repo.issues.label_delete"}}</a>
|
<div class="ui label" style="color: {{.ForegroundColor}}; background-color: {{.Color}}"><i class="octicon octicon-tag"></i> {{.Name}}</div>
|
||||||
<a class="ui right edit-label-button" href="#" data-id={{.ID}} data-title={{.Name}} data-color={{.Color}}><i class="octicon octicon-pencil"></i> {{$.i18n.Tr "repo.issues.label_edit"}}</a>
|
</div>
|
||||||
{{end}}
|
<div class="seven wide column">
|
||||||
<a class="ui right open-issues" href="{{$.RepoLink}}/issues?labels={{.ID}}"><i class="octicon octicon-issue-opened"></i> {{$.i18n.Tr "repo.issues.label_open_issues" .NumOpenIssues}}</a>
|
{{.Description}}
|
||||||
|
</div>
|
||||||
|
<div class="three wide column">
|
||||||
|
<a class="ui right open-issues" href="{{$.RepoLink}}/issues?labels={{.ID}}"><i class="octicon octicon-issue-opened"></i> {{$.i18n.Tr "repo.issues.label_open_issues" .NumOpenIssues}}</a>
|
||||||
|
</div>
|
||||||
|
<div class="three wide column">
|
||||||
|
{{if $.IsRepositoryWriter}}
|
||||||
|
<a class="ui right delete-button" href="#" data-url="{{$.RepoLink}}/labels/delete" data-id="{{.ID}}"><i class="octicon octicon-trashcan"></i> {{$.i18n.Tr "repo.issues.label_delete"}}</a>
|
||||||
|
<a class="ui right edit-label-button" href="#" data-id="{{.ID}}" data-title="{{.Name}}" data-description="{{.Description}}" data-color={{.Color}}><i class="octicon octicon-pencil"></i> {{$.i18n.Tr "repo.issues.label_edit"}}</a>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
@ -129,11 +147,16 @@
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
<input id="label-modal-id" name="id" type="hidden">
|
<input id="label-modal-id" name="id" type="hidden">
|
||||||
<div class="ui grid">
|
<div class="ui grid">
|
||||||
<div class="five wide column">
|
<div class="three wide column">
|
||||||
<div class="ui small input">
|
<div class="ui small input">
|
||||||
<input class="new-label-input" name="title" placeholder="{{.i18n.Tr "repo.issues.new_label_placeholder"}}" autofocus required>
|
<input class="new-label-input" name="title" placeholder="{{.i18n.Tr "repo.issues.new_label_placeholder"}}" autofocus required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="five wide column">
|
||||||
|
<div class="ui small fluid input">
|
||||||
|
<input class="new-label-desc-input" name="description" placeholder="{{.i18n.Tr "repo.issues.new_label_desc_placeholder"}}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="color picker column">
|
<div class="color picker column">
|
||||||
<input class="color-picker" name="color" value="#70c24a" required>
|
<input class="color-picker" name="color" value="#70c24a" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -191,7 +191,7 @@
|
||||||
<a class="ui label" href="{{$.RepoLink}}/src/branch/{{.Ref}}">{{.Ref}}</a>
|
<a class="ui label" href="{{$.RepoLink}}/src/branch/{{.Ref}}">{{.Ref}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{range .Labels}}
|
{{range .Labels}}
|
||||||
<a class="ui label" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}" style="color: {{.ForegroundColor}}; background-color: {{.Color}}">{{.Name}}</a>
|
<a class="ui label" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}" style="color: {{.ForegroundColor}}; background-color: {{.Color}}" title="{{.Description}}">{{.Name}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if .NumComments}}
|
{{if .NumComments}}
|
||||||
|
|
|
@ -10,7 +10,8 @@
|
||||||
<div class="filter menu" data-action="update" data-issue-id="{{$.Issue.ID}}" data-update-url="{{$.RepoLink}}/issues/labels">
|
<div class="filter menu" data-action="update" data-issue-id="{{$.Issue.ID}}" data-update-url="{{$.RepoLink}}/issues/labels">
|
||||||
<div class="no-select item">{{.i18n.Tr "repo.issues.new.clear_labels"}}</div>
|
<div class="no-select item">{{.i18n.Tr "repo.issues.new.clear_labels"}}</div>
|
||||||
{{range .Labels}}
|
{{range .Labels}}
|
||||||
<a class="{{if .IsChecked}}checked{{end}} item" href="#" data-id="{{.ID}}" data-id-selector="#label_{{.ID}}"><span class="octicon {{if .IsChecked}}octicon-check{{end}}"></span><span class="label color" style="background-color: {{.Color}}"></span> {{.Name}}</a>
|
<a class="{{if .IsChecked}}checked{{end}} item" href="#" data-id="{{.ID}}" data-id-selector="#label_{{.ID}}"><span class="octicon {{if .IsChecked}}octicon-check{{end}}"></span><span class="label color" style="background-color: {{.Color}}"></span> {{.Name}}
|
||||||
|
{{if .Description }}<br><small class="desc">{{.Description}}</small>{{end}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -18,7 +19,7 @@
|
||||||
<span class="no-select item {{if .HasSelectedLabel}}hide{{end}}">{{.i18n.Tr "repo.issues.new.no_label"}}</span>
|
<span class="no-select item {{if .HasSelectedLabel}}hide{{end}}">{{.i18n.Tr "repo.issues.new.no_label"}}</span>
|
||||||
{{range .Labels}}
|
{{range .Labels}}
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<a class="ui label {{if not .IsChecked}}hide{{end}}" id="label_{{.ID}}" href="{{$.RepoLink}}/issues?labels={{.ID}}" style="color: {{.ForegroundColor}}; background-color: {{.Color}}">{{.Name}}</a>
|
<a class="ui label {{if not .IsChecked}}hide{{end}}" id="label_{{.ID}}" href="{{$.RepoLink}}/issues?labels={{.ID}}" style="color: {{.ForegroundColor}}; background-color: {{.Color}}" title="{{.Description}}">{{.Name}}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -71,7 +71,7 @@
|
||||||
especially on mobile views. */}}
|
especially on mobile views. */}}
|
||||||
<span style="line-height: 2.5">
|
<span style="line-height: 2.5">
|
||||||
{{range .}}
|
{{range .}}
|
||||||
<a class="ui label" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}" style="color: {{.ForegroundColor}}; background-color: {{.Color}}">{{.Name}}</a>
|
<a class="ui label" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}" style="color: {{.ForegroundColor}}; background-color: {{.Color}}" title="{{.Description}}">{{.Name}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</span>
|
</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
Loading…
Reference in a new issue