Rendering: Add light theme for errors (#41616)
* Add light theme for error rendering * Fix lint * Update images and add rendering_limit_x images
@ -65,6 +65,7 @@ func (hs *HTTPServer) RenderToPng(c *models.ReqContext) {
|
||||
ConcurrentLimit: hs.Cfg.RendererConcurrentRequestLimit,
|
||||
DeviceScaleFactor: scale,
|
||||
Headers: headers,
|
||||
Theme: rendering.ThemeDark,
|
||||
})
|
||||
if err != nil {
|
||||
if errors.Is(err, rendering.ErrTimeout) {
|
||||
|
@ -206,6 +206,7 @@ func (n *notificationService) renderAndUploadImage(evalCtx *EvalContext, timeout
|
||||
OrgID: evalCtx.Rule.OrgID,
|
||||
OrgRole: models.ROLE_ADMIN,
|
||||
ConcurrentLimit: setting.AlertingRenderLimit,
|
||||
Theme: rendering.ThemeDark,
|
||||
}
|
||||
|
||||
ref, err := evalCtx.GetDashboardUID()
|
||||
|
@ -365,7 +365,7 @@ func (s *testRenderService) RenderCSV(ctx context.Context, opts rendering.CSVOpt
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *testRenderService) RenderErrorImage(err error) (*rendering.RenderResult, error) {
|
||||
func (s *testRenderService) RenderErrorImage(theme rendering.Theme, err error) (*rendering.RenderResult, error) {
|
||||
if s.renderErrorImageProvider != nil {
|
||||
return s.renderErrorImageProvider(err)
|
||||
}
|
||||
|
@ -19,6 +19,13 @@ const (
|
||||
RenderPNG RenderType = "png"
|
||||
)
|
||||
|
||||
type Theme string
|
||||
|
||||
const (
|
||||
ThemeLight Theme = "light"
|
||||
ThemeDark Theme = "dark"
|
||||
)
|
||||
|
||||
type Opts struct {
|
||||
Width int
|
||||
Height int
|
||||
@ -32,6 +39,7 @@ type Opts struct {
|
||||
ConcurrentLimit int
|
||||
DeviceScaleFactor float64
|
||||
Headers map[string][]string
|
||||
Theme Theme
|
||||
}
|
||||
|
||||
type CSVOpts struct {
|
||||
@ -63,6 +71,6 @@ type Service interface {
|
||||
Version() string
|
||||
Render(ctx context.Context, opts Opts) (*RenderResult, error)
|
||||
RenderCSV(ctx context.Context, opts CSVOpts) (*RenderCSVResult, error)
|
||||
RenderErrorImage(error error) (*RenderResult, error)
|
||||
RenderErrorImage(theme Theme, error error) (*RenderResult, error)
|
||||
GetRenderUser(key string) (*RenderUser, bool)
|
||||
}
|
||||
|
@ -156,9 +156,18 @@ func (rs *RenderingService) Version() string {
|
||||
return rs.version
|
||||
}
|
||||
|
||||
func (rs *RenderingService) RenderErrorImage(_ error) (*RenderResult, error) {
|
||||
imgUrl := "public/img/rendering_error.png"
|
||||
imgPath := filepath.Join(setting.HomePath, imgUrl)
|
||||
func (rs *RenderingService) RenderErrorImage(theme Theme, err error) (*RenderResult, error) {
|
||||
if theme == "" {
|
||||
theme = ThemeDark
|
||||
}
|
||||
imgUrl := "public/img/rendering_%s_%s.png"
|
||||
if errors.Is(err, ErrTimeout) {
|
||||
imgUrl = fmt.Sprintf(imgUrl, "timeout", theme)
|
||||
} else {
|
||||
imgUrl = fmt.Sprintf(imgUrl, "error", theme)
|
||||
}
|
||||
|
||||
imgPath := filepath.Join(rs.Cfg.HomePath, imgUrl)
|
||||
if _, err := os.Stat(imgPath); errors.Is(err, os.ErrNotExist) {
|
||||
return nil, err
|
||||
}
|
||||
@ -188,8 +197,13 @@ func (rs *RenderingService) Render(ctx context.Context, opts Opts) (*RenderResul
|
||||
|
||||
func (rs *RenderingService) render(ctx context.Context, opts Opts) (*RenderResult, error) {
|
||||
if int(atomic.LoadInt32(&rs.inProgressCount)) > opts.ConcurrentLimit {
|
||||
theme := ThemeDark
|
||||
if opts.Theme != "" {
|
||||
theme = opts.Theme
|
||||
}
|
||||
filePath := fmt.Sprintf("public/img/rendering_limit_%s.png", theme)
|
||||
return &RenderResult{
|
||||
FilePath: filepath.Join(setting.HomePath, "public/img/rendering_limit.png"),
|
||||
FilePath: filepath.Join(rs.Cfg.HomePath, filePath),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,13 @@
|
||||
package rendering
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@ -58,3 +62,80 @@ func TestGetUrl(t *testing.T) {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestRenderErrorImage(t *testing.T) {
|
||||
path, err := filepath.Abs("../../../")
|
||||
require.NoError(t, err)
|
||||
|
||||
rs := RenderingService{
|
||||
Cfg: &setting.Cfg{
|
||||
HomePath: path,
|
||||
},
|
||||
}
|
||||
t.Run("No theme set returns error image with dark theme", func(t *testing.T) {
|
||||
result, err := rs.RenderErrorImage("", nil)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, result.FilePath, path+"/public/img/rendering_error_dark.png")
|
||||
})
|
||||
|
||||
t.Run("Timeout error returns timeout error image", func(t *testing.T) {
|
||||
result, err := rs.RenderErrorImage(ThemeLight, ErrTimeout)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, result.FilePath, path+"/public/img/rendering_timeout_light.png")
|
||||
})
|
||||
|
||||
t.Run("Generic error returns error image", func(t *testing.T) {
|
||||
result, err := rs.RenderErrorImage(ThemeLight, errors.New("an error"))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, result.FilePath, path+"/public/img/rendering_error_light.png")
|
||||
})
|
||||
|
||||
t.Run("Unknown image path returns error", func(t *testing.T) {
|
||||
result, err := rs.RenderErrorImage("abc", errors.New("random error"))
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, result)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRenderLimitImage(t *testing.T) {
|
||||
path, err := filepath.Abs("../../../")
|
||||
require.NoError(t, err)
|
||||
|
||||
rs := RenderingService{
|
||||
Cfg: &setting.Cfg{
|
||||
HomePath: path,
|
||||
},
|
||||
inProgressCount: 2,
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
theme Theme
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "Light theme returns light image",
|
||||
theme: ThemeLight,
|
||||
expected: path + "/public/img/rendering_limit_light.png",
|
||||
},
|
||||
{
|
||||
name: "Dark theme returns dark image",
|
||||
theme: ThemeDark,
|
||||
expected: path + "/public/img/rendering_limit_dark.png",
|
||||
},
|
||||
{
|
||||
name: "No theme returns dark image",
|
||||
theme: "",
|
||||
expected: path + "/public/img/rendering_limit_dark.png",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
opts := Opts{Theme: tc.theme, ConcurrentLimit: 1}
|
||||
result, err := rs.Render(context.Background(), opts)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tc.expected, result.FilePath)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
BIN
public/img/rendering_error_light.png
Normal file
After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
BIN
public/img/rendering_limit_light.png
Normal file
After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
BIN
public/img/rendering_timeout_light.png
Normal file
After Width: | Height: | Size: 11 KiB |