Add `--fields` to notification & milestone listings (#422)

Together with #415 this finally adds the field flag to all entity listings.
closes #342

### ⚠️ breaking changes ⚠️
This changes the column names of `tea milestones ls`:

```diff
 - TITLE  | OPEN/CLOSED ISSUES | DUEDATE
 + TITLE  | ITEMS | DUEDATE
```

Co-authored-by: Norwin <git@nroo.de>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/422
Reviewed-by: delvh <dev.lh@web.de>
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
This commit is contained in:
Norwin 2022-09-14 03:08:18 +08:00 committed by 6543
parent bbb287e29e
commit 99e49991bb
5 changed files with 149 additions and 80 deletions

View File

@ -13,6 +13,10 @@ import (
"github.com/urfave/cli/v2"
)
var fieldsFlag = flags.FieldsFlag(print.MilestoneFields, []string{
"title", "items", "duedate",
})
// CmdMilestonesList represents a sub command of milestones to list milestones
var CmdMilestonesList = cli.Command{
Name: "list",
@ -22,6 +26,7 @@ var CmdMilestonesList = cli.Command{
ArgsUsage: " ", // command does not accept arguments
Action: RunMilestonesList,
Flags: append([]cli.Flag{
fieldsFlag,
&cli.StringFlag{
Name: "state",
Usage: "Filter by milestone state (all|open|closed)",
@ -37,10 +42,18 @@ func RunMilestonesList(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
fields, err := fieldsFlag.GetValues(cmd)
if err != nil {
return err
}
state := gitea.StateOpen
switch ctx.String("state") {
case "all":
state = gitea.StateAll
if !cmd.IsSet("fields") { // add to default fields
fields = append(fields, "state")
}
case "closed":
state = gitea.StateClosed
}
@ -55,6 +68,6 @@ func RunMilestonesList(cmd *cli.Context) error {
return err
}
print.MilestonesList(milestones, ctx.Output, state)
print.MilestonesList(milestones, ctx.Output, fields)
return nil
}

View File

@ -15,7 +15,11 @@ import (
"github.com/urfave/cli/v2"
)
var notifTypeFlag = flags.NewCsvFlag("types", "subject types to filter by", []string{"t"},
var notifyFieldsFlag = flags.FieldsFlag(print.NotificationFields, []string{
"id", "status", "index", "type", "state", "title",
})
var notifyTypeFlag = flags.NewCsvFlag("types", "subject types to filter by", []string{"t"},
[]string{"issue", "pull", "repository", "commit"}, nil)
// CmdNotificationsList represents a sub command of notifications to list notifications
@ -26,7 +30,10 @@ var CmdNotificationsList = cli.Command{
Description: `List notifications`,
ArgsUsage: " ", // command does not accept arguments
Action: RunNotificationsList,
Flags: append([]cli.Flag{notifTypeFlag}, flags.NotificationFlags...),
Flags: append([]cli.Flag{
notifyFieldsFlag,
notifyTypeFlag,
}, flags.NotificationFlags...),
}
// RunNotificationsList list notifications
@ -41,7 +48,7 @@ func RunNotificationsList(ctx *cli.Context) error {
}
var types []gitea.NotifySubjectType
typesStr, err := notifTypeFlag.GetValues(ctx)
typesStr, err := notifyTypeFlag.GetValues(ctx)
if err != nil {
return err
}
@ -67,7 +74,17 @@ func listNotifications(cmd *cli.Context, status []gitea.NotifyStatus, subjects [
listOpts.Page = 1
}
fields, err := notifyFieldsFlag.GetValues(cmd)
if err != nil {
return err
}
if all {
// add repository to the default fields
if !cmd.IsSet("fields") {
fields = append(fields, "repository")
}
news, _, err = client.ListNotifications(gitea.ListNotificationOptions{
ListOptions: listOpts,
Status: status,
@ -85,6 +102,6 @@ func listNotifications(cmd *cli.Context, status []gitea.NotifyStatus, subjects [
log.Fatal(err)
}
print.NotificationsList(news, ctx.Output, all)
print.NotificationsList(news, ctx.Output, fields)
return nil
}

View File

@ -28,7 +28,7 @@ var CmdNotificationsMarkRead = cli.Command{
if err != nil {
return err
}
if !flags.NotificationStateFlag.IsSet() {
if !cmd.IsSet(flags.NotificationStateFlag.Name) {
filter = []string{string(gitea.NotifyStatusUnread)}
}
return markNotificationAs(cmd, filter, gitea.NotifyStatusRead)
@ -49,7 +49,7 @@ var CmdNotificationsMarkUnread = cli.Command{
if err != nil {
return err
}
if !flags.NotificationStateFlag.IsSet() {
if !cmd.IsSet(flags.NotificationStateFlag.Name) {
filter = []string{string(gitea.NotifyStatusRead)}
}
return markNotificationAs(cmd, filter, gitea.NotifyStatusUnread)
@ -70,7 +70,7 @@ var CmdNotificationsMarkPinned = cli.Command{
if err != nil {
return err
}
if !flags.NotificationStateFlag.IsSet() {
if !cmd.IsSet(flags.NotificationStateFlag.Name) {
filter = []string{string(gitea.NotifyStatusUnread)}
}
return markNotificationAs(cmd, filter, gitea.NotifyStatusPinned)

View File

@ -24,40 +24,65 @@ func MilestoneDetails(milestone *gitea.Milestone) {
}
// MilestonesList prints a listing of milestones
func MilestonesList(miles []*gitea.Milestone, output string, state gitea.StateType) {
headers := []string{
"Title",
func MilestonesList(news []*gitea.Milestone, output string, fields []string) {
var printables = make([]printable, len(news))
for i, x := range news {
printables[i] = &printableMilestone{x}
}
if state == gitea.StateAll {
headers = append(headers, "State")
}
headers = append(headers,
"Open/Closed Issues",
"DueDate",
)
t := table{headers: headers}
for _, m := range miles {
var deadline = ""
if m.Deadline != nil && !m.Deadline.IsZero() {
deadline = FormatTime(*m.Deadline, isMachineReadable(output))
}
item := []string{
m.Title,
}
if state == gitea.StateAll {
item = append(item, string(m.State))
}
item = append(item,
fmt.Sprintf("%d/%d", m.OpenIssues, m.ClosedIssues),
deadline,
)
t.addRowSlice(item)
}
t := tableFromItems(fields, printables, isMachineReadable(output))
t.sort(0, true)
t.print(output)
}
// MilestoneFields are all available fields to print with MilestonesList
var MilestoneFields = []string{
"title",
"state",
"items_open",
"items_closed",
"items",
"duedate",
"description",
"created",
"updated",
"closed",
"id",
}
type printableMilestone struct {
*gitea.Milestone
}
func (m printableMilestone) FormatField(field string, machineReadable bool) string {
switch field {
case "title":
return m.Title
case "state":
return string(m.State)
case "items_open":
return fmt.Sprintf("%d", m.OpenIssues)
case "items_closed":
return fmt.Sprintf("%d", m.ClosedIssues)
case "items":
return fmt.Sprintf("%d/%d", m.OpenIssues, m.ClosedIssues)
case "duedate":
if m.Deadline != nil && !m.Deadline.IsZero() {
return FormatTime(*m.Deadline, machineReadable)
}
case "id":
return fmt.Sprintf("%d", m.ID)
case "description":
return m.Description
case "created":
return FormatTime(m.Created, machineReadable)
case "updated":
if m.Updated != nil {
return FormatTime(*m.Updated, machineReadable)
}
case "closed":
if m.Closed != nil {
return FormatTime(*m.Closed, machineReadable)
}
}
return ""
}

View File

@ -12,26 +12,51 @@ import (
)
// NotificationsList prints a listing of notification threads
func NotificationsList(news []*gitea.NotificationThread, output string, showRepository bool) {
headers := []string{
"ID",
"Status",
"Type",
"State",
"Index",
"Title",
}
if showRepository {
headers = append(headers, "Repository")
func NotificationsList(news []*gitea.NotificationThread, output string, fields []string) {
var printables = make([]printable, len(news))
for i, x := range news {
printables[i] = &printableNotification{x}
}
t := tableFromItems(fields, printables, isMachineReadable(output))
t.print(output)
}
t := table{headers: headers}
// NotificationFields are all available fields to print with NotificationsList
var NotificationFields = []string{
"id",
"status",
"updated",
for _, n := range news {
if n.Subject == nil {
continue
// these are about the notification subject
"index",
"type",
"state",
"title",
"repository",
}
type printableNotification struct {
*gitea.NotificationThread
}
func (n printableNotification) FormatField(field string, machineReadable bool) string {
switch field {
case "id":
return fmt.Sprintf("%d", n.ID)
case "status":
status := "read"
if n.Pinned {
status = "pinned"
} else if n.Unread {
status = "unread"
}
// if pull or Issue get Index
return status
case "updated":
return FormatTime(n.UpdatedAt, machineReadable)
case "index":
var index string
if n.Subject.Type == "Issue" || n.Subject.Type == "Pull" {
index = n.Subject.URL
@ -39,31 +64,20 @@ func NotificationsList(news []*gitea.NotificationThread, output string, showRepo
if len(urlParts) != 0 {
index = urlParts[len(urlParts)-1]
}
index = "#" + index
}
return index
status := "read"
if n.Pinned {
status = "pinned"
} else if n.Unread {
status = "unread"
}
case "type":
return string(n.Subject.Type)
item := []string{
fmt.Sprint(n.ID),
status,
string(n.Subject.Type),
string(n.Subject.State),
index,
n.Subject.Title,
}
if showRepository {
item = append(item, n.Repository.FullName)
}
t.addRowSlice(item)
}
if t.Len() != 0 {
t.print(output)
case "state":
return string(n.Subject.State)
case "title":
return n.Subject.Title
case "repo", "repository":
return n.Repository.FullName
}
return ""
}