Addon Template processor

Overview

Template processors are created from classes that inherit the ITfTemplateProcessorAddon interface. Tefter.bg scans for these classes during startup and makes them available to users. Template processors also require typed components for their lifecycle.

The typical process for creating and distributing a template processor for Tefter.bg involves developing a Razor library project and then distributing the result as a NuGet package. For practical examples, you can review the projects of existing processors created by us, such as:

Seed Project GitHub
Text Content Processor GitHub
Text File Processor GitHub
Excel File Processor GitHub
Word File Processor GitHub
Email Processor GitHub

Template processor project

The usual structure of the projects is as follows:

Template processor project

Template processor class

This is they usual structure of a template processor method and its properties and callback methods.

using System.Text;
namespace WebVella.Tefter.Seeds.SampleTemplateProcessor.Addons;
public class SampleTemplateProcessor : ITfTemplateProcessorAddon
{

	public const string ID = "9754c7dc-80da-4b65-bf10-eb441d370fe2";
	public const string NAME = "Sample content template";
	public const string DESCRIPTION = "scrambles text";
	public const string FLUENT_ICON_NAME = "ScanText";
	public const TfTemplateResultType RESULT_TYPE = TfTemplateResultType.Text;

	public Guid Id  { get; init; } = new Guid(ID);
	public string Name { get; init; } = NAME;
	public string Description { get; init; } = DESCRIPTION;
	public string FluentIconName { get; init; } = FLUENT_ICON_NAME;
	public TfTemplateResultType ResultType  { get; init; } = RESULT_TYPE;

	/// <summary>
	/// Called when template preview result is submitted for generation.
	/// Sometimes when the user selects template from this processor, 
	/// it needs to provide input needed by the processor to generate the final result.
	/// This method validates this input
	/// </summary>
	public void ValidatePreview(
		TfTemplate template,
		ITfTemplatePreviewResult preview,
		IServiceProvider serviceProvider)
	{
	}

	/// <summary>
	/// Presented to the user when it wants to use this processor with data.
	/// </summary>
	/// <returns></returns>
	public ITfTemplatePreviewResult GenerateTemplatePreviewResult(
		TfTemplate template,
		TfDataTable dataTable,
		IServiceProvider serviceProvider)
	{
		var result = (SampleTemplateResult)GenerateResultInternal(
			template, dataTable, serviceProvider);

		return new SampleTemplatePreviewResult
		{
			Errors = result.Errors,
			Items = result.Items
		};
	}

	/// <summary>
	/// Method generating the final result
	/// </summary>
	/// <returns></returns>
	public ITfTemplateResult ProcessTemplate(
		TfTemplate template,
		TfDataTable dataTable,
		ITfTemplatePreviewResult preview,
		IServiceProvider serviceProvider)
	{
		return GenerateResultInternal(template, dataTable, serviceProvider);
	}

	/// <summary>
	/// Called when user submits settings
	/// </summary>
	public List<ValidationError> ValidateSettings(
			string settingsJson,
			IServiceProvider serviceProvider)
	{
		return new List<ValidationError>();
	}

	/// <summary>
	/// Called in transaction with the creation method, but before it.
	/// </summary>
	public List<ValidationError> OnCreate(
		TfManageTemplateModel template,
		IServiceProvider serviceProvider)
	{
		return new List<ValidationError>();
	}

	/// <summary>
	/// called after the creation method outside its transaction
	/// </summary>
	public void OnCreated(
		TfTemplate template,
		IServiceProvider serviceProvider)
	{
	}

	/// <summary>
	/// Called in transaction with the update method, but before it.
	/// </summary>
	public List<ValidationError> OnUpdate(
		TfManageTemplateModel template,
		IServiceProvider serviceProvider)
	{
		return new List<ValidationError>();
	}

	/// <summary>
	/// called after the update method outside its transaction
	/// </summary>
	public void OnUpdated(
		TfTemplate template,
		IServiceProvider serviceProvider)
	{
	}
	/// <summary>
	/// Called in transaction with the update method, but before it.
	/// </summary>
	public List<ValidationError> OnDelete(
		TfTemplate template,
		IServiceProvider serviceProvider)
	{
		return new List<ValidationError>();
	}
	/// <summary>
	/// called after the delete method outside its transaction
	/// </summary>
	public void OnDeleted(
		TfTemplate template,
		IServiceProvider serviceProvider)
	{
	}

	private ITfTemplateResult GenerateResultInternal(
		TfTemplate template,
		TfDataTable dataTable,
		IServiceProvider serviceProvider)
	{
		var result = new SampleTemplateResult();


		var tfService = serviceProvider.GetService<ITfService>();

		if (string.IsNullOrWhiteSpace(template.SettingsJson))
		{
			result.Errors.Add(new ValidationError("", "Template settings are not set."));
			return result;
		}

		var settings = JsonSerializer.Deserialize<SampleTemplateSettings>(template.SettingsJson);
	
		try
		{

			foreach (TfDataRow row in dataTable.Rows)
			{
				var item = new SampleTemplateResultItem();
				item.NumberOfRows = 1;

				//foreach row scrables values of TEXT type and append them to string builder
				StringBuilder sb = new StringBuilder();
				foreach (var column in dataTable.Columns)
				{
					if (column.DbType == TfDatabaseColumnType.Text)
					{
						if (row[column.Name] == null)
							continue;

						var scrabledText = Scramble( row[column.Name].ToString());
						sb.Append(scrabledText);
					}
				}
				item.Content = sb.ToString();
				result.Items.Add(item);
			}
		}
		catch (Exception ex)
		{
			result.Errors.Add(new ValidationError("", $"Unexpected error occurred. {ex.Message} {ex.StackTrace}"));
		}

		return result;
	}

	private static Random rand = new Random();

	private string Scramble( String str)
	{
		var list = new SortedList<int, char>();
		foreach (var c in str)
			list.Add(rand.Next(), c);
		return new string(list.Values.ToArray());
	}
}


DisplaySettings component

This is a component that is used to display the custom settings of the template processor. It needs to be created as a ScreenRegionComponent Addon and the class needs to inherit the ITfScreenRegionComponent<TfTemplateProcessorDisplaySettingsComponentContext> interface.

Help component

This is a component that is used in the help modal to guide the user how to properly configure the template. It needs to be created as a ScreenRegionComponent Addon and the class needs to inherit the ITfScreenRegionComponent<TfTemplateProcessorHelpComponentContext> interface.

ManageSettings component

This is a component that is used in the manage settings modal to enable template custom settings management. It needs to be created as a ScreenRegionComponent Addon and the class needs to inherit the ITfScreenRegionComponent<TfTemplateProcessorManageSettingsComponentContext> interface.

ResultPreview component

This is a component is used in the result preview modal, to represent the expected outcome to the user, as well as get necessary feedback from it. It needs to be created as a ScreenRegionComponent Addon and the class needs to inherit the ITfScreenRegionComponent<TfTemplateProcessorResultPreviewComponentContext> interface.

Result component

This is a component is used in the result modal, to present information about the result of the template processing. It needs to be created as a ScreenRegionComponent Addon and the class needs to inherit the ITfScreenRegionComponent<TfTemplateProcessorResultComponentContext> interface.