feat: edit menu
This commit is contained in:
@@ -78,6 +78,24 @@ func (c *APIClient) CreateAsset(request types.CreateAssetRequest) (*types.Asset,
|
|||||||
return resp.Asset, nil
|
return resp.Asset, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *APIClient) UpdateAsset(id string, request types.CreateAssetRequest) (*types.Asset, error) {
|
||||||
|
url := fmt.Sprintf("%s/assets/%s", c.Host, id)
|
||||||
|
|
||||||
|
body, err := json.Marshal(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, _ := http.NewRequest("PUT", url, bytes.NewBuffer(body))
|
||||||
|
|
||||||
|
resp, err := makeRequest[types.AssetResponse](c, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp.Asset, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *APIClient) RetrieveAllAssets() ([]*types.Asset, error) {
|
func (c *APIClient) RetrieveAllAssets() ([]*types.Asset, error) {
|
||||||
url := fmt.Sprintf("%s/assets", c.Host)
|
url := fmt.Sprintf("%s/assets", c.Host)
|
||||||
req, _ := http.NewRequest("GET", url, bytes.NewBuffer([]byte{}))
|
req, _ := http.NewRequest("GET", url, bytes.NewBuffer([]byte{}))
|
||||||
|
|||||||
@@ -21,3 +21,8 @@ type APIError struct {
|
|||||||
|
|
||||||
Messages []string `json:"messages"`
|
Messages []string `json:"messages"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CountResponse struct {
|
||||||
|
*Response
|
||||||
|
Count int64 `json:"count"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ type CreateAssetRequest struct {
|
|||||||
ModelName string `json:"model_name,omitempty"`
|
ModelName string `json:"model_name,omitempty"`
|
||||||
Price float64 `json:"price,omitempty"`
|
Price float64 `json:"price,omitempty"`
|
||||||
Comments string `json:"comments,omitempty"`
|
Comments string `json:"comments,omitempty"`
|
||||||
ShelfLocationID int `json:"shelf_location_id,omitempty"`
|
ShelfLocationID *uint64 `json:"shelf_location_id,omitempty"`
|
||||||
CategoryID int `json:"category_id,omitempty"`
|
CategoryID *uint64 `json:"category_id,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Asset struct {
|
type Asset struct {
|
||||||
|
|||||||
@@ -20,3 +20,7 @@ type MultipleCategoryResponse struct {
|
|||||||
Categories []*Category `json:"categories"`
|
Categories []*Category `json:"categories"`
|
||||||
Total int64 `json:"total"`
|
Total int64 `json:"total"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CreateCategoryRequest struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,3 +23,10 @@ type ShelfLocation struct {
|
|||||||
UpdatedAt time.Time `json:"updated_at"`
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
DeletedAt *time.Time `json:"deleted_at,omitempty"`
|
DeletedAt *time.Time `json:"deleted_at,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CreateShelfRequest struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
RoomNumber string `json:"room_number,omitempty"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
BuildingID uint64 `json:"building_id"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
package assets
|
package assets
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.brettb.xyz/goinv/client/internal/ui/assets/astdialogs"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"git.brettb.xyz/goinv/client/internal/ui/assets/astdialogs"
|
||||||
|
|
||||||
"git.brettb.xyz/goinv/client/internal/api"
|
"git.brettb.xyz/goinv/client/internal/api"
|
||||||
"git.brettb.xyz/goinv/client/internal/types"
|
"git.brettb.xyz/goinv/client/internal/types"
|
||||||
"git.brettb.xyz/goinv/client/internal/ui/dialogs"
|
"git.brettb.xyz/goinv/client/internal/ui/dialogs"
|
||||||
@@ -34,6 +35,7 @@ type Assets struct {
|
|||||||
progressDialog *dialogs.ProgressDialog
|
progressDialog *dialogs.ProgressDialog
|
||||||
messageDialog *dialogs.MessageDialog
|
messageDialog *dialogs.MessageDialog
|
||||||
createDialog *astdialogs.AssetCreateDialog
|
createDialog *astdialogs.AssetCreateDialog
|
||||||
|
editDialog *astdialogs.AssetEditDialog
|
||||||
allDialogs []dialogs.Dialog
|
allDialogs []dialogs.Dialog
|
||||||
confirmData string
|
confirmData string
|
||||||
assetListFunc func() ([]types.Asset, error)
|
assetListFunc func() ([]types.Asset, error)
|
||||||
@@ -74,6 +76,8 @@ func NewAssets(logger *zap.Logger, client *api.APIClient) *Assets {
|
|||||||
errorDialog: dialogs.NewErrorDialog(logger),
|
errorDialog: dialogs.NewErrorDialog(logger),
|
||||||
progressDialog: dialogs.NewProgressDialog(logger),
|
progressDialog: dialogs.NewProgressDialog(logger),
|
||||||
messageDialog: dialogs.NewMessageDialog(logger, ""),
|
messageDialog: dialogs.NewMessageDialog(logger, ""),
|
||||||
|
createDialog: astdialogs.NewAssetCreateDialog(logger, client),
|
||||||
|
editDialog: astdialogs.NewAssetEditDialog(logger, client),
|
||||||
}
|
}
|
||||||
|
|
||||||
assets.assetTable.SetBackgroundColor(style.BgColor)
|
assets.assetTable.SetBackgroundColor(style.BgColor)
|
||||||
@@ -95,7 +99,7 @@ func NewAssets(logger *zap.Logger, client *api.APIClient) *Assets {
|
|||||||
|
|
||||||
assets.cmdDialog = dialogs.NewCommandDialog(logger, [][]string{
|
assets.cmdDialog = dialogs.NewCommandDialog(logger, [][]string{
|
||||||
{"create asset", "create a new asset"},
|
{"create asset", "create a new asset"},
|
||||||
{"view asset", "view the selected asset"},
|
{"edit asset", "edit the selected asset"},
|
||||||
{"delete asset", "delete the selected asset"},
|
{"delete asset", "delete the selected asset"},
|
||||||
{"refresh", "refresh the page"},
|
{"refresh", "refresh the page"},
|
||||||
})
|
})
|
||||||
@@ -125,6 +129,14 @@ func NewAssets(logger *zap.Logger, client *api.APIClient) *Assets {
|
|||||||
assets.createDialog.Hide()
|
assets.createDialog.Hide()
|
||||||
}).SetCreateFunc(func() {
|
}).SetCreateFunc(func() {
|
||||||
assets.createDialog.Hide()
|
assets.createDialog.Hide()
|
||||||
|
assets.create()
|
||||||
|
})
|
||||||
|
|
||||||
|
assets.editDialog.SetCancelFunc(func() {
|
||||||
|
assets.editDialog.Hide()
|
||||||
|
}).SetEditFunc(func() {
|
||||||
|
assets.editDialog.Hide()
|
||||||
|
assets.edit()
|
||||||
})
|
})
|
||||||
|
|
||||||
assets.SetAssetListFunc(func() ([]types.Asset, error) {
|
assets.SetAssetListFunc(func() ([]types.Asset, error) {
|
||||||
@@ -160,6 +172,8 @@ func NewAssets(logger *zap.Logger, client *api.APIClient) *Assets {
|
|||||||
assets.messageDialog,
|
assets.messageDialog,
|
||||||
assets.progressDialog,
|
assets.progressDialog,
|
||||||
assets.confirmDialog,
|
assets.confirmDialog,
|
||||||
|
assets.createDialog,
|
||||||
|
assets.editDialog,
|
||||||
assets.cmdDialog,
|
assets.cmdDialog,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ package astdialogs
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"git.brettb.xyz/goinv/client/internal/api"
|
"git.brettb.xyz/goinv/client/internal/api"
|
||||||
"git.brettb.xyz/goinv/client/internal/types"
|
"git.brettb.xyz/goinv/client/internal/types"
|
||||||
"git.brettb.xyz/goinv/client/internal/ui/dialogs"
|
"git.brettb.xyz/goinv/client/internal/ui/dialogs"
|
||||||
@@ -10,12 +13,11 @@ import (
|
|||||||
"github.com/gdamore/tcell/v2"
|
"github.com/gdamore/tcell/v2"
|
||||||
"github.com/rivo/tview"
|
"github.com/rivo/tview"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
assetCreateDialogMaxWidth = 100
|
assetCreateDialogMaxWidth = 100
|
||||||
assetCreateDialogHeight = 10
|
assetCreateDialogHeight = 17
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -172,6 +174,13 @@ func (d *AssetCreateDialog) Focus(delegate func(tview.Primitive)) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if event.Key() == tcell.KeyBacktab {
|
||||||
|
d.focusElement = createAssetFormFocus
|
||||||
|
d.Focus(delegate)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
event = utils.ParseKeyEventKey(d.logger, event)
|
event = utils.ParseKeyEventKey(d.logger, event)
|
||||||
if event.Key() == tcell.KeyDown {
|
if event.Key() == tcell.KeyDown {
|
||||||
d.nextCategory()
|
d.nextCategory()
|
||||||
@@ -206,6 +215,10 @@ func (d *AssetCreateDialog) InputHandler() func(*tcell.EventKey, func(tview.Prim
|
|||||||
d.setGeneralInfoNextFocus()
|
d.setGeneralInfoNextFocus()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if event.Key() == tcell.KeyBacktab {
|
||||||
|
d.setGeneralInfoPrevFocus()
|
||||||
|
}
|
||||||
|
|
||||||
handler(event, setFocus)
|
handler(event, setFocus)
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -218,6 +231,10 @@ func (d *AssetCreateDialog) InputHandler() func(*tcell.EventKey, func(tview.Prim
|
|||||||
d.setLocationNextFocus()
|
d.setLocationNextFocus()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if event.Key() == tcell.KeyBacktab {
|
||||||
|
d.setLocationPrevFocus()
|
||||||
|
}
|
||||||
|
|
||||||
handler(event, setFocus)
|
handler(event, setFocus)
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -230,6 +247,10 @@ func (d *AssetCreateDialog) InputHandler() func(*tcell.EventKey, func(tview.Prim
|
|||||||
d.setCommentsNextFocus()
|
d.setCommentsNextFocus()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if event.Key() == tcell.KeyBacktab {
|
||||||
|
d.setCommentsPrevFocus()
|
||||||
|
}
|
||||||
|
|
||||||
handler(event, setFocus)
|
handler(event, setFocus)
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -300,6 +321,10 @@ func (d *AssetCreateDialog) SetCreateFunc(f func()) *AssetCreateDialog {
|
|||||||
|
|
||||||
func (d *AssetCreateDialog) SetCancelFunc(f func()) *AssetCreateDialog {
|
func (d *AssetCreateDialog) SetCancelFunc(f func()) *AssetCreateDialog {
|
||||||
d.cancelHandler = f
|
d.cancelHandler = f
|
||||||
|
cancelButton := d.form.GetButton(d.form.GetButtonCount() - 2)
|
||||||
|
|
||||||
|
cancelButton.SetSelectedFunc(f)
|
||||||
|
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,9 +349,11 @@ func (d *AssetCreateDialog) initData() {
|
|||||||
|
|
||||||
categoryOptions := []string{""}
|
categoryOptions := []string{""}
|
||||||
for _, category := range d.categoryList {
|
for _, category := range d.categoryList {
|
||||||
categoryOptions = append(shelfOptions, fmt.Sprintf("%s", category.Name))
|
categoryOptions = append(categoryOptions, fmt.Sprintf("%s", category.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d.setActiveCategory(0)
|
||||||
|
|
||||||
// General category
|
// General category
|
||||||
d.assetNameField.SetText("")
|
d.assetNameField.SetText("")
|
||||||
d.assetQuantityField.SetText("")
|
d.assetQuantityField.SetText("")
|
||||||
@@ -347,11 +374,13 @@ func (d *AssetCreateDialog) initData() {
|
|||||||
|
|
||||||
func (d *AssetCreateDialog) setupLayout() {
|
func (d *AssetCreateDialog) setupLayout() {
|
||||||
bgColor := style.DialogBgColor
|
bgColor := style.DialogBgColor
|
||||||
|
fgColor := style.DialogFgColor
|
||||||
|
|
||||||
d.categories.SetDynamicColors(true).
|
d.categories.SetDynamicColors(true).
|
||||||
SetWrap(true).
|
SetWrap(true).
|
||||||
SetTextAlign(tview.AlignLeft)
|
SetTextAlign(tview.AlignLeft)
|
||||||
d.categories.SetBackgroundColor(bgColor)
|
d.categories.SetBackgroundColor(fgColor)
|
||||||
|
d.categories.SetTextColor(bgColor)
|
||||||
d.categories.SetBorder(true)
|
d.categories.SetBorder(true)
|
||||||
d.categories.SetBorderColor(style.DialogSubBoxBorderColor)
|
d.categories.SetBorderColor(style.DialogSubBoxBorderColor)
|
||||||
|
|
||||||
@@ -383,6 +412,7 @@ func (d *AssetCreateDialog) setupLayout() {
|
|||||||
d.layout.SetBorder(true)
|
d.layout.SetBorder(true)
|
||||||
d.layout.SetBorderColor(style.DialogBorderColor)
|
d.layout.SetBorderColor(style.DialogBorderColor)
|
||||||
d.layout.SetTitle("ASSET CREATE")
|
d.layout.SetTitle("ASSET CREATE")
|
||||||
|
d.layout.SetTitleColor(style.DialogFgColor)
|
||||||
|
|
||||||
_, layoutWidth := utils.AlignStringListWidth(d.createCategoryLabels)
|
_, layoutWidth := utils.AlignStringListWidth(d.createCategoryLabels)
|
||||||
layout := tview.NewFlex().SetDirection(tview.FlexColumn)
|
layout := tview.NewFlex().SetDirection(tview.FlexColumn)
|
||||||
@@ -390,6 +420,7 @@ func (d *AssetCreateDialog) setupLayout() {
|
|||||||
layout.AddItem(d.categories, layoutWidth+6, 0, true)
|
layout.AddItem(d.categories, layoutWidth+6, 0, true)
|
||||||
layout.AddItem(d.categoryPages, 0, 1, true)
|
layout.AddItem(d.categoryPages, 0, 1, true)
|
||||||
layout.SetBackgroundColor(bgColor)
|
layout.SetBackgroundColor(bgColor)
|
||||||
|
d.layout.SetDirection(tview.FlexRow)
|
||||||
d.layout.AddItem(layout, 0, 1, true)
|
d.layout.AddItem(layout, 0, 1, true)
|
||||||
|
|
||||||
d.layout.AddItem(d.form, dialogs.DialogFormHeight, 0, true)
|
d.layout.AddItem(d.form, dialogs.DialogFormHeight, 0, true)
|
||||||
@@ -398,7 +429,7 @@ func (d *AssetCreateDialog) setupLayout() {
|
|||||||
func (d *AssetCreateDialog) setupGeneralInfoPageUI() {
|
func (d *AssetCreateDialog) setupGeneralInfoPageUI() {
|
||||||
bgColor := style.DialogBgColor
|
bgColor := style.DialogBgColor
|
||||||
inputFieldBgColor := style.InputFieldBgColor
|
inputFieldBgColor := style.InputFieldBgColor
|
||||||
pageLabelWidth := 12
|
pageLabelWidth := 14
|
||||||
|
|
||||||
d.assetNameField.SetLabel("name:")
|
d.assetNameField.SetLabel("name:")
|
||||||
d.assetNameField.SetLabelWidth(pageLabelWidth)
|
d.assetNameField.SetLabelWidth(pageLabelWidth)
|
||||||
@@ -495,8 +526,8 @@ func (d *AssetCreateDialog) setupCommentsPageUI() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *AssetCreateDialog) setActiveCategory(idx int) {
|
func (d *AssetCreateDialog) setActiveCategory(idx int) {
|
||||||
fgColor := style.DialogFgColor
|
fgColor := style.ButtonSelectedFgColor
|
||||||
bgBolor := style.ButtonBgColor
|
bgBolor := style.ButtonSelectedBgColor
|
||||||
ctgTextColor := style.GetColorHex(fgColor)
|
ctgTextColor := style.GetColorHex(fgColor)
|
||||||
ctgBgColor := style.GetColorHex(bgBolor)
|
ctgBgColor := style.GetColorHex(bgBolor)
|
||||||
|
|
||||||
@@ -598,6 +629,44 @@ func (d *AssetCreateDialog) setGeneralInfoNextFocus() {
|
|||||||
d.focusElement = createAssetFormFocus
|
d.focusElement = createAssetFormFocus
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *AssetCreateDialog) setGeneralInfoPrevFocus() {
|
||||||
|
if d.assetNameField.HasFocus() {
|
||||||
|
d.focusElement = createCategoriesFocus
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.assetQuantityField.HasFocus() {
|
||||||
|
d.focusElement = createAssetNameFieldFocus
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.assetLengthField.HasFocus() {
|
||||||
|
d.focusElement = createAssetQuantityFieldFocus
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.assetManufacturerField.HasFocus() {
|
||||||
|
d.focusElement = createAssetLengthFieldFocus
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.assetModelField.HasFocus() {
|
||||||
|
d.focusElement = createAssetManufacturerFieldFocus
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.assetPriceField.HasFocus() {
|
||||||
|
d.focusElement = createAssetModelFieldFocus
|
||||||
|
}
|
||||||
|
|
||||||
|
d.focusElement = createAssetPriceFieldFocus
|
||||||
|
}
|
||||||
|
|
||||||
func (d *AssetCreateDialog) setLocationNextFocus() {
|
func (d *AssetCreateDialog) setLocationNextFocus() {
|
||||||
// Category -> Shelf
|
// Category -> Shelf
|
||||||
if d.assetCategoryField.HasFocus() {
|
if d.assetCategoryField.HasFocus() {
|
||||||
@@ -609,6 +678,73 @@ func (d *AssetCreateDialog) setLocationNextFocus() {
|
|||||||
d.focusElement = createAssetFormFocus
|
d.focusElement = createAssetFormFocus
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *AssetCreateDialog) setLocationPrevFocus() {
|
||||||
|
if d.assetCategoryField.HasFocus() {
|
||||||
|
d.focusElement = createCategoriesFocus
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.assetShelfField.HasFocus() {
|
||||||
|
d.focusElement = createAssetCategoryFieldFocus
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
d.focusElement = createAssetShelfFieldFocus
|
||||||
|
}
|
||||||
|
|
||||||
func (d *AssetCreateDialog) setCommentsNextFocus() {
|
func (d *AssetCreateDialog) setCommentsNextFocus() {
|
||||||
d.focusElement = createAssetFormFocus
|
d.focusElement = createAssetFormFocus
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *AssetCreateDialog) setCommentsPrevFocus() {
|
||||||
|
d.focusElement = createCategoriesFocus
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetCreateDialog) CreateAssetOptions() types.CreateAssetRequest {
|
||||||
|
var (
|
||||||
|
quantity int
|
||||||
|
categoryID *uint64
|
||||||
|
shelfID *uint64
|
||||||
|
price float64
|
||||||
|
)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
selectedCategoryIndex, _ := d.assetCategoryField.GetCurrentOption()
|
||||||
|
if len(d.categoryList) > 0 && selectedCategoryIndex > 0 {
|
||||||
|
categoryID = &d.categoryList[selectedCategoryIndex-1].ID
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedShelfIndex, _ := d.assetShelfField.GetCurrentOption()
|
||||||
|
if len(d.shelfList) > 0 && selectedShelfIndex > 0 {
|
||||||
|
shelfID = &d.shelfList[selectedShelfIndex-1].ID
|
||||||
|
}
|
||||||
|
|
||||||
|
quantityStr := d.assetQuantityField.GetText()
|
||||||
|
quantity, err = strconv.Atoi(quantityStr)
|
||||||
|
if err != nil {
|
||||||
|
quantity = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
priceStr := d.assetPriceField.GetText()
|
||||||
|
price, err = strconv.ParseFloat(priceStr, 64)
|
||||||
|
if err != nil {
|
||||||
|
price = 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
req := types.CreateAssetRequest{
|
||||||
|
Name: d.assetNameField.GetText(),
|
||||||
|
Quantity: quantity,
|
||||||
|
Length: d.assetLengthField.GetText(),
|
||||||
|
Manufacturer: d.assetManufacturerField.GetText(),
|
||||||
|
ModelName: d.assetModelField.GetText(),
|
||||||
|
Price: price,
|
||||||
|
Comments: d.assetCommentsArea.GetText(),
|
||||||
|
ShelfLocationID: shelfID,
|
||||||
|
CategoryID: categoryID,
|
||||||
|
}
|
||||||
|
|
||||||
|
return req
|
||||||
|
}
|
||||||
|
|||||||
695
internal/ui/assets/astdialogs/edit.go
Normal file
695
internal/ui/assets/astdialogs/edit.go
Normal file
@@ -0,0 +1,695 @@
|
|||||||
|
package astdialogs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"slices"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.brettb.xyz/goinv/client/internal/api"
|
||||||
|
"git.brettb.xyz/goinv/client/internal/types"
|
||||||
|
"git.brettb.xyz/goinv/client/internal/ui/dialogs"
|
||||||
|
"git.brettb.xyz/goinv/client/internal/ui/style"
|
||||||
|
"git.brettb.xyz/goinv/client/internal/ui/utils"
|
||||||
|
"github.com/gdamore/tcell/v2"
|
||||||
|
"github.com/rivo/tview"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
assetEditDialogMaxWidth = 100
|
||||||
|
assetEditDialogHeight = 17
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
editAssetFormFocus = 0 + iota
|
||||||
|
editCategoriesFocus
|
||||||
|
editCategoryPagesFocus
|
||||||
|
editAssetNameFieldFocus
|
||||||
|
editAssetQuantityFieldFocus
|
||||||
|
editAssetLengthFieldFocus
|
||||||
|
editAssetManufacturerFieldFocus
|
||||||
|
editAssetModelFieldFocus
|
||||||
|
editAssetPriceFieldFocus
|
||||||
|
editAssetCategoryFieldFocus
|
||||||
|
editAssetShelfFieldFocus
|
||||||
|
editAssetCommentFieldFocus
|
||||||
|
)
|
||||||
|
|
||||||
|
type AssetEditDialog struct {
|
||||||
|
*tview.Box
|
||||||
|
layout *tview.Flex
|
||||||
|
editCategoryLabels []string
|
||||||
|
categories *tview.TextView
|
||||||
|
categoryPages *tview.Pages
|
||||||
|
generalInfoPage *tview.Flex
|
||||||
|
locationPage *tview.Flex
|
||||||
|
commentsPage *tview.Flex
|
||||||
|
form *tview.Form
|
||||||
|
|
||||||
|
display bool
|
||||||
|
activePageIndex int
|
||||||
|
focusElement int
|
||||||
|
logger *zap.Logger
|
||||||
|
client *api.APIClient
|
||||||
|
asset *types.Asset
|
||||||
|
|
||||||
|
categoryList []*types.Category
|
||||||
|
shelfList []*types.ShelfLocation
|
||||||
|
|
||||||
|
assetNameField *tview.InputField
|
||||||
|
assetQuantityField *tview.InputField
|
||||||
|
assetLengthField *tview.InputField
|
||||||
|
assetManufacturerField *tview.InputField
|
||||||
|
assetModelField *tview.InputField
|
||||||
|
assetPriceField *tview.InputField
|
||||||
|
assetCategoryField *tview.DropDown
|
||||||
|
assetShelfField *tview.DropDown
|
||||||
|
assetCommentsArea *tview.TextArea
|
||||||
|
|
||||||
|
focusMap map[int]tview.Primitive
|
||||||
|
|
||||||
|
cancelHandler func()
|
||||||
|
editHandler func()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAssetEditDialog(logger *zap.Logger, client *api.APIClient) *AssetEditDialog {
|
||||||
|
editDialog := AssetEditDialog{
|
||||||
|
Box: tview.NewBox(),
|
||||||
|
layout: tview.NewFlex(),
|
||||||
|
editCategoryLabels: []string{
|
||||||
|
"General",
|
||||||
|
"Location",
|
||||||
|
"Comments",
|
||||||
|
},
|
||||||
|
categories: tview.NewTextView(),
|
||||||
|
categoryPages: tview.NewPages(),
|
||||||
|
generalInfoPage: tview.NewFlex(),
|
||||||
|
locationPage: tview.NewFlex(),
|
||||||
|
commentsPage: tview.NewFlex(),
|
||||||
|
form: tview.NewForm(),
|
||||||
|
display: false,
|
||||||
|
activePageIndex: 0,
|
||||||
|
logger: logger,
|
||||||
|
client: client,
|
||||||
|
assetNameField: tview.NewInputField(),
|
||||||
|
assetQuantityField: tview.NewInputField(),
|
||||||
|
assetLengthField: tview.NewInputField(),
|
||||||
|
assetManufacturerField: tview.NewInputField(),
|
||||||
|
assetModelField: tview.NewInputField(),
|
||||||
|
assetPriceField: tview.NewInputField(),
|
||||||
|
assetCategoryField: tview.NewDropDown(),
|
||||||
|
assetShelfField: tview.NewDropDown(),
|
||||||
|
assetCommentsArea: tview.NewTextArea(),
|
||||||
|
}
|
||||||
|
|
||||||
|
editDialog.focusMap = map[int]tview.Primitive{
|
||||||
|
editAssetNameFieldFocus: editDialog.assetNameField,
|
||||||
|
editAssetQuantityFieldFocus: editDialog.assetQuantityField,
|
||||||
|
editAssetLengthFieldFocus: editDialog.assetLengthField,
|
||||||
|
editAssetManufacturerFieldFocus: editDialog.assetManufacturerField,
|
||||||
|
editAssetModelFieldFocus: editDialog.assetModelField,
|
||||||
|
editAssetPriceFieldFocus: editDialog.assetPriceField,
|
||||||
|
editAssetCategoryFieldFocus: editDialog.assetCategoryField,
|
||||||
|
editAssetShelfFieldFocus: editDialog.assetShelfField,
|
||||||
|
editAssetCommentFieldFocus: editDialog.assetCommentsArea,
|
||||||
|
}
|
||||||
|
|
||||||
|
editDialog.setupLayout()
|
||||||
|
editDialog.setActiveCategory(0)
|
||||||
|
editDialog.initCustomInputHandlers()
|
||||||
|
|
||||||
|
return &editDialog
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetEditDialog) Display() {
|
||||||
|
d.display = true
|
||||||
|
d.initData()
|
||||||
|
d.focusElement = editCategoryPagesFocus
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetEditDialog) IsDisplay() bool {
|
||||||
|
return d.display
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetEditDialog) Hide() {
|
||||||
|
d.display = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetEditDialog) HasFocus() bool {
|
||||||
|
return utils.CheckFocus(d.categories, d.categoryPages, d.Box, d.form)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetEditDialog) Focus(delegate func(tview.Primitive)) {
|
||||||
|
switch d.focusElement {
|
||||||
|
case editAssetFormFocus:
|
||||||
|
button := d.form.GetButton(d.form.GetButtonCount() - 1)
|
||||||
|
button.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
||||||
|
if event.Key() == utils.SwitchFocusKey.EventKey() {
|
||||||
|
d.focusElement = editCategoriesFocus
|
||||||
|
|
||||||
|
d.Focus(delegate)
|
||||||
|
d.form.SetFocus(0)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.Key() == tcell.KeyEnter {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return event
|
||||||
|
})
|
||||||
|
delegate(d.form)
|
||||||
|
case editCategoriesFocus:
|
||||||
|
d.categories.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
||||||
|
if event.Key() == utils.SwitchFocusKey.EventKey() {
|
||||||
|
d.focusElement = editCategoryPagesFocus
|
||||||
|
d.Focus(delegate)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
event = utils.ParseKeyEventKey(d.logger, event)
|
||||||
|
if event.Key() == tcell.KeyDown {
|
||||||
|
d.nextCategory()
|
||||||
|
}
|
||||||
|
if event.Key() == tcell.KeyUp {
|
||||||
|
d.previousCategory()
|
||||||
|
}
|
||||||
|
|
||||||
|
return event
|
||||||
|
})
|
||||||
|
delegate(d.categories)
|
||||||
|
case editCategoryPagesFocus:
|
||||||
|
delegate(d.categoryPages)
|
||||||
|
default:
|
||||||
|
delegate(d.focusMap[d.focusElement])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetEditDialog) InputHandler() func(*tcell.EventKey, func(tview.Primitive)) {
|
||||||
|
return d.WrapInputHandler(func(event *tcell.EventKey, setFocus func(tview.Primitive)) {
|
||||||
|
d.logger.Sugar().Debugf("asset edit dialog event %v received", event)
|
||||||
|
|
||||||
|
if event.Key() == utils.CloseDialogKey.EventKey() && !d.dropdownHasFocus() {
|
||||||
|
d.cancelHandler()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.generalInfoPage.HasFocus() {
|
||||||
|
if handler := d.generalInfoPage.InputHandler(); handler != nil {
|
||||||
|
if event.Key() == utils.SwitchFocusKey.EventKey() {
|
||||||
|
d.setGeneralInfoNextFocus()
|
||||||
|
}
|
||||||
|
|
||||||
|
handler(event, setFocus)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.locationPage.HasFocus() {
|
||||||
|
if handler := d.locationPage.InputHandler(); handler != nil {
|
||||||
|
if event.Key() == utils.SwitchFocusKey.EventKey() {
|
||||||
|
d.setLocationNextFocus()
|
||||||
|
}
|
||||||
|
|
||||||
|
handler(event, setFocus)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.commentsPage.HasFocus() {
|
||||||
|
if handler := d.commentsPage.InputHandler(); handler != nil {
|
||||||
|
if event.Key() == utils.SwitchFocusKey.EventKey() {
|
||||||
|
d.setCommentsNextFocus()
|
||||||
|
}
|
||||||
|
|
||||||
|
handler(event, setFocus)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.categories.HasFocus() {
|
||||||
|
if categoryHandler := d.categories.InputHandler(); categoryHandler != nil {
|
||||||
|
categoryHandler(event, setFocus)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.form.HasFocus() {
|
||||||
|
if formHandler := d.form.InputHandler(); formHandler != nil {
|
||||||
|
if event.Key() == tcell.KeyEnter {
|
||||||
|
enterButton := d.form.GetButton(d.form.GetButtonCount() - 1)
|
||||||
|
if enterButton.HasFocus() {
|
||||||
|
d.editHandler()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
formHandler(event, setFocus)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetEditDialog) SetRect(x, y, width, height int) {
|
||||||
|
if width > assetEditDialogMaxWidth {
|
||||||
|
emptySpace := (width - assetEditDialogMaxWidth) / 2
|
||||||
|
x += emptySpace
|
||||||
|
width = assetEditDialogMaxWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
if height > assetEditDialogHeight {
|
||||||
|
emptySpace := (height - assetEditDialogHeight) / 2
|
||||||
|
y += emptySpace
|
||||||
|
height = assetEditDialogHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Box.SetRect(x, y, width, height)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetEditDialog) Draw(screen tcell.Screen) {
|
||||||
|
if !d.display {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Box.DrawForSubclass(screen, d)
|
||||||
|
x, y, width, height := d.Box.GetInnerRect()
|
||||||
|
|
||||||
|
d.layout.SetRect(x, y, width, height)
|
||||||
|
d.layout.Draw(screen)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetEditDialog) SetEditFunc(f func()) *AssetEditDialog {
|
||||||
|
d.editHandler = f
|
||||||
|
enterButton := d.form.GetButton(d.form.GetButtonCount() - 1)
|
||||||
|
|
||||||
|
enterButton.SetSelectedFunc(f)
|
||||||
|
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetEditDialog) SetCancelFunc(f func()) *AssetEditDialog {
|
||||||
|
d.cancelHandler = f
|
||||||
|
cancelButton := d.form.GetButton(d.form.GetButtonCount() - 2)
|
||||||
|
|
||||||
|
cancelButton.SetSelectedFunc(f)
|
||||||
|
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetEditDialog) dropdownHasFocus() bool {
|
||||||
|
return utils.CheckFocus(d.assetCategoryField, d.assetShelfField)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetEditDialog) SetAsset(a *types.Asset) {
|
||||||
|
d.asset = a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetEditDialog) initData() {
|
||||||
|
|
||||||
|
// Get available shelves
|
||||||
|
shelfList, _ := d.client.RetrieveAllShelves()
|
||||||
|
d.shelfList = shelfList
|
||||||
|
|
||||||
|
shelfOptions := []string{""}
|
||||||
|
for _, shelf := range d.shelfList {
|
||||||
|
shelfOptions = append(shelfOptions, shelf.Name) // In case we want to do custom formatting later
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get available categories
|
||||||
|
categoryList, _ := d.client.RetrieveAllCategories()
|
||||||
|
d.categoryList = categoryList
|
||||||
|
|
||||||
|
categoryOptions := []string{""}
|
||||||
|
for _, category := range d.categoryList {
|
||||||
|
categoryOptions = append(categoryOptions, category.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.setActiveCategory(0)
|
||||||
|
|
||||||
|
// General category
|
||||||
|
if d.asset == nil {
|
||||||
|
d.assetNameField.SetText("")
|
||||||
|
d.assetQuantityField.SetText("")
|
||||||
|
d.assetLengthField.SetText("")
|
||||||
|
d.assetManufacturerField.SetText("")
|
||||||
|
d.assetModelField.SetText("")
|
||||||
|
d.assetPriceField.SetText("")
|
||||||
|
|
||||||
|
// Location category
|
||||||
|
d.assetShelfField.SetOptions(shelfOptions, nil)
|
||||||
|
d.assetShelfField.SetCurrentOption(0)
|
||||||
|
d.assetCategoryField.SetOptions(categoryOptions, nil)
|
||||||
|
d.assetCategoryField.SetCurrentOption(0)
|
||||||
|
|
||||||
|
// Comments category
|
||||||
|
d.assetCommentsArea.SetText("", true)
|
||||||
|
} else {
|
||||||
|
d.assetNameField.SetText(d.asset.Name)
|
||||||
|
d.assetQuantityField.SetText(fmt.Sprintf("%d", d.asset.Quantity))
|
||||||
|
d.assetLengthField.SetText(d.asset.Length)
|
||||||
|
d.assetManufacturerField.SetText(d.asset.Manufacturer)
|
||||||
|
d.assetModelField.SetText(d.asset.ModelName)
|
||||||
|
d.assetPriceField.SetText(fmt.Sprintf("%.2f", d.asset.Price))
|
||||||
|
|
||||||
|
// Location category
|
||||||
|
d.assetShelfField.SetOptions(shelfOptions, nil)
|
||||||
|
d.assetShelfField.SetCurrentOption(findOption(shelfOptions, d.asset.ShelfLocation.Name))
|
||||||
|
d.assetCategoryField.SetOptions(categoryOptions, nil)
|
||||||
|
d.assetCategoryField.SetCurrentOption(findOption(categoryOptions, d.asset.Category.Name))
|
||||||
|
|
||||||
|
// Comments category
|
||||||
|
d.assetCommentsArea.SetText("", true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func findOption(options []string, search string) int {
|
||||||
|
return slices.Index(options, search)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetEditDialog) setupLayout() {
|
||||||
|
bgColor := style.DialogBgColor
|
||||||
|
fgColor := style.DialogFgColor
|
||||||
|
|
||||||
|
d.categories.SetDynamicColors(true).
|
||||||
|
SetWrap(true).
|
||||||
|
SetTextAlign(tview.AlignLeft)
|
||||||
|
d.categories.SetBackgroundColor(fgColor)
|
||||||
|
d.categories.SetTextColor(bgColor)
|
||||||
|
d.categories.SetBorder(true)
|
||||||
|
d.categories.SetBorderColor(style.DialogSubBoxBorderColor)
|
||||||
|
|
||||||
|
d.categoryPages.SetBackgroundColor(bgColor)
|
||||||
|
d.categoryPages.SetBorder(true)
|
||||||
|
d.categoryPages.SetBorderColor(style.DialogSubBoxBorderColor)
|
||||||
|
|
||||||
|
d.setupGeneralInfoPageUI()
|
||||||
|
d.setupLocationPageUI()
|
||||||
|
d.setupCommentsPageUI()
|
||||||
|
|
||||||
|
activatedStyle := tcell.StyleDefault.
|
||||||
|
Background(style.ButtonSelectedBgColor).
|
||||||
|
Foreground(style.ButtonSelectedFgColor)
|
||||||
|
|
||||||
|
d.form.SetBackgroundColor(bgColor)
|
||||||
|
d.form.AddButton("Cancel", nil)
|
||||||
|
d.form.AddButton("Edit", nil)
|
||||||
|
d.form.SetButtonsAlign(tview.AlignRight)
|
||||||
|
d.form.SetButtonBackgroundColor(style.ButtonBgColor)
|
||||||
|
d.form.SetButtonTextColor(style.ButtonFgColor)
|
||||||
|
d.form.SetButtonActivatedStyle(activatedStyle)
|
||||||
|
|
||||||
|
d.categoryPages.AddPage(d.editCategoryLabels[generalPageIndex], d.generalInfoPage, true, true)
|
||||||
|
d.categoryPages.AddPage(d.editCategoryLabels[locationPageIndex], d.locationPage, true, true)
|
||||||
|
d.categoryPages.AddPage(d.editCategoryLabels[commentPageIndex], d.commentsPage, true, true)
|
||||||
|
|
||||||
|
d.layout.SetBackgroundColor(bgColor)
|
||||||
|
d.layout.SetBorder(true)
|
||||||
|
d.layout.SetBorderColor(style.DialogBorderColor)
|
||||||
|
d.layout.SetTitle("ASSET EDIT")
|
||||||
|
d.layout.SetTitleColor(style.DialogFgColor)
|
||||||
|
|
||||||
|
_, layoutWidth := utils.AlignStringListWidth(d.editCategoryLabels)
|
||||||
|
layout := tview.NewFlex().SetDirection(tview.FlexColumn)
|
||||||
|
|
||||||
|
layout.AddItem(d.categories, layoutWidth+6, 0, true)
|
||||||
|
layout.AddItem(d.categoryPages, 0, 1, true)
|
||||||
|
layout.SetBackgroundColor(bgColor)
|
||||||
|
d.layout.SetDirection(tview.FlexRow)
|
||||||
|
d.layout.AddItem(layout, 0, 1, true)
|
||||||
|
|
||||||
|
d.layout.AddItem(d.form, dialogs.DialogFormHeight, 0, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetEditDialog) setupGeneralInfoPageUI() {
|
||||||
|
bgColor := style.DialogBgColor
|
||||||
|
inputFieldBgColor := style.InputFieldBgColor
|
||||||
|
pageLabelWidth := 12
|
||||||
|
|
||||||
|
d.assetNameField.SetLabel("name:")
|
||||||
|
d.assetNameField.SetLabelWidth(pageLabelWidth)
|
||||||
|
d.assetNameField.SetLabelColor(bgColor)
|
||||||
|
d.assetNameField.SetBackgroundColor(style.DialogFgColor)
|
||||||
|
d.assetNameField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||||
|
|
||||||
|
d.assetQuantityField.SetLabel("quantity:")
|
||||||
|
d.assetQuantityField.SetLabelWidth(pageLabelWidth)
|
||||||
|
d.assetQuantityField.SetLabelColor(bgColor)
|
||||||
|
d.assetQuantityField.SetBackgroundColor(style.DialogFgColor)
|
||||||
|
d.assetQuantityField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||||
|
|
||||||
|
d.assetLengthField.SetLabel("length:")
|
||||||
|
d.assetLengthField.SetLabelWidth(pageLabelWidth)
|
||||||
|
d.assetLengthField.SetLabelColor(bgColor)
|
||||||
|
d.assetLengthField.SetBackgroundColor(style.DialogFgColor)
|
||||||
|
d.assetLengthField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||||
|
|
||||||
|
d.assetManufacturerField.SetLabel("manufacturer:")
|
||||||
|
d.assetManufacturerField.SetLabelWidth(pageLabelWidth)
|
||||||
|
d.assetManufacturerField.SetLabelColor(bgColor)
|
||||||
|
d.assetManufacturerField.SetBackgroundColor(style.DialogFgColor)
|
||||||
|
d.assetManufacturerField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||||
|
|
||||||
|
d.assetModelField.SetLabel("model:")
|
||||||
|
d.assetModelField.SetLabelWidth(pageLabelWidth)
|
||||||
|
d.assetModelField.SetLabelColor(bgColor)
|
||||||
|
d.assetModelField.SetBackgroundColor(style.DialogFgColor)
|
||||||
|
d.assetModelField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||||
|
|
||||||
|
d.assetPriceField.SetLabel("price:")
|
||||||
|
d.assetPriceField.SetLabelWidth(pageLabelWidth)
|
||||||
|
d.assetPriceField.SetLabelColor(bgColor)
|
||||||
|
d.assetPriceField.SetBackgroundColor(style.DialogFgColor)
|
||||||
|
d.assetPriceField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||||
|
|
||||||
|
d.generalInfoPage.SetDirection(tview.FlexRow)
|
||||||
|
d.generalInfoPage.AddItem(d.assetNameField, 1, 0, true)
|
||||||
|
d.generalInfoPage.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||||
|
d.generalInfoPage.AddItem(d.assetQuantityField, 1, 0, true)
|
||||||
|
d.generalInfoPage.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||||
|
d.generalInfoPage.AddItem(d.assetLengthField, 1, 0, true)
|
||||||
|
d.generalInfoPage.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||||
|
d.generalInfoPage.AddItem(d.assetManufacturerField, 1, 0, true)
|
||||||
|
d.generalInfoPage.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||||
|
d.generalInfoPage.AddItem(d.assetModelField, 1, 0, true)
|
||||||
|
d.generalInfoPage.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||||
|
d.generalInfoPage.AddItem(d.assetPriceField, 1, 0, true)
|
||||||
|
d.generalInfoPage.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetEditDialog) setupLocationPageUI() {
|
||||||
|
bgColor := style.DialogBgColor
|
||||||
|
inputFieldBgColor := style.InputFieldBgColor
|
||||||
|
pageLabelWidth := 12
|
||||||
|
ddUnselectedStyle := style.DropdownUnselected
|
||||||
|
ddSelectedStyle := style.DropdownSelected
|
||||||
|
|
||||||
|
d.assetCategoryField.SetLabel("category:")
|
||||||
|
d.assetCategoryField.SetLabelWidth(pageLabelWidth)
|
||||||
|
d.assetCategoryField.SetBackgroundColor(bgColor)
|
||||||
|
d.assetCategoryField.SetLabelColor(style.DialogFgColor)
|
||||||
|
d.assetCategoryField.SetListStyles(ddUnselectedStyle, ddSelectedStyle)
|
||||||
|
d.assetCategoryField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||||
|
|
||||||
|
d.assetShelfField.SetLabel("shelf:")
|
||||||
|
d.assetShelfField.SetLabelWidth(pageLabelWidth)
|
||||||
|
d.assetShelfField.SetBackgroundColor(bgColor)
|
||||||
|
d.assetShelfField.SetLabelColor(style.DialogFgColor)
|
||||||
|
d.assetShelfField.SetListStyles(ddUnselectedStyle, ddSelectedStyle)
|
||||||
|
d.assetShelfField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||||
|
|
||||||
|
d.locationPage.SetDirection(tview.FlexRow)
|
||||||
|
d.locationPage.AddItem(d.assetCategoryField, 1, 0, true)
|
||||||
|
d.locationPage.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||||
|
d.locationPage.AddItem(d.assetShelfField, 1, 0, true)
|
||||||
|
d.locationPage.SetBackgroundColor(bgColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetEditDialog) setupCommentsPageUI() {
|
||||||
|
bgColor := style.DialogBgColor
|
||||||
|
inputFieldBgColor := style.InputFieldBgColor
|
||||||
|
pageLabelWidth := 12
|
||||||
|
|
||||||
|
d.assetCommentsArea.SetLabel("comments:")
|
||||||
|
d.assetCommentsArea.SetLabelWidth(pageLabelWidth)
|
||||||
|
d.assetCommentsArea.SetBackgroundColor(inputFieldBgColor)
|
||||||
|
d.assetCommentsArea.SetLabelStyle(tcell.StyleDefault.Foreground(style.DialogFgColor).Background(bgColor))
|
||||||
|
d.assetCommentsArea.SetWrap(true)
|
||||||
|
|
||||||
|
d.commentsPage.AddItem(d.assetCommentsArea, 0, 1, true)
|
||||||
|
d.commentsPage.SetBackgroundColor(bgColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetEditDialog) setActiveCategory(idx int) {
|
||||||
|
fgColor := style.ButtonSelectedFgColor
|
||||||
|
bgBolor := style.ButtonSelectedBgColor
|
||||||
|
ctgTextColor := style.GetColorHex(fgColor)
|
||||||
|
ctgBgColor := style.GetColorHex(bgBolor)
|
||||||
|
|
||||||
|
d.activePageIndex = idx
|
||||||
|
|
||||||
|
d.categories.Clear()
|
||||||
|
|
||||||
|
alignedList, _ := utils.AlignStringListWidth(d.editCategoryLabels)
|
||||||
|
|
||||||
|
var ctgList []string
|
||||||
|
|
||||||
|
for i, lbl := range alignedList {
|
||||||
|
if i == idx {
|
||||||
|
ctgList = append(ctgList, fmt.Sprintf("[%s:%s:b]-> %s ", ctgTextColor, ctgBgColor, lbl))
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ctgList = append(ctgList, fmt.Sprintf("[-:-:-] %s ", lbl))
|
||||||
|
}
|
||||||
|
|
||||||
|
d.categories.SetText(strings.Join(ctgList, "\n"))
|
||||||
|
|
||||||
|
d.categoryPages.SwitchToPage(d.editCategoryLabels[idx])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetEditDialog) nextCategory() {
|
||||||
|
activePage := d.activePageIndex
|
||||||
|
if d.activePageIndex < len(d.editCategoryLabels)-1 {
|
||||||
|
activePage++
|
||||||
|
|
||||||
|
d.setActiveCategory(activePage)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
d.setActiveCategory(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetEditDialog) previousCategory() {
|
||||||
|
activePage := d.activePageIndex
|
||||||
|
if d.activePageIndex > 0 {
|
||||||
|
activePage--
|
||||||
|
|
||||||
|
d.setActiveCategory(activePage)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
d.setActiveCategory(len(d.editCategoryLabels) - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetEditDialog) initCustomInputHandlers() {
|
||||||
|
d.assetShelfField.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
||||||
|
event = utils.ParseKeyEventKey(d.logger, event)
|
||||||
|
|
||||||
|
return event
|
||||||
|
})
|
||||||
|
|
||||||
|
d.assetCategoryField.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
||||||
|
event = utils.ParseKeyEventKey(d.logger, event)
|
||||||
|
|
||||||
|
return event
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetEditDialog) setGeneralInfoNextFocus() {
|
||||||
|
// Name -> Quantity -> Length -> Manufacturer -> Model -> Price
|
||||||
|
if d.assetNameField.HasFocus() {
|
||||||
|
d.focusElement = editAssetQuantityFieldFocus
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.assetQuantityField.HasFocus() {
|
||||||
|
d.focusElement = editAssetLengthFieldFocus
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.assetLengthField.HasFocus() {
|
||||||
|
d.focusElement = editAssetManufacturerFieldFocus
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.assetManufacturerField.HasFocus() {
|
||||||
|
d.focusElement = editAssetModelFieldFocus
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.assetModelField.HasFocus() {
|
||||||
|
d.focusElement = editAssetPriceFieldFocus
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
d.focusElement = editAssetFormFocus
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetEditDialog) setLocationNextFocus() {
|
||||||
|
// Category -> Shelf
|
||||||
|
if d.assetCategoryField.HasFocus() {
|
||||||
|
d.focusElement = editAssetShelfFieldFocus
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
d.focusElement = editAssetFormFocus
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetEditDialog) setCommentsNextFocus() {
|
||||||
|
d.focusElement = editAssetFormFocus
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *AssetEditDialog) EditAssetOptions() types.CreateAssetRequest {
|
||||||
|
var (
|
||||||
|
quantity int
|
||||||
|
categoryID *uint64
|
||||||
|
shelfID *uint64
|
||||||
|
price float64
|
||||||
|
)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
selectedCategoryIndex, _ := d.assetCategoryField.GetCurrentOption()
|
||||||
|
if len(d.categoryList) > 0 && selectedCategoryIndex > 0 {
|
||||||
|
categoryID = &d.categoryList[selectedCategoryIndex-1].ID
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedShelfIndex, _ := d.assetShelfField.GetCurrentOption()
|
||||||
|
if len(d.shelfList) > 0 && selectedShelfIndex > 0 {
|
||||||
|
shelfID = &d.shelfList[selectedShelfIndex-1].ID
|
||||||
|
}
|
||||||
|
|
||||||
|
quantityStr := d.assetQuantityField.GetText()
|
||||||
|
quantity, err = strconv.Atoi(quantityStr)
|
||||||
|
if err != nil {
|
||||||
|
quantity = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
priceStr := d.assetPriceField.GetText()
|
||||||
|
price, err = strconv.ParseFloat(priceStr, 64)
|
||||||
|
if err != nil {
|
||||||
|
price = 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
req := types.CreateAssetRequest{
|
||||||
|
Name: d.assetNameField.GetText(),
|
||||||
|
Quantity: quantity,
|
||||||
|
Length: d.assetLengthField.GetText(),
|
||||||
|
Manufacturer: d.assetManufacturerField.GetText(),
|
||||||
|
ModelName: d.assetModelField.GetText(),
|
||||||
|
Price: price,
|
||||||
|
Comments: d.assetCommentsArea.GetText(),
|
||||||
|
ShelfLocationID: shelfID,
|
||||||
|
CategoryID: categoryID,
|
||||||
|
}
|
||||||
|
|
||||||
|
return req
|
||||||
|
}
|
||||||
@@ -11,8 +11,8 @@ func (a *Assets) runCommand(cmd string) {
|
|||||||
switch cmd {
|
switch cmd {
|
||||||
case "create asset":
|
case "create asset":
|
||||||
a.createDialog.Display()
|
a.createDialog.Display()
|
||||||
case "view asset":
|
case "edit asset":
|
||||||
a.cNotImplemented()
|
a.cedit()
|
||||||
case "delete asset":
|
case "delete asset":
|
||||||
a.cdelete()
|
a.cdelete()
|
||||||
case "refresh":
|
case "refresh":
|
||||||
@@ -48,6 +48,41 @@ func (a *Assets) cdelete() {
|
|||||||
a.confirmDialog.Display()
|
a.confirmDialog.Display()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *Assets) cedit() {
|
||||||
|
selectedItem := a.getSelectedItem()
|
||||||
|
if selectedItem == nil {
|
||||||
|
a.displayError("DELETE ASSET ERROR", fmt.Errorf("no assets to edit"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
asset, err := a.client.RetrieveAssetByID(selectedItem.id)
|
||||||
|
if err != nil {
|
||||||
|
a.displayError("DELETE ASSET ERROR", fmt.Errorf("unable to retrieve asset from server"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
a.editDialog.SetAsset(asset)
|
||||||
|
a.editDialog.Display()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Assets) edit() {
|
||||||
|
selectedItem := a.getSelectedItem()
|
||||||
|
createReq := a.editDialog.EditAssetOptions()
|
||||||
|
if createReq.Name == "" {
|
||||||
|
a.displayError("ASSET EDIT ERROR", fmt.Errorf("asset name cannot be empty"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := a.client.UpdateAsset(selectedItem.id, createReq)
|
||||||
|
if err != nil {
|
||||||
|
a.displayError("ASSET EDIT ERROR", err)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
a.crefresh()
|
||||||
|
}
|
||||||
|
|
||||||
func (a *Assets) delete() {
|
func (a *Assets) delete() {
|
||||||
selectedItem := a.getSelectedItem()
|
selectedItem := a.getSelectedItem()
|
||||||
|
|
||||||
@@ -87,7 +122,7 @@ func (a *Assets) crefresh() {
|
|||||||
a.progressDialog.Hide()
|
a.progressDialog.Hide()
|
||||||
|
|
||||||
if !a.errorDialog.IsDisplay() {
|
if !a.errorDialog.IsDisplay() {
|
||||||
a.messageDialog.SetTitle(fmt.Sprintf("asset refresh"))
|
a.messageDialog.SetTitle("asset refresh")
|
||||||
a.messageDialog.SetText(dialogs.MessageGeneric, "Refreshed!", "Successfully refreshed page.")
|
a.messageDialog.SetText(dialogs.MessageGeneric, "Refreshed!", "Successfully refreshed page.")
|
||||||
a.messageDialog.Display()
|
a.messageDialog.Display()
|
||||||
}
|
}
|
||||||
@@ -96,6 +131,25 @@ func (a *Assets) crefresh() {
|
|||||||
ref()
|
ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *Assets) create() {
|
||||||
|
createReq := a.createDialog.CreateAssetOptions()
|
||||||
|
if createReq.Name == "" {
|
||||||
|
a.displayError("ASSET CREATE ERROR", fmt.Errorf("asset name cannot be empty"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := a.client.CreateAsset(createReq)
|
||||||
|
if err != nil {
|
||||||
|
a.displayError("ASSET CREATE ERROR", err)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
a.crefresh()
|
||||||
|
a.assetTable.ScrollToEnd()
|
||||||
|
a.assetTable.Select(a.assetTable.GetRowCount(), 0)
|
||||||
|
}
|
||||||
|
|
||||||
func (a *Assets) displayError(title string, err error) {
|
func (a *Assets) displayError(title string, err error) {
|
||||||
a.errorDialog.SetTitle(title)
|
a.errorDialog.SetTitle(title)
|
||||||
a.errorDialog.SetText(fmt.Sprintf("%v", err))
|
a.errorDialog.SetText(fmt.Sprintf("%v", err))
|
||||||
|
|||||||
@@ -33,6 +33,18 @@ func (a *Assets) InputHandler() func(*tcell.EventKey, func(tview.Primitive)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if a.createDialog.HasFocus() {
|
||||||
|
if createHandler := a.createDialog.InputHandler(); createHandler != nil {
|
||||||
|
createHandler(event, setFocus)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.editDialog.HasFocus() {
|
||||||
|
if editHandler := a.editDialog.InputHandler(); editHandler != nil {
|
||||||
|
editHandler(event, setFocus)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if a.cmdDialog.HasFocus() {
|
if a.cmdDialog.HasFocus() {
|
||||||
if cmdHandler := a.cmdDialog.InputHandler(); cmdHandler != nil {
|
if cmdHandler := a.cmdDialog.InputHandler(); cmdHandler != nil {
|
||||||
cmdHandler(event, setFocus)
|
cmdHandler(event, setFocus)
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ var (
|
|||||||
// dialogs
|
// dialogs
|
||||||
DialogBgColor = tcell.ColorLightBlue
|
DialogBgColor = tcell.ColorLightBlue
|
||||||
DialogFgColor = tcell.ColorBlack
|
DialogFgColor = tcell.ColorBlack
|
||||||
DialogBorderColor = tcell.ColorLightBlue
|
DialogBorderColor = tcell.ColorWhite
|
||||||
DialogSubBoxBgColor = tcell.ColorWhite
|
DialogSubBoxBgColor = tcell.ColorWhite
|
||||||
DialogSubBoxFgColor = tcell.ColorBlack
|
DialogSubBoxFgColor = tcell.ColorBlack
|
||||||
DialogSubBoxBorderColor = tcell.ColorLightBlue
|
DialogSubBoxBorderColor = tcell.ColorLightBlue
|
||||||
|
|||||||
Reference in New Issue
Block a user