Tuesday, December 17, 2019

How to resolve Nintex forms custom button submit AND redirect issue

We have a Nintex forms with one custom button submit then redirect to a confirmation page. When user click the button, it was redirecting to something strange. See screenshot below.

After debugging this issue, it seems like Nintex form button redirect could not resolve the link you copied from browser directly. See the screenshot below.


The solution is to copy the redirect URL from browser to notepad first, then copy to the Nintex form. This seems like trivial but took me an hour to figured out from Nintex support site.

Hope this will remind me in the future.

Thursday, December 12, 2019

How to resolve Nintex workflow email action 'The specified string is not in the form required for a subject.' error


We have a running Nintex workflow in production failed for few email actions with the error message “The specified string is not in the form required for a subject.”


 After debugging this, it seems like there is an limitation for O365 outlook that subject line cannot be folded across multiple lines. It does not seem to have the character limitation for the subject. However, no matter how long of a subject you submit, exchange will ultimately truncate the unencoded version of that subject down to 255 characters and append "...".

So in order to resolve the error listed above, we have implemented in two different palaces for our SharePoint framework solution as UI with Nintex workflow.

1. Inside SharePoint framework solution, trim and leading and trailing spaces and returns. Then also replace inside returns with space.


    let trimedTitlestring = title;
    if(title !=null){
//This javascript trim leading and trailing spaces and returns
      trimedTitle = title.trim(); 

      if (trimedTitle != null){
//This javascript replaces all 3 types of line breaks with a space 
        trimedTitle = trimedTitle.replace(/(\r\n|\n|\r)/gm," "); 
    }

//The trimedTitle will be the good subject that could be used in exchange email


2. In Nintex workflow, add a “Trim String” activity on the subject before send email.


This will ultimately resolve the email action error 'The specified string is not in the form required for a subject.'.

Friday, November 8, 2019

Easy to detect device from SharePoint SPFX React application

We have a SharePoint framework application need to behavior differently when invoked from mobile device. Here is the quick way to implement this.

1. Install react-device-detect package
npm install react-device-detect --save
2. Import the package
import {
  BrowserView,
  MobileView,
  isBrowser,
  isMobile
} from "react-device-detect";
3. Use it inside your application

  if(!isSubmitDisabled && !recordIsReadOnly && isMobile){

      submitMenuProps = {
        items: [
          {
            key: 'saveOnly',
            name:'Save only',
            secondaryText: 'Do not submit to approval workflow',
            text: 'Save as draft',
            title: 'Save without submitting to a workflow',
            iconProps: { iconName: 'Save'},
            onClick: this.props.onSaveOnly
          },                       
          {
            key: 'Submit',
            name:'Submit',
            secondaryText: 'Submit to approval workflow',
            text: 'Submit from Mobile',
            title: 'Submitting to a workflow',
            iconProps: { iconName: 'SaveToMobile'},
            onClick: this.props.onSubmit
          }                     
        ]
      };
    }

Thursday, October 10, 2019

Procedure to resolve the issue - cannot add SharePoint online list item with form does not exist error

We have found an issue that we could add new item to a SharePoint online list. The error is the form does not found. After debugging the issue, we identified that display item, edit item, and add item all have the same issue. Here is the details how to debug and fix the issue.

1. Verify three forms. If you understand how SharePoint works, you will know immediately that this should be the issue on SharePoint three form issue (NewForm.aspx, DidForm.aspx, and EditForm.aspx).  You can verify after open the site with SharePoint designer. 

2. Try to recreate the missing forms. The next step is to use SharePoint designer to add these three forms as described here. However, we got server error.

3. The next step is to migrate the same list from another place using Sharegate. The migration failed and has the following message.

"Unable to create web part 'Microsoft.SharePoint.WebPartPages.ListFormWebPart': A Web Part or Web Form Control on this Page cannot be displayed or imported. You don't have Add and Customize Pages permissions required to perform this action.. In Office 365, this is mainly caused by the farm setting "Custom Script" being deactivated."

Now we identified the root cause.

4. Enable the "Custom Script" on the site using the script described here

Connect-SPOService -Url https://mycompany-admin.sharepoint.com
Set-SPOSite -Identity https://mycompany.sharepoint.com -DenyAddAndCustomizePages

5. The final step is either recreate the three forms from SharePoint designer or migrate content from another environment.

6. You might want to disable the "Custom Script" again suing Powershell.

Connect-SPOService -Url https://mycompany-admin.sharepoint.com
Set-SPOSite -Identity https://mycompany.sharepoint.com -DenyAddAndCustomizePages 1


We are not sure why the three forms lost in the first place but this blog will give you the procedure to fix the issue. 

Thursday, September 26, 2019

How to display Url object in reatctable

If you need to display Url object with link and descriptions inside reatctable, here are the steps.

1. Create a Url interfance and add to the object.
export interface Url {
    Urlstring;
    Descriptionstring;
}

export interface ApproverWithLink {
  name?: string;
  emailstring;
  idnumber;
  rolestring;
  statusstring;
  lastmodifiedstring;
  taskLinkUrl;
}


2. Create the object and fill in Url object.

  public static _getApproverWIthUrl(workflowUsersIWorkflowUsers): ApproverWithLink[] 

    let authorsApproverWithLink[] = [] as ApproverWithLink[];

    if(workflowUsers != null && workflowUsers != undefined && 
workflowUsers.approvers != null &&  workflowUsers.approvers != undefined){
      let localApprovalsApprover[] = workflowUsers.approvers;  
      for (let i = 0i < localApprovals.lengthi++) {

        let localUrlUrl = {Url: 'https://www.google.com'Description:'Google'};
        let returnRecApproverWithLink = {name: localApprovals[i].name
email: localApprovals[i].emailid: 0,  role: localApprovals[i].role
status: localApprovals[i].status
lastmodified: localApprovals[i].lastmodifiedtaskLink: localUrl  };


        authors.push(returnRec);
      }
    }
    
    return authors;

  }


3. Display on the webpart

let localApprovalsApproverWithLink[] = 
SPFacade._getApproverWIthUrl(this.props.wfApprovalReviewerList);


<ReactTable
                                  data={localApprovals}
                                  columns={[
                                    {
                                      
                                      columns: [
                                        {
                                          Header: "Name",
                                          accessor: "name"
                                          
                                        },
 
                                        {
                                          Header: "Role",
                                          accessor: "role"
                                        },
                                        {
                                          Header: "Status",
                                          accessor: "status"
                                        },
                                        {
                                          Header: "Last Modified",
                                          accessor: "lastmodified"
                                        },
                                        {
                                          Header: "Link",
                                          accessor: "taskLink",
                                          Cell: e=><a href={e.value.Url}> {e.value.Description} </a>
                                          
                                        }
                                      ]
                                    }
                                  ]}
                                  defaultPageSize={5}
                                  showPagination={false}
                                  noDataText="No approvals assigned!"
                                  style={{
                                    height: "200px" // This will force the table body to overflow and scroll, since there is not enough room
                                  }}
                                  className="-striped -highlight"
                                />
                          </div>



Thursday, September 19, 2019

Procedure to hide SharePoint online list public views

We have a SharePoint site that is used by two different type of users. One type is admin who should be able to see list item. The other type is regular user who should see some list item based on the column value. We do not want to have item level permissions that will need additional development effort. Here is the quick solution.



  1. Create public view to exclude list item based on the column value. 
  2. Create another master view to display all items. 
  3. Add a page that is only be accessed by Admin group that has the link to the master view and include the master view.
  4. Use Powershell to hide the view from view selections.


#Install-Module SharePointPnPPowerShellOnline

#Change this to the URL of your SharePoint site
$sharePointUrl = "https://yourcompany.sharepoint.com/sites/sitename"

#Connect-PnPOnline –Url $sharePointUrl –Credentials (Get-Credential)

# open learner list
$listUrl = "Lists/listname"
$list = Get-PnPList -Identity $listUrl

$list.Context.Load($list.Views)
$list.Context.ExecuteQuery()

ForEach($v in $list.Views){

    if($v.Title -eq 'ListViewName'){ 
    $v.Hidden = $true;
    #$v.Hidden = $false;
    $v.Update()
    }
}

$list.Context.ExecuteQuery()

Monday, August 12, 2019

React component to display data in table format with scroll bar and pagination

There are many different ways you could choice to display data in table format with scroll bar and pagination in react. We decided to use react-table since it's simple and has many features.

React-table might be the easy way and it comes with both scroll bar and page pagination. You could configure the screen size to display and few customization to apply. There are few good examples to show the implementations. We are using this to display the workflow approvals and reviewers for SharePoint list item with pagination hidden.  Here is the screenshot.


The code is also very simple. Here is the sniipet.

return (
<div className={styles.container}>
<div className={styles.row}>
<Pivot>
<PivotItem headerText="Workflow Approvals" itemIcon="People">
<div className={styles.column}>
{/* <h3>Workflow Approvers</h3> */}
<ReactTable
data={data}
columns={[
{
columns: [
{
Header: "Name",
accessor: "name",
},
// {
// Header: "email",
// id: "email",
// accessor: d => d.email
// },
{
Header: "Role",
accessor: "role"
},
{
Header: "Status",
accessor: "status"
}
]
}
]}
defaultPageSize={5}
showPagination={false}
style={{
height: "200px" // This will force the table body to overflow and scroll, since there is not enough room
}}
className="-striped -highlight"
/>
</div>
</PivotItem>
<PivotItem headerText="Workflow Reviewers" itemIcon="People">
<div className={styles.column}>
{/* <h3>Workflow Approvers</h3> */}
<ReactTable
data={data1}
columns={[
{
columns: [
{
Header: "Name",
accessor: "name",
},
// {
// Header: "email",
// id: "email",
// accessor: d => d.email
// },
{
Header: "Reason",
accessor: "reason"
},
{
Header: "Status",
accessor: "status"
}
]
}
]}
defaultPageSize={5}
showPagination={false}
style={{
height: "200px" // This will force the table body to overflow and scroll, since there is not enough room
}}
className="-striped -highlight"
/>
</div>
</PivotItem>

</Pivot>
</div>
</div>
);


The mock-up data is listed below for your reference.

export const data1 = [
{
id: 22,
name: 'Test User',
email: 'test.user@mycompany.com',
role: 'Some role',
status: 'Open',
},
{
id: 23,
name: "John Smith",
email: 'jsmith@mycompany.com',
role: 'Pubs developer',
status: 'Open',
}

];

There are few other data tables you could check for your own purposes.

  1. React semantic UI
  2. Material UI
  3. Material table with group feature
  4. MD table
Some implementations are using bootstrap or other packages that we may not want to introduce to your project.




Friday, July 26, 2019

How to use Microsoft flow to provide Adobe Sign process as http services

We have a external process running on AWS need to integrate with SharePoint document using Adobe Sign. The document will be pushed to SharePoint through Graph API and like to call service to initialize the Adobe Sign process.  There are may different ways to provide this as service but the quickest way might be the Microsoft Flow.

The way I implemented is to start with OoB "Get signatures on a selected file in SharePoint" flow template. Test this manually and then build our own process. The key two actions we need to use are:

  • Adobe "Upload a document and get a document ID"
  • Adobe "Create an agreement from an uploaded document and send for signature"

In order to be easily called, I've created the activity "When a HTTP request is received" as the trigger for the flow. The overall flow is very simple and actions are listed below.


To demonstrate you could receive the parameter, The relativePath Document/{documentName} has been added. The http call will pass the document name as parameter so flow could find the document. This is described as the below screenshot. 



The url to call the flow is like this below. Please note I have updated the real GUID and the way pass the Document as parameter in red.

https://prod-41.westus.logic.azure.com/workflows/9452e067c6b648c3ac4ed60ab1234567/triggers/manual/paths/invoke/Document/myDocument.docx?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=L5LqW-NVBFc6sdxHpthXXXXXXXXXX

The next key is to get the file content and I found the easy way is to use "Get file content using path" action. You could use other actions but may need to get file Id. The rest actions are same as the OoO flow as we mentioned "Get signatures on a selected file in SharePoint" with few parameters modified for file content.


Now, you have a working http service that can be invoked to integrate SharePoint denouement with Adobe Sign. 

Few enhancements in the future.

  1. Pass file ID like DocID only and the flow to retrieve file name, path, and content form the file ID.
  2. Retrieve "Recipient Email" from SharePoint list item.
  3. Retrieve the Signed document and stored to SharePoint some where or update the document item with the Signed Adobe document Url.
This is my first SharePoint Adobe flow, there will be more integration and enhancements we could implement in the future. 




Wednesday, July 17, 2019

Ultimate procedures to configure "Calendar E-mail Extension for Office 365" apps for SharePoint online


Calendar E-mail Extension for Office 365 sends invitations, handles responses and allows Exchange resources to be booked from a SharePoint calendar, making organizing your calendar as simple and efficient as possible. Here is the summary of the features.

  • Send meeting requests from SharePoint calendars. Now it's possible to invite attendees directly from a SharePoint Online calendar.
  • Book Exchange rooms and equipment. You can book rooms and equipment in Exchange directly from a SharePoint Online calendar.
  • View status replies and attendance status. The SharePoint Online Calendar displays every attendee’s invite status, including their acceptance status, tentative acceptances or any new time suggested.
  • Check availability of attendees and resources. You can check resources' and attendees' availability when scheduling an event directly from a SharePoint Online calendar.

One of the key feature we are looking for is to check the availability of the Exchange rooms and equipment. There are few tricks to make this work in SharePoint online. Here are the details to configured this correctly.


1. The first step is to add "Calendar E-mail Extension for Office 365" to SharePoint online site collection.

You could "Add an app" from the SharePoint online site collection. Here is the app you should add.


2. The second step is to enable the conflict checking scripting on the site collection. This has to be done before you configure the calendar! Otherwise you have to update each existing calendar and save it to pick up the conflict checking script! 

The two steps are:
a. Enable the custom scripts on the site. The SharePoint Online Management  Powershell script is like this below.

# Change this URL to match your admin site
Connect-SPOService -Url https://<yourdomain>-admin.sharepoint.com
# Enter username and password
# Change this URL to match your SharePoint site
Set-SPOSite -Identity https://<yourdomain>.sharepoint.com/sites/yoursite -DenyAddAndCustomizePages $false

b. Update Calendar E-mail Extension for Office 365 app permission. 

  • Open the SharePoint online site where the add-in is installed and navigate to http://<SharePointWebsite>/_layouts/15/AppInv.aspx.
  • Enter the following App Id (d4f43231-f66d-4f82-93b1-bd5a9d9945c1) and click on Lookup.
  • In the Permission Request XML box, enter the following xml:

      <AppPermissionRequests AllowAppOnlyPolicy="true" >
        <AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web"       
         Right="FullControl" />
      </AppPermissionRequests>

  • Click on Trust it.
  • Click on the Calendar E-Mail Extension for Office 365 add-in in the site contents page
  • Click on Configure on each calendar list where the add-in is configured and save the settings again.

The details is listed in vendor's documentation here.

3. The third step is to add calendar and configure the resources.
Click Settings->Site contents->"Calendar E-mail Extension for Office 365", this will bring to configuration page like below.

After add a new calendar, click "Configuration" of the calendar. Enter the account or the shared mailbox account. The enter password to verify.


The you could configure the "Attendees" and "Resources". Please note you might need to add additional room and equipment mailbox for your application as in the below screenshot. Please select "Check Availability".


Then you would need to click save.

4. The forth step is to hide some fields users may not need to simplify the forms.

You could change the room to one of the following three options. This depends on your business requirement
  • Drop-Down Menu
  • Radio Buttons
  • Checkboxes (allow multiple selection)

The procedure is to click "List Settings"->Click "Event (with email extension) Content Types->"Exchange Rooms and Equipment"-> Click "Edit column". Then select one of the three options.



If you need to hide some files from users, please refer to my previous blog for details.



5. The fifth step you might need to do is to disable users to save booking when there is a conflict.

The default behavior after you configure to check availability of the resource, when you try to save the booking, it will prompt the dialog box when there is a conflict.



You will noticed that there are two buttons "Don't save" and "Save Anyway" that do not make sense to allow users to save if there is conflict. 

Well, there is a way to remove these two buttons and here are the details. There are three places you need to make the change. The URLs are listed below for list named "PCP Booking 2".

Go to "Settings" -> "Edit the page" and find the "SharePoint|sapiens Calendar E-Mail Extension Client Script" webpart->Click "EDIT SNIPPET".


Then append the following script to hide two buttons. Click "Insert" and save the page.

      <style type="text/css">
      input[value='Save Anyway'] { display: none; }
      input[value="Don't save"]  { display: none; }
      input[value="Don't save"] + input[value='Save'] { display: none; }

      </style>


5. The sixth optional step you might want to do prevent users to create past event.You could configure this in the lsit Validation setting.

Click the list settings->Validation settings. Enter the following formula to prevent past event to be created.

=[End Time]>Created



You could use another formula to prevent the past event to be modified.

=[End Time]>Now() 

5. The seventh optional step you might want to allow user to edit their events created by themselves.

You can go into the List SettingsAdvanced Settings, and you should be able to set Read and Edit access to items that the user has created.




Now the  "Calendar E-mail Extension for Office 365" apps is ready on the SharePoint online site.