Automatically creating Perspective Navigation

Hi there,

Been having a lot of fun playing around with Ignition 8 and the new Perspective module!

I’ve been working on automatically creating all of the navigation based on the current folder structure setup in the project. If I add a new Folder or View, I want that to automatically be created in my NavTree and linked properly in the Page Configuration.

I have it working, but find myself wondering if there are some built in functions that can make it easier and more intuitive.

Currently, I’m using the python os library to determine which files and folders are present on the gateway under the perspective views folder and using that information I’m creating a item dict and writing that to a tag that is linked to via an expression binding on the NavTree.

I am then building a json string and writing it to the page-config json file to link up the navigation.

I have 2 questions:

  1. Is it possible to, using some undocumented function, get a list of all perspective views (including their path) in the current project? Akin to system.gui.getWindowNames() in Vision?
  2. Is it possible to programatically alter the Page Configuration without modifying the page-config/config.json stored on the filesystem?

Thanks for your time!

1 Like

No to both questions - but we do have plans to add similar “reflective” operations to Perspective as there are in vision, ie system.perspective.getMountedViews (or something like that). Exactly what that looks like, we’re not sure yet.

Once that’s possible, you should be able to use a binding on a navigation component to construct your views - no hacking into the resource directory required.

1 Like

Awesome, glad to hear you’re planning on adding those features.

I will use my current code and wait patiently for these features to be added :smiley:

Thank you for the reply!

Any idea on when this will be added?

1 Like

I want to 2nd this idea! any word on when the above mentioned feature set may be added?

No timeline, but I did just do what I could to escalate the existing ticket.

Ok, here’s my take on how to tackle this. Rather than add a scripting function, instead, I’d like to inject information about the current project into session props. I’m thinking an object at session.props.project that would be shaped like this:

{
  name: string,
  title: string,
  description: string,
  lastModified: date,
  lastModifiedBy: string,
  views: array< { path: string} >,
  pageConfigs: array< { url: string, primaryView: string } >
}

It’s a bit odd to have “views” be an array of objects with only one attribute in them, but I figure that way it’ll be more flexible in the future if we want to add more information in about each view.

Thoughts?

2 Likes

Would this poll, or it it static on Session Startup? Who gets listed under lastModifiedBy if I delete a View folder on the file system without going through the Designer? This is all read-only (system-level security), correct? I can’t write a new pageConfig entry on-the-fly?

1 Like

I’d be fine with that, really any mechanism inside Ignition to get the list of views that exist within a project works for me.

I currently have a script that runs whenever I save a project that checks the file system to find any newly added / removed views in project and stores them in a tag.

Having it built in means one less custom script I need to manage!

Would this poll, or it it static on Session Startup?

It would be updated on-demand as the project is changed.

Who gets listed under lastModifiedBy if I delete a View folder on the file system without going through the Designer?

“external”

This is all read-only (system-level security), correct?

Yes

I can’t write a new pageConfig entry on-the-fly?

No

We ended up implementing this as a scripting call after all. The json shape I indicated above will be returned from session.getProjectInfo() and system.perspective.getProjectInfo() as of 8.1.4

5 Likes

I’d like to use this getProjectInfo() function to retrieve the pageConfigs and automatically construct my Menu Tree navigation. However, there are a few drawbacks/limitations that have prevented me:

  • My project uses different icons in the Menu Tree for different pages. There doesn’t seem to be any way to define parameters like this in the Page Configuration that can then be retrieved by getProjectInfo().
    (viewParams can be configured for individual docked views, but not for individual primary views. Furthermore, the getProjectInfo() function doesn’t return the details of the docked views configured for each primary view.)

  • There seems to be no way to re-order pages in a Page Configuration. If I want to reorder items in my automatically generated Menu Tree navigation, I need to rebuild the Page Configuration from scratch.

Correct, there is no way to configure icons as part of the page definition, because pages don’t have icons - they’re entirely a concept of the Menu Tree. What you could do is provide logic to determine icons within your script. this would require you to maintain a dictionary system of page:icon listings.

The following script is for very basic structures. It could get very complicated depending on the nesting of your pages within the menu tree.

configs = system.perspective.getProjectInfo().pageConfigs
tree_items = []
icon_map = {
    "Home": "material/home",
    "Time": "material/access_time",
}
for config in configs:
    item = {}
    item['target'] = config.url
    item['label'] = config.primaryView.split("/")[-1]
    # default icon to navigation icon if no special icon is mapped
    item['navIcon']['path'] = icon_map.get(item['label'], "material/navigate")
    tree_items.append(item)
# I'm not sure where this is being called from, but you need to eventually set the value of the menu tree
self.getSibling('Menu Tree').props.items = tree_items

You’re already in a script, so you could order the configurations however you choose. You could sort them alpha (which I think is the default anyway), or you could build your own ordering algorithm.

# sort by the displayed label instead
# This could probably be done purely on self.props.items without needing to copy it
items = self.props.items.copy()
sorted(items, key=lambda item: item['label'])
self.props.items = items
1 Like