diff --git a/splunk_add_on_ucc_framework/ucc_ui_lib/package.json b/splunk_add_on_ucc_framework/ucc_ui_lib/package.json index 92d991452..a5ead9af2 100644 --- a/splunk_add_on_ucc_framework/ucc_ui_lib/package.json +++ b/splunk_add_on_ucc_framework/ucc_ui_lib/package.json @@ -31,6 +31,7 @@ "@splunk/stylelint-config": "^4.0.0", "@splunk/themes": "^0.7.0", "@splunk/webpack-configs": "^5.0.0", + "axios": "^0.21.1", "babel-eslint": "^10.1.0", "babel-loader": "^8.0.4", "chai": "^3.5.0", diff --git a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/resources/splunk/default/data/ui/nav/default.xml b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/resources/splunk/default/data/ui/nav/default.xml index 79d0fcff1..4fb6bfd91 100644 --- a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/resources/splunk/default/data/ui/nav/default.xml +++ b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/resources/splunk/default/data/ui/nav/default.xml @@ -1,5 +1,5 @@ diff --git a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/CheckBoxComponent.jsx b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/CheckBoxComponent.jsx new file mode 100644 index 000000000..e21fce7ca --- /dev/null +++ b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/CheckBoxComponent.jsx @@ -0,0 +1,36 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import Switch from '@splunk/react-ui/Switch'; + +class CheckBoxComponent extends Component { + constructor(props) { + super(props); + } + + handleChange = (e) => { + this.props.handleChange(this.props.id, 1 - this.props.value); + }; + + render() { + return ( + + ); + } +} + +CheckBoxComponent.propTypes = { + id: PropTypes.number.isRequired, + value: PropTypes.string, + handleClick: PropTypes.func.isRequired, + field: PropTypes.string, + controlOptions: PropTypes.object, +}; + +export default CheckBoxComponent; diff --git a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/MultiInputControl.jsx b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/MultiInputControl.jsx new file mode 100644 index 000000000..ef254b8f2 --- /dev/null +++ b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/MultiInputControl.jsx @@ -0,0 +1,50 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Multiselect from '@splunk/react-ui/Multiselect'; + +function MultiInputControl(props) { + const { id, field, disabled = false, value, controlOptions, ...restProps } = props; + const { items, placeholder, createSearchChoice, delimiter = ',' } = controlOptions; + + function handleChange(e, { values }) { + restProps.handleChange(id, values.join(delimiter)); + } + + const valueList = value ? value.split(delimiter) : []; + + return ( + + {items.map((item) => ( + + ))} + + ); +} + +MultiInputControl.propTypes = { + id: PropTypes.number.isRequired, + disabled: PropTypes.bool, + value: PropTypes.string, + handleChange: PropTypes.func.isRequired, + field: PropTypes.string, + controlOptions: PropTypes.shape({ + delimiter: PropTypes.string, + placeholder: PropTypes.string, + createSearchChoice: PropTypes.bool, + items: PropTypes.arrayOf( + PropTypes.shape({ + label: PropTypes.string.isRequired, + value: PropTypes.string.isRequired, + }) + ).isRequired, + }), +}; + +export default MultiInputControl; diff --git a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/RadioComponent.jsx b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/RadioComponent.jsx new file mode 100644 index 000000000..a64c312bf --- /dev/null +++ b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/RadioComponent.jsx @@ -0,0 +1,40 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import RadioBar from '@splunk/react-ui/RadioBar'; + +class RadioComponent extends Component { + constructor(props) { + super(props); + } + + handleChange = (e, { value }) => { + this.props.handleChange(this.props.id, value); + }; + + render() { + return ( + + {this.props.controlOptions.items.map(item => ( + + ))} + + ); + } +} + +RadioComponent.propTypes = { + id: PropTypes.number.isRequired, + value: PropTypes.string, + handleChange: PropTypes.func.isRequired, + field: PropTypes.string, + controlOptions: PropTypes.object +}; + + +export default RadioComponent; + diff --git a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/SingleInputControl.jsx b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/SingleInputControl.jsx new file mode 100644 index 000000000..df7ff873e --- /dev/null +++ b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/SingleInputControl.jsx @@ -0,0 +1,49 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Select from '@splunk/react-ui/Select'; + +function SingleInputControl(props) { + const { id, field, disabled = false, value, controlOptions, ...restProps } = props; + const { autoCompleteFields } = controlOptions; + + function handleChange(e, { value }) { + restProps.handleChange(id, value); + } + + function generateOptions() { + const data = []; + autoCompleteFields.forEach((item) => { + if (item.value && item.label) { + data.push(); + } + if (item.children && item.label) { + data.push({item.label}); + item.children.forEach((child) => { + data.push( + + ); + }); + } + }); + return data; + } + + return ( + + ); +} + +SingleInputControl.propTypes = { + id: PropTypes.number.isRequired, + disabled: PropTypes.bool, + value: PropTypes.string, + handleChange: PropTypes.func.isRequired, + field: PropTypes.string, + controlOptions: PropTypes.shape({ + autoCompleteFields: PropTypes.array.isRequired, + }), +}; + +export default SingleInputControl; diff --git a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/TestComponent.jsx b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/TestComponent.jsx index 74468207e..183954185 100644 --- a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/TestComponent.jsx +++ b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/TestComponent.jsx @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import Button from '@splunk/react-ui/Button'; import { StyledContainer, StyledGreeting } from './TestComponentStyles'; import { getUnifiedConfigs } from '../util/util'; +import { axiosCallWrapper } from '../util/axiosCallWrapper'; class TestComponent extends Component { static propTypes = { @@ -11,6 +12,7 @@ class TestComponent extends Component { static defaultProps = { name: 'User', + serviceName: 'example_input_one', }; constructor(props) { @@ -19,7 +21,14 @@ class TestComponent extends Component { } componentDidMount() { - console.log("getUnifiedConfigs: ", getUnifiedConfigs()); + console.log('getUnifiedConfigs: ', getUnifiedConfigs()); + axiosCallWrapper(this.props.serviceName) + .then((response) => { + console.log(response.data); + }) + .catch((error) => { + console.log(error); + }); } render() { @@ -30,13 +39,6 @@ class TestComponent extends Component { counter === 0 ? 'You should try clicking the button.' : `You've clicked the button ${counter} time${counter > 1 ? 's' : ''}.`; - // const requireFunc = typeof __webpack_require__ === "function" ? __non_webpack_require__ : require; - function requireDynamically(path) { - return eval(`require`); // Ensure Webpack does not analyze the require statement - } - requireDynamically(['custom/' + module], (CustomRow) => { - this.CustomRow = CustomRow; - }); return ( diff --git a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/TextComponent.jsx b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/TextComponent.jsx new file mode 100644 index 000000000..85ae0036e --- /dev/null +++ b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/TextComponent.jsx @@ -0,0 +1,37 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import Text from '@splunk/react-ui/Text'; + +class TextComponent extends Component { + constructor(props) { + super(props); + } + + handleChange = (e, {value}) => { + this.props.handleChange(this.props.id, value); + }; + + render() { + return ( + + ); + } +} + +TextComponent.propTypes = { + id: PropTypes.number.isRequired, + value: PropTypes.string, + handleChange: PropTypes.func.isRequired, + field: PropTypes.string, + controlOptions: PropTypes.object, +}; + +export default TextComponent; diff --git a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/table/Table.jsx b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/table/Table.jsx new file mode 100644 index 000000000..f5bbcc0a2 --- /dev/null +++ b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/table/Table.jsx @@ -0,0 +1,183 @@ +import React, { useState, useEffect } from 'react'; +import Table from '@splunk/react-ui/Table'; +import Switch from '@splunk/react-ui/Switch'; +import ButtonGroup from '@splunk/react-ui/ButtonGroup'; +import Pencil from '@splunk/react-icons/Pencil'; +import Clone from '@splunk/react-icons/Clone'; +import Trash from '@splunk/react-icons/Trash'; +import Tooltip from '@splunk/react-ui/Tooltip'; +import { _ } from '@splunk/ui-utils/i18n'; +import PropTypes from 'prop-types'; + +import { ActionButtonComponent } from './TableStyle'; +import { getUnifiedConfigs } from '../../util/util'; +import { getExpansionRow } from './TableExpansionRow'; + +function InputTable({ isInput, serviceName, data, handleToggleActionClick }) { + const [sortKey, setSortKey] = useState('name'); + const [sortDir, setSortDir] = useState('asc'); + const [columns, setColumns] = useState([]); + + useEffect(() => { + generateColumns(); + }, []); + + const generateColumns = () => { + const unifiedConfigs = getUnifiedConfigs(); + let column = []; + if (isInput) { + let headers = unifiedConfigs.pages.inputs.table.header; + if (headers && headers.length) { + headers.forEach((header) => { + column.push({ + ...header, + sortKey: header.field || null, + }); + }); + } + column.push({ label: 'Actions', field: 'actions', sortKey: '' }); + setColumns(column); + } + }; + + const handleSort = (e, val) => { + const prevSortKey = sortKey; + const prevSortDir = prevSortKey === val.sortKey ? sortDir : 'none'; + const nextSortDir = prevSortDir === 'asc' ? 'desc' : 'asc'; + setSortDir(nextSortDir); + setSortKey(val.sortKey); + }; + + const getTableHeaders = () => { + return ( + + {columns && + columns.length && + columns.map((headData) => ( + + {headData.label} + + ))} + + ); + }; + + const handleEditActionClick = () => {}; + + const handleCloneActionClick = () => {}; + + const handleDeleteActionClick = () => {}; + + const rowActionsPrimaryButton = (row) => { + return ( + + + + } + onClick={() => handleEditActionClick(row)} + /> + + + } + onClick={() => handleCloneActionClick(row)} + /> + + + } + onClick={() => handleDeleteActionClick(row)} + /> + + + + ); + }; + + const getTableRow = (row) => { + return ( + + {columns && + columns.length && + columns.map((header) => { + if (header.field === 'disabled') { + return ( + + handleToggleActionClick(row)} + selected={!row.disabled} + appearance="toggle" + > + {row.disabled ? 'Disabled' : 'Enabled'} + + + ); + } else if (header.field == 'actions') { + return rowActionsPrimaryButton(row); + } else { + return {row[header.field]}; + } + })} + + ); + }; + + const getTableBody = () => { + return ( + + {data && + data.length && + data + .sort((rowA, rowB) => { + if (sortDir === 'asc') { + return rowA[sortKey] > rowB[sortKey] ? 1 : -1; + } + if (sortDir === 'desc') { + return rowB[sortKey] > rowA[sortKey] ? 1 : -1; + } + return 0; + }) + .map((row) => getTableRow(row))} + + ); + }; + + return ( + <> + {columns && columns.length && ( + <> + + {getTableHeaders()} + {getTableBody()} +
+ + )} + + ); +} + +InputTable.propTypes = { + isInput: PropTypes.boolean, + serviceName: PropTypes.string.isRequired, + data: PropTypes.object.isRequired, + handleToggleActionClick: PropTypes.func, +}; + +export default InputTable; diff --git a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/table/TableExpansionRow.js b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/table/TableExpansionRow.js new file mode 100644 index 000000000..db23ad989 --- /dev/null +++ b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/table/TableExpansionRow.js @@ -0,0 +1,40 @@ +import React from 'react'; +import DL from '@splunk/react-ui/DefinitionList'; +import Table from '@splunk/react-ui/Table'; +import { _ } from '@splunk/ui-utils/i18n'; + +import { getUnifiedConfigs } from '../../util/util'; + +function getExpansionRowData(row) { + const unifiedConfigs = getUnifiedConfigs(); + let moreInfo = unifiedConfigs.pages.inputs.table.moreInfo; + return ( + moreInfo && moreInfo.length && moreInfo.map((val) => { + const label = _(val.label); + return ( + <> + { (row[val.field] || val.label == "Status") && + <> + {label} + + { val.label == "Status" ? row[val.field] ? 'Disabled': 'Enabled': `${row[val.field]}` } + + + } + + ) + }) + ) +} + +export function getExpansionRow(colSpan, row) { + return ( + + +
+ {getExpansionRowData(row)} +
+
+
+ ); +} diff --git a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/table/TableStyle.jsx b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/table/TableStyle.jsx new file mode 100644 index 000000000..098eb5697 --- /dev/null +++ b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/components/table/TableStyle.jsx @@ -0,0 +1,13 @@ +import styled from 'styled-components'; +import Button from '@splunk/react-ui/Button'; +import WaitSpinner from '@splunk/react-ui/WaitSpinner'; + +export const ActionButtonComponent = styled(Button)` + margin: 0px 5px; +`; + +export const WaitSpinnerWrapper = styled(WaitSpinner)` + position: fixed; + top: 50%; + left: 50%; +`; diff --git a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/pages/Configuration/ConfigurationPage.jsx b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/pages/Configuration/ConfigurationPage.jsx new file mode 100644 index 000000000..2ec133218 --- /dev/null +++ b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/pages/Configuration/ConfigurationPage.jsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { TitleComponent, SubTitleComponent } from '../Input/InputPageStyle'; + +function ConfigurationPage() { + return ( + <> + Configuration + Set up your add-on +
+ + ) +}; + +export default ConfigurationPage; diff --git a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/pages/StartStyles.js b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/pages/EntryPageStyle.js similarity index 100% rename from splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/pages/StartStyles.js rename to splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/pages/EntryPageStyle.js diff --git a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/pages/Input/InputPage.jsx b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/pages/Input/InputPage.jsx new file mode 100644 index 000000000..62328c4fa --- /dev/null +++ b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/pages/Input/InputPage.jsx @@ -0,0 +1,410 @@ +import React, { useState, useEffect } from 'react'; +import { _ } from '@splunk/ui-utils/i18n'; + +import { getUnifiedConfigs } from '../../util/util'; +import { WaitSpinnerWrapper } from '../../components/table/TableStyle'; +import { TitleComponent, SubTitleComponent, TableCaptionComponent } from './InputPageStyle'; +import Table from '../../components/table/Table'; + +function InputPage({ isInput, serviceName }) { + const [loading, setLoading] = useState(true); + const [rowData, setRowData] = useState([]); + const [title, setTitle] = useState(null); + const [description, setDescription] = useState(null); + + useEffect(() => { + const unifiedConfigs = getUnifiedConfigs(); + setTitle(_(unifiedConfigs.pages.inputs.title)); + setDescription(_(unifiedConfigs.pages.inputs.description)); + fetchInputs(); + }, []); + + const fetchInputs = () => { + setLoading(true); + setTimeout(() => { + // API call response + const data = [ + { + name: 'account', + id: + 'https://10.202.39.212:8000/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/account', + updated: '1970-01-01T00:00:00+00:00', + links: { + alternate: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/account', + list: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/account', + edit: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/account', + remove: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/account', + }, + author: 'nobody', + acl: { + app: 'Splunk_TA_salesforce', + can_list: true, + can_write: true, + modifiable: false, + owner: 'nobody', + perms: { + read: ['admin', 'power', 'splunk-system-role', 'user'], + write: ['admin', 'splunk-system-role'], + }, + removable: true, + sharing: 'app', + }, + content: { + disabled: false, + 'eai:acl': null, + host: '$decideOnStartup', + host_resolved: 'so1', + index: '11default', + interval: '1200', + limit: '1000', + object: 'Account', + object_fields: 'Id,LastModifiedById,LastModifiedDate,Name', + order_by: 'LastModifiedDate', + 'python.version': null, + sourcetype: 'sfdc:object', + start_by_shell: 'false', + }, + }, + { + name: 'contentversion', + id: + 'https://10.202.39.212:8000/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/contentversion', + updated: '1970-01-01T00:00:00+00:00', + links: { + alternate: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/contentversion', + list: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/contentversion', + edit: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/contentversion', + remove: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/contentversion', + }, + author: 'nobody', + acl: { + app: 'Splunk_TA_salesforce', + can_list: true, + can_write: true, + modifiable: false, + owner: 'nobody', + perms: { + read: ['admin', 'power', 'splunk-system-role', 'user'], + write: ['admin', 'splunk-system-role'], + }, + removable: true, + sharing: 'app', + }, + content: { + disabled: false, + 'eai:acl': null, + host: '$decideOnStartup', + host_resolved: 'so1', + index: 'default', + interval: '1200', + limit: '1000', + object: 'ContentVersion', + object_fields: 'Id,LastModifiedById,LastModifiedDate,Title', + order_by: 'LastModifiedDate', + 'python.version': null, + sourcetype: 'sfdc:object', + start_by_shell: 'false', + }, + }, + { + name: 'dashboard', + id: + 'https://10.202.39.212:8000/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/dashboard', + updated: '1970-01-01T00:00:00+00:00', + links: { + alternate: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/dashboard', + list: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/dashboard', + edit: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/dashboard', + remove: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/dashboard', + }, + author: 'nobody', + acl: { + app: 'Splunk_TA_salesforce', + can_list: true, + can_write: true, + modifiable: false, + owner: 'nobody', + perms: { + read: ['admin', 'power', 'splunk-system-role', 'user'], + write: ['admin', 'splunk-system-role'], + }, + removable: true, + sharing: 'app', + }, + content: { + disabled: true, + 'eai:acl': null, + account: 'Temp1', + host: '$decideOnStartup', + host_resolved: 'so1', + index: '22default', + interval: '1200', + limit: '1000', + object: 'Dashboard', + object_fields: 'Id,LastModifiedDate,Title', + order_by: 'LastModifiedDate', + 'python.version': null, + sourcetype: 'sfdc:object', + start_by_shell: 'false', + }, + }, + { + name: 'loginhistory', + id: + 'https://10.202.39.212:8000/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/loginhistory', + updated: '1970-01-01T00:00:00+00:00', + links: { + alternate: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/loginhistory', + list: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/loginhistory', + edit: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/loginhistory', + remove: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/loginhistory', + }, + author: 'nobody', + acl: { + app: 'Splunk_TA_salesforce', + can_list: true, + can_write: true, + modifiable: false, + owner: 'nobody', + perms: { + read: ['admin', 'power', 'splunk-system-role', 'user'], + write: ['admin', 'splunk-system-role'], + }, + removable: true, + sharing: 'app', + }, + content: { + disabled: true, + 'eai:acl': null, + account: 'Other', + host: '$decideOnStartup', + host_resolved: 'so1', + index: 'default', + interval: '60', + limit: '1000', + object: 'LoginHistory', + object_fields: + 'ApiType,ApiVersion,Application,Browser,ClientVersion,Id,LoginTime,LoginType,LoginUrl,Platform,SourceIp,Status,UserId', + order_by: 'LoginTime', + 'python.version': null, + sourcetype: 'sfdc:object', + start_by_shell: 'false', + }, + }, + { + name: 'opportunity', + id: + 'https://10.202.39.212:8000/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/opportunity', + updated: '1970-01-01T00:00:00+00:00', + links: { + alternate: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/opportunity', + list: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/opportunity', + edit: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/opportunity', + remove: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/opportunity', + }, + author: 'nobody', + acl: { + app: 'Splunk_TA_salesforce', + can_list: true, + can_write: true, + modifiable: false, + owner: 'nobody', + perms: { + read: ['admin', 'power', 'splunk-system-role', 'user'], + write: ['admin', 'splunk-system-role'], + }, + removable: true, + sharing: 'app', + }, + content: { + disabled: true, + 'eai:acl': null, + account: 'Dummy1', + host: '$decideOnStartup', + host_resolved: 'so1', + index: 'default', + interval: '1200', + limit: '1000', + object: 'Opportunity', + object_fields: 'Id,LastModifiedById,LastModifiedDate,Name', + order_by: 'LastModifiedDate', + 'python.version': null, + sourcetype: 'sfdc:object', + start_by_shell: 'false', + }, + }, + { + name: 'report', + id: + 'https://10.202.39.212:8000/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/report', + updated: '1970-01-01T00:00:00+00:00', + links: { + alternate: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/report', + list: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/report', + edit: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/report', + remove: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/report', + }, + author: 'nobody', + acl: { + app: 'Splunk_TA_salesforce', + can_list: true, + can_write: true, + modifiable: false, + owner: 'nobody', + perms: { + read: ['admin', 'power', 'splunk-system-role', 'user'], + write: ['admin', 'splunk-system-role'], + }, + removable: true, + sharing: 'app', + }, + content: { + disabled: true, + 'eai:acl': null, + account: 'Test', + host: '$decideOnStartup', + host_resolved: 'so1', + index: 'default', + interval: '1200', + limit: '1000', + object: 'Report', + object_fields: 'Id,LastModifiedDate,Name', + order_by: 'LastModifiedDate', + 'python.version': null, + sourcetype: 'sfdc:object', + start_by_shell: 'false', + }, + }, + { + name: 'user', + id: + 'https://10.202.39.212:8000/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/user', + updated: '1970-01-01T00:00:00+00:00', + links: { + alternate: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/user', + list: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/user', + edit: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/user', + remove: + '/servicesNS/nobody/Splunk_TA_salesforce/Splunk_TA_salesforce_sfdc_object/user', + }, + author: 'nobody', + acl: { + app: 'Splunk_TA_salesforce', + can_list: true, + can_write: true, + modifiable: false, + owner: 'nobody', + perms: { + read: ['admin', 'power', 'splunk-system-role', 'user'], + write: ['admin', 'splunk-system-role'], + }, + removable: true, + sharing: 'app', + }, + content: { + disabled: true, + account: 'Tushar', + 'eai:acl': null, + host: '$decideOnStartup', + host_resolved: 'so1', + index: 'default', + interval: '1200', + limit: '1000', + object: 'User', + object_fields: + 'LastModifiedDate,City,Country,FirstName,Id,IsActive,LastLoginDate,LastName,Latitude,Longitude,MobilePhone,Name,PostalCode,State,Username,UserRoleId,UserType,Email,CompanyName,ProfileId,Profile.PermissionsApiEnabled,Profile.PermissionsModifyAllData,Profile.PermissionsViewSetup', + order_by: 'LastModifiedDate', + 'python.version': null, + sourcetype: 'sfdc:object', + start_by_shell: 'false', + }, + }, + ]; + modifyAPIResponse(data); + }, 1000); + }; + + const modifyAPIResponse = (data) => { + if (data && data.length) { + let modifiedResponse = []; + data.map((val) => { + modifiedResponse.push({ + ...val.content, + id: val.id, + name: val.name, + }); + }); + setRowData(modifiedResponse); + setLoading(false); + } + }; + + /** + * + * @param row {Object} row + */ + const changeStatus = (row) => { + let oldData = rowData; + const index = oldData.findIndex((val) => { + return val.id == row.id; + }); + if (index != -1) { + oldData[index].disabled = !oldData[index].disabled; + } + setRowData((data) => [...oldData]); + }; + + return ( + <> + {loading ? ( + + ) : ( + <> + {title} + {description} +
+ +
+ {rowData.length} Input {rowData.legnth > 1 && s} +
+
+ changeStatus(row)} + /> + + )} + + ); +} + +export default InputPage; diff --git a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/pages/Input/InputPageStyle.jsx b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/pages/Input/InputPageStyle.jsx new file mode 100644 index 000000000..2088c95f8 --- /dev/null +++ b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/pages/Input/InputPageStyle.jsx @@ -0,0 +1,16 @@ +import styled from 'styled-components'; +import { variables } from '@splunk/themes'; + +export const TitleComponent = styled.div` + font-size: ${variables.fontSizeXXLarge}; +`; + +export const SubTitleComponent = styled.div` + font-size: ${variables.fontSize}; +`; + +export const TableCaptionComponent = styled.div` + .table-caption-inner { + text-align: left; + } +`; diff --git a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/pages/entry_page.jsx b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/pages/entry_page.jsx index 66287f671..5facbb451 100644 --- a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/pages/entry_page.jsx +++ b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/pages/entry_page.jsx @@ -1,13 +1,12 @@ import React from 'react'; - import layout from '@splunk/react-page'; import { SplunkThemeProvider } from '@splunk/themes'; - import { defaultTheme } from '@splunk/splunk-utils/themes'; +import { StyledContainer } from './EntryPageStyle'; import ConfigManager from '../util/configManager'; -import TestComponent from '../components/TestComponent'; -import { StyledContainer, StyledGreeting } from './StartStyles'; +import InputPage from './Input/InputPage'; +import ConfigurationPage from './Configuration/ConfigurationPage'; const defaultThemeSplunkThemeProviderMap = { enterprise: { @@ -40,13 +39,8 @@ if (page === 'inputs') { - {({loading, appData}) => { - return !loading && appData && ( - <> - Hello, from inside Inputs! - - - ) + {({ loading, appData }) => { + return !loading && appData && ; }} @@ -58,13 +52,8 @@ if (page === 'inputs') { - {({loading, appData}) => { - return !loading && appData && ( - <> - Hello, from inside Configuration! - - - ) + {({ loading, appData }) => { + return !loading && appData && ; }} diff --git a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/util/axiosCallWrapper.js b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/util/axiosCallWrapper.js new file mode 100644 index 000000000..022c8cc76 --- /dev/null +++ b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/util/axiosCallWrapper.js @@ -0,0 +1,50 @@ +import axios from 'axios'; +import { CSRFToken, app } from '@splunk/splunk-utils/config'; +import { createRESTURL } from '@splunk/splunk-utils/url'; +import { generateEndPointUrl } from './util'; + +/** + * Provides a axios wrapper with applied common options + * @param {string} serviceName service name which is input name or tab name based on the page + * @param {string} endpointUrl rest endpoint path + * @param {object} params object with params as key value pairs + * @param {object} customHeaders extra headers as key value pair + * @param {string} method rest method type + */ +const axiosCallWrapper = ( + serviceName, + endpointUrl = null, + params = {}, + customHeaders = {}, + method = 'get' +) => { + const endpoint = serviceName ? generateEndPointUrl(serviceName) : endpointUrl; + const appData = { + app, + owner: 'nobody', + }; + const baseHeaders = { + 'X-Splunk-Form-Key': CSRFToken, + 'X-Requested-With': 'XMLHttpRequest', + 'Content-Type': 'application/json', + }; + const headers = Object.assign(baseHeaders, customHeaders); + const url = `${createRESTURL(endpoint, appData)}?output_mode=json`; + + const options = { + method, + url, + credentials: 'include', + headers, + }; + + if (method === 'post') { + options.data = params; + } else { + options.params = params; + } + + return axios(options); +}; + +export { axiosCallWrapper }; diff --git a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/util/configManager.js b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/util/configManager.js index 6e0e5cde0..91de7ca20 100644 --- a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/util/configManager.js +++ b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/util/configManager.js @@ -1,12 +1,20 @@ import React, {Component} from "react"; import WaitSpinner from '@splunk/react-ui/WaitSpinner'; +import styled from 'styled-components'; import * as _ from "lodash"; import { validateSchema } from './uccConfigurationValidators'; import { getFormattedMessage } from './messageUtil'; import { setMetaInfo, setUnifiedConfig } from './util'; +import { loadGlobalConfig } from './script'; import ErrorModal from '../components/ErrorModal'; +const WaitSpinnerWrapper = styled(WaitSpinner)` + position: fixed; + top: 50%; + left: 50%; +`; + class ConfigManager extends Component { constructor(props) { @@ -21,7 +29,8 @@ class ConfigManager extends Component { } componentWillMount() { - this.loadGlobalConfig().then((val) => { + this.setState({loading: true}); + loadGlobalConfig().then((val) => { // The configuration object should be attached to global object, // before executing the code below. // this.unifiedConfig = window.__globalConfig; @@ -35,34 +44,6 @@ class ConfigManager extends Component { }); } - loadGlobalConfig() { - // Get the configuraiton json file in sync mode - this.setState({loading: true}); - return new Promise((resolve, reject) => { - fetch(`${this.getBuildDirPath()}/globalConfig.json`).then((res) => { - return res.json(); - }).then((json) => { - // window.__globalConfig = json; - resolve(json); - }).catch((err) => { - reject(err); - }); - }); - } - - getBuildDirPath() { - const scripts = document.getElementsByTagName('script'); - const scriptsCount = scripts.length; - for (let i = 0; i < scriptsCount; i++) { - const s = scripts[i]; - if(s.src && s.src.match(/js\/build/)) { - const lastSlashIndex = s.src.lastIndexOf('/'); - return s.src.slice(0, lastSlashIndex); - } - } - return ''; - } - attchPropertie(unifiedConfig) { const validationResult = validateSchema(unifiedConfig); const { meta } = unifiedConfig; @@ -103,8 +84,8 @@ class ConfigManager extends Component { return ( <> { - this.state.loading ? - : + this.state.loading ? + : this.renderComponents() } diff --git a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/util/script.js b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/util/script.js new file mode 100644 index 000000000..0eac1a2bb --- /dev/null +++ b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/util/script.js @@ -0,0 +1,42 @@ +// NOTE: The resolve will only be executed if the globalConfig exist +export function loadGlobalConfig() { + // Get the configuraiton json file in sync mode + return new Promise((resolve, reject) => { + fetch(`${getBuildDirPath()}/globalConfig.json`).then((res) => { + return res.json(); + }).then((json) => { + // window.__globalConfig = json; + resolve(json); + }).catch((err) => { + reject(err); + }); + }); +} + +// NOTE: if bundle script is put some dir instead of js/build, this function will broken. +export function getBuildDirPath() { + const scripts = document.getElementsByTagName('script'); + const scriptsCount = scripts.length; + for (let i = 0; i < scriptsCount; i++) { + const s = scripts[i]; + if(s.src && s.src.match(/js\/build/)) { + const lastSlashIndex = s.src.lastIndexOf('/'); + return s.src.slice(0, lastSlashIndex); + } + } + return ''; +} + +export function parseFuncRawStr(rawStr) { + let result; + + try { + if (rawStr) { + result = eval(`(${rawStr})`); + } + } catch (e) { + console.warn(`${rawStr} ${_('is not a function').t()}${_('.').t()}`); + } + + return result; +} diff --git a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/util/uccConfigurationValidators.js b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/util/uccConfigurationValidators.js index 725cb5755..08c14fc7a 100644 --- a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/util/uccConfigurationValidators.js +++ b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/util/uccConfigurationValidators.js @@ -252,4 +252,4 @@ export const validateSchema = (config) => { failed: !!res.errors.length, errors: res.errors }); -} \ No newline at end of file +} diff --git a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/util/util.js b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/util/util.js index 8222aa04c..24e75e3a0 100644 --- a/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/util/util.js +++ b/splunk_add_on_ucc_framework/ucc_ui_lib/src/main/webapp/util/util.js @@ -7,12 +7,12 @@ export function setMetaInfo(data) { export function getMetaInfo() { return { - appData: appData - } + appData: appData, + }; } export function generateEndPointUrl(name) { - return `${unifiedConfigs.meta.restRoot}/${name}`; + return `${unifiedConfigs.meta.restRoot}_${name}`; } export function setUnifiedConfig(unifiedConfig) { @@ -21,4 +21,4 @@ export function setUnifiedConfig(unifiedConfig) { export function getUnifiedConfigs() { return unifiedConfigs; -} \ No newline at end of file +} diff --git a/splunk_add_on_ucc_framework/ucc_ui_lib/yarn.lock b/splunk_add_on_ucc_framework/ucc_ui_lib/yarn.lock index d6d43b67e..f63339fc0 100644 --- a/splunk_add_on_ucc_framework/ucc_ui_lib/yarn.lock +++ b/splunk_add_on_ucc_framework/ucc_ui_lib/yarn.lock @@ -2045,6 +2045,13 @@ axe-core@^4.0.2: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.1.2.tgz#7cf783331320098bfbef620df3b3c770147bc224" integrity sha512-V+Nq70NxKhYt89ArVcaNL9FDryB3vQOd+BFXZIfO3RP6rwtj+2yqqqdHEkacutglPaZLkJeuXKCjCJDMGPtPqg== +axios@^0.21.1: + version "0.21.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" + integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA== + dependencies: + follow-redirects "^1.10.0" + axobject-query@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be" @@ -4155,6 +4162,11 @@ flush-write-stream@^1.0.0: inherits "^2.0.3" readable-stream "^2.3.6" +follow-redirects@^1.10.0: + version "1.13.3" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267" + integrity sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA== + for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"