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 eb1aaba commit b3e6cd3
Show file tree
Hide file tree
Showing 13 changed files with 291 additions and 99 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
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/CAFxX/httpcompression v0.0.9
github.com/alecthomas/chroma v0.10.0
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/dsoprea/go-exif/v3 v3.0.1
Expand Down Expand Up @@ -72,7 +73,7 @@ require (
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.3.3 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgtype v1.14.3 // indirect
github.com/jackc/pgtype v1.14.4 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect
github.com/lestrrat-go/blackmagic v1.0.2 // indirect
Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuP
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
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 Down Expand Up @@ -165,8 +167,8 @@ github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCM
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
github.com/jackc/pgtype v1.14.3 h1:h6W9cPuHsRWQFTWUZMAKMgG5jSwQI0Zurzdvlx3Plus=
github.com/jackc/pgtype v1.14.3/go.mod h1:aKeozOde08iifGosdJpz9MBZonJOUJxqNpPBcMJTlVA=
github.com/jackc/pgtype v1.14.4 h1:fKuNiCumbKTAIxQwXfB/nsrnkEI6bPJrrSiMKgbJ2j8=
github.com/jackc/pgtype v1.14.4/go.mod h1:aKeozOde08iifGosdJpz9MBZonJOUJxqNpPBcMJTlVA=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
Expand Down
10 changes: 10 additions & 0 deletions views/components/view/Any.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@
{%= Int(t) %}
{% case int64 %}
{%= Int(t) %}
{% case util.ToOrderedMap[any] %}
{%= OrderedMap(false, t.ToOrderedMap(), ps) %}
{% case *util.OrderedMap[any] %}
{%= OrderedMap(false, t, ps) %}
{% case util.ToOrderedMaps[any] %}
{%= OrderedMapArray(false, ps, t.ToOrderedMaps()...) %}
{% case []*util.OrderedMap[any] %}
{%= OrderedMapArray(false, ps, t...) %}
{% case util.ToMap %}
{%= Map(false, t.ToMap(), ps) %}
{% case util.ValueMap %}
Expand Down Expand Up @@ -71,6 +79,8 @@
<div class="bb"><em>...and{% space %}{%d extra %}{% space %}more</em></div>
{% endif %}
{%- endif -%}
{% case fmt.Stringer %}
{%= String(t.String()) %}
{% default %}
unhandled type [{%s fmt.Sprintf("%T", x) %}]
{% endswitch %}
Expand Down
Loading

0 comments on commit b3e6cd3

Please sign in to comment.