Versionable/Revisionable Models
Created 1 year ago by ryanthompson

The outline of this feature would be to basically allow versioning of model entries. My thought is to add a version column to the models and auto-scope the query similar to trashable and soft deletes in laravel.

We could sort by version descending first and use the latest inside the query builder. Index the column for optimization. Then save / save as new version would be options in the forms? Or we could just always save to new version?

The purpose of this would be to allow you to roll back to an earlier state of the entry you modified. This is huge with larger entities like banks and legal industry businesses.

ryanthompson  —  1 year ago Best Answer

This has been completed. To give it a test drive checkout the PyroCMS 3.5 branch and upgrade per normal (see help guide for cheatsheet). Variables is the only module that has it now that will update others (toggle versioning on on the group you desire to track).

edster  —  1 year ago

I assume you would have a versioning table with poly back to models? and maybe a data column with a jsoned entry? I don't want to see version tables for every fucking model.

ryanthompson  —  1 year ago

We will be able to cherry pick values from older versions this way as well if we wanted to.

ryanthompson  —  1 year ago

@edster the idea would be to add a single version column on the entries table.


For example.

edster  —  1 year ago

Ah, so as an example, I had a page with 3 fields saved. I resave the page changing one field, I now have 2 entries in the table, V1, V2. What happens if I hit save, but didn't change any fields? Am I getting a V3 row as well?

I don't know about others, but I would rather see the base tables behave the same, with a pre saved cache being saved as a json into a version table with a poly to the record.

Keeps the table cleaner, also what happens if I delete a page/trashed entry, are we deleting the old versions as well?

frednwt  —  1 year ago

Then save / save as new version would be options in the forms? Or we could just always save to new version?

Why not having a $autoversion = true / false? So we can pick?

ryanthompson  —  1 year ago

@frednwt that's not a bad idea at all.

ryanthompson  —  1 year ago

I think something closer to this will be a tighter solution:

Problem with column is inefficient when querying and make returning sets of entries (latest) very tough. So definitely need a table for it.

Need to think about UI for it. I guess something along the lines of the fields and others type controllers and builders.

william  —  1 year ago

This is something i would really love.

finnito  —  1 year ago

Just want to +1 this.

I'm making a site for a volunteer organisation and often there are a number of people who have edit access to various pages. It'd be really swell to have be able to see revision history for pages.

ryanthompson  —  1 year ago

Almost done with this feature - next to integrate with some starter addons / document. This will be in PyroCMS v3.5 on Streams Platform v1.4

ryanthompson  —  1 year ago

Here is a simple example of the versioning in action:

webformatik  —  1 year ago

Nice! Do you plan more information on the versions screen? We often used laravel revisionable to show a log of changes for a model. I think about a "Changes" button for each version, which shows old and new value for every modified attribute - this is what editors want to know in my opinion...

ryanthompson  —  1 year ago

@webformatik yes I would like to show a small delta info graphic like GitHub has which would expand to more information. But I will likely roll that out later since it's ONLY UI. There are a few new things I am rolling out and fluffing up UI later.. One thing I am struggling to finish up is revisions on complex objects like a page with grid / blocks content for example. Proving to be pretty difficult. Would be curious if you have any pointers or experience on the subject!

webformatik  —  1 year ago

I understand the problem - i came to the same point as i was thinking about re-implementing the old revisionable trait to a relaunch project with pyro. Data structures are more complex so i can't "convert" my old history. My old revisionable output was more technical like:

User "A" changed field "B" at YYYY-MM-DD hh Old value: xxx New value: yyy

which was not very handy in some cases, for example large text blocks or many changed fields at once.

My thoughts: A editor would prefer a diff view very similar to what he sees on the edit page and/or what he sees as rendered content. The second is nearly impossible to implement due to the backend doesn't know how content is used in the front. So we will have to display the diff like "how has my edit view changed", which means to look at everything on field level (field content and order). Do we want a split screen view?

Every field has a form represantation, so every field needs at least:

  • a getContentForDiff method to compare fields (we want the ability to specify which raw data changes are relevant for diff view and what is not)
  • a diff renderer for resentation. There will be a simple renderer for example for a bool field, showing only the value change. Or more complex renderers for example for texts showing the inline word-by-word diff. Every field type can get the most usable diff renderer for the editors view.

If the diff view walks through the data structures like the edit view, there are now problems with complex data structures. If the are representable as edit form(s), they also will be representable in diff view.

I would not render unchanged fields (content/position) regardless if we use splitscreen or page mode. If the edit view has tabs, i would render them below another and ony if they contain at least one changed field. Colors would be a good idea: green = field added, red = field deleted, green = field modified. I have no final idea how to display the difference between "only order has changed" and "order and content have changed".

Last: Will reorder of models in tables result in an new version?

I hope i was able to write down my thoughts clear enough. Feel free also to ask me at slack: Martin

ryanthompson  —  1 year ago Best Answer

This has been completed. To give it a test drive checkout the PyroCMS 3.5 branch and upgrade per normal (see help guide for cheatsheet). Variables is the only module that has it now that will update others (toggle versioning on on the group you desire to track).

webformatik  —  1 year ago

Any docs for this yet? ;)

girvydas  —  10 months ago

How about repeater field types and multi/relation field types? Are they implemented in this versionable model solution? As I tested, this solution works only on simple field types, because it saves changes as json data to database.

What about idea of saving every version as new entry and setting active attribute for chosen/latest version? This adds more complexity and unused entries at database, but works more seamlessly imho.

ryanthompson  —  10 months ago

@girvydas this does work and applies to ALL streams. The complication is that there is a bug for deep deep relations when submitting forms and catching differences. I've confirmed they save fine if forced and revert fine for versions but the detection of deep relation changes (repeaters / grids) has a bug currently I am working on.

webformatik  —  7 months ago

Is there any kind of diff view implemented yet? Because my customer asks to see revisions 😄

All other laravel versioning/revisioning packages i've checked will not version relations. So they will be nearly useless in pyro as we will often have repeater/grid relations in models which are considered as "content" together with the model...

ryanthompson  —  7 months ago

Ours versions relations for blocks / content on screen - but the RELATED model in the one-to-one type situation would also need versioned. Which is why this feature is still in testing. Using blocks as an example it's a very very deep relational map we're versioning.

Difference views are not currently in there but DEFINITELY a next step as our clients are asking for them too!