Image Rendering: Add settings for default width, height and scale (#82040)

* Add Image width & height

* ability to change default width, height and scale

* default ini

* Update conf/defaults.ini

Co-authored-by: Agnès Toulet <35176601+AgnesToulet@users.noreply.github.com>

* Update pkg/setting/setting.go

Co-authored-by: Agnès Toulet <35176601+AgnesToulet@users.noreply.github.com>

* Update pkg/setting/setting.go

Co-authored-by: Agnès Toulet <35176601+AgnesToulet@users.noreply.github.com>

* Added docs, changed frontend

* Update conf/defaults.ini

Co-authored-by: Agnès Toulet <35176601+AgnesToulet@users.noreply.github.com>

* Update conf/defaults.ini

Co-authored-by: Agnès Toulet <35176601+AgnesToulet@users.noreply.github.com>

* Update conf/defaults.ini

Co-authored-by: Agnès Toulet <35176601+AgnesToulet@users.noreply.github.com>

* Update docs/sources/setup-grafana/configure-grafana/_index.md

Co-authored-by: Agnès Toulet <35176601+AgnesToulet@users.noreply.github.com>

* Update pkg/api/dtos/frontend_settings.go

Co-authored-by: Agnès Toulet <35176601+AgnesToulet@users.noreply.github.com>

* Update pkg/api/frontendsettings.go

Co-authored-by: Agnès Toulet <35176601+AgnesToulet@users.noreply.github.com>

* Update pkg/api/render.go

Co-authored-by: Agnès Toulet <35176601+AgnesToulet@users.noreply.github.com>

* add query float 64

* Update packages/grafana-runtime/src/config.ts

Co-authored-by: Agnès Toulet <35176601+AgnesToulet@users.noreply.github.com>

* Update public/app/features/dashboard/components/ShareModal/utils.ts

Co-authored-by: Agnès Toulet <35176601+AgnesToulet@users.noreply.github.com>

* spacing

* fix tests

* Update docs/sources/setup-grafana/configure-grafana/_index.md

Co-authored-by: Christopher Moyer <35463610+chri2547@users.noreply.github.com>

* Update docs/sources/setup-grafana/configure-grafana/_index.md

Co-authored-by: Christopher Moyer <35463610+chri2547@users.noreply.github.com>

* Update docs/sources/setup-grafana/configure-grafana/_index.md

Co-authored-by: Christopher Moyer <35463610+chri2547@users.noreply.github.com>

---------

Co-authored-by: Agnès Toulet <35176601+AgnesToulet@users.noreply.github.com>
Co-authored-by: Christopher Moyer <35463610+chri2547@users.noreply.github.com>
This commit is contained in:
Khushi Jain 2024-02-26 17:57:34 +05:30 committed by GitHub
parent 3f2eb8bd6a
commit d02de5ddb9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 62 additions and 18 deletions

View File

@ -1568,6 +1568,12 @@ concurrent_render_request_limit = 30
# Default is 5m. This should be more than enough for most deployments.
# Change the value only if image rendering is failing and you see `Failed to get the render key from cache` in Grafana logs.
render_key_lifetime = 5m
# Default width for panel screenshot
default_image_width = 1000
# Default height for panel screenshot
default_image_height = 500
# Default scale for panel screenshot
default_image_scale = 1
[panels]
# here for to support old env variables, can remove after a few months

View File

@ -2168,6 +2168,18 @@ If the remote HTTP image renderer service runs on a different server than the Gr
Concurrent render request limit affects when the /render HTTP endpoint is used. Rendering many images at the same time can overload the server,
which this setting can help protect against by only allowing a certain number of concurrent requests. Default is `30`.
### default_image_width
Configures the width of the rendered image. The default width is `1000`.
### default_image_height
Configures the height of the rendered image. The default height is `500`.
### default_image_scale
Configures the scale of the rendered image. The default scale is `1`.
## [panels]
### enable_alpha

View File

@ -99,6 +99,9 @@ export class GrafanaBootConfig implements GrafanaConfig {
licenseInfo: LicenseInfo = {} as LicenseInfo;
rendererAvailable = false;
rendererVersion = '';
rendererDefaultImageWidth = 1000;
rendererDefaultImageHeight = 500;
rendererDefaultImageScale = 1;
secretsManagerPluginEnabled = false;
supportBundlesEnabled = false;
http2Enabled = false;

View File

@ -208,6 +208,9 @@ type FrontendSettingsDTO struct {
AnonymousDeviceLimit int64 `json:"anonymousDeviceLimit"`
RendererAvailable bool `json:"rendererAvailable"`
RendererVersion string `json:"rendererVersion"`
RendererDefaultImageWidth int `json:"rendererDefaultImageWidth"`
RendererDefaultImageHeight int `json:"rendererDefaultImageHeight"`
RendererDefaultImageScale float64 `json:"rendererDefaultImageScale"`
SecretsManagerPluginEnabled bool `json:"secretsManagerPluginEnabled"`
Http2Enabled bool `json:"http2Enabled"`
GrafanaJavascriptAgent setting.GrafanaJavascriptAgent `json:"grafanaJavascriptAgent"`

View File

@ -245,6 +245,9 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro
AnonymousDeviceLimit: hs.Cfg.AnonymousDeviceLimit,
RendererAvailable: hs.RenderService.IsAvailable(c.Req.Context()),
RendererVersion: hs.RenderService.Version(),
RendererDefaultImageWidth: hs.Cfg.RendererDefaultImageWidth,
RendererDefaultImageHeight: hs.Cfg.RendererDefaultImageHeight,
RendererDefaultImageScale: hs.Cfg.RendererDefaultImageScale,
SecretsManagerPluginEnabled: secretsManagerPluginEnabled,
Http2Enabled: hs.Cfg.Protocol == setting.HTTP2Scheme,
GrafanaJavascriptAgent: hs.Cfg.GrafanaJavascriptAgent,

View File

@ -24,16 +24,14 @@ func (hs *HTTPServer) RenderToPng(c *contextmodel.ReqContext) {
queryParams := fmt.Sprintf("?%s", c.Req.URL.RawQuery)
width, err := strconv.Atoi(queryReader.Get("width", "800"))
if err != nil {
c.Handle(hs.Cfg, 400, "Render parameters error", fmt.Errorf("cannot parse width as int: %s", err))
return
width := c.QueryInt("width")
if width == 0 {
width = hs.Cfg.RendererDefaultImageWidth
}
height, err := strconv.Atoi(queryReader.Get("height", "400"))
if err != nil {
c.Handle(hs.Cfg, 400, "Render parameters error", fmt.Errorf("cannot parse height as int: %s", err))
return
height := c.QueryInt("height")
if height == 0 {
height = hs.Cfg.RendererDefaultImageHeight
}
timeout, err := strconv.Atoi(queryReader.Get("timeout", "60"))
@ -42,10 +40,9 @@ func (hs *HTTPServer) RenderToPng(c *contextmodel.ReqContext) {
return
}
scale, err := strconv.ParseFloat(queryReader.Get("scale", "1"), 64)
if err != nil {
c.Handle(hs.Cfg, 400, "Render parameters error", fmt.Errorf("cannot parse scale as float: %s", err))
return
scale := c.QueryFloat64("scale")
if scale == 0 {
scale = hs.Cfg.RendererDefaultImageScale
}
headers := http.Header{}

View File

@ -149,6 +149,9 @@ type Cfg struct {
RendererAuthToken string
RendererConcurrentRequestLimit int
RendererRenderKeyLifeTime time.Duration
RendererDefaultImageWidth int
RendererDefaultImageHeight int
RendererDefaultImageScale float64
// Security
DisableInitAdminCreation bool
@ -1739,6 +1742,9 @@ func (cfg *Cfg) readRenderingSettings(iniFile *ini.File) error {
cfg.RendererConcurrentRequestLimit = renderSec.Key("concurrent_render_request_limit").MustInt(30)
cfg.RendererRenderKeyLifeTime = renderSec.Key("render_key_lifetime").MustDuration(5 * time.Minute)
cfg.RendererDefaultImageWidth = renderSec.Key("default_image_width").MustInt(1000)
cfg.RendererDefaultImageHeight = renderSec.Key("default_image_height").MustInt(500)
cfg.RendererDefaultImageScale = renderSec.Key("default_image_scale").MustFloat64(1)
cfg.ImagesDir = filepath.Join(cfg.DataPath, "png")
cfg.CSVsDir = filepath.Join(cfg.DataPath, "csv")
cfg.PDFsDir = filepath.Join(cfg.DataPath, "pdf")

View File

@ -205,3 +205,9 @@ func (ctx *Context) GetCookie(name string) string {
val, _ := url.QueryUnescape(cookie.Value)
return val
}
// QueryFloat64 returns query result in float64 type.
func (ctx *Context) QueryFloat64(name string) float64 {
n, _ := strconv.ParseFloat(ctx.Query(name), 64)
return n
}

View File

@ -105,7 +105,7 @@ describe('ShareModal', () => {
render(<ShareLink {...props} />);
const base = 'http://dashboards.grafana.com/render/d-solo/abcdefghi/my-dash';
const params = '?from=1000&to=2000&orgId=1&panelId=22&width=1000&height=500&tz=UTC';
const params = '?from=1000&to=2000&orgId=1&panelId=22&width=1000&height=500&scale=1&tz=UTC';
expect(
await screen.findByRole('link', { name: selectors.pages.SharePanelModal.linkToRenderedImage })
).toHaveAttribute('href', base + params);
@ -116,7 +116,7 @@ describe('ShareModal', () => {
render(<ShareLink {...props} />);
const base = 'http://dashboards.grafana.com/render/dashboard-solo/script/my-dash.js';
const params = '?from=1000&to=2000&orgId=1&panelId=22&width=1000&height=500&tz=UTC';
const params = '?from=1000&to=2000&orgId=1&panelId=22&width=1000&height=500&scale=1&tz=UTC';
expect(
await screen.findByRole('link', { name: selectors.pages.SharePanelModal.linkToRenderedImage })
).toHaveAttribute('href', base + params);
@ -151,7 +151,10 @@ describe('ShareModal', () => {
);
expect(
await screen.findByRole('link', { name: selectors.pages.SharePanelModal.linkToRenderedImage })
).toHaveAttribute('href', base + path + '?from=1000&to=2000&orgId=1&panelId=1&width=1000&height=500&tz=UTC');
).toHaveAttribute(
'href',
base + path + '?from=1000&to=2000&orgId=1&panelId=1&width=1000&height=500&scale=1&tz=UTC'
);
});
it('should shorten url', async () => {
@ -168,7 +171,7 @@ describe('ShareModal', () => {
render(<ShareLink {...props} />);
const base = 'http://dashboards.grafana.com/render/d-solo/abcdefghi/my-dash';
const params = '?from=1000&to=2000&orgId=1&panelId=22&width=1000&height=500&tz=UTC';
const params = '?from=1000&to=2000&orgId=1&panelId=22&width=1000&height=500&scale=1&tz=UTC';
expect(
await screen.findByRole('link', { name: selectors.pages.SharePanelModal.linkToRenderedImage })
).toHaveAttribute('href', base + params);
@ -209,7 +212,7 @@ describe('when appUrl is set in the grafana config', () => {
await screen.findByRole('link', { name: selectors.pages.SharePanelModal.linkToRenderedImage })
).toHaveAttribute(
'href',
`http://dashboards.grafana.com/render/d-solo/${mockDashboard.uid}?orgId=1&from=1000&to=2000&panelId=${mockPanel.id}&width=1000&height=500&tz=UTC`
`http://dashboards.grafana.com/render/d-solo/${mockDashboard.uid}?orgId=1&from=1000&to=2000&panelId=${mockPanel.id}&width=1000&height=500&scale=1&tz=UTC`
);
});
});

View File

@ -121,7 +121,12 @@ export function buildImageUrl(
let soloUrl = buildSoloUrl(useCurrentTimeRange, dashboardUid, selectedTheme, panel);
let imageUrl = soloUrl.replace(config.appSubUrl + '/dashboard-solo/', config.appSubUrl + '/render/dashboard-solo/');
imageUrl = imageUrl.replace(config.appSubUrl + '/d-solo/', config.appSubUrl + '/render/d-solo/');
imageUrl += '&width=1000&height=500' + getLocalTimeZone();
imageUrl +=
`&width=${config.rendererDefaultImageWidth}` +
`&height=${config.rendererDefaultImageHeight}` +
`&scale=${config.rendererDefaultImageScale}` +
getLocalTimeZone();
return imageUrl;
}