Chore: Dependency clean up

This commit is contained in:
Zoltán Bedi
2023-09-24 22:59:27 +02:00
parent fe55c450bd
commit fdca810285
33 changed files with 4052 additions and 14822 deletions

View File

@@ -1,331 +0,0 @@
version: 2.1
aliases:
# Workflow filters
- &filter-not-release-or-master
tags:
ignore: /^v[0-9]+(\.[0-9]+){2}(-.+|[^-.]*)$/
branches:
ignore:
- master
- /^release-[0-9]+(\.[0-9]+){2}(-.+|[^-.]*)$/
- docs
- gh-pages
- &filter-only-master
branches:
only: master
- &filter-only-release
branches:
ignore: /.*/
tags:
only: /^v[0-9]+(\.[0-9]+){2}(-.+|[^-.]*)$/
- &filter-docs
branches:
only: docs
executors:
e2e_exec:
docker:
- image: srclosson/grafana-plugin-ci-e2e:latest
jobs:
build:
working_directory: ~/alexanderzobnin/grafana-zabbix
docker:
- image: circleci/golang:1.14-node
environment:
YARN_NO_PROGRESS: "true"
steps:
- checkout
- restore_cache:
keys:
- dependency-cache-npm-{{ checksum "yarn.lock" }}
- restore_cache:
keys:
- dependency-cache-go-{{ checksum "go.sum" }}
- run:
name: Install Dependencies
command: 'make install'
no_output_timeout: 15m
- save_cache:
key: dependency-cache-npm-{{ checksum "yarn.lock" }}
paths:
- ./node_modules
- save_cache:
key: dependency-cache-go-{{ checksum "go.sum" }}
paths:
- ./vendor
- /go/pkg/mod
- run: make build
lint:
working_directory: ~/alexanderzobnin/grafana-zabbix
docker:
- image: circleci/golang:1.14-node
steps:
- checkout
- restore_cache:
keys:
- dependency-cache-npm-{{ checksum "yarn.lock" }}
- restore_cache:
keys:
- dependency-cache-go-{{ checksum "go.sum" }}
- run:
name: Install Dependencies
command: 'make install'
no_output_timeout: 15m
- save_cache:
key: dependency-cache-npm-{{ checksum "yarn.lock" }}
paths:
- ./node_modules
- save_cache:
key: dependency-cache-go-{{ checksum "go.sum" }}
paths:
- ./vendor
- /go/pkg/mod
- run: make lint
test:
working_directory: ~/alexanderzobnin/grafana-zabbix
environment:
CIRCLE_ARTIFACTS: /tmp/circleci-artifacts
CIRCLE_TEST_REPORTS: /tmp/circleci-test-results
docker:
- image: circleci/golang:1.14-node
steps:
- checkout
# Prepare for artifact and test results collection equivalent to how it was done on 1.0.
# In many cases you can simplify this from what is generated here.
# 'See docs on artifact collection here https://circleci.com/docs/2.0/artifacts/'
- run: mkdir -p $CIRCLE_ARTIFACTS $CIRCLE_TEST_REPORTS
- restore_cache:
keys:
- dependency-cache-npm-{{ checksum "yarn.lock" }}
- restore_cache:
keys:
- dependency-cache-go-{{ checksum "go.sum" }}
- run:
name: Install Dependencies
command: 'make install'
no_output_timeout: 15m
- save_cache:
key: dependency-cache-npm-{{ checksum "yarn.lock" }}
paths:
- ./node_modules
- save_cache:
key: dependency-cache-go-{{ checksum "go.sum" }}
paths:
- ./vendor
- /go/pkg/mod
- run: make test-ci
- run: bash <(curl -s https://codecov.io/bash) || echo "Codecov did not collect coverage reports"
- store_test_results:
path: /tmp/circleci-test-results
- store_artifacts:
path: /tmp/circleci-artifacts
- store_artifacts:
path: /tmp/circleci-test-results
get-plugin:
working_directory: ~/alexanderzobnin/grafana-zabbix
docker:
- image: circleci/golang:1.14-node
environment:
YARN_NO_PROGRESS: "true"
steps:
- checkout
- restore_cache:
keys:
- dependency-cache-npm-{{ checksum "yarn.lock" }}
- restore_cache:
keys:
- dependency-cache-go-{{ checksum "go.sum" }}
- persist_to_workspace:
root: ~/alexanderzobnin/
paths:
- grafana-zabbix
package-plugin:
executor: e2e_exec
working_directory: ~/alexanderzobnin/grafana-zabbix
steps:
- attach_workspace:
at: ~/alexanderzobnin
- run:
name: Install Dependencies
command: 'make install'
no_output_timeout: 15m
- save_cache:
key: dependency-cache-npm-{{ checksum "yarn.lock" }}
paths:
- ./node_modules
- save_cache:
key: dependency-cache-go-{{ checksum "go.sum" }}
paths:
- ./vendor
- /go/pkg/mod
- run:
name: Build plugin for all platforms
command: 'make dist'
no_output_timeout: 15m
- run:
name: Prepare plugin for packaging
command: |
mkdir -p ci/jobs/build_plugin
mv dist/ ci/jobs/build_plugin
cp CHANGELOG.md ci/jobs/build_plugin/dist
- run:
name: Package and sign plugin
command: yarn grafana-toolkit plugin:ci-package
no_output_timeout: 15m
- persist_to_workspace:
root: ~/alexanderzobnin/
paths:
- grafana-zabbix
- store_artifacts:
path: ci/packages
make-github-release:
working_directory: ~/alexanderzobnin/grafana-zabbix
docker:
- image: circleci/golang:1.14-node
environment:
steps:
- attach_workspace:
at: ~/alexanderzobnin
- run:
name: Publish release
command: 'node ./scripts/github/publishRelease.js'
no_output_timeout: 15m
make-release-commit:
working_directory: ~/alexanderzobnin/grafana-zabbix
docker:
- image: circleci/golang:1.13-node
environment:
CI_GIT_USER: CircleCI
CI_GIT_EMAIL: ci@grafana.com
steps:
- add_ssh_keys:
fingerprints:
- "dc:7e:54:e0:aa:56:4d:e5:60:7b:f3:51:24:2d:d3:29"
- checkout
- restore_cache:
keys:
- dependency-cache-npm-{{ checksum "yarn.lock" }}
- restore_cache:
keys:
- dependency-cache-go-{{ checksum "go.sum" }}
- run:
name: Install Dependencies
command: 'make install'
no_output_timeout: 15m
- save_cache:
key: dependency-cache-npm-{{ checksum "yarn.lock" }}
paths:
- ./node_modules
- save_cache:
key: dependency-cache-go-{{ checksum "go.sum" }}
paths:
- ./vendor
- /go/pkg/mod
- run: ./.circleci/make-release.sh
build-docs:
working_directory: ~/grafana-zabbix
docker:
- image: circleci/python:2.7
steps:
- run: sudo pip install --upgrade pip
- run: sudo pip install mkdocs
- checkout
- run: cd docs && mkdocs build --clean
- persist_to_workspace:
root: .
paths:
- docs/site
deploy-docs:
working_directory: ~/grafana-zabbix
docker:
- image: circleci/golang:1.14-node
environment:
GH_PAGES_BRANCH: gh-pages
CI_GIT_USER: CircleCI
CI_GIT_EMAIL: ci@grafana.com
steps:
- add_ssh_keys:
fingerprints:
- "dc:7e:54:e0:aa:56:4d:e5:60:7b:f3:51:24:2d:d3:29"
- checkout
- attach_workspace:
at: ../gh-pages
- run: ./.circleci/deploy-docs.sh
codespell:
docker:
- image: circleci/python
steps:
- checkout
- run: sudo pip install codespell
- run: codespell -S './.git*,./src/img*,./go.sum,./yarn.lock' -L que --ignore-words=./.codespell_ignore
workflows:
version: 2
build-master:
jobs:
- build:
filters: *filter-only-master
- codespell:
filters: *filter-only-master
- lint:
filters: *filter-only-master
- test:
filters: *filter-only-master
build-branches-and-prs:
jobs:
- build:
filters: *filter-not-release-or-master
- codespell:
filters: *filter-not-release-or-master
- lint:
filters: *filter-not-release-or-master
- test:
filters: *filter-not-release-or-master
build-release:
jobs:
- build:
filters: *filter-only-release
- codespell:
filters: *filter-only-release
- lint:
filters: *filter-only-release
- test:
filters: *filter-only-release
- get-plugin:
requires:
- build
- codespell
- lint
- test
filters: *filter-only-release
- package-plugin:
requires:
- get-plugin
filters: *filter-only-release
- make-github-release:
requires:
- package-plugin
filters: *filter-only-release
build-docs:
jobs:
- build-docs:
filters: *filter-docs
- deploy-docs:
requires:
- build-docs
filters: *filter-docs

View File

@@ -1,24 +0,0 @@
#!/bin/bash
# Exit script if you try to use an uninitialized variable.
set -o nounset
# Exit script if a statement returns a non-true return value.
set -o errexit
# Use the error status of the first failure, rather than that of the last item in a pipeline.
set -o pipefail
echo "current dir: $(pwd)"
# Setup git env
git config --global user.email "$CI_GIT_EMAIL"
git config --global user.name "$CI_GIT_USER"
echo "git user is $CI_GIT_USER ($CI_GIT_EMAIL)"
git checkout -b "$GH_PAGES_BRANCH"
rm -rf ./* || true
mv ../gh-pages/docs/site/* ./
git add --force .
git commit -m "build docs from commit ${CIRCLE_SHA1:0:7} (branch $CIRCLE_BRANCH)"
git log -n 3
git push origin "$GH_PAGES_BRANCH" --force

View File

@@ -1,27 +0,0 @@
#!/bin/bash
# Exit script if you try to use an uninitialized variable.
set -o nounset
# Exit script if a statement returns a non-true return value.
set -o errexit
# Use the error status of the first failure, rather than that of the last item in a pipeline.
set -o pipefail
RELEASE_VER=$(echo "$CIRCLE_TAG" | grep -Po "(?<=v)[0-9]+(\.[0-9]+){2}(-.+|[^-.]*)")
if [ -z "$RELEASE_VER" ]; then
echo "No release version provided"
exit 1
fi
if [[ $RELEASE_VER =~ ^[0-9]+(\.[0-9]+){2}(-.+|[^-.]*) ]]; then
echo "Preparing release $RELEASE_VER"
else
echo "Release should has format 1.2.3[-meta], got $RELEASE_VER"
exit 1
fi
# Create zip package
PACKAGE_NAME="grafana-zabbix-${RELEASE_VER}.zip"
echo "packaging into $PACKAGE_NAME"
mv ./dist alexanderzobnin-zabbix-app
zip -r $PACKAGE_NAME ./alexanderzobnin-zabbix-app

View File

@@ -1,42 +0,0 @@
#!/bin/bash
# Exit script if you try to use an uninitialized variable.
set -o nounset
# Exit script if a statement returns a non-true return value.
set -o errexit
# Use the error status of the first failure, rather than that of the last item in a pipeline.
set -o pipefail
# Setup git env
git config --global user.email "$CI_GIT_EMAIL"
git config --global user.name "$CI_GIT_USER"
echo "git user is $CI_GIT_USER ($CI_GIT_EMAIL)"
RELEASE_VER=$(echo "$CIRCLE_TAG" | grep -Po "(?<=v)[0-9]+(\.[0-9]+){2}(-.+|[^-.]*)")
if [ -z "$RELEASE_VER" ]; then
echo "No release version provided"
exit 1
fi
if [[ $RELEASE_VER =~ ^[0-9]+(\.[0-9]+){2}(-.+|[^-.]*) ]]; then
echo "Preparing release $RELEASE_VER"
else
echo "Release should has format 1.2.3[-meta], got $RELEASE_VER"
exit 1
fi
RELEASE_BRANCH=release-$RELEASE_VER
# Build plugin
git checkout -b "$RELEASE_BRANCH"
make clean install dist
# Commit release
git add --force dist/
git commit -m "release $RELEASE_VER"
RELEASE_COMMIT_HASH=$(git log -n 1 | grep -Po "(?<=commit )[0-9a-z]{40}")
echo "$RELEASE_COMMIT_HASH"
# Push release branch
git push origin "$RELEASE_BRANCH"

View File

@@ -1,17 +0,0 @@
coverage:
precision: 2
round: down
range: 50...100
status:
project:
default:
threshold: 5
patch: off
changes: off
comment: off
ignore:
- "dist/test/test-setup/.*"
- "src/test-setup/.*"

View File

@@ -1 +0,0 @@
hist

View File

@@ -1,12 +1,12 @@
/* /*
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️ * ⚠️⚠️⚠️ 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 * In order to extend the configuration follow the steps in
* https://grafana.com/developers/plugin-tools/create-a-plugin/extend-a-plugin/extend-configurations#extend-the-eslint-config
*/ */
{ {
"extends": ["@grafana/eslint-config"], "extends": ["@grafana/eslint-config"],
"root": true, "root": true,
"ignorePatterns": ["**/*.js", "./src/test-setup/**/*.*"],
"rules": { "rules": {
"react/prop-types": "off" "react/prop-types": "off"
} }

View File

@@ -1,6 +1,7 @@
ARG grafana_version=latest ARG grafana_version=latest
ARG grafana_image=grafana-enterprise
FROM grafana/grafana:${grafana_version} FROM grafana/${grafana_image}:${grafana_version}
# Make it as simple as possible to access the grafana instance for development purposes # 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 # Do NOT enable these settings in a public facing / production grafana instance
@@ -12,4 +13,4 @@ ENV GF_DEFAULT_APP_MODE "development"
# Inject livereload script into grafana index.html # Inject livereload script into grafana index.html
USER root USER root
RUN sed -i 's/<\/body><\/html>/<script src=\"http:\/\/localhost:35729\/livereload.js\"><\/script><\/body><\/html>/g' /usr/share/grafana/public/views/index.html RUN sed -i 's/<\/body><\/html>/<script src=\"http:\/\/localhost:35729\/livereload.js\"><\/script><\/body><\/html>/g' /usr/share/grafana/public/views/index.html

View File

@@ -60,7 +60,7 @@ A common issue found with the current jest config involves importing an npm pack
```javascript ```javascript
process.env.TZ = 'UTC'; process.env.TZ = 'UTC';
const { grafanaESModules, nodeModulesToTransform } = require('./jest/utils'); const { grafanaESModules, nodeModulesToTransform } = require('./config/jest/utils');
module.exports = { module.exports = {
// Jest configuration provided by Grafana // Jest configuration provided by Grafana
@@ -139,3 +139,26 @@ We need to update the `scripts` in the `package.json` to use the extended Webpac
-"dev": "webpack -w -c ./.config/webpack/webpack.config.ts --env development", -"dev": "webpack -w -c ./.config/webpack/webpack.config.ts --env development",
+"dev": "webpack -w -c ./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 behaviour simply alter the `docker-compose.yaml` by adding the following build arg `grafana_image`.
**Example:**
```yaml
version: '3.7'
services:
grafana:
container_name: 'myorg-basic-app'
build:
context: ./.config
args:
grafana_version: ${GRAFANA_VERSION:-9.1.2}
grafana_image: ${GRAFANA_IMAGE:-grafana}
```
In this example we are assigning the environment variable `GRAFANA_IMAGE` to the build arg `grafana_image` with a default value of `grafana`. This will give you the possibility to set the value while running the docker-compose commands which might be convinent in some scenarios.
---

View File

@@ -1,7 +1,8 @@
/* /*
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️ * ⚠️⚠️⚠️ 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 * In order to extend the configuration follow the steps in
* https://grafana.com/developers/plugin-tools/create-a-plugin/extend-a-plugin/extend-configurations#extend-the-jest-config
*/ */
import '@testing-library/jest-dom'; import '@testing-library/jest-dom';

View File

@@ -1,7 +1,8 @@
/* /*
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️ * ⚠️⚠️⚠️ 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 * In order to extend the configuration follow the steps in
* https://grafana.com/developers/plugin-tools/create-a-plugin/extend-a-plugin/extend-configurations#extend-the-jest-config
*/ */
const path = require('path'); const path = require('path');
@@ -24,7 +25,7 @@ module.exports = {
'^.+\\.(t|j)sx?$': [ '^.+\\.(t|j)sx?$': [
'@swc/jest', '@swc/jest',
{ {
sourceMaps: true, sourceMaps: 'inline',
jsc: { jsc: {
parser: { parser: {
syntax: 'typescript', syntax: 'typescript',

View File

@@ -8,12 +8,24 @@
* This utility function is useful in combination with jest `transformIgnorePatterns` config * 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. * to transform specific packages (e.g.ES modules) in a projects node_modules folder.
*/ */
const nodeModulesToTransform = (moduleNames) => `node_modules\/(?!(${moduleNames.join('|')})\/)`; const nodeModulesToTransform = (moduleNames) => `node_modules\/(?!.*(${moduleNames.join('|')})\/.*)`;
// Array of known nested grafana package dependencies that only bundle an ESM version // Array of known nested grafana package dependencies that only bundle an ESM version
const grafanaESModules = ['ol', 'react-colorful', 'uuid']; const grafanaESModules = [
'.pnpm', // Support using pnpm symlinked packages
'@grafana/schema',
'd3',
'd3-color',
'd3-force',
'd3-interpolate',
'd3-scale-chromatic',
'ol',
'react-colorful',
'rxjs',
'uuid',
];
module.exports = { module.exports = {
nodeModulesToTransform, nodeModulesToTransform,
grafanaESModules grafanaESModules,
} };

View File

@@ -1,16 +1,17 @@
/* /*
* THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. * 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 * In order to extend the configuration follow the steps in
* https://grafana.com/developers/plugin-tools/create-a-plugin/extend-a-plugin/extend-configurations#extend-the-typescript-config
*/ */
{ {
"compilerOptions": { "compilerOptions": {
"alwaysStrict": true, "alwaysStrict": true,
"declaration": false, "declaration": false,
"rootDir": "../src", "rootDir": "../src",
"baseUrl": "../src", "baseUrl": "../src",
"typeRoots": ["../node_modules/@types"], "typeRoots": ["../node_modules/@types"],
"resolveJsonModule": true, "resolveJsonModule": true
}, },
"ts-node": { "ts-node": {
"compilerOptions": { "compilerOptions": {
@@ -20,6 +21,6 @@
}, },
"transpileOnly": true "transpileOnly": true
}, },
"include": ["../src", "./types", "../test-setup"], "include": ["../src", "./types"],
"extends": "@grafana/tsconfig" "extends": "@grafana/tsconfig"
} }

View File

@@ -1,45 +1,58 @@
import fs from 'fs'; import fs from 'fs';
import process from 'process';
import os from 'os';
import path from 'path'; import path from 'path';
import util from 'util'; import { glob } from 'glob';
import glob from 'glob';
import { SOURCE_DIR } from './constants'; import { SOURCE_DIR } from './constants';
const globAsync = util.promisify(glob); 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;
}
}
export function getPackageJson() { export function getPackageJson() {
return require(path.resolve(process.cwd(), 'package.json')); return require(path.resolve(process.cwd(), 'package.json'));
} }
export function getPluginId() { export function getPluginJson() {
const { id } = require(path.resolve(process.cwd(), `${SOURCE_DIR}/plugin.json`)); return require(path.resolve(process.cwd(), `${SOURCE_DIR}/plugin.json`));
return id;
} }
export function hasReadme() { export function hasReadme() {
return fs.existsSync(path.resolve(process.cwd(), SOURCE_DIR, 'README.md')); 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(): Promise<Record<string, string>> { export async function getEntries(): Promise<Record<string, string>> {
const parent = '..'; const pluginsJson = await glob('**/src/**/plugin.json', { absolute: true });
const pluginsJson = await globAsync('**/src/**/plugin.json');
const plugins = await Promise.all( const plugins = await Promise.all(
pluginsJson.map((pluginJson) => { pluginsJson.map((pluginJson) => {
const folder = path.dirname(pluginJson); const folder = path.dirname(pluginJson);
return globAsync(`${folder}/module.{ts,tsx,js}`); return glob(`${folder}/module.{ts,tsx,js,jsx}`, { absolute: true });
}) })
); );
const entries = plugins.reduce((result, modules) => { return plugins.reduce((result, modules) => {
return modules.reduce((result, module) => { return modules.reduce((result, module) => {
const pluginPath = path.resolve(path.dirname(module), parent); const pluginPath = path.dirname(module);
const pluginName = path.basename(pluginPath); const pluginName = path.relative(process.cwd(), pluginPath).replace(/src\/?/i, '');
const entryName = plugins.length > 1 ? `${pluginName}/module` : 'module'; const entryName = pluginName === '' ? 'module' : `${pluginName}/module`;
result[entryName] = path.join(parent, module); result[entryName] = module;
return result; return result;
}, result); }, result);
}, {}); }, {});
return entries;
} }

View File

@@ -1,7 +1,8 @@
/* /*
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️ * ⚠️⚠️⚠️ 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 * In order to extend the configuration follow the steps in
* https://grafana.com/developers/plugin-tools/create-a-plugin/extend-a-plugin/extend-configurations#extend-the-webpack-config
*/ */
import CopyWebpackPlugin from 'copy-webpack-plugin'; import CopyWebpackPlugin from 'copy-webpack-plugin';
@@ -12,189 +13,200 @@ import path from 'path';
import ReplaceInFileWebpackPlugin from 'replace-in-file-webpack-plugin'; import ReplaceInFileWebpackPlugin from 'replace-in-file-webpack-plugin';
import { Configuration } from 'webpack'; import { Configuration } from 'webpack';
import { getPackageJson, getPluginId, hasReadme, getEntries } from './utils'; import { getPackageJson, getPluginJson, hasReadme, getEntries, isWSL } from './utils';
import { SOURCE_DIR, DIST_DIR } from './constants'; import { SOURCE_DIR, DIST_DIR } from './constants';
const config = async (env): Promise<Configuration> => ({ const pluginJson = getPluginJson();
cache: {
type: 'filesystem', const config = async (env): Promise<Configuration> => {
buildDependencies: { const baseConfig: Configuration = {
config: [__filename], cache: {
type: 'filesystem',
buildDependencies: {
config: [__filename],
},
}, },
},
context: path.join(process.cwd(), SOURCE_DIR), context: path.join(process.cwd(), SOURCE_DIR),
devtool: env.production ? 'source-map' : 'eval-source-map', devtool: env.production ? 'source-map' : 'eval-source-map',
// Entries from getEntries() work incorrect, so declare it manually in root webpack config entry: await getEntries(),
// entry: await getEntries(),
externals: [ externals: [
'lodash', 'lodash',
'jquery', 'jquery',
'moment', 'moment',
'slate', 'slate',
'emotion', 'emotion',
'@emotion/react', '@emotion/react',
'@emotion/css', '@emotion/css',
'prismjs', 'prismjs',
'slate-plain-serializer', 'slate-plain-serializer',
'@grafana/slate-react', '@grafana/slate-react',
'react', 'react',
'react-dom', 'react-dom',
'react-redux', 'react-redux',
'redux', 'redux',
'rxjs', 'rxjs',
'react-router', 'react-router',
'react-router-dom', 'react-router-dom',
'd3', 'd3',
'angular', 'angular',
'@grafana/ui', '@grafana/ui',
'@grafana/runtime', '@grafana/runtime',
'@grafana/data', '@grafana/data',
// Mark legacy SDK imports as external if their name starts with the "grafana/" prefix // Mark legacy SDK imports as external if their name starts with the "grafana/" prefix
({ request }, callback) => { ({ request }, callback) => {
const prefix = 'grafana/'; const prefix = 'grafana/';
const hasPrefix = (request) => request.indexOf(prefix) === 0; const hasPrefix = (request) => request.indexOf(prefix) === 0;
const stripPrefix = (request) => request.substr(prefix.length); const stripPrefix = (request) => request.substr(prefix.length);
if (hasPrefix(request)) { if (hasPrefix(request)) {
return callback(undefined, stripPrefix(request)); return callback(undefined, stripPrefix(request));
} }
callback(); callback();
}, },
], ],
mode: env.production ? 'production' : 'development', mode: env.production ? 'production' : 'development',
module: { module: {
rules: [ rules: [
{ {
exclude: /(node_modules)/, exclude: /(node_modules)/,
test: /\.[tj]sx?$/, test: /\.[tj]sx?$/,
use: { use: {
loader: 'swc-loader', loader: 'swc-loader',
options: { options: {
jsc: { jsc: {
baseUrl: './src', baseUrl: './src',
target: 'es2015', target: 'es2015',
loose: false, loose: false,
parser: { parser: {
syntax: 'typescript', syntax: 'typescript',
tsx: true, tsx: true,
decorators: false, decorators: false,
dynamicImport: true, dynamicImport: true,
},
}, },
}, },
}, },
}, },
}, {
{ test: /\.css$/,
test: /\.css$/, use: ['style-loader', 'css-loader'],
use: ['style-loader', 'css-loader'],
},
{
exclude: /(node_modules)/,
test: /\.s[ac]ss$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
{
test: /\.(png|jpe?g|gif|svg)$/,
type: 'asset/resource',
generator: {
// Keep publicPath relative for host.com/grafana/ deployments
publicPath: `public/plugins/${getPluginId()}/img/`,
outputPath: 'img/',
filename: Boolean(env.production) ? '[hash][ext]' : '[name][ext]',
}, },
}, {
{ test: /\.s[ac]ss$/,
test: /\.(woff|woff2|eot|ttf|otf)(\?v=\d+\.\d+\.\d+)?$/, use: ['style-loader', 'css-loader', 'sass-loader'],
type: 'asset/resource', },
generator: { {
// Keep publicPath relative for host.com/grafana/ deployments test: /\.(png|jpe?g|gif|svg)$/,
publicPath: `public/plugins/${getPluginId()}/fonts`, type: 'asset/resource',
outputPath: 'fonts/', generator: {
filename: Boolean(env.production) ? '[hash][ext]' : '[name][ext]', // Keep publicPath relative for host.com/grafana/ deployments
publicPath: `public/plugins/${pluginJson.id}/img/`,
outputPath: 'img/',
filename: Boolean(env.production) ? '[hash][ext]' : '[name][ext]',
},
},
{
test: /\.(woff|woff2|eot|ttf|otf)(\?v=\d+\.\d+\.\d+)?$/,
type: 'asset/resource',
generator: {
// Keep publicPath relative for host.com/grafana/ deployments
publicPath: `public/plugins/${pluginJson.id}/fonts/`,
outputPath: 'fonts/',
filename: Boolean(env.production) ? '[hash][ext]' : '[name][ext]',
},
}, },
},
],
},
output: {
clean: {
keep: /gpx_.*/,
},
filename: '[name].js',
library: {
type: 'amd',
},
path: path.resolve(process.cwd(), DIST_DIR),
publicPath: '/',
},
plugins: [
new CopyWebpackPlugin({
patterns: [
// 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: '.' }, // TODO<Add an error for checking the basic structure of the repo>
{ from: '**/*.svg', to: '.', noErrorOnMissing: true }, // Optional
{ from: '**/*.png', to: '.', noErrorOnMissing: true }, // Optional
{ from: '**/*.html', to: '.', noErrorOnMissing: true }, // Optional
{ from: 'img/**/*', to: '.', noErrorOnMissing: true }, // Optional
{ from: 'libs/**/*', to: '.', noErrorOnMissing: true }, // Optional
{ from: 'static/**/*', to: '.', noErrorOnMissing: true }, // Optional
], ],
}), },
// Replace certain template-variables in the README and plugin.json
new ReplaceInFileWebpackPlugin([
{
dir: DIST_DIR,
files: ['plugin.json', 'README.md'],
rules: [
{
search: /\%VERSION\%/g,
replace: getPackageJson().version,
},
{
search: /\%TODAY\%/g,
replace: new Date().toISOString().substring(0, 10),
},
{
search: /\%PLUGIN_ID\%/g,
replace: getPluginId(),
},
],
},
]),
new ForkTsCheckerWebpackPlugin({
async: Boolean(env.development),
issue: {
include: [{ file: '**/*.{ts,tsx}' }],
},
typescript: { configFile: path.join(process.cwd(), 'tsconfig.json') },
}),
new ESLintPlugin({
extensions: ['.ts', '.tsx'],
lintDirtyModulesOnly: Boolean(env.development), // don't lint on start, only lint changed files
}),
...(env.development ? [new LiveReloadPlugin()] : []),
],
resolve: { output: {
extensions: ['.js', '.jsx', '.ts', '.tsx'], clean: {
// handle resolving "rootDir" paths keep: new RegExp(`(.*?_(amd64|arm(64)?)(.exe)?|go_plugin_build_manifest)`),
modules: [path.resolve(process.cwd(), 'src'), 'node_modules'], },
unsafeCache: true, filename: '[name].js',
}, library: {
}); type: 'amd',
},
path: path.resolve(process.cwd(), DIST_DIR),
publicPath: '/',
},
plugins: [
new CopyWebpackPlugin({
patterns: [
// 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: '.' }, // TODO<Add an error for checking the basic structure of the repo>
{ from: '**/*.svg', to: '.', noErrorOnMissing: true }, // Optional
{ from: '**/*.png', to: '.', noErrorOnMissing: true }, // Optional
{ from: '**/*.html', to: '.', noErrorOnMissing: true }, // Optional
{ from: 'img/**/*', to: '.', noErrorOnMissing: true }, // Optional
{ from: 'libs/**/*', to: '.', noErrorOnMissing: true }, // Optional
{ from: 'static/**/*', to: '.', noErrorOnMissing: true }, // Optional
],
}),
// Replace certain template-variables in the README and plugin.json
new ReplaceInFileWebpackPlugin([
{
dir: DIST_DIR,
files: ['plugin.json', 'README.md'],
rules: [
{
search: /\%VERSION\%/g,
replace: getPackageJson().version,
},
{
search: /\%TODAY\%/g,
replace: new Date().toISOString().substring(0, 10),
},
{
search: /\%PLUGIN_ID\%/g,
replace: pluginJson.id,
},
],
},
]),
new ForkTsCheckerWebpackPlugin({
async: Boolean(env.development),
issue: {
include: [{ file: '**/*.{ts,tsx}' }],
},
typescript: { configFile: path.join(process.cwd(), 'tsconfig.json') },
}),
new ESLintPlugin({
extensions: ['.ts', '.tsx'],
lintDirtyModulesOnly: Boolean(env.development), // don't lint on start, only lint changed files
}),
...(env.development ? [new LiveReloadPlugin()] : []),
],
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
// handle resolving "rootDir" paths
modules: [path.resolve(process.cwd(), 'src'), 'node_modules'],
unsafeCache: true,
},
};
if (isWSL()) {
baseConfig.watchOptions = {
poll: 3000,
ignored: /node_modules/,
};
}
return baseConfig;
};
export default config; export default config;

View File

@@ -1,5 +1,6 @@
{ {
"extends": "./.config/.eslintrc", "extends": "./.config/.eslintrc",
"ignorePatterns": ["/src/test-setup/**/*"],
"rules": { "rules": {
"react-hooks/exhaustive-deps": "off" "react-hooks/exhaustive-deps": "off"
} }

View File

@@ -1,193 +0,0 @@
name: CI
on:
push:
branches:
- master
- main
pull_request:
branches:
- master
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Node.js environment
uses: actions/setup-node@v2.1.2
with:
node-version: '16.x'
- name: Setup Go environment
uses: actions/setup-go@v3
with:
go-version: '1.19'
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Cache yarn cache
uses: actions/cache@v2
id: cache-yarn-cache
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Cache node_modules
id: cache-node-modules
uses: actions/cache@v2
with:
path: node_modules
key: ${{ runner.os }}-${{ matrix.node-version }}-nodemodules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ matrix.node-version }}-nodemodules-
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Build frontend
run: yarn build
- name: Build backend
if: steps.check-for-backend.outputs.has-backend == 'true'
uses: magefile/mage-action@v1
with:
version: latest
args: buildAll
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Node.js environment
uses: actions/setup-node@v2.1.2
with:
node-version: '16.x'
- name: Setup Go environment
uses: actions/setup-go@v3
with:
go-version: '1.19'
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Cache yarn cache
uses: actions/cache@v2
id: cache-yarn-cache
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Cache node_modules
id: cache-node-modules
uses: actions/cache@v2
with:
path: node_modules
key: ${{ runner.os }}-${{ matrix.node-version }}-nodemodules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ matrix.node-version }}-nodemodules-
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Test backend
if: steps.check-for-backend.outputs.has-backend == 'true'
uses: magefile/mage-action@v1
with:
version: latest
args: coverage
- name: Test frontend
run: yarn test:ci
e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js environment
uses: actions/setup-node@v3
with:
node-version: '16'
cache: 'yarn'
- name: Install dependencies
run: yarn install --immutable --prefer-offline
- name: Build frontend
run: yarn build
- name: Setup Go environment
if: steps.check-for-backend.outputs.has-backend == 'true'
uses: actions/setup-go@v3
with:
go-version: '1.19'
- name: Build backend
if: steps.check-for-backend.outputs.has-backend == 'true'
uses: magefile/mage-action@v1
with:
version: latest
args: buildAll
- name: Start grafana docker
run: yarn server -d
- name: Run e2e tests
run: yarn e2e
- name: Stop grafana docker
run: yarn server:stop
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Node.js environment
uses: actions/setup-node@v2.1.2
with:
node-version: '16.x'
- name: Setup Go environment
uses: actions/setup-go@v2
with:
go-version: '1.19'
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Cache yarn cache
uses: actions/cache@v2
id: cache-yarn-cache
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Cache node_modules
id: cache-node-modules
uses: actions/cache@v2
with:
path: node_modules
key: ${{ runner.os }}-${{ matrix.node-version }}-nodemodules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ matrix.node-version }}-nodemodules-
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Install golint
run: GO111MODULE=off go get -u golang.org/x/lint/golint
- name: Lint frontend
run: yarn lint
- name: Lint backend
run: golint -min_confidence=1.1 -set_exit_status pkg/...

3
.gitignore vendored
View File

@@ -41,8 +41,7 @@ dist/
ci/ ci/
alexanderzobnin-zabbix-app.zip alexanderzobnin-zabbix-app.zip
# Grafana toolkit configs .eslintcache
# .prettierrc.js
# locally required config files # locally required config files
public/css/*.min.css public/css/*.min.css

View File

@@ -1,10 +0,0 @@
import { e2e } from '@grafana/e2e';
e2e.scenario({
describeName: 'Smoke test',
itName: 'Smoke test',
scenario: () => {
e2e.pages.Home.visit();
e2e().contains('Welcome to Grafana').should('be.visible');
},
});

View File

@@ -3,7 +3,7 @@ version: "3"
services: services:
# Grafana # Grafana
grafana: grafana:
image: grafana/grafana:8.4.7 image: grafana/grafana:10.1.2
ports: ports:
- "3001:3000" - "3001:3000"
volumes: volumes:
@@ -48,7 +48,7 @@ services:
POSTGRES_DB: zabbix POSTGRES_DB: zabbix
database: database:
image: postgres image: postgres:15
ports: ports:
- "15432:5432" - "15432:5432"
command: postgres -c 'max_connections=1000' command: postgres -c 'max_connections=1000'

View File

@@ -1,137 +1,98 @@
{ {
"name": "grafana-zabbix", "name": "grafana-zabbix",
"private": false,
"version": "4.4.1", "version": "4.4.1",
"description": "Zabbix plugin for Grafana", "description": "Zabbix plugin for Grafana",
"homepage": "http://grafana-zabbix.org", "homepage": "http://grafana-zabbix.org",
"scripts": { "bugs": {
"build": "webpack -c ./webpack.config.ts --env production", "url": "https://github.com/alexanderzobnin/grafana-zabbix/issues"
"dev": "webpack -w -c ./webpack.config.ts --env development",
"test": "jest --watch --onlyChanged",
"test:ci": "jest --maxWorkers 4",
"typecheck": "tsc --noEmit",
"lint": "eslint --cache --ignore-path ./.gitignore --ext .js,.jsx,.ts,.tsx .",
"lint:fix": "yarn lint --fix",
"e2e": "yarn cypress install && yarn grafana-e2e run",
"e2e:update": "yarn cypress install && yarn grafana-e2e run --update-screenshots",
"server": "docker-compose --file ./devenv/default/docker-compose.yml up --build",
"server:stop": "docker-compose --file ./devenv/default/docker-compose.yml stop",
"server:down": "docker-compose --file ./devenv/default/docker-compose.yml down",
"sign": "grafana-toolkit plugin:sign",
"spellcheck": "cspell -c cspell.config.json \"**/*.{ts,tsx,js,go,md,mdx,yml,yaml,json,scss,css}\""
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/alexanderzobnin/grafana-zabbix.git" "url": "git+https://github.com/alexanderzobnin/grafana-zabbix.git"
}, },
"author": "Alexander Zobnin",
"license": "Apache-2.0", "license": "Apache-2.0",
"bugs": { "author": "Alexander Zobnin",
"url": "https://github.com/alexanderzobnin/grafana-zabbix/issues" "scripts": {
"build": "webpack -c ./webpack.config.ts --env production",
"dev": "webpack -w -c ./webpack.config.ts --env development",
"e2e": "yarn exec cypress install && yarn exec grafana-e2e run",
"e2e:update": "yarn exec cypress install && yarn exec grafana-e2e run --update-screenshots",
"lint": "eslint --cache --ignore-path ./.gitignore --ext .js,.jsx,.ts,.tsx .",
"lint:fix": "yarn run lint --fix",
"server": "docker-compose up --build",
"server:down": "docker-compose --file ./devenv/default/docker-compose.yml down",
"server:stop": "docker-compose --file ./devenv/default/docker-compose.yml stop",
"sign": "npx --yes @grafana/sign-plugin@latest",
"spellcheck": "cspell -c cspell.config.json \"**/*.{ts,tsx,js,go,md,mdx,yml,yaml,json,scss,css}\"",
"test": "jest --watch --onlyChanged",
"test:ci": "jest --passWithNoTests --maxWorkers 4",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@emotion/css": "^11.1.3",
"@grafana/data": "10.1.2",
"@grafana/runtime": "10.1.2",
"@grafana/ui": "10.1.2",
"react": "17.0.2",
"react-dom": "17.0.2",
"tslib": "2.5.3"
}, },
"devDependencies": { "devDependencies": {
"@emotion/css": "11.1.3", "@babel/core": "^7.21.4",
"@emotion/react": "11.1.5", "@grafana/eslint-config": "^6.0.0",
"@grafana/data": "9.3.2",
"@grafana/e2e": "9.2.5",
"@grafana/e2e-selectors": "9.2.5",
"@grafana/eslint-config": "^5.1.0",
"@grafana/runtime": "9.3.2",
"@grafana/toolkit": "9.1.2",
"@grafana/tsconfig": "^1.2.0-rc1", "@grafana/tsconfig": "^1.2.0-rc1",
"@grafana/ui": "9.3.2", "@swc/core": "1.3.75",
"@popperjs/core": "2.4.0", "@swc/helpers": "^0.5.0",
"@swc/core": "^1.2.144", "@swc/jest": "^0.2.26",
"@swc/helpers": "^0.4.12", "@testing-library/jest-dom": "^5.16.5",
"@swc/jest": "^0.2.23",
"@testing-library/jest-dom": "^5.16.2",
"@testing-library/react": "^12.1.4", "@testing-library/react": "^12.1.4",
"@types/classnames": "2.2.9",
"@types/glob": "^8.0.0", "@types/glob": "^8.0.0",
"@types/grafana": "github:CorpGlory/types-grafana", "@types/grafana": "github:CorpGlory/types-grafana",
"@types/jest": "^29.2.2", "@types/jest": "^29.5.0",
"@types/jquery": "3.3.32", "@types/lodash": "^4.14.194",
"@types/lodash": "^4.14.188", "@types/node": "^18.15.11",
"@types/node": "^18.11.9", "@typescript-eslint/eslint-plugin": "5.59.5",
"@types/react": "17.0.42", "@typescript-eslint/parser": "5.59.5",
"@types/react-dom": "17.0.14",
"@types/react-router-dom": "^5.3.3",
"@types/react-transition-group": "4.2.4",
"@typescript-eslint/eslint-plugin": "^5.42.1",
"@typescript-eslint/parser": "^5.42.1",
"autoprefixer": "10.4.7", "autoprefixer": "10.4.7",
"axios": "^0.21.1",
"benchmark": "^2.1.4",
"classnames": "2.2.6",
"clean-webpack-plugin": "^0.1.19", "clean-webpack-plugin": "^0.1.19",
"codecov": "^3.1.0",
"copy-webpack-plugin": "^11.0.0", "copy-webpack-plugin": "^11.0.0",
"cspell": "6.13.3", "cspell": "6.13.3",
"css-loader": "^6.7.1", "css-loader": "^6.7.3",
"eslint": "8.26.0", "eslint": "8.42.0",
"eslint-config-prettier": "^8.3.0", "eslint-plugin-jsdoc": "^46.8.2",
"eslint-plugin-jsdoc": "^39.6.2", "eslint-plugin-react": "^7.33.2",
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react": "^7.26.1", "eslint-webpack-plugin": "^4.0.1",
"eslint-plugin-react-hooks": "^4.2.0", "fork-ts-checker-webpack-plugin": "^8.0.0",
"eslint-webpack-plugin": "^3.1.1", "glob": "^10.2.7",
"fork-ts-checker-webpack-plugin": "^7.2.0",
"glob": "^8.0.3",
"html-loader": "0.5.5", "html-loader": "0.5.5",
"identity-obj-proxy": "3.0.0", "identity-obj-proxy": "3.0.0",
"jest": "^29.3.1", "jest": "^29.5.0",
"jest-environment-jsdom": "^29.3.1", "jest-environment-jsdom": "^29.5.0",
"jest-environment-jsdom-fifteen": "^1.0.2",
"jscs": "^3.0.7",
"jsdom": "~11.3.0",
"jshint": "^2.9.6",
"jshint-stylish": "^2.1.0",
"lodash": "4.17.21", "lodash": "4.17.21",
"memoize-one": "5.1.1",
"mini-css-extract-plugin": "2.6.1", "mini-css-extract-plugin": "2.6.1",
"moment": "2.24.0", "moment": "2.29.4",
"node-sass": "^7.0.1",
"postcss": "8.4.14", "postcss": "8.4.14",
"postcss-loader": "7.0.1", "postcss-loader": "7.0.1",
"postcss-reporter": "7.0.5", "postcss-reporter": "7.0.5",
"postcss-scss": "4.0.4", "postcss-scss": "4.0.4",
"prettier": "^2.5.0", "prettier": "^2.8.7",
"prop-types": "15.7.2", "prop-types": "15.7.2",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-popper": "^2.2.3",
"react-table-6": "6.11.0", "react-table-6": "6.11.0",
"react-test-renderer": "17.0.2",
"react-transition-group": "4.3.0",
"react-use": "17.4.0", "react-use": "17.4.0",
"replace-in-file-webpack-plugin": "^1.0.6", "replace-in-file-webpack-plugin": "^1.0.6",
"rxjs": "6.6.3", "sass": "1.63.2",
"sass": "1.56.1", "sass-loader": "13.3.1",
"sass-loader": "13.2.0", "semver": "7.5.4",
"semver": "^7.3.2", "style-loader": "3.3.3",
"style-loader": "3.3.1",
"swc-loader": "^0.2.3", "swc-loader": "^0.2.3",
"tether-drop": "^1.4.2", "ts-node": "^10.9.1",
"ts-jest": "26.4.1", "tsconfig-paths": "^4.2.0",
"ts-loader": "4.4.1", "typescript": "4.8.4",
"ts-node": "^10.5.0", "webpack": "^5.86.0",
"tsconfig-paths": "^4.1.0", "webpack-cli": "^5.1.4",
"tslint": "^6.1.3",
"typescript": "4.8.2",
"webpack": "^5.69.1",
"webpack-cli": "^4.9.2",
"webpack-livereload-plugin": "^3.0.2", "webpack-livereload-plugin": "^3.0.2",
"webpack-remove-empty-scripts": "^1.0.1" "webpack-remove-empty-scripts": "^1.0.1"
}, },
"engines": { "packageManager": "yarn@1.22.19"
"node": ">=16"
},
"resolutions": {
"js-yaml": "^3.13.1",
"lodash": "~4.17.13",
"set-value": "^2.0.1",
"mixin-deep": "^1.3.2",
"minimatch": "^3.0.2",
"fstream": "^1.0.12"
}
} }

View File

@@ -1,31 +0,0 @@
const axios = require('axios');
const githubURL = (owner, repo) => `https://api.github.com/repos/${owner}/${repo}`;
class GithubClient {
constructor(owner, repo, required = false) {
const username = process.env.GITHUB_USERNAME;
const token = process.env.GITHUB_ACCESS_TOKEN;
const clientConfig = {
baseURL: githubURL(owner, repo),
timeout: 30000,
};
if (required && (!username || !token)) {
throw new Error('operation needs a GITHUB_USERNAME and GITHUB_ACCESS_TOKEN environment variables');
}
if (username && token) {
clientConfig.auth = { username: username, password: token };
}
this.client = this.createClient(clientConfig);
}
createClient(clientConfig) {
return axios.create(clientConfig);
}
}
module.exports = GithubClient;

View File

@@ -1,153 +0,0 @@
const GithubClient = require('./githubClient');
const fs = require('fs');
const path = require('path');
const GRAFANA_ZABBIX_OWNER = 'grafana';
const GRAFANA_ZABBIX_REPO = 'grafana-zabbix';
const github = new GithubClient(GRAFANA_ZABBIX_OWNER, GRAFANA_ZABBIX_REPO, true);
async function main() {
let releaseVersion = '';
if (process.env.CIRCLE_TAG) {
const tag = process.env.CIRCLE_TAG;
const tagRegex = /v[0-9]+(\.[0-9]+){2}(-.+|[^-.]*)/;
if (!tagRegex.test(tag)) {
console.error(`Release tag should has format v1.2.3[-meta], got ${tag}`);
process.exit(1);
}
releaseVersion = tag.slice(1);
} else {
releaseVersion = getPluginVersion();
}
console.log('Release version', releaseVersion);
if (!releaseVersion) {
console.error('Release not found');
process.exit(1);
}
const releaseNotes = `# Grafana-Zabbix ${releaseVersion}`;
const preRelease = /(alpha|beta)/.test(releaseVersion);
let releaseId;
try {
const latestRelease = await github.client.get(`releases/tags/v${releaseVersion}`);
releaseId = latestRelease.data.id;
console.log('Release found', releaseId);
} catch (reason) {
if (reason.response.status !== 404) {
// 404 just means no release found. Not an error. Anything else though, re throw the error
console.error(reason.response.data);
process.exit(1);
}
}
if (!releaseId) {
console.log('No release exist, finding a tag');
let releaseCommitHash;
try {
const tags = await github.client.get(`tags`);
const releaseTag = tags.data.find((t) => t.name === `v${releaseVersion}`);
releaseCommitHash = releaseTag.commit.sha;
console.log('Tag found', releaseTag.name, releaseCommitHash);
} catch (reason) {
if (reason.response.status !== 404) {
// 404 just means no release found. Not an error. Anything else though, re throw the error
console.error(reason.response.data);
process.exit(1);
} else {
console.error('No release tag found');
process.exit(1);
}
}
try {
const newReleaseResponse = await github.client.post('releases', {
tag_name: `v${releaseVersion}`,
target_commitish: releaseCommitHash,
name: `${releaseVersion}`,
body: releaseNotes,
draft: false,
prerelease: preRelease,
});
releaseId = newReleaseResponse.data.id;
console.log('Release published with id', releaseId);
} catch (reason) {
console.error(reason.response.data);
process.exit(1);
}
} else {
try {
github.client.patch(`releases/${releaseId}`, {
tag_name: `v${releaseVersion}`,
name: `${releaseVersion}`,
body: releaseNotes,
draft: false,
prerelease: preRelease,
});
} catch (reason) {
console.error(reason.response.data);
process.exit(1);
}
}
try {
await publishAssets(
`alexanderzobnin-zabbix-app-${releaseVersion}.zip`,
`https://uploads.github.com/repos/${GRAFANA_ZABBIX_OWNER}/${GRAFANA_ZABBIX_REPO}/releases/${releaseId}/assets`
);
// Upload package info with md5 checksum
await publishAssets(
`info.json`,
`https://uploads.github.com/repos/${GRAFANA_ZABBIX_OWNER}/${GRAFANA_ZABBIX_REPO}/releases/${releaseId}/assets`
);
} catch (reason) {
console.error(reason);
process.exit(1);
}
}
async function publishAssets(fileName, destUrl) {
// Add the assets. Loop through files in the ci/dist folder and upload each asset.
const fileStat = fs.statSync(`${__dirname}/../../ci/packages/${fileName}`);
const fileData = fs.readFileSync(`${__dirname}/../../ci/packages/${fileName}`);
return await github.client.post(`${destUrl}?name=${fileName}`, fileData, {
headers: {
'Content-Type': resolveContentType(path.extname(fileName)),
'Content-Length': fileStat.size,
},
maxContentLength: fileStat.size * 2 * 1024 * 1024,
maxBodyLength: fileStat.size * 2 * 1024 * 1024,
});
}
const resolveContentType = (extension) => {
if (extension.startsWith('.')) {
extension = extension.substr(1);
}
switch (extension) {
case 'zip':
return 'application/zip';
case 'json':
return 'application/json';
case 'sha1':
return 'text/plain';
default:
return 'application/octet-stream';
}
};
const getPluginVersion = () => {
const pkg = fs.readFileSync(`${__dirname}/../../package.json`, 'utf8');
const { version } = JSON.parse(pkg);
if (!version) {
throw `Could not find the toolkit version`;
}
return version;
};
main();

View File

@@ -1,8 +0,0 @@
#!/bin/bash
# Exit script if a statement returns a non-true return value.
set -o errexit
# Use the error status of the first failure, rather than that of the last item in a pipeline.
set -o pipefail
node ./scripts/github/publishRelease.js

View File

@@ -1,38 +0,0 @@
#!/bin/bash
# Exit script if a statement returns a non-true return value.
set -o errexit
# Use the error status of the first failure, rather than that of the last item in a pipeline.
set -o pipefail
GREEN='\033[0;32m'
BLUE='\033[0;34m'
RED='\033[0;31m'
NC='\033[0m' # No Color
if [ -z "$GRAFANA_API_KEY" ]
then
echo -e "${RED}Error: \$GRAFANA_API_KEY variable should be set to sign plugin${NC}"
exit 1
fi
# Install Dependencies
echo -e "${GREEN}Installing dependencies${NC}"
make install
# Build plugin for all platforms
echo -e "${GREEN}Building plugin for all platforms${NC}"
make dist
# Prepare plugin for packaging
echo -e "${GREEN}Preparing plugin for packaging${NC}"
rm -rf ci/jobs/build_plugin/dist
mkdir -p ci/jobs/build_plugin
mv dist/ ci/jobs/build_plugin
cp CHANGELOG.md ci/jobs/build_plugin/dist
# Package and sign plugin
echo -e "${GREEN}Packaging and signing plugin${NC}"
yarn grafana-toolkit plugin:ci-package
echo -e "${GREEN}Packaged plugin located in ${BLUE}ci/packages${NC}"

View File

@@ -1,4 +1,4 @@
import React, { FC } from 'react'; import React, { PropsWithChildren } from 'react';
import { cx, css } from '@emotion/css'; import { cx, css } from '@emotion/css';
import { stylesFactory, useTheme, Tooltip } from '@grafana/ui'; import { stylesFactory, useTheme, Tooltip } from '@grafana/ui';
import { GrafanaTheme, GrafanaThemeType } from '@grafana/data'; import { GrafanaTheme, GrafanaThemeType } from '@grafana/data';
@@ -12,14 +12,16 @@ interface Props {
onClick(event: React.MouseEvent<HTMLButtonElement>): void; onClick(event: React.MouseEvent<HTMLButtonElement>): void;
} }
export const ActionButton: FC<Props> = ({ icon, width, tooltip, className, children, onClick }) => { export const ActionButton = ({ icon, width, tooltip, className, children, onClick }: PropsWithChildren<Props>) => {
const theme = useTheme(); const theme = useTheme();
const styles = getStyles(theme); const styles = getStyles(theme);
const buttonClass = cx( const buttonClass = cx(
'btn', 'btn',
styles.button, styles.button,
css`width: ${width || 3}rem`, css`
className, width: ${width || 3}rem;
`,
className
); );
let button = ( let button = (

View File

@@ -25,8 +25,10 @@ jest.mock('../components/AnnotationQueryEditor', () => ({
describe('ZabbixDatasource', () => { describe('ZabbixDatasource', () => {
let ctx: any = {}; let ctx: any = {};
let consoleSpy: jest.SpyInstance;
beforeEach(() => { beforeEach(() => {
consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
ctx.instanceSettings = { ctx.instanceSettings = {
jsonData: { jsonData: {
alerting: false, alerting: false,
@@ -60,6 +62,10 @@ describe('ZabbixDatasource', () => {
ctx.ds.templateSrv = templateSrvMock; ctx.ds.templateSrv = templateSrvMock;
}); });
afterEach(() => {
consoleSpy.mockRestore();
});
describe('When querying text data', () => { describe('When querying text data', () => {
beforeEach(() => { beforeEach(() => {
ctx.ds.replaceTemplateVars = (str) => str; ctx.ds.replaceTemplateVars = (str) => str;

View File

@@ -56,7 +56,6 @@ export class CachingProxy {
* with same params when waiting for result. * with same params when waiting for result.
*/ */
function callOnce(func, promiseKeeper, funcScope) { function callOnce(func, promiseKeeper, funcScope) {
// tslint:disable-next-line: only-arrow-functions
return function () { return function () {
const hash = getRequestHash(arguments); const hash = getRequestHash(arguments);
if (!promiseKeeper[hash]) { if (!promiseKeeper[hash]) {
@@ -78,7 +77,6 @@ function callOnce(func, promiseKeeper, funcScope) {
} }
function cacheRequest(func, funcName, funcScope, self) { function cacheRequest(func, funcName, funcScope, self) {
// tslint:disable-next-line: only-arrow-functions
return function () { return function () {
if (!self.cache[funcName]) { if (!self.cache[funcName]) {
self.cache[funcName] = {}; self.cache[funcName] = {};

View File

@@ -1,108 +0,0 @@
import { Zabbix } from './zabbix';
jest.mock('@grafana/runtime', () => ({
getBackendSrv: () => ({
datasourceRequest: jest.fn().mockResolvedValue({data: {result: ''}}),
}),
getBackendSrv: () => ({
datasourceRequest: jest.fn().mockResolvedValue({ data: { result: '' } }),
fetch: () => ({
toPromise: () => jest.fn().mockResolvedValue({ data: { result: '' } })
}),
}),
}), {virtual: true});
describe('Zabbix', () => {
let ctx = {};
let zabbix;
let options = {
url: 'http://localhost',
username: 'zabbix',
password: 'zabbix',
};
beforeEach(() => {
ctx.options = options;
// ctx.backendSrv = mocks.backendSrvMock;
// ctx.datasourceSrv = mocks.datasourceSrvMock;
zabbix = new Zabbix(ctx.options);
});
describe('When querying proxies', () => {
beforeEach(() => {
zabbix.zabbixAPI.getProxies = jest.fn().mockResolvedValue([
{ host: 'proxy-foo', proxyid: '10101' },
{ host: 'proxy-bar', proxyid: '10102' },
]);
});
it("should return all proxies if filter set to /.*/", done => {
zabbix.getFilteredProxies('/.*/').then(proxies => {
expect(proxies).toMatchObject([{ host: 'proxy-foo' }, { host: 'proxy-bar' }]);
done();
});
});
it("should return matched proxies if regex filter used", done => {
zabbix.getFilteredProxies('/.*-foo/').then(proxies => {
expect(proxies).toMatchObject([{ host: 'proxy-foo' }]);
done();
});
});
it("should return matched proxies if simple filter used", done => {
zabbix.getFilteredProxies('proxy-bar').then(proxies => {
expect(proxies).toMatchObject([{ host: 'proxy-bar' }]);
done();
});
});
it("should return empty list for empty filter", done => {
zabbix.getFilteredProxies('').then(proxies => {
expect(proxies).toEqual([]);
done();
});
});
});
describe('When filtering triggers by proxy', () => {
beforeEach(() => {
zabbix.zabbixAPI.getProxies = jest.fn().mockResolvedValue([
{ host: 'proxy-foo', proxyid: '10101' },
{ host: 'proxy-bar', proxyid: '10102' },
]);
ctx.triggers = [
{ triggerid: '1', hosts: [{ name: 'backend01', proxy_hostid: '0' }] },
{ triggerid: '2', hosts: [{ name: 'backend02', proxy_hostid: '0' }] },
{ triggerid: '3', hosts: [{ name: 'frontend01', proxy_hostid: '10101' }] },
{ triggerid: '4', hosts: [{ name: 'frontend02', proxy_hostid: '10101' }] },
{ triggerid: '5', hosts: [{ name: 'db01', proxy_hostid: '10102' }] },
{ triggerid: '6', hosts: [{ name: 'db02', proxy_hostid: '10102' }] },
];
});
it("should return all triggers for empty filter", done => {
zabbix.filterTriggersByProxy(ctx.triggers, '').then(triggers => {
const triggerids = triggers.map(t => t.triggerid);
expect(triggerids).toEqual(['1', '2', '3', '4', '5', '6']);
done();
});
});
it("should return triggers belonging proxy matched regex filter", done => {
zabbix.filterTriggersByProxy(ctx.triggers, '/.*-foo/').then(triggers => {
const triggerids = triggers.map(t => t.triggerid);
expect(triggerids).toEqual(['3', '4']);
done();
});
});
it("should return triggers belonging proxy matched name filter", done => {
zabbix.filterTriggersByProxy(ctx.triggers, 'proxy-bar').then(triggers => {
const triggerids = triggers.map(t => t.triggerid);
expect(triggerids).toEqual(['5', '6']);
done();
});
});
});
});

View File

@@ -0,0 +1,113 @@
import { Zabbix } from './zabbix';
jest.mock(
'@grafana/runtime',
() => ({
getBackendSrv: () => ({
datasourceRequest: jest.fn().mockResolvedValue({ data: { result: '' } }),
fetch: () => ({
toPromise: () => jest.fn().mockResolvedValue({ data: { result: '' } }),
}),
}),
}),
{ virtual: true }
);
describe('Zabbix', () => {
let consoleSpy: jest.SpyInstance;
let ctx = {
options: {
url: 'http://localhost',
username: 'zabbix',
password: 'zabbix',
},
};
let zabbix;
beforeEach(() => {
zabbix = new Zabbix(ctx.options);
consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
});
afterEach(() => {
consoleSpy.mockRestore();
});
describe('When querying proxies', () => {
beforeEach(() => {
zabbix.zabbixAPI.getProxies = jest.fn().mockResolvedValue([
{ host: 'proxy-foo', proxyid: '10101' },
{ host: 'proxy-bar', proxyid: '10102' },
]);
});
it('should return all proxies if filter set to /.*/', (done) => {
zabbix.getFilteredProxies('/.*/').then((proxies) => {
expect(proxies).toMatchObject([{ host: 'proxy-foo' }, { host: 'proxy-bar' }]);
done();
});
});
it('should return matched proxies if regex filter used', (done) => {
zabbix.getFilteredProxies('/.*-foo/').then((proxies) => {
expect(proxies).toMatchObject([{ host: 'proxy-foo' }]);
done();
});
});
it('should return matched proxies if simple filter used', (done) => {
zabbix.getFilteredProxies('proxy-bar').then((proxies) => {
expect(proxies).toMatchObject([{ host: 'proxy-bar' }]);
done();
});
});
it('should return empty list for empty filter', (done) => {
zabbix.getFilteredProxies('').then((proxies) => {
expect(proxies).toEqual([]);
done();
});
});
});
describe('When filtering triggers by proxy', () => {
const triggers = [
{ triggerid: '1', hosts: [{ name: 'backend01', proxy_hostid: '0' }] },
{ triggerid: '2', hosts: [{ name: 'backend02', proxy_hostid: '0' }] },
{ triggerid: '3', hosts: [{ name: 'frontend01', proxy_hostid: '10101' }] },
{ triggerid: '4', hosts: [{ name: 'frontend02', proxy_hostid: '10101' }] },
{ triggerid: '5', hosts: [{ name: 'db01', proxy_hostid: '10102' }] },
{ triggerid: '6', hosts: [{ name: 'db02', proxy_hostid: '10102' }] },
];
beforeEach(() => {
zabbix.zabbixAPI.getProxies = jest.fn().mockResolvedValue([
{ host: 'proxy-foo', proxyid: '10101' },
{ host: 'proxy-bar', proxyid: '10102' },
]);
});
it('should return all triggers for empty filter', (done) => {
zabbix.filterTriggersByProxy(triggers, '').then((triggers) => {
const triggerids = triggers.map((t) => t.triggerid);
expect(triggerids).toEqual(['1', '2', '3', '4', '5', '6']);
done();
});
});
it('should return triggers belonging proxy matched regex filter', (done) => {
zabbix.filterTriggersByProxy(triggers, '/.*-foo/').then((triggers) => {
const triggerids = triggers.map((t) => t.triggerid);
expect(triggerids).toEqual(['3', '4']);
done();
});
});
it('should return triggers belonging proxy matched name filter', (done) => {
zabbix.filterTriggersByProxy(triggers, 'proxy-bar').then((triggers) => {
const triggerids = triggers.map((t) => t.triggerid);
expect(triggerids).toEqual(['5', '6']);
done();
});
});
});
});

View File

@@ -2,8 +2,7 @@ import React, { PureComponent } from 'react';
import { cx } from '@emotion/css'; import { cx } from '@emotion/css';
import ReactTable from 'react-table-6'; import ReactTable from 'react-table-6';
import _ from 'lodash'; import _ from 'lodash';
// eslint-disable-next-line import moment from 'moment-timezone';
import moment from 'moment';
import { isNewProblem } from '../../utils'; import { isNewProblem } from '../../utils';
import { EventTag } from '../EventTag'; import { EventTag } from '../EventTag';
import { ProblemDetails } from './ProblemDetails'; import { ProblemDetails } from './ProblemDetails';

View File

@@ -1,12 +1,5 @@
// JSHint options
/* globals global: false */
import { JSDOM } from 'jsdom';
import { PanelCtrl, MetricsPanelCtrl } from './panelStub'; import { PanelCtrl, MetricsPanelCtrl } from './panelStub';
// Suppress messages
console.log = () => {};
jest.mock('grafana/app/features/templating/template_srv', () => { jest.mock('grafana/app/features/templating/template_srv', () => {
return {}; return {};
}, {virtual: true}); }, {virtual: true});
@@ -82,8 +75,6 @@ jest.mock('grafana/app/core/config', () => {
}; };
}, {virtual: true}); }, {virtual: true});
jest.mock('jquery', () => 'module not found', {virtual: true});
jest.mock('grafana/app/core/utils/kbn', () => { jest.mock('grafana/app/core/utils/kbn', () => {
return { return {
round_interval: n => n, round_interval: n => n,
@@ -91,12 +82,6 @@ jest.mock('grafana/app/core/utils/kbn', () => {
}; };
}, {virtual: true}); }, {virtual: true});
// Setup jsdom
let dom = new JSDOM('<html><head><script></script></head><body></body></html>');
global.window = dom.window;
global.document = global.window.document;
global.Node = window.Node;
// Mock Canvas.getContext(), fixes // Mock Canvas.getContext(), fixes
// Error: Not implemented: HTMLCanvasElement.prototype.getContext (without installing the canvas npm package) // Error: Not implemented: HTMLCanvasElement.prototype.getContext (without installing the canvas npm package)
window.HTMLCanvasElement.prototype.getContext = () => {}; // window.HTMLCanvasElement.prototype.getContext = () => {};

17113
yarn.lock

File diff suppressed because it is too large Load Diff