Skip to content

Instantly share code, notes, and snippets.

@PNergard
Last active February 4, 2025 08:41
Show Gist options
  • Save PNergard/31e8ab4ad39ddb2bfc123fc4d540ad64 to your computer and use it in GitHub Desktop.
Save PNergard/31e8ab4ad39ddb2bfc123fc4d540ad64 to your computer and use it in GitHub Desktop.
Optimizely PageCriteriaQueryService builder
@using BlazorLabs.Cms.BlazorComponents
@using EPiServer.Framework.Web.Mvc.Html
@using System.Diagnostics.Metrics
<!DOCTYPE html>
<html lang="@(Model.CurrentPage.Language)">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=10" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@Model.CurrentPage.MetaTitle</title>
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
<link href="~/_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
<base href="~/" />
</head>
<body>
@RenderBody()
<script src="~/_framework/blazor.server.js"></script>
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
</body>
</html>
@using EPiServer.Editor
@using EPiServer.Filters
@using EPiServer.Web
@using EPiServer.Web.Routing
@using EPiServer.Shell
@using Microsoft.AspNetCore.Http.Extensions
@inject IPageCriteriaQueryService _pageCriteriaQueryService
@inject ISiteDefinitionRepository _siteDefinitionRepository
@inject IContentTypeRepository _contentTypeRepository
@inject UrlResolver _urlResolver
<MudGrid>
@* Start Criteria builder*@
<MudItem xs="12" sm="3">
<MudPaper Class="d-flex align-items-start justify-center mud-width-full">
<MudStack Class="mud-width-full">
<MudText Typo="Typo.h5">Criterias</MudText>
<MudSelect Variant="Variant.Outlined" Label="Content Type" Value="CriteriaContentTypeID" ValueChanged="@(async (int contentTypeID) => await OnContentTypeValueChanged(contentTypeID))">
@foreach (var contentType in ContentTypesList)
{
<MudSelectItem Value="contentType.ID">@contentType.Name</MudSelectItem>
}
</MudSelect>
<MudButton Variant="Variant.Outlined" OnClick="AddRequiredContentTypeCritera">Add required contentype criteria</MudButton>
<MudButton Variant="Variant.Outlined" OnClick="AddNonRequiredContentTypeCritera">Add non required contentype criteria</MudButton>
<MudSelect Variant="Variant.Outlined" Label="Property name" Value="CriteriaPropertyName" ValueChanged="@(async (PropertyDefinition property) => await OnPropertyNameValueChanged(property))">
@if (CriteriaContentTypeID != 0)
{
var contentType = _contentTypeRepository.Load(CriteriaContentTypeID);
@foreach (var property in contentType.PropertyDefinitions)
{
<MudSelectItem Value="property">@property.Name</MudSelectItem>
}
}
</MudSelect>
<MudSelect Disabled="true" Variant="Variant.Outlined" @bind-Value="CriteriaPropertyDataType" Label="Property Data Type">
@foreach (var dataType in Enum.GetValues(typeof(PropertyDataType)).Cast<PropertyDataType>())
{
<MudSelectItem Value="dataType">@dataType</MudSelectItem>
}
</MudSelect>
<MudSelect Variant="Variant.Outlined" @bind-Value="CriteriaEvaluationCondion" Label="Compare Condition">
@foreach (var condition in Enum.GetValues(typeof(CompareCondition)).Cast<CompareCondition>())
{
<MudSelectItem Value="condition">@condition</MudSelectItem>
}
</MudSelect>
<MudTextField @bind-Value="CriteriaValue" Label="Value" Variant="Variant.Outlined"></MudTextField>
<MudCheckBox @bind-Value="CriteriaRequired">Required</MudCheckBox>
<MudButton Variant="Variant.Outlined" OnClick="AddCriteria">Add criteria</MudButton>
</MudStack>
</MudPaper>
</MudItem>
@* End Criteria builder*@
@* Start Visualize query and search*@
<MudItem xs="12" sm="3">
<MudPaper Class="d-flex align-items-start justify-center mud-width-full mud-height-full align-items-start ">
<MudStack Class="mud-width-full align-items-start">
<MudText Typo="Typo.h5">Search</MudText>
<MudButton Variant="Variant.Outlined" OnClick="ClearQriteriasAndResults">Clear</MudButton>
<MudButton Variant="Variant.Outlined" OnClick="Search">Search</MudButton>
<MudSelect Class="align-items-start" Variant="Variant.Outlined" @bind-Value="CriteriaSearchRoot" Label="Search Root">
<MudSelectItem Value="@ContentReference.Parse(ContentReference.RootPage.ToString())">Root</MudSelectItem>
@foreach (var site in _siteDefinitionRepository.List())
{
<MudSelectItem Value="@site.StartPage">@site.Name</MudSelectItem>
}
</MudSelect>
@foreach (var criteria in QueryCriterasCollection)
{
<MudChip Class="align-items-start" T="PropertyCriteria" Color="(criteria.Required ? Color.Success : Color.Default)" OnClose="@(async () => await RemoveCriteria(criteria))">
@criteria.Name @GetConditionString(criteria.Condition) @criteria.Value
</MudChip>
}
</MudStack>
</MudPaper>
</MudItem>
@* End Visualize query and search*@
@* Start Display results*@
<MudItem xs="12" sm="3">
<MudPaper Class="align-items-start d-flex justify-center mud-width-full mud-height-full">
<MudStack>
<MudText Typo="Typo.h5">Results</MudText>
@foreach (var searchHit in SearchResults)
{
<MudLink Href="@GetEditModeUrl(searchHit.ContentLink)" Target="_blank">@searchHit.Name</MudLink>
}
</MudStack>
</MudPaper>
</MudItem>
@* End Display results*@
@* Start perform action on result*@
<MudItem xs="12" sm="3">
<MudPaper Class="d-flex align-items-start justify-center mud-width-full mud-height-full">
<MudStack Class="mud-width-full align-items-start">
<MudText Typo="Typo.h5">Actions</MudText>
<MudButton Variant="Variant.Outlined">Publish</MudButton>
<MudButton Variant="Variant.Outlined">Unpublish</MudButton>
<MudButton Variant="Variant.Outlined">Move to waste basket</MudButton>
<MudButton Variant="Variant.Outlined">Delete</MudButton>
</MudStack>
</MudPaper>
</MudItem>
@* End perform action on result*@
</MudGrid>
@code {
public ContentReference? CriteriaSearchRoot { get; set; }
public PropertyDataType CriteriaPropertyDataType { get; set; }
public CompareCondition CriteriaEvaluationCondion { get; set; }
public int CriteriaContentTypeID { get; set; }
public PropertyDefinition CriteriaPropertyName { get; set; }
public string CriteriaValue { get; set; }
public bool CriteriaRequired { get; set; }
public List<PropertyDefinition> ContentTypePropertyDefinitions { get; set; } = new();
public PropertyCriteriaCollection QueryCriterasCollection { get; set; }
public PageDataCollection SearchResults { get; set; }
public List<ContentType> ContentTypesList { get; set; }
protected override void OnInitialized()
{
base.OnInitialized();
CriteriaSearchRoot = ContentReference.Parse(ContentReference.RootPage.ToString());
ContentTypesList = _contentTypeRepository.List().Where(t => t.Base.ToString().Contains("Page")).OrderBy(x => x.Name).ToList();
CriteriaContentTypeID = ContentTypesList.FirstOrDefault().ID;
QueryCriterasCollection = new();
SearchResults = new();
}
private void AddRequiredContentTypeCritera()
{
QueryCriterasCollection.Add(new PropertyCriteria
{
Name = "PageTypeID",
Condition = CompareCondition.Equal,
Type = PropertyDataType.PageType,
Value = CriteriaContentTypeID.ToString(),
Required = true
});
}
private void AddNonRequiredContentTypeCritera()
{
QueryCriterasCollection.Add(new PropertyCriteria
{
Name = "PageTypeID",
Condition = CompareCondition.Equal,
Type = PropertyDataType.PageType,
Value = CriteriaContentTypeID.ToString(),
Required = false
});
}
private void AddCriteria()
{
QueryCriterasCollection.Add(new PropertyCriteria
{
Name = CriteriaPropertyName.Name,
Condition = CriteriaEvaluationCondion,
Type = CriteriaPropertyDataType,
Value = CriteriaValue,
Required = CriteriaRequired
});
}
private async Task RemoveCriteria(PropertyCriteria criteria)
{
if (QueryCriterasCollection.Contains(criteria))
{
QueryCriterasCollection.Remove(criteria);
StateHasChanged(); // Notify Blazor that the state has changed
}
}
private void ClearQriteriasAndResults()
{
QueryCriterasCollection.Clear();
SearchResults.Clear();
StateHasChanged();
}
private void Search()
{
var searchCriterias = new PropertyCriteriaCollection();
foreach (var criteria in QueryCriterasCollection)
{
searchCriterias.Add(new PropertyCriteria
{
Name = criteria.Name,
Condition = criteria.Condition,
Type = criteria.Type,
Value = criteria.Value,
Required = criteria.Required
}
);
}
SearchResults = _pageCriteriaQueryService.FindPagesWithCriteria(CriteriaSearchRoot.ToPageReference(), searchCriterias);
StateHasChanged();
}
private async Task OnContentTypeValueChanged(int contentTypeID)
{
CriteriaContentTypeID = contentTypeID;
LoadPropertyDefinitions();
}
private async Task OnPropertyNameValueChanged(PropertyDefinition propertyDefinition)
{
if (propertyDefinition.Type != null)
{
CriteriaPropertyDataType = GetPropertyDataType(propertyDefinition.Type.Name);
CriteriaPropertyName = propertyDefinition;
}
}
private void LoadPropertyDefinitions()
{
if (CriteriaContentTypeID != 0)
{
var contentType = _contentTypeRepository.Load(CriteriaContentTypeID);
ContentTypePropertyDefinitions = contentType.PropertyDefinitions.ToList();
CriteriaPropertyName = ContentTypePropertyDefinitions.FirstOrDefault();
StateHasChanged();
}
else
{
ContentTypePropertyDefinitions.Clear();
}
}
private string GetConditionString(CompareCondition condition)
{
return condition switch
{
CompareCondition.Equal => "=",
CompareCondition.NotEqual => "!=",
CompareCondition.GreaterThan => ">",
CompareCondition.LessThan => "<",
CompareCondition.Contained => "<contains>",
CompareCondition.StartsWith => "^=",
CompareCondition.EndsWith => "$=",
_ => "UNKNOWN"
};
}
private PropertyDataType GetPropertyDataType(string type)
{
return type switch
{
"String" => PropertyDataType.String,
"Boolean" => PropertyDataType.Boolean,
"DateTime" => PropertyDataType.Date,
"Double" => PropertyDataType.FloatNumber,
"Integer" => PropertyDataType.Number,
"LongString" => PropertyDataType.LongString,
"ContentReference" => PropertyDataType.ContentReference,
"XhtmlString" => PropertyDataType.LongString,
_ => PropertyDataType.String,
};
}
private string GetEditModeUrl(ContentReference contentLink)
{
return PageEditing.GetEditUrl(contentLink);
}
public class PageDataSearchHit : PageData
{
public bool Selected { get; set; }
}
}
@PNergard
Copy link
Author

PNergard commented Feb 3, 2025

Optimizely Blazor component that lets you visually create PageCriteraQueries and execute them in Visaul tool.

  • Add required / non required paramers for contenttype, properties with all built in comparison types and run query on any of your solution defined sites.

How to use

Two good resources to get you started with optimizely and Blazor

MudBlazor

https://mudblazor.com/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment