App Component Reuse Solution

1. Summary

  • We would like to take a subset (Data, UX and Behavior) of an App and be able to reuse this subset into another existing App quickly and reliably. (See example in figures 1 and 2).
  • We propose a solution which is much faster and safer than replicating each single change by hand. (See Figures 3 and 4).
  • The solution is intentionally simple but it is powerful, flexible and fairly easy to implement. There is no hidden magic, the App Author is in control of every step.



op04


2. The Problem (Why we need this)

2.1 Description of the problem

  • It is not possible to take a subset of the Data, UX and Behavior of an App and reuse this subset in another existing App without redoing all changes manually in the App Editor.

2.2 Examples of the problem

2.2.1 Replicating a complex feature in another App is a lot of work

  • We have two existing Apps, App A and App B. We need to add in App B a complex feature that we already have in App A. Since this feature consists of a set of interrelated tables, columns, views and actions, the only way at present is to open App B with the App Editor and to manually enter all these objects and their properties by looking in detail at what we did in App A. This is time consuming and error prone. (See an example in Figures 1 and 2)

2.2.2 One general App VS Many specific Apps dilemma

  • When we use AppSheet to build Apps, we eventually end up with a set of Apps for a given Line of Business. Often there are some common features needed by the Apps. Example of such common features are : People and Organizations, Access Control, Projects and Tasks, Approval Workflows, Notifications, etc. Once we have built such a feature in an App and need to add it to other Apps we are faced with a dilemma. One choice is to merge all the specific Apps into a single general App that has all the common features; this causes negative issues : performance degradation because of the large number of tables and also difficulty to maintain a big App. Another choice is to recreate the common feature into each of the specific Apps; this is tedious and error-prone, especially that we will have to redo it in all apps every time we make a change of logic to a common feature.

2.2.3 App Templates do not help in the long run

  • App Templates that include common features may help save time when you first create an App, but when business rules require changes in a common feature, you still have to manually make the same changes in all the Apps that were derived from the template.

2.2.4 Two authors cannot work in parallel on an App and merge their work

  • It is often beneficial for an organization when two people work on an App because it fosters sharing ideas for business process improvement and ensures that more than one person understand the internals of an App. Ideally each author would work on his own copy of the App to build a feature, then the co-author can review it before the feature is merged into the main version. At present, an author can Upgrade an App based on another App copy, but the Upgrade takes the complete App. Therefore the other author has to wait his turn to make his own copy and start to work on his feature.

3. The Goal (What we need)

  • We define a “Component” in an AppSheet App as a set of Objects that work together to provide a feature.
  • The Object types that can be put in a Component are : a Table’s Set of Columns, an Action, a Slice, a View, a Format Rule, a Workflow Rule, a Report Rule.
  • To determine the contents of a Component, we want to be able to Tag Objects as soon as we add or modify them in the App Editor.
  • We would like to take a Component of an App and be able to add or update this Component into another existing App quickly and reliably, without having to enter the properties of the Objects.

4. The Solution (How to do it)

4.1 Description of the Solution

  • A Component is stored in a json file in which each Object has a name, a type, a set of properties and the values of the properties. (See Figures 3 and 4)
  • In the App Editor, if an Object is included in a Component, the App Author enters a Tag in the Descriptive Comment property, for example “#Component_RBAC”. An Object can have more than one Component Tag in the Descriptive Comment property.
  • In the App Editor for an existing App A, in Manage / Author / Components, the button “EXPORT an App Component Object” opens a dialog asking for a Component Tag and then filters only the Objects for which the Descriptive Comment property contains this tag. The resulting list of Objects is shown to the Author who may then copy the list to the clipboard for documentation purposes. The user must then enter the name of local file that will be created and click OK. For each object in the list, the Export operation will read App A’s Object properties and their values and write them to the file in json format, creating a Component. (See Figure 3)
  • In the App Editor for an existing App B, in Manage / Author / Components, the button “IMPORT an App Component Object” asks to choose an existing local json file (a Component of App A) and opens a popup list which allows to select by name an Object for which the values of its properties will be entered in the corresponding fields in the App Editor form. The import operation asks for confirmation before replacing an object that is already present in the App. The order of imports matters because some Objects depend on others (i.e. a grouped action depends on actions, a slice may depend on a action, a view may depend on a slice). Generally the Author should import Objects in this order : Table’s Column Set, Action, Slice, View, Format Rule, Workflow Rule, Report Rule. Any errors found in the file are shown in a dialog popup, but the App Editor will also validate properties values like when they are entered by hand. By default, subsequent imports read from the same file as the previous import operation. (See Figure 4)

4.2 Important Notes about the solution

  • There is no table object in export nor in import, since the tables and their columns are always created by manually copying the table(s) from App A into the data source of App B and then by adding these as new tables of App B in the App Editor.
  • For a “Table’s Set of Columns” object, the import operation checks that the set of column names in the Component exactly matches the set of column names of the existing table in App B; if not it opens an error popup. The import does not create columns, it simply updates the properties of the columns in the App.
  • The App Editor performs the same validations that are done when entering properties values manually. The App author has to correct errors manually and later has to click the Save button.
  • The Component file is in json format because :
    • We must be able to open the file in an external text editor when it is necessary to rename some identifiers, for example when there are name conflicts with names in the target App or when expressions in the Component must reference columns in tables of the target App.
    • When a Component is updated in an App and exported to a new Component file, in order to know which objects have been added or changed in the component, we must be able to find the difference between the old and new json files, using a tool such as “json-diff”; this is very useful to minimize the number of object imports in other Apps that use this Component.

4.3 Examples of applying the solution

4.3.1 Example : Creating and Reusing a Component

  • Description of the case : We have an Inventory Management App (App A) that includes a “Role Based Access Control” (RBAC) feature to manage what users can see, update, add etc. We also have a Field Service App (App B) that was built a while ago without Access Control. Now we get a request to add the RBAC feature to App B. This feature has 5 tables, 4 slices, 9 views, 12 actions. (See Figures 1 and 2).
  • Steps to perform
    • Make notes that :
      • Since App B already has a table called “Member” which has a different purpose, in the Component we will have to rename “Member” to become “Person” everywhere, including in expressions.
      • Table Person (renamed from Member) in the Component has a column EmployeeID that will have to reference Table Employee in App B.
    • Open App A in the App Editor
      • Enter a Tag#Component_RBAC” in the Descriptive Comment property of each of the Objects included in the RBAC feature of App A :
        • 5 objects which are Table Column Sets : Member, Role, Permission, MemberRole, RolePermission
        • 4 objects which are Slices : S_Role, S_RolePermission, S_MemberRole, S_MemberRole_a
        • 9 objects which are Views : v_Role_detail, v_Role_form, v_Role_inline, v_RolePermission_detail, v_RolePermission_form, v_RolePermission_inline, v_MemberRole_detail, v_MemberRole_form, v_MemberRole_inline
        • 12 objects which are Actions : a_member_grp, a_member_member_exec_permissions, a_member_memberrole_add, a_member_memberrole_all, a_member_permissions, a_member_permissions_sel, a_member_role_all, a_member_roleperm_all, a_memberrole_delete, a_roleperm_add, a_roleperm_delete, a_roleperm_export_csv.
      • In Manage / Author / Components, click on button “Export an App Component Object”, then in the popup enter tag “#Component_RBAC” and click Filter, look at the list of objects to make sure it is complete, then click Export, then in the dialog enter the file name to be created “App_A_RBAC.json”, then click OK. (See Figure 3)
    • Copy the 5 tables from App A’s data source to App B’s data source and then replace the text “Member” by “Person” in the table name and in all column names.
    • Open file “App_A_RBAC.json” in a Text Editor, replace the text “Member” by “Person” everywhere.
    • Open App B in the App Editor
      • In Data / Tables, add the 5 new tables : Person, Role, Permission, PersonRole, RolePermission.
      • In Data / Columns, choose Table Person, expand Column EmployeeID, (it already has type Ref) and set the Source Table to Employee.
      • For each of objects in the Component, do the following in the proper order so that dependencies are satisfied (An Object on which other Objects depend must be imported first) : In Manage / Author / Components, click on button “Import an App Component Object”, then in the popup choose file name “App_A_RBAC.json” (for subsequent imports simply accept the same file which will be remembered by default), then in the selection popup scroll to the line having the Object to import, then select the line and click OK. The App Editor will then automatically open the properties form for the object that was imported so that we can check that there are no errors, then click “Save”. (See Figure 4)

4.3.2 Example : Updating a Component

  • Description of the case : App A has evolved over time and its original RBAC feature has been improved, with two new actions being added and a few slices and views modified. App B already has the original RBAC Component, but we want to update it so that it benefits from the improvements. Instead of having to manually find all the changes in App A that we need to redo in App B, we want to refer to the RBAC Component that we created in example 1 and import the changes to this Component into App B.
  • Steps to follow
    • Remember that since App B already has a table called “Member” which has a different purpose, in the Component we will again have to rename “Member” to become “Person” everywhere, including in expressions.
    • Open App A in the App Editor
      • Enter a Tag#Component_RBAC” in the Descriptive Comment of each of the Objects that were added in the RBAC feature of App A since the last time we first imported the Component into App B. These are the 2 Actions : a_member_permission_add and a_member_permission_delete.
      • In Manage / Author / Components, click on button “Export an App Component Object”, then in the popup enter tag “#Component_RBAC” and click Filter, look at the list of objects to make sure it is complete, then click Export, then enter file name “App_A_RBAC_v2.json”, then click OK. (See Figure 3)
    • To find which Objects must be imported in App B, compare files “App_A_RBAC.json” and “App_A_RBAC_v2.json” using a tool such as www.jsondiff.com; we find 6 Objects that were added or changed : Action a_member_permission_add, Action a_member_permission_add, Slice S_RolePermission, View v_RolePermission_detail, View v_RolePermission_form, View v_RolePermission_inline.
    • Open file “App_A_RBAC_v2.json” in a Text Editor, replace the text “Member” by “Person” everywhere.
    • Open App B in the App Editor
      • For Each of the 6 objects that we found above, do the following in the proper order so that dependencies are satisfied (An Object on which other Objects depend must be imported first) : In Manage / Author / Components, click on button “Import an App Component Object”, then in the popup choose file name “App_A_RBAC_v2.json” (for subsequent imports simply accept the same file which will be remembered by default), then in the selection popup scroll to the line having the Object to import, then select the line and click OK. The App Editor will then automatically open the properties form for the object that was imported so that we can check that there are no errors, then click “Save”. (See Figure 4)

5. References

This June 2020 topic presents many Reusability Ideas as well as a list of related topics in the Community

6. Final thoughts

  • This is a long post which has too much detail for a Feature Request, but I feel a Modularity / Reusability solution is long overdue. I really care about AppSheet.
  • I welcome comments from the AppSheet Community about this Proposed Feature. In particular, I have probably forgotten some details and many heads are better than one.

The holy grail we’ve been begging for…
For-ev-er (Sandlot)

I’ve managed to figure out ways to make AppSheet automatically configure columns when you import or regenerate the column structure; that’s how I accomplished In-App Guides.

  • The problem is really with the method required to produce the code necessary for things to work; the app I’ve built is… complicated, to put it lightly.
    • I’ve thought long and hard, put many dozens of hours into things, to try and bring something like that to the public; but ultimately it’s wrought with problems and pitfalls - so it’ll likely never see the light of day.

Appsheet - long ago - talked about the ability to copy portions of your app and carry them over to others; hopefully they’re listening again. partyparrot (Appsheet)

5 Likes

@praveen thought you might like to see this.

4 Likes

I have read this post and agree with the concept of it. I also think you might consider how your concept my work more operationally if you want to share the development of the reusable item with others outside your organisation (to avoid reinventing the wheel).

I am not sure if having external files which require renaming items within is a good idea where some mapping could be done within each dependant app with the re-useable component.

I think a good place to start is with having expressions made reusable just so we can get something simple and manageable?

3 Likes

@aucforum Hi Colin, Thanks for your comment.

a) To share a component outside of an organization, I think that a possible method is to provide an example App that includes the component and to have detailed documentation of the component’s tables, columns, slices, views and actions. This will allow other authors to try the App, understand its behavior and then use the Export feature to get the .json component from the App.

b) I propose a solution based on the Export / Import of a .json file for a component, in order to keep the solution very simple. There are no changes in the App Interpreter, so testing by the AppSheet team will be faster because there is no risk of breaking the large number of Apps in production. The Export and Import features are only in the App Editor, so it should be feasible to develop this rapidly.

c) I see no simple way to make AppSheet expressions “reusable” because they work on named columns, and have no parameters. Also the foreign keys in a component may refer to columns elsewhere in the App, and vice-versa. Therefore when “hooking” a component to a new App, these references have to be verified. Within an organization, naming conventions for tables and columns may allow a component to be reused without renaming some identifiers. However, with existing Apps built by different people without naming standards, hooking a component will require renaming of some of its tables or columns.

d) I have reread your June 2020 post about Reusable Items and I think that it has great potential. I just propose a very basic solution which does much less than yours, but hopefully could be available quickly. I totally agree with you that we definitely need some reusability and modularity in AppSheet.

1 Like

a, b) I can see the advantages of .json as a simple solution. I think some library, catalogue or even shop might be good for promoting and distributing shared componets like the .json with.

c) I think I had suggested Parameters previously as a key feature of reusable components, including expressions (and maybe charts). I would have appsheet within the reusable features to allo to map references, tables, columns etc, plus parameters of course. It would avoid the need to edit any external file.

d) I would think the suggestion of the .json file might be good, simple step forward, if it makes it possible to get this major feature started. (See my reply to a, b.)

1 Like

Did Praveen respond to this as far as you know?

1 Like

Negative. I know in the past it’s a direction he was trying to get to.

1 Like

I dare say, the inefficiency of repeating so many items of Appsheet has discouraged me from making or improving any more applications that I might make or more critically recommend it as a platform for others to use.

I notice you @lamontfr too want to make a viable business out of developing Appsheet Solutions. I am hoping they might follow through with this suggestion I made:

1 Like

Has anyone sought @tony attention on this request yet?

@aucforum @Grant_Stead

Thanks for helping to get some attention from AppSheet about this issue.