Giter VIP home page Giter VIP logo

Comments (44)

StephenOTT avatar StephenOTT commented on May 3, 2024

This is a needed feature! ๐Ÿ˜„ as big use case issue would be once you delete a field from the Form, you cannot view it in your submissions. Simple example would be the Signature Field. If you have submissions wth Signatures, and then your delete the signature field from your form, and view the submission with the signature, the signature is no longer visible / appears as though there was never any signature field.

from formio.

travist avatar travist commented on May 3, 2024

Yeah, I agree we need this. However, the data is still there, it is just not visible in the form submission preview since the component does not exist. However, if you pinged the endpoint for that submission, you will see that the signature is still there.

from formio.

StephenOTT avatar StephenOTT commented on May 3, 2024

@travist yes saw that when exporting the json :)

@travist is this worth a PR or would you prefer to do this in house?

from formio.

StephenOTT avatar StephenOTT commented on May 3, 2024

@travist on a related note to how versioning would work. From a enterprise perspective very important that everything about the version of the form is versioned. Rules, validations, configurations, etc, so a admin can "inspect the past". Additionally versions of forms should be able to have a version ID (and potentially a version description or change description?). There would of course be the diff, but a explanation of what the purpose of the changes from the previous version would be helpful when looking back.

If you really want to get "fancy" ๐Ÿ˜„ , the additional feature would be to support different versions of a form at the same time. So if you are transitioning to a new version of the form but you want to support the old form for N amount of time, then you can do so without having to create a new form with new url etc.

from formio.

travist avatar travist commented on May 3, 2024

Thanks @StephenOTT for the notes. It is very helpful to get insight from others on how this could be done. You inquired about PR or inhouse. Right now, our plates are pretty full with other things, so I do not see us getting to this feature request in the near future (3 months). If you would like to give it a go, I would be very grateful for the effort. Most of the changes that would need to be made would be made within this Open Source core library.

from formio.

StephenOTT avatar StephenOTT commented on May 3, 2024

Will spec out the changes in this issue before going forward with PR. We are very familiar with "versioning" requirements as its a huge part of gov space.

from formio.

travist avatar travist commented on May 3, 2024

This is great Stephen and I really appreciate it. Having someone very familiar with how it should work spec out the changes needed will provide a significant amount of value. Once you have the specs outline, I can provide assistance on where in the code the changes would need to be made. We can have another hangout session if that would help. Thanks again!

from formio.

StephenOTT avatar StephenOTT commented on May 3, 2024

Spec:

WIP

Overall goal: keep in-line with current formio scheme and design patterns. Maintain simplicity whenever possible.

Notes:

  1. Each Submission is associated with a form version
  2. A Form Version is a full schema of the form.
  3. Each change/save to a form results in a Form Version being created.
    1. Note: need to think about data structure: should versions be help in a Array of Versions where each item in the array is a version object with the object containing metadata about the version and the components, OR should versioned components be another collection/object that is not inside of the main form object: concern is MongoDB document Size for long term forms where many changes could occur.
  4. Each version of a Form should allow for a comment/note
  5. Versions should only be created when a form is "published". Should look into OSS client/version having a "published" checkbox/tag. When a form is in development you do not have to have multiple form versions being created that will never have submissions.
  6. Once a form is "published" and has submissions, if a change is made to the form, a new version should be created.
  7. Viewing a submission will use the Form version to render the form
  8. Note: Should someone be able to submit using a previous version of a form? Likely an un-needed complexity, but should still be thought about for use case.
  9. Note: consider adding object id to each component for future ability to run Diff/history of a component. If key field is changed, then history of the component would be compromised. Object id would not be able to change and would provide full history/path of component across versions.

screen shot 2016-06-22 at 1 45 36 pm

Form Revision Spec:

WIP - coming

from formio.

zackurben avatar zackurben commented on May 3, 2024

@StephenOTT looks good so far, but for point 3, each version needs to be a new form so that there can theoretically be an infinite number of revisions.

Each form should contain a property called formVersions for example, which is an array of Form ObjectIds corresponding to revisions of the form.

Additionally, we should make a property on the form called revision which is a boolean, denoting whether or not this form is a copy/revision of another. With that extra tag, we can add middleware to filter out revision forms by default, thus ensuring the form index isnt littered with revisions of other forms.

from formio.

StephenOTT avatar StephenOTT commented on May 3, 2024

@StephenOTT looks good so far, but for point 3, each version needs to be a new form so that there can theoretically be an infinite number of revisions.

@zackurben are you suggesting to replicate/duplicate the permissions and other non-component fields across all form versions? So that technically two revisions of the same forms would have different permissions?

@zackurben, Do you want to version everything about the form? Including things like permissions and non-component configurations?

from formio.

zackurben avatar zackurben commented on May 3, 2024

@zackurben are you suggesting to replicate/duplicate the permissions and other non-component fields across all form versions? So that technically two revisions of the same forms would have different permissions?

Yeah, that would allow for forms to be staged. Then someone could totally change a form, test it, and potentially revert back to a stable version.

from formio.

StephenOTT avatar StephenOTT commented on May 3, 2024

@zackurben what you thinking for the Link/association key between versions?

How do you propose to handle conflicting permissions between latest and versioned submissions?

example: Permission are set so userABC can view submission data. Form is updated/revisioned, and UserABC now no longer has permission to view submission data. New submissions are made.

Does UserABC have permission to still view the data from the previous submissions?

It creates a conflict of permissions between permissions being for each version of a form, but do you respect only the latest permissions?

from formio.

zackurben avatar zackurben commented on May 3, 2024

@StephenOTT yeah, pondering that now..

@StephenOTT looks good so far, but for point 3, each version needs to be a new form so that there can theoretically be an infinite number of revisions.

Each form should contain a property called formVersions for example, which is an array of Form ObjectIds corresponding to revisions of the form.

Technically, that still isn't sound, because eventually that list could exceed the maximum mongo document size.

Additionally, we should make a property on the form called revision which is a boolean, denoting whether or not this form is a copy/revision of another. With that extra tag, we can add middleware to filter out revision forms by default, thus ensuring the form index isnt littered with revisions of other forms.

I think this would work better..

Each form has the following field: latestRevision which is a single form object id or null. When a form is loaded, look at the latestRevision, and if it exists, load the latest revision instead. For a base form, e.g. a non clone, the latestRevision will start as itself, any clone will have the latestRevision as null, then we can stop any clone itself from being loaded if it isn't the current latestRevision.

When a form is edited and saved, clone the current form with the new changes and update the base forms latestRevision property.

Then when looking at the form in the editor, we could pull up all of the revisions to cycle through and possibly remove for cleanup.

We could then update the submission viewer to have an option for essentially zipping all the submissions for all the cloned forms together, to view in one place.

from formio.

StephenOTT avatar StephenOTT commented on May 3, 2024

and if it exists, load the latest revision instead.

How are you determining which is the first document/object to load? / which is the base form? / how do you know it is the base form?

the latestRevision does not seem to solve the permission conflict issue, correct?


If you want to go down the latestRevision route with the cycling to pull up the various revisions, would it not make sense to just create a new collection called something like FormRevisions, store base forms in the Forms collection, and store all revisions to all forms in the new collection. Each revision can ref the object id of the base form, and the base form can control the permissions and other non-versioned information?

from formio.

zackurben avatar zackurben commented on May 3, 2024

I like that, because each form is separated from its revisions, along with each forms submissions. Additionally, there would need to be a submission migration path:

e.g. you make a submission to the user resource when there are no revisions.
5 Revisions are made.
If you look at the latestRevision user resource, you don't technically have a submission there.

We would need to take the base submission and look at its base form. Then traverse all the revisions to the form, modifying the key:value pairs as they were changed in each revisions to attempt to have a current version of an old submission.

How are you determining which is the first document/object to load?

If you make a form with the path /user, that form will always load first, that is to say the base form will always be loaded, before any revisions.

which is the base form?

The first form to be created in the revision chain.

how do you know it is the base form?

When ever a form is loaded, the base form is the one people will type in the url. If we make form revisions have the property latestRevision and we force all form clones to have a null latestRevision, then the base form will be the only form in the chain without a latestRevision. We could also add a baseForm property that is protected and always points to the base form, from which you can always determine which is the most recent copy of any form.

the 'latestRevision' does not seem to solve the permission conflict issue, correct?

What is the permissions issue? Each version of a form specifies its own version of permissions.


edited for quote formatting

from formio.

StephenOTT avatar StephenOTT commented on May 3, 2024

Rather than only storing the changes with each revision, why not store the entire form? You can query for all revisions of a form, and get the "latest" form (how ever we determine that) (probably best to use a date, so you don't need to change previous revisions and you don't have to update the base for). If you foresee performance as a issue, then could always update the base form object with a "latestRevision" field that is the objectID link to the latest Revision.

I would also suggest that if you want to bake revisions as a core feature rather than some sort of optional extension to formio, that you make the base form object an object of "metadata" about the form (permissions, ownerships, dates, etc)/things that don't want/need to be revisioned, and have the first set of components for a form be a revision. e.g.: when the first is created for the first time, this would create a Base Form object and Revision 1.

from formio.

zackurben avatar zackurben commented on May 3, 2024

Rather than only storing the changes with each revision, why not store the entire form?

Ah sorry if I mislead you, I'm jumping between working and replying to this. I was envisioning storing the entire contents of a form, for every revision.

You can query for all revisions of a form, and get the "latest" form (how ever we determine that) (probably best to use a date, so you don't need to change previous revisions and you don't have to update the base for). If you foresee performance as a issue, then could always update the base form object with a "latestRevision" field that is the objectID link to the latest Revision.

I would still use a reference from the original (base) form, to the latest, because the newest version of the form, may not be the "latest" that you want people using. E.g. someone else (with permissions) modifies your form, and you want to roll back to a previous version.. the dates of all the forms is essentially useless at this point.

I would also suggest that if you want to bake revisions as a core feature rather than some sort of optional extension to formio, that you make the base form object an object of "metadata" about the form (permissions, ownerships, dates, etc)/things that don't want/need to be revisioned, and have the first set of components for a form be a revision. e.g.: when the first is created for the first time, this would create a Base Form object and Revision 1.

It would be nice to store a subset of information, to reduce duplicated information, however I think for auditing reasons, we probably need to store whole copies; the created and modified timestamps are important for both a base form and any revision of it.

from formio.

StephenOTT avatar StephenOTT commented on May 3, 2024
Recap: 1. Two Collections: `Forms` and `FormRevisions`. 1. `Forms` contains the form's base information (non-revisioned information). The base information also contains a reference to the "latest revision" which represents the revision of a form that is called when the form is rendered for a new submission. 2. `FormRevisions` would contain entire copies of the Form's Components schema/config. Every save to a form would create a new revision. 2. When a form is first created this creates a Base Form object and a Revision ("Revision 1" or "Revision 0" depending on how you want to look at it). 3. For an initial implementation, very likely that only Form Components would be versioned.? 4. The "Latest Revision" does not represent the new revision. It represents the most recent "published" revision. I would suggest we using something like simple implementation of "states" between Draft, Published, and Unpublished. (Draft is any new revisions before the first Published or after the first published, but the revision has not bee published yet, Published is the "live" form that is used when a new submission is made, and Unpublished are any old revisions that used to be published )? 5. Each submission is associated with the Base Form Object and the Revision Object. 6. When a submission is rendered, it uses the Revision Object for the component configuration 7. When a Form is rendered for a new submission, it uses the "Latest Rivision"/published revision of the form.

All of that correct? @zackurben

from formio.

zackurben avatar zackurben commented on May 3, 2024

@StephenOTT actually, no, I was proposing just using the Form collection, but I like two collections more, because it keeps it more simple; Simplicity is ๐Ÿ‘

How about something like this:

  1. Two collections (only adding one new one)

    • Forms
      • Base form collection
      • Add a revision property, null by default
    • FormRevisions
      • New collection used solely for tracking modifications to a form.
      • has its own id
      • has a form id (the base form reference)
      • has an object of changes, e.g. modifications
  2. When a form is created, the system behaves as it currently does.

  3. When a form is modified, we take the changes from the base form, and save it as a FormRevision

    • A form revision is a simple document that shows what property(s) of the base form have been modified since its original creation time.
    • When a FormRevision is created, we update its base form (denoted by FormRevision.form) to have the revision id set to this new FormRevision
    • Example document:
    {
      _id: <FormRevision BSON ID>,
      form: <Form BSON ID>,
      modifications: {
        components: [ .. ]
      }
    }
  4. When a form is loaded, we follow the natural path of execution, but before the results are returned or used for processing, we look to see if the revision field is non-null

    • If the revision field is null, we continue as usual (this means the form has never been modified since the original save.
    • If the revision field is populated with a FormRevision ID, we load the revision, and iterate its modified properties.
      • For each property of modified we will blindly overwrite the forms corresponding property (no extra processing time before loading)
  5. Each submission is associated with the base form

    • potentially include the FormRevision also? This could be helpful for tracking its initial form configuration, but there isnt really a migration path, so it would only be useful for displaying the submission in its original state
  6. When a submission is rendered, it uses the base form and the forms current FormRevision (if any)

    • This means, removing or hiding any fields that have since been removed (or renamed, because we can't track name changes, unless we document them in the FormRevision, which would take more processing time on save)
  7. When a form is rendered for a new submission, the API will first load the base form object from mongo, then check if it needs to load a FormRevision.

    • If a FormRevision is present, load that too and apply each modification to the current form object in memory, then serve that as the form request.
    • If the FormRevision is null, just return the base form

Footnote thoughts of this mentioned implementation:

One thing I'll make note of, is that as a form is modified, each FormRevision will slowly grow in size if fields are just added each time, eventually resulting in a ton of duplicate data (worst case scenario). If each modification is wildly different, then there is potentially no duplicate data, and its pretty quick to apply the changes from a FromRevision to the base Form

However, the processing time is good, at worst we only ever need to do 2 db calls, still not ideal, but potentially infinitely better than a diff system. A diff system would have theoretically zero duplicate data, but potentially infinite db calls (one for each diff), that then need to be sequentially processed to create the aggregate result (if we keep all FormRevisions, that is to say, we allow any change to be undone, which I think we should have).

Thoughts @StephenOTT?

from formio.

StephenOTT avatar StephenOTT commented on May 3, 2024

@zackurben

When a form is modified, we take the changes from the base form, and save it as a FormRevision
A form revision is a simple document that shows what property(s) of the base form have been modified since its original creation time.
When a FormRevision is created, we update its base form (denoted by FormRevision.form) to have the revision id set to this new FormRevision

Why would you always take the changes from the base form? Once the first revision has been made, the "base form components" are essentially irrelevant. What matters if the new revision. When a second revision is made, the second revision should only care about the previous revision. The second revision should not really 'care' about what the base form components were when the form was first created. At least thats how I have been thinking of it. I see it in the same manner as any versioning systems (such as a CMS), the original content is just revision 1 or revision 0 (depending on how you want to think about it), and the numbers increment from there. But when i read your description, i read it as there is special value being placed on the original/first created components/base form components.


If the revision field is populated with a FormRevision ID, we load the revision, and iterate its modified properties.
For each property of modified we will blindly overwrite the forms corresponding property (no extra processing time before loading)

Do you want to do this because you do not want to keep "full copies" of the forms as revisions, and you are looking to implement a sort of diff system?


Each submission is associated with the base form
potentially include the FormRevision also? This could be helpful for tracking its initial form configuration, but there isnt really a migration path, so it would only be useful for displaying the submission in its original state
When a submission is rendered, it uses the base form and the forms current FormRevision (if any)
This means, removing or hiding any fields that have since been removed (or renamed, because we can't track name changes, unless we document them in the FormRevision, which would take more processing time on save)

When viewing a submission it should most defiantly use the form version/revision that was used during submission. viewing a submission should show the form in the 'state' that it was in when the submission occurred. Could also add some extra feature to allow changing the "rendering form version" post-submission, but the core of the need for revisioning is having the ability to view submissions with the components that were used at the time of the submission. Should never be a question to someone looking at a form saying: "Wait.. why is that mandatory field empty?", where it was empty because it did not exist at the time of the submission.


One thing I'll make note of, is that as a form is modified, each FormRevision will slowly grow in size if fields are just added each time, eventually resulting in a ton of duplicate data (worst case scenario). If each modification is wildly different, then there is potentially no duplicate data, and its pretty quick to apply the changes from a FromRevision to the base Form

However, the processing time is good, at worst we only ever need to do 2 db calls, still not ideal, but potentially infinitely better than a diff system. A diff system would have theoretically zero duplicate data, but potentially infinite db calls (one for each diff), that then need to be sequentially processed to create the aggregate result (if we keep all FormRevisions, that is to say, we allow any change to be undone, which I think we should have).

I have a preference towards storing entire versions of the component config on each revision, and the 'base form' is just "revision 0/1". Yes there is duplication of data, but in the grand scheme of things, it is: simple, easy to understand, easy to inspect and each query against. Overtime you could add the ability to prune unused revisions (revisions that don't have submissions against them), and yes it will grow over time, but we are not really talking about a lot of data, i would be surprised if all of the revisions would hit the document size limit in mongo on your typical or even specialized form. (not saying to put all the revisions in a single document. Just using it as context for putting the future concern of duplication of data into perspective of size.)

When a form is called for data entry, the system looks up the form in the Forms collections, and using the formRevision field it gets the current 'published' reversion of the form from the Revisions collection. When a submission is called, it uses the submission Form Reference ID to get the revision of the form (could also store the base form id in the submission).

in terms of the current application flow, it would be the same flow, but instead of loading the components from the components array in the base form, it does an extra look-up using the FormRevision object id.
Following this allows each comparison of form revisions, allows easy diff across multiple revisions, it is super easy to understand, and query against, and allows additional revision data to be easily added if required.

If you are looking to implement numbers 3, 4 and 5 in your description because it means less work or modification to code, then okay, lets then try and stay close to current code so 're-architecting' is not required. I don't know the code base as well as you, so will leave that for you to decide.

from formio.

zackurben avatar zackurben commented on May 3, 2024

@StephenOTT

Why would you always take the changes from the base form? Once the first revision has been made, the "base form components" are essentially irrelevant. What matters if the new revision. When a second revision is made, the second revision should only care about the previous revision. The second revision should not really 'care' about what the base form components were when the form was first created. At least thats how I have been thinking of it. I see it in the same manner as any versioning systems (such as a CMS), the original content is just revision 1 or revision 0 (depending on how you want to think about it), and the numbers increment from there. But when i read your description, i read it as there is special value being placed on the original/first created components/base form components.

I don't want the diffs to be dependent on each other. If the form is stored in the form collection, I want the changes in the FormRevisions to be the contents of whats changed from the base form. So, loading any version of the form requires two things: loading the base form, applying the current form revision. Each FormRevision would contain anything that has been modified, e.g. components or permissions.

Do you want to do this because you do not want to keep "full copies" of the forms as revisions, and you are looking to implement a sort of diff system?

I want to implement a simple diff system, where every revision is a diff of the current state of the form, and the base form. I want it to be simple and not dependent on more than one diff at a time, because those need to be loaded at runtime.

When viewing a submission it should most defiantly use the form version/revision that was used during submission. viewing a submission should show the form in the 'state' that it was in when the submission occurred. Could also add some extra feature to allow changing the "rendering form version" post-submission, but the core of the need for revisioning is having the ability to view submissions with the components that were used at the time of the submission. Should never be a question to someone looking at a form saying: "Wait.. why is that mandatory field empty?", where it was empty because it did not exist at the time of the submission.

I'm fine with this, I do think we need some sort of migration path, because I can already see people being confused on why they have submissions that are missing required fields (validations added after the submission was added).

I have a preference towards storing entire versions of the component config on each revision, and the 'base form' is just "revision 0/1". Yes there is duplication of data, but in the grand scheme of things, it is: simple, easy to understand, easy to inspect and each query against. Overtime you could add the ability to prune unused revisions (revisions that don't have submissions against them), and yes it will grow over time, but we are not really talking about a lot of data, i would be surprised if all of the revisions would hit the document size limit in mongo on your typical or even specialized form. (not saying to put all the revisions in a single document. Just using it as context for putting the future concern of duplication of data into perspective of size.)

I'm fine with duplicate data, and in fact we have to have to, because the components and all permissions are stored in an array, so there isn't a way to express that in a simple js object (the fact that properties were removed). Since storage is cheaper than cpu power, I'm totally fine with this atm. If things get out of hand later, we can remove all revisions that don't have submissions, or limit it to a time available. I'm thinking something along the lines of the following:

// Form Obj
{
  _id: < .. >, // mongo id
  revision: < .. >, // mongo id
  components: [ .. ],
  access: [ .. ]
}

// Revision Obj
{
  _id: < .. >, // mongo id
  form: < .. >, // mongo id
  modifications: {
    components: [ .. ]
  }
}

When the form is loaded, we see there is a form revision id, so we load the form revision also. If we look at the keys of the revisions modification object, we see components - meaning that the components were changed on the form and we can simply assign form.components = revision.modifications.components; (we don't care what changes are in here, as this was the entire components array copied when it was last saved.)

When a form is called for data entry, the system looks up the form in the Forms collections, and using the formRevision field it gets the current 'published' reversion of the form from the Revisions collection. When a submission is called, it uses the submission Form Reference ID to get the revision of the form (could also store the base form id in the submission).

Yeah, every submission has a ref to its parent form, I would just add the form revision id as well (we can update all the old ones with our db update system)

in terms of the current application flow, it would be the same flow, but instead of loading the components from the components array in the base form, it does an extra look-up using the FormRevision object id.

I would like to store permissions as well, since permissions could break an application and would possibly want to be reverted.

If you are looking to implement numbers 3, 4 and 5 in your description because it means less work or modification to code, then okay, lets then try and stay close to current code so 're-architecting' is not required. I don't know the code base as well as you, so will leave that for you to decide.

I don't mind, it wouldn't be a ton of work, but I would have to get it into my schedule.

from formio.

StephenOTT avatar StephenOTT commented on May 3, 2024

Okay so if we want to implement a diff system (even just a simple one as you suggest), any preference or aversion to something like: https://github.com/mirek/node-rus-diff ?

Edit: or something like: https://www.npmjs.com/package/fast-json-patch

from formio.

StephenOTT avatar StephenOTT commented on May 3, 2024

I don't mind, it wouldn't be a ton of work, but I would have to get it into my schedule.

We have some resources we are looking to put time on this as it is a much needed feature. So happy to provide PRs

from formio.

zackurben avatar zackurben commented on May 3, 2024

Okay so if we want to implement a diff system (even just a simple one as you suggest), any preference or aversion to something like: https://github.com/mirek/node-rus-diff ?

Edit: or something like: https://www.npmjs.com/package/fast-json-patch

Hah, I knew I would get pushback for using that word.. The only thing I have against that, is that it adds (unnecessary?) friction to the system, other than that, I have no aversion to adding dependencies.

I'm just trying to imagine the most simple solution, which to me is this:
I have a simple form, and I want to update it. At this point, I only have a base form, and no revisions. When I edit my form and click save the following happens:

We sweep the base form and the update to determine what changed, if a new component was added, we will flag the components property as modified, and persist the entire contents of form.components to the form revision.

Then, when the form is loaded again, we see it has a revision, load the revision (which has the components property flagged as modified) so we just replace the forms components with those in the form revision and serve the modified form object.

We have some resources we are looking to put time on this as it is a much needed feature. So happy to provide PRs

That is awesome to hear! Don't hesitate to reach out if you guys need some questions answered about how stuff works.

from formio.

StephenOTT avatar StephenOTT commented on May 3, 2024

Hah, I knew I would get pushback for using that word.

haha ๐Ÿ˜† . Not pushback. Just a slippery slope. nothing wrong with a json diff system.

You see value in just using something such as node-rus-diff or think better to go more 'tailored' approach?

from formio.

StephenOTT avatar StephenOTT commented on May 3, 2024

@zackurben so thoughts on diff system or the approach you mentioned with the Diff from Base Form without the dependencies.?

from formio.

zackurben avatar zackurben commented on May 3, 2024

@StephenOTT sorry for the delay.

I would personally like to stray more away from actual diffing, and use the tailored system I mentioned last (the bullet point list). I think that adds for the most flexibility and speed when toggling between form revision versions. Do you have any hesitation to going that route?

from formio.

StephenOTT avatar StephenOTT commented on May 3, 2024

@zackurben. the reason to not use a Diff was that the potentially "endless" processing of the diff information to load the form may create a delays, correct?

If we are using the concept of a "base form", what is the "base form" was always the most up to date form/would be the form that is called during submission, and when a submission is being viewed using a form revision it would load it from diffs? The base form would just be a sort of double save, where the base form is updated on revision, and the revision is created. (could even have a simple internal cache that pre-rendered the diff).

I am just thinking that we keep talking about diffs, but don't want to implement diffs for reason XYZ, but feels like we are dancing around the exact use case for using diff ๐Ÿ˜„

from formio.

zackurben avatar zackurben commented on May 3, 2024

@StephenOTT, correct.

The base form is the first form to be created, the only time the base form would be modified, is to update its current revision id (done by middleware on form save). Then every modification made to a form, is saved as a new revision.

So at the end of the day, you have the base form obj (potentially outdated information, but this serves as the connection point for all submissions to the form) and you have form revisions. To get the most current version of any form that has at least one modification, you need the base form and the form revision.

Does that make sense?

Yeah, I think so haha

from formio.

StephenOTT avatar StephenOTT commented on May 3, 2024

Does that make sense?

Yes. 100% makes sense. What i am asking/suggesting, is if we do the "double save" aspect where the base form is always updated with the latest revision, then you get Diffs and do not need to traverse the Diffs when loading the form for a submission. Could also just implement a internal cache that maintains the cached version of the latest form to be loaded for submissions, and that would eliminate the double save.

What you are suggesting makes total sense. I just keep circling around that we are essentially recreating diffs because of the Diff Processing/Traversal. If the traversal was not a concern, then diffs would very likely be what was suggested in the first place. So what if we address the traversal problem (double save or cache or something else)?

from formio.

travist avatar travist commented on May 3, 2024

I will also mention that @zackurben proposal is actually very similar to how Drupal CMS deals with versioning and it has been pretty successful. I am not claiming preference here, but just bringing up that the proposed versioning system @zackurben proposed has already been battle testing with an Enterprise CMS, and is fairly simple to implement and maintain.

The other proposal on the table sounds a lot like version control. There are a lot of gotcha's with a version control system, and as far as I am concerned, GIT is the best out there to handle all the gotchas (take a look at the docs @ https://git-scm.com/docs/git-merge to get an idea at some of the crazy things that could happen). Because of this, I have a tendency to use the simplest of both ideas, and version control seems really heavy for what we really need.

Just my thoughts on the subject. Great discussion!

from formio.

StephenOTT avatar StephenOTT commented on May 3, 2024

actually very similar to how Drupal CMS deals with versioning and it has been pretty successful.

Haha i knew Drupal was going to come up ๐Ÿ‘ ๐Ÿ˜„

I am good/happy with @zackurben proposal. It gets where we need to be. ๐Ÿ˜„

from formio.

zackurben avatar zackurben commented on May 3, 2024

@travist hah thanks for the input! Do you see anything missing here, because I don't actually know how drupal does it.

Other than that, I feel good about this @StephenOTT, thanks for the collaboration! ๐Ÿ‘

from formio.

travist avatar travist commented on May 3, 2024

Thank you for your approval @StephenOTT. Since you are going to be the first customer for this feature it is important to us that we have your buy in and we would not move forward without your nod. We can definitely show a diff between the versions (like the way drupal does), so you may get what you need as far as visualizing diffs between the versions.

Haha i knew Drupal was going to come up ๐Ÿ‘ ๐Ÿ˜„

Yeah, I can't help myself... ;) There are a lot of things within Form.io that take leverage our teams knowledge of that CMS, but what I like about this specific feature is that it really can serve as the spec for our implementation plan, and has been battle tested over the years.

@zackurben I am sure you can find some documentation over the versioning system in Drupal. It is VERY similar to what you proposed. I am sure we will need to modify it so that it is entirely RESTful, but that shouldn't be to difficult.

from formio.

zackurben avatar zackurben commented on May 3, 2024

@travist great, sounds good!

from formio.

irfansiddiqui avatar irfansiddiqui commented on May 3, 2024

I am curious if this feature was actually implented, we are using form.io for inspection forms. It will be really helpful if we can version control changes of our inspection forms.

from formio.

travist avatar travist commented on May 3, 2024

It has not been officially implemented, but we have implemented a pretty elegant way to solve this within a few projects we have created for our customers. Here is what we did...

  1. Create a new resource called Form Version
  2. Within this form, drag-and-drop a single Hidden field and call it Form
  3. You now will need to implement our form builder within your Application. There are many examples of how to do this within the following apps. https://github.com/formio/formio-app-formbuilder or https://github.com/formio/formio-app-humanresources
  4. Override the create and edit controller of the form builder within your app so that when a new form is created or edited, you will send an API request to the Form Version resource to save the current Form JSON schema in the form field of that resource. This will create a new submission that will save the JSON schema of the form.
  5. Within the application, you will add a new tab called Versions which will show a Grid view of all the submissions within the Form Version resource where the form _id matches the one being shown. The Revert button on that grid will simply take the schema of that submission and overwrite the form with that schema to essentially revert the form to that version.
  6. You will also implement a default field that is added to those forms which will be called Form Version. This can be a hidden field. Now every time the form is submitted, you can save the current version (__id_ of the Form Version submission) of the form along with the submission of that form. This will be used when viewing submissions, where you could load the JSON schema from the Form Version resource for that submission and use that as the form to view the submission.

We absolutely will be building this into the platform in the future, but this is an elegant strategy that you can implement as a stopgap until we get it in place. Feel free to contact us at [email protected] if you would like for us to implement this for you within your project, or if you would like to expedite the feature.

from formio.

multinerd avatar multinerd commented on May 3, 2024

I see the form.io platform currently has revisions implemented, would that ever make it to the open sourced version?

from formio.

randallknutson avatar randallknutson commented on May 3, 2024

We implemented this as part of our commercial platform and would love to connect and show you all the additional features we add to the open source version.

from formio.

multinerd avatar multinerd commented on May 3, 2024

I already have the open sourced version setup and running and looking at the commercial platform, the only thing I need that's not offered in the open sourced version is version control and $250/mo seems too much for that one feature.

The only thing preventing me from implementing @travist's suggestion is the fact that most of the application is built in angular and i would need help with 5.

Feel free to contact us at [email protected] if you would like for us to implement this for you within your project

Is that limited to the commercial platform or can this be done with the OS version.

Bottom line is we don't want to be tied to any 3rd parties.

from formio.

randallknutson avatar randallknutson commented on May 3, 2024

Form versions can be implemented on top of our open source platform but we don't provide the code for that. It would be up to you to write that part.

from formio.

multinerd avatar multinerd commented on May 3, 2024

Ok, thanks for clarifying. I guess i need to learn angular now.

from formio.

DonAmit197 avatar DonAmit197 commented on May 3, 2024

There is a Javascript embed of formio builder and an angular version of formio builder.
Do both have the same functionality?

from formio.

brendanbond avatar brendanbond commented on May 3, 2024

@DonAmit197 by and large the angular renderer is built as a wrapper for the Javascript renderer, which includes the builder

from formio.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.