Overview¶
Early Stage Feature
This feature is in its early stages. While the main concepts are expected to remain consistent, minor configuration changes may occur in future releases.
The UCC package simplifies the deployment of React applications featuring the Splunk UI by eliminating the need for NodeJS, Yarn, or front-end dependency installations. The core requirement for deployment is a globalConfig.json
file. While UCC supports a broad range of use cases, there may be scenarios where the provided API options do not fully meet your needs.
For such instances, UCC offers a component context-based loading mechanism. Similar to standard extensions (runtime custom JavaScript), this feature enables the invocation of specific functionalities at pivotal moments in the application lifecycle, such as onChange
and onRender
events.
Note: Unlike standard extensions, this feature requires NodeJS and other libraries to function correctly. However, it facilitates easier and faster development through type checking and type interfaces that describe allowed properties and functionalities.
Integrating Custom Components¶
Example globalConfig.json
¶
{
"inputs": {
"title": "Inputs",
"description": "Manage your data inputs",
"services": [
{
"name": "example_input_one",
"title": "Example Input One",
"hook": {
"src": "CustomHook",
"type": "external"
},
"entity": [{
"field": "custom_input_field",
"label": "My Custom Input",
"type": "custom",
"options": {
"src": "CustomInput",
"type": "external"
}
}]
}
]
}
}
Key Notes:
- Specify the
type
key asexternal
to indicate that these scripts should use the ESM syntax for module exporting and importing.
To integrate custom components, you can configure the globalConfig.json
file as follows. For example, custom JavaScript files can be located at:
ta_directory/ui/src/ui_extensions/
Component Initialization¶
Although UCC does not directly support components due to its design choices, you can integrate them through JavaScript. Below is an example of integrating a React component to create a custom date picker.
Example: CustomComponentDatePicker.ts
¶
File path:
ta_directory/ui/src/ucc-ui-extensions/CustomComponentDatePicker.ts
import React from "react";
import ReactDOM from "react-dom";
import { CustomControlBase } from "@splunk/add-on-ucc-framework";
import { DateChangeHandler } from "@splunk/react-ui/Date";
const CustomDateInput = React.lazy(() => import("./DateInput"));
export default class CustomComponentDatePicker extends CustomControlBase {
onDateChange: DateChangeHandler = (_event, data) => {
this.setValue(data.value);
};
render() {
const dateValue = this.data.value;
const date =
typeof dateValue === "string" && dateValue.length !== 0
? dateValue
: undefined;
ReactDOM.render(
<React.Suspense fallback={<div></div>}>
<CustomDateInput value={date} onChange={this.onDateChange} />
</React.Suspense>,
this.el
);
}
}
Initializing Components in ucc-ui.ts
¶
To initialize front-end code, you need to provide an uccInit
function in the ucc-ui.ts
file. The execution must follow the proper format:
{
ComponentNameFromGlobalConfig: {
component: ComponentClassUsedForRendering,
type: 'control',
}
}
Key Properties:
ComponentNameFromGlobalConfig
: Matches thesrc
defined in theglobalConfig.json
file.component
: Refers to a component that extends one of the available custom component types (CustomHookBase
,CustomControlBase
,CustomTabBase
,CustomMenuBase
,CustomCellBase
,CustomRowBase
).type
: Defines the component type. Available types"hook"
,"cell"
,"row"
,"control"
,"tab"
, and"menu"
.
Example: ucc-ui.ts
¶
File path:
ta_directory/ui/src/ucc-ui.ts
import { uccInit } from "@splunk/add-on-ucc-framework";
import DateInputClass from "./ucc-ui-extensions/CustomComponentDatePicker";
import AdvancedInputsTabClass from "./ucc-ui-extensions/AdvancedInputsTab";
uccInit({
DateInput: {
component: DateInputClass,
type: 'control',
},
AdvancedInputsTab: {
component: AdvancedInputsTabClass,
type: 'tab',
},
}).catch((error) => {
console.error("Could not load UCC", error);
});
Adding Build Commands¶
To streamline the build process, you may need to adjust the package.json
file to include a build command:
module.exports = {
//...
"scripts": {
"ucc-gen": "ucc-gen-ui ta_name=Splunk_TA_Example init_file_dir=src/ucc-ui.ts",
},
}
The command accepts the following parameters:
Parameter | Description | Default Value |
---|---|---|
ta_name |
The name of the current TA, used to locate the correct directory in the output folder. | None |
init_file_dir |
The file containing the uccInit function. While .ts files are recommended, .js files can also be used for easier transitions. |
src/ucc-ui.ts |
output |
The destination directory containing the TA output and all required files. | ../output (relative to the UI code) |
Smooth Build Process¶
To ensure a smooth build process, follow these steps:
- Create a
build-ui.sh
Script
File path:
ta_directory/scripts/build-ui.sh
#!/bin/bash
# Determine the directory of the script
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Check if Node.js is installed
if ! command -v node &> /dev/null
then
echo "Node.JS is not installed. Please install Node.JS to continue."
exit 1
fi
if [ "$CI" = "true" ]; then
npm --prefix "$SCRIPT_DIR/../ui" ci
else
npm --prefix "$SCRIPT_DIR/../ui" install
fi
npm --prefix "$SCRIPT_DIR/../ui" run ucc-gen output=$(pwd)
- Extend
additional_packaging.py
to Execute the Script
File path:
ta_directory/additional_packaging.py
import os
from os import path
def additional_packaging(addon_name: str) -> None:
# ...
build_ui_script = os.path.join(
os.path.dirname(os.path.realpath(__file__)), "scripts", "build-ui.sh"
)
if path.exists(build_ui_script):
os.system(f"chmod +x {build_ui_script}")
return_code = os.system(build_ui_script)
if return_code != 0:
os._exit(os.WEXITSTATUS(return_code))
Best Practices¶
Lazy Loading¶
Currently, all components are loaded directly upon initialization. For larger components, we recommend introducing a lazy loading mechanism within the components themselves.
Example:
const CustomDateInput = React.lazy(() => import("./DateInput"));
This approach imports the final DateInput
component. The CustomComponentDatePicker
acts as a wrapper to control rendering and handle data flow.