How can i get the list of link files from a translated compressed/zip of revit file? - autodesk-forge

I have translated a revit file with several link files. From viewer i can browse all elements from the root revit model including all elements from link files using 'Model Browser' default extension. Even i also created a custom extension from where i can isolate each object type's all elements.
Now, i want to create a extension like 'Model Browser', which will show Root file name as top or parent node and all link file's name as child node.I also want, by clicking each link file, all elements from that link file should isolate in the viewer and by clicking Root file, all elements including all link files elements should show .
For information, my application is built using C# and JavaScript in .Net platform.
Can anyone advice me which api, i can try? It would be also very helpful if someone share examples or url where i can get help.
Thanks in advance!

You can take advantage of the AecModelData to get linked models data and rebuild relationships from the PropertyDB inside Forge Viewer.
If an object is from the linked RVT, you can check its' external id. If the external id contains a slash symbol, then this means it is from a linked RVT. Here is an example:
Object extetnal id: ffa0b0a8-8aab-48f9-beb5-dba5d9b4968f-0010cfee/e021b7a9-1e57-428c-87db-8e087322cd49-0015a0f6
An instanceId from the linkedDocuments in the AECModelData: ffa0b0a8-8aab-48f9-beb5-dba5d9b4968f-0010cfee
You can see the GUID on the left side of the slash symbol matches the instance id mentioned above.
To get the linked RVT model name, we can reuse the instanceId from the linkedDocuments of the AECModelData to get the information we need again. Here is a code snippet for you, and assume the instance id is ffa0b0a8-8aab-48f9-beb5-dba5d9b4968f-0010cfee:
function getExternalIdMappingAsync( model ) {
return new Promise( ( resolve, reject ) => {
model.getExternalIdMapping(
map => resolve( map ),
error => reject( error )
);
});
}
function getPropertiesAsync( dbId, viewer ) {
return new Promise( ( resolve, reject ) => {
viewer.getProperties(
dbId,
result => resolve( result ),
error => reject( error )
);
});
}
//1. Get external id mapping for converting external id to Viewer's dbId
let externalIdMapping = await getExternalIdMappingAsync( viewer.model );
let dbId = externalIdMapping['ffa0b0a8-8aab-48f9-beb5-dba5d9b4968f-0010cfee'];
//2. Get properties of the linked model instance
let propResult = await getPropertiesAsync( dbId, viewer )
//3. Find the type name property for its value
let linkNameProp = propResult.properties.find( prop => prop.displayName == 'Type Name' || prop.attributeName == 'Type Name' );
let linkName = linkNameProp.displayValue; //!<<< This is linked RVT name
Here is the snapshot of my test:
Hope it helps~

Related

Forge Viewer_New model browser_Linked rvt files

Thank you all in advance for your help.
My problem is that in the model browser I can't see the elements organized by model. They are all seen together in no order. I have been able to load linked files via jobpayload with rootFilename. I have seen a lot of information about it but if someone has done it or has an idea of how to do it, I would greatly appreciate the help or start. All the best.
If the model is a composite Revit model translation, the host and linked RVT files are translated by a zip package, the model structure will be merged into a single tree, so it won't organize the tree structure by models.
However, we can tell which object is from the linked RVT. See the concept here:
https://stackoverflow.com/a/64672951
and here is a code example that I use this function to get their dbIds.
async getRevitLinkedElementIds(rvtLinkExternalIds, model) {
const modelKey = model.getModelKey();
const externalIdMap = this.modelExternalIdMaps[modelKey];
const entities = Object.entries(externalIdMap);
const linkedElementIds = rvtLinkExternalIds.map(instanceId => {
return entities.filter(entity => entity[0].includes(`${instanceId}/`)).map(entity => entity[1]);
})
.flat();
return linkedElementIds;
}
I think you can make use of the linkedElementIds, and then call model.getInstanceTree().getNodeParentId( dbId ) repeatedly until you get the root node id, so that you can get name of non-leaf nodes, e.g., Family Type, Family, and Category, to rebuild your own tree nodes using jstree.js. (Don't use non-leaf nodes' dbIds, since they are shared by the host and linked contents)
Afterward, you can build node data of the jstree.js like this for each models (host and links) to expand the tree structure of my custom panel in the code example.
[
{ id1, externalId: -1, type: 'revit-category', text: 'Curtain Panels' },
{ id2, externalId: -1, type: 'revit-family', text: 'System Panel' },
{ id3, externalId: -1, type: 'revit-family-type', text: 'Glazed' },
{ id4, externalId: '03d1b04e-ba90-4a0e-8fe2-eca95236e26a/ab343b7e-3705-4b87-bacc-33c06a6cee1d-000ee82e', type: 'revit-elements', text: 'System Panel [976942]' }
]

How to access any .json from windows file explorer in vuejs

I looked up how to access a .json file without saving it to my code base but was not able to find it - all posts are like this one: How to acces external json file objects in vue.js app
where they assumed that I could save the .json file in the code base like so: import json from './json/data.json' - they are going to call it json, it is in json folder from the file named data.json.
In my case, on the contrary, when the user tries to read their own .json file saved in their windows file explorer's "Download" folder, there can be one or multiple files, and the user will select any one of them to be accessed and read by the website.
Me as a developer don't own the file that the user will select, don't know which file the user will choose, therefore don't know the name of the file or the file content, and so, I cannot have that file saved in the code base.
Is there a way for me to enable the user to select any .json file they want, have that accessed and read?
Thank you.
UPDATE: from the suggestions from the comment section, fileSelector appears as null in the dev tool
<input type="file" id="file-selector" accept="application/JSON" multiple>
interface HTMLInputEvent extends Event {
target: HTMLInputElement & EventTarget;
}
mounted() {
const fileSelector = document.getElementById('file-selector');
fileSelector.addEventListener('change', (event: HTMLInputEvent) => {
let files: any = event.target.files[0];
const fileList = event.target.files;
console.log(fileList);
});
}
Apparently you're using Typescript, so your error is at runtime or at build time?
the type of the event argument doesn't seem correct to me, try:
fileSelector.addEventListener('change', (event: Event) => {
const files = (e.target as HTMLInputElement).files
})

Data from Mongo db arrives later than data from a json file on server in Next js App

I have a form that currently uses data from a json file.
The data is retrieved like so
const categoryList = require('../data/categories.json');
I am changing this to retrieve data from an api which fetches data from mongodb.
http://localhost:3000/api/categories
The above link gives me same results as the json file.
import { getCategories } from '../../lib/hooks';
....
const PostEditor = () => {
const [categories] = getCategories(); // this gives me all the categories from api as an array
console.log("categories from db")
console.log(categories)
const catList = require('../data/categories.json'); // same result as above
console.log("cat list from json file")
console.log(catList)
...
...
return (
<>
...
...
<Autocomplete
multiple
options={catList} // Data from db(categories field) does not reach here.
limitTags={2}
From the above code, both console log from db and console log from the json file have same values in browser.
The console log in command prompt shows values from db as "undefined". I think the data from db is not reaching the page in time but from the json file it does.
How to solve this problem?
I use Next js.
Edit:
I moved the data fetching from Api into a parent component (directly under pages) and passed the categories as props to the child component
<PostEditor categories={cats}/>
Still facing the same issue.
As mongodb data is external, so it's taking time to load. You have to call asynchronously. Check like this:
const PostEditor = async() => {
const [categories] = await getCategories();
...
}

How do I display json get result using Wix Code?

I'm working with a non-profit cat shelter trying to update their website. They want to have a page that connects to their shelter manager software to display the available cats for adoption. Luckily, their shelter manager offers API calls to get the information I need from it.
They use Wix as their platform and are pretty set on keeping it as most of their volunteers know how to make easy adjustments to other pages. I researched and found Wix offers the ability to connect to the API using their fetch method.
Basically, I am trying to get a dynamic page to display a repeater that is populated from their json API Get method.
Currently, for the backend I have (URL to API removed for security):
import {fetch} from 'wix-fetch';
export function getdata(){
return fetch('URL to API Service', {method: 'get'})
.then( (httpResponse) => {
if (httpResponse.ok) {
return httpResponse.json();
}
} );
}
On the page, this is where I think I am getting stuck:
import {getdata} from 'backend/fetchCats';
getdata()
.then(json => {
console.log(json);
var catData = json;
// static repeater data
$w.onReady(function () {
// handle creation of new repeated items
$w("#repeater1").onItemReady( ($item, itemData, index) => {
$item("#text23").text = itemData.ANIMALNAME;
} );
// set the repeater data, triggering the creation of new items
$w("#repeater1").data = catData;
} );
});
The above is giving me the error: Wix code SDK error: Each item in the items array must have a member named _id which contains a unique value identifying the item.
I know the JSON call has an ID field in it, but I am guessing Wix is expecting an _id field.
Am I just doing this wrong? Or am I missing something simple? I've spent a couple nights searching but can't really find a full example online that uses Wix's fetch method to get data via my HTTPS Get.
Thanks for any help!
You are doing fine.
You are getting the error from the line $w("#repeater1").data = catData;
which is the line used to set the items into the repeater. A repeater expects to have a _id member for each of the items, and your data quite probably does not have such an attribute.
I assume the API you are using, when returning an array, each item has some identifying attribute? if so, you can just do a simple transform like -
let catDataWithId = catData.map(item => {
item._id = item.<whatever id attribute>;
return item;
});
$w("#repeater1").data = catData;

Get shared link through Google Drive API

I am working on an app using Google Drive. I want the user to be able to share files by link, setting the permissions to anyone and withLink as described in the Google Developers documentation.
However, I cannot figure out what link to share. When I share a file in the Google Drive browser interface, I see the Link to share in the format:
https://docs.google.com/presentation/d/[...]/edit?usp=sharing
A link in this format is not part of the file resource object, nor it is returned from the http call setting the permissions. I hope someone can explain to me how to get this link through the REST api?
You can use the alternateLink property in the File resource to get a link that can be shared for opening the file in the relevant Google editor or viewer:
https://developers.google.com/drive/v2/reference/files
Update
[With API V3](https://developers.google.com/drive/api/v3/reference/files it is suggested to use the webViewLink property.
To actually enable link sharing using Google Drive API:
drive.permissions.create({
fileId: '......',
requestBody: {
role: 'reader',
type: 'anyone',
}
});
Get the webLinkView value using:
const webViewLink = await drive.files.get({
fileId: file.id,
fields: 'webViewLink'
}).then(response =>
response.data.webViewLink
);
In my case using the PHP Api v3, for the link to be non-empty you must define that you request this field... and if you have the right permissions:
so something like this:
$file =self::$service->files->get("1ogXyGxcJdMXt7nJddTpVqwd6_G8Hd5sUfq4b4cxvotest",array("fields"=>"webViewLink"));
Here's a practical example on how to get the WebViewLink file property (A.K.A. File edit link):
$file = $service->files->get($file_id, array('fields' => 'webViewLink'));
$web_link_view = $file->getWebViewLink();
OR
$sheetsList = $drive_service->files->listFiles([
'fields' => 'files(id, name, webViewLink, webContentLink)',
]);
$web_link_view = $sheetsList->current()->getWebViewLink();
Pay attention that you should load the file specifying which fields you wanna bring with it (In this case, webViewLink). If you don't do that, only id and name will be available.
In case you need to adjust the file sharing settings, this is how you do it:
$permissions = new \Google_Service_Drive_Permission();
$permissions->setRole('writer');
$permissions->setType('anyone');
$drive_service->permissions->create($file_id, $permissions);
Possible values for setRole() and setType() can be found here: https://developers.google.com/drive/api/v3/reference/permissions/create
For python, I only needed to get the file "id".
Then "created" the link like this:
def create_folder(folder_name, folder_id):
"""Create a folder and prints the folder ID and Folder link
Returns : Folder Id
"""
try:
# create drive api client
service = build("drive", "v3", credentials=creds)
file_metadata = {
"name": folder_name,
"mimeType": "application/vnd.google-apps.folder",
"parents": [folder_id],
}
file = (
service.files().create(body=file_metadata, fields="id").execute()
)
id = file.get("id")
print(
f'Folder ID: "{id}".',
f'https://drive.google.com/drive/u/0/folders/{id}',
)
return id
except HttpError as error:
print(f"An error occurred: {error}")
return None