diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5c54fb6ef1ce4..000943bf62d8e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -5,6 +5,10 @@ # The #CC# prefix delineates Code Coverage, # used for the 'team' designator within Kibana Stats +# Tech leads +/dev_docs @elastic/kibana-tech-leads +/packages/kbn-docs-utils/ @elastic/kibana-tech-leads @elastic/kibana-operations + # App /x-pack/plugins/discover_enhanced/ @elastic/kibana-app /x-pack/plugins/lens/ @elastic/kibana-app @@ -201,6 +205,7 @@ /test/functional/services/remote @elastic/kibana-qa # Core +/examples/hello_world/ @elastic/kibana-core /src/core/ @elastic/kibana-core /src/plugins/saved_objects_tagging_oss @elastic/kibana-core /config/kibana.yml @elastic/kibana-core diff --git a/dev_docs/dev_welcome.mdx b/dev_docs/dev_welcome.mdx deleted file mode 100644 index cc185e689fa43..0000000000000 --- a/dev_docs/dev_welcome.mdx +++ /dev/null @@ -1,17 +0,0 @@ ---- -id: kibDevDocsWelcome -slug: /kibana-dev-docs/welcome -title: Welcome -summary: Build custom solutions and applications on top of Kibana. -date: 2021-01-02 -tags: ['kibana','dev', 'contributor'] ---- - -Welcome to Kibana's plugin developer documentation! - -Did you know that the vast majority of functionality built inside of Kibana is a plugin? A handful of core services hold the system together, -but it's our vast system of plugin developers that provide the amazing, out of the box, functionality you can use when building your own set of -custom utilities and applications. - -Browse the `Services` section to view all the plugins that offer functionality you can take advantage of, or check out the -`API documentation` to dig into the nitty gritty details of every public plugin API. diff --git a/dev_docs/getting_started/dev_welcome.mdx b/dev_docs/getting_started/dev_welcome.mdx new file mode 100644 index 0000000000000..3d645b4e54d66 --- /dev/null +++ b/dev_docs/getting_started/dev_welcome.mdx @@ -0,0 +1,20 @@ +--- +id: kibDevDocsWelcome +slug: /kibana-dev-docs/welcome +title: Welcome +summary: Build custom solutions and applications on top of Kibana. +date: 2021-01-02 +tags: ['kibana', 'dev', 'contributor'] +--- + +[Kibana](https://www.elastic.co/what-is/kibana) is a pluggable platform that allows users to search, visualize and analyze data in Elasticsearch. + +Kibana ships with many out-of-the-box capabilities that can be extended and enhanced by custom javascript plugins. Developers can also write their own custom applications. + +Recommended next reading: + +1. +2. Create a simple . + +Check out our to dig into the nitty gritty details of +every public plugin API. diff --git a/dev_docs/getting_started/hello_world_generated.png b/dev_docs/getting_started/hello_world_generated.png new file mode 100644 index 0000000000000..57f389389b794 Binary files /dev/null and b/dev_docs/getting_started/hello_world_generated.png differ diff --git a/dev_docs/getting_started/hello_world_manual.png b/dev_docs/getting_started/hello_world_manual.png new file mode 100644 index 0000000000000..bb36aab32f392 Binary files /dev/null and b/dev_docs/getting_started/hello_world_manual.png differ diff --git a/dev_docs/getting_started/hello_world_plugin.mdx b/dev_docs/getting_started/hello_world_plugin.mdx new file mode 100644 index 0000000000000..d3b30b240dedc --- /dev/null +++ b/dev_docs/getting_started/hello_world_plugin.mdx @@ -0,0 +1,157 @@ +--- +id: kibHelloWorldApp +slug: /kibana-dev-docs/hello-world-app +title: Hello World +summary: Build a very basic plugin that registers an application that says "Hello World!". +date: 2021-08-03 +tags: ['kibana', 'dev', 'contributor', 'tutorials'] +--- + +This tutorial walks you through two ways to create a plugin that registers an application that says "Hello World!". + +You can view the tested example plugin at [examples/hello_world](https://github.com/elastic/kibana/tree/master/examples/hello_world). + +## 1. Set up your development environment + +Read through to get your development environment set up. + +## 2. Option 1 - Write it manually + +This is a good option if you want to understand the bare minimum needed to register a "Hello world" application. The example plugin is based off of this option. + +1. Create your plugin folder. Start off in the `kibana` folder. + +``` +$ cd examples +$ mkdir hello_world +$ cd hello_world +``` + +2. Create the . + +``` +$ touch kibana.json +``` + +and add the following: + +``` +{ + "id": "helloWorld", + "version": "1.0.0", + "kibanaVersion": "kibana", + "ui": true +} +``` + +3. Create a `tsconfig.json` file. + +``` +$ touch tsconfig.json +``` + +And add the following to it: + +``` +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./target", + "skipLibCheck": true + }, + "include": [ + "index.ts", + "common/**/*.ts", + "public/**/*.ts", + "public/**/*.tsx", + "server/**/*.ts", + "../../typings/**/*" + ], + "exclude": [] +} +``` + +4. Create a . + +``` +$ mkdir public +$ touch plugin.tsx +``` + +And add the following to it: + +```ts +import React from 'react'; +import ReactDOM from 'react-dom'; +import { AppMountParameters, CoreSetup, CoreStart, Plugin } from '../../../src/core/public'; + +export class HelloWorldPlugin implements Plugin { + public setup(core: CoreSetup) { + // Register an application into the side navigation menu + core.application.register({ + id: 'helloWorld', + title: 'Hello World', + async mount({ element }: AppMountParameters) { + ReactDOM.render(
Hello World!
, element); + return () => ReactDOM.unmountComponentAtNode(element); + }, + }); + } + public start(core: CoreStart) { + return {}; + } + public stop() {} +} +``` + +5. Create a . + +``` +$ touch index.ts +``` + +```ts +import { HelloWorldPlugin } from './plugin'; + +export function plugin() { + return new HelloWorldPlugin(); +} +``` + +## 2. Option 2 - Use the automatic plugin generator + +This is an easy option to get up and running ASAP and includes additional code. + +Use the Automatic plugin generator to get a basic structure for a new plugin. Plugins that are not part of the Kibana repo should be developed inside the plugins folder. If you are building a new plugin to check in to the Kibana repo, you will choose between a few locations: + +`x-pack/plugins` for plugins related to subscription features +`src/plugins` for plugins related to free features +`examples` for developer example plugins (these will not be included in the distributables) + +``` +% node scripts/generate_plugin hello_world +? Plugin name (use camelCase) helloWorld +? Will this plugin be part of the Kibana repository? Yes +? What type of internal plugin would you like to create Kibana Example +? Should an UI plugin be generated? Yes +? Should a server plugin be generated? No + succ 🎉 + + Your plugin has been created in examples/hello_world +``` + +## 3. Build your new application + +Run `yarn kbn bootstrap` + +## 3. Start Kibana with examples and navigate to your new application + +In one terminal window, run `yarn es snapshot --license trial` to boot up Elasticsearch. + +In another terminal window, run `yarn start --run-examples` to boot up Kibana and include the example plugins. Your example plugin should show up in the navigation at the very bottom. + +If you build it manually it will look something like this: +![hello world manual](./hello_world_manual.png) + +If you built it with the generator, it will look something like this: +![hello world generated](./hello_world_generated.png) diff --git a/dev_docs/tutorials/setting_up_a_development_env.mdx b/dev_docs/getting_started/setting_up_a_development_env.mdx similarity index 87% rename from dev_docs/tutorials/setting_up_a_development_env.mdx rename to dev_docs/getting_started/setting_up_a_development_env.mdx index 449e8b886a44d..04e0511e255b1 100644 --- a/dev_docs/tutorials/setting_up_a_development_env.mdx +++ b/dev_docs/getting_started/setting_up_a_development_env.mdx @@ -1,8 +1,8 @@ --- id: kibDevTutorialSetupDevEnv slug: /kibana-dev-docs/tutorial/setup-dev-env -title: Setting up a Development Environment -summary: Learn how to setup a development environemnt for contributing to the Kibana repository +title: Set up a Development Environment +summary: Learn how to setup a development environment for contributing to the Kibana repository date: 2021-04-26 tags: ['kibana', 'onboarding', 'dev', 'architecture', 'setup'] --- @@ -12,11 +12,11 @@ Setting up a development environment is pretty easy. In order to support Windows development we currently require you to use one of the following: - - [Git Bash](https://git-scm.com/download/win) - - [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/about) +- [Git Bash](https://git-scm.com/download/win) +- [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/about) +Before running the steps below, please make sure you have installed [Visual C++ Redistributable for Visual Studio 2015](https://www.microsoft.com/en-us/download/details.aspx?id=48145) and that you are running all commands in either Git Bash or WSL. - Before running the steps below, please make sure you have installed [Visual C++ Redistributable for Visual Studio 2015](https://www.microsoft.com/en-us/download/details.aspx?id=48145) and that you are running all commands in either Git Bash or WSL. ## Get the code diff --git a/examples/hello_world/README.md b/examples/hello_world/README.md new file mode 100755 index 0000000000000..f43c12886f52d --- /dev/null +++ b/examples/hello_world/README.md @@ -0,0 +1,5 @@ +## Hello World + +A very simple Hello World example plugin. + +If you are external, you can view the tutorial [here](../../dev_docs/getting_started/hello_world_plugin.mdx), if you are internal, you can view the tutorial [here](https://docs.elastic.dev/kibana-dev-docs/hello-world-app). diff --git a/examples/hello_world/kibana.json b/examples/hello_world/kibana.json new file mode 100644 index 0000000000000..d3de28c2cbd7a --- /dev/null +++ b/examples/hello_world/kibana.json @@ -0,0 +1,12 @@ +{ + "id": "helloWorld", + "version": "1.0.0", + "kibanaVersion": "kibana", + "ui": true, + "owner": { + "name": "Kibana core", + "githubTeam": "kibana-core" + }, + "description": "A plugin which registers a very simple hello world application.", + "requiredPlugins": ["developerExamples"] +} diff --git a/examples/hello_world/public/index.ts b/examples/hello_world/public/index.ts new file mode 100755 index 0000000000000..51a911493e9aa --- /dev/null +++ b/examples/hello_world/public/index.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import { HelloWorldPlugin } from './plugin'; + +export function plugin() { + return new HelloWorldPlugin(); +} diff --git a/examples/hello_world/public/plugin.tsx b/examples/hello_world/public/plugin.tsx new file mode 100755 index 0000000000000..cb648bffbb57c --- /dev/null +++ b/examples/hello_world/public/plugin.tsx @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { AppMountParameters, CoreSetup, CoreStart, Plugin } from '../../../src/core/public'; +import { DeveloperExamplesSetup } from '../../developer_examples/public'; + +interface SetupDeps { + developerExamples: DeveloperExamplesSetup; +} + +export class HelloWorldPlugin implements Plugin { + public setup(core: CoreSetup, deps: SetupDeps) { + // Register an application into the side navigation menu + core.application.register({ + id: 'helloWorld', + title: 'Hello World', + async mount({ element }: AppMountParameters) { + ReactDOM.render(
Hello World!
, element); + return () => ReactDOM.unmountComponentAtNode(element); + }, + }); + + // This section is only needed to get this example plugin to show up in our Developer Examples. + deps.developerExamples.register({ + appId: 'helloWorld', + title: 'Hello World Application', + description: `Build a plugin that registers an application that simply says "Hello World"`, + }); + } + public start(core: CoreStart) { + return {}; + } + public stop() {} +} diff --git a/examples/hello_world/tsconfig.json b/examples/hello_world/tsconfig.json new file mode 100644 index 0000000000000..7fa03739119b4 --- /dev/null +++ b/examples/hello_world/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./target", + "skipLibCheck": true + }, + "include": [ + "index.ts", + "common/**/*.ts", + "public/**/*.ts", + "public/**/*.tsx", + "server/**/*.ts", + "../../typings/**/*" + ], + "exclude": [] +} diff --git a/test/examples/hello_world/index.ts b/test/examples/hello_world/index.ts new file mode 100644 index 0000000000000..d1a37968a9a6c --- /dev/null +++ b/test/examples/hello_world/index.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from 'test/functional/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function ({ getService, getPageObjects, loadTestFile }: FtrProviderContext) { + const retry = getService('retry'); + const testSubjects = getService('testSubjects'); + const PageObjects = getPageObjects(['common']); + + describe('Hello world', function () { + before(async () => { + this.tags('ciGroup2'); + await PageObjects.common.navigateToApp('helloWorld'); + }); + + it('renders hello world text', async () => { + await retry.try(async () => { + const message = await testSubjects.getVisibleText('helloWorldDiv'); + expect(message).to.be('Hello World!'); + }); + }); + }); +}