Open avernet opened 9 years ago
Looking forward to this. Keep it up
@Kevinhebertd We are working on it :)
We have done quite a bit of progress on the UI. Remaining steps:
Orbeon-Workflow-Stage
headermetadata
column / metadata.xml
metadata.xml
and stage
columnchange-workflow-stage()
action (store alongside mode & version)fr:workflow-stage()
functionDo you have an updated release date for 4.11 ?? :smiley:
It's not going to be in 2015, that's for sure. Shooting for sometime Q1 2016.
UPDATE: We have progressed on this until the end of 2015, but then decided that 2016.1 (AKA 4.11) would focus instead a number of features and fixes for customers. For 2016.2, we have decided to focus on one Form Builder usability feature.
Still, there was some work done:
When we pick this up, we should focus on addressing #2762 first.
2016-09-26: RESOLUTION: For now we write our workflow configuration UI with XForms, with the following thoughts:
Tasks:
workflow-ui
branch to workflow-ui-experiment
workflow-ui
branch and integrate into buildWorkflowState
WorkflowState
fr:tabbable
) to support dynamic tabs for operationsInitial UI is in! Here is a screenshot.
The UI is done but there is quite a lot left to do in the backend and that won't make it for 2016.3. Moving to 2017.1.
For 2016.3, we will just disable the "Workflow and Permissions" toolbox button.
Remaining UI tasks:
defaultStageKey
if allowedcolor: gray
or similarWith the current permissions settings, the picture is pretty clear: CRUD operations are enabled to a user depending on:
The basic workflow adds to this:
Now at the persistence layer permission must be known in terms of CRUD. So the idea was to generate, from a workflow configuration, a permissions configuration which can be used at the lower level.
create
, this is easy: we have a single built-in create operation. That operation doesn't have explicit actions, and usually doesn't have a button because you just navigate to `/new', but a "Create" button is possible like Form Builder's "New" button to create a new form definition.view
, we may or may not have a button, and here as well we don't have explicit operations. We raised the question or custom-naming the button above, but this is doable.delete
, same thing. Usually there won't be a button but there can be one, and the permission is built into the operation name.update
. This is not built-in, although we discussed that maybe the "Save" operation should be present by default but removable. In many cases, the update permissions will be the result of doing a "Save" or other custom operations such as "Submit" (to workflow) or "Approve". These operations change the stage, so require the update
permission.The idea was that the update
operation would be inferred from the actions, specifically processes, associated with the operation. If the button associated with the operation runs a "Save" process, then we infer update
. How? Probably by looking at the process definition in the properties?
One issue with that is that:
So we need to decide how to make this as clear as possible.
Possibly, we could infer the update
permission depending on the process, but show it as a checkbox. This would clarify to the form author that the permission is set or not. Then the user could override the update
permission with that checkbox (or other).
Also noting that we want to infer read
permissions for any update
permission.
Discussion with @avernet, we think this is ok. We make it clear to the user what the update
and read
permissions are in the UI at least.
Also, the idea for the persistence layer is to have enhanced permissions check:
Our existing format for permissions is restricted to 2-level expressions that looks like (… AND … AND…) OR (… AND … AND…) OR…
. This is enough as any multi-level expression can be flattened into 2-levels. For instance:
a OR (b AND (c OR (d AND e)))
⇔ a OR (b AND c) OR (b AND d AND e)
We'll leave the proof thereof to the reader. However, the current format does not support subtractive rules, i.e. it doesn't support NOT
. We could expand it to have a 3rd level for NOT
, which would allow us to rewrite any expression to the 3 levels OR / AND / NOT
, in that order. For instance:
a OR (b AND NOT (NOT c OR (d AND NOT e)))
⇔ a OR (b AND (c AND NOT (d AND NOT e)))
⇔ a OR (b AND (c AND (NOT d OR e)))
⇔ a OR (b AND c AND (NOT d OR e))
⇔ a OR (b AND c AND NOT d) OR (b AND c AND e)
With this in mind, we can either:
AND
, OR
, and NOT
.The second option would make the conversion from the workflow format to the permissions format much simpler, but makes other algorithms more complex, e.g. to determine if a user has a access to a certain operation only based on their role. With this, my current preference is for option 2.
The pre-defined operations we have in the dialog ("Create", "View", and "Delete"), correspond to built-in operations available from the Form Builder summary page. We drive other pre-defined operations from those 3, e.g. View ⇒ PDF, Create + View ⇒ Duplicate.
Now, say we have a duplicate process (once #1874 is implemented), and users define a custom operation that runs the duplicate process. Per the logic we use for Update, if users can run a operation that runs a process (duplicate) that requires Create and View, they should have the permission to Create and View. But:
/edit/123
page.It seems to me that we're having those problems because we try to reduce the permissions to run increasingly more complex operations (and even, with processes, arbitrarily complex operations), to 4 booleans Create-Read-Update-Delete. And for built-in operations, like Duplicate, PDF, and maybe more in the future, we're trying to go from a combination of the 4 booleans to the operation itself.
This is not unlike a web app with complex permissions trying to also enforce permissions at the database level, mapping application-level permissions to a coarser database-level permissions, which in general isn't being done.
I suggest we should:
This would have the following:
Concretely, we would:
For the purpose of this discussion, let's assume we go for the change suggested in the previous comment. I have 3 questions relative to the operations:
To the first question:
save-final
process.To the second question:
To the third question:
/new
, but only clerks who do lots of data entry have the New button.review
and new
processes.Edit doesn't have the checkbox "Show button on detail page".
What if you are on the review page, and want to go back to edit?
Other smaller changes to discuss and maybe implement:
What if you are on the review page, and want to go back to edit?
This is covered by the second item in my previous comment. We need a general mechanism here, in particular for the case where we have a "fill out form → review → submit" process, in which case "submit" should only show on the "review page". (And we can leverage the stage here, so it doesn't show when users go to /new
.)
Thinking about it, the term "perspective" seems to be fitting as in typical use / in the context of a workflow:
I updated the mockups above to make the checkbox "Fill new form" readonly if the constraints contain something that depends on the data (e.g. stage).
We have a new "perspective-based" design from 2017-04, and no significant work has been done to update the UI per this new design since then. Next steps:
Possible next steps:
Consider the case of an expense report, and say that after an employee submits an expense report, the employee can update it, but not approve it, and a manager can approve it (or reject it), but not update it.
When a persistence API implementation gets a PUT, it doesn't have enough information to discriminate between an update of the initial expense report (only allowed if done by the employee) and an approval or rejection (only allowed if done by the manager). It doesn't have enough information to properly enforce the permissions.
It could reject operations that are clearly forbidden, like a POST by someone other than the employee or the manager. And this is something we could do in the future, but it has two downsides:
(It should be noted that this second point is already a problem right now: a form can implement the above scenario by hiding controls or making them readonly based on the user's role, and persistence API implementation doesn't check that.)
Summary of how do we handle the workflow UI so far:
object WorkflowTemplates
exposes to the UI templates for repeated content, etc. This is some amount of boilerplate.The idea is that:
In practice, our XForms implementation requires XPath expressions pointing to XML. That is why we do this Scala ↔ XML translation. See also #3455 for similar considerations on how we could improve that.
I think we can continue along these lines for now. Steps:
Next steps:
oxf.fr.detail.button.BUTTON.enabled.*.*
property to determine if the button is enabled or disabled).Supporting native instances would be good, see #3455.
For reading/writing from/to the form definition:
Converting (option in the Form Builder permissions and/or Workflow dialogs?):
PermissionsXML.parse()
)WorkflowConfig
(PermissionsToWorkflowConfig.convert()
)instance(fr-form-metadata)/workflow
2020.1
)Running:
TODO
[ ] Q: The "simplified XML" is useful right now for the UI. But should we store the definition to the form in JSON or XML? Right now we don't have a "simplified JSON".
[ ] write Form Runner functions usable at runtime:
WorkflowConfig
from XMLFollowing discussion with @avernet today, we suggest, for the stage name, to have a localizable label. This is usual for:
Related issues
Use case
In a small business, anyone with the role
employee
can submit an expense report by filling out a form. After it has been submitted, the employee who created the expense report can can see but not edit the data (but other employees can't see the data), and anyone with the rolemanager
can either approve or reject it.New concept: stage
Overview
started
,submitted
,approved
,rejected
, withstarted
marked as the initial stage.approved
and the reject button will change the state torejected
.In Form Builder
Stages
Out of the box, we'll have 2 stages:
started
(the default), andsubmitted
. Oursubmit
process will change the workflow stage tosubmitted
, which will allow us to make a distinction in the database between form data that has been just saved, but hasn't been submitted yet, and data that has been submitted.Available to
The Available to section shows in the Operations tab of the Workflow dialog. Its purpose is to allow form authors to whom a given operation is available, e.g. based on the user's authentication role or the workflow stage.
Pre-defined operations
Custom operations
Implementation
metadata.xml
. For the REST API, the stage is sent off-band through headers, as done currently for say, roles and operations.WHERE
clause.change-stage('approved')
.fr:stage()
- A new XPath function is added that returns the current stage, so the stage can be used in MIPS and in processes where XPath expressions are used./edit
and has only the right to view, then she is redirect to/view
.