<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>Managing Widget Source and Distribution</title><link>https://community.telligent.com/community/11/w/developer-training/65068/managing-widget-source-and-distribution</link><description /><dc:language>en-US</dc:language><generator>14.0.0.586 14</generator><item><title>Managing Widget Source and Distribution</title><link>https://community.telligent.com/community/11/w/developer-training/65068/managing-widget-source-and-distribution</link><pubDate>Wed, 05 Aug 2020 15:02:25 GMT</pubDate><guid isPermaLink="false">a7478cac-9ea0-4d12-98e2-da6b8f32b086</guid><dc:creator>Former Member</dc:creator><comments>https://community.telligent.com/community/11/w/developer-training/65068/managing-widget-source-and-distribution#comments</comments><description>Current Revision posted to Developer Training by Former Member on 08/05/2020 15:02:25&lt;br /&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;When working on widgets within a team or on a redistributable set of work, it is beneficial to make use of Verint Community platform services to make development, versioning, and deployment easier.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;[toc]&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;&lt;a id="Making_Development_and_Deployment_Easier" name="Making_Development_and_Deployment_Easier"&gt;&lt;/a&gt;&lt;span style="font-weight:400;"&gt;Making Development and Deployment Easier&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;To make development easier, you&amp;nbsp;can leverage the same functionality used by the core components of Verint Community, specifically:&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;A [[Factory Default Widget Providers|factory default widget provider]]. Factory default widget providers enable widget source to be stored on the file system. This makes source management within a system such as SVN, Git, or TFS possible which better enables development within a team.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;[[Editing Widgets in Developer Mode|Developer Mode]]. Developer mode is a feature of Verint Community that enables developers to work on factory default widgets within the platform widget editor while saving directly to the file system (to enable source control).&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Automatic installation of source files. Using&amp;nbsp;an [[api-documentation:IInstallablePlugin Plugin Type|IInstallablePlugin]]&amp;nbsp;implementation along with the widget versioning support in the [[UI Automation|UI automation APIs]] and embedded resources enable a complete installation story for custom widgets deployed as part of a factory default provider.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;Let&amp;#39;s look at a sample implementation and then talk through the details of leveraging these capabilities.&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;&lt;a id="Implementation" name="Implementation"&gt;&lt;/a&gt;&lt;span style="font-weight:400;"&gt;Implementation&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;A sample implementation of this approach is available on GitHub:&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;&lt;a href="https://github.com/Telligent/Widget-Source-Management-Sample"&gt;github.com/.../Widget-Source-Management-Sample&lt;/a&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;This implementation contains two projects: &lt;a href="https://github.com/Telligent/Widget-Source-Management-Sample/tree/master/Samples"&gt;Samples&lt;/a&gt; and &lt;a href="https://github.com/Telligent/Widget-Source-Management-Sample/tree/master/FactoryDefaultWidgetFileManifestUpdater"&gt;FactoryDefaultWidgetFileManifestUpdater&lt;/a&gt;. The Samples project identifies the factory default widget provider against which widgets can be created. This particular implementation also includes support for automatic file installation and [[Editing Widgets in Developer Mode|developer mode]] considerations. The FactoryDefaultWidgetFileManifestUpdater is a utility console app, suitable for use on a build server, that packages widgets created in Verint Community with the Samples project for deployment as a single installable DLL.&lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a id="Sample_Factory_Default_Widget_Provider_Implementation" name="Sample_Factory_Default_Widget_Provider_Implementation"&gt;&lt;/a&gt;&lt;span style="font-weight:400;"&gt;Sample Factory Default Widget Provider Implementation&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;The sample factory default provider is a [[Plugins|plugin]] to Verint Community. It provides a container&amp;nbsp;for storing factory default&amp;nbsp;widgets on the file system by implementing [[api-documentation:IScriptedContentFragmentFactoryDefaultProvider Plugin Type|IScriptedContentFragmentFactoryDefaultProvider]]. It also implements&amp;nbsp;[[api-documentation:IInstallablePlugin Plugin Type|IInstallablePlugin]] to enable installing the source of all widgets associated to the factory default provider from embedded resources in the release build of the project.&lt;/p&gt;
&lt;p&gt;Instead of reviewing all of the source code, let&amp;#39;s instead review the unique areas and discuss why they are implemented the way they are.&lt;/p&gt;
&lt;h4&gt;&lt;a id="The_Factory_Default_Widget_Provider_Identifier" name="The_Factory_Default_Widget_Provider_Identifier"&gt;&lt;/a&gt;The Factory Default Widget Provider Identifier&lt;/h4&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;// the provider ID should be updated to be unique (with Developer Mode enabled, go to Administration &amp;gt; Development &amp;gt;  Generate GUID to get a new GUID)
private readonly Guid _providerId = new Guid(&amp;quot;fa801aba-84a0-4746-92cc-b418a7106c0b&amp;quot;);&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Note at the top of the &lt;a href="https://github.com/Telligent/Widget-Source-Management-Sample/blob/master/Samples/FactoryDefaultWidgetProvider.cs"&gt;FactoryDefaultWidgetProvder.cs&lt;/a&gt; file the comment about updating the readonly identifier in this file. This is the identifier that should be unique to your implementation.&amp;nbsp;The sample is implemented as a sample without a compiled version because it requires modification and custom building to be used. Generally, a factory default widget provider would be included with other functionality, such as [[Creating Custom Applications and Content|custom content types]] or [[Widget Extensions|custom widget extensions]]. At a minimum, this identifier&amp;nbsp;should be updated.&lt;/p&gt;
&lt;h4&gt;&lt;a id="Developer_Mode_Considerations" name="Developer_Mode_Considerations"&gt;&lt;/a&gt;Developer Mode Considerations&lt;/h4&gt;
&lt;p&gt;To better support [[Editing Widgets in Developer Mode|developer mode]], where developers can edit their factory default widgets within the Verint Community UI, a few considerations need to be made to the implementation of the factory default widget provider.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;private Version _emptyVersion = new Version(0, 0, 0, 0);
#if DEBUG
    private Version _version = new Version(0, 0, 0, 0);
#else
    private Version _version = null;
#endif&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;[[api-documentation:IInstallablePlugin Plugin Type|IInstallablePlugins]] are installed whenever the plugin&amp;#39;s version changes, however, when developing widgets, you&amp;nbsp;do not want to install any widget source files as these installed files would overwrite your in-development versions. To account for this conflict of functionality, we&amp;#39;ll make use of compile-time conditions and preset versions.&lt;/p&gt;
&lt;p&gt;When in debug-mode build, developer mode can be enabled. In this situation, the plugin will always identify a version of &lt;code&gt;0.0.0.0&lt;/code&gt; which is also the default version value. When the version is set to &lt;code&gt;0.0.0.0&lt;/code&gt;, we bypass the version determination logic:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public Version Version
{
    get
    {
        if (_version == null)
        {
            // only executed when the version isn&amp;#39;t preset to 0.0.0.0
        }

        return _version;
    }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;and bypass the installation process:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public void Install(Version lastInstalledVersion)
{
    if (Version == _emptyVersion)
        return;
        
    // Normal installation logic...
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;These changes ensure that while using developer mode, you&amp;#39;ll&amp;nbsp;never accidentally overwrite our widget source with a previous-built version of the widget package.&lt;/p&gt;
&lt;h4&gt;&lt;a id="Support_for_Installation_and_Version_Review" name="Support_for_Installation_and_Version_Review"&gt;&lt;/a&gt;Support for Installation and Version Review&lt;/h4&gt;
&lt;p&gt;Verint Community 9 includes support for reviewing changes made to widgets by end-users. When a new version of a factory default is available, the platform can version the existing implementation of the widget (whether or not it is customized pre-upgrade), update the underlying version of the factory default to the latest, and provide a review process post-upgrade to opt-in or review differences to individual widgets either visually (via the preview panel) or within the widget editor. This sample makes use of this process within the &lt;code&gt;IInstallablePlugin&lt;/code&gt; implementation.&lt;/p&gt;
&lt;p&gt;When in a release build, the version is left unset until first accessed:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;private Version _emptyVersion = new Version(0, 0, 0, 0);
#if DEBUG
    private Version _version = new Version(0, 0, 0, 0);
#else
    private Version _version = null;
#endif&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Then, when accessed, we&amp;#39;ll determine the latest file version based on the newest/greatest version from the file manifest (the file manifest is described later, but it is a programmatic, versioned listing of embedded files that should be installed):&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public Version Version
{
    get
    {
        if (_version == null)
        {
            Version version = _emptyVersion;

            foreach(var file in FactoryDefaultWidgetFileManifest.Files().Where(x =&amp;gt; x.WidgetProviderId == ScriptedContentFragmentFactoryDefaultIdentifier))
            {
                if (file.LastModifiedVersion &amp;gt; version)
                    version = file.LastModifiedVersion;
            }

            _version = version;
        }

        return _version;
    }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Then, when the version is&amp;nbsp;different than what is currently installed (either because it is the first time this plugin is enabled or an update has been installed), the embedded files are installed within the &lt;code&gt;Install()&lt;/code&gt; method:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public void Install(Version lastInstalledVersion)
{
    if (Version == _emptyVersion)
        return;

    var files = FactoryDefaultWidgetFileManifest.Files().Where(x =&amp;gt; x.WidgetProviderId == ScriptedContentFragmentFactoryDefaultIdentifier).ToList();

    DetectedDeletedProviderFiles(files);

    // detect upgrade changes and version widgets appropriately for post-upgrade review (or just install all of the files if this isn&amp;#39;t an upgrade)
    var message = ContentFragments.UpdateScriptedContentFragments(
        lastInstalledVersion,
        files.Select(x =&amp;gt; x as IInstallableFile).ToList()
        );

    // if this was an upgrade, identify the upgrade as complete and provide a way to review widgets (if any were modified as part of the upgrade)
    if (lastInstalledVersion &amp;gt; _emptyVersion)
    {
        // identify that the plugin was upgraded and provide the note to review widget changes, if there was one
        Apis.Get&amp;lt;ISystemNotifications&amp;gt;().Create(
            string.Concat(Name, &amp;quot; Upgraded&amp;quot;),
            string.Concat(&amp;quot;&amp;lt;p&amp;gt;&amp;quot;, Name, &amp;quot; has been upgraded to &amp;quot;, Version.ToString(), &amp;quot;.&amp;lt;/p&amp;gt;&amp;quot;, message ?? &amp;quot;&amp;quot;)
            );
    }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;This installation requires a few steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Load the&amp;nbsp;file manifest.&lt;/strong&gt; Specifically, only the files in the manifest affecting this factory default provider are retrieved (the sample can be expanded to support more than one factory default provider, if necessary).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Determine deleted files.&lt;/strong&gt; To find deleted files, we use the &lt;code&gt;DetectedDeletedProviderFiles()&lt;/code&gt; method to compare the currently installed file list against the file manifest. Anything that is currently installed but not in the latest manifest is assumed to be deleted.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Upgrade the files.&lt;/strong&gt; To do this, we use our modified manifest (the list of embedded files combined with the list of deleted files) and provide it to the [[api-documentation:ContentFragments In-Process API Service|ContentFragments.UpdateScriptedContentFragments() UI Automation API]]. This API will version any existing implementation of modified source files and then install the updated factory default files. Any changes that are found are returned in an HTML-formatted message returned from the method that can be provided to site administrators to review widget updates and approve/deny them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Send the upgrade message.&lt;/strong&gt; If the plugin is an upgrade (and not an initial installation), an upgrade system notification is sent using the [[api-documentation:SystemNotifications In-Process API Service|ISystemNotifications.Create() API]] to notify system administrators that the plugin has been upgraded successfully and, if there are any widget changes, provide the review message.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;&lt;a id="Factory_Default_Widget_File_Manifest_Updater" name="Factory_Default_Widget_File_Manifest_Updater"&gt;&lt;/a&gt;Factory Default Widget File Manifest Updater&lt;/h3&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;The manifest updater is a console application that can be used when packaging the Sample project for deployment. The console app updates the file manifest used by the Sample factory default widget provider&amp;#39;s installation process and ensures that sources files are embedded in the resulting DLL. This console app should be executed before building the Samples project in release mode for deployment.&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;&lt;a id="Using_the_Sample" name="Using_the_Sample"&gt;&lt;/a&gt;Using the Sample&lt;/h2&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;Using the sample is slightly different for development and deployment&lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a id="Development_with_the_Sample" name="Development_with_the_Sample"&gt;&lt;/a&gt;Development with the Sample&lt;/h3&gt;
&lt;h4&gt;&lt;a id="Incorporate_the_Sample_In_Your_Project" name="Incorporate_the_Sample_In_Your_Project"&gt;&lt;/a&gt;Incorporate the Sample In Your Project&lt;/h4&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;Generally, a factory default widget provider is used to expose other custom functionality implemented using [[Plugins|plugins]]. This sample should then be incorporated into the same project so all of the components are distributed together. I&lt;/span&gt;&lt;span style="font-weight:400;"&gt;f this project is used only for widget source file management, the namespace, project name, and assembly name should at least be updated.&lt;/span&gt;&lt;/p&gt;
&lt;h4&gt;&lt;a id="Update_the_Factory_Default_Provider_ID" name="Update_the_Factory_Default_Provider_ID"&gt;&lt;/a&gt;Update the Factory Default Provider ID&lt;/h4&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;Once the project source is in a good location, generate a new GUID for the factory default provider identifier. &lt;span style="color:#800000;"&gt;&lt;strong&gt;The value in the sample should not be used.&lt;/strong&gt;&lt;/span&gt; To generate a GUID in developer mode, go to &lt;strong&gt;Administration &amp;gt; Development &amp;gt; Generate GUID&lt;/strong&gt; and copy the generated GUID. Update the &lt;code&gt;_providerId&lt;/code&gt; GUID on line 17 of &lt;a href="https://github.com/Telligent/Widget-Source-Management-Sample/blob/master/Samples/FactoryDefaultWidgetProvider.cs"&gt;FactoryDefaultWidgetProvider.cs&lt;/a&gt; (or wherever this code gets relocated within an existing project).&lt;/span&gt;&lt;/p&gt;
&lt;h4&gt;&lt;a id="Update_Project_References" name="Update_Project_References"&gt;&lt;/a&gt;Update Project References&lt;/h4&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;To use the sample, the project will need to have valid references to Telligent.Evolution.Api.dll, Telligent.Evolution.Components.dll, and Telligent.Evolution.ScriptedContentFragments.dll -- all DLLs that are part of the Verint Community platform.&lt;/span&gt;&lt;/p&gt;
&lt;h4&gt;&lt;a id="Build_and_Deploy" name="Build_and_Deploy"&gt;&lt;/a&gt;Build and Deploy&lt;/h4&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;Ensure that you are building the project in Debug mode. Build the project and deploy the resulting DLL to a development instance of Verint Community (if your development instance contains multiple instances of the platform, install the DLL in each instance... for example, each web node and job scheduler node).&lt;/span&gt;&lt;/p&gt;
&lt;h4&gt;&lt;a id="Enable_the_Plugin" name="Enable_the_Plugin"&gt;&lt;/a&gt;Enable the Plugin&lt;/h4&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;Within Verint Community, enable the plugin. Go to &lt;strong&gt;Administration&lt;/strong&gt; and search for the name of the plugin (the sample is called &amp;quot;Sample Widgets&amp;quot;). Click to view the plugin, check the enabled box, and save.&lt;/span&gt;&lt;/p&gt;
&lt;h4&gt;&lt;a id="Develop_Widgets" name="Develop_Widgets"&gt;&lt;/a&gt;Develop Widgets&lt;/h4&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;Within the widget editor at &lt;strong&gt;Administration &amp;gt; Interface &amp;gt; Widgets&lt;/strong&gt;, with [[Editing Widgets in Developer Mode|developer mode]] enabled, you should be able to create a new widget by clicking the&amp;nbsp;&lt;a href="/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/44.05-PM.png"&gt;&lt;img alt=" " src="/resized-image/__size/13x12/__key/communityserver-wikis-components-files/00-00-00-12-83/44.05-PM.png" /&gt;&lt;/a&gt;&amp;nbsp;icon. Within the Developer Mode Widget Details modal, select the name of your factory default provider, for example, &amp;quot;Sample Widgets&amp;quot;:&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;&lt;a href="/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/20780.png"&gt;&lt;img alt=" " src="/resized-image/__size/1040x0/__key/communityserver-wikis-components-files/00-00-00-12-83/20780.png" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;If you don&amp;#39;t see your sample widget provider, you can go to &lt;strong&gt;Administration &amp;gt; Development &amp;gt; Expire Caches&lt;/strong&gt; and select &lt;strong&gt;Expire All Caches&lt;/strong&gt;, then try again. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;After clicking &lt;strong&gt;Continue&lt;/strong&gt; on the &lt;strong&gt;Developer Mode Widget Details&lt;/strong&gt; modal, you will have created a new staged widget within your factory default provider. You can then [[Widgets|develop the widget normally]]. When you save, the widget will be saved to the file system where you&amp;#39;ve configured the centralized file system, by default,&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="text"&gt;Web\filestorage\defaultwidgets\{FACTORY_DEFAULT_PROVIDER_ID}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;where&amp;nbsp;&lt;code&gt;{FACTORY_DEFAULT_PROVIDER_ID}&lt;/code&gt; is the ID you provided as the factory default provider ID when you customized the sample implementation. This is the folder that you&amp;#39;ll also want to add to your source control/management system. Any files within this folder are sources files used to implement the widgets associated to the factory default. As you [[Editing Widgets in Developer Mode|develop widgets]], you&amp;#39;ll want to commit any changes to this folder (new files, edited files, deleted files) to your source management solution.&lt;/p&gt;
&lt;h3&gt;&lt;a id="Building_a_Deployment_Package" name="Building_a_Deployment_Package"&gt;&lt;/a&gt;Building a Deployment Package&lt;/h3&gt;
&lt;p&gt;Once you have developed the widgets as part of your factory default widget provider implementation, you can package the plugin and the widget source files for deployment. To do this,&lt;/p&gt;
&lt;h4&gt;&lt;a id="Setup_Your_Build_Environment" name="Setup_Your_Build_Environment"&gt;&lt;/a&gt;Setup Your Build Environment&lt;/h4&gt;
&lt;p&gt;Your build environment should not be the same as your [[Editing Widgets in Developer Mode|development environment]]. Ideally, this step would be performed as part of a continuous integration process. It could also be performed carefully within a second local instance of your provider implementation.&lt;/p&gt;
&lt;h4&gt;&lt;a id="Get_the_Latest_Source" name="Get_the_Latest_Source"&gt;&lt;/a&gt;Get the Latest Source&lt;/h4&gt;
&lt;p&gt;Load the latest implementation of the plugin source and the widget source from your source management solution. These two collections of source files should be in separate folders (one should not be within the other).&lt;/p&gt;
&lt;p&gt;Execute the FactoryDefaultWidgetFileManfiestUpdater console app.&amp;nbsp;Specifically&lt;span style="font-weight:400;"&gt;, execute:&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;&lt;pre class="ui-code" data-mode="text"&gt;FactoryDefaultWidgetFileManifestUpdater.exe /proj:&amp;quot;{FULL_PROJECT_PATH}&amp;quot;  /providerid:{WIDGET_PROVIDER_ID} /cfs:&amp;quot;{FULL_CFS_PATH}&amp;quot; /out:&amp;quot;{PATH_TO_MANIFEST_CLASS}&amp;quot;&lt;/pre&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;Where the following tokens are replaced:&lt;/span&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;{FULL_PROJECT_PATH}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The full local path to the &lt;a href="https://github.com/Telligent/Widget-Source-Management-Sample/blob/master/Samples/Samples.csproj"&gt;Samples.csproj&lt;/a&gt; project file.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;{WIDGET_PROVIDER_ID}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The GUID representing the Samples factory default provider (specified in the &lt;a href="https://github.com/Telligent/Widget-Source-Management-Sample/blob/master/Samples/FactoryDefaultWidgetProvider.cs"&gt;FactoryDefaultProvider.cs&lt;/a&gt; file in the Samples project).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;{FULL_CFS_PATH}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The full local path to the root CFS folder (Web/filestorage/, for example) containing the source of the widgets for this factory default provider. This should not be located within the Samples project&amp;#39;s folder structure.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;{PATH_TO_MANIFEST_CLASS}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;The full local path to the &lt;a href="https://github.com/Telligent/Widget-Source-Management-Sample/blob/master/Samples/Generated/FactoryDefaultWidgetFileManifest.cs"&gt;FactoryDefaultWidgetFileManifest.cs&lt;/a&gt;&amp;nbsp;file in the Samples project.&amp;nbsp;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;&lt;a id="Build_the_Deployment_Package" name="Build_the_Deployment_Package"&gt;&lt;/a&gt;Build the Deployment Package&lt;/h4&gt;
&lt;p&gt;Ensure that the sample project is set to be built in release mode and build the project. The resulting DLL will include all of the widget source files along with the manifest and will be built to enable widget source file installation. This DLL can now be deployed.&lt;/p&gt;
&lt;h3&gt;&lt;a id="Installing_the_Deployment_Package" name="Installing_the_Deployment_Package"&gt;&lt;/a&gt;Installing the Deployment Package&lt;/h3&gt;
&lt;p&gt;To install the deployment package,&lt;/p&gt;
&lt;h4&gt;&lt;a id="Install_the_Package_DLL" name="Install_the_Package_DLL"&gt;&lt;/a&gt;Install the Package DLL&lt;/h4&gt;
&lt;p&gt;Install the resulting deployment package DLL into each instance of the Verint Community platform (each web and job server node). Note that you should not install the deployment package on a development site since you will overwrite any&amp;nbsp;widgets in development.&lt;/p&gt;
&lt;h4&gt;&lt;a id="Enable_the_Plugin" name="Enable_the_Plugin"&gt;&lt;/a&gt;Enable the Plugin&lt;/h4&gt;
&lt;p&gt;If the plugin had not yet been enabled, enable it by going to &lt;strong&gt;Administration&lt;/strong&gt; and search for the name of the plugin (the sample defaults to &amp;quot;Sample Plugins&amp;quot;). Select the matching plugin, check to enable it, and save the plugin.&lt;/p&gt;
&lt;h4&gt;&lt;a id="Review_the_Upgrade_Note" name="Review_the_Upgrade_Note"&gt;&lt;/a&gt;Review the Upgrade Note&lt;/h4&gt;
&lt;p&gt;If this was the first enablement of the plugin, no notification will be sent, but the widgets should be installed and be available for use.&lt;/p&gt;
&lt;p&gt;If the plugin is updated, a notification should be sent to administrators of the site:&lt;/p&gt;
&lt;p&gt;&lt;a href="/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/1882.png"&gt;&lt;img alt=" " src="/resized-image/__size/1040x0/__key/communityserver-wikis-components-files/00-00-00-12-83/1882.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If the update included any changes to widgets, those widgets will have been versioned and the review text in the sample above will be shown. Clicking &lt;strong&gt;Review Widget Updates&lt;/strong&gt; will start the widget review process where modified widgets are listed and available for preview, review, and editing before being published to the community.&lt;/p&gt;
&lt;h2&gt;&lt;a id="Download_Fork_Source" name="Download_Fork_Source"&gt;&lt;/a&gt;Download/Fork Source&lt;/h2&gt;
&lt;p&gt;The source for this example is available on GitHub at&amp;nbsp;&lt;a href="https://github.com/Telligent/Widget-Source-Management-Sample"&gt;https://github.com/Telligent/Widget-Source-Management-Sample&lt;/a&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;
</description></item><item><title>Managing Widget Source and Distribution</title><link>https://community.telligent.com/community/11/w/developer-training/65068/managing-widget-source-and-distribution/revision/1</link><pubDate>Thu, 20 Jun 2019 20:13:47 GMT</pubDate><guid isPermaLink="false">a7478cac-9ea0-4d12-98e2-da6b8f32b086</guid><dc:creator>Ben Tiedt</dc:creator><comments>https://community.telligent.com/community/11/w/developer-training/65068/managing-widget-source-and-distribution#comments</comments><description>Revision 1 posted to Developer Training by Ben Tiedt on 06/20/2019 20:13:47&lt;br /&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;When working on widgets within a team or on a redistributable set of work, it is beneficial to make use of Telligent Community platform services to make development, versioning, and deployment easier.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;[toc]&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;&lt;a id="Making_Development_and_Deployment_Easier" name="Making_Development_and_Deployment_Easier"&gt;&lt;/a&gt;&lt;span style="font-weight:400;"&gt;Making Development and Deployment Easier&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;To make development easier, you&amp;nbsp;can leverage the same functionality used by the core components of Telligent Community, specifically:&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;A [[Factory Default Widget Providers|factory default widget provider]]. Factory default widget providers enable widget source to be stored on the file system. This makes source management within a system such as SVN, Git, or TFS possible which better enables development within a team.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;[[Editing Widgets in Developer Mode|Developer Mode]]. Developer mode is a feature of Telligent Community that enables developers to work on factory default widgets within the platform widget editor while saving directly to the file system (to enable source control).&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Automatic installation of source files. Using&amp;nbsp;an [[api-documentation:IInstallablePlugin Plugin Type|IInstallablePlugin]]&amp;nbsp;implementation along with the widget versioning support in the [[UI Automation|UI automation APIs]] and embedded resources enable a complete installation story for custom widgets deployed as part of a factory default provider.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;Let&amp;#39;s look at a sample implementation and then talk through the details of leveraging these capabilities.&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;&lt;a id="Implementation" name="Implementation"&gt;&lt;/a&gt;&lt;span style="font-weight:400;"&gt;Implementation&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;A sample implementation of this approach is available on GitHub:&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;&lt;a href="https://github.com/Telligent/Widget-Source-Management-Sample"&gt;github.com/.../Widget-Source-Management-Sample&lt;/a&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;This implementation contains two projects: &lt;a href="https://github.com/Telligent/Widget-Source-Management-Sample/tree/master/Samples"&gt;Samples&lt;/a&gt; and &lt;a href="https://github.com/Telligent/Widget-Source-Management-Sample/tree/master/FactoryDefaultWidgetFileManifestUpdater"&gt;FactoryDefaultWidgetFileManifestUpdater&lt;/a&gt;. The Samples project identifies the factory default widget provider against which widgets can be created. This particular implementation also includes support for automatic file installation and [[Editing Widgets in Developer Mode|developer mode]] considerations. The FactoryDefaultWidgetFileManifestUpdater is a utility console app, suitable for use on a build server, that packages widgets created in Telligent Community with the Samples project for deployment as a single installable DLL.&lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a id="Sample_Factory_Default_Widget_Provider_Implementation" name="Sample_Factory_Default_Widget_Provider_Implementation"&gt;&lt;/a&gt;&lt;span style="font-weight:400;"&gt;Sample Factory Default Widget Provider Implementation&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;The sample factory default provider is a [[Plugins|plugin]] to Telligent Community. It provides a container&amp;nbsp;for storing factory default&amp;nbsp;widgets on the file system by implementing [[api-documentation:IScriptedContentFragmentFactoryDefaultProvider Plugin Type|IScriptedContentFragmentFactoryDefaultProvider]]. It also implements&amp;nbsp;[[api-documentation:IInstallablePlugin Plugin Type|IInstallablePlugin]] to enable installing the source of all widgets associated to the factory default provider from embedded resources in the release build of the project.&lt;/p&gt;
&lt;p&gt;Instead of reviewing all of the source code, let&amp;#39;s instead review the unique areas and discuss why they are implemented the way they are.&lt;/p&gt;
&lt;h4&gt;&lt;a id="The_Factory_Default_Widget_Provider_Identifier" name="The_Factory_Default_Widget_Provider_Identifier"&gt;&lt;/a&gt;The Factory Default Widget Provider Identifier&lt;/h4&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;// the provider ID should be updated to be unique (with Developer Mode enabled, go to Administration &amp;gt; Development &amp;gt;  Generate GUID to get a new GUID)
private readonly Guid _providerId = new Guid(&amp;quot;fa801aba-84a0-4746-92cc-b418a7106c0b&amp;quot;);&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Note at the top of the &lt;a href="https://github.com/Telligent/Widget-Source-Management-Sample/blob/master/Samples/FactoryDefaultWidgetProvider.cs"&gt;FactoryDefaultWidgetProvder.cs&lt;/a&gt; file the comment about updating the readonly identifier in this file. This is the identifier that should be unique to your implementation.&amp;nbsp;The sample is implemented as a sample without a compiled version because it requires modification and custom building to be used. Generally, a factory default widget provider would be included with other functionality, such as [[Creating Custom Applications and Content|custom content types]] or [[Widget Extensions|custom widget extensions]]. At a minimum, this identifier&amp;nbsp;should be updated.&lt;/p&gt;
&lt;h4&gt;&lt;a id="Developer_Mode_Considerations" name="Developer_Mode_Considerations"&gt;&lt;/a&gt;Developer Mode Considerations&lt;/h4&gt;
&lt;p&gt;To better support [[Editing Widgets in Developer Mode|developer mode]], where developers can edit their factory default widgets within the Telligent Community UI, a few considerations need to be made to the implementation of the factory default widget provider.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;private Version _emptyVersion = new Version(0, 0, 0, 0);
#if DEBUG
    private Version _version = new Version(0, 0, 0, 0);
#else
    private Version _version = null;
#endif&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;[[api-documentation:IInstallablePlugin Plugin Type|IInstallablePlugins]] are installed whenever the plugin&amp;#39;s version changes, however, when developing widgets, you&amp;nbsp;do not want to install any widget source files as these installed files would overwrite your in-development versions. To account for this conflict of functionality, we&amp;#39;ll make use of compile-time conditions and preset versions.&lt;/p&gt;
&lt;p&gt;When in debug-mode build, developer mode can be enabled. In this situation, the plugin will always identify a version of &lt;code&gt;0.0.0.0&lt;/code&gt; which is also the default version value. When the version is set to &lt;code&gt;0.0.0.0&lt;/code&gt;, we bypass the version determination logic:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public Version Version
{
    get
    {
        if (_version == null)
        {
            // only executed when the version isn&amp;#39;t preset to 0.0.0.0
        }

        return _version;
    }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;and bypass the installation process:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public void Install(Version lastInstalledVersion)
{
    if (Version == _emptyVersion)
        return;
        
    // Normal installation logic...
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;These changes ensure that while using developer mode, you&amp;#39;ll&amp;nbsp;never accidentally overwrite our widget source with a previous-built version of the widget package.&lt;/p&gt;
&lt;h4&gt;&lt;a id="Support_for_Installation_and_Version_Review" name="Support_for_Installation_and_Version_Review"&gt;&lt;/a&gt;Support for Installation and Version Review&lt;/h4&gt;
&lt;p&gt;Telligent Community 9 includes support for reviewing changes made to widgets by end-users. When a new version of a factory default is available, the platform can version the existing implementation of the widget (whether or not it is customized pre-upgrade), update the underlying version of the factory default to the latest, and provide a review process post-upgrade to opt-in or review differences to individual widgets either visually (via the preview panel) or within the widget editor. This sample makes use of this process within the &lt;code&gt;IInstallablePlugin&lt;/code&gt; implementation.&lt;/p&gt;
&lt;p&gt;When in a release build, the version is left unset until first accessed:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;private Version _emptyVersion = new Version(0, 0, 0, 0);
#if DEBUG
    private Version _version = new Version(0, 0, 0, 0);
#else
    private Version _version = null;
#endif&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Then, when accessed, we&amp;#39;ll determine the latest file version based on the newest/greatest version from the file manifest (the file manifest is described later, but it is a programmatic, versioned listing of embedded files that should be installed):&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public Version Version
{
    get
    {
        if (_version == null)
        {
            Version version = _emptyVersion;

            foreach(var file in FactoryDefaultWidgetFileManifest.Files().Where(x =&amp;gt; x.WidgetProviderId == ScriptedContentFragmentFactoryDefaultIdentifier))
            {
                if (file.LastModifiedVersion &amp;gt; version)
                    version = file.LastModifiedVersion;
            }

            _version = version;
        }

        return _version;
    }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Then, when the version is&amp;nbsp;different than what is currently installed (either because it is the first time this plugin is enabled or an update has been installed), the embedded files are installed within the &lt;code&gt;Install()&lt;/code&gt; method:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public void Install(Version lastInstalledVersion)
{
    if (Version == _emptyVersion)
        return;

    var files = FactoryDefaultWidgetFileManifest.Files().Where(x =&amp;gt; x.WidgetProviderId == ScriptedContentFragmentFactoryDefaultIdentifier).ToList();

    DetectedDeletedProviderFiles(files);

    // detect upgrade changes and version widgets appropriately for post-upgrade review (or just install all of the files if this isn&amp;#39;t an upgrade)
    var message = ContentFragments.UpdateScriptedContentFragments(
        lastInstalledVersion,
        files.Select(x =&amp;gt; x as IInstallableFile).ToList()
        );

    // if this was an upgrade, identify the upgrade as complete and provide a way to review widgets (if any were modified as part of the upgrade)
    if (lastInstalledVersion &amp;gt; _emptyVersion)
    {
        // identify that the plugin was upgraded and provide the note to review widget changes, if there was one
        Apis.Get&amp;lt;ISystemNotifications&amp;gt;().Create(
            string.Concat(Name, &amp;quot; Upgraded&amp;quot;),
            string.Concat(&amp;quot;&amp;lt;p&amp;gt;&amp;quot;, Name, &amp;quot; has been upgraded to &amp;quot;, Version.ToString(), &amp;quot;.&amp;lt;/p&amp;gt;&amp;quot;, message ?? &amp;quot;&amp;quot;)
            );
    }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;This installation requires a few steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Load the&amp;nbsp;file manifest.&lt;/strong&gt; Specifically, only the files in the manifest affecting this factory default provider are retrieved (the sample can be expanded to support more than one factory default provider, if necessary).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Determine deleted files.&lt;/strong&gt; To find deleted files, we use the &lt;code&gt;DetectedDeletedProviderFiles()&lt;/code&gt; method to compare the currently installed file list against the file manifest. Anything that is currently installed but not in the latest manifest is assumed to be deleted.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Upgrade the files.&lt;/strong&gt; To do this, we use our modified manifest (the list of embedded files combined with the list of deleted files) and provide it to the [[api-documentation:ContentFragments In-Process API Service|ContentFragments.UpdateScriptedContentFragments() UI Automation API]]. This API will version any existing implementation of modified source files and then install the updated factory default files. Any changes that are found are returned in an HTML-formatted message returned from the method that can be provided to site administrators to review widget updates and approve/deny them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Send the upgrade message.&lt;/strong&gt; If the plugin is an upgrade (and not an initial installation), an upgrade system notification is sent using the [[api-documentation:SystemNotifications In-Process API Service|ISystemNotifications.Create() API]] to notify system administrators that the plugin has been upgraded successfully and, if there are any widget changes, provide the review message.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;&lt;a id="Factory_Default_Widget_File_Manifest_Updater" name="Factory_Default_Widget_File_Manifest_Updater"&gt;&lt;/a&gt;Factory Default Widget File Manifest Updater&lt;/h3&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;The manifest updater is a console application that can be used when packaging the Sample project for deployment. The console app updates the file manifest used by the Sample factory default widget provider&amp;#39;s installation process and ensures that sources files are embedded in the resulting DLL. This console app should be executed before building the Samples project in release mode for deployment.&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;&lt;a id="Using_the_Sample" name="Using_the_Sample"&gt;&lt;/a&gt;Using the Sample&lt;/h2&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;Using the sample is slightly different for development and deployment&lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a id="Development_with_the_Sample" name="Development_with_the_Sample"&gt;&lt;/a&gt;Development with the Sample&lt;/h3&gt;
&lt;h4&gt;&lt;a id="Incorporate_the_Sample_In_Your_Project" name="Incorporate_the_Sample_In_Your_Project"&gt;&lt;/a&gt;Incorporate the Sample In Your Project&lt;/h4&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;Generally, a factory default widget provider is used to expose other custom functionality implemented using [[Plugins|plugins]]. This sample should then be incorporated into the same project so all of the components are distributed together. I&lt;/span&gt;&lt;span style="font-weight:400;"&gt;f this project is used only for widget source file management, the namespace, project name, and assembly name should at least be updated.&lt;/span&gt;&lt;/p&gt;
&lt;h4&gt;&lt;a id="Update_the_Factory_Default_Provider_ID" name="Update_the_Factory_Default_Provider_ID"&gt;&lt;/a&gt;Update the Factory Default Provider ID&lt;/h4&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;Once the project source is in a good location, generate a new GUID for the factory default provider identifier. &lt;span style="color:#800000;"&gt;&lt;strong&gt;The value in the sample should not be used.&lt;/strong&gt;&lt;/span&gt; To generate a GUID in developer mode, go to &lt;strong&gt;Administration &amp;gt; Development &amp;gt; Generate GUID&lt;/strong&gt; and copy the generated GUID. Update the &lt;code&gt;_providerId&lt;/code&gt; GUID on line 17 of &lt;a href="https://github.com/Telligent/Widget-Source-Management-Sample/blob/master/Samples/FactoryDefaultWidgetProvider.cs"&gt;FactoryDefaultWidgetProvider.cs&lt;/a&gt; (or wherever this code gets relocated within an existing project).&lt;/span&gt;&lt;/p&gt;
&lt;h4&gt;&lt;a id="Update_Project_References" name="Update_Project_References"&gt;&lt;/a&gt;Update Project References&lt;/h4&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;To use the sample, the project will need to have valid references to Telligent.Evolution.Api.dll, Telligent.Evolution.Components.dll, and Telligent.Evolution.ScriptedContentFragments.dll -- all DLLs that are part of the Telligent Community platform.&lt;/span&gt;&lt;/p&gt;
&lt;h4&gt;&lt;a id="Build_and_Deploy" name="Build_and_Deploy"&gt;&lt;/a&gt;Build and Deploy&lt;/h4&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;Ensure that you are building the project in Debug mode. Build the project and deploy the resulting DLL to a development instance of Telligent Community (if your development instance contains multiple instances of the platform, install the DLL in each instance... for example, each web node and job scheduler node).&lt;/span&gt;&lt;/p&gt;
&lt;h4&gt;&lt;a id="Enable_the_Plugin" name="Enable_the_Plugin"&gt;&lt;/a&gt;Enable the Plugin&lt;/h4&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;Within Telligent Community, enable the plugin. Go to &lt;strong&gt;Administration&lt;/strong&gt; and search for the name of the plugin (the sample is called &amp;quot;Sample Widgets&amp;quot;). Click to view the plugin, check the enabled box, and save.&lt;/span&gt;&lt;/p&gt;
&lt;h4&gt;&lt;a id="Develop_Widgets" name="Develop_Widgets"&gt;&lt;/a&gt;Develop Widgets&lt;/h4&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;Within the widget editor at &lt;strong&gt;Administration &amp;gt; Interface &amp;gt; Widgets&lt;/strong&gt;, with [[Editing Widgets in Developer Mode|developer mode]] enabled, you should be able to create a new widget by clicking the&amp;nbsp;&lt;a href="/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/44.05-PM.png"&gt;&lt;img src="/resized-image/__size/13x12/__key/communityserver-wikis-components-files/00-00-00-12-83/44.05-PM.png" alt=" " /&gt;&lt;/a&gt;&amp;nbsp;icon. Within the Developer Mode Widget Details modal, select the name of your factory default provider, for example, &amp;quot;Sample Widgets&amp;quot;:&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;&lt;a href="/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/20780.png"&gt;&lt;img src="/resized-image/__size/1040x0/__key/communityserver-wikis-components-files/00-00-00-12-83/20780.png" alt=" " /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;If you don&amp;#39;t see your sample widget provider, you can go to &lt;strong&gt;Administration &amp;gt; Development &amp;gt; Expire Caches&lt;/strong&gt; and select &lt;strong&gt;Expire All Caches&lt;/strong&gt;, then try again. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;After clicking &lt;strong&gt;Continue&lt;/strong&gt; on the &lt;strong&gt;Developer Mode Widget Details&lt;/strong&gt; modal, you will have created a new staged widget within your factory default provider. You can then [[Widgets|develop the widget normally]]. When you save, the widget will be saved to the file system where you&amp;#39;ve configured the centralized file system, by default,&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="text"&gt;Web\filestorage\defaultwidgets\{FACTORY_DEFAULT_PROVIDER_ID}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;where&amp;nbsp;&lt;code&gt;{FACTORY_DEFAULT_PROVIDER_ID}&lt;/code&gt; is the ID you provided as the factory default provider ID when you customized the sample implementation. This is the folder that you&amp;#39;ll also want to add to your source control/management system. Any files within this folder are sources files used to implement the widgets associated to the factory default. As you [[Editing Widgets in Developer Mode|develop widgets]], you&amp;#39;ll want to commit any changes to this folder (new files, edited files, deleted files) to your source management solution.&lt;/p&gt;
&lt;h3&gt;&lt;a id="Building_a_Deployment_Package" name="Building_a_Deployment_Package"&gt;&lt;/a&gt;Building a Deployment Package&lt;/h3&gt;
&lt;p&gt;Once you have developed the widgets as part of your factory default widget provider implementation, you can package the plugin and the widget source files for deployment. To do this,&lt;/p&gt;
&lt;h4&gt;&lt;a id="Setup_Your_Build_Environment" name="Setup_Your_Build_Environment"&gt;&lt;/a&gt;Setup Your Build Environment&lt;/h4&gt;
&lt;p&gt;Your build environment should not be the same as your [[Editing Widgets in Developer Mode|development environment]]. Ideally, this step would be performed as part of a continuous integration process. It could also be performed carefully within a second local instance of your provider implementation.&lt;/p&gt;
&lt;h4&gt;&lt;a id="Get_the_Latest_Source" name="Get_the_Latest_Source"&gt;&lt;/a&gt;Get the Latest Source&lt;/h4&gt;
&lt;p&gt;Load the latest implementation of the plugin source and the widget source from your source management solution. These two collections of source files should be in separate folders (one should not be within the other).&lt;/p&gt;
&lt;p&gt;Execute the FactoryDefaultWidgetFileManfiestUpdater console app.&amp;nbsp;Specifically&lt;span style="font-weight:400;"&gt;, execute:&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;&lt;pre class="ui-code" data-mode="text"&gt;FactoryDefaultWidgetFileManifestUpdater.exe /proj:&amp;quot;{FULL_PROJECT_PATH}&amp;quot;  /providerid:{WIDGET_PROVIDER_ID} /cfs:&amp;quot;{FULL_CFS_PATH}&amp;quot; /out:&amp;quot;{PATH_TO_MANIFEST_CLASS}&amp;quot;&lt;/pre&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-weight:400;"&gt;Where the following tokens are replaced:&lt;/span&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;{FULL_PROJECT_PATH}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The full local path to the &lt;a href="https://github.com/Telligent/Widget-Source-Management-Sample/blob/master/Samples/Samples.csproj"&gt;Samples.csproj&lt;/a&gt; project file.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;{WIDGET_PROVIDER_ID}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The GUID representing the Samples factory default provider (specified in the &lt;a href="https://github.com/Telligent/Widget-Source-Management-Sample/blob/master/Samples/FactoryDefaultWidgetProvider.cs"&gt;FactoryDefaultProvider.cs&lt;/a&gt; file in the Samples project).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;{FULL_CFS_PATH}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The full local path to the root CFS folder (Web/filestorage/, for example) containing the source of the widgets for this factory default provider. This should not be located within the Samples project&amp;#39;s folder structure.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;{PATH_TO_MANIFEST_CLASS}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;The full local path to the &lt;a href="https://github.com/Telligent/Widget-Source-Management-Sample/blob/master/Samples/Generated/FactoryDefaultWidgetFileManifest.cs"&gt;FactoryDefaultWidgetFileManifest.cs&lt;/a&gt;&amp;nbsp;file in the Samples project.&amp;nbsp;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;&lt;a id="Build_the_Deployment_Package" name="Build_the_Deployment_Package"&gt;&lt;/a&gt;Build the Deployment Package&lt;/h4&gt;
&lt;p&gt;Ensure that the sample project is set to be built in release mode and build the project. The resulting DLL will include all of the widget source files along with the manifest and will be built to enable widget source file installation. This DLL can now be deployed.&lt;/p&gt;
&lt;h3&gt;&lt;a id="Installing_the_Deployment_Package" name="Installing_the_Deployment_Package"&gt;&lt;/a&gt;Installing the Deployment Package&lt;/h3&gt;
&lt;p&gt;To install the deployment package,&lt;/p&gt;
&lt;h4&gt;&lt;a id="Install_the_Package_DLL" name="Install_the_Package_DLL"&gt;&lt;/a&gt;Install the Package DLL&lt;/h4&gt;
&lt;p&gt;Install the resulting deployment package DLL into each instance of the Telligent Community platform (each web and job server node). Note that you should not install the deployment package on a development site since you will overwrite any&amp;nbsp;widgets in development.&lt;/p&gt;
&lt;h4&gt;&lt;a id="Enable_the_Plugin" name="Enable_the_Plugin"&gt;&lt;/a&gt;Enable the Plugin&lt;/h4&gt;
&lt;p&gt;If the plugin had not yet been enabled, enable it by going to &lt;strong&gt;Administration&lt;/strong&gt; and search for the name of the plugin (the sample defaults to &amp;quot;Sample Plugins&amp;quot;). Select the matching plugin, check to enable it, and save the plugin.&lt;/p&gt;
&lt;h4&gt;&lt;a id="Review_the_Upgrade_Note" name="Review_the_Upgrade_Note"&gt;&lt;/a&gt;Review the Upgrade Note&lt;/h4&gt;
&lt;p&gt;If this was the first enablement of the plugin, no notification will be sent, but the widgets should be installed and be available for use.&lt;/p&gt;
&lt;p&gt;If the plugin is updated, a notification should be sent to administrators of the site:&lt;/p&gt;
&lt;p&gt;&lt;a href="/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/1882.png"&gt;&lt;img src="/resized-image/__size/1040x0/__key/communityserver-wikis-components-files/00-00-00-12-83/1882.png" alt=" " /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If the update included any changes to widgets, those widgets will have been versioned and the review text in the sample above will be shown. Clicking &lt;strong&gt;Review Widget Updates&lt;/strong&gt; will start the widget review process where modified widgets are listed and available for preview, review, and editing before being published to the community.&lt;/p&gt;
&lt;h2&gt;&lt;a id="Download_Fork_Source" name="Download_Fork_Source"&gt;&lt;/a&gt;Download/Fork Source&lt;/h2&gt;
&lt;p&gt;The source for this example is available on GitHub at&amp;nbsp;&lt;a href="https://github.com/Telligent/Widget-Source-Management-Sample"&gt;https://github.com/Telligent/Widget-Source-Management-Sample&lt;/a&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;
</description></item></channel></rss>