Entry in Platform > Configured Items

I’m checking to make sure my mental model for the Ignition 8.3 config experience is correct.

Our module has registered its own configuration page under the Connections section (Seeq > Settings).

I noticed that under the Platform section, there’s also an entry for “Seeq Settings” and I’m not sure what causes that. Should I do something in my module code to remove that? Or do something to cause a “Configure” hyperlink to appear on the right?

Okay, so there's a few concepts to unpack here.

Most fundamentally, what you're looking at on the "Overview" page is surfaced by the new to 8.3 EntityManager API.

As mentioned in the Javadoc there:

NOTE: the entity system is automatically aware of the configuration Resource system. Any resources that have a ResourceTypeMeta registered will automatically be included in the configuration entity.

That's why you have an entry automatically.
It looks like the link to the configure section is attached to whether your Category definition has is providing a set of ResourceTypes - which it isn't unless you've changed the code since you posted it here: Ignition 8.3: Controlling placement of nav entries :smiley:

That default behavior, linking based on associated resource types, is ultimately decided by the DefaultResourceEntityDelegate we're creating for you in DefaultResourceTypeMeta.Builder - if you don't provide or customize one, the no-arg constructor of the default resource entity delegate is used, but you can also provide your own or customize it via withEntityDelegate or buildEntityDelegate on your type meta builder.

The general recommendation is to have it show up on the platform overview page (which is deliberately meant to be "absolutely everything on this particular gateway"), with customization as needed to tweak the behavior.

1 Like

Hey Paul, I’m stabbing around but feeling lost.

I would love for there to be a Configure hyperlink on the right that takes the user to my settings page… Here’s what my resource code looks like, what do I need to add?

    public static final ResourceTypeMeta<IgnitionModuleConfigurationV2> RESOURCE_TYPE_META =
            ResourceTypeMeta.newBuilder(IgnitionModuleConfigurationV2.class)
                    .resourceType(RESOURCE_TYPE)
                    .categoryName("Seeq Settings")
                    // Call buildGson if you need to register any custom
                    // JsonSerializer/Deserializer classes.
                    // You may omit this call to use default GSON serialization.
                    //                    .buildGson(gson -> gson.registerTypeAdapter(
                    //                            IgnitionModuleConfigurationV2.class,
                    //                                    new CustomSettingsGsonEncoder()
                    //                            )
                    //                    )
                    // You must call this to opt-into the route system
                    .buildRouteDelegate(routes -> routes
                            .configSchema(IgnitionModuleConfigurationV2.class)
                            .openApiGroupName("Seeq")
                            .openApiTagName("settings")
                    )
                    // The status delegate is optional.
                    // It allows you to associate metrics and healthchecks with
                    // instances of your resource
                    .buildStatusDelegate(status -> status
                            .instanceMetric("throughput", "mymodule.%s.throughput")
                            .instanceHealthCheck("status", "mymodule.%s.status"))

                    // The 'reference delegate' is used to register any properties in
                    // your resource that are references to other properties.
                    // Each reference property needs a reference finder that knows how
                    // to match references as well as create updated copies of your resource
                    // used for when the referenced resource is renamed.
                    // In this example, pretend the "bar" property is the name of another
                    // resource of type BAR_RESOURCE_TYPE.
                    //                    .buildReferenceDelegate(refs -> refs
                    //                            .referenceProperty("bar", refFinder -> refFinder
                    //                                    .targetType(BAR_RESOURCE_TYPE)
                    //                                    .match((mySettings, name) -> mySettings.bar().equals(name))
                    //                                    .onUpdate((mySettings, newName) ->
                    //                                            new MySettingsResource(mySettings.foo(), newName)
                    //                                    )
                    //                            )
                    //                    )
                    .build();

What does your Category definition look like?

Here’s all the relevant code I think around categories:

        this.context.getConfigurationManager().getResourceTypeMetaRegistry()
                .register(IgnitionModuleConfigurationV2.RESOURCE_TYPE_META);


        // Register GatewayHook.properties by registering the GatewayHook.class with BundleUtils
        BundleUtil.get().addBundle("Seeq", this.getClass(), "Seeq");

        this.context.getConfigurationManager().getResourceTypeMetaRegistry()
                .register(IgnitionModuleConfigurationV2.RESOURCE_TYPE_META);

        this.configHandler = SingletonResourceHandler.newBuilder(
                        IgnitionModuleConfigurationV2.RESOURCE_TYPE_META
                )
                .context(this.context)
                .onChange(seeqSettingsRecord -> {
                    this.settingsChangedEvent.set();
                })
                .build();


        SystemJsModule jsModule =
                new SystemJsModule("com.seeq.ignition.SeeqSettings", "/res/seeq/seeqSettings.js");

        this.context.getWebResourceManager().getNavigationModel().getConnections()
                .addCategory("seeq", cat -> cat
                        // See https://forum.inductiveautomation.com/t/ignition-8-3-controlling-placement-of-nav-entries/113736
                        .position(120)
                        .label("Seeq")
                        .addPage("Settings", page -> page
                                .position(0)
                                // Note the second parameter is the name of the JS component that was exported
                                .mount("/seeq/settings", "SeeqSettings", jsModule)
                        )
                );

Use the addAssociatedResourceType on your category builder instance, and the default entity delegate should see that automatically and figure it out.

If that doesn't automatically work, you could provide your own ResourceEntityDelegate from your ResourceTypeMeta; I would strongly recommend extending DefaultResourceEntityDelegate and overriding buildEntity or maybe just configureNavigation.

The former method looks like this, which is why I'm guiding you to adjusting your category:

  protected Entity buildEntity(GatewayContext context, ResourceTypeMeta<?> meta) {
    EntityBuilder builder = new EntityBuilder(meta.getResourceCategoryName(Locale.getDefault()));

    builder.description(desc -> configureDescription(meta, desc));

    context
        .getWebResourceManager()
        .getNavigationModel()
        .findNavLocationForResourceType(meta.getResourceType())
        .ifPresent(
            location ->
                // This means we've found a navigation location for this resource type, so we can
                // add a navigation link
                builder.navigation(
                    location.path().getPathComponent(0),
                    nav -> configureNavigation(meta, location, nav)));

    configureDiagnostics(context, meta, builder);
    configureChildren(context, meta, builder);

    return builder.build();
  }

Where the findNavLocationForResourceType function is ultimately walking all categories, pages, and tabs to find a reference for a given resource type.

1 Like

Bingo! Here’s my new code, and now the Configure link shows up and works perfectly.

        this.context.getWebResourceManager().getNavigationModel().getConnections()
                .addCategory("seeq", cat -> cat
                        // See https://forum.inductiveautomation.com/t/ignition-8-3-controlling-placement-of-nav-entries/113736
                        .position(120)
                        .label("Seeq")
                        .addPage("Settings", page -> page
                                .position(0)
                                .addAssociatedResourceType(IgnitionModuleConfigurationV2.RESOURCE_TYPE)
                                // Note the second parameter is the name of the JS component that was exported
                                .mount("/seeq/settings", "SeeqSettings", jsModule)
                        )
                );
2 Likes