Creating Custom Tuxboard Widgets

September 4th, 2024

In today's post, we cover the process of building and adding new widgets to Tuxboard

What's Next?

Full examples located at Tuxboard.Examples.

In the last post, we discussed how a user could view available widgets based on their roles in the application.

While widgets are a fundamental part of Tuxboard, this series of posts never mentioned how to create a widget.

Since widgets are a big thing with Tuxboard, there's a lot to cover. For this initial post, we'll break this into multiples posts to make it easier to digest.

In this post, we'll go over the process of creating a new Tuxboard widget.

Overview

To review the goals of Tuxboard,  

  1. Easy Integration - Simple enhancement to applications
  2. Declarative first, Programmatic second - The concept of modifying Tuxboard using HTML, CSS, and JavaScript/TypeScript was more enticing than modifying code, then compiling. However, the option of writing code is available.
  3. Extensibility - Providing simple hooks at the programmatic and database level to speed up custom development requirements.

These three goals are always at the top of the list for easy dashboard development, but today, we focus on the "Extensibility" and "Easy Integration" part of Tuxboard.

Once a Tuxboard dashboard is running for users, the ability to create additional widgets was essential.

Since developers need a way to keep up with the latest news, we'll add a Stack Overflow Blog RSS feed widget.

Type of Widgets

There are two types of widgets in Tuxboard: Standard and Static.

  1. Standard - Widgets with a heading allowing users to interact with the widget's information/settings
  2. Static - Widget meant to display information with no interaction

The posts in series focused primarily on standard widgets. Static widgets are simply a box displaying information with no interaction or actions.

We'll get into static widgets in a later post.

Setup

We're using the source code from the last project (11-Creating-Default-Widgets / repository). Follow the steps under the "Getting Started" heading.

Once finished, we'll continue with the next section.

Creating the RSS Widget

When building a new widget, only two places are required to update: The Components folder and the database.

Let's break down each one and examine what's required to add the Stack Overflow Blog RSS Widget (Man, that's a mouthful...I'll just call it RSS Widget from now on).

Step 1: Creating the RSS [View]Component Folder

In Tuxboard, the term widget and ViewComponent are interchangeable. If you understand ViewComponents, then you already understand a widget in Tuxboard.

ViewComponents are absolutely essential in creating these "islands of HTML." As mentioned in the past, there are a lot of benefits to using ViewComponents

To add the RSS Widget, create a folder called "Rss" under the Pages/Shared/Components folder and add the following files into the "Rss" folder.

Pages/Shared/Components/Rss/RssViewComponent.cs

using Microsoft.AspNetCore.Mvc;
using Tuxboard.Core.Domain.Entities;

namespace
CreatingWidgets.Pages.Shared.Components.Rss;

[
ViewComponent(Name = "rss")]
public class RssViewComponent : ViewComponent
{
    public IViewComponentResult Invoke(WidgetPlacement placement)
    {
        var rssFeed = new Uri("https://stackoverflow.blog/feed");

       var feed = new FeedReader(rssFeed).Get();

       var widgetModel = new RssWidgetModel { Placement = placement, Feed = feed };

       return View(widgetModel);
    }
}

Pages/Shared/Components/Rss/Default.cshtml

@model RssWidgetModel

<
h6>@Model.Feed.Title.Text</h6>
<ul class="list-unstyled">
    @foreach (var feedItem in Model.Feed.Items.Take(Model.Limit))
    {
        <li>
            <p>
                <a href="@feedItem.Links.First().Uri.ToString()"
                   class="fw-bold">
                    @feedItem.Title.Text
                </a><br />
                @feedItem.Summary.Text
            </p>
        </li>
    }
</ul>

Pages/Shared/Components/Rss/FeedReader.cs

using System.ServiceModel.Syndication;
using System.Xml;

namespace
CreatingWidgets.Pages.Shared.Components.Rss;

public
 class FeedReader
{
    private readonly Uri _rssFeed;

   public FeedReader(Uri rssFeed)
    {
        _rssFeed = rssFeed;
    }

   public SyndicationFeed Get()
    {
        using (var reader = XmlReader.Create(_rssFeed.AbsoluteUri))
        {
            var feed = SyndicationFeed.Load(reader);
            reader.Close();

            return feed;
        }
    }
}

Pages/Shared/Components/Rss/RssWidgetModel.cs

using System.ServiceModel.Syndication;
using Tuxboard.Core.Infrastructure.Models;

namespace CreatingWidgets.Pages.Shared.Components.Rss;

public class RssWidgetModel : WidgetModel
{
    public SyndicationFeed Feed { get; set; } = null!;
    public int Limit { get; set; } = 10;
}

One of the first steps is creating the RssViewComponent which accepts an instance of a WidgetPlacement object.

For convenience, we create a FeedReader class so we can immediately consume the Stack Overflow RSS feed.

The RssWidgetModel passes the data onto the view (default.cshtml). If you notice, we're allowing only 10 articles to display in the widget.

Once passed in, the data is rendered with links and a summary of each post.

Step 2: Adding the Widget Record

With the RSS widget created, we can now focus on adding the record to the Tuxboard tables.

The widget structure consists of the following tables:

When a user adds a widget to their dashboard, these records are transformed from a Widget record into a WidgetPlacement record with corresponding default settings.

Using SSMS (SQL Server Management Studio), we can use SQL to insert a new record into the Widget table.

INSERT INTO Widget
SELECT
    newid() as WidgetId,
    'rss' as Name,
    'StackOverflow Blog RSS Feed' as Title,
    'Latest News from Stack Overflow''s Blog' as Description,
    '' as ImageUrl,
    'Programming' as GroupName,
    0 as Permission,
    1 as Moveable,
    1 as CanDelete,
    1 as UseSetting,
    1 as UseTemplate

Here's a breakdown of the inserted record:

Next is the WidgetDefault table. Each widget should contain at least one setting, usually a widget title.

Here's the SQL statement to add a Title setting to our RSS widget.

INSERT INTO WidgetDefault
SELECT
    newid() as WidgetDefaultId,
    '<EnterYourWidgetIdHere>' as WidgetId,
    'widgettitle' as SettingName,
    'Title' as SettingTitle,
    0 as SettingType,
    'Latest News from Stack Overflow' as DefaultValue,
    1 as SettingIndex

Again, let's break down each field to understand what's happening.

To confirm these records are connected properly, run this SQL statement.

SELECT
    w.Name,
    w.Title,
    w.Description,
    wd.SettingTitle,
    wd.DefaultValue
FROM Widget w
JOIN WidgetDefault wd on wd.WidgetId=w.WidgetId
WHERE w.WidgetId='<YourWidgetIdHere>'

The SQL statement above is definitely reusable for validating settings for a widget.

If everything looks good, users can add the latest widget to their dashboard.

Troubleshooting

While that's everything required to add a widget, there could be some problems. Let's look at some common issues (I know there's only one, but more will be added as they're asked).

Viewing the Results

With our RSS widget now in place, users can add the widget to see the latest news from Stack Overflow.

Conclusion

In this post, we created a simple widget for users to view the latest news from Stack Overflow through an RSS feed.

The best part of this post is we'll continue to build and extend this example to show other features of Tuxboard like widget settings and how to defer rendering.

The repository for this post is the 12-Creating-Widgets at Tuxboard.Examples.

What's Next?

Full examples located at Tuxboard.Examples.