gitee_cli/utils/tui/table.go

208 lines
5.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package tui
import (
"fmt"
"gitee_cli/config"
"gitee_cli/internal/api/enterprises"
"gitee_cli/internal/api/issue"
"gitee_cli/internal/api/issue_state"
"gitee_cli/internal/api/pull_request"
"gitee_cli/utils/git_utils"
"gitee_cli/utils/tui/selector_tui"
"github.com/atotto/clipboard"
"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/bubbles/table"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/fatih/color"
"github.com/pkg/browser"
"os"
"strings"
)
var baseStyle = lipgloss.NewStyle().
BorderStyle(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color("240"))
const (
Issue = iota
IssueType
PullRequest
Enterprise
SSHKey
)
// Table TODO 初始化改成 options 模式
type Table struct {
table table.Model
SelectedKey string
ViewMode bool
ResourceType int
Enterprise enterprises.Enterprise
}
func NewTableModel(enterprise enterprises.Enterprise, resourceType int, columns []table.Column, rows []table.Row) Table {
height := 5
if resourceType == PullRequest {
height = 10
}
t := table.New(
table.WithColumns(columns),
table.WithRows(rows),
table.WithFocused(true),
table.WithHeight(height),
)
s := table.DefaultStyles()
s.Header = s.Header.
BorderStyle(lipgloss.NormalBorder()).
BorderForeground(lipgloss.Color("240")).
BorderBottom(true).
Bold(false)
s.Selected = s.Selected.
Foreground(lipgloss.Color("229")).
Background(lipgloss.Color("57")).
Bold(false)
if resourceType == PullRequest {
s.Selected = s.Selected.Background(lipgloss.Color("#8B4789"))
// 避免与 diff 快捷键冲突
t.KeyMap.HalfPageDown = key.NewBinding(
key.WithDisabled(),
)
}
t.SetStyles(s)
return Table{table: t, Enterprise: enterprise, ResourceType: resourceType}
}
func NewTable(enterprise enterprises.Enterprise, resourceType int, columns []table.Column, rows []table.Row) *tea.Program {
if resourceType == SSHKey || resourceType == Enterprise {
return tea.NewProgram(NewTableModel(enterprise, resourceType, columns, rows), tea.WithAltScreen())
}
return tea.NewProgram(NewTableModel(enterprise, resourceType, columns, rows))
}
func (t Table) Init() tea.Cmd { return nil }
func (t Table) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "esc":
if t.table.Focused() {
t.table.Blur()
} else {
t.table.Focus()
}
case "c":
if t.ResourceType == Issue || t.ResourceType == Enterprise {
clipboard.WriteAll(t.table.SelectedRow()[0])
} else if t.ResourceType == PullRequest {
clipboard.WriteAll(t.table.SelectedRow()[1])
}
case "q", "ctrl+c":
t.SelectedKey = ""
return t, tea.Quit
case "s":
if t.ResourceType == Issue {
targetIssue, err := issue.Detail(t.Enterprise.Id, t.table.SelectedRow()[0])
if err != nil {
color.Red("获取任务详情失败!")
return t, tea.Quit
}
if issueStates, err := issue_state.ListWithIssue(t.Enterprise.Id, targetIssue.Id); err == nil {
var model tea.Model
options := make([]string, 0)
optionMap := make(map[string]int, 0)
optionMap, options = issue_state.FillOptions(issueStates, optionMap, options)
promote := "请选择要变更的状态"
selector := selector_tui.NewMapSelector(optionMap, options, promote, true)
if model, err = selector.Run(); err != nil {
color.Red("任务状态选择器加载失败!")
os.Exit(1)
}
mapSelector, _ := model.(selector_tui.MapSelector)
issueStateId, err := mapSelector.SelectedValue()
if err != nil {
color.Red(err.Error())
os.Exit(1)
}
if targetIssue, err = issue.Update(t.Enterprise.Id, targetIssue.Id, map[string]interface{}{
"issue_state_id": issueStateId,
}); err != nil {
color.Red(err.Error())
os.Exit(1)
}
return t, tea.ClearScrollArea
} else {
color.Red("获取任务状态列表失败!")
os.Exit(1)
}
}
case "v":
if t.ResourceType == Issue {
if _issue, err := issue.Detail(t.Enterprise.Id, t.table.SelectedRow()[0]); err == nil {
NewPager(_issue.Title, _issue.Description, Markdown).Run()
} else {
color.Red("获取任务详情失败!")
return t, tea.Quit
}
} else if t.ResourceType == PullRequest {
path, _ := git_utils.ParseCurrentRepo()
if path == "" {
path = config.Conf.DefaultPathWithNamespace
}
t.SelectedKey = t.table.SelectedRow()[1]
if pullRequerst, err := pull_request.Detail(t.SelectedKey, path); err == nil {
NewPager(pullRequerst.Title, pullRequerst.Body, Markdown).Run()
} else {
color.Red("获取pr详情失败")
return t, tea.Quit
}
}
case "d":
if t.ResourceType == PullRequest {
path, _ := git_utils.ParseCurrentRepo()
t.SelectedKey = t.table.SelectedRow()[1]
if path == "" {
path = config.Conf.DefaultPathWithNamespace
}
if diff, err := pull_request.FetchPatchContent(t.SelectedKey, path); err == nil {
NewPager(t.table.SelectedRow()[0], diff, Diff).Run()
} else {
color.Red(err.Error())
return t, tea.Quit
}
}
case "enter":
t.SelectedKey = t.table.SelectedRow()[0]
if t.ResourceType == Issue {
url := fmt.Sprintf("https://e.gitee.com/%s/dashboard?issue=%s", t.Enterprise.Path, t.SelectedKey)
browser.OpenURL(url)
} else if t.ResourceType == PullRequest {
path, _ := git_utils.ParseCurrentRepo()
if path == "" {
path = config.Conf.DefaultPathWithNamespace
}
t.SelectedKey = t.table.SelectedRow()[1]
url := fmt.Sprintf("https://gitee.com/%s/pulls/%s", path, t.SelectedKey)
if os.Getenv("CONVERT_ENT_URL") != "" {
url = fmt.Sprintf("https://e.gitee.com/%s/repos/%s/pulls/%s", strings.Split(path, "/")[0], path, t.SelectedKey)
}
browser.OpenURL(url)
} else {
return t, tea.Quit
}
}
}
t.table, cmd = t.table.Update(msg)
return t, cmd
}
func (t Table) View() string {
return baseStyle.Render(t.table.View()) + "\n"
}