Skip to content

Commit

Permalink
feat: Split config into sections
Browse files Browse the repository at this point in the history
* For better organisation, we split config in UI into different sections

* README has been modified to reflect the config sections in UI

Signed-off-by: Mahendra Paipuri <mahendra.paipuri@gmail.com>
  • Loading branch information
mahendrapaipuri committed Jul 8, 2024
1 parent 88d0c23 commit e69c31b
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 81 deletions.
2 changes: 1 addition & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ services:
context: ./.config
args:
grafana_image: ${GRAFANA_IMAGE:-grafana-oss}
grafana_version: ${GRAFANA_VERSION:-10.4.2}
grafana_version: ${GRAFANA_VERSION:-11.1.0}
ports:
- 3000:${GF_SERVER_HTTP_PORT:-3000}/tcp
volumes:
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
"@grafana/data": "10.3.3",
"@grafana/runtime": "10.3.3",
"@grafana/ui": "10.3.3",
"@grafana/experimental": "1.7.12",
"@grafana/schema": "10.3.3",
"react": "18.2.0",
"react-dom": "18.2.0",
Expand Down
38 changes: 23 additions & 15 deletions src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ parameters set in the `reporter.yml` file.
Grafana Provisioning is a programmatic way of configuring the plugin app. However, it is
possible to configure the app from Grafana UI as well as explained in the first option.


Different configuration parameters are explained below:

### Grafana related parameters
Expand All @@ -151,9 +150,17 @@ can only be set using provisioning method and **it is not possible to configure
will get the Grafana's data path based on its own executable path. If the existing provisioned
configs have this parameter set, it will be ignored while loading the plugin's configuration.

### Report parameters
### Authentication settings

This config section allows to configure authentication related settings.

- `Service Account Token`: A service account token that will be used to generate reports
_via_ API requests. More details on how to use it is briefed in
[Using Grafana API](#using-grafana-api) section.

### Report settings

All the configuration parameters can only be modified by `Admin` role.
All the configuration parameters can only be modified by `Admin` role from Grafana UI.

- `Layout`: Layout of the report. Using grid layout renders the report as it is rendered
in the browser. A simple layout will render the report with one panel per row
Expand All @@ -169,10 +176,16 @@ All the configuration parameters can only be modified by `Admin` role.
[IANA format](https://www.iana.org/time-zones). By default, local Grafana server's
time zone will be used.

Although these parameters can only be changed by users with `Admin` role for whole instance
- `Branding Logo`: This parameter takes a base64 encoded png image that will be included
in the footer of each page in the report. Typically, operators can include their
organization logos to have "customized" reports.

#### Overriding report settings

Although report settings can only be modified by users with `Admin` role for whole instance
of Grafana, it is possible to override the global defaults for a particular report
by using query parameters. It is enough to add query parameters to dashboard report URL
to set these values.
to set these values. Currently, the supported query parameters are:

- Query field for layout is `layout` and it takes either `simple` or `grid` as value.
Example is `<grafanaAppUrl>/api/plugins/mahendrapaipuri-dashboardreporter-app/resources/report?dashUid=<UID of dashboard>&layout=grid`
Expand Down Expand Up @@ -209,15 +222,9 @@ Besides there are two special query parameters available namely:
it will be **included** in the report. Query parameter `includePanelID` has more
precedence over `excludePanelID`.

### Advanced parameters
### Additional settings

- `Service Account Token`: A service account token that will be used to generate reports
_via_ API requests. More details on how to use it is briefed in
[Using Grafana API](#using-grafana-api) section.

- `Branding Logo`: This parameter takes a base64 encoded png image that will be included
in the footer of each page in the report. Typically, operators can include their
organization logos to have "customized" reports.
These are debugging and performance related settings.

- `Maximum Render Workers`: Number of concurrent workers to create PNGs of panels in the
dashboard. Do not use too high value as it starve the machine
Expand Down Expand Up @@ -285,9 +292,10 @@ any HTTP client of your favorite programming language.
> If you are using Grafana >= 10.3.0, there is a feature flag called `externalServiceAccounts`
that can create a service account and provision a service account token automatically for
the plugin. Hence, there is no need to configure the service account token to the plugin.
To enable this feature, it is necessary to set
`enable = externalServiceAccounts` in `feature_toggles` section of Grafana configuration.
However, the user will still need to create a service account and token to make the API
requests to generate report. To enable this feature, it is necessary to set
`enable = externalServiceAccounts` in `feature_toggles` section of Grafana configuration.
requests to generate report.

### Security

Expand Down
146 changes: 87 additions & 59 deletions src/components/AppConfig/AppConfig.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useState, ChangeEvent } from 'react';
import { lastValueFrom } from 'rxjs';
import { css } from '@emotion/css';
import { ConfigSection } from "@grafana/experimental";
import {
Button,
useStyles2,
Expand Down Expand Up @@ -144,7 +145,6 @@ export const AppConfig = ({ plugin }: Props) => {
});
};


const onChangeLogo = (event: ChangeEvent<HTMLInputElement>) => {
setState({
...state,
Expand Down Expand Up @@ -263,9 +263,12 @@ export const AppConfig = ({ plugin }: Props) => {
)}
</FieldSet>

{/* CUSTOM SETTINGS */}
<FieldSet label="Plugin Settings" className={s.marginTopXl}>
{/* Service account token */}
{/* Authentication Settings */}
<hr className={`${s.hrTopSpace} ${s.hrBottomSpace}`} />
<ConfigSection
title="Authentication"
description="Use this section to configure service account tokens when Grafana < 10.3.0 is used or externalServiceAccounts feature is not enabled"
>
<Field
label="Service Account Token"
description="This token will be used to make API requests to Grafana for generating reports."
Expand All @@ -285,7 +288,14 @@ export const AppConfig = ({ plugin }: Props) => {
onReset={onResetSaToken}
/>
</Field>

</ConfigSection>

{/* Report Settings */}
<hr className={`${s.hrTopSpace} ${s.hrBottomSpace}`} />
<ConfigSection
title="Report Settings"
description="Use this section to customise the generated report"
>
{/* Use Grid Layout */}
<Field
label="Layout"
Expand Down Expand Up @@ -361,7 +371,16 @@ export const AppConfig = ({ plugin }: Props) => {
onChange={onChangeLogo}
/>
</Field>

</ConfigSection>

{/* Additional Settings */}
<hr className={`${s.hrTopSpace} ${s.hrBottomSpace}`} />
<ConfigSection
title="Additional Settings"
description="Performance and debug related settings"
isCollapsible
isInitiallyOpen={false}
>
{/* Persist data */}
<Field
label="Persist Data Files"
Expand Down Expand Up @@ -392,64 +411,73 @@ export const AppConfig = ({ plugin }: Props) => {
onChange={onChangeMaxWorkers}
/>
</Field>

<div className={s.marginTop}>
<Button
type="submit"
data-testid={testIds.appConfig.submit}
onClick={() =>
updatePluginAndReload(plugin.meta.id, {
enabled,
pinned,
jsonData: {
appUrl: appUrl,
skipTlsCheck: skipTlsCheck,
maxRenderWorkers: state.maxRenderWorkers,
orientation: state.orientation,
layout: state.layout,
dashboardMode: state.dashboardMode,
timeZone: state.timeZone,
logo: state.logo,
persistData: state.persistData,
},
// This cannot be queried later by the frontend.
// We don't want to override it in case it was set previously and left untouched now.
secureJsonData: state.isSaTokenSet
? undefined
: {
saToken: state.saToken,
},
})
}
disabled={Boolean(
!state.layoutChanged &&
!state.orientationChanged &&
!state.dashboardModeChanged &&
!state.timeZoneChanged &&
!state.logoChanged &&
!state.maxRenderWorkersChanged &&
!state.persistDataChanged &&
!state.saToken
)}
>
Save settings
</Button>
</div>
</FieldSet>
</ConfigSection>

<div className={s.marginTop}>
<Button
type="submit"
data-testid={testIds.appConfig.submit}
onClick={() =>
updatePluginAndReload(plugin.meta.id, {
enabled,
pinned,
jsonData: {
appUrl: appUrl,
skipTlsCheck: skipTlsCheck,
maxRenderWorkers: state.maxRenderWorkers,
orientation: state.orientation,
layout: state.layout,
dashboardMode: state.dashboardMode,
timeZone: state.timeZone,
logo: state.logo,
persistData: state.persistData,
},
// This cannot be queried later by the frontend.
// We don't want to override it in case it was set previously and left untouched now.
secureJsonData: state.isSaTokenSet
? undefined
: {
saToken: state.saToken,
},
})
}
disabled={Boolean(
!state.layoutChanged &&
!state.orientationChanged &&
!state.dashboardModeChanged &&
!state.timeZoneChanged &&
!state.logoChanged &&
!state.maxRenderWorkersChanged &&
!state.persistDataChanged &&
!state.saToken
)}
>
Save settings
</Button>
</div>
</div>
);
};

const getStyles = (theme: GrafanaTheme2) => ({
colorWeak: css`
color: ${theme.colors.text.secondary};
`,
marginTop: css`
margin-top: ${theme.spacing(3)};
`,
marginTopXl: css`
margin-top: ${theme.spacing(6)};
`,
colorWeak: css({
color: `${theme.colors.text.secondary}`,
}),
marginTop: css({
marginTop: `${theme.spacing(3)}`,
}),
marginTopXl: css({
marginTop: `${theme.spacing(6)}`,
}),
hrBottomSpace: css({
marginBottom: "56px",
}),
hrTopSpace: css({
marginTop: "50px",
}),
reportSettings: css({
paddingTop: "32px",
}),
});

const updatePluginAndReload = async (pluginId: string, data: Partial<PluginMeta<JsonData>>) => {
Expand Down
Binary file modified src/img/dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src/img/light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions tests/appConfig.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ test("should be possible to save app configuration", async ({
.getByRole("textbox", { name: "Service Account Token" })
.fill("secret-api-key");
await page.getByLabel("Grid").click();
await page.getByLabel("Expand section Additional Settings").click();
await page.getByLabel("Maximum Render Workers").clear();
await page.getByLabel("Maximum Render Workers").fill("3");

Expand Down
Loading

0 comments on commit e69c31b

Please sign in to comment.