How to add external JavaScript file without typings in SharePoint Framework

Problem Statement 

In one of my requirement I have to reference https://c64.assets-yammer.com/assets/platform_embed.js file in SharePoint Framework WebPart to display the yammer feeds. But the platform_embed.js file is not available in npm and typings are also not available.

Solution

As the TypeScript typings is not available for yammer platform_embed.js file, we can’t use import * as yammer from the external settings. Instead, we should use require(‘yammer’).

Also yam is a global object, so we have to change the way we reference it to (window as any).yam.connect.embedFeed() instead of (yam as any).connect.embedFeed()

Thank you Waldek Mastykarz for this suggestion.

Check the below example

spfx1

spfx2.PNG

SharePoint Framework – Yammer Feed WebPart using Angular

Summary

This Web Part displays the feeds from yammer using https://c64.assets-yammer.com/assets/platform_embed.js.

Yammer Feed WebPart using Angular Yammer Feed WebPart Properties

Used SharePoint Framework Version

drop

Applies to

Solution

Solution Author(s)
angular-yammer Joseph Velliah (SPRIDER, @sprider)

Version history

Version Date Comments
1.0 March 03, 2017 Initial release

Disclaimer

THIS CODE IS PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.


Minimal Path to Awesome

  • clone this repo
  • in the command line run:
    • npm i
    • tsd install
    • gulp serve

Features

The Yammer Feed is a sample Client-Side Web Part built on the SharePoint Framework using Angular.

This Web Part illustrates the following concepts on top of the SharePoint Framework:

  • using Angular for building SharePoint Framework Client-Side Web Parts
  • including Angular in the Web Part bundle
  • using non-reactive Web Part Property Pane and custom Properties
  • using conditional rendering for one-time Web Part setup
  • passing Web Part configuration to Angular and reacting to configuration changes
  • display the yammer feed based on configuration changes

Download SharePoint Online Files using MAC CURL Command

Problem Statement
MAC SharePoint users were downloading the files from SharePoint 2007 Document Libraries using the CURL command but the same is not working after migrating the SharePoint 2007 sites to SharePoint Online(SPOL).

Example
curl -k https://domain.sharepoint.com/sites/test/librarytitle/foldertitle/filename.zip --NTLM --user "domain\user":"password" -o filename.zip

Cause
SharePoint Online uses claims based authentication and direct NTLM based curl commands are not allowed.

Resolution
SPOL allows remote applications to call the REST API with user impersonation. This article demonstrates how to access SPOL REST API and download the files from a tenant using Apple Bash Script and Curl commands. However, outside of .NET the authentication piece is not so straightforward. App authentication solves this issue for registered apps but in this document you will see how remote user authentication can be achieved, regardless of platform.

The below diagram illustrates the HTTP requests which need to be made in order to authenticate SharePoint Online.

spolremoteauth

Applies To
Office 365 Tenant connected with Active Directory Federated Service(ADFS) and MAC OS

Execution Steps

  • Download the BashSPOLFileDownload.sh file from here
  • Open BashSPOLFileDownload.sh file in a text editor(TextWrangler/TextMate) and update the UserName (Line #4) and Password (Line #5).

remotecodebash

Note: The UserName & Password provided should have access to download the file from SharePoint Online.

  • To download the file from a different SharePoint Online site/library/folder/file where the account has access, change the values of EndPoint(Line #6) and FileServerRelativeUrl(Line #7) values.
  • Save the BashSPOLFileDownload.sh file
  • Open Terminal (command line tool) and go to the path where BashSPOLFileDownload.sh file is saved
  • Execute the following command to convert the BashSPOLFileDownload.sh file executable chmod 700 BashSPOLFileDownload.sh
  • Run the script using just the name of the script(Example : ./ BashSPOLFileDownload.sh)
  • If all goes well, you should be able to see the downloaded file in the output path given in OutputFilePath(Line #9).

Failure Chances

  • UserName and Password provided might be wrong
  • Access denied from SharePoint Online for the UserName and Password provided
  • Provided Site/Document Library/Folder/File is not available in SharePoint Online or wrong
  • Text Editor might have changed or corrupted the BashSPOLFileDownload.sh file while saving

ASP.NET Custom Web API & Curl Bash and PowerShell commands to download files from SharePoint Online

In this article I am going to illustrate how to download a file from SharePoint Online using Custom ASP.NET Web API and Curl Bash Command.

Model Definition

using System.ComponentModel.DataAnnotations;
using SPOL.FileDownload.Filters;

namespace SPOL.FileDownload.Models
{
public class SPOLFile
{
[Required(ErrorMessage = “Site Url is not passed with the endpoint”)]
[Display(Name = “SiteUrl”)]
[ValidateSite]
public string SiteUrl { get; set; }

[Required(ErrorMessage = “Library Name is not passed with the endpoint”)]
[Display(Name = “LibraryName”)]
[ValidateLibrary]
public string LibraryName { get; set; }

[Display(Name = “FolderPath”)]
[ValidateFolder]
public string FolderPath { get; set; }

[Required(ErrorMessage = “File Name is not passed with the endpoint”)]
[Display(Name = “FileName”)]
[ValidateFile]
public string FileName { get; set; }
}
}

Model Validation

using System.Net;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;

namespace SPOL.FileDownload.Filters
{
public class ValidateSPOSiteModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.ModelState.IsValid == false)
{
actionContext.Response = actionContext.Request.CreateErrorResponse(
HttpStatusCode.BadRequest, actionContext.ModelState);
}
}
}
}

Model Field Validation

using System.ComponentModel.DataAnnotations;
using SPOL.FileDownload.Helpers;
using Microsoft.SharePoint.Client;

namespace SPOL.FileDownload.Filters
{
public class ValidateSiteAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
try
{
ClientContext clientContext = null;
var url = value as string;

if (string.IsNullOrEmpty(url))
return false;

clientContext = new OfficeDevPnP.Core.AuthenticationManager().GetSharePointOnlineAuthenticatedContextTenant(url, Settings.serviceAccountUserId, Settings.serviceAccountPassword);
var web = clientContext.Web;
clientContext.Load(web);

try
{
clientContext.ExecuteQuery();
return true;
}
catch
{
ErrorMessage = “Site url you have passed in not valid.”;
return false;
}
finally
{
if (clientContext != null)
clientContext.Dispose();
}
}
catch
{
ErrorMessage = “There is a problem accessing the site url.”;
return false;
}
}

}
}

Model Field Validation with Validation Context to pass parameters

using System.ComponentModel.DataAnnotations;
using SPOL.FileDownload.Helpers;
using Microsoft.SharePoint.Client;
using System;
using System.Reflection;
using System.IO;

namespace SPOL.FileDownload.Filters
{
public class ValidateFileAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
bool isValid = true;
string ErrorMessage = "";
ClientContext clientContext = null;

try
{

var filename = value as string;

object instance = validationContext.ObjectInstance;
Type type = instance.GetType();

PropertyInfo propertySiteUrl = type.GetProperty("SiteUrl");
PropertyInfo propertyLibraryName = type.GetProperty("LibraryName");
PropertyInfo propertyFolderPath = type.GetProperty("FolderPath");

object siteUrl = propertySiteUrl.GetValue(instance);
object libraryName = propertyLibraryName.GetValue(instance);
object objFolderPath = propertyFolderPath.GetValue(instance);

string folderpath = Convert.ToString(string.IsNullOrEmpty((string)objFolderPath) ? "" : objFolderPath);

if (string.IsNullOrEmpty(filename))
{
isValid = false;
ErrorMessage = "File name is not passed with the endpoint";
}

string extention = Path.GetExtension(filename);

if (string.IsNullOrEmpty(extention))
{
ErrorMessage = "Not a valid file name extention.";
isValid = false;
}
else
{

clientContext = new OfficeDevPnP.Core.AuthenticationManager().GetSharePointOnlineAuthenticatedContextTenant(siteUrl.ToString(), Settings.serviceAccountUserId, Settings.serviceAccountPassword);

var url = new Uri(siteUrl.ToString());
var relativeUrl = String.Format("{0}/{1}/{2}/{3}", url.AbsolutePath, libraryName.ToString(), folderpath, filename);

try
{
var fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(clientContext, relativeUrl);
isValid = true;
}
catch
{
ErrorMessage = "File name you have passed in not avilable.";
isValid = false;
}
finally
{
if (clientContext != null)
clientContext.Dispose();
}
}
}
catch
{
ErrorMessage = "There is a problem accessing the file.";
isValid = false;
}

if (isValid)
return ValidationResult.Success;
else
return new ValidationResult(ErrorMessage);
}
}
}

Controller

using SPOL.FileDownload.Filters;
using SPOL.FileDownload.Helpers;
using SPOL.FileDownload.Models;
using Microsoft.SharePoint.Client;
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Web;
using System.Web.Http;

namespace SPOL.FileDownload.Controllers
{
public class DownloadFileController : ApiController
{
[Route(“api/file”)]
[HttpGet]
[ValidateSPOSiteModel]
public HttpResponseMessage DownloadFile([FromUri] SPOLFile spolFile)
{
MemoryStream stream = new MemoryStream();
ClientContext clientContext = null;

try
{
if (ModelState.IsValid)
{
clientContext = new OfficeDevPnP.Core.AuthenticationManager().GetSharePointOnlineAuthenticatedContextTenant(spolFile.SiteUrl, Settings.serviceAccountUserId, Settings.serviceAccountPassword);

var url = new Uri(spolFile.SiteUrl);
var relativeUrl = String.Format(“{0}/{1}/{2}/{3}”, url.AbsolutePath, spolFile.LibraryName, spolFile.FolderPath, spolFile.FileName);

var fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(clientContext, relativeUrl);

var buf = new byte[1024 * 16];
int byteSize;

while ((byteSize = fileInfo.Stream.Read(buf, 0, buf.Length)) > 0)
{
stream.Write(buf, 0, byteSize);
}

string mediaType = MimeMapping.GetMimeMapping(spolFile.FileName);

var result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new ByteArrayContent(stream.ToArray());
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue(“attachment”);
result.Content.Headers.ContentDisposition.FileName = spolFile.FileName;
result.Content.Headers.ContentType = new MediaTypeHeaderValue(mediaType);

return result;
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
}
catch (Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex.ToString()); // new HttpResponseMessage(HttpStatusCode.InternalServerError);
}
finally
{
if (stream != null)
stream.Dispose();
if (clientContext != null)
clientContext.Dispose();
}
}

}
}

 

Bash Command

endpoint='http://site.azurewebsites.net/api/file'
siteurl='https://site.sharepoint.com/sites/dev'
libraryname='Files to Download'
folderpath='First Level/Second Level'
filename='Azure_Application_Insights.pptx'

url=”${endpoint}?siteurl=${siteurl}&libraryname=${libraryname}&folderpath=${folderpath}&filename=${filename}”

curl “${url}” -o “${filename}”
PowerShell Command
The same operation can be done in windows OS using PowerShell commands as well.

Invoke-RestMethod -Uri "http://site.azurewebsites.net/api/file?siteurl=https://site.sharepoint.com/sites/dev&libraryname=Files to Download&folderpath=&filename=Azure_Application_Insights.pptx" -Method Get | Out-File -filepath "C:\Users\joseph\Downloads\Azure_Application_Insights.pptx"

KPI Indicators using SharePoint JavaScript Display Templates & Bootstrap

SharePoint users can reference a JavaScript files and use the same as settings to Control the rendering of fields, row items, list forms. In this article i will show you how we can display KPI indicator using a JavaScript file.

Steps 

  • Create a custom list with the following columns
Column Name Filed Type
Title Single line of text
Status Choice

 

The values are

Success

Info

Warning

Danger

  • Add some items to the newly created list with different Status values
  • Upload the Task_Status_Indicator.js file under Site Settings –> Web Designer Galleries –> Master pages and page layouts and update the following properties

properties

  • Publish Task_Status_Indicator.js file as major Version
  • Upload your own images for indicators with the following names

Circle_Blue.png

Circle_Red.png

Circle_Yellow.png

Circle_Green.png

Note: I have uploaded my images in the Site Assets library. If you wish to change the image names or location where it is uploaded, change the img tag references in Task_Status_Indicator.js and upload again.

  • Go to List URL/AllItems.aspx and edit the List View webpart and add the javascript display template file path as shown below

wpconfig

Note: In my case it will be ~site/_catalogs/masterpage/Task_Status_Indicator.js

  • Click OK/Apply to see the changes as shown below

kpi

With pagination 

kpi

Notes:

Change the logic in JS file as per your requirement and design.

Pagination is also implemented in this approach.

Basic Site Provisioning using SharePoint Framework client-side web part and Microsoft Bot Framework

Summary

Sample SharePoint Framework client-side web part illustrating Site Provisioning using Microsoft Bot Framework.

preview.png

 

Applies to

Solution

Solution Author(s)
js-bot-framework Joseph Velliah (SPRIDER, @sprider)

Version history

Version Date Comments
1.0 December 13, 2016 Initial release

Disclaimer

THIS CODE IS PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.


Minimal Path to Awesome

  • clone this repo from here

Register Bot

  • go to https://dev.botframework.com/ and sign in with your Microsoft account
  • click on Register a bot link at the top botregister-step1.png
  • fill all the details like Name, Bot handle, Description and Messaging endpoint
  • generate a new App ID and password by clicking Create Microsoft App ID and password button. Save this value somewhere as we will use in this next step
  • accept the terms and click Register
  • your bot is now registered
  • click edit link under Web Chat channel and notedown the Secret key to configure the client web part botregister-step3
  • you can test your connection here by typing hello message and click Send. Try this step after completing “Publish Bot in Azure Web App” step

Publish Bot in Azure Web App

  • in the Azure Management Portal at https://portal.azure.com create a new Web App(example: https://asksprider.azurewebsites.net/)
  • download the publishing profile from the web app we just created. This will be used to publish the Bot in Azure using Visual Studio
  • Open the web.config file in AskSPRider.sln and update the MicrosoftAppId, MicrosoftAppPassword, O365AdminId and O365AdminPassword
    • MicrosoftAppId – App ID generated from Bot Registration Process
    • MicrosoftAppPassword – App Secret generated from Bot Registration Process
    • O365AdminId – SharePoint Online Admin User Id(example: user@tenant.onmicrosoft.com)
    • O365AdminPassword – SharePoint Online Admin Password
  • save the web.config file
  • right click on the project and publish the bot in Azure using the publishing profile downloaded

Configure web part

  • go to the working directory to the webpart folder in the command line run:
    • npm i
    • tsd install
    • gulp serve
  • add Ask SP Rider webpart and edit it
    • configure bot name and web chat secret key botregister-step4
    • type hello and proceed with site creation process
    • final output botregister-step4

Features

This project illustrates the following concepts:

  • connecting SharePoint Framework client-side web part to a custom bot
  • showing how to embed bot within client-side web part
  • how to create a sub-site by posting set of questions to the user via bot
  • bot form field validations

WebParts in Tabs & Accordions where Tabs Act as Accordions in Lower Resolutions

Purpose

The purpose of this document is to highlight conversion of several WebParts added in a page to tabs which act as accordions in lower resolutions.

Requirement

Convert all WebParts in a zone to TABS

  • Default Order
  • Specific Order

Establish responsive behavior of TABS i.e. Tabs to act as accordions in lower resolutions

Implement CA theme and allow for theme customization.

Multi-browser support

Insights on Code

To convert web parts to tabs layout

To establish interactions on tab, conversion to accordion in lower resolutions

  • Custom code

Dependencies

  • JQuery library

Tested On

  • Chrome (Latest)
  • Firefox (Latest)
  • Internet Explorer 11

Code

Download the code from Github

Usage

Pre-requisite – if files are not on CDN:

Upload the below files in the site-specific documents library that you are currently working and capture its absolute URL path

  • jquery-1.11.1.min.js
  • custom-tabs.js
  • custom-tabs.css
  • tabs.js

Pre-requisite – if CDN dependencies are on CDN

Upload the below files in the site-specific documents library that you are currently working and capture its absolute URL path

  • tab.js

Creating Default Tab Order

CREATE a web part page

new page.PNG

ADD required WebParts into desired zones.

add-webparts

For instance, we’ve added

  • Page Viewer Web part
  • Image Viewer Web part

After adding the required web parts, add a content editor web part

cewp

EDIT the content editor web part and paste tabs.js URL inside the Content Link box

cewp tab config.PNG

Click OK. You’d see that all web parts will now be converted into TABS

Stop Editing to preview the page. The page would look as below

new tabs.PNG

To check Responsivity, resize your browser. Tabs Would Render as Accordions

responsive.PNG

Note: Tabs layout turns into Accordion layout below 992 pixels

The above illustrates the default behavior of the Tabs. All web parts would become tabs in a random order.

Creating Specific Tab Order

To create a specific tab order,

Edit tabs.js file in notepad

Add two forward slashes (//) before genWebpartTabs(); function as shown below

comment genWebpartTabs.png

Find “//Put 2 web parts in 2 different tabs” uncomment i.e. removed forward slashes as shown below

add titles genWebpartTabs.png
webPartTitles is an array of web part titles. As shown in the above snapshot, write the tiles of your WebParts using the following rules

  • Web part titles to be enclosed in double quotes or single quotes
  • Each web part title must be comma separated
  • The last web part title must not end with a comma after the quote

For instance, in the Default Tab Order (Previous section), we’ve created web parts in a random order. Currently the order is as below:

  1. Page Viewer
  2. Image Viewer

If you’d like to change this to

  1. Image Viewer
  2. Page viewer

Then update the script as below and save the file.
//Put 2 web parts in 2 different tabs
var webPartTitles = [“Image Viewer”,”Page Viwer”];
genWebpartTabs(webPartTitles);

Upload the file to your site’s document library and capture its absolute URL path.

Follow steps 3 to 5 as illustrated in Default Tab Order section and you’d see the tab order being changed as specified in the above mentioned snippet.

capture

Customization – Appearance

tabs.js file allows you to customize the appearance of the of the tabs which includes

  • Active Tab Color
  • Active Tab Text Color
  • Inactive Tab Color
  • Inactive Tab Text Color
  • Inactive Tab Color On Mouse Hover
  • Tab Content Background Color

These parameters are available in appearance_config object inside tabs.js file as shown below:

default color config.png

To change the appearance of the tabs, change the values inside the quotes of this object. You can also use common color names such as red, blue etc. but it is recommended to use a HEX value only.

For instance, we’d like to see

  • Active tab color as Light Blue i.e. #53bbD4
  • Active tab text color as white i.e. #FFFFFF
  • Inactive tab color as Dark Blue i.e. #22465E
  • Inactive tab text color as Middle Grey i.e. #91838B
  • Inactive tab hover color as Dark Blue i.e. #22465E
  • Tab content background color as Warm Grey i.e. #D8D8D8

To do so, update the appearance_config as below

color-config
Save and Upload the tabs.js (replace existing in the document library). The output would be as below:

capture

Limitations

  • All web parts would not be integrated into tabs cause of SharePoint specific behavior.
  • Only one instance of tabs could be used at a time in the current scenario which would be scaled further on usage scenarios.
  • Older browsers i.e. IE below 9 would require additional coding effort.

Thank you Srikar for the wonderful UI design.