Plugins can optionally expose configuration options which are shown by the platform in the administration UI.
[toc]
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.Version1 namespace of Telligent.Evolution.Components.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 widgets, that enables the automatic generation of forms based on metadata. A sample is below:
using System; using Telligent.DynamicConfiguration.Components; using Telligent.Evolution.Extensibility.Version1; namespace Samples { public class SampleConfigurablePlugin : IConfigurablePlugin { private IPluginConfiguration _configuration; #region IPlugin // ... #endregion #region IConfigurablePlugin public Telligent.DynamicConfiguration.Components.PropertyGroup[] ConfigurationOptions { get { var group = new PropertyGroup("options", "Options", 0); var stringProperty = new Property("stringProperty", "Sample String Property", PropertyType.String, 0, "This is the default value") { DescriptionText = "Sample String Property Description" }; group.Properties.Add(stringProperty); var selectableProperty = new Property("selectableProperty", "Sample Selectable Property", PropertyType.String, 1, "One") { DescriptionText = "Sample Selectable Property Description" }; selectableProperty.SelectableValues.Add(new PropertyValue("One", "Choose One", 1)); selectableProperty.SelectableValues.Add(new PropertyValue("Two", "Choose Two", 2)); selectableProperty.SelectableValues.Add(new PropertyValue("Three", "Choose Three", 3)); selectableProperty.SelectableValues.Add(new PropertyValue("Four", "Choose Four", 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.DynamicConfiguration.Components namespace in Telligent.DynamicConfiguration.dll are used. These include:
- PropertyGroup. Groups represent tabs in the Telligent 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 property value editor can be customized by setting the ControlType property to a class implementing IPropertyControl. A list of available property controls in the platform is below.
- 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.
Available property controls
When defining configuration metadata using Dynamic Configuration Property instances, the Telligent Community platform will render a default editor for each data type aside from Custom. To customize the rendering of the value editor, the ControlType property of the Property can be set to the Type of a class implementing IPropertyControl. The Telligent Community platform includes some property controls that can be used by plugins and widgets:
- Blog Selection Custom Control
- Checkbox List String Control
- Custom Navigation Custom Control
- Email String Control
- Forum Selection Custom Control
- Forum Sortable List Control
- Group or Application Selection Custom Control
- Group Selection Custom Control
- Media Gallery Selection Custom Control
- Property Visibility Select Box Control
- Rich Editor HTML Control
- Sortable List Custom Control
- Tokenized String Control
- User File URL Control
- User Profile Field Selection Custom Control
- User Profile Group Int Control
- Wiki Selection Custom Control
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.Components.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.DynamicConfiguration.Components; using Telligent.Evolution.Extensibility.Version1; namespace Samples { public class SampleConfigurablePlugin : IConfigurablePlugin, IRequiredConfigurationPlugin { private IPluginConfiguration _configuration; #region IPlugin // ... #endregion #region IConfigurablePlugin public Telligent.DynamicConfiguration.Components.PropertyGroup[] ConfigurationOptions { get { var group = new PropertyGroup("options", "Options", 0); var stringProperty = new Property("stringProperty", "Sample String Property", PropertyType.String, 0, "This is the default value") { DescriptionText = "Sample String Property Description" }; group.Properties.Add(stringProperty); var selectableProperty = new Property("selectableProperty", "Sample Selectable Property", PropertyType.String, 1, "One") { DescriptionText = "Sample Selectable Property Description" }; selectableProperty.SelectableValues.Add(new PropertyValue("One", "Choose One", 1)); selectableProperty.SelectableValues.Add(new PropertyValue("Two", "Choose Two", 2)); selectableProperty.SelectableValues.Add(new PropertyValue("Three", "Choose Three", 3)); selectableProperty.SelectableValues.Add(new PropertyValue("Four", "Choose Four", 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 Telligent 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.Version1 namespace of Telligent.Evolution.Components.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.DynamicConfiguration.Components; using Telligent.Evolution.Extensibility.Version1; namespace Samples { public class SampleConfigurablePlugin : IConfigurablePlugin, IRenderableConfigurablePlugin { private IPluginConfiguration _configuration; #region IPlugin // .. #endregion #region IConfigurablePlugin public Telligent.DynamicConfiguration.Components.PropertyGroup[] ConfigurationOptions { get { var group = new PropertyGroup("options", "Options", 0); var stringProperty = new Property("stringProperty", "Sample String Property", PropertyType.String, 0, "This is the default value") { DescriptionText = "Sample String Property Description" }; group.Properties.Add(stringProperty); var selectableProperty = new Property("selectableProperty", "Sample Selectable Property", PropertyType.String, 1, "One") { DescriptionText = "Sample Selectable Property Description" }; selectableProperty.SelectableValues.Add(new PropertyValue("One", "Choose One", 1)); selectableProperty.SelectableValues.Add(new PropertyValue("Two", "Choose Two", 2)); selectableProperty.SelectableValues.Add(new PropertyValue("Three", "Choose Three", 3)); selectableProperty.SelectableValues.Add(new PropertyValue("Four", "Choose Four", 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.