From c3d19d5891d7316ce0e49a2d28520adc6318d1a8 Mon Sep 17 00:00:00 2001
From: Leon Mika <lmika@lmika.org>
Date: Sun, 27 Mar 2022 21:43:53 +0000
Subject: [PATCH] Have got the item view working

---
 cmd/dynamo-browse/main.go                     |  3 +-
 .../ui/teamodels/dynamoitemview/events.go     |  8 ++
 .../ui/teamodels/dynamoitemview/model.go      | 89 +++++++++++++++++++
 .../ui/teamodels/dynamotableview/model.go     | 16 +++-
 4 files changed, 112 insertions(+), 4 deletions(-)
 create mode 100644 internal/dynamo-browse/ui/teamodels/dynamoitemview/events.go
 create mode 100644 internal/dynamo-browse/ui/teamodels/dynamoitemview/model.go

diff --git a/cmd/dynamo-browse/main.go b/cmd/dynamo-browse/main.go
index 803afd4..ee61135 100644
--- a/cmd/dynamo-browse/main.go
+++ b/cmd/dynamo-browse/main.go
@@ -21,6 +21,7 @@ import (
 	"github.com/lmika/awstools/internal/dynamo-browse/services/tables"
 	"github.com/lmika/awstools/internal/dynamo-browse/ui"
 	"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels"
+	"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/dynamoitemview"
 	"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/dynamotableview"
 	"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/frame"
 	"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/layout"
@@ -81,7 +82,7 @@ func main() {
 		layout.NewVBox(
 			layout.LastChildFixedAt(11),
 			frame.NewFrame("This is the header", true, dynamotableview.New(tableReadController)),
-			frame.NewFrame("This is another header", false, layout.Model(newTestModel("this is the bottom"))),
+			frame.NewFrame("This is another header", false, dynamoitemview.New()),
 		),
 		"Hello world",
 	)
diff --git a/internal/dynamo-browse/ui/teamodels/dynamoitemview/events.go b/internal/dynamo-browse/ui/teamodels/dynamoitemview/events.go
new file mode 100644
index 0000000..c3db12a
--- /dev/null
+++ b/internal/dynamo-browse/ui/teamodels/dynamoitemview/events.go
@@ -0,0 +1,8 @@
+package dynamoitemview
+
+import "github.com/lmika/awstools/internal/dynamo-browse/models"
+
+type NewItemSelected struct {
+	ResultSet *models.ResultSet
+	Item      models.Item
+}
diff --git a/internal/dynamo-browse/ui/teamodels/dynamoitemview/model.go b/internal/dynamo-browse/ui/teamodels/dynamoitemview/model.go
new file mode 100644
index 0000000..6c962b7
--- /dev/null
+++ b/internal/dynamo-browse/ui/teamodels/dynamoitemview/model.go
@@ -0,0 +1,89 @@
+package dynamoitemview
+
+import (
+	"fmt"
+	"strings"
+	"text/tabwriter"
+
+	"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
+	"github.com/charmbracelet/bubbles/viewport"
+	tea "github.com/charmbracelet/bubbletea"
+	"github.com/lmika/awstools/internal/dynamo-browse/models"
+	"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/layout"
+)
+
+type Model struct {
+	ready    bool
+	viewport viewport.Model
+	w, h     int
+
+	// model state
+	currentResultSet *models.ResultSet
+	selectedItem     models.Item
+}
+
+func New() Model {
+	return Model{
+		viewport: viewport.New(100, 100),
+	}
+}
+
+func (Model) Init() tea.Cmd {
+	return nil
+}
+
+func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+	switch msg := msg.(type) {
+	case NewItemSelected:
+		m.currentResultSet = msg.ResultSet
+		m.selectedItem = msg.Item
+		m.updateViewportToSelectedMessage()
+		return m, nil
+	}
+	return m, nil
+}
+
+func (m Model) View() string {
+	if !m.ready {
+		return ""
+	}
+	return m.viewport.View()
+}
+
+func (m Model) Resize(w, h int) layout.ResizingModel {
+	m.w, m.h = w, h
+	if !m.ready {
+		m.viewport = viewport.New(w, h-1)
+		m.ready = true
+	} else {
+		m.viewport.Width = w
+		m.viewport.Height = h
+	}
+	return m
+}
+
+func (m *Model) updateViewportToSelectedMessage() {
+	if m.selectedItem == nil {
+		m.viewport.SetContent("")
+	}
+
+	viewportContent := &strings.Builder{}
+	tabWriter := tabwriter.NewWriter(viewportContent, 0, 1, 1, ' ', 0)
+	for _, colName := range m.currentResultSet.Columns {
+		switch colVal := m.selectedItem[colName].(type) {
+		case nil:
+			break
+		case *types.AttributeValueMemberS:
+			fmt.Fprintf(tabWriter, "%v\tS\t%s\n", colName, colVal.Value)
+		case *types.AttributeValueMemberN:
+			fmt.Fprintf(tabWriter, "%v\tN\t%s\n", colName, colVal.Value)
+		default:
+			fmt.Fprintf(tabWriter, "%v\t?\t%s\n", colName, "(other)")
+		}
+	}
+
+	tabWriter.Flush()
+	m.viewport.Width = m.w
+	m.viewport.Height = m.h
+	m.viewport.SetContent(viewportContent.String())
+}
diff --git a/internal/dynamo-browse/ui/teamodels/dynamotableview/model.go b/internal/dynamo-browse/ui/teamodels/dynamotableview/model.go
index 925d067..09b0d1b 100644
--- a/internal/dynamo-browse/ui/teamodels/dynamotableview/model.go
+++ b/internal/dynamo-browse/ui/teamodels/dynamotableview/model.go
@@ -5,6 +5,7 @@ import (
 	tea "github.com/charmbracelet/bubbletea"
 	"github.com/lmika/awstools/internal/dynamo-browse/controllers"
 	"github.com/lmika/awstools/internal/dynamo-browse/models"
+	"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/dynamoitemview"
 	"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/layout"
 )
 
@@ -34,16 +35,16 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	case controllers.NewResultSet:
 		m.resultSet = msg.ResultSet
 		m.updateTable()
-		return m, nil
+		return m, m.postSelectedItemChanged
 	case tea.KeyMsg:
 		switch msg.String() {
 		// Table nav
 		case "i", "up":
 			m.table.GoUp()
-			return m, nil
+			return m, m.postSelectedItemChanged
 		case "k", "down":
 			m.table.GoDown()
-			return m, nil
+			return m, m.postSelectedItemChanged
 
 		// TEMP
 		case "s":
@@ -91,6 +92,15 @@ func (m *Model) selectedItem() (itemTableRow, bool) {
 	return itemTableRow{}, false
 }
 
+func (m *Model) postSelectedItemChanged() tea.Msg {
+	item, ok := m.selectedItem()
+	if !ok {
+		return nil
+	}
+
+	return dynamoitemview.NewItemSelected{ResultSet: item.resultSet, Item: item.item}
+}
+
 /*
 func (m *Model) updateViewportToSelectedMessage() {
 	selectedItem, ok := m.selectedItem()