SkySpark by SkyFoundry

10. NavTrees

Overview

Project navigation is organized using a concept called nav trees. A nav tree is a named application-specific tree used to navigate records with specific tags. Each extension may define multiple nav trees. Some of the common nav trees are:

Each navigation tree has a nav path which defines each level of the tree using a tag name separated by a forward slash. For example the default equip tree path is:

/site/equip/point

If we wished to organize sites using a region level then:

/region/site/equip/point

Square brackets may be used to indicate that a level is optional. For example if some sites organize their equipment using floors, but not all sites, then we might have a path like:

/site/[floor]/equip/point

The first and last levels may not be optional. Also optional levels may only be between required levels.

For every level of the tree, there must be a corresponding ref tag pointing up to every ancestor level. For example lets assume we have this nav path definition:

/region/site/floor/equip/point

This means that the root recs must define the region tag. The next level of the tree includes all recs with the site tag. Each site must define a regionRef tag indicating its parent. The next level of the tree is recs with floor tag. Each floor must define both a regionRef and siteRef tag. Likewise each equip must define regionRef, siteRef, and floorRef. Summary of tags at each level:

Level 0: region
Level 1: site, regionRef
Level 2: floor, regionRef, siteRef
Level 3: equip, regionRef, siteRef, floorRef
Level 4: point, regionRef, siteRef, floorRef, equipRef

Every project has one navMeta record used to customize the navigation for that specific project. Extensions that define nav trees will automatically publish a tag on the navMeta to define the default nav path. But this can be easily customized. For example the "equip" tree's path is defined as a tag named equipPath. Use the Folio app to query for navMeta to manually edit the nav configuration.

Dependent Trees

Some navigation trees are designed to use the configured path of another tree. We call these dependent trees. For example "sparkTarget" always uses the path of the "equip" tree. The "kpiTarget" tree uses the "equip" tree also, but clips it to the "site" level. The navTrees function indicates which trees are dependent.

The following functions are available to navigate a nav tree:

All the navigation functions take a tree name such as "equip". The base is null for the root or you may use either a Ref or Dict to indicate which base record.

Often we are looking for a specific type of record in a tree. For example we might just be interested in the site recs under the "equip" tree. In this case we can use the "stop" option to indicate we are only navigating to recs with the site tag:

navChildren("equip", null, {stop:"site"})

Navigation trees may be used to create filters for batch selection. For example the "sparkTarget" tree is used to select which sites, equip, and points to examine for sparks. We might wish to look at all targets in the project, all targets under a specific site or group of sites, or maybe just a specific piece of equipment.

The navFilter function is used to define a filter from a navigation tree. For example, in the demo to look at all sparks under Carytown we could build a navigation filter like this:

navFilter("sparkTarget", read(dis=="Carytown")).sparks(lastWeek)

Or if we wanted to examine both Carytown and Gaithersburg:

navFilter("sparkTarget", [read(dis=="Carytown"), read(dis=="Gaithersburg")])
  .sparks(lastWeek)

Or we could just pass the Ref of each base rec. If we want to get all spark targets in the project then we can use null:

navFilter("sparkTarget", null).sparks(lastWeek)

The navFilter itself is just a grid that defines the base. It gets exploded into a record list automatically by the toRecList function. For example to explode a site into all the points under the navigation tree:

navFilter("equip", read(dis=="Gaithersburg"), {targetTag:"point"}).toRecList

Functions like sparks and kpis will automatically do this, so you can pipe a navFilter result to them.

Default Nav Filters

Fresco apps will initially use a default nav filter which can be accessed programmatically by passing the string literal "default" for the base:

navFilter("sparkTarget", "default").sparks(lastWeek)

The standard default filter is the same as root (or all targets), but it may be customized on a per user or a per project basis. Each tree's default filter is customized with a tag using the naming convention "{tree}FilterDefault" and a string value which is the comma separated list of refs encoded with the leading "@":

sparkTargetFilterDefault: "@1858a4e5-07d7e8d1,@1858a4ee-85b94fec"

Use an empty string to create a default filter which is empty. To customize on a per project basis, this tag should be added to the navMeta record. To customize a per user basis add to the user record. The User configuration trumps the navMeta configuration.

Access Filters

Access filters allow navigation to be customized on a per user basis. Each level of a nav tree maps to a tag name such as site or equip. You can restrict which records are visible to a user by adding a tag on the user record with the naming convention "{tag}AccessFilter". The value of the tag is a string filter. For example if you wish to restrict a user to only sites with geoState of "VA" and only equip with the hvac tag:

siteAccessFilter: geoState=="VA"
equipAccessFilter: hvac

Any tag you use as a level in a nav tree may have an access filter. Note that access filters may not use pathing via the -> operator (for performance reasons).

Note: access filters do not provide REST wire protocol security. They merely limit visibility for standard Fresco applications.

The search functionality in the navigation functions and dialogs is currently based on a case insensitive match against the record's dis string.