mirror of
https://github.com/grafana/grafana.git
synced 2025-07-29 18:42:23 +08:00
React generator (#23150)
* Toolkit: Setup templates * Toolkit: Add plop * Toolkit: Setup createComponent task * Toolkit: Use lodash templates * Toolkit: Generate story and mdx file * Toolkit: Add story type * Toolkit: Fix types * Toolkit: Add test template * Toolkit: Remove plop * Toolkit: Tweak types * Toolkit: Minor fixes * Toolkit: Add internal story option * Toolkit: Fix test * Toolkit: Clarify prompt * Toolkit: add prompt list for component group * Toolkit: make generator script internal * Toolkit: add description * Toolkit: add missing when condition
This commit is contained in:
86
packages/grafana-toolkit/src/cli/tasks/component.create.ts
Normal file
86
packages/grafana-toolkit/src/cli/tasks/component.create.ts
Normal file
@ -0,0 +1,86 @@
|
||||
import { Task, TaskRunner } from './task';
|
||||
import fs from 'fs';
|
||||
import _ from 'lodash';
|
||||
import { prompt } from 'inquirer';
|
||||
import { pascalCase } from '../utils/pascalCase';
|
||||
import { promptConfirm, promptInput, promptList } from '../utils/prompt';
|
||||
import { componentTpl, docsTpl, storyTpl, testTpl } from '../templates';
|
||||
|
||||
interface Details {
|
||||
name?: string;
|
||||
hasStory: boolean;
|
||||
group?: string;
|
||||
isStoryPublic: boolean;
|
||||
hasTests: boolean;
|
||||
}
|
||||
|
||||
interface GeneratorOptions {
|
||||
details: Details;
|
||||
path: string;
|
||||
}
|
||||
|
||||
type ComponentGenerator = (options: GeneratorOptions) => Promise<any>;
|
||||
|
||||
const componentGroups = [
|
||||
{ name: 'General', value: 'General' },
|
||||
{ name: 'Forms', value: 'Forms' },
|
||||
{ name: 'Panel', value: 'Panel' },
|
||||
{ name: 'Visualizations', value: 'Visualizations' },
|
||||
{ name: 'Others', value: 'Others' },
|
||||
];
|
||||
|
||||
export const promptDetails = () => {
|
||||
return prompt<Details>([
|
||||
promptInput('name', 'Component name', true),
|
||||
promptConfirm('hasTests', "Generate component's test file?"),
|
||||
promptConfirm('hasStory', "Generate component's story file?"),
|
||||
promptConfirm(
|
||||
'isStoryPublic',
|
||||
'Generate public story? (Selecting "No" will create an internal story)',
|
||||
true,
|
||||
({ hasStory }) => hasStory
|
||||
),
|
||||
promptList(
|
||||
'group',
|
||||
'Select component group for the story (e.g. Forms, Layout)',
|
||||
() => componentGroups,
|
||||
0,
|
||||
({ hasStory }) => hasStory
|
||||
),
|
||||
]);
|
||||
};
|
||||
|
||||
export const generateComponents: ComponentGenerator = async ({ details, path }) => {
|
||||
const name = pascalCase(details.name);
|
||||
const getCompiled = (template: string) => {
|
||||
return _.template(template)({ ...details, name });
|
||||
};
|
||||
const filePath = `${path}/${name}`;
|
||||
let paths = [];
|
||||
|
||||
fs.writeFileSync(`${filePath}.tsx`, getCompiled(componentTpl));
|
||||
paths.push(`${filePath}.tsx`);
|
||||
|
||||
if (details.hasTests) {
|
||||
fs.writeFileSync(`${filePath}.test.tsx`, getCompiled(testTpl));
|
||||
paths.push(`${filePath}.test.tsx`);
|
||||
}
|
||||
|
||||
if (details.hasStory) {
|
||||
const storyExt = details.isStoryPublic ? '.story.tsx' : '.story.internal.tsx';
|
||||
fs.writeFileSync(`${filePath}${storyExt}`, getCompiled(storyTpl));
|
||||
fs.writeFileSync(`${filePath}.mdx`, getCompiled(docsTpl));
|
||||
paths.push(`${filePath}${storyExt}`, `${filePath}.mdx`);
|
||||
}
|
||||
|
||||
console.log('Generated files:');
|
||||
console.log(paths.join('\n'));
|
||||
};
|
||||
|
||||
const componentCreateRunner: TaskRunner<any> = async () => {
|
||||
const destPath = process.cwd();
|
||||
const details = await promptDetails();
|
||||
await generateComponents({ details, path: destPath });
|
||||
};
|
||||
|
||||
export const componentCreateTask = new Task('component:create', componentCreateRunner);
|
Reference in New Issue
Block a user