From 8c74d739e953db439b700183d09dfab58be8e508 Mon Sep 17 00:00:00 2001 From: Adam Cooper Date: Tue, 21 Mar 2023 18:45:53 +0100 Subject: [PATCH] Help (#31) * Add helps --- main.go | 3 +- models/orgKeyMap.go | 69 +++++++++++++++ models/{organisationModel.go => orgModel.go} | 69 ++++++++------- models/orgModel_test.go | 66 ++++++++++++++ models/organisationModel_test.go | 35 -------- models/repoKeyMap.go | 63 ++++++++++++++ models/{repositoryModel.go => repoModel.go} | 65 +++++++------- models/repoModel_test.go | 30 +++++++ models/styles.go | 24 ++---- models/userModel.go | 8 +- models/utils.go | 19 +++++ models/utils_test.go | 68 +++++++++++++++ structs/repositorySetting.go | 90 ++++++++++---------- 13 files changed, 438 insertions(+), 171 deletions(-) create mode 100644 models/orgKeyMap.go rename models/{organisationModel.go => orgModel.go} (65%) create mode 100644 models/orgModel_test.go delete mode 100644 models/organisationModel_test.go create mode 100644 models/repoKeyMap.go rename models/{repositoryModel.go => repoModel.go} (58%) create mode 100644 models/repoModel_test.go create mode 100644 models/utils.go create mode 100644 models/utils_test.go diff --git a/main.go b/main.go index a06c44a..07c800c 100644 --- a/main.go +++ b/main.go @@ -5,11 +5,12 @@ import ( "os" "hub-bub/models" + tea "github.com/charmbracelet/bubbletea" ) func main() { - models.MainModel = []tea.Model{&models.UserModel{}, &models.OrganisationModel{}} + models.MainModel = []tea.Model{&models.UserModel{}, &models.OrgModel{}} p := tea.NewProgram(models.MainModel[models.UserModelName]) if _, err := p.Run(); err != nil { diff --git a/models/orgKeyMap.go b/models/orgKeyMap.go new file mode 100644 index 0000000..f9ee5b5 --- /dev/null +++ b/models/orgKeyMap.go @@ -0,0 +1,69 @@ +package models + +import "github.com/charmbracelet/bubbles/key" + +// keyMap defines a set of keybindings. To work for help it must satisfy +// key.Map. It could also very easily be a map[string]key.Binding. +type orgKeyMap struct { + Up key.Binding + Down key.Binding + Left key.Binding + Right key.Binding + Enter key.Binding + Esc key.Binding + Help key.Binding + Quit key.Binding +} + +// ShortHelp returns keybindings to be shown in the mini help view. It's part +// of the key.Map interface. +func (k orgKeyMap) ShortHelp() []key.Binding { + k.Help.SetEnabled(true) + return []key.Binding{k.Up, k.Down, k.Enter, k.Esc, k.Quit} +} + +// FullHelp returns keybindings for the expanded help view. It's part of the +// key.Map interface. +func (k orgKeyMap) FullHelp() [][]key.Binding { + return [][]key.Binding{ + {k.Up, k.Down, k.Left, k.Right}, // first column + {k.Enter, k.Esc, k.Help, k.Quit}, // second column + } +} + +func NewKeyMap() orgKeyMap { + return orgKeyMap{ + Up: key.NewBinding( + key.WithKeys("up", "k"), + key.WithHelp("↑/k", "up"), + ), + Down: key.NewBinding( + key.WithKeys("down", "j"), + key.WithHelp("↓/j", "down"), + ), + Left: key.NewBinding( + key.WithKeys("left", "h"), + key.WithHelp("←/h", "move left"), + ), + Right: key.NewBinding( + key.WithKeys("right", "l"), + key.WithHelp("→/l", "move right"), + ), + Enter: key.NewBinding( + key.WithKeys("enter"), + key.WithHelp("enter", "select"), + ), + Esc: key.NewBinding( + key.WithKeys("esc"), + key.WithHelp("esc", "back"), + ), + Help: key.NewBinding( + key.WithKeys("?"), + key.WithHelp("?", "toggle help"), + ), + Quit: key.NewBinding( + key.WithKeys("q"), + key.WithHelp("q", "quit"), + ), + } +} diff --git a/models/organisationModel.go b/models/orgModel.go similarity index 65% rename from models/organisationModel.go rename to models/orgModel.go index 9cd436e..4acf507 100644 --- a/models/organisationModel.go +++ b/models/orgModel.go @@ -5,6 +5,8 @@ import ( "hub-bub/messages" "hub-bub/structs" + + "github.com/charmbracelet/bubbles/help" "github.com/charmbracelet/bubbles/list" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" @@ -12,13 +14,14 @@ import ( graphql "github.com/cli/shurcooL-graphql" ) -type OrganisationModel struct { +type OrgModel struct { Title string - Url string RepoQuery structs.OrganizationQuery repoList list.Model - repoModel RepositoryModel + repoModel RepoModel + help help.Model + keys orgKeyMap loaded bool width int @@ -26,36 +29,39 @@ type OrganisationModel struct { tabsHaveFocus bool } -func (m *OrganisationModel) panelWidth() int { - return m.width / 2 +func NewOrgModel(title string, width, height int) OrgModel { + return OrgModel{ + Title: title, + width: width, + height: height, + help: help.New(), + keys: NewKeyMap(), + repoModel: NewRepoModel(width/2, height), + repoList: list.New([]list.Item{}, list.NewDefaultDelegate(), width/2, height), + } +} + +func (m *OrgModel) helpView() string { + if m.tabsHaveFocus { + return m.repoModel.help.View(m.repoModel.keys) + } + + return m.help.View(m.keys) } -func (m *OrganisationModel) getSelectedRepo() structs.RepositoryQuery { +func (m *OrgModel) getSelectedRepo() structs.RepositoryQuery { return m.RepoQuery.Organization.Repositories.Edges[m.repoList.Index()].Node } -func (m *OrganisationModel) init(width, height int) { - m.width = width - m.height = height - m.repoModel.width = m.panelWidth() - m.repoModel.height = m.height +func (m *OrgModel) init(width, height int) { m.loaded = true - - m.repoList = list.New( - []list.Item{}, - list.NewDefaultDelegate(), - m.panelWidth(), - m.height, - ) - - m.repoModel = NewRepositoryModel(m.panelWidth(), m.height) } -func (m OrganisationModel) Init() tea.Cmd { +func (m OrgModel) Init() tea.Cmd { return nil } -func (m OrganisationModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { +func (m OrgModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmd tea.Cmd // var cmds []tea.Cmd @@ -70,12 +76,11 @@ func (m OrganisationModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case messages.RepoListMsg: m.repoList = buildRepoListModel(msg.OrganizationQuery, m.width, m.height) m.RepoQuery = msg.OrganizationQuery - m.repoModel.SelectRepo(m.getSelectedRepo(), m.panelWidth(), m.height) + m.repoModel.SelectRepo(m.getSelectedRepo(), half(m.width), m.height) return m, nil case tea.KeyMsg: if m.tabsHaveFocus { - // Pass messages to repository model switch msg.Type { case tea.KeyEsc: m.tabsHaveFocus = false @@ -91,10 +96,10 @@ func (m OrganisationModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg.Type { case tea.KeyDown, tea.KeyUp: m.repoList, cmd = m.repoList.Update(msg) - m.repoModel.SelectRepo(m.getSelectedRepo(), m.panelWidth(), m.height) + m.repoModel.SelectRepo(m.getSelectedRepo(), half(m.width), m.height) case tea.KeyEnter: m.tabsHaveFocus = true - m.repoModel.SelectRepo(m.getSelectedRepo(), m.panelWidth(), m.height) + m.repoModel.SelectRepo(m.getSelectedRepo(), half(m.width), m.height) case tea.KeyEsc: return MainModel[UserModelName], nil } @@ -108,16 +113,18 @@ func (m OrganisationModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, cmd } -func (m OrganisationModel) View() string { - var repoList = appStyle.Width(m.panelWidth() - 4).Render(m.repoList.View()) - var settings = appStyle.Width(m.panelWidth()).Render(m.repoModel.View()) +func (m OrgModel) View() string { + var repoList = appStyle.Width(half(m.width)).Render(m.repoList.View()) + var settings = appStyle.Width(half(m.width)).Render(m.repoModel.View()) + help := m.helpView() + var rightPanel = lipgloss.JoinVertical(lipgloss.Center, settings, help) - var views = []string{repoList, settings} + var views = []string{repoList, rightPanel} return lipgloss.JoinHorizontal(lipgloss.Top, views...) } -func (m OrganisationModel) GetRepositories() tea.Msg { +func (m OrgModel) GetRepositories() tea.Msg { client, err := gh.GQLClient(nil) if err != nil { return messages.AuthenticationErrorMsg{Err: err} diff --git a/models/orgModel_test.go b/models/orgModel_test.go new file mode 100644 index 0000000..7459ec0 --- /dev/null +++ b/models/orgModel_test.go @@ -0,0 +1,66 @@ +package models + +import ( + "reflect" + "testing" + + tea "github.com/charmbracelet/bubbletea" +) + +func TestOrgModel_Update(t *testing.T) { + type args struct { + msg tea.Msg + } + tests := []struct { + name string + m OrgModel + args args + wantModel tea.Model + wantCmd tea.Cmd + }{ + // TODO: Add more test cases. + {"Quit KeyMsg", OrgModel{}, args{tea.KeyMsg{Type: tea.KeyCtrlC}}, OrgModel{}, tea.Quit}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotModel, gotCmd := tt.m.Update(tt.args.msg) + if !reflect.DeepEqual(gotModel, tt.wantModel) { + t.Errorf("OrganisationModel.Update() gotModel = %v, want %v", gotModel, tt.wantModel) + } + if reflect.ValueOf(gotCmd) != reflect.ValueOf(tt.wantCmd) { + t.Errorf("OrganisationModel.Update() gotCmd = %v, want %v", gotCmd, tt.wantCmd) + } + }) + } +} + +func TestOrgModel_NewOrgModel(t *testing.T) { + type args struct { + title string + width int + height int + } + tests := []struct { + name string + args args + }{ + {name: "Test NewOrgModel", args: args{title: "hub-bub", width: 1024, height: 768}}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := NewOrgModel(tt.args.title, tt.args.width, tt.args.height) + if got.Title != tt.args.title { + t.Errorf("NewOrgModel title got = %v, want %v", got.Title, tt.args.title) + } + if got.width != tt.args.width { + t.Errorf("NewOrgModel width got = %v, want %v", got.width, tt.args.width) + } + if got.height != tt.args.height { + t.Errorf("NewOrgModel height got = %v, want %v", got.height, tt.args.height) + } + if got.keys.Enter.Enabled() != true { + t.Errorf("NewOrgModel keys.Enter got = %v, want %v", got.keys.Enter.Enabled(), true) + } + }) + } +} diff --git a/models/organisationModel_test.go b/models/organisationModel_test.go deleted file mode 100644 index 4f538ef..0000000 --- a/models/organisationModel_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package models - -import ( - "reflect" - "testing" - - tea "github.com/charmbracelet/bubbletea" -) - -func TestOrganisationModel_Update(t *testing.T) { - type args struct { - msg tea.Msg - } - tests := []struct { - name string - m OrganisationModel - args args - wantModel tea.Model - wantCmd tea.Cmd - }{ - // TODO: Add more test cases. - {"Quit KeyMsg", OrganisationModel{}, args{tea.KeyMsg{Type: tea.KeyCtrlC}}, OrganisationModel{}, tea.Quit}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotModel, gotCmd := tt.m.Update(tt.args.msg) - if !reflect.DeepEqual(gotModel, tt.wantModel) { - t.Errorf("OrganisationModel.Update() gotModel = %v, want %v", gotModel, tt.wantModel) - } - if reflect.ValueOf(gotCmd) != reflect.ValueOf(tt.wantCmd) { - t.Errorf("OrganisationModel.Update() gotCmd = %v, want %v", gotCmd, tt.wantCmd) - } - }) - } -} diff --git a/models/repoKeyMap.go b/models/repoKeyMap.go new file mode 100644 index 0000000..6295a88 --- /dev/null +++ b/models/repoKeyMap.go @@ -0,0 +1,63 @@ +package models + +import "github.com/charmbracelet/bubbles/key" + +// keyMap defines a set of keybindings. To work for help it must satisfy +// key.Map. It could also very easily be a map[string]key.Binding. +type repoKeyMap struct { + Up key.Binding + Down key.Binding + Left key.Binding + Right key.Binding + Filter key.Binding + Esc key.Binding + Quit key.Binding +} + +// ShortHelp returns keybindings to be shown in the mini help view. It's part +// of the key.Map interface. +func (k repoKeyMap) ShortHelp() []key.Binding { + return []key.Binding{k.Left, k.Right, k.Esc, k.Quit} +} + +// FullHelp returns keybindings for the expanded help view. It's part of the +// key.Map interface. +func (k repoKeyMap) FullHelp() [][]key.Binding { + return [][]key.Binding{ + {k.Up, k.Down, k.Left, k.Right}, // first column + {k.Filter, k.Esc, k.Quit}, // second column + } +} + +func NewRepoKeyMap() repoKeyMap { + return repoKeyMap{ + Up: key.NewBinding( + key.WithKeys("up", "k"), + key.WithHelp("↑/k", "up"), + ), + Down: key.NewBinding( + key.WithKeys("down", "j"), + key.WithHelp("↓/j", "down"), + ), + Left: key.NewBinding( + key.WithKeys("left", "h"), + key.WithHelp("←/h", "prev tab"), + ), + Right: key.NewBinding( + key.WithKeys("right", "l"), + key.WithHelp("→/l", "next tab"), + ), + Filter: key.NewBinding( + key.WithKeys("/"), + key.WithHelp("/", "filter"), + ), + Esc: key.NewBinding( + key.WithKeys("esc"), + key.WithHelp("esc", "back"), + ), + Quit: key.NewBinding( + key.WithKeys("q"), + key.WithHelp("q", "quit"), + ), + } +} diff --git a/models/repositoryModel.go b/models/repoModel.go similarity index 58% rename from models/repositoryModel.go rename to models/repoModel.go index 37bea76..08411bd 100644 --- a/models/repositoryModel.go +++ b/models/repoModel.go @@ -2,50 +2,57 @@ package models import ( "hub-bub/structs" + + "github.com/charmbracelet/bubbles/help" "github.com/charmbracelet/bubbles/table" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" ) -type RepositoryModel struct { - repositorySettingsTabs []structs.RepositorySettingsTab +type RepoModel struct { + repoSettingsTabs []structs.RepositorySettingsTab settingsTable table.Model + help help.Model + keys repoKeyMap + activeTab int loaded bool width int height int } -func NewRepositoryModel(width, height int) RepositoryModel { - return RepositoryModel{ - repositorySettingsTabs: []structs.RepositorySettingsTab{}, - width: width, - height: height, +func NewRepoModel(width, height int) RepoModel { + return RepoModel{ + repoSettingsTabs: []structs.RepositorySettingsTab{}, + width: width, + height: height, + help: help.New(), + keys: NewRepoKeyMap(), } } -func (m RepositoryModel) Init() tea.Cmd { +func (m RepoModel) Init() tea.Cmd { return nil } -func (m *RepositoryModel) SelectRepo(RepositoryQuery structs.RepositoryQuery, width, height int) { - m.repositorySettingsTabs = structs.BuildRepositorySettings(RepositoryQuery) +func (m *RepoModel) SelectRepo(RepositoryQuery structs.RepositoryQuery, width, height int) { + m.repoSettingsTabs = structs.BuildRepoSettings(RepositoryQuery) m.width = width m.height = height } -func (m *RepositoryModel) NextTab() { - m.activeTab = min(m.activeTab+1, len(m.repositorySettingsTabs)-1) +func (m *RepoModel) NextTab() { + m.activeTab = min(m.activeTab+1, len(m.repoSettingsTabs)-1) } -func (m *RepositoryModel) PreviousTab() { +func (m *RepoModel) PreviousTab() { m.activeTab = max(m.activeTab-1, 0) } -func (m RepositoryModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { +func (m RepoModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmd tea.Cmd switch msg.(type) { @@ -59,23 +66,23 @@ func (m RepositoryModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, cmd } -func (m RepositoryModel) View() string { - if m.repositorySettingsTabs == nil || len(m.repositorySettingsTabs) == 0 { +func (m RepoModel) View() string { + if m.repoSettingsTabs == nil || len(m.repoSettingsTabs) == 0 { return "" } m.buildSettingsTable() var tabs = m.RenderTabs() - var settings = settingsStyle.Padding(0).Width(m.width - 6).Render(m.settingsTable.View()) + var settings = settingsStyle.Padding(0).Width(m.width - 2).Render(m.settingsTable.View()) return lipgloss.JoinVertical(lipgloss.Left, tabs, settings) } -func (m *RepositoryModel) buildSettingsTable() { - var activeSettings = m.repositorySettingsTabs[m.activeTab] +func (m *RepoModel) buildSettingsTable() { + var activeSettings = m.repoSettingsTabs[m.activeTab] - columns := []table.Column{{Title: "", Width: 40}, {Title: "", Width: 11}} + columns := []table.Column{{Title: "", Width: 50}, {Title: "", Width: 11}} rows := make([]table.Row, len(activeSettings.Settings)) for i, setting := range activeSettings.Settings { @@ -87,9 +94,9 @@ func (m *RepositoryModel) buildSettingsTable() { table.WithRows(rows)) } -func (m RepositoryModel) RenderTabs() string { +func (m RepoModel) RenderTabs() string { Tabs := []string{} - for _, t := range m.repositorySettingsTabs { + for _, t := range m.repoSettingsTabs { Tabs = append(Tabs, t.Name) } @@ -127,17 +134,3 @@ func (m RepositoryModel) RenderTabs() string { return row } - -func max(a, b int) int { - if a > b { - return a - } - return b -} - -func min(a, b int) int { - if a < b { - return a - } - return b -} diff --git a/models/repoModel_test.go b/models/repoModel_test.go new file mode 100644 index 0000000..db4d2da --- /dev/null +++ b/models/repoModel_test.go @@ -0,0 +1,30 @@ +package models + +import "testing" + +func TestRepoModel_NewRepoModel(t *testing.T) { + type args struct { + width int + height int + } + tests := []struct { + name string + args args + }{ + {name: "Test NewRepoModel", args: args{width: 1024, height: 768}}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := NewRepoModel(tt.args.width, tt.args.height) + if got.width != tt.args.width { + t.Errorf("NewRepoModel width got = %v, want %v", got.width, tt.args.width) + } + if got.height != tt.args.height { + t.Errorf("NewRepoModel height got = %v, want %v", got.height, tt.args.height) + } + if got.keys.Esc.Enabled() != true { + t.Errorf("NewRepoModel keys.Esc.Enabled got = %v, want %v", got.keys.Esc.Enabled(), true) + } + }) + } +} diff --git a/models/styles.go b/models/styles.go index 0c5c34f..e485ef1 100644 --- a/models/styles.go +++ b/models/styles.go @@ -5,38 +5,28 @@ import "github.com/charmbracelet/lipgloss" var ( // Colors // purple = "#cdb4db" - // pink = "#ffc8dd" + // pink = "#ffc8dd" // pinkDarker = "#ffafcc" // blue = "#bde0fe" blueDarker = "#a2d2ff" white = "#FFFDF5" - appStyle = lipgloss.NewStyle().Padding(1, 2) + appStyle = lipgloss.NewStyle().Padding(1, 0) titleStyle = lipgloss.NewStyle(). Foreground(lipgloss.Color(white)). Background(lipgloss.Color(blueDarker)). Padding(0, 1) - titleHeight = 2 - - // Custom list - // itemStyle = lipgloss.NewStyle().PaddingLeft(4) - // selectedItemStyle = lipgloss.NewStyle(). - // PaddingLeft(2). - // Foreground(lipgloss.Color(blue)) - - // Tabs + titleHeight = 2 inactiveTabBorder = tabBorderWithBottom("┴", "─", "┴") activeTabBorder = tabBorderWithBottom("┘", " ", "└") - // docStyle = lipgloss.NewStyle().Padding(1, 2, 1, 2) - // highlightColor = lipgloss.Color(pinkDarker) - borderColor = lipgloss.Color(blueDarker) - inactiveTabStyle = lipgloss.NewStyle().Border(inactiveTabBorder, true).BorderForeground(borderColor).Padding(0, 1) - activeTabStyle = inactiveTabStyle.Copy().Border(activeTabBorder, true) + borderColor = lipgloss.Color(blueDarker) + inactiveTabStyle = lipgloss.NewStyle().Border(inactiveTabBorder, true).BorderForeground(borderColor).Padding(0) + activeTabStyle = inactiveTabStyle.Copy().Border(activeTabBorder, true) settingsStyle = appStyle.Copy().Border(settingsBorder()). - BorderForeground(borderColor).Padding(0, 1, 1, 1) + BorderForeground(borderColor).Padding(0).Margin(0) ) func tabBorderWithBottom(left, middle, right string) lipgloss.Border { diff --git a/models/userModel.go b/models/userModel.go index 4281c5a..54ab4d1 100644 --- a/models/userModel.go +++ b/models/userModel.go @@ -5,6 +5,7 @@ import ( "hub-bub/messages" "hub-bub/structs" + "github.com/cli/go-gh" "github.com/charmbracelet/bubbles/list" @@ -69,12 +70,7 @@ func (m UserModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case "enter", " ": MainModel[UserModelName] = m item := m.list.SelectedItem() - orgModel := &OrganisationModel{ - Title: item.(structs.ListItem).Title(), - Url: item.(structs.ListItem).Description(), - width: m.width, - height: m.height, - } + orgModel := NewOrgModel(item.(structs.ListItem).Title(), m.width, m.height) MainModel[OrganisationModelName] = orgModel diff --git a/models/utils.go b/models/utils.go new file mode 100644 index 0000000..fa1d572 --- /dev/null +++ b/models/utils.go @@ -0,0 +1,19 @@ +package models + +func half(width int) int { + return width / 2 +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} diff --git a/models/utils_test.go b/models/utils_test.go new file mode 100644 index 0000000..2936689 --- /dev/null +++ b/models/utils_test.go @@ -0,0 +1,68 @@ +package models + +import "testing" + +func TestHalf(t *testing.T) { + type args struct { + width int + } + tests := []struct { + name string + args args + want int + }{ + {"Half", args{4}, 2}, + {"Half", args{5}, 2}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := half(tt.args.width); got != tt.want { + t.Errorf("half() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestMax(t *testing.T) { + type args struct { + a int + b int + } + tests := []struct { + name string + args args + want int + }{ + {"Max", args{1, 2}, 2}, + {"Max", args{2, 1}, 2}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := max(tt.args.a, tt.args.b); got != tt.want { + t.Errorf("max() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestMin(t *testing.T) { + type args struct { + a int + b int + } + tests := []struct { + name string + args args + want int + }{ + {"Min", args{1, 2}, 1}, + {"Min", args{2, 1}, 1}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := min(tt.args.a, tt.args.b); got != tt.want { + t.Errorf("min() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/structs/repositorySetting.go b/structs/repositorySetting.go index 87b1e25..5b85bbc 100644 --- a/structs/repositorySetting.go +++ b/structs/repositorySetting.go @@ -16,7 +16,7 @@ type RepositorySettingsTab struct { Settings []RepositorySetting } -func NewRepositorySetting(name, value, url, propertyName string, loaded bool) RepositorySetting { +func NewRepoSetting(name, value, url, propertyName string, loaded bool) RepositorySetting { return RepositorySetting{ Name: name, Value: value, @@ -25,14 +25,14 @@ func NewRepositorySetting(name, value, url, propertyName string, loaded bool) Re } } -func NewRepositorySettingsTab(name string, settings []RepositorySetting) RepositorySettingsTab { +func NewRepoSettingsTab(name string, settings []RepositorySetting) RepositorySettingsTab { return RepositorySettingsTab{ Name: name, Settings: settings, } } -func BuildRepositorySettings(ornq RepositoryQuery) []RepositorySettingsTab { +func BuildRepoSettings(ornq RepositoryQuery) []RepositorySettingsTab { var respositorySettings []RepositorySettingsTab return append(respositorySettings, @@ -46,34 +46,34 @@ func buildOverviewSettings(ornq RepositoryQuery) RepositorySettingsTab { var repositorySettings []RepositorySetting repositorySettings = append(repositorySettings, - NewRepositorySetting("Private", YesNo(ornq.IsPrivate), "", "", true), - NewRepositorySetting("Template", YesNo(ornq.IsTemplate), "", "", true), - NewRepositorySetting("Archived", YesNo(ornq.IsArchived), "", "", true), - NewRepositorySetting("Disabled", YesNo(ornq.IsDisabled), "", "", true), - NewRepositorySetting("Fork", YesNo(ornq.IsFork), "", "", true), - NewRepositorySetting("Last updated", ornq.UpdatedAt.Format("2006/01/02"), "", "", true), - NewRepositorySetting("Stars", fmt.Sprint(ornq.StargazerCount), "", "", true), - NewRepositorySetting("Wiki", YesNo(ornq.HasWikiEnabled), "", "", true), - NewRepositorySetting("Issues", YesNo(ornq.HasIssuesEnabled), "", "", true), - NewRepositorySetting("Projects", YesNo(ornq.HasProjectsEnabled), "", "", true), - NewRepositorySetting("Discussions", YesNo(ornq.HasDiscussionsEnabled), "", "", true)) - - return NewRepositorySettingsTab("Overview", repositorySettings) + NewRepoSetting("Private", YesNo(ornq.IsPrivate), "", "", true), + NewRepoSetting("Template", YesNo(ornq.IsTemplate), "", "", true), + NewRepoSetting("Archived", YesNo(ornq.IsArchived), "", "", true), + NewRepoSetting("Disabled", YesNo(ornq.IsDisabled), "", "", true), + NewRepoSetting("Fork", YesNo(ornq.IsFork), "", "", true), + NewRepoSetting("Last updated", ornq.UpdatedAt.Format("2006/01/02"), "", "", true), + NewRepoSetting("Stars", fmt.Sprint(ornq.StargazerCount), "", "", true), + NewRepoSetting("Wiki", YesNo(ornq.HasWikiEnabled), "", "", true), + NewRepoSetting("Issues", YesNo(ornq.HasIssuesEnabled), "", "", true), + NewRepoSetting("Projects", YesNo(ornq.HasProjectsEnabled), "", "", true), + NewRepoSetting("Discussions", YesNo(ornq.HasDiscussionsEnabled), "", "", true)) + + return NewRepoSettingsTab("Overview", repositorySettings) } func buildPullRequestSettings(ornq RepositoryQuery) RepositorySettingsTab { var repositorySettings []RepositorySetting repositorySettings = append(repositorySettings, - NewRepositorySetting("Allow merge commits", YesNo(ornq.MergeCommitAllowed), "", "", true), - NewRepositorySetting("Allow squash merging", YesNo(ornq.SquashMergeAllowed), "", "", true), - NewRepositorySetting("Allow rebase merging", YesNo(ornq.RebaseMergeAllowed), "", "", true), - NewRepositorySetting("Allow auto-merge", YesNo(ornq.AutoMergeAllowed), "", "", true), - NewRepositorySetting("Automatically delete head branches", YesNo(ornq.DeleteBranchOnMerge), "", "", true), - NewRepositorySetting("Open pull requests", fmt.Sprint(ornq.PullRequests.TotalCount), "", "", true), + NewRepoSetting("Allow merge commits", YesNo(ornq.MergeCommitAllowed), "", "", true), + NewRepoSetting("Allow squash merging", YesNo(ornq.SquashMergeAllowed), "", "", true), + NewRepoSetting("Allow rebase merging", YesNo(ornq.RebaseMergeAllowed), "", "", true), + NewRepoSetting("Allow auto-merge", YesNo(ornq.AutoMergeAllowed), "", "", true), + NewRepoSetting("Automatically delete head branches", YesNo(ornq.DeleteBranchOnMerge), "", "", true), + NewRepoSetting("Open pull requests", fmt.Sprint(ornq.PullRequests.TotalCount), "", "", true), ) - return NewRepositorySettingsTab("Pull Requests", repositorySettings) + return NewRepoSettingsTab("Pull Requests", repositorySettings) } func buildDefaultBranchSettings(ornq RepositoryQuery) RepositorySettingsTab { @@ -82,38 +82,38 @@ func buildDefaultBranchSettings(ornq RepositoryQuery) RepositorySettingsTab { rule := ornq.DefaultBranchRef.BranchProtectionRule repositorySettings = append(repositorySettings, - NewRepositorySetting("Name", ornq.DefaultBranchRef.Name, "", "", true), - NewRepositorySetting("Require approving reviews", YesNo(rule.RequiresApprovingReviews), "", "", true), - NewRepositorySetting("Number of approvals required", fmt.Sprint(rule.RequiredApprovingReviewCount), "", "", true), - NewRepositorySetting("Dismiss stale requests", YesNo(rule.DismissesStaleReviews), "", "", true), - NewRepositorySetting("Require review from Code Owners", YesNo(rule.RequiresCodeOwnerReviews), "", "", true), - NewRepositorySetting("Restrict who can dismiss pull request reviews", YesNo(rule.RestrictsReviewDismissals), "", "", true), - NewRepositorySetting("Require approval of the most recent reviewable push", YesNo(rule.RequireLastPushApproval), "", "", true), + NewRepoSetting("Name", ornq.DefaultBranchRef.Name, "", "", true), + NewRepoSetting("Require approving reviews", YesNo(rule.RequiresApprovingReviews), "", "", true), + NewRepoSetting("Number of approvals required", fmt.Sprint(rule.RequiredApprovingReviewCount), "", "", true), + NewRepoSetting("Dismiss stale requests", YesNo(rule.DismissesStaleReviews), "", "", true), + NewRepoSetting("Require review from Code Owners", YesNo(rule.RequiresCodeOwnerReviews), "", "", true), + NewRepoSetting("Restrict who can dismiss pull request reviews", YesNo(rule.RestrictsReviewDismissals), "", "", true), + NewRepoSetting("Require approval of the most recent reviewable push", YesNo(rule.RequireLastPushApproval), "", "", true), // Allow specified actors to bypass required pull requests - NewRepositorySetting("Require status checks to pass before merging", YesNo(rule.RequiresStatusChecks), "", "", true), - NewRepositorySetting("Require conversation resolution before merging", YesNo(rule.RequiresConversationResolution), "", "", true), - NewRepositorySetting("Requires signed commits", YesNo(rule.RequiresCommitSignatures), "", "", true), - NewRepositorySetting("Require linear history", YesNo(rule.RequiresLinearHistory), "", "", true), - NewRepositorySetting("Require deployments to succeed before merging", YesNo(rule.RequiresDeployments), "", "", true), - NewRepositorySetting("Lock branch", YesNo(rule.LockBranch), "", "", true), - NewRepositorySetting("Do not allow bypassing the above settings", YesNo(rule.IsAdminEnforced), "", "", true), - NewRepositorySetting("Restrict who can push to matching branches", YesNo(rule.RestrictsPushes), "", "", true), - - NewRepositorySetting("Allow force pushes", YesNo(rule.AllowsForcePushes), "", "", true), - NewRepositorySetting("Allow deletions", YesNo(rule.AllowsDeletions), "", "", true), + NewRepoSetting("Require status checks to pass before merging", YesNo(rule.RequiresStatusChecks), "", "", true), + NewRepoSetting("Require conversation resolution before merging", YesNo(rule.RequiresConversationResolution), "", "", true), + NewRepoSetting("Requires signed commits", YesNo(rule.RequiresCommitSignatures), "", "", true), + NewRepoSetting("Require linear history", YesNo(rule.RequiresLinearHistory), "", "", true), + NewRepoSetting("Require deployments to succeed before merging", YesNo(rule.RequiresDeployments), "", "", true), + NewRepoSetting("Lock branch", YesNo(rule.LockBranch), "", "", true), + NewRepoSetting("Do not allow bypassing the above settings", YesNo(rule.IsAdminEnforced), "", "", true), + NewRepoSetting("Restrict who can push to matching branches", YesNo(rule.RestrictsPushes), "", "", true), + + NewRepoSetting("Allow force pushes", YesNo(rule.AllowsForcePushes), "", "", true), + NewRepoSetting("Allow deletions", YesNo(rule.AllowsDeletions), "", "", true), ) - return NewRepositorySettingsTab("Default Branch", repositorySettings) + return NewRepoSettingsTab("Default Branch", repositorySettings) } func buildSecuritySettings(ornq RepositoryQuery) RepositorySettingsTab { var repositorySettings []RepositorySetting repositorySettings = append(repositorySettings, - NewRepositorySetting("Vulnerability alerts enabled", YesNo(ornq.HasVulnerabilityAlertsEnabled), "", "", true), - NewRepositorySetting("Vulnerability alert count", fmt.Sprint(ornq.VulnerabilityAlerts.TotalCount), "", "", true), + NewRepoSetting("Vulnerability alerts enabled", YesNo(ornq.HasVulnerabilityAlertsEnabled), "", "", true), + NewRepoSetting("Vulnerability alert count", fmt.Sprint(ornq.VulnerabilityAlerts.TotalCount), "", "", true), ) - return NewRepositorySettingsTab("Security", repositorySettings) + return NewRepoSettingsTab("Security", repositorySettings) }