@grafana/create-plugin 4.10.0-canary.871.d9a32f7.0 → 4.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/dist/commands/generate.command.js +6 -37
- package/dist/commands/migrate.command.js +2 -1
- package/dist/commands/provisioning.command.js +2 -1
- package/dist/utils/utils.handlebars.js +3 -3
- package/dist/utils/utils.templates.js +62 -28
- package/fixtures/test-template/src/plugin.json +1 -1
- package/package.json +2 -2
- package/src/commands/generate/print-success-message.ts +2 -2
- package/src/commands/generate/prompt-user.ts +5 -5
- package/src/commands/generate.command.ts +7 -43
- package/src/commands/migrate.command.ts +2 -1
- package/src/commands/provisioning.command.ts +2 -2
- package/src/types.ts +10 -1
- package/src/utils/utils.handlebars.ts +3 -2
- package/src/utils/utils.templates.ts +77 -32
- package/templates/app/README.md +1 -1
- package/templates/app/provisioning/plugins/apps.yaml +1 -1
- package/templates/app/src/plugin.json +1 -1
- package/templates/backend/pkg/main.go +2 -2
- package/templates/backend-app/pkg/main.go +1 -1
- package/templates/common/.config/webpack/webpack.config.ts +2 -3
- package/templates/common/_package.json +1 -1
- package/templates/common/src/README.md +1 -1
- package/templates/datasource/README.md +1 -1
- package/templates/datasource/provisioning/datasources/datasources.yml +1 -1
- package/templates/datasource/src/plugin.json +1 -1
- package/templates/panel/README.md +1 -1
- package/templates/panel/src/plugin.json +1 -1
- package/templates/scenes-app/provisioning/plugins/app.yaml +1 -1
- package/templates/scenes-app/src/plugin.json +1 -1
- package/dist/commands/types.js +0 -1
- package/src/commands/types.ts +0 -24
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,33 @@
|
|
|
1
|
+
# v4.10.0 (Mon May 06 2024)
|
|
2
|
+
|
|
3
|
+
#### 🚀 Enhancement
|
|
4
|
+
|
|
5
|
+
- Webpack: Generate meta-data using the plugin-meta-extractor during builds [#871](https://github.com/grafana/plugin-tools/pull/871) ([@leventebalogh](https://github.com/leventebalogh))
|
|
6
|
+
|
|
7
|
+
#### Authors: 1
|
|
8
|
+
|
|
9
|
+
- Levente Balogh ([@leventebalogh](https://github.com/leventebalogh))
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# v4.9.2 (Fri May 03 2024)
|
|
14
|
+
|
|
15
|
+
#### 🐛 Bug Fix
|
|
16
|
+
|
|
17
|
+
- Create-plugin: Refactor getTemplateData to be used in generate command and update commands [#837](https://github.com/grafana/plugin-tools/pull/837) ([@oshirohugo](https://github.com/oshirohugo) [@Ukochka](https://github.com/Ukochka) [@leventebalogh](https://github.com/leventebalogh) [@josmperez](https://github.com/josmperez) [@sunker](https://github.com/sunker) [@grafanabot](https://github.com/grafanabot) [@jackw](https://github.com/jackw))
|
|
18
|
+
|
|
19
|
+
#### Authors: 7
|
|
20
|
+
|
|
21
|
+
- Erik Sundell ([@sunker](https://github.com/sunker))
|
|
22
|
+
- Grot (@grafanabot) ([@grafanabot](https://github.com/grafanabot))
|
|
23
|
+
- Hugo Kiyodi Oshiro ([@oshirohugo](https://github.com/oshirohugo))
|
|
24
|
+
- Jack Westbrook ([@jackw](https://github.com/jackw))
|
|
25
|
+
- Joseph Perez ([@josmperez](https://github.com/josmperez))
|
|
26
|
+
- Levente Balogh ([@leventebalogh](https://github.com/leventebalogh))
|
|
27
|
+
- Yulia Shanyrova ([@Ukochka](https://github.com/Ukochka))
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
1
31
|
# v4.9.0 (Thu Apr 25 2024)
|
|
2
32
|
|
|
3
33
|
#### 🚀 Enhancement
|
|
@@ -2,23 +2,19 @@ import { glob } from 'glob';
|
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { mkdir, readdir, writeFile } from 'node:fs/promises';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
-
import {
|
|
6
|
-
import { getConfig } from '../utils/utils.config.js';
|
|
5
|
+
import { EXTRA_TEMPLATE_VARIABLES, IS_DEV, TEMPLATE_PATHS } from '../constants.js';
|
|
7
6
|
import { printError } from '../utils/utils.console.js';
|
|
8
7
|
import { directoryExists, getExportFileName, isFile } from '../utils/utils.files.js';
|
|
9
|
-
import { normalizeId } from '../utils/utils.handlebars.js';
|
|
10
|
-
import { getPackageManagerFromUserAgent, getPackageManagerInstallCmd } from '../utils/utils.packageManager.js';
|
|
11
8
|
import { getExportPath } from '../utils/utils.path.js';
|
|
12
|
-
import { renderTemplateFromFile } from '../utils/utils.templates.js';
|
|
13
|
-
import { getVersion } from '../utils/utils.version.js';
|
|
9
|
+
import { renderTemplateFromFile, getTemplateData } from '../utils/utils.templates.js';
|
|
14
10
|
import { prettifyFiles } from '../utils/utils.prettifyFiles.js';
|
|
15
11
|
import { printGenerateSuccessMessage } from './generate/print-success-message.js';
|
|
16
12
|
import { promptUser } from './generate/prompt-user.js';
|
|
17
13
|
import { updateGoSdkAndModules } from './generate/update-go-sdk-and-packages.js';
|
|
18
14
|
export const generate = async (argv) => {
|
|
19
15
|
const answers = await promptUser(argv);
|
|
20
|
-
const templateData = getTemplateData(answers);
|
|
21
|
-
const exportPath = getExportPath(
|
|
16
|
+
const templateData = getTemplateData({ ...answers });
|
|
17
|
+
const exportPath = getExportPath(templateData.pluginName, templateData.orgName, templateData.pluginType);
|
|
22
18
|
const exportPathExists = await directoryExists(exportPath);
|
|
23
19
|
const exportPathIsPopulated = exportPathExists ? (await readdir(exportPath)).length > 0 : false;
|
|
24
20
|
if (exportPathIsPopulated && !IS_DEV) {
|
|
@@ -33,39 +29,12 @@ export const generate = async (argv) => {
|
|
|
33
29
|
failures.forEach((failure) => {
|
|
34
30
|
printError(`${failure.error}`);
|
|
35
31
|
});
|
|
36
|
-
if (
|
|
32
|
+
if (templateData.hasBackend) {
|
|
37
33
|
await execPostScaffoldFunction(updateGoSdkAndModules, exportPath);
|
|
38
34
|
}
|
|
39
35
|
await execPostScaffoldFunction(prettifyFiles, { targetPath: exportPath });
|
|
40
|
-
printGenerateSuccessMessage(
|
|
36
|
+
printGenerateSuccessMessage(templateData);
|
|
41
37
|
};
|
|
42
|
-
function getTemplateData(answers) {
|
|
43
|
-
const { pluginName, orgName, pluginType } = answers;
|
|
44
|
-
const { features } = getConfig();
|
|
45
|
-
const currentVersion = getVersion();
|
|
46
|
-
const pluginId = normalizeId(pluginName, orgName, pluginType);
|
|
47
|
-
const { packageManagerName, packageManagerVersion } = getPackageManagerFromUserAgent();
|
|
48
|
-
const packageManagerInstallCmd = getPackageManagerInstallCmd(packageManagerName);
|
|
49
|
-
const isAppType = pluginType === PLUGIN_TYPES.app || pluginType === PLUGIN_TYPES.scenes;
|
|
50
|
-
const useReactRouterV6 = features.useReactRouterV6 === true && pluginType === PLUGIN_TYPES.app;
|
|
51
|
-
const usePlaywright = features.usePlaywright === true;
|
|
52
|
-
const templateData = {
|
|
53
|
-
...answers,
|
|
54
|
-
pluginId,
|
|
55
|
-
packageManagerName,
|
|
56
|
-
packageManagerInstallCmd,
|
|
57
|
-
packageManagerVersion,
|
|
58
|
-
isAppType,
|
|
59
|
-
isNPM: packageManagerName === 'npm',
|
|
60
|
-
version: currentVersion,
|
|
61
|
-
bundleGrafanaUI: features.bundleGrafanaUI ?? DEFAULT_FEATURE_FLAGS.bundleGrafanaUI,
|
|
62
|
-
useReactRouterV6,
|
|
63
|
-
reactRouterVersion: useReactRouterV6 ? '6.22.0' : '5.2.0',
|
|
64
|
-
usePlaywright,
|
|
65
|
-
e2eTestCmd: 'playwright test',
|
|
66
|
-
};
|
|
67
|
-
return templateData;
|
|
68
|
-
}
|
|
69
38
|
function getTemplateActions({ exportPath, templateData }) {
|
|
70
39
|
const commonActions = getActionsForTemplateFolder({
|
|
71
40
|
folderPath: TEMPLATE_PATHS.common,
|
|
@@ -8,7 +8,8 @@ export const migrate = async () => {
|
|
|
8
8
|
try {
|
|
9
9
|
printMessage(TEXT.migrationCommandWarning);
|
|
10
10
|
if (await confirmPrompt(TEXT.overrideFilesPrompt + '\n' + displayArrayAsList(MIGRATION_CONFIG.filesToOverride))) {
|
|
11
|
-
|
|
11
|
+
const templateData = getTemplateData();
|
|
12
|
+
compileTemplateFiles(MIGRATION_CONFIG.filesToOverride.map(getExportTemplateName), templateData);
|
|
12
13
|
printSuccessMessage(TEXT.overrideFilesSuccess);
|
|
13
14
|
}
|
|
14
15
|
else {
|
|
@@ -12,8 +12,9 @@ export const provisioning = async () => {
|
|
|
12
12
|
if (await confirmPrompt(TEXT.addProvisioning)) {
|
|
13
13
|
if (!fs.existsSync(provisioningFolder)) {
|
|
14
14
|
const provisioningSpecificFiles = glob.sync(`${TEMPLATE_PATHS[type]}/provisioning/**`, { dot: true });
|
|
15
|
+
const templateData = getTemplateData();
|
|
15
16
|
provisioningSpecificFiles.forEach((file) => {
|
|
16
|
-
compileProvisioningTemplateFile(type, file,
|
|
17
|
+
compileProvisioningTemplateFile(type, file, templateData);
|
|
17
18
|
});
|
|
18
19
|
printSuccessMessage(TEXT.addProvisioningSuccess);
|
|
19
20
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Handlebars from 'handlebars';
|
|
2
2
|
import { camelCase, snakeCase, dotCase, pathCase, sentenceCase, constantCase, kebabCase, pascalCase, } from 'change-case';
|
|
3
3
|
import { titleCase } from 'title-case';
|
|
4
|
-
import { PARTIALS_DIR } from '../constants.js';
|
|
4
|
+
import { PARTIALS_DIR, PLUGIN_TYPES } from '../constants.js';
|
|
5
5
|
import { readFileSync, readdirSync } from 'node:fs';
|
|
6
6
|
import { basename, join } from 'node:path';
|
|
7
7
|
export const ifEq = (a, b, options) => {
|
|
@@ -12,7 +12,8 @@ export const normalizeId = (pluginName, orgName, type) => {
|
|
|
12
12
|
const nameRegex = new RegExp('[^0-9a-zA-Z]', 'g');
|
|
13
13
|
const newPluginName = pluginName.replace(re, '').replace(nameRegex, '');
|
|
14
14
|
const newOrgName = orgName.replace(nameRegex, '');
|
|
15
|
-
|
|
15
|
+
const newType = type === PLUGIN_TYPES.scenes ? PLUGIN_TYPES.app : type;
|
|
16
|
+
return newOrgName.toLowerCase() + '-' + newPluginName.toLowerCase() + `-${newType}`;
|
|
16
17
|
};
|
|
17
18
|
export const kebabToPascalKebab = (str) => {
|
|
18
19
|
if (typeof str !== 'string') {
|
|
@@ -43,7 +44,6 @@ function registerHandlebarsHelpers() {
|
|
|
43
44
|
properCase: pascalCase,
|
|
44
45
|
pascalCase: pascalCase,
|
|
45
46
|
if_eq: ifEq,
|
|
46
|
-
normalize_id: normalizeId,
|
|
47
47
|
};
|
|
48
48
|
Object.keys(helpers).forEach((helperName) => Handlebars.registerHelper(helperName, helpers[helperName]));
|
|
49
49
|
}
|
|
@@ -4,10 +4,10 @@ import fs from 'node:fs';
|
|
|
4
4
|
import { mkdirp } from 'mkdirp';
|
|
5
5
|
import createDebug from 'debug';
|
|
6
6
|
import { filterOutCommonFiles, isFile, isFileStartingWith } from './utils.files.js';
|
|
7
|
-
import { renderHandlebarsTemplate } from './utils.handlebars.js';
|
|
7
|
+
import { normalizeId, renderHandlebarsTemplate } from './utils.handlebars.js';
|
|
8
8
|
import { getPluginJson } from './utils.plugin.js';
|
|
9
9
|
import { TEMPLATE_PATHS, EXPORT_PATH_PREFIX, EXTRA_TEMPLATE_VARIABLES, PLUGIN_TYPES, DEFAULT_FEATURE_FLAGS, } from '../constants.js';
|
|
10
|
-
import { getPackageManagerInstallCmd, getPackageManagerWithFallback } from './utils.packageManager.js';
|
|
10
|
+
import { getPackageManagerInstallCmd, getPackageManagerWithFallback, getPackageManagerFromUserAgent, } from './utils.packageManager.js';
|
|
11
11
|
import { getExportFileName } from '../utils/utils.files.js';
|
|
12
12
|
import { getVersion } from './utils.version.js';
|
|
13
13
|
import { getConfig } from './utils.config.js';
|
|
@@ -54,37 +54,71 @@ export function compileProvisioningTemplateFile(pluginType, templateFile, data)
|
|
|
54
54
|
export function renderTemplateFromFile(templateFile, data) {
|
|
55
55
|
return renderHandlebarsTemplate(fs.readFileSync(templateFile).toString(), data);
|
|
56
56
|
}
|
|
57
|
-
export function getTemplateData() {
|
|
58
|
-
const pluginJson = getPluginJson();
|
|
57
|
+
export function getTemplateData(cliArgs) {
|
|
59
58
|
const { features } = getConfig();
|
|
60
59
|
const currentVersion = getVersion();
|
|
61
|
-
const useReactRouterV6 = features.useReactRouterV6 === true && pluginJson.type === PLUGIN_TYPES.app;
|
|
62
|
-
const { packageManagerName, packageManagerVersion } = getPackageManagerWithFallback();
|
|
63
|
-
const packageManagerInstallCmd = getPackageManagerInstallCmd(packageManagerName);
|
|
64
60
|
const usePlaywright = features.usePlaywright === true || isFile(path.join(process.cwd(), 'playwright.config.ts'));
|
|
65
|
-
const
|
|
61
|
+
const bundleGrafanaUI = features.bundleGrafanaUI ?? DEFAULT_FEATURE_FLAGS.bundleGrafanaUI;
|
|
62
|
+
const shouldUseReactRouterV6 = (pluginType) => features.useReactRouterV6 === true && pluginType === PLUGIN_TYPES.app;
|
|
63
|
+
const getReactRouterVersion = (pluginType) => (shouldUseReactRouterV6(pluginType) ? '6.22.0' : '5.2.0');
|
|
64
|
+
const isAppType = (pluginType) => pluginType === PLUGIN_TYPES.app || pluginType === PLUGIN_TYPES.scenes;
|
|
65
|
+
const isNPM = (packageManagerName) => packageManagerName === 'npm';
|
|
66
|
+
const getE2eTestCmd = (packageManagerName) => usePlaywright
|
|
66
67
|
? 'playwright test'
|
|
67
68
|
: `${packageManagerName} exec cypress install && ${packageManagerName} exec grafana-e2e run`;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
69
|
+
let templateData;
|
|
70
|
+
if (cliArgs) {
|
|
71
|
+
const { packageManagerName, packageManagerVersion } = getPackageManagerFromUserAgent();
|
|
72
|
+
templateData = {
|
|
73
|
+
...EXTRA_TEMPLATE_VARIABLES,
|
|
74
|
+
pluginId: normalizeId(cliArgs.pluginName, cliArgs.orgName, cliArgs.pluginType),
|
|
75
|
+
pluginName: cliArgs.pluginName,
|
|
76
|
+
pluginDescription: cliArgs.pluginDescription,
|
|
77
|
+
hasBackend: cliArgs.hasBackend,
|
|
78
|
+
orgName: cliArgs.orgName,
|
|
79
|
+
pluginType: cliArgs.pluginType,
|
|
80
|
+
packageManagerName,
|
|
81
|
+
packageManagerVersion,
|
|
82
|
+
packageManagerInstallCmd: getPackageManagerInstallCmd(packageManagerName),
|
|
83
|
+
isAppType: isAppType(cliArgs.pluginType),
|
|
84
|
+
isNPM: isNPM(packageManagerName),
|
|
85
|
+
version: currentVersion,
|
|
86
|
+
bundleGrafanaUI,
|
|
87
|
+
useReactRouterV6: shouldUseReactRouterV6(cliArgs.pluginType),
|
|
88
|
+
reactRouterVersion: getReactRouterVersion(cliArgs.pluginType),
|
|
89
|
+
usePlaywright,
|
|
90
|
+
e2eTestCmd: getE2eTestCmd(packageManagerName),
|
|
91
|
+
hasGithubWorkflows: cliArgs.hasGithubWorkflows,
|
|
92
|
+
hasGithubLevitateWorkflow: cliArgs.hasGithubLevitateWorkflow,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
const pluginJson = getPluginJson();
|
|
97
|
+
const { packageManagerName, packageManagerVersion } = getPackageManagerWithFallback();
|
|
98
|
+
const githubFolder = path.join(process.cwd(), '.github', 'workflows');
|
|
99
|
+
templateData = {
|
|
100
|
+
...EXTRA_TEMPLATE_VARIABLES,
|
|
101
|
+
pluginId: pluginJson.id,
|
|
102
|
+
pluginName: pluginJson.name,
|
|
103
|
+
pluginDescription: pluginJson.info.description,
|
|
104
|
+
hasBackend: pluginJson.backend,
|
|
105
|
+
orgName: pluginJson.info.author.name,
|
|
106
|
+
pluginType: pluginJson.type,
|
|
107
|
+
packageManagerName: packageManagerName,
|
|
108
|
+
packageManagerVersion: packageManagerVersion,
|
|
109
|
+
packageManagerInstallCmd: getPackageManagerInstallCmd(packageManagerName),
|
|
110
|
+
isAppType: isAppType(pluginJson.type),
|
|
111
|
+
isNPM: isNPM(packageManagerName),
|
|
112
|
+
version: currentVersion,
|
|
113
|
+
bundleGrafanaUI,
|
|
114
|
+
useReactRouterV6: shouldUseReactRouterV6(pluginJson.type),
|
|
115
|
+
reactRouterVersion: getReactRouterVersion(pluginJson.type),
|
|
116
|
+
usePlaywright,
|
|
117
|
+
e2eTestCmd: getE2eTestCmd(packageManagerName),
|
|
118
|
+
hasGithubWorkflows: isFile(path.join(githubFolder, 'ci.yml')),
|
|
119
|
+
hasGithubLevitateWorkflow: isFile(path.join(githubFolder, 'is-compatible.yml')),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
88
122
|
debug('\nTemplate data:\n' + JSON.stringify(templateData, null, 2));
|
|
89
123
|
return templateData;
|
|
90
124
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://raw.githubusercontent.com/grafana/grafana/main/docs/sources/developers/plugins/plugin.schema.json",
|
|
3
3
|
"type": "app",
|
|
4
4
|
"name": "{{ titleCase pluginName }}",
|
|
5
|
-
"id": "{{
|
|
5
|
+
"id": "{{ pluginId }}",
|
|
6
6
|
"backend": true,
|
|
7
7
|
"executable": "gpx_{{ snakeCase pluginName }}",
|
|
8
8
|
"info": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grafana/create-plugin",
|
|
3
|
-
"version": "4.10.0
|
|
3
|
+
"version": "4.10.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"directory": "packages/create-plugin",
|
|
6
6
|
"url": "https://github.com/grafana/plugin-tools"
|
|
@@ -87,5 +87,5 @@
|
|
|
87
87
|
"engines": {
|
|
88
88
|
"node": ">=20"
|
|
89
89
|
},
|
|
90
|
-
"gitHead": "
|
|
90
|
+
"gitHead": "86d9d0de52b0d0fccb13b6977810daef1b484015"
|
|
91
91
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { displayAsMarkdown } from '../../utils/utils.console.js';
|
|
2
2
|
import { normalizeId } from '../../utils/utils.handlebars.js';
|
|
3
3
|
import { getPackageManagerFromUserAgent } from '../../utils/utils.packageManager.js';
|
|
4
|
-
import {
|
|
4
|
+
import { TemplateData } from '../../types.js';
|
|
5
5
|
|
|
6
|
-
export function printGenerateSuccessMessage(answers:
|
|
6
|
+
export function printGenerateSuccessMessage(answers: TemplateData) {
|
|
7
7
|
const directory = normalizeId(answers.pluginName, answers.orgName, answers.pluginType);
|
|
8
8
|
const { packageManagerName } = getPackageManagerFromUserAgent();
|
|
9
9
|
const commands = [
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import minimist from 'minimist';
|
|
2
2
|
import Enquirer from 'enquirer';
|
|
3
3
|
import { PLUGIN_TYPES } from '../../constants.js';
|
|
4
|
-
import {
|
|
4
|
+
import { GenerateCliArgs } from '../../types.js';
|
|
5
5
|
|
|
6
6
|
export async function promptUser(argv: minimist.ParsedArgs) {
|
|
7
|
-
let answers: Partial<
|
|
7
|
+
let answers: Partial<GenerateCliArgs> = {};
|
|
8
8
|
const enquirer = new Enquirer();
|
|
9
9
|
|
|
10
10
|
for (const prompt of prompts) {
|
|
@@ -22,17 +22,17 @@ export async function promptUser(argv: minimist.ParsedArgs) {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
return answers as
|
|
25
|
+
return answers as GenerateCliArgs;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
type Prompt = {
|
|
29
|
-
name: keyof
|
|
29
|
+
name: keyof GenerateCliArgs;
|
|
30
30
|
type: string | (() => string);
|
|
31
31
|
message: string | (() => string) | (() => Promise<string>);
|
|
32
32
|
validate?: (value: string) => boolean | string | Promise<boolean | string>;
|
|
33
33
|
initial?: any;
|
|
34
34
|
choices?: Array<string | Choice>;
|
|
35
|
-
shouldPrompt?: (answers: Partial<
|
|
35
|
+
shouldPrompt?: (answers: Partial<GenerateCliArgs>) => boolean;
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
type Choice = {
|
|
@@ -3,25 +3,21 @@ import minimist from 'minimist';
|
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import { mkdir, readdir, writeFile } from 'node:fs/promises';
|
|
5
5
|
import path from 'node:path';
|
|
6
|
-
import {
|
|
7
|
-
import { getConfig } from '../utils/utils.config.js';
|
|
6
|
+
import { EXTRA_TEMPLATE_VARIABLES, IS_DEV, TEMPLATE_PATHS } from '../constants.js';
|
|
8
7
|
import { printError } from '../utils/utils.console.js';
|
|
9
8
|
import { directoryExists, getExportFileName, isFile } from '../utils/utils.files.js';
|
|
10
|
-
import { normalizeId } from '../utils/utils.handlebars.js';
|
|
11
|
-
import { getPackageManagerFromUserAgent, getPackageManagerInstallCmd } from '../utils/utils.packageManager.js';
|
|
12
9
|
import { getExportPath } from '../utils/utils.path.js';
|
|
13
|
-
import { renderTemplateFromFile } from '../utils/utils.templates.js';
|
|
14
|
-
import { getVersion } from '../utils/utils.version.js';
|
|
10
|
+
import { renderTemplateFromFile, getTemplateData } from '../utils/utils.templates.js';
|
|
15
11
|
import { prettifyFiles } from '../utils/utils.prettifyFiles.js';
|
|
16
12
|
import { printGenerateSuccessMessage } from './generate/print-success-message.js';
|
|
17
13
|
import { promptUser } from './generate/prompt-user.js';
|
|
18
14
|
import { updateGoSdkAndModules } from './generate/update-go-sdk-and-packages.js';
|
|
19
|
-
import {
|
|
15
|
+
import { TemplateData } from '../types.js';
|
|
20
16
|
|
|
21
17
|
export const generate = async (argv: minimist.ParsedArgs) => {
|
|
22
18
|
const answers = await promptUser(argv);
|
|
23
|
-
const templateData = getTemplateData(answers);
|
|
24
|
-
const exportPath = getExportPath(
|
|
19
|
+
const templateData = getTemplateData({ ...answers });
|
|
20
|
+
const exportPath = getExportPath(templateData.pluginName, templateData.orgName, templateData.pluginType);
|
|
25
21
|
const exportPathExists = await directoryExists(exportPath);
|
|
26
22
|
const exportPathIsPopulated = exportPathExists ? (await readdir(exportPath)).length > 0 : false;
|
|
27
23
|
|
|
@@ -42,46 +38,14 @@ export const generate = async (argv: minimist.ParsedArgs) => {
|
|
|
42
38
|
printError(`${failure.error}`);
|
|
43
39
|
});
|
|
44
40
|
|
|
45
|
-
if (
|
|
41
|
+
if (templateData.hasBackend) {
|
|
46
42
|
await execPostScaffoldFunction(updateGoSdkAndModules, exportPath);
|
|
47
43
|
}
|
|
48
44
|
await execPostScaffoldFunction(prettifyFiles, { targetPath: exportPath });
|
|
49
45
|
|
|
50
|
-
printGenerateSuccessMessage(
|
|
46
|
+
printGenerateSuccessMessage(templateData);
|
|
51
47
|
};
|
|
52
48
|
|
|
53
|
-
function getTemplateData(answers: CliArgs) {
|
|
54
|
-
const { pluginName, orgName, pluginType } = answers;
|
|
55
|
-
const { features } = getConfig();
|
|
56
|
-
const currentVersion = getVersion();
|
|
57
|
-
const pluginId = normalizeId(pluginName, orgName, pluginType);
|
|
58
|
-
// Support the users package manager of choice.
|
|
59
|
-
const { packageManagerName, packageManagerVersion } = getPackageManagerFromUserAgent();
|
|
60
|
-
const packageManagerInstallCmd = getPackageManagerInstallCmd(packageManagerName);
|
|
61
|
-
const isAppType = pluginType === PLUGIN_TYPES.app || pluginType === PLUGIN_TYPES.scenes;
|
|
62
|
-
// We don't enable this by default yet for new scenes plugins.
|
|
63
|
-
const useReactRouterV6 = features.useReactRouterV6 === true && pluginType === PLUGIN_TYPES.app;
|
|
64
|
-
const usePlaywright = features.usePlaywright === true;
|
|
65
|
-
|
|
66
|
-
const templateData: TemplateData = {
|
|
67
|
-
...answers,
|
|
68
|
-
pluginId,
|
|
69
|
-
packageManagerName,
|
|
70
|
-
packageManagerInstallCmd,
|
|
71
|
-
packageManagerVersion,
|
|
72
|
-
isAppType,
|
|
73
|
-
isNPM: packageManagerName === 'npm',
|
|
74
|
-
version: currentVersion,
|
|
75
|
-
bundleGrafanaUI: features.bundleGrafanaUI ?? DEFAULT_FEATURE_FLAGS.bundleGrafanaUI,
|
|
76
|
-
useReactRouterV6,
|
|
77
|
-
reactRouterVersion: useReactRouterV6 ? '6.22.0' : '5.2.0',
|
|
78
|
-
usePlaywright,
|
|
79
|
-
e2eTestCmd: 'playwright test',
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
return templateData;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
49
|
type TemplateAction = {
|
|
86
50
|
templateFile: string;
|
|
87
51
|
path: string;
|
|
@@ -28,7 +28,8 @@ export const migrate = async () => {
|
|
|
28
28
|
// 1. Add / update configuration files
|
|
29
29
|
// --------------------------
|
|
30
30
|
if (await confirmPrompt(TEXT.overrideFilesPrompt + '\n' + displayArrayAsList(MIGRATION_CONFIG.filesToOverride))) {
|
|
31
|
-
|
|
31
|
+
const templateData = getTemplateData();
|
|
32
|
+
compileTemplateFiles(MIGRATION_CONFIG.filesToOverride.map(getExportTemplateName), templateData);
|
|
32
33
|
printSuccessMessage(TEXT.overrideFilesSuccess);
|
|
33
34
|
} else {
|
|
34
35
|
printMessage(TEXT.overrideFilesAborted);
|
|
@@ -13,9 +13,9 @@ export const provisioning = async () => {
|
|
|
13
13
|
if (await confirmPrompt(TEXT.addProvisioning)) {
|
|
14
14
|
if (!fs.existsSync(provisioningFolder)) {
|
|
15
15
|
const provisioningSpecificFiles = glob.sync(`${TEMPLATE_PATHS[type]}/provisioning/**`, { dot: true });
|
|
16
|
-
|
|
16
|
+
const templateData = getTemplateData();
|
|
17
17
|
provisioningSpecificFiles.forEach((file) => {
|
|
18
|
-
compileProvisioningTemplateFile(type, file,
|
|
18
|
+
compileProvisioningTemplateFile(type, file, templateData);
|
|
19
19
|
});
|
|
20
20
|
printSuccessMessage(TEXT.addProvisioningSuccess);
|
|
21
21
|
} else {
|
package/src/types.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { PLUGIN_TYPES } from './constants.js';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
// The arguments that are passed to the CLI when generating a new plugin.
|
|
4
|
+
// (Either via user prompts or CLI arguments)
|
|
5
|
+
export type GenerateCliArgs = {
|
|
4
6
|
pluginName: string;
|
|
5
7
|
pluginDescription: string;
|
|
6
8
|
orgName: string;
|
|
@@ -12,6 +14,11 @@ export type CliArgs = {
|
|
|
12
14
|
|
|
13
15
|
export type TemplateData = {
|
|
14
16
|
pluginId: string;
|
|
17
|
+
pluginName: string;
|
|
18
|
+
pluginDescription: string;
|
|
19
|
+
hasBackend: boolean;
|
|
20
|
+
orgName: string;
|
|
21
|
+
pluginType: PLUGIN_TYPES;
|
|
15
22
|
packageManagerName: string;
|
|
16
23
|
packageManagerInstallCmd: string;
|
|
17
24
|
packageManagerVersion: string;
|
|
@@ -23,4 +30,6 @@ export type TemplateData = {
|
|
|
23
30
|
reactRouterVersion: string;
|
|
24
31
|
usePlaywright: boolean;
|
|
25
32
|
e2eTestCmd: string;
|
|
33
|
+
hasGithubWorkflows: boolean;
|
|
34
|
+
hasGithubLevitateWorkflow: boolean;
|
|
26
35
|
};
|
|
@@ -25,7 +25,9 @@ export const normalizeId = (pluginName: string, orgName: string, type: PLUGIN_TY
|
|
|
25
25
|
|
|
26
26
|
const newPluginName = pluginName.replace(re, '').replace(nameRegex, '');
|
|
27
27
|
const newOrgName = orgName.replace(nameRegex, '');
|
|
28
|
-
|
|
28
|
+
const newType = type === PLUGIN_TYPES.scenes ? PLUGIN_TYPES.app : type;
|
|
29
|
+
|
|
30
|
+
return newOrgName.toLowerCase() + '-' + newPluginName.toLowerCase() + `-${newType}`;
|
|
29
31
|
};
|
|
30
32
|
|
|
31
33
|
export const kebabToPascalKebab = (str: string) => {
|
|
@@ -60,7 +62,6 @@ function registerHandlebarsHelpers() {
|
|
|
60
62
|
properCase: pascalCase,
|
|
61
63
|
pascalCase: pascalCase,
|
|
62
64
|
if_eq: ifEq,
|
|
63
|
-
normalize_id: normalizeId,
|
|
64
65
|
};
|
|
65
66
|
|
|
66
67
|
Object.keys(helpers).forEach((helperName) =>
|
|
@@ -4,7 +4,7 @@ import fs from 'node:fs';
|
|
|
4
4
|
import { mkdirp } from 'mkdirp';
|
|
5
5
|
import createDebug from 'debug';
|
|
6
6
|
import { filterOutCommonFiles, isFile, isFileStartingWith } from './utils.files.js';
|
|
7
|
-
import { renderHandlebarsTemplate } from './utils.handlebars.js';
|
|
7
|
+
import { normalizeId, renderHandlebarsTemplate } from './utils.handlebars.js';
|
|
8
8
|
import { getPluginJson } from './utils.plugin.js';
|
|
9
9
|
import {
|
|
10
10
|
TEMPLATE_PATHS,
|
|
@@ -13,8 +13,12 @@ import {
|
|
|
13
13
|
PLUGIN_TYPES,
|
|
14
14
|
DEFAULT_FEATURE_FLAGS,
|
|
15
15
|
} from '../constants.js';
|
|
16
|
-
import { TemplateData } from '../types.js';
|
|
17
|
-
import {
|
|
16
|
+
import { GenerateCliArgs, TemplateData } from '../types.js';
|
|
17
|
+
import {
|
|
18
|
+
getPackageManagerInstallCmd,
|
|
19
|
+
getPackageManagerWithFallback,
|
|
20
|
+
getPackageManagerFromUserAgent,
|
|
21
|
+
} from './utils.packageManager.js';
|
|
18
22
|
import { getExportFileName } from '../utils/utils.files.js';
|
|
19
23
|
import { getVersion } from './utils.version.js';
|
|
20
24
|
import { getConfig } from './utils.config.js';
|
|
@@ -88,38 +92,79 @@ export function renderTemplateFromFile(templateFile: string, data?: any) {
|
|
|
88
92
|
return renderHandlebarsTemplate(fs.readFileSync(templateFile).toString(), data);
|
|
89
93
|
}
|
|
90
94
|
|
|
91
|
-
export function getTemplateData(): TemplateData {
|
|
92
|
-
const pluginJson = getPluginJson();
|
|
95
|
+
export function getTemplateData(cliArgs?: GenerateCliArgs): TemplateData {
|
|
93
96
|
const { features } = getConfig();
|
|
94
97
|
const currentVersion = getVersion();
|
|
95
|
-
const useReactRouterV6 = features.useReactRouterV6 === true && pluginJson.type === PLUGIN_TYPES.app;
|
|
96
|
-
const { packageManagerName, packageManagerVersion } = getPackageManagerWithFallback();
|
|
97
|
-
const packageManagerInstallCmd = getPackageManagerInstallCmd(packageManagerName);
|
|
98
98
|
const usePlaywright = features.usePlaywright === true || isFile(path.join(process.cwd(), 'playwright.config.ts'));
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
packageManagerVersion
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
99
|
+
const bundleGrafanaUI = features.bundleGrafanaUI ?? DEFAULT_FEATURE_FLAGS.bundleGrafanaUI;
|
|
100
|
+
const shouldUseReactRouterV6 = (pluginType: string) =>
|
|
101
|
+
features.useReactRouterV6 === true && pluginType === PLUGIN_TYPES.app;
|
|
102
|
+
const getReactRouterVersion = (pluginType: string) => (shouldUseReactRouterV6(pluginType) ? '6.22.0' : '5.2.0');
|
|
103
|
+
const isAppType = (pluginType: string) => pluginType === PLUGIN_TYPES.app || pluginType === PLUGIN_TYPES.scenes;
|
|
104
|
+
const isNPM = (packageManagerName: string) => packageManagerName === 'npm';
|
|
105
|
+
const getE2eTestCmd = (packageManagerName: string) =>
|
|
106
|
+
usePlaywright
|
|
107
|
+
? 'playwright test'
|
|
108
|
+
: `${packageManagerName} exec cypress install && ${packageManagerName} exec grafana-e2e run`;
|
|
109
|
+
|
|
110
|
+
let templateData: TemplateData;
|
|
111
|
+
|
|
112
|
+
// `cliArgs` is only passed in when scaffolding a new plugin via the CLI (generate command)
|
|
113
|
+
if (cliArgs) {
|
|
114
|
+
const { packageManagerName, packageManagerVersion } = getPackageManagerFromUserAgent();
|
|
115
|
+
|
|
116
|
+
templateData = {
|
|
117
|
+
...EXTRA_TEMPLATE_VARIABLES,
|
|
118
|
+
pluginId: normalizeId(cliArgs.pluginName, cliArgs.orgName, cliArgs.pluginType),
|
|
119
|
+
pluginName: cliArgs.pluginName,
|
|
120
|
+
pluginDescription: cliArgs.pluginDescription,
|
|
121
|
+
hasBackend: cliArgs.hasBackend,
|
|
122
|
+
orgName: cliArgs.orgName,
|
|
123
|
+
pluginType: cliArgs.pluginType,
|
|
124
|
+
packageManagerName,
|
|
125
|
+
packageManagerVersion,
|
|
126
|
+
packageManagerInstallCmd: getPackageManagerInstallCmd(packageManagerName),
|
|
127
|
+
isAppType: isAppType(cliArgs.pluginType),
|
|
128
|
+
isNPM: isNPM(packageManagerName),
|
|
129
|
+
version: currentVersion,
|
|
130
|
+
bundleGrafanaUI,
|
|
131
|
+
useReactRouterV6: shouldUseReactRouterV6(cliArgs.pluginType),
|
|
132
|
+
reactRouterVersion: getReactRouterVersion(cliArgs.pluginType),
|
|
133
|
+
usePlaywright,
|
|
134
|
+
e2eTestCmd: getE2eTestCmd(packageManagerName),
|
|
135
|
+
hasGithubWorkflows: cliArgs.hasGithubWorkflows,
|
|
136
|
+
hasGithubLevitateWorkflow: cliArgs.hasGithubLevitateWorkflow,
|
|
137
|
+
};
|
|
138
|
+
// Updating or migrating a plugin
|
|
139
|
+
// (plugin.json and package.json files are only present if it's an existing plugin)
|
|
140
|
+
} else {
|
|
141
|
+
const pluginJson = getPluginJson();
|
|
142
|
+
const { packageManagerName, packageManagerVersion } = getPackageManagerWithFallback();
|
|
143
|
+
const githubFolder = path.join(process.cwd(), '.github', 'workflows');
|
|
144
|
+
|
|
145
|
+
templateData = {
|
|
146
|
+
...EXTRA_TEMPLATE_VARIABLES,
|
|
147
|
+
pluginId: pluginJson.id,
|
|
148
|
+
pluginName: pluginJson.name,
|
|
149
|
+
pluginDescription: pluginJson.info.description,
|
|
150
|
+
hasBackend: pluginJson.backend,
|
|
151
|
+
orgName: pluginJson.info.author.name,
|
|
152
|
+
pluginType: pluginJson.type,
|
|
153
|
+
packageManagerName: packageManagerName,
|
|
154
|
+
packageManagerVersion: packageManagerVersion,
|
|
155
|
+
packageManagerInstallCmd: getPackageManagerInstallCmd(packageManagerName),
|
|
156
|
+
isAppType: isAppType(pluginJson.type),
|
|
157
|
+
isNPM: isNPM(packageManagerName),
|
|
158
|
+
version: currentVersion,
|
|
159
|
+
bundleGrafanaUI,
|
|
160
|
+
useReactRouterV6: shouldUseReactRouterV6(pluginJson.type),
|
|
161
|
+
reactRouterVersion: getReactRouterVersion(pluginJson.type),
|
|
162
|
+
usePlaywright,
|
|
163
|
+
e2eTestCmd: getE2eTestCmd(packageManagerName),
|
|
164
|
+
hasGithubWorkflows: isFile(path.join(githubFolder, 'ci.yml')),
|
|
165
|
+
hasGithubLevitateWorkflow: isFile(path.join(githubFolder, 'is-compatible.yml')),
|
|
166
|
+
};
|
|
167
|
+
}
|
|
123
168
|
|
|
124
169
|
debug('\nTemplate data:\n' + JSON.stringify(templateData, null, 2));
|
|
125
170
|
|
package/templates/app/README.md
CHANGED
|
@@ -18,5 +18,5 @@ App plugins can let you create a custom out-of-the-box monitoring experience by
|
|
|
18
18
|
Below you can find source code for existing app plugins and other related documentation.
|
|
19
19
|
|
|
20
20
|
- [Basic app plugin example](https://github.com/grafana/grafana-plugin-examples/tree/master/examples/app-basic#readme)
|
|
21
|
-
- [`plugin.json` documentation](https://grafana.com/developers/plugin-tools/reference
|
|
21
|
+
- [`plugin.json` documentation](https://grafana.com/developers/plugin-tools/reference/plugin-jsonplugin-json)
|
|
22
22
|
- [Sign a plugin](https://grafana.com/developers/plugin-tools/publish-a-plugin/sign-a-plugin)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://raw.githubusercontent.com/grafana/grafana/main/docs/sources/developers/plugins/plugin.schema.json",
|
|
3
3
|
"type": "app",
|
|
4
4
|
"name": "{{ titleCase pluginName }}",
|
|
5
|
-
"id": "{{
|
|
5
|
+
"id": "{{ pluginId }}",{{#if hasBackend}}
|
|
6
6
|
"backend": true,
|
|
7
7
|
"executable": "gpx_{{ snakeCase pluginName }}",{{/if}}
|
|
8
8
|
"info": {
|
|
@@ -17,8 +17,8 @@ func main() {
|
|
|
17
17
|
// from Grafana to create different instances of SampleDatasource (per datasource
|
|
18
18
|
// ID). When datasource configuration changed Dispose method will be called and
|
|
19
19
|
// new datasource instance created using NewSampleDatasource factory.
|
|
20
|
-
if err := datasource.Manage("{{
|
|
20
|
+
if err := datasource.Manage("{{ pluginId }}", plugin.NewDatasource, datasource.ManageOpts{}); err != nil {
|
|
21
21
|
log.DefaultLogger.Error(err.Error())
|
|
22
22
|
os.Exit(1)
|
|
23
23
|
}
|
|
24
|
-
}
|
|
24
|
+
}
|
|
@@ -16,7 +16,7 @@ func main() {
|
|
|
16
16
|
// argument. This factory will be automatically called on incoming request
|
|
17
17
|
// from Grafana to create different instances of `App` (per plugin
|
|
18
18
|
// ID).
|
|
19
|
-
if err := app.Manage("{{
|
|
19
|
+
if err := app.Manage("{{ pluginId }}", plugin.NewApp, app.ManageOpts{}); err != nil {
|
|
20
20
|
log.DefaultLogger.Error(err.Error())
|
|
21
21
|
os.Exit(1)
|
|
22
22
|
}
|
|
@@ -20,7 +20,6 @@ import { SOURCE_DIR, DIST_DIR } from './constants';
|
|
|
20
20
|
const pluginJson = getPluginJson();
|
|
21
21
|
|
|
22
22
|
const config = async (env): Promise<Configuration> => {
|
|
23
|
-
const entry = await getEntries();
|
|
24
23
|
const baseConfig: Configuration = {
|
|
25
24
|
cache: {
|
|
26
25
|
type: 'filesystem',
|
|
@@ -33,7 +32,7 @@ const config = async (env): Promise<Configuration> => {
|
|
|
33
32
|
|
|
34
33
|
devtool: env.production ? 'source-map' : 'eval-source-map',
|
|
35
34
|
|
|
36
|
-
entry,
|
|
35
|
+
entry: await getEntries(),
|
|
37
36
|
|
|
38
37
|
externals: [
|
|
39
38
|
'lodash',
|
|
@@ -144,7 +143,7 @@ const config = async (env): Promise<Configuration> => {
|
|
|
144
143
|
},
|
|
145
144
|
|
|
146
145
|
plugins: [
|
|
147
|
-
new GrafanaPluginMetaExtractor(
|
|
146
|
+
new GrafanaPluginMetaExtractor(),
|
|
148
147
|
new CopyWebpackPlugin({
|
|
149
148
|
patterns: [
|
|
150
149
|
// If src/README.md exists use it; otherwise the root README
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"@grafana/eslint-config": "^7.0.0",{{#if usePlaywright}}
|
|
25
25
|
"@grafana/plugin-e2e": "^1.0.1",{{/if}}
|
|
26
26
|
"@grafana/tsconfig": "^1.2.0-rc1",
|
|
27
|
-
"@grafana/plugin-meta-extractor": "
|
|
27
|
+
"@grafana/plugin-meta-extractor": "^0.0.1",{{#if usePlaywright}}
|
|
28
28
|
"@playwright/test": "^1.41.2",{{/if}}
|
|
29
29
|
"@swc/core": "^1.3.90",
|
|
30
30
|
"@swc/helpers": "^0.5.0",
|
|
@@ -33,7 +33,7 @@ Consider other [badges](https://shields.io/badges) as you feel appropriate for y
|
|
|
33
33
|
Provide one or more paragraphs as an introduction to your plugin to help users understand why they should use it.
|
|
34
34
|
|
|
35
35
|
Consider including screenshots:
|
|
36
|
-
- in [plugin.json](https://grafana.com/developers/plugin-tools/reference
|
|
36
|
+
- in [plugin.json](https://grafana.com/developers/plugin-tools/reference/plugin-json#info) include them as relative links.
|
|
37
37
|
- in the README ensure they are absolute URLs.
|
|
38
38
|
|
|
39
39
|
## Requirements
|
|
@@ -18,5 +18,5 @@ Grafana supports a wide range of data sources, including Prometheus, MySQL, and
|
|
|
18
18
|
Below you can find source code for existing app plugins and other related documentation.
|
|
19
19
|
|
|
20
20
|
- [Basic data source plugin example](https://github.com/grafana/grafana-plugin-examples/tree/master/examples/datasource-basic#readme)
|
|
21
|
-
- [`plugin.json` documentation](https://grafana.com/developers/plugin-tools/reference
|
|
21
|
+
- [`plugin.json` documentation](https://grafana.com/developers/plugin-tools/reference/plugin-json)
|
|
22
22
|
- [How to sign a plugin?](https://grafana.com/developers/plugin-tools/publish-a-plugin/sign-a-plugin)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://raw.githubusercontent.com/grafana/grafana/main/docs/sources/developers/plugins/plugin.schema.json",
|
|
3
3
|
"type": "datasource",
|
|
4
4
|
"name": "{{ titleCase pluginName }}",
|
|
5
|
-
"id": "{{
|
|
5
|
+
"id": "{{ pluginId }}",
|
|
6
6
|
"metrics": true,{{#if hasBackend}}
|
|
7
7
|
"backend": true,
|
|
8
8
|
"executable": "gpx_{{ snakeCase pluginName }}",{{/if}}
|
|
@@ -19,5 +19,5 @@ Use panel plugins when you want to do things like visualize data returned by dat
|
|
|
19
19
|
Below you can find source code for existing app plugins and other related documentation.
|
|
20
20
|
|
|
21
21
|
- [Basic panel plugin example](https://github.com/grafana/grafana-plugin-examples/tree/master/examples/panel-basic#readme)
|
|
22
|
-
- [`plugin.json` documentation](https://grafana.com/developers/plugin-tools/reference
|
|
22
|
+
- [`plugin.json` documentation](https://grafana.com/developers/plugin-tools/reference/plugin-json)
|
|
23
23
|
- [How to sign a plugin?](https://grafana.com/developers/plugin-tools/publish-a-plugin/sign-a-plugin)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://raw.githubusercontent.com/grafana/grafana/main/docs/sources/developers/plugins/plugin.schema.json",
|
|
3
3
|
"type": "panel",
|
|
4
4
|
"name": "{{ titleCase pluginName }}",
|
|
5
|
-
"id": "{{
|
|
5
|
+
"id": "{{ pluginId }}",
|
|
6
6
|
"info": {
|
|
7
7
|
"keywords": ["panel"],
|
|
8
8
|
"description": "{{ sentenceCase pluginDescription }}",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://raw.githubusercontent.com/grafana/grafana/main/docs/sources/developers/plugins/plugin.schema.json",
|
|
3
3
|
"type": "app",
|
|
4
4
|
"name": "{{ titleCase pluginName }}",
|
|
5
|
-
"id": "{{
|
|
5
|
+
"id": "{{ pluginId }}",{{#if hasBackend}}
|
|
6
6
|
"backend": true,
|
|
7
7
|
"executable": "gpx_{{ snakeCase pluginName }}",{{/if}}
|
|
8
8
|
"info": {
|
package/dist/commands/types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/src/commands/types.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { PLUGIN_TYPES } from '../constants.js';
|
|
2
|
-
|
|
3
|
-
export type CliArgs = {
|
|
4
|
-
pluginName: string;
|
|
5
|
-
pluginDescription: string;
|
|
6
|
-
orgName: string;
|
|
7
|
-
pluginType: PLUGIN_TYPES;
|
|
8
|
-
hasBackend: boolean;
|
|
9
|
-
hasGithubWorkflows: boolean;
|
|
10
|
-
hasGithubLevitateWorkflow: boolean;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export type TemplateData = {
|
|
14
|
-
pluginId: string;
|
|
15
|
-
packageManagerName: string;
|
|
16
|
-
packageManagerInstallCmd: string;
|
|
17
|
-
packageManagerVersion: string;
|
|
18
|
-
isAppType: boolean;
|
|
19
|
-
isNPM: boolean;
|
|
20
|
-
version: string;
|
|
21
|
-
bundleGrafanaUI: boolean;
|
|
22
|
-
useReactRouterV6: boolean;
|
|
23
|
-
reactRouterVersion: string;
|
|
24
|
-
};
|