mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 10:40:07 -04:00
[serverless] Add Advanced Settings page (#167383)
## Summary This PR adds a Settings application component for rendering the Advanced Settings page in serverless. ### How to test: 1. Start Es with `yarn es serverless` and Kibana with `yarn serverless-{es/oblt/security}` 2. Go to Management -> Advanced Settings 3. Verify that the settings can be changed and saved. ### Advanced Settings page: <img width="1495" alt="Screenshot 2023-09-28 at 20 56 25" src="374b3bbd
-7bf6-4de7-8129-8b293dd1698e"> ### Added an Advanced Settings card to the Management landing page: <img width="1575" alt="Screenshot 2023-09-28 at 12 24 23" src="c08b8b36
-ff40-4772-87d6-597629d78342"> <!--- ### Checklist Delete any items that are not applicable to this PR. - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) ### Risk Matrix Delete this section if it is not applicable to this PR. Before closing this PR, invite QA, stakeholders, and other developers to identify risks that should be tested prior to the change/feature release. When forming the risk matrix, consider some of the following examples and how they may potentially impact the change: | Risk | Probability | Severity | Mitigation/Notes | |---------------------------|-------------|----------|-------------------------| | Multiple Spaces—unexpected behavior in non-default Kibana Space. | Low | High | Integration tests will verify that all features are still supported in non-default Kibana Space and when user switches between spaces. | | Multiple nodes—Elasticsearch polling might have race conditions when multiple Kibana nodes are polling for the same tasks. | High | Low | Tasks are idempotent, so executing them multiple times will not result in logical error, but will degrade performance. To test for this case we add plenty of unit tests around this logic and document manual testing procedure. | | Code should gracefully handle cases when feature X or plugin Y are disabled. | Medium | High | Unit tests will verify that any feature flag or plugin combination still results in our service operational. | | [See more potential risk examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx) | ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --> --------- Co-authored-by: Clint Andrew Hall <clint@clintandrewhall.com> Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Clint Andrew Hall <clint.hall@elastic.co>
This commit is contained in:
parent
aa065b710c
commit
d37d8ae85c
33 changed files with 510 additions and 83 deletions
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
@ -485,6 +485,7 @@ packages/kbn-managed-vscode-config @elastic/kibana-operations
|
|||
packages/kbn-managed-vscode-config-cli @elastic/kibana-operations
|
||||
packages/kbn-management/cards_navigation @elastic/platform-deployment-management
|
||||
src/plugins/management @elastic/platform-deployment-management
|
||||
packages/kbn-management/settings/application @elastic/platform-deployment-management
|
||||
packages/kbn-management/settings/components/field_category @elastic/platform-deployment-management
|
||||
packages/kbn-management/settings/components/field_input @elastic/platform-deployment-management
|
||||
packages/kbn-management/settings/components/field_row @elastic/platform-deployment-management
|
||||
|
|
|
@ -507,6 +507,7 @@
|
|||
"@kbn/logstash-plugin": "link:x-pack/plugins/logstash",
|
||||
"@kbn/management-cards-navigation": "link:packages/kbn-management/cards_navigation",
|
||||
"@kbn/management-plugin": "link:src/plugins/management",
|
||||
"@kbn/management-settings-application": "link:packages/kbn-management/settings/application",
|
||||
"@kbn/management-settings-components-field-category": "link:packages/kbn-management/settings/components/field_category",
|
||||
"@kbn/management-settings-components-field-input": "link:packages/kbn-management/settings/components/field_input",
|
||||
"@kbn/management-settings-components-field-row": "link:packages/kbn-management/settings/components/field_row",
|
||||
|
|
|
@ -27,6 +27,7 @@ export enum appIds {
|
|||
CONNECTORS = 'triggersActionsConnectors',
|
||||
RULES = 'triggersActions',
|
||||
MAINTENANCE_WINDOWS = 'maintenanceWindows',
|
||||
SERVERLESS_SETTINGS = 'settings',
|
||||
}
|
||||
|
||||
// Create new type that is a union of all the appId values
|
||||
|
@ -155,6 +156,14 @@ export const appDefinitions: Record<AppId, AppDefinition> = {
|
|||
}),
|
||||
icon: <EuiIcon size="l" type="lockOpen" />,
|
||||
},
|
||||
|
||||
[appIds.SERVERLESS_SETTINGS]: {
|
||||
category: appCategories.OTHER,
|
||||
description: i18n.translate('management.landing.withCardNavigation.settingsDescription', {
|
||||
defaultMessage: 'Control project behavior, such as date display and default sorting.',
|
||||
}),
|
||||
icon: <EuiIcon size="l" type="gear" />,
|
||||
},
|
||||
};
|
||||
|
||||
// Compose a list of app ids that belong to a given category
|
||||
|
|
13
packages/kbn-management/settings/application/README.md
Normal file
13
packages/kbn-management/settings/application/README.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
id: management/settings/application
|
||||
slug: /management/settings/application
|
||||
title: Management Settings Application
|
||||
description: A package containing a component for rendering the Settings page.
|
||||
tags: ['management', 'settings']
|
||||
date: 2023-09-27
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
This package contains a component for rendering the Settings page that contains a `Form` component for displaying and changing the available uiSettings.
|
||||
The settings application also handles the logic for filtering out the uiSettings that are not in the allowlist.
|
38
packages/kbn-management/settings/application/application.tsx
Normal file
38
packages/kbn-management/settings/application/application.tsx
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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 { Form } from '@kbn/management-settings-components-form';
|
||||
|
||||
import { EuiText, EuiSpacer } from '@elastic/eui';
|
||||
import { i18n as i18nLib } from '@kbn/i18n';
|
||||
import { useFields } from './hooks/use_fields';
|
||||
|
||||
const title = i18nLib.translate('management.settings.advancedSettingsLabel', {
|
||||
defaultMessage: 'Advanced Settings',
|
||||
});
|
||||
|
||||
export const DATA_TEST_SUBJ_SETTINGS_TITLE = 'managementSettingsTitle';
|
||||
|
||||
/**
|
||||
* Component for displaying a {@link Form} component.
|
||||
* @param props The {@link SettingsApplicationProps} for the {@link SettingsApplication} component.
|
||||
*/
|
||||
export const SettingsApplication = () => {
|
||||
const fields = useFields();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<EuiText>
|
||||
<h1 data-test-subj={DATA_TEST_SUBJ_SETTINGS_TITLE}>{title}</h1>
|
||||
</EuiText>
|
||||
<EuiSpacer size="xxl" />
|
||||
<Form fields={fields} isSavingEnabled={true} />
|
||||
</div>
|
||||
);
|
||||
};
|
10
packages/kbn-management/settings/application/hooks/index.ts
Normal file
10
packages/kbn-management/settings/application/hooks/index.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { useFields } from './use_fields';
|
||||
export { useSettings } from './use_settings';
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* 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 { getFieldDefinitions } from '@kbn/management-settings-field-definition';
|
||||
import { FieldDefinition, SettingType } from '@kbn/management-settings-types';
|
||||
import { useServices } from '../services';
|
||||
import { useSettings } from './use_settings';
|
||||
|
||||
/**
|
||||
* React hook which retrieves settings and returns an observed collection of
|
||||
* {@link FieldDefinition} objects derived from those settings.
|
||||
*/
|
||||
export const useFields = (): Array<FieldDefinition<SettingType>> => {
|
||||
const { isCustomSetting: isCustom, isOverriddenSetting: isOverridden } = useServices();
|
||||
const settings = useSettings();
|
||||
return getFieldDefinitions(settings, { isCustom, isOverridden });
|
||||
};
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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 { useState } from 'react';
|
||||
import useEffectOnce from 'react-use/lib/useEffectOnce';
|
||||
|
||||
import { useServices } from '../services';
|
||||
|
||||
/**
|
||||
* React hook which retrieves settings from a particular {@link IUiSettingsClient},
|
||||
* normalizes them to a predictable format, {@link UiSettingMetadata}, and returns
|
||||
* them as an observed collection.
|
||||
*/
|
||||
export const useSettings = () => {
|
||||
const { getAllowlistedSettings, subscribeToUpdates } = useServices();
|
||||
|
||||
const [settings, setSettings] = useState(getAllowlistedSettings());
|
||||
|
||||
useEffectOnce(() => {
|
||||
const subscription = subscribeToUpdates(() => {
|
||||
setSettings(getAllowlistedSettings());
|
||||
});
|
||||
|
||||
return () => {
|
||||
subscription.unsubscribe();
|
||||
};
|
||||
});
|
||||
|
||||
return settings;
|
||||
};
|
34
packages/kbn-management/settings/application/index.tsx
Normal file
34
packages/kbn-management/settings/application/index.tsx
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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 { SettingsApplication } from './application';
|
||||
import {
|
||||
SettingsApplicationKibanaDependencies,
|
||||
SettingsApplicationKibanaProvider,
|
||||
} from './services';
|
||||
|
||||
export { SettingsApplication } from './application';
|
||||
export {
|
||||
SettingsApplicationProvider,
|
||||
SettingsApplicationKibanaProvider,
|
||||
type SettingsApplicationServices,
|
||||
type SettingsApplicationKibanaDependencies,
|
||||
} from './services';
|
||||
|
||||
export const KibanaSettingsApplication = ({
|
||||
docLinks,
|
||||
i18n,
|
||||
notifications,
|
||||
settings,
|
||||
theme,
|
||||
}: SettingsApplicationKibanaDependencies) => (
|
||||
<SettingsApplicationKibanaProvider {...{ settings, theme, i18n, notifications, docLinks }}>
|
||||
<SettingsApplication />
|
||||
</SettingsApplicationKibanaProvider>
|
||||
);
|
13
packages/kbn-management/settings/application/jest.config.js
Normal file
13
packages/kbn-management/settings/application/jest.config.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
preset: '@kbn/test',
|
||||
rootDir: '../../../..',
|
||||
roots: ['<rootDir>/packages/kbn-management/settings/application'],
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type": "shared-common",
|
||||
"id": "@kbn/management-settings-application",
|
||||
"owner": "@elastic/platform-deployment-management"
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"name": "@kbn/management-settings-application",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"license": "SSPL-1.0 OR Elastic License 2.0"
|
||||
}
|
121
packages/kbn-management/settings/application/services.tsx
Normal file
121
packages/kbn-management/settings/application/services.tsx
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* 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, { FC, useContext } from 'react';
|
||||
|
||||
import {
|
||||
FormProvider,
|
||||
FormKibanaProvider,
|
||||
type FormKibanaDependencies,
|
||||
type FormServices,
|
||||
} from '@kbn/management-settings-components-form';
|
||||
import { UiSettingMetadata } from '@kbn/management-settings-types';
|
||||
import { IUiSettingsClient } from '@kbn/core-ui-settings-browser';
|
||||
import { normalizeSettings } from '@kbn/management-settings-utilities';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
export interface Services {
|
||||
getAllowlistedSettings: () => Record<string, UiSettingMetadata>;
|
||||
subscribeToUpdates: (fn: () => void) => Subscription;
|
||||
isCustomSetting: (key: string) => boolean;
|
||||
isOverriddenSetting: (key: string) => boolean;
|
||||
}
|
||||
|
||||
export type SettingsApplicationServices = Services & FormServices;
|
||||
|
||||
export interface KibanaDependencies {
|
||||
settings: {
|
||||
client: Pick<IUiSettingsClient, 'getAll' | 'isCustom' | 'isOverridden' | 'getUpdate$'>;
|
||||
};
|
||||
}
|
||||
|
||||
export type SettingsApplicationKibanaDependencies = KibanaDependencies & FormKibanaDependencies;
|
||||
|
||||
const SettingsApplicationContext = React.createContext<Services | null>(null);
|
||||
|
||||
/**
|
||||
* A Context Provider that provides services to the component and its dependencies.
|
||||
*/
|
||||
export const SettingsApplicationProvider: FC<SettingsApplicationServices> = ({
|
||||
children,
|
||||
...services
|
||||
}) => {
|
||||
// Destructure the services to avoid a type-widening inclusion of unrelated services.
|
||||
const {
|
||||
saveChanges,
|
||||
showError,
|
||||
showReloadPagePrompt,
|
||||
links,
|
||||
showDanger,
|
||||
getAllowlistedSettings,
|
||||
subscribeToUpdates,
|
||||
isCustomSetting,
|
||||
isOverriddenSetting,
|
||||
} = services;
|
||||
|
||||
return (
|
||||
<SettingsApplicationContext.Provider
|
||||
value={{ getAllowlistedSettings, subscribeToUpdates, isCustomSetting, isOverriddenSetting }}
|
||||
>
|
||||
<FormProvider {...{ saveChanges, showError, showReloadPagePrompt, links, showDanger }}>
|
||||
{children}
|
||||
</FormProvider>
|
||||
</SettingsApplicationContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Kibana-specific Provider that maps dependencies to services.
|
||||
*/
|
||||
export const SettingsApplicationKibanaProvider: FC<SettingsApplicationKibanaDependencies> = ({
|
||||
children,
|
||||
...dependencies
|
||||
}) => {
|
||||
const { docLinks, notifications, theme, i18n, settings } = dependencies;
|
||||
const { client } = settings;
|
||||
|
||||
const getAllowlistedSettings = () => {
|
||||
const rawSettings = Object.fromEntries(
|
||||
Object.entries(client.getAll()).filter(
|
||||
([settingId, settingDef]) => !settingDef.readonly && !client.isCustom(settingId)
|
||||
)
|
||||
);
|
||||
|
||||
return normalizeSettings(rawSettings);
|
||||
};
|
||||
|
||||
const services: Services = {
|
||||
getAllowlistedSettings,
|
||||
isCustomSetting: (key: string) => client.isCustom(key),
|
||||
isOverriddenSetting: (key: string) => client.isOverridden(key),
|
||||
subscribeToUpdates: (fn: () => void) => client.getUpdate$().subscribe(fn),
|
||||
};
|
||||
|
||||
return (
|
||||
<SettingsApplicationContext.Provider value={services}>
|
||||
<FormKibanaProvider {...{ docLinks, notifications, theme, i18n, settings }}>
|
||||
{children}
|
||||
</FormKibanaProvider>
|
||||
</SettingsApplicationContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* React hook for accessing pre-wired services.
|
||||
*/
|
||||
export const useServices = () => {
|
||||
const context = useContext(SettingsApplicationContext);
|
||||
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
'SettingsApplicationContext is missing. Ensure your component or React root is wrapped with SettingsApplicationProvider.'
|
||||
);
|
||||
}
|
||||
|
||||
return context;
|
||||
};
|
26
packages/kbn-management/settings/application/tsconfig.json
Normal file
26
packages/kbn-management/settings/application/tsconfig.json
Normal file
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"extends": "../../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "target/types",
|
||||
"types": [
|
||||
"jest",
|
||||
"node",
|
||||
"react"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*"
|
||||
],
|
||||
"kbn_references": [
|
||||
"@kbn/core-ui-settings-browser",
|
||||
"@kbn/management-settings-types",
|
||||
"@kbn/management-settings-field-definition",
|
||||
"@kbn/management-settings-utilities",
|
||||
"@kbn/management-settings-components-form",
|
||||
"@kbn/i18n",
|
||||
]
|
||||
}
|
|
@ -27,7 +27,7 @@ export const FieldInputProvider: FC<FieldInputServices> = ({ children, ...servic
|
|||
*/
|
||||
export const FieldInputKibanaProvider: FC<FieldInputKibanaDependencies> = ({
|
||||
children,
|
||||
toasts,
|
||||
notifications: { toasts },
|
||||
}) => {
|
||||
return (
|
||||
<FieldInputContext.Provider
|
||||
|
|
|
@ -31,7 +31,9 @@ export interface FieldInputServices {
|
|||
*/
|
||||
export interface FieldInputKibanaDependencies {
|
||||
/** The portion of the {@link ToastsStart} contract used by this component. */
|
||||
toasts: Pick<ToastsStart, 'addDanger'>;
|
||||
notifications: {
|
||||
toasts: Pick<ToastsStart, 'addDanger'>;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -44,7 +44,7 @@ export const FieldRowProvider = ({ children, ...services }: FieldRowProviderProp
|
|||
export const FieldRowKibanaProvider: FC<FieldRowKibanaDependencies> = ({
|
||||
children,
|
||||
docLinks,
|
||||
toasts,
|
||||
notifications,
|
||||
}) => {
|
||||
return (
|
||||
<FieldRowContext.Provider
|
||||
|
@ -52,7 +52,7 @@ export const FieldRowKibanaProvider: FC<FieldRowKibanaDependencies> = ({
|
|||
links: docLinks.links.management,
|
||||
}}
|
||||
>
|
||||
<FieldInputKibanaProvider {...{ toasts }}>{children}</FieldInputKibanaProvider>
|
||||
<FieldInputKibanaProvider {...{ notifications }}>{children}</FieldInputKibanaProvider>
|
||||
</FieldRowContext.Provider>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
*/
|
||||
|
||||
import React, { FC, useContext } from 'react';
|
||||
import { UnsavedFieldChange } from '@kbn/management-settings-types';
|
||||
|
||||
import {
|
||||
FieldCategoryKibanaProvider,
|
||||
|
@ -42,22 +41,22 @@ export const FormProvider = ({ children, ...services }: FormProviderProps) => {
|
|||
* Kibana-specific Provider that maps Kibana plugins and services to a {@link FormProvider}.
|
||||
*/
|
||||
export const FormKibanaProvider: FC<FormKibanaDependencies> = ({ children, ...deps }) => {
|
||||
const { settings, toasts, docLinks, theme, i18nStart } = deps;
|
||||
const { settings, notifications, docLinks, theme, i18n } = deps;
|
||||
|
||||
const services: Services = {
|
||||
saveChanges: (changes) => {
|
||||
const arr = Object.entries(changes).map(([key, value]) =>
|
||||
settings.client.set(key, value.unsavedValue)
|
||||
);
|
||||
return Promise.all(arr);
|
||||
},
|
||||
showError: (message: string) => notifications.toasts.addDanger(message),
|
||||
showReloadPagePrompt: () => notifications.toasts.add(reloadPageToast(theme, i18n)),
|
||||
};
|
||||
|
||||
return (
|
||||
<FormContext.Provider
|
||||
value={{
|
||||
saveChanges: (changes: Record<string, UnsavedFieldChange>) => {
|
||||
const arr = Object.entries(changes).map(([key, value]) =>
|
||||
settings.client.set(key, value.unsavedValue)
|
||||
);
|
||||
return Promise.all(arr);
|
||||
},
|
||||
showError: (message: string) => toasts.addDanger(message),
|
||||
showReloadPagePrompt: () => toasts.add(reloadPageToast(theme, i18nStart)),
|
||||
}}
|
||||
>
|
||||
<FieldCategoryKibanaProvider {...{ docLinks, toasts }}>
|
||||
<FormContext.Provider value={services}>
|
||||
<FieldCategoryKibanaProvider {...{ docLinks, notifications }}>
|
||||
{children}
|
||||
</FieldCategoryKibanaProvider>
|
||||
</FormContext.Provider>
|
||||
|
|
|
@ -11,7 +11,7 @@ import type {
|
|||
FieldRowServices,
|
||||
} from '@kbn/management-settings-components-field-row';
|
||||
import { UnsavedFieldChange } from '@kbn/management-settings-types';
|
||||
import { SettingsStart } from '@kbn/core-ui-settings-browser';
|
||||
import { IUiSettingsClient } from '@kbn/core-ui-settings-browser';
|
||||
import { I18nStart } from '@kbn/core-i18n-browser';
|
||||
import { ThemeServiceStart } from '@kbn/core-theme-browser';
|
||||
import { ToastsStart } from '@kbn/core-notifications-browser';
|
||||
|
@ -36,12 +36,14 @@ export type FormServices = FieldRowServices & Services;
|
|||
*/
|
||||
interface KibanaDependencies {
|
||||
settings: {
|
||||
client: SettingsStart['client'];
|
||||
client: Pick<IUiSettingsClient, 'set'>;
|
||||
};
|
||||
theme: ThemeServiceStart;
|
||||
i18nStart: I18nStart;
|
||||
i18n: I18nStart;
|
||||
/** The portion of the {@link ToastsStart} contract used by this component. */
|
||||
toasts: Pick<ToastsStart, 'addError' | 'add'>;
|
||||
notifications: {
|
||||
toasts: Pick<ToastsStart, 'addError' | 'add'>;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import { KnownTypeToMetadata, SettingType } from '@kbn/management-settings-types';
|
||||
|
||||
type Settings = {
|
||||
[key in SettingType]: KnownTypeToMetadata<key>;
|
||||
[key in Exclude<SettingType, 'json' | 'markdown'>]: KnownTypeToMetadata<key>;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -71,24 +71,25 @@ export const getSettingsMock = (
|
|||
category: ['dashboard', 'discover'],
|
||||
...defaults,
|
||||
},
|
||||
json: {
|
||||
name: 'json:test:setting',
|
||||
description: 'Description for Json test setting',
|
||||
type: 'json',
|
||||
userValue: null,
|
||||
value: '{"foo": "bar"}',
|
||||
category: ['dashboard', 'discover'],
|
||||
...defaults,
|
||||
},
|
||||
markdown: {
|
||||
name: 'markdown:test:setting',
|
||||
description: 'Description for Markdown test setting',
|
||||
type: 'markdown',
|
||||
userValue: null,
|
||||
value: '',
|
||||
category: ['notifications', 'search'],
|
||||
...defaults,
|
||||
},
|
||||
// These are notoriously difficult to test, in both Jest and Storybook.
|
||||
// json: {
|
||||
// name: 'json:test:setting',
|
||||
// description: 'Description for Json test setting',
|
||||
// type: 'json',
|
||||
// userValue: null,
|
||||
// value: '{"foo": "bar"}',
|
||||
// category: ['dashboard', 'discover'],
|
||||
// ...defaults,
|
||||
// },
|
||||
// markdown: {
|
||||
// name: 'markdown:test:setting',
|
||||
// description: 'Description for Markdown test setting',
|
||||
// type: 'markdown',
|
||||
// userValue: null,
|
||||
// value: '',
|
||||
// category: ['notifications', 'search'],
|
||||
// ...defaults,
|
||||
// },
|
||||
select: {
|
||||
description: 'Description for Select test setting',
|
||||
name: 'select:test:setting',
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { i18n as kbnI18n } from '@kbn/i18n';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import type { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import { HomePublicPluginSetup } from '@kbn/home-plugin/public';
|
||||
|
@ -23,6 +25,8 @@ import {
|
|||
AppNavLinkStatus,
|
||||
AppDeepLink,
|
||||
} from '@kbn/core/public';
|
||||
import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render';
|
||||
import { withSuspense } from '@kbn/shared-ux-utility';
|
||||
import { ConfigSchema, ManagementSetup, ManagementStart, NavigationCardsSubject } from './types';
|
||||
|
||||
import { MANAGEMENT_APP_ID } from '../common/contants';
|
||||
|
@ -43,6 +47,12 @@ interface ManagementStartDependencies {
|
|||
serverless?: ServerlessPluginStart;
|
||||
}
|
||||
|
||||
const LazyKibanaSettingsApplication = React.lazy(async () => ({
|
||||
default: (await import('@kbn/management-settings-application')).KibanaSettingsApplication,
|
||||
}));
|
||||
|
||||
const KibanaSettingsApplication = withSuspense(LazyKibanaSettingsApplication);
|
||||
|
||||
export class ManagementPlugin
|
||||
implements
|
||||
Plugin<
|
||||
|
@ -99,10 +109,10 @@ export class ManagementPlugin
|
|||
if (home) {
|
||||
home.featureCatalogue.register({
|
||||
id: 'stack-management',
|
||||
title: i18n.translate('management.stackManagement.managementLabel', {
|
||||
title: kbnI18n.translate('management.stackManagement.managementLabel', {
|
||||
defaultMessage: 'Stack Management',
|
||||
}),
|
||||
description: i18n.translate('management.stackManagement.managementDescription', {
|
||||
description: kbnI18n.translate('management.stackManagement.managementDescription', {
|
||||
defaultMessage: 'Your center console for managing the Elastic Stack.',
|
||||
}),
|
||||
icon: 'managementApp',
|
||||
|
@ -115,7 +125,7 @@ export class ManagementPlugin
|
|||
|
||||
core.application.register({
|
||||
id: MANAGEMENT_APP_ID,
|
||||
title: i18n.translate('management.stackManagement.title', {
|
||||
title: kbnI18n.translate('management.stackManagement.title', {
|
||||
defaultMessage: 'Stack Management',
|
||||
}),
|
||||
order: 9040,
|
||||
|
@ -152,7 +162,7 @@ export class ManagementPlugin
|
|||
};
|
||||
}
|
||||
|
||||
public start(core: CoreStart, _plugins: ManagementStartDependencies): ManagementStart {
|
||||
public start(core: CoreStart, plugins: ManagementStartDependencies): ManagementStart {
|
||||
this.managementSections.start({ capabilities: core.application.capabilities });
|
||||
this.hasAnyEnabledApps = getSectionsServiceStartPrivate()
|
||||
.getSectionsEnabled()
|
||||
|
@ -167,6 +177,33 @@ export class ManagementPlugin
|
|||
});
|
||||
}
|
||||
|
||||
// Register the Settings app only if in serverless, until we integrate the SettingsApplication into the Advanced settings plugin
|
||||
// Otherwise, it will be double registered from the Advanced settings plugin
|
||||
if (plugins.serverless) {
|
||||
const title = kbnI18n.translate('management.settings.settingsLabel', {
|
||||
defaultMessage: 'Advanced Settings',
|
||||
});
|
||||
|
||||
this.managementSections.definedSections.kibana.registerApp({
|
||||
id: 'settings',
|
||||
title,
|
||||
order: 3,
|
||||
async mount({ element, setBreadcrumbs }) {
|
||||
setBreadcrumbs([{ text: title }]);
|
||||
|
||||
ReactDOM.render(
|
||||
<KibanaRenderContextProvider {...core}>
|
||||
<KibanaSettingsApplication {...core} />
|
||||
</KibanaRenderContextProvider>,
|
||||
element
|
||||
);
|
||||
return () => {
|
||||
ReactDOM.unmountComponentAtNode(element);
|
||||
};
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
setIsSidebarEnabled: (isSidebarEnabled: boolean) =>
|
||||
this.isSidebarEnabled$.next(isSidebarEnabled),
|
|
@ -26,7 +26,10 @@
|
|||
"@kbn/config-schema",
|
||||
"@kbn/core-application-browser",
|
||||
"@kbn/core-http-browser",
|
||||
"@kbn/serverless"
|
||||
"@kbn/serverless",
|
||||
"@kbn/management-settings-application",
|
||||
"@kbn/react-kibana-context-render",
|
||||
"@kbn/shared-ux-utility"
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*"
|
||||
|
|
|
@ -964,6 +964,8 @@
|
|||
"@kbn/management-cards-navigation/*": ["packages/kbn-management/cards_navigation/*"],
|
||||
"@kbn/management-plugin": ["src/plugins/management"],
|
||||
"@kbn/management-plugin/*": ["src/plugins/management/*"],
|
||||
"@kbn/management-settings-application": ["packages/kbn-management/settings/application"],
|
||||
"@kbn/management-settings-application/*": ["packages/kbn-management/settings/application/*"],
|
||||
"@kbn/management-settings-components-field-category": ["packages/kbn-management/settings/components/field_category"],
|
||||
"@kbn/management-settings-components-field-category/*": ["packages/kbn-management/settings/components/field_category/*"],
|
||||
"@kbn/management-settings-components-field-input": ["packages/kbn-management/settings/components/field_input"],
|
||||
|
|
|
@ -4738,9 +4738,6 @@
|
|||
"management.sections.section.title": "Sécurité",
|
||||
"management.sections.stackTip": "Gérez votre licence et mettez la Suite à niveau.",
|
||||
"management.sections.stackTitle": "Suite",
|
||||
"management.stackManagement.managementDescription": "La console centrale de gestion de la Suite Elastic.",
|
||||
"management.stackManagement.managementLabel": "Gestion de la Suite",
|
||||
"management.stackManagement.title": "Gestion de la Suite",
|
||||
"newsfeed.flyoutList.versionTextLabel": "{version}",
|
||||
"newsfeed.emptyPrompt.noNewsText": "Si votre instance Kibana n'a pas accès à Internet, demandez à votre administrateur de désactiver cette fonctionnalité. Sinon, nous continuerons d'essayer de récupérer les actualités.",
|
||||
"newsfeed.emptyPrompt.noNewsTitle": "Pas d'actualités ?",
|
||||
|
|
|
@ -4754,9 +4754,6 @@
|
|||
"management.sections.section.title": "セキュリティ",
|
||||
"management.sections.stackTip": "ライセンスを管理し、スタックをアップグレードします",
|
||||
"management.sections.stackTitle": "スタック",
|
||||
"management.stackManagement.managementDescription": "Elastic Stack の管理を行うセンターコンソールです。",
|
||||
"management.stackManagement.managementLabel": "スタック管理",
|
||||
"management.stackManagement.title": "スタック管理",
|
||||
"newsfeed.flyoutList.versionTextLabel": "{version}",
|
||||
"newsfeed.emptyPrompt.noNewsText": "Kibana インスタンスがインターネットにアクセスできない場合、管理者にこの機能を無効にするように依頼してください。そうでない場合は、ニュースを取り込み続けます。",
|
||||
"newsfeed.emptyPrompt.noNewsTitle": "ニュースがない場合",
|
||||
|
|
|
@ -4753,9 +4753,6 @@
|
|||
"management.sections.section.title": "安全",
|
||||
"management.sections.stackTip": "管理您的许可并升级 Stack",
|
||||
"management.sections.stackTitle": "Stack",
|
||||
"management.stackManagement.managementDescription": "您用于管理 Elastic Stack 的中心控制台。",
|
||||
"management.stackManagement.managementLabel": "Stack Management",
|
||||
"management.stackManagement.title": "Stack Management",
|
||||
"newsfeed.flyoutList.versionTextLabel": "{version}",
|
||||
"newsfeed.emptyPrompt.noNewsText": "如果您的 Kibana 实例没有 Internet 连接,请让您的管理员禁用此功能。否则,我们将不断尝试获取新闻。",
|
||||
"newsfeed.emptyPrompt.noNewsTitle": "无新闻?",
|
||||
|
|
|
@ -72,7 +72,7 @@ export function createTestConfig(options: CreateTestConfigOptions) {
|
|||
connectors: {
|
||||
pathname: '/app/management/insightsAndAlerting/triggersActionsConnectors/',
|
||||
},
|
||||
advancedSettings: {
|
||||
settings: {
|
||||
pathname: '/app/management/kibana/settings',
|
||||
},
|
||||
login: {
|
||||
|
|
|
@ -7,18 +7,37 @@
|
|||
|
||||
import expect from '@kbn/expect';
|
||||
import { ALL_COMMON_SETTINGS } from '@kbn/serverless-common-settings';
|
||||
import * as settings from '@kbn/management-settings-ids';
|
||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
|
||||
const editorSettings = new Set<string>([
|
||||
settings.BANNERS_TEXT_CONTENT_ID,
|
||||
settings.DATE_FORMAT_SCALED_ID,
|
||||
settings.ML_ANOMALY_DETECTION_RESULTS_TIME_DEFAULTS_ID,
|
||||
settings.NOTIFICATIONS_BANNER_ID,
|
||||
settings.TIMEPICKER_TIME_DEFAULTS_ID,
|
||||
settings.TIMEPICKER_QUICK_RANGES_ID,
|
||||
settings.SECURITY_SOLUTION_REFRESH_INTERVAL_DEFAULTS_ID,
|
||||
settings.SECURITY_SOLUTION_TIME_DEFAULTS_ID,
|
||||
settings.SECURITY_SOLUTION_RULES_TABLE_REFRESH_ID,
|
||||
settings.SECURITY_SOLUTION_IP_REPUTATION_LINKS_ID,
|
||||
]);
|
||||
export const isEditorFieldSetting = (settingId: string) => editorSettings.has(settingId);
|
||||
|
||||
export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
||||
const testSubjects = getService('testSubjects');
|
||||
const pageObjects = getPageObjects(['common']);
|
||||
const pageObjects = getPageObjects(['svlCommonPage', 'common']);
|
||||
const browser = getService('browser');
|
||||
const retry = getService('retry');
|
||||
|
||||
// Skip until we enable the Advanced settings app in serverless
|
||||
describe.skip('Common advanced settings', function () {
|
||||
describe('Common advanced settings', function () {
|
||||
before(async () => {
|
||||
await pageObjects.common.navigateToApp('advancedSettings');
|
||||
await pageObjects.svlCommonPage.login();
|
||||
await pageObjects.common.navigateToApp('settings');
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await pageObjects.svlCommonPage.forceLogout();
|
||||
});
|
||||
|
||||
it('renders the page', async () => {
|
||||
|
@ -32,13 +51,18 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
|
||||
describe('renders common settings', () => {
|
||||
for (const settingId of ALL_COMMON_SETTINGS) {
|
||||
// Code editors don't have their test subjects rendered
|
||||
if (isEditorFieldSetting(settingId)) {
|
||||
continue;
|
||||
}
|
||||
const isColorPickerField =
|
||||
settingId === settings.BANNERS_TEXT_COLOR_ID ||
|
||||
settingId === settings.BANNERS_BACKGROUND_COLOR_ID;
|
||||
const fieldTestSubj =
|
||||
(isColorPickerField ? 'euiColorPickerAnchor ' : '') +
|
||||
'management-settings-editField-' +
|
||||
settingId;
|
||||
it('renders ' + settingId + ' edit field', async () => {
|
||||
const isColorPickerField =
|
||||
settingId === 'banners:textColor' || settingId === 'banners:backgroundColor';
|
||||
const fieldTestSubj =
|
||||
(isColorPickerField ? 'euiColorPickerAnchor ' : '') +
|
||||
'advancedSetting-editField-' +
|
||||
settingId;
|
||||
expect(await testSubjects.exists(fieldTestSubj)).to.be(true);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -8,17 +8,22 @@
|
|||
import expect from '@kbn/expect';
|
||||
import { OBSERVABILITY_PROJECT_SETTINGS } from '@kbn/serverless-observability-settings';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import { isEditorFieldSetting } from '../common/management/advanced_settings';
|
||||
|
||||
export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
||||
const testSubjects = getService('testSubjects');
|
||||
const pageObjects = getPageObjects(['common']);
|
||||
const pageObjects = getPageObjects(['svlCommonPage', 'common']);
|
||||
const browser = getService('browser');
|
||||
const retry = getService('retry');
|
||||
|
||||
// Skip until we enable the Advanced settings app in serverless
|
||||
describe.skip('Observability advanced settings', function () {
|
||||
describe('Observability advanced settings', function () {
|
||||
before(async () => {
|
||||
await pageObjects.common.navigateToApp('advancedSettings');
|
||||
await pageObjects.svlCommonPage.login();
|
||||
await pageObjects.common.navigateToApp('settings');
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await pageObjects.svlCommonPage.forceLogout();
|
||||
});
|
||||
|
||||
it('renders the page', async () => {
|
||||
|
@ -32,8 +37,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
|
||||
describe('renders observability settings', () => {
|
||||
for (const settingId of OBSERVABILITY_PROJECT_SETTINGS) {
|
||||
// Code editors don't have their test subjects rendered
|
||||
if (isEditorFieldSetting(settingId)) {
|
||||
continue;
|
||||
}
|
||||
it('renders ' + settingId + ' edit field', async () => {
|
||||
const fieldTestSubj = 'advancedSetting-editField-' + settingId;
|
||||
const fieldTestSubj = 'management-settings-editField-' + settingId;
|
||||
expect(await testSubjects.exists(fieldTestSubj)).to.be(true);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -8,17 +8,22 @@
|
|||
import expect from '@kbn/expect';
|
||||
import { SEARCH_PROJECT_SETTINGS } from '@kbn/serverless-search-settings';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import { isEditorFieldSetting } from '../common/management/advanced_settings';
|
||||
|
||||
export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
||||
const testSubjects = getService('testSubjects');
|
||||
const pageObjects = getPageObjects(['common']);
|
||||
const pageObjects = getPageObjects(['svlCommonPage', 'common']);
|
||||
const browser = getService('browser');
|
||||
const retry = getService('retry');
|
||||
|
||||
// Skip until we enable the Advanced settings app in serverless
|
||||
describe.skip('Search advanced settings', function () {
|
||||
describe('Search advanced settings', function () {
|
||||
before(async () => {
|
||||
await pageObjects.common.navigateToApp('advancedSettings');
|
||||
await pageObjects.svlCommonPage.login();
|
||||
await pageObjects.common.navigateToApp('settings');
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await pageObjects.svlCommonPage.forceLogout();
|
||||
});
|
||||
|
||||
it('renders the page', async () => {
|
||||
|
@ -32,8 +37,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
|
||||
describe('renders search settings', () => {
|
||||
for (const settingId of SEARCH_PROJECT_SETTINGS) {
|
||||
// Code editors don't have their test subjects rendered
|
||||
if (isEditorFieldSetting(settingId)) {
|
||||
continue;
|
||||
}
|
||||
it('renders ' + settingId + ' edit field', async () => {
|
||||
const fieldTestSubj = 'advancedSetting-editField-' + settingId;
|
||||
const fieldTestSubj = 'management-settings-editField-' + settingId;
|
||||
expect(await testSubjects.exists(fieldTestSubj)).to.be(true);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -8,17 +8,22 @@
|
|||
import expect from '@kbn/expect';
|
||||
import { SECURITY_PROJECT_SETTINGS } from '@kbn/serverless-security-settings';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import { isEditorFieldSetting } from '../common/management/advanced_settings';
|
||||
|
||||
export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
||||
const testSubjects = getService('testSubjects');
|
||||
const pageObjects = getPageObjects(['common']);
|
||||
const pageObjects = getPageObjects(['svlCommonPage', 'common']);
|
||||
const browser = getService('browser');
|
||||
const retry = getService('retry');
|
||||
|
||||
// Skip until we enable the Advanced settings app in serverless
|
||||
describe.skip('Security advanced settings', function () {
|
||||
describe('Security advanced settings', function () {
|
||||
before(async () => {
|
||||
await pageObjects.common.navigateToApp('advancedSettings');
|
||||
await pageObjects.svlCommonPage.login();
|
||||
await pageObjects.common.navigateToApp('settings');
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await pageObjects.svlCommonPage.forceLogout();
|
||||
});
|
||||
|
||||
it('renders the page', async () => {
|
||||
|
@ -32,8 +37,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
|
||||
describe('renders security settings', () => {
|
||||
for (const settingId of SECURITY_PROJECT_SETTINGS) {
|
||||
// Code editors don't have their test subjects rendered
|
||||
if (isEditorFieldSetting(settingId)) {
|
||||
continue;
|
||||
}
|
||||
it('renders ' + settingId + ' edit field', async () => {
|
||||
const fieldTestSubj = 'advancedSetting-editField-' + settingId;
|
||||
const fieldTestSubj = 'management-settings-editField-' + settingId;
|
||||
expect(await testSubjects.exists(fieldTestSubj)).to.be(true);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -57,5 +57,6 @@
|
|||
"@kbn/serverless-observability-settings",
|
||||
"@kbn/serverless-search-settings",
|
||||
"@kbn/serverless-security-settings",
|
||||
"@kbn/management-settings-ids",
|
||||
]
|
||||
}
|
||||
|
|
|
@ -4871,6 +4871,10 @@
|
|||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/management-settings-application@link:packages/kbn-management/settings/application":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/management-settings-components-field-category@link:packages/kbn-management/settings/components/field_category":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue