mirror of
https://github.com/akvorado/akvorado.git
synced 2025-12-11 22:14:02 +01:00
console/frontend: better error formatting
This commit is contained in:
13
common/helpers/strings.go
Normal file
13
common/helpers/strings.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package helpers
|
||||
|
||||
import "unicode"
|
||||
|
||||
// Capitalize turns the first letter of a string to its upper case version.
|
||||
func Capitalize(str string) string {
|
||||
if len(str) == 0 {
|
||||
return ""
|
||||
}
|
||||
r := []rune(str)
|
||||
r[0] = unicode.ToUpper(r[0])
|
||||
return string(r)
|
||||
}
|
||||
22
common/helpers/strings_test.go
Normal file
22
common/helpers/strings_test.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package helpers
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestCapitalize(t *testing.T) {
|
||||
cases := []struct {
|
||||
In string
|
||||
Out string
|
||||
}{
|
||||
{"", ""},
|
||||
{"Hello", "Hello"},
|
||||
{"bye", "Bye"},
|
||||
{" nothing", " nothing"},
|
||||
{"école", "École"},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
got := Capitalize(tc.In)
|
||||
if diff := Diff(got, tc.Out); diff != "" {
|
||||
t.Errorf("Capitalize(%q) (-got, +want):\n%s", tc.In, diff)
|
||||
}
|
||||
}
|
||||
}
|
||||
20
console/filter/error.go
Normal file
20
console/filter/error.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package filter
|
||||
|
||||
import "fmt"
|
||||
|
||||
// HumanError returns a more human-readable error for errList. It only outputs the first one.
|
||||
func HumanError(err error) string {
|
||||
el, ok := err.(errList)
|
||||
if !ok {
|
||||
return err.Error()
|
||||
}
|
||||
if len(el) == 0 {
|
||||
return ""
|
||||
}
|
||||
switch e := el[0].(type) {
|
||||
case *parserError:
|
||||
return fmt.Sprintf("at line %d, position %d: %s", e.pos.line, e.pos.col, e.Inner.Error())
|
||||
default:
|
||||
return e.Error()
|
||||
}
|
||||
}
|
||||
18
console/filter/error_test.go
Normal file
18
console/filter/error_test.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package filter
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"akvorado/common/helpers"
|
||||
)
|
||||
|
||||
func TestFilterError(t *testing.T) {
|
||||
_, err := Parse("", []byte(`
|
||||
InIfDescription = "Gi0/0/0/0"
|
||||
AND Proto = 1000
|
||||
OR `))
|
||||
expected := "at line 3, position 13: expecting an unsigned 8-bit integer"
|
||||
if diff := helpers.Diff(HumanError(err), expected); diff != "" {
|
||||
t.Errorf("HumanError() (-got, +want):\n%s", diff)
|
||||
}
|
||||
}
|
||||
@@ -98,10 +98,10 @@ func TestInvalidFilter(t *testing.T) {
|
||||
{`Proto = 1000`},
|
||||
{`SrcPort = 1000000`},
|
||||
{`ForwardingStatus >= 900`},
|
||||
{`Proto = 1000 AND`},
|
||||
{`AND Proto = 1000`},
|
||||
{`Proto = 1000AND Proto = 1000`},
|
||||
{`Proto = 1000 ANDProto = 1000`},
|
||||
{`Proto = 100 AND`},
|
||||
{`AND Proto = 100`},
|
||||
{`Proto = 100AND Proto = 100`},
|
||||
{`Proto = 100 ANDProto = 100`},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
_, err := Parse("", []byte(tc.Input))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="my-4 flex rounded-lg p-4 text-sm" :class="classes" role="alert">
|
||||
<InformationCircleIcon class="mr-2 h-5 w-5" />
|
||||
<slot></slot>
|
||||
<InformationCircleIcon class="mr-2 h-5 w-5 shrink-0" />
|
||||
<span><slot></slot></span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ func (gc graphColumn) MarshalText() ([]byte, error) {
|
||||
if ok {
|
||||
return []byte(got), nil
|
||||
}
|
||||
return nil, errors.New("unknown group operator")
|
||||
return nil, errors.New("unknown field")
|
||||
}
|
||||
func (gc graphColumn) String() string {
|
||||
got, _ := graphColumnMap.LoadValue(gc)
|
||||
@@ -101,7 +101,7 @@ func (gc *graphColumn) UnmarshalText(input []byte) error {
|
||||
*gc = got
|
||||
return nil
|
||||
}
|
||||
return errors.New("unknown group operator")
|
||||
return errors.New("unknown field")
|
||||
}
|
||||
|
||||
type graphFilter struct {
|
||||
@@ -114,7 +114,7 @@ func (gf graphFilter) MarshalText() ([]byte, error) {
|
||||
func (gf *graphFilter) UnmarshalText(input []byte) error {
|
||||
got, err := filter.Parse("", input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot parse filter: %w", err)
|
||||
return fmt.Errorf("cannot parse filter: %s", filter.HumanError(err))
|
||||
}
|
||||
*gf = graphFilter{got.(string)}
|
||||
return nil
|
||||
@@ -212,28 +212,28 @@ func (c *Component) graphHandlerFunc(gc *gin.Context) {
|
||||
ctx := c.t.Context(gc.Request.Context())
|
||||
var query graphQuery
|
||||
if err := gc.ShouldBindJSON(&query); err != nil {
|
||||
gc.JSON(http.StatusBadRequest, gin.H{"message": err.Error()})
|
||||
gc.JSON(http.StatusBadRequest, gin.H{"message": helpers.Capitalize(err.Error())})
|
||||
return
|
||||
}
|
||||
if query.Start.After(query.End) {
|
||||
gc.JSON(http.StatusBadRequest, gin.H{"message": "start should not be after end"})
|
||||
gc.JSON(http.StatusBadRequest, gin.H{"message": "Start should not be after end"})
|
||||
return
|
||||
}
|
||||
if query.Points < 5 || query.Points > 2000 {
|
||||
gc.JSON(http.StatusBadRequest, gin.H{"message": "points should be >= 5 and <= 2000"})
|
||||
gc.JSON(http.StatusBadRequest, gin.H{"message": "Points should be >= 5 and <= 2000"})
|
||||
return
|
||||
}
|
||||
if query.Limit == 0 {
|
||||
query.Limit = 10
|
||||
}
|
||||
if query.Limit < 5 || query.Limit > 50 {
|
||||
gc.JSON(http.StatusBadRequest, gin.H{"message": "limit should be >= 5 and <= 50"})
|
||||
gc.JSON(http.StatusBadRequest, gin.H{"message": "Limit should be >= 5 and <= 50"})
|
||||
return
|
||||
}
|
||||
|
||||
sqlQuery, err := query.toSQL()
|
||||
if err != nil {
|
||||
gc.JSON(http.StatusBadRequest, gin.H{"message": err.Error()})
|
||||
gc.JSON(http.StatusBadRequest, gin.H{"message": helpers.Capitalize(err.Error())})
|
||||
return
|
||||
}
|
||||
resolution := time.Duration(int64(query.End.Sub(query.Start).Nanoseconds()) / int64(query.Points))
|
||||
|
||||
@@ -23,7 +23,7 @@ func (c *Component) widgetFlowLastHandlerFunc(gc *gin.Context) {
|
||||
}
|
||||
|
||||
if !rows.Next() {
|
||||
gc.JSON(http.StatusNotFound, gin.H{"message": "no flow currently in database."})
|
||||
gc.JSON(http.StatusNotFound, gin.H{"message": "No flow currently in database."})
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
Reference in New Issue
Block a user