UIXv2: IShellItems.GetObjectVersionsAndProperties does not return more than 50 objects

In UIX v1 we had the IShellItems.GetObjectVersionsAndProperties method which would return OVAPs for all objects in the respective view (listing).

In UIX v2 the identically named method IShellItems.GetObjectVersionsAndProperties appears to return max. 50 objects, even for views with hundreds of objects (tested with views containing 200 and 500 objects). It seems those are the objects visible on the first "page" of the listing.

We call from UIXv2 dashboard code is as follows:

shellFrame.ActiveListing.Items.GetObjectVersionsAndProperties().then(allItems => { /* further processing */ });

For Kanbanoo we need a way to get the OVAPs for all objects in a given view (the current listing). Is there a method or parameter to achieve that?

Background: Kanbanoo operates as UIX Dashboard that replaces the Listing view. Customers are expecting to manage hundreds of cards in a board.

Parents Reply Children
  • Hi Craig,

    shellFrame.ActiveListing.Items is the ShellItems instance. It has the following properties (vNext web client M-Files 24.10):

    {
        "__updatedAt": 1730224712082,
        "Count": 50,
        "ObjectVersions": [  /* array of objects, length 50 */  ],
        "ObjectFiles": [],
        "Folders": [],
        "FoldersParentLocation": []
    }

    So the ObjectVersions array is itself also only 50 long.

    GetObjectVersionsAndProperties returns an array of length 50 on both vNext web and vNext desktop clients (M-Files 24.10). In the classic desktop client in the exact same view listing.items.ObjectVersionsAndProperties is an array of 200 objects, as expected.

    The view itself has 200 objects. In all clients I can paginate through 4 pages of 50 objects each.

  • Right.  So the listing itself contains 50 items by default I believe in the new clients (with then pagination options to get the other items), so it makes sense that the items property only contains 50 items (as the listing only contains 50 items), and it also makes sense that then getting the object versions and properties returns 50.  I believe that this value can be configured, but by sounds of it that won't help here.

    My assumption is that you will need instead to retrieve data from the server rather than using the listing itself, as the listing is inherently limited.  Have you tried using something like GetFolderContents?

  • I get it - so the semantics of a Listing is not identical to the M-Files view, but it's only what is visible on the current page including scrolling.

    I will look into GetFolderContents (I haven't yet). Looking at the message parameters:

    Can I leave target "Search options" empty to retrieve all items of the view?

    It seems that I could pass as path a copy of ShellFrame.CurrentFolder ? (there it's only documented as Any but if I look at what it holds it looks like an array of Folder).

    Thank you!

  • I am not 100% sure I've tried this but at first glance I would agree with all your comments.  Let me know how it goes.

  • Ok, so I got it work to retrieve all 200 or 500 objects, depending on the view. I'm calling GetFolderContents then massage the search results and call GetObjectDataOfMultipleObjects to retrieve the OVAPs (i.e. inluding M-Files properties) as follows:

    
    
    // retrieve all obj_ver of the current view
    // then use that result to retrieve all OVAPs
    vault.SearchOperations.GetFolderContents({
        call_importance: 2 /* Enum: CallImportance */,
        path: shellFrame.CurrentFolder /* Array of Folder */,
        limit: 0    // no limit
    }).then(searchResults => {

        if (searchResults.objects) {
            // build request to retrieve OVAPs
            var request = {
                obj_vers: [] /* Array of requested ObjVer */,
                data_request: {
                    required_data_flags: {
                        all: false,
                        object_version: true,
                        properties: true,
                        acl: false,
                        current_user_permissions: false,
                        properties_for_display: false,
                        relationships: false,
                        collection_member_relationships: false,
                        object_activities: false
                    },
                    error_tolerance: 1 /* Enum: ObjectVersionDataRequestErrorTolerance */,
                    identity_type: 1 /* Enum: ObjectVersionDataRequestIdentityType */,
                    object_activities_parameters: {
                        category_filter: {
                            all: false,
                            metadata: false,
                            file_content: false,
                            comments: true
                        },
                        limit: 0,
                        offset_obj_ver_version: {
                            type: 7 /* Enum: ObjVerVersionType */,
                            internal_version: 0,
                            external_repository_version: "",
                            external_repository_sort_key: 0,
                        },
                    },
                },
            };
            // map SearchResultsItem[] to ObjVer[]
            request.obj_vers = searchResults.objects.map(resItem => ({
                obj_id: resItem.object.object_info.obj_id,
                version: resItem.object.version_info.version
            }));

            // chain the call to retrieve the OVAPs:
            return vault.ObjectOperations.GetObjectDataOfMultipleObjects(request);
        } else {
            // we did not get valid searchResults, view empty, server offline?
            callback([]);
        }
    }).then((ObjectVersionDataResult) => {
        
        if (ObjectVersionDataResult && ObjectVersionDataResult.results) {
            // convert to M-Files COM OVAPs
            var OVAPs = makeObjectVersionAndPropertiesFromMultObjResults(ObjectVersionDataResult.results);
            callback(OVAPs);
        } else
            callback([]);
        
    }).catch((reason) => {
        console.error("failed. reason=", reason);
    });

    Not sure whether my error handling is water-tight here though.