[ResponseOps] [OnWeek] Adding new fields to the form lib library (#157040)

## Summary

Adding the following new fields to form lib:

- ButtonGroupField
- MultiButtonGroupField
- DatePickerField
- PasswordField
- HiddenField

I updated the maintenance windows form and the following connector forms
to use the new fields:

- cases_webhook
- email
- servicenow
- swimlane
- torq
- webhook
- xmatters
This commit is contained in:
Alexi Doak 2023-05-26 17:38:27 -04:00 committed by GitHub
parent 5850a1cf67
commit 30ba9a985d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 657 additions and 490 deletions

View file

@ -28,6 +28,11 @@ import {
SuperSelectField,
ToggleField,
JsonEditorField,
ButtonGroupField,
MultiButtonGroupField,
DatePickerField,
PasswordField,
HiddenField,
} from './fields';
const mapTypeToFieldComponent: { [key: string]: ComponentType<any> } = {
@ -43,6 +48,11 @@ const mapTypeToFieldComponent: { [key: string]: ComponentType<any> } = {
[FIELD_TYPES.SUPER_SELECT]: SuperSelectField,
[FIELD_TYPES.TOGGLE]: ToggleField,
[FIELD_TYPES.JSON]: JsonEditorField,
[FIELD_TYPES.BUTTON_GROUP]: ButtonGroupField,
[FIELD_TYPES.MULTI_BUTTON_GROUP]: MultiButtonGroupField,
[FIELD_TYPES.DATE_PICKER]: DatePickerField,
[FIELD_TYPES.PASSWORD]: PasswordField,
[FIELD_TYPES.HIDDEN]: HiddenField,
};
export const Field = (props: Props) => {

View file

@ -0,0 +1,50 @@
/*
* 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 { EuiButtonGroup, EuiButtonGroupOptionProps, EuiFormRow } from '@elastic/eui';
import { FieldHook, getFieldValidityAndErrorMessage } from '../../hook_form_lib';
interface Props {
field: FieldHook;
euiFieldProps: {
options: EuiButtonGroupOptionProps[];
legend: string;
[key: string]: any;
};
idAria?: string;
[key: string]: any;
}
export const ButtonGroupField = ({ field, euiFieldProps, idAria, ...rest }: Props) => {
const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field);
return (
<EuiFormRow
label={field.label}
helpText={typeof field.helpText === 'function' ? field.helpText() : field.helpText}
error={errorMessage}
isInvalid={isInvalid}
fullWidth
describedByIds={idAria ? [idAria] : undefined}
{...rest}
>
<EuiButtonGroup
isFullWidth
onChange={(e) => {
field.setValue(e);
}}
idSelected={field.value as string}
type="single"
data-test-subj="button-group"
{...euiFieldProps}
/>
</EuiFormRow>
);
};

View file

@ -0,0 +1,46 @@
/*
* 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 { Moment } from 'moment';
import { EuiDatePicker, EuiFormRow } from '@elastic/eui';
import { FieldHook, getFieldValidityAndErrorMessage } from '../../hook_form_lib';
interface Props {
field: FieldHook;
euiFieldProps: Record<string, any>;
idAria?: string;
[key: string]: any;
}
export const DatePickerField = ({ field, euiFieldProps, idAria, ...rest }: Props) => {
const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field);
return (
<EuiFormRow
label={field.label}
helpText={typeof field.helpText === 'function' ? field.helpText() : field.helpText}
error={errorMessage}
isInvalid={isInvalid}
fullWidth
describedByIds={idAria ? [idAria] : undefined}
{...rest}
>
<EuiDatePicker
fullWidth
selected={field.value as Moment}
onChange={(e) => {
field.setValue(e);
}}
data-test-subj="input"
{...euiFieldProps}
/>
</EuiFormRow>
);
};

View file

@ -0,0 +1,15 @@
/*
* 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 const HiddenField = () => {
/**
* This is a hidden field. We return null so we do not render
* any field on the form
*/
return null;
};

View file

@ -18,3 +18,8 @@ export * from './super_select_field';
export * from './toggle_field';
export * from './text_area_field';
export * from './json_editor_field';
export * from './button_group_field';
export * from './multi_button_group_field';
export * from './date_picker_field';
export * from './password_field';
export * from './hidden_field';

View file

@ -0,0 +1,55 @@
/*
* 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 { EuiButtonGroup, EuiButtonGroupOptionProps, EuiFormRow } from '@elastic/eui';
import { FieldHook, getFieldValidityAndErrorMessage } from '../../hook_form_lib';
export interface MultiButtonGroupFieldValue {
[id: string]: boolean;
}
interface Props {
field: FieldHook;
euiFieldProps: {
options: EuiButtonGroupOptionProps[];
legend: string;
[key: string]: any;
};
idAria?: string;
[key: string]: any;
}
export const MultiButtonGroupField = ({ field, euiFieldProps, idAria, ...rest }: Props) => {
const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field);
return (
<EuiFormRow
label={field.label}
helpText={typeof field.helpText === 'function' ? field.helpText() : field.helpText}
error={errorMessage}
isInvalid={isInvalid}
fullWidth
describedByIds={idAria ? [idAria] : undefined}
{...rest}
>
<EuiButtonGroup
isFullWidth
onChange={(e) => {
const value = field.value as MultiButtonGroupFieldValue;
field.setValue({ ...value, [e]: !value[e] });
}}
idToSelectedMap={field.value as MultiButtonGroupFieldValue}
type="multi"
data-test-subj="button-group"
{...euiFieldProps}
/>
</EuiFormRow>
);
};

View file

@ -0,0 +1,44 @@
/*
* 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 { EuiFieldPassword, EuiFormRow } from '@elastic/eui';
import { FieldHook, getFieldValidityAndErrorMessage } from '../../hook_form_lib';
interface Props {
field: FieldHook;
euiFieldProps: Record<string, any>;
idAria?: string;
[key: string]: any;
}
export const PasswordField = ({ field, euiFieldProps, idAria, ...rest }: Props) => {
const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field);
return (
<EuiFormRow
label={field.label}
helpText={typeof field.helpText === 'function' ? field.helpText() : field.helpText}
error={errorMessage}
isInvalid={isInvalid}
fullWidth
describedByIds={idAria ? [idAria] : undefined}
{...rest}
>
<EuiFieldPassword
fullWidth
isInvalid={isInvalid}
value={field.value as string}
onChange={field.onChange}
data-test-subj="input"
{...euiFieldProps}
/>
</EuiFormRow>
);
};

View file

@ -46,6 +46,11 @@ This is the list of component we currently have. This list might grow in the fut
* MultiSelectField
* RadioGroupField
* RangeField
* ButtonGroupField
* MultiButtonGroupField
* DatePickerField
* PasswordField
* HiddenField
(*) Currently the `<ComboBoxField />` only support the free form entry of items (e.g a list of "tags" that the user enters). This means that it does not work (yet) **with predefined selections** to chose from.

View file

@ -20,6 +20,11 @@ export const FIELD_TYPES = {
SUPER_SELECT: 'superSelect',
MULTI_SELECT: 'multiSelect',
JSON: 'json',
BUTTON_GROUP: 'buttonGroup',
MULTI_BUTTON_GROUP: 'multiButtonGroup',
DATE_PICKER: 'datePicker',
PASSWORD: 'password',
HIDDEN: 'hidden',
};
// Validation types

View file

@ -1,74 +0,0 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React, { useCallback } from 'react';
import { EuiButtonGroup, EuiButtonGroupOptionProps, EuiFormRow } from '@elastic/eui';
import {
useFormData,
useFormContext,
FieldHook,
} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { get } from 'lodash';
interface ButtonGroupFieldProps {
field: FieldHook;
legend: string;
options: EuiButtonGroupOptionProps[];
type?: 'single' | 'multi';
'data-test-subj'?: string;
}
export const ButtonGroupField: React.FC<ButtonGroupFieldProps> = React.memo(
({ field, legend, options, type = 'single', ...rest }) => {
const { setFieldValue } = useFormContext();
const [formData] = useFormData({ watch: [field.path] });
const selected = get(formData, field.path);
const onChange = useCallback(
(current: string) => {
setFieldValue(field.path, current);
},
[setFieldValue, field.path]
);
const onChangeMulti = useCallback(
(current: string) => {
const newSelectedValue = { ...selected, [current]: !selected[current] };
// Don't allow the user to deselect all options
if (!Object.values(newSelectedValue).every((v) => v === false)) {
setFieldValue(field.path, newSelectedValue);
}
},
[setFieldValue, selected, field.path]
);
return (
<EuiFormRow label={field.label} {...rest} fullWidth>
{type === 'multi' ? (
<EuiButtonGroup
isFullWidth
legend={legend}
onChange={onChangeMulti}
idToSelectedMap={selected}
options={options}
type="multi"
/>
) : (
<EuiButtonGroup
isFullWidth
legend={legend}
onChange={onChange}
idSelected={selected}
options={options}
type="single"
/>
)}
</EuiFormRow>
);
}
);
ButtonGroupField.displayName = 'ButtonGroupField';

View file

@ -1,55 +0,0 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React, { useCallback, useState } from 'react';
import moment, { Moment } from 'moment';
import { EuiDatePicker, EuiFormRow } from '@elastic/eui';
import {
useFormData,
useFormContext,
FieldHook,
} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { getSelectedForDatePicker as getSelected } from '../../helpers/get_selected_for_date_picker';
interface DatePickerFieldProps {
field: FieldHook;
showTimeSelect?: boolean;
'data-test-subj'?: string;
}
export const DatePickerField: React.FC<DatePickerFieldProps> = React.memo(
({ field, showTimeSelect = true, ...rest }) => {
const [today] = useState<Moment>(moment());
const { setFieldValue } = useFormContext();
const [form] = useFormData({ watch: [field.path] });
const { selected, utcOffset } = getSelected(form, field.path);
const onChange = useCallback(
(currentDate: Moment | null) => {
// convert the moment date back into a string if it's not null
setFieldValue(field.path, currentDate ? currentDate.toISOString() : currentDate);
},
[setFieldValue, field.path]
);
return (
<EuiFormRow label={field.label} {...rest} fullWidth>
<EuiDatePicker
showTimeSelect={showTimeSelect}
selected={selected}
onChange={onChange}
minDate={today}
utcOffset={utcOffset}
fullWidth
/>
</EuiFormRow>
);
}
);
DatePickerField.displayName = 'DatePickerField';

View file

@ -7,12 +7,18 @@
import React, { useMemo } from 'react';
import moment from 'moment';
import { css } from '@emotion/react';
import { getUseField, useFormData } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { Field } from '@kbn/es-ui-shared-plugin/static/forms/components';
import {
FIELD_TYPES,
getUseField,
useFormData,
} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import {
Field,
MultiButtonGroupFieldValue,
} from '@kbn/es-ui-shared-plugin/static/forms/components';
import { EuiFlexGroup, EuiFlexItem, EuiFormLabel, EuiSpacer } from '@elastic/eui';
import { CREATE_FORM_CUSTOM_FREQUENCY, Frequency, WEEKDAY_OPTIONS } from '../../constants';
import * as i18n from '../../translations';
import { ButtonGroupField } from '../fields/button_group_field';
import { getInitialByWeekday } from '../../helpers/get_initial_by_weekday';
import { getWeekdayInfo } from '../../helpers/get_weekday_info';
import { FormProps } from '../schema';
@ -103,13 +109,30 @@ export const CustomRecurringSchedule: React.FC = React.memo(() => {
recurringSchedule?.frequency === Frequency.DAILY ? (
<UseField
path="recurringSchedule.byweekday"
config={{ label: '', validations: [], defaultValue: defaultByWeekday }}
component={ButtonGroupField}
config={{
type: FIELD_TYPES.MULTI_BUTTON_GROUP,
label: '',
validations: [
{
validator: ({ value }) => {
if (
Object.values(value as MultiButtonGroupFieldValue).every((v) => v === false)
) {
return {
message: i18n.CREATE_FORM_BYWEEKDAY_REQUIRED,
};
}
},
},
],
defaultValue: defaultByWeekday,
}}
componentProps={{
'data-test-subj': 'byweekday-field',
legend: 'Repeat on weekday',
options: WEEKDAY_OPTIONS,
type: 'multi',
euiFieldProps: {
legend: 'Repeat on weekday',
options: WEEKDAY_OPTIONS,
},
}}
/>
) : null}
@ -117,12 +140,12 @@ export const CustomRecurringSchedule: React.FC = React.memo(() => {
{recurringSchedule?.customFrequency === Frequency.MONTHLY ? (
<UseField
path="recurringSchedule.bymonth"
config={{ label: '', validations: [], defaultValue: 'day' }}
component={ButtonGroupField}
componentProps={{
'data-test-subj': 'bymonth-field',
legend: 'Repeat on weekday or month day',
options: bymonthOptions,
euiFieldProps: {
legend: 'Repeat on weekday or month day',
options: bymonthOptions,
},
}}
/>
) : null}

View file

@ -4,8 +4,8 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React, { useMemo } from 'react';
import moment from 'moment';
import React, { useMemo, useState } from 'react';
import moment, { Moment } from 'moment';
import {
EuiComboBox,
EuiFlexGroup,
@ -15,7 +15,11 @@ import {
EuiSpacer,
EuiSplitPanel,
} from '@elastic/eui';
import { getUseField, useFormData } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import {
FIELD_TYPES,
getUseField,
useFormData,
} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { Field } from '@kbn/es-ui-shared-plugin/static/forms/components';
import { getWeekdayInfo } from '../../helpers/get_weekday_info';
import {
@ -26,8 +30,6 @@ import {
RECURRENCE_END_OPTIONS,
} from '../../constants';
import * as i18n from '../../translations';
import { ButtonGroupField } from '../fields/button_group_field';
import { DatePickerField } from '../fields/date_picker_field';
import { CustomRecurringSchedule } from './custom_recurring_schedule';
import { recurringSummary } from '../../helpers/recurring_summary';
import { getPresets } from '../../helpers/get_presets';
@ -35,7 +37,12 @@ import { FormProps } from '../schema';
const UseField = getUseField({ component: Field });
export const toMoment = (value: string): Moment => moment(value);
export const toString = (value: Moment): string => value.toISOString();
export const RecurringSchedule: React.FC = React.memo(() => {
const [today] = useState<Moment>(moment());
const [{ startDate, endDate, timezone, recurringSchedule }] = useFormData<FormProps>({
watch: [
'startDate',
@ -105,11 +112,12 @@ export const RecurringSchedule: React.FC = React.memo(() => {
) : null}
<UseField
path="recurringSchedule.ends"
component={ButtonGroupField}
componentProps={{
'data-test-subj': 'ends-field',
legend: 'Recurrence ends',
options: RECURRENCE_END_OPTIONS,
euiFieldProps: {
legend: 'Recurrence ends',
options: RECURRENCE_END_OPTIONS,
},
}}
/>
{recurringSchedule?.ends === EndsOptions.ON_DATE ? (
@ -120,14 +128,19 @@ export const RecurringSchedule: React.FC = React.memo(() => {
<UseField
path="recurringSchedule.until"
config={{
type: FIELD_TYPES.DATE_PICKER,
label: '',
defaultValue: moment(endDate).endOf('day').toISOString(),
validations: [],
serializer: toString,
deserializer: toMoment,
}}
component={DatePickerField}
componentProps={{
'data-test-subj': 'until-field',
showTimeSelect: false,
euiFieldProps: {
showTimeSelect: false,
minDate: today,
},
}}
/>
</EuiFlexItem>

View file

@ -69,6 +69,7 @@ export const schema: FormSchema<FormProps> = {
],
},
ends: {
type: FIELD_TYPES.BUTTON_GROUP,
label: i18n.CREATE_FORM_ENDS,
defaultValue: EndsOptions.NEVER,
validations: [],
@ -90,6 +91,6 @@ export const schema: FormSchema<FormProps> = {
defaultValue: Frequency.WEEKLY,
},
byweekday: {},
bymonth: {},
bymonth: { type: FIELD_TYPES.BUTTON_GROUP, label: '', validations: [], defaultValue: 'day' },
},
};

View file

@ -312,6 +312,13 @@ export const CREATE_FORM_WEEKDAY_SHORT = (dayOfWeek: string) => [
}),
];
export const CREATE_FORM_BYWEEKDAY_REQUIRED = i18n.translate(
'xpack.alerting.maintenanceWindows.createForm.byweekdayFieldRequiredError',
{
defaultMessage: 'A week day is required.',
}
);
export const CREATE_FORM_CUSTOM_REPEAT_MONTHLY_ON_DAY = (startDate: Moment) =>
i18n.translate('xpack.alerting.maintenanceWindows.createForm.repeatOnMonthlyDay', {
defaultMessage: 'On day {dayNumber}',

View file

@ -21,9 +21,8 @@ import {
useFormContext,
useFormData,
} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { Field, TextField } from '@kbn/es-ui-shared-plugin/static/forms/components';
import { Field, TextField, PasswordField } from '@kbn/es-ui-shared-plugin/static/forms/components';
import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers';
import { PasswordField } from '@kbn/triggers-actions-ui-plugin/public';
import * as i18n from '../translations';
const { emptyField } = fieldValidators;
@ -85,11 +84,20 @@ export const AuthStep: FunctionComponent<Props> = ({ display, readOnly }) => {
/>
</EuiFlexItem>
<EuiFlexItem>
<PasswordField
<UseField
path="secrets.password"
label={i18n.PASSWORD}
readOnly={readOnly}
data-test-subj="webhookPasswordInput"
config={{
label: i18n.PASSWORD,
validations: [
{
validator: emptyField(i18n.PASSWORD_REQUIRED),
},
],
}}
component={PasswordField}
componentProps={{
euiFieldProps: { readOnly, 'data-test-subj': 'webhookPasswordInput' },
}}
/>
</EuiFlexItem>
</EuiFlexGroup>

View file

@ -119,6 +119,13 @@ export const USERNAME_REQUIRED = i18n.translate(
}
);
export const PASSWORD_REQUIRED = i18n.translate(
'xpack.stackConnectors.components.casesWebhook.error.requiredAuthPasswordText',
{
defaultMessage: 'Password is required.',
}
);
export const SUMMARY_REQUIRED = i18n.translate(
'xpack.stackConnectors.components.casesWebhook.error.requiredWebhookSummaryText',
{

View file

@ -24,13 +24,10 @@ import {
SelectField,
TextField,
ToggleField,
PasswordField,
} from '@kbn/es-ui-shared-plugin/static/forms/components';
import type { ActionConnectorFieldsProps } from '@kbn/triggers-actions-ui-plugin/public';
import {
PasswordField,
useConnectorContext,
useKibana,
} from '@kbn/triggers-actions-ui-plugin/public';
import { useConnectorContext, useKibana } from '@kbn/triggers-actions-ui-plugin/public';
import { AdditionalEmailServices } from '../../../common';
import { getEmailServices } from './email';
import { useEmailConfig } from './use_email_config';
@ -297,11 +294,20 @@ export const EmailActionConnectorFields: React.FunctionComponent<ActionConnector
/>
</EuiFlexItem>
<EuiFlexItem>
<PasswordField
<UseField
path="secrets.password"
label={i18n.PASSWORD_LABEL}
readOnly={readOnly}
data-test-subj="emailPasswordInput"
config={{
label: i18n.PASSWORD_LABEL,
validations: [
{
validator: emptyField(i18n.PASSWORD_REQUIRED),
},
],
}}
component={PasswordField}
componentProps={{
euiFieldProps: { readOnly, 'data-test-subj': 'emailPasswordInput' },
}}
/>
</EuiFlexItem>
</EuiFlexGroup>

View file

@ -10,8 +10,8 @@ import { EuiFlexItem, EuiFlexGroup, EuiLink } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers';
import { UseField } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { TextField } from '@kbn/es-ui-shared-plugin/static/forms/components';
import { PasswordField, useKibana } from '@kbn/triggers-actions-ui-plugin/public';
import { TextField, PasswordField } from '@kbn/es-ui-shared-plugin/static/forms/components';
import { useKibana } from '@kbn/triggers-actions-ui-plugin/public';
import * as i18n from './translations';
const { emptyField } = fieldValidators;
@ -83,22 +83,31 @@ const ExchangeFormFields: React.FC<ExchangeFormFieldsProps> = ({ readOnly }) =>
</EuiFlexGroup>
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexItem>
<PasswordField
<UseField
path="secrets.clientSecret"
label={i18n.CLIENT_SECRET_LABEL}
readOnly={readOnly}
helpText={
<EuiLink
href={docLinks.links.alerting.emailExchangeClientSecretConfig}
target="_blank"
>
<FormattedMessage
id="xpack.stackConnectors.components.email.exchangeForm.clientSecretHelpLabel"
defaultMessage="Configure Client Secret"
/>
</EuiLink>
}
data-test-subj="emailClientSecret"
config={{
label: i18n.CLIENT_SECRET_LABEL,
validations: [
{
validator: emptyField(i18n.CLIENT_SECRET_REQUIRED),
},
],
helpText: (
<EuiLink
href={docLinks.links.alerting.emailExchangeClientSecretConfig}
target="_blank"
>
<FormattedMessage
id="xpack.stackConnectors.components.email.exchangeForm.clientSecretHelpLabel"
defaultMessage="Configure Client Secret"
/>
</EuiLink>
),
}}
component={PasswordField}
componentProps={{
euiFieldProps: { readOnly, 'data-test-subj': 'emailClientSecret' },
}}
/>
</EuiFlexItem>
</EuiFlexGroup>

View file

@ -161,6 +161,20 @@ export const SUBJECT_REQUIRED = i18n.translate(
}
);
export const PASSWORD_REQUIRED = i18n.translate(
'xpack.stackConnectors.components.email.error.requiredPasswordText',
{
defaultMessage: 'Password is required.',
}
);
export const CLIENT_SECRET_REQUIRED = i18n.translate(
'xpack.stackConnectors.components.email.requiredClientSecretText',
{
defaultMessage: 'Client Secret is required.',
}
);
export function getInvalidEmailAddress(email: string) {
return i18n.translate('xpack.stackConnectors.components.email.error.invalidEmail', {
defaultMessage: 'Email address {email} is not valid.',

View file

@ -25,14 +25,15 @@ import {
VALIDATION_TYPES,
} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers';
import { ToggleField, SelectField } from '@kbn/es-ui-shared-plugin/static/forms/components';
import {
ToggleField,
SelectField,
HiddenField,
} from '@kbn/es-ui-shared-plugin/static/forms/components';
import { DocLinksStart } from '@kbn/core/public';
import { FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';
import {
type ActionConnectorFieldsProps,
HiddenField,
} from '@kbn/triggers-actions-ui-plugin/public';
import { type ActionConnectorFieldsProps } from '@kbn/triggers-actions-ui-plugin/public';
import {
firstFieldOption,
getFields,
@ -134,7 +135,7 @@ const IndexActionConnectorFields: React.FunctionComponent<ActionConnectorFieldsP
/>
</h5>
</EuiTitle>
<HiddenField path={'config.refresh'} />
<UseField path="config.refresh" component={HiddenField} />
<EuiSpacer size="m" />
<UseField path="config.index" config={getIndexConfig(docLinks)}>
{(field) => {

View file

@ -8,8 +8,7 @@
import React, { memo } from 'react';
import { UseField } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers';
import { TextField } from '@kbn/es-ui-shared-plugin/static/forms/components';
import { PasswordField } from '@kbn/triggers-actions-ui-plugin/public';
import { TextField, PasswordField } from '@kbn/es-ui-shared-plugin/static/forms/components';
import * as i18n from '../translations';
interface Props {
@ -43,13 +42,25 @@ const CredentialsAuthComponent: React.FC<Props> = ({ isLoading, readOnly, pathPr
},
}}
/>
<PasswordField
<UseField
path={`${pathPrefix}secrets.password`}
label={i18n.PASSWORD_LABEL}
readOnly={readOnly}
data-test-subj="connector-servicenow-password-form-input"
isLoading={isLoading}
disabled={readOnly || isLoading}
config={{
label: i18n.PASSWORD_LABEL,
validations: [
{
validator: emptyField(i18n.PASSWORD_REQUIRED),
},
],
}}
component={PasswordField}
componentProps={{
euiFieldProps: {
'data-test-subj': 'connector-servicenow-password-form-input',
isLoading,
readOnly,
disabled: readOnly || isLoading,
},
}}
/>
</>
);

View file

@ -8,8 +8,11 @@
import React, { memo } from 'react';
import { UseField } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers';
import { TextAreaField, TextField } from '@kbn/es-ui-shared-plugin/static/forms/components';
import { PasswordField } from '@kbn/triggers-actions-ui-plugin/public';
import {
TextAreaField,
TextField,
PasswordField,
} from '@kbn/es-ui-shared-plugin/static/forms/components';
import * as i18n from '../translations';
interface Props {
@ -83,13 +86,25 @@ const OAuthComponent: React.FC<Props> = ({ isLoading, readOnly, pathPrefix = ''
},
}}
/>
<PasswordField
<UseField
path={`${pathPrefix}secrets.clientSecret`}
label={i18n.CLIENTSECRET_LABEL}
readOnly={readOnly}
data-test-subj="connector-servicenow-client-secret-form-input"
isLoading={isLoading}
disabled={readOnly || isLoading}
config={{
label: i18n.CLIENTSECRET_LABEL,
validations: [
{
validator: emptyField(i18n.CLIENTSECRET_REQUIRED),
},
],
}}
component={PasswordField}
componentProps={{
euiFieldProps: {
'data-test-subj': 'connector-servicenow-client-secret-form-input',
isLoading,
readOnly,
disabled: readOnly || isLoading,
},
}}
/>
<UseField
path="secrets.privateKey"
@ -110,15 +125,22 @@ const OAuthComponent: React.FC<Props> = ({ isLoading, readOnly, pathPrefix = ''
},
}}
/>
<PasswordField
<UseField
path={`${pathPrefix}secrets.privateKeyPassword`}
label={i18n.PRIVATE_KEY_PASSWORD_LABEL}
helpText={i18n.PRIVATE_KEY_PASSWORD_HELPER_TEXT}
validate={false}
data-test-subj="connector-servicenow-private-key-password-form-input"
readOnly={readOnly}
isLoading={isLoading}
disabled={readOnly || isLoading}
config={{
label: i18n.PRIVATE_KEY_PASSWORD_LABEL,
validations: [],
helpText: i18n.PRIVATE_KEY_PASSWORD_HELPER_TEXT,
}}
component={PasswordField}
componentProps={{
euiFieldProps: {
'data-test-subj': 'connector-servicenow-private-key-password-form-input',
isLoading,
readOnly,
disabled: readOnly || isLoading,
},
}}
/>
</>
);

View file

@ -8,13 +8,14 @@
import React, { useCallback, useEffect, useState, useMemo } from 'react';
import { EuiSpacer } from '@elastic/eui';
import { useFormContext, useFormData } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import type { ActionConnectorFieldsProps } from '@kbn/triggers-actions-ui-plugin/public';
import {
HiddenField,
updateActionConnector,
useKibana,
} from '@kbn/triggers-actions-ui-plugin/public';
UseField,
useFormContext,
useFormData,
} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { HiddenField } from '@kbn/es-ui-shared-plugin/static/forms/components';
import type { ActionConnectorFieldsProps } from '@kbn/triggers-actions-ui-plugin/public';
import { updateActionConnector, useKibana } from '@kbn/triggers-actions-ui-plugin/public';
import type { ConnectorFormSchema } from '@kbn/triggers-actions-ui-plugin/public';
import { snExternalServiceConfig } from '../../../../common/servicenow_config';
import { DeprecatedCallout } from './deprecated_callout';
@ -174,7 +175,12 @@ const ServiceNowConnectorFields: React.FC<ActionConnectorFieldsProps> = ({
<InstallationCallout appId={snExternalServiceConfig[action.actionTypeId]?.appId ?? ''} />
)}
{!requiresNewApplication && <SpacedDeprecatedCallout onMigrate={onMigrateClick} />}
<HiddenField path={'config.usesTableApi'} config={{ defaultValue: false }} />
<UseField
path="config.usesTableApi"
component={HiddenField}
config={{ defaultValue: false }}
/>
<Credentials readOnly={readOnly} isLoading={isLoading} isOAuth={isOAuth} />
</>
);

View file

@ -360,6 +360,20 @@ export const USER_IDENTIFIER_REQUIRED = i18n.translate(
}
);
export const PASSWORD_REQUIRED = i18n.translate(
'xpack.stackConnectors.components.serviceNow.requiredPasswordTextField',
{
defaultMessage: 'Password is required.',
}
);
export const CLIENTSECRET_REQUIRED = i18n.translate(
'xpack.stackConnectors.components.serviceNow.requiredClientSecretTextField',
{
defaultMessage: 'Client Secret is required.',
}
);
export const IS_OAUTH = i18n.translate('xpack.stackConnectors.components.serviceNow.useOAuth', {
defaultMessage: 'Use OAuth authentication',
});

View file

@ -8,10 +8,10 @@
import React from 'react';
import { EuiLink } from '@elastic/eui';
import { UseField } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { TextField } from '@kbn/es-ui-shared-plugin/static/forms/components';
import { TextField, PasswordField } from '@kbn/es-ui-shared-plugin/static/forms/components';
import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers';
import { FormattedMessage } from '@kbn/i18n-react';
import { PasswordField, useKibana } from '@kbn/triggers-actions-ui-plugin/public';
import { useKibana } from '@kbn/triggers-actions-ui-plugin/public';
import * as i18n from '../translations';
interface Props {
@ -62,22 +62,34 @@ const SwimlaneConnectionComponent: React.FunctionComponent<Props> = ({ readOnly
},
}}
/>
<PasswordField
<UseField
path="secrets.apiToken"
label={i18n.SW_API_TOKEN_TEXT_FIELD_LABEL}
readOnly={readOnly}
helpText={
<EuiLink
href={`${docLinks.ELASTIC_WEBSITE_URL}guide/en/kibana/${docLinks.DOC_LINK_VERSION}/swimlane-action-type.html`}
target="_blank"
>
<FormattedMessage
id="xpack.stackConnectors.components.swimlane.apiTokenNameHelpLabel"
defaultMessage="Provide a Swimlane API Token"
/>
</EuiLink>
}
data-test-subj="swimlaneApiTokenInput"
config={{
label: i18n.SW_API_TOKEN_TEXT_FIELD_LABEL,
validations: [
{
validator: emptyField(i18n.SW_REQUIRED_API_TOKEN),
},
],
helpText: (
<EuiLink
href={`${docLinks.ELASTIC_WEBSITE_URL}guide/en/kibana/${docLinks.DOC_LINK_VERSION}/swimlane-action-type.html`}
target="_blank"
>
<FormattedMessage
id="xpack.stackConnectors.components.swimlane.apiTokenNameHelpLabel"
defaultMessage="Provide a Swimlane API Token"
/>
</EuiLink>
),
}}
component={PasswordField}
componentProps={{
euiFieldProps: {
'data-test-subj': 'swimlaneApiTokenInput',
readOnly,
},
}}
/>
</>
);

View file

@ -14,9 +14,9 @@ import {
useFormData,
VALIDATION_TYPES,
} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { ComboBoxField } from '@kbn/es-ui-shared-plugin/static/forms/components';
import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers';
import { ComboBoxField, ButtonGroupField } from '@kbn/es-ui-shared-plugin/static/forms/components';
import { ButtonGroupField } from '@kbn/triggers-actions-ui-plugin/public';
import * as i18n from '../translations';
import {
MappingConfigurationKeys,
@ -25,6 +25,8 @@ import {
} from '../types';
import { isRequiredField, isValidFieldForConnector } from '../helpers';
const { emptyField } = fieldValidators;
const SINGLE_SELECTION = { asPlainText: true };
const EMPTY_COMBO_BOX_ARRAY: Array<EuiComboBoxOptionOption<string>> | undefined = [];
@ -176,12 +178,26 @@ const SwimlaneFieldsComponent: React.FC<Props> = ({ fields, readOnly }) => {
return (
<>
<ButtonGroupField
defaultValue={SwimlaneConnectorType.All}
path={'config.connectorType'}
label={i18n.SW_CONNECTOR_TYPE_LABEL}
legend={i18n.SW_CONNECTOR_TYPE_LABEL}
options={connectorTypeButtons}
<UseField
path="config.connectorType"
component={ButtonGroupField}
config={{
label: i18n.SW_CONNECTOR_TYPE_LABEL,
defaultValue: SwimlaneConnectorType.All,
validations: [
{
validator: emptyField(i18n.SW_REQUIRED_CONNECTOR_TYPE),
},
],
}}
componentProps={{
euiFieldProps: {
legend: i18n.SW_CONNECTOR_TYPE_LABEL,
options: connectorTypeButtons,
buttonSize: 'm',
color: 'primary',
},
}}
/>
{isValidFieldForConnector(connectorType as SwimlaneConnectorType.All, 'alertIdConfig') && (
<MappingField

View file

@ -187,6 +187,20 @@ export const SW_REQUIRED_ALERT_ID = i18n.translate(
}
);
export const SW_REQUIRED_API_TOKEN = i18n.translate(
'xpack.stackConnectors.components.swimlane.error.requiredApiToken',
{
defaultMessage: 'API Token is required.',
}
);
export const SW_REQUIRED_CONNECTOR_TYPE = i18n.translate(
'xpack.stackConnectors.components.swimlane.error.requiredConnectorType',
{
defaultMessage: 'Connector Type is required.',
}
);
export const SW_BACK = i18n.translate('xpack.stackConnectors.components.swimlane.prevStep', {
defaultMessage: 'Back',
});

View file

@ -6,7 +6,7 @@
*/
import { EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui';
import { Field } from '@kbn/es-ui-shared-plugin/static/forms/components';
import { Field, PasswordField } from '@kbn/es-ui-shared-plugin/static/forms/components';
import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers';
import { ERROR_CODE } from '@kbn/es-ui-shared-plugin/static/forms/helpers/field_validators/types';
import {
@ -15,11 +15,11 @@ import {
ValidationFunc,
} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { isUrl } from '@kbn/es-ui-shared-plugin/static/validators/string';
import { ActionConnectorFieldsProps, PasswordField } from '@kbn/triggers-actions-ui-plugin/public';
import { ActionConnectorFieldsProps } from '@kbn/triggers-actions-ui-plugin/public';
import React from 'react';
import * as i18n from './translations';
const { urlField } = fieldValidators;
const { urlField, emptyField } = fieldValidators;
const Callout: React.FC<{ title: string; dataTestSubj: string }> = ({ title, dataTestSubj }) => {
return (
@ -78,12 +78,24 @@ const TorqActionConnectorFields: React.FunctionComponent<ActionConnectorFieldsPr
/>
</EuiFlexItem>
<EuiFlexItem>
<PasswordField
<UseField
path="secrets.token"
label={i18n.TORQ_TOKEN_LABEL}
readOnly={readOnly}
helpText={i18n.TORQ_TOKEN_HELP_TEXT}
data-test-subj="torqTokenInput"
config={{
label: i18n.TORQ_TOKEN_LABEL,
validations: [
{
validator: emptyField(i18n.TORQ_TOKEN_REQUIRED),
},
],
helpText: i18n.TORQ_TOKEN_HELP_TEXT,
}}
component={PasswordField}
componentProps={{
euiFieldProps: {
'data-test-subj': 'torqTokenInput',
readOnly,
},
}}
/>
</EuiFlexItem>
</EuiFlexGroup>

View file

@ -40,6 +40,13 @@ export const TORQ_TOKEN_LABEL = i18n.translate('xpack.stackConnectors.torqAction
defaultMessage: 'Torq integration token',
});
export const TORQ_TOKEN_REQUIRED = i18n.translate(
'xpack.stackConnectors.error.requiredWebhookTorqTokenText',
{
defaultMessage: 'Torq integration token is required.',
}
);
export const BODY_REQUIRED = i18n.translate('xpack.stackConnectors.error.requiredWebhookBodyText', {
defaultMessage: 'Body is required.',
});

View file

@ -104,3 +104,10 @@ export const BODY_REQUIRED = i18n.translate(
defaultMessage: 'Body is required.',
}
);
export const PASSWORD_REQUIRED = i18n.translate(
'xpack.stackConnectors.components.webhook.error.requiredWebhookPasswordText',
{
defaultMessage: 'Password is required.',
}
);

View file

@ -27,10 +27,10 @@ import {
SelectField,
TextField,
ToggleField,
PasswordField,
} from '@kbn/es-ui-shared-plugin/static/forms/components';
import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers';
import type { ActionConnectorFieldsProps } from '@kbn/triggers-actions-ui-plugin/public';
import { PasswordField } from '@kbn/triggers-actions-ui-plugin/public';
import * as i18n from './translations';
const HTTP_VERBS = ['post', 'put'];
@ -138,11 +138,23 @@ const WebhookActionConnectorFields: React.FunctionComponent<ActionConnectorField
/>
</EuiFlexItem>
<EuiFlexItem>
<PasswordField
<UseField
path="secrets.password"
label={i18n.PASSWORD_LABEL}
readOnly={readOnly}
data-test-subj="webhookPasswordInput"
config={{
label: i18n.PASSWORD_LABEL,
validations: [
{
validator: emptyField(i18n.PASSWORD_REQUIRED),
},
],
}}
component={PasswordField}
componentProps={{
euiFieldProps: {
'data-test-subj': 'webhookPasswordInput',
readOnly,
},
}}
/>
</EuiFlexItem>
</EuiFlexGroup>

View file

@ -14,6 +14,13 @@ export const BASIC_AUTH_LABEL = i18n.translate(
}
);
export const BASIC_AUTH_REQUIRED = i18n.translate(
'xpack.stackConnectors.components.xmatters.error.requiredConnectorSettingsText',
{
defaultMessage: 'Authentication method is required.',
}
);
export const BASIC_AUTH_BUTTON_GROUP_LEGEND = i18n.translate(
'xpack.stackConnectors.components.xmatters.basicAuthButtonGroupLegend',
{
@ -39,6 +46,13 @@ export const PASSWORD_LABEL = i18n.translate(
}
);
export const PASSWORD_REQUIRED = i18n.translate(
'xpack.stackConnectors.components.xmatters.error.requiredPasswordText',
{
defaultMessage: 'Password is required.',
}
);
export const BASIC_AUTH_BUTTON_LABEL = i18n.translate(
'xpack.stackConnectors.components.xmatters.basicAuthLabel',
{

View file

@ -15,13 +15,13 @@ import {
useFormContext,
useFormData,
} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { TextField } from '@kbn/es-ui-shared-plugin/static/forms/components';
import type { ActionConnectorFieldsProps } from '@kbn/triggers-actions-ui-plugin/public';
import {
ButtonGroupField,
HiddenField,
TextField,
PasswordField,
} from '@kbn/triggers-actions-ui-plugin/public';
HiddenField,
ButtonGroupField,
} from '@kbn/es-ui-shared-plugin/static/forms/components';
import type { ActionConnectorFieldsProps } from '@kbn/triggers-actions-ui-plugin/public';
import { XmattersAuthenticationType } from '../types';
import * as i18n from './translations';
@ -107,14 +107,28 @@ const XmattersActionConnectorFields: React.FunctionComponent<ActionConnectorFiel
</h4>
</EuiTitle>
<EuiSpacer size="xs" />
<ButtonGroupField
defaultValue={selectedAuthDefaultValue}
path={'__internal__.auth'}
label={i18n.BASIC_AUTH_LABEL}
legend={i18n.BASIC_AUTH_BUTTON_GROUP_LEGEND}
options={authenticationButtons}
<UseField
path="__internal__.auth"
component={ButtonGroupField}
config={{
label: i18n.BASIC_AUTH_LABEL,
defaultValue: selectedAuthDefaultValue,
validations: [
{
validator: emptyField(i18n.BASIC_AUTH_REQUIRED),
},
],
}}
componentProps={{
euiFieldProps: {
legend: i18n.BASIC_AUTH_BUTTON_GROUP_LEGEND,
options: authenticationButtons,
buttonSize: 'm',
color: 'primary',
},
}}
/>
<HiddenField path={'config.usesBasic'} config={{ defaultValue: true }} />
<UseField path="config.usesBasic" component={HiddenField} config={{ defaultValue: true }} />
<EuiSpacer size="m" />
{selectedAuth === XmattersAuthenticationType.URL ? (
<EuiFlexGroup justifyContent="spaceBetween">
@ -167,11 +181,23 @@ const XmattersActionConnectorFields: React.FunctionComponent<ActionConnectorFiel
</EuiFlexGroup>
<EuiFlexGroup>
<EuiFlexItem>
<PasswordField
<UseField
path="secrets.password"
label={i18n.PASSWORD_LABEL}
readOnly={readOnly}
data-test-subj="xmattersPasswordInput"
config={{
label: i18n.PASSWORD_LABEL,
validations: [
{
validator: emptyField(i18n.PASSWORD_REQUIRED),
},
],
}}
component={PasswordField}
componentProps={{
euiFieldProps: {
'data-test-subj': 'xmattersPasswordInput',
readOnly,
},
}}
/>
</EuiFlexItem>
</EuiFlexGroup>

View file

@ -37723,7 +37723,6 @@
"xpack.triggersActionsUI.checkActionTypeEnabled.actionTypeDisabledByLicenseMessage": "Ce connecteur requiert une licence {minimumLicenseRequired}.",
"xpack.triggersActionsUI.checkRuleTypeEnabled.ruleTypeDisabledByLicenseMessage": "Ce type de règle requiert une licence {minimumLicenseRequired}.",
"xpack.triggersActionsUI.components.builtinActionTypes.missingSecretsValuesLabel": "Les informations sensibles ne sont pas importées. Veuillez saisir une/des valeur{encryptedFieldsLength, plural, one {} many {s} other {s}} pour le ou les champ{encryptedFieldsLength, plural, one {} many {s} other {s}} suivants {secretFieldsLabel}.",
"xpack.triggersActionsUI.components.buttonGroupField.error.requiredField": "{label} est requis.",
"xpack.triggersActionsUI.components.deleteSelectedIdsErrorNotification.descriptionText": "Impossible de supprimer {numErrors, number} {numErrors, plural, one {{singleTitle}} many {{multipleTitle}} other {{multipleTitle}}}",
"xpack.triggersActionsUI.components.deleteSelectedIdsPartialSuccessNotification.descriptionText": "Suppression effectuée de {numberOfSuccess, number} {numberOfSuccess, plural, one {{singleTitle}} many {{multipleTitle}} other {{multipleTitle}}}, {numberOfErrors, number} {numberOfErrors, plural, one {{singleTitle}} many {{multipleTitle}} other {{multipleTitle}}} erreur(s) rencontrée(s)",
"xpack.triggersActionsUI.components.deleteSelectedIdsSuccessNotification.descriptionText": "La suppression de {numSuccesses, number} {numSuccesses, plural, one {{singleTitle}} many {{multipleTitle}} other {{multipleTitle}}} a été effectuée",
@ -37733,7 +37732,6 @@
"xpack.triggersActionsUI.components.enableSelectedIdsErrorNotification.descriptionText": "Impossible d'activer {numErrors, number} {numErrors, plural, one {{singleTitle}} many {{multipleTitle}} other {{multipleTitle}}}",
"xpack.triggersActionsUI.components.enableSelectedIdsPartialSuccessNotification.descriptionText": "Activation effectuée de {numberOfSuccess, number} {numberOfSuccess, plural, one {{singleTitle}} many {{multipleTitle}} other {{multipleTitle}}}, {numberOfErrors, number} {numberOfErrors, plural, one {{singleTitle}} many {{multipleTitle}} other {{multipleTitle}}} erreur(s) rencontrée(s)",
"xpack.triggersActionsUI.components.enableSelectedIdsSuccessNotification.descriptionText": "Activation effectuée de {numSuccesses, number} {numSuccesses, plural, one {{singleTitle}} many {{multipleTitle}} other {{multipleTitle}}}",
"xpack.triggersActionsUI.components.passwordField.error.requiredNameText": "{label} est requis.",
"xpack.triggersActionsUI.components.simpleConnectorForm.secrets.reenterValuesLabel": "Mémorisez votre/vos {encryptedFieldsLength, plural, one {valeur} many {valeurs} other {valeurs}} {secretFieldsLabel}. Vous devrez {encryptedFieldsLength, plural, one {le} many {les} other {les}} entrer à nouveau chaque fois que vous modifierez le connecteur.",
"xpack.triggersActionsUI.components.simpleConnectorForm.secrets.reenterValuesMessage": "La/les valeur{encryptedFieldsLength, plural, one {} many {s} other {s}} {secretFieldsLabel} {encryptedFieldsLength, plural, one {est} many {sont} other {sont}} chiffrée(s). Veuillez entrer à nouveau la/les valeur{encryptedFieldsLength, plural, one {} many {s} other {s}} pour {encryptedFieldsLength, plural, one {ce} many {ces} other {ces}} champ{encryptedFieldsLength, plural, one {} many {s} other {s}}.",
"xpack.triggersActionsUI.data.coreQueryParams.aggTypeRequiredErrorMessage": "[aggField] : doit posséder une valeur lorsque [aggType] est \"{aggType}\"",

View file

@ -37704,8 +37704,6 @@
"xpack.triggersActionsUI.checkActionTypeEnabled.actionTypeDisabledByLicenseMessage": "このコネクターには{minimumLicenseRequired}ライセンスが必要です。",
"xpack.triggersActionsUI.checkRuleTypeEnabled.ruleTypeDisabledByLicenseMessage": "このルールタイプには{minimumLicenseRequired}ライセンスが必要です。",
"xpack.triggersActionsUI.components.builtinActionTypes.missingSecretsValuesLabel": "機密情報はインポートされません。次のフィールド{encryptedFieldsLength, plural, other {s}}{secretFieldsLabel}の値{encryptedFieldsLength, plural, other {s}}を入力してください。",
"xpack.triggersActionsUI.components.buttonGroupField.error.requiredField": "{label}は必須です。",
"xpack.triggersActionsUI.components.passwordField.error.requiredNameText": "{label}は必須です。",
"xpack.triggersActionsUI.components.simpleConnectorForm.secrets.reenterValuesLabel": "{secretFieldsLabel} {encryptedFieldsLength, plural, other {値}}を記憶しておいてください。コネクターを編集するたびに、{encryptedFieldsLength, plural, other {それらを}}再入力する必要があります。",
"xpack.triggersActionsUI.components.simpleConnectorForm.secrets.reenterValuesMessage": "値{encryptedFieldsLength, plural, other {s}}{secretFieldsLabel}{encryptedFieldsLength, plural, other {あります}}暗号化されました。{encryptedFieldsLength, plural, other {これらの}}フィールド{encryptedFieldsLength, plural, other {s}}の値{encryptedFieldsLength, plural, other {s}}を再入力してください。",
"xpack.triggersActionsUI.data.coreQueryParams.aggTypeRequiredErrorMessage": "[aggType]が\"{aggType}\"のときには[aggField]に値が必要です",

View file

@ -37698,8 +37698,6 @@
"xpack.triggersActionsUI.checkActionTypeEnabled.actionTypeDisabledByLicenseMessage": "此连接器需要{minimumLicenseRequired}许可证。",
"xpack.triggersActionsUI.checkRuleTypeEnabled.ruleTypeDisabledByLicenseMessage": "此规则类型需要{minimumLicenseRequired}许可证。",
"xpack.triggersActionsUI.components.builtinActionTypes.missingSecretsValuesLabel": "未导入敏感信息。请为以下字段{encryptedFieldsLength, plural, other {s}} {secretFieldsLabel} 输入值{encryptedFieldsLength, plural, other {s}}。",
"xpack.triggersActionsUI.components.buttonGroupField.error.requiredField": "{label} 必填。",
"xpack.triggersActionsUI.components.passwordField.error.requiredNameText": "{label} 必填。",
"xpack.triggersActionsUI.components.simpleConnectorForm.secrets.reenterValuesLabel": "记住您的 {secretFieldsLabel} {encryptedFieldsLength, plural, other {值}}。每次编辑连接器时都必须重新输入{encryptedFieldsLength, plural, other {这些值}}。",
"xpack.triggersActionsUI.components.simpleConnectorForm.secrets.reenterValuesMessage": "值{encryptedFieldsLength, plural, other {s}} {secretFieldsLabel}{encryptedFieldsLength, plural, other { }}已加密。请为{encryptedFieldsLength, plural, other {这些}}字段{encryptedFieldsLength, plural, other {s}}重新输入值{encryptedFieldsLength, plural, other {s}}。",
"xpack.triggersActionsUI.data.coreQueryParams.aggTypeRequiredErrorMessage": "[aggField]:当 [aggType] 为“{aggType}”时必须具有值",

View file

@ -1,80 +0,0 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React, { memo, ReactNode } from 'react';
import { EuiButtonGroup, EuiFormRow } from '@elastic/eui';
import {
getFieldValidityAndErrorMessage,
UseField,
} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers';
import { i18n } from '@kbn/i18n';
const { emptyField } = fieldValidators;
const getFieldConfig = ({ label, defaultValue }: { label: string; defaultValue?: string }) => ({
label,
defaultValue,
validations: [
{
validator: emptyField(
i18n.translate('xpack.triggersActionsUI.components.buttonGroupField.error.requiredField', {
values: { label },
defaultMessage: '{label} is required.',
})
),
},
],
});
interface Props {
path: string;
label: string;
defaultValue?: string;
helpText?: string | ReactNode;
[key: string]: any;
}
const ButtonGroupFieldComponent: React.FC<Props> = ({
path,
label,
helpText,
defaultValue,
...rest
}) => {
return (
<UseField<string> path={path} config={getFieldConfig({ label, defaultValue })}>
{(field) => {
const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field);
return (
<EuiFormRow
label={field.label}
labelAppend={field.labelAppend}
helpText={helpText}
error={errorMessage}
isInvalid={isInvalid}
fullWidth
>
<EuiButtonGroup
isFullWidth
buttonSize="m"
legend="Select"
color="primary"
options={[]}
idSelected={field.value}
onChange={field.setValue}
{...rest}
/>
</EuiFormRow>
);
}}
</UseField>
);
};
export const ButtonGroupField = memo(ButtonGroupFieldComponent);

View file

@ -1,25 +0,0 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React, { memo } from 'react';
import { UseField, UseFieldProps } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
const HiddenFieldComponent = <T,>(props: UseFieldProps<T>) => {
return (
<UseField<T> {...props}>
{(field) => {
/**
* This is a hidden field. We return null so we do not render
* any field on the form
*/
return null;
}}
</UseField>
);
};
export const HiddenField = memo(HiddenFieldComponent);

View file

@ -6,13 +6,10 @@
*/
export { JsonEditorWithMessageVariables } from './json_editor_with_message_variables';
export { HiddenField } from './hidden_field';
export { PasswordField } from './password_field';
export { TextFieldWithMessageVariables } from './text_field_with_message_variables';
export { TextAreaWithMessageVariables } from './text_area_with_message_variables';
export { SimpleConnectorForm } from './simple_connector_form';
export type { ConfigFieldSchema, SecretsFieldSchema } from './simple_connector_form';
export { ButtonGroupField } from './button_group_field';
export { JsonFieldWrapper } from './json_field_wrapper';
export { MustacheTextFieldWrapper } from './mustache_text_field_wrapper';
export { SectionLoading } from './section_loading';

View file

@ -1,86 +0,0 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React, { memo, ReactNode } from 'react';
import { EuiFieldPassword, EuiFormRow } from '@elastic/eui';
import {
getFieldValidityAndErrorMessage,
UseField,
} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers';
import { i18n } from '@kbn/i18n';
const { emptyField } = fieldValidators;
const getFieldConfig = ({ label, validate }: { label: string; validate: boolean }) => ({
label,
validations: [
...(validate
? [
{
validator: emptyField(
i18n.translate(
'xpack.triggersActionsUI.components.passwordField.error.requiredNameText',
{
values: { label },
defaultMessage: '{label} is required.',
}
)
),
},
]
: []),
],
});
interface PasswordFieldProps {
path: string;
label: string;
helpText?: string | ReactNode;
validate?: boolean;
isLoading?: boolean;
[key: string]: any;
}
const PasswordFieldComponent: React.FC<PasswordFieldProps> = ({
path,
label,
helpText,
validate = true,
isLoading,
...rest
}) => {
return (
<UseField<string> path={path} config={getFieldConfig({ label, validate })}>
{(field) => {
const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field);
return (
<EuiFormRow
label={field.label}
labelAppend={field.labelAppend}
helpText={helpText}
error={errorMessage}
isInvalid={isInvalid}
fullWidth
>
<EuiFieldPassword
isInvalid={isInvalid}
value={field.value}
onChange={field.onChange}
isLoading={field.isValidating || isLoading === true}
fullWidth
{...rest}
/>
</EuiFormRow>
);
}}
</UseField>
);
};
export const PasswordField = memo(PasswordFieldComponent);

View file

@ -7,11 +7,10 @@
import React, { memo, ReactNode } from 'react';
import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiTitle } from '@elastic/eui';
import { Field } from '@kbn/es-ui-shared-plugin/static/forms/components';
import { Field, PasswordField } from '@kbn/es-ui-shared-plugin/static/forms/components';
import { getUseField } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers';
import { i18n } from '@kbn/i18n';
import { PasswordField } from './password_field';
export interface CommonFieldSchema {
id: string;
@ -104,12 +103,17 @@ const FormRow: React.FC<FormRowProps> = ({
}}
/>
) : (
<PasswordField
<UseField
path={id}
label={label}
readOnly={readOnly}
data-test-subj={dataTestSub}
config={getFieldConfig({ label })}
helpText={helpText}
component={PasswordField}
componentProps={{
euiFieldProps: {
'data-test-subj': dataTestSub,
readOnly,
},
}}
/>
)}
</EuiFlexItem>

View file

@ -9,11 +9,9 @@ import React, { memo } from 'react';
import { FieldConfig, UseField } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers';
import { Field } from '@kbn/es-ui-shared-plugin/static/forms/components';
import { Field, HiddenField } from '@kbn/es-ui-shared-plugin/static/forms/components';
import { i18n } from '@kbn/i18n';
import { HiddenField } from '../../components/hidden_field';
interface ConnectorFormData {
name: string;
}
@ -43,9 +41,9 @@ const nameConfig: FieldConfig<{ name: string }, ConnectorFormData> = {
const ConnectorFormFieldsGlobalComponent: React.FC<ConnectorFormFieldsProps> = ({ canSave }) => {
return (
<>
<HiddenField path={'id'} />
<HiddenField path={'actionTypeId'} />
<HiddenField path={'isDeprecated'} />
<UseField path="id" component={HiddenField} />
<UseField path="actionTypeId" component={HiddenField} />
<UseField path="isDeprecated" component={HiddenField} />
<UseField
path="name"
config={nameConfig}

View file

@ -75,12 +75,9 @@ export { getCategory } from './application/sections/field_browser/helpers';
export type { ConfigFieldSchema, SecretsFieldSchema } from './application/components';
export {
ButtonGroupField,
HiddenField,
JsonEditorWithMessageVariables,
JsonFieldWrapper,
MustacheTextFieldWrapper,
PasswordField,
SimpleConnectorForm,
TextAreaWithMessageVariables,
TextFieldWithMessageVariables,