@ibm-adw/skill-toolkit
Version:
Developing your own skills with IBM Automation Digital Worker Skill Toolkit
1,190 lines (1,061 loc) • 36.1 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var React = require('react');
var React__default = _interopDefault(React);
var formCommon = require('@adw/form-common');
var carbonComponentsReact = require('carbon-components-react');
var carbonIcons = require('carbon-icons');
var StateDecorator = require('state-decorator');
var StateDecorator__default = _interopDefault(StateDecorator);
var axios = _interopDefault(require('axios'));
/*
Licensed Materials - Property of IBM
5737-I23
Copyright IBM Corp. 2019. All Rights Reserved.
U.S. Government Users Restricted Rights:
Use, duplication or disclosure restricted by GSA ADP Schedule
Contract with IBM Corp.
*/
function CarbonLinkField(props) {
const {
schema,
disabled
} = props;
return React__default.createElement("div", null, React__default.createElement(carbonComponentsReact.Link, {
className: "baiw--field-link",
href: schema.url,
disabled: disabled,
target: "_blank"
}, schema.title, React__default.createElement(carbonComponentsReact.Icon, {
icon: carbonIcons.iconLaunch,
fill: "#0062ff",
className: "baiw--field-link-icon",
description: "",
height: "16px",
width: "16px"
})));
}
CarbonLinkField.defaultProps = {
autofocus: false
};
/*
Licensed Materials - Property of IBM
5737-I23
Copyright IBM Corp. 2019. All Rights Reserved.
U.S. Government Users Restricted Rights:
Use, duplication or disclosure restricted by GSA ADP Schedule
Contract with IBM Corp.
*/
const fields = {
LinkField: CarbonLinkField
};
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function _extends() {
_extends = Object.assign || function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
function ownKeys(object, enumerableOnly) {
var keys = Object.keys(object);
if (Object.getOwnPropertySymbols) {
var symbols = Object.getOwnPropertySymbols(object);
if (enumerableOnly) symbols = symbols.filter(function (sym) {
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
});
keys.push.apply(keys, symbols);
}
return keys;
}
function _objectSpread2(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? arguments[i] : {};
if (i % 2) {
ownKeys(source, true).forEach(function (key) {
_defineProperty(target, key, source[key]);
});
} else if (Object.getOwnPropertyDescriptors) {
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
} else {
ownKeys(source).forEach(function (key) {
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
});
}
}
return target;
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
function _objectWithoutProperties(source, excluded) {
if (source == null) return {};
var target = _objectWithoutPropertiesLoose(source, excluded);
var key, i;
if (Object.getOwnPropertySymbols) {
var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
for (i = 0; i < sourceSymbolKeys.length; i++) {
key = sourceSymbolKeys[i];
if (excluded.indexOf(key) >= 0) continue;
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
target[key] = source[key];
}
}
return target;
}
function CarbonCheckboxWidgetWrapper(props) {
const {
formContext,
options,
value
} = props; // Checkbox's value are by default boolean
// We add the possibility to have checkbox with string values
// This provides the compatibility of checkbox with schema dependencies (oneOf)
let checked = typeof value === 'undefined' || typeof value === 'boolean' ? value : true;
let label = props.label;
if (props.schema && props.schema.type === 'string' && props.schema.enum && props.schema.enum.length === 2) {
if (value && typeof value === 'string') {
checked = value === props.schema.enum[0];
if (props.schema.enumNames && props.schema.enumNames.length === 2) {
label = props.schema.enumNames[props.schema.enum.indexOf(value)];
} else {
label = value;
}
} else {
checked = true;
label = props.schema.enum[0];
}
} // the onChange function called by Carbon's Checkbox has the value as first parameter
const _onChange = checked => {
if (options && options.triggerEvent) {
formContext.setTriggerEvent(options.triggerEvent);
}
let value = checked;
if (props.schema && props.schema.type === 'string' && props.schema.enum && props.schema.enum.length === 2) {
value = checked ? props.schema.enum[0] : props.schema.enum[1];
}
props.onChange(value);
};
return React__default.createElement(formCommon.widgets.CheckboxWidget, _extends({}, props, {
onChange: _onChange,
value: checked,
label: label
}));
}
function CarbonSelectWidgetWrapper(props) {
const {
options,
formContext
} = props;
const _onChange = event => {
props.onChange(event);
if (options && options.triggerEvent) {
formContext.setTriggerEvent(options.triggerEvent);
}
};
return React__default.createElement(formCommon.widgets.SelectWidget, _extends({}, props, {
onChange: _onChange
}));
}
/*
Licensed Materials - Property of IBM
5737-I23
Copyright IBM Corp. 2019. All Rights Reserved.
U.S. Government Users Restricted Rights:
Use, duplication or disclosure restricted by GSA ADP Schedule
Contract with IBM Corp.
*/
function CarbonRadioWidget(props) {
//TODO Carbon had problem with : value, valueSelected, checked pros
// check this is still valid
const {
options,
value,
required,
disabled,
readonly,
autofocus,
formContext,
schema,
onChange,
id
} = props; // Generating a unique field name to identify this set of radio buttons
const name = Math.random().toString();
const {
enumOptions,
enumDisabled
/*, inline*/
} = options; // checked={checked} has been moved above name={name}, As mentioned in #349;
// this is a temporary fix for radio button rendering bug in React, facebook/react#7630.
const _onGlobalChange = function _onGlobalChange(value) {
if (options.triggerEvent) {
formContext.setTriggerEvent(options.triggerEvent);
}
onChange(value === '' ? options.emptyValue : value);
};
return React__default.createElement("div", {
className: "bx--form-item"
}, React__default.createElement(carbonComponentsReact.RadioButtonGroup // TODO: temporary fix for carbon issue with orientation vertical
, {
className: "baiw--vertical-radio-button",
orientation: "vertical",
legend: "Group Legend",
name: id,
valueSelected: value,
onChange: _onGlobalChange
}, enumOptions.map((option, i) => {
const itemDisabled = enumDisabled && enumDisabled.indexOf(option.value) !== -1;
return React__default.createElement(carbonComponentsReact.RadioButton, {
name: name,
required: required,
value: option.value,
disabled: disabled || itemDisabled || readonly,
autoFocus: autofocus && i === 0 //onChange={() => onChange(option.value)}
,
labelText: option.label,
labelPosition: "right",
key: `id${i}` // TODO: temporary fix for carbon issue with orientation vertical
,
className: "baiw--vertical-radio-button-wrapper"
});
})), schema.invalid ? React__default.createElement("div", {
className: "baiw--vertical-radio-button-invalid-wrapper"
}, React__default.createElement("div", {
className: "baiw--vertical-radio-button-invalid bx--form-requirement"
}, schema.invalidText)) : null);
}
CarbonRadioWidget.defaultProps = {
autofocus: false
};
function CarbonBaseInput(props) {
const {
options,
formContext
} = props;
const _onChange = value => {
if (options && options.triggerEvent) {
formContext.setTriggerEvent(options.triggerEvent);
}
props.onChange(value);
};
return React__default.createElement(formCommon.widgets.BaseInput, _extends({}, props, {
onChange: _onChange
}));
}
function CarbonPasswordWidget(props) {
const {
id,
value,
defaultValue,
readonly,
disabled,
autofocus,
onBlur,
onFocus,
onChange,
options,
schema,
formContext,
registry,
rawErrors
} = props,
inputProps = _objectWithoutProperties(props, ["id", "value", "defaultValue", "readonly", "disabled", "autofocus", "onBlur", "onFocus", "onChange", "options", "schema", "formContext", "registry", "rawErrors"]);
const _onChange = React.useCallback(({
target: {
value
}
}) => {
if (options.triggerEvent) {
formContext.setTriggerEvent(options.triggerEvent);
}
onChange(value === '' ? options.emptyValue : value);
}, [options, formContext, onChange]);
const [inputDirty, __onChange, _onBlur] = formCommon.useDirtyInput(_onChange, onBlur, value, defaultValue);
const [invalid, setInvalid] = React.useState(false);
React.useEffect(() => {
if (formContext && formContext.ignoreDirty) {
setInvalid(schema.invalid);
} else {
setInvalid(inputDirty ? schema.invalid : false);
}
}, [formContext, inputDirty, schema.invalid]);
const [showPasswordLabel, setShowPasswordLabel] = React.useState();
const [hidePasswordLabel, setHidePasswordLabel] = React.useState();
React.useEffect(() => {
if (formContext && formContext.showPasswordLabel) {
setShowPasswordLabel(formContext.showPasswordLabel);
}
if (formContext && formContext.hidePasswordLabel) {
setHidePasswordLabel(formContext.hidePasswordLabel);
}
}, [formContext]);
return React__default.createElement(carbonComponentsReact.TextInput.PasswordInput, _extends({
id: id,
disabled: disabled,
invalid: invalid,
invalidText: schema.invalid ? schema.invalidText : '',
labelText: "",
showPasswordLabel: showPasswordLabel,
hidePasswordLabel: hidePasswordLabel,
value: value == null ? '' : value,
defaultValue: defaultValue,
hideLabel: true,
onChange: __onChange,
onBlur: _onBlur
}, inputProps));
}
CarbonPasswordWidget.defaultProps = {
required: true,
disabled: false,
readonly: false,
autofocus: false
};
/*
Licensed Materials - Property of IBM
5737-I23
Copyright IBM Corp. 2019,2020. All Rights Reserved.
U.S. Government Users Restricted Rights:
Use, duplication or disclosure restricted by GSA ADP Schedule
Contract with IBM Corp.
*/
function CarbonTextAreaWidget(props) {
const {
id,
options,
formContext,
schema,
value,
defaultValue,
disabled,
placeholder,
onChange,
onBlur
} = props;
const _onChange = React.useCallback(({
target: {
value
}
}) => {
if (options.triggerEvent) {
formContext.setTriggerEvent(options.triggerEvent);
}
onChange(value === '' ? options.emptyValue : value);
}, [onChange, options, formContext]);
const [inputDirty, __onChange, _onBlur] = formCommon.useDirtyInput(_onChange, onBlur, value, defaultValue);
const [invalid, setInvalid] = React.useState(false);
React.useEffect(() => {
if (formContext && formContext.ignoreDirty) {
setInvalid(schema.invalid);
} else {
setInvalid(inputDirty ? schema.invalid : false);
}
}, [formContext, inputDirty, schema.invalid]);
return React__default.createElement(carbonComponentsReact.TextArea, {
hideLabel: true,
id: id,
onChange: __onChange,
onBlur: _onBlur,
labelText: "",
invalid: invalid,
invalidText: schema.invalid ? schema.invalidText : '',
disabled: disabled,
value: value == null ? '' : value,
defaultValue: defaultValue,
placeholder: placeholder
});
}
CarbonTextAreaWidget.defaultProps = {
autofocus: false,
options: {}
};
function CarbonEmailWidget(props) {
const {
BaseInput
} = props.registry.widgets;
return React__default.createElement(BaseInput, _extends({
type: "email"
}, props));
} //
function CarbonUpDownWidget(props) {
const {
value,
readonly,
disabled,
autofocus,
onBlur,
onFocus,
options,
schema,
formContext,
registry,
rawErrors
} = props,
inputProps = _objectWithoutProperties(props, ["value", "readonly", "disabled", "autofocus", "onBlur", "onFocus", "options", "schema", "formContext", "registry", "rawErrors"]);
const _onChange = function _onChange(_ref) {
const value = _ref.imaginaryTarget.value;
return props.onChange(value === '' ? options.emptyValue : value);
};
return React__default.createElement(carbonComponentsReact.NumberInput, _extends({
className: "form-control bx--fieldset",
readOnly: readonly,
disabled: disabled,
autoFocus: autofocus
}, inputProps, {
onChange: _onChange,
label: "Number Input label",
hideLabel: true //min={min}
//max={max}
,
value: parseInt(value),
step: 1,
isMobile: false,
invalidText: "Number is not valid",
helperText: "Optional helper text."
}));
}
CarbonUpDownWidget.defaultProps = {
required: false,
disabled: false,
readonly: false,
autofocus: false,
value: 0,
options: {}
};
/*
Licensed Materials - Property of IBM
5737-I23
Copyright IBM Corp. 2019. All Rights Reserved.
U.S. Government Users Restricted Rights:
Use, duplication or disclosure restricted by GSA ADP Schedule
Contract with IBM Corp.
*/
const widgets = {
BaseInput: CarbonBaseInput,
CheckboxWidget: CarbonCheckboxWidgetWrapper,
EmailWidget: CarbonEmailWidget,
PasswordWidget: CarbonPasswordWidget,
RadioWidget: CarbonRadioWidget,
SelectWidget: CarbonSelectWidgetWrapper,
TextareaWidget: CarbonTextAreaWidget,
UpDownWidget: CarbonUpDownWidget
};
function updateValidity(errors, schema) {
const updatedSchema = _objectSpread2({}, schema);
if (updatedSchema.error) {
// server side validation error
updatedSchema.invalid = true;
updatedSchema.invalidText = updatedSchema.error;
updatedSchema.error = '';
} else if (errors) {
// client side validation error
updatedSchema.invalid = true;
updatedSchema.invalidText = errors[0];
} else {
updatedSchema.invalid = false;
updatedSchema.invalidText = '';
}
return updatedSchema;
}
function CustomFieldTemplateWrapper(props) {
const {
children
} = props;
const displayLabel = props.displayLabel && typeof props.schema.title !== 'undefined';
return React__default.createElement(formCommon.templates.FieldTemplate, _extends({
updateValidity: updateValidity
}, props, {
displayLabel: displayLabel
}), children); //
}
/*
Licensed Materials - Property of IBM
5737-I23
Copyright IBM Corp. 2019. All Rights Reserved.
U.S. Government Users Restricted Rights:
Use, duplication or disclosure restricted by GSA ADP Schedule
Contract with IBM Corp.
*/
const templates = {
FieldTemplate: CustomFieldTemplateWrapper
};
/*
Licensed Materials - Property of IBM
5737-I23
Copyright IBM Corp. 2019,2020. All Rights Reserved.
U.S. Government Users Restricted Rights:
Use, duplication or disclosure restricted by GSA ADP Schedule
Contract with IBM Corp.
*/
const LINK_TYPES = {
DOCUMENTATION: 'documentation',
SNIPPET: 'snippet',
INPUT_SCHEMA: 'inputSchema',
OUTPUT_SCHEMA: 'outputSchema'
};
const SkillFormLinks = React__default.forwardRef((props, ref) => {
const {
serverUrl,
labels,
supportedLocales,
saveConfig
} = props;
const [disabled, setDisabled] = React.useState(false);
React.useImperativeHandle(ref, () => ({
setDisabled: value => {
setDisabled(value);
}
}), []); // linkType: One of 'documentation', 'inputSchema', 'outputSchema' or 'snippet'
const buildLink = React.useCallback(linkType => {
if (linkType === LINK_TYPES.SNIPPET) {
return `${serverUrl}/snippet`;
} else if (linkType === LINK_TYPES.DOCUMENTATION) {
return `${serverUrl}/documentation?language=${supportedLocales}`;
}
return `${serverUrl}/schema?type=${linkType === LINK_TYPES.INPUT_SCHEMA ? 'input' : 'output'}&pretty=true`;
}, [serverUrl, supportedLocales]);
const handleClick = React.useCallback(linkType => {
return async () => {
if (saveConfig) {
// When saveConfig function is provided, try to save config before opening link
if (await saveConfig()) {
// Open link only when successfully saved config
window.open(buildLink(linkType), '_blank', 'noopener,noreferrer');
}
} else {
window.open(buildLink(linkType), '_blank', 'noopener,noreferrer');
}
};
}, [buildLink, saveConfig]);
const openDocumentation = React.useCallback(() => {
window.open(buildLink(LINK_TYPES.DOCUMENTATION), '_blank', 'noopener,noreferrer');
}, [buildLink]);
return React__default.createElement("div", {
className: "baiw--skills-form-links"
}, React__default.createElement(React__default.Fragment, null, React__default.createElement("div", {
className: 'bx--fieldset baiw--skills-form-links--fieldset'
}, React__default.createElement(carbonComponentsReact.Button, {
id: "skillDocumentationBtn",
className: "baiw--skills-form-links--button",
kind: "ghost",
onClick: openDocumentation
}, labels.buttons.skillDocumentation, React__default.createElement(carbonComponentsReact.Icon, {
icon: carbonIcons.iconLaunch,
description: ""
}))), React__default.createElement("div", {
className: `bx--fieldset baiw--skills-form-links--fieldset ${disabled ? 'baiw--skills-form-links--fieldset-disabled' : ''}`
}, React__default.createElement(carbonComponentsReact.Button, {
id: "sampleInstructionsBtn",
className: "baiw--skills-form-links--button",
kind: "ghost",
disabled: disabled,
onClick: handleClick(LINK_TYPES.SNIPPET)
}, labels.buttons.sampleInstructions, React__default.createElement(carbonComponentsReact.Icon, {
icon: carbonIcons.iconLaunch,
description: ""
}))), React__default.createElement("div", {
className: `bx--fieldset baiw--skills-form-links--fieldset ${disabled ? 'baiw--skills-form-links--fieldset-disabled' : ''}`
}, React__default.createElement(carbonComponentsReact.Button, {
id: "schemaInputBtn",
className: "baiw--skills-form-links--button",
kind: "ghost",
disabled: disabled,
onClick: handleClick(LINK_TYPES.INPUT_SCHEMA)
}, labels.buttons.schemaInput, React__default.createElement(carbonComponentsReact.Icon, {
icon: carbonIcons.iconLaunch,
description: ""
}))), React__default.createElement("div", {
className: `bx--fieldset baiw--skills-form-links--fieldset ${disabled ? 'baiw--skills-form-links--fieldset-disabled' : ''}`
}, React__default.createElement(carbonComponentsReact.Button, {
id: "schemaOutputBtn",
className: "baiw--skills-form-links--button",
kind: "ghost",
disabled: disabled,
onClick: handleClick(LINK_TYPES.OUTPUT_SCHEMA)
}, labels.buttons.schemaOutput, React__default.createElement(carbonComponentsReact.Icon, {
icon: carbonIcons.iconLaunch,
description: ""
})))));
});
/*
Licensed Materials - Property of IBM
5737-I23
Copyright IBM Corp. 2019,2020. All Rights Reserved.
U.S. Government Users Restricted Rights:
Use, duplication or disclosure restricted by GSA ADP Schedule
Contract with IBM Corp.
*/
const SkillFormButtons = React__default.forwardRef((props, ref) => {
const {
onClickCancel,
onClickSubmit,
buttonLabelCancel,
buttonLabelSubmit,
isFormSubmittable
} = props;
const [buttonDisabled, setButtonDisabled] = React.useState(!isFormSubmittable);
React.useImperativeHandle(ref, () => ({
setDisabled: value => {
setButtonDisabled(value);
}
}), []);
return React__default.createElement("div", {
className: "baiw--form_buttons"
}, React__default.createElement(carbonComponentsReact.Button, {
className: "baiw--form_button_left_column",
type: "button",
kind: "secondary",
onClick: onClickCancel
}, buttonLabelCancel), React__default.createElement(carbonComponentsReact.Button, {
className: "baiw--form_button_right_column",
type: "submit",
kind: "primary",
disabled: buttonDisabled,
onClick: onClickSubmit
}, buttonLabelSubmit));
});
/*
Licensed Materials - Property of IBM
5737-I23
Copyright IBM Corp. 2019, 2020. All Rights Reserved.
U.S. Government Users Restricted Rights:
Use, duplication or disclosure restricted by GSA ADP Schedule
Contract with IBM Corp.
*/
function SkillForm(props) {
const {
schema,
uiSchema,
formData,
isLastStaticStep,
isFormSubmittable,
onSubmit,
cancel,
labels,
serverUrl,
saveConfig,
loading,
runStep,
debounceRunStep,
clearDebounceTimeout,
isInitial,
supportedLocales,
transformErrors
} = props; // 'triggerEvent' is created with useRef so all children components get always the same ref object
const triggerEvent = React.useRef(null); // 'setTriggerEvent' is exposed in formContext so any child component can update its value
const setTriggerEvent = React.useCallback(event => {
triggerEvent.current = event;
}, []); // context exposed in formContext
const [context, setContext] = React.useState({});
React.useEffect(() => {
setContext({
setTriggerEvent,
optionalLabel: labels.skillForm.optional,
addItemLabel: labels.skillForm.buttons.addItem,
moveItemUpLabel: labels.skillForm.buttons.moveItemUp,
moveItemDownLabel: labels.skillForm.buttons.moveItemDown,
removeItemLabel: labels.skillForm.buttons.removeItem,
showPasswordLabel: labels.skillForm.password.showPasswordLabel,
hidePasswordLabel: labels.skillForm.password.hidePasswordLabel,
unsupportedFieldLabel: labels.skillForm.unsupportedField,
ignoreDirty: !isInitial
});
}, [setTriggerEvent, labels.skillForm.optional, isInitial, labels.skillForm.buttons, labels.skillForm.password, labels.skillForm.unsupportedField]);
const isInTimeOut = React.useRef(false);
const setIsInTimeOut = React.useCallback(boolean => {
isInTimeOut.current = boolean;
}, []);
let buttonLabel;
let action;
if (isLastStaticStep) {
buttonLabel = labels.skillForm.buttons.submit;
action = onSubmit;
} else {
buttonLabel = labels.skillForm.buttons.next;
action = runStep;
} // 'submitButtonRef' is exposed in skillFormButtons to update the submit button state
const submitButtonRef = React.useRef(null);
const setSubmitButtonRef = React.useCallback(button => {
submitButtonRef.current = button;
}, [submitButtonRef]); // 'skillLinksRef' is exposed in SkillFormLinks to update the links disable state
const skillLinksRef = React.useRef(null);
const setSkillLinksRef = React.useCallback(skillLinks => {
skillLinksRef.current = skillLinks;
}, [skillLinksRef]); // set the submit button and links 'disabled' state
const setButtonLinkDisabledState = React.useCallback(formErrorList => {
if (isInTimeOut.current || loading || !isFormSubmittable || Object.keys(formErrorList).length > 0) {
submitButtonRef.current.setDisabled(true);
skillLinksRef.current.setDisabled(true);
} else {
submitButtonRef.current.setDisabled(false);
skillLinksRef.current.setDisabled(false);
}
}, [loading, isFormSubmittable]);
const _onChange = React.useCallback(state => {
if (triggerEvent.current !== null) {
// At this point the form validation is already done
// Don't call nextStaticStep if there are any errors from validation
if (Object.keys(state.errors).length > 0) {
setTriggerEvent(null);
if (submitButtonRef.current && skillLinksRef.current) {
setButtonLinkDisabledState(state.errors);
}
if (isInTimeOut.current) {
clearDebounceTimeout();
}
return;
}
if (debounceRunStep) {
if (submitButtonRef.current && skillLinksRef.current) {
setIsInTimeOut(true);
setButtonLinkDisabledState(state.errors);
} // Defer execution of step in case there are lots of request in a short amount of time
debounceRunStep(state, triggerEvent.current, () => {
setIsInTimeOut(false);
});
setTriggerEvent(null);
}
} else if (submitButtonRef.current && skillLinksRef.current) {
setButtonLinkDisabledState(state.errors);
}
}, [debounceRunStep, setTriggerEvent, setButtonLinkDisabledState, clearDebounceTimeout, setIsInTimeOut]);
const _onSubmit = React.useCallback(action => {
return state => {
clearDebounceTimeout(); // Execute action (submit or nextStaticStep)
action(state);
};
}, [clearDebounceTimeout]);
const handlerKeyDownEnter = React.useCallback(event => {
if (event.key === 'Enter') {
event.preventDefault();
}
}, []); //Reference the form in order to externalize buttons
//See https://react-jsonschema-form.readthedocs.io/en/latest/#submit-form-programmatically
const formRef = React.useRef(null);
const refCallback = React.useCallback(form => {
if (form) {
formRef.current = form; // Disable the "Enter" keydown by adding an event listener
formRef.current.formElement.addEventListener('keydown', handlerKeyDownEnter);
}
}, [handlerKeyDownEnter]); // On unmount: remove the event listener
React.useEffect(() => () => {
if (formRef.current) {
formRef.current.formElement.removeEventListener('keydown', handlerKeyDownEnter);
}
}, [handlerKeyDownEnter]); // when isFormSubmittable changes we update the submit button state
React.useEffect(() => {
if (formRef.current && submitButtonRef.current && skillLinksRef.current) {
setButtonLinkDisabledState(formRef.current.state.errors);
}
}, [isFormSubmittable, loading, setButtonLinkDisabledState]);
const _saveConfig = React.useCallback(async () => {
try {
await saveConfig(formRef.current.state);
return true;
} catch (error) {
// This means that there was an error when trying to save the configuration. The errors are handled by SkillFormManager.
return false;
}
}, [saveConfig]);
const _transformErrors = React.useCallback(errors => {
//translate errors
if (transformErrors instanceof Function) {
errors = transformErrors(errors);
} // Update "disable" status of buttons based on errors
if (submitButtonRef.current && skillLinksRef.current) {
setButtonLinkDisabledState(errors);
}
return errors;
}, [setButtonLinkDisabledState, transformErrors]); // If schema has a type : Form is not empty
// Display the form
// Avoid displaying buttons without form
if (schema.type) {
return React__default.createElement("div", {
className: "baiw--skill-form"
}, React__default.createElement("div", {
className: "baiw--loading-skeleton"
}, loading ? React__default.createElement(carbonComponentsReact.SkeletonPlaceholder, {
className: "baiw--loading-skeleton-color"
}) : ''), React__default.createElement("div", {
className: "baiw--content"
}, React__default.createElement("div", {
className: "baiw--content-left_column"
}, React__default.createElement(formCommon.FormCommon, {
schema: schema,
uiSchema: uiSchema,
formData: formData,
formContext: context,
onChange: _onChange,
liveValidate: true,
showErrorList: false,
onSubmit: _onSubmit(action),
ref: refCallback,
customWidgets: widgets,
customFields: fields,
customTemplates: templates,
transformErrors: _transformErrors
}, React__default.createElement("span", null))), React__default.createElement("div", {
className: "baiw--content-right_column"
}, React__default.createElement("div", {
id: 'right_column__info',
className: 'bx--fieldset'
}, React__default.createElement(formCommon.fields.TitleField, {
id: 'right_column__title',
title: labels.skillForm.details.header
}), React__default.createElement(formCommon.fields.DescriptionField, {
id: 'right_column__description',
description: labels.skillForm.details.description
})), React__default.createElement(SkillFormLinks, {
ref: setSkillLinksRef,
labels: labels.skillFormLinks,
serverUrl: serverUrl,
saveConfig: _saveConfig,
supportedLocales: supportedLocales
}))), React__default.createElement(SkillFormButtons, {
ref: setSubmitButtonRef,
onClickCancel: cancel,
onClickSubmit: () => formRef.current.submit(),
buttonLabelCancel: labels.skillForm.buttons.cancel,
buttonLabelSubmit: buttonLabel,
isFormSubmittable: isFormSubmittable
}));
} else {
return React__default.createElement("div", {
className: "baiw--skill-form"
}, React__default.createElement("div", {
className: "baiw--content"
}, React__default.createElement("div", {
className: "baiw--loading"
}, React__default.createElement(carbonComponentsReact.Loading, {
withOverlay: false
}))));
}
}
const FINAL_STEP = '__baiw_final';
let runStepSource;
let runStepPromise;
let debounceTimeout;
const DEBOUNCE_DELAY = 500;
const actions = (serverUrl, supportedLocales, {
currentLocale,
fallbackLocale
}, formTitle) => {
return {
clearDebounceTimeout: state => {
clearTimeout(debounceTimeout);
if (runStepSource) {
runStepSource.cancel();
}
return state;
},
debounceRunStep: {
action: (state, [formState]) => {
if (runStepPromise && runStepSource) {
runStepSource.cancel();
}
clearTimeout(debounceTimeout);
return _objectSpread2({}, state, {
formData: formState.formData
});
},
onActionDone: (state, [{
formData
}, step, callback], props, actions) => {
debounceTimeout = setTimeout(() => {
actions.runStep(formData, step);
callback();
}, DEBOUNCE_DELAY);
}
},
runStep: {
promise: ([formData, stepOverride], state) => {
runStepSource = axios.CancelToken.source();
const step = stepOverride === undefined ? state.nextStaticStep : stepOverride;
const options = {
method: 'POST',
headers: {
'Content-Language': supportedLocales
},
url: serverUrl,
data: formData,
params: {
event: step,
currentLocale: currentLocale,
fallbackLocale: fallbackLocale
},
cancelToken: runStepSource ? runStepSource.token : null
};
runStepPromise = axios(options);
return runStepPromise;
},
reducer: (state, {
data
}, [, stepOverride]) => {
const step = stepOverride === undefined ? state.nextStaticStep : stepOverride;
data.schema.title = formTitle;
return {
event: step,
nextStaticStep: data.nextStaticStep,
isLastStaticStep: !data.nextStaticStep,
isFormSubmittable: data.isFormSubmittable === undefined ? true : data.isFormSubmittable,
schema: data.schema,
uiSchema: data.uiSchema || {},
formData: data.formData,
isInitial: data.isInitial !== undefined ? data.isInitial : false
};
},
errorReducer: (state, error, args, props) => {
if (!axios.isCancel(error)) {
// Call onError function if it was passed (only when the error is not due to the request being cancelled)
props.onError(error);
}
return null;
},
conflictPolicy: StateDecorator.ConflictPolicy.KEEP_LAST
},
saveConfig: {
preReducer: (state, [{
formData
}]) => {
// Update state with latest formData
return _objectSpread2({}, state, {
formData
});
},
promise: ([{
formData
}]) => {
const options = {
method: 'POST',
headers: {
'Content-Language': supportedLocales
},
url: serverUrl,
data: formData,
params: {
event: FINAL_STEP
}
};
return axios(options);
},
reducer: () => {
// Schema validation ok and data saved
return null;
},
errorReducer: (state, error, args, props) => {
// Call onError function if it was passed
props.onError(error);
return null;
},
rejectPromiseOnError: true
},
cancel: () => {
return null;
}
};
};
const initialState = {
event: '__baiw_init',
nextStaticStep: undefined,
isLastStaticStep: true,
isFormSubmittable: false,
schema: {},
uiSchema: {},
formData: {},
isInitial: false
};
const onMount = actions => {
// On initialization, the step 0 is requested
actions.runStep({}, initialState.event);
};
const SkillFormManager = ({
serverUrl,
supportedLocales,
locales,
onSubmit,
onCancel,
onError,
labels,
transformErrors
}) => {
const formActions = React.useRef(actions(`${serverUrl}/form-configuration`, supportedLocales, locales || {}, labels.skillForm.title));
const _onSubmit = React.useCallback(saveConfig => {
return async formState => {
// Run 'saveConfig' action
try {
await saveConfig(formState); // If passed in props, run onSubmit function (only when no errors)
onSubmit && onSubmit(formState);
} catch (err) {// Don't call user 'onSubmit' function when there are errors (errors are handled on the errorReducer of the 'saveConfig' action)
}
};
}, [onSubmit]);
const _onCancel = React.useCallback(cancel => {
return () => {
// Run 'cancel' action
cancel(); // If passed in props, run onCancel function
onCancel && onCancel();
};
}, [onCancel]);
const _onError = React.useCallback(error => {
// Call onError function if it was passed
onError && onError(error);
}, [onError]);
return React__default.createElement(StateDecorator__default, {
actions: formActions.current,
initialState: initialState,
onMount: onMount,
logEnabled: true,
props: {
onError: _onError
},
name: "SkillFormManager"
}, (state, actions, loading) => // TODO 'loading' could be used to show spinner when Saving or requesting next step
React__default.createElement(SkillForm, _extends({}, state, {
cancel: _onCancel(actions.cancel),
onSubmit: _onSubmit(actions.saveConfig),
debounceRunStep: actions.debounceRunStep,
runStep: actions.runStep,
clearDebounceTimeout: actions.clearDebounceTimeout,
labels: labels,
serverUrl: serverUrl,
saveConfig: actions.saveConfig,
loading: loading,
supportedLocales: supportedLocales,
transformErrors: transformErrors
})));
};
exports.SkillForm = SkillForm;
exports.SkillFormLinks = SkillFormLinks;
exports.SkillFormManager = SkillFormManager;
exports.fields = fields;
exports.templates = templates;
exports.widgets = widgets;
//# sourceMappingURL=index.js.map