Merge pull request #13 from lmika/feature/issue-10
issue-10: copy item to clipboard
This commit is contained in:
commit
7e87b3e5a6
|
@ -15,9 +15,11 @@ import (
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/controllers"
|
"github.com/lmika/audax/internal/dynamo-browse/controllers"
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/providers/dynamo"
|
"github.com/lmika/audax/internal/dynamo-browse/providers/dynamo"
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/providers/workspacestore"
|
"github.com/lmika/audax/internal/dynamo-browse/providers/workspacestore"
|
||||||
|
"github.com/lmika/audax/internal/dynamo-browse/services/itemrenderer"
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/services/tables"
|
"github.com/lmika/audax/internal/dynamo-browse/services/tables"
|
||||||
workspaces_service "github.com/lmika/audax/internal/dynamo-browse/services/workspaces"
|
workspaces_service "github.com/lmika/audax/internal/dynamo-browse/services/workspaces"
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/ui"
|
"github.com/lmika/audax/internal/dynamo-browse/ui"
|
||||||
|
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/styles"
|
||||||
"github.com/lmika/gopkgs/cli"
|
"github.com/lmika/gopkgs/cli"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
@ -66,18 +68,20 @@ func main() {
|
||||||
dynamoClient = dynamodb.NewFromConfig(cfg)
|
dynamoClient = dynamodb.NewFromConfig(cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uiStyles := styles.DefaultStyles
|
||||||
dynamoProvider := dynamo.NewProvider(dynamoClient)
|
dynamoProvider := dynamo.NewProvider(dynamoClient)
|
||||||
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(ws)
|
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(ws)
|
||||||
|
|
||||||
tableService := tables.NewService(dynamoProvider)
|
tableService := tables.NewService(dynamoProvider)
|
||||||
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
||||||
|
itemRendererService := itemrenderer.NewService(uiStyles.ItemView.FieldType, uiStyles.ItemView.MetaInfo)
|
||||||
|
|
||||||
state := controllers.NewState()
|
state := controllers.NewState()
|
||||||
tableReadController := controllers.NewTableReadController(state, tableService, workspaceService, *flagTable)
|
tableReadController := controllers.NewTableReadController(state, tableService, workspaceService, itemRendererService, *flagTable)
|
||||||
tableWriteController := controllers.NewTableWriteController(state, tableService, tableReadController)
|
tableWriteController := controllers.NewTableWriteController(state, tableService, tableReadController)
|
||||||
|
|
||||||
commandController := commandctrl.NewCommandController()
|
commandController := commandctrl.NewCommandController()
|
||||||
model := ui.NewModel(tableReadController, tableWriteController, commandController)
|
model := ui.NewModel(tableReadController, tableWriteController, itemRendererService, commandController)
|
||||||
|
|
||||||
// Pre-determine if layout has dark background. This prevents calls for creating a list to hang.
|
// Pre-determine if layout has dark background. This prevents calls for creating a list to hang.
|
||||||
lipgloss.HasDarkBackground()
|
lipgloss.HasDarkBackground()
|
||||||
|
|
5
go.mod
5
go.mod
|
@ -25,6 +25,7 @@ require (
|
||||||
github.com/lmika/shellwords v0.0.0-20140714114018-ce258dd729fe
|
github.com/lmika/shellwords v0.0.0-20140714114018-ce258dd729fe
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/stretchr/testify v1.7.1
|
github.com/stretchr/testify v1.7.1
|
||||||
|
golang.design/x/clipboard v0.6.2
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
@ -61,6 +62,10 @@ require (
|
||||||
github.com/sahilm/fuzzy v0.1.0 // indirect
|
github.com/sahilm/fuzzy v0.1.0 // indirect
|
||||||
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
|
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
|
||||||
go.etcd.io/bbolt v1.3.6 // indirect
|
go.etcd.io/bbolt v1.3.6 // indirect
|
||||||
|
golang.design/x/clipboard v0.6.2 // indirect
|
||||||
|
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 // indirect
|
||||||
|
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 // indirect
|
||||||
|
golang.org/x/mobile v0.0.0-20210716004757-34ab1303b554 // indirect
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
|
||||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect
|
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
|
|
36
go.sum
36
go.sum
|
@ -1,3 +1,4 @@
|
||||||
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8=
|
github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8=
|
||||||
github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
|
github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
|
||||||
github.com/Sereal/Sereal v0.0.0-20220220040404-e0d1e550e879 h1:M5ptEKnqKqpFTKbe+p5zEf3ro1deJ6opUz5j3g3/ErQ=
|
github.com/Sereal/Sereal v0.0.0-20220220040404-e0d1e550e879 h1:M5ptEKnqKqpFTKbe+p5zEf3ro1deJ6opUz5j3g3/ErQ=
|
||||||
|
@ -146,29 +147,64 @@ github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMT
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
|
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
|
||||||
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
||||||
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
|
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
|
||||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||||
|
golang.design/x/clipboard v0.6.2 h1:a3Np4qfKnLWwfFJQhUWU3IDeRfmVuqWl+QPtP4CSYGw=
|
||||||
|
golang.design/x/clipboard v0.6.2/go.mod h1:kqBSweBP0/im4SZGGjLrppH0D400Hnfo5WbFKSNK8N4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 h1:estk1glOnSVeJ9tdEZZc5mAMDZk5lNJNyJ6DvrBkTEU=
|
||||||
|
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
|
||||||
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
|
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
|
||||||
|
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||||
|
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||||
|
golang.org/x/mobile v0.0.0-20210716004757-34ab1303b554 h1:3In5TnfvnuXTF/uflgpYxSCEGP2NdYT37KsPh3VjZYU=
|
||||||
|
golang.org/x/mobile v0.0.0-20210716004757-34ab1303b554/go.mod h1:jFTmtFYCV0MFtXBU+J5V/+5AUeVS0ON/0WkE/KSrl6E=
|
||||||
|
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||||
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65 h1:+rhAzEzT3f4JtomfC371qB+0Ola2caSKcY69NUBZrRQ=
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65 h1:+rhAzEzT3f4JtomfC371qB+0Ola2caSKcY69NUBZrRQ=
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 h1:CBpWXWQpIRjzmkkA+M7q9Fqnwd2mZr3AFqexg8YTfoM=
|
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 h1:CBpWXWQpIRjzmkkA+M7q9Fqnwd2mZr3AFqexg8YTfoM=
|
||||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
|
|
|
@ -3,34 +3,47 @@ package controllers
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/csv"
|
"encoding/csv"
|
||||||
|
"fmt"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"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/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"
|
||||||
|
"golang.design/x/clipboard"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TableReadController struct {
|
type TableReadController struct {
|
||||||
tableService TableReadService
|
tableService TableReadService
|
||||||
workspaceService *workspaces.ViewSnapshotService
|
workspaceService *workspaces.ViewSnapshotService
|
||||||
tableName string
|
itemRendererService *itemrenderer.Service
|
||||||
|
tableName string
|
||||||
|
|
||||||
// state
|
// state
|
||||||
mutex *sync.Mutex
|
mutex *sync.Mutex
|
||||||
state *State
|
state *State
|
||||||
|
clipboardInit bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTableReadController(state *State, tableService TableReadService, workspaceService *workspaces.ViewSnapshotService, tableName string) *TableReadController {
|
func NewTableReadController(
|
||||||
|
state *State,
|
||||||
|
tableService TableReadService,
|
||||||
|
workspaceService *workspaces.ViewSnapshotService,
|
||||||
|
itemRendererService *itemrenderer.Service,
|
||||||
|
tableName string,
|
||||||
|
) *TableReadController {
|
||||||
return &TableReadController{
|
return &TableReadController{
|
||||||
state: state,
|
state: state,
|
||||||
tableService: tableService,
|
tableService: tableService,
|
||||||
workspaceService: workspaceService,
|
workspaceService: workspaceService,
|
||||||
tableName: tableName,
|
itemRendererService: itemRendererService,
|
||||||
mutex: new(sync.Mutex),
|
tableName: tableName,
|
||||||
|
mutex: new(sync.Mutex),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,3 +267,40 @@ func (c *TableReadController) ViewBack() tea.Msg {
|
||||||
tableInfo.Name, viewSnapshot.Query, viewSnapshot.Filter)
|
tableInfo.Name, viewSnapshot.Query, viewSnapshot.Filter)
|
||||||
return c.runQuery(tableInfo, viewSnapshot.Query, viewSnapshot.Filter, false)
|
return c.runQuery(tableInfo, viewSnapshot.Query, viewSnapshot.Filter, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *TableReadController) CopyItemToClipboard(idx int) tea.Msg {
|
||||||
|
if err := c.initClipboard(); err != nil {
|
||||||
|
return events.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
itemCount := 0
|
||||||
|
c.state.withResultSet(func(resultSet *models.ResultSet) {
|
||||||
|
sb := new(strings.Builder)
|
||||||
|
_ = applyToMarkedItems(resultSet, idx, func(idx int, item models.Item) error {
|
||||||
|
if sb.Len() > 0 {
|
||||||
|
fmt.Fprintln(sb, "---")
|
||||||
|
}
|
||||||
|
c.itemRendererService.RenderItem(sb, resultSet.Items()[idx], resultSet, true)
|
||||||
|
itemCount += 1
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
clipboard.Write(clipboard.FmtText, []byte(sb.String()))
|
||||||
|
})
|
||||||
|
|
||||||
|
return events.SetStatus(applyToN("", itemCount, "item", "items", " copied to clipboard"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TableReadController) initClipboard() error {
|
||||||
|
c.mutex.Lock()
|
||||||
|
defer c.mutex.Unlock()
|
||||||
|
|
||||||
|
if c.clipboardInit {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := clipboard.Init(); err != nil {
|
||||||
|
return errors.Wrap(err, "unable to enable clipboard")
|
||||||
|
}
|
||||||
|
c.clipboardInit = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/controllers"
|
"github.com/lmika/audax/internal/dynamo-browse/controllers"
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/providers/dynamo"
|
"github.com/lmika/audax/internal/dynamo-browse/providers/dynamo"
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/providers/workspacestore"
|
"github.com/lmika/audax/internal/dynamo-browse/providers/workspacestore"
|
||||||
|
"github.com/lmika/audax/internal/dynamo-browse/services/itemrenderer"
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/services/tables"
|
"github.com/lmika/audax/internal/dynamo-browse/services/tables"
|
||||||
workspaces_service "github.com/lmika/audax/internal/dynamo-browse/services/workspaces"
|
workspaces_service "github.com/lmika/audax/internal/dynamo-browse/services/workspaces"
|
||||||
"github.com/lmika/audax/test/testdynamo"
|
"github.com/lmika/audax/test/testdynamo"
|
||||||
|
@ -22,12 +23,13 @@ func TestTableReadController_InitTable(t *testing.T) {
|
||||||
|
|
||||||
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
||||||
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
||||||
|
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
||||||
|
|
||||||
provider := dynamo.NewProvider(client)
|
provider := dynamo.NewProvider(client)
|
||||||
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, "")
|
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "")
|
||||||
|
|
||||||
event := readController.Init()
|
event := readController.Init()
|
||||||
|
|
||||||
|
@ -35,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, "")
|
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "")
|
||||||
|
|
||||||
event := readController.Init()
|
event := readController.Init()
|
||||||
|
|
||||||
|
@ -48,10 +50,11 @@ func TestTableReadController_ListTables(t *testing.T) {
|
||||||
|
|
||||||
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
||||||
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
||||||
|
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
||||||
|
|
||||||
provider := dynamo.NewProvider(client)
|
provider := dynamo.NewProvider(client)
|
||||||
service := tables.NewService(provider)
|
service := tables.NewService(provider)
|
||||||
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, "")
|
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "")
|
||||||
|
|
||||||
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)
|
||||||
|
@ -72,11 +75,12 @@ func TestTableReadController_Rescan(t *testing.T) {
|
||||||
|
|
||||||
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
||||||
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
||||||
|
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
||||||
|
|
||||||
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, "bravo-table")
|
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "bravo-table")
|
||||||
|
|
||||||
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())
|
||||||
|
@ -109,10 +113,11 @@ func TestTableReadController_ExportCSV(t *testing.T) {
|
||||||
|
|
||||||
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
||||||
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
||||||
|
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
||||||
|
|
||||||
provider := dynamo.NewProvider(client)
|
provider := dynamo.NewProvider(client)
|
||||||
service := tables.NewService(provider)
|
service := tables.NewService(provider)
|
||||||
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, "bravo-table")
|
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "bravo-table")
|
||||||
|
|
||||||
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)
|
||||||
|
@ -133,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, "non-existant-table")
|
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "non-existant-table")
|
||||||
|
|
||||||
invokeCommandExpectingError(t, readController.Init())
|
invokeCommandExpectingError(t, readController.Init())
|
||||||
invokeCommandExpectingError(t, readController.ExportCSV(tempFile))
|
invokeCommandExpectingError(t, readController.ExportCSV(tempFile))
|
||||||
|
@ -147,10 +152,11 @@ func TestTableReadController_Query(t *testing.T) {
|
||||||
|
|
||||||
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
||||||
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
||||||
|
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
||||||
|
|
||||||
provider := dynamo.NewProvider(client)
|
provider := dynamo.NewProvider(client)
|
||||||
service := tables.NewService(provider)
|
service := tables.NewService(provider)
|
||||||
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, "bravo-table")
|
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "bravo-table")
|
||||||
|
|
||||||
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)
|
||||||
|
@ -170,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, "non-existant-table")
|
readController := controllers.NewTableReadController(controllers.NewState(), service, workspaceService, itemRendererService, "non-existant-table")
|
||||||
|
|
||||||
invokeCommandExpectingError(t, readController.Init())
|
invokeCommandExpectingError(t, readController.Init())
|
||||||
invokeCommandExpectingError(t, readController.ExportCSV(tempFile))
|
invokeCommandExpectingError(t, readController.ExportCSV(tempFile))
|
||||||
|
|
|
@ -107,7 +107,7 @@ func (twc *TableWriteController) setStringValue(idx int, attr attrPath) tea.Msg
|
||||||
Prompt: "string value: ",
|
Prompt: "string value: ",
|
||||||
OnDone: func(value string) tea.Msg {
|
OnDone: func(value string) tea.Msg {
|
||||||
if err := twc.state.withResultSetReturningError(func(set *models.ResultSet) error {
|
if err := twc.state.withResultSetReturningError(func(set *models.ResultSet) error {
|
||||||
if err := twc.applyToItems(set, idx, func(idx int, item models.Item) error {
|
if err := applyToMarkedItems(set, idx, func(idx int, item models.Item) error {
|
||||||
if err := attr.setAt(item, &types.AttributeValueMemberS{Value: value}); err != nil {
|
if err := attr.setAt(item, &types.AttributeValueMemberS{Value: value}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -126,25 +126,12 @@ func (twc *TableWriteController) setStringValue(idx int, attr attrPath) tea.Msg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (twc *TableWriteController) applyToItems(rs *models.ResultSet, selectedIndex int, applyFn func(idx int, item models.Item) error) error {
|
|
||||||
if markedItems := rs.MarkedItems(); len(markedItems) > 0 {
|
|
||||||
for _, mi := range markedItems {
|
|
||||||
if err := applyFn(mi.Index, mi.Item); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return applyFn(selectedIndex, rs.Items()[selectedIndex])
|
|
||||||
}
|
|
||||||
|
|
||||||
func (twc *TableWriteController) setNumberValue(idx int, attr attrPath) tea.Msg {
|
func (twc *TableWriteController) setNumberValue(idx int, attr attrPath) tea.Msg {
|
||||||
return events.PromptForInputMsg{
|
return events.PromptForInputMsg{
|
||||||
Prompt: "number value: ",
|
Prompt: "number value: ",
|
||||||
OnDone: func(value string) tea.Msg {
|
OnDone: func(value string) tea.Msg {
|
||||||
if err := twc.state.withResultSetReturningError(func(set *models.ResultSet) error {
|
if err := twc.state.withResultSetReturningError(func(set *models.ResultSet) error {
|
||||||
if err := twc.applyToItems(set, idx, func(idx int, item models.Item) error {
|
if err := applyToMarkedItems(set, idx, func(idx int, item models.Item) error {
|
||||||
if err := attr.setAt(item, &types.AttributeValueMemberN{Value: value}); err != nil {
|
if err := attr.setAt(item, &types.AttributeValueMemberN{Value: value}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -173,7 +160,7 @@ func (twc *TableWriteController) setBoolValue(idx int, attr attrPath) tea.Msg {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := twc.state.withResultSetReturningError(func(set *models.ResultSet) error {
|
if err := twc.state.withResultSetReturningError(func(set *models.ResultSet) error {
|
||||||
if err := twc.applyToItems(set, idx, func(idx int, item models.Item) error {
|
if err := applyToMarkedItems(set, idx, func(idx int, item models.Item) error {
|
||||||
if err := attr.setAt(item, &types.AttributeValueMemberBOOL{Value: b}); err != nil {
|
if err := attr.setAt(item, &types.AttributeValueMemberBOOL{Value: b}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -194,7 +181,7 @@ func (twc *TableWriteController) setBoolValue(idx int, attr attrPath) tea.Msg {
|
||||||
|
|
||||||
func (twc *TableWriteController) setNullValue(idx int, attr attrPath) tea.Msg {
|
func (twc *TableWriteController) setNullValue(idx int, attr attrPath) tea.Msg {
|
||||||
if err := twc.state.withResultSetReturningError(func(set *models.ResultSet) error {
|
if err := twc.state.withResultSetReturningError(func(set *models.ResultSet) error {
|
||||||
if err := twc.applyToItems(set, idx, func(idx int, item models.Item) error {
|
if err := applyToMarkedItems(set, idx, func(idx int, item models.Item) error {
|
||||||
if err := attr.setAt(item, &types.AttributeValueMemberNULL{Value: true}); err != nil {
|
if err := attr.setAt(item, &types.AttributeValueMemberNULL{Value: true}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/models"
|
"github.com/lmika/audax/internal/dynamo-browse/models"
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/providers/dynamo"
|
"github.com/lmika/audax/internal/dynamo-browse/providers/dynamo"
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/providers/workspacestore"
|
"github.com/lmika/audax/internal/dynamo-browse/providers/workspacestore"
|
||||||
|
"github.com/lmika/audax/internal/dynamo-browse/services/itemrenderer"
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/services/tables"
|
"github.com/lmika/audax/internal/dynamo-browse/services/tables"
|
||||||
workspaces_service "github.com/lmika/audax/internal/dynamo-browse/services/workspaces"
|
workspaces_service "github.com/lmika/audax/internal/dynamo-browse/services/workspaces"
|
||||||
"github.com/lmika/audax/test/testdynamo"
|
"github.com/lmika/audax/test/testdynamo"
|
||||||
|
@ -17,6 +18,7 @@ import (
|
||||||
func TestTableWriteController_NewItem(t *testing.T) {
|
func TestTableWriteController_NewItem(t *testing.T) {
|
||||||
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
||||||
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
||||||
|
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
||||||
|
|
||||||
t.Run("should add an item with pk and sk set at the end of the result set", func(t *testing.T) {
|
t.Run("should add an item with pk and sk set at the end of the result set", func(t *testing.T) {
|
||||||
client := testdynamo.SetupTestTable(t, testData)
|
client := testdynamo.SetupTestTable(t, testData)
|
||||||
|
@ -25,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, "alpha-table")
|
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table")
|
||||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||||
|
|
||||||
invokeCommand(t, readController.Init())
|
invokeCommand(t, readController.Init())
|
||||||
|
@ -50,6 +52,7 @@ func TestTableWriteController_NewItem(t *testing.T) {
|
||||||
func TestTableWriteController_SetAttributeValue(t *testing.T) {
|
func TestTableWriteController_SetAttributeValue(t *testing.T) {
|
||||||
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
||||||
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
||||||
|
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
||||||
|
|
||||||
t.Run("should preserve the type of the field if unspecified", func(t *testing.T) {
|
t.Run("should preserve the type of the field if unspecified", func(t *testing.T) {
|
||||||
|
|
||||||
|
@ -88,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, "alpha-table")
|
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table")
|
||||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||||
|
|
||||||
invokeCommand(t, readController.Init())
|
invokeCommand(t, readController.Init())
|
||||||
|
@ -108,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, "alpha-table")
|
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table")
|
||||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||||
|
|
||||||
invokeCommand(t, readController.Init())
|
invokeCommand(t, readController.Init())
|
||||||
|
@ -162,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, "alpha-table")
|
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table")
|
||||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||||
|
|
||||||
invokeCommand(t, readController.Init())
|
invokeCommand(t, readController.Init())
|
||||||
|
@ -183,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, "alpha-table")
|
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table")
|
||||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||||
|
|
||||||
invokeCommand(t, readController.Init())
|
invokeCommand(t, readController.Init())
|
||||||
|
@ -215,13 +218,14 @@ func TestTableWriteController_DeleteAttribute(t *testing.T) {
|
||||||
|
|
||||||
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
||||||
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
||||||
|
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
||||||
|
|
||||||
provider := dynamo.NewProvider(client)
|
provider := dynamo.NewProvider(client)
|
||||||
service := tables.NewService(provider)
|
service := tables.NewService(provider)
|
||||||
|
|
||||||
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, "alpha-table")
|
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table")
|
||||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||||
|
|
||||||
invokeCommand(t, readController.Init())
|
invokeCommand(t, readController.Init())
|
||||||
|
@ -237,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, "alpha-table")
|
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table")
|
||||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||||
|
|
||||||
invokeCommand(t, readController.Init())
|
invokeCommand(t, readController.Init())
|
||||||
|
@ -260,6 +264,7 @@ func TestTableWriteController_DeleteAttribute(t *testing.T) {
|
||||||
func TestTableWriteController_PutItem(t *testing.T) {
|
func TestTableWriteController_PutItem(t *testing.T) {
|
||||||
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
||||||
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
||||||
|
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
||||||
|
|
||||||
t.Run("should put the selected item if dirty", func(t *testing.T) {
|
t.Run("should put the selected item if dirty", func(t *testing.T) {
|
||||||
client := testdynamo.SetupTestTable(t, testData)
|
client := testdynamo.SetupTestTable(t, testData)
|
||||||
|
@ -268,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, "alpha-table")
|
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table")
|
||||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||||
|
|
||||||
// Read the table
|
// Read the table
|
||||||
|
@ -295,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, "alpha-table")
|
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table")
|
||||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||||
|
|
||||||
// Read the table
|
// Read the table
|
||||||
|
@ -326,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, "alpha-table")
|
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table")
|
||||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||||
|
|
||||||
// Read the table
|
// Read the table
|
||||||
|
@ -342,6 +347,7 @@ func TestTableWriteController_PutItem(t *testing.T) {
|
||||||
func TestTableWriteController_PutItems(t *testing.T) {
|
func TestTableWriteController_PutItems(t *testing.T) {
|
||||||
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
||||||
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
||||||
|
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
||||||
|
|
||||||
t.Run("should put all dirty items if none are marked", func(t *testing.T) {
|
t.Run("should put all dirty items if none are marked", func(t *testing.T) {
|
||||||
client := testdynamo.SetupTestTable(t, testData)
|
client := testdynamo.SetupTestTable(t, testData)
|
||||||
|
@ -350,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, "alpha-table")
|
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table")
|
||||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||||
|
|
||||||
invokeCommand(t, readController.Init())
|
invokeCommand(t, readController.Init())
|
||||||
|
@ -378,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, "alpha-table")
|
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table")
|
||||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||||
|
|
||||||
invokeCommand(t, readController.Init())
|
invokeCommand(t, readController.Init())
|
||||||
|
@ -414,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, "alpha-table")
|
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table")
|
||||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||||
|
|
||||||
invokeCommand(t, readController.Init())
|
invokeCommand(t, readController.Init())
|
||||||
|
@ -447,6 +453,7 @@ func TestTableWriteController_PutItems(t *testing.T) {
|
||||||
func TestTableWriteController_TouchItem(t *testing.T) {
|
func TestTableWriteController_TouchItem(t *testing.T) {
|
||||||
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
||||||
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
||||||
|
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
||||||
|
|
||||||
t.Run("should put the selected item if unmodified", func(t *testing.T) {
|
t.Run("should put the selected item if unmodified", func(t *testing.T) {
|
||||||
client := testdynamo.SetupTestTable(t, testData)
|
client := testdynamo.SetupTestTable(t, testData)
|
||||||
|
@ -455,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, "alpha-table")
|
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table")
|
||||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||||
|
|
||||||
// Read the table
|
// Read the table
|
||||||
|
@ -481,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, "alpha-table")
|
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table")
|
||||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||||
|
|
||||||
// Read the table
|
// Read the table
|
||||||
|
@ -499,6 +506,7 @@ func TestTableWriteController_TouchItem(t *testing.T) {
|
||||||
func TestTableWriteController_NoisyTouchItem(t *testing.T) {
|
func TestTableWriteController_NoisyTouchItem(t *testing.T) {
|
||||||
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
resultSetSnapshotStore := workspacestore.NewResultSetSnapshotStore(testWorkspace(t))
|
||||||
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
workspaceService := workspaces_service.NewService(resultSetSnapshotStore)
|
||||||
|
itemRendererService := itemrenderer.NewService(itemrenderer.PlainTextRenderer(), itemrenderer.PlainTextRenderer())
|
||||||
|
|
||||||
t.Run("should delete and put the selected item if unmodified", func(t *testing.T) {
|
t.Run("should delete and put the selected item if unmodified", func(t *testing.T) {
|
||||||
client := testdynamo.SetupTestTable(t, testData)
|
client := testdynamo.SetupTestTable(t, testData)
|
||||||
|
@ -507,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, "alpha-table")
|
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table")
|
||||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||||
|
|
||||||
// Read the table
|
// Read the table
|
||||||
|
@ -533,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, "alpha-table")
|
readController := controllers.NewTableReadController(state, service, workspaceService, itemRendererService, "alpha-table")
|
||||||
writeController := controllers.NewTableWriteController(state, service, readController)
|
writeController := controllers.NewTableWriteController(state, service, readController)
|
||||||
|
|
||||||
// Read the table
|
// Read the table
|
||||||
|
|
16
internal/dynamo-browse/controllers/utils.go
Normal file
16
internal/dynamo-browse/controllers/utils.go
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package controllers
|
||||||
|
|
||||||
|
import "github.com/lmika/audax/internal/dynamo-browse/models"
|
||||||
|
|
||||||
|
func applyToMarkedItems(rs *models.ResultSet, selectedIndex int, applyFn func(idx int, item models.Item) error) error {
|
||||||
|
if markedItems := rs.MarkedItems(); len(markedItems) > 0 {
|
||||||
|
for _, mi := range markedItems {
|
||||||
|
if err := applyFn(mi.Index, mi.Item); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return applyFn(selectedIndex, rs.Items()[selectedIndex])
|
||||||
|
}
|
62
internal/dynamo-browse/services/itemrenderer/service.go
Normal file
62
internal/dynamo-browse/services/itemrenderer/service.go
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
package itemrenderer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/lmika/audax/internal/dynamo-browse/models"
|
||||||
|
"github.com/lmika/audax/internal/dynamo-browse/models/itemrender"
|
||||||
|
"io"
|
||||||
|
"text/tabwriter"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
styles styleRenderer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(fileTypeStyle StyleRenderer, metaInfoStyle StyleRenderer) *Service {
|
||||||
|
return &Service{
|
||||||
|
styles: styleRenderer{
|
||||||
|
fileTypeRenderer: fileTypeStyle,
|
||||||
|
metaInfoRenderer: metaInfoStyle,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) RenderItem(w io.Writer, item models.Item, resultSet *models.ResultSet, plainText bool) {
|
||||||
|
styles := s.styles
|
||||||
|
if plainText {
|
||||||
|
styles = styleRenderer{plainTextStyleRenderer{}, plainTextStyleRenderer{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
tabWriter := tabwriter.NewWriter(w, 0, 1, 1, ' ', 0)
|
||||||
|
|
||||||
|
seenColumns := make(map[string]struct{})
|
||||||
|
for _, colName := range resultSet.Columns() {
|
||||||
|
seenColumns[colName] = struct{}{}
|
||||||
|
if r := item.Renderer(colName); r != nil {
|
||||||
|
s.renderItem(tabWriter, "", colName, r, styles)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for k, _ := range item {
|
||||||
|
if _, seen := seenColumns[k]; !seen {
|
||||||
|
if r := item.Renderer(k); r != nil {
|
||||||
|
s.renderItem(tabWriter, "", k, r, styles)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tabWriter.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Service) renderItem(w io.Writer, prefix string, name string, r itemrender.Renderer, sr styleRenderer) {
|
||||||
|
fmt.Fprintf(w, "%s%v\t%s\t%s%s\n",
|
||||||
|
prefix, name, sr.fileTypeRenderer.Render(r.TypeName()), r.StringValue(), sr.metaInfoRenderer.Render(r.MetaInfo()))
|
||||||
|
if subitems := r.SubItems(); len(subitems) > 0 {
|
||||||
|
for _, si := range subitems {
|
||||||
|
m.renderItem(w, prefix+" ", si.Key, si.Value, sr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type styleRenderer struct {
|
||||||
|
fileTypeRenderer StyleRenderer
|
||||||
|
metaInfoRenderer StyleRenderer
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package itemrenderer
|
||||||
|
|
||||||
|
type StyleRenderer interface {
|
||||||
|
Render(str string) string
|
||||||
|
}
|
||||||
|
|
||||||
|
func PlainTextRenderer() StyleRenderer {
|
||||||
|
return plainTextStyleRenderer{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type plainTextStyleRenderer struct{}
|
||||||
|
|
||||||
|
func (plainTextStyleRenderer) Render(str string) string {
|
||||||
|
return str
|
||||||
|
}
|
|
@ -6,6 +6,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/controllers"
|
"github.com/lmika/audax/internal/dynamo-browse/controllers"
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/models"
|
"github.com/lmika/audax/internal/dynamo-browse/models"
|
||||||
|
"github.com/lmika/audax/internal/dynamo-browse/services/itemrenderer"
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/dialogprompt"
|
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/dialogprompt"
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/dynamoitemedit"
|
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/dynamoitemedit"
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/dynamoitemview"
|
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/dynamoitemview"
|
||||||
|
@ -31,11 +32,16 @@ type Model struct {
|
||||||
itemView *dynamoitemview.Model
|
itemView *dynamoitemview.Model
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewModel(rc *controllers.TableReadController, wc *controllers.TableWriteController, cc *commandctrl.CommandController) Model {
|
func NewModel(
|
||||||
|
rc *controllers.TableReadController,
|
||||||
|
wc *controllers.TableWriteController,
|
||||||
|
itemRendererService *itemrenderer.Service,
|
||||||
|
cc *commandctrl.CommandController,
|
||||||
|
) Model {
|
||||||
uiStyles := styles.DefaultStyles
|
uiStyles := styles.DefaultStyles
|
||||||
|
|
||||||
dtv := dynamotableview.New(uiStyles)
|
dtv := dynamotableview.New(uiStyles)
|
||||||
div := dynamoitemview.New(uiStyles)
|
div := dynamoitemview.New(itemRendererService, uiStyles)
|
||||||
mainView := layout.NewVBox(layout.LastChildFixedAt(13), dtv, div)
|
mainView := layout.NewVBox(layout.LastChildFixedAt(13), dtv, div)
|
||||||
|
|
||||||
itemEdit := dynamoitemedit.NewModel(mainView)
|
itemEdit := dynamoitemedit.NewModel(mainView)
|
||||||
|
@ -143,6 +149,10 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
if idx := m.tableView.SelectedItemIndex(); idx >= 0 {
|
if idx := m.tableView.SelectedItemIndex(); idx >= 0 {
|
||||||
return m, func() tea.Msg { return m.tableWriteController.ToggleMark(idx) }
|
return m, func() tea.Msg { return m.tableWriteController.ToggleMark(idx) }
|
||||||
}
|
}
|
||||||
|
case "c":
|
||||||
|
if idx := m.tableView.SelectedItemIndex(); idx >= 0 {
|
||||||
|
return m, func() tea.Msg { return m.tableReadController.CopyItemToClipboard(idx) }
|
||||||
|
}
|
||||||
case "R":
|
case "R":
|
||||||
return m, m.tableReadController.Rescan
|
return m, m.tableReadController.Rescan
|
||||||
case "?":
|
case "?":
|
||||||
|
|
|
@ -1,48 +1,34 @@
|
||||||
package dynamoitemview
|
package dynamoitemview
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/models/itemrender"
|
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/styles"
|
|
||||||
"io"
|
|
||||||
"strings"
|
|
||||||
"text/tabwriter"
|
|
||||||
|
|
||||||
"github.com/charmbracelet/bubbles/viewport"
|
"github.com/charmbracelet/bubbles/viewport"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/charmbracelet/lipgloss"
|
"github.com/charmbracelet/lipgloss"
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/models"
|
"github.com/lmika/audax/internal/dynamo-browse/models"
|
||||||
|
"github.com/lmika/audax/internal/dynamo-browse/services/itemrenderer"
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/frame"
|
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/frame"
|
||||||
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/layout"
|
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/layout"
|
||||||
)
|
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/styles"
|
||||||
|
"strings"
|
||||||
var (
|
|
||||||
activeHeaderStyle = lipgloss.NewStyle().
|
|
||||||
Bold(true).
|
|
||||||
Foreground(lipgloss.Color("#ffffff")).
|
|
||||||
Background(lipgloss.Color("#4479ff"))
|
|
||||||
|
|
||||||
fieldTypeStyle = lipgloss.NewStyle().
|
|
||||||
Foreground(lipgloss.AdaptiveColor{Light: "#2B800C", Dark: "#73C653"})
|
|
||||||
metaInfoStyle = lipgloss.NewStyle().
|
|
||||||
Foreground(lipgloss.Color("#888888"))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Model struct {
|
type Model struct {
|
||||||
ready bool
|
ready bool
|
||||||
frameTitle frame.FrameTitle
|
frameTitle frame.FrameTitle
|
||||||
viewport viewport.Model
|
viewport viewport.Model
|
||||||
w, h int
|
itemRendererService *itemrenderer.Service
|
||||||
|
w, h int
|
||||||
|
|
||||||
// model state
|
// model state
|
||||||
currentResultSet *models.ResultSet
|
currentResultSet *models.ResultSet
|
||||||
selectedItem models.Item
|
selectedItem models.Item
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(uiStyles styles.Styles) *Model {
|
func New(itemRendererService *itemrenderer.Service, uiStyles styles.Styles) *Model {
|
||||||
return &Model{
|
return &Model{
|
||||||
frameTitle: frame.NewFrameTitle("Item", false, uiStyles.Frames),
|
itemRendererService: itemRendererService,
|
||||||
viewport: viewport.New(100, 100),
|
frameTitle: frame.NewFrameTitle("Item", false, uiStyles.Frames),
|
||||||
|
viewport: viewport.New(100, 100),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,35 +75,8 @@ func (m *Model) updateViewportToSelectedMessage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
viewportContent := &strings.Builder{}
|
viewportContent := &strings.Builder{}
|
||||||
tabWriter := tabwriter.NewWriter(viewportContent, 0, 1, 1, ' ', 0)
|
m.itemRendererService.RenderItem(viewportContent, m.selectedItem, m.currentResultSet, false)
|
||||||
|
|
||||||
seenColumns := make(map[string]struct{})
|
|
||||||
for _, colName := range m.currentResultSet.Columns() {
|
|
||||||
seenColumns[colName] = struct{}{}
|
|
||||||
if r := m.selectedItem.Renderer(colName); r != nil {
|
|
||||||
m.renderItem(tabWriter, "", colName, r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for k, _ := range m.selectedItem {
|
|
||||||
if _, seen := seenColumns[k]; !seen {
|
|
||||||
if r := m.selectedItem.Renderer(k); r != nil {
|
|
||||||
m.renderItem(tabWriter, "", k, r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tabWriter.Flush()
|
|
||||||
m.viewport.Width = m.w
|
m.viewport.Width = m.w
|
||||||
m.viewport.Height = m.h - m.frameTitle.HeaderHeight()
|
m.viewport.Height = m.h - m.frameTitle.HeaderHeight()
|
||||||
m.viewport.SetContent(viewportContent.String())
|
m.viewport.SetContent(viewportContent.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) renderItem(w io.Writer, prefix string, name string, r itemrender.Renderer) {
|
|
||||||
fmt.Fprintf(w, "%s%v\t%s\t%s%s\n",
|
|
||||||
prefix, name, fieldTypeStyle.Render(r.TypeName()), r.StringValue(), metaInfoStyle.Render(r.MetaInfo()))
|
|
||||||
if subitems := r.SubItems(); len(subitems) > 0 {
|
|
||||||
for _, si := range subitems {
|
|
||||||
m.renderItem(w, prefix+" ", si.Key, si.Value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,11 +7,21 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Styles struct {
|
type Styles struct {
|
||||||
|
ItemView ItemViewStyle
|
||||||
Frames frame.Style
|
Frames frame.Style
|
||||||
StatusAndPrompt statusandprompt.Style
|
StatusAndPrompt statusandprompt.Style
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ItemViewStyle struct {
|
||||||
|
FieldType lipgloss.Style
|
||||||
|
MetaInfo lipgloss.Style
|
||||||
|
}
|
||||||
|
|
||||||
var DefaultStyles = Styles{
|
var DefaultStyles = Styles{
|
||||||
|
ItemView: ItemViewStyle{
|
||||||
|
FieldType: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#2B800C", Dark: "#73C653"}),
|
||||||
|
MetaInfo: lipgloss.NewStyle().Foreground(lipgloss.Color("#888888")),
|
||||||
|
},
|
||||||
Frames: frame.Style{
|
Frames: frame.Style{
|
||||||
ActiveTitle: lipgloss.NewStyle().
|
ActiveTitle: lipgloss.NewStyle().
|
||||||
Bold(true).
|
Bold(true).
|
||||||
|
|
Loading…
Reference in a new issue