Getting a list of Salesforce Files

  • 3
  • Idea
  • Updated 10 months ago
This post details how you can access Salesforce Files in a Skuid page. I'm using Millau 11.0.3 in this post.

My requirement was to display a list of files (via a Deck) related to an opportunity. Here's how I did it.

Firstly I created a model based on the ContentDocumentLink object. Querying this object retrieves the file ids related to the opportunity. I created a condition based on the field LinkedEntityId, which I filled with Opportunity Id.

Then I created a second model based on the ContentDocument object. This model then fed the Deck component with the fields I wanted to display (Title, Size, Type etc). The model had a condition set against the Id field (set to multiple specified values as there may be multiple files per opportunity).

I populated the condition's values and querying of the models in the required sequence via a series of actions (against an opportunity list in a table, which shows a popup containing further details of the opportunity along with related objects such as the files).

One other thing, because my model based on the ContentDocument object had a multiple specified values condition, I created a JS snippet to grab the Ids from the model based on the ContentDocumentLink object and pass these into the condition. The snippet can be found below.


Hope this helps.
Matt


var params = arguments[0],
$ = skuid.$;

var SourceModel = skuid.$M('DocumentLinking');
var selectedIds = [];

//Build the array of linked document Ids, based on the values from the DocumentLinking model
$.each(SourceModel.data,function(i,row){
   
        selectedIds.push(row.ContentDocumentId);
});


//Filter the ContentDocument model to get the files, but only if there are links
if (selectedIds.length >= 1)
{
var TargetModel = skuid.$M('ContentDocument');
var ConIdsCondition = TargetModel.getConditionByName('DocIds');
TargetModel.setCondition(ConIdsCondition,selectedIds);
TargetModel.updateData();
}
Photo of Matt Potts

Matt Potts, Employee

  • 182 Points 100 badge 2x thumb

Posted 10 months ago

  • 3
Photo of Chandra V

Chandra V, Champion

  • 6,966 Points 5k badge 2x thumb
Would you mind posting a stripped down page xml of this (on the Opportunity object would be great) so we can see it all in action?  I'm sure many of us are facing this Files conversion (I know we are doing that right now) and the Skuid UI is one that has left us scratching our heads, although we have a solution put together in testing.  Yours might be better, so I'd like to see it.  :)

Thanks for putting this together!
Photo of Matt Potts

Matt Potts, Employee

  • 182 Points 100 badge 2x thumb
Hi Chandra, I have attached the page XML below. I have stripped the page back as much as possible. All custom fields have been removed so hopefully this works ok in other orgs.


<skuidpage unsavedchangeswarning="yes" personalizationmode="server" showsidebar="false" useviewportmeta="true" showheader="false" theme="Lightning Design">
    <models>
        <model id="Opportunities" limit="20" query="true" createrowifnonefound="false" datasource="salesforce" type="" sobject="Opportunity">
            <fields>
                <field id="Name"/>
                <field id="StageName"/>
                <field id="OwnerId"/>
                <field id="Owner.Name"/>
                <field id="Id"/>
                <field id="Amount"/>
                <field id="Description"/>
            </fields>
            <conditions/>
            <actions/>
        </model>
        <model id="SelectedOpportunity" limit="1" query="false" createrowifnonefound="false" datasource="salesforce" type="" sobject="Opportunity">
            <fields>
                <field id="Name"/>
                <field id="StageName"/>
                <field id="OwnerId"/>
                <field id="Owner.Name"/>
                <field id="Id"/>
                <field id="Amount"/>
                <field id="Description"/>
            </fields>
            <conditions>
                <condition type="fieldvalue" value="" field="Id" operator="=" state="filterableoff" inactive="true" name="Id" enclosevalueinquotes="true"/>
            </conditions>
            <actions/>
        </model>
        <model id="ContentDocument" limit="20" query="false" createrowifnonefound="false" datasource="salesforce" type="" sobject="ContentDocument">
            <fields>
                <field id="Title"/>
                <field id="FileType"/>
                <field id="ContentSize"/>
                <field id="Id"/>
            </fields>
            <conditions>
                <condition type="multiple" value="" field="Id" state="filterableoff" inactive="true" name="DocIds" operator="in" enclosevalueinquotes="true">
                    <values>
                        <value/>
                    </values>
                </condition>
            </conditions>
            <actions/>
        </model>
        <model id="DocumentLinking" limit="20" query="false" createrowifnonefound="false" datasource="salesforce" type="" sobject="ContentDocumentLink">
            <fields>
                <field id="ShareType"/>
                <field id="ContentDocumentId"/>
                <field id="ContentDocument.Title"/>
                <field id="LinkedEntityId"/>
            </fields>
            <conditions>
                <condition type="fieldvalue" value="" enclosevalueinquotes="true" field="LinkedEntityId" fieldtargetobjects="LinkedEntityId" state="filterableoff" inactive="true" name="LinkedEntityId"/>
            </conditions>
            <actions/>
        </model>
    </models>
    <components>
        <skootable showconditions="true" showsavecancel="false" showerrorsinline="true" searchmethod="server" searchbox="true" showexportbuttons="false" pagesize="10" alwaysresetpagination="false" createrecords="false" model="Opportunities" buttonposition="" mode="readonly" allowcolumnreordering="true" responsive="true" uniqueid="sk-3RboX8-660">
            <fields>
                <field id="Name" hideable="true" uniqueid="sk-3RboX8-661" valuehalign="" type="" allowordering="true"/>
                <field id="StageName" hideable="true" uniqueid="sk-3RboX8-662" valuehalign="" type="" allowordering="true"/>
                <field id="OwnerId" hideable="true" uniqueid="sk-3RboX8-665" valuehalign="" type=""/>
            </fields>
            <rowactions>
                <action type="multi" label="View Details" icon="sk-icon-listview">
                    <actions>
                        <action type="action-sequence" action-sequence-id="24519ed6-ef57-466d-bb1a-97a2e653fd99"/>
                    </actions>
                </action>
            </rowactions>
            <massactions usefirstitemasdefault="true"/>
            <views>
                <view type="standard"/>
            </views>
        </skootable>
    </components>
    <resources>
        <labels/>
        <javascript>
            <jsitem location="inlinesnippet" name="getFiles" cachelocation="false">var params = arguments[0],
$ = skuid.$;

var SourceModel = skuid.$M('DocumentLinking');
var selectedIds = [];

//Build the array of linked document Ids, based on the values from the DocumentLinking model
$.each(SourceModel.data,function(i,row){
   
        selectedIds.push(row.ContentDocumentId);
});


//Filter the ContentDocument model to get the files, but only if there are links
if (selectedIds.length &gt;= 1)
{
var TargetModel = skuid.$M('ContentDocument');
var ConIdsCondition = TargetModel.getConditionByName('DocIds');
TargetModel.setCondition(ConIdsCondition,selectedIds);
TargetModel.updateData();
}</jsitem>
        </javascript>
        <css>
            <cssitem location="inline" name="pageCSS" cachelocation="false">.hidetablefooter .nx-list-footer {
    display: none;
}</cssitem>
            <cssitem location="inline" name="stepIndicatorCSS" cachelocation="false">.progress-indicator .progress-chunk.current .progress-text .step-label {
    color: #30ad60;
}

.progress-indicator .progress-chunk.current .progress-text .text-content {
    background-color: #30ad61;
    color: white;
}

.progress-indicator .progress-chunk.done .progress-text .text-content {
    background-color: #ddd;
    color: white;
}

.progress-indicator .progress-chunk.done .progress-text .step-label {
    color: #dddddd;
}

.progress-indicator .progress-chunk.done .progress-text .indicator-line {
    background: #30ad60;
}</cssitem>
        </css>
        <actionsequences uniqueid="sk-3QZynU-261">
            <actionsequence id="24519ed6-ef57-466d-bb1a-97a2e653fd99" label="ViewOppDetails" type="reusable" uniqueid="sk-3WRMkW-306">
                <actions>
                    <action type="setCondition" model="DocumentLinking" condition="LinkedEntityId" value="{{Id}}"/>
                    <action type="requeryModels" behavior="standard">
                        <models>
                            <model>DocumentLinking</model>
                        </models>
                    </action>
                    <action type="setCondition" model="SelectedOpportunity" condition="Id" value="{{Id}}"/>
                    <action type="requeryModels" behavior="standard">
                        <models>
                            <model>SelectedOpportunity</model>
                        </models>
                    </action>
                    <action type="custom" snippet="getFiles"/>
                    <action type="showPopup">
                        <popup title="View Grant Details" width="95%">
                            <components>
                                <wrapper uniqueid="sk-3aQ8E--1234">
                                    <components>
                                        <wrapper uniqueid="sk-3aQExf-1271">
                                            <components>
                                                <wrapper uniqueid="sk-3cMHtY-2457">
                                                    <components>
                                                        <pagetitle model="SelectedOpportunity" uniqueid="sk-3RboX8-666">
                                                            <maintitle>{{{Name}}}</maintitle>
                                                            <actions>
                                                                <action type="multi" label="Save" uniqueid="sk-3RboX8-667">
                                                                    <actions>
                                                                        <action type="save">
                                                                            <models>
                                                                                <model>SelectedOpportunity</model>
                                                                            </models>
                                                                        </action>
                                                                    </actions>
                                                                    <renderconditions logictype="and">
                                                                        <rendercondition type="fieldvalue" enclosevalueinquotes="false" fieldmodel="SelectedOpportunity" sourcetype="modelproperty" sourceproperty="hasChanged" value="true" operator="="/>
                                                                    </renderconditions>
                                                                    <enableconditions/>
                                                                </action>
                                                                <action type="multi" label="Cancel" uniqueid="sk-3RboX8-668">
                                                                    <actions>
                                                                        <action type="cancel">
                                                                            <models>
                                                                                <model>SelectedOpportunity</model>
                                                                            </models>
                                                                        </action>
                                                                    </actions>
                                                                    <renderconditions logictype="and">
                                                                        <rendercondition type="fieldvalue" enclosevalueinquotes="false" fieldmodel="SelectedOpportunity" sourcetype="modelproperty" sourceproperty="hasChanged" value="true" operator="="/>
                                                                    </renderconditions>
                                                                    <enableconditions/>
                                                                </action>
                                                            </actions>
                                                            <conditions/>
                                                            <renderconditions logictype="and"/>
                                                        </pagetitle>
                                                    </components>
                                                    <styles>
                                                        <styleitem type="background"/>
                                                        <styleitem type="border"/>
                                                        <styleitem type="size"/>
                                                    </styles>
                                                </wrapper>
                                                <wrapper uniqueid="sk-3aPJYG-1061">
                                                    <components>
                                                        <basicfieldeditor showheader="true" showsavecancel="false" showerrorsinline="true" model="SelectedOpportunity" buttonposition="" uniqueid="sk-3RboX8-669" mode="read">
                                                            <columns>
                                                                <column width="100%">
                                                                    <sections>
                                                                        <section title="Details" collapsible="no">
                                                                            <fields>
                                                                                <field uniqueid="sk-3RboX8-671" id="StageName"/>
                                                                                <field uniqueid="sk-3RboX8-672" id="Amount" showhelp="true" decimalplaces="" valuehalign="" type=""/>
                                                                            </fields>
                                                                        </section>
                                                                    </sections>
                                                                </column>
                                                            </columns>
                                                            <conditions/>
                                                        </basicfieldeditor>
                                                    </components>
                                                    <styles>
                                                        <styleitem type="background"/>
                                                        <styleitem type="border" borders="all" padding="bottom,left,top,">
                                                            <styles>
                                                                <styleitem property="border" value="1px solid #f2f2f2"/>
                                                                <styleitem property="padding-left" value="25px"/>
                                                                <styleitem property="padding-top" value="5px"/>
                                                                <styleitem property="padding-bottom" value="5px"/>
                                                                <styleitem property="box-sizing" value="border-box"/>
                                                            </styles>
                                                        </styleitem>
                                                        <styleitem type="size"/>
                                                    </styles>
                                                </wrapper>
                                            </components>
                                            <styles>
                                                <styleitem type="background" bgtype="none"/>
                                                <styleitem type="border" padding="none">
                                                    <styles>
                                                        <styleitem property="box-sizing" value="border-box"/>
                                                    </styles>
                                                </styleitem>
                                                <styleitem type="size"/>
                                            </styles>
                                        </wrapper>
                                        <wrapper uniqueid="sk-3bT3rS-904">
                                            <components>
                                                <grid uniqueid="sk-3WvHN7-587">
                                                    <divisions>
                                                        <division behavior="flex" minwidth="100px" ratio="1">
                                                            <components>
                                                                <richtext multiple="false" uniqueid="sk-3WlJlQ-1196">
                                                                    <contents>&lt;p&gt;&lt;span style="color:#000000;"&gt;&lt;span style="font-size:18px;"&gt;&lt;strong&gt;Files&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
</contents>
                                                                </richtext>
                                                                <file storeas="contentdocumentwithrecord" displayas="filename" uniqueid="sk-3WvJuQ-611" datasource="salesforce" model="SelectedOpportunity" label="" autorefreshmodels="false">
                                                                    <uploadsuccessactions>
                                                                        <action type="setCondition" model="DocumentLinking" condition="LinkedEntityId" value="{{$Model.SelectedOpportunity.data.0.Id}}"/>
                                                                        <action type="requeryModels" behavior="standard">
                                                                            <models>
                                                                                <model>DocumentLinking</model>
                                                                            </models>
                                                                        </action>
                                                                        <action type="custom" snippet="getFiles"/>
                                                                    </uploadsuccessactions>
                                                                    <uploadfailureactions/>
                                                                </file>
                                                            </components>
                                                        </division>
                                                        <division behavior="flex" verticalalign="top" minwidth="100px" ratio="1">
                                                            <components/>
                                                        </division>
                                                    </divisions>
                                                    <styles>
                                                        <styleitem type="background" bgtype="none"/>
                                                    </styles>
                                                </grid>
                                                <deck searchmethod="server" searchbox="false" columngutter=".75em" rowgutter=".75em" model="ContentDocument" filtersposition="top" filterswidth="150px" showsavecancel="false" behavior="flex" verticalalign="top" ratio="1" minwidth="350px" uniqueid="sk-3WkVqp-813" buttonposition="" pagesize="10" emptysearchbehavior="query" cssclass="hidetablefooter">
                                                    <components>
                                                        <wrapper uniqueid="sk-3f71aN-1039">
                                                            <components>
                                                                <grid uniqueid="sk-3WkYde-952"> <divisions> <division behavior="specified" verticalalign="top" width="80px"> <components>
                                                                    <image source="url" uniqueid="sk-3WuqdW-525" datasource="salesforce" behavior="none" model="Opportunities" url="https://image.flaticon.com/icons/png/512/32/32329.png">;
                                                                        <styles>
                                                                            <styleitem type="itemsize"/>
                                                                            <styleitem type="border"/>
                                                                        </styles>
                                                                    </image> </components> </division> <division behavior="flex" verticalalign="top" minwidth="100px" ratio="1">
                                                                    <components>
                                                                        <richtext multiple="false" uniqueid="sk-3WkfwY-978" model="ContentDocument">
                                                                            <contents>&lt;p&gt;&lt;span style="font-size:14px;"&gt;&lt;strong&gt;{{Title}}&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;{{FileType}} -&amp;nbsp;{{FileSize}}Kb&lt;/p&gt;
</contents>
                                                                        </richtext>
                                                                    </components>
                                                                </division>
                                                            </divisions> <styles>
                                                            <styleitem type="background" bgtype="none"/>
                                                        </styles>
                                                    </grid>
                                                </components>
                                                <styles>
                                                    <styleitem type="background"/>
                                                    <styleitem type="border" padding="left,top,">
                                                        <styles>
                                                            <styleitem property="padding-left" value="25px"/>
                                                            <styleitem property="padding-top" value="5px"/>
                                                            <styleitem property="box-sizing" value="border-box"/>
                                                        </styles>
                                                    </styleitem>
                                                    <styleitem type="size"/>
                                                </styles>
                                            </wrapper>
                                        </components>
                                        <massactions/>
                                        <interactions/>
                                        <actions/>
                                        <styles>
                                            <styleitem type="border"/>
                                        </styles>
                                        <conditions/>
                                        <searchfields/>
                                    </deck>
                                </components>
                                <styles>
                                    <styleitem type="background" bgtype="none"/>
                                    <styleitem type="border" padding="right,left,bottom,top," borders="all">
                                        <styles>
                                            <styleitem property="border" value="1px solid #f2f2f2"/>
                                            <styleitem property="padding-left" value="25px"/>
                                            <styleitem property="padding-top" value="5px"/>
                                            <styleitem property="padding-right" value="25px"/>
                                            <styleitem property="padding-bottom" value="5px"/>
                                            <styleitem property="box-sizing" value="border-box"/>
                                        </styles>
                                    </styleitem>
                                    <styleitem type="size"/>
                                </styles>
                            </wrapper>
                        </components>
                        <styles>
                            <styleitem type="background"/>
                            <styleitem type="border" margin="none">
                                <styles>
                                    <styleitem property="box-sizing" value="border-box"/>
                                </styles>
                            </styleitem>
                            <styleitem type="size" height="custom">
                                <styles>
                                    <styleitem property="min-height" value="100vh"/>
                                </styles>
                            </styleitem>
                        </styles>
                    </wrapper>
                </components>
                <afterclose/>
            </popup>
        </action>
    </actions>
    <description/>
</actionsequence>
</actionsequences>
</resources>
<styles>
    <styleitem type="background" bgtype="none"/>
</styles>
</skuidpage>
Photo of John Dahlberg

John Dahlberg, Champion

  • 2,442 Points 2k badge 2x thumb
Matt - You should be able to do most of this in one model.  The ContentDocumentLink has a lookup to ContentDocument, which has a lookup to LatestPublishedVersion, which is the currently relevant ContentVersion record.  ContentDocument has most of the fields of interest and ContentVersion has additional information such as custom fields and the Id used for a download link.  Here's an example download link:

/sfc/servlet.shepherd/version/download/{{{ContentDocumentLink.ContentDocument.LatestPublishedVersionId}}}

Also, with models, you can declaratively use a set of record Ids (or other fields) from a prior model to use in a secondary models' filters. You just load your first model to get the records of interest and then in your next model, setup your filter like so:

Photo of Matt Potts

Matt Potts, Employee

  • 182 Points 100 badge 2x thumb
Thanks John.