Copy row along with children: rebirth of mothra II

โ€ฆA long time ago in an app far far away, some folks built a mechanism to handle โ€œvariable depth row creationโ€ for parent-child objects. This solution pattern required the Appsheet API at first, and then there were solutions for doing the same without the Rest API. The concept was to have a library of structures to then allow creation of instances of those structures. Several folks were working on this including @tsuji_koichi , @Grant_Stead and others.

Here is the post that required the Rest API:

And here was the post that did the same thing but without the Rest API:

Anyway, since then, I was mulling over any improvements that could be made to this idea of generating instances of variable-depth โ€œthingsโ€ using actions, but also include support for multiple users and even sequential, ordered tasks, and this is what I came up with:

https://www.appsheet.com/samples/Reference-design-for-Ordered-Tasks-and-punchlists-in-a-workflow-env...

(The title is misleading, this is not a medical app per se)
Imagine you want a customizable workflow engine, but instead of using our workflows and field values, you want the data itself to be the workflow. New row = new task. But you donโ€™t want a fixed type of workflow process. You want your audience to create NN types of workflows with variable numbers of steps. This is the โ€œvariable depth child record problemโ€. And, to make it even more complex, workflow steps might require predecessor steps, so you need to let your audience specify those as well. You want your workflows to run in series, in sequence.

Some of the design pillars of this app include:

Creating the workflow types

3X_8_b_8b15b1dee02815910b22100cfba3b7feb21943af.png

These are parent child relations using tables โ€œTemplate Libraryโ€ and โ€œTemplate Library Stepsโ€: if you study these tables, youโ€™ll see that things are pretty appsheet-normal here. Typical stuff.

We provide a UX view called โ€œRequestsโ€.

Each end user will get only 1 row of data here, so the UX shows a detail view. I have to admit, this part of the solution feels incomplete and janky. But this single row of data has all of the information the operator has selected from the Template Library, plus whatever optional fields a designer wants to add. This data and view is at the very heart of this solution. You select from your template library and then click the red button โ€œCreate New Instanceโ€ (an action), which triggers the next part:

"Create New Instance" is a grouped action which simply calls two other actions:

** Action โ€œAdd New Order from Requestโ€ - Copy the template parent to the instance parent (โ€œwork ordersโ€) - we have all of our info on our โ€œrequestโ€ page already, per previous step. We synthesize the Key/UniqueID for โ€œWork Orderโ€ at runtime:
any(Work Order Request[TemplateLibraryID]) & "-" & any(Work Order Request[UniqueID])

** Action โ€œCopy Children from Template to Work Orderโ€ - Copy the template children to the instance children (โ€œstepโ€). Same basic premise as the previous step, but this one is a bit more complex, and involves a) executing an action of a a set of rows, and then the copy command for the children. Again, we synthesize the Key.

Thatโ€™s pretty much it. Copy as desired if you would like to study it. We threw in some usual extras like a menu system, users, and such. Hopefully this app can be โ€œpre a porterโ€ for all of your workflow needs.

As always, improvements, errors, ommissions always welcome.

14 32 2,483
32 REPLIES 32

Is there any chance to elabrate the details what the new tricks and differences what I introduced to the community before?

Hi!

In the non-rest-api thread/post I didnโ€™t see an app to copy so itโ€™s hard to see what the exact details are, but at a glance:

  1. it looks like you were using Device() and uniqueID() whereas I chose to use a โ€œglobalโ€ table filtered to one row per user. Seems like the same end result. We both chose to ignore a simplistic UniqueID() when initializing the copies.
  2. In my example children can have predecessors to create sequential steps. In this sense, my app is very โ€œworkflowโ€ centric and not as generalized as your solution.

They are quite similar overall and I could not have done what I did without your amazing research!

Hi, though i copied the app, im still not sure what itโ€™s supposed to do. Can you make a short video to explain?

Thatโ€™s fair! I have just recorded a quick five minute video on this app:

Hope that helps!

Thanks, you filled the gaps for me. The next step of this idea would be to allow drag and drop steps on a dashboard

Excellent work, @TyAlevizos! This is the first sample that I would consider copying and actually building on, instead of just โ€˜looking under the hoodโ€™ to copy the idea. Definitely adding this one to the toolkit. Thanks for sharing!

Agreedโ€ฆ Copiedโ€ฆ Very clever appโ€ฆ! Thanks @TyAlevizosโ€ฆ

@TyAlevizos first, awesome post, and Iโ€™m looking forward to digging into your app!

One thing Iโ€™m doing to get around the janky feelingโ€ฆ

I have a project table, with child task tableโ€ฆ Built as normal so you can create a project, then add tasksโ€ฆ I have three extra fields/columns at the project level.
is_template
creation_template
template_options

This allows you to โ€œconvertโ€ any project into a template. Then while creating a new project the user can simply choose a template to start from, if they choose one, then we reveal the enumlist template options showing all of the tasks that they can choose to include, pre selected.

Then on save we run our grouped actions conditional on ISNOTBLANK([creation_template]) that creates the downstream tasks. We drop the user into a quick edit table that will let them alter the tasksโ€ฆ

This process does a couple of neat things. First, you donโ€™t have to create additional screens, etc. The process of creating a project is always the same. Second it allows you to turn almost any parent table into templatesโ€ฆ Weโ€™ve almost started including this in all our tables. (If you donโ€™t include the template options then itโ€™s only two fields, one Boolean, the other an enumref drop-down.) So it creates a standard design model and user experience model.

Give it a shot.

Hi Grant,

Iโ€™m working on a Production app at the moment & am intrigued by your approach. I really like the idea that โ€˜The process of creating a project is always the sameโ€™โ€ฆ Sounds great! I have a few questionsโ€ฆ

Would it be possible to use a Dropdown for theโ€ฆ
is_template
create_template
template_options
โ€ฆor is it better to keep them in three separate columns?

Does your โ€˜Projectsโ€™ Table basically work the same as Tyโ€™s โ€˜Template Libraryโ€™ Table?

Do you use the โ€˜Project IDโ€™ for the key or the โ€˜User emailโ€™?

How do you โ€˜drop the user into a quick edit tableโ€™โ€ฆ Is it just by a Reference to the โ€˜Usersโ€™ Table? Or is it done in the โ€˜Detailsโ€™ View?

What details do the Users edit? Is it the โ€˜In Progressโ€™, โ€˜Completedโ€™ etc.?

Thanks
Darren

Hey Darren!
Congrats on choosing appsheet, itโ€™s amazing.

Iโ€™d leave them separate. They serve different functions. Keeping them distinct will make it easier for your developers to understand the intent. As a people we make boxes, it helps us understand.

Yes, my projects table also doubles as the templates.

Iโ€™m not sure I fully understand the rest of your questions. Mind clarifying on how they apply to your situation?

One more condition on the action is an in expression to make sure itโ€™s a new project, or to make sure it doesnโ€™t have tasks alreadyโ€ฆ You can include other rules to suit.

โ€œThen while creating a new project the user can simply choose a template to start fromโ€

This part is in the app I linked above, however:

โ€œThis allows you to โ€œconvertโ€ any project into a templateโ€

I didnโ€™t think to build something in the opposite direction! E.g. if I build a one-time workflow process Iโ€™d like it to also be a template. Thatโ€™s a cool idea.

But I guess in my app link above, the โ€œtemplates that have tasksโ€ (from the main menu) is the place where you would design something ad hoc. Maybe I could add a โ€œstatusโ€ flag like DRAFT | PRODUCTION so that end users can only select production workflows, or something like that.

I didnโ€™t want to go nuts over-building this though, so that the copy-and-customize would not be overly complex for the receiver of the app

Ohhh I like the template status instead of Booleanโ€ฆ I might have to look into thatโ€ฆ

Looking forward to looking under the hood later.

@Micah_Cole and @Martin_Pace when were talking about templating this is a good resource to reference.

One more errata or homework (future work) for this app:

** The USERS table should have an ENUMLIST for skills, e.g John Smith is good at / qualified for: Sorting, Painting, Reading RFPs and so forth.

** the TASKS in the task library should have a ENUM to allow a single skill type to be added to a task. A nice, atomic one to one relationship.

** With the above, when we create an instance of a template, when we fire off the child action to copy each task in the template to our new instance, we should be able to find which USER has the least number of open tasks by the skill set and assign the child task to that user.

Now we have a workflow engine with built in load balancer.

I can envision this in my mind but havenโ€™t had time to squirrel out the expressions. Should be doable though with a couple of complex select statements inside the actionsโ€ฆ and performant as the selects would happen on action time, and not at app load.

I changed the USERS Table [skills] to ENUMLIST type, which allows me to add several skills to each USER. However I now have some other columns on two Tables showing errors.

Tableโ€ฆ
USER SKILLS

The Column showing the errorโ€ฆ
[Current count of open steps for this skill] (Number)

The Formula isโ€ฆ
count(select(Step[Key], AND(
[AssignedTo] = [_THISROW].[Email],
[Skill] = [_THISROW].[Skill],
[Status] <> โ€œCompletedโ€
)
))

The error isโ€ฆ
Cannot compare Text with List in ([Skill] = [_THISROW-1].[Key].[Skill])

There is also another errorโ€ฆ
Tableโ€ฆ
โ€œTemplate Library Stepsโ€

The Column showing the errorโ€ฆ
[All users with this skill] (List)

The Formula isโ€ฆ
select(User Skills[Email], [Skill] = [_THISROW].[Skill])

The error isโ€ฆ
Cannot compare List with Text in ([Skill] = [_THISROW-1].[UniqueID].[Skill])

Iโ€™ve tried to change the Base type of the โ€œUSER SKILLS[Skill]โ€ to LongText but that doesnโ€™t work. I was thinking about changing the โ€œUSER SKILLS[Skill]โ€ to Base type โ€˜Refโ€™ but Iโ€™m not sure which way to go next. Iโ€™m thinking that I may have to use the IN() formula so as the โ€˜Load Balancingโ€™ can extract one of the skills.

Darren

Apologies but I have kind of moved on from this and wonโ€™t have time to take a close look. However:

That table is a child table. You should not convert skill from enum to enumlist and instead should add a second row for the given user. Otherwise, youโ€™re going to have to unwind the various logic throughout the rest of the app. Hope this helps!

Okay, so just keep it โ€˜one user = one skillโ€™

Could I ask one more questionโ€ฆ what triggers the โ€œRegen Request IDโ€ action?

  1. No you can have more than one skill: itโ€™s a child table and you can add a second, third, Nth skill to each user table entry.

  2. Regen ID is part of the main grouped action. I think I built that in the case where someone clicks the red button twice without making any other changes on that view.

OK another follow up. This stuff will nag and nag and nag my brain until I figure it outโ€ฆ

re: the concept of load balancing tasks among a group of users who have the skillset to perform the task

I was able to get this working in the above app. (If you already copied it, youโ€™ll need to copy it again). Itโ€™s some crazy gnarly expression work to get a list of โ€œpeople who have the least number of open tasks, which tasks have a given skillset assigned to themโ€.

  • People can have more than one skill, but
  • a task in the task library can have one and only one skill

Anyhoo, hereโ€™s a short video showing the end result:

And you will see the gnarly calcs in table โ€œTemplate Library Stepsโ€. These calcs are referenced in Action โ€œcopy template child to work order stepโ€

I was not able to place these calcs in the action itself. I wanted to for performance reasons. But the platform was ignoring the email assignments. I think this is due to the way we perform client-side vs. server-side expressions. I mention this in case - at scale - these calcs start to perform slowly.

And now, itโ€™s advil timeโ€ฆ

Awesome work! thank you for posting this Ty. Videos & Help files includedโ€ฆ perfect!

btw @Grant_Stead your idea of โ€œdropping a user into a quick edit tableโ€ on a grid to further edit the assignments was great, Iโ€™ve added that to the example. E.g. after an instance is created:

You can also hack the URL to force quick edit true, and then they have to hit saveโ€ฆ And you could change the save button to say finalize, or verifyโ€ฆ lol

Yeah actually, what is the url for a table quick edit mode? Pls elucidate

It was posted here:

@Grant_Stead - thatโ€™s nice. Iโ€™ve added this, and the idea of the โ€œFinishโ€ button, to the template above.

Hi guys.

Thank you again Ty for this sample app. Iโ€™m trying to adopt & integrate this app into our workflow.

Iโ€™m having a problem with the โ€˜Create New Instance +โ€™ actionโ€ฆ it keeps disappearing! It is still set to โ€˜Display Prominentlyโ€™. Iโ€™ve tried to go back through the versions to see if I can get it back with no success.

Iโ€™m asking for help now because even when I copy Tyโ€™s app again, the action is still not showing even in the sample app.

Iโ€™m thinking that it may have something to do with having two views with the same name. Can this cause any issues?

Thanks,
Darren

Actually thatโ€™s a bug. Iโ€™ve fixed the app on my side. Work order request is โ€œsecurity filteredโ€ per-useremail, but the view is set to Show-if for this condition:
count(Work Order Request[UniqueID]) = 1

The trick is to add a second view of type โ€œformโ€ whose show-if is:
count(Work Order Request[UniqueID]) = 0

I have updated the original app. Thanks for catching that!

Sorry to be back again but I still canโ€™t see the โ€˜Create New Instanceโ€™ action in my version of your app.

I added a second view of type โ€˜formโ€™ for the โ€˜Work Order Requestโ€™, & entered the โ€˜Show_ifโ€™ as mentionedโ€ฆ
count(Work Order Request[UniqueID]) = 0

I have also copied the original app again & cannot see the action in there either.

Thanks,
Darren

screenshots will help.

@Brand-It just to be clear: I was asking for screenshots on your side as opposed to stating that screenshots would help on my side

Yes I knowโ€ฆ Iโ€™m just not sure which screen shoots to post

Iโ€™ve been working on it all day trying to get the action backโ€ฆ I know that Iโ€™ll learn more if I can sort it myself but Iโ€™m running out of options.

I donโ€™t mind spending the time going through every setting & checking them against your sample app. However even when I copy your sample app again (from the link above) to use as a reference, the action is not showing for me in that either.

Got itโ€ฆ Iโ€™ve got the Action button to show again.

I think that it was something to do with my โ€˜Request_Detailโ€™ & โ€˜Request_Formโ€™ views being mixed up.

This is a great appโ€ฆ Iโ€™m definitely going to be using this a lot. I really like the โ€˜Predecessorโ€™ options, making it very versatile.

Thanks for the help,
Darren

Top Labels in this Space