Plugins can optionally expose configuration options which are shown by the platform in the administration UI.
When should I expose configuration options?
When you're developing a plugin that would benefit from administrative configuration values, for example, global options or authentication details, you can implement a configurable plugin to expose those options easily through the administration UI.
Creating a configurable plugin
To add configuration options to an existing plugin, the plugin must implement the IConfigurablePlugin interface. The IConfigurablePlugin interface is defined in the Telligent.Evolution.Extensibility.Version2 namespace of Telligent.Evolution.Platform.dll. The IConfigurablePlugin interface has two members: the configuration options to expose are identified by the ConfigurationOptions property and the current configuration data is provided to the Update() method. Configuration options are defined using Dynamic Configuration, an implementation that is shared with scripted customizations, that enables the automatic generation of forms based on metadata. A sample is below:
using System; using Telligent.Evolution.Extensibility.Version2; using Telligent.Evolution.Extensibility.Configuration.Version1; namespace Samples { public class SampleConfigurablePlugin : IConfigurablePlugin { private IPluginConfiguration _configuration; #region IPlugin // ... #endregion #region IConfigurablePlugin public PropertyGroup[] ConfigurationOptions { get { var group = new PropertyGroup { Id = "options", LabelText = "Options", OrderNumber = 0 }; var stringProperty = new Property { Id = "stringProperty", LabelText = "Sample String Property", DescriptionText = "Sample String Property Description", DataType = "String", OrderNumber = 0, DefaultValue = "This is the default value" }; group.Properties.Add(stringProperty); var selectableProperty = new Property { Id = "selectableProperty", LabelText = "Sample Selectable Property", DescriptionText = "Sample Selectable Property Description", DataType = "String", OrderNumber = 1, DefaultValue = "One" }; selectableProperty.SelectableValues.Add(new PropertyValue { LabelText = "One", Value = "Choose One", OrderNumber = 1 }); selectableProperty.SelectableValues.Add(new PropertyValue { LabelText = "Two", Value = "Choose Two", OrderNumber = 2 }); selectableProperty.SelectableValues.Add(new PropertyValue { LabelText = "Three", Value = "Choose Three", OrderNumber = 3 }); selectableProperty.SelectableValues.Add(new PropertyValue { LabelText = "Four", Value = "Choose Four", OrderNumber = 4 }); group.Properties.Add(selectableProperty); return new[] { group }; } } public void Update(IPluginConfiguration configuration) { _configuration = configuration; } #endregion } }
In this sample, two properties are added to a group called "Options" within the ConfigurationOptions definition. The first property is called "Sample String Property" and represents a string value. The second property, "Sample Selectable Property", is also a string value, but it defines selectable options which will cause the UI to render this field as a drop down. When this plugin is deployed and viewed within the administration UI, it will appear as:
The Update() method receives the configuration data for the plugin based on the metadata defined by ConfigurationOptions. The plugin can then read and use this configuration data however it sees fit to implement its behavior. The IPluginConfiguration entity provided to the Update() method includes methods to get and set configuration values for the plugin. For example, to read the current value of the first string property defined by the sample, the plugin would call:
var stringValue = _configuration.GetString("stringProperty");
When defining configuration metadata, items from the Telligent.Evolution.Extensibility.Configuration.Version1 namespace in Telligent.Evolution.Platform.dll are used. These include:
- PropertyGroup. Groups represent tabs in the Verint Community administration UI.
- PropertySubGroup. Sub-groups represent sub-groupings of fields within a group in the administration UI.
- Property. Properties exist in groups or sub-groups and represent single values with names and descriptions. The platform will automatically render all properties (other than of type "Custom") using default UI implementations. The template used to render a property can be changed using the Template property.
- PropertyValue. Property values exist within properties to defined selectable options for the property. By default, defining one or more property values on a property will cause the property to render as a drop-down list.
- PropertyRule. Rules can be defined on properties to automate value constraints by referencing a rule implementation which is a class implementing the IPropertyRule interface.
Requiring configuration to enable a plugin
Often, the configuration values of a plugin may be required for the plugin to function at all. In those situations it is beneficial to not allow the plugin to function until the configuration is adequately specified. This scenario is enabled by implementing the IRequiredConfigurationPlugin interface defined in Telligent.Evolution.Platform.dll. This interface adds a single property, IsConfigured, which is read by the platform to determine if the plugin is satisfactorily configured before allowing it to be actively enabled. If a plugin is enabled, but the configuration is not satisfactory, the plugin will be highlighted in red in the administration UI and will not be actively enabled (that is, it will not be fully initialized, so it will not be able to interact with the platform). A sample implementation based on the previous configurable plugin example is below:
using System; using Telligent.Evolution.Extensibility.Version2; using Telligent.Evolution.Extensibility.Configuration.Version1; namespace Samples { public class SampleConfigurablePlugin : IConfigurablePlugin, IRequiredConfigurationPlugin { private IPluginConfiguration _configuration; #region IPlugin // ... #endregion #region IConfigurablePlugin public PropertyGroup[] ConfigurationOptions { get { var group = new PropertyGroup { Id = "options", LabelText = "Options", OrderNumber = 0 }; var stringProperty = new Property { Id = "stringProperty", LabelText = "Sample String Property", DescriptionText = "Sample String Property Description", DataType = "String", OrderNumber = 0, DefaultValue = "This is the default value" }; group.Properties.Add(stringProperty); var selectableProperty = new Property { Id = "selectableProperty", LabelText = "Sample Selectable Property", DescriptionText = "Sample Selectable Property Description", DataType = "String", OrderNumber = 1, DefaultValue = "One" }; selectableProperty.SelectableValues.Add(new PropertyValue { LabelText = "One", Value = "Choose One", OrderNumber = 1 }); selectableProperty.SelectableValues.Add(new PropertyValue { LabelText = "Two", Value = "Choose Two", OrderNumber = 2 }); selectableProperty.SelectableValues.Add(new PropertyValue { LabelText = "Three", Value = "Choose Three", OrderNumber = 3 }); selectableProperty.SelectableValues.Add(new PropertyValue { LabelText = "Four", Value = "Choose Four", OrderNumber = 4 }); group.Properties.Add(selectableProperty); return new[] { group }; } } public void Update(IPluginConfiguration configuration) { _configuration = configuration; } #endregion #region IRequiredConfigurationPlugin public bool IsConfigured { get { return _configuration.GetString("stringProperty") == "valid"; } } #endregion } }
In this sample implementation, the configuration is only accepted when the "stringProperty" configuration field has a value of "valid". When the plugin is enabled and the value is not "valid", the plugin is shown with a red background in listings:
And when it has a valid value, it is listed normally (and fully enabled/initialized):
Customizing the rendering of the configuration UI
While Verint Community will automatically generate a configuration form based on the configuration options exposed by a plugin implementing IConfigurablePlugin and handle situations where custom property controls are used for individual fields, there are times when the entire configuration UI would benefit from a custom layout and implementation. To enable completely overriding the configuration UI, a plugin can implement the IRenderableConfigurablePlugin interface from the Telligent.Evolution.Extensibility.Version2 namespace of Telligent.Evolution.Platform.dll. This interface adds a single method, GetConfigurationHtml(), that expects an HTML result that can be inserted into the plugin editing UI. For example,
using System; using Telligent.Evolution.Extensibility.Version2; using Telligent.Evolution.Extensibility.Configuration.Version1; namespace Samples { public class SampleConfigurablePlugin : IConfigurablePlugin, IRenderableConfigurablePlugin { private IPluginConfiguration _configuration; #region IPlugin // ... #endregion #region IConfigurablePlugin public PropertyGroup[] ConfigurationOptions { get { var group = new PropertyGroup { Id = "options", LabelText = "Options", OrderNumber = 0 }; var stringProperty = new Property { Id = "stringProperty", LabelText = "Sample String Property", DescriptionText = "Sample String Property Description", DataType = "String", OrderNumber = 0, DefaultValue = "This is the default value" }; group.Properties.Add(stringProperty); var selectableProperty = new Property { Id = "selectableProperty", LabelText = "Sample Selectable Property", DescriptionText = "Sample Selectable Property Description", DataType = "String", OrderNumber = 1, DefaultValue = "One" }; selectableProperty.SelectableValues.Add(new PropertyValue { LabelText = "One", Value = "Choose One", OrderNumber = 1 }); selectableProperty.SelectableValues.Add(new PropertyValue { LabelText = "Two", Value = "Choose Two", OrderNumber = 2 }); selectableProperty.SelectableValues.Add(new PropertyValue { LabelText = "Three", Value = "Choose Three", OrderNumber = 3 }); selectableProperty.SelectableValues.Add(new PropertyValue { LabelText = "Four", Value = "Choose Four", OrderNumber = 4 }); group.Properties.Add(selectableProperty); return new[] { group }; } } public void Update(IPluginConfiguration configuration) { _configuration = configuration; } #endregion #region IRenderableConfigurable public string GetConfigurationHtml(string apiJson) { return string.Format(@" <div id=""sample-configurable-plugin-editor""> This is the <strong>custom</strong> configuration UI. </div> <script type=""text/javascript""> (function() {{ var api = {0}; api.registerContent([{{ name: 'Sample', orderNumber: 0, selected: function() {{ $('#sample-configurable-plugin').show(); }}, unselected: function() {{ $('#sample-configurable-plugin').hide(); }} }}]); }})(); </script> ", apiJson); } #endregion } }
This sample implementation is not editable, but renders as:
The GetConfigurationHtml() method is provided with a client-side API in JSON format that can be used to interact with and extend the platform-defined plugin editor UI. The sample registers a single tab named "Sample" but could add multiple tabs.
This example is not a real-world example because it doesn't actually expose or edit any configuration fields. Generally, a full implementation would use a plugin-defined widget with access to read/write plugin configuration values to implement the GetConfigurationHtml() by passing the JSON API through to a private widget API.