Skip to content

Commit 146474a

Browse files
committed
Initial commit.
0 parents  commit 146474a

47 files changed

Lines changed: 18423 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.config/.cprc.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"version": "6.8.3"
3+
}

.config/.prettierrc.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/*
2+
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
3+
*
4+
* In order to extend the configuration follow the steps in .config/README.md
5+
*/
6+
7+
module.exports = {
8+
endOfLine: 'auto',
9+
printWidth: 120,
10+
trailingComma: 'es5',
11+
semi: true,
12+
jsxSingleQuote: false,
13+
singleQuote: true,
14+
useTabs: false,
15+
tabWidth: 2,
16+
};

.config/Dockerfile

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
ARG grafana_version=latest
2+
ARG grafana_image=grafana-enterprise
3+
4+
FROM grafana/${grafana_image}:${grafana_version}
5+
6+
ARG anonymous_auth_enabled=true
7+
ARG development=false
8+
ARG TARGETARCH
9+
10+
11+
ENV DEV "${development}"
12+
13+
# Make it as simple as possible to access the grafana instance for development purposes
14+
# Do NOT enable these settings in a public facing / production grafana instance
15+
ENV GF_AUTH_ANONYMOUS_ORG_ROLE "Admin"
16+
ENV GF_AUTH_ANONYMOUS_ENABLED "${anonymous_auth_enabled}"
17+
ENV GF_AUTH_BASIC_ENABLED "false"
18+
# Set development mode so plugins can be loaded without the need to sign
19+
ENV GF_DEFAULT_APP_MODE "development"
20+
21+
22+
LABEL maintainer="Grafana Labs <hello@grafana.com>"
23+
24+
ENV GF_PATHS_HOME="/usr/share/grafana"
25+
WORKDIR $GF_PATHS_HOME
26+
27+
USER root
28+
29+
# Installing supervisor and inotify-tools
30+
RUN if [ "${development}" = "true" ]; then \
31+
if grep -i -q alpine /etc/issue; then \
32+
apk add supervisor inotify-tools git; \
33+
elif grep -i -q ubuntu /etc/issue; then \
34+
DEBIAN_FRONTEND=noninteractive && \
35+
apt-get update && \
36+
apt-get install -y supervisor inotify-tools git && \
37+
rm -rf /var/lib/apt/lists/*; \
38+
else \
39+
echo 'ERROR: Unsupported base image' && /bin/false; \
40+
fi \
41+
fi
42+
43+
COPY supervisord/supervisord.conf /etc/supervisor.d/supervisord.ini
44+
COPY supervisord/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
45+
46+
47+
48+
# Inject livereload script into grafana index.html
49+
RUN sed -i 's|</body>|<script src="http://localhost:35729/livereload.js"></script></body>|g' /usr/share/grafana/public/views/index.html
50+
51+
52+
COPY entrypoint.sh /entrypoint.sh
53+
RUN chmod +x /entrypoint.sh
54+
ENTRYPOINT ["/entrypoint.sh"]

.config/README.md

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
# Default build configuration by Grafana
2+
3+
**This is an auto-generated directory and is not intended to be changed! ⚠️**
4+
5+
The `.config/` directory holds basic configuration for the different tools
6+
that are used to develop, test and build the project. In order to make it updates easier we ask you to
7+
not edit files in this folder to extend configuration.
8+
9+
## How to extend the basic configs?
10+
11+
Bear in mind that you are doing it at your own risk, and that extending any of the basic configuration can lead
12+
to issues around working with the project.
13+
14+
### Extending the ESLint config
15+
16+
Edit the `eslint.config.mjs` file in the project root to extend the ESLint configuration. The following example disables deprecation notices for source files.
17+
18+
**Example:**
19+
20+
```javascript
21+
import { defineConfig } from 'eslint/config';
22+
import baseConfig from './.config/eslint.config.mjs';
23+
24+
export default defineConfig([
25+
{
26+
ignores: [
27+
//...
28+
],
29+
},
30+
...baseConfig,
31+
{
32+
files: ['src/**/*.{ts,tsx}'],
33+
rules: {
34+
'@typescript-eslint/no-deprecated': 'off',
35+
},
36+
},
37+
]);
38+
```
39+
40+
---
41+
42+
### Extending the Prettier config
43+
44+
Edit the `.prettierrc.js` file in the project root in order to extend the Prettier configuration.
45+
46+
**Example:**
47+
48+
```javascript
49+
module.exports = {
50+
// Prettier configuration provided by Grafana scaffolding
51+
...require('./.config/.prettierrc.js'),
52+
53+
semi: false,
54+
};
55+
```
56+
57+
---
58+
59+
### Extending the Jest config
60+
61+
There are two configuration in the project root that belong to Jest: `jest-setup.js` and `jest.config.js`.
62+
63+
**`jest-setup.js`:** A file that is run before each test file in the suite is executed. We are using it to
64+
set up the Jest DOM for the testing library and to apply some polyfills. ([link to Jest docs](https://jestjs.io/docs/configuration#setupfilesafterenv-array))
65+
66+
**`jest.config.js`:** The main Jest configuration file that extends the Grafana recommended setup. ([link to Jest docs](https://jestjs.io/docs/configuration))
67+
68+
#### ESM errors with Jest
69+
70+
A common issue with the current jest config involves importing an npm package that only offers an ESM build. These packages cause jest to error with `SyntaxError: Cannot use import statement outside a module`. To work around this, we provide a list of known packages to pass to the `[transformIgnorePatterns](https://jestjs.io/docs/configuration#transformignorepatterns-arraystring)` jest configuration property. If need be, this can be extended in the following way:
71+
72+
```javascript
73+
process.env.TZ = 'UTC';
74+
const { grafanaESModules, nodeModulesToTransform } = require('./config/jest/utils');
75+
76+
module.exports = {
77+
// Jest configuration provided by Grafana
78+
...require('./.config/jest.config'),
79+
// Inform jest to only transform specific node_module packages.
80+
transformIgnorePatterns: [nodeModulesToTransform([...grafanaESModules, 'packageName'])],
81+
};
82+
```
83+
84+
---
85+
86+
### Extending the TypeScript config
87+
88+
Edit the `tsconfig.json` file in the project root in order to extend the TypeScript configuration.
89+
90+
**Example:**
91+
92+
```json
93+
{
94+
"extends": "./.config/tsconfig.json",
95+
"compilerOptions": {
96+
"preserveConstEnums": true
97+
}
98+
}
99+
```
100+
101+
---
102+
103+
### Extending the Webpack config
104+
105+
Follow these steps to extend the basic Webpack configuration that lives under `.config/`:
106+
107+
#### 1. Create a new Webpack configuration file
108+
109+
Create a new config file that is going to extend the basic one provided by Grafana.
110+
It can live in the project root, e.g. `webpack.config.ts`.
111+
112+
#### 2. Merge the basic config provided by Grafana and your custom setup
113+
114+
We are going to use [`webpack-merge`](https://github.com/survivejs/webpack-merge) for this.
115+
116+
```typescript
117+
// webpack.config.ts
118+
import type { Configuration } from 'webpack';
119+
import { merge } from 'webpack-merge';
120+
import grafanaConfig, { type Env } from './.config/webpack/webpack.config';
121+
122+
const config = async (env: Env): Promise<Configuration> => {
123+
const baseConfig = await grafanaConfig(env);
124+
125+
return merge(baseConfig, {
126+
// Add custom config here...
127+
output: {
128+
asyncChunks: true,
129+
},
130+
});
131+
};
132+
133+
export default config;
134+
```
135+
136+
#### 3. Update the `package.json` to use the new Webpack config
137+
138+
We need to update the `scripts` in the `package.json` to use the extended Webpack configuration.
139+
140+
**Update for `build`:**
141+
142+
```diff
143+
-"build": "webpack -c ./.config/webpack/webpack.config.ts --env production",
144+
+"build": "webpack -c ./webpack.config.ts --env production",
145+
```
146+
147+
**Update for `dev`:**
148+
149+
```diff
150+
-"dev": "webpack -w -c ./.config/webpack/webpack.config.ts --env development",
151+
+"dev": "webpack -w -c ./webpack.config.ts --env development",
152+
```
153+
154+
### Configure grafana image to use when running docker
155+
156+
By default, `grafana-enterprise` will be used as the docker image for all docker related commands. If you want to override this behavior, simply alter the `docker-compose.yaml` by adding the following build arg `grafana_image`.
157+
158+
**Example:**
159+
160+
```yaml
161+
version: '3.7'
162+
163+
services:
164+
grafana:
165+
extends:
166+
file: .config/docker-compose-base.yaml
167+
service: grafana
168+
build:
169+
args:
170+
grafana_version: ${GRAFANA_VERSION:-9.1.2}
171+
grafana_image: ${GRAFANA_IMAGE:-grafana}
172+
```
173+
174+
In this example, we assign the environment variable `GRAFANA_IMAGE` to the build arg `grafana_image` with a default value of `grafana`. This will allow you to set the value while running the docker compose commands, which might be convenient in some scenarios.
175+
176+
---

.config/bundler/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export const SOURCE_DIR = 'src';
2+
export const DIST_DIR = 'dist';

.config/bundler/copyFiles.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { getPluginJson, hasReadme } from './utils.ts';
2+
3+
const pluginJson = getPluginJson();
4+
const logoPaths: string[] = Array.from(new Set([pluginJson.info?.logos?.large, pluginJson.info?.logos?.small])).filter(
5+
Boolean
6+
);
7+
const screenshotPaths: string[] = pluginJson.info?.screenshots?.map((s: { path: string }) => s.path) || [];
8+
9+
export const copyFilePatterns = [
10+
// If src/README.md exists use it; otherwise the root README
11+
// To `compiler.options.output`
12+
{ from: hasReadme() ? 'README.md' : '../README.md', to: '.', force: true },
13+
{ from: 'plugin.json', to: '.' },
14+
{ from: '../LICENSE', to: '.' },
15+
{ from: '../CHANGELOG.md', to: '.', force: true },
16+
{ from: '**/*.json', to: '.' },
17+
{ from: '**/query_help.md', to: '.', noErrorOnMissing: true },
18+
...logoPaths.map((logoPath) => ({ from: logoPath, to: logoPath })),
19+
...screenshotPaths.map((screenshotPath) => ({
20+
from: screenshotPath,
21+
to: screenshotPath,
22+
})),
23+
];

.config/bundler/externals.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import type { Configuration, ExternalItemFunctionData } from 'webpack';
2+
3+
type ExternalsType = Configuration['externals'];
4+
5+
export const externals: ExternalsType = [
6+
// Required for dynamic publicPath resolution
7+
{ 'amd-module': 'module' },
8+
'lodash',
9+
'jquery',
10+
'moment',
11+
'slate',
12+
'emotion',
13+
'@emotion/react',
14+
'@emotion/css',
15+
'prismjs',
16+
'slate-plain-serializer',
17+
'@grafana/slate-react',
18+
'react',
19+
'react-dom',
20+
'react-redux',
21+
'redux',
22+
'rxjs',
23+
'i18next',
24+
'react-router',
25+
'd3',
26+
'angular',
27+
/^@grafana\/ui/i,
28+
/^@grafana\/runtime/i,
29+
/^@grafana\/data/i,
30+
31+
// Mark legacy SDK imports as external if their name starts with the "grafana/" prefix
32+
({ request }: ExternalItemFunctionData, callback: (error?: Error, result?: string) => void) => {
33+
const prefix = 'grafana/';
34+
const hasPrefix = (request: string) => request.indexOf(prefix) === 0;
35+
const stripPrefix = (request: string) => request.slice(prefix.length);
36+
37+
if (request && hasPrefix(request)) {
38+
return callback(undefined, stripPrefix(request));
39+
}
40+
41+
callback();
42+
},
43+
];

.config/bundler/utils.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import fs from 'fs';
2+
import process from 'process';
3+
import os from 'os';
4+
import path from 'path';
5+
import { glob } from 'glob';
6+
import { SOURCE_DIR } from './constants.ts';
7+
8+
export function isWSL() {
9+
if (process.platform !== 'linux') {
10+
return false;
11+
}
12+
13+
if (os.release().toLowerCase().includes('microsoft')) {
14+
return true;
15+
}
16+
17+
try {
18+
return fs.readFileSync('/proc/version', 'utf8').toLowerCase().includes('microsoft');
19+
} catch {
20+
return false;
21+
}
22+
}
23+
24+
function loadJson(path: string) {
25+
const rawJson = fs.readFileSync(path, 'utf8');
26+
return JSON.parse(rawJson);
27+
}
28+
29+
export function getPackageJson() {
30+
return loadJson(path.resolve(process.cwd(), 'package.json'));
31+
}
32+
33+
export function getPluginJson() {
34+
return loadJson(path.resolve(process.cwd(), `${SOURCE_DIR}/plugin.json`));
35+
}
36+
37+
export function getCPConfigVersion() {
38+
const cprcJson = path.resolve(process.cwd(), './.config', '.cprc.json');
39+
return fs.existsSync(cprcJson) ? loadJson(cprcJson).version : { version: 'unknown' };
40+
}
41+
42+
export function hasReadme() {
43+
return fs.existsSync(path.resolve(process.cwd(), SOURCE_DIR, 'README.md'));
44+
}
45+
46+
// Support bundling nested plugins by finding all plugin.json files in src directory
47+
// then checking for a sibling module.[jt]sx? file.
48+
export async function getEntries() {
49+
const pluginsJson = await glob('**/src/**/plugin.json', { absolute: true });
50+
51+
const plugins = await Promise.all(
52+
pluginsJson.map((pluginJson) => {
53+
const folder = path.dirname(pluginJson);
54+
return glob(`${folder}/module.{ts,tsx,js,jsx}`, { absolute: true });
55+
})
56+
);
57+
58+
return plugins.reduce<Record<string, string>>((result, modules) => {
59+
return modules.reduce((innerResult, module) => {
60+
const pluginPath = path.dirname(module);
61+
const pluginName = path.relative(process.cwd(), pluginPath).replace(/src\/?/i, '');
62+
const entryName = pluginName === '' ? 'module' : `${pluginName}/module`;
63+
64+
innerResult[entryName] = module;
65+
return innerResult;
66+
}, result);
67+
}, {});
68+
}

0 commit comments

Comments
 (0)