A coworker and I are trying to build a “Search columns” feature that selectively hides columns in an object table. To do this without hard coding column names, we need to get an object type’s properties’ display names and api names from TypeScript. The code below gets the display names, but we need help getting the property api names. These usually look like “property_first_display_name”, “property_second_display_name”, etc. (see screenshot at bottom from Workshop after enabling “Variable-Backed Column Visibility”). The immediate goal is a TypeScript function similar to get_display_names, but even any suggestions, ideas, or guesses are greatly appreciated and encouraged here.
@Function()
public get_display_names(): string[] {
const properties = MyObjectType.properties as {[key: string]: {displayName: string}};
var names: string[] = [];
for (let key in properties) {
names.push(properties[key].displayName);
}
return names;
}
This tooltip is trying to indicate that the “API Names” are used for conditional visibility, but what it doesn’t highlight, is that these are generated by Workshop, so would not be available on the object type in a typescript function.
The Workshop UI is the place you can get these API names. They should remain stable over time since the variable backed conditional visibility feature relies on them.
Note: I don’t know why this website banned my reply with the word “i m p l”, but it’s critical here. Please accept this reply with that word obfuscated with spaces, but I’ll understand if this gets taken down.
One potential path is to get them from ontology-i m p l. I’ve never used this before, but the code below logs propertyTypeIds that seem to match the api names generated in Workshop (after “property_”). Is there a way to parse the class definition below in TypeScript?
import { MyObjectTypeI m p l } from "@foundry/ontology-api/my-env/ontology-i m p l/MyObjectTypeI m p l";
export class MyFunctions {
@Function()
public temp(): boolean {
console.log(MyObjectTypeI m p l)
return true;
}
}
Logs:
class MyObjectTypeI m p l {
constructor(osp, primaryKeySupplier, rid) {
this.osp = osp;
this.primaryKeySupplier = primaryKeySupplier;
this.rid = rid;
this.typeId = "xxx.my-object-type";
this[_a] = MyObjectType.MyObjectType;
this.primaryKey = primaryKeySupplier(this);
}
get firstProperty() {
const property = {
version: 2,
propertyTypeId: "first_property",
type: {
type: "string",
},
};
return this.osp.getPropertyValue(this, property);
}
get secondProperty() {
const property = {
version: 2,
propertyTypeId: "second_property",
type: {
type: "string",
},
};
return this.osp.getPropertyValue(this, property);
}
}
@evanj, thank you for noting that these can be pulled from the UI. That is my current solution, and I am trying to automate that step to prevent schema changes from breaking this. For context, the end goal looks like this (client data removed for privacy):
Your initial code already has the base setup. The api names would be accessible by replacing displayName with apiName in your code. So you can parse both property display name and api name by using the object type instead of the i m p l references:
import { MyObjectType } from "@foundry/ontology-api";
// ...
// get list of display names
Object.values(MyObjectType.properties).map(property => property.displayName);
// get list of api names
Object.values(MyObjectType.properties).map(property => property.apiName);
// or get both as an object pair
Object.values(MyObjectType.properties).map(property => ({
"apiName": property.apiName,
"displayName": property.displayName
}));
I figured it out by parsing the I m p l class definition. (Workshop uses different api names starting with “property_”.) Please let me know if there’s a way to avoid parsing the class definition with regex, but this is working for now:
@Function()
public get_property_type_ids(): string[] {
const str = MyObjTypeI m p l.toString();
const propertyTypeIds: string[] = [];
const regex = /propertyTypeId:\s*"([^"]+)"/g;
let match;
while ((match = regex.exec(str)) !== null) {
propertyTypeIds.push("property_" + match[1]);
}
return propertyTypeIds;
}
Here’s my updated code to map display names to workshop api names:
public get_columns(inputDisplayNames: string[]): string[] {
// Map property display names to API names
const properties = MyObjectType.properties as {[apiName: string]: {displayName: string}};
const apiNames: {[displayName: string]: string} = {};
for (let apiName in properties) {
apiNames[properties[apiName].displayName] = apiName;
}
// Map property API names to property type IDs
const str = MyObjectTypeI m p l.toString();
const propertyTypeIds: { [key: string]: string } = {};
const pattern = /get (\w+)\(\) ?\{[\s\S]*?propertyTypeId:\s*"([^"]+)"/g;
let match;
while ((match = pattern.exec(str)) !== null) {
const apiName = match[1];
const propertyTypeId = "property_" + match[2];
propertyTypeIds[apiName] = propertyTypeId;
}
// Return mapped property type IDs
const output = inputDisplayNames.map((displayName) => {
const apiName = apiNames[displayName];
if (!apiName) {
throw new Error(`Property display name "${displayName}" not found.`);
}
const propertyTypeId = propertyTypeIds[apiName];
if (!propertyTypeId) {
throw new Error(`Property API name "${apiName}" not found.`);
}
return propertyTypeId;
});
return output;
}