Resolved some of suggestions from copilot
This commit is contained in:
@@ -6,10 +6,25 @@ import (
|
|||||||
"github.com/charmbracelet/lipgloss"
|
"github.com/charmbracelet/lipgloss"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// modalBoxWidth returns a clamped width for modal content. Never returns a value < 1.
|
||||||
|
func modalBoxWidth(maxWidth, width int) int {
|
||||||
|
if width < 5 {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
w := min(maxWidth, width-4)
|
||||||
|
if w < 1 {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
// components contains reusable TUI modal renderers for issue actions.
|
// components contains reusable TUI modal renderers for issue actions.
|
||||||
|
|
||||||
func RenderEditTitle(width, height int, inputView string) string {
|
func RenderEditTitle(width, height int, inputView string) string {
|
||||||
editBoxWidth := min(60, width-4)
|
if width < 5 || height < 5 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
editBoxWidth := modalBoxWidth(60, width)
|
||||||
editContent := lipgloss.JoinVertical(lipgloss.Left,
|
editContent := lipgloss.JoinVertical(lipgloss.Left,
|
||||||
styles.LabelStyle.Render("Edit title (Enter to save, Esc to cancel):"),
|
styles.LabelStyle.Render("Edit title (Enter to save, Esc to cancel):"),
|
||||||
inputView,
|
inputView,
|
||||||
@@ -22,7 +37,10 @@ func RenderEditTitle(width, height int, inputView string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RenderEditDescription(width, height int, inputView string) string {
|
func RenderEditDescription(width, height int, inputView string) string {
|
||||||
editBoxWidth := min(60, width-4)
|
if width < 5 || height < 5 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
editBoxWidth := modalBoxWidth(60, width)
|
||||||
editContent := lipgloss.JoinVertical(lipgloss.Left,
|
editContent := lipgloss.JoinVertical(lipgloss.Left,
|
||||||
styles.LabelStyle.Render("Edit description (Ctrl+S to save, Esc to cancel):"),
|
styles.LabelStyle.Render("Edit description (Ctrl+S to save, Esc to cancel):"),
|
||||||
inputView,
|
inputView,
|
||||||
@@ -35,7 +53,10 @@ func RenderEditDescription(width, height int, inputView string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RenderCreateIssue(width, height int, inputView string) string {
|
func RenderCreateIssue(width, height int, inputView string) string {
|
||||||
createBoxWidth := min(60, width-4)
|
if width < 5 || height < 5 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
createBoxWidth := modalBoxWidth(60, width)
|
||||||
createContent := lipgloss.JoinVertical(lipgloss.Left,
|
createContent := lipgloss.JoinVertical(lipgloss.Left,
|
||||||
styles.LabelStyle.Render("New issue (Enter to create, Esc to cancel):"),
|
styles.LabelStyle.Render("New issue (Enter to create, Esc to cancel):"),
|
||||||
inputView,
|
inputView,
|
||||||
@@ -48,11 +69,14 @@ func RenderCreateIssue(width, height int, inputView string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RenderConfirmDelete(width, height int, issueID string) string {
|
func RenderConfirmDelete(width, height int, issueID string) string {
|
||||||
|
if width < 5 || height < 5 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
confirmContent := lipgloss.JoinVertical(lipgloss.Left,
|
confirmContent := lipgloss.JoinVertical(lipgloss.Left,
|
||||||
styles.LabelStyle.Render("Delete issue "+issueID+"?"),
|
styles.LabelStyle.Render("Delete issue "+issueID+"?"),
|
||||||
lipgloss.NewStyle().Foreground(styles.FaintText).Render("Press y to delete, n or Esc to cancel"),
|
lipgloss.NewStyle().Foreground(styles.FaintText).Render("Press y to delete, n or Esc to cancel"),
|
||||||
)
|
)
|
||||||
confirmBoxWidth := min(50, width-4)
|
confirmBoxWidth := modalBoxWidth(50, width)
|
||||||
confirmBox := styles.ContainerStyle.
|
confirmBox := styles.ContainerStyle.
|
||||||
Width(confirmBoxWidth).
|
Width(confirmBoxWidth).
|
||||||
BorderForeground(styles.PrimaryBorder).
|
BorderForeground(styles.PrimaryBorder).
|
||||||
@@ -61,12 +85,15 @@ func RenderConfirmDelete(width, height int, issueID string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RenderChooseStatus(width, height int, issueID string) string {
|
func RenderChooseStatus(width, height int, issueID string) string {
|
||||||
|
if width < 5 || height < 5 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
statusContent := lipgloss.JoinVertical(lipgloss.Left,
|
statusContent := lipgloss.JoinVertical(lipgloss.Left,
|
||||||
styles.LabelStyle.Render("Change status for "+issueID+":"),
|
styles.LabelStyle.Render("Change status for "+issueID+":"),
|
||||||
lipgloss.NewStyle().Foreground(styles.FaintText).Render("o = open i = in_progress c = closed"),
|
lipgloss.NewStyle().Foreground(styles.FaintText).Render("o = open i = in_progress c = closed"),
|
||||||
lipgloss.NewStyle().Foreground(styles.FaintText).Render("Esc = cancel"),
|
lipgloss.NewStyle().Foreground(styles.FaintText).Render("Esc = cancel"),
|
||||||
)
|
)
|
||||||
statusBoxWidth := min(50, width-4)
|
statusBoxWidth := modalBoxWidth(50, width)
|
||||||
statusBox := styles.ContainerStyle.
|
statusBox := styles.ContainerStyle.
|
||||||
Width(statusBoxWidth).
|
Width(statusBoxWidth).
|
||||||
BorderForeground(styles.PrimaryBorder).
|
BorderForeground(styles.PrimaryBorder).
|
||||||
@@ -75,12 +102,15 @@ func RenderChooseStatus(width, height int, issueID string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RenderChoosePriority(width, height int, issueID string) string {
|
func RenderChoosePriority(width, height int, issueID string) string {
|
||||||
|
if width < 5 || height < 5 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
priorityContent := lipgloss.JoinVertical(lipgloss.Left,
|
priorityContent := lipgloss.JoinVertical(lipgloss.Left,
|
||||||
styles.LabelStyle.Render("Change priority for "+issueID+":"),
|
styles.LabelStyle.Render("Change priority for "+issueID+":"),
|
||||||
lipgloss.NewStyle().Foreground(styles.FaintText).Render("0 = irrelevant 1 = low 2 = normal 3 = high 4 = critical"),
|
lipgloss.NewStyle().Foreground(styles.FaintText).Render("0 = irrelevant 1 = low 2 = normal 3 = high 4 = critical"),
|
||||||
lipgloss.NewStyle().Foreground(styles.FaintText).Render("Esc = cancel"),
|
lipgloss.NewStyle().Foreground(styles.FaintText).Render("Esc = cancel"),
|
||||||
)
|
)
|
||||||
priorityBoxWidth := min(60, width-4)
|
priorityBoxWidth := modalBoxWidth(60, width)
|
||||||
priorityBox := styles.ContainerStyle.
|
priorityBox := styles.ContainerStyle.
|
||||||
Width(priorityBoxWidth).
|
Width(priorityBoxWidth).
|
||||||
BorderForeground(styles.PrimaryBorder).
|
BorderForeground(styles.PrimaryBorder).
|
||||||
@@ -89,12 +119,15 @@ func RenderChoosePriority(width, height int, issueID string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RenderChooseType(width, height int, issueID string) string {
|
func RenderChooseType(width, height int, issueID string) string {
|
||||||
|
if width < 5 || height < 5 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
typeContent := lipgloss.JoinVertical(lipgloss.Left,
|
typeContent := lipgloss.JoinVertical(lipgloss.Left,
|
||||||
styles.LabelStyle.Render("Change type for "+issueID+":"),
|
styles.LabelStyle.Render("Change type for "+issueID+":"),
|
||||||
lipgloss.NewStyle().Foreground(styles.FaintText).Render("b = bug f = feature t = task e = epic c = chore"),
|
lipgloss.NewStyle().Foreground(styles.FaintText).Render("b = bug f = feature t = task e = epic c = chore"),
|
||||||
lipgloss.NewStyle().Foreground(styles.FaintText).Render("Esc = cancel"),
|
lipgloss.NewStyle().Foreground(styles.FaintText).Render("Esc = cancel"),
|
||||||
)
|
)
|
||||||
typeBoxWidth := min(65, width-4)
|
typeBoxWidth := modalBoxWidth(65, width)
|
||||||
typeBox := styles.ContainerStyle.
|
typeBox := styles.ContainerStyle.
|
||||||
Width(typeBoxWidth).
|
Width(typeBoxWidth).
|
||||||
BorderForeground(styles.PrimaryBorder).
|
BorderForeground(styles.PrimaryBorder).
|
||||||
|
|||||||
@@ -14,10 +14,15 @@ type KanbanKeyMap struct {
|
|||||||
MoveColumnRight key.Binding
|
MoveColumnRight key.Binding
|
||||||
MoveIssueLeft key.Binding
|
MoveIssueLeft key.Binding
|
||||||
MoveIssueRight key.Binding
|
MoveIssueRight key.Binding
|
||||||
|
SubmitValidation key.Binding
|
||||||
}
|
}
|
||||||
|
|
||||||
var defaultKanbanKeyMap = KanbanKeyMap{
|
var defaultKanbanKeyMap = KanbanKeyMap{
|
||||||
CommonKeyMap: components.DefaultCommonKeyMap(),
|
CommonKeyMap: components.DefaultCommonKeyMap(),
|
||||||
|
SubmitValidation: key.NewBinding(
|
||||||
|
key.WithKeys("S"),
|
||||||
|
key.WithHelp("S", "submit validation"),
|
||||||
|
),
|
||||||
SwitchToDashboard: key.NewBinding(
|
SwitchToDashboard: key.NewBinding(
|
||||||
key.WithKeys("v"),
|
key.WithKeys("v"),
|
||||||
key.WithHelp("v", "dashboard 1"),
|
key.WithHelp("v", "dashboard 1"),
|
||||||
@@ -44,6 +49,13 @@ func (d *Model) handleKeyMsg(msg tea.KeyMsg) tea.Cmd {
|
|||||||
var cmd tea.Cmd
|
var cmd tea.Cmd
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
case key.Matches(msg, d.keyMap.SubmitValidation):
|
||||||
|
if d.submitChan != nil {
|
||||||
|
select {
|
||||||
|
case d.submitChan <- struct{}{}:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
case key.Matches(msg, d.keyMap.Help):
|
case key.Matches(msg, d.keyMap.Help):
|
||||||
d.helpBar.ToggleHelp()
|
d.helpBar.ToggleHelp()
|
||||||
case key.Matches(msg, d.keyMap.Quit):
|
case key.Matches(msg, d.keyMap.Quit):
|
||||||
|
|||||||
@@ -55,11 +55,12 @@ type Model struct {
|
|||||||
typeIssueID string
|
typeIssueID string
|
||||||
feedbackChan chan models.ValidationFeedback
|
feedbackChan chan models.ValidationFeedback
|
||||||
quitChan chan bool
|
quitChan chan bool
|
||||||
|
submitChan chan<- struct{}
|
||||||
currentFeedback models.ValidationFeedback
|
currentFeedback models.ValidationFeedback
|
||||||
showComplete bool
|
showComplete bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDashboard(app *app.App, feedbackChan chan models.ValidationFeedback, quitChan chan bool) *Model {
|
func NewDashboard(app *app.App, feedbackChan chan models.ValidationFeedback, quitChan chan bool, submitChan chan<- struct{}) *Model {
|
||||||
m := &Model{
|
m := &Model{
|
||||||
header: components.NewHeader("Kanban Board"),
|
header: components.NewHeader("Kanban Board"),
|
||||||
keyMap: defaultKanbanKeyMap,
|
keyMap: defaultKanbanKeyMap,
|
||||||
@@ -70,6 +71,7 @@ func NewDashboard(app *app.App, feedbackChan chan models.ValidationFeedback, qui
|
|||||||
focusOnDetail: false,
|
focusOnDetail: false,
|
||||||
feedbackChan: feedbackChan,
|
feedbackChan: feedbackChan,
|
||||||
quitChan: quitChan,
|
quitChan: quitChan,
|
||||||
|
submitChan: submitChan,
|
||||||
}
|
}
|
||||||
|
|
||||||
allIssues, _ := app.Issues.SearchIssues(context.Background(), "", models.IssueFilter{})
|
allIssues, _ := app.Issues.SearchIssues(context.Background(), "", models.IssueFilter{})
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ type RootModel struct {
|
|||||||
app *app.App
|
app *app.App
|
||||||
feedbackChan chan models.ValidationFeedback
|
feedbackChan chan models.ValidationFeedback
|
||||||
quitChan chan bool
|
quitChan chan bool
|
||||||
|
submitChan chan<- struct{}
|
||||||
lastSize tea.WindowSizeMsg
|
lastSize tea.WindowSizeMsg
|
||||||
hasSize bool
|
hasSize bool
|
||||||
}
|
}
|
||||||
@@ -25,6 +26,7 @@ func NewRootView(app *app.App, feedbackChan chan models.ValidationFeedback, quit
|
|||||||
app: app,
|
app: app,
|
||||||
feedbackChan: feedbackChan,
|
feedbackChan: feedbackChan,
|
||||||
quitChan: quitChan,
|
quitChan: quitChan,
|
||||||
|
submitChan: submitChan,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +46,7 @@ func (r *RootModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
return r, cmd
|
return r, cmd
|
||||||
case msgs.SwitchToDashboardMsg:
|
case msgs.SwitchToDashboardMsg:
|
||||||
// switch back to dashboard 1 and apply the last known size.
|
// switch back to dashboard 1 and apply the last known size.
|
||||||
r.currentView = dashboard.NewDashboard(r.app, r.feedbackChan, r.quitChan, r.app.SubmitChan)
|
r.currentView = dashboard.NewDashboard(r.app, r.feedbackChan, r.quitChan, r.submitChan)
|
||||||
var cmds []tea.Cmd
|
var cmds []tea.Cmd
|
||||||
if r.hasSize {
|
if r.hasSize {
|
||||||
// check if there is a size, and then update it
|
// check if there is a size, and then update it
|
||||||
@@ -59,7 +61,7 @@ func (r *RootModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
return r, tea.Batch(cmds...)
|
return r, tea.Batch(cmds...)
|
||||||
case msgs.SwitchToKanbanBoardMsg:
|
case msgs.SwitchToKanbanBoardMsg:
|
||||||
// switch to kanban board and apply the last known size.
|
// switch to kanban board and apply the last known size.
|
||||||
r.currentView = kanban.NewDashboard(r.app, r.feedbackChan, r.quitChan)
|
r.currentView = kanban.NewDashboard(r.app, r.feedbackChan, r.quitChan, r.submitChan)
|
||||||
var cmds []tea.Cmd
|
var cmds []tea.Cmd
|
||||||
if r.hasSize {
|
if r.hasSize {
|
||||||
// check if there is a size, and then update it
|
// check if there is a size, and then update it
|
||||||
|
|||||||
Reference in New Issue
Block a user