mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
* Allow custom paths * Add translation file * Fix jest test * Added more tests * Update docs Content of translation jsons * Leave only one translation file * generate default translations file * Simplify i18n setup * Code review changes Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
c5727c1f2f
commit
ea14b97420
5 changed files with 209 additions and 30 deletions
|
@ -44,19 +44,14 @@ exports.run = function run(argv) {
|
|||
# {dim Usage:}
|
||||
node scripts/generate-plugin {bold [name]}
|
||||
Generate a fresh Kibana plugin in the plugins/ directory
|
||||
|
||||
# {dim Core Kibana plugins:}
|
||||
node scripts/generate-plugin {bold [name]} -i
|
||||
To generate a core Kibana plugin inside the src/plugins/ directory, add the -i flag.
|
||||
`) + '\n'
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const name = options._[0];
|
||||
const isKibanaPlugin = options.internal;
|
||||
const template = resolve(__dirname, './sao_template');
|
||||
const kibanaPlugins = resolve(__dirname, isKibanaPlugin ? '../../src/plugins' : '../../plugins');
|
||||
const kibanaPlugins = resolve(process.cwd(), 'plugins');
|
||||
const targetPath = resolve(kibanaPlugins, snakeCase(name));
|
||||
|
||||
sao({
|
||||
|
@ -64,7 +59,6 @@ exports.run = function run(argv) {
|
|||
targetPath: targetPath,
|
||||
configOptions: {
|
||||
name,
|
||||
isKibanaPlugin,
|
||||
targetPath,
|
||||
},
|
||||
}).catch(error => {
|
||||
|
|
|
@ -17,7 +17,8 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
const { relative } = require('path');
|
||||
const { relative, resolve } = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
const startCase = require('lodash.startcase');
|
||||
const camelCase = require('lodash.camelcase');
|
||||
|
@ -29,9 +30,55 @@ const pkg = require('../package.json');
|
|||
const kibanaPkgPath = require.resolve('../../../package.json');
|
||||
const kibanaPkg = require(kibanaPkgPath); // eslint-disable-line import/no-dynamic-require
|
||||
|
||||
module.exports = function({ name, targetPath, isKibanaPlugin }) {
|
||||
async function gitInit(dir) {
|
||||
// Only plugins in /plugins get git init
|
||||
try {
|
||||
await execa('git', ['init', dir]);
|
||||
console.log(`Git repo initialized in ${dir}`);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw new Error(`Failure to git init ${dir}: ${error.all || error}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function moveToCustomFolder(from, to) {
|
||||
try {
|
||||
await execa('mv', [from, to]);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw new Error(`Failure to move plugin to ${to}: ${error.all || error}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function eslintPlugin(dir) {
|
||||
try {
|
||||
await execa('yarn', ['lint:es', `./${dir}/**/*.ts*`, '--no-ignore', '--fix']);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw new Error(`Failure when running prettier on the generated output: ${error.all || error}`);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = function({ name, targetPath }) {
|
||||
return {
|
||||
prompts: {
|
||||
customPath: {
|
||||
message: 'Would you like to create the plugin in a different folder?',
|
||||
default: '/plugins',
|
||||
filter(value) {
|
||||
// Keep default value empty
|
||||
if (value === '/plugins') return '';
|
||||
// Remove leading slash
|
||||
return value.startsWith('/') ? value.slice(1) : value;
|
||||
},
|
||||
validate(customPath) {
|
||||
const p = resolve(process.cwd(), customPath);
|
||||
const exists = fs.existsSync(p);
|
||||
if (!exists)
|
||||
return `Folder should exist relative to the kibana root folder. Consider /src/plugins or /x-pack/plugins.`;
|
||||
return true;
|
||||
},
|
||||
},
|
||||
description: {
|
||||
message: 'Provide a short description',
|
||||
default: 'An awesome Kibana plugin',
|
||||
|
@ -50,11 +97,18 @@ module.exports = function({ name, targetPath, isKibanaPlugin }) {
|
|||
message: 'Should a server API be generated?',
|
||||
default: true,
|
||||
},
|
||||
// generateTranslations: {
|
||||
// type: 'confirm',
|
||||
// message: 'Should translation files be generated?',
|
||||
// default: true,
|
||||
// },
|
||||
generateTranslations: {
|
||||
type: 'confirm',
|
||||
when: answers => {
|
||||
// only for 3rd party plugins
|
||||
return !answers.customPath && answers.generateApp;
|
||||
},
|
||||
message: 'Should translation files be generated?',
|
||||
default({ customPath }) {
|
||||
// only for 3rd party plugins
|
||||
return !customPath;
|
||||
},
|
||||
},
|
||||
generateScss: {
|
||||
type: 'confirm',
|
||||
message: 'Should SCSS be used?',
|
||||
|
@ -64,19 +118,22 @@ module.exports = function({ name, targetPath, isKibanaPlugin }) {
|
|||
generateEslint: {
|
||||
type: 'confirm',
|
||||
message: 'Would you like to use a custom eslint file?',
|
||||
default: !isKibanaPlugin,
|
||||
default({ customPath }) {
|
||||
return !customPath;
|
||||
},
|
||||
},
|
||||
},
|
||||
filters: {
|
||||
'public/**/index.scss': 'generateScss',
|
||||
'public/**/*': 'generateApp',
|
||||
'server/**/*': 'generateApi',
|
||||
// 'translations/**/*': 'generateTranslations',
|
||||
// '.i18nrc.json': 'generateTranslations',
|
||||
'translations/**/*': 'generateTranslations',
|
||||
'i18nrc.json': 'generateTranslations',
|
||||
'eslintrc.js': 'generateEslint',
|
||||
},
|
||||
move: {
|
||||
'eslintrc.js': '.eslintrc.js',
|
||||
'i18nrc.json': '.i18nrc.json',
|
||||
},
|
||||
data: answers =>
|
||||
Object.assign(
|
||||
|
@ -86,31 +143,35 @@ module.exports = function({ name, targetPath, isKibanaPlugin }) {
|
|||
camelCase,
|
||||
snakeCase,
|
||||
name,
|
||||
isKibanaPlugin,
|
||||
// kibana plugins are placed in a the non default path
|
||||
isKibanaPlugin: !answers.customPath,
|
||||
kbnVersion: answers.kbnVersion,
|
||||
upperCamelCaseName: name.charAt(0).toUpperCase() + camelCase(name).slice(1),
|
||||
hasUi: !!answers.generateApp,
|
||||
hasServer: !!answers.generateApi,
|
||||
hasScss: !!answers.generateScss,
|
||||
relRoot: isKibanaPlugin ? '../../../..' : '../../..',
|
||||
relRoot: relative(
|
||||
resolve(answers.customPath || targetPath, name, 'public'),
|
||||
process.cwd()
|
||||
),
|
||||
},
|
||||
answers
|
||||
),
|
||||
enforceNewFolder: true,
|
||||
installDependencies: false,
|
||||
gitInit: !isKibanaPlugin,
|
||||
async post({ log }) {
|
||||
const dir = relative(process.cwd(), targetPath);
|
||||
async post({ log, answers }) {
|
||||
let dir = relative(process.cwd(), targetPath);
|
||||
if (answers.customPath) {
|
||||
// Move to custom path
|
||||
moveToCustomFolder(targetPath, answers.customPath);
|
||||
dir = relative(process.cwd(), resolve(answers.customPath, snakeCase(name)));
|
||||
} else {
|
||||
// Init git only in the default path
|
||||
await gitInit(dir);
|
||||
}
|
||||
|
||||
// Apply eslint to the generated plugin
|
||||
try {
|
||||
await execa('yarn', ['lint:es', `./${dir}/**/*.ts*`, '--no-ignore', '--fix']);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw new Error(
|
||||
`Failure when running prettier on the generated output: ${error.all || error}`
|
||||
);
|
||||
}
|
||||
eslintPlugin(dir);
|
||||
|
||||
log.success(chalk`🎉
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ const template = {
|
|||
fromPath: __dirname,
|
||||
configOptions: {
|
||||
name: 'Some fancy plugin',
|
||||
targetPath: '',
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -46,6 +47,7 @@ describe('plugin generator sao integration', () => {
|
|||
const res = await sao.mockPrompt(template, {
|
||||
generateApp: true,
|
||||
generateApi: false,
|
||||
generateScss: true,
|
||||
});
|
||||
|
||||
// check output files
|
||||
|
@ -54,6 +56,7 @@ describe('plugin generator sao integration', () => {
|
|||
expect(res.fileList).toContain('public/plugin.ts');
|
||||
expect(res.fileList).toContain('public/types.ts');
|
||||
expect(res.fileList).toContain('public/components/app.tsx');
|
||||
expect(res.fileList).toContain('public/index.scss');
|
||||
expect(res.fileList).not.toContain('server/index.ts');
|
||||
});
|
||||
|
||||
|
@ -71,6 +74,20 @@ describe('plugin generator sao integration', () => {
|
|||
expect(res.fileList).toContain('server/routes/index.ts');
|
||||
});
|
||||
|
||||
it('skips eslintrc and scss', async () => {
|
||||
const res = await sao.mockPrompt(template, {
|
||||
generateApp: true,
|
||||
generateApi: true,
|
||||
generateScss: false,
|
||||
generateEslint: false,
|
||||
});
|
||||
|
||||
// check output files
|
||||
expect(res.fileList).toContain('public/plugin.ts');
|
||||
expect(res.fileList).not.toContain('public/index.scss');
|
||||
expect(res.fileList).not.toContain('.eslintrc.js');
|
||||
});
|
||||
|
||||
it('plugin package has correct title', async () => {
|
||||
const res = await sao.mockPrompt(template, {
|
||||
generateApp: true,
|
||||
|
@ -120,5 +137,20 @@ describe('plugin generator sao integration', () => {
|
|||
it('includes dotfiles', async () => {
|
||||
const res = await sao.mockPrompt(template);
|
||||
expect(res.files['.eslintrc.js']).toBeTruthy();
|
||||
expect(res.files['.i18nrc.json']).toBeTruthy();
|
||||
});
|
||||
|
||||
it('validaes path override', async () => {
|
||||
try {
|
||||
await sao.mockPrompt(template, {
|
||||
generateApp: true,
|
||||
generateApi: true,
|
||||
generateScss: false,
|
||||
generateEslint: false,
|
||||
customPath: 'banana',
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.message).toContain('Validation failed at prompt "customPath"');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"prefix": "<%= camelCase(name) %>",
|
||||
"paths": {
|
||||
"<%= camelCase(name) %>": "."
|
||||
},
|
||||
"translations": [
|
||||
"translations/ja-JP.json"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
|
||||
{
|
||||
"formats": {
|
||||
"number": {
|
||||
"currency": {
|
||||
"style": "currency"
|
||||
},
|
||||
"percent": {
|
||||
"style": "percent"
|
||||
}
|
||||
},
|
||||
"date": {
|
||||
"short": {
|
||||
"month": "numeric",
|
||||
"day": "numeric",
|
||||
"year": "2-digit"
|
||||
},
|
||||
"medium": {
|
||||
"month": "short",
|
||||
"day": "numeric",
|
||||
"year": "numeric"
|
||||
},
|
||||
"long": {
|
||||
"month": "long",
|
||||
"day": "numeric",
|
||||
"year": "numeric"
|
||||
},
|
||||
"full": {
|
||||
"weekday": "long",
|
||||
"month": "long",
|
||||
"day": "numeric",
|
||||
"year": "numeric"
|
||||
}
|
||||
},
|
||||
"time": {
|
||||
"short": {
|
||||
"hour": "numeric",
|
||||
"minute": "numeric"
|
||||
},
|
||||
"medium": {
|
||||
"hour": "numeric",
|
||||
"minute": "numeric",
|
||||
"second": "numeric"
|
||||
},
|
||||
"long": {
|
||||
"hour": "numeric",
|
||||
"minute": "numeric",
|
||||
"second": "numeric",
|
||||
"timeZoneName": "short"
|
||||
},
|
||||
"full": {
|
||||
"hour": "numeric",
|
||||
"minute": "numeric",
|
||||
"second": "numeric",
|
||||
"timeZoneName": "short"
|
||||
}
|
||||
},
|
||||
"relative": {
|
||||
"years": {
|
||||
"units": "year"
|
||||
},
|
||||
"months": {
|
||||
"units": "month"
|
||||
},
|
||||
"days": {
|
||||
"units": "day"
|
||||
},
|
||||
"hours": {
|
||||
"units": "hour"
|
||||
},
|
||||
"minutes": {
|
||||
"units": "minute"
|
||||
},
|
||||
"seconds": {
|
||||
"units": "second"
|
||||
}
|
||||
}
|
||||
},
|
||||
"messages": {
|
||||
"<%= camelCase(name) %>.buttonText": "Translate me to Japanese",
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue