mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Enterprise Search] Add connector configurable field dependencies (#155039)
This PR hides a configurable field if its dependencies (document field `depends_on`) are not satisfied. Fields that have one or many dependencies also have some styling changes.
This commit is contained in:
parent
7172905d63
commit
a7c9880263
7 changed files with 104 additions and 14 deletions
|
@ -13,6 +13,7 @@ export const NATIVE_CONNECTOR_DEFINITIONS: Record<string, NativeConnector | unde
|
|||
mongodb: {
|
||||
configuration: {
|
||||
host: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
label: i18n.translate(
|
||||
'xpack.enterpriseSearch.nativeConnectors.mongodb.configuration.hostLabel',
|
||||
|
@ -27,6 +28,7 @@ export const NATIVE_CONNECTOR_DEFINITIONS: Record<string, NativeConnector | unde
|
|||
value: '',
|
||||
},
|
||||
user: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
label: i18n.translate(
|
||||
'xpack.enterpriseSearch.nativeConnectors.mongodb.configuration.usernameLabel',
|
||||
|
@ -41,6 +43,7 @@ export const NATIVE_CONNECTOR_DEFINITIONS: Record<string, NativeConnector | unde
|
|||
value: '',
|
||||
},
|
||||
password: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
label: i18n.translate(
|
||||
'xpack.enterpriseSearch.nativeConnectors.mongodb.configuration.passwordLabel',
|
||||
|
@ -55,6 +58,7 @@ export const NATIVE_CONNECTOR_DEFINITIONS: Record<string, NativeConnector | unde
|
|||
value: '',
|
||||
},
|
||||
database: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
label: i18n.translate(
|
||||
'xpack.enterpriseSearch.nativeConnectors.mongodb.configuration.databaseLabel',
|
||||
|
@ -69,6 +73,7 @@ export const NATIVE_CONNECTOR_DEFINITIONS: Record<string, NativeConnector | unde
|
|||
value: '',
|
||||
},
|
||||
collection: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
label: i18n.translate(
|
||||
'xpack.enterpriseSearch.nativeConnectors.mongodb.configuration.collectionLabel',
|
||||
|
@ -83,6 +88,7 @@ export const NATIVE_CONNECTOR_DEFINITIONS: Record<string, NativeConnector | unde
|
|||
value: '',
|
||||
},
|
||||
direct_connection: {
|
||||
depends_on: [],
|
||||
display: 'toggle',
|
||||
label: i18n.translate(
|
||||
'xpack.enterpriseSearch.nativeConnectors.mongodb.configuration.directConnectionLabel',
|
||||
|
@ -113,6 +119,7 @@ export const NATIVE_CONNECTOR_DEFINITIONS: Record<string, NativeConnector | unde
|
|||
mysql: {
|
||||
configuration: {
|
||||
host: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
label: i18n.translate(
|
||||
'xpack.enterpriseSearch.nativeConnectors.mysql.configuration.hostLabel',
|
||||
|
@ -127,6 +134,7 @@ export const NATIVE_CONNECTOR_DEFINITIONS: Record<string, NativeConnector | unde
|
|||
value: '',
|
||||
},
|
||||
port: {
|
||||
depends_on: [],
|
||||
display: 'numeric',
|
||||
label: i18n.translate(
|
||||
'xpack.enterpriseSearch.nativeConnectors.mysql.configuration.portLabel',
|
||||
|
@ -141,6 +149,7 @@ export const NATIVE_CONNECTOR_DEFINITIONS: Record<string, NativeConnector | unde
|
|||
value: '',
|
||||
},
|
||||
user: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
label: i18n.translate(
|
||||
'xpack.enterpriseSearch.nativeConnectors.mysql.configuration.usernameLabel',
|
||||
|
@ -155,6 +164,7 @@ export const NATIVE_CONNECTOR_DEFINITIONS: Record<string, NativeConnector | unde
|
|||
value: '',
|
||||
},
|
||||
password: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
label: i18n.translate(
|
||||
'xpack.enterpriseSearch.nativeConnectors.mysql.configuration.passwordLabel',
|
||||
|
@ -169,6 +179,7 @@ export const NATIVE_CONNECTOR_DEFINITIONS: Record<string, NativeConnector | unde
|
|||
value: '',
|
||||
},
|
||||
database: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
label: i18n.translate(
|
||||
'xpack.enterpriseSearch.nativeConnectors.mysql.configuration.databaseLabel',
|
||||
|
@ -183,6 +194,7 @@ export const NATIVE_CONNECTOR_DEFINITIONS: Record<string, NativeConnector | unde
|
|||
value: '',
|
||||
},
|
||||
tables: {
|
||||
depends_on: [],
|
||||
display: 'textarea',
|
||||
label: i18n.translate(
|
||||
'xpack.enterpriseSearch.nativeConnectors.mysql.configuration.tablesLabel',
|
||||
|
@ -197,6 +209,7 @@ export const NATIVE_CONNECTOR_DEFINITIONS: Record<string, NativeConnector | unde
|
|||
value: '',
|
||||
},
|
||||
ssl_enabled: {
|
||||
depends_on: [],
|
||||
display: 'toggle',
|
||||
label: i18n.translate(
|
||||
'xpack.enterpriseSearch.nativeConnectors.mysql.configuration.sslEnabledLabel',
|
||||
|
@ -211,6 +224,7 @@ export const NATIVE_CONNECTOR_DEFINITIONS: Record<string, NativeConnector | unde
|
|||
value: false,
|
||||
},
|
||||
ssl_ca: {
|
||||
depends_on: [{ field: 'ssl_enabled', value: true }],
|
||||
display: 'textbox',
|
||||
label: i18n.translate(
|
||||
'xpack.enterpriseSearch.nativeConnectors.mysql.configuration.sslCertificateLabel',
|
||||
|
|
|
@ -5,15 +5,23 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
export interface SelectOptions {
|
||||
export interface SelectOption {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface Dependency {
|
||||
field: string;
|
||||
value: string | number | boolean | null;
|
||||
}
|
||||
|
||||
export type DependencyLookup = Record<string, string | number | boolean | null>;
|
||||
|
||||
export interface ConnectorConfigProperties {
|
||||
depends_on: Dependency[];
|
||||
display: string;
|
||||
label: string;
|
||||
options: SelectOptions[];
|
||||
options: SelectOption[];
|
||||
order?: number | null;
|
||||
required: boolean;
|
||||
sensitive: boolean;
|
||||
|
|
|
@ -34,6 +34,7 @@ export const indices: ElasticsearchIndexWithIngestion[] = [
|
|||
api_key_id: null,
|
||||
configuration: {
|
||||
foo: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
key: 'foo',
|
||||
label: 'bar',
|
||||
|
@ -141,6 +142,7 @@ export const indices: ElasticsearchIndexWithIngestion[] = [
|
|||
api_key_id: null,
|
||||
configuration: {
|
||||
foo: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
key: 'foo',
|
||||
label: 'bar',
|
||||
|
|
|
@ -44,6 +44,7 @@ export const connectorIndex: ConnectorViewIndex = {
|
|||
api_key_id: null,
|
||||
configuration: {
|
||||
foo: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
key: 'foo',
|
||||
label: 'bar',
|
||||
|
@ -155,6 +156,7 @@ export const crawlerIndex: CrawlerViewIndex = {
|
|||
api_key_id: null,
|
||||
configuration: {
|
||||
foo: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
key: 'foo',
|
||||
label: 'bar',
|
||||
|
|
|
@ -16,16 +16,22 @@ import {
|
|||
EuiFlexItem,
|
||||
EuiButton,
|
||||
EuiButtonEmpty,
|
||||
EuiPanel,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { Status } from '../../../../../../common/types/api';
|
||||
import { DependencyLookup } from '../../../../../../common/types/connectors';
|
||||
|
||||
import { ConnectorConfigurationApiLogic } from '../../../api/connector/update_connector_configuration_api_logic';
|
||||
|
||||
import { ConnectorConfigurationField } from './connector_configuration_field';
|
||||
import { ConnectorConfigurationLogic } from './connector_configuration_logic';
|
||||
import {
|
||||
ConfigEntry,
|
||||
ConnectorConfigurationLogic,
|
||||
dependenciesSatisfied,
|
||||
} from './connector_configuration_logic';
|
||||
|
||||
export const ConnectorConfigurationForm = () => {
|
||||
const { status } = useValues(ConnectorConfigurationApiLogic);
|
||||
|
@ -33,6 +39,14 @@ export const ConnectorConfigurationForm = () => {
|
|||
const { localConfigView } = useValues(ConnectorConfigurationLogic);
|
||||
const { saveConfig, setIsEditing } = useActions(ConnectorConfigurationLogic);
|
||||
|
||||
const dependencyLookup: DependencyLookup = localConfigView.reduce(
|
||||
(prev: Record<string, string | number | boolean | null>, configEntry: ConfigEntry) => ({
|
||||
...prev,
|
||||
[configEntry.key]: configEntry.value,
|
||||
}),
|
||||
{}
|
||||
);
|
||||
|
||||
return (
|
||||
<EuiForm
|
||||
onSubmit={(event) => {
|
||||
|
@ -42,9 +56,20 @@ export const ConnectorConfigurationForm = () => {
|
|||
component="form"
|
||||
>
|
||||
{localConfigView.map((configEntry) => {
|
||||
const { key, label } = configEntry;
|
||||
const { depends_on: dependencies, key, label } = configEntry;
|
||||
const hasDependencies = dependencies.length > 0;
|
||||
|
||||
return (
|
||||
return hasDependencies ? (
|
||||
dependenciesSatisfied(dependencies, dependencyLookup) ? (
|
||||
<EuiPanel color="subdued" borderRadius="none">
|
||||
<EuiFormRow label={label ?? ''} key={key}>
|
||||
<ConnectorConfigurationField configEntry={configEntry} />
|
||||
</EuiFormRow>
|
||||
</EuiPanel>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
) : (
|
||||
<EuiFormRow label={label ?? ''} key={key}>
|
||||
<ConnectorConfigurationField configEntry={configEntry} />
|
||||
</EuiFormRow>
|
||||
|
|
|
@ -52,6 +52,7 @@ describe('ConnectorConfigurationLogic', () => {
|
|||
ConnectorConfigurationApiLogic.actions.apiSuccess({
|
||||
configuration: {
|
||||
foo: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
label: 'newBar',
|
||||
options: [],
|
||||
|
@ -67,6 +68,7 @@ describe('ConnectorConfigurationLogic', () => {
|
|||
...DEFAULT_VALUES,
|
||||
configState: {
|
||||
foo: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
label: 'newBar',
|
||||
options: [],
|
||||
|
@ -78,6 +80,7 @@ describe('ConnectorConfigurationLogic', () => {
|
|||
},
|
||||
configView: [
|
||||
{
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
key: 'foo',
|
||||
label: 'newBar',
|
||||
|
@ -93,6 +96,7 @@ describe('ConnectorConfigurationLogic', () => {
|
|||
it('should set config on setConfigState', () => {
|
||||
ConnectorConfigurationLogic.actions.setConfigState({
|
||||
foo: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
label: 'thirdBar',
|
||||
options: [],
|
||||
|
@ -106,6 +110,7 @@ describe('ConnectorConfigurationLogic', () => {
|
|||
...DEFAULT_VALUES,
|
||||
configState: {
|
||||
foo: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
label: 'thirdBar',
|
||||
options: [],
|
||||
|
@ -117,6 +122,7 @@ describe('ConnectorConfigurationLogic', () => {
|
|||
},
|
||||
configView: [
|
||||
{
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
key: 'foo',
|
||||
label: 'thirdBar',
|
||||
|
@ -133,6 +139,7 @@ describe('ConnectorConfigurationLogic', () => {
|
|||
it('should set local config entry and sort keys', () => {
|
||||
ConnectorConfigurationLogic.actions.setConfigState({
|
||||
bar: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
label: 'foo',
|
||||
options: [],
|
||||
|
@ -142,6 +149,7 @@ describe('ConnectorConfigurationLogic', () => {
|
|||
value: 'foofoo',
|
||||
},
|
||||
password: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
label: 'thirdBar',
|
||||
options: [],
|
||||
|
@ -153,6 +161,7 @@ describe('ConnectorConfigurationLogic', () => {
|
|||
});
|
||||
ConnectorConfigurationLogic.actions.setLocalConfigState({
|
||||
bar: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
label: 'foo',
|
||||
options: [],
|
||||
|
@ -162,6 +171,7 @@ describe('ConnectorConfigurationLogic', () => {
|
|||
value: 'foofoo',
|
||||
},
|
||||
password: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
label: 'thirdBar',
|
||||
options: [],
|
||||
|
@ -172,6 +182,7 @@ describe('ConnectorConfigurationLogic', () => {
|
|||
},
|
||||
});
|
||||
ConnectorConfigurationLogic.actions.setLocalConfigEntry({
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
key: 'bar',
|
||||
label: 'foo',
|
||||
|
@ -185,6 +196,7 @@ describe('ConnectorConfigurationLogic', () => {
|
|||
...DEFAULT_VALUES,
|
||||
configState: {
|
||||
bar: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
label: 'foo',
|
||||
options: [],
|
||||
|
@ -194,6 +206,7 @@ describe('ConnectorConfigurationLogic', () => {
|
|||
value: 'foofoo',
|
||||
},
|
||||
password: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
label: 'thirdBar',
|
||||
options: [],
|
||||
|
@ -205,6 +218,7 @@ describe('ConnectorConfigurationLogic', () => {
|
|||
},
|
||||
configView: [
|
||||
{
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
key: 'bar',
|
||||
label: 'foo',
|
||||
|
@ -215,6 +229,7 @@ describe('ConnectorConfigurationLogic', () => {
|
|||
value: 'foofoo',
|
||||
},
|
||||
{
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
key: 'password',
|
||||
label: 'thirdBar',
|
||||
|
@ -227,6 +242,7 @@ describe('ConnectorConfigurationLogic', () => {
|
|||
],
|
||||
localConfigState: {
|
||||
bar: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
label: 'foo',
|
||||
options: [],
|
||||
|
@ -236,6 +252,7 @@ describe('ConnectorConfigurationLogic', () => {
|
|||
value: 'fafa',
|
||||
},
|
||||
password: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
label: 'thirdBar',
|
||||
options: [],
|
||||
|
@ -247,6 +264,7 @@ describe('ConnectorConfigurationLogic', () => {
|
|||
},
|
||||
localConfigView: [
|
||||
{
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
key: 'bar',
|
||||
label: 'foo',
|
||||
|
@ -257,6 +275,7 @@ describe('ConnectorConfigurationLogic', () => {
|
|||
value: 'fafa',
|
||||
},
|
||||
{
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
key: 'password',
|
||||
label: 'thirdBar',
|
||||
|
@ -278,6 +297,7 @@ describe('ConnectorConfigurationLogic', () => {
|
|||
configState: connectorIndex.connector.configuration,
|
||||
configView: [
|
||||
{
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
key: 'foo',
|
||||
label: 'bar',
|
||||
|
@ -311,6 +331,7 @@ describe('ConnectorConfigurationLogic', () => {
|
|||
configState: connectorIndex.connector.configuration,
|
||||
configView: [
|
||||
{
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
key: 'foo',
|
||||
label: 'bar',
|
||||
|
@ -329,6 +350,7 @@ describe('ConnectorConfigurationLogic', () => {
|
|||
localConfigState: connectorIndex.connector.configuration,
|
||||
localConfigView: [
|
||||
{
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
key: 'foo',
|
||||
label: 'bar',
|
||||
|
@ -349,6 +371,7 @@ describe('ConnectorConfigurationLogic', () => {
|
|||
ConnectorConfigurationLogic.actions.fetchIndexApiSuccess(connectorIndex);
|
||||
ConnectorConfigurationLogic.actions.setLocalConfigState({
|
||||
foo: {
|
||||
depends_on: [],
|
||||
display: 'textbox',
|
||||
label: 'bar',
|
||||
options: [],
|
||||
|
|
|
@ -7,7 +7,13 @@
|
|||
|
||||
import { kea, MakeLogicType } from 'kea';
|
||||
|
||||
import { ConnectorConfiguration, ConnectorStatus } from '../../../../../../common/types/connectors';
|
||||
import {
|
||||
ConnectorConfiguration,
|
||||
ConnectorStatus,
|
||||
Dependency,
|
||||
DependencyLookup,
|
||||
SelectOption,
|
||||
} from '../../../../../../common/types/connectors';
|
||||
import { isNotNullish } from '../../../../../../common/utils/is_not_nullish';
|
||||
|
||||
import {
|
||||
|
@ -48,16 +54,12 @@ interface ConnectorConfigurationValues {
|
|||
shouldStartInEditMode: boolean;
|
||||
}
|
||||
|
||||
interface SelectOptions {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface ConfigEntry {
|
||||
depends_on: Dependency[];
|
||||
display: string;
|
||||
key: string;
|
||||
label: string;
|
||||
options: SelectOptions[];
|
||||
options: SelectOption[];
|
||||
order?: number;
|
||||
required: boolean;
|
||||
sensitive: boolean;
|
||||
|
@ -107,6 +109,19 @@ export function ensureBooleanType(value: string | number | boolean | null): bool
|
|||
return Boolean(value);
|
||||
}
|
||||
|
||||
export function dependenciesSatisfied(
|
||||
dependencies: Dependency[],
|
||||
dependencyLookup: DependencyLookup
|
||||
): boolean {
|
||||
for (const dependency of dependencies) {
|
||||
if (dependency.value !== dependencyLookup[dependency.field]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export const ConnectorConfigurationLogic = kea<
|
||||
MakeLogicType<ConnectorConfigurationValues, ConnectorConfigurationActions>
|
||||
>({
|
||||
|
@ -214,10 +229,11 @@ export const ConnectorConfigurationLogic = kea<
|
|||
{
|
||||
setLocalConfigEntry: (
|
||||
configState,
|
||||
{ key, display, label, options, order, required, sensitive, value }
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
{ key, depends_on, display, label, options, order, required, sensitive, value }
|
||||
) => ({
|
||||
...configState,
|
||||
[key]: { display, label, options, order, required, sensitive, value },
|
||||
[key]: { depends_on, display, label, options, order, required, sensitive, value },
|
||||
}),
|
||||
setLocalConfigState: (_, { configState }) => configState,
|
||||
},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue