mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
parent
3f2eb8bd6a
commit
d02de5ddb9
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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"`
|
||||
|
@ -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,
|
||||
|
@ -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{}
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user