diff --git a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/BaseFormView.jsx b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/BaseFormView.jsx
index 654edd3b6..395b6b55e 100644
--- a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/BaseFormView.jsx
+++ b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/BaseFormView.jsx
@@ -201,21 +201,21 @@ class BaseFormView extends PureComponent {
}
if (!error) {
- const params = new URLSearchParams();
+ const body = new URLSearchParams();
Object.keys(datadict).forEach((key) => {
- if (datadict[key]) {
- params.append(key, datadict[key]);
+ if (datadict[key] != null) {
+ body.append(key, datadict[key]);
}
});
if (this.props.mode === MODE_EDIT) {
- params.delete('name');
+ body.delete('name');
}
axiosCallWrapper({
serviceName: this.endpoint,
- params,
+ body,
customHeaders: { 'Content-Type': 'application/x-www-form-urlencoded' },
method: 'post',
handleError: false,
@@ -256,7 +256,7 @@ class BaseFormView extends PureComponent {
const changes = {};
if (this.dependencyMap.has(field)) {
const value = this.dependencyMap.get(field);
- for (const loadField in value) {
+ Object.keys(value).forEach((loadField) => {
const data = {};
let load = true;
@@ -265,19 +265,23 @@ class BaseFormView extends PureComponent {
return e.field === dependency;
}).required;
- const value =
- dependency == field ? targetValue : this.state.data[dependency]['value'];
- if (required && !value) {
+ const currentValue =
+ dependency === field ? targetValue : this.state.data[dependency].value;
+ if (required && !currentValue) {
load = false;
+ data[dependency] = null;
} else {
- data[dependency] = value;
+ data[dependency] = currentValue;
}
});
if (load) {
- changes[loadField] = { dependencyValues: { $set: data } };
+ changes[loadField] = {
+ dependencyValues: { $set: data },
+ value: { $set: null },
+ };
}
- }
+ });
}
changes[field] = { value: { $set: targetValue } };
@@ -296,7 +300,7 @@ class BaseFormView extends PureComponent {
addCustomValidator = (field, validatorFunc) => {
const index = this.entities.findIndex((x) => x.field === field);
- const validator = [{ type: 'custom', validatorFunc: validatorFunc }];
+ const validator = [{ type: 'custom', validatorFunc }];
this.entities[index].validators = validator;
};
diff --git a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/MultiInputComponent.jsx b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/MultiInputComponent.jsx
index 18bf45be8..f727163f8 100644
--- a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/MultiInputComponent.jsx
+++ b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/MultiInputComponent.jsx
@@ -1,29 +1,108 @@
-import React from 'react';
+import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import Multiselect from '@splunk/react-ui/Multiselect';
+import { _ } from '@splunk/ui-utils/i18n';
+import axios from 'axios';
+import { axiosCallWrapper } from '../util/axiosCallWrapper';
+import { filterResponse } from '../util/util';
function MultiInputComponent(props) {
- const { field, disabled = false, value, controlOptions, ...restProps } = props;
- const { items, placeholder, createSearchChoice, delimiter = ',' } = controlOptions;
+ const {
+ field,
+ disabled = false,
+ error = false,
+ value,
+ controlOptions,
+ dependencyValues,
+ ...restProps
+ } = props;
+ const {
+ endpointUrl,
+ denyList,
+ allowList,
+ items,
+ dependencies,
+ referenceName,
+ placeholder,
+ createSearchChoice,
+ labelField,
+ delimiter = ',',
+ } = controlOptions;
function handleChange(e, { values }) {
restProps.handleChange(field, values.join(delimiter));
}
+ function generateOptions(items) {
+ return items.map((item) => (
+
+ ));
+ }
+
+ const [loading, setLoading] = useState(false);
+ const [options, setOptions] = useState(null);
+
+ useEffect(() => {
+ if (items) {
+ setOptions(generateOptions(items));
+ return;
+ }
+
+ let current = true;
+ const source = axios.CancelToken.source();
+
+ const options = { CancelToken: source.token, handleError: true };
+ if (referenceName) {
+ options.serviceName = referenceName;
+ } else if (endpointUrl) {
+ options.endpointUrl = endpointUrl;
+ }
+
+ if (dependencyValues) {
+ options.params = dependencyValues;
+ }
+ if (!dependencies || dependencyValues) {
+ setLoading(true);
+ axiosCallWrapper(options)
+ .then((response) => {
+ if (current) {
+ setOptions(
+ generateOptions(
+ filterResponse(response.data.entry, labelField, allowList, denyList)
+ )
+ );
+ setLoading(false);
+ }
+ })
+ .catch((error) => {
+ if (current) {
+ setLoading(false);
+ }
+ });
+ }
+ return () => {
+ source.cancel('Operation canceled.');
+ current = false;
+ };
+ }, [dependencyValues]);
+
+ const effectiveDisabled = loading ? true : disabled;
+ const effectivePlaceholder = loading ? _('Loading') : placeholder;
+
const valueList = value ? value.split(delimiter) : [];
return (
- {items.map((item) => (
-
- ))}
+ {options && options.length > 0 && options}
);
}
@@ -31,18 +110,26 @@ function MultiInputComponent(props) {
MultiInputComponent.propTypes = {
disabled: PropTypes.bool,
value: PropTypes.string,
+ error: PropTypes.bool,
handleChange: PropTypes.func.isRequired,
field: PropTypes.string,
+ dependencyValues: PropTypes.object,
controlOptions: PropTypes.shape({
delimiter: PropTypes.string,
placeholder: PropTypes.string,
createSearchChoice: PropTypes.bool,
+ referenceName: PropTypes.string,
+ dependencies: PropTypes.array,
+ endpointUrl: PropTypes.string,
+ denyList: PropTypes.string,
+ allowList: PropTypes.string,
+ labelField: PropTypes.string,
items: PropTypes.arrayOf(
PropTypes.shape({
label: PropTypes.string.isRequired,
value: PropTypes.string.isRequired,
})
- ).isRequired,
+ ),
}),
};
diff --git a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/SingleInputComponent.jsx b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/SingleInputComponent.jsx
index c0d06727a..44228d1f2 100644
--- a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/SingleInputComponent.jsx
+++ b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/SingleInputComponent.jsx
@@ -1,18 +1,41 @@
-import React from 'react';
+import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import Select from '@splunk/react-ui/Select';
+import { _ } from '@splunk/ui-utils/i18n';
+import axios from 'axios';
+import { axiosCallWrapper } from '../util/axiosCallWrapper';
+import { filterResponse } from '../util/util';
function SingleInputComponent(props) {
- const { field, disabled = false, value, controlOptions, ...restProps } = props;
- const { autoCompleteFields=[] } = controlOptions;
+ const {
+ field,
+ disabled = false,
+ error = false,
+ value,
+ controlOptions,
+ dependencyValues,
+ ...restProps
+ } = props;
+ const {
+ endpointUrl,
+ denyList,
+ allowList,
+ placeholder = _('Select a value'),
+ dependencies,
+ createSearchChoice,
+ referenceName,
+ disableSearch,
+ labelField,
+ autoCompleteFields,
+ } = controlOptions;
function handleChange(e, { value }) {
restProps.handleChange(field, value);
}
- function generateOptions() {
+ function generateOptions(items) {
const data = [];
- autoCompleteFields.forEach((item) => {
+ items.forEach((item) => {
if (item.value && item.label) {
data.push();
}
@@ -28,9 +51,67 @@ function SingleInputComponent(props) {
return data;
}
+ const [loading, setLoading] = useState(false);
+ const [options, setOptions] = useState(null);
+
+ useEffect(() => {
+ if (autoCompleteFields) {
+ setOptions(generateOptions(autoCompleteFields));
+ return;
+ }
+
+ let current = true;
+ const source = axios.CancelToken.source();
+
+ const options = { CancelToken: source.token, handleError: true };
+ if (referenceName) {
+ options.serviceName = referenceName;
+ } else if (endpointUrl) {
+ options.endpointUrl = endpointUrl;
+ }
+
+ if (dependencyValues) {
+ options.params = dependencyValues;
+ }
+ if (!dependencies || dependencyValues) {
+ setLoading(true);
+ axiosCallWrapper(options)
+ .then((response) => {
+ if (current) {
+ setOptions(
+ generateOptions(
+ filterResponse(response.data.entry, labelField, allowList, denyList)
+ )
+ );
+ setLoading(false);
+ }
+ })
+ .catch((error) => {
+ if (current) {
+ setLoading(false);
+ }
+ });
+ }
+ return () => {
+ source.cancel('Operation canceled.');
+ current = false;
+ };
+ }, [dependencyValues]);
+
+ const effectiveDisabled = loading ? true : disabled;
+ const effectivePlaceholder = loading ? _('Loading') : placeholder;
+
return (
-