Skip to content

Commit 3eab553

Browse files
committed
feat: allow setting of fixed columns in the list of issues
1 parent 84206aa commit 3eab553

File tree

4 files changed

+82
-23
lines changed

4 files changed

+82
-23
lines changed

Diff for: internal/cmd/issue/list/list.go

+9-3
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ func loadList(cmd *cobra.Command) {
116116
noTruncate, err := cmd.Flags().GetBool("no-truncate")
117117
cmdutil.ExitIfError(err)
118118

119+
fixedColumns, err := cmd.Flags().GetUint("fixed-columns")
120+
cmdutil.ExitIfError(err)
121+
119122
columns, err := cmd.Flags().GetString("columns")
120123
cmdutil.ExitIfError(err)
121124

@@ -128,16 +131,18 @@ func loadList(cmd *cobra.Command) {
128131
loadList(cmd)
129132
},
130133
Display: view.DisplayFormat{
131-
Plain: plain,
132-
NoHeaders: noHeaders,
133-
NoTruncate: noTruncate,
134+
Plain: plain,
135+
NoHeaders: noHeaders,
136+
NoTruncate: noTruncate,
137+
FixedColumns: fixedColumns,
134138
Columns: func() []string {
135139
if columns != "" {
136140
return strings.Split(columns, ",")
137141
}
138142
return []string{}
139143
}(),
140144
TableStyle: cmdutil.GetTUIStyleConfig(),
145+
CustomKeys: viper.GetStringMap("custom_keys.issues"),
141146
},
142147
}
143148

@@ -178,6 +183,7 @@ func SetFlags(cmd *cobra.Command) {
178183
cmd.Flags().Bool("plain", false, "Display output in plain mode")
179184
cmd.Flags().Bool("no-headers", false, "Don't display table headers in plain mode. Works only with --plain")
180185
cmd.Flags().Bool("no-truncate", false, "Show all available columns in plain mode. Works only with --plain")
186+
cmd.Flags().Uint("fixed-columns", 1, "Number of fixed columns in the interactive mode.")
181187

182188
if cmd.HasParent() && cmd.Parent().Name() != "sprint" {
183189
cmd.Flags().String("columns", "", "Comma separated list of columns to display in the plain mode.\n"+

Diff for: internal/view/helper.go

+19
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"io"
66
"os"
7+
"os/exec"
78
"strings"
89
"text/tabwriter"
910
"time"
@@ -115,6 +116,24 @@ func jiraURLFromTuiData(server string, r int, d interface{}) string {
115116
return fmt.Sprintf("%s/browse/%s", server, issueKeyFromTuiData(r, d))
116117
}
117118

119+
func runInSh(command string) {
120+
cmd := exec.Command("sh", "-c", command)
121+
_ = cmd.Run()
122+
}
123+
124+
func customKeyFunc(row, _ int, data interface{}, command string) {
125+
i := issueKeyFromTuiData(row, data)
126+
expandedCommand := strings.ReplaceAll(command, "%KEY%", i)
127+
if strings.HasPrefix(expandedCommand, "&") {
128+
go func() {
129+
expandedCommand = strings.TrimPrefix(expandedCommand, "&")
130+
runInSh(expandedCommand)
131+
}()
132+
} else {
133+
runInSh(expandedCommand)
134+
}
135+
}
136+
118137
func navigate(server string) tui.SelectedFunc {
119138
return func(r, c int, d interface{}) {
120139
_ = browser.Browse(jiraURLFromTuiData(server, r, d))

Diff for: internal/view/issues.go

+9-5
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ import (
1515

1616
// DisplayFormat is a issue display type.
1717
type DisplayFormat struct {
18-
Plain bool
19-
NoHeaders bool
20-
NoTruncate bool
21-
Columns []string
22-
TableStyle tui.TableStyle
18+
Plain bool
19+
NoHeaders bool
20+
NoTruncate bool
21+
Columns []string
22+
FixedColumns uint
23+
TableStyle tui.TableStyle
24+
CustomKeys map[string]interface{}
2325
}
2426

2527
// IssueList is a list view for issues.
@@ -51,6 +53,7 @@ func (l *IssueList) Render() error {
5153
}
5254

5355
view := tui.NewTable(
56+
tui.WithCustomKeyFunc(customKeyFunc, l.Display.CustomKeys),
5457
tui.WithTableStyle(l.Display.TableStyle),
5558
tui.WithTableFooterText(l.FooterText),
5659
tui.WithSelectedFunc(navigate(l.Server)),
@@ -73,6 +76,7 @@ func (l *IssueList) Render() error {
7376
tui.WithCopyFunc(copyURL(l.Server)),
7477
tui.WithCopyKeyFunc(copyKey()),
7578
tui.WithRefreshFunc(l.Refresh),
79+
tui.WithFixedColumns(l.Display.FixedColumns),
7680
)
7781

7882
return view.Paint(data)

Diff for: pkg/tui/table.go

+45-15
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ type CopyFunc func(row, column int, data interface{})
3030
// CopyKeyFunc is fired when a user press 'CTRL+K' character in the table cell.
3131
type CopyKeyFunc func(row, column int, data interface{})
3232

33+
// CustomKeyFunc is fired when one of custom keys is pressed in the table cell.
34+
type CustomKeyFunc func(row, column int, data interface{}, command string)
35+
3336
// TableData is the data to be displayed in a table.
3437
type TableData [][]string
3538

@@ -42,20 +45,23 @@ type TableStyle struct {
4245

4346
// Table is a table layout.
4447
type Table struct {
45-
screen *Screen
46-
painter *tview.Pages
47-
view *tview.Table
48-
footer *tview.TextView
49-
style TableStyle
50-
data TableData
51-
colPad uint
52-
maxColWidth uint
53-
footerText string
54-
selectedFunc SelectedFunc
55-
viewModeFunc ViewModeFunc
56-
refreshFunc RefreshFunc
57-
copyFunc CopyFunc
58-
copyKeyFunc CopyKeyFunc
48+
screen *Screen
49+
painter *tview.Pages
50+
view *tview.Table
51+
footer *tview.TextView
52+
style TableStyle
53+
data TableData
54+
colPad uint
55+
colFixed uint
56+
maxColWidth uint
57+
footerText string
58+
selectedFunc SelectedFunc
59+
viewModeFunc ViewModeFunc
60+
customKeys map[string]interface{}
61+
customKeyFunc CustomKeyFunc
62+
refreshFunc RefreshFunc
63+
copyFunc CopyFunc
64+
copyKeyFunc CopyKeyFunc
5965
}
6066

6167
// TableOption is a functional option to wrap table properties.
@@ -120,6 +126,14 @@ func WithViewModeFunc(fn ViewModeFunc) TableOption {
120126
}
121127
}
122128

129+
// WithCustomKeyFunc sets a func that is triggered when one of custom keys is pressed.
130+
func WithCustomKeyFunc(fn CustomKeyFunc, keys map[string]interface{}) TableOption {
131+
return func(t *Table) {
132+
t.customKeyFunc = fn
133+
t.customKeys = keys
134+
}
135+
}
136+
123137
// WithRefreshFunc sets a func that is triggered when a user press 'CTRL+R' or 'F5'.
124138
func WithRefreshFunc(fn RefreshFunc) TableOption {
125139
return func(t *Table) {
@@ -141,6 +155,13 @@ func WithCopyKeyFunc(fn CopyKeyFunc) TableOption {
141155
}
142156
}
143157

158+
// WithFixedColumns sets the number of columns that are locked (do not scroll right).
159+
func WithFixedColumns(cols uint) TableOption {
160+
return func(t *Table) {
161+
t.colFixed = cols
162+
}
163+
}
164+
144165
// Paint paints the table layout. First row is treated as a table header.
145166
func (t *Table) Paint(data TableData) error {
146167
if len(data) == 0 {
@@ -224,12 +245,21 @@ func (t *Table) initTable() {
224245
// Refresh the screen.
225246
t.screen.Draw()
226247
}()
248+
default:
249+
if t.customKeyFunc != nil && t.customKeys != nil {
250+
for k, command := range t.customKeys {
251+
if string(ev.Rune()) == k {
252+
r, c := t.view.GetSelection()
253+
t.customKeyFunc(r, c, t.data, command.(string))
254+
}
255+
}
256+
}
227257
}
228258
}
229259
return ev
230260
})
231261

232-
t.view.SetFixed(1, 1)
262+
t.view.SetFixed(1, int(t.colFixed))
233263
}
234264

235265
func renderTableHeader(t *Table, data []string) {

0 commit comments

Comments
 (0)