29 Oct 2018
Show a list like BIM 360 Docs Plans folder
BIM 360 Plans folder shows extracted views of a file, how can we mimic that via API?
First we have to start looking at the visibleType property, which defines what's visible on a given folder. On Plans folder that will be Document (and not Files). Then as we have 2 main attributes, we need to check both data for what's visible, then included to get views names, then back to data to find where it is visible (URN). The following C# sample is based on the Learn Forge tutorial, but it's modified as shown below (also full sample here).
private async Task<IList<jsTreeNode>> GetFolderContents(string href)
{
IList<jsTreeNode> nodes = new List<jsTreeNode>();
// the API SDK
FoldersApi folderApi = new FoldersApi();
folderApi.Configuration.AccessToken = Credentials.TokenInternal;
// extract the projectId & folderId from the href
string[] idParams = href.Split('/');
string folderId = idParams[idParams.Length - 1];
string projectId = idParams[idParams.Length - 3];
// check if folder specifies visible types
JArray visibleTypes = null;
dynamic folder = (await folderApi.GetFolderAsync(projectId, folderId)).ToJson();
if (folder.data.attributes != null && folder.data.attributes.extension != null && folder.data.attributes.extension.data != null && !(folder.data.attributes.extension.data is JArray) && folder.data.attributes.extension.data.visibleTypes != null)
visibleTypes = folder.data.attributes.extension.data.visibleTypes;
var folderContents = await folderApi.GetFolderContentsAsync(projectId, folderId);
// the GET Folder Contents has 2 main properties: data & included (not always available)
var folderData = new DynamicDictionaryItems(folderContents.data);
var folderIncluded = (folderContents.Dictionary.ContainsKey("included") ? new DynamicDictionaryItems(folderContents.included) : null);
// let's start iterating the FOLDER DATA
foreach (KeyValuePair<string, dynamic> folderContentItem in folderData)
{
// do we need to skip some items? based on the visibleTypes of this folder
string extension = folderContentItem.Value.attributes.extension.type;
if (extension.IndexOf("Folder") /*any folder*/ == -1 && visibleTypes != null && !visibleTypes.ToString().Contains(extension)) continue;
// if the type is items:autodesk.bim360:Document we need some manipulation...
if (extension.Equals("items:autodesk.bim360:Document"))
{
// as this is a DOCUMENT, lets interate the FOLDER INCLUDED to get the name (known issue)
foreach (KeyValuePair<string, dynamic> includedItem in folderIncluded)
{
// check if the id match...
if (includedItem.Value.relationships.item.data.id.IndexOf(folderContentItem.Value.id) != -1)
{
// found it! now we need to go back on the FOLDER DATA to get the respective FILE for this DOCUMENT
foreach (KeyValuePair<string, dynamic> folderContentItem1 in folderData)
{
if (folderContentItem1.Value.attributes.extension.type.IndexOf("File") == -1) continue; // skip if type is NOT File
// check if the sourceFileName match...
if (folderContentItem1.Value.attributes.extension.data.sourceFileName == includedItem.Value.attributes.extension.data.sourceFileName)
{
// ready!
// let's return for the jsTree with a special id:
// itemUrn|versionUrn|viewableId
// itemUrn: used as target_urn to get document issues
// versionUrn: used to launch the Viewer
// viewableId: which viewable should be loaded on the Viewer
// this information will be extracted when the user click on the tree node, see ForgeTree.js:136 (activate_node.jstree event handler)
string treeId = string.Format("{0}|{1}|{2}",
folderContentItem.Value.id, // item urn
Base64Encode(folderContentItem1.Value.relationships.tip.data.id), // version urn
includedItem.Value.attributes.extension.data.viewableId // viewableID
);
nodes.Add(new jsTreeNode(treeId, WebUtility.UrlDecode(includedItem.Value.attributes.name), "bim360documents", false));
}
}
}
}
}
else
{
// non-Plans folder items
nodes.Add(new jsTreeNode(folderContentItem.Value.links.self.href, folderContentItem.Value.attributes.displayName, (string)folderContentItem.Value.type, true));
}
}
return nodes;
}
Finally, as in most of our samples we show the 1st viewable, we need a small change to show a specific view instead (if that's the case). The following code is based on the Basic Application tutorial and we just need to modify the following (full sample here):
if (viewableId !== undefined) {
viewables.forEach(function (viewable) {
if (viewable.data.viewableID == viewableId)
viewerApp.selectItem(viewable.data, onItemLoadSuccess, onItemLoadFail);
});
}
else
viewerApp.selectItem(viewables[0].data, onItemLoadSuccess, onItemLoadFail); // this is the original line