Skip to content

Commit 149f812

Browse files
committed
start new user interface
Lays out the structure for the new React-based user interface. Implements wallet initialization sequence. Implements basic header and sidebar interface used for most views. Implements functionality related to forms and context management.
1 parent 1664c16 commit 149f812

130 files changed

Lines changed: 9959 additions & 194 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

client/core/core.go

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1736,13 +1736,13 @@ func (c *Core) Run(ctx context.Context) {
17361736

17371737
// Construct enabled fiat rate sources.
17381738
fetchers:
1739-
for token, rateFetcher := range fiatRateFetchers {
1739+
for src, f := range fiatRateFetchers {
17401740
for _, v := range disabledSources {
1741-
if token == v {
1741+
if src == v {
17421742
continue fetchers
17431743
}
17441744
}
1745-
c.fiatRateSources[token] = newCommonRateSource(rateFetcher)
1745+
c.fiatRateSources[src] = newCommonRateSource(src, f)
17461746
}
17471747
c.fetchFiatExchangeRates(ctx)
17481748

@@ -2537,12 +2537,14 @@ func (c *Core) assetMap() map[uint32]*SupportedAsset {
25372537
// User is a thread-safe getter for the User.
25382538
func (c *Core) User() *User {
25392539
m := c.coreMesh()
2540+
idRates, tickerRates := c.fiatConversions()
25402541
return &User{
25412542
Assets: c.assetMap(),
25422543
Exchanges: c.Exchanges(),
25432544
Initialized: c.IsInitialized(),
25442545
SeedGenerationTime: c.seedGenerationTime,
2545-
FiatRates: c.fiatConversions(),
2546+
FiatRates: idRates,
2547+
TickerRates: tickerRates,
25462548
Net: c.net,
25472549
ExtensionConfig: c.extensionModeConfig,
25482550
Actions: c.requestedActionsList(),
@@ -10725,9 +10727,9 @@ func (c *Core) refreshFiatRates(ctx context.Context) {
1072510727
// Remove expired rate source if any.
1072610728
c.removeExpiredRateSources()
1072710729

10728-
fiatRatesMap := c.fiatConversions()
10729-
if len(fiatRatesMap) != 0 {
10730-
c.notify(newFiatRatesUpdate(fiatRatesMap))
10730+
idRates, tickerRates := c.fiatConversions()
10731+
if len(idRates) != 0 {
10732+
c.notify(newFiatRatesUpdate(idRates, tickerRates))
1073110733
}
1073210734
}
1073310735

@@ -10746,12 +10748,13 @@ func (c *Core) FiatRateSources() map[string]bool {
1074610748
// FiatConversionRates are the currently cached fiat conversion rates. Must have
1074710749
// 1 or more fiat rate sources enabled.
1074810750
func (c *Core) FiatConversionRates() map[uint32]float64 {
10749-
return c.fiatConversions()
10751+
idRates, _ := c.fiatConversions()
10752+
return idRates
1075010753
}
1075110754

1075210755
// fiatConversions returns fiat rate for all supported assets that have a
1075310756
// wallet.
10754-
func (c *Core) fiatConversions() map[uint32]float64 {
10757+
func (c *Core) fiatConversions() (map[uint32]float64, map[string]float64) {
1075510758
assetIDs := make(map[uint32]struct{})
1075610759
supportedAssets := asset.Assets()
1075710760
for assetID, asset := range supportedAssets {
@@ -10762,6 +10765,7 @@ func (c *Core) fiatConversions() map[uint32]float64 {
1076210765
}
1076310766

1076410767
fiatRatesMap := make(map[uint32]float64, len(supportedAssets))
10768+
tickerRatesMap := make(map[string]float64)
1076510769
for assetID := range assetIDs {
1076610770
var rateSum float64
1076710771
var sources int
@@ -10780,19 +10784,22 @@ func (c *Core) fiatConversions() map[uint32]float64 {
1078010784
}
1078110785
}
1078210786
if rateSum != 0 {
10783-
fiatRatesMap[assetID] = rateSum / float64(sources) // get average rate.
10787+
r := rateSum / float64(sources) // get average rate.
10788+
fiatRatesMap[assetID] = r
10789+
ui, _ := asset.UnitInfo(assetID)
10790+
tickerRatesMap[ui.Conventional.Unit] = r
1078410791
}
1078510792
}
10786-
return fiatRatesMap
10793+
return fiatRatesMap, tickerRatesMap
1078710794
}
1078810795

1078910796
// ToggleRateSourceStatus toggles a fiat rate source status. If disable is true,
1079010797
// the fiat rate source is disabled, otherwise the rate source is enabled.
10791-
func (c *Core) ToggleRateSourceStatus(source string, disable bool) error {
10792-
if disable {
10793-
return c.disableRateSource(source)
10798+
func (c *Core) ToggleRateSourceStatus(source string, enable bool) error {
10799+
if enable {
10800+
return c.enableRateSource(source)
1079410801
}
10795-
return c.enableRateSource(source)
10802+
return c.disableRateSource(source)
1079610803
}
1079710804

1079810805
// enableRateSource enables a fiat rate source.
@@ -10810,7 +10817,7 @@ func (c *Core) enableRateSource(source string) error {
1081010817
}
1081110818

1081210819
// Build fiat rate source.
10813-
rateSource := newCommonRateSource(rateFetcher)
10820+
rateSource := newCommonRateSource(source, rateFetcher)
1081410821
c.fiatRateSources[source] = rateSource
1081510822

1081610823
select {
@@ -11294,6 +11301,11 @@ func (c *Core) ExtensionModeConfig() *ExtensionModeConfig {
1129411301
return c.extensionModeConfig
1129511302
}
1129611303

11304+
func (c *Core) ValidateSeed(seed string) (bool, error) {
11305+
_, _, err := decodeSeedString(seed)
11306+
return err == nil, nil
11307+
}
11308+
1129711309
// calcParcelLimit computes the users score-scaled user parcel limit.
1129811310
func calcParcelLimit(tier int64, score, maxScore int32) uint32 {
1129911311
// Users limit starts at 2 parcels per tier.

client/core/core_test.go

Lines changed: 3 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -10524,7 +10524,7 @@ func TestToggleRateSourceStatus(t *testing.T) {
1052410524

1052510525
// Test disabling fiat rate source.
1052610526
for _, test := range tests {
10527-
err := tCore.ToggleRateSourceStatus(test.source, true)
10527+
err := tCore.ToggleRateSourceStatus(test.source, false)
1052810528
if test.wantErr != (err != nil) {
1052910529
t.Fatalf("%s: wantErr = %t, err = %v", test.name, test.wantErr, err)
1053010530
}
@@ -10533,76 +10533,15 @@ func TestToggleRateSourceStatus(t *testing.T) {
1053310533
// Test enabling fiat rate source.
1053410534
for _, test := range tests {
1053510535
if test.init {
10536-
tCore.fiatRateSources[test.source] = newCommonRateSource(tFetcher)
10536+
tCore.fiatRateSources[test.source] = newCommonRateSource(test.source, tFetcher)
1053710537
}
10538-
err := tCore.ToggleRateSourceStatus(test.source, false)
10538+
err := tCore.ToggleRateSourceStatus(test.source, true)
1053910539
if test.wantErr != (err != nil) {
1054010540
t.Fatalf("%s: wantErr = %t, err = %v", test.name, test.wantErr, err)
1054110541
}
1054210542
}
1054310543
}
1054410544

10545-
func TestFiatRateSources(t *testing.T) {
10546-
rig := newTestRig()
10547-
defer rig.shutdown()
10548-
tCore := rig.core
10549-
supportedFetchers := len(fiatRateFetchers)
10550-
rateSources := tCore.FiatRateSources()
10551-
if len(rateSources) != supportedFetchers {
10552-
t.Fatalf("Expected %d number of fiat rate source/fetchers", supportedFetchers)
10553-
}
10554-
}
10555-
10556-
func TestFiatConversions(t *testing.T) {
10557-
rig := newTestRig()
10558-
defer rig.shutdown()
10559-
tCore := rig.core
10560-
10561-
// No fiat rate source initialized
10562-
fiatRates := tCore.fiatConversions()
10563-
if len(fiatRates) != 0 {
10564-
t.Fatal("Unexpected asset rate values.")
10565-
}
10566-
10567-
// Initialize fiat rate sources.
10568-
for token := range fiatRateFetchers {
10569-
tCore.fiatRateSources[token] = newCommonRateSource(tFetcher)
10570-
}
10571-
10572-
// Fetch fiat rates.
10573-
tCore.wg.Add(1)
10574-
go func() {
10575-
defer tCore.wg.Done()
10576-
tCore.refreshFiatRates(tCtx)
10577-
}()
10578-
tCore.wg.Wait()
10579-
10580-
// Expects assets fiat rate values.
10581-
fiatRates = tCore.fiatConversions()
10582-
if len(fiatRates) != 2 {
10583-
t.Fatal("Expected assets fiat rate for two assets")
10584-
}
10585-
10586-
// fiat rates for assets can expire, and fiat rate fetchers can be
10587-
// removed if expired.
10588-
for token, source := range tCore.fiatRateSources {
10589-
source.fiatRates[tUTXOAssetA.ID].lastUpdate = time.Now().Add(-time.Minute)
10590-
source.fiatRates[tUTXOAssetB.ID].lastUpdate = time.Now().Add(-time.Minute)
10591-
if source.isExpired(55 * time.Second) {
10592-
delete(tCore.fiatRateSources, token)
10593-
}
10594-
}
10595-
10596-
fiatRates = tCore.fiatConversions()
10597-
if len(fiatRates) != 0 {
10598-
t.Fatal("Unexpected assets fiat rate values, expected to ignore expired fiat rates.")
10599-
}
10600-
10601-
if len(tCore.fiatRateSources) != 0 {
10602-
t.Fatal("Expected fiat conversion to be disabled, all rate source data has expired.")
10603-
}
10604-
}
10605-
1060610545
func TestValidateAddress(t *testing.T) {
1060710546
rig := newTestRig()
1060810547
defer rig.shutdown()

client/core/exchangeratefetcher.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ const (
2525

2626
// Tokens. Used to identify fiat rate source, source name must not contain a
2727
// comma.
28-
messari = "Messari"
2928
coinpaprika = "Coinpaprika"
3029
dcrdataDotOrg = "dcrdata"
3130
)
@@ -64,6 +63,7 @@ type fiatRateInfo struct {
6463
type rateFetcher func(context context.Context, logger dex.Logger, assets map[uint32]*SupportedAsset) map[uint32]float64
6564

6665
type commonRateSource struct {
66+
source string
6767
fetchRates rateFetcher
6868

6969
mtx sync.RWMutex
@@ -114,7 +114,7 @@ func (source *commonRateSource) refreshRates(ctx context.Context, logger dex.Log
114114
}
115115

116116
// Used to initialize a fiat rate source.
117-
func newCommonRateSource(fetcher rateFetcher) *commonRateSource {
117+
func newCommonRateSource(name string, fetcher rateFetcher) *commonRateSource {
118118
return &commonRateSource{
119119
fetchRates: fetcher,
120120
fiatRates: make(map[uint32]*fiatRateInfo),

client/core/notification.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -522,15 +522,17 @@ func newConnEventNote(topic Topic, subject, host string, status comms.Connection
522522
// FiatRatesNote is an update of fiat rate data for assets.
523523
type FiatRatesNote struct {
524524
db.Notification
525-
FiatRates map[uint32]float64 `json:"fiatRates"`
525+
FiatRates map[uint32]float64 `json:"fiatRates"`
526+
TickerRates map[string]float64 `json:"tickerRates"`
526527
}
527528

528529
const TopicFiatRatesUpdate Topic = "fiatrateupdate"
529530

530-
func newFiatRatesUpdate(rates map[uint32]float64) *FiatRatesNote {
531+
func newFiatRatesUpdate(idRates map[uint32]float64, tickerRates map[string]float64) *FiatRatesNote {
531532
return &FiatRatesNote{
532533
Notification: db.NewNotification(NoteTypeFiatRates, TopicFiatRatesUpdate, "", "", db.Data),
533-
FiatRates: rates,
534+
FiatRates: idRates,
535+
TickerRates: tickerRates,
534536
}
535537
}
536538

client/core/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ type User struct {
203203
SeedGenerationTime uint64 `json:"seedgentime"`
204204
Assets map[uint32]*SupportedAsset `json:"assets"`
205205
FiatRates map[uint32]float64 `json:"fiatRates"`
206+
TickerRates map[string]float64 `json:"tickerRates"`
206207
Net dex.Network `json:"net"`
207208
ExtensionConfig *ExtensionModeConfig `json:"extensionModeConfig,omitempty"`
208209
Actions []*asset.ActionRequiredNote `json:"actions,omitempty"`

client/webserver/api.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,25 @@ func (s *WebServer) apiInit(w http.ResponseWriter, r *http.Request) {
964964
})
965965
}
966966

967+
func (s *WebServer) apiValidateSeed(w http.ResponseWriter, r *http.Request) {
968+
var seed string
969+
if !readPost(w, r, &seed) {
970+
return
971+
}
972+
973+
ok, err := s.core.ValidateSeed(seed)
974+
if err != nil {
975+
s.writeAPIError(w, fmt.Errorf("error validating seed: %w", err))
976+
return
977+
}
978+
979+
writeJSON(w, struct {
980+
OK bool `json:"ok"`
981+
}{
982+
OK: ok,
983+
})
984+
}
985+
967986
// apiIsInitialized is the handler for the '/isinitialized' request.
968987
func (s *WebServer) apiIsInitialized(w http.ResponseWriter, r *http.Request) {
969988
writeJSON(w, &struct {
@@ -1607,13 +1626,13 @@ func (s *WebServer) apiUser(w http.ResponseWriter, r *http.Request) {
16071626
// apiToggleRateSource handles the /toggleratesource API request.
16081627
func (s *WebServer) apiToggleRateSource(w http.ResponseWriter, r *http.Request) {
16091628
form := &struct {
1610-
Disable bool `json:"disable"`
1611-
Source string `json:"source"`
1629+
Enable bool `json:"enable"`
1630+
Source string `json:"source"`
16121631
}{}
16131632
if !readPost(w, r, form) {
16141633
return
16151634
}
1616-
err := s.core.ToggleRateSourceStatus(form.Source, form.Disable)
1635+
err := s.core.ToggleRateSourceStatus(form.Source, form.Enable)
16171636
if err != nil {
16181637
s.writeAPIError(w, fmt.Errorf("error disabling/enabling rate source: %w", err))
16191638
return
@@ -2256,6 +2275,7 @@ func (s *WebServer) writeAPIError(w http.ResponseWriter, err error) {
22562275
innerErr := core.UnwrapErr(err)
22572276
resp := &standardResponse{
22582277
OK: false,
2278+
Bad: true,
22592279
Msg: innerErr.Error(),
22602280
Code: code,
22612281
}

client/webserver/live_test.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1890,8 +1890,8 @@ func (c *TCore) UpdateDEXHost(string, string, []byte, any) (*core.Exchange, erro
18901890
func (c *TCore) WalletRestorationInfo(pw []byte, assetID uint32) ([]*asset.WalletRestoration, error) {
18911891
return nil, nil
18921892
}
1893-
func (c *TCore) ToggleRateSourceStatus(src string, disable bool) error {
1894-
c.fiatSources[src] = !disable
1893+
func (c *TCore) ToggleRateSourceStatus(src string, enable bool) error {
1894+
c.fiatSources[src] = enable
18951895
return nil
18961896
}
18971897
func (c *TCore) FiatRateSources() map[string]bool {
@@ -2038,6 +2038,10 @@ func (c *TCore) BridgeHistory(assetID uint32, n int, refID *string, past bool) (
20382038
return nil, nil
20392039
}
20402040

2041+
func (*TCore) ValidateSeed(string) (bool, error) {
2042+
return true, nil
2043+
}
2044+
20412045
func newMarketDay() *libxc.MarketDay {
20422046
avgPrice := tenToThe(7)
20432047
return &libxc.MarketDay{

client/webserver/middleware.go

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -63,21 +63,6 @@ func (s *WebServer) tokenAuthMiddleware(next http.Handler) http.Handler {
6363
})
6464
}
6565

66-
// extractBooleanCookie extracts the cookie value with key k from the Request,
67-
// and interprets the value as true only if it's equal to the string "1".
68-
func extractBooleanCookie(r *http.Request, k string, defaultVal bool) bool {
69-
cookie, err := r.Cookie(k)
70-
switch {
71-
// Dark mode is the default
72-
case err == nil:
73-
return cookie.Value == "1"
74-
case errors.Is(err, http.ErrNoCookie):
75-
default:
76-
log.Errorf("Cookie %q retrieval error: %v", k, err)
77-
}
78-
return defaultVal
79-
}
80-
8166
// requireInit ensures that the core app is initialized before allowing the
8267
// incoming request to proceed. Redirects to the register page if the app is
8368
// not initialized.

client/webserver/newui.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//go:build newui
2+
3+
// This code is available on the terms of the project LICENSE.md file,
4+
// also available online at https://blueoakcouncil.org/license/1.0.0.
5+
6+
package webserver
7+
8+
import (
9+
"embed"
10+
"io/fs"
11+
)
12+
13+
const (
14+
newUI = true
15+
// site is the common prefix for the site resources with respect to this
16+
// webserver package.
17+
site = "newui"
18+
)
19+
20+
var (
21+
//go:embed newui/dist newui/src/img newui/src/font
22+
staticSiteRes embed.FS
23+
24+
// Unused for New UI
25+
htmlTmplRes embed.FS
26+
htmlTmplSub fs.FS
27+
)

0 commit comments

Comments
 (0)