Skip to content

Commit

Permalink
[Feature Flags Service] Hello world 👋 (#188562)
Browse files Browse the repository at this point in the history
Co-authored-by: kibanamachine <[email protected]>
Co-authored-by: Jean-Louis Leysens <[email protected]>
  • Loading branch information
3 people committed Sep 18, 2024
1 parent 38d6143 commit 02ce1b9
Show file tree
Hide file tree
Showing 164 changed files with 3,607 additions and 1,943 deletions.
7 changes: 7 additions & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,12 @@ packages/core/execution-context/core-execution-context-server-mocks @elastic/kib
packages/core/fatal-errors/core-fatal-errors-browser @elastic/kibana-core
packages/core/fatal-errors/core-fatal-errors-browser-internal @elastic/kibana-core
packages/core/fatal-errors/core-fatal-errors-browser-mocks @elastic/kibana-core
packages/core/feature-flags/core-feature-flags-browser @elastic/kibana-core
packages/core/feature-flags/core-feature-flags-browser-internal @elastic/kibana-core
packages/core/feature-flags/core-feature-flags-browser-mocks @elastic/kibana-core
packages/core/feature-flags/core-feature-flags-server @elastic/kibana-core
packages/core/feature-flags/core-feature-flags-server-internal @elastic/kibana-core
packages/core/feature-flags/core-feature-flags-server-mocks @elastic/kibana-core
test/plugin_functional/plugins/core_history_block @elastic/kibana-core
packages/core/http/core-http-browser @elastic/kibana-core
packages/core/http/core-http-browser-internal @elastic/kibana-core
Expand Down Expand Up @@ -453,6 +459,7 @@ examples/expressions_explorer @elastic/kibana-visualizations
src/plugins/expressions @elastic/kibana-visualizations
packages/kbn-failed-test-reporter-cli @elastic/kibana-operations @elastic/appex-qa
examples/feature_control_examples @elastic/kibana-security
examples/feature_flags_example @elastic/kibana-core
x-pack/test/plugin_api_integration/plugins/feature_usage_test @elastic/kibana-security
x-pack/plugins/features @elastic/kibana-core
x-pack/test/functional_execution_context/plugins/alerts @elastic/kibana-core
Expand Down
10 changes: 5 additions & 5 deletions dev_docs/nav-kibana-dev.docnav.json
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,6 @@
},
{
"id": "kibDevDocsEmbeddables"
},
{
"id": "kibCloudExperimentsPlugin",
"label": "A/B testing on Elastic Cloud"
}
]
},
Expand Down Expand Up @@ -205,6 +201,10 @@
},
{
"id": "kibDevTutorialCcsSetup"
},
{
"id": "kibFeatureFlagsService",
"label": "Feature Flags"
}
]
},
Expand Down Expand Up @@ -646,4 +646,4 @@
]
}
]
}
}
4 changes: 2 additions & 2 deletions docs/developer/plugin-list.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -499,8 +499,8 @@ The plugin exposes the static DefaultEditorController class to consume.
|{kib-repo}blob/{branch}/x-pack/plugins/cloud_integrations/cloud_experiments/README.mdx[cloudExperiments]
|[!WARNING]
These APIs are deprecated and should not be used as we're working on a replacement Core Feature Flags Service that will arrive soon.
|[!NOTE]
This plugin no-longer exposes any evaluation APIs. Refer to <DocLink id="kibFeatureFlagsService" /> for more information about how to interact with feature flags.
|{kib-repo}blob/{branch}/x-pack/plugins/cloud_integrations/cloud_full_story/README.md[cloudFullStory]
Expand Down
5 changes: 5 additions & 0 deletions examples/feature_flags_example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# featureFlagsExample

This plugin's goal is to demonstrate how to use the core feature flags service.

Refer to [the docs](../../packages/core/feature-flags/README.mdx) to know more.
12 changes: 12 additions & 0 deletions examples/feature_flags_example/common/feature_flags.ts
Original file line number Diff line number Diff line change
@@ -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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

export const FeatureFlagExampleBoolean = 'example-boolean';
export const FeatureFlagExampleString = 'example-string';
export const FeatureFlagExampleNumber = 'example-number';
11 changes: 11 additions & 0 deletions examples/feature_flags_example/common/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

export const PLUGIN_ID = 'featureFlagsExample';
export const PLUGIN_NAME = 'Feature Flags Example';
13 changes: 13 additions & 0 deletions examples/feature_flags_example/kibana.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"type": "plugin",
"id": "@kbn/feature-flags-example-plugin",
"owner": "@elastic/kibana-core",
"description": "Plugin that shows how to make use of the feature flags core service.",
"plugin": {
"id": "featureFlagsExample",
"server": true,
"browser": true,
"requiredPlugins": ["developerExamples"],
"optionalPlugins": []
}
}
33 changes: 33 additions & 0 deletions examples/feature_flags_example/public/application.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import React from 'react';
import ReactDOM from 'react-dom';
import { AppMountParameters, CoreStart } from '@kbn/core/public';
import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';
import { KibanaRootContextProvider } from '@kbn/react-kibana-context-root';
import { FeatureFlagsExampleApp } from './components/app';

export const renderApp = (coreStart: CoreStart, { element }: AppMountParameters) => {
const { notifications, http, featureFlags } = coreStart;
ReactDOM.render(
<KibanaRootContextProvider {...coreStart}>
<KibanaPageTemplate>
<FeatureFlagsExampleApp
featureFlags={featureFlags}
notifications={notifications}
http={http}
/>
</KibanaPageTemplate>
</KibanaRootContextProvider>,
element
);

return () => ReactDOM.unmountComponentAtNode(element);
};
91 changes: 91 additions & 0 deletions examples/feature_flags_example/public/components/app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import React from 'react';
import {
EuiHorizontalRule,
EuiPageTemplate,
EuiTitle,
EuiText,
EuiLink,
EuiListGroup,
EuiListGroupItem,
} from '@elastic/eui';
import type { CoreStart, FeatureFlagsStart } from '@kbn/core/public';

import useObservable from 'react-use/lib/useObservable';
import {
FeatureFlagExampleBoolean,
FeatureFlagExampleNumber,
FeatureFlagExampleString,
} from '../../common/feature_flags';
import { PLUGIN_NAME } from '../../common';

interface FeatureFlagsExampleAppDeps {
featureFlags: FeatureFlagsStart;
notifications: CoreStart['notifications'];
http: CoreStart['http'];
}

export const FeatureFlagsExampleApp = ({ featureFlags }: FeatureFlagsExampleAppDeps) => {
// Fetching the feature flags synchronously
const bool = featureFlags.getBooleanValue(FeatureFlagExampleBoolean, false);
const str = featureFlags.getStringValue(FeatureFlagExampleString, 'red');
const num = featureFlags.getNumberValue(FeatureFlagExampleNumber, 1);

// Use React Hooks to observe feature flags changes
const bool$ = useObservable(featureFlags.getBooleanValue$(FeatureFlagExampleBoolean, false));
const str$ = useObservable(featureFlags.getStringValue$(FeatureFlagExampleString, 'red'));
const num$ = useObservable(featureFlags.getNumberValue$(FeatureFlagExampleNumber, 1));

return (
<>
<EuiPageTemplate>
<EuiPageTemplate.Header>
<EuiTitle size="l">
<h1>{PLUGIN_NAME}</h1>
</EuiTitle>
</EuiPageTemplate.Header>
<EuiPageTemplate.Section>
<EuiTitle>
<h2>Demo of the feature flags service</h2>
</EuiTitle>
<EuiText>
<p>
To learn more, refer to{' '}
<EuiLink
href={'https://docs.elastic.dev/kibana-dev-docs/tutorials/feature-flags-service'}
>
the docs
</EuiLink>
.
</p>
<EuiHorizontalRule />
<EuiListGroup>
<p>
The feature flags are:
<EuiListGroupItem label={`${FeatureFlagExampleBoolean}: ${bool}`} />
<EuiListGroupItem label={`${FeatureFlagExampleString}: ${str}`} />
<EuiListGroupItem label={`${FeatureFlagExampleNumber}: ${num}`} />
</p>
</EuiListGroup>
<EuiListGroup>
<p>
The <strong>observed</strong> feature flags are:
<EuiListGroupItem label={`${FeatureFlagExampleBoolean}: ${bool$}`} />
<EuiListGroupItem label={`${FeatureFlagExampleString}: ${str$}`} />
<EuiListGroupItem label={`${FeatureFlagExampleNumber}: ${num$}`} />
</p>
</EuiListGroup>
</EuiText>
</EuiPageTemplate.Section>
</EuiPageTemplate>
</>
);
};
14 changes: 14 additions & 0 deletions examples/feature_flags_example/public/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import { FeatureFlagsExamplePlugin } from './plugin';

export function plugin() {
return new FeatureFlagsExamplePlugin();
}
40 changes: 40 additions & 0 deletions examples/feature_flags_example/public/plugin.ts
Original file line number Diff line number Diff line change
@@ -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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import { AppMountParameters, CoreSetup, CoreStart, Plugin } from '@kbn/core/public';
import { AppPluginSetupDependencies } from './types';
import { PLUGIN_NAME } from '../common';

export class FeatureFlagsExamplePlugin implements Plugin {
public setup(core: CoreSetup, deps: AppPluginSetupDependencies) {
// Register an application into the side navigation menu
core.application.register({
id: 'featureFlagsExample',
title: PLUGIN_NAME,
async mount(params: AppMountParameters) {
// Load application bundle
const { renderApp } = await import('./application');
// Get start services as specified in kibana.json
const [coreStart] = await core.getStartServices();
// Render the application
return renderApp(coreStart, params);
},
});

deps.developerExamples.register({
appId: 'featureFlagsExample',
title: PLUGIN_NAME,
description: 'Plugin that shows how to make use of the feature flags core service.',
});
}

public start(core: CoreStart) {}

public stop() {}
}
14 changes: 14 additions & 0 deletions examples/feature_flags_example/public/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import type { DeveloperExamplesSetup } from '@kbn/developer-examples-plugin/public';

export interface AppPluginSetupDependencies {
developerExamples: DeveloperExamplesSetup;
}
77 changes: 77 additions & 0 deletions examples/feature_flags_example/server/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import type { FeatureFlagDefinitions } from '@kbn/core-feature-flags-server';
import type { PluginInitializerContext } from '@kbn/core-plugins-server';
import {
FeatureFlagExampleBoolean,
FeatureFlagExampleNumber,
FeatureFlagExampleString,
} from '../common/feature_flags';

export const featureFlags: FeatureFlagDefinitions = [
{
key: FeatureFlagExampleBoolean,
name: 'Example boolean',
description: 'This is a demo of a boolean flag',
tags: ['example', 'my-plugin'],
variationType: 'boolean',
variations: [
{
name: 'On',
description: 'Auto-hides the bar',
value: true,
},
{
name: 'Off',
description: 'Static always-on',
value: false,
},
],
},
{
key: FeatureFlagExampleString,
name: 'Example string',
description: 'This is a demo of a string flag',
tags: ['example', 'my-plugin'],
variationType: 'string',
variations: [
{
name: 'Pink',
value: '#D75489',
},
{
name: 'Turquoise',
value: '#65BAAF',
},
],
},
{
key: FeatureFlagExampleNumber,
name: 'Example Number',
description: 'This is a demo of a number flag',
tags: ['example', 'my-plugin'],
variationType: 'number',
variations: [
{
name: 'Five',
value: 5,
},
{
name: 'Ten',
value: 10,
},
],
},
];

export async function plugin(initializerContext: PluginInitializerContext) {
const { FeatureFlagsExamplePlugin } = await import('./plugin');
return new FeatureFlagsExamplePlugin(initializerContext);
}
Loading

0 comments on commit 02ce1b9

Please sign in to comment.