How to connect and sync Bryntum Calendar to Microsoft Planner
Bryntum Calendar is a JavaScript calendar component that’s performant, fully customizable, and can easily be used with your framework of choice: React, Angular, or Vue. In this tutorial, we’ll connect and sync Bryntum Calendar to a Microsoft Planner plan by doing the following:
- Creating a client-side Bryntum Calendar JavaScript app that users can access using their Microsoft 365 Developer Program login credentials.
- Using Microsoft Graph to get the users’ Microsoft Planner plan tasks.
- Displaying the Microsoft Planner tasks in Bryntum Calendar.
- Syncing event changes in Bryntum Scheduler to the user’s Microsoft Planner plan.
We’ll build a Bryntum Calendar app that syncs with a Microsoft Planner plan:
Getting started
Clone the starter GitHub repository, which is a client-side Bryntum Calendar app. The code for the Bryntum Calendar that syncs with Microsoft Planner is in the completed-calendar
branch of the starter GitHub repository.
The starter repository uses Vite, a development server and JavaScript bundler. You’ll need Node.js version 18+ for Vite to work. Install the Vite dev dependency by running the following command:
npm install
Install the Bryntum Calendar component by following step 1 and step 4 of the vanilla JavaScript with npm setup guide.
Run the local dev server using the following command:
npm run dev
You’ll see a Bryntum Calendar with a single event:
Now, let’s learn how to retrieve a user’s Microsoft Planner tasks with Microsoft Graph.
Accessing Microsoft Planner data: Joining the Microsoft 365 Developer Program
If you have Microsoft 365 Developer Program access or can get it, use those credentials and proceed to the next section: Creating a Microsoft Entra app to connect to Microsoft 365. Otherwise, sign up for a Microsoft 365 subscription with Planner Plan 1 and continue with this section.
Microsoft Planner is a Microsoft 365 app. To get access to Microsoft 365 data, we’ll register a Microsoft 365 app by creating an application registration in Microsoft Entra ID, which is an identity and access management service that we’ll use to authenticate users. Microsoft Entra ID is the new name for Azure Active Directory.
We’ll add a login button to the Bryntum Calendar app so that users can sign in to the app using their Microsoft 365 account. This will allow us to access the data that users give the app permission to access. A user will sign in using OAuth, which sends an access token to our app to be stored in local storage. We’ll then use the token to make authorized requests for Microsoft Planner data using Microsoft Graph. The Microsoft Graph REST API is the single endpoint that provides access to Microsoft 365 app data.
To use Microsoft Graph, you need global administrator access to a Microsoft 365 tenant. If you don’t have global administrator access, join the Microsoft 365 Developer Program with your Microsoft account. When you join the program, the subscription setup flow for a Microsoft 365 E5 developer sandbox will automatically start if you qualify for a Microsoft 365 E5 sandbox subscription. Add the following input:
- Select Instant sandbox and click the Next button.
- Choose the Country/region for your data center, selecting your closest data center region.
- Create an Admin username and Admin password. Save your username and password, because you’ll need it to access your developer subscription.
- Click the Continue button.
- Provide a valid cell phone number and click the Send code button. Enter the code that you receive, and then click Set up.
Once your subscription has been created, your subscription domain name and expiration date appear on your dashboard.
Creating a Microsoft Entra app to connect to Microsoft 365
Let’s register a Microsoft 365 application to get access to Microsoft 365 data.
Follow these steps to create a creating an application registration in the Microsoft Entra admin center:
- Use the admin email address from your Microsoft 365 Developer Program account to sign in to Microsoft Entra.
- In the left navigation menu, select Applications and then select App registrations in the dropdown menu.
- Click the New registration button to create a new app registration.
- Name your app and select the “Single tenant” option for the Supported account types.
- Set the Redirect URI to
http://localhost:5173
, select Single page application (SPA) from the dropdown, and then click the Register button.
After registering your application, take note of the Application (client) ID and the Directory (tenant) ID; you’ll need these to set up authentication for your Bryntum Calendar web app later.
Creating a Microsoft Planner plan
Sign in to Microsoft Planner using the admin email address from your Microsoft 365 Developer Program account.
Click the Create a plan button in the center of the screen.
Select the New Blank Plan option in the New Plan dialog that opens.
Give your plan a name and click the Create button.
The plan is set to private by default. Private plans can only be viewed by members that you add. Public plans can be viewed by anyone in your organization.
The plan has four different views: Grid, Board, Charts, and Schedule.
Open the Schedule tab to see the calendar view of the data.
Create an example task by clicking on the plus icon in the top right corner of a day block. Name the task (for example, “Design app”) in the popup form and click the Add task button.
Add more details to the task by clicking on your task in the calendar. This will open the task editor. Set the Start date and the Due date, set the Progress value to “In progress”, and add a note in the Notes section.
The changes to the task are automatically saved. Close the task editor by clicking the close button at the top right of the task editor modal or by clicking outside of the modal.
The taskbar in the calendar will display an icon indicating that the task is in progress.
Now that you have a plan in Microsoft Planner, you can create a JavaScript web app that uses the Microsoft Graph API to get your Microsoft Planner data.
Next, let’s set up authentication in the Bryntum Calendar web app.
Setting up Microsoft 365 authentication in the JavaScript app
To get data using the Microsoft Graph REST API, your app needs to prove that you’re the owner of the app you just registered in Microsoft Entra. Your app will get an access token from Microsoft Entra and include it in each request to Microsoft Graph. After this is set up, users will be able to sign in to your app using their Microsoft 365 accounts. This means that you won’t have to implement authentication in your app or maintain users’ credentials.
The following diagram outlines how we’ll access the Microsoft Planner data from the Bryntum Calendar app. We’ll log in to our apps, using Microsoft Entra ID to authenticate the user. We’ll use the access token returned by Microsoft Entra ID to connect to Microsoft Planner via the Microsoft Graph API.
First, we’ll create the variables and functions we need for authentication and retrieving tasks from Microsoft Planner. Then, we’ll add the Microsoft Authentication Library and Microsoft Graph SDK that we need for authentication and using the Microsoft Graph API.
Create a .env.local
file in the root directory of your Bryntum Calendar app and add the following environment variables to it:
VITE_MICROSOFT_PLANNER_PLAN_ID=""
VITE_MICROSOFT_ENTRA_APP_ID=""
VITE_MICROSOFT_ENTRA_TENANT_ID=""
Add your Microsoft Planner plan ID. You can find it in the URL of your plan at https://tasks.office.com. Add the Application (client) ID and the Directory (tenant) ID of your registered Microsoft Entra app. Prefix the variables with VITE_
to expose the variables to the JavaScript app. Vite only exposes environmental variables prefixed with VITE_
to your Vite-processed code. The JavaScript app runs on the client side, so the environment variables would be exposed to the user, which is fine in this case.
Install the Microsoft Authentication Library, MSAL.js
, for single-page JavaScript web apps.
npm i @azure/msal-browser
Create a file called auth.js
in your project’s root directory and add the following code to it:
const msalConfig = {
auth : {
clientId : import.meta.env.VITE_MICROSOFT_ENTRA_APP_ID,
authority : `https://login.microsoftonline.com/${
import.meta.env.VITE_MICROSOFT_ENTRA_TENANT_ID
}`,
redirectUri : 'http://localhost:5173'
}
};
This code configures the Microsoft Authentication Library (MSAL) for authentication with Microsoft Entra ID. The clientID
is the unique ID of your Microsoft Entra app. The authority
is the endpoint that MSAL will use to authenticate a user. The redirectUri
is the URL
that users will be redirected to after they’ve been authenticated.
Add the following imports to the auth.js
file:
import {
PublicClientApplication,
InteractionRequiredAuthError
} from '@azure/msal-browser';
Add the following code to the bottom of the file:
// Initialize a PublicClientApplication object.
const msalInstance =
await PublicClientApplication.createPublicClientApplication(msalConfig);
const msalRequest = { scopes : [] };
export function ensureScope(scope) {
if (
!msalRequest.scopes.some((s) => s.toLowerCase() === scope.toLowerCase())
) {
msalRequest.scopes.push(scope);
}
}
// Log the user in
export async function signIn() {
const authResult = await msalInstance.loginPopup(msalRequest);
localStorage.setItem('msalAccount', authResult.account.username);
}
export async function getToken() {
const account = localStorage.getItem('msalAccount');
if (!account) {
throw new Error(
'User info cleared from local storage. Please sign out and sign in again.'
);
}
try {
// First, attempt to get the token silently
const silentRequest = {
scopes : msalRequest.scopes,
account : msalInstance.getAccountByUsername(account)
};
const silentResult = await msalInstance.acquireTokenSilent(silentRequest);
return silentResult.accessToken;
}
catch (silentError) {
// If silent request fails with InteractionRequiredAuthError,
// attempt to get the token interactively
if (silentError instanceof InteractionRequiredAuthError) {
const interactiveResult = await msalInstance.acquireTokenPopup(
msalRequest
);
return interactiveResult.accessToken;
}
else {
throw silentError;
}
}
}
export async function signOut() {
const account = localStorage.getItem('msalAccount');
if (account) {
const logoutRequest = {
account : msalInstance.getAccountByUsername(account)
};
await msalInstance.logoutPopup(logoutRequest);
localStorage.removeItem('msalAccount');
}
}
This code instantiates a PublicClientApplication
object to use the MSAL.js
library. The msalRequest
variable stores the current Microsoft Authentication Library request. This variable initially contains an empty array of scopes because your app needs to include a list of scopes when it requests an access token from Microsoft Entra ID. The list of permissions granted to your app is part of the access token returned when a user logs in.
The ensureScope
function checks the permissions the user has. We’ll use this function when making requests to the Microsoft Graph API to perform CRUD operations on the user’s Microsoft Planner tasks. Each operation in Microsoft Graph has its own list of scopes. The list of permissions required for each operation is available in the Microsoft Graph permissions reference.
The signIn
function grants the user access and stores their access token in the browser’s local storage. The getToken
function gets the user’s access token from local storage.
The signOut
function uses the username stored in local storage to sign out the user.
Using Microsoft Graph to access a user’s Microsoft Planner events
We’ll use the Microsoft Graph Planner REST API to perform CRUD operations on the user’s Microsoft Planner plan tasks.
First, install the Microsoft Graph JavaScript client library:
npm i @microsoft/microsoft-graph-client
This library is a lightweight wrapper around the Microsoft Graph API.
Create a file called graph.js
in your project’s root directory and add the following lines of code to it:
import { Client } from '@microsoft/microsoft-graph-client';
import { ensureScope, getToken } from './auth.js';
const authProvider = {
getAccessToken : async() => {
return await getToken();
}
};
// Initialize the Graph client
const graphClient = Client.initWithMiddleware({ authProvider });
export async function getTasks() {
ensureScope('Tasks.Read');
return await graphClient
.api(
`/planner/plans/${
import.meta.env.VITE_MICROSOFT_PLANNER_PLAN_ID
}/tasks?$expand=details`
)
.select('id, title, startDateTime, dueDateTime, details, percentComplete')
.get();
}
This code creates a Microsoft Graph SDK client instance, grantClient
and passes in the authProvider
to the instance as one of the ClientOptions. This passes the user’s access token to the Microsoft Graph API.
The getTasks
function uses the client instance to fetch the user’s tasks from their Microsoft Planner plan. It ensures that the user has read access and then fetches the tasks using the plan ID. It fetches the data from the Microsoft Graph REST API plannerPlan endpoint. The request URL
has an expand parameter to get the task details object, which contains additional information about the tasks. Each task object has a details object. You can use the select
method to select the fields that you want to fetch. We only select some of the available fields for simplicity in this guide.
Adding the Microsoft Planner events to Bryntum Calendar
Let’s add a Microsoft 365 sign-in link to the Bryntum Gantt app.
Replace the contents of the <main>
HTML tag in the index.html
with the following:
<div id="content" style="display: none">
<div id="calendar"></div>
</div>
<div class="loader-container">
<div class="loader"></div>
</div>
<a id="signin" href="#" style="display: none">
<img
src="./images/ms-symbollockup_signin_light.png"
alt="Sign in with Microsoft"
/>
</a>
Add the following styles to the styles.css
file:
.loader-container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh
}
.loader {
display: inline-block;
width: 50px;
height: 50px;
border: 3px solid black;
border-radius: 50%;
border-top-color: #fff;
animation: spin 1s ease-in-out infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
@-webkit-keyframes spin {
to {transform: rotate(360deg); }
}
Initially, the app will display the sign-in link only. When a user signs in, it will display the Bryntum Calendar.
In the main.js
file, add the following lines to store the “Sign in with Microsoft” link element object and loader container in variables:
const signInLink = document.getElementById('signin');
const loaderContainer = document.querySelector('.loader-container');
Now add the following function at the bottom of the file:
async function displayUI() {
const account = localStorage.getItem('msalAccount');
if (!account) {
await signIn();
}
const content = document.getElementById('content');
content.style = 'display: block';
// Display calendar after sign in
const events = await getTasks();
const calendarEvents = [];
const resourceID = 1;
events.value.forEach((event) => {
const startDateUTC = new Date(event.startDateTime);
// Convert to local timezone
const startDateLocal = new Date(
startDateUTC.getTime() - startDateUTC.getTimezoneOffset() * 60000
);
const endDateUTC = new Date(event.dueDateTime);
// Convert to local timezone
const endDateLocal = new Date(
endDateUTC.getTime() - endDateUTC.getTimezoneOffset() * 60000
);
calendarEvents.push({
id : event.id,
name : event.title,
startDate : startDateLocal,
endDate : endDateLocal,
taskETag : event['@odata.etag'].replace(/\\"/g, '"'),
taskDetailsETag : event?.details['@odata.etag'].replace(/\\"/g, '"'),
resourceId : resourceID,
description : event.details ? event.details.description : '',
percentComplete : event?.percentComplete
});
});
calendar.events = calendarEvents;
}
Remove the example inline events
data in the calendar
config and add the signIn
and getTasks
function imports:
import { signIn } from './auth.js';
import { getTasks } from './graph.js';
The displayUI
function calls the signIn
function in auth.js
to sign the user in to the app. Once the user is signed in, the sign-in link is hidden and the Bryntum Calendar is displayed. The getTasks
function in the graph.js
file gets the Microsoft Planner plan tasks. The push method then uses the retrieved tasks to create events for the Bryntum Calendar and adds them to the calendar.events
store. The Bryntum EventModel represents a single event. This code populates some of the Bryntum EventModel fields with the Microsoft Planner plan tasks data.
The calendar will have a single example resource with an ID of 1
and the events will link to this resource. You can learn more about Bryntum Calendar data models in the project data guide.
Now add code to display the correct HTML elements as well as a “click” event listener to the “Sign in with Microsoft” link:
if (localStorage.getItem('msalAccount')) {
displayUI();
signInLink.style = 'display: none';
}
else {
signInLink.style = 'display: block';
}
loaderContainer.style = 'display: none';
signInLink.addEventListener('click', displayUI);
Some of the Microsoft Planner plan task fields, such as the Etags, don’t have an equivalent field in the Bryntum Calendar events. The ETag is used to determine the change in the content of a resource at a given URL. There are two different ETags: taskETag
and taskDetailsETag
.
We need to create a custom Bryntum Calendar event model to add these fields.
Create a lib
folder in the root directory and create a CustomEventModel.js
file inside it. Add the following lines of code to the CustomEventModel.js
file:
import { EventModel } from '@bryntum/calendar';
// Custom event model
export default class CustomEventModel extends EventModel {
static $name = 'CustomEventModel';
static fields = [
{ name : 'taskETag', type : 'string' },
{ name : 'taskDetailsETag', type : 'string' },
{ name : 'description', type : 'string' },
{ name : 'percentComplete', type : 'number', values : [0, 50, 100] }
];
}
This extends the Bryntum Calendar EventModel
to include the Microsoft Planner plan task-specific fields. You can find the types of the Microsoft Planner task properties in the Microsoft Graph docs: plannerTask resource type.
Import this custom event model in the main.js
file:
import CustomEventModel from './lib/CustomEventModel.js';
Set the calendar
to use this event model for its event store:
eventStore : {
modelClass : CustomEventModel
}
Run your dev server using npm run dev
, you’ll see the sign-in link. Sign in with the same admin email address that you used to log in to Microsoft Planner:
Once you’ve signed in and given the app the necessary permissions, you’ll see your Microsoft Planner plan task in your Bryntum Calendar:
Next, we’ll sync the Microsoft Planner plan to the Bryntum Calendar by implementing CRUD functionality using Microsoft Graph. Updates to Bryntum Calendar events will update the tasks in the Microsoft Planner plan.
Syncing changes in the Bryntum Calendar to Microsoft Planner
Now that we’ve connected our calendar to the Graph API, let’s create the functions needed to implement the rest of the CRUD functionality using the Microsoft Graph JavaScript Client Library.
Creating events
In the graph.js
file, add the following createTask
function:
export async function createTask(
name,
startDate,
endDate,
description,
percentComplete
) {
ensureScope('Tasks.ReadWrite');
const task = {
planId : import.meta.env.VITE_MICROSOFT_PLANNER_PLAN_ID,
title : `${name}`,
startDateTime : `${startDate.toISOString()}`,
dueDateTime : `${endDate.toISOString()}`,
details : { description : description },
percentComplete : percentComplete
};
return await graphClient.api('/planner/tasks').post(task);
}
This code first checks that the user has read-write access and then make a POST request to the Microsoft Graph API endpoint. The event object added to the POST request body has the planId
It then passes the event
object, which is a representation of a plannerTask object, in the request body. The plannerTask object must use the ID of an existing plannerPlan object as its planID
.
Updating events
In the graph.js
file, add the following updateTask
function:
export async function updateTask(
id,
name,
startDate,
endDate,
taskETag,
taskDetailsETag,
description,
percentComplete
) {
ensureScope('Tasks.ReadWrite');
const resData = {
id : '',
taskETag : '',
taskDetailsETag : ''
};
// update task and task details
const task = {};
const taskDetails = {};
if (name) task.title = `${name}`;
if (startDate) task.startDateTime = `${startDate.toISOString()}`;
if (endDate) task.dueDateTime = `${endDate.toISOString()}`;
if (percentComplete) task.percentComplete = percentComplete;
if (description) taskDetails.description = description;
// update task only
if (
Object.keys(task).length !== 0 &&
Object.keys(taskDetails).length === 0
) {
const updateTaskRes = await graphClient
.api(`/planner/tasks/${id}/`)
.header('If-Match', taskETag)
.header('prefer', 'return=representation')
.update(task);
resData.id = updateTaskRes.id;
resData.taskETag = updateTaskRes['@odata.etag'];
return resData;
}
// update task details only
if (
Object.keys(taskDetails).length !== 0 &&
Object.keys(task).length === 0
) {
const updateTaskDetailsRes = await graphClient
.api(`/planner/tasks/${id}/details`)
.header('If-Match', taskDetailsETag)
.header('prefer', 'return=representation')
.update(taskDetails);
resData.id = updateTaskDetailsRes.id;
resData.taskDetailsETag = updateTaskDetailsRes['@odata.etag'];
return resData;
}
if (
Object.keys(task).length !== 0 &&
Object.keys(taskDetails).length !== 0
) {
// update task and task details
const updateTaskPromise = graphClient
.api(`/planner/tasks/${id}/`)
.header('If-Match', taskETag)
.header('prefer', 'return=representation')
.update(task);
const updateTaskDetailsPromise = graphClient
.api(`/planner/tasks/${id}/details`)
.header('If-Match', taskDetailsETag)
.header('prefer', 'return=representation')
.update(taskDetails);
const [updateTaskRes, updateTaskDetailsRes] = await Promise.all([
updateTaskPromise,
updateTaskDetailsPromise
]);
resData.id = updateTaskRes.id;
resData.taskETag = updateTaskRes['@odata.etag'];
resData.taskDetailsETag = updateTaskDetailsRes['@odata.etag'];
return resData;
}
}
This function first checks that the user has read-write access, then makes a PATCH request to the Microsoft Graph API endpoint, passing in the changed data to the update
method.
It then updates the event, the event details, or both based on the event data. The request has the required ‘If-Match’ header with the latest ETag value for the task. The Prefer
header has a value of return=representation
so that the response returns the updated task or task details object in the response body. If this header is not specified, the update
methods return a 204 No Content
response and empty content.
Deleting events
In the graph.js
file, add the following deleteTask
function:
export async function deleteTask(id, taskEtag) {
ensureScope('Tasks.ReadWrite');
return await graphClient
.api(`/planner/tasks/${id}`)
.header('If-Match', taskEtag)
.delete();
}
This deletes the event by its id
.
Listening for event data changes in Bryntum Scheduler
Next, we’ll add a data change event listener to the Bryntum Calendar so that we can update the user’s Microsoft Planner plan tasks when the user updates the Calendar events.
Add the following listener
property to the calendar
config in the main.js
file:
listeners: {
dataChange: function (event) {
if (event.store.id === "events") {
updateMicrosoftPlanner(event);
}
},
},
The event
argument in the dataChange
event listener callback contains the event data of the changed event. The property passes the event data to a function called updateMicrosoftPlanner
that will update the user’s Microsoft Planner plan tasks.
Add the following definition for the updateMicrosoftPlanner
function to the bottom of your main.js
file:
async function updateMicrosoftPlanner(event) {
if (event.action == 'update') {
const id = event.record.id;
if (`${id}`.startsWith('_generated')) {
const createTaskRes = await createTask(
event.record.name,
event.record.startDate,
event.record.endDate,
event.record.description,
event.record.percentComplete
);
// update id and eTags
calendar.eventStore.applyChangeset({
updated : [
// Will set proper id and eTag for added task
{
$PhantomId : id,
id : createTaskRes.id,
taskETag : createTaskRes['@odata.etag']
}
]
});
return;
}
if (!event.record.taskDetailsETag) return;
const updateTaskRes = await updateTask(
id,
event.record.name,
event.record.startDate,
event.record.endDate,
event.record.taskETag,
event.record.taskDetailsETag,
event.record.description,
event.record.percentComplete
);
const updatedObj = {
id : updateTaskRes.id
};
if (updateTaskRes.taskETag) {
updatedObj.taskETag = updateTaskRes.taskETag;
}
if (updateTaskRes.taskDetailsETag) {
updatedObj.taskDetailsETag = updateTaskRes.taskDetailsETag;
}
calendar.eventStore.applyChangeset({
updated : [
// Will set proper eTags for updated task
updatedObj
]
});
}
if (event.action == 'remove') {
const recordsData = event.records.map((record) => record.data);
recordsData.forEach((record) => {
if (record.id.startsWith('_generated')) return;
deleteTask(record.id, record.taskETag);
});
}
}
This code calls the appropriate CRUD function in the graph.js
file, depending on the action that triggered the data change: “update” or “remove”. It creates a new task when an “update” action occurs and the event has an id
that starts with "_generated"
. New records in a Bryntum Calendar are assigned a temporary UUID that starts with "_generated"
and an “update” action occurs right after a “create” action occurs for a created event.
After creating a Microsoft Planner plan task, the applyChangeset
method updates the calendar task store with the id
and taskEtag
values assigned to the task by Microsoft Planner. The $PhantomId
is a phantom identifier, a unique, autogenerated client-side value used to identify a record. You can read more about phantom identifiers in the Bryntum docs.
Import the CRUD functions from the graph.js
file:
import { createTask, deleteTask, updateTask } from './graph.js';
Changes in the Bryntum Calendar app will now be synced to the Microsoft Planner plan.
Customizing the event editor
Open the event editor in the Bryntum Calendar by double-clicking on an event. You’ll see that our two custom fields, description
and percentComplete
, are not displayed in the form. To display them, we need to customize the event editor.
Add the following features
property to the calendar
configuration object in main.js
:
features : {
eventEdit : {
items : {
nameField : {
required : true
},
// Custom fields
percentCompleteField : {
type : 'combo',
label : 'Progress',
name : 'percentComplete',
multiSelect : false,
required : true,
items : [
{
value : 0,
text : 'Not started'
},
{
value : 50,
text : 'In progress'
},
{ value : 100, text : 'Completed' }
]
},
descriptionField : {
type : 'textarea',
label : 'Notes',
// Name of the field in the event record to read/write data to
// NOTE: Make sure your EventModel has this field for this to link up correctly
name : 'description'
}
}
}
},
This property sets the nameField
to be required so that the user must supply a name for the event. It adds the two custom fields as form items and sets the input types, labels, and names. The name of each item should match the name of the custom field in the lib/CustomEventModel.js
file.
Customizing the rendered events
We can make our Bryntum Calendar match the Microsoft Planner plan schedule view more closely by changing the month view.
Add the following modes
property to the calendar
to configure the month view:
modes : {
month : {
// Render an icon showing progress state (editable in the event editor)
eventRenderer : ({ eventRecord, renderData }) => {
if (eventRecord.percentComplete === 0) {
renderData.eventColor = '#605e5c';
}
if (eventRecord.percentComplete === 50) {
renderData.eventColor = '#327eaa';
renderData.iconCls['b-fa b-fa-hourglass-half'] = 1;
}
if (eventRecord.percentComplete === 100) {
renderData.eventColor = '#107c41';
renderData.iconCls['b-fa b-fa-exclamation'] = 1;
}
return `
<span class="b-event-name">${StringHelper.xss`${eventRecord.name}`}</span>
`;
}
}
},
The eventRenderer
method alters the styling of the rendered event to indicate event progress by changing the color and adding an icon based on the percentComplete
field.
Add the import for the StringHelper
function that we use to perform HTML encoding that prevents XSS (Cross-Site Scripting) attacks:
import { StringHelper } from "@bryntum/calendar";
Add the following toolbar
property to the calendar
to add a sign-out button to the toolbar:
tbar : {
items : {
deleteButton : {
text : 'Signout',
icon : 'b-fa b-fa-sign-out',
onClick() {
signOut().then(() => {
// Refresh the page after sign out
location.reload();
});
}
}
}
},
Import the signOut
function:
import { signOut } from './auth.js';
Run your dev server using npm run dev
. Try to create, update, delete, and edit an event in the Bryntum Calendar. Changes you make will be reflected in your Microsoft Planner plan.
Next steps
This tutorial gives you a starting point for creating a Bryntum Calendar with vanilla JavaScript and syncing it to Microsoft Teams. You can sync more of the Microsoft Planner plan task fields, including assignments, priority, bucket, checklist, comments, and attachments. At present, you can only sync recurring events using the Beta version of the Microsoft Graph REST API.
You can further recreate the Microsoft Planner Schedule view by using a Bryntum Task Board to add an Unscheduled tasks to-do list next to the Bryntum Calendar. Take a look at our blog post Using multiple Bryntum components to learn how to do this.