From 3f71389ac1430d853e4c2d2628a0339d7f2566f7 Mon Sep 17 00:00:00 2001 From: Krish Suchak Date: Fri, 3 May 2024 10:00:48 -0400 Subject: [PATCH 01/25] implement going back to list --- tui/attributeView.go | 8 +++++++- tui/read.go | 24 ++++++++++++------------ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/tui/attributeView.go b/tui/attributeView.go index 1723ae42..36ab900b 100644 --- a/tui/attributeView.go +++ b/tui/attributeView.go @@ -6,6 +6,7 @@ import ( "github.com/opentdf/otdfctl/pkg/cli" "github.com/opentdf/otdfctl/pkg/handlers" "github.com/opentdf/otdfctl/tui/constants" + "github.com/opentdf/platform/protocol/go/policy" ) type AttributeSubItem struct { @@ -26,15 +27,18 @@ func (m AttributeSubItem) Description() string { } type AttributeView struct { + attr *policy.Attribute read Read + sdk handlers.Handler } func InitAttributeView(id string, h handlers.Handler) (AttributeView, tea.Cmd) { - m := AttributeView{} + m := AttributeView{sdk: h} attr, err := h.GetAttribute(id) if err != nil { return m, nil } + m.attr = attr var vals []string for _, val := range attr.Values { vals = append(vals, val.Value) @@ -68,6 +72,8 @@ func (m AttributeView) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil case tea.KeyMsg: switch msg.String() { + case "backspace": + return InitAttributeList(m.attr.Id, m.sdk) case "ctrl+c", "q": return m, tea.Quit case "ctrl+d": diff --git a/tui/read.go b/tui/read.go index ac5f1167..249338d0 100644 --- a/tui/read.go +++ b/tui/read.go @@ -23,18 +23,18 @@ func (m Read) Init() tea.Cmd { } func (m Read) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - switch msg := msg.(type) { - case tea.WindowSizeMsg: - constants.WindowSize = msg - m.list.SetSize(msg.Width, msg.Height) - m.width = msg.Width - return m, nil - case tea.KeyMsg: - switch msg.Type { - case tea.KeyCtrlC, tea.KeyEsc: - return m, tea.Quit - } - } + // switch msg := msg.(type) { + // case tea.WindowSizeMsg: + // constants.WindowSize = msg + // m.list.SetSize(msg.Width, msg.Height) + // m.width = msg.Width + // return m, nil + // case tea.KeyMsg: + // switch msg.Type { + // case tea.KeyCtrlC, tea.KeyEsc: + // return m, tea.Quit + // } + // } return m, nil } From 57dc8527ae923e1005009a55aafccb3dbbd02fa1 Mon Sep 17 00:00:00 2001 From: Krish Suchak Date: Fri, 3 May 2024 10:07:19 -0400 Subject: [PATCH 02/25] refactor --- tui/attributeView.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tui/attributeView.go b/tui/attributeView.go index 36ab900b..17fc95db 100644 --- a/tui/attributeView.go +++ b/tui/attributeView.go @@ -33,12 +33,10 @@ type AttributeView struct { } func InitAttributeView(id string, h handlers.Handler) (AttributeView, tea.Cmd) { - m := AttributeView{sdk: h} attr, err := h.GetAttribute(id) if err != nil { - return m, nil + // return error view } - m.attr = attr var vals []string for _, val := range attr.Values { vals = append(vals, val.Value) @@ -52,9 +50,8 @@ func InitAttributeView(id string, h handlers.Handler) (AttributeView, tea.Cmd) { AttributeSubItem{title: "Created At", description: attr.Metadata.CreatedAt.String()}, AttributeSubItem{title: "Updated At", description: attr.Metadata.UpdatedAt.String()}, } - model, _ := InitRead("Read Attribute", items) - m.read = model.(Read) + m := AttributeView{sdk: h, attr: attr, read: model.(Read)} model, msg := m.Update(WindowMsg()) m = model.(AttributeView) return m, msg From 4a4fbdb9cb44748c005d4d8a7742c07de77dc21f Mon Sep 17 00:00:00 2001 From: Krish Suchak Date: Fri, 3 May 2024 10:14:51 -0400 Subject: [PATCH 03/25] refactor list up down --- tui/attributeList.go | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/tui/attributeList.go b/tui/attributeList.go index a797cc7f..5e8d4245 100644 --- a/tui/attributeList.go +++ b/tui/attributeList.go @@ -103,14 +103,6 @@ func (m AttributeList) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // make enum for Attributes idx in AppMenu am.list.Select(0) return am.Update(WindowMsg()) - case "down", "j": - if m.list.Index() < len(m.list.Items())-1 { - m.list.Select(m.list.Index() + 1) - } - case "up", "k": - if m.list.Index() > 0 { - m.list.Select(m.list.Index() - 1) - } // case "c": // create new attribute // return InitAttributeView(m.list.Items(), len(m.list.Items())) @@ -125,7 +117,9 @@ func (m AttributeList) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.list.Select(newIndex) } } - return m, nil + var cmd tea.Cmd + m.list, cmd = m.list.Update(msg) + return m, cmd } func (m AttributeList) View() string { From 507f09e1a461801303ed576818df1aa27d7c9bdb Mon Sep 17 00:00:00 2001 From: Krish Suchak Date: Fri, 3 May 2024 10:24:24 -0400 Subject: [PATCH 04/25] refactor --- tui/attributeList.go | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/tui/attributeList.go b/tui/attributeList.go index 5e8d4245..fc7bca42 100644 --- a/tui/attributeList.go +++ b/tui/attributeList.go @@ -10,9 +10,9 @@ import ( ) type AttributeList struct { - list list.Model - width int - sdk handlers.Handler + list list.Model + // width int + sdk handlers.Handler } type AttributeItem struct { @@ -38,11 +38,10 @@ func (m AttributeItem) Description() string { } func InitAttributeList(id string, sdk handlers.Handler) (tea.Model, tea.Cmd) { - m := AttributeList{sdk: sdk} - m.list = list.New([]list.Item{}, list.NewDefaultDelegate(), constants.WindowSize.Width, constants.WindowSize.Height) + l := list.New([]list.Item{}, list.NewDefaultDelegate(), constants.WindowSize.Width, constants.WindowSize.Height) res, err := sdk.ListAttributes(common.ActiveStateEnum_ACTIVE_STATE_ENUM_ANY) if err != nil { - return m, nil + // return error view } var attrs []list.Item selectIdx := 0 @@ -63,9 +62,10 @@ func InitAttributeList(id string, sdk handlers.Handler) (tea.Model, tea.Cmd) { } attrs = append(attrs, item) } - m.list.Title = "Attributes" - m.list.SetItems(attrs) - m.list.Select(selectIdx) + l.Title = "Attributes" + l.SetItems(attrs) + l.Select(selectIdx) + m := AttributeList{sdk: sdk, list: l} return m.Update(WindowMsg()) } @@ -92,7 +92,7 @@ func (m AttributeList) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case tea.WindowSizeMsg: constants.WindowSize = msg m.list.SetSize(msg.Width, msg.Height) - m.width = msg.Width + // m.width = msg.Width return m, nil case tea.KeyMsg: switch msg.String() { @@ -108,13 +108,13 @@ func (m AttributeList) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // return InitAttributeView(m.list.Items(), len(m.list.Items())) case "enter", "e": return InitAttributeView(m.list.Items()[m.list.Index()].(AttributeItem).id, m.sdk) - case "ctrl+d": - m.list.RemoveItem(m.list.Index()) - newIndex := m.list.Index() - 1 - if newIndex < 0 { - newIndex = 0 - } - m.list.Select(newIndex) + // case "ctrl+d": + // m.list.RemoveItem(m.list.Index()) + // newIndex := m.list.Index() - 1 + // if newIndex < 0 { + // newIndex = 0 + // } + // m.list.Select(newIndex) } } var cmd tea.Cmd From 251da42dfd5eda15221a88a328d28c53e2f03efd Mon Sep 17 00:00:00 2001 From: Krish Suchak Date: Mon, 6 May 2024 14:09:32 -0400 Subject: [PATCH 05/25] simplify attributeitem --- tui/attributeList.go | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/tui/attributeList.go b/tui/attributeList.go index fc7bca42..1a4fbb07 100644 --- a/tui/attributeList.go +++ b/tui/attributeList.go @@ -16,13 +16,8 @@ type AttributeList struct { } type AttributeItem struct { - id string - namespace string - name string - description string - rule string - values []string - title string + id string + name string } func (m AttributeItem) FilterValue() string { @@ -34,7 +29,7 @@ func (m AttributeItem) Title() string { } func (m AttributeItem) Description() string { - return m.description + return m.id } func InitAttributeList(id string, sdk handlers.Handler) (tea.Model, tea.Cmd) { @@ -54,11 +49,11 @@ func InitAttributeList(id string, sdk handlers.Handler) (tea.Model, tea.Cmd) { selectIdx = i } item := AttributeItem{ - id: attr.Id, - namespace: attr.Namespace.Name, - name: attr.Name, - rule: attr.Rule.String(), - values: vals, + id: attr.Id, + // namespace: attr.Namespace.Name, + name: attr.Name, + // rule: attr.Rule.String(), + // values: vals, } attrs = append(attrs, item) } From c74942c5f6d6d4f046977296b01a22d12f00277b Mon Sep 17 00:00:00 2001 From: Krish Suchak Date: Mon, 6 May 2024 15:42:17 -0400 Subject: [PATCH 06/25] use simple attribute --- tui/attributeView.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tui/attributeView.go b/tui/attributeView.go index 17fc95db..67b7a19b 100644 --- a/tui/attributeView.go +++ b/tui/attributeView.go @@ -41,14 +41,17 @@ func InitAttributeView(id string, h handlers.Handler) (AttributeView, tea.Cmd) { for _, val := range attr.Values { vals = append(vals, val.Value) } + sa := cli.GetSimpleAttribute(attr) items := []list.Item{ AttributeSubItem{title: "ID", description: attr.Id}, AttributeSubItem{title: "Name", description: attr.Name}, AttributeSubItem{title: "Rule", description: attr.Rule.String()}, AttributeSubItem{title: "Values", description: cli.CommaSeparated(vals)}, AttributeSubItem{title: "Namespace", description: attr.Namespace.Name}, - AttributeSubItem{title: "Created At", description: attr.Metadata.CreatedAt.String()}, - AttributeSubItem{title: "Updated At", description: attr.Metadata.UpdatedAt.String()}, + // AttributeSubItem{title: "Labels", description: cli.CommaSeparated(maps.Keys(attr.Metadata.Labels))}, + AttributeSubItem{title: "Labels", description: sa.Metadata["Labels"]}, + AttributeSubItem{title: "Created At", description: sa.Metadata["Created At"]}, + AttributeSubItem{title: "Updated At", description: sa.Metadata["Updated At"]}, } model, _ := InitRead("Read Attribute", items) m := AttributeView{sdk: h, attr: attr, read: model.(Read)} From 602d669ff84016027243f2aa597953e90635c0e0 Mon Sep 17 00:00:00 2001 From: Krish Suchak Date: Mon, 6 May 2024 15:47:36 -0400 Subject: [PATCH 07/25] finish using simple attribute --- tui/attributeView.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tui/attributeView.go b/tui/attributeView.go index 67b7a19b..d20eb0a9 100644 --- a/tui/attributeView.go +++ b/tui/attributeView.go @@ -37,18 +37,18 @@ func InitAttributeView(id string, h handlers.Handler) (AttributeView, tea.Cmd) { if err != nil { // return error view } - var vals []string - for _, val := range attr.Values { - vals = append(vals, val.Value) - } + // var vals []string + // for _, val := range attr.Values { + // vals = append(vals, val.Value) + // } sa := cli.GetSimpleAttribute(attr) items := []list.Item{ - AttributeSubItem{title: "ID", description: attr.Id}, - AttributeSubItem{title: "Name", description: attr.Name}, - AttributeSubItem{title: "Rule", description: attr.Rule.String()}, - AttributeSubItem{title: "Values", description: cli.CommaSeparated(vals)}, - AttributeSubItem{title: "Namespace", description: attr.Namespace.Name}, - // AttributeSubItem{title: "Labels", description: cli.CommaSeparated(maps.Keys(attr.Metadata.Labels))}, + AttributeSubItem{title: "ID", description: sa.Id}, + AttributeSubItem{title: "Name", description: sa.Name}, + AttributeSubItem{title: "Rule", description: sa.Rule}, + AttributeSubItem{title: "Values", description: cli.CommaSeparated(sa.Values)}, + AttributeSubItem{title: "Namespace", description: sa.Namespace}, + AttributeSubItem{title: "Active", description: sa.Active}, AttributeSubItem{title: "Labels", description: sa.Metadata["Labels"]}, AttributeSubItem{title: "Created At", description: sa.Metadata["Created At"]}, AttributeSubItem{title: "Updated At", description: sa.Metadata["Updated At"]}, From c8b3566476eeb7d3ad7176dc955cfbfcf6f93fa7 Mon Sep 17 00:00:00 2001 From: Krish Suchak Date: Mon, 6 May 2024 16:24:32 -0400 Subject: [PATCH 08/25] import cycles --- tui/attributes/attributeCreateView.go | 59 +++++++++++ tui/attributes/attributeList.go | 147 ++++++++++++++++++++++++++ tui/attributes/attributeView.go | 111 +++++++++++++++++++ tui/common/common.go | 54 ++++++++++ tui/constants/types.go | 5 + tui/crud/read.go | 44 ++++++++ tui/crud/update.go | 1 + tui/menu/appMenu.go | 101 ++++++++++++++++++ 8 files changed, 522 insertions(+) create mode 100644 tui/attributes/attributeCreateView.go create mode 100644 tui/attributes/attributeList.go create mode 100644 tui/attributes/attributeView.go create mode 100644 tui/common/common.go create mode 100644 tui/constants/types.go create mode 100644 tui/crud/read.go create mode 100644 tui/crud/update.go create mode 100644 tui/menu/appMenu.go diff --git a/tui/attributes/attributeCreateView.go b/tui/attributes/attributeCreateView.go new file mode 100644 index 00000000..9132d04b --- /dev/null +++ b/tui/attributes/attributeCreateView.go @@ -0,0 +1,59 @@ +package attributes + +import ( + "fmt" + + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/huh" + "github.com/opentdf/otdfctl/tui/constants" +) + +type AttributeCreateModel struct { + form *huh.Form +} + +func InitAttributeCreateModel() (tea.Model, tea.Cmd) { + namespace := "" + m := AttributeCreateModel{} + m.form = huh.NewForm( + huh.NewGroup( + huh.NewSelect[string](). + Title("Namespace"). + Options( + huh.NewOption("demo.com", "demo.com"), + huh.NewOption("demo.net", "demo.net"), + ). + Validate(func(str string) error { + // Check if namespace exists + fmt.Println(str) + return nil + }). + Value(&namespace), + ), + ) + + return m, nil +} + +func (m AttributeCreateModel) Init() tea.Cmd { + return nil +} + +func (m AttributeCreateModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.WindowSizeMsg: + constants.WindowSize = msg + return m, nil + case tea.KeyMsg: + switch msg.String() { + case "ctrl+c", "q": + return m, tea.Quit + } + } + + return m, nil +} + +func (m AttributeCreateModel) View() string { + return "" +} diff --git a/tui/attributes/attributeList.go b/tui/attributes/attributeList.go new file mode 100644 index 00000000..9586a439 --- /dev/null +++ b/tui/attributes/attributeList.go @@ -0,0 +1,147 @@ +package attributes + +import ( + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + "github.com/opentdf/otdfctl/pkg/handlers" + "github.com/opentdf/otdfctl/tui/constants" + "github.com/opentdf/platform/protocol/go/common" +) + +type AttributeList struct { + list list.Model + // width int + sdk handlers.Handler +} + +type AttributeItem struct { + id string + name string +} + +func (m AttributeItem) FilterValue() string { + return m.name +} + +func (m AttributeItem) Title() string { + return m.name +} + +func (m AttributeItem) Description() string { + return m.id +} + +func InitAttributeList(id string, sdk handlers.Handler) (tea.Model, tea.Cmd) { + l := list.New([]list.Item{}, list.NewDefaultDelegate(), constants.WindowSize.Width, constants.WindowSize.Height) + res, err := sdk.ListAttributes(common.ActiveStateEnum_ACTIVE_STATE_ENUM_ANY) + if err != nil { + // return error view + } + var attrs []list.Item + selectIdx := 0 + for i, attr := range res { + var vals []string + for _, val := range attr.Values { + vals = append(vals, val.Value) + } + if attr.Id == id { + selectIdx = i + } + item := AttributeItem{ + id: attr.Id, + // namespace: attr.Namespace.Name, + name: attr.Name, + // rule: attr.Rule.String(), + // values: vals, + } + attrs = append(attrs, item) + } + l.Title = "Attributes" + l.SetItems(attrs) + l.Select(selectIdx) + m := AttributeList{sdk: sdk, list: l} + return m.Update(WindowMsg()) +} + +func (m AttributeList) Init() tea.Cmd { + return nil +} + +func StyleAttr(attr string) string { + return lipgloss.NewStyle(). + Foreground(constants.Magenta). + Render(attr) +} + +func CreateViewFormat(num int) string { + var format string + for i := 0; i < num; i++ { + format += "%s %s\n" + } + return format +} + +func (m AttributeList) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.WindowSizeMsg: + constants.WindowSize = msg + m.list.SetSize(msg.Width, msg.Height) + // m.width = msg.Width + return m, nil + case tea.KeyMsg: + switch msg.String() { + case "ctrl+c", "q": + return m, tea.Quit + case "ctrl+[", "backspace": + am, _ := InitAppMenu(m.sdk) + // make enum for Attributes idx in AppMenu + am.list.Select(0) + return am.Update(WindowMsg()) + // case "c": + // create new attribute + // return InitAttributeView(m.list.Items(), len(m.list.Items())) + case "enter", "e": + return InitAttributeView(m.list.Items()[m.list.Index()].(AttributeItem).id, m.sdk) + // case "ctrl+d": + // m.list.RemoveItem(m.list.Index()) + // newIndex := m.list.Index() - 1 + // if newIndex < 0 { + // newIndex = 0 + // } + // m.list.Select(newIndex) + } + } + var cmd tea.Cmd + m.list, cmd = m.list.Update(msg) + return m, cmd +} + +func (m AttributeList) View() string { + return ViewList(m.list) +} + +// func AddAttribute() { +// var namespace string + +// form := huh.NewForm( +// huh.NewGroup( +// huh.NewSelect[string](). +// Title("Namespace"). +// Options( +// huh.NewOption("demo.com", "demo.com"), +// huh.NewOption("demo.net", "demo.net"), +// ). +// Validate(func(str string) error { +// // Check if namespace exists +// fmt.Println(str) +// return nil +// }). +// Value(&namespace), +// ), +// ) + +// if err := form.Run(); err != nil { +// return +// } +// } diff --git a/tui/attributes/attributeView.go b/tui/attributes/attributeView.go new file mode 100644 index 00000000..1b5e01a9 --- /dev/null +++ b/tui/attributes/attributeView.go @@ -0,0 +1,111 @@ +package attributes + +import ( + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" + "github.com/opentdf/otdfctl/pkg/cli" + "github.com/opentdf/otdfctl/pkg/handlers" + "github.com/opentdf/otdfctl/tui/common" + "github.com/opentdf/otdfctl/tui/constants" + "github.com/opentdf/otdfctl/tui/crud" + "github.com/opentdf/platform/protocol/go/policy" +) + +type AttributeSubItem struct { + title string + description string +} + +func (m AttributeSubItem) FilterValue() string { + return m.title +} + +func (m AttributeSubItem) Title() string { + return m.title +} + +func (m AttributeSubItem) Description() string { + return m.description +} + +type AttributeView struct { + attr *policy.Attribute + read crud.Read + sdk handlers.Handler +} + +func InitAttributeView(id string, h handlers.Handler) (AttributeView, tea.Cmd) { + attr, err := h.GetAttribute(id) + if err != nil { + // return error view + } + // var vals []string + // for _, val := range attr.Values { + // vals = append(vals, val.Value) + // } + sa := cli.GetSimpleAttribute(attr) + items := []list.Item{ + AttributeSubItem{title: "ID", description: sa.Id}, + AttributeSubItem{title: "Name", description: sa.Name}, + AttributeSubItem{title: "Rule", description: sa.Rule}, + AttributeSubItem{title: "Values", description: cli.CommaSeparated(sa.Values)}, + AttributeSubItem{title: "Namespace", description: sa.Namespace}, + AttributeSubItem{title: "Active", description: sa.Active}, + AttributeSubItem{title: "Labels", description: sa.Metadata["Labels"]}, + AttributeSubItem{title: "Created At", description: sa.Metadata["Created At"]}, + AttributeSubItem{title: "Updated At", description: sa.Metadata["Updated At"]}, + } + model, _ := crud.InitRead("Read Attribute", items) + m := AttributeView{sdk: h, attr: attr, read: model.(crud.Read)} + model, msg := m.Update(common.WindowMsg()) + m = model.(AttributeView) + return m, msg +} + +func (m AttributeView) Init() tea.Cmd { + return nil +} + +func (m AttributeView) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.WindowSizeMsg: + constants.WindowSize = msg + m.read.list.SetSize(msg.Width, msg.Height) + return m, nil + case tea.KeyMsg: + switch msg.String() { + case "backspace": + return InitAttributeList(m.attr.Id, m.sdk) + case "ctrl+c", "q": + return m, tea.Quit + case "ctrl+d": + return m, nil + case "enter": + if m.read.list.SelectedItem().(AttributeSubItem).title == "Labels" { + // return InitLabelList(m.attr, m.sdk) + // list values + // vl, cmd := InitAttributeValueList(m.attr.Id, m.sdk) + // return vl, cmd + } + // case "enter": + // switch m.list.SelectedItem().(AttributeItem).id { + // // case namespaceMenu: + // // // get namespaces + // // nl, cmd := InitNamespaceList([]list.Item{}, 0) + // // return nl, cmd + // case attributeMenu: + // // list attributes + // al, cmd := InitAttributeList("", m.sdk) + // return al, cmd + // } + } + } + + var cmd tea.Cmd + m.read.list, cmd = m.read.list.Update(msg) + return m, cmd +} + +func (m AttributeView) View() string { + return m.read.View() +} diff --git a/tui/common/common.go b/tui/common/common.go new file mode 100644 index 00000000..ed0d4e31 --- /dev/null +++ b/tui/common/common.go @@ -0,0 +1,54 @@ +package common + +import ( + "fmt" + "log" + "os" + + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + "github.com/opentdf/otdfctl/pkg/handlers" + "github.com/opentdf/otdfctl/tui/constants" + "github.com/opentdf/otdfctl/tui/menu" +) + +// StartTea the entry point for the UI. Initializes the model. +func StartTea(h handlers.Handler) error { + if f, err := tea.LogToFile("debug.log", "help"); err != nil { + fmt.Println("Couldn't open a file for logging:", err) + os.Exit(1) + } else { + defer func() { + err = f.Close() + if err != nil { + log.Fatal(err) + } + }() + } + + m, _ := menu. + InitAppMenu(h) + constants.P = tea.NewProgram(m, tea.WithAltScreen(), tea.WithMouseCellMotion()) + if _, err := constants.P.Run(); err != nil { + fmt.Println("Error running program:", err) + os.Exit(1) + } + return nil +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} + +func ViewList(m list.Model) string { + lipgloss.NewStyle().Padding(1, 2, 1, 2) + return lipgloss.JoinVertical(lipgloss.Top, m.View()) +} + +func WindowMsg() tea.WindowSizeMsg { + return tea.WindowSizeMsg{Width: constants.WindowSize.Width, Height: constants.WindowSize.Height} +} diff --git a/tui/constants/types.go b/tui/constants/types.go new file mode 100644 index 00000000..ba1872a7 --- /dev/null +++ b/tui/constants/types.go @@ -0,0 +1,5 @@ +package constants + +type errMsg struct { + error +} diff --git a/tui/crud/read.go b/tui/crud/read.go new file mode 100644 index 00000000..f8678a4c --- /dev/null +++ b/tui/crud/read.go @@ -0,0 +1,44 @@ +package crud + +import ( + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" + "github.com/opentdf/otdfctl/tui/common" + "github.com/opentdf/otdfctl/tui/constants" +) + +type Read struct { + list list.Model + width int +} + +func InitRead(title string, items []list.Item) (tea.Model, tea.Cmd) { + m := Read{} + m.list = list.New(items, list.NewDefaultDelegate(), constants.WindowSize.Width, constants.WindowSize.Height) + m.list.Title = title + return m.Update(common.WindowMsg()) +} + +func (m Read) Init() tea.Cmd { + return nil +} + +func (m Read) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + // switch msg := msg.(type) { + // case tea.WindowSizeMsg: + // constants.WindowSize = msg + // m.list.SetSize(msg.Width, msg.Height) + // m.width = msg.Width + // return m, nil + // case tea.KeyMsg: + // switch msg.Type { + // case tea.KeyCtrlC, tea.KeyEsc: + // return m, tea.Quit + // } + // } + return m, nil +} + +func (m Read) View() string { + return common.ViewList(m.list) +} diff --git a/tui/crud/update.go b/tui/crud/update.go new file mode 100644 index 00000000..db1528c3 --- /dev/null +++ b/tui/crud/update.go @@ -0,0 +1 @@ +package crud diff --git a/tui/menu/appMenu.go b/tui/menu/appMenu.go new file mode 100644 index 00000000..e03541f2 --- /dev/null +++ b/tui/menu/appMenu.go @@ -0,0 +1,101 @@ +package menu + +import ( + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" + "github.com/opentdf/otdfctl/pkg/handlers" + "github.com/opentdf/otdfctl/tui/attributes" + "github.com/opentdf/otdfctl/tui/common" + "github.com/opentdf/otdfctl/tui/constants" +) + +const ( + mainMenu menuState = iota + namespaceMenu + attributeMenu + entitlementMenu + resourceEncodingMenu + subjectEncodingMenu +) + +type menuState int + +type AppMenuItem struct { + id menuState + title string + description string +} + +func (m AppMenuItem) FilterValue() string { + return m.title +} + +func (m AppMenuItem) Title() string { + return m.title +} + +func (m AppMenuItem) Description() string { + return m.description +} + +type AppMenu struct { + list list.Model + view tea.Model + sdk handlers.Handler +} + +func InitAppMenu(h handlers.Handler) (AppMenu, tea.Cmd) { + m := AppMenu{ + view: nil, + sdk: h, + } + m.list = list.New([]list.Item{}, list.NewDefaultDelegate(), 8, 8) + m.list.Title = "OpenTDF" + m.list.SetItems([]list.Item{ + // AppMenuItem{title: "Namespaces", description: "Manage namespaces", id: namespaceMenu}, + AppMenuItem{title: "Attributes", description: "Manage attributes", id: attributeMenu}, + // AppMenuItem{title: "Entitlements", description: "Manage entitlements", id: entitlementMenu}, + // AppMenuItem{title: "Resource Encodings", description: "Manage resource encodings", id: resourceEncodingMenu}, + // AppMenuItem{title: "Subject Encodings", description: "Manage subject encodings", id: subjectEncodingMenu}, + }) + return m, func() tea.Msg { return nil } +} + +func (m AppMenu) Init() tea.Cmd { + return nil +} + +func (m AppMenu) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.WindowSizeMsg: + constants.WindowSize = msg + m.list.SetSize(msg.Width, msg.Height) + return m, nil + case tea.KeyMsg: + switch msg.String() { + case "ctrl+c", "q": + return m, tea.Quit + case "ctrl+d": + return m, nil + case "enter": + switch m.list.SelectedItem().(AppMenuItem).id { + // case namespaceMenu: + // // get namespaces + // nl, cmd := InitNamespaceList([]list.Item{}, 0) + // return nl, cmd + case attributeMenu: + // list attributes + al, cmd := attributes.InitAttributeList("", m.sdk) + return al, cmd + } + } + } + + var cmd tea.Cmd + m.list, cmd = m.list.Update(msg) + return m, cmd +} + +func (m AppMenu) View() string { + return common.ViewList(m.list) +} From d3388eb8e7af0e8e5bc0bc6edf9cc14d798d91f4 Mon Sep 17 00:00:00 2001 From: Krish Suchak Date: Mon, 6 May 2024 16:28:55 -0400 Subject: [PATCH 09/25] revert import cycles --- tui/attributeView.go | 7 ++ tui/attributes/attributeCreateView.go | 59 ----------- tui/attributes/attributeList.go | 147 -------------------------- tui/attributes/attributeView.go | 111 ------------------- tui/common.go | 3 +- tui/common/common.go | 54 ---------- tui/constants/types.go | 5 - tui/crud/read.go | 44 -------- tui/crud/update.go | 1 - tui/menu/appMenu.go | 101 ------------------ tui/update.go | 1 + 11 files changed, 10 insertions(+), 523 deletions(-) delete mode 100644 tui/attributes/attributeCreateView.go delete mode 100644 tui/attributes/attributeList.go delete mode 100644 tui/attributes/attributeView.go delete mode 100644 tui/common/common.go delete mode 100644 tui/constants/types.go delete mode 100644 tui/crud/read.go delete mode 100644 tui/crud/update.go delete mode 100644 tui/menu/appMenu.go create mode 100644 tui/update.go diff --git a/tui/attributeView.go b/tui/attributeView.go index d20eb0a9..3a60e78c 100644 --- a/tui/attributeView.go +++ b/tui/attributeView.go @@ -78,6 +78,13 @@ func (m AttributeView) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, tea.Quit case "ctrl+d": return m, nil + case "enter": + if m.read.list.SelectedItem().(AttributeSubItem).title == "Labels" { + // return InitLabelList(m.attr, m.sdk) + // list values + // vl, cmd := InitAttributeValueList(m.attr.Id, m.sdk) + // return vl, cmd + } // case "enter": // switch m.list.SelectedItem().(AttributeItem).id { // // case namespaceMenu: diff --git a/tui/attributes/attributeCreateView.go b/tui/attributes/attributeCreateView.go deleted file mode 100644 index 9132d04b..00000000 --- a/tui/attributes/attributeCreateView.go +++ /dev/null @@ -1,59 +0,0 @@ -package attributes - -import ( - "fmt" - - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/huh" - "github.com/opentdf/otdfctl/tui/constants" -) - -type AttributeCreateModel struct { - form *huh.Form -} - -func InitAttributeCreateModel() (tea.Model, tea.Cmd) { - namespace := "" - m := AttributeCreateModel{} - m.form = huh.NewForm( - huh.NewGroup( - huh.NewSelect[string](). - Title("Namespace"). - Options( - huh.NewOption("demo.com", "demo.com"), - huh.NewOption("demo.net", "demo.net"), - ). - Validate(func(str string) error { - // Check if namespace exists - fmt.Println(str) - return nil - }). - Value(&namespace), - ), - ) - - return m, nil -} - -func (m AttributeCreateModel) Init() tea.Cmd { - return nil -} - -func (m AttributeCreateModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - switch msg := msg.(type) { - case tea.WindowSizeMsg: - constants.WindowSize = msg - return m, nil - case tea.KeyMsg: - switch msg.String() { - case "ctrl+c", "q": - return m, tea.Quit - } - } - - return m, nil -} - -func (m AttributeCreateModel) View() string { - return "" -} diff --git a/tui/attributes/attributeList.go b/tui/attributes/attributeList.go deleted file mode 100644 index 9586a439..00000000 --- a/tui/attributes/attributeList.go +++ /dev/null @@ -1,147 +0,0 @@ -package attributes - -import ( - "github.com/charmbracelet/bubbles/list" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" - "github.com/opentdf/otdfctl/pkg/handlers" - "github.com/opentdf/otdfctl/tui/constants" - "github.com/opentdf/platform/protocol/go/common" -) - -type AttributeList struct { - list list.Model - // width int - sdk handlers.Handler -} - -type AttributeItem struct { - id string - name string -} - -func (m AttributeItem) FilterValue() string { - return m.name -} - -func (m AttributeItem) Title() string { - return m.name -} - -func (m AttributeItem) Description() string { - return m.id -} - -func InitAttributeList(id string, sdk handlers.Handler) (tea.Model, tea.Cmd) { - l := list.New([]list.Item{}, list.NewDefaultDelegate(), constants.WindowSize.Width, constants.WindowSize.Height) - res, err := sdk.ListAttributes(common.ActiveStateEnum_ACTIVE_STATE_ENUM_ANY) - if err != nil { - // return error view - } - var attrs []list.Item - selectIdx := 0 - for i, attr := range res { - var vals []string - for _, val := range attr.Values { - vals = append(vals, val.Value) - } - if attr.Id == id { - selectIdx = i - } - item := AttributeItem{ - id: attr.Id, - // namespace: attr.Namespace.Name, - name: attr.Name, - // rule: attr.Rule.String(), - // values: vals, - } - attrs = append(attrs, item) - } - l.Title = "Attributes" - l.SetItems(attrs) - l.Select(selectIdx) - m := AttributeList{sdk: sdk, list: l} - return m.Update(WindowMsg()) -} - -func (m AttributeList) Init() tea.Cmd { - return nil -} - -func StyleAttr(attr string) string { - return lipgloss.NewStyle(). - Foreground(constants.Magenta). - Render(attr) -} - -func CreateViewFormat(num int) string { - var format string - for i := 0; i < num; i++ { - format += "%s %s\n" - } - return format -} - -func (m AttributeList) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - switch msg := msg.(type) { - case tea.WindowSizeMsg: - constants.WindowSize = msg - m.list.SetSize(msg.Width, msg.Height) - // m.width = msg.Width - return m, nil - case tea.KeyMsg: - switch msg.String() { - case "ctrl+c", "q": - return m, tea.Quit - case "ctrl+[", "backspace": - am, _ := InitAppMenu(m.sdk) - // make enum for Attributes idx in AppMenu - am.list.Select(0) - return am.Update(WindowMsg()) - // case "c": - // create new attribute - // return InitAttributeView(m.list.Items(), len(m.list.Items())) - case "enter", "e": - return InitAttributeView(m.list.Items()[m.list.Index()].(AttributeItem).id, m.sdk) - // case "ctrl+d": - // m.list.RemoveItem(m.list.Index()) - // newIndex := m.list.Index() - 1 - // if newIndex < 0 { - // newIndex = 0 - // } - // m.list.Select(newIndex) - } - } - var cmd tea.Cmd - m.list, cmd = m.list.Update(msg) - return m, cmd -} - -func (m AttributeList) View() string { - return ViewList(m.list) -} - -// func AddAttribute() { -// var namespace string - -// form := huh.NewForm( -// huh.NewGroup( -// huh.NewSelect[string](). -// Title("Namespace"). -// Options( -// huh.NewOption("demo.com", "demo.com"), -// huh.NewOption("demo.net", "demo.net"), -// ). -// Validate(func(str string) error { -// // Check if namespace exists -// fmt.Println(str) -// return nil -// }). -// Value(&namespace), -// ), -// ) - -// if err := form.Run(); err != nil { -// return -// } -// } diff --git a/tui/attributes/attributeView.go b/tui/attributes/attributeView.go deleted file mode 100644 index 1b5e01a9..00000000 --- a/tui/attributes/attributeView.go +++ /dev/null @@ -1,111 +0,0 @@ -package attributes - -import ( - "github.com/charmbracelet/bubbles/list" - tea "github.com/charmbracelet/bubbletea" - "github.com/opentdf/otdfctl/pkg/cli" - "github.com/opentdf/otdfctl/pkg/handlers" - "github.com/opentdf/otdfctl/tui/common" - "github.com/opentdf/otdfctl/tui/constants" - "github.com/opentdf/otdfctl/tui/crud" - "github.com/opentdf/platform/protocol/go/policy" -) - -type AttributeSubItem struct { - title string - description string -} - -func (m AttributeSubItem) FilterValue() string { - return m.title -} - -func (m AttributeSubItem) Title() string { - return m.title -} - -func (m AttributeSubItem) Description() string { - return m.description -} - -type AttributeView struct { - attr *policy.Attribute - read crud.Read - sdk handlers.Handler -} - -func InitAttributeView(id string, h handlers.Handler) (AttributeView, tea.Cmd) { - attr, err := h.GetAttribute(id) - if err != nil { - // return error view - } - // var vals []string - // for _, val := range attr.Values { - // vals = append(vals, val.Value) - // } - sa := cli.GetSimpleAttribute(attr) - items := []list.Item{ - AttributeSubItem{title: "ID", description: sa.Id}, - AttributeSubItem{title: "Name", description: sa.Name}, - AttributeSubItem{title: "Rule", description: sa.Rule}, - AttributeSubItem{title: "Values", description: cli.CommaSeparated(sa.Values)}, - AttributeSubItem{title: "Namespace", description: sa.Namespace}, - AttributeSubItem{title: "Active", description: sa.Active}, - AttributeSubItem{title: "Labels", description: sa.Metadata["Labels"]}, - AttributeSubItem{title: "Created At", description: sa.Metadata["Created At"]}, - AttributeSubItem{title: "Updated At", description: sa.Metadata["Updated At"]}, - } - model, _ := crud.InitRead("Read Attribute", items) - m := AttributeView{sdk: h, attr: attr, read: model.(crud.Read)} - model, msg := m.Update(common.WindowMsg()) - m = model.(AttributeView) - return m, msg -} - -func (m AttributeView) Init() tea.Cmd { - return nil -} - -func (m AttributeView) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - switch msg := msg.(type) { - case tea.WindowSizeMsg: - constants.WindowSize = msg - m.read.list.SetSize(msg.Width, msg.Height) - return m, nil - case tea.KeyMsg: - switch msg.String() { - case "backspace": - return InitAttributeList(m.attr.Id, m.sdk) - case "ctrl+c", "q": - return m, tea.Quit - case "ctrl+d": - return m, nil - case "enter": - if m.read.list.SelectedItem().(AttributeSubItem).title == "Labels" { - // return InitLabelList(m.attr, m.sdk) - // list values - // vl, cmd := InitAttributeValueList(m.attr.Id, m.sdk) - // return vl, cmd - } - // case "enter": - // switch m.list.SelectedItem().(AttributeItem).id { - // // case namespaceMenu: - // // // get namespaces - // // nl, cmd := InitNamespaceList([]list.Item{}, 0) - // // return nl, cmd - // case attributeMenu: - // // list attributes - // al, cmd := InitAttributeList("", m.sdk) - // return al, cmd - // } - } - } - - var cmd tea.Cmd - m.read.list, cmd = m.read.list.Update(msg) - return m, cmd -} - -func (m AttributeView) View() string { - return m.read.View() -} diff --git a/tui/common.go b/tui/common.go index 436731ee..f0d98837 100644 --- a/tui/common.go +++ b/tui/common.go @@ -26,7 +26,8 @@ func StartTea(h handlers.Handler) error { }() } - m, _ := InitAppMenu(h) + m, _ := + InitAppMenu(h) constants.P = tea.NewProgram(m, tea.WithAltScreen(), tea.WithMouseCellMotion()) if _, err := constants.P.Run(); err != nil { fmt.Println("Error running program:", err) diff --git a/tui/common/common.go b/tui/common/common.go deleted file mode 100644 index ed0d4e31..00000000 --- a/tui/common/common.go +++ /dev/null @@ -1,54 +0,0 @@ -package common - -import ( - "fmt" - "log" - "os" - - "github.com/charmbracelet/bubbles/list" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" - "github.com/opentdf/otdfctl/pkg/handlers" - "github.com/opentdf/otdfctl/tui/constants" - "github.com/opentdf/otdfctl/tui/menu" -) - -// StartTea the entry point for the UI. Initializes the model. -func StartTea(h handlers.Handler) error { - if f, err := tea.LogToFile("debug.log", "help"); err != nil { - fmt.Println("Couldn't open a file for logging:", err) - os.Exit(1) - } else { - defer func() { - err = f.Close() - if err != nil { - log.Fatal(err) - } - }() - } - - m, _ := menu. - InitAppMenu(h) - constants.P = tea.NewProgram(m, tea.WithAltScreen(), tea.WithMouseCellMotion()) - if _, err := constants.P.Run(); err != nil { - fmt.Println("Error running program:", err) - os.Exit(1) - } - return nil -} - -func max(a, b int) int { - if a > b { - return a - } - return b -} - -func ViewList(m list.Model) string { - lipgloss.NewStyle().Padding(1, 2, 1, 2) - return lipgloss.JoinVertical(lipgloss.Top, m.View()) -} - -func WindowMsg() tea.WindowSizeMsg { - return tea.WindowSizeMsg{Width: constants.WindowSize.Width, Height: constants.WindowSize.Height} -} diff --git a/tui/constants/types.go b/tui/constants/types.go deleted file mode 100644 index ba1872a7..00000000 --- a/tui/constants/types.go +++ /dev/null @@ -1,5 +0,0 @@ -package constants - -type errMsg struct { - error -} diff --git a/tui/crud/read.go b/tui/crud/read.go deleted file mode 100644 index f8678a4c..00000000 --- a/tui/crud/read.go +++ /dev/null @@ -1,44 +0,0 @@ -package crud - -import ( - "github.com/charmbracelet/bubbles/list" - tea "github.com/charmbracelet/bubbletea" - "github.com/opentdf/otdfctl/tui/common" - "github.com/opentdf/otdfctl/tui/constants" -) - -type Read struct { - list list.Model - width int -} - -func InitRead(title string, items []list.Item) (tea.Model, tea.Cmd) { - m := Read{} - m.list = list.New(items, list.NewDefaultDelegate(), constants.WindowSize.Width, constants.WindowSize.Height) - m.list.Title = title - return m.Update(common.WindowMsg()) -} - -func (m Read) Init() tea.Cmd { - return nil -} - -func (m Read) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - // switch msg := msg.(type) { - // case tea.WindowSizeMsg: - // constants.WindowSize = msg - // m.list.SetSize(msg.Width, msg.Height) - // m.width = msg.Width - // return m, nil - // case tea.KeyMsg: - // switch msg.Type { - // case tea.KeyCtrlC, tea.KeyEsc: - // return m, tea.Quit - // } - // } - return m, nil -} - -func (m Read) View() string { - return common.ViewList(m.list) -} diff --git a/tui/crud/update.go b/tui/crud/update.go deleted file mode 100644 index db1528c3..00000000 --- a/tui/crud/update.go +++ /dev/null @@ -1 +0,0 @@ -package crud diff --git a/tui/menu/appMenu.go b/tui/menu/appMenu.go deleted file mode 100644 index e03541f2..00000000 --- a/tui/menu/appMenu.go +++ /dev/null @@ -1,101 +0,0 @@ -package menu - -import ( - "github.com/charmbracelet/bubbles/list" - tea "github.com/charmbracelet/bubbletea" - "github.com/opentdf/otdfctl/pkg/handlers" - "github.com/opentdf/otdfctl/tui/attributes" - "github.com/opentdf/otdfctl/tui/common" - "github.com/opentdf/otdfctl/tui/constants" -) - -const ( - mainMenu menuState = iota - namespaceMenu - attributeMenu - entitlementMenu - resourceEncodingMenu - subjectEncodingMenu -) - -type menuState int - -type AppMenuItem struct { - id menuState - title string - description string -} - -func (m AppMenuItem) FilterValue() string { - return m.title -} - -func (m AppMenuItem) Title() string { - return m.title -} - -func (m AppMenuItem) Description() string { - return m.description -} - -type AppMenu struct { - list list.Model - view tea.Model - sdk handlers.Handler -} - -func InitAppMenu(h handlers.Handler) (AppMenu, tea.Cmd) { - m := AppMenu{ - view: nil, - sdk: h, - } - m.list = list.New([]list.Item{}, list.NewDefaultDelegate(), 8, 8) - m.list.Title = "OpenTDF" - m.list.SetItems([]list.Item{ - // AppMenuItem{title: "Namespaces", description: "Manage namespaces", id: namespaceMenu}, - AppMenuItem{title: "Attributes", description: "Manage attributes", id: attributeMenu}, - // AppMenuItem{title: "Entitlements", description: "Manage entitlements", id: entitlementMenu}, - // AppMenuItem{title: "Resource Encodings", description: "Manage resource encodings", id: resourceEncodingMenu}, - // AppMenuItem{title: "Subject Encodings", description: "Manage subject encodings", id: subjectEncodingMenu}, - }) - return m, func() tea.Msg { return nil } -} - -func (m AppMenu) Init() tea.Cmd { - return nil -} - -func (m AppMenu) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - switch msg := msg.(type) { - case tea.WindowSizeMsg: - constants.WindowSize = msg - m.list.SetSize(msg.Width, msg.Height) - return m, nil - case tea.KeyMsg: - switch msg.String() { - case "ctrl+c", "q": - return m, tea.Quit - case "ctrl+d": - return m, nil - case "enter": - switch m.list.SelectedItem().(AppMenuItem).id { - // case namespaceMenu: - // // get namespaces - // nl, cmd := InitNamespaceList([]list.Item{}, 0) - // return nl, cmd - case attributeMenu: - // list attributes - al, cmd := attributes.InitAttributeList("", m.sdk) - return al, cmd - } - } - } - - var cmd tea.Cmd - m.list, cmd = m.list.Update(msg) - return m, cmd -} - -func (m AppMenu) View() string { - return common.ViewList(m.list) -} diff --git a/tui/update.go b/tui/update.go new file mode 100644 index 00000000..89aa0ee2 --- /dev/null +++ b/tui/update.go @@ -0,0 +1 @@ +package tui From 6c517572246a4678d84924c02f37b12b184688f1 Mon Sep 17 00:00:00 2001 From: Krish Suchak Date: Wed, 8 May 2024 15:31:11 -0400 Subject: [PATCH 10/25] start label list --- tui/attributeView.go | 2 +- tui/common.go | 3 +- tui/labelList.go | 73 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 tui/labelList.go diff --git a/tui/attributeView.go b/tui/attributeView.go index 3a60e78c..0b1aeb31 100644 --- a/tui/attributeView.go +++ b/tui/attributeView.go @@ -80,7 +80,7 @@ func (m AttributeView) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil case "enter": if m.read.list.SelectedItem().(AttributeSubItem).title == "Labels" { - // return InitLabelList(m.attr, m.sdk) + return InitLabelList(m.attr, m.sdk) // list values // vl, cmd := InitAttributeValueList(m.attr.Id, m.sdk) // return vl, cmd diff --git a/tui/common.go b/tui/common.go index f0d98837..436731ee 100644 --- a/tui/common.go +++ b/tui/common.go @@ -26,8 +26,7 @@ func StartTea(h handlers.Handler) error { }() } - m, _ := - InitAppMenu(h) + m, _ := InitAppMenu(h) constants.P = tea.NewProgram(m, tea.WithAltScreen(), tea.WithMouseCellMotion()) if _, err := constants.P.Run(); err != nil { fmt.Println("Error running program:", err) diff --git a/tui/labelList.go b/tui/labelList.go new file mode 100644 index 00000000..f9c02923 --- /dev/null +++ b/tui/labelList.go @@ -0,0 +1,73 @@ +package tui + +import ( + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" + "github.com/opentdf/otdfctl/pkg/handlers" + "github.com/opentdf/otdfctl/tui/constants" + "github.com/opentdf/platform/protocol/go/policy" +) + +// func (m LabelList) + +type LabelList struct { + attr *policy.Attribute + sdk handlers.Handler + read tea.Model +} + +type LabelItem struct { + title string + description string +} + +func (m LabelItem) FilterValue() string { + return m.title +} + +func (m LabelItem) Title() string { + return m.title +} + +func (m LabelItem) Description() string { + return m.description +} + +func InitLabelList(attr *policy.Attribute, sdk handlers.Handler) (tea.Model, tea.Cmd) { + labels := attr.Metadata.Labels + var items []list.Item + for k, v := range labels { + item := LabelItem{ + title: k, + description: v, + } + items = append(items, item) + } + model, _ := InitRead("Read Labels", items) + return LabelList{attr: attr, sdk: sdk, read: model}, nil +} + +func (m LabelList) Init() tea.Cmd { + return nil +} + +func (m LabelList) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.WindowSizeMsg: + constants.WindowSize = msg + m.read.list.SetSize(msg.Width, msg.Height) + return m, nil + case tea.KeyMsg: + switch msg.String() { + // case "backspace": + // return InitAttributeList(m.attr.Id, m.sdk) + case "ctrl+c", "q": + return m, tea.Quit + } + } + return m, nil +} + +func (m LabelList) View() string { + return "" +} From 6688fd435699e3fcec535c6221d9c65c7930b692 Mon Sep 17 00:00:00 2001 From: Krish Suchak Date: Thu, 9 May 2024 11:11:59 -0400 Subject: [PATCH 11/25] display label list --- tui/labelList.go | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/tui/labelList.go b/tui/labelList.go index f9c02923..051ff231 100644 --- a/tui/labelList.go +++ b/tui/labelList.go @@ -13,7 +13,7 @@ import ( type LabelList struct { attr *policy.Attribute sdk handlers.Handler - read tea.Model + read Read } type LabelItem struct { @@ -44,7 +44,7 @@ func InitLabelList(attr *policy.Attribute, sdk handlers.Handler) (tea.Model, tea items = append(items, item) } model, _ := InitRead("Read Labels", items) - return LabelList{attr: attr, sdk: sdk, read: model}, nil + return LabelList{attr: attr, sdk: sdk, read: model.(Read)}, nil } func (m LabelList) Init() tea.Cmd { @@ -59,15 +59,24 @@ func (m LabelList) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil case tea.KeyMsg: switch msg.String() { - // case "backspace": - // return InitAttributeList(m.attr.Id, m.sdk) + case "backspace": + return InitAttributeView(m.attr.Id, m.sdk) case "ctrl+c", "q": return m, tea.Quit + case "enter", "e": + // edit? + return m, nil + case "c": + // create new label + return m, nil + case "d": + // delete label + return m, nil } } return m, nil } func (m LabelList) View() string { - return "" + return ViewList(m.read.list) } From fb2e906ab79fc191fe307f4b6eb86f12d03034fb Mon Sep 17 00:00:00 2001 From: Krish Suchak Date: Tue, 14 May 2024 10:38:18 -0400 Subject: [PATCH 12/25] start label update --- tui/labelList.go | 2 +- tui/labelUpdate.go | 170 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 tui/labelUpdate.go diff --git a/tui/labelList.go b/tui/labelList.go index 051ff231..03e4241f 100644 --- a/tui/labelList.go +++ b/tui/labelList.go @@ -64,7 +64,7 @@ func (m LabelList) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case "ctrl+c", "q": return m, tea.Quit case "enter", "e": - // edit? + return initialModel(), nil return m, nil case "c": // create new label diff --git a/tui/labelUpdate.go b/tui/labelUpdate.go new file mode 100644 index 00000000..446ee87f --- /dev/null +++ b/tui/labelUpdate.go @@ -0,0 +1,170 @@ +package tui + +// A simple example demonstrating the use of multiple text input components +// from the Bubbles component library. + +import ( + "fmt" + "strings" + + "github.com/charmbracelet/bubbles/cursor" + "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")) +) + +type model struct { + focusIndex int + inputs []textinput.Model + cursorMode cursor.Mode +} + +func initialModel() model { + m := model{ + inputs: make([]textinput.Model, 3), + } + + var t textinput.Model + for i := range m.inputs { + t = textinput.New() + t.Cursor.Style = cursorStyle + t.CharLimit = 32 + + switch i { + case 0: + t.Placeholder = "Nickname" + t.Focus() + t.PromptStyle = focusedStyle + t.TextStyle = focusedStyle + case 1: + t.Placeholder = "Email" + t.CharLimit = 64 + case 2: + t.Placeholder = "Password" + t.EchoMode = textinput.EchoPassword + t.EchoCharacter = '•' + } + + 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 > cursor.CursorHide { + m.cursorMode = cursor.CursorBlink + } + cmds := make([]tea.Cmd, len(m.inputs)) + for i := range m.inputs { + cmds[i] = m.inputs[i].Cursor.SetMode(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 + + 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() +} From a1efde56d196fda50e070172844556ca9234e5c7 Mon Sep 17 00:00:00 2001 From: Krish Suchak Date: Tue, 14 May 2024 10:39:38 -0400 Subject: [PATCH 13/25] move to update.go --- tui/labelUpdate.go | 169 --------------------------------------------- tui/update.go | 169 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+), 169 deletions(-) diff --git a/tui/labelUpdate.go b/tui/labelUpdate.go index 446ee87f..89aa0ee2 100644 --- a/tui/labelUpdate.go +++ b/tui/labelUpdate.go @@ -1,170 +1 @@ package tui - -// A simple example demonstrating the use of multiple text input components -// from the Bubbles component library. - -import ( - "fmt" - "strings" - - "github.com/charmbracelet/bubbles/cursor" - "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")) -) - -type model struct { - focusIndex int - inputs []textinput.Model - cursorMode cursor.Mode -} - -func initialModel() model { - m := model{ - inputs: make([]textinput.Model, 3), - } - - var t textinput.Model - for i := range m.inputs { - t = textinput.New() - t.Cursor.Style = cursorStyle - t.CharLimit = 32 - - switch i { - case 0: - t.Placeholder = "Nickname" - t.Focus() - t.PromptStyle = focusedStyle - t.TextStyle = focusedStyle - case 1: - t.Placeholder = "Email" - t.CharLimit = 64 - case 2: - t.Placeholder = "Password" - t.EchoMode = textinput.EchoPassword - t.EchoCharacter = '•' - } - - 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 > cursor.CursorHide { - m.cursorMode = cursor.CursorBlink - } - cmds := make([]tea.Cmd, len(m.inputs)) - for i := range m.inputs { - cmds[i] = m.inputs[i].Cursor.SetMode(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 - - 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() -} diff --git a/tui/update.go b/tui/update.go index 89aa0ee2..446ee87f 100644 --- a/tui/update.go +++ b/tui/update.go @@ -1 +1,170 @@ package tui + +// A simple example demonstrating the use of multiple text input components +// from the Bubbles component library. + +import ( + "fmt" + "strings" + + "github.com/charmbracelet/bubbles/cursor" + "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")) +) + +type model struct { + focusIndex int + inputs []textinput.Model + cursorMode cursor.Mode +} + +func initialModel() model { + m := model{ + inputs: make([]textinput.Model, 3), + } + + var t textinput.Model + for i := range m.inputs { + t = textinput.New() + t.Cursor.Style = cursorStyle + t.CharLimit = 32 + + switch i { + case 0: + t.Placeholder = "Nickname" + t.Focus() + t.PromptStyle = focusedStyle + t.TextStyle = focusedStyle + case 1: + t.Placeholder = "Email" + t.CharLimit = 64 + case 2: + t.Placeholder = "Password" + t.EchoMode = textinput.EchoPassword + t.EchoCharacter = '•' + } + + 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 > cursor.CursorHide { + m.cursorMode = cursor.CursorBlink + } + cmds := make([]tea.Cmd, len(m.inputs)) + for i := range m.inputs { + cmds[i] = m.inputs[i].Cursor.SetMode(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 + + 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() +} From 684b37b9fb3a33051e3cafab78020d8a23a002ee Mon Sep 17 00:00:00 2001 From: Krish Suchak Date: Tue, 14 May 2024 13:35:43 -0400 Subject: [PATCH 14/25] display label and edit --- tui/labelList.go | 3 +-- tui/labelUpdate.go | 24 +++++++++++++++++++++++ tui/update.go | 48 ++++++++++++++++++++++++++++------------------ 3 files changed, 54 insertions(+), 21 deletions(-) diff --git a/tui/labelList.go b/tui/labelList.go index 03e4241f..574fceef 100644 --- a/tui/labelList.go +++ b/tui/labelList.go @@ -64,8 +64,7 @@ func (m LabelList) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case "ctrl+c", "q": return m, tea.Quit case "enter", "e": - return initialModel(), nil - return m, nil + return InitLabelUpdate(m.read.list.Items()[m.read.list.Index()].(LabelItem)), nil case "c": // create new label return m, nil diff --git a/tui/labelUpdate.go b/tui/labelUpdate.go index 89aa0ee2..171b2f7f 100644 --- a/tui/labelUpdate.go +++ b/tui/labelUpdate.go @@ -1 +1,25 @@ package tui + +import tea "github.com/charmbracelet/bubbletea" + +type LabelUpdate struct { + update Update +} + +func InitLabelUpdate(label LabelItem) LabelUpdate { + return LabelUpdate{ + update: InitUpdate([]string{"Key", "Value"}, []string{label.title, label.description}), + } +} + +func (m LabelUpdate) Init() tea.Cmd { + return nil +} + +func (m LabelUpdate) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + return m.update.Update(msg) +} + +func (m LabelUpdate) View() string { + return m.update.View() +} diff --git a/tui/update.go b/tui/update.go index 446ee87f..9dceaf4e 100644 --- a/tui/update.go +++ b/tui/update.go @@ -25,15 +25,19 @@ var ( blurredButton = fmt.Sprintf("[ %s ]", blurredStyle.Render("Submit")) ) -type model struct { +type Update struct { focusIndex int inputs []textinput.Model cursorMode cursor.Mode + keys []string + // vals []string } -func initialModel() model { - m := model{ - inputs: make([]textinput.Model, 3), +func InitUpdate(keys []string, vals []string) Update { + m := Update{ + inputs: make([]textinput.Model, len(keys)), + keys: keys, + // vals: vals, } var t textinput.Model @@ -41,21 +45,26 @@ func initialModel() model { t = textinput.New() t.Cursor.Style = cursorStyle t.CharLimit = 32 - - switch i { - case 0: - t.Placeholder = "Nickname" + t.SetValue(vals[i]) + if i == 0 { t.Focus() t.PromptStyle = focusedStyle t.TextStyle = focusedStyle - case 1: - t.Placeholder = "Email" - t.CharLimit = 64 - case 2: - t.Placeholder = "Password" - t.EchoMode = textinput.EchoPassword - t.EchoCharacter = '•' } + // switch i { + // case 0: + // t.Placeholder = "Nickname" + // t.Focus() + // t.PromptStyle = focusedStyle + // t.TextStyle = focusedStyle + // case 1: + // t.Placeholder = "Email" + // t.CharLimit = 64 + // case 2: + // t.Placeholder = "Password" + // t.EchoMode = textinput.EchoPassword + // t.EchoCharacter = '•' + // } m.inputs[i] = t } @@ -63,11 +72,11 @@ func initialModel() model { return m } -func (m model) Init() tea.Cmd { +func (m Update) Init() tea.Cmd { return textinput.Blink } -func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { +func (m Update) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.KeyMsg: switch msg.String() { @@ -134,7 +143,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, cmd } -func (m *model) updateInputs(msg tea.Msg) tea.Cmd { +func (m *Update) 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 @@ -146,10 +155,11 @@ func (m *model) updateInputs(msg tea.Msg) tea.Cmd { return tea.Batch(cmds...) } -func (m model) View() string { +func (m Update) View() string { var b strings.Builder for i := range m.inputs { + b.WriteString(m.keys[i] + "\n") b.WriteString(m.inputs[i].View()) if i < len(m.inputs)-1 { b.WriteRune('\n') From f611ba439f5947a88ccd1a1d0f5ba26b9f780db7 Mon Sep 17 00:00:00 2001 From: Krish Suchak Date: Tue, 14 May 2024 17:04:42 -0400 Subject: [PATCH 15/25] label submit goes back to list --- tui/labelList.go | 4 ++-- tui/labelUpdate.go | 26 +++++++++++++++++++++++--- tui/update.go | 5 ++++- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/tui/labelList.go b/tui/labelList.go index 574fceef..a232b390 100644 --- a/tui/labelList.go +++ b/tui/labelList.go @@ -61,10 +61,10 @@ func (m LabelList) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg.String() { case "backspace": return InitAttributeView(m.attr.Id, m.sdk) - case "ctrl+c", "q": + case "ctrl+c", "q", "esc": return m, tea.Quit case "enter", "e": - return InitLabelUpdate(m.read.list.Items()[m.read.list.Index()].(LabelItem)), nil + return InitLabelUpdate(m.read.list.Items()[m.read.list.Index()].(LabelItem), m.attr, m.sdk), nil case "c": // create new label return m, nil diff --git a/tui/labelUpdate.go b/tui/labelUpdate.go index 171b2f7f..86499250 100644 --- a/tui/labelUpdate.go +++ b/tui/labelUpdate.go @@ -1,14 +1,22 @@ package tui -import tea "github.com/charmbracelet/bubbletea" +import ( + tea "github.com/charmbracelet/bubbletea" + "github.com/opentdf/otdfctl/pkg/handlers" + "github.com/opentdf/platform/protocol/go/policy" +) type LabelUpdate struct { update Update + attr *policy.Attribute + sdk handlers.Handler } -func InitLabelUpdate(label LabelItem) LabelUpdate { +func InitLabelUpdate(label LabelItem, attr *policy.Attribute, sdk handlers.Handler) LabelUpdate { return LabelUpdate{ update: InitUpdate([]string{"Key", "Value"}, []string{label.title, label.description}), + attr: attr, + sdk: sdk, } } @@ -17,7 +25,19 @@ func (m LabelUpdate) Init() tea.Cmd { } func (m LabelUpdate) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - return m.update.Update(msg) + switch msg := msg.(type) { + case tea.KeyMsg: + switch msg.String() { + case "enter": + // return InitLabelList(m.attr, m.sdk) + if m.update.focusIndex == len(m.update.inputs) { + return InitLabelList(m.attr, m.sdk) + } + } + } + update, cmd := m.update.Update(msg) + m.update = update.(Update) + return m, cmd } func (m LabelUpdate) View() string { diff --git a/tui/update.go b/tui/update.go index 9dceaf4e..4fe61755 100644 --- a/tui/update.go +++ b/tui/update.go @@ -102,7 +102,10 @@ func (m Update) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // 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 + return m, nil + // type updateMsg string + // a := interface{}(nil) + // return m, "abc".(tea.Cmd) } // Cycle indexes From fe5f592317a3b6707055065c9d543d2b6ebd1a65 Mon Sep 17 00:00:00 2001 From: Krish Suchak Date: Tue, 14 May 2024 17:43:34 -0400 Subject: [PATCH 16/25] trying to figure out update call --- tui/labelList.go | 3 ++- tui/labelUpdate.go | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/tui/labelList.go b/tui/labelList.go index a232b390..7946332f 100644 --- a/tui/labelList.go +++ b/tui/labelList.go @@ -64,7 +64,8 @@ func (m LabelList) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case "ctrl+c", "q", "esc": return m, tea.Quit case "enter", "e": - return InitLabelUpdate(m.read.list.Items()[m.read.list.Index()].(LabelItem), m.attr, m.sdk), nil + return InitLabelUpdate(m.read.list.Index(), m.attr, m.sdk), nil + // return InitLabelUpdate(m.read.list.Items()[m.read.list.Index()].(LabelItem), m.attr, m.sdk), nil case "c": // create new label return m, nil diff --git a/tui/labelUpdate.go b/tui/labelUpdate.go index 86499250..0e8c913b 100644 --- a/tui/labelUpdate.go +++ b/tui/labelUpdate.go @@ -3,6 +3,7 @@ package tui import ( tea "github.com/charmbracelet/bubbletea" "github.com/opentdf/otdfctl/pkg/handlers" + "github.com/opentdf/platform/protocol/go/common" "github.com/opentdf/platform/protocol/go/policy" ) @@ -12,7 +13,8 @@ type LabelUpdate struct { sdk handlers.Handler } -func InitLabelUpdate(label LabelItem, attr *policy.Attribute, sdk handlers.Handler) LabelUpdate { +func InitLabelUpdate(labelIdx int, attr *policy.Attribute, sdk handlers.Handler) LabelUpdate { + // label := attr.Metadata.Labels[labelIdx] return LabelUpdate{ update: InitUpdate([]string{"Key", "Value"}, []string{label.title, label.description}), attr: attr, @@ -31,7 +33,15 @@ func (m LabelUpdate) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case "enter": // return InitLabelList(m.attr, m.sdk) if m.update.focusIndex == len(m.update.inputs) { - return InitLabelList(m.attr, m.sdk) + // update the label + metadata := common.MetadataMutable{Labels: map[string]string{"abc": "def"}} + behavior := common.MetadataUpdateEnum_METADATA_UPDATE_ENUM_REPLACE + // behavior := common.MetadataUpdateEnum_METADATA_UPDATE_ENUM_EXTEND + attr, err := m.sdk.UpdateAttribute(m.attr.Id, metadata, behavior) + if err != nil { + // return error view + } + return InitLabelList(attr, m.sdk) } } } From 242001a04383f536822609e5543f3ae8452c6ae1 Mon Sep 17 00:00:00 2001 From: Krish Suchak Date: Tue, 14 May 2024 18:27:22 -0400 Subject: [PATCH 17/25] successful update --- tui/labelList.go | 4 ++-- tui/labelUpdate.go | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/tui/labelList.go b/tui/labelList.go index 7946332f..6e541b22 100644 --- a/tui/labelList.go +++ b/tui/labelList.go @@ -64,8 +64,8 @@ func (m LabelList) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case "ctrl+c", "q", "esc": return m, tea.Quit case "enter", "e": - return InitLabelUpdate(m.read.list.Index(), m.attr, m.sdk), nil - // return InitLabelUpdate(m.read.list.Items()[m.read.list.Index()].(LabelItem), m.attr, m.sdk), nil + // return InitLabelUpdate(m.read.list.Index(), m.attr, m.sdk), nil + return InitLabelUpdate(m.read.list.Items()[m.read.list.Index()].(LabelItem), m.attr, m.sdk), nil case "c": // create new label return m, nil diff --git a/tui/labelUpdate.go b/tui/labelUpdate.go index 0e8c913b..3e3600a3 100644 --- a/tui/labelUpdate.go +++ b/tui/labelUpdate.go @@ -8,14 +8,16 @@ import ( ) type LabelUpdate struct { + label LabelItem update Update attr *policy.Attribute sdk handlers.Handler } -func InitLabelUpdate(labelIdx int, attr *policy.Attribute, sdk handlers.Handler) LabelUpdate { +func InitLabelUpdate(label LabelItem, attr *policy.Attribute, sdk handlers.Handler) LabelUpdate { // label := attr.Metadata.Labels[labelIdx] return LabelUpdate{ + label: label, update: InitUpdate([]string{"Key", "Value"}, []string{label.title, label.description}), attr: attr, sdk: sdk, @@ -34,7 +36,16 @@ func (m LabelUpdate) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // return InitLabelList(m.attr, m.sdk) if m.update.focusIndex == len(m.update.inputs) { // update the label - metadata := common.MetadataMutable{Labels: map[string]string{"abc": "def"}} + metadata := &common.MetadataMutable{Labels: m.attr.Metadata.Labels} + oldKey := m.label.title + // oldVal := m.label.description + newKey := m.update.inputs[0].Value() + newVal := m.update.inputs[1].Value() + if oldKey != newKey { + delete(metadata.Labels, oldKey) + } + metadata.Labels[newKey] = newVal + // metadata := common.MetadataMutable{Labels: map[string]string{"abc": "def"}} behavior := common.MetadataUpdateEnum_METADATA_UPDATE_ENUM_REPLACE // behavior := common.MetadataUpdateEnum_METADATA_UPDATE_ENUM_EXTEND attr, err := m.sdk.UpdateAttribute(m.attr.Id, metadata, behavior) From 6ad96fdefe43e6f3b5942646d203782d5d260bab Mon Sep 17 00:00:00 2001 From: Krish Suchak Date: Tue, 14 May 2024 19:07:12 -0400 Subject: [PATCH 18/25] create new label --- tui/labelList.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tui/labelList.go b/tui/labelList.go index 6e541b22..792105f7 100644 --- a/tui/labelList.go +++ b/tui/labelList.go @@ -67,14 +67,15 @@ func (m LabelList) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // return InitLabelUpdate(m.read.list.Index(), m.attr, m.sdk), nil return InitLabelUpdate(m.read.list.Items()[m.read.list.Index()].(LabelItem), m.attr, m.sdk), nil case "c": - // create new label - return m, nil + return InitLabelUpdate(LabelItem{}, m.attr, m.sdk), nil case "d": // delete label return m, nil } } - return m, nil + var cmd tea.Cmd + m.read.list, cmd = m.read.list.Update(msg) + return m, cmd } func (m LabelList) View() string { From ace1b707001da4d4e0cc323c8820f479e2b6273b Mon Sep 17 00:00:00 2001 From: Krish Suchak Date: Wed, 15 May 2024 11:16:23 -0400 Subject: [PATCH 19/25] clean up --- tui/labelList.go | 1 - 1 file changed, 1 deletion(-) diff --git a/tui/labelList.go b/tui/labelList.go index 792105f7..196d60d3 100644 --- a/tui/labelList.go +++ b/tui/labelList.go @@ -64,7 +64,6 @@ func (m LabelList) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case "ctrl+c", "q", "esc": return m, tea.Quit case "enter", "e": - // return InitLabelUpdate(m.read.list.Index(), m.attr, m.sdk), nil return InitLabelUpdate(m.read.list.Items()[m.read.list.Index()].(LabelItem), m.attr, m.sdk), nil case "c": return InitLabelUpdate(LabelItem{}, m.attr, m.sdk), nil From df2f95cfc70652afaf72a311714f9003cc3e0ab2 Mon Sep 17 00:00:00 2001 From: Krish Suchak Date: Wed, 15 May 2024 11:18:37 -0400 Subject: [PATCH 20/25] clean up update.go --- tui/update.go | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/tui/update.go b/tui/update.go index 4fe61755..069c83af 100644 --- a/tui/update.go +++ b/tui/update.go @@ -30,14 +30,12 @@ type Update struct { inputs []textinput.Model cursorMode cursor.Mode keys []string - // vals []string } func InitUpdate(keys []string, vals []string) Update { m := Update{ inputs: make([]textinput.Model, len(keys)), keys: keys, - // vals: vals, } var t textinput.Model @@ -51,20 +49,6 @@ func InitUpdate(keys []string, vals []string) Update { t.PromptStyle = focusedStyle t.TextStyle = focusedStyle } - // switch i { - // case 0: - // t.Placeholder = "Nickname" - // t.Focus() - // t.PromptStyle = focusedStyle - // t.TextStyle = focusedStyle - // case 1: - // t.Placeholder = "Email" - // t.CharLimit = 64 - // case 2: - // t.Placeholder = "Password" - // t.EchoMode = textinput.EchoPassword - // t.EchoCharacter = '•' - // } m.inputs[i] = t } @@ -103,9 +87,6 @@ func (m Update) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // If so, exit. if s == "enter" && m.focusIndex == len(m.inputs) { return m, nil - // type updateMsg string - // a := interface{}(nil) - // return m, "abc".(tea.Cmd) } // Cycle indexes From 2855378019a372fa7c4da9e0186795a911cdd6a2 Mon Sep 17 00:00:00 2001 From: Krish Suchak Date: Wed, 15 May 2024 11:20:50 -0400 Subject: [PATCH 21/25] clean up read.go --- tui/read.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tui/read.go b/tui/read.go index 249338d0..ac5f1167 100644 --- a/tui/read.go +++ b/tui/read.go @@ -23,18 +23,18 @@ func (m Read) Init() tea.Cmd { } func (m Read) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - // switch msg := msg.(type) { - // case tea.WindowSizeMsg: - // constants.WindowSize = msg - // m.list.SetSize(msg.Width, msg.Height) - // m.width = msg.Width - // return m, nil - // case tea.KeyMsg: - // switch msg.Type { - // case tea.KeyCtrlC, tea.KeyEsc: - // return m, tea.Quit - // } - // } + switch msg := msg.(type) { + case tea.WindowSizeMsg: + constants.WindowSize = msg + m.list.SetSize(msg.Width, msg.Height) + m.width = msg.Width + return m, nil + case tea.KeyMsg: + switch msg.Type { + case tea.KeyCtrlC, tea.KeyEsc: + return m, tea.Quit + } + } return m, nil } From 37a3ef313f68e331441b2a25e3639bdc890e8609 Mon Sep 17 00:00:00 2001 From: Krish Suchak Date: Wed, 15 May 2024 11:21:41 -0400 Subject: [PATCH 22/25] clean up labelUpdate.go --- tui/labelUpdate.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tui/labelUpdate.go b/tui/labelUpdate.go index 3e3600a3..c831a7ea 100644 --- a/tui/labelUpdate.go +++ b/tui/labelUpdate.go @@ -15,7 +15,6 @@ type LabelUpdate struct { } func InitLabelUpdate(label LabelItem, attr *policy.Attribute, sdk handlers.Handler) LabelUpdate { - // label := attr.Metadata.Labels[labelIdx] return LabelUpdate{ label: label, update: InitUpdate([]string{"Key", "Value"}, []string{label.title, label.description}), @@ -33,21 +32,17 @@ func (m LabelUpdate) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case tea.KeyMsg: switch msg.String() { case "enter": - // return InitLabelList(m.attr, m.sdk) if m.update.focusIndex == len(m.update.inputs) { // update the label metadata := &common.MetadataMutable{Labels: m.attr.Metadata.Labels} oldKey := m.label.title - // oldVal := m.label.description newKey := m.update.inputs[0].Value() newVal := m.update.inputs[1].Value() if oldKey != newKey { delete(metadata.Labels, oldKey) } metadata.Labels[newKey] = newVal - // metadata := common.MetadataMutable{Labels: map[string]string{"abc": "def"}} behavior := common.MetadataUpdateEnum_METADATA_UPDATE_ENUM_REPLACE - // behavior := common.MetadataUpdateEnum_METADATA_UPDATE_ENUM_EXTEND attr, err := m.sdk.UpdateAttribute(m.attr.Id, metadata, behavior) if err != nil { // return error view From 72fc47615ce7b760308e9d2949a45e1001da5b08 Mon Sep 17 00:00:00 2001 From: Krish Suchak Date: Wed, 15 May 2024 11:22:09 -0400 Subject: [PATCH 23/25] clean up labelList.go --- tui/labelList.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/tui/labelList.go b/tui/labelList.go index 196d60d3..d067d030 100644 --- a/tui/labelList.go +++ b/tui/labelList.go @@ -8,8 +8,6 @@ import ( "github.com/opentdf/platform/protocol/go/policy" ) -// func (m LabelList) - type LabelList struct { attr *policy.Attribute sdk handlers.Handler From e474ce29a1c7aba1d7e2a95ccaf88dcad2579742 Mon Sep 17 00:00:00 2001 From: Krish Suchak Date: Wed, 15 May 2024 11:22:59 -0400 Subject: [PATCH 24/25] clean up attributeView.go --- tui/attributeView.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tui/attributeView.go b/tui/attributeView.go index 0b1aeb31..5aeecc03 100644 --- a/tui/attributeView.go +++ b/tui/attributeView.go @@ -37,10 +37,6 @@ func InitAttributeView(id string, h handlers.Handler) (AttributeView, tea.Cmd) { if err != nil { // return error view } - // var vals []string - // for _, val := range attr.Values { - // vals = append(vals, val.Value) - // } sa := cli.GetSimpleAttribute(attr) items := []list.Item{ AttributeSubItem{title: "ID", description: sa.Id}, @@ -81,9 +77,6 @@ func (m AttributeView) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case "enter": if m.read.list.SelectedItem().(AttributeSubItem).title == "Labels" { return InitLabelList(m.attr, m.sdk) - // list values - // vl, cmd := InitAttributeValueList(m.attr.Id, m.sdk) - // return vl, cmd } // case "enter": // switch m.list.SelectedItem().(AttributeItem).id { From e37aadcc1c99da896f7aa3e61ca55682baa61940 Mon Sep 17 00:00:00 2001 From: Krish Suchak Date: Wed, 15 May 2024 11:24:37 -0400 Subject: [PATCH 25/25] clean up attributeList.go --- tui/attributeList.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tui/attributeList.go b/tui/attributeList.go index 1a4fbb07..9bca3bde 100644 --- a/tui/attributeList.go +++ b/tui/attributeList.go @@ -11,8 +11,7 @@ import ( type AttributeList struct { list list.Model - // width int - sdk handlers.Handler + sdk handlers.Handler } type AttributeItem struct { @@ -49,11 +48,8 @@ func InitAttributeList(id string, sdk handlers.Handler) (tea.Model, tea.Cmd) { selectIdx = i } item := AttributeItem{ - id: attr.Id, - // namespace: attr.Namespace.Name, + id: attr.Id, name: attr.Name, - // rule: attr.Rule.String(), - // values: vals, } attrs = append(attrs, item) } @@ -87,7 +83,6 @@ func (m AttributeList) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case tea.WindowSizeMsg: constants.WindowSize = msg m.list.SetSize(msg.Width, msg.Height) - // m.width = msg.Width return m, nil case tea.KeyMsg: switch msg.String() {