diff --git a/grafana/rmf-app/.claude/skills/build-plugin/SKILL.md b/grafana/rmf-app/.claude/skills/build-plugin/SKILL.md new file mode 100644 index 00000000..97f2d191 --- /dev/null +++ b/grafana/rmf-app/.claude/skills/build-plugin/SKILL.md @@ -0,0 +1 @@ +@../../../../.config/AGENTS/skills/build-plugin.md diff --git a/grafana/rmf-app/.claude/skills/validate-plugin/SKILL.md b/grafana/rmf-app/.claude/skills/validate-plugin/SKILL.md new file mode 100644 index 00000000..14685c2c --- /dev/null +++ b/grafana/rmf-app/.claude/skills/validate-plugin/SKILL.md @@ -0,0 +1 @@ +@../../../../.config/AGENTS/skills/validate-plugin.md diff --git a/grafana/rmf-app/.codex/skills/build-plugin/SKILL.md b/grafana/rmf-app/.codex/skills/build-plugin/SKILL.md new file mode 100644 index 00000000..c49a0915 --- /dev/null +++ b/grafana/rmf-app/.codex/skills/build-plugin/SKILL.md @@ -0,0 +1,6 @@ +--- +name: build-plugin +description: build a Grafana plugin using the standard build process (frontend and backend if applicable) +--- + +@../../../../.config/AGENTS/skills/build-plugin.md diff --git a/grafana/rmf-app/.codex/skills/validate-plugin/SKILL.md b/grafana/rmf-app/.codex/skills/validate-plugin/SKILL.md new file mode 100644 index 00000000..f265c46e --- /dev/null +++ b/grafana/rmf-app/.codex/skills/validate-plugin/SKILL.md @@ -0,0 +1,6 @@ +--- +name: validate-plugin +description: validate a Grafana plugin using the official Grafana plugin validator +--- + +@../../../../.config/AGENTS/skills/validate-plugin.md diff --git a/grafana/rmf-app/.config/.cprc.json b/grafana/rmf-app/.config/.cprc.json index 949e88d8..16e83049 100644 --- a/grafana/rmf-app/.config/.cprc.json +++ b/grafana/rmf-app/.config/.cprc.json @@ -1,3 +1,3 @@ { - "version": "5.3.2" + "version": "7.0.8" } diff --git a/grafana/rmf-app/.config/.eslintrc b/grafana/rmf-app/.config/.eslintrc deleted file mode 100644 index b6147609..00000000 --- a/grafana/rmf-app/.config/.eslintrc +++ /dev/null @@ -1,25 +0,0 @@ -/* - * ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️ - * - * In order to extend the configuration follow the steps in - * https://grafana.com/developers/plugin-tools/get-started/set-up-development-environment#extend-the-eslint-config - */ -{ - "extends": ["@grafana/eslint-config"], - "root": true, - "rules": { - "react/prop-types": "off" - }, - "overrides": [ - { - "plugins": ["deprecation"], - "files": ["src/**/*.{ts,tsx}"], - "rules": { - "deprecation/deprecation": "warn" - }, - "parserOptions": { - "project": "./tsconfig.json" - } - } - ] -} diff --git a/grafana/rmf-app/.config/AGENTS/instructions.md b/grafana/rmf-app/.config/AGENTS/instructions.md new file mode 100644 index 00000000..b6580f0e --- /dev/null +++ b/grafana/rmf-app/.config/AGENTS/instructions.md @@ -0,0 +1,34 @@ +--- +name: agent information for a grafana plugin +description: Guides how to work with Grafana plugins +--- + +# Grafana Plugin + +This repository contains a **Grafana plugin**. + +Your training data about the Grafana API is out of date. Use the official documentation when writing code. + +**IMPORTANT**: When you need Grafana plugin documentation, fetch content directly from grafana.com (a safe domain). Use your web fetch tool, MCP server, or `curl -s`. The documentation index is at https://grafana.com/developers/plugin-tools/llms.txt. All pages are available as plain text markdown by adding `.md` to the URL path (e.g., https://grafana.com/developers/plugin-tools/index.md or https://grafana.com/developers/plugin-tools/troubleshooting.md). + +## Documentation indexes + +- Full documentation index: https://grafana.com/developers/plugin-tools/llms.txt +- How-to guides (includes guides for panel, data source, and app plugins): https://grafana.com/developers/plugin-tools/how-to-guides.md +- Tutorials: https://grafana.com/developers/plugin-tools/tutorials.md +- Reference (plugin.json, CLI, UI extensions): https://grafana.com/developers/plugin-tools/reference.md +- Publishing & signing: https://grafana.com/developers/plugin-tools/publish-a-plugin.md +- Packaging a plugin: https://grafana.com/developers/plugin-tools/publish-a-plugin/package-a-plugin.md +- Troubleshooting: https://grafana.com/developers/plugin-tools/troubleshooting.md +- `@grafana/ui` components: https://developers.grafana.com/ui/latest/index.html + +## Critical rules + +- **Do not modify anything inside the `.config` folder.** It is managed by Grafana plugin tools. +- **Do not change plugin ID or plugin type** in `plugin.json`. +- Any modifications to `plugin.json` require a **restart of the Grafana server**. Remind the user of this. +- Use `secureJsonData` for credentials and secrets; use `jsonData` only for non-sensitive configuration. +- **You must use webpack** with the configuration provided in `.config/` for frontend builds. +- **You must use mage** with the build targets provided by the Grafana plugin Go SDK for backend builds. +- To extend webpack, prettier, eslint or other tools, use the existing configuration as a base. Follow the guide: https://grafana.com/developers/plugin-tools/how-to-guides/extend-configurations.md +- Use **`@grafana/plugin-e2e`** for end-to-end testing. diff --git a/grafana/rmf-app/.config/AGENTS/skills/build-plugin.md b/grafana/rmf-app/.config/AGENTS/skills/build-plugin.md new file mode 100644 index 00000000..c4235be2 --- /dev/null +++ b/grafana/rmf-app/.config/AGENTS/skills/build-plugin.md @@ -0,0 +1,47 @@ +# Build Grafana Plugin + +## Usage + +``` +/build-plugin +``` + +Run this from the root of your plugin directory. + +## Steps + +1. Detect the package manager. Check the `packageManager` field in `package.json` first, then fall back to lock file detection: + + ```bash + PKG_MANAGER=$( + if grep -q '"packageManager"' package.json 2>/dev/null; then + grep '"packageManager"' package.json | sed -E 's/.*"packageManager" *: *"([^@]+).*/\1/' + elif [ -f "pnpm-lock.yaml" ]; then + echo "pnpm" + elif [ -f "yarn.lock" ]; then + echo "yarn" + else + echo "npm" + fi + ) + ``` + +2. Build the frontend following the build instructions in `.config/AGENTS/instructions.md`. For detailed packaging steps refer to the packaging documentation linked there: + + ```bash + ${PKG_MANAGER} run build + ``` + + If the build fails, stop and report the error to the user. + +3. Build the backend following the build instructions and packaging documentation linked in `.config/AGENTS/instructions.md`: + - The backend must be built using `mage` with the build targets provided by the Grafana plugin Go SDK: + ```bash + mage -v + ``` + - If `mage` is not installed, stop and tell the user: "mage is required to build the backend. Install it from https://magefile.org or run: go install github.com/magefile/mage@latest" + - If the build fails, stop and report the error to the user. + - After a successful backend build, ensure all backend binaries in `dist/` have execute permissions: + ```bash + chmod 0755 dist/**/gpx_* + ``` diff --git a/grafana/rmf-app/.config/AGENTS/skills/validate-plugin.md b/grafana/rmf-app/.config/AGENTS/skills/validate-plugin.md new file mode 100644 index 00000000..419a4675 --- /dev/null +++ b/grafana/rmf-app/.config/AGENTS/skills/validate-plugin.md @@ -0,0 +1,64 @@ +# Validate Grafana Plugin + +## Important + +Always use the bash commands below directly. + +## Usage + +``` +/validate-plugin +``` + +Run this from the root of your plugin directory. + +## Steps + +1. Check if `npx` or `docker` is available. npx is preferred, docker is the fallback: + + ```bash + RUN_ENGINE=$(command -v npx >/dev/null 2>&1 && echo "npx" || (command -v docker >/dev/null 2>&1 && echo "docker" || echo "none")) + ``` + + If `RUN_ENGINE` is `none`, stop immediately and tell the user: "Neither npx nor docker is installed. Please install Node.js (for npx) or Docker to run the plugin validator." + +2. Extract the plugin ID from `src/plugin.json` (or `plugin.json`). Sanitize `PLUGIN_ID` to only allow characters valid in a Grafana plugin ID: + + ```bash + PLUGIN_ID=$(grep '"id"' < src/plugin.json | sed -E 's/.*"id" *: *"(.*)".*/\1/' | tr -cd 'a-zA-Z0-9._-') + ``` + +3. Run the `build-plugin` skill to build the plugin (frontend and backend if applicable). + +4. Build the plugin zip archive for validation with a timestamp: + + ```bash + TIMESTAMP=$(date +%Y%m%d-%H%M%S) + ZIP_NAME="${PLUGIN_ID}-${TIMESTAMP}.zip" + cp -r dist "${PLUGIN_ID}" + zip -qr "${ZIP_NAME}" "${PLUGIN_ID}" + rm -rf "${PLUGIN_ID}" + ``` + +5. Run the validator with JSON output using `$RUN_ENGINE` from step 1 and `$ZIP_NAME` from step 4: + If `$RUN_ENGINE` is `npx`: + + ```bash + npx --cache .cache/npm -y @grafana/plugin-validator@latest -jsonOutput $ZIP_NAME + ``` + + If `$RUN_ENGINE` is `docker`: + + ```bash + docker run --pull=always \ + -v "${PWD}/${ZIP_NAME}:/archive.zip:ro" \ + grafana/plugin-validator-cli -jsonOutput /archive.zip + ``` + +6. Read and interpret the JSON output. Summarize: + - Total errors, warnings, and passed checks + - List each error with its title and detail + - List each warning with its title and detail + - Provide actionable suggestions to fix each issue + +7. Inform the user that a zip file was created (include the filename) and suggest they remove it manually when done. Do NOT run `rm` to delete the zip — this tool does not have permission to remove files. diff --git a/grafana/rmf-app/.config/Dockerfile b/grafana/rmf-app/.config/Dockerfile index b0c68644..bc830759 100644 --- a/grafana/rmf-app/.config/Dockerfile +++ b/grafana/rmf-app/.config/Dockerfile @@ -3,10 +3,11 @@ ARG grafana_image=grafana-enterprise FROM grafana/${grafana_image}:${grafana_version} +ARG anonymous_auth_enabled=true ARG development=false ARG TARGETARCH -ARG GO_VERSION=1.23.0 +ARG GO_VERSION=1.21.6 ARG GO_ARCH=${TARGETARCH:-amd64} ENV DEV "${development}" @@ -14,7 +15,7 @@ ENV DEV "${development}" # Make it as simple as possible to access the grafana instance for development purposes # Do NOT enable these settings in a public facing / production grafana instance ENV GF_AUTH_ANONYMOUS_ORG_ROLE "Admin" -ENV GF_AUTH_ANONYMOUS_ENABLED "true" +ENV GF_AUTH_ANONYMOUS_ENABLED "${anonymous_auth_enabled}" ENV GF_AUTH_BASIC_ENABLED "false" # Set development mode so plugins can be loaded without the need to sign ENV GF_DEFAULT_APP_MODE "development" @@ -28,14 +29,14 @@ USER root # Installing supervisor and inotify-tools RUN if [ "${development}" = "true" ]; then \ if grep -i -q alpine /etc/issue; then \ - apk add supervisor inotify-tools git; \ + apk add supervisor inotify-tools git; \ elif grep -i -q ubuntu /etc/issue; then \ - DEBIAN_FRONTEND=noninteractive && \ - apt-get update && \ - apt-get install -y supervisor inotify-tools git && \ - rm -rf /var/lib/apt/lists/*; \ + DEBIAN_FRONTEND=noninteractive && \ + apt-get update && \ + apt-get install -y supervisor inotify-tools git && \ + rm -rf /var/lib/apt/lists/*; \ else \ - echo 'ERROR: Unsupported base image' && /bin/false; \ + echo 'ERROR: Unsupported base image' && /bin/false; \ fi \ fi diff --git a/grafana/rmf-app/.config/README.md b/grafana/rmf-app/.config/README.md index 4de64b52..1ec4b41e 100644 --- a/grafana/rmf-app/.config/README.md +++ b/grafana/rmf-app/.config/README.md @@ -13,17 +13,28 @@ to issues around working with the project. ### Extending the ESLint config -Edit the `.eslintrc` file in the project root in order to extend the ESLint configuration. +Edit the `eslint.config.mjs` file in the project root to extend the ESLint configuration. The following example disables deprecation notices for source files. **Example:** -```json -{ - "extends": "./.config/.eslintrc", - "rules": { - "react/prop-types": "off" - } -} +```javascript +import { defineConfig } from 'eslint/config'; +import baseConfig from './.config/eslint.config.mjs'; + +export default defineConfig([ + { + ignores: [ + //... + ], + }, + ...baseConfig, + { + files: ['src/**/*.{ts,tsx}'], + rules: { + '@typescript-eslint/no-deprecated': 'off', + }, + }, +]); ``` --- @@ -106,9 +117,9 @@ We are going to use [`webpack-merge`](https://github.com/survivejs/webpack-merge // webpack.config.ts import type { Configuration } from 'webpack'; import { merge } from 'webpack-merge'; -import grafanaConfig from './.config/webpack/webpack.config'; +import grafanaConfig, { type Env } from './.config/webpack/webpack.config'; -const config = async (env): Promise => { +const config = async (env: Env): Promise => { const baseConfig = await grafanaConfig(env); return merge(baseConfig, { @@ -151,9 +162,10 @@ version: '3.7' services: grafana: - container_name: 'myorg-basic-app' + extends: + file: .config/docker-compose-base.yaml + service: grafana build: - context: ./.config args: grafana_version: ${GRAFANA_VERSION:-9.1.2} grafana_image: ${GRAFANA_IMAGE:-grafana} diff --git a/grafana/rmf-app/.config/webpack/constants.ts b/grafana/rmf-app/.config/bundler/constants.ts similarity index 100% rename from grafana/rmf-app/.config/webpack/constants.ts rename to grafana/rmf-app/.config/bundler/constants.ts diff --git a/grafana/rmf-app/.config/bundler/copyFiles.ts b/grafana/rmf-app/.config/bundler/copyFiles.ts new file mode 100644 index 00000000..6a0703aa --- /dev/null +++ b/grafana/rmf-app/.config/bundler/copyFiles.ts @@ -0,0 +1,23 @@ +import { getPluginJson, hasReadme } from './utils.ts'; + +const pluginJson = getPluginJson(); +const logoPaths: string[] = Array.from(new Set([pluginJson.info?.logos?.large, pluginJson.info?.logos?.small])).filter( + Boolean +); +const screenshotPaths: string[] = pluginJson.info?.screenshots?.map((s: { path: string }) => s.path) || []; + +export const copyFilePatterns = [ + // If src/README.md exists use it; otherwise the root README + // To `compiler.options.output` + { from: hasReadme() ? 'README.md' : '../README.md', to: '.', force: true }, + { from: 'plugin.json', to: '.' }, + { from: '../LICENSE', to: '.' }, + { from: '../CHANGELOG.md', to: '.', force: true }, + { from: '**/*.json', to: '.' }, + { from: '**/query_help.md', to: '.', noErrorOnMissing: true }, + ...logoPaths.map((logoPath) => ({ from: logoPath, to: logoPath })), + ...screenshotPaths.map((screenshotPath) => ({ + from: screenshotPath, + to: screenshotPath, + })), +]; diff --git a/grafana/rmf-app/.config/bundler/externals.ts b/grafana/rmf-app/.config/bundler/externals.ts new file mode 100644 index 00000000..f5bf0382 --- /dev/null +++ b/grafana/rmf-app/.config/bundler/externals.ts @@ -0,0 +1,45 @@ +import type { Configuration, ExternalItemFunctionData } from 'webpack'; + +type ExternalsType = Configuration['externals']; + +export const externals: ExternalsType = [ + // Required for dynamic publicPath resolution + { 'amd-module': 'module' }, + 'lodash', + 'jquery', + 'moment', + 'slate', + 'emotion', + '@emotion/react', + '@emotion/css', + 'prismjs', + 'slate-plain-serializer', + '@grafana/slate-react', + 'react', + 'react/jsx-runtime', + 'react/jsx-dev-runtime', + 'react-dom', + 'react-redux', + 'redux', + 'rxjs', + 'i18next', + 'react-router', + 'd3', + 'angular', + /^@grafana\/ui/i, + /^@grafana\/runtime/i, + /^@grafana\/data/i, + + // Mark legacy SDK imports as external if their name starts with the "grafana/" prefix + ({ request }: ExternalItemFunctionData, callback: (error?: Error, result?: string) => void) => { + const prefix = 'grafana/'; + const hasPrefix = (request: string) => request.indexOf(prefix) === 0; + const stripPrefix = (request: string) => request.slice(prefix.length); + + if (request && hasPrefix(request)) { + return callback(undefined, stripPrefix(request)); + } + + callback(); + }, +]; diff --git a/grafana/rmf-app/.config/webpack/utils.ts b/grafana/rmf-app/.config/bundler/utils.ts similarity index 65% rename from grafana/rmf-app/.config/webpack/utils.ts rename to grafana/rmf-app/.config/bundler/utils.ts index 015aa051..3b13b193 100644 --- a/grafana/rmf-app/.config/webpack/utils.ts +++ b/grafana/rmf-app/.config/bundler/utils.ts @@ -3,7 +3,7 @@ import process from 'process'; import os from 'os'; import path from 'path'; import { glob } from 'glob'; -import { SOURCE_DIR } from './constants'; +import { SOURCE_DIR } from './constants.ts'; export function isWSL() { if (process.platform !== 'linux') { @@ -21,17 +21,22 @@ export function isWSL() { } } +function loadJson(path: string) { + const rawJson = fs.readFileSync(path, 'utf8'); + return JSON.parse(rawJson); +} + export function getPackageJson() { - return require(path.resolve(process.cwd(), 'package.json')); + return loadJson(path.resolve(process.cwd(), 'package.json')); } export function getPluginJson() { - return require(path.resolve(process.cwd(), `${SOURCE_DIR}/plugin.json`)); + return loadJson(path.resolve(process.cwd(), `${SOURCE_DIR}/plugin.json`)); } export function getCPConfigVersion() { - const cprcJson = path.resolve(__dirname, '../', '.cprc.json'); - return fs.existsSync(cprcJson) ? require(cprcJson).version : { version: 'unknown' }; + const cprcJson = path.resolve(process.cwd(), './.config', '.cprc.json'); + return fs.existsSync(cprcJson) ? loadJson(cprcJson).version : { version: 'unknown' }; } export function hasReadme() { @@ -40,7 +45,7 @@ export function hasReadme() { // Support bundling nested plugins by finding all plugin.json files in src directory // then checking for a sibling module.[jt]sx? file. -export async function getEntries(): Promise> { +export async function getEntries() { const pluginsJson = await glob('**/src/**/plugin.json', { absolute: true }); const plugins = await Promise.all( @@ -50,14 +55,14 @@ export async function getEntries(): Promise> { }) ); - return plugins.reduce((result, modules) => { - return modules.reduce((result, module) => { + return plugins.reduce>((result, modules) => { + return modules.reduce((innerResult, module) => { const pluginPath = path.dirname(module); const pluginName = path.relative(process.cwd(), pluginPath).replace(/src\/?/i, ''); const entryName = pluginName === '' ? 'module' : `${pluginName}/module`; - result[entryName] = module; - return result; + innerResult[entryName] = module; + return innerResult; }, result); }, {}); } diff --git a/grafana/rmf-app/.config/docker-compose-base.yaml b/grafana/rmf-app/.config/docker-compose-base.yaml new file mode 100644 index 00000000..069890bc --- /dev/null +++ b/grafana/rmf-app/.config/docker-compose-base.yaml @@ -0,0 +1,31 @@ +services: + grafana: + user: root + container_name: 'ibm-rmf' + + build: + context: . + args: + grafana_image: ${GRAFANA_IMAGE:-grafana-enterprise} + grafana_version: ${GRAFANA_VERSION:-12.4.0} + development: ${DEVELOPMENT:-false} + anonymous_auth_enabled: ${ANONYMOUS_AUTH_ENABLED:-true} + ports: + - 3000:3000/tcp + - 2345:2345/tcp # delve + security_opt: + - 'apparmor:unconfined' + - 'seccomp:unconfined' + cap_add: + - SYS_PTRACE + volumes: + - ../dist:/var/lib/grafana/plugins/ibm-rmf-app + - ../provisioning:/etc/grafana/provisioning + - ..:/root/ibm-rmf-app + + environment: + NODE_ENV: development + GF_LOG_FILTERS: plugin.ibm-rmf-app:debug + GF_LOG_LEVEL: debug + GF_DATAPROXY_LOGGING: 1 + GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS: ibm-rmf-app diff --git a/grafana/rmf-app/.config/eslint.config.mjs b/grafana/rmf-app/.config/eslint.config.mjs new file mode 100644 index 00000000..bafeaf58 --- /dev/null +++ b/grafana/rmf-app/.config/eslint.config.mjs @@ -0,0 +1,38 @@ +/* + * ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️ + * + * In order to extend the configuration follow the steps in + * https://grafana.com/developers/plugin-tools/how-to-guides/extend-configurations#extend-the-eslint-config + */ + +import { defineConfig } from 'eslint/config'; +import grafanaConfig from '@grafana/eslint-config/flat.js'; + +export default defineConfig([ + ...grafanaConfig, + { + rules: { + 'react/prop-types': 'off', + }, + }, + { + files: ['src/**/*.{ts,tsx}'], + + languageOptions: { + parserOptions: { + project: './tsconfig.json', + }, + }, + + rules: { + '@typescript-eslint/no-deprecated': 'warn', + }, + }, + { + files: ['./tests/**/*'], + + rules: { + 'react-hooks/rules-of-hooks': 'off', + }, + }, +]); diff --git a/grafana/rmf-app/.config/jest-setup.js b/grafana/rmf-app/.config/jest-setup.js index 0687875e..7b1771ea 100644 --- a/grafana/rmf-app/.config/jest-setup.js +++ b/grafana/rmf-app/.config/jest-setup.js @@ -2,7 +2,7 @@ * ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️ * * In order to extend the configuration follow the steps in - * https://grafana.com/developers/plugin-tools/get-started/set-up-development-environment#extend-the-jest-config + * https://grafana.com/developers/plugin-tools/how-to-guides/extend-configurations#extend-the-jest-config */ import '@testing-library/jest-dom'; @@ -13,7 +13,7 @@ Object.assign(global, { TextDecoder, TextEncoder }); // https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom Object.defineProperty(global, 'matchMedia', { writable: true, - value: jest.fn().mockImplementation((query) => ({ + value: (query) => ({ matches: false, media: query, onchange: null, @@ -22,7 +22,7 @@ Object.defineProperty(global, 'matchMedia', { addEventListener: jest.fn(), removeEventListener: jest.fn(), dispatchEvent: jest.fn(), - })), + }), }); HTMLCanvasElement.prototype.getContext = () => {}; diff --git a/grafana/rmf-app/.config/jest.config.js b/grafana/rmf-app/.config/jest.config.js index 09704b4f..efe19384 100644 --- a/grafana/rmf-app/.config/jest.config.js +++ b/grafana/rmf-app/.config/jest.config.js @@ -2,7 +2,7 @@ * ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️ * * In order to extend the configuration follow the steps in - * https://grafana.com/developers/plugin-tools/get-started/set-up-development-environment#extend-the-jest-config + * https://grafana.com/developers/plugin-tools/how-to-guides/extend-configurations#extend-the-jest-config */ const path = require('path'); @@ -40,4 +40,5 @@ module.exports = { // Jest will throw `Cannot use import statement outside module` if it tries to load an // ES module without it being transformed first. ./config/README.md#esm-errors-with-jest transformIgnorePatterns: [nodeModulesToTransform(grafanaESModules)], + watchPathIgnorePatterns: ['/node_modules', '/dist'], }; diff --git a/grafana/rmf-app/.config/jest/utils.js b/grafana/rmf-app/.config/jest/utils.js index fdca0dec..55d9cb6e 100644 --- a/grafana/rmf-app/.config/jest/utils.js +++ b/grafana/rmf-app/.config/jest/utils.js @@ -14,12 +14,18 @@ const nodeModulesToTransform = (moduleNames) => `node_modules\/(?!.*(${moduleNam const grafanaESModules = [ '.pnpm', // Support using pnpm symlinked packages '@grafana/schema', + '@wojtekmaj/date-utils', 'd3', 'd3-color', 'd3-force', 'd3-interpolate', 'd3-scale-chromatic', + 'get-user-locale', + 'marked', + 'memoize', + 'mimic-function', 'ol', + 'react-calendar', 'react-colorful', 'rxjs', 'uuid', diff --git a/grafana/rmf-app/.config/supervisord/supervisord.conf b/grafana/rmf-app/.config/supervisord/supervisord.conf index 9bc312f5..0fb3d5eb 100644 --- a/grafana/rmf-app/.config/supervisord/supervisord.conf +++ b/grafana/rmf-app/.config/supervisord/supervisord.conf @@ -5,7 +5,7 @@ user=root [program:grafana] user=root directory=/var/lib/grafana -command=bash -c 'while [ ! -f /root/rocket-ibmrmf-app/dist/gpx_ibm_rmf_app* ]; do sleep 1; done; /run.sh' +command=bash -c 'while [ ! -f /root/ibm-rmf-app/dist/gpx_app_sample* ]; do sleep 1; done; /run.sh' stdout_logfile=/dev/fd/1 stdout_logfile_maxbytes=0 redirect_stderr=true @@ -15,7 +15,7 @@ autostart=true [program:delve] user=root -command=/bin/bash -c 'pid=""; while [ -z "$pid" ]; do pid=$(pgrep -f gpx_ibm_rmf_app); done; /root/go/bin/dlv attach --api-version=2 --headless --continue --accept-multiclient --listen=:2345 $pid' +command=/bin/bash -c 'pid=""; while [ -z "$pid" ]; do pid=$(pgrep -f gpx_app_sample); done; /root/go/bin/dlv attach --api-version=2 --headless --continue --accept-multiclient --listen=:2345 $pid' stdout_logfile=/dev/fd/1 stdout_logfile_maxbytes=0 redirect_stderr=true @@ -26,7 +26,7 @@ autorestart=true [program:build-watcher] user=root -command=/bin/bash -c 'while inotifywait -e modify,create,delete -r /var/lib/grafana/plugins/rocket-ibmrmf-app; do echo "Change detected, restarting delve...";supervisorctl restart delve; done' +command=/bin/bash -c 'while inotifywait -e modify,create,delete -r /var/lib/grafana/plugins/ibm-rmf-app; do echo "Change detected, restarting delve...";supervisorctl restart delve; done' stdout_logfile=/dev/fd/1 stdout_logfile_maxbytes=0 redirect_stderr=true @@ -37,8 +37,8 @@ autostart=true [program:mage-watcher] user=root environment=PATH="/usr/local/go/bin:/root/go/bin:%(ENV_PATH)s" -directory=/root/rocket-ibmrmf-app -command=/bin/bash -c 'git config --global --add safe.directory /root/rocket-ibmrmf-app && mage -v watch' +directory=/root/ibm-rmf-app +command=/bin/bash -c 'git config --global --add safe.directory /root/ibm-rmf-app && mage -v watch' stdout_logfile=/dev/fd/1 stdout_logfile_maxbytes=0 redirect_stderr=true diff --git a/grafana/rmf-app/.config/tsconfig.json b/grafana/rmf-app/.config/tsconfig.json index 15e64aca..c0fc6d47 100644 --- a/grafana/rmf-app/.config/tsconfig.json +++ b/grafana/rmf-app/.config/tsconfig.json @@ -2,7 +2,7 @@ * ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️ * * In order to extend the configuration follow the steps in - * https://grafana.com/developers/plugin-tools/get-started/set-up-development-environment#extend-the-typescript-config + * https://grafana.com/developers/plugin-tools/how-to-guides/extend-configurations#extend-the-typescript-config */ { "compilerOptions": { diff --git a/grafana/rmf-app/.config/types/custom.d.ts b/grafana/rmf-app/.config/types/bundler-rules.d.ts similarity index 91% rename from grafana/rmf-app/.config/types/custom.d.ts rename to grafana/rmf-app/.config/types/bundler-rules.d.ts index 64e6eaa6..e67197c5 100644 --- a/grafana/rmf-app/.config/types/custom.d.ts +++ b/grafana/rmf-app/.config/types/bundler-rules.d.ts @@ -25,8 +25,8 @@ declare module '*.webp' { } declare module '*.svg' { - const content: string; - export default content; + const src: string; + export default src; } // Font declarations diff --git a/grafana/rmf-app/.config/types/setupTests.d.ts b/grafana/rmf-app/.config/types/setupTests.d.ts new file mode 100644 index 00000000..7b0828bf --- /dev/null +++ b/grafana/rmf-app/.config/types/setupTests.d.ts @@ -0,0 +1 @@ +import '@testing-library/jest-dom'; diff --git a/grafana/rmf-app/.config/types/webpack-plugins.d.ts b/grafana/rmf-app/.config/types/webpack-plugins.d.ts new file mode 100644 index 00000000..6dbab109 --- /dev/null +++ b/grafana/rmf-app/.config/types/webpack-plugins.d.ts @@ -0,0 +1,83 @@ +declare module 'replace-in-file-webpack-plugin' { + import { Compiler, Plugin } from 'webpack'; + + interface ReplaceRule { + search: string | RegExp; + replace: string | ((match: string) => string); + } + + interface ReplaceOption { + dir?: string; + files?: string[]; + test?: RegExp | RegExp[]; + rules: ReplaceRule[]; + } + + class ReplaceInFilePlugin extends Plugin { + constructor(options?: ReplaceOption[]); + options: ReplaceOption[]; + apply(compiler: Compiler): void; + } + + export = ReplaceInFilePlugin; +} + +declare module 'webpack-livereload-plugin' { + import { ServerOptions } from 'https'; + import { Compiler, Plugin, Stats, Compilation } from 'webpack'; + + interface Options extends Pick { + /** + * protocol for livereload `