Thursday 30 March 2023

Sitecore Forms - Markdown in Text Field

Update 30/03/2023: Bonus, now with added bold and line breaks!


One of the main limitations of Sitecore Forms in my opinion is not having a rich text field. No doubt this is something that could be implemented without too much of a headache, but a simpler option is to allow basic markdown such as links.

eg. this is a sentence with [a link](https://google.com) in it

Fortunately, using a custom field factory (see my previous post) this is pretty simple!

Wednesday 22 March 2023

Custom Form Elements in Headless (JSS) Forms

I've been getting pretty deep into the Sitecore React/Next.JS Forms libraries over the last couple of weeks, and while there's some half decent information out there if you look hard enough, it's generally not that accessible or complete. For example, one of the better pages altering field types is hidden away in GitHub and doesn't seem to pop up for me in a Google search.

I find that Sitecore Forms, while a great form builder, still lacks (at least) a couple of fields which I would consider a must-have: hidden fields, and raw HTML. Fortunately these can be found in Sitecore Forms Extensions, so we can copy the relevant code from there.

Once you've got the fields into Sitecore - in the form builder and rendering their properties into the layout service - the next step is to ensure your React/Next.JS code knows how to render the fields. Fortunately per the link above, this is fairly easy to inject/extend using a custom field factory:

We can then add our custom field factory to our form, and we should be good to go!

<Form
  form={fields}
  sitecoreApiHost={process.env.SITECORE_API_HOST}
  sitecoreApiKey={process.env.SITECORE_API_KEY}
  onRedirect={(url: string) => router.push(url)}
  fieldFactory={CustomFieldFactory}
/>

Issues / wish list:

  • CustomFieldFactory.setComponent first parameter relies on the FieldTypes enum (but works with any string). This causes Typescript errors. It would be great if this parameter/enum were extendable.
  • The Form component extends Component<FormProps, FormState & FieldStateCollection> but is itself not generic! This means that props can't be overridden, which means adding custom properties causes Typescript errors (though the code still works). Ideally Form would be generic so that we could pass custom props and properly override the Form class.
  • Conditions are not included anywhere in the Sitecore Forms React code :( See an upcoming post for how we can achieve conditional logic using OOTB Sitecore Forms conditions.
  • There is no validation on form submission! This was very surprising (and frustrating) to find (and implement).
  • There is no validation for mandatory fields on a couple of fields, eg. CheckboxList
  • Fields are still submitted by the JSS code even when adding a 'disabled' attribute to the field. This super painful to work around!

Monday 13 March 2023

Something went wrong. See SPE logs for more details.

 A nice quick one since I didn't find much useful info around on this particular issue (maybe nobody else has made this stupid mistake).

While working on a client implementation I came across the following error:

7952 03:31:46 INFO  Script item set to master:\system\Modules\PowerShell\Script Library\JSS SXA\Scaffolding\Content Editor\Insert Item\JSS Site in ScriptSession $scriptSession$|gmnwpaqx1sn0u3gz2hwu5bkr|fef42854-5de9-4f59-ab6a-13edd7d2862e.
ManagedPoolThread #4 03:31:47 ERROR Cannot bind argument to parameter 'TenantTemplatesRoot' because it is null.
7444 03:36:59 WARN  Session state elevated for 'ItemSave' by user: sitecore\admin

Digging into the powershell script which was being called (/sitecore/system/Modules/PowerShell/Script Library/JSS SXA/Scaffolding/Functions/New-JSSSite) you can quickly find the relevant line: 

$tenantTemplatesRootID = $tenant.Fields['Templates'].Value

Looking at the fields in my Tenant, I noticed they were all blank! Seems that while transferring items between environments someone forgot to package some of the necessary items.

Long story short, when packaging up your Tenant don't forget to include:

  1. /sitecore/templates/Project/YourTenant
  2. /sitecore/media library/Project/YourTenant
  3. /sitecore/media library/Project/YourTenant/shared
  4. /sitecore/layout/Renderings/Project/YourTenant
  5. /sitecore/layout/Placeholder Settings/Project/YourTenant

Wednesday 1 March 2023

When Disabling xDB Isn't Enough

If you read the documentation on using CMS-only mode to run Sitecore without xDB you'd be forgiven for thinking that a config patch such as this is the simple end of the story:

<configuration>
    <sitecore>
        <settings>
            <setting name="Xdb.Enabled" value="false" />
            <setting name="Xdb.Tracking.Enabled" value="false" />
        </settings>
    </sitecore>
</configuration>

Unfortunately as someone on Slack recently discovered, this doesn't help if you're trying to run Sitecore (XP container images, but in CMS-only mode without the xConnect instances) in containers. 

The issue is fairly obvious when you notice CM is not starting and take a look at an example of the logs

920 08:52:34 ERROR Health check Sitecore.XConnect.Client.WebApi.CollectionWebApiClient completed after 0.0038ms with status Unhealthy and 'Error during CollectionWebApiClient initialization: An error occurred while sending the request.'

1920 08:52:35 ERROR Health check Sitecore.XConnect.Client.WebApi.ConfigurationWebApiClient completed after 0.0054ms with status Unhealthy and 'Error during ConfigurationWebApiClient initialization: An error occurred while sending the request.'

1920 08:52:36 ERROR Health check Sitecore.XConnect.Client.WebApi.SearchWebApiClient completed after 0.0068ms with status Unhealthy and 'Error during SearchWebApiClient initialization: An error occurred while sending the request.'

Yes, there are in fact health checks on CM and CD which check the status of xConnect, and completely ignore the config settings I mentioned above.

Not to worry, there are a couple of options at this point:

  1. Use a config patch to remove the health checks (the easier option)
  2. Update and override the health checks so that they respect the Xdb.Enabled setting

Config patch

Here's an easy patch you can apply which should remove these from your Sitecore configuration and complete the disabling of xDB:

Updating the code

The "proper" way, I feel, would be to update the code to respect the Xdb.Enabled setting. This is what the setting is indicating, and what the documentation explains that it is for.

To take XConnectCollectionHealthCheckServicesConfigurator as an example:

public class XConnectCollectionHealthCheckServicesConfigurator : Sitecore.XConnect.Client.Configuration.HealthCheckServicesConfigurators.XConnectCollectionHealthCheckServicesConfigurator
{
  protected override IHealthCheck CreateCommonWebApiHealthCheck(IServiceProvider provider)
  {
    if (Sitecore.Configuration.Settings.GetBoolSetting("Xdb.Enabled", true))
      return base.CreateCommonWebApiHealthCheck(provider);
    else
      return new SuccessHealthCheck();
  }
}

public class SuccessHealthCheck : IHealthCheck
{
  public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
  {
    return Task.FromResult(HealthCheckResult.Healthy());
  }
}

We add our settings check, and - because there does not seem to be any easy out-of-the-box way to return a successful health check - we also need to create a class for that. Repeat for all 3 health checks, and you're good to go.

Enjoy running your Sitecore topology nice and lean!