Skip to content

Commit

Permalink
UI and utility method improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
kyleu committed Nov 28, 2024
1 parent d6e1ef5 commit 024cd7e
Show file tree
Hide file tree
Showing 13 changed files with 294 additions and 102 deletions.
16 changes: 11 additions & 5 deletions app/util/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ func ToJSONBytes(x any, indent bool) []byte {
enc.SetIndent("", " ")
}
enc.SetEscapeHTML(false)
jsonHandleError(enc.Encode(x))
jsonHandleError(x, enc.Encode(x))
return bytes.TrimSuffix(bts.Bytes(), trailingNewline)
}
b, err := json.Marshal(x)
jsonHandleError(err)
jsonHandleError(x, err)
return bytes.TrimSuffix(b, trailingNewline)
}

Expand All @@ -50,6 +50,12 @@ func FromJSONMap(msg json.RawMessage) (ValueMap, error) {
return tgt, err
}

func FromJSONOrderedMap[V any](msg json.RawMessage) (*OrderedMap[V], error) {
var tgt *OrderedMap[V]
err := json.NewDecoder(bytes.NewReader(msg)).Decode(tgt)
return tgt, err
}

func FromJSONAny(msg json.RawMessage) (any, error) {
if bytes.HasPrefix(msg, []byte("\"{")) {
if str, err := FromJSONString(msg); err == nil {
Expand Down Expand Up @@ -92,12 +98,12 @@ func CycleJSON(src any, tgt any) error {

func JSONToMap(i any) map[string]any {
m := map[string]any{}
jsonHandleError(CycleJSON(i, &m))
jsonHandleError(i, CycleJSON(i, &m))
return m
}

func jsonHandleError(err error) {
func jsonHandleError(src any, err error) {
if err != nil && RootLogger != nil {
RootLogger.Warnf("error encountered serializing JSON: %+v", err)
RootLogger.Warnf("error [%s] encountered serializing JSON for type [%T]", err.Error(), src)
}
}
44 changes: 29 additions & 15 deletions app/util/mapordered.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ package util

import (
"bytes"
"cmp"
"encoding/json"
"encoding/xml"
"slices"
"strings"

"github.com/buger/jsonparser"
"github.com/samber/lo"
"golang.org/x/exp/maps"
)
Expand Down Expand Up @@ -41,6 +42,9 @@ func NewOMap[V any]() *OrderedMap[V] {
}

func (o *OrderedMap[V]) Set(k string, v V) {
if o.Map == nil {
o.Map = map[string]V{}
}
if _, ok := o.Map[k]; !ok {
o.Order = append(o.Order, k)
}
Expand Down Expand Up @@ -88,6 +92,11 @@ func (o *OrderedMap[V]) Clone() *OrderedMap[V] {
return &OrderedMap[V]{Lexical: o.Lexical, Order: slices.Clone(o.Order), Map: maps.Clone(o.Map)}
}

func (o *OrderedMap[V]) Clear() {
o.Order = nil
o.Map = map[string]V{}
}

func (o OrderedMap[V]) MarshalYAML() (any, error) {
return o.Map, nil
}
Expand Down Expand Up @@ -119,24 +128,29 @@ func (o OrderedMap[V]) MarshalXML(e *xml.Encoder, start xml.StartElement) error
return e.Flush()
}

func (o *OrderedMap[V]) UnmarshalJSON(b []byte) error {
if err := FromJSON(b, &o.Map); err != nil {
return err
}
func (o *OrderedMap[V]) UnmarshalJSON(data []byte) error {
o.Clear()
err := jsonparser.ObjectEach(data, func(keyData []byte, valueData []byte, dataType jsonparser.ValueType, offset int) error {
if dataType == jsonparser.String {
valueData = data[offset-len(valueData)-2 : offset]
}

index := make(map[string]int)
lo.ForEach(lo.Keys(o.Map), func(key string, _ int) {
o.Order = append(o.Order, key)
esc := ToJSONBytes(key, false) // escape the key
index[key] = bytes.Index(b, esc)
key, err := DecodeUTF8(keyData)
if err != nil {
return err
}
var value V
if err := json.Unmarshal(valueData, &value); err != nil {
return err
}
o.Set(key, value)
return nil
})

if err != nil {
return err
}
if o.Lexical {
slices.Sort(o.Order)
} else {
slices.SortFunc(o.Order, func(l string, r string) int {
return cmp.Compare(index[l], index[r])
})
}
return nil
}
Expand Down
113 changes: 113 additions & 0 deletions app/util/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,66 @@ func DefaultValue[T any]() T {
return ret
}

func ParseBoolSimple(r any) bool {
ret, _ := ParseBool(r, "", true)
return ret
}

func ParseFloatSimple(r any) float64 {
ret, _ := ParseFloat(r, "", true)
return ret
}

func ParseIntSimple(r any) int {
ret, _ := ParseInt(r, "", true)
return ret
}

func ParseInt16Simple(r any) int16 {
ret, _ := ParseInt16(r, "", true)
return ret
}

func ParseInt32Simple(r any) int32 {
ret, _ := ParseInt32(r, "", true)
return ret
}

func ParseInt64Simple(r any) int64 {
ret, _ := ParseInt64(r, "", true)
return ret
}

func ParseJSONSimple(r any) any {
ret, _ := ParseJSON(r, "", true)
return ret
}

func ParseMapSimple(r any) ValueMap {
ret, _ := ParseMap(r, "", true)
return ret
}

func ParseOrderedMapSimple(r any) *OrderedMap[any] {
ret, _ := ParseOrderedMap(r, "", true)
return ret
}

func ParseStringSimple(r any) string {
ret, _ := ParseString(r, "", true)
return ret
}

func ParseTimeSimple(r any) *time.Time {
ret, _ := ParseTime(r, "", true)
return ret
}

func ParseUUIDSimple(r any) *uuid.UUID {
ret, _ := ParseUUID(r, "", true)
return ret
}

func ParseBool(r any, path string, allowEmpty bool) (bool, error) {
switch t := r.(type) {
case bool:
Expand Down Expand Up @@ -196,6 +256,59 @@ func ParseMap(r any, path string, allowEmpty bool) (ValueMap, error) {
}
}

func ParseOrderedMap(r any, path string, allowEmpty bool) (*OrderedMap[any], error) {
switch t := r.(type) {
case *OrderedMap[any]:
if (!allowEmpty) && len(t.Map) == 0 {
return nil, errors.New("empty map")
}
return t, nil
case ValueMap:
if (!allowEmpty) && len(t) == 0 {
return nil, errors.New("empty map")
}
o := NewOrderedMap[any](false, len(t))
for k, v := range t {
o.Set(k, v)
}
return o, nil
case map[string]any:
if (!allowEmpty) && len(t) == 0 {
return nil, errors.New("empty map")
}
o := NewOrderedMap[any](false, len(t))
for k, v := range t {
o.Set(k, v)
}
return o, nil
case string:
if strings.TrimSpace(t) == "" {
return nil, nil
}
ret, err := FromJSONOrderedMap[any]([]byte(t))
if err != nil {
return nil, wrapError(path, "time", errors.Wrap(err, "invalid JSON"))
}
return ret, err
case []byte:
if len(t) == 0 {
return nil, nil
}
ret, err := FromJSONOrderedMap[any](t)
if err != nil {
return nil, wrapError(path, "time", errors.Wrap(err, "invalid JSON"))
}
return ret, err
case nil:
if !allowEmpty {
return nil, errors.Errorf("could not find ordered map for path [%s]", path)
}
return nil, nil
default:
return nil, invalidTypeError(path, "ordered map", t)
}
}

func ParseString(r any, path string, allowEmpty bool) (string, error) {
switch t := r.(type) {
case rune:
Expand Down
24 changes: 20 additions & 4 deletions app/util/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"reflect"
"runtime"
"strings"
"unicode/utf8"

"github.com/pkg/errors"
"github.com/samber/lo"
Expand Down Expand Up @@ -173,6 +174,13 @@ func StringReplaceBetween(s string, l string, r string, replacement string) (str
return s[:lio] + replacement + s[ri:], nil
}

func StringNullable(s fmt.Stringer) string {
if s == nil || reflect.ValueOf(s).IsNil() {
return ""
}
return s.String()
}

func CountryFlag(code string) string {
if len(code) != 2 {
return fmt.Sprintf("INVALID: %q", code)
Expand All @@ -188,9 +196,17 @@ func Filename(s string) string {
return filenameReplacer.Replace(s)
}

func StringNullable(s fmt.Stringer) string {
if s == nil || reflect.ValueOf(s).IsNil() {
return ""
func DecodeUTF8(input []byte) (string, error) {
remaining, offset := input, 0
runes := make([]rune, 0, len(remaining))
for len(remaining) > 0 {
r, size := utf8.DecodeRune(remaining)
if r == utf8.RuneError && size <= 1 {
return "", fmt.Errorf("not a valid UTF-8 string (at position %d): %s", offset, string(input))
}
runes = append(runes, r)
remaining = remaining[size:]
offset += size
}
return s.String()
return string(runes), nil
}
2 changes: 1 addition & 1 deletion assets/client.css

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions assets/client.css.map

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"@types/jest": "^29.5.14",
"@types/node": "^22.8.6",
"@typescript-eslint/eslint-plugin": "^8.12.2",
"cross-spawn": "^7.0.5",
"eslint": "^8.56.0",
"jest": "^29.7.0",
"ts-jest": "^29.2.5",
Expand Down
8 changes: 8 additions & 0 deletions client/src/style/modal.css
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@
flex-direction: column;
}

.modal.wide .modal-content {
min-width: 90%;
}

.modal.tall .modal-content {
min-height: 90%;
}

.modal-content .modal-header {
flex-grow: 0;
padding: var(--padding) var(--padding) 0 var(--padding);
Expand Down
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ require (
github.com/alecthomas/chroma v0.10.0
github.com/andybalholm/brotli v1.1.1
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de
github.com/buger/jsonparser v1.1.1
github.com/buildkite/shellwords v0.0.0-20180315110454-59467a9b8e10
github.com/coreos/go-semver v0.3.1
github.com/dop251/goja v0.0.0-20240828124009-016eb7256539
github.com/dop251/goja v0.0.0-20241024094426-79f3a7efcdbd
github.com/dsoprea/go-exif/v3 v3.0.1
github.com/dustin/go-humanize v1.0.1
github.com/gertd/go-pluralize v0.2.1
Expand Down Expand Up @@ -67,7 +68,7 @@ require (
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
github.com/golang/geo v0.0.0-20230421003525-6adc56603217 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/pprof v0.0.0-20240829160300-da1f7e9f2b25 // indirect
github.com/google/pprof v0.0.0-20241101162523-b92577c0c142 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
Expand Down
10 changes: 6 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhP
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/buildkite/shellwords v0.0.0-20180315110454-59467a9b8e10 h1:XwHQ5xDtYPdtBbVPyRO6UZoWZe8/mbKUb076f8x7RvI=
github.com/buildkite/shellwords v0.0.0-20180315110454-59467a9b8e10/go.mod h1:gv0DYOzHEsKgo31lTCDGauIg4DTTGn41Bzp+t3wSOlk=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
Expand All @@ -30,8 +32,8 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dop251/goja v0.0.0-20240828124009-016eb7256539 h1:YIxvsQAoCLGScK2c9ag+4sFCgiQFpMzywJG6dQZFu9k=
github.com/dop251/goja v0.0.0-20240828124009-016eb7256539/go.mod h1:MxLav0peU43GgvwVgNbLAj1s/bSGboKkhuULvq/7hx4=
github.com/dop251/goja v0.0.0-20241024094426-79f3a7efcdbd h1:QMSNEh9uQkDjyPwu/J541GgSH+4hw+0skJDIj9HJ3mE=
github.com/dop251/goja v0.0.0-20241024094426-79f3a7efcdbd/go.mod h1:MxLav0peU43GgvwVgNbLAj1s/bSGboKkhuULvq/7hx4=
github.com/dsoprea/go-exif/v2 v2.0.0-20200321225314-640175a69fe4/go.mod h1:Lm2lMM2zx8p4a34ZemkaUV95AnMl4ZvLbCUbwOvLC2E=
github.com/dsoprea/go-exif/v3 v3.0.0-20200717053412-08f1b6708903/go.mod h1:0nsO1ce0mh5czxGeLo4+OCZ/C6Eo6ZlMWsz7rH/Gxv8=
github.com/dsoprea/go-exif/v3 v3.0.0-20210625224831-a6301f85c82b/go.mod h1:cg5SNYKHMmzxsr9X6ZeLh/nfBRHHp5PngtEPcujONtk=
Expand Down Expand Up @@ -104,8 +106,8 @@ github.com/google/go-github/v39 v39.2.0 h1:rNNM311XtPOz5rDdsJXAp2o8F67X9FnROXTvt
github.com/google/go-github/v39 v39.2.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/pprof v0.0.0-20240829160300-da1f7e9f2b25 h1:sEDPKUw6iPjczdu33njxFjO6tYa9bfc0z/QyB/zSsBw=
github.com/google/pprof v0.0.0-20240829160300-da1f7e9f2b25/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/pprof v0.0.0-20241101162523-b92577c0c142 h1:sAGdeJj0bnMgUNVeUpp6AYlVdCt3/GdI3pGRqsNSQLs=
github.com/google/pprof v0.0.0-20241101162523-b92577c0c142/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
Expand Down
Loading

0 comments on commit 024cd7e

Please sign in to comment.