Skip to content

Commit

Permalink
Improving workflows page load time (#13680)
Browse files Browse the repository at this point in the history
  • Loading branch information
wAsnk authored Jul 18, 2023
1 parent f6d7676 commit d063766
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ public async Task<IActionResult> Index(int workflowTypeId, WorkflowIndexViewMode

var workflowType = await _workflowTypeStore.GetAsync(workflowTypeId);

var query = _session.Query<Workflow, WorkflowIndex>();
query = query.Where(x => x.WorkflowTypeId == workflowType.WorkflowTypeId);
var query = _session.QueryIndex<WorkflowIndex>()
.Where(x => x.WorkflowTypeId == workflowType.WorkflowTypeId);

switch (model.Options.Filter)
{
Expand Down Expand Up @@ -123,14 +123,14 @@ public async Task<IActionResult> Index(int workflowTypeId, WorkflowIndexViewMode
var pagerShape = (await New.Pager(pager)).TotalItemCount(await query.CountAsync()).RouteData(routeData);
var pageOfItems = await query.Skip(pager.GetStartIndex()).Take(pager.PageSize).ListAsync();

var workflowIds = pageOfItems.Select(item => item.WorkflowId);
var workflows = await _session.Query<Workflow, WorkflowIndex>(item => item.WorkflowId.IsIn(workflowIds))
.ListAsync();

var viewModel = new WorkflowIndexViewModel
{
WorkflowType = workflowType,
Workflows = pageOfItems.Select(x => new WorkflowEntry
{
Workflow = x,
Id = x.Id
}).ToList(),
Workflows = workflows.Select(x => new WorkflowEntry { Workflow = x, Id = x.Id }).ToList(),
Options = model.Options,
Pager = pagerShape,
ReturnUrl = returnUrl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Dapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Localization;
Expand All @@ -13,6 +14,7 @@
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using OrchardCore.Admin;
using OrchardCore.Data;
using OrchardCore.DisplayManagement;
using OrchardCore.DisplayManagement.ModelBinding;
using OrchardCore.DisplayManagement.Notify;
Expand Down Expand Up @@ -124,11 +126,16 @@ public async Task<IActionResult> Index(WorkflowTypeIndexOptions options, PagerPa
.Take(pager.PageSize)
.ListAsync();

var workflowTypeIds = workflowTypes.Select(x => x.WorkflowTypeId).ToList();
var workflowGroups = (await _session.QueryIndex<WorkflowIndex>(x => x.WorkflowTypeId.IsIn(workflowTypeIds))
.ListAsync())
.GroupBy(x => x.WorkflowTypeId)
.ToDictionary(x => x.Key);
var connection = await _session.CreateConnectionAsync();

var dialect = _session.Store.Configuration.SqlDialect;
var sqlBuilder = dialect.CreateBuilder(_session.Store.Configuration.TablePrefix);
sqlBuilder.Select();
sqlBuilder.Distinct();
sqlBuilder.Selector(nameof(WorkflowIndex.WorkflowTypeId));
sqlBuilder.Table(nameof(WorkflowIndex), alias: null, _session.Store.Configuration.Schema);

var workflowTypeIdsWithInstances = await connection.QueryAsync<string>(sqlBuilder.ToSqlString());

// Maintain previous route data when generating page links.
var routeData = new RouteData();
Expand All @@ -144,16 +151,20 @@ public async Task<IActionResult> Index(WorkflowTypeIndexOptions options, PagerPa
{
WorkflowType = x,
Id = x.Id,
WorkflowCount = workflowGroups.ContainsKey(x.WorkflowTypeId) ? workflowGroups[x.WorkflowTypeId].Count() : 0,
HasInstances = workflowTypeIdsWithInstances.Contains(x.WorkflowTypeId),
Name = x.Name
})
.ToList(),
Options = options,
Pager = pagerShape
};

model.Options.WorkflowTypesBulkAction = new List<SelectListItem>() {
new SelectListItem() { Text = S["Delete"].Value, Value = nameof(WorkflowTypeBulkAction.Delete) }
model.Options.WorkflowTypesBulkAction = new List<SelectListItem>()
{
new SelectListItem()
{
Text = S["Delete"].Value, Value = nameof(WorkflowTypeBulkAction.Delete)
}
};

return View(model);
Expand All @@ -163,8 +174,11 @@ public async Task<IActionResult> Index(WorkflowTypeIndexOptions options, PagerPa
[FormValueRequired("submit.Filter")]
public ActionResult IndexFilterPOST(WorkflowTypeIndexViewModel model)
{
return RedirectToAction(nameof(Index), new RouteValueDictionary {
{ "Options.Search", model.Options.Search }
return RedirectToAction(nameof(Index), new RouteValueDictionary
{
{
"Options.Search", model.Options.Search
}
});
}

Expand All @@ -180,7 +194,8 @@ public async Task<IActionResult> BulkEdit(WorkflowTypeIndexOptions options, IEnu

if (itemIds?.Count() > 0)
{
var checkedEntries = await _session.Query<WorkflowType, WorkflowTypeIndex>().Where(x => x.DocumentId.IsIn(itemIds)).ListAsync();
var checkedEntries = await _session.Query<WorkflowType, WorkflowTypeIndex>()
.Where(x => x.DocumentId.IsIn(itemIds)).ListAsync();
switch (options.BulkAction)
{
case WorkflowTypeBulkAction.None:
Expand Down Expand Up @@ -217,8 +232,7 @@ public async Task<IActionResult> EditProperties(int? id, string returnUrl = null
{
return View(new WorkflowTypePropertiesViewModel
{
IsEnabled = true,
ReturnUrl = returnUrl
IsEnabled = true, ReturnUrl = returnUrl
});
}
else
Expand Down Expand Up @@ -280,10 +294,13 @@ public async Task<IActionResult> EditProperties(WorkflowTypePropertiesViewModel
await _workflowTypeStore.SaveAsync(workflowType);

return isNew
? RedirectToAction(nameof(Edit), new { workflowType.Id })
? RedirectToAction(nameof(Edit), new
{
workflowType.Id
})
: Url.IsLocalUrl(viewModel.ReturnUrl)
? (IActionResult)this.Redirect(viewModel.ReturnUrl, true)
: RedirectToAction(nameof(Index));
? (IActionResult)this.Redirect(viewModel.ReturnUrl, true)
: RedirectToAction(nameof(Index));
}

public async Task<IActionResult> Duplicate(int id, string returnUrl = null)
Expand Down Expand Up @@ -340,7 +357,10 @@ public async Task<IActionResult> Duplicate(WorkflowTypePropertiesViewModel viewM

await _workflowTypeStore.SaveAsync(workflowType);

return RedirectToAction(nameof(Edit), new { workflowType.Id });
return RedirectToAction(nameof(Edit), new
{
workflowType.Id
});
}

public async Task<IActionResult> Edit(int id, string localId)
Expand All @@ -361,8 +381,10 @@ public async Task<IActionResult> Edit(int id, string localId)

var workflow = _workflowManager.NewWorkflow(workflowType);
var workflowContext = await _workflowManager.CreateWorkflowExecutionContextAsync(workflowType, workflow);
var activityContexts = await Task.WhenAll(workflowType.Activities.Select(x => _workflowManager.CreateActivityExecutionContextAsync(x, x.Properties)));
var workflowCount = await _session.QueryIndex<WorkflowIndex>(x => x.WorkflowTypeId == workflowType.WorkflowTypeId).CountAsync();
var activityContexts = await Task.WhenAll(workflowType.Activities.Select(x =>
_workflowManager.CreateActivityExecutionContextAsync(x, x.Properties)));
var workflowCount = await _session
.QueryIndex<WorkflowIndex>(x => x.WorkflowTypeId == workflowType.WorkflowTypeId).CountAsync();

var activityThumbnailShapes = new List<dynamic>();
var index = 0;
Expand All @@ -377,7 +399,8 @@ public async Task<IActionResult> Edit(int id, string localId)

foreach (var activityContext in activityContexts)
{
activityDesignShapes.Add(await BuildActivityDisplay(activityContext, index++, id, newLocalId, "Design"));
activityDesignShapes.Add(await BuildActivityDisplay(activityContext, index++, id, newLocalId,
"Design"));
}

var activitiesDataQuery = activityContexts.Select(x => new
Expand All @@ -401,7 +424,11 @@ public async Task<IActionResult> Edit(int id, string localId)
var viewModel = new WorkflowTypeViewModel
{
WorkflowType = workflowType,
WorkflowTypeJson = JsonConvert.SerializeObject(workflowTypeData, Formatting.None, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }),
WorkflowTypeJson = JsonConvert.SerializeObject(workflowTypeData, Formatting.None,
new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
}),
ActivityThumbnailShapes = activityThumbnailShapes,
ActivityDesignShapes = activityDesignShapes,
ActivityCategories = _activityLibrary.ListCategories().ToList(),
Expand Down Expand Up @@ -462,7 +489,10 @@ from activityId in currentActivities.Keys
await _workflowTypeStore.SaveAsync(workflowType);
await _notifier.SuccessAsync(H["Workflow has been saved."]);

return RedirectToAction(nameof(Edit), new { id = model.Id });
return RedirectToAction(nameof(Edit), new
{
id = model.Id
});
}

[HttpPost]
Expand All @@ -486,26 +516,37 @@ public async Task<IActionResult> Delete(int id)
return RedirectToAction(nameof(Index));
}

private async Task<dynamic> BuildActivityDisplay(IActivity activity, int index, int workflowTypeId, string localId, string displayType)
private async Task<dynamic> BuildActivityDisplay(IActivity activity, int index, int workflowTypeId,
string localId, string displayType)
{
dynamic activityShape = await _activityDisplayManager.BuildDisplayAsync(activity, _updateModelAccessor.ModelUpdater, displayType);
dynamic activityShape =
await _activityDisplayManager.BuildDisplayAsync(activity, _updateModelAccessor.ModelUpdater,
displayType);
activityShape.Metadata.Type = $"Activity_{displayType}";
activityShape.Activity = activity;
activityShape.WorkflowTypeId = workflowTypeId;
activityShape.Index = index;
activityShape.ReturnUrl = Url.Action(nameof(Edit), new { id = workflowTypeId, localId = localId });
activityShape.ReturnUrl = Url.Action(nameof(Edit), new
{
id = workflowTypeId, localId = localId
});
return activityShape;
}

private async Task<dynamic> BuildActivityDisplay(ActivityContext activityContext, int index, int workflowTypeId, string localId, string displayType)
private async Task<dynamic> BuildActivityDisplay(ActivityContext activityContext, int index, int workflowTypeId,
string localId, string displayType)
{
dynamic activityShape = await _activityDisplayManager.BuildDisplayAsync(activityContext.Activity, _updateModelAccessor.ModelUpdater, displayType);
dynamic activityShape = await _activityDisplayManager.BuildDisplayAsync(activityContext.Activity,
_updateModelAccessor.ModelUpdater, displayType);
activityShape.Metadata.Type = $"Activity_{displayType}";
activityShape.Activity = activityContext.Activity;
activityShape.ActivityRecord = activityContext.ActivityRecord;
activityShape.WorkflowTypeId = workflowTypeId;
activityShape.Index = index;
activityShape.ReturnUrl = Url.Action(nameof(Edit), new { id = workflowTypeId, localId = localId });
activityShape.ReturnUrl = Url.Action(nameof(Edit), new
{
id = workflowTypeId, localId = localId
});
return activityShape;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class WorkflowTypeEntry
public bool IsChecked { get; set; }
public int Id { get; set; }
public string Name { get; set; }
public int WorkflowCount { get; set; }
public bool HasInstances { get; set; }
}

public class WorkflowTypeIndexOptions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@
{
<span class="badge text-danger"><i class="fa-solid fa-power-off" aria-hidden="true"></i> @T["Disabled"]</span>
}
@if (entry.WorkflowCount > 0)
@if (entry.HasInstances)
{
<a asp-action="Index" asp-controller="Workflow" asp-route-workflowtypeid="@entry.WorkflowType.Id" class="badge ta-badge"><i class="fa-solid fa-list-ol" aria-hidden="true"></i> @T.Plural(entry.WorkflowCount, "1 instance", "{0} instances")</a>
<a asp-action="Index" asp-controller="Workflow" asp-route-workflowtypeid="@entry.WorkflowType.Id" class="badge ta-badge"><i class="fa-solid fa-list-ol" aria-hidden="true"></i> @T["Instances"]</a>
}

<div class="metadata">
Expand Down

0 comments on commit d063766

Please sign in to comment.