UNPKG

@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
'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