mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Adding running workflows list view
--HG-- branch : 1.x
This commit is contained in:
@@ -120,8 +120,8 @@ namespace Orchard.Workflows.Activities {
|
||||
|
||||
|
||||
foreach (var action in awaiting) {
|
||||
var tokens = new Dictionary<string, object> { { "Content", _contentManager.Get(action.ContentItemRecord.Id, VersionOptions.Latest) } };
|
||||
var contentItem = _contentManager.Get(action.ContentItemRecord.Id, VersionOptions.Latest);
|
||||
var tokens = new Dictionary<string, object> { { "Content", _contentManager.Get(action.WorkflowRecord.ContentItemRecord.Id, VersionOptions.Latest) } };
|
||||
var contentItem = _contentManager.Get(action.WorkflowRecord.ContentItemRecord.Id, VersionOptions.Latest);
|
||||
var workflowState = FormParametersHelper.FromJsonString(action.WorkflowRecord.State);
|
||||
workflowState.TimerActivity_StartedUtc = null;
|
||||
action.WorkflowRecord.State = FormParametersHelper.ToJsonString(workflowState);
|
||||
|
@@ -25,6 +25,7 @@ namespace Orchard.Workflows.Controllers {
|
||||
public class AdminController : Controller, IUpdateModel {
|
||||
private readonly ISiteService _siteService;
|
||||
private readonly IRepository<WorkflowDefinitionRecord> _workflowDefinitionRecords;
|
||||
private readonly IRepository<WorkflowRecord> _workflowRecords;
|
||||
private readonly IActivitiesManager _activitiesManager;
|
||||
private readonly IFormManager _formManager;
|
||||
|
||||
@@ -33,11 +34,13 @@ namespace Orchard.Workflows.Controllers {
|
||||
IShapeFactory shapeFactory,
|
||||
ISiteService siteService,
|
||||
IRepository<WorkflowDefinitionRecord> workflowDefinitionRecords,
|
||||
IRepository<WorkflowRecord> workflowRecords,
|
||||
IActivitiesManager activitiesManager,
|
||||
IFormManager formManager
|
||||
) {
|
||||
_siteService = siteService;
|
||||
_workflowDefinitionRecords = workflowDefinitionRecords;
|
||||
_workflowRecords = workflowRecords;
|
||||
_activitiesManager = activitiesManager;
|
||||
_formManager = formManager;
|
||||
Services = services;
|
||||
@@ -107,6 +110,25 @@ namespace Orchard.Workflows.Controllers {
|
||||
return View(model);
|
||||
}
|
||||
|
||||
public ActionResult List(int id) {
|
||||
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to list workflows")))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
var contentItem = Services.ContentManager.Get(id, VersionOptions.Latest);
|
||||
|
||||
if (contentItem == null) {
|
||||
return HttpNotFound();
|
||||
}
|
||||
|
||||
var workflows = _workflowRecords.Table.Where(x => x.ContentItemRecord == contentItem.Record).ToList();
|
||||
|
||||
var viewModel = New.ViewModel(
|
||||
ContentItem: contentItem,
|
||||
Workflows: workflows
|
||||
);
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
public ActionResult Create() {
|
||||
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to create workflows")))
|
||||
return new HttpUnauthorizedResult();
|
||||
@@ -268,11 +290,14 @@ namespace Orchard.Workflows.Controllers {
|
||||
return HttpNotFound();
|
||||
}
|
||||
|
||||
IShape shape = New.Activity(activity);
|
||||
dynamic shape = New.Activity(activity);
|
||||
|
||||
if (model.State != null) {
|
||||
var dynamicState = FormParametersHelper.ToDynamic(FormParametersHelper.ToString(model.State));
|
||||
((dynamic)shape).State(dynamicState);
|
||||
var state = FormParametersHelper.ToDynamic(FormParametersHelper.ToString(model.State));
|
||||
shape.State(state);
|
||||
}
|
||||
else {
|
||||
shape.State(FormParametersHelper.FromJsonString("{}"));
|
||||
}
|
||||
|
||||
shape.Metadata.Alternates.Add("Activity__" + activity.Name);
|
||||
|
@@ -47,7 +47,7 @@ namespace Orchard.Workflows.Drivers {
|
||||
var workContext = _workContextAccessor.GetContext();
|
||||
var user = workContext.CurrentUser;
|
||||
|
||||
var awaiting = _awaitingActivityRepository.Table.Where(x => x.ContentItemRecord == part.ContentItem.Record && x.ActivityRecord.Name == "UserTask").ToList();
|
||||
var awaiting = _awaitingActivityRepository.Table.Where(x => x.WorkflowRecord.ContentItemRecord == part.ContentItem.Record && x.ActivityRecord.Name == "UserTask").ToList();
|
||||
var actions = awaiting.Where(x => UserIsInRole(x, user)).SelectMany(ListAction).ToList();
|
||||
|
||||
return shapeHelper.UserTask_ActionButton().Actions(actions);
|
||||
@@ -87,7 +87,7 @@ namespace Orchard.Workflows.Drivers {
|
||||
|
||||
var user = Services.WorkContext.CurrentUser;
|
||||
|
||||
var awaiting = _awaitingActivityRepository.Table.Where(x => x.ContentItemRecord == part.ContentItem.Record && x.ActivityRecord.Name == "UserTask").ToList();
|
||||
var awaiting = _awaitingActivityRepository.Table.Where(x => x.WorkflowRecord.ContentItemRecord == part.ContentItem.Record && x.ActivityRecord.Name == "UserTask").ToList();
|
||||
var actions = awaiting.Where(x => UserIsInRole(x, user)).SelectMany(ListAction).ToList();
|
||||
|
||||
if (!actions.Contains(name)) {
|
||||
|
@@ -7,13 +7,13 @@ using Orchard.Workflows.Models;
|
||||
|
||||
namespace Orchard.Workflows.Drivers {
|
||||
public class WorkflowDriver : ContentPartDriver<CommonPart> {
|
||||
private readonly IRepository<AwaitingActivityRecord> _awaitingActivityRepository;
|
||||
private readonly IRepository<WorkflowRecord> _workflowRepository;
|
||||
|
||||
public WorkflowDriver(
|
||||
IOrchardServices services,
|
||||
IRepository<AwaitingActivityRecord> awaitingActivityRepository
|
||||
IRepository<WorkflowRecord> workflowRepository
|
||||
) {
|
||||
_awaitingActivityRepository = awaitingActivityRepository;
|
||||
_workflowRepository = workflowRepository;
|
||||
T = NullLocalizer.Instance;
|
||||
Services = services;
|
||||
}
|
||||
@@ -27,8 +27,8 @@ namespace Orchard.Workflows.Drivers {
|
||||
|
||||
protected override DriverResult Display(CommonPart part, string displayType, dynamic shapeHelper) {
|
||||
return ContentShape("Parts_Workflow_SummaryAdmin", () => {
|
||||
var awaiting = _awaitingActivityRepository.Table.Where(x => x.ContentItemRecord == part.ContentItem.Record).ToList();
|
||||
return shapeHelper.Parts_Workflow_SummaryAdmin().Activities(awaiting.Select(x => x.ActivityRecord));
|
||||
var workflows = _workflowRepository.Table.Where(x => x.ContentItemRecord == part.ContentItem.Record).Distinct().ToList();
|
||||
return shapeHelper.Parts_Workflow_SummaryAdmin().Workflows(workflows);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Handlers;
|
||||
using Orchard.Data;
|
||||
@@ -10,17 +9,16 @@ namespace Orchard.Workflows.Handlers {
|
||||
public class WorkflowHandler : ContentHandler {
|
||||
|
||||
public WorkflowHandler(
|
||||
IRepository<AwaitingActivityRecord> awaitingActivityRepository,
|
||||
IRepository<WorkflowRecord> workflowRepository
|
||||
) {
|
||||
|
||||
// Delete any pending workflow related to a deleted content item
|
||||
OnRemoving<ContentPart>(
|
||||
(context, part) => {
|
||||
var awaiting = awaitingActivityRepository.Table.Where(x => x.ContentItemRecord == context.ContentItemRecord).ToList();
|
||||
var workflows = workflowRepository.Table.Where(x => x.ContentItemRecord == context.ContentItemRecord).ToList();
|
||||
|
||||
foreach (var item in awaiting) {
|
||||
workflowRepository.Delete(item.WorkflowRecord);
|
||||
foreach (var item in workflows) {
|
||||
workflowRepository.Delete(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@@ -19,7 +19,8 @@ namespace Orchard.Workflows {
|
||||
.Column<int>("Id", column => column.PrimaryKey().Identity())
|
||||
.Column<string>("State", column => column.Unlimited())
|
||||
.Column<int>("WorkflowDefinitionRecord_id")
|
||||
);
|
||||
.Column<int>("ContentItemRecord_id")
|
||||
);
|
||||
|
||||
// Creating table WorkflowDefinitionRecord
|
||||
SchemaBuilder.CreateTable("WorkflowDefinitionRecord", table => table
|
||||
@@ -32,7 +33,6 @@ namespace Orchard.Workflows {
|
||||
SchemaBuilder.CreateTable("AwaitingActivityRecord", table => table
|
||||
.Column<int>("Id", column => column.PrimaryKey().Identity())
|
||||
.Column<int>("ActivityRecord_id")
|
||||
.Column<int>("ContentItemRecord_id")
|
||||
.Column<int>("WorkflowRecord_id")
|
||||
);
|
||||
|
||||
|
@@ -1,13 +1,9 @@
|
||||
using Orchard.ContentManagement.Records;
|
||||
|
||||
namespace Orchard.Workflows.Models {
|
||||
namespace Orchard.Workflows.Models {
|
||||
public class AwaitingActivityRecord {
|
||||
public virtual int Id { get; set; }
|
||||
|
||||
public virtual ActivityRecord ActivityRecord { get; set; }
|
||||
|
||||
public virtual ContentItemRecord ContentItemRecord { get; set; }
|
||||
|
||||
// Parent property
|
||||
public virtual WorkflowRecord WorkflowRecord { get; set; }
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Orchard.ContentManagement.Records;
|
||||
using Orchard.Data.Conventions;
|
||||
|
||||
namespace Orchard.Workflows.Models {
|
||||
@@ -25,6 +26,11 @@ namespace Orchard.Workflows.Models {
|
||||
[CascadeAllDeleteOrphan]
|
||||
public virtual IList<AwaitingActivityRecord> AwaitingActivities { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The associated content item
|
||||
/// </summary>
|
||||
public virtual ContentItemRecord ContentItemRecord { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Parent <see cref="WorkflowDefinitionRecord"/>
|
||||
/// </summary>
|
||||
|
@@ -4,6 +4,7 @@ Author: The Orchard Team
|
||||
Website: http://orchardproject.net
|
||||
Version: 1.0
|
||||
OrchardVersion: 1.0
|
||||
Category: Content
|
||||
Description: Description for the module
|
||||
Features:
|
||||
Orchard.Workflows:
|
||||
|
@@ -71,6 +71,7 @@
|
||||
<Content Include="Scripts\jquery.jsPlumb-1.3.16-all-min.js" />
|
||||
<Content Include="Scripts\orchard-workflows-serialize.js" />
|
||||
<Content Include="Scripts\orchard-workflows.js" />
|
||||
<Content Include="Styles\images\cog.png" />
|
||||
<Content Include="Styles\workflows-activity-delete-publish.css" />
|
||||
<Content Include="Styles\workflows-activity-timer.css" />
|
||||
<Content Include="Styles\workflows-activity-branch.css" />
|
||||
@@ -203,7 +204,7 @@
|
||||
<Content Include="Views\Activity-IsInRole.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Styles\images\" />
|
||||
<Content Include="Views\Admin\List.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\Activity-SendEmail.cshtml" />
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<Placement>
|
||||
<Match DisplayType="SummaryAdmin">
|
||||
<Place Parts_Workflow_SummaryAdmin="Meta:5"/>
|
||||
<Place Parts_Workflow_SummaryAdmin="Meta:2"/>
|
||||
</Match>
|
||||
|
||||
<Place UserTask_ActionButton="Sidebar:24.1"/>
|
||||
|
@@ -66,7 +66,7 @@ namespace Orchard.Workflows.Services {
|
||||
// it's important to return activities at this point as a workflow could be awaiting
|
||||
// on several ones. When an activity is restarted, all the other ones of the same workflow are cancelled.
|
||||
awaitingActivities.AddRange(_awaitingActivityRepository.Table.Where(
|
||||
x => x.ActivityRecord.Name == name && x.ActivityRecord.Start == false && x.ContentItemRecord == target.ContentItem.Record
|
||||
x => x.ActivityRecord.Name == name && x.ActivityRecord.Start == false && x.WorkflowRecord.ContentItemRecord == target.ContentItem.Record
|
||||
).ToList()
|
||||
);
|
||||
|
||||
@@ -139,7 +139,8 @@ namespace Orchard.Workflows.Services {
|
||||
// workflow halted, create a workflow state
|
||||
var workflow = new WorkflowRecord {
|
||||
WorkflowDefinitionRecord = activityRecord.WorkflowDefinitionRecord,
|
||||
State = "{}"
|
||||
State = "{}",
|
||||
ContentItemRecord = workflowContext.Content.ContentItem.Record
|
||||
};
|
||||
|
||||
workflowContext.Record = workflow;
|
||||
@@ -169,7 +170,6 @@ namespace Orchard.Workflows.Services {
|
||||
foreach (var blocking in blockedOn) {
|
||||
workflow.AwaitingActivities.Add(new AwaitingActivityRecord {
|
||||
ActivityRecord = blocking,
|
||||
ContentItemRecord = workflowContext.Content.ContentItem.Record
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -205,7 +205,6 @@ namespace Orchard.Workflows.Services {
|
||||
foreach (var blocking in blockedOn) {
|
||||
workflow.AwaitingActivities.Add(new AwaitingActivityRecord {
|
||||
ActivityRecord = blocking,
|
||||
ContentItemRecord = workflowContext.Content.ContentItem.Record
|
||||
});
|
||||
}
|
||||
}
|
||||
|
BIN
src/Orchard.Web/Modules/Orchard.Workflows/Styles/images/cog.png
Normal file
BIN
src/Orchard.Web/Modules/Orchard.Workflows/Styles/images/cog.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 348 B |
@@ -2,8 +2,12 @@
|
||||
|
||||
@{
|
||||
string name = Model.Name;
|
||||
string notification = Model.State.Notification;
|
||||
string message = Model.State.Message;
|
||||
|
||||
string description = String.IsNullOrEmpty(notification) ? "" : T("{0}: {1}", notification, message).ToString();
|
||||
}
|
||||
|
||||
<div class="activity-notify" title="@Model.State.Notification: @Model.State.Message">
|
||||
<div class="activity-notify" title="@description">
|
||||
<div>@name.CamelFriendly()</div>
|
||||
</div>
|
||||
|
@@ -74,7 +74,7 @@
|
||||
@Html.Hidden("localId", Model.LocalId)
|
||||
@Html.Hidden("data", String.Empty)
|
||||
|
||||
@Html.Hidden("confirm-delete-activity", T("Delete activity ?"))
|
||||
@Html.Hidden("confirm-delete-activity", T("Are you sure you want to remove this activity?"))
|
||||
|
||||
using (Script.Foot()) {
|
||||
<script type="text/javascript">
|
||||
|
@@ -1,5 +1,4 @@
|
||||
@model Orchard.Workflows.ViewModels.AdminIndexViewModel
|
||||
@using Orchard.Workflows.Models;
|
||||
@model AdminIndexViewModel
|
||||
@using Orchard.Workflows.ViewModels;
|
||||
|
||||
@{
|
||||
@@ -12,10 +11,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
<h1>@Html.TitleForPage(T("Manage Workflows").ToString()) </h1>
|
||||
<h1>@Html.TitleForPage(T("Manage Workflow Definitions").ToString()) </h1>
|
||||
@using (Html.BeginFormAntiForgeryPost()) {
|
||||
@Html.ValidationSummary()
|
||||
<div class="manage">@Html.ActionLink(T("Create new Wokflow").ToString(), "Create", new { Area = "Orchard.Workflows", returnurl = HttpContext.Current.Request.RawUrl }, new { @class = "button primaryAction" })</div>
|
||||
<div class="manage">@Html.ActionLink(T("Create new Wokflow Definition").ToString(), "Create", new { Area = "Orchard.Workflows", returnurl = HttpContext.Current.Request.RawUrl }, new { @class = "button primaryAction" })</div>
|
||||
|
||||
<fieldset class="bulk-actions">
|
||||
<label for="publishActions">@T("Actions:")</label>
|
||||
@@ -46,6 +45,7 @@
|
||||
<tr>
|
||||
<th scope="col" class="checkbox"> ↓</th>
|
||||
<th scope="col">@T("Name")</th>
|
||||
<th scope="col"> </th>
|
||||
<th scope="col" class="actions"> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -58,6 +58,12 @@
|
||||
<td>
|
||||
@Html.ActionLink(entry.Name, "Edit", new { id = entry.WokflowDefinitionId })
|
||||
</td>
|
||||
<td>
|
||||
@if (entry.WorkflowDefinitionRecord.WorkflowRecords.Any()) {
|
||||
@T("{0} Running", entry.WorkflowDefinitionRecord.WorkflowRecords.Count)
|
||||
}
|
||||
|
||||
</td>
|
||||
<td>
|
||||
@* TODO: As WD is not a Content Item, an EditProperties action is necessary @Html.ActionLink(T("Properties").ToString(), "Edit", new { Area = "Contents", id = entry.WokflowDefinitionId, returnurl = HttpContext.Current.Request.RawUrl }) |*@
|
||||
@Html.ActionLink(T("Edit").ToString(), "Edit", new { id = entry.WokflowDefinitionId }) |
|
||||
|
@@ -0,0 +1,38 @@
|
||||
@using Orchard.Utility.Extensions
|
||||
@using Orchard.Workflows.Models
|
||||
<h1>@Html.TitleForPage(T("Running workflows").ToString()) </h1>
|
||||
|
||||
<fieldset>
|
||||
<table class="items">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="checkbox"> ↓</th>
|
||||
<th scope="col">@T("Worfklow Definition")</th>
|
||||
<th scope="col">Blocking activities</th>
|
||||
<th scope="col" class="actions"> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
@foreach (WorkflowRecord workflow in Model.Workflows) {
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
@Html.ActionLink(workflow.WorkflowDefinitionRecord.Name, "Edit", new { id = workflow.WorkflowDefinitionRecord.Id })
|
||||
</td>
|
||||
<td>
|
||||
@foreach (AwaitingActivityRecord awaiting in workflow.AwaitingActivities) {
|
||||
@awaiting.ActivityRecord.Name.CamelFriendly()
|
||||
<br/>
|
||||
}
|
||||
|
||||
</td>
|
||||
<td>
|
||||
@*@Html.ActionLink(T("Edit").ToString(), "EditWorkflow", new { id = workflow.Id })*@ |
|
||||
@*@Html.ActionLink(T("Delete").ToString(), "DeleteWorkflow", new { id = workflow.Id }, new { itemprop = "RemoveUrl UnsafeUrl" })*@
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</table>
|
||||
</fieldset>
|
||||
|
@@ -1,10 +1,14 @@
|
||||
@{
|
||||
IEnumerable<Orchard.Workflows.Models.ActivityRecord> activities = Model.Activities;
|
||||
IEnumerable<Orchard.Workflows.Models.WorkflowRecord> activities = Model.Workflows;
|
||||
var count = activities.Count();
|
||||
}
|
||||
|
||||
@if (count > 0) {
|
||||
<div>
|
||||
@T("{0} active workflow(s)", count)
|
||||
</div>
|
||||
<ul class="pageStatus">
|
||||
<li title="@T("Running workflows")" >
|
||||
<img class="icon" src="@Href("~/Modules/Orchard.Workflows/Styles/Images/cog.png")" alt="@T("Running ({0})", count)" />
|
||||
@T("Running ({0})", count)
|
||||
|
|
||||
</li>
|
||||
</ul>
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@ Website: http://orchardproject.net
|
||||
Version: 1.6
|
||||
OrchardVersion: 1.6
|
||||
Description: Description for the module
|
||||
Category: Developer
|
||||
Features:
|
||||
UpgradeTo16:
|
||||
Description: Description for feature UpgradeTo16.
|
||||
|
Reference in New Issue
Block a user