Cloning Teams and Configuring Tabs via Microsoft Graph: Configuring the Planner tab

Cloning Teams and Configuring Tabs via Microsoft Graph: Configuring the Planner tab

We’ve already come quite far in this blog post series! In the prelude, I covered the reasons why you might want to clone a team and configure its tabs programmatically. In the first technical post, we did the most compulsory thing: cloning a team. And after that, we moved on to configuring the tabs.

In the Configuring tabs — The Fundamentals, I shared with you a bunch of code for going through all the template team channels and tabs and collecting the required information for configuring the tabs in the new team. In that same blog post, I also told you that each different type of tab needs to be configured individually. And that’s what we are here for.

Last time I showed you how you can configure the OneNote tab. This time, we’ll go through what is required for getting the Planner tab up and running.

Published articles in this blog post series

Table of Contents

  1. Planner App ID
  2. Creating and displaying a new plan
    1. Remember to use delegated permissions
    2. Copying a plan?!
  3. Forming the body for the update request
  4. Supportive methods
  5. Afterword

Planner App ID

If you read my previous blog post, you know the drill here. In order for us to deduce which kind of a tab we are dealing with, we need to check its app ID. For the Planner tab, the ID is com.microsoft.teamspace.tab.planner. You can either add that to the TeamsAppId class we created last time, or create the class now if you are just getting started with the tab configurations. Reading the previous blog post about configuring the OneNote tab is not a prerequisite for following the instructions in this blog post.

public class TeamsAppId
{
    public static readonly string OneNote = "0d820ecd-def2-4297-adad-78056cde7c78"; // You can omit this if you are not interested in configuring OneNote tabs
    public static readonly string Planner = "com.microsoft.teamspace.tab.planner";
}

Creating and displaying a new plan

Now that we’ve added the Planner app ID to our TeamsAppId class, the execution will proceed to the correct code block whenever we are processing a Planner type of tab. For the code that actually loops through the template channels and tabs, check out my earlier blog post Configuring Tabs — The Fundamentals.

Let’s take a look at the code snippet below. After deducing that we are indeed configuring a Planner tab, we’ll create a brand new plan for the new team/group that we just cloned. We will name the plan based on the tab name (by default tab names are URL encoded). After that, we’ll pass the template tab content URL and the new plan ID to a method that forms the body for the tab update request. But more of that a bit later.

if (teamsAppId == TeamsAppId.Planner)
{
    var planId = await MicrosoftGraph.CreatePlan(newTeamId, WebUtility.UrlDecode(templateTabDisplayName));

    body = ConfigurePlannerTab(templateTab.SelectToken("configuration.contentUrl").ToString(), planId);

    // If you want the plan to be similar as on the template, you need to either write a bunch of custom code or cross your fingers for a built-in operation in Microsoft Graph in the future!
}

Remember to use delegated permissions

I want to remind you that all Planner related operations in Microsoft Graph only work with delegated permissions. This means that you need to actually get authenticated using user or service credentials; application identity won’t work.

I think delegated permissions are a better fit also for cloning a team because there’s just so many issues you have to deal with when using application permissions for that. You can read more of those from my earlier blog post in this same series: Cloning a Team.

Copying a plan?!

It is actually possible to also clone an existing plan via Microsoft Graph. However, doing so doesn’t automatically put them in the same order as in the original plan. If you want them to appear in the exact same order, you should check out my blog post How to sort Planner tasks using OrderHint and Microsoft Graph which explains the process.

There’s also good news! Copy plan feature was recently introduced to the Planner UI. Whether copying a plan will be included as a single operation in Microsoft Graph or not, remains to be seen.

Forming the body for the update request

Now, let’s get back to the actual topic. Here’s the method that forms the body for the tab update request. Forming the new content URL is actually very simple for Planner tabs. We simply extract the templatePlanId from that template tab contentUrl, and then replace that ID with the new planId. And there we have the content URL for the new tab.

private static string ConfigurePlannerTab(string templateTabContentUrl, string planId)
{
    var templatePlanId = ExtractTemplatePlanId(templateTabContentUrl);

    //Example contentUrl: https://tasks.office.com/mytenant.onmicrosoft.com/Home/PlannerFrame?page=7&planId={planId}&auth_pvr=Orgid&auth_upn={{upn}}&mkt={{locale}}
    return $"{{ 'configuration': {{ 'contentUrl': '{templateTabContentUrl.Replace(templatePlanId, planId)}' }} }}";
}

For extracting the templatePlanId from the contentUrl, you can use the method below. We first look for the &planId= query string parameter and then take text between that and the next ampersand.

private static string ExtractTemplatePlanId(string contentUrl)
{
    const string param = "&planId=";
    var index = contentUrl.IndexOf(param, StringComparison.OrdinalIgnoreCase) + param.Length;
    return contentUrl.Substring(index, contentUrl.IndexOf('&', index) - index);
}

For the code that does the actual update operation, check the Configuring Tabs — The Fundamentals blog post.

Supportive methods

If you’ve been following this blog post series and have already included the classes from the Configuring Tabs — The Fundamentals blog post, you only need to add the following method to the MicrosoftGraph helper class for creating the new plan.

public static async Task<string> CreatePlan(string groupId, string planTitle)
{
    var body = $@"{{'owner': '{groupId}', 'title': '{planTitle}'}}";
    return (await HttpRequest.GetResponseBodyAsJson("https://graph.microsoft.com/v1.0/planner/plans", HttpRequest.Method.Post, body)).SelectToken("id")?.ToString();
}

Afterword

How is it going for you with all these tab configurations? Having fun with it? Encountering problems? Let me know in the comments section below!

Next time, we will take a look at how you can configure the SharePoint tab to display lists and pages. It requires a little bit more effort than this Planner tab, but it’s nothing we can’t handle! And if you want to hear from me in the meanwhile or fancy being notified whenever I publish new content, feel free to follow me on Twitter.

Thank you for reading, I hope you enjoyed it, and catch with you later!

Laura



3 thoughts on “Cloning Teams and Configuring Tabs via Microsoft Graph: Configuring the Planner tab”

  • I am wanting to know if I share the SWIF T Calendar with all teams members can they see everyone’s schedule and if so how do they pull it up when the notice is sent to them

  • Laura,

    Great write-up! I was wondering if you’ve had any luck adding a Planner tab through Powershell. I’ve been able to get the tab added but I can’t seem to get the URL correct.

    • Hi Doug,

      If it is some PowerShell commandlet related issue, you can always create a REST request in PowerShell and it works the same regardless of the used language/platform/solution. Regarless, the contentUrl format is always https://tasks.office.com/{tenantName}/Home/PlannerFrame?page=7&planId={planId}

      Laura

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.