issue-8: added going forward in backstack and restoring last view

This commit is contained in:
Leon Mika 2022-08-23 22:32:27 +10:00
parent 1109f2c9ee
commit 4c187ebb4d
9 changed files with 204 additions and 50 deletions

View file

@ -77,7 +77,7 @@ func main() {
itemRendererService := itemrenderer.NewService(uiStyles.ItemView.FieldType, uiStyles.ItemView.MetaInfo) itemRendererService := itemrenderer.NewService(uiStyles.ItemView.FieldType, uiStyles.ItemView.MetaInfo)
state := controllers.NewState() state := controllers.NewState()
tableReadController := controllers.NewTableReadController(state, tableService, workspaceService, itemRendererService, *flagTable) tableReadController := controllers.NewTableReadController(state, tableService, workspaceService, itemRendererService, *flagTable, true)
tableWriteController := controllers.NewTableWriteController(state, tableService, tableReadController) tableWriteController := controllers.NewTableWriteController(state, tableService, tableReadController)
commandController := commandctrl.NewCommandController() commandController := commandctrl.NewCommandController()

View file

@ -8,6 +8,7 @@ import (
"github.com/lmika/audax/internal/common/ui/events" "github.com/lmika/audax/internal/common/ui/events"
"github.com/lmika/audax/internal/dynamo-browse/models" "github.com/lmika/audax/internal/dynamo-browse/models"
"github.com/lmika/audax/internal/dynamo-browse/models/queryexpr" "github.com/lmika/audax/internal/dynamo-browse/models/queryexpr"
"github.com/lmika/audax/internal/dynamo-browse/models/serialisable"
"github.com/lmika/audax/internal/dynamo-browse/services/itemrenderer" "github.com/lmika/audax/internal/dynamo-browse/services/itemrenderer"
"github.com/lmika/audax/internal/dynamo-browse/services/workspaces" "github.com/lmika/audax/internal/dynamo-browse/services/workspaces"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -23,6 +24,7 @@ type TableReadController struct {
workspaceService *workspaces.ViewSnapshotService workspaceService *workspaces.ViewSnapshotService
itemRendererService *itemrenderer.Service itemRendererService *itemrenderer.Service
tableName string tableName string
loadFromLastView bool
// state // state
mutex *sync.Mutex mutex *sync.Mutex
@ -36,6 +38,7 @@ func NewTableReadController(
workspaceService *workspaces.ViewSnapshotService, workspaceService *workspaces.ViewSnapshotService,
itemRendererService *itemrenderer.Service, itemRendererService *itemrenderer.Service,
tableName string, tableName string,
loadFromLastView bool,
) *TableReadController { ) *TableReadController {
return &TableReadController{ return &TableReadController{
state: state, state: state,
@ -49,6 +52,13 @@ func NewTableReadController(
// Init does an initial scan of the table. If no table is specified, it prompts for a table, then does a scan. // Init does an initial scan of the table. If no table is specified, it prompts for a table, then does a scan.
func (c *TableReadController) Init() tea.Msg { func (c *TableReadController) Init() tea.Msg {
// Restore previous view
if c.loadFromLastView {
if vs, err := c.workspaceService.ViewRestore(); err == nil && vs != nil {
return c.updateViewToSnapshot(vs)
}
}
if c.tableName == "" { if c.tableName == "" {
return c.ListTables() return c.ListTables()
} else { } else {
@ -234,15 +244,39 @@ func (c *TableReadController) Filter() tea.Msg {
} }
func (c *TableReadController) ViewBack() tea.Msg { func (c *TableReadController) ViewBack() tea.Msg {
viewSnapshot, err := c.workspaceService.PopSnapshot() viewSnapshot, err := c.workspaceService.ViewBack()
if err != nil { if err != nil {
return events.Error(err) return events.Error(err)
} else if viewSnapshot == nil { } else if viewSnapshot == nil {
return events.StatusMsg("Backstack is empty") return events.StatusMsg("Backstack is empty")
} }
return c.updateViewToSnapshot(viewSnapshot)
}
func (c *TableReadController) ViewForward() tea.Msg {
viewSnapshot, err := c.workspaceService.ViewForward()
if err != nil {
return events.Error(err)
} else if viewSnapshot == nil {
return events.StatusMsg("At top of view stack")
}
return c.updateViewToSnapshot(viewSnapshot)
}
func (c *TableReadController) updateViewToSnapshot(viewSnapshot *serialisable.ViewSnapshot) tea.Msg {
var err error
currentResultSet := c.state.ResultSet() currentResultSet := c.state.ResultSet()
if currentResultSet == nil {
tableInfo, err := c.tableService.Describe(context.Background(), viewSnapshot.TableName)
if err != nil {
return events.Error(err)
}
return c.runQuery(tableInfo, viewSnapshot.Query, viewSnapshot.Filter, false)
}
var currentQueryExpr string var currentQueryExpr string
if currentResultSet.Query != nil { if currentResultSet.Query != nil {
currentQueryExpr = currentResultSet.Query.String() currentQueryExpr = currentResultSet.Query.String()

View file

@ -29,7 +29,7 @@ func TestTableReadController_InitTable(t *testing.T) {
service := tables.NewService(provider) service := tables.NewService(provider)
t.Run("should prompt for table if no table name provided", func(t *testing.T) { t.Run("should prompt for table if no table name provided", func(t *testing.T) {
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "") readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "", false)
event := readController.Init() event := readController.Init()
@ -37,7 +37,7 @@ func TestTableReadController_InitTable(t *testing.T) {
}) })
t.Run("should scan table if table name provided", func(t *testing.T) { t.Run("should scan table if table name provided", func(t *testing.T) {
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "") readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "", false)
event := readController.Init() event := readController.Init()
@ -54,7 +54,7 @@ func TestTableReadController_ListTables(t *testing.T) {
provider := dynamo.NewProvider(client) provider := dynamo.NewProvider(client)
service := tables.NewService(provider) service := tables.NewService(provider)
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "") readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "", false)
t.Run("returns a list of tables", func(t *testing.T) { t.Run("returns a list of tables", func(t *testing.T) {
event := readController.ListTables().(controllers.PromptForTableMsg) event := readController.ListTables().(controllers.PromptForTableMsg)
@ -80,7 +80,7 @@ func TestTableReadController_Rescan(t *testing.T) {
provider := dynamo.NewProvider(client) provider := dynamo.NewProvider(client)
service := tables.NewService(provider) service := tables.NewService(provider)
state := controllers.NewState() state := controllers.NewState()
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "bravo-table") readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "bravo-table", false)
t.Run("should perform a rescan", func(t *testing.T) { t.Run("should perform a rescan", func(t *testing.T) {
invokeCommand(t, readController.Init()) invokeCommand(t, readController.Init())
@ -117,7 +117,7 @@ func TestTableReadController_ExportCSV(t *testing.T) {
provider := dynamo.NewProvider(client) provider := dynamo.NewProvider(client)
service := tables.NewService(provider) service := tables.NewService(provider)
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "bravo-table") readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "bravo-table", false)
t.Run("should export result set to CSV file", func(t *testing.T) { t.Run("should export result set to CSV file", func(t *testing.T) {
tempFile := tempFile(t) tempFile := tempFile(t)
@ -138,7 +138,7 @@ func TestTableReadController_ExportCSV(t *testing.T) {
t.Run("should return error if result set is not set", func(t *testing.T) { t.Run("should return error if result set is not set", func(t *testing.T) {
tempFile := tempFile(t) tempFile := tempFile(t)
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "non-existant-table") readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "non-existant-table", false)
invokeCommandExpectingError(t, readController.Init()) invokeCommandExpectingError(t, readController.Init())
invokeCommandExpectingError(t, readController.ExportCSV(tempFile)) invokeCommandExpectingError(t, readController.ExportCSV(tempFile))
@ -156,7 +156,7 @@ func TestTableReadController_Query(t *testing.T) {
provider := dynamo.NewProvider(client) provider := dynamo.NewProvider(client)
service := tables.NewService(provider) service := tables.NewService(provider)
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "bravo-table") readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "bravo-table", false)
t.Run("should run scan with filter based on user query", func(t *testing.T) { t.Run("should run scan with filter based on user query", func(t *testing.T) {
tempFile := tempFile(t) tempFile := tempFile(t)
@ -176,7 +176,7 @@ func TestTableReadController_Query(t *testing.T) {
t.Run("should return error if result set is not set", func(t *testing.T) { t.Run("should return error if result set is not set", func(t *testing.T) {
tempFile := tempFile(t) tempFile := tempFile(t)
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "non-existant-table") readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "non-existant-table", false)
invokeCommandExpectingError(t, readController.Init()) invokeCommandExpectingError(t, readController.Init())
invokeCommandExpectingError(t, readController.ExportCSV(tempFile)) invokeCommandExpectingError(t, readController.ExportCSV(tempFile))

View file

@ -27,7 +27,7 @@ func TestTableWriteController_NewItem(t *testing.T) {
service := tables.NewService(provider) service := tables.NewService(provider)
state := controllers.NewState() state := controllers.NewState()
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table") readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
writeController := controllers.NewTableWriteController(state, service, readController) writeController := controllers.NewTableWriteController(state, service, readController)
invokeCommand(t, readController.Init()) invokeCommand(t, readController.Init())
@ -91,7 +91,7 @@ func TestTableWriteController_SetAttributeValue(t *testing.T) {
service := tables.NewService(provider) service := tables.NewService(provider)
state := controllers.NewState() state := controllers.NewState()
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table") readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
writeController := controllers.NewTableWriteController(state, service, readController) writeController := controllers.NewTableWriteController(state, service, readController)
invokeCommand(t, readController.Init()) invokeCommand(t, readController.Init())
@ -111,7 +111,7 @@ func TestTableWriteController_SetAttributeValue(t *testing.T) {
service := tables.NewService(provider) service := tables.NewService(provider)
state := controllers.NewState() state := controllers.NewState()
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table") readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
writeController := controllers.NewTableWriteController(state, service, readController) writeController := controllers.NewTableWriteController(state, service, readController)
invokeCommand(t, readController.Init()) invokeCommand(t, readController.Init())
@ -165,7 +165,7 @@ func TestTableWriteController_SetAttributeValue(t *testing.T) {
for _, scenario := range scenarios { for _, scenario := range scenarios {
t.Run(fmt.Sprintf("should change the value of a field to type %v", scenario.attrType), func(t *testing.T) { t.Run(fmt.Sprintf("should change the value of a field to type %v", scenario.attrType), func(t *testing.T) {
state := controllers.NewState() state := controllers.NewState()
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table") readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
writeController := controllers.NewTableWriteController(state, service, readController) writeController := controllers.NewTableWriteController(state, service, readController)
invokeCommand(t, readController.Init()) invokeCommand(t, readController.Init())
@ -186,7 +186,7 @@ func TestTableWriteController_SetAttributeValue(t *testing.T) {
t.Run(fmt.Sprintf("should change value of nested field to type %v", scenario.attrType), func(t *testing.T) { t.Run(fmt.Sprintf("should change value of nested field to type %v", scenario.attrType), func(t *testing.T) {
state := controllers.NewState() state := controllers.NewState()
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table") readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
writeController := controllers.NewTableWriteController(state, service, readController) writeController := controllers.NewTableWriteController(state, service, readController)
invokeCommand(t, readController.Init()) invokeCommand(t, readController.Init())
@ -225,7 +225,7 @@ func TestTableWriteController_DeleteAttribute(t *testing.T) {
t.Run("should delete top level attribute", func(t *testing.T) { t.Run("should delete top level attribute", func(t *testing.T) {
state := controllers.NewState() state := controllers.NewState()
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table") readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
writeController := controllers.NewTableWriteController(state, service, readController) writeController := controllers.NewTableWriteController(state, service, readController)
invokeCommand(t, readController.Init()) invokeCommand(t, readController.Init())
@ -241,7 +241,7 @@ func TestTableWriteController_DeleteAttribute(t *testing.T) {
t.Run("should delete attribute of map", func(t *testing.T) { t.Run("should delete attribute of map", func(t *testing.T) {
state := controllers.NewState() state := controllers.NewState()
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table") readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
writeController := controllers.NewTableWriteController(state, service, readController) writeController := controllers.NewTableWriteController(state, service, readController)
invokeCommand(t, readController.Init()) invokeCommand(t, readController.Init())
@ -273,7 +273,7 @@ func TestTableWriteController_PutItem(t *testing.T) {
service := tables.NewService(provider) service := tables.NewService(provider)
state := controllers.NewState() state := controllers.NewState()
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table") readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
writeController := controllers.NewTableWriteController(state, service, readController) writeController := controllers.NewTableWriteController(state, service, readController)
// Read the table // Read the table
@ -300,7 +300,7 @@ func TestTableWriteController_PutItem(t *testing.T) {
service := tables.NewService(provider) service := tables.NewService(provider)
state := controllers.NewState() state := controllers.NewState()
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table") readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
writeController := controllers.NewTableWriteController(state, service, readController) writeController := controllers.NewTableWriteController(state, service, readController)
// Read the table // Read the table
@ -331,7 +331,7 @@ func TestTableWriteController_PutItem(t *testing.T) {
service := tables.NewService(provider) service := tables.NewService(provider)
state := controllers.NewState() state := controllers.NewState()
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table") readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
writeController := controllers.NewTableWriteController(state, service, readController) writeController := controllers.NewTableWriteController(state, service, readController)
// Read the table // Read the table
@ -356,7 +356,7 @@ func TestTableWriteController_PutItems(t *testing.T) {
service := tables.NewService(provider) service := tables.NewService(provider)
state := controllers.NewState() state := controllers.NewState()
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table") readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
writeController := controllers.NewTableWriteController(state, service, readController) writeController := controllers.NewTableWriteController(state, service, readController)
invokeCommand(t, readController.Init()) invokeCommand(t, readController.Init())
@ -384,7 +384,7 @@ func TestTableWriteController_PutItems(t *testing.T) {
service := tables.NewService(provider) service := tables.NewService(provider)
state := controllers.NewState() state := controllers.NewState()
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table") readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
writeController := controllers.NewTableWriteController(state, service, readController) writeController := controllers.NewTableWriteController(state, service, readController)
invokeCommand(t, readController.Init()) invokeCommand(t, readController.Init())
@ -420,7 +420,7 @@ func TestTableWriteController_PutItems(t *testing.T) {
service := tables.NewService(provider) service := tables.NewService(provider)
state := controllers.NewState() state := controllers.NewState()
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table") readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
writeController := controllers.NewTableWriteController(state, service, readController) writeController := controllers.NewTableWriteController(state, service, readController)
invokeCommand(t, readController.Init()) invokeCommand(t, readController.Init())
@ -462,7 +462,7 @@ func TestTableWriteController_TouchItem(t *testing.T) {
service := tables.NewService(provider) service := tables.NewService(provider)
state := controllers.NewState() state := controllers.NewState()
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table") readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
writeController := controllers.NewTableWriteController(state, service, readController) writeController := controllers.NewTableWriteController(state, service, readController)
// Read the table // Read the table
@ -488,7 +488,7 @@ func TestTableWriteController_TouchItem(t *testing.T) {
service := tables.NewService(provider) service := tables.NewService(provider)
state := controllers.NewState() state := controllers.NewState()
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table") readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
writeController := controllers.NewTableWriteController(state, service, readController) writeController := controllers.NewTableWriteController(state, service, readController)
// Read the table // Read the table
@ -515,7 +515,7 @@ func TestTableWriteController_NoisyTouchItem(t *testing.T) {
service := tables.NewService(provider) service := tables.NewService(provider)
state := controllers.NewState() state := controllers.NewState()
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table") readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
writeController := controllers.NewTableWriteController(state, service, readController) writeController := controllers.NewTableWriteController(state, service, readController)
// Read the table // Read the table
@ -541,7 +541,7 @@ func TestTableWriteController_NoisyTouchItem(t *testing.T) {
service := tables.NewService(provider) service := tables.NewService(provider)
state := controllers.NewState() state := controllers.NewState()
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table") readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table", false)
writeController := controllers.NewTableWriteController(state, service, readController) writeController := controllers.NewTableWriteController(state, service, readController)
// Read the table // Read the table

View file

@ -7,6 +7,7 @@ import (
type ViewSnapshot struct { type ViewSnapshot struct {
ID int64 `storm:"id,increment"` ID int64 `storm:"id,increment"`
BackLink int64 `storm:"index"` BackLink int64 `storm:"index"`
ForeLink int64 `storm:"index"`
Time time.Time Time time.Time
TableName string TableName string
Query string Query string

View file

@ -43,6 +43,55 @@ func (s *ResultSetSnapshotStore) SetAsHead(resultSetID int64) error {
return nil return nil
} }
func (s *ResultSetSnapshotStore) CurrentlyViewedSnapshot() (*serialisable.ViewSnapshot, error) {
var resultSetID int64
if err := s.ws.Get("viewIds", "current", &resultSetID); err != nil {
if errors.Is(err, storm.ErrNotFound) {
return nil, nil
}
return nil, errors.Wrap(err, "cannot get head")
}
var rss serialisable.ViewSnapshot
if err := s.ws.One("ID", resultSetID, &rss); err != nil {
if errors.Is(err, storm.ErrNotFound) {
return nil, nil
} else {
return nil, errors.Wrap(err, "cannot get head")
}
}
return &rss, nil
}
func (s *ResultSetSnapshotStore) SetCurrentlyViewedSnapshot(resultSetID int64) error {
if resultSetID == 0 {
if err := s.ws.Delete("viewIds", "current"); err != nil {
return errors.Wrap(err, "cannot remove head")
}
return nil
}
if err := s.ws.Set("viewIds", "current", resultSetID); err != nil {
return errors.Wrap(err, "cannot set as head")
}
return nil
}
func (s *ResultSetSnapshotStore) Find(resultSetID int64) (*serialisable.ViewSnapshot, error) {
var rss serialisable.ViewSnapshot
if err := s.ws.One("ID", resultSetID, &rss); err != nil {
if errors.Is(err, storm.ErrNotFound) {
return nil, nil
} else {
return nil, errors.Wrap(err, "cannot get head")
}
}
return &rss, nil
}
func (s *ResultSetSnapshotStore) Head() (*serialisable.ViewSnapshot, error) { func (s *ResultSetSnapshotStore) Head() (*serialisable.ViewSnapshot, error) {
var headResultSetID int64 var headResultSetID int64
if err := s.ws.Get("head", "id", &headResultSetID); err != nil && !errors.Is(err, storm.ErrNotFound) { if err := s.ws.Get("head", "id", &headResultSetID); err != nil && !errors.Is(err, storm.ErrNotFound) {
@ -61,6 +110,23 @@ func (s *ResultSetSnapshotStore) Head() (*serialisable.ViewSnapshot, error) {
return &rss, nil return &rss, nil
} }
func (s *ResultSetSnapshotStore) Dehead(fromNode *serialisable.ViewSnapshot) error {
n := fromNode.ForeLink
for n != 0 {
node, err := s.Find(n)
if err != nil {
return errors.Wrapf(err, "cannot get node with ID: %v", n)
} else if node == nil {
return errors.Errorf("expected node with ID %v, but did not find it", n)
}
if err := s.Remove(node.ID); err != nil {
log.Printf("warn: cannot delete node with ID %v", node.ID)
}
n = node.ForeLink
}
return nil
}
func (s *ResultSetSnapshotStore) Remove(resultSetId int64) error { func (s *ResultSetSnapshotStore) Remove(resultSetId int64) error {
var rss serialisable.ViewSnapshot var rss serialisable.ViewSnapshot
if err := s.ws.One("ID", resultSetId, &rss); err != nil { if err := s.ws.One("ID", resultSetId, &rss); err != nil {

View file

@ -5,6 +5,10 @@ import "github.com/lmika/audax/internal/dynamo-browse/models/serialisable"
type ViewSnapshotStore interface { type ViewSnapshotStore interface {
Save(rs *serialisable.ViewSnapshot) error Save(rs *serialisable.ViewSnapshot) error
SetAsHead(resultSetId int64) error SetAsHead(resultSetId int64) error
CurrentlyViewedSnapshot() (*serialisable.ViewSnapshot, error)
SetCurrentlyViewedSnapshot(resultSetId int64) error
Find(resultSetID int64) (*serialisable.ViewSnapshot, error)
Head() (*serialisable.ViewSnapshot, error) Head() (*serialisable.ViewSnapshot, error)
Remove(resultSetId int64) error Remove(resultSetId int64) error
Dehead(fromNode *serialisable.ViewSnapshot) error
} }

View file

@ -27,43 +27,89 @@ func (s *ViewSnapshotService) PushSnapshot(rs *models.ResultSet, filter string)
} }
newSnapshot.Filter = filter newSnapshot.Filter = filter
if head, err := s.store.Head(); head != nil { oldHead, err := s.store.CurrentlyViewedSnapshot()
newSnapshot.BackLink = head.ID if err != nil {
} else if err != nil { return errors.Wrap(err, "cannot get snapshot head")
return errors.Wrap(err, "cannot get head result set") }
if oldHead != nil {
newSnapshot.BackLink = oldHead.ID
// Remove all nodes from this point on the head
if err := s.store.Dehead(oldHead); err != nil {
return errors.Wrap(err, "cannot remove head")
}
} }
if err := s.store.Save(newSnapshot); err != nil { if err := s.store.Save(newSnapshot); err != nil {
return errors.Wrap(err, "cannot save snapshot") return errors.Wrap(err, "cannot save snapshot")
} }
if oldHead != nil {
oldHead.ForeLink = newSnapshot.ID
if err := s.store.Save(oldHead); err != nil {
return errors.Wrap(err, "cannot update old head")
}
}
if err := s.store.SetAsHead(newSnapshot.ID); err != nil { if err := s.store.SetAsHead(newSnapshot.ID); err != nil {
return errors.Wrap(err, "cannot set new snapshot as head") return errors.Wrap(err, "cannot set new snapshot as head")
} }
if err := s.store.SetCurrentlyViewedSnapshot(newSnapshot.ID); err != nil {
return errors.Wrap(err, "cannot set new snapshot as head")
}
return nil return nil
} }
func (s *ViewSnapshotService) PopSnapshot() (*serialisable.ViewSnapshot, error) { func (s *ViewSnapshotService) ViewRestore() (*serialisable.ViewSnapshot, error) {
vs, err := s.store.Head() vs, err := s.store.CurrentlyViewedSnapshot()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "cannot get snapshot head") return nil, errors.Wrap(err, "cannot get snapshot head")
} else if vs == nil || vs.BackLink == 0 {
return nil, nil
} }
if err := s.store.SetAsHead(vs.BackLink); err != nil {
return nil, errors.Wrap(err, "cannot set new head")
}
if err := s.store.Remove(vs.ID); err != nil {
return nil, errors.Wrap(err, "cannot remove old ID")
}
vs, err = s.store.Head()
if err != nil {
return nil, errors.Wrap(err, "cannot get snapshot head")
} else if vs == nil || vs.BackLink == 0 {
return nil, nil
}
return vs, nil return vs, nil
} }
func (s *ViewSnapshotService) ViewBack() (*serialisable.ViewSnapshot, error) {
vs, err := s.store.CurrentlyViewedSnapshot()
if err != nil {
return nil, errors.Wrap(err, "cannot get snapshot head")
} else if vs == nil || vs.BackLink == 0 {
return nil, nil
}
vsToReturn, err := s.store.Find(vs.BackLink)
if err != nil {
return nil, errors.Wrap(err, "cannot get snapshot head")
} else if vsToReturn == nil {
return nil, nil
}
if err := s.store.SetCurrentlyViewedSnapshot(vsToReturn.ID); err != nil {
return nil, errors.Wrap(err, "cannot set new head")
}
return vsToReturn, nil
}
func (s *ViewSnapshotService) ViewForward() (*serialisable.ViewSnapshot, error) {
vs, err := s.store.CurrentlyViewedSnapshot()
if err != nil {
return nil, errors.Wrap(err, "cannot get snapshot head")
} else if vs == nil || vs.ForeLink == 0 {
return nil, nil
}
vsToReturn, err := s.store.Find(vs.ForeLink)
if err != nil {
return nil, errors.Wrap(err, "cannot get snapshot head")
} else if vsToReturn == nil {
return nil, nil
}
if err := s.store.SetCurrentlyViewedSnapshot(vsToReturn.ID); err != nil {
return nil, errors.Wrap(err, "cannot set new head")
}
return vsToReturn, nil
}

View file

@ -163,6 +163,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, m.tableView.Refresh() return m, m.tableView.Refresh()
case tea.KeyMsg: case tea.KeyMsg:
if !m.statusAndPrompt.InPrompt() && !m.tableSelect.Visible() { if !m.statusAndPrompt.InPrompt() && !m.tableSelect.Visible() {
log.Printf("key = %+v", msg)
switch msg.String() { switch msg.String() {
case "m": case "m":
if idx := m.tableView.SelectedItemIndex(); idx >= 0 { if idx := m.tableView.SelectedItemIndex(); idx >= 0 {
@ -180,6 +181,8 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, m.tableReadController.Filter return m, m.tableReadController.Filter
case "backspace": case "backspace":
return m, m.tableReadController.ViewBack return m, m.tableReadController.ViewBack
case "\\":
return m, m.tableReadController.ViewForward
case "w": case "w":
return m, func() tea.Msg { return m, func() tea.Msg {
return controllers.SetTableItemView{ViewIndex: utils.Cycle(m.mainViewIndex, 1, ViewModeCount)} return controllers.SetTableItemView{ViewIndex: utils.Cycle(m.mainViewIndex, 1, ViewModeCount)}