I figured out why some addons were also listen under “Other”, it again has to do with some weirdness of the “demo app”. The “Other” category consists of all add-ons that aren’t of type “eclipse”, “karaf” or “marketplace”:
otherAddons () {
return Object.keys(this.addons).filter((k) => k !== 'eclipse' && k !== 'karaf' && k !== 'marketplace').flatMap((k) => this.addons[k]).filter((a) => this.isInFilter(a)).filter((a) => !this.suggestedAddons.includes(a))
},
In reality that means JARs dropped in the addons folder and those available from a JSON marketplace. For some magical reason, the add-ons provided via Maven/Eclipse are registered both as “eclipse” and as “jar” add-ons when running the “demo app”. So, that’s not actually a “problem”, it’s just another one of those “weirdnesses” that applies to the “demo app”.
So, instead, I started a “webui dev server” (npm start) with my tweaked code that works against the REST API of my production OH installation. There I have nothing under “Other”, and I haven’t enabled “show incompatible & unpublished”, which means that this is the view I get with my above tweak.
There’s no possibility to categorize them “by type of transformation” without changing things in Core as far as I can see. The way it is done with “automation” is that contentType is used to categorize by. Unfortunately (?), all transformations share the same contentType, so that’s not on option:
public class MarketplaceConstants {
public static final String JAR_CONTENT_TYPE = "application/vnd.openhab.bundle";
public static final String KAR_CONTENT_TYPE = "application/vnd.openhab.feature;type=karfile";
public static final String RULETEMPLATES_CONTENT_TYPE = "application/vnd.openhab.ruletemplate";
public static final String UIWIDGETS_CONTENT_TYPE = "application/vnd.openhab.uicomponent;type=widget";
public static final String BLOCKLIBRARIES_CONTENT_TYPE = "application/vnd.openhab.uicomponent;type=blocks";
public static final String TRANSFORMATIONS_CONTENT_TYPE = "application/vnd.openhab.transformation";
public static final String JAR_DOWNLOAD_URL_PROPERTY = "jar_download_url";
public static final String KAR_DOWNLOAD_URL_PROPERTY = "kar_download_url";
public static final String JSON_DOWNLOAD_URL_PROPERTY = "json_download_url";
public static final String YAML_DOWNLOAD_URL_PROPERTY = "yaml_download_url";
}
The contentTypes could be changed of course, but that would have to be done in Core, and there would have to be a meaningful way to assign the correct type without first having to parse the content of the add-on. Once there is a way to differentiate them, it would be easy to add a “type extension” also for transformations, e.g application/vnd.openhab.transformation;type=map. But these “structural changes” would be needed to have the necessary information available for MainUI to tell them apart.
Unfortunately, the way this is currently done is a bit “fishy”. Core has the concept of AddonType (new AddonTypes can be created dynamically by code, these are the default ones):
public static final AddonType AUTOMATION = new AddonType("automation", "Automation");
public static final AddonType BINDING = new AddonType("binding", "Bindings");
public static final AddonType MISC = new AddonType("misc", "Misc");
public static final AddonType PERSISTENCE = new AddonType("persistence", "Persistence");
public static final AddonType TRANSFORMATION = new AddonType("transformation", "Transformations");
public static final AddonType UI = new AddonType("ui", "User Interfaces");
public static final AddonType VOICE = new AddonType("voice", "Voice");
..while the categories come straight from Discourse as integer values:
private static final Integer BUNDLES_CATEGORY = 73;
private static final Integer RULETEMPLATES_CATEGORY = 74;
private static final Integer UIWIDGETS_CATEGORY = 75;
private static final Integer BLOCKLIBRARIES_CATEGORY = 76;
private static final Integer TRANSFORMATIONS_CATEGORY = 80;
This is then all “mapped” like this:
private @Nullable AddonType getAddonType(@Nullable Integer category, List<String> tags) {
// check if we can determine the addon type from the category
if (TRANSFORMATIONS_CATEGORY.equals(category)) {
return AddonType.TRANSFORMATION;
} else if (RULETEMPLATES_CATEGORY.equals(category)) {
return AddonType.AUTOMATION;
} else if (UIWIDGETS_CATEGORY.equals(category)) {
return AddonType.UI;
} else if (BLOCKLIBRARIES_CATEGORY.equals(category)) {
return AddonType.AUTOMATION;
} else if (BUNDLES_CATEGORY.equals(category)) {
// try to get it from tags if we have tags
return AddonType.DEFAULT_TYPES.stream().filter(type -> tags.contains(type.getId())).findFirst()
.orElse(null);
}
// or return null
return null;
}
To sum it up, all that can be done without some restructuring in Core, is to separate between “official”, “markedplace” and “other” similar to my tweak, as far as I can understand.