Skip to content

Commit

Permalink
feat: new changes for draft + work-item linking
Browse files Browse the repository at this point in the history
  • Loading branch information
sheldonhull committed Feb 17, 2023
1 parent 0d77f65 commit 271c149
Show file tree
Hide file tree
Showing 8 changed files with 341 additions and 15 deletions.
7 changes: 0 additions & 7 deletions .changes/unreleased/🎉 Feature-20230214-152153.yaml

This file was deleted.

12 changes: 12 additions & 0 deletions .changes/v0.2.0.md
@@ -0,0 +1,12 @@
## v0.2.0 - 2023-02-16

### 🎉 Feature

- When running `az-pr` by itself, it uses boa (powered by Bubbletea from Charm) to allow exploration of the subcommands and help content.
This might be replaced later, but is a nice experiment for better user exploration without running `--help` on every level of subcommand.
- Link workitems via `az-pr new`.
This runs a post step after creation due to limitations on the azure-cli to associate work-items on a created pull request.
Whatever is linked will be automatically set to complete once the pull request is merged.
Additionally, allow selection of draft true/false when creating.
- Enter into confetty mode after running. Rough work in progress, so press ctrl+c to exit after it triggers.
Why? The world needs more confetty and tacos.
15 changes: 12 additions & 3 deletions .changie.yaml
Expand Up @@ -9,15 +9,24 @@ versionFormat: '## {{.Version}} - {{.Time.Format "2006-01-02"}}'
kindFormat: '### {{.Kind}}'
changeFormat: '- {{ .Body -}}'
kinds:
- label: 🤖 CI
- label: 🤖 Development
- label: 🤖 CI & Build
auto: patch
- label: 🎉 Feature
- label: 🔨 Refactor
auto: minor
- label: ⬇️ Deprecated
auto: minor
- label: 🔨 Refactor
auto: patch
- label: 🐛 Bug Fix
auto: patch
- label: 🔥 Breaking Change
auto: minor
- label: 🔒 Security
auto: patch
- label: ⬆️ Dependencies
auto: patch
- label: 🔥 Major Version Change (Breaking Changes)
auto: major
newlines:
afterChange: 0
afterChangelogHeader: 1
Expand Down
11 changes: 11 additions & 0 deletions CHANGELOG.md
Expand Up @@ -6,6 +6,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
and is generated by [Changie](https://github.com/miniscruff/changie).

## v0.2.0 - 2023-02-16

### 🎉 Feature

- When running `az-pr` by itself, it uses boa (powered by Bubbletea from Charm) to allow exploration of the subcommands and help content.
This might be replaced later, but is a nice experiment for better user exploration without running `--help` on every level of subcommand.
- Link workitems via `az-pr new`.
This runs a post step after creation due to limitations on the azure-cli to associate work-items on a created pull request.
Whatever is linked will be automatically set to complete once the pull request is merged.
Additionally, allow selection of draft true/false when creating.

## v0.1.3 - 2023-02-13

### 🔨 Refactor
Expand Down
228 changes: 228 additions & 0 deletions bubbletea/form.go
@@ -0,0 +1,228 @@
package main

// Initialized from the Bubbletea examples library for simple text inputs

import (
"fmt"
"io"
"os"
"strings"

"github.com/charmbracelet/bubbles/list"
"github.com/charmbracelet/bubbles/textarea"
"github.com/charmbracelet/bubbles/textinput"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)

var (
focusedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("205"))
blurredStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("240"))
cursorStyle = focusedStyle.Copy()
noStyle = lipgloss.NewStyle()
helpStyle = blurredStyle.Copy()
cursorModeHelpStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("244"))

focusedButton = focusedStyle.Copy().Render("[ Submit ]")
blurredButton = fmt.Sprintf("[ %s ]", blurredStyle.Render("Submit"))

itemStyle = lipgloss.NewStyle().PaddingLeft(4)
selectedItemStyle = lipgloss.NewStyle().PaddingLeft(2).Foreground(lipgloss.Color("170"))
)

const (
listHeight = 14
)

type item string

func (i item) FilterValue() string { return "" }

type itemDelegate struct{}

func (d itemDelegate) Height() int { return 1 }
func (d itemDelegate) Spacing() int { return 0 }
func (d itemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil }
func (d itemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
i, ok := listItem.(item)
if !ok {
return
}

str := fmt.Sprintf("%d. %s", index+1, i)

fn := itemStyle.Render
if index == m.Index() {
fn = func(s string) string {
return selectedItemStyle.Render("> " + s)
}
}

fmt.Fprint(w, fn(str))
}

type model struct {
focusIndex int
inputs []textinput.Model
textarea textarea.Model
cursorMode textinput.CursorMode
list list.Model
}

// type item struct {
// title, desc string
// }

func initialModel() model {
var ta textarea.Model
ta = textarea.New()
ta.Placeholder = "change type"
ta.Focus()

items := []list.Item{
item("feat"), //, desc: "new feature work"},
item("feat"), //, desc: "new feature work"},
item("feat"), //, desc: "new feature work"},
}
m := model{
list: list.New(items, list.NewDefaultDelegate(), 0, 0),
inputs: make([]textinput.Model, 2),
textarea: ta,
}

var t textinput.Model

for i := range m.inputs {
t = textinput.New()
t.CursorStyle = cursorStyle
t.CharLimit = 32

switch i {
case 0:
t.Placeholder = "scope"
// t.Focus()
t.PromptStyle = focusedStyle
t.TextStyle = focusedStyle
case 1:
t.Placeholder = "title"
t.CharLimit = 64
}

m.inputs[i] = t
}

return m
}

func (m model) Init() tea.Cmd {
return textinput.Blink
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "esc":
return m, tea.Quit

// Change cursor mode
case "ctrl+r":
m.cursorMode++
if m.cursorMode > textinput.CursorHide {
m.cursorMode = textinput.CursorBlink
}
cmds := make([]tea.Cmd, len(m.inputs))
for i := range m.inputs {
cmds[i] = m.inputs[i].SetCursorMode(m.cursorMode)
}
return m, tea.Batch(cmds...)

// Set focus to next input
case "tab", "shift+tab", "enter", "up", "down":
s := msg.String()

// Did the user press enter while the submit button was focused?
// If so, exit.
if s == "enter" && m.focusIndex == len(m.inputs) {
return m, tea.Quit
}

// Cycle indexes
if s == "up" || s == "shift+tab" {
m.focusIndex--
} else {
m.focusIndex++
}

if m.focusIndex > len(m.inputs) {
m.focusIndex = 0
} else if m.focusIndex < 0 {
m.focusIndex = len(m.inputs)
}

cmds := make([]tea.Cmd, len(m.inputs))
for i := 0; i <= len(m.inputs)-1; i++ {
if i == m.focusIndex {
// Set focused state
cmds[i] = m.inputs[i].Focus()
m.inputs[i].PromptStyle = focusedStyle
m.inputs[i].TextStyle = focusedStyle
continue
}
// Remove focused state
m.inputs[i].Blur()
m.inputs[i].PromptStyle = noStyle
m.inputs[i].TextStyle = noStyle
}

return m, tea.Batch(cmds...)
}
}

// Handle character input and blinking
cmd := m.updateInputs(msg)

return m, cmd
}

func (m *model) updateInputs(msg tea.Msg) tea.Cmd {
cmds := make([]tea.Cmd, len(m.inputs))

// Only text inputs with Focus() set will respond, so it's safe to simply
// update all of them here without any further logic.
for i := range m.inputs {
m.inputs[i], cmds[i] = m.inputs[i].Update(msg)
}

return tea.Batch(cmds...)
}

func (m model) View() string {
var b strings.Builder
b.WriteString(m.list.View())
for i := range m.inputs {
b.WriteString(m.inputs[i].View())
if i < len(m.inputs)-1 {
b.WriteRune('\n')
}
}

button := &blurredButton
if m.focusIndex == len(m.inputs) {
button = &focusedButton
}
fmt.Fprintf(&b, "\n\n%s\n\n", *button)

b.WriteString(helpStyle.Render("cursor mode is "))
b.WriteString(cursorModeHelpStyle.Render(m.cursorMode.String()))
b.WriteString(helpStyle.Render(" (ctrl+r to change style)"))

return b.String()
}

func main() {
if _, err := tea.NewProgram(initialModel()).Run(); err != nil {
fmt.Printf("could not start program: %s\n", err)
os.Exit(1)
}
}

0 comments on commit 271c149

Please sign in to comment.