@grafana/create-plugin 3.4.0 → 3.6.0-canary.669.68b0597.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 CHANGED
@@ -1,3 +1,15 @@
1
+ # v3.5.0 (Fri Feb 02 2024)
2
+
3
+ #### 🚀 Enhancement
4
+
5
+ - Create-plugin: Use react-router v6 by default [#710](https://github.com/grafana/plugin-tools/pull/710) ([@leventebalogh](https://github.com/leventebalogh))
6
+
7
+ #### Authors: 1
8
+
9
+ - Levente Balogh ([@leventebalogh](https://github.com/leventebalogh))
10
+
11
+ ---
12
+
1
13
  # v3.4.0 (Fri Feb 02 2024)
2
14
 
3
15
  :tada: This release contains work from a new contributor! :tada:
@@ -11,7 +11,7 @@ import { getPackageManagerFromUserAgent, getPackageManagerInstallCmd } from '../
11
11
  import { getExportPath } from '../utils/utils.path.js';
12
12
  import { renderTemplateFromFile } from '../utils/utils.templates.js';
13
13
  import { getVersion } from '../utils/utils.version.js';
14
- import { prettifyFiles } from './generate/prettify-files.js';
14
+ import { prettifyFiles } from '../utils/utils.prettifyFiles.js';
15
15
  import { printGenerateSuccessMessage } from './generate/print-success-message.js';
16
16
  import { promptUser } from './generate/prompt-user.js';
17
17
  import { updateGoSdkAndModules } from './generate/update-go-sdk-and-packages.js';
@@ -36,7 +36,7 @@ export const generate = async (argv) => {
36
36
  if (answers.hasBackend) {
37
37
  await execPostScaffoldFunction(updateGoSdkAndModules, exportPath);
38
38
  }
39
- await execPostScaffoldFunction(prettifyFiles, exportPath);
39
+ await execPostScaffoldFunction(prettifyFiles, { targetPath: exportPath });
40
40
  printGenerateSuccessMessage(answers);
41
41
  };
42
42
  function getTemplateData(answers) {
@@ -47,6 +47,7 @@ function getTemplateData(answers) {
47
47
  const { packageManagerName, packageManagerVersion } = getPackageManagerFromUserAgent();
48
48
  const packageManagerInstallCmd = getPackageManagerInstallCmd(packageManagerName);
49
49
  const isAppType = pluginType === PLUGIN_TYPES.app || pluginType === PLUGIN_TYPES.scenes;
50
+ const useReactRouterV6 = features.useReactRouterV6 && pluginType === PLUGIN_TYPES.app;
50
51
  const templateData = {
51
52
  ...answers,
52
53
  pluginId,
@@ -57,6 +58,8 @@ function getTemplateData(answers) {
57
58
  isNPM: packageManagerName === 'npm',
58
59
  version: currentVersion,
59
60
  bundleGrafanaUI: features.bundleGrafanaUI,
61
+ useReactRouterV6,
62
+ reactRouterVersion: useReactRouterV6 ? '6.22.0' : '5.2.0',
60
63
  };
61
64
  return templateData;
62
65
  }
@@ -3,9 +3,10 @@ import { TEXT, UDPATE_CONFIG } from '../constants.js';
3
3
  import { compileTemplateFiles, getTemplateData } from '../utils/utils.templates.js';
4
4
  import { confirmPrompt, selectPrompt, printMessage, printSuccessMessage, printRedBox } from '../utils/utils.console.js';
5
5
  import { updatePackageJson, hasNpmDependenciesToUpdate, getPackageJsonUpdatesAsText, updateNpmScripts, writePackageManagerInPackageJson, } from '../utils/utils.npm.js';
6
- import { getPackageManagerWithFallback } from '../utils/utils.packageManager.js';
7
6
  import { isGitDirectory, isGitDirectoryClean } from '../utils/utils.git.js';
8
7
  import { isPluginDirectory } from '../utils/utils.plugin.js';
8
+ import { getPackageManagerWithFallback } from '../utils/utils.packageManager.js';
9
+ import { prettifyFiles } from '../utils/utils.prettifyFiles.js';
9
10
  export const update = async (argv) => {
10
11
  try {
11
12
  if (!(await isGitDirectory()) && !argv.force) {
@@ -38,6 +39,8 @@ In case you want to proceed as is please use the ${chalk.bold('--force')} flag.)
38
39
  if (await confirmPrompt(TEXT.updateConfigPrompt)) {
39
40
  compileTemplateFiles(UDPATE_CONFIG.filesToOverride, getTemplateData());
40
41
  printSuccessMessage(TEXT.overrideFilesSuccess);
42
+ const prettifyMsg = await prettifyFiles({ targetPath: '.config', projectRoot: '.' });
43
+ printMessage(prettifyMsg);
41
44
  }
42
45
  else {
43
46
  printMessage(TEXT.overrideFilesAborted);
@@ -78,6 +81,8 @@ In case you want to proceed as is please use the ${chalk.bold('--force')} flag.)
78
81
  }
79
82
  const packageManager = getPackageManagerWithFallback();
80
83
  writePackageManagerInPackageJson(packageManager);
84
+ const prettifyMsg = await prettifyFiles({ targetPath: '.config', projectRoot: '.' });
85
+ printMessage(prettifyMsg);
81
86
  printSuccessMessage(TEXT.updateCommandSuccess);
82
87
  }
83
88
  catch (error) {
@@ -51,6 +51,7 @@ function readRCFileSync(path) {
51
51
  }
52
52
  function createFeatureFlags(flags) {
53
53
  return {
54
+ useReactRouterV6: true,
54
55
  bundleGrafanaUI: false,
55
56
  ...flags,
56
57
  };
@@ -3,8 +3,8 @@ import { TEMPLATE_PATHS } from '../constants.js';
3
3
  import { readJsonFile } from './utils.files.js';
4
4
  import { getTemplateData, renderTemplateFromFile } from './utils.templates.js';
5
5
  import fs from 'node:fs';
6
- export function getPackageJson() {
7
- return readJsonFile(path.join(process.cwd(), 'package.json'));
6
+ export function getPackageJson(rootPath = process.cwd()) {
7
+ return readJsonFile(path.join(rootPath, 'package.json'));
8
8
  }
9
9
  export function getLatestPackageJson() {
10
10
  const packageJsonPath = path.join(TEMPLATE_PATHS.common, '_package.json');
@@ -0,0 +1,31 @@
1
+ import { exec as nodeExec } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ import fs from 'node:fs';
4
+ import { getPackageJson } from './utils.packagejson.js';
5
+ const exec = promisify(nodeExec);
6
+ export async function prettifyFiles(options) {
7
+ const targetPath = options.targetPath ?? process.cwd();
8
+ const projectRoot = options.projectRoot ?? targetPath;
9
+ if (!isPrettierUsed(projectRoot)) {
10
+ return 'Prettify skipped, because it is not used in this project.';
11
+ }
12
+ if (!fs.existsSync(targetPath)) {
13
+ return '';
14
+ }
15
+ const prettierVersion = getPrettierVersion(projectRoot);
16
+ try {
17
+ let command = `npx -y prettier@${prettierVersion} . --write`;
18
+ await exec(command, { cwd: targetPath });
19
+ }
20
+ catch (error) {
21
+ throw new Error('There was a problem running prettier on the plugin files. Please run `npx -y prettier@2 . --write` manually in your plugin directory.');
22
+ }
23
+ return 'Successfully ran prettier against new plugin.';
24
+ }
25
+ function isPrettierUsed(projectRoot) {
26
+ return Boolean(getPrettierVersion(projectRoot));
27
+ }
28
+ function getPrettierVersion(projectRoot) {
29
+ const packageJson = getPackageJson(projectRoot);
30
+ return packageJson.devDependencies?.prettier || packageJson.dependencies?.prettier;
31
+ }
@@ -5,7 +5,7 @@ import mkdirp from 'mkdirp';
5
5
  import { filterOutCommonFiles, isFile, isFileStartingWith } from './utils.files.js';
6
6
  import { renderHandlebarsTemplate } from './utils.handlebars.js';
7
7
  import { getPluginJson } from './utils.plugin.js';
8
- import { TEMPLATE_PATHS, EXPORT_PATH_PREFIX, EXTRA_TEMPLATE_VARIABLES } from '../constants.js';
8
+ import { TEMPLATE_PATHS, EXPORT_PATH_PREFIX, EXTRA_TEMPLATE_VARIABLES, PLUGIN_TYPES } from '../constants.js';
9
9
  import { getPackageManagerWithFallback } from './utils.packageManager.js';
10
10
  import { getExportFileName } from '../utils/utils.files.js';
11
11
  import { getVersion } from './utils.version.js';
@@ -69,5 +69,7 @@ export function getTemplateData() {
69
69
  packageManagerVersion,
70
70
  version: currentVersion,
71
71
  bundleGrafanaUI: features.bundleGrafanaUI,
72
+ useReactRouterV6: features.useReactRouterV6 && pluginJson.type === PLUGIN_TYPES.app,
73
+ reactRouterVersion: features.useReactRouterV6 ? '6.22.0' : '5.2.0',
72
74
  };
73
75
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grafana/create-plugin",
3
- "version": "3.4.0",
3
+ "version": "3.6.0-canary.669.68b0597.0",
4
4
  "repository": {
5
5
  "directory": "packages/create-plugin",
6
6
  "url": "https://github.com/grafana/plugin-tools"
@@ -86,5 +86,5 @@
86
86
  "engines": {
87
87
  "node": ">=20"
88
88
  },
89
- "gitHead": "750878c5c6952236d376adfec30c35510555eb72"
89
+ "gitHead": "68b05979a4745baaf52da1de8a5e4c002ecb5ca6"
90
90
  }
@@ -12,7 +12,7 @@ import { getPackageManagerFromUserAgent, getPackageManagerInstallCmd } from '../
12
12
  import { getExportPath } from '../utils/utils.path.js';
13
13
  import { renderTemplateFromFile } from '../utils/utils.templates.js';
14
14
  import { getVersion } from '../utils/utils.version.js';
15
- import { prettifyFiles } from './generate/prettify-files.js';
15
+ import { prettifyFiles } from '../utils/utils.prettifyFiles.js';
16
16
  import { printGenerateSuccessMessage } from './generate/print-success-message.js';
17
17
  import { promptUser } from './generate/prompt-user.js';
18
18
  import { updateGoSdkAndModules } from './generate/update-go-sdk-and-packages.js';
@@ -45,7 +45,7 @@ export const generate = async (argv: minimist.ParsedArgs) => {
45
45
  if (answers.hasBackend) {
46
46
  await execPostScaffoldFunction(updateGoSdkAndModules, exportPath);
47
47
  }
48
- await execPostScaffoldFunction(prettifyFiles, exportPath);
48
+ await execPostScaffoldFunction(prettifyFiles, { targetPath: exportPath });
49
49
 
50
50
  printGenerateSuccessMessage(answers);
51
51
  };
@@ -59,6 +59,7 @@ function getTemplateData(answers: CliArgs) {
59
59
  const { packageManagerName, packageManagerVersion } = getPackageManagerFromUserAgent();
60
60
  const packageManagerInstallCmd = getPackageManagerInstallCmd(packageManagerName);
61
61
  const isAppType = pluginType === PLUGIN_TYPES.app || pluginType === PLUGIN_TYPES.scenes;
62
+ const useReactRouterV6 = features.useReactRouterV6 && pluginType === PLUGIN_TYPES.app;
62
63
  const templateData: TemplateData = {
63
64
  ...answers,
64
65
  pluginId,
@@ -69,6 +70,8 @@ function getTemplateData(answers: CliArgs) {
69
70
  isNPM: packageManagerName === 'npm',
70
71
  version: currentVersion,
71
72
  bundleGrafanaUI: features.bundleGrafanaUI,
73
+ useReactRouterV6,
74
+ reactRouterVersion: useReactRouterV6 ? '6.22.0' : '5.2.0',
72
75
  };
73
76
 
74
77
  return templateData;
@@ -19,4 +19,6 @@ export type TemplateData = {
19
19
  isNPM: boolean;
20
20
  version: string;
21
21
  bundleGrafanaUI: boolean;
22
+ useReactRouterV6: boolean;
23
+ reactRouterVersion: string;
22
24
  };
@@ -10,9 +10,10 @@ import {
10
10
  updateNpmScripts,
11
11
  writePackageManagerInPackageJson,
12
12
  } from '../utils/utils.npm.js';
13
- import { getPackageManagerWithFallback } from '../utils/utils.packageManager.js';
14
13
  import { isGitDirectory, isGitDirectoryClean } from '../utils/utils.git.js';
15
14
  import { isPluginDirectory } from '../utils/utils.plugin.js';
15
+ import { getPackageManagerWithFallback } from '../utils/utils.packageManager.js';
16
+ import { prettifyFiles } from '../utils/utils.prettifyFiles.js';
16
17
 
17
18
  export const update = async (argv: minimist.ParsedArgs) => {
18
19
  try {
@@ -58,7 +59,11 @@ In case you want to proceed as is please use the ${chalk.bold('--force')} flag.)
58
59
  // -----------------------------------
59
60
  if (await confirmPrompt(TEXT.updateConfigPrompt)) {
60
61
  compileTemplateFiles(UDPATE_CONFIG.filesToOverride, getTemplateData());
62
+
61
63
  printSuccessMessage(TEXT.overrideFilesSuccess);
64
+
65
+ const prettifyMsg = await prettifyFiles({ targetPath: '.config', projectRoot: '.' });
66
+ printMessage(prettifyMsg);
62
67
  } else {
63
68
  printMessage(TEXT.overrideFilesAborted);
64
69
  process.exit(0);
@@ -110,6 +115,9 @@ In case you want to proceed as is please use the ${chalk.bold('--force')} flag.)
110
115
  const packageManager = getPackageManagerWithFallback();
111
116
  writePackageManagerInPackageJson(packageManager);
112
117
 
118
+ const prettifyMsg = await prettifyFiles({ targetPath: '.config', projectRoot: '.' });
119
+ printMessage(prettifyMsg);
120
+
113
121
  // 4. Summary
114
122
  // -------------
115
123
  printSuccessMessage(TEXT.updateCommandSuccess);
@@ -4,6 +4,10 @@ import { getVersion } from './utils.version.js';
4
4
 
5
5
  type FeatureFlags = {
6
6
  bundleGrafanaUI: boolean;
7
+
8
+ // If set to true, the plugin will be scaffolded with React Router v6. Defaults to true.
9
+ // (Attention! We always scaffold new projects with React Router v6, so if you are changing this to `false` manually you will need to make changes to the React code as well.)
10
+ useReactRouterV6: boolean;
7
11
  };
8
12
 
9
13
  type CreatePluginConfig = UserConfig & {
@@ -66,6 +70,7 @@ function readRCFileSync(path: string): CreatePluginConfig | undefined {
66
70
 
67
71
  function createFeatureFlags(flags?: FeatureFlags): FeatureFlags {
68
72
  return {
73
+ useReactRouterV6: true,
69
74
  bundleGrafanaUI: false,
70
75
  ...flags,
71
76
  };
@@ -10,8 +10,8 @@ export type PackageJson = {
10
10
  devDependencies: Record<string, string>;
11
11
  packageManager?: string;
12
12
  } & Record<string, any>;
13
- export function getPackageJson(): PackageJson {
14
- return readJsonFile(path.join(process.cwd(), 'package.json'));
13
+ export function getPackageJson(rootPath = process.cwd()): PackageJson {
14
+ return readJsonFile(path.join(rootPath, 'package.json'));
15
15
  }
16
16
 
17
17
  // Returns with a package.json that is generated based on the latest templates
@@ -0,0 +1,48 @@
1
+ import { exec as nodeExec } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ import fs from 'node:fs';
4
+ import { getPackageJson } from './utils.packagejson.js';
5
+
6
+ const exec = promisify(nodeExec);
7
+
8
+ type PrettifyFilesArgs = {
9
+ // The path where we want to prettify files, defaults to the CWD
10
+ targetPath?: string;
11
+
12
+ // In case the `targetPath` would be set to a subdirectory, e.g. `.config/`. Defaults to `targetPath`.
13
+ projectRoot?: string;
14
+ };
15
+
16
+ export async function prettifyFiles(options: PrettifyFilesArgs) {
17
+ const targetPath = options.targetPath ?? process.cwd();
18
+ const projectRoot = options.projectRoot ?? targetPath;
19
+
20
+ if (!isPrettierUsed(projectRoot)) {
21
+ return 'Prettify skipped, because it is not used in this project.';
22
+ }
23
+
24
+ if (!fs.existsSync(targetPath)) {
25
+ return '';
26
+ }
27
+
28
+ const prettierVersion = getPrettierVersion(projectRoot);
29
+
30
+ try {
31
+ let command = `npx -y prettier@${prettierVersion} . --write`;
32
+ await exec(command, { cwd: targetPath });
33
+ } catch (error) {
34
+ throw new Error(
35
+ 'There was a problem running prettier on the plugin files. Please run `npx -y prettier@2 . --write` manually in your plugin directory.'
36
+ );
37
+ }
38
+ return 'Successfully ran prettier against new plugin.';
39
+ }
40
+
41
+ function isPrettierUsed(projectRoot?: string) {
42
+ return Boolean(getPrettierVersion(projectRoot));
43
+ }
44
+
45
+ function getPrettierVersion(projectRoot?: string) {
46
+ const packageJson = getPackageJson(projectRoot);
47
+ return packageJson.devDependencies?.prettier || packageJson.dependencies?.prettier;
48
+ }
@@ -5,7 +5,7 @@ import mkdirp from 'mkdirp';
5
5
  import { filterOutCommonFiles, isFile, isFileStartingWith } from './utils.files.js';
6
6
  import { renderHandlebarsTemplate } from './utils.handlebars.js';
7
7
  import { getPluginJson } from './utils.plugin.js';
8
- import { TEMPLATE_PATHS, EXPORT_PATH_PREFIX, EXTRA_TEMPLATE_VARIABLES } from '../constants.js';
8
+ import { TEMPLATE_PATHS, EXPORT_PATH_PREFIX, EXTRA_TEMPLATE_VARIABLES, PLUGIN_TYPES } from '../constants.js';
9
9
  import { getPackageManagerWithFallback } from './utils.packageManager.js';
10
10
  import { getExportFileName } from '../utils/utils.files.js';
11
11
  import { getVersion } from './utils.version.js';
@@ -97,5 +97,7 @@ export function getTemplateData() {
97
97
  packageManagerVersion,
98
98
  version: currentVersion,
99
99
  bundleGrafanaUI: features.bundleGrafanaUI,
100
+ useReactRouterV6: features.useReactRouterV6 && pluginJson.type === PLUGIN_TYPES.app,
101
+ reactRouterVersion: features.useReactRouterV6 ? '6.22.0' : '5.2.0',
100
102
  };
101
103
  }
@@ -1,21 +1,20 @@
1
1
  import React from 'react';
2
- import { Route, Switch } from 'react-router-dom';
2
+ import { Route, Routes } from 'react-router-dom';
3
3
  import { AppRootProps } from '@grafana/data';
4
4
  import { ROUTES } from '../../constants';
5
5
  import { PageFour, PageOne, PageThree, PageTwo } from '../../pages';
6
- import { prefixRoute } from '../../utils/utils.routing';
7
6
 
8
7
  export function App(props: AppRootProps) {
9
8
  return (
10
- <Switch>
11
- <Route exact path={prefixRoute(ROUTES.Two)} component={PageTwo} />
12
- <Route exact path={prefixRoute(`${ROUTES.Three}/:id?`)} component={PageThree} />
9
+ <Routes>
10
+ <Route path={ROUTES.Two} element={<PageTwo />} />
11
+ <Route path={`${ROUTES.Three}/:id?`} element={<PageThree />} />
13
12
 
14
13
  {/* Full-width page (this page will have no side navigation) */}
15
- <Route exact path={prefixRoute(ROUTES.Four)} component={PageFour} />
14
+ <Route path={ROUTES.Four} element={<PageFour />} />
16
15
 
17
16
  {/* Default page */}
18
- <Route component={PageOne} />
19
- </Switch>
17
+ <Route path="*" element={<PageOne />} />
18
+ </Routes>
20
19
  );
21
20
  }
@@ -49,8 +49,8 @@ const config = async (env): Promise<Configuration> => {
49
49
  'react-redux',
50
50
  'redux',
51
51
  'rxjs',
52
- 'react-router',
53
- 'react-router-dom',
52
+ 'react-router',{{#unless useReactRouterV6}}
53
+ 'react-router-dom',{{/unless}}
54
54
  'd3',
55
55
  'angular',{{#unless bundleGrafanaUI}}
56
56
  '@grafana/ui',{{/unless}}
@@ -2,5 +2,7 @@
2
2
  "features": {
3
3
  {{#if bundleGrafanaUI}}
4
4
  "bundleGrafanaUI": true{{/if}}
5
+ {{#if useReactRouterV6}}
6
+ "useReactRouterV6": true{{/if}}
5
7
  }
6
8
  }
@@ -30,8 +30,8 @@
30
30
  "@testing-library/react": "14.0.0",
31
31
  "@types/jest": "^29.5.0",
32
32
  "@types/lodash": "^4.14.194",
33
- "@types/node": "^20.8.7",{{#if isAppType}}
34
- "@types/react-router-dom": "^5.3.3",{{/if}}
33
+ "@types/node": "^20.8.7",{{#unless useReactRouterV6}}
34
+ "@types/react-router-dom": "^{{ reactRouterVersion }}",{{/unless}}
35
35
  "@types/testing-library__jest-dom": "5.14.8",
36
36
  "copy-webpack-plugin": "^11.0.0",
37
37
  "css-loader": "^6.7.3",
@@ -67,7 +67,7 @@
67
67
  "@grafana/scenes": "^1.28.0",{{/if_eq}}
68
68
  "react": "18.2.0",
69
69
  "react-dom": "18.2.0",{{#if isAppType}}
70
- "react-router-dom": "5.3.3",
70
+ "react-router-dom": "^{{ reactRouterVersion }}",
71
71
  "rxjs": "7.8.0",{{/if}}
72
72
  "tslib": "2.5.3"
73
73
  },
@@ -1,17 +0,0 @@
1
- import { exec as nodeExec } from 'node:child_process';
2
- import { promisify } from 'node:util';
3
- import fs from 'node:fs';
4
- const exec = promisify(nodeExec);
5
- export async function prettifyFiles(exportPath) {
6
- if (!fs.existsSync(exportPath)) {
7
- return '';
8
- }
9
- try {
10
- let command = 'npx -y prettier@2 . --write';
11
- await exec(command, { cwd: exportPath });
12
- }
13
- catch (error) {
14
- throw new Error('There was a problem running prettier on the plugin files. Please run `npx -y prettier@2 . --write` manually in your plugin directory.');
15
- }
16
- return 'Successfully ran prettier against new plugin.';
17
- }
@@ -1,21 +0,0 @@
1
- import { exec as nodeExec } from 'node:child_process';
2
- import { promisify } from 'node:util';
3
- import fs from 'node:fs';
4
-
5
- const exec = promisify(nodeExec);
6
-
7
- export async function prettifyFiles(exportPath: string) {
8
- if (!fs.existsSync(exportPath)) {
9
- return '';
10
- }
11
-
12
- try {
13
- let command = 'npx -y prettier@2 . --write';
14
- await exec(command, { cwd: exportPath });
15
- } catch (error) {
16
- throw new Error(
17
- 'There was a problem running prettier on the plugin files. Please run `npx -y prettier@2 . --write` manually in your plugin directory.'
18
- );
19
- }
20
- return 'Successfully ran prettier against new plugin.';
21
- }