Friday, March 17, 2023

Boost you PnP Modern Search List Layout

 

When working with the PnP Modern Search web parts I am often ask by my customers to tweak the layout of the results.

The Lists Layout seems to be the most popular layout. It looks like this out of the box when searching for documents with some metadata:



We can enhance this layout by making a few simple updates.


Go the Layout section and click on Edit results template



Step one: Upgrade the user info

Find the code block below in the layout template


<span class="template--listItem--author">

{{#with (split (slot item @root.slots.Author) '|')}}{{[1]}}

{{/with}}

</span>


This section shows the name of the Author. Replace it with this section


<mgt-person

ser-id="{{getUserEmail (slot item @root.slots.Author)}}"

      view='threelines'

      show-presence="true"

      person-card="hover"

      avatar-size="large"

      />

</mgt-person>



This is mgt-person, a very powerful component from the Microsoft Graph Toolkit gallery. This component is very configurable, see Person component in MGT for details.

In this case I have chosen the 3 line view (Name + Email + Job title) and that the person-card shall be available. The person card is the card that shows up when the mouse hover above a user's photo. The content of the hover card can also be tweaked, see the link above.



Step two: Update the metadata tags

Find this section:

{{#if (slot item @root.slots.Tags)}}
pnp-icon data-name="Tag" aria-hidden="true" data-theme-variant="{{JSONstringify @root.theme}}"></pnp-icon>
      <div>
      {#each (split (slot item @root.slots.Tags) ",") as |tag| }}
      pan>{{trim tag}}</span>
     {{/each}}
      </div>
{{/if}}


Replace it with this

{{#if (slot item @root.slots.Tags)}}
div>
      {#each (split (slot item @root.slots.Tags) ";") as |tag| }}
            pnp-icon data-name="Tag" aria-hidden="true" data-theme-variant="{{JSONstringify @root.theme}}"></pnp-icon> {{last (split tag "|")}}
            {{/each}}    
/div>
{{/if}}


Finally update the css for template--listItem--result :

 .template--listItem--result {
            flex-basis: 100%!important;
            background-color: antiquewhite;
            box-shadow: 5px 10px #888888;
        }



The final result looks like this.





The layout file can be downloaded from GitHub

Sunday, March 12, 2023

Boost the person fields in your PnP Modern Search Layout

 

This rather generic SharePoint list is created by a self-service site provisioning setup, and it shows who is in change of any Site Collection.






On the front page on each of the Site Collections the customer requests that we insert a web part with some basic site information. In this case the People web part is not sufficient as some of the metadatea can change over time, such as e.g. the Site Owner.

The obvious choice is therefore a PnP Modern Search results web part using a query like 

Path:https://tcwlv.sharepoint.com/sites/SampleTeamSite/Lists/SiteCreationRequestList* basicProvisioningSiteUrlOWSTEXT:{Site.Url}

(basicProvisioningSiteUrlOWSTEXT is the internal name for the SiteUrl column as seen above)

This will give me the data in the list item having the SiteUrl that is the same as the current Site Collection. 


I looked in the People layout and found that the template used to display a person is a pnp-persona template and used it in the custom layout. It looks like this and has not hover card.



This is off cause better than nothing, but even the OOTB List has a hover card, so it needed an upgrade.

I asked the community on the PnP-modern-search discussions and @patrikhellgren provided an incredibly detailed sample using the mgt-person template. (Microsoft Graph Toolkit).

So, by updating the Layout to this I get a tree line Card and the hover card as well 😀

<template id="content">

    {{#> resultTypes item=item}}
        {{!-- The block below will be used as default item template if no result types matched --}}
       
       
        <div class="contactheader">
        Primary Contact
        </div>
       
        <mgt-person
            user-id="{{getUserEmail (slot item @root.slots.Owner)}}"
            view='threelines'
            show-presence="true"
            person-card="hover"
            avatar-size="large"
        />
        </mgt-person>
        <br><br>
    Template: "{{slot item @root.slots.Template}}"

    {{/resultTypes}}
</template>






As an additional bonus I am pretty sure (not verified yet), that the photo comes from AAD and not the User Profile Application, a service that have provided several headaches over the years, especially related to the employee photo ;-)













Saturday, February 25, 2023

Creating a Planner tab in Teams, including a number of Tasks, in an Azure Function

( Updated 1 March 2023)

As part of an update to a provisioning tool I was looking into creating a Planner, a Bucket and a handful of tasks and finally connecting the Planner to a tab in one of the channels in my Teams Team.   




The tools of choice is an Azure Function running PnP.PowerShell ( version 1.12 )  as this combo allows both us and the client to alter existing functions and create new ones without having to hire a hardcore developer. Quite a few consultants and IT administrators knows enough PowerShell to work with these fairly simple scripts.  💪

Creating the Planner, the bucket and the tasks goes like this: (draft version , not ready for product yet)



$localConn = Connect-PnPOnline -Url $siteUrl -ClientId $ClientId -thumbprint $thumbprint -Tenant $TenantName -ReturnConnection -erroraction stop

$PlannerPlan = Get-PnPPlannerPlan -Group $groupId -Identity $PlannerName -Connection $localConn

if(-not $PlannerPlan)
{
    $PlannerPlan = New-PnPPlannerPlan -Group $groupId -Title $PlannerName -Connection $localConn
}

$bucket = Add-PnPPlannerBucket -Group $groupId -Plan $PlannerPlan.Id -Name "Tasks" -Connection $localConn

$newTask = Add-PnPPlannerTask -Group $groupId -Plan $PlannerPlan.Id -Bucket $bucket.Id -Title "Task A" -Connection $conn

$newTask = Add-PnPPlannerTask -Group $groupId -Plan $PlannerPlan.Id -Bucket $bucket.Id -Title "Task B" -Connection $conn

$newTask = Add-PnPPlannerTask -Group $groupId -Plan $PlannerPlan.Id -Bucket $bucket.Id -Title "Task C" -Connection $conn

$newTask = Add-PnPPlannerTask -Group $groupId -Plan $PlannerPlan.Id -Bucket $bucket.Id -Title "Task D" -Connection $conn

$plannerChannel = Get-PnPTeamsChannel -Team $groupId -Connection $conn | Where-Object {$_.DisplayName -eq "RFP"}

However, connecting the Planner to the tab in Teams proved to be a challange as the Add-PnPTeamsTab looks like this:


Prefect, as one of the options in the Type enum is "Planner" this should do the trick:

Add-PnPTeamsTab -Team $groupId -Channel $teamsChannel -DisplayName "RFP" -Type Planner -ContentUrl $contentUrl


But no. Error : Add-PnPTeamsTab: A parameter cannot be found that matches parameter name 'ContentUrl'.


Later in the day I saw that @PaoloPia (Paolo Pialorsi) had released a YouTube video : "Learn how to use Graph to automate provisioning of Planner plans, buckets, and tasks". In that video Paolo was using MS Graph to create the tab and connect it to the Planner.

When I added a comment on Twitter that I most likely was going to use the same approach as the Add-PnPTeamsTab approach apparently didn't work.

Gautam Sheth (@gautamdsheth) saw this and answered that I should use -type "Custom" instead as this would allow me to set the ContentUrl.

This will create a Planner tab to your channel:

$teamsTab = Add-PnPTeamsTab -Team $groupId -Channel $plannerChannel -DisplayName "RFP" -Type Custom -TeamsAppId "com.microsoft.teamspace.tab.planner" -Connection $conn -ContentUrl "https://tasks.office.com/[TenantName].onmicrosoft.com/Home/PlannerFrame?page=7&planId=$($PlannerPlan.Id)"


So thanks to a comment on Twitter and to Paolo and Gautam I learned something new, got the function to work using PnP.PowerShell exclusively. 

In order to ensure that this option reaches a broader audience the documentation for Add-PnPTeamsTab has been updated with a example like the code above.

  
Update 1 March 2023:

Gautam has updated the Cmdlet and I have updated the documentation with this example:
No need to use -Type Custom anymore ✌




Monday, February 20, 2023

Microsoft search : using a DateTime field in your Result Types

In one of our products, we are using a Generic SharePoint list to store some information that is required to be visible within a specific timeslot ( beginDate & EndDate).

In the ol' days we could easily exclude those listitems in a data source derived from the LocalSharePointResults data source using a Date variable.


But these days we are dealing with Microsoft Search and a different set of rules.


 Since Microsoft Search will display those list items by default we have a few options:

Option 1: Create two Result Types and use e.g. ContentTypeId and the RefinableDates to handle the items that should be show and not shown respectively.



 Well, this is as far down that path that I got. Date fields in the Result type builder does NOT have any date variables, and according to a very reliable source with Microsoft there are no plans to offer this option.


So, we are left with Option 2 or 3.

Option 2: For each relevant Search Vertical we must add a filter to hide any item outside the range.
(risky as this rule might be forgotten and not implemented in a Vertical added at a letter date)


Option 3: Use the Result Type without any date filter and set up the Adaptive Card to hide any item outside the range.

I am not happy about having "business logic" in the GUI/Display layer but I guess we will go with Option 3 for now.

Tuesday, January 24, 2023

Shortcomings of the Managed Metadata fields on a SharePoint User Profile

Summary: This blog post will explain what you can and can't do when the User Profile field is a Managed Metadata field.


This blog post is a fellow up on the previous post about using PnP Modern Web Parts as a department web part.

While working on that blog post I had the idea that it should be possible to show the members of a specific department and a division as well.





Showing the members of a department was easy, however I had a hard time getting the division to work.

According to an article from Mikael Svenson, I should be able to query for the Marketing Division by using the GPP|#c  syntaxwhich should return User Profile Accounts where the Department field was a term beneath the Marketing Division. 

Looking at the data using the excellent SP Editor extension for Chrome/Edge I found that the data looked just as expected where the Department termset was using on a Site Column. The search worked just fine.


So why didn't it work in People Search? 

After inspecting the Managed Property ( in this case ows_taxid_spshdepartment was mapped to RefinableString100) in SP Editor this showed up:







Once the Department field on the User Profile Account is crawled it does NOT contain the same value as if the field had been using on content.

So the short story is that we can use the PnP Modern Search solution to show departments and all employees, but not the levels between.

It is of course an option to set the query like ows_taxid_spshdepartment:[ID for Marketing] OR ows_taxid_spshdepartment:[ID for Sales] and so on. However, this option is brittle and will require an update each time a department is added or removed from the Division.

Sunday, January 22, 2023

Using the PnP Modern Search Results web part as a Department Web Part



Update: If you prefer the video version you can find it here: Using PnP Modern Search As Department Web Part - YouTube
Occasionally we get the request to display the members of a department on a modern SharePoint web page. Using the People Web part is out of the question as this web part only shows a static list of people, and we want the listing to show the members of the Department at any given time.
The Organization Chart is an option if your departments always have one manager, and each manager only has one department. 




However you might be looking for something a little more flexible than the Org Chart, and the PnP Modern Search solution can provide just that 😀

Before you can start using PnP Modern Search the solution must be installed in the App Catalog as per the official guide to PnP Modern Search

Even before we start working with the web part we need some information, the ID number for the department in question.
You find the list of departments in the Term Store. Find the department in the People group and select the Usage Settings in the right hand section, and there you will find the unique ID for that department. 



Back on the modern page again.

Once the App is installed in your site the steps are as follows:
1) Edit the page
2) Insert the Web Part (PnP Search Results)



3) Select Configure or click the Edit Web part Icon
4) Select SharePoint as the Data Source
5) Enter owstaxIdSPShDepartment:"THE_ID_OF_THE_DEPARTMENT" in the Query Template Field, in this case it will be owstaxIdSPShDepartment:"2ce09d31-c9d3-4265-abd7-5ac99fc3a060"
6) Scroll down and select LocalPeopleResults in the Result Source Id/Scop|Name field




7) Now you should see some results in the web part, however we are currently using a wrong layout/Display. Scroll further down and change to Page 2.
8) Select the People Layout 
9) Scroll down and enable the field "Show persona card on hover"
10) Change the Component size to a value that fits your design.



11) Rename the web part to the title of the department.

And here you go, an always updated department web part free of change.