From 3dc7347c36cae5c0d874108510ec39dac6ad10b7 Mon Sep 17 00:00:00 2001 From: Yousef Khan Date: Tue, 30 Jun 2026 10:13:50 -0700 Subject: [PATCH 01/86] Create Grafana Plugin --- nasa-hermes-datasource/.config/.cprc.json | 3 + nasa-hermes-datasource/.config/.prettierrc.js | 16 + nasa-hermes-datasource/.config/Dockerfile | 77 + nasa-hermes-datasource/.config/README.md | 176 + .../.config/bundler/constants.ts | 2 + .../.config/bundler/copyFiles.ts | 23 + .../.config/bundler/externals.ts | 45 + .../.config/bundler/utils.ts | 68 + .../.config/docker-compose-base.yaml | 31 + nasa-hermes-datasource/.config/entrypoint.sh | 18 + .../.config/eslint.config.mjs | 38 + nasa-hermes-datasource/.config/jest-setup.js | 28 + nasa-hermes-datasource/.config/jest.config.js | 44 + .../.config/jest/mocks/react-inlinesvg.tsx | 25 + nasa-hermes-datasource/.config/jest/utils.js | 37 + .../.config/supervisord/supervisord.conf | 47 + nasa-hermes-datasource/.config/tsconfig.json | 29 + .../.config/types/bundler-rules.d.ts | 37 + .../.config/types/setupTests.d.ts | 1 + .../.config/types/webpack-plugins.d.ts | 83 + .../.config/webpack/BuildModeWebpackPlugin.ts | 33 + .../.config/webpack/webpack.config.ts | 234 + nasa-hermes-datasource/.cprc.json | 6 + nasa-hermes-datasource/.github/dependabot.yml | 64 + .../.github/workflows/bundle-stats.yml | 27 + .../.github/workflows/ci.yml | 217 + .../.github/workflows/cp-update.yml | 20 + .../.github/workflows/is-compatible.yml | 37 + .../.github/workflows/release.yml | 29 + nasa-hermes-datasource/.gitignore | 54 + nasa-hermes-datasource/.golangci.yml | 5 + nasa-hermes-datasource/.npmrc | 5 + nasa-hermes-datasource/.nvmrc | 1 + nasa-hermes-datasource/.prettierrc.js | 4 + nasa-hermes-datasource/CHANGELOG.md | 5 + nasa-hermes-datasource/LICENSE | 201 + nasa-hermes-datasource/Magefile.go | 11 + nasa-hermes-datasource/README.md | 136 + nasa-hermes-datasource/docker-compose.yaml | 5 + nasa-hermes-datasource/eslint.config.mjs | 39 + nasa-hermes-datasource/go.mod | 85 + nasa-hermes-datasource/go.sum | 362 + nasa-hermes-datasource/jest-setup.js | 2 + nasa-hermes-datasource/jest.config.js | 8 + nasa-hermes-datasource/package-lock.json | 16876 ++++++++++++++++ nasa-hermes-datasource/package.json | 80 + nasa-hermes-datasource/pkg/main.go | 24 + nasa-hermes-datasource/pkg/models/settings.go | 35 + .../pkg/plugin/datasource.go | 116 + .../pkg/plugin/datasource_test.go | 28 + nasa-hermes-datasource/playwright.config.ts | 53 + nasa-hermes-datasource/provisioning/README.md | 1 + .../provisioning/datasources/.gitkeep | 0 .../provisioning/datasources/datasources.yml | 14 + nasa-hermes-datasource/src/README.md | 50 + .../src/components/ConfigEditor.tsx | 71 + .../src/components/QueryEditor.tsx | 45 + nasa-hermes-datasource/src/datasource.ts | 26 + nasa-hermes-datasource/src/img/logo.svg | 1 + nasa-hermes-datasource/src/module.ts | 9 + nasa-hermes-datasource/src/plugin.json | 28 + nasa-hermes-datasource/src/types.ts | 34 + .../tests/configEditor.spec.ts | 31 + .../tests/queryEditor.spec.ts | 28 + nasa-hermes-datasource/tsconfig.json | 3 + 65 files changed, 19971 insertions(+) create mode 100644 nasa-hermes-datasource/.config/.cprc.json create mode 100644 nasa-hermes-datasource/.config/.prettierrc.js create mode 100644 nasa-hermes-datasource/.config/Dockerfile create mode 100644 nasa-hermes-datasource/.config/README.md create mode 100644 nasa-hermes-datasource/.config/bundler/constants.ts create mode 100644 nasa-hermes-datasource/.config/bundler/copyFiles.ts create mode 100644 nasa-hermes-datasource/.config/bundler/externals.ts create mode 100644 nasa-hermes-datasource/.config/bundler/utils.ts create mode 100644 nasa-hermes-datasource/.config/docker-compose-base.yaml create mode 100644 nasa-hermes-datasource/.config/entrypoint.sh create mode 100644 nasa-hermes-datasource/.config/eslint.config.mjs create mode 100644 nasa-hermes-datasource/.config/jest-setup.js create mode 100644 nasa-hermes-datasource/.config/jest.config.js create mode 100644 nasa-hermes-datasource/.config/jest/mocks/react-inlinesvg.tsx create mode 100644 nasa-hermes-datasource/.config/jest/utils.js create mode 100644 nasa-hermes-datasource/.config/supervisord/supervisord.conf create mode 100644 nasa-hermes-datasource/.config/tsconfig.json create mode 100644 nasa-hermes-datasource/.config/types/bundler-rules.d.ts create mode 100644 nasa-hermes-datasource/.config/types/setupTests.d.ts create mode 100644 nasa-hermes-datasource/.config/types/webpack-plugins.d.ts create mode 100644 nasa-hermes-datasource/.config/webpack/BuildModeWebpackPlugin.ts create mode 100644 nasa-hermes-datasource/.config/webpack/webpack.config.ts create mode 100644 nasa-hermes-datasource/.cprc.json create mode 100644 nasa-hermes-datasource/.github/dependabot.yml create mode 100644 nasa-hermes-datasource/.github/workflows/bundle-stats.yml create mode 100644 nasa-hermes-datasource/.github/workflows/ci.yml create mode 100644 nasa-hermes-datasource/.github/workflows/cp-update.yml create mode 100644 nasa-hermes-datasource/.github/workflows/is-compatible.yml create mode 100644 nasa-hermes-datasource/.github/workflows/release.yml create mode 100644 nasa-hermes-datasource/.gitignore create mode 100644 nasa-hermes-datasource/.golangci.yml create mode 100644 nasa-hermes-datasource/.npmrc create mode 100644 nasa-hermes-datasource/.nvmrc create mode 100644 nasa-hermes-datasource/.prettierrc.js create mode 100644 nasa-hermes-datasource/CHANGELOG.md create mode 100644 nasa-hermes-datasource/LICENSE create mode 100644 nasa-hermes-datasource/Magefile.go create mode 100644 nasa-hermes-datasource/README.md create mode 100644 nasa-hermes-datasource/docker-compose.yaml create mode 100644 nasa-hermes-datasource/eslint.config.mjs create mode 100644 nasa-hermes-datasource/go.mod create mode 100644 nasa-hermes-datasource/go.sum create mode 100644 nasa-hermes-datasource/jest-setup.js create mode 100644 nasa-hermes-datasource/jest.config.js create mode 100644 nasa-hermes-datasource/package-lock.json create mode 100644 nasa-hermes-datasource/package.json create mode 100644 nasa-hermes-datasource/pkg/main.go create mode 100644 nasa-hermes-datasource/pkg/models/settings.go create mode 100644 nasa-hermes-datasource/pkg/plugin/datasource.go create mode 100644 nasa-hermes-datasource/pkg/plugin/datasource_test.go create mode 100644 nasa-hermes-datasource/playwright.config.ts create mode 100644 nasa-hermes-datasource/provisioning/README.md create mode 100644 nasa-hermes-datasource/provisioning/datasources/.gitkeep create mode 100644 nasa-hermes-datasource/provisioning/datasources/datasources.yml create mode 100644 nasa-hermes-datasource/src/README.md create mode 100644 nasa-hermes-datasource/src/components/ConfigEditor.tsx create mode 100644 nasa-hermes-datasource/src/components/QueryEditor.tsx create mode 100644 nasa-hermes-datasource/src/datasource.ts create mode 100644 nasa-hermes-datasource/src/img/logo.svg create mode 100644 nasa-hermes-datasource/src/module.ts create mode 100644 nasa-hermes-datasource/src/plugin.json create mode 100644 nasa-hermes-datasource/src/types.ts create mode 100644 nasa-hermes-datasource/tests/configEditor.spec.ts create mode 100644 nasa-hermes-datasource/tests/queryEditor.spec.ts create mode 100644 nasa-hermes-datasource/tsconfig.json diff --git a/nasa-hermes-datasource/.config/.cprc.json b/nasa-hermes-datasource/.config/.cprc.json new file mode 100644 index 0000000..4189d6a --- /dev/null +++ b/nasa-hermes-datasource/.config/.cprc.json @@ -0,0 +1,3 @@ +{ + "version": "7.8.0" +} diff --git a/nasa-hermes-datasource/.config/.prettierrc.js b/nasa-hermes-datasource/.config/.prettierrc.js new file mode 100644 index 0000000..bf506f5 --- /dev/null +++ b/nasa-hermes-datasource/.config/.prettierrc.js @@ -0,0 +1,16 @@ +/* + * ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️ + * + * In order to extend the configuration follow the steps in .config/README.md + */ + +module.exports = { + endOfLine: 'auto', + printWidth: 120, + trailingComma: 'es5', + semi: true, + jsxSingleQuote: false, + singleQuote: true, + useTabs: false, + tabWidth: 2, +}; diff --git a/nasa-hermes-datasource/.config/Dockerfile b/nasa-hermes-datasource/.config/Dockerfile new file mode 100644 index 0000000..0c5e6e8 --- /dev/null +++ b/nasa-hermes-datasource/.config/Dockerfile @@ -0,0 +1,77 @@ +ARG grafana_version=latest +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.21.6 +ARG GO_ARCH=${TARGETARCH:-amd64} + +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 "${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" + + +LABEL maintainer="Grafana Labs " + +ENV GF_PATHS_HOME="/usr/share/grafana" +WORKDIR $GF_PATHS_HOME + +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; \ + 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/*; \ + else \ + echo 'ERROR: Unsupported base image' && /bin/false; \ + fi \ + fi + +COPY supervisord/supervisord.conf /etc/supervisor.d/supervisord.ini +COPY supervisord/supervisord.conf /etc/supervisor/conf.d/supervisord.conf + + +# Installing Go +RUN if [ "${development}" = "true" ]; then \ + curl -O -L https://golang.org/dl/go${GO_VERSION}.linux-${GO_ARCH}.tar.gz && \ + rm -rf /usr/local/go && \ + tar -C /usr/local -xzf go${GO_VERSION}.linux-${GO_ARCH}.tar.gz && \ + echo "export PATH=$PATH:/usr/local/go/bin:~/go/bin" >> ~/.bashrc && \ + rm -f go${GO_VERSION}.linux-${GO_ARCH}.tar.gz; \ + fi + +# Installing delve for debugging +RUN if [ "${development}" = "true" ]; then \ + /usr/local/go/bin/go install github.com/go-delve/delve/cmd/dlv@latest; \ + fi + +# Installing mage for plugin (re)building +RUN if [ "${development}" = "true" ]; then \ + git clone https://github.com/magefile/mage; \ + cd mage; \ + export PATH=$PATH:/usr/local/go/bin; \ + go run bootstrap.go; \ + fi + +# Inject livereload script into grafana index.html +RUN sed -i 's|||g' /usr/share/grafana/public/views/index.html + + +COPY entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh +ENTRYPOINT ["/entrypoint.sh"] diff --git a/nasa-hermes-datasource/.config/README.md b/nasa-hermes-datasource/.config/README.md new file mode 100644 index 0000000..1ec4b41 --- /dev/null +++ b/nasa-hermes-datasource/.config/README.md @@ -0,0 +1,176 @@ +# Default build configuration by Grafana + +**This is an auto-generated directory and is not intended to be changed! ⚠️** + +The `.config/` directory holds basic configuration for the different tools +that are used to develop, test and build the project. In order to make it updates easier we ask you to +not edit files in this folder to extend configuration. + +## How to extend the basic configs? + +Bear in mind that you are doing it at your own risk, and that extending any of the basic configuration can lead +to issues around working with the project. + +### Extending the ESLint config + +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:** + +```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', + }, + }, +]); +``` + +--- + +### Extending the Prettier config + +Edit the `.prettierrc.js` file in the project root in order to extend the Prettier configuration. + +**Example:** + +```javascript +module.exports = { + // Prettier configuration provided by Grafana scaffolding + ...require('./.config/.prettierrc.js'), + + semi: false, +}; +``` + +--- + +### Extending the Jest config + +There are two configuration in the project root that belong to Jest: `jest-setup.js` and `jest.config.js`. + +**`jest-setup.js`:** A file that is run before each test file in the suite is executed. We are using it to +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)) + +**`jest.config.js`:** The main Jest configuration file that extends the Grafana recommended setup. ([link to Jest docs](https://jestjs.io/docs/configuration)) + +#### ESM errors with Jest + +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: + +```javascript +process.env.TZ = 'UTC'; +const { grafanaESModules, nodeModulesToTransform } = require('./config/jest/utils'); + +module.exports = { + // Jest configuration provided by Grafana + ...require('./.config/jest.config'), + // Inform jest to only transform specific node_module packages. + transformIgnorePatterns: [nodeModulesToTransform([...grafanaESModules, 'packageName'])], +}; +``` + +--- + +### Extending the TypeScript config + +Edit the `tsconfig.json` file in the project root in order to extend the TypeScript configuration. + +**Example:** + +```json +{ + "extends": "./.config/tsconfig.json", + "compilerOptions": { + "preserveConstEnums": true + } +} +``` + +--- + +### Extending the Webpack config + +Follow these steps to extend the basic Webpack configuration that lives under `.config/`: + +#### 1. Create a new Webpack configuration file + +Create a new config file that is going to extend the basic one provided by Grafana. +It can live in the project root, e.g. `webpack.config.ts`. + +#### 2. Merge the basic config provided by Grafana and your custom setup + +We are going to use [`webpack-merge`](https://github.com/survivejs/webpack-merge) for this. + +```typescript +// webpack.config.ts +import type { Configuration } from 'webpack'; +import { merge } from 'webpack-merge'; +import grafanaConfig, { type Env } from './.config/webpack/webpack.config'; + +const config = async (env: Env): Promise => { + const baseConfig = await grafanaConfig(env); + + return merge(baseConfig, { + // Add custom config here... + output: { + asyncChunks: true, + }, + }); +}; + +export default config; +``` + +#### 3. Update the `package.json` to use the new Webpack config + +We need to update the `scripts` in the `package.json` to use the extended Webpack configuration. + +**Update for `build`:** + +```diff +-"build": "webpack -c ./.config/webpack/webpack.config.ts --env production", ++"build": "webpack -c ./webpack.config.ts --env production", +``` + +**Update for `dev`:** + +```diff +-"dev": "webpack -w -c ./.config/webpack/webpack.config.ts --env development", ++"dev": "webpack -w -c ./webpack.config.ts --env development", +``` + +### Configure grafana image to use when running docker + +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`. + +**Example:** + +```yaml +version: '3.7' + +services: + grafana: + extends: + file: .config/docker-compose-base.yaml + service: grafana + build: + args: + grafana_version: ${GRAFANA_VERSION:-9.1.2} + grafana_image: ${GRAFANA_IMAGE:-grafana} +``` + +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. + +--- diff --git a/nasa-hermes-datasource/.config/bundler/constants.ts b/nasa-hermes-datasource/.config/bundler/constants.ts new file mode 100644 index 0000000..071e4fd --- /dev/null +++ b/nasa-hermes-datasource/.config/bundler/constants.ts @@ -0,0 +1,2 @@ +export const SOURCE_DIR = 'src'; +export const DIST_DIR = 'dist'; diff --git a/nasa-hermes-datasource/.config/bundler/copyFiles.ts b/nasa-hermes-datasource/.config/bundler/copyFiles.ts new file mode 100644 index 0000000..6a0703a --- /dev/null +++ b/nasa-hermes-datasource/.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/nasa-hermes-datasource/.config/bundler/externals.ts b/nasa-hermes-datasource/.config/bundler/externals.ts new file mode 100644 index 0000000..f5bf038 --- /dev/null +++ b/nasa-hermes-datasource/.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/nasa-hermes-datasource/.config/bundler/utils.ts b/nasa-hermes-datasource/.config/bundler/utils.ts new file mode 100644 index 0000000..3b13b19 --- /dev/null +++ b/nasa-hermes-datasource/.config/bundler/utils.ts @@ -0,0 +1,68 @@ +import fs from 'fs'; +import process from 'process'; +import os from 'os'; +import path from 'path'; +import { glob } from 'glob'; +import { SOURCE_DIR } from './constants.ts'; + +export function isWSL() { + if (process.platform !== 'linux') { + return false; + } + + if (os.release().toLowerCase().includes('microsoft')) { + return true; + } + + try { + return fs.readFileSync('/proc/version', 'utf8').toLowerCase().includes('microsoft'); + } catch { + return false; + } +} + +function loadJson(path: string) { + const rawJson = fs.readFileSync(path, 'utf8'); + return JSON.parse(rawJson); +} + +export function getPackageJson() { + return loadJson(path.resolve(process.cwd(), 'package.json')); +} + +export function getPluginJson() { + return loadJson(path.resolve(process.cwd(), `${SOURCE_DIR}/plugin.json`)); +} + +export function getCPConfigVersion() { + const cprcJson = path.resolve(process.cwd(), './.config', '.cprc.json'); + return fs.existsSync(cprcJson) ? loadJson(cprcJson).version : { version: 'unknown' }; +} + +export function hasReadme() { + return fs.existsSync(path.resolve(process.cwd(), SOURCE_DIR, 'README.md')); +} + +// 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() { + const pluginsJson = await glob('**/src/**/plugin.json', { absolute: true }); + + const plugins = await Promise.all( + pluginsJson.map((pluginJson) => { + const folder = path.dirname(pluginJson); + return glob(`${folder}/module.{ts,tsx,js,jsx}`, { absolute: true }); + }) + ); + + 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`; + + innerResult[entryName] = module; + return innerResult; + }, result); + }, {}); +} diff --git a/nasa-hermes-datasource/.config/docker-compose-base.yaml b/nasa-hermes-datasource/.config/docker-compose-base.yaml new file mode 100644 index 0000000..10b355b --- /dev/null +++ b/nasa-hermes-datasource/.config/docker-compose-base.yaml @@ -0,0 +1,31 @@ +services: + grafana: + user: root + container_name: 'nasa-hermes-datasource' + + build: + context: . + args: + grafana_image: ${GRAFANA_IMAGE:-grafana-enterprise} + grafana_version: ${GRAFANA_VERSION:-13.0.2} + 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/nasa-hermes-datasource + - ../provisioning:/etc/grafana/provisioning + - ..:/root/nasa-hermes-datasource + + environment: + NODE_ENV: development + GF_LOG_FILTERS: plugin.nasa-hermes-datasource:debug + GF_LOG_LEVEL: debug + GF_DATAPROXY_LOGGING: 1 + GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS: nasa-hermes-datasource diff --git a/nasa-hermes-datasource/.config/entrypoint.sh b/nasa-hermes-datasource/.config/entrypoint.sh new file mode 100644 index 0000000..00c69f2 --- /dev/null +++ b/nasa-hermes-datasource/.config/entrypoint.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +if [ "${DEV}" = "false" ]; then + echo "Starting test mode" + exec /run.sh +fi + +echo "Starting development mode" + +if grep -i -q alpine /etc/issue; then + exec /usr/bin/supervisord -c /etc/supervisord.conf +elif grep -i -q ubuntu /etc/issue; then + exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf +else + echo 'ERROR: Unsupported base image' + exit 1 +fi + diff --git a/nasa-hermes-datasource/.config/eslint.config.mjs b/nasa-hermes-datasource/.config/eslint.config.mjs new file mode 100644 index 0000000..bafeaf5 --- /dev/null +++ b/nasa-hermes-datasource/.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/nasa-hermes-datasource/.config/jest-setup.js b/nasa-hermes-datasource/.config/jest-setup.js new file mode 100644 index 0000000..7b1771e --- /dev/null +++ b/nasa-hermes-datasource/.config/jest-setup.js @@ -0,0 +1,28 @@ +/* + * ⚠️⚠️⚠️ 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-jest-config + */ + +import '@testing-library/jest-dom'; +import { TextEncoder, TextDecoder } from 'util'; + +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: (query) => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), // deprecated + removeListener: jest.fn(), // deprecated + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + }), +}); + +HTMLCanvasElement.prototype.getContext = () => {}; diff --git a/nasa-hermes-datasource/.config/jest.config.js b/nasa-hermes-datasource/.config/jest.config.js new file mode 100644 index 0000000..efe1938 --- /dev/null +++ b/nasa-hermes-datasource/.config/jest.config.js @@ -0,0 +1,44 @@ +/* + * ⚠️⚠️⚠️ 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-jest-config + */ + +const path = require('path'); +const { grafanaESModules, nodeModulesToTransform } = require('./jest/utils'); + +module.exports = { + moduleNameMapper: { + '\\.(css|scss|sass)$': 'identity-obj-proxy', + 'react-inlinesvg': path.resolve(__dirname, 'jest', 'mocks', 'react-inlinesvg.tsx'), + }, + modulePaths: ['/src'], + setupFilesAfterEnv: ['/jest-setup.js'], + testEnvironment: 'jest-environment-jsdom', + testMatch: [ + '/src/**/__tests__/**/*.{js,jsx,ts,tsx}', + '/src/**/*.{spec,test,jest}.{js,jsx,ts,tsx}', + '/src/**/*.{spec,test,jest}.{js,jsx,ts,tsx}', + ], + transform: { + '^.+\\.(t|j)sx?$': [ + '@swc/jest', + { + sourceMaps: 'inline', + jsc: { + parser: { + syntax: 'typescript', + tsx: true, + decorators: false, + dynamicImport: true, + }, + }, + }, + ], + }, + // 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/nasa-hermes-datasource/.config/jest/mocks/react-inlinesvg.tsx b/nasa-hermes-datasource/.config/jest/mocks/react-inlinesvg.tsx new file mode 100644 index 0000000..d540f3a --- /dev/null +++ b/nasa-hermes-datasource/.config/jest/mocks/react-inlinesvg.tsx @@ -0,0 +1,25 @@ +// Due to the grafana/ui Icon component making fetch requests to +// `/public/img/icon/.svg` we need to mock react-inlinesvg to prevent +// the failed fetch requests from displaying errors in console. + +import React from 'react'; + +type Callback = (...args: any[]) => void; + +export interface StorageItem { + content: string; + queue: Callback[]; + status: string; +} + +export const cacheStore: { [key: string]: StorageItem } = Object.create(null); + +const SVG_FILE_NAME_REGEX = /(.+)\/(.+)\.svg$/; + +const InlineSVG = ({ src }: { src: string }) => { + // testId will be the file name without extension (e.g. `public/img/icons/angle-double-down.svg` -> `angle-double-down`) + const testId = src.replace(SVG_FILE_NAME_REGEX, '$2'); + return ; +}; + +export default InlineSVG; diff --git a/nasa-hermes-datasource/.config/jest/utils.js b/nasa-hermes-datasource/.config/jest/utils.js new file mode 100644 index 0000000..55d9cb6 --- /dev/null +++ b/nasa-hermes-datasource/.config/jest/utils.js @@ -0,0 +1,37 @@ +/* + * ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️ + * + * In order to extend the configuration follow the steps in .config/README.md + */ + +/* + * This utility function is useful in combination with jest `transformIgnorePatterns` config + * to transform specific packages (e.g.ES modules) in a projects node_modules folder. + */ +const nodeModulesToTransform = (moduleNames) => `node_modules\/(?!.*(${moduleNames.join('|')})\/.*)`; + +// Array of known nested grafana package dependencies that only bundle an ESM version +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', +]; + +module.exports = { + nodeModulesToTransform, + grafanaESModules, +}; diff --git a/nasa-hermes-datasource/.config/supervisord/supervisord.conf b/nasa-hermes-datasource/.config/supervisord/supervisord.conf new file mode 100644 index 0000000..2e1e34d --- /dev/null +++ b/nasa-hermes-datasource/.config/supervisord/supervisord.conf @@ -0,0 +1,47 @@ +[supervisord] +nodaemon=true +user=root + +[program:grafana] +user=root +directory=/var/lib/grafana +command=bash -c 'while [ ! -f /root/nasa-hermes-datasource/dist/gpx_hermes_datasource* ]; do sleep 1; done; /run.sh' +stdout_logfile=/dev/fd/1 +stdout_logfile_maxbytes=0 +redirect_stderr=true +killasgroup=true +stopasgroup=true +autostart=true + +[program:delve] +user=root +command=/bin/bash -c 'pid=""; while [ -z "$pid" ]; do pid=$(pgrep -f gpx_hermes_datasource); 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 +killasgroup=false +stopasgroup=false +autostart=true +autorestart=true + +[program:build-watcher] +user=root +command=/bin/bash -c 'while inotifywait -e modify,create,delete -r /var/lib/grafana/plugins/nasa-hermes-datasource; do echo "Change detected, restarting delve...";supervisorctl restart delve; done' +stdout_logfile=/dev/fd/1 +stdout_logfile_maxbytes=0 +redirect_stderr=true +killasgroup=true +stopasgroup=true +autostart=true + +[program:mage-watcher] +user=root +environment=PATH="/usr/local/go/bin:/root/go/bin:%(ENV_PATH)s" +directory=/root/nasa-hermes-datasource +command=/bin/bash -c 'git config --global --add safe.directory /root/nasa-hermes-datasource && mage -v watch' +stdout_logfile=/dev/fd/1 +stdout_logfile_maxbytes=0 +redirect_stderr=true +killasgroup=true +stopasgroup=true +autostart=true diff --git a/nasa-hermes-datasource/.config/tsconfig.json b/nasa-hermes-datasource/.config/tsconfig.json new file mode 100644 index 0000000..385a223 --- /dev/null +++ b/nasa-hermes-datasource/.config/tsconfig.json @@ -0,0 +1,29 @@ +/* + * ⚠️⚠️⚠️ 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-typescript-config + */ +{ + "compilerOptions": { + "alwaysStrict": true, + "declaration": false, + "rootDir": "../src", + "paths": { + "*": ["../src/*"] + }, + "typeRoots": ["../node_modules/@types"], + "resolveJsonModule": true + }, + "ts-node": { + "compilerOptions": { + "module": "nodenext", + "moduleResolution": "nodenext", + "target": "es2022", + "esModuleInterop": true + }, + "transpileOnly": true + }, + "include": ["../src", "./types"], + "extends": "@grafana/tsconfig" +} diff --git a/nasa-hermes-datasource/.config/types/bundler-rules.d.ts b/nasa-hermes-datasource/.config/types/bundler-rules.d.ts new file mode 100644 index 0000000..e67197c --- /dev/null +++ b/nasa-hermes-datasource/.config/types/bundler-rules.d.ts @@ -0,0 +1,37 @@ +// Image declarations +declare module '*.gif' { + const src: string; + export default src; +} + +declare module '*.jpg' { + const src: string; + export default src; +} + +declare module '*.jpeg' { + const src: string; + export default src; +} + +declare module '*.png' { + const src: string; + export default src; +} + +declare module '*.webp' { + const src: string; + export default src; +} + +declare module '*.svg' { + const src: string; + export default src; +} + +// Font declarations +declare module '*.woff'; +declare module '*.woff2'; +declare module '*.eot'; +declare module '*.ttf'; +declare module '*.otf'; diff --git a/nasa-hermes-datasource/.config/types/setupTests.d.ts b/nasa-hermes-datasource/.config/types/setupTests.d.ts new file mode 100644 index 0000000..7b0828b --- /dev/null +++ b/nasa-hermes-datasource/.config/types/setupTests.d.ts @@ -0,0 +1 @@ +import '@testing-library/jest-dom'; diff --git a/nasa-hermes-datasource/.config/types/webpack-plugins.d.ts b/nasa-hermes-datasource/.config/types/webpack-plugins.d.ts new file mode 100644 index 0000000..6dbab10 --- /dev/null +++ b/nasa-hermes-datasource/.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 `