symbiote / silverstripe-advancedworkflow

A highly configurable step-based workflow module.
BSD 3-Clause "New" or "Revised" License
47 stars 71 forks source link

Usability: Embargo/Expiry #47

Open LukePercy opened 12 years ago

LukePercy commented 12 years ago

Some Usability Adjustments:

  1. Label each field appropriately and separately

Embargo: 'Select Publish date'

'Select Publish time'

Expiry: 'Select Un-publish date'

'Select Un-publish time'

  1. Add Time Picker to time field to assist in data entry and format required. Currently a text field, this should probably have a time picker drop down of some sort.
  2. "Click "Save Draft" to save changes" instruction.
  3. Add an additional button/indication when a page is under Embargo preventing early Publishing. Additionally a Content Publisher would need to be able to 'Remove' an embargo in this state - rather than editing date/time to null

Maintainer note: See framework commit 585a8bc "Removed 'showdropdown' option from TimeField, use custom libraries instead (Ingo Schommer)" This is why a dropdown no-longer shows for this workflow functionality.

hafriedlander commented 12 years ago

Before we can come up with a solution we have to think about what the customer requirements are:

With that in mind, there's (at least) a couple of ways to approach this problem technically:

1) Right now any page in a workflow transitions from WorkflowAction to WorkflowAction via manual control. You could extend this to allow transition on a schedule. By setting a transition to only move to publish after a certain date you can implement embargo.

Implementing expiry this way is a bit trickier. Effectively expiry can be seen as an embargoed change set to happen on the expiry date, where the embargoed change is either "revert to old version" or "remove page from live". Or we can have pages maintain their workflow state indefinitely, so that a page version can move in and out of published state multiple times, and implement expiry as another transition

2) We could ignore advancedworkflow entirely. Treat embargo / expiry as an extension to Versioned instead, where instead of "publishing" from Page_versions to Page, publishing consists of updating a timeline which defines what version should be live on a particular date.

3) We could provide an underlying API that both modules hook into

An uncovered issue: how does the UI for this look? How do we clearly convey to administrators when changes will happen, and what they'll look like.

My personal feeling:

Deal with expiry has embargoed change to a newer version, not as a separate concept

Extend the Page_versions table to include a date to be published on. When that date passes, update live Page table to have that new version

Show in the tree the upcoming versions, like:

When using advancedworkflow, each pending version will have it's own workflow like:

Instead of having embargo / expiry dates, each action can be performed in the future, i.e.

Save & Publish Save & Publish On.... Delete from Live Delete from Live On...

Internally implemented by providing IsPublishedInterface which both expiry/embargo & advancedworkflow would hook into. Example implementation:

class ExpiryEmbargo implements IsPublishedInterface {
  static $version_fields = array(
    'LiveFrom' => 'Date',
    'LiveTo' => 'Date'
  );

  function IsLive($version) {
    return $version->LiveFrom <= time() && $version->LiveTo >= time();
  }

  function LiveDescription($version) {
    return "from ".$version->LiveFrom;
  }
}
smagnusson commented 12 years ago

Good points and I like your thinking. One additional layer of complexity is that the embargo and expiry dates would be requested then approved.

E.g. the button would effectively need to provide this label's functionality: "(I request that Hamish, my manager, will) Save & Publish On…."

in other words... "Request Publish for date…."

This therefore means that when the manager gets the response, the date has been pre-filled.

I'm pretty sure some of our customers (like one that flies planes) use the above concept already in SSv2 (that you can seek a date for adding or removing a page, for your manager to enact.)

Sig

On 14 November 2012 15:07, Hamish Friedlander notifications@github.comwrote:

Before we can come up with a solution we have to think about what the customer requirements are:

-

When you set an embargo, what does it mean? Does the existing page (if their is one) remain until the embargo passes, or does the page disappear / become unaccessible until the embargo date? Can you have more than one embargoed version? What happens if you need to fix a spelling mistake on the current live page when there's a newer version under embargo - do you have to discard your pending changes (which might be difficult to replicate later) in order to fix the current issue?

When you set an expiry, what happens once the expiry passes? Does it revert back to the previous version? Or to a newer version? Or just disappear / become unaccessible?

With that in mind, there's (at least) a couple of ways to approach this problem technically:

1) Right now any page in a workflow transitions from WorkflowAction to WorkflowAction via manual control. You could extend this to allow transition on a schedule. By setting a transition to only move to publish after a certain date you can implement embargo.

Implementing expiry this way is a bit trickier. Effectively expiry can be seen as an embargoed change set to happen on the expiry date, where the embargoed change is either "revert to old version" or "remove page from live". Or we can have pages maintain their workflow state indefinitely, so that a page version can move in and out of published state multiple times, and implement expiry as another transition

2) We could ignore advancedworkflow entirely. Treat embargo / expiry as an extension to Versioned instead, where instead of "publishing" from Page_versions to Page, publishing consists of updating a timeline which defines what version should be live on a particular date.

3) We could provide an underlying API that both modules hook into

An uncovered issue: how does the UI for this look? How do we clearly convey to administrators when changes will happen, and what they'll look like.

My personal feeling:

Deal with expiry has embargoed change to a newer version, not as a separate concept

Extend the Page_versions table to include a date to be published on. When that date passes, update live Page table to have that new version

Show in the tree the upcoming versions, like:

  • Home
  • About
    • About (from 1 Feb)
    • About Us (from 10 Feb)
    • (from 20 Feb)

When using advancedworkflow, each pending version will have it's own workflow like:

  • About
    • About (from 1 Feb)
    • About Us (from 10 Feb, currently pending approval by Editor)
    • (from 20 Feb)

Instead of having embargo / expiry dates, each action can be performed in the future, i.e.

Save & Publish Save & Publish On.... Delete from Live Delete from Live On...

Internally implemented by providing IsPublishedInterface which both expiry/embargo & advancedworkflow would hook into. Example implementation:

class ExpiryEmbargo implements IsPublishedInterface { static $version_fields = array( 'LiveFrom' => 'Date', 'LiveTo' => 'Date' );

function IsLive($version) { return $version->LiveFrom <= time() && $version->LiveTo >= time(); }

function LiveDescription($version) { return "from ".$version->LiveFrom; }}

— Reply to this email directly or view it on GitHubhttps://github.com/silverstripe-australia/advancedworkflow/issues/47#issuecomment-10352477.

Sigurd Magnusson Business Relationship Manager SilverStripe

DDI: +64 4 978 7332 Mobile: (NZ): +64 21 42 12 08 Skype: sigurdmagnusson twitter.com/SigurdMagnusson www.silverstripe.com

nyeholt commented 12 years ago

I kind of like the idea of having an effective_from effective_to field pair on versioned; theoretically it shouldn't be tooo tough to make use of these for viewing Stage content.

One possibility is that as soon as someone sets a future publish/expire date, a 'future' version is created, and a 'now' version (ie what exists in the base table) is recreated from live content

How would changes to 'now' content be then merged into 'future' version (this is basically the same problem as the 'minor edit before the future publish date' problem you raised Hamish)? Would it be something that the user is notified about to make sure they're updating changes manually? What about fields that are set programmatically?

A couple of thoughts -

hafriedlander commented 12 years ago

Probably not that many cases where there are multiple changes, except in the case where Expiry becomes a second Embargoed change, which is probably the easiest way to deal with the various things you might want to do after Expiry.

As far as creating "now" content, I was thinking the logic for finding the "current" live version would just be stepping back from the most recent version, checking for validity on each version until we find one that is - if expiry isn't set, a version would be valid from the embargo date onwards, and vice versa. If neither is set, it's valid forever. This does mean we'd need to handle deleting by explicitly adding a "deleted" record to the versions table though, since we couldn't just use presence in the live table to determine deletion.

Splitting Versioned would be fun but hard. Publishable is a simpler case of the more generic workflow / acts as state machine design. You could have each version travel through a state machine where some states are "published", and then the current live version is the most recent version that is in a "published" state.

hafriedlander commented 12 years ago

Thinking about it, it'd have to travel through multiple state machines. One would be workflow (or just publish), one would be embargo / expiry. A version would only be live if all state machies were in published states.

Not pictured is how we trigger transitions from one state to the other on a schedule. It feels like an event system would be nicest, so you could also transition in all sorts of situations (when 1000 members have signed up, when a particular data object has a field set in a particular way).

smagnusson commented 12 years ago

Context, probably obvious, from a user perspective. Seems what you guys are talking about supports all of this, but I basically see two a half scenarios.

  1. Embargo; normally used for a news item or press release to go live 9am Monday Next Week.
  2. Expiry: normally used for a page describing a promotion (e.g. 42" Flatscreen TV only $999 until midnight Friday) - then page is removed.

2.5: In the case you want to make the $999 TV deal turn into an insane $899 deal or return to the 'old price' of $1299 effective midnight Friday, I assume you would use embargo on an already published page.

On 14 November 2012 15:54, Hamish Friedlander notifications@github.comwrote:

Probably not that many cases where there are multiple changes, except in the case where Expiry becomes a second Embargoed change, which is probably the easiest way to deal with the various things you might want to do after Expiry.

As far as creating "now" content, I was thinking the logic for finding the "current" live version would just be stepping back from the most recent version, checking for validity on each version until we find one that is - if expiry isn't set, a version would be valid from the embargo date onwards, and vice versa. If neither is set, it's valid forever. This does mean we'd need to handle deleting by explicitly adding a "deleted" record to the versions table though, since we couldn't just use presence in the live table to determine deletion.

Splitting Versioned would be fun but hard. Publishable is a simpler case of the more generic workflow / acts as state machine design. You could have each version travel through a state machine where some states are "published", and then the current live version is the most recent version that is in a "published" state.

— Reply to this email directly or view it on GitHubhttps://github.com/silverstripe-australia/advancedworkflow/issues/47#issuecomment-10353350.

Sigurd Magnusson Business Relationship Manager SilverStripe

DDI: +64 4 978 7332 Mobile: (NZ): +64 21 42 12 08 Skype: sigurdmagnusson twitter.com/SigurdMagnusson www.silverstripe.com

phptek commented 11 years ago

The solutions suggested thus far, appear to be good but are particularly difficult and time-consuming to implement (howsoever "proper" each solution appears to be).

Note the embargo/expiry functionality that comes out of the box (along with enabling the QueuedJobs module) takes care of a bog-standard implementation, but is admittedly rather crude in comparison with some of the suggestions above.

As far as Sig's requirements go, the ability to simply "enable" and "disable" the published state of a content-object based on future dates, will suffice given a few UI tweaks.

So my middle-ground proposals are as follows, and comprise augmenting the existing WorkflowEmbargoExpiryExtension functionality - apologies if I'm simply re-wording what has already been suggested and claiming as my own :-P

1).

The provision of a DropDownField on WorkflowEmbargoExpiryExtension comprising a list of all versions of the current content-object. When selected and saved, publishes that object at that version when the expiry date comes around. By default the page is simply un-published and any attempts to access it from the frontend result in a 404. (Current behaviour), or a more intelligent default might be to revert back to the previous version - either way, as long as the CMS admin user was availed in some way as to how their system is configured.

2).

As well as/instead of 1). (With a radio/checkbox selection) a TreeDropDownfield of SiteTree objects, that when selected and saved, results in front-end requests to the current content-object being redirected to the selected item, when the current content becomes un-published.

Thoughts welcome.

phptek commented 11 years ago

For UI improvements see: https://github.com/silverstripe-scienceninjas/advancedworkflow/tree/issues/47-B

phptek commented 11 years ago

Note that a pull-request has been accepted on this, but the ticket will remain open for now, to encourage further discussion on improvements to the current embargo/expiry implementation.

chillu commented 6 years ago

The Terraformers (SilverStripe Ltd. team in Auckland) have started to build a separate embargo/expiry module over at https://github.com/silverstripe-terraformers/embargo-expiry. Its initial requirements are pretty basic. The main aim is to separate it from advancedworkflow. As well as getting it working with SS4 and the new silverstripe/fluent 2.0 version. Ideally this would work with advancedworkflow, but it's not a goal for that particular client project, so would need community help to get over the line. I'll start filing some enhancement issues in the module to map the critical path of missing features, and provide a space for more focused discussions.

nyeholt commented 6 years ago

Yep - ideally we'd not have two separate modules providing the same functionality, so if embargo-expiry was able to replace the functionality of advancedworkflow I'd happily remove it.