diff --git a/.vscode/settings.json b/.vscode/settings.json
index c0a42c9f..f04ae7fa 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -18,5 +18,8 @@
"typescript.preferences.importModuleSpecifier": "relative",
"typescript.suggest.autoImports": true,
"javascript.suggest.autoImports": true,
- "editor.acceptSuggestionOnEnter": "on"
+ "editor.acceptSuggestionOnEnter": "on",
+ "files.associations": {
+ "*.tbx": "json"
+ }
}
diff --git a/app/app.go b/app/app.go
index 129b118e..928fc475 100644
--- a/app/app.go
+++ b/app/app.go
@@ -3,33 +3,29 @@ package app
import (
"context"
"encoding/json"
- "os"
- "path/filepath"
+ "errors"
+ "fmt"
"sync"
"github.com/TrueBlocks/trueblocks-browse/pkg/daemons"
- "github.com/TrueBlocks/trueblocks-browse/pkg/messages"
"github.com/TrueBlocks/trueblocks-browse/pkg/types"
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
- coreConfig "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/config"
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/file"
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger"
+ "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/names"
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/output"
coreTypes "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types"
- "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/utils"
sdk "github.com/TrueBlocks/trueblocks-sdk/v3"
"github.com/wailsapp/wails/v2/pkg/runtime"
)
type App struct {
- sdk.Globals `json:",inline"`
+ sdk.Globals
ctx context.Context
meta coreTypes.MetaData
dirty bool
- renderCtxs map[base.Address][]*output.RenderCtx
-
// Containers
projects types.ProjectContainer
monitors types.MonitorContainer
@@ -43,101 +39,112 @@ type App struct {
config types.ConfigContainer
// Memory caches
- HistoryCache *types.HistoryMap `json:"historyCache"`
- EnsCache *sync.Map `json:"ensCache"`
- BalanceCache *sync.Map `json:"balanceCache"`
+ ensCache *sync.Map
+ balanceCache *sync.Map
+ namesMap map[base.Address]coreTypes.Name
+ historyCache *types.HistoryMap
+ renderCtxs map[base.Address][]*output.RenderCtx
// Controllers
- ScraperController *daemons.DaemonScraper
- FreshenController *daemons.DaemonFreshen
- IpfsController *daemons.DaemonIpfs
+ scraperController *daemons.DaemonScraper
+ freshenController *daemons.DaemonFreshen
+ ipfsController *daemons.DaemonIpfs
+
+ // During initialization, we do things that may cause errors, but
+ // we have not yet opened the window, so we defer them until we can
+ // decide what to do.
+ deferredErrors []error
+}
+
+func (a *App) String() string {
+ bytes, _ := json.Marshal(a)
+ return string(bytes)
}
func NewApp() *App {
- a := App{
- renderCtxs: make(map[base.Address][]*output.RenderCtx),
+ a := &App{
+ ensCache: &sync.Map{},
+ balanceCache: &sync.Map{},
+ namesMap: make(map[base.Address]coreTypes.Name),
+ historyCache: &types.HistoryMap{},
+ renderCtxs: make(map[base.Address][]*output.RenderCtx),
}
- a.EnsCache = &sync.Map{}
- a.BalanceCache = &sync.Map{}
- a.HistoryCache = &types.HistoryMap{}
- a.names.NamesMap = make(map[base.Address]coreTypes.Name)
- a.projects = types.NewProjectContainer("", []types.HistoryContainer{})
+ a.freshenController = daemons.NewFreshen(a, "freshen", 3000, a.IsShowing("freshen"))
+ a.scraperController = daemons.NewScraper(a, "scraper", 7000, a.IsShowing("scraper"))
+ a.ipfsController = daemons.NewIpfs(a, "ipfs", 10000, a.IsShowing("ipfs"))
a.session.LastSub = make(map[string]string)
- return &a
+ return a
}
-func (a *App) String() string {
- bytes, _ := json.MarshalIndent(a, "", " ")
- return string(bytes)
-}
+var ErrLoadingNames = errors.New("error loading names")
+var ErrWindowSize = errors.New("error fixing window size")
func (a *App) Startup(ctx context.Context) {
a.ctx = ctx
- a.loadSession()
- a.Chain = a.session.LastChain
- a.FreshenController = daemons.NewFreshen(a, "freshen", 3000, a.IsShowing("freshen"))
- a.ScraperController = daemons.NewScraper(a, "scraper", 7000, a.IsShowing("scraper"))
- a.IpfsController = daemons.NewIpfs(a, "ipfs", 10000, a.IsShowing("ipfs"))
- go a.startDaemons()
+ // We do various setups prior to showing the window. Improves interactivity.
+ // But...something may fail, so we need to keep track of errors.
+ var err error
+ if err = a.session.Load(); err != nil {
+ a.deferredErrors = append(a.deferredErrors, err)
+ }
- fn := filepath.Join(a.session.LastFolder, a.session.LastFile)
- if file.FileExists(fn) {
- a.LoadFile(fn)
- a.dirty = false
- } else {
- a.dirty = true
+ // Load the trueBlocks.toml file
+ if err = a.config.Load(); err != nil {
+ a.deferredErrors = append(a.deferredErrors, err)
+ }
+ if a.session.LastChain, err = a.config.IsValidChain(a.session.LastChain); err != nil {
+ a.deferredErrors = append(a.deferredErrors, err)
}
+ a.Chain = a.session.LastChain
- logger.Info("Starting freshen process...")
- _ = a.Refresh()
+ // We always need names, so let's load it before showing the window
+ if a.namesMap, err = names.LoadNamesMap(a.getChain(), coreTypes.All, nil); err == nil {
+ wErr := fmt.Errorf("%w: %v", ErrLoadingNames, err)
+ a.deferredErrors = append(a.deferredErrors, wErr)
+ }
}
+// DomReady is called by Wails when the app is ready to go. Adjust the window size and show it.
func (a *App) DomReady(ctx context.Context) {
- win := a.GetWindow()
- runtime.WindowSetPosition(a.ctx, win.X, win.Y)
- runtime.WindowSetSize(a.ctx, win.Width, win.Height)
- runtime.WindowShow(a.ctx)
+ var err error
- if path, err := utils.GetConfigFn("", "trueBlocks.toml"); err != nil {
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: err.Error(),
- })
- } else {
- if err := coreConfig.ReadToml(path, &a.config.Config); err != nil {
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: err.Error(),
- })
- }
+ // We're ready to open the window, but first we need to make sure it will show...
+ if a.session.Window, err = a.session.CleanWindowSize(a.ctx); err != nil {
+ wErr := fmt.Errorf("%w: %v", ErrWindowSize, err)
+ a.deferredErrors = append(a.deferredErrors, wErr)
+ }
+ // DO NOT COLLAPSE - A VALID WINDOW IS RETURNED EVEN ON ERROR
+ runtime.WindowSetPosition(a.ctx, a.session.Window.X, a.session.Window.Y)
+ runtime.WindowSetSize(a.ctx, a.session.Window.Width, a.session.Window.Height)
+ runtime.WindowShow(a.ctx)
+ if err != nil {
+ a.deferredErrors = append(a.deferredErrors, err)
}
-}
-func (a *App) Shutdown(ctx context.Context) {
- a.saveSession()
-}
+ // We now have a window, so we can finally show any accumulated errors
+ for _, err := range a.deferredErrors {
+ a.emitErrorMsg(err, nil)
+ }
-func (a *App) saveSession() {
- if !isTesting {
- a.session.Window.X, a.session.Window.Y = runtime.WindowGetPosition(a.ctx)
- a.session.Window.Width, a.session.Window.Height = runtime.WindowGetSize(a.ctx)
- a.session.Window.Y += 38 // TODO: This is a hack to account for the menu bar - not sure why it's needed
+ fn := a.getFullPath()
+ if file.FileExists(fn) {
+ a.readFile(fn)
+ } else {
+ a.newFile()
}
- _ = a.session.Save()
-}
-func (a *App) loadSession() {
- _ = a.session.Load()
- a.session.CleanWindowSize(a.ctx)
- a.Chain = a.session.LastChain
-}
+ go a.Refresh()
-func (a *App) Logger(msg string) {
- logger.Info(msg)
-}
+ go a.freshenController.Run()
+ go a.scraperController.Run()
+ go a.ipfsController.Run()
-var isTesting bool
+ logger.Info("Fininished loading...")
+}
-func init() {
- isTesting = os.Getenv("TB_TEST_MODE") == "true"
+// Shutdown is called by Wails when the app is closed
+func (a *App) Shutdown(ctx context.Context) {
+ a.saveSession()
}
diff --git a/app/app_debug.go b/app/app_debug.go
deleted file mode 100644
index b9e32314..00000000
--- a/app/app_debug.go
+++ /dev/null
@@ -1,7 +0,0 @@
-package app
-
-import "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger"
-
-func debugMsg(v ...any) {
- logger.Info(v...)
-}
diff --git a/app/app_getters.go b/app/app_getters.go
index 480b1a66..daf39946 100644
--- a/app/app_getters.go
+++ b/app/app_getters.go
@@ -34,16 +34,12 @@ func (a *App) GetEnv(key string) string {
return os.Getenv(key)
}
-func (a *App) GetMeta() coreTypes.MetaData {
- return a.meta
-}
-
func (a *App) GetAppTitle() string {
return a.session.Window.Title
}
func (a *App) GetRoute() string {
- if !a.IsConfigured() {
+ if !a.isConfigured() {
return "/wizard"
}
@@ -55,12 +51,12 @@ func (a *App) GetRoute() string {
return route
}
-func (a *App) GetAddress() base.Address {
+func (a *App) GetSelected() base.Address {
addr := a.session.LastSub["/history"]
return base.HexToAddress(addr)
}
-func (a *App) GetChain() string {
+func (a *App) getChain() string {
return a.Chain
}
diff --git a/app/app_info.go b/app/app_info.go
new file mode 100644
index 00000000..6970d6e4
--- /dev/null
+++ b/app/app_info.go
@@ -0,0 +1,39 @@
+package app
+
+import (
+ "path/filepath"
+
+ coreTypes "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types"
+)
+
+type AppInfo struct {
+ Chain string `json:"chain"`
+ Filename string `json:"filename"`
+ Dirty bool `json:"dirty"`
+ Meta coreTypes.MetaData `json:"meta"`
+ State coreTypes.WizState `json:"state"`
+ IsConfigured bool `json:"isConfigured"`
+}
+
+func (a *App) getFolder() string {
+ return a.session.LastFolder
+}
+
+func (a *App) getFilename() string {
+ return a.session.LastFile
+}
+
+func (a *App) getFullPath() string {
+ return filepath.Join(a.getFolder(), a.getFilename())
+}
+
+func (a *App) GetAppInfo() AppInfo {
+ return AppInfo{
+ Chain: a.Chain,
+ Filename: a.getFullPath(),
+ Dirty: a.dirty,
+ Meta: a.meta,
+ State: a.getWizardState(),
+ IsConfigured: a.isConfigured(),
+ }
+}
diff --git a/app/app_setters.go b/app/app_setters.go
index 54b3237b..032d0589 100644
--- a/app/app_setters.go
+++ b/app/app_setters.go
@@ -3,7 +3,6 @@ package app
import (
"os"
- "github.com/TrueBlocks/trueblocks-browse/pkg/types"
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
)
@@ -22,11 +21,12 @@ func (a *App) SetRoute(route, subRoute string) {
}
func (a *App) SetChain(chain string, address base.Address) {
- a.CancelAllContexts() // cancel what's happening on the old chain
+ a.emitInfoMsg("Switching to chain", chain)
+ a.CancelAllContexts()
a.Chain = chain
a.session.LastChain = chain
a.saveSession()
- a.Reload(address)
+ a.GoToAddress(address)
a.monitors = types.MonitorContainer{}
a.names = types.NameContainer{}
a.abis = types.AbiContainer{}
diff --git a/app/data_abi.go b/app/data_abi.go
index 9dcff6ba..31d9fc07 100644
--- a/app/data_abi.go
+++ b/app/data_abi.go
@@ -9,7 +9,6 @@ import (
"sync/atomic"
"time"
- "github.com/TrueBlocks/trueblocks-browse/pkg/messages"
"github.com/TrueBlocks/trueblocks-browse/pkg/types"
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
coreTypes "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types"
@@ -76,12 +75,10 @@ func (a *App) loadAbis(wg *sync.WaitGroup, errorChan chan error) error {
// EXISTING_CODE
// EXISTING_CODE
if err := sdk.SortAbis(a.abis.Items, a.abis.Sorts); err != nil {
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: err.Error(),
- })
+ a.emitErrorMsg(err, nil)
}
a.abis.Summarize()
- messages.EmitMessage(a.ctx, messages.Info, &messages.MessageMsg{String1: "Loaded abis"})
+ a.emitInfoMsg("Loaded abis", "")
}
return nil
@@ -95,10 +92,7 @@ func (a *App) ModifyAbi(modData *ModifyData) error {
opts.Globals.Decache = true
if _, _, err := opts.Abis(); err != nil {
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: err.Error(),
- Address: modData.Address,
- })
+ a.emitAddressErrorMsg(err, modData.Address)
return err
} else {
newAbis := make([]coreTypes.Abi, 0, len(a.abis.Items))
@@ -113,8 +107,7 @@ func (a *App) ModifyAbi(modData *ModifyData) error {
}
a.abis.LastUpdate = time.Time{}
a.abis.Items = newAbis
- msg := fmt.Sprintf("ModifyAbi delete: %s", modData.Address.Hex())
- messages.EmitMessage(a.ctx, messages.Info, &messages.MessageMsg{String1: msg})
+ a.emitInfoMsg("ModifyAbi delete", modData.Address.Hex())
return nil
}
}
diff --git a/app/data_history.go b/app/data_history.go
index cc0ee615..7b5e8176 100644
--- a/app/data_history.go
+++ b/app/data_history.go
@@ -6,6 +6,7 @@ import (
"fmt"
"sort"
"sync"
+ "time"
"github.com/TrueBlocks/trueblocks-browse/pkg/messages"
"github.com/TrueBlocks/trueblocks-browse/pkg/types"
@@ -19,20 +20,18 @@ func (a *App) HistoryPage(addr string, first, pageSize int) *types.HistoryContai
address, ok := a.ConvertToAddress(addr)
if !ok {
err := fmt.Errorf("Invalid address: " + addr)
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: err.Error(),
- })
+ a.emitErrorMsg(err, nil)
return &types.HistoryContainer{}
}
- _, exists := a.HistoryCache.Load(address)
+ _, exists := a.historyCache.Load(address)
if !exists {
return &types.HistoryContainer{}
}
first = base.Max(0, base.Min(first, a.txCount(address)-1))
last := base.Min(a.txCount(address), first+pageSize)
- history, _ := a.HistoryCache.Load(address)
+ history, _ := a.historyCache.Load(address)
history.Summarize()
copy := history.ShallowCopy().(*types.HistoryContainer)
copy.Balance = a.getBalance(address)
@@ -46,10 +45,7 @@ func (a *App) getHistoryCnt(address base.Address) uint64 {
Globals: a.toGlobals(),
}
if appearances, meta, err := opts.ListCount(); err != nil {
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: err.Error(),
- Address: address,
- })
+ a.emitAddressErrorMsg(err, address)
return 0
} else if len(appearances) == 0 {
return 0
@@ -60,13 +56,13 @@ func (a *App) getHistoryCnt(address base.Address) uint64 {
}
func (a *App) isFileOpen(address base.Address) bool {
- _, isOpen := a.HistoryCache.Load(address)
+ _, isOpen := a.historyCache.Load(address)
return isOpen
}
func (a *App) txCount(address base.Address) int {
if a.isFileOpen(address) {
- history, _ := a.HistoryCache.Load(address)
+ history, _ := a.historyCache.Load(address)
return len(history.Items)
} else {
return 0
@@ -89,7 +85,7 @@ func (a *App) loadHistory(address base.Address, wg *sync.WaitGroup, errorChan ch
// }
// defer historyLock.CompareAndSwap(1, 0)
- history, exists := a.HistoryCache.Load(address)
+ history, exists := a.historyCache.Load(address)
if exists {
if !history.NeedsUpdate(a.forceHistory()) {
return nil
@@ -99,10 +95,7 @@ func (a *App) loadHistory(address base.Address, wg *sync.WaitGroup, errorChan ch
_ = errorChan // delint
logger.Info("Loading history for address: ", address.Hex())
if err := a.thing(address, 15); err != nil {
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: err.Error(),
- Address: address,
- })
+ a.emitAddressErrorMsg(err, address)
return err
}
a.loadProjects(nil, nil)
@@ -133,10 +126,10 @@ func (a *App) thing(address base.Address, freq int) error {
if !ok {
continue
}
- summary, _ := a.HistoryCache.Load(address)
+ summary, _ := a.historyCache.Load(address)
summary.NTotal = nItems
summary.Address = address
- summary.Name = a.names.NamesMap[address].Name
+ summary.Name = a.namesMap[address].Name
summary.Items = append(summary.Items, *tx)
if len(summary.Items)%(freq*3) == 0 {
sort.Slice(summary.Items, func(i, j int) bool {
@@ -145,24 +138,17 @@ func (a *App) thing(address base.Address, freq int) error {
}
return summary.Items[i].BlockNumber > summary.Items[j].BlockNumber
})
- messages.EmitMessage(a.ctx, messages.Progress, &messages.MessageMsg{
- Address: address,
- Num1: len(summary.Items),
- Num2: int(nItems),
- })
+ a.emitProgressMsg(messages.Progress, address, len(summary.Items), int(nItems))
}
if len(summary.Items) == 0 {
- a.HistoryCache.Delete(address)
+ a.historyCache.Delete(address)
} else {
- a.HistoryCache.Store(address, summary)
+ a.historyCache.Store(address, summary)
}
case err := <-opts.RenderCtx.ErrorChan:
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: err.Error(),
- Address: address,
- })
+ a.emitAddressErrorMsg(err, address)
default:
if opts.RenderCtx.WasCanceled() {
@@ -178,7 +164,7 @@ func (a *App) thing(address base.Address, freq int) error {
}
a.meta = *meta
- history, _ := a.HistoryCache.Load(address)
+ history, _ := a.historyCache.Load(address)
sort.Slice(history.Items, func(i, j int) bool {
if history.Items[i].BlockNumber == history.Items[j].BlockNumber {
return history.Items[i].TransactionIndex > history.Items[j].TransactionIndex
@@ -186,12 +172,8 @@ func (a *App) thing(address base.Address, freq int) error {
return history.Items[i].BlockNumber > history.Items[j].BlockNumber
})
history.Summarize()
- a.HistoryCache.Store(address, history)
- messages.EmitMessage(a.ctx, messages.Completed, &messages.MessageMsg{
- Address: address,
- Num1: a.txCount(address),
- Num2: a.txCount(address),
- })
+ a.historyCache.Store(address, history)
+ a.emitProgressMsg(messages.Completed, address, a.txCount(address), a.txCount(address))
return nil
}
@@ -201,3 +183,36 @@ func (a *App) forceHistory() (force bool) {
// EXISTING_CODE
return
}
+
+// EXISTING_CODE
+func (a *App) Reload() {
+ switch a.session.LastRoute {
+ case "/names":
+ logger.InfoC("Reloading names")
+ a.names.LastUpdate = time.Time{}
+ if err := a.loadNames(nil, nil); err != nil {
+ a.emitErrorMsg(err, nil)
+ }
+ }
+}
+
+func (a *App) GoToAddress(address base.Address) {
+ logger.Info("--------------------------- enter -------------------------------------------")
+ logger.Info("GoToAddress: ", address.Hex())
+ if address == base.ZeroAddr {
+ logger.Info("--------------------------- zeroAddr exit -------------------------------------------")
+ return
+ }
+
+ a.SetRoute("/history", address.Hex())
+
+ a.cancelContext(address)
+ a.historyCache.Delete(address)
+ a.loadHistory(address, nil, nil)
+
+ a.emitNavigateMsg(a.GetRoute())
+ a.emitInfoMsg("viewing address", address.Hex())
+ logger.Info("--------------------------- exit -------------------------------------------")
+}
+
+// EXISTING_CODE
diff --git a/app/data_index.go b/app/data_index.go
index 65f7b6b1..4ac5a3ae 100644
--- a/app/data_index.go
+++ b/app/data_index.go
@@ -8,7 +8,6 @@ import (
"sync"
"sync/atomic"
- "github.com/TrueBlocks/trueblocks-browse/pkg/messages"
"github.com/TrueBlocks/trueblocks-browse/pkg/types"
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
sdk "github.com/TrueBlocks/trueblocks-sdk/v3"
@@ -71,12 +70,10 @@ func (a *App) loadIndexes(wg *sync.WaitGroup, errorChan chan error) error {
// EXISTING_CODE
// EXISTING_CODE
if err := sdk.SortIndexes(a.indexes.Items, a.indexes.Sorts); err != nil {
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: err.Error(),
- })
+ a.emitErrorMsg(err, nil)
}
a.indexes.Summarize()
- messages.EmitMessage(a.ctx, messages.Info, &messages.MessageMsg{String1: "Loaded indexes"})
+ a.emitInfoMsg("Loaded indexes", "")
}
return nil
diff --git a/app/data_manifest.go b/app/data_manifest.go
index cd806dc4..e6e22563 100644
--- a/app/data_manifest.go
+++ b/app/data_manifest.go
@@ -8,7 +8,6 @@ import (
"sync"
"sync/atomic"
- "github.com/TrueBlocks/trueblocks-browse/pkg/messages"
"github.com/TrueBlocks/trueblocks-browse/pkg/types"
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
sdk "github.com/TrueBlocks/trueblocks-sdk/v3"
@@ -71,12 +70,10 @@ func (a *App) loadManifests(wg *sync.WaitGroup, errorChan chan error) error {
// EXISTING_CODE
// EXISTING_CODE
if err := sdk.SortManifests(a.manifests.Items, a.manifests.Sorts); err != nil {
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: err.Error(),
- })
+ a.emitErrorMsg(err, nil)
}
a.manifests.Summarize()
- messages.EmitMessage(a.ctx, messages.Info, &messages.MessageMsg{String1: "Loaded manifests"})
+ a.emitInfoMsg("Loaded manifests", "")
}
return nil
diff --git a/app/data_monitor.go b/app/data_monitor.go
index ab8fe3a8..ff8ab02e 100644
--- a/app/data_monitor.go
+++ b/app/data_monitor.go
@@ -9,7 +9,6 @@ import (
"sync"
"sync/atomic"
- "github.com/TrueBlocks/trueblocks-browse/pkg/messages"
"github.com/TrueBlocks/trueblocks-browse/pkg/types"
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/crud"
@@ -71,7 +70,7 @@ func (a *App) loadMonitors(wg *sync.WaitGroup, errorChan chan error) error {
} else {
// EXISTING_CODE
for i := 0; i < len(monitors); i++ {
- monitors[i].Name = a.names.NamesMap[monitors[i].Address].Name
+ monitors[i].Name = a.namesMap[monitors[i].Address].Name
}
// EXISTING_CODE
a.meta = *meta
@@ -86,7 +85,7 @@ func (a *App) loadMonitors(wg *sync.WaitGroup, errorChan chan error) error {
})
// EXISTING_CODE
a.monitors.Summarize()
- messages.EmitMessage(a.ctx, messages.Info, &messages.MessageMsg{String1: "Loaded monitors"})
+ a.emitInfoMsg("Loaded monitors", "")
}
return nil
@@ -116,9 +115,7 @@ func (a *App) ModifyMonitors(modData *ModifyData) error {
}
if _, _, err := opts.Monitors(); err != nil {
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: err.Error(),
- })
+ a.emitErrorMsg(err, nil)
return err
}
diff --git a/app/data_name.go b/app/data_name.go
index c7fd85ce..4400d5d6 100644
--- a/app/data_name.go
+++ b/app/data_name.go
@@ -8,7 +8,6 @@ import (
"sync"
"sync/atomic"
- "github.com/TrueBlocks/trueblocks-browse/pkg/messages"
"github.com/TrueBlocks/trueblocks-browse/pkg/types"
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
coreConfig "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/config"
@@ -85,7 +84,7 @@ func (a *App) loadNames(wg *sync.WaitGroup, errorChan chan error) error {
// EXISTING_CODE
// EXISTING_CODE
a.names.Summarize()
- messages.EmitMessage(a.ctx, messages.Info, &messages.MessageMsg{String1: "Loaded names"})
+ a.emitInfoMsg("Loaded names", "")
}
return nil
@@ -114,7 +113,7 @@ func (a *App) ModifyName(modData *ModifyData) error {
Source: "TrueBlocks Browse",
Tags: "99-User-Defined",
}
- if existing, ok := a.names.NamesMap[modData.Address]; ok {
+ if existing, ok := a.namesMap[modData.Address]; ok {
if existing.IsCustom {
// We preserve the tags if it's already customized
newName.Tags = existing.Tags
@@ -128,9 +127,7 @@ func (a *App) ModifyName(modData *ModifyData) error {
opts.Globals.Chain = namesChain
if _, _, err := opts.ModifyName(crud.OpFromString(op), cd); err != nil {
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: err.Error(),
- })
+ a.emitErrorMsg(err, nil)
return err
}
@@ -154,7 +151,7 @@ func (a *App) ModifyName(modData *ModifyData) error {
}
}
nameMutex.Lock()
- a.names.NamesMap[modData.Address] = name
+ a.namesMap[modData.Address] = name
nameMutex.Unlock()
}
newArray = append(newArray, name)
diff --git a/app/data_project.go b/app/data_project.go
index 28281fa8..d9c25690 100644
--- a/app/data_project.go
+++ b/app/data_project.go
@@ -9,7 +9,6 @@ import (
"sync"
"sync/atomic"
- "github.com/TrueBlocks/trueblocks-browse/pkg/messages"
"github.com/TrueBlocks/trueblocks-browse/pkg/types"
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/crud"
@@ -45,12 +44,11 @@ func (a *App) loadProjects(wg *sync.WaitGroup, errorChan chan error) error {
// EXISTING_CODE
items := []types.HistoryContainer{}
- a.HistoryCache.Range(func(_ base.Address, h types.HistoryContainer) bool {
+ a.historyCache.Range(func(_ base.Address, h types.HistoryContainer) bool {
items = append(items, h)
return true
})
a.projects = types.NewProjectContainer(a.session.LastChain, items)
-
if !a.projects.NeedsUpdate(a.forceProject()) {
return nil
}
@@ -82,10 +80,7 @@ func (a *App) loadProjects(wg *sync.WaitGroup, errorChan chan error) error {
aj := a.projects.Items[j].Address
return ai.Hex() < aj.Hex()
})
- messages.EmitMessage(a.ctx, messages.Info, &messages.MessageMsg{
- String1: fmt.Sprintf("After loadProject: %d projects", len(a.projects.Items)),
- })
-
+ a.emitInfoMsg("Loaded projects", "")
return nil
}
@@ -97,39 +92,17 @@ func (a *App) forceProject() (force bool) {
}
// EXISTING_CODE
-func (a *App) ModifyProject(modData *ModifyData) {
+func (a *App) DeleteAddress(modData *ModifyData) {
switch crud.OpFromString(modData.Operation) {
case crud.Delete:
a.cancelContext(modData.Address)
- a.HistoryCache.Delete(modData.Address)
- for i, history := range a.projects.Items {
- if history.Address == modData.Address {
- a.projects.Items = append(a.projects.Items[:i], a.projects.Items[i+1:]...)
- break
- }
- }
- a.loadProjects(nil, nil)
- }
-}
+ a.dirty = true
-func (a *App) Reload(address base.Address) {
- a.ModifyProject(&ModifyData{
- Operation: "delete",
- Address: address,
- })
- a.loadHistory(a.GetAddress(), nil, nil)
- _ = a.Refresh()
- a.loadProjects(nil, nil)
-}
-
-func (a *App) GoToHistory(address base.Address) {
- a.SetRoute("/history", address.Hex())
- a.Reload(address)
+ a.historyCache.Delete(modData.Address)
+ a.loadProjects(nil, nil)
- route := "/history/" + address.Hex()
- messages.EmitMessage(a.ctx, messages.Navigate, &messages.MessageMsg{
- String1: route,
- })
+ a.emitInfoMsg(a.getFullPath(), fmt.Sprint("deleted address", modData.Address.Hex()))
+ }
}
// EXISTING_CODE
diff --git a/app/data_session.go b/app/data_session.go
index 3efdc075..d69c12e7 100644
--- a/app/data_session.go
+++ b/app/data_session.go
@@ -8,9 +8,9 @@ import (
"sync"
"sync/atomic"
- "github.com/TrueBlocks/trueblocks-browse/pkg/messages"
"github.com/TrueBlocks/trueblocks-browse/pkg/types"
sdk "github.com/TrueBlocks/trueblocks-sdk/v3"
+ "github.com/wailsapp/wails/v2/pkg/runtime"
)
// EXISTING_CODE
@@ -69,7 +69,7 @@ func (a *App) loadSessions(wg *sync.WaitGroup, errorChan chan error) error {
a.session.Session = ss
// EXISTING_CODE
a.session.Summarize()
- messages.EmitMessage(a.ctx, messages.Info, &messages.MessageMsg{String1: "Loaded sessions"})
+ a.emitInfoMsg("Loaded sessions", "")
}
return nil
}
@@ -81,4 +81,13 @@ func (a *App) forceSession() (force bool) {
}
// EXISTING_CODE
+func (a *App) saveSession() {
+ if !isTesting {
+ a.session.Window.X, a.session.Window.Y = runtime.WindowGetPosition(a.ctx)
+ a.session.Window.Width, a.session.Window.Height = runtime.WindowGetSize(a.ctx)
+ a.session.Window.Y += 38 // TODO: This is a hack to account for the menu bar - not sure why it's needed
+ }
+ _ = a.session.Save()
+}
+
// EXISTING_CODE
diff --git a/app/data_settings.go b/app/data_settings.go
index 4c8737b8..34429731 100644
--- a/app/data_settings.go
+++ b/app/data_settings.go
@@ -6,7 +6,6 @@ import (
"sync"
"sync/atomic"
- "github.com/TrueBlocks/trueblocks-browse/pkg/messages"
"github.com/TrueBlocks/trueblocks-browse/pkg/types"
coreConfig "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/config"
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/utils"
@@ -36,17 +35,13 @@ func (a *App) loadSettings(wg *sync.WaitGroup, errorChan chan error) error {
_ = errorChan // delint
if path, err := utils.GetConfigFn("", "trueBlocks.toml"); err != nil {
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: err.Error(),
- })
+ a.emitErrorMsg(err, nil)
} else {
if err := coreConfig.ReadToml(path, &a.config.Config); err != nil {
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: err.Error(),
- })
+ a.emitErrorMsg(err, nil)
}
}
- a.loadSession()
+
a.settings = types.NewSettingsGroup(&a.status.Status, &a.config.Config, &a.session.Session)
a.settings.Summarize()
@@ -111,7 +106,7 @@ func (a *App) l oadStatus(wg *sync.WaitGroup, errorChan chan error) error {
})
a.status.Summarize()
logger.SetLoggerWriter(w)
- messages.EmitMessage(a.ctx, messages.Info, &messages.MessageMsg{String1: "Loaded status"})
+ a.emitInfoMsg("Loaded status")
}
return nil
}
diff --git a/app/data_status.go b/app/data_status.go
index 0998cbd7..cd4db51e 100644
--- a/app/data_status.go
+++ b/app/data_status.go
@@ -10,7 +10,6 @@ import (
"sync"
"sync/atomic"
- "github.com/TrueBlocks/trueblocks-browse/pkg/messages"
"github.com/TrueBlocks/trueblocks-browse/pkg/types"
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger"
@@ -82,7 +81,7 @@ func (a *App) loadStatus(wg *sync.WaitGroup, errorChan chan error) error {
logger.SetLoggerWriter(w)
// EXISTING_CODE
a.status.Summarize()
- messages.EmitMessage(a.ctx, messages.Info, &messages.MessageMsg{String1: "Loaded status"})
+ a.emitInfoMsg("Loaded status", "")
}
return nil
diff --git a/app/editor_names.go b/app/editor_names.go
index 377f51a0..ab87beda 100644
--- a/app/editor_names.go
+++ b/app/editor_names.go
@@ -11,7 +11,7 @@ import (
)
func (a *App) LoadName(addr string) editors.Name {
- if name, ok := a.names.NamesMap[base.HexToAddress(addr)]; ok {
+ if name, ok := a.namesMap[base.HexToAddress(addr)]; ok {
logger.Info("Found name for ", name.Address.Hex())
return editors.CoreToName(name)
} else {
diff --git a/app/menu_file.go b/app/menu_file.go
index 17b0ca93..f505549b 100644
--- a/app/menu_file.go
+++ b/app/menu_file.go
@@ -1,43 +1,27 @@
package app
import (
- "fmt"
- "path/filepath"
- "sync"
+ "errors"
- "github.com/TrueBlocks/trueblocks-browse/pkg/messages"
- "github.com/TrueBlocks/trueblocks-browse/pkg/types"
- "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger"
- coreTypes "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types"
"github.com/wailsapp/wails/v2/pkg/menu"
"github.com/wailsapp/wails/v2/pkg/runtime"
)
-func (a *App) FileNew(cd *menu.CallbackData) {
- // save current file (it will ask to save if it's dirty)
- if _, err := a.SaveFile(); err != nil {
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: fmt.Sprintf("error saving project: %s", err.Error()),
- })
+var ErrSavingProject = errors.New("error saving project file")
+var ErrOpeningProject = errors.New("error opening file")
+var ErrLoadingProject = errors.New("error loading file")
+var ErrProjectNotSaved = errors.New("project not saved")
+
+func (a *App) FileNew(cb *menu.CallbackData) {
+ if ok := a.shouldSaveDialog(); !ok {
return
}
- a.projects = types.NewProjectContainer("Untitled.tbx", []types.HistoryContainer{})
- messages.EmitMessage(a.ctx, messages.Navigate, &messages.MessageMsg{
- String1: "/",
- })
- messages.EmitMessage(a.ctx, messages.Document, &messages.MessageMsg{
- String1: filepath.Join(a.session.LastFolder, a.session.LastFile),
- String2: "New file created: Untitled.tbx",
- })
+ a.newFile()
}
-func (a *App) FileOpen(cd *menu.CallbackData) {
- // save current file (it will ask to save if it's dirty)
- if _, err := a.SaveFile(); err != nil {
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: fmt.Sprintf("error saving project: %s", err.Error()),
- })
+func (a *App) FileOpen(cb *menu.CallbackData) {
+ if ok := a.shouldSaveDialog(); !ok {
return
}
@@ -53,133 +37,26 @@ func (a *App) FileOpen(cd *menu.CallbackData) {
{DisplayName: "Monitor Groups", Pattern: "*.tbx"},
},
}); err != nil {
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: fmt.Sprintf("error opening project: %s", err.Error()),
- })
- } else if len(fn) == 0 {
- messages.EmitMessage(a.ctx, messages.Document, &messages.MessageMsg{
- String1: "No file was opened",
- })
- } else {
- if _, err := a.LoadFile(fn); err != nil {
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: fmt.Sprintf("error opening project: %s", err.Error()),
- })
- } else {
- messages.EmitMessage(a.ctx, messages.Document, &messages.MessageMsg{
- String1: filepath.Join(a.session.LastFolder, a.session.LastFile),
- String2: "Opened",
- })
-
- }
- }
-}
+ a.emitErrorMsg(ErrOpeningProject, err)
-func (a *App) FileSave(cd *menu.CallbackData) {
- a.SaveFile()
-}
-
-func (a *App) FileSaveAs(cd *menu.CallbackData) {
- a.dirty = true
- a.SaveFile()
-}
-
-// ------------------------------------------------------------------
-func (a *App) LoadFile(fn string) (bool, error) {
- newProject := types.NewProjectContainer(a.session.LastChain, []types.HistoryContainer{})
- if pF, err := newProject.Load(fn); err != nil {
- return false, fmt.Errorf("newProject::Load failed: %s", err.Error())
-
- } else if len(pF.Addresses) == 0 {
- logger.Info("I am here:", pF.String())
- return false, fmt.Errorf("project file contains no records: %s", fn)
+ } else if len(fn) == 0 {
+ a.emitInfoMsg("no file was opened", "")
} else {
a.CancelAllContexts()
- a.HistoryCache = &types.HistoryMap{}
- histories := []types.HistoryContainer{}
- for _, address := range pF.Addresses {
- history := types.NewHistoryContainer(a.session.LastChain, []coreTypes.Transaction{}, address)
- histories = append(histories, history)
- a.HistoryCache.Store(address, history)
- }
- a.projects = types.NewProjectContainer(a.session.LastChain, histories)
-
- a.session.LastFolder, a.session.LastFile = filepath.Split(fn)
- a.session.LastSub[pF.Selected.Hex()] = pF.Selected.Hex()
- a.saveSession()
-
- messages.EmitMessage(a.ctx, messages.Document, &messages.MessageMsg{
- String1: filepath.Join(a.session.LastFolder, a.session.LastFile),
- String2: "Opened",
- })
-
- var wg sync.WaitGroup
- for _, history := range a.projects.Items {
- wg.Add(1)
- go a.loadHistory(history.Address, &wg, nil)
+ if _, err := a.readFile(fn); err != nil {
+ a.emitErrorMsg(ErrOpeningProject, err)
+ } else {
+ a.emitInfoMsg(a.getFullPath(), "file was opened")
}
- wg.Wait()
-
- return true, nil
}
}
-func (a *App) WriteFile(fn string) (bool, error) {
- if err := a.projects.Save(fn, a.GetAddress()); err != nil {
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: fmt.Sprintf("error writing project: %s", err.Error()),
- })
- return false, err
- }
- a.session.LastFolder, a.session.LastFile = filepath.Split(fn)
- a.saveSession()
- a.dirty = false
- messages.EmitMessage(a.ctx, messages.Document, &messages.MessageMsg{
- String1: filepath.Join(a.session.LastFolder, a.session.LastFile),
- String2: "Saved",
- })
- return true, nil
-}
-
-func (a *App) SaveFile() (bool, error) {
- if !a.dirty {
- return a.WriteFile(filepath.Join(a.session.LastFolder, a.session.LastFile))
- }
-
- var fn string
- var err error
- if isTesting {
- fn = filepath.Join(a.session.LastFolder, a.session.LastFile)
- } else {
- fn, err = runtime.SaveFileDialog(a.ctx, runtime.SaveDialogOptions{
- DefaultDirectory: a.session.LastFolder,
- DefaultFilename: a.session.LastFile,
- Title: "Save File",
- CanCreateDirectories: true,
- ShowHiddenFiles: false,
- TreatPackagesAsDirectories: false,
- Filters: []runtime.FileFilter{
- {DisplayName: "Projects", Pattern: "*.tbx"},
- },
- })
- }
-
- if err != nil {
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: fmt.Sprintf("error saving project: %s", err.Error()),
- })
- return false, err
- } else if len(fn) == 0 {
- messages.EmitMessage(a.ctx, messages.Document, &messages.MessageMsg{
- String1: "User hit escape...file not saved",
- })
- return false, nil
- } else {
- return a.WriteFile(fn)
- }
+func (a *App) FileSave(cb *menu.CallbackData) {
+ a.dirty, _ = a.saveFileDialog()
}
-func (a *App) Filename() string {
- return filepath.Join(a.session.LastFolder, a.session.LastFile)
+func (a *App) FileSaveAs(cb *menu.CallbackData) {
+ a.dirty = true // force the dialog
+ a.dirty, _ = a.saveFileDialog()
}
diff --git a/app/menu_file_load.go b/app/menu_file_load.go
new file mode 100644
index 00000000..3dcb0e69
--- /dev/null
+++ b/app/menu_file_load.go
@@ -0,0 +1,59 @@
+package app
+
+import (
+ "fmt"
+ "path/filepath"
+
+ "github.com/TrueBlocks/trueblocks-browse/pkg/types"
+ "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
+ coreTypes "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types"
+)
+
+func (a *App) newFile() {
+ a.session.LastFile = "Untitled.tbx"
+ a.saveSession()
+
+ address := base.HexToAddress("0x3836b0e02b4a613ba1d15834e6d77f409099d8f8")
+ history := types.NewHistoryContainer(a.getChain(), []coreTypes.Transaction{}, address)
+
+ a.historyCache = &types.HistoryMap{}
+ a.historyCache.Store(address, history)
+ a.projects = types.NewProjectContainer(a.getChain(), []types.HistoryContainer{history})
+
+ a.emitNavigateMsg("/")
+ a.emitInfoMsg(a.getFullPath(), "new file created")
+}
+
+func (a *App) readFile(fn string) (bool, error) {
+ newProject := types.NewProjectContainer(a.session.LastChain, []types.HistoryContainer{})
+ if pF, err := newProject.Load(fn); err != nil {
+ return false, fmt.Errorf("%w: %v", ErrLoadingProject, err)
+
+ } else if len(pF.Addresses) == 0 {
+ return false, fmt.Errorf("project file contains no records: %s", fn)
+
+ } else {
+ a.CancelAllContexts()
+ a.historyCache = &types.HistoryMap{}
+ histories := []types.HistoryContainer{}
+ for _, address := range pF.Addresses {
+ history := types.NewHistoryContainer(a.getChain(), []coreTypes.Transaction{}, address)
+ histories = append(histories, history)
+ a.historyCache.Store(address, history)
+ }
+ a.projects = types.NewProjectContainer(a.getChain(), histories)
+ a.dirty = false
+
+ a.session.LastFolder, a.session.LastFile = filepath.Split(fn)
+ a.session.LastSub["/history"] = pF.Selected.Hex()
+ a.saveSession()
+
+ for _, history := range a.projects.Items {
+ go a.loadHistory(history.Address, nil, nil)
+ }
+
+ a.emitInfoMsg(a.getFullPath(), "file was opened")
+
+ return true, nil
+ }
+}
diff --git a/app/menu_file_save.go b/app/menu_file_save.go
new file mode 100644
index 00000000..4c5d3d92
--- /dev/null
+++ b/app/menu_file_save.go
@@ -0,0 +1,55 @@
+package app
+
+import (
+ "fmt"
+ "path/filepath"
+
+ "github.com/wailsapp/wails/v2/pkg/runtime"
+)
+
+func (a *App) saveFileDialog() (bool, error) {
+ if !a.dirty {
+ return true, nil
+ }
+
+ fn, err := runtime.SaveFileDialog(a.ctx, runtime.SaveDialogOptions{
+ DefaultDirectory: a.session.LastFolder,
+ DefaultFilename: a.session.LastFile,
+ Title: "Save File",
+ CanCreateDirectories: true,
+ ShowHiddenFiles: false,
+ TreatPackagesAsDirectories: false,
+ Filters: []runtime.FileFilter{
+ {DisplayName: "Projects", Pattern: "*.tbx"},
+ },
+ })
+
+ if err != nil {
+ a.emitErrorMsg(ErrSavingProject, err)
+ return false, err
+
+ } else if len(fn) == 0 {
+ a.emitInfoMsg(a.getFullPath(), "file was not saved")
+ return false, nil
+
+ } else {
+ a.CancelAllContexts()
+ if _, err := a.writeFile(fn); err != nil {
+ a.emitErrorMsg(ErrSavingProject, err)
+ return false, err
+ } else {
+ a.emitInfoMsg(a.getFullPath(), "file was saved")
+ return true, nil
+ }
+ }
+}
+
+func (a *App) writeFile(fn string) (bool, error) {
+ if err := a.projects.Save(fn, a.GetSelected()); err != nil {
+ return false, fmt.Errorf("%w: %v", ErrProjectNotSaved, err)
+ }
+ a.dirty = false
+ a.session.LastFolder, a.session.LastFile = filepath.Split(fn)
+ a.saveSession()
+ return true, nil
+}
diff --git a/app/menu_file_shouldsave.go b/app/menu_file_shouldsave.go
new file mode 100644
index 00000000..8f3d703a
--- /dev/null
+++ b/app/menu_file_shouldsave.go
@@ -0,0 +1,38 @@
+package app
+
+import "strings"
+
+func (a *App) shouldSaveDialog() bool {
+ if !a.dirty {
+ return true
+ }
+
+ if response, err := a.okCancel(saveFile); err != nil {
+ // there was an error, do not proceed
+ a.emitErrorMsg(ErrSavingProject, err)
+ return false
+
+ } else if response.canceled {
+ // user hit cancel, do not proceed
+ return false
+
+ } else if response.save {
+ // saveFileDialog sends messages since it is called from FileSave, etc.
+ if strings.HasPrefix(a.getFilename(), "Untitled.") {
+ if saved, err := a.saveFileDialog(); err != nil || !saved {
+ // there was an error or the user told us not to save.
+ // in both bases, messages have been sent. do not proceed.
+ return false
+ }
+ } else {
+ if a.dirty, err = a.writeFile(a.getFullPath()); err != nil {
+ a.emitErrorMsg(ErrSavingProject, err)
+ return false
+ }
+ }
+ } else {
+ // do nothing - user said not to save, so just continue
+ }
+
+ return true
+}
diff --git a/app/menu_file_test.go b/app/menu_file_test.go
deleted file mode 100644
index fcd1d714..00000000
--- a/app/menu_file_test.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package app
-
-import (
- "fmt"
- "os"
- "path/filepath"
- "testing"
-
- "github.com/TrueBlocks/trueblocks-browse/pkg/types"
- "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
- "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/file"
-)
-
-func TestFileSave(t *testing.T) {
- sessionFn := "/Users/jrush/Library/Application Support/TrueBlocks/browse/session.json"
- contents := file.AsciiFileToString(sessionFn)
- os.Setenv("TB_TEST_MODE", "true")
- app := NewApp()
- app.SetRoute("/history", "0xf503017d7baf7fbc0fff7492b751025c6a78179b")
- app.SetRoute("/", "")
- fn := "/tmp/test1.tbx"
- app.session.LastFolder, app.session.LastFile = filepath.Split(fn)
- app.saveSession()
- app.projects = types.NewProjectContainer("Untitled.tbx", []types.HistoryContainer{{Address: base.HexToAddress("0xf503017d7baf7fbc0fff7492b751025c6a78179b")}})
- app.dirty = true
- saved, err := app.SaveFile()
- fmt.Println(saved, err)
- fmt.Println(file.AsciiFileToString(fn))
- os.Remove(fn)
- file.StringToAsciiFile(sessionFn, contents)
-}
diff --git a/app/menu_system.go b/app/menu_system.go
index 616e4dc9..ed0c8c9d 100644
--- a/app/menu_system.go
+++ b/app/menu_system.go
@@ -6,10 +6,11 @@ import (
"github.com/wailsapp/wails/v2/pkg/runtime"
)
-func (a *App) SystemAbout(cd *menu.CallbackData) {
+func (a *App) SystemAbout(cb *menu.CallbackData) {
logger.Info("This is the about box plus some other stuff")
}
-func (a *App) SystemQuit(cd *menu.CallbackData) {
+func (a *App) SystemQuit(cb *menu.CallbackData) {
+ a.dirty, _ = a.saveFileDialog()
runtime.Quit(a.ctx)
}
diff --git a/app/menu_toggle.go b/app/menu_toggle.go
index d633c9b3..bccf7f34 100644
--- a/app/menu_toggle.go
+++ b/app/menu_toggle.go
@@ -7,35 +7,27 @@ import (
"github.com/wailsapp/wails/v2/pkg/menu"
)
-func (a *App) HeaderToggle(cd *menu.CallbackData) {
+func (a *App) HeaderToggle(cb *menu.CallbackData) {
which := "header"
- messages.EmitMessage(a.ctx, messages.ToggleLayout, &messages.MessageMsg{
- String1: which,
- })
+ a.emitMsg(messages.ToggleLayout, &messages.MessageMsg{String1: which})
}
-func (a *App) MenuToggle(cd *menu.CallbackData) {
+func (a *App) MenuToggle(cb *menu.CallbackData) {
which := "menu"
- messages.EmitMessage(a.ctx, messages.ToggleLayout, &messages.MessageMsg{
- String1: which,
- })
+ a.emitMsg(messages.ToggleLayout, &messages.MessageMsg{String1: which})
}
-func (a *App) HelpToggle(cd *menu.CallbackData) {
+func (a *App) HelpToggle(cb *menu.CallbackData) {
which := "help"
- messages.EmitMessage(a.ctx, messages.ToggleLayout, &messages.MessageMsg{
- String1: which,
- })
+ a.emitMsg(messages.ToggleLayout, &messages.MessageMsg{String1: which})
}
-func (a *App) FooterToggle(cd *menu.CallbackData) {
+func (a *App) FooterToggle(cb *menu.CallbackData) {
which := "footer"
- messages.EmitMessage(a.ctx, messages.ToggleLayout, &messages.MessageMsg{
- String1: which,
- })
+ a.emitMsg(messages.ToggleLayout, &messages.MessageMsg{String1: which})
}
-func (a *App) AccordionToggle(cd *menu.CallbackData) {
+func (a *App) AccordionToggle(cb *menu.CallbackData) {
route := a.GetRoute()
route = strings.TrimPrefix(route, "/")
parts := strings.Split(route, "/")
@@ -43,17 +35,15 @@ func (a *App) AccordionToggle(cd *menu.CallbackData) {
if route == "" {
route = "project"
}
- messages.EmitMessage(a.ctx, messages.ToggleHeader, &messages.MessageMsg{
- String1: route,
- })
+ a.emitMsg(messages.ToggleAccordion, &messages.MessageMsg{String1: route})
}
-func (a *App) SwitchTabPrev(cd *menu.CallbackData) {
+func (a *App) SwitchTabPrev(cb *menu.CallbackData) {
which := "prev"
- messages.EmitMessage(a.ctx, messages.SwitchTab, &messages.MessageMsg{String1: which})
+ a.emitMsg(messages.SwitchTab, &messages.MessageMsg{String1: which})
}
-func (a *App) SwitchTabNext(cd *menu.CallbackData) {
+func (a *App) SwitchTabNext(cb *menu.CallbackData) {
which := "next"
- messages.EmitMessage(a.ctx, messages.SwitchTab, &messages.MessageMsg{String1: which})
+ a.emitMsg(messages.SwitchTab, &messages.MessageMsg{String1: which})
}
diff --git a/app/menu_view.go b/app/menu_view.go
index e919872d..62ae61d2 100644
--- a/app/menu_view.go
+++ b/app/menu_view.go
@@ -7,57 +7,57 @@ import (
"github.com/wailsapp/wails/v2/pkg/menu"
)
-func (a *App) ProjectView(cd *menu.CallbackData) {
+func (a *App) ProjectView(cb *menu.CallbackData) {
a.Navigate("/", "")
}
-func (a *App) HistoryView(cd *menu.CallbackData) {
- address := a.GetAddress()
+func (a *App) HistoryView(cb *menu.CallbackData) {
+ address := a.GetSelected()
a.Navigate("/history", address.Hex())
}
-func (a *App) MonitorsView(cd *menu.CallbackData) {
+func (a *App) MonitorsView(cb *menu.CallbackData) {
a.Navigate("/monitors", "")
}
-func (a *App) NamesView(cd *menu.CallbackData) {
+func (a *App) NamesView(cb *menu.CallbackData) {
a.Navigate("/names", "")
}
-func (a *App) AbisView(cd *menu.CallbackData) {
+func (a *App) AbisView(cb *menu.CallbackData) {
a.Navigate("/abis", "")
}
-func (a *App) IndexesView(cd *menu.CallbackData) {
+func (a *App) IndexesView(cb *menu.CallbackData) {
a.Navigate("/indexes", "")
}
-func (a *App) ManifestsView(cd *menu.CallbackData) {
+func (a *App) ManifestsView(cb *menu.CallbackData) {
a.Navigate("/manifests", "")
}
-func (a *App) StatusView(cd *menu.CallbackData) {
+func (a *App) StatusView(cb *menu.CallbackData) {
a.Navigate("/status", "")
}
-func (a *App) SettingsView(cd *menu.CallbackData) {
+func (a *App) SettingsView(cb *menu.CallbackData) {
a.Navigate("/settings", "")
}
-func (a *App) DaemonsView(cd *menu.CallbackData) {
+func (a *App) DaemonsView(cb *menu.CallbackData) {
a.Navigate("/daemons", "")
}
-func (a *App) SessionView(cd *menu.CallbackData) {
+func (a *App) SessionView(cb *menu.CallbackData) {
a.Navigate("/session", "")
}
-func (a *App) ConfigView(cd *menu.CallbackData) {
+func (a *App) ConfigView(cb *menu.CallbackData) {
a.Navigate("/config", "")
}
-func (a *App) WizardView(cd *menu.CallbackData) {
- if a.IsConfigured() {
+func (a *App) WizardView(cb *menu.CallbackData) {
+ if a.isConfigured() {
a.StepWizard(coreTypes.Reset)
} else {
a.StepWizard(coreTypes.Next)
diff --git a/app/message.go b/app/message.go
new file mode 100644
index 00000000..914ef918
--- /dev/null
+++ b/app/message.go
@@ -0,0 +1,52 @@
+package app
+
+import (
+ "fmt"
+
+ "github.com/TrueBlocks/trueblocks-browse/pkg/messages"
+ "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
+)
+
+func (a *App) emitNavigateMsg(route string) {
+ messages.EmitMessage(a.ctx, messages.Navigate, &messages.MessageMsg{
+ String1: route,
+ })
+}
+
+func (a *App) emitErrorMsg(err1, err2 error) {
+ if err2 != nil {
+ messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
+ String1: fmt.Errorf("%w: %v", err1, err2).Error(),
+ })
+ } else {
+ messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
+ String1: fmt.Errorf("%v", err1).Error(),
+ })
+ }
+}
+
+func (a *App) emitAddressErrorMsg(err error, address base.Address) {
+ messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
+ String1: err.Error(),
+ Address: address,
+ })
+}
+
+func (a *App) emitInfoMsg(str1, str2 string) {
+ messages.EmitMessage(a.ctx, messages.Info, &messages.MessageMsg{
+ String1: str1,
+ String2: str2,
+ })
+}
+
+func (a *App) emitProgressMsg(msg messages.Message, address base.Address, n1, n2 int) {
+ messages.EmitMessage(a.ctx, msg, &messages.MessageMsg{
+ Address: address,
+ Num1: n1,
+ Num2: n2,
+ })
+}
+
+func (a *App) emitMsg(msg messages.Message, val *messages.MessageMsg) {
+ messages.EmitMessage(a.ctx, msg, val)
+}
diff --git a/app/app_modify.go b/app/modify_data.go
similarity index 52%
rename from app/app_modify.go
rename to app/modify_data.go
index f46bcaab..84ef5b5f 100644
--- a/app/app_modify.go
+++ b/app/modify_data.go
@@ -1,15 +1,9 @@
package app
-import (
- "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
-)
+import "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
type ModifyData struct {
Operation string `json:"operation"`
Address base.Address `json:"address"`
Value string `json:"value"`
}
-
-func (a *App) UnusedFunc(modData *ModifyData) error {
- return nil
-}
diff --git a/app/navigate.go b/app/navigate.go
index ad53e7ef..962f6816 100644
--- a/app/navigate.go
+++ b/app/navigate.go
@@ -1,7 +1,7 @@
package app
import (
- "github.com/TrueBlocks/trueblocks-browse/pkg/messages"
+ "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger"
)
func (a *App) Navigate(route, subRoute string) {
@@ -10,14 +10,12 @@ func (a *App) Navigate(route, subRoute string) {
sep = "/"
}
- if route != "/wizard" && !a.IsConfigured() {
+ if route != "/wizard" && !a.isConfigured() {
route, subRoute, sep = "/wizard", "", ""
}
a.SetRoute(route, subRoute)
- debugMsg("Message sent", route, subRoute)
- messages.EmitMessage(a.ctx, messages.Navigate, &messages.MessageMsg{
- String1: route + sep + subRoute,
- })
+ logger.Info("Message sent", route, subRoute)
+ a.emitNavigateMsg(route + sep + subRoute)
}
diff --git a/app/proc_ctxs.go b/app/proc_ctxs.go
index 9378fa8a..88d9008b 100644
--- a/app/proc_ctxs.go
+++ b/app/proc_ctxs.go
@@ -28,9 +28,7 @@ func (a *App) cancelContext(address base.Address) (removed bool) {
defer ctxMutex.Unlock()
if ctxArrays, ok := a.renderCtxs[address]; ok {
for _, ctx := range ctxArrays {
- messages.EmitMessage(a.ctx, messages.Cancelled, &messages.MessageMsg{
- Address: address,
- })
+ a.emitMsg(messages.Cancelled, &messages.MessageMsg{Address: address})
ctx.Cancel()
}
delete(a.renderCtxs, address)
diff --git a/app/proc_daemons.go b/app/proc_daemons.go
index 8b6adc6f..a5903d4a 100644
--- a/app/proc_daemons.go
+++ b/app/proc_daemons.go
@@ -5,12 +5,6 @@ import (
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger"
)
-func (a *App) startDaemons() {
- go a.FreshenController.Run()
- go a.ScraperController.Run()
- go a.IpfsController.Run()
-}
-
func (a *App) ToggleDaemon(name string) error {
d := a.getDaemon(name)
if err := d.Toggle(); err != nil {
@@ -31,11 +25,11 @@ func (a *App) GetState(name string) string {
func (a *App) getDaemon(name string) daemons.Daemoner {
switch name {
case "freshen":
- return a.FreshenController
+ return a.freshenController
case "scraper":
- return a.ScraperController
+ return a.scraperController
case "ipfs":
- return a.IpfsController
+ return a.ipfsController
default:
if len(name) > 0 {
logger.Fatal("getDaemon", "should not happen", name)
diff --git a/app/proc_export.go b/app/proc_export.go
index a9c88017..836ee250 100644
--- a/app/proc_export.go
+++ b/app/proc_export.go
@@ -4,7 +4,6 @@ import (
"fmt"
"strings"
- "github.com/TrueBlocks/trueblocks-browse/pkg/messages"
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/file"
coreTypes "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types"
@@ -23,7 +22,7 @@ func (a *App) ExportAddress(address base.Address) {
fn := fmt.Sprintf("history_%s.csv", address)
lines := make([]string, 0, a.txCount(address)+2)
- exportLine := func(item coreTypes.Transaction, data any) bool {
+ exportLine := func(item *coreTypes.Transaction, data any) bool {
if len(lines) == 0 {
lines = append(lines, fmt.Sprintf("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s",
"BlockNumber",
@@ -60,13 +59,11 @@ func (a *App) ExportAddress(address base.Address) {
return true
}
- h, _ := a.HistoryCache.Load(address)
+ h, _ := a.historyCache.Load(address)
completed := h.ForEveryTransaction(exportLine, nil)
if !completed {
err := fmt.Errorf("export for %s interrupted after %d lines", address.Hex(), len(lines))
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: err.Error(),
- })
+ a.emitErrorMsg(err, nil)
return
}
diff --git a/app/proc_refresh.go b/app/proc_refresh.go
index 1b7bf877..77e555b1 100644
--- a/app/proc_refresh.go
+++ b/app/proc_refresh.go
@@ -7,7 +7,6 @@ import (
"time"
"github.com/TrueBlocks/trueblocks-browse/pkg/messages"
- "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/colors"
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger"
)
@@ -18,7 +17,7 @@ var freshenMutex sync.Mutex
// by extension the frontend to update. We protect against updating too fast... Note
// that this routine is called as a goroutine.
func (a *App) Refresh() error {
- if !a.IsConfigured() {
+ if !a.isConfigured() {
return fmt.Errorf("App not configured")
}
@@ -30,16 +29,14 @@ func (a *App) Refresh() error {
freshenMutex.Lock()
defer freshenMutex.Unlock()
- if !a.ScraperController.IsRunning() {
- logger.Info(colors.Green, "Freshening...", colors.Off)
+ if !a.scraperController.IsRunning() {
+ logger.InfoG("Freshening...")
}
// We always load names first since we need them everywhere
err := a.loadNames(nil, nil)
if err != nil {
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: err.Error(),
- })
+ a.emitErrorMsg(err, nil)
}
// And then update everything else in the fullness of time
@@ -47,14 +44,14 @@ func (a *App) Refresh() error {
errorChan := make(chan error, 5) // Buffered channel to hold up to 5 errors (one from each goroutine)
wg.Add(8)
- go a.loadAbis(&wg, errorChan)
- go a.loadManifests(&wg, errorChan)
+ go a.loadProjects(&wg, errorChan)
go a.loadMonitors(&wg, errorChan)
- go a.loadIndexes(&wg, errorChan)
- go a.loadStatus(&wg, errorChan)
go a.loadSessions(&wg, errorChan)
go a.loadSettings(&wg, errorChan)
- go a.loadProjects(&wg, errorChan)
+ go a.loadStatus(&wg, errorChan)
+ go a.loadAbis(&wg, errorChan)
+ go a.loadManifests(&wg, errorChan)
+ go a.loadIndexes(&wg, errorChan)
go func() {
wg.Wait()
@@ -71,16 +68,14 @@ func (a *App) Refresh() error {
if len(errors) > 0 {
// Handle errors, e.g., wait 1/2 second between each error message
for _, err := range errors {
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: err.Error(),
- })
+ a.emitErrorMsg(err, nil)
time.Sleep(500 * time.Millisecond)
}
} else {
- messages.EmitMessage(a.ctx, messages.Daemon, &messages.MessageMsg{
- Name: a.FreshenController.Name,
+ a.emitMsg(messages.Daemon, &messages.MessageMsg{
+ Name: a.freshenController.Name,
String1: "Freshening...",
- String2: a.FreshenController.Color,
+ String2: a.freshenController.Color,
})
}
return nil
diff --git a/app/util_address.go b/app/util_address.go
index 3d05e412..df823868 100644
--- a/app/util_address.go
+++ b/app/util_address.go
@@ -3,13 +3,12 @@ package app
import (
"strings"
- "github.com/TrueBlocks/trueblocks-browse/pkg/messages"
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
sdk "github.com/TrueBlocks/trueblocks-sdk/v3"
)
func (a *App) ConvertToAddress(addr string) (base.Address, bool) {
- if !a.IsConfigured() {
+ if !a.isConfigured() {
return base.ZeroAddr, false
}
@@ -18,7 +17,7 @@ func (a *App) ConvertToAddress(addr string) (base.Address, bool) {
return ret, ret != base.ZeroAddr
}
- ensAddr, exists := a.EnsCache.Load(addr)
+ ensAddr, exists := a.ensCache.Load(addr)
if exists {
return ensAddr.(base.Address), true
}
@@ -29,14 +28,12 @@ func (a *App) ConvertToAddress(addr string) (base.Address, bool) {
Globals: a.toGlobals(),
}
if names, meta, err := opts.Names(); err != nil {
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: err.Error(),
- })
+ a.emitErrorMsg(err, nil)
return base.ZeroAddr, false
} else {
a.meta = *meta
if len(names) > 0 {
- a.EnsCache.Store(addr, names[0].Address)
+ a.ensCache.Store(addr, names[0].Address)
return names[0].Address, true
} else {
ret := base.HexToAddress(addr)
@@ -46,7 +43,7 @@ func (a *App) ConvertToAddress(addr string) (base.Address, bool) {
}
func (a *App) AddrToName(address base.Address) string {
- if name, exists := a.names.NamesMap[address]; exists {
+ if name, exists := a.namesMap[address]; exists {
return name.Name
}
return ""
diff --git a/app/util_balance.go b/app/util_balance.go
index 2ec44f6a..e69c906e 100644
--- a/app/util_balance.go
+++ b/app/util_balance.go
@@ -6,11 +6,11 @@ import (
)
func (a *App) getBalance(address base.Address) string {
- if !a.IsConfigured() {
+ if !a.isConfigured() {
return "0"
}
- b, exists := a.BalanceCache.Load(address)
+ b, exists := a.balanceCache.Load(address)
if exists {
return b.(string)
}
@@ -28,7 +28,7 @@ func (a *App) getBalance(address base.Address) string {
} else {
a.meta = *meta
value := balances[0].Balance.ToEtherStr(18)
- a.BalanceCache.Store(address, value)
+ a.balanceCache.Store(address, value)
return value
}
}
diff --git a/app/util_debug.go b/app/util_debug.go
new file mode 100644
index 00000000..afae1431
--- /dev/null
+++ b/app/util_debug.go
@@ -0,0 +1,17 @@
+package app
+
+import (
+ "os"
+
+ "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger"
+)
+
+func (a *App) Logger(msg []string) {
+ logger.Info(msg)
+}
+
+var isTesting bool
+
+func init() {
+ isTesting = os.Getenv("TB_TEST_MODE") == "true"
+}
diff --git a/app/util_explore.go b/app/util_explore.go
index 436fc958..4d4dcabd 100644
--- a/app/util_explore.go
+++ b/app/util_explore.go
@@ -4,7 +4,6 @@ import (
"fmt"
"os"
- "github.com/TrueBlocks/trueblocks-browse/pkg/messages"
sdk "github.com/TrueBlocks/trueblocks-sdk/v3"
)
@@ -25,15 +24,11 @@ func (a *App) GetExploreUrl(term string, google, dalle bool) string {
// TODO: Expose this to the user and/or put it in trueBlocks.toml
os.Setenv("TB_DALLE_SERIES", "five-tone-postal-protozoa")
if result, meta, err := opts.Explore(); err != nil {
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: err.Error(),
- })
+ a.emitErrorMsg(err, nil)
return ""
} else if (result == nil) || (len(result) == 0) {
err := fmt.Errorf("url not found")
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: err.Error(),
- })
+ a.emitErrorMsg(err, nil)
return ""
} else {
a.meta = *meta
diff --git a/app/util_okcancel.go b/app/util_okcancel.go
new file mode 100644
index 00000000..2a0cf581
--- /dev/null
+++ b/app/util_okcancel.go
@@ -0,0 +1,40 @@
+package app
+
+import "github.com/wailsapp/wails/v2/pkg/runtime"
+
+type OkCancel struct {
+ title string
+ msg string
+ options []string
+ // output
+ save bool
+ canceled bool
+}
+
+var saveFile = OkCancel{
+ title: "Unsaved Changes",
+ msg: "File has changed. Save it?",
+ options: []string{"Save", "Don't Save", "Cancel"},
+}
+
+func (a *App) okCancel(in OkCancel) (OkCancel, error) {
+ if !a.dirty {
+ return OkCancel{}, nil
+ }
+
+ a.CancelAllContexts()
+ if response, err := runtime.MessageDialog(a.ctx, runtime.MessageDialogOptions{
+ Type: runtime.QuestionDialog,
+ Title: in.title,
+ Message: in.msg,
+ Buttons: in.options,
+ }); err != nil {
+ return OkCancel{}, err
+ } else if response == "Don't Save" {
+ return OkCancel{}, nil
+ } else if response == "Cancel" {
+ return OkCancel{canceled: true}, nil
+ } else {
+ return OkCancel{save: true}, nil
+ }
+}
diff --git a/app/wizard.go b/app/wizard.go
index 126cebe3..8eaadc3b 100644
--- a/app/wizard.go
+++ b/app/wizard.go
@@ -5,25 +5,23 @@ import (
coreTypes "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types"
)
-func (a *App) IsConfigured() bool {
- return a.GetWizardState() == coreTypes.Okay
+func (a *App) isConfigured() bool {
+ return a.getWizardState() == coreTypes.Okay
}
-func (a *App) GetWizardState() coreTypes.WizState {
+func (a *App) getWizardState() coreTypes.WizState {
return a.session.Wizard.State
}
func (a *App) StepWizard(step coreTypes.WizStep) coreTypes.WizState {
defer func() {
- if a.IsConfigured() {
+ if a.isConfigured() {
a.Navigate("/", "")
}
- messages.EmitMessage(a.ctx, messages.Wizard, &messages.MessageMsg{
- State: a.session.Wizard.State,
- })
+ a.emitMsg(messages.Wizard, &messages.MessageMsg{State: a.session.Wizard.State})
}()
a.session.Wizard.Step(step)
a.saveSession()
- return a.GetWizardState()
+ return a.getWizardState()
}
diff --git a/code_gen/templates/generators/codebase/app_menu+view.go.tmpl b/code_gen/templates/generators/codebase/app_menu+view.go.tmpl
index d19f33f8..6747e65f 100644
--- a/code_gen/templates/generators/codebase/app_menu+view.go.tmpl
+++ b/code_gen/templates/generators/codebase/app_menu+view.go.tmpl
@@ -8,12 +8,12 @@ import (
)
{{range .Structures -}}
-func (a *App) {{firstUpper .UiRouteName}}View(cd *menu.CallbackData) {
+func (a *App) {{firstUpper .UiRouteName}}View(cb *menu.CallbackData) {
{{if .IsHistory -}}
- address := a.GetAddress()
+ address := a.GetSelected()
a.Navigate("/{{toLower .UiRouteName}}", address.Hex())
{{- else if .IsWizard -}}
- if a.IsConfigured() {
+ if a.isConfigured() {
a.StepWizard(coreTypes.Reset)
} else {
a.StepWizard(coreTypes.Next)
diff --git a/code_gen/templates/generators/types/app_data+type.go.tmpl b/code_gen/templates/generators/types/app_data+type.go.tmpl
index 13f02c9b..56c61815 100644
--- a/code_gen/templates/generators/types/app_data+type.go.tmpl
+++ b/code_gen/templates/generators/types/app_data+type.go.tmpl
@@ -62,13 +62,11 @@ func (a *App) load{{toPlural .Class}}(wg *sync.WaitGroup, errorChan chan error)
// EXISTING_CODE
{{if .HasSorts -}}
if err := sdk.Sort{{toPlural .Class}}(a.{{toLowerPlural .Class}}.Items, a.{{toLowerPlural .Class}}.Sorts); err != nil {
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: err.Error(),
- })
+ a.emitErrorMsg(err, nil)
}
{{end -}}
a.{{toLowerPlural .Class}}.Summarize()
- messages.EmitMessage(a.ctx, messages.Info, &messages.MessageMsg{String1: "Loaded {{toLowerPlural .Class}}"})
+ a.emitInfoMsg("Loaded {{toLowerPlural .Class}}")
}
return nil
@@ -82,10 +80,7 @@ func (a *App) load{{toPlural .Class}}(wg *sync.WaitGroup, errorChan chan error)
opts.Globals.Decache = true
if _, _, err := opts.{{toPlural .Class}}(); err != nil {
- messages.EmitMessage(a.ctx, messages.Error, &messages.MessageMsg{
- String1: err.Error(),
- Address: modData.Address,
- })
+ a.emitAddressErrorMsg(err, modData.Address)
return err
} else {
new{{toPlural .Class}} := make([]{{.ItemType}}, 0, len(a.{{toLowerPlural .Class}}.Items))
@@ -101,7 +96,7 @@ func (a *App) load{{toPlural .Class}}(wg *sync.WaitGroup, errorChan chan error)
a.{{toLowerPlural .Class}}.LastUpdate = time.Time{}
a.{{toLowerPlural .Class}}.Items = new{{toPlural .Class}}
msg := fmt.Sprintf("Modify{{.Class}} delete: %s", modData.Address.Hex())
- messages.EmitMessage(a.ctx, messages.Info, &messages.MessageMsg{String1: msg})
+ a.emitInfoMsg(msg)
return nil
}
}
diff --git a/code_gen/templates/generators/types/pkg_types_types+containertype.go.tmpl b/code_gen/templates/generators/types/pkg_types_types+containertype.go.tmpl
index 161e1a14..f3e89d2f 100644
--- a/code_gen/templates/generators/types/pkg_types_types+containertype.go.tmpl
+++ b/code_gen/templates/generators/types/pkg_types_types+containertype.go.tmpl
@@ -40,6 +40,7 @@ func (s *{{.Class}}Container) String() string {
func (s *{{.Class}}Container) NeedsUpdate(force bool) bool {
latest, reload := s.get{{.Class}}Reload()
if force || reload {
+ logger.InfoG("{{.Class}}Container", s.LastUpdate.String(), latest.String())
s.LastUpdate = latest
return true
}
diff --git a/frontend/src/components/buttons/CopyButton.tsx b/frontend/src/components/buttons/CopyButton.tsx
index 1929cd3a..3176d946 100644
--- a/frontend/src/components/buttons/CopyButton.tsx
+++ b/frontend/src/components/buttons/CopyButton.tsx
@@ -1,12 +1,12 @@
import { IconCopy } from "@tabler/icons-react";
-import { BaseButton, ButtonProps, ButtonMouseEvent, notifyCopy } from "@components";
+import { BaseButton, ButtonProps, notifyCopy } from "@components";
import { useUtils } from "@hooks";
import { ClipboardSetText } from "@runtime";
// CopyButton copies the address of the row to the clipboard.
export const CopyButton = ({ value, onClose, ...props }: ButtonProps) => {
const { ShortenAddr } = useUtils();
- const handleClick = (e: ButtonMouseEvent) => {
+ const handleClick = () => {
ClipboardSetText(value as string).then(() => {});
notifyCopy(ShortenAddr(value as string));
};
diff --git a/frontend/src/components/buttons/ExportButton.tsx b/frontend/src/components/buttons/ExportButton.tsx
index 30d4337c..8e438e0a 100644
--- a/frontend/src/components/buttons/ExportButton.tsx
+++ b/frontend/src/components/buttons/ExportButton.tsx
@@ -5,11 +5,9 @@ import { base } from "@gocode/models";
// ExportButton exports an address's history to a .csv file.
export const ExportButton = ({ value, ...props }: ButtonProps) => {
- const icon = ;
-
const handleClick = () => {
ExportAddress(value as base.Address);
};
- return ;
+ return } />;
};
diff --git a/frontend/src/components/buttons/ViewButton.tsx b/frontend/src/components/buttons/ViewButton.tsx
index ce2572b3..a8198972 100644
--- a/frontend/src/components/buttons/ViewButton.tsx
+++ b/frontend/src/components/buttons/ViewButton.tsx
@@ -1,16 +1,15 @@
import { IconLink } from "@tabler/icons-react";
import { BaseButton, ButtonProps } from "@components";
-import { GoToHistory } from "@gocode/app/App";
+import { GoToAddress } from "@gocode/app/App";
import { base } from "@gocode/models";
// ViewButton opens the history page for a given address.
export const ViewButton = ({ value, ...props }: ButtonProps) => {
const address = value as base.Address;
- const icon = ;
const handleClick = () => {
- GoToHistory(address).then(() => {});
+ GoToAddress(address).then(() => {});
};
- return ;
+ return } />;
};
diff --git a/frontend/src/components/dialogs/AddressDialog.tsx b/frontend/src/components/dialogs/AddressDialog.tsx
index 2a20ec94..9ef2c7d4 100644
--- a/frontend/src/components/dialogs/AddressDialog.tsx
+++ b/frontend/src/components/dialogs/AddressDialog.tsx
@@ -1,13 +1,10 @@
import { useState } from "react";
-import { Logger } from "@gocode/app/App";
function InputDialog({ isOpen, onClose }: { isOpen: boolean; onClose: () => void }) {
const [inputValue, setInputValue] = useState("");
- const handleSubmit = async () => {
+ const handleSubmit = () => {
try {
- // const result =
- await Logger(inputValue);
// Handle the result as needed
onClose();
} catch (error) {
diff --git a/frontend/src/components/editors/Validators.tsx b/frontend/src/components/editors/Validators.tsx
index d80e5e0d..50cb6c17 100644
--- a/frontend/src/components/editors/Validators.tsx
+++ b/frontend/src/components/editors/Validators.tsx
@@ -1,5 +1,3 @@
-import React from "react";
-
export function validAddress(value: string) {
if (!/^0x[a-fA-F0-9]{40}$/.test(value) && !/^[a-zA-Z0-9.-]+\.eth$/.test(value)) {
return "Please enter a valid Ethereum address.";
diff --git a/frontend/src/components/formatters/AddressFormatter.tsx b/frontend/src/components/formatters/AddressFormatter.tsx
index 71a7f30c..3fd1414f 100644
--- a/frontend/src/components/formatters/AddressFormatter.tsx
+++ b/frontend/src/components/formatters/AddressFormatter.tsx
@@ -27,7 +27,7 @@ export const AddressFormatter = ({ value, value2, className, mode = EdMode.All }
const givenAddress = value as unknown as string;
useEffect(() => {
- const formatAddress = async () => {
+ const formatAddress = () => {
if (!givenAddress || givenAddress === "0x0") {
setLine1(givenName);
setLine2("");
diff --git a/frontend/src/components/formatters/LoadProgress.tsx b/frontend/src/components/formatters/LoadProgress.tsx
index e4c047aa..76884520 100644
--- a/frontend/src/components/formatters/LoadProgress.tsx
+++ b/frontend/src/components/formatters/LoadProgress.tsx
@@ -1,16 +1,36 @@
+import { useState, useEffect } from "react";
import { Progress, Text } from "@mantine/core";
import { FormatterProps } from "@components";
export const LoadProgress = ({ value, value2 }: Omit) => {
- const n2 = value2 as number;
- const loadedItems = Math.round((value / 100) * n2); // Calculate X
+ const [loaded, setLoaded] = useState(0);
+ const [total, setTotal] = useState(0);
- if (value > 98) {
+ useEffect(() => {
+ setTotal(value2 as number);
+ }, [value2]);
+
+ useEffect(() => {
+ setLoaded(Math.round((value * total) / 100));
+ }, [value, total]);
+
+ if (loaded === 0) {
return (
<>
- {loadedItems} of {n2}
+ not loaded
+
+ >
+ );
+ }
+
+ if (value > 98) {
+ return (
+ <>
+
+
+ {loaded} of {total}
>
);
@@ -20,7 +40,7 @@ export const LoadProgress = ({ value, value2 }: Omit) =>
<>
- {loadedItems} of {n2}
+ {loaded} of {total}
>
);
diff --git a/frontend/src/components/index.tsx b/frontend/src/components/index.tsx
index a5aa9dd6..ac5575b9 100644
--- a/frontend/src/components/index.tsx
+++ b/frontend/src/components/index.tsx
@@ -1,5 +1,4 @@
export * from "./buttons";
-export * from "./dialogs";
export * from "./editors";
export * from "./formatters";
export * from "./help";
diff --git a/frontend/src/components/layout/Menu.tsx b/frontend/src/components/layout/Menu.tsx
index 059b6dc0..7ead02a4 100644
--- a/frontend/src/components/layout/Menu.tsx
+++ b/frontend/src/components/layout/Menu.tsx
@@ -1,7 +1,7 @@
import { useEffect, useState } from "react";
import { useLocation } from "wouter";
import { StyledNavLink } from "@components";
-import { GetRoute, GetAddress, SetRoute } from "@gocode/app/App";
+import { GetRoute, GetSelected, SetRoute } from "@gocode/app/App";
import { messages } from "@gocode/models";
import { routeItems, RouteItem } from "@layout";
import { EventsOn, EventsOff } from "@runtime";
@@ -39,11 +39,11 @@ export const Menu = () => {
const handleRouteChange = (route: string) => {
setActiveRoute(route);
if (route.startsWith("/history")) {
- GetAddress().then((address) => {
+ GetSelected().then((address) => {
const addr = address as unknown as string;
route = route.replace(":address", addr);
setLocation(route);
- SetRoute(route, addr);
+ SetRoute("/history", addr);
});
setActiveRoute("/history/:address");
} else {
diff --git a/frontend/src/components/view/ViewStatus.tsx b/frontend/src/components/view/ViewStatus.tsx
index 09cc098d..28bb8c7e 100644
--- a/frontend/src/components/view/ViewStatus.tsx
+++ b/frontend/src/components/view/ViewStatus.tsx
@@ -11,17 +11,6 @@ export const ViewStatus = () => {
const [color, setColor] = useState("green");
useEffect(() => {
- const handleDocument = (msg: messages.MessageMsg) => {
- setStatusMessage(`${msg.string2} ${msg.string1}`);
- setColor("green");
- if (timeoutRef.current) {
- clearTimeout(timeoutRef.current);
- }
- timeoutRef.current = setTimeout(() => {
- setStatusMessage("");
- }, 2000);
- };
-
const handleProgress = (msg: messages.MessageMsg) => {
setStatusMessage(`Progress (${msg.address}): ${msg.num1}/${msg.num2}`);
setColor("green");
@@ -63,7 +52,7 @@ export const ViewStatus = () => {
};
const handleInfo = (msg: messages.MessageMsg) => {
- setStatusMessage(`Info [${new Date().toLocaleString()}]: ${msg.string1}`);
+ setStatusMessage(`Info ${msg.string2} ${msg.string1}`);
setColor("blue");
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
@@ -76,7 +65,6 @@ export const ViewStatus = () => {
const { Message } = messages;
EventsOn(Message.CANCELLED, handleCancelled);
EventsOn(Message.COMPLETED, handleCompleted);
- EventsOn(Message.DOCUMENT, handleDocument);
EventsOn(Message.ERROR, handleError);
EventsOn(Message.INFO, handleInfo);
EventsOn(Message.PROGRESS, handleProgress);
@@ -85,7 +73,6 @@ export const ViewStatus = () => {
return () => {
EventsOff(Message.CANCELLED);
EventsOff(Message.COMPLETED);
- EventsOff(Message.DOCUMENT);
EventsOff(Message.ERROR);
EventsOff(Message.INFO);
EventsOff(Message.PROGRESS);
diff --git a/frontend/src/hooks/useEnvironment.tsx b/frontend/src/hooks/useEnvironment.tsx
index 8460a29b..d42569f5 100644
--- a/frontend/src/hooks/useEnvironment.tsx
+++ b/frontend/src/hooks/useEnvironment.tsx
@@ -5,7 +5,7 @@ export const useEnvironment = (key: string): string => {
const [envMap, setEnvMap] = useState