mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
* Allow nested declaration for `exposeToBrowser` (#128864)
* Allow nested declaration for `exposeToBrowser`
* update generated doc
* add utest
(cherry picked from commit dd0a19033f
)
# Conflicts:
# src/core/server/server.api.md
* update generated doc
This commit is contained in:
parent
fc773a387c
commit
d2b47b1b13
11 changed files with 341 additions and 24 deletions
|
@ -0,0 +1,16 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ExposedToBrowserDescriptor](./kibana-plugin-core-server.exposedtobrowserdescriptor.md)
|
||||
|
||||
## ExposedToBrowserDescriptor type
|
||||
|
||||
Type defining the list of configuration properties that will be exposed on the client-side Object properties can either be fully exposed
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type ExposedToBrowserDescriptor<T> = {
|
||||
[Key in keyof T]?: T[Key] extends Maybe<any[]> ? boolean : T[Key] extends Maybe<object> ? // can be nested for objects
|
||||
ExposedToBrowserDescriptor<T[Key]> | boolean : boolean;
|
||||
};
|
||||
```
|
|
@ -265,6 +265,7 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
|
|||
| [ElasticsearchClient](./kibana-plugin-core-server.elasticsearchclient.md) | Client used to query the elasticsearch cluster. |
|
||||
| [ElasticsearchClientConfig](./kibana-plugin-core-server.elasticsearchclientconfig.md) | Configuration options to be used to create a [cluster client](./kibana-plugin-core-server.iclusterclient.md) using the [createClient API](./kibana-plugin-core-server.elasticsearchservicestart.createclient.md) |
|
||||
| [ExecutionContextStart](./kibana-plugin-core-server.executioncontextstart.md) | |
|
||||
| [ExposedToBrowserDescriptor](./kibana-plugin-core-server.exposedtobrowserdescriptor.md) | Type defining the list of configuration properties that will be exposed on the client-side Object properties can either be fully exposed |
|
||||
| [GetAuthHeaders](./kibana-plugin-core-server.getauthheaders.md) | Get headers to authenticate a user against Elasticsearch. |
|
||||
| [GetAuthState](./kibana-plugin-core-server.getauthstate.md) | Gets authentication state for a request. Returned by <code>auth</code> interceptor. |
|
||||
| [HandlerContextType](./kibana-plugin-core-server.handlercontexttype.md) | Extracts the type of the first argument of a [HandlerFunction](./kibana-plugin-core-server.handlerfunction.md) to represent the type of the context. |
|
||||
|
|
|
@ -9,7 +9,5 @@ List of configuration properties that will be available on the client-side plugi
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
exposeToBrowser?: {
|
||||
[P in keyof T]?: boolean;
|
||||
};
|
||||
exposeToBrowser?: ExposedToBrowserDescriptor<T>;
|
||||
```
|
||||
|
|
|
@ -44,7 +44,7 @@ export const config: PluginConfigDescriptor<ConfigType> = {
|
|||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [deprecations?](./kibana-plugin-core-server.pluginconfigdescriptor.deprecations.md) | ConfigDeprecationProvider | <i>(Optional)</i> Provider for the to apply to the plugin configuration. |
|
||||
| [exposeToBrowser?](./kibana-plugin-core-server.pluginconfigdescriptor.exposetobrowser.md) | { \[P in keyof T\]?: boolean; } | <i>(Optional)</i> List of configuration properties that will be available on the client-side plugin. |
|
||||
| [exposeToBrowser?](./kibana-plugin-core-server.pluginconfigdescriptor.exposetobrowser.md) | ExposedToBrowserDescriptor<T> | <i>(Optional)</i> List of configuration properties that will be available on the client-side plugin. |
|
||||
| [exposeToUsage?](./kibana-plugin-core-server.pluginconfigdescriptor.exposetousage.md) | MakeUsageFromSchema<T> | <i>(Optional)</i> Expose non-default configs to usage collection to be sent via telemetry. set a config to <code>true</code> to report the actual changed config value. set a config to <code>false</code> to report the changed config value as \[redacted\].<!-- -->All changed configs except booleans and numbers will be reported as \[redacted\] unless otherwise specified.[MakeUsageFromSchema](./kibana-plugin-core-server.makeusagefromschema.md) |
|
||||
| [schema](./kibana-plugin-core-server.pluginconfigdescriptor.schema.md) | PluginConfigSchema<T> | Schema to use to validate the plugin configuration.[PluginConfigSchema](./kibana-plugin-core-server.pluginconfigschema.md) |
|
||||
|
||||
|
|
|
@ -268,6 +268,7 @@ export type {
|
|||
PluginName,
|
||||
SharedGlobalConfig,
|
||||
MakeUsageFromSchema,
|
||||
ExposedToBrowserDescriptor,
|
||||
} from './plugins';
|
||||
|
||||
export {
|
||||
|
|
162
src/core/server/plugins/create_browser_config.test.ts
Normal file
162
src/core/server/plugins/create_browser_config.test.ts
Normal file
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* 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 { ExposedToBrowserDescriptor } from './types';
|
||||
import { createBrowserConfig } from './create_browser_config';
|
||||
|
||||
describe('createBrowserConfig', () => {
|
||||
it('picks nothing by default', () => {
|
||||
const config = {
|
||||
foo: 'bar',
|
||||
nested: {
|
||||
str: 'string',
|
||||
num: 42,
|
||||
},
|
||||
};
|
||||
const descriptor: ExposedToBrowserDescriptor<typeof config> = {};
|
||||
|
||||
const browserConfig = createBrowserConfig(config, descriptor);
|
||||
|
||||
expect(browserConfig).toEqual({});
|
||||
});
|
||||
|
||||
it('picks all the nested properties when using `true`', () => {
|
||||
const config = {
|
||||
foo: 'bar',
|
||||
nested: {
|
||||
str: 'string',
|
||||
num: 42,
|
||||
},
|
||||
};
|
||||
|
||||
const descriptor: ExposedToBrowserDescriptor<typeof config> = {
|
||||
foo: true,
|
||||
nested: true,
|
||||
};
|
||||
|
||||
const browserConfig = createBrowserConfig(config, descriptor);
|
||||
|
||||
expect(browserConfig).toEqual({
|
||||
foo: 'bar',
|
||||
nested: {
|
||||
str: 'string',
|
||||
num: 42,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('picks specific nested properties when using a nested declaration', () => {
|
||||
const config = {
|
||||
foo: 'bar',
|
||||
nested: {
|
||||
str: 'string',
|
||||
num: 42,
|
||||
},
|
||||
};
|
||||
|
||||
const descriptor: ExposedToBrowserDescriptor<typeof config> = {
|
||||
foo: true,
|
||||
nested: {
|
||||
str: true,
|
||||
num: false,
|
||||
},
|
||||
};
|
||||
|
||||
const browserConfig = createBrowserConfig(config, descriptor);
|
||||
|
||||
expect(browserConfig).toEqual({
|
||||
foo: 'bar',
|
||||
nested: {
|
||||
str: 'string',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('accepts deeply nested structures', () => {
|
||||
const config = {
|
||||
foo: 'bar',
|
||||
deeply: {
|
||||
str: 'string',
|
||||
nested: {
|
||||
hello: 'dolly',
|
||||
structure: {
|
||||
propA: 'propA',
|
||||
propB: 'propB',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const descriptor: ExposedToBrowserDescriptor<typeof config> = {
|
||||
foo: false,
|
||||
deeply: {
|
||||
str: false,
|
||||
nested: {
|
||||
hello: true,
|
||||
structure: {
|
||||
propA: true,
|
||||
propB: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const browserConfig = createBrowserConfig(config, descriptor);
|
||||
|
||||
expect(browserConfig).toEqual({
|
||||
deeply: {
|
||||
nested: {
|
||||
hello: 'dolly',
|
||||
structure: {
|
||||
propA: 'propA',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('only includes leaf properties that are `true` when in nested structures', () => {
|
||||
const config = {
|
||||
foo: 'bar',
|
||||
deeply: {
|
||||
str: 'string',
|
||||
nested: {
|
||||
hello: 'dolly',
|
||||
structure: {
|
||||
propA: 'propA',
|
||||
propB: 'propB',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const descriptor: ExposedToBrowserDescriptor<typeof config> = {
|
||||
deeply: {
|
||||
nested: {
|
||||
hello: true,
|
||||
structure: {
|
||||
propA: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const browserConfig = createBrowserConfig(config, descriptor);
|
||||
|
||||
expect(browserConfig).toEqual({
|
||||
deeply: {
|
||||
nested: {
|
||||
hello: 'dolly',
|
||||
structure: {
|
||||
propA: 'propA',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
32
src/core/server/plugins/create_browser_config.ts
Normal file
32
src/core/server/plugins/create_browser_config.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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 { ExposedToBrowserDescriptor } from './types';
|
||||
|
||||
export const createBrowserConfig = <T = unknown>(
|
||||
config: T,
|
||||
descriptor: ExposedToBrowserDescriptor<T>
|
||||
): unknown => {
|
||||
return recursiveCreateConfig(config, descriptor);
|
||||
};
|
||||
|
||||
const recursiveCreateConfig = <T = unknown>(
|
||||
config: T,
|
||||
descriptor: ExposedToBrowserDescriptor<T> = {}
|
||||
): unknown => {
|
||||
return Object.entries(config || {}).reduce((browserConfig, [key, value]) => {
|
||||
const exposedConfig = descriptor[key as keyof ExposedToBrowserDescriptor<T>];
|
||||
if (exposedConfig && typeof exposedConfig === 'object') {
|
||||
browserConfig[key] = recursiveCreateConfig(value, exposedConfig);
|
||||
}
|
||||
if (exposedConfig === true) {
|
||||
browserConfig[key] = value;
|
||||
}
|
||||
return browserConfig;
|
||||
}, {} as Record<string, unknown>);
|
||||
};
|
|
@ -9,7 +9,7 @@
|
|||
import Path from 'path';
|
||||
import { Observable } from 'rxjs';
|
||||
import { filter, first, map, tap, toArray } from 'rxjs/operators';
|
||||
import { getFlattenedObject, pick } from '@kbn/std';
|
||||
import { getFlattenedObject } from '@kbn/std';
|
||||
|
||||
import { CoreService } from '../../types';
|
||||
import { CoreContext } from '../core_context';
|
||||
|
@ -26,6 +26,7 @@ import {
|
|||
} from './types';
|
||||
import { PluginsConfig, PluginsConfigType } from './plugins_config';
|
||||
import { PluginsSystem } from './plugins_system';
|
||||
import { createBrowserConfig } from './create_browser_config';
|
||||
import { InternalCorePreboot, InternalCoreSetup, InternalCoreStart } from '../internal_types';
|
||||
import { IConfigService } from '../config';
|
||||
import { InternalEnvironmentServicePreboot } from '../environment';
|
||||
|
@ -228,16 +229,11 @@ export class PluginsService implements CoreService<PluginsServiceSetup, PluginsS
|
|||
const configDescriptor = this.pluginConfigDescriptors.get(pluginId)!;
|
||||
return [
|
||||
pluginId,
|
||||
this.configService.atPath(plugin.configPath).pipe(
|
||||
map((config: any) =>
|
||||
pick(
|
||||
config || {},
|
||||
Object.entries(configDescriptor.exposeToBrowser!)
|
||||
.filter(([_, exposed]) => exposed)
|
||||
.map(([key, _]) => key)
|
||||
)
|
||||
)
|
||||
),
|
||||
this.configService
|
||||
.atPath(plugin.configPath)
|
||||
.pipe(
|
||||
map((config: any) => createBrowserConfig(config, configDescriptor.exposeToBrowser!))
|
||||
),
|
||||
];
|
||||
})
|
||||
);
|
||||
|
|
90
src/core/server/plugins/types.test.ts
Normal file
90
src/core/server/plugins/types.test.ts
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* 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 { ExposedToBrowserDescriptor } from './types';
|
||||
|
||||
describe('ExposedToBrowserDescriptor', () => {
|
||||
interface ConfigType {
|
||||
str: string;
|
||||
array: number[];
|
||||
obj: {
|
||||
sub1: string;
|
||||
sub2: number;
|
||||
};
|
||||
deep: {
|
||||
foo: number;
|
||||
nested: {
|
||||
str: string;
|
||||
arr: number[];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
it('allows to use recursion on objects', () => {
|
||||
const exposeToBrowser: ExposedToBrowserDescriptor<ConfigType> = {
|
||||
obj: {
|
||||
sub1: true,
|
||||
},
|
||||
};
|
||||
expect(exposeToBrowser).toBeDefined();
|
||||
});
|
||||
|
||||
it('allows to use recursion at multiple levels', () => {
|
||||
const exposeToBrowser: ExposedToBrowserDescriptor<ConfigType> = {
|
||||
deep: {
|
||||
foo: true,
|
||||
nested: {
|
||||
str: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
expect(exposeToBrowser).toBeDefined();
|
||||
});
|
||||
|
||||
it('does not allow to use recursion on arrays', () => {
|
||||
const exposeToBrowser: ExposedToBrowserDescriptor<ConfigType> = {
|
||||
// @ts-expect-error Type '{ 0: true; }' is not assignable to type 'boolean | undefined'.
|
||||
array: {
|
||||
0: true,
|
||||
},
|
||||
};
|
||||
expect(exposeToBrowser).toBeDefined();
|
||||
});
|
||||
|
||||
it('does not allow to use recursion on arrays at lower levels', () => {
|
||||
const exposeToBrowser: ExposedToBrowserDescriptor<ConfigType> = {
|
||||
deep: {
|
||||
nested: {
|
||||
// @ts-expect-error Type '{ 0: true; }' is not assignable to type 'boolean | undefined'.
|
||||
arr: {
|
||||
0: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
expect(exposeToBrowser).toBeDefined();
|
||||
});
|
||||
|
||||
it('allows to specify all the properties', () => {
|
||||
const exposeToBrowser: ExposedToBrowserDescriptor<ConfigType> = {
|
||||
str: true,
|
||||
array: false,
|
||||
obj: {
|
||||
sub1: true,
|
||||
},
|
||||
deep: {
|
||||
foo: true,
|
||||
nested: {
|
||||
arr: false,
|
||||
str: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
expect(exposeToBrowser).toBeDefined();
|
||||
});
|
||||
});
|
|
@ -26,6 +26,23 @@ type Maybe<T> = T | undefined;
|
|||
*/
|
||||
export type PluginConfigSchema<T> = Type<T>;
|
||||
|
||||
/**
|
||||
* Type defining the list of configuration properties that will be exposed on the client-side
|
||||
* Object properties can either be fully exposed
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ExposedToBrowserDescriptor<T> = {
|
||||
[Key in keyof T]?: T[Key] extends Maybe<any[]>
|
||||
? // handles arrays as primitive values
|
||||
boolean
|
||||
: T[Key] extends Maybe<object>
|
||||
? // can be nested for objects
|
||||
ExposedToBrowserDescriptor<T[Key]> | boolean
|
||||
: // primitives
|
||||
boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes a plugin configuration properties.
|
||||
*
|
||||
|
@ -64,7 +81,7 @@ export interface PluginConfigDescriptor<T = any> {
|
|||
/**
|
||||
* List of configuration properties that will be available on the client-side plugin.
|
||||
*/
|
||||
exposeToBrowser?: { [P in keyof T]?: boolean };
|
||||
exposeToBrowser?: ExposedToBrowserDescriptor<T>;
|
||||
/**
|
||||
* Schema to use to validate the plugin configuration.
|
||||
*
|
||||
|
|
|
@ -1010,6 +1010,14 @@ export interface ExecutionContextSetup {
|
|||
// @public (undocumented)
|
||||
export type ExecutionContextStart = ExecutionContextSetup;
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "Maybe" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// @public
|
||||
export type ExposedToBrowserDescriptor<T> = {
|
||||
[Key in keyof T]?: T[Key] extends Maybe<any[]> ? boolean : T[Key] extends Maybe<object> ? // can be nested for objects
|
||||
ExposedToBrowserDescriptor<T[Key]> | boolean : boolean;
|
||||
};
|
||||
|
||||
// @public
|
||||
export interface FakeRequest {
|
||||
headers: Headers_2;
|
||||
|
@ -1465,8 +1473,6 @@ export { LogMeta }
|
|||
|
||||
export { LogRecord }
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "Maybe" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// @public
|
||||
export type MakeUsageFromSchema<T> = {
|
||||
[Key in keyof T]?: T[Key] extends Maybe<object[]> ? false : T[Key] extends Maybe<any[]> ? boolean : T[Key] extends Maybe<object> ? MakeUsageFromSchema<T[Key]> | boolean : boolean;
|
||||
|
@ -1658,9 +1664,7 @@ export { Plugin_2 as Plugin }
|
|||
export interface PluginConfigDescriptor<T = any> {
|
||||
// Warning: (ae-unresolved-link) The @link reference could not be resolved: This type of declaration is not supported yet by the resolver
|
||||
deprecations?: ConfigDeprecationProvider;
|
||||
exposeToBrowser?: {
|
||||
[P in keyof T]?: boolean;
|
||||
};
|
||||
exposeToBrowser?: ExposedToBrowserDescriptor<T>;
|
||||
exposeToUsage?: MakeUsageFromSchema<T>;
|
||||
schema: PluginConfigSchema<T>;
|
||||
}
|
||||
|
@ -3173,8 +3177,8 @@ export const validBodyOutput: readonly ["data", "stream"];
|
|||
//
|
||||
// src/core/server/elasticsearch/client/types.ts:93:7 - (ae-forgotten-export) The symbol "Explanation" needs to be exported by the entry point index.d.ts
|
||||
// src/core/server/http/router/response.ts:302:3 - (ae-forgotten-export) The symbol "KibanaResponse" needs to be exported by the entry point index.d.ts
|
||||
// src/core/server/plugins/types.ts:375:3 - (ae-forgotten-export) The symbol "SharedGlobalConfigKeys" needs to be exported by the entry point index.d.ts
|
||||
// src/core/server/plugins/types.ts:377:3 - (ae-forgotten-export) The symbol "SavedObjectsConfigType" needs to be exported by the entry point index.d.ts
|
||||
// src/core/server/plugins/types.ts:483:5 - (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "create"
|
||||
// src/core/server/plugins/types.ts:392:3 - (ae-forgotten-export) The symbol "SharedGlobalConfigKeys" needs to be exported by the entry point index.d.ts
|
||||
// src/core/server/plugins/types.ts:394:3 - (ae-forgotten-export) The symbol "SavedObjectsConfigType" needs to be exported by the entry point index.d.ts
|
||||
// src/core/server/plugins/types.ts:500:5 - (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "create"
|
||||
|
||||
```
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue