Introduction
Enhance Lichtblick's functionality with custom extensions tailored to your team's specific workflows. Create personalized panels, transform custom messages into Lichtblick-compatible schemas, and map topic names for improved visualization.
After developing and installing your extension, navigate to your app settings to view all available and installed extensions.
Settings API
The Panel Settings API allows users to link settings to message converters based on panel types.
PanelSettings Interface
The PanelSettings<ExtensionSettings>
interface defines the structure for managing custom settings associated with message converters and panels. It allows users to define settings that can be dynamically applied to specific topics or schemas, enabling flexible configuration of message processing behavior.
Generic Type Parameter
ExtensionSettings
: Represents the type of the custom settings object. This is user-defined and should match the structure of the settings you want to configure.
Properties
settings
settings: (config?: ExtensionSettings) => SettingsTreeNode;
-
Purpose: Defines how the settings should be rendered in the settings UI.
-
Parameters:
config
: An optional object containing the current configuration values. Its type is inferred from thedefaultConfig
property.
-
Returns: A
SettingsTreeNode
that describes the structure of the settings UI. This node will be merged with the settings tree for the associated topic (under the path["topics", "__topic_name__"]
). -
Example:
settings: (config) => ({
fields: {
threshold: {
input: "number",
value: config?.threshold,
label: "Threshold Value",
},
},
}),
handler
handler: (action: SettingsTreeAction, config?: ExtensionSettings) => void;
-
Purpose: Handles changes to the settings made by the user in the UI.
-
Parameters:
action
: ASettingsTreeAction
object describing the user's action (e.g., updating a field).config
: A mutable object representing the current configuration. Modifying this object updates the state.
-
Behavior:
- This function is called after the default settings handler.
- It allows you to validate or transform the settings before they are applied.
-
Example:
handler: (action, config) => {
if (action.action === "update" && action.payload.path[1] === "threshold") {
// Ensure threshold is within valid range
config.threshold = Math.max(0, Math.min(1, action.payload.value));
}
},
defaultConfig
defaultConfig?: ExtensionSettings;
-
Purpose: Provides default values for the settings. These values are used when no configuration is explicitly set.
-
Type: Must match the
ExtensionSettings
type. -
Example:
defaultConfig: {
threshold: 0.5,
enableFeature: true,
},
Expected Behavior
When implementing this interface:
- Settings UI: The
settings
function defines how the settings are displayed in the UI. It creates a settings tree node that is merged into the topic's settings. - Configuration Management: The
handler
function processes user interactions with the settings UI, allowing you to validate or transform the configuration. - Defaults: The
defaultConfig
provides initial values for the settings, ensuring the panel or converter has a valid configuration even if the user hasn't customized it.
Possible Outcomes
-
Dynamic Settings UI:
- The
settings
defined in the settings function will appear in the UI under the associated topic. - Users can modify these settings, and changes will be handled by the
handler
function.
- The
-
Custom Configuration:
- The
handler
function allows you to enforce constraints or transform values before they are applied. - For example, you can ensure a threshold value stays within a valid range.
- The
-
Default Behavior:
- If no custom configuration is provided, the
defaultConfig
values are used. - This ensures the panel or converter works out of the box without requiring user input.
- If no custom configuration is provided, the
Example Implementation:
type Schema1Schema = {
value: number;
}
type Schema2Schema = {
value: number;
}
// Define the configuration type
type Config = { threshold: number };
// Helper function to cast PanelSettings to the correct type
const generatePanelSettings = <T>(obj: PanelSettings<T>) =>
obj as PanelSettings<unknown>;
export function activate(extensionContext: ExtensionContext): void {
// Register the message converter
extensionContext.registerMessageConverter({
fromSchemaName: "schema1",
toSchemaName: "schema2",
converter: (msg: Schema1Schema, event): Schema2Schema | undefined => {
// Access the threshold setting for the current topic
const config = event.topicConfig as Config | undefined;
const threshold = config?.threshold;
// Filter messages based on the threshold
if (threshold && msg.value > threshold) {
return { value: msg.value }; // Forward the message if it exceeds the threshold
}
return undefined; // Ignore the message if it doesn't meet the threshold
},
// Define the settings for the threshold
panelSettings: {
ThresholdPanel: generatePanelSettings({
settings: (config) => ({
fields: {
threshold: {
label: "Threshold Value",
input: "number",
value: config?.threshold,
placeholder: "Enter a threshold value",
},
},
}),
handler: (action, config) => {
if (config == undefined) {
return;
}
// Update the threshold setting when the user changes it in the UI
if (
action.action === "update" &&
action.payload.path[2] === "threshold"
) {
config.threshold = action.payload.value as number;
}
},
defaultConfig: {
threshold: 0.5, // Default threshold value
},
}),
},
});
}
Use Case
This interface is typically used when registering a message converter:
extensionContext.registerMessageConverter({
fromSchemaName: "schema1",
toSchemaName: "schema2",
converter: (msg: Schema1Schema, event): Schema2Schema | undefined => {
// Access the threshold setting for the current topic
const config = event.topicConfig as Config | undefined;
const threshold = config?.threshold;
// Filter messages based on the threshold
if (msg.value > threshold) {
return { value: msg.value }; // Forward the message if it exceeds the threshold
}
return undefined; // Ignore the message if it doesn't meet the threshold
},
Summary
The PanelSettings<ExtensionSettings>
interface provides a structured way to:
- Define custom settings for panels or message converters.
- Render these settings in the UI.
- Handle user interactions with the settings.
- Provide default values for the settings.
By implementing this interface, you enable users to configure their panel or converter dynamically, making it more flexible and adaptable to different use cases.