ENGINEERED CODE BLOG

Dynamics 365 Portal & SharePoint: Using CSS To Save Some Clicks

In a previous post, I asked you not to forget about CSS when customizing the user experience of some of the out-of-the-box features of the Dynamics 365 Portal product. In this post I’ll provide another example of using this technique to reduce the number of clicks required to remove a SharePoint document.

In a previous post, I asked you not to forget about CSS when customizing the user experience of some of the out-of-the-box features of the Dynamics 365 Portal product. In this post I’ll provide another example of using this technique to reduce the number of clicks required to remove a SharePoint document.

Consistency Can Be the Enemy of Simplicity

We all rejoiced when Microsoft added the out-of-the-box SharePoint integration back to the Dynamics 365 Portal product. For some technical reasons, the SharePoint integration wasn’t available when the product first moved from Adxstudio to Microsoft, but thankfully as part of the October ’18 release, it is now back.

I was using this integration in a project recently when the client asked me if I could make one of the user experiences a bit cleaner. Specifically, they wanted to know if it was possible to make the Delete button that appears within the row of a document appear directly in the table, without have to click the drop down arrow.

I knew that I could probably do this with JavaScript (because you can pretty much do anything with regards to the interface with JavaScript), however my goal was to try to do it using only CSS.

Now, it may seem like a bit of an odd user experience to have to click the drop down to get to the Delete button, and that’s because it is. But it’s not really intentional. It’s because Microsoft uses the same user interface elements across the Portal. What you’re seeing for the SharePoint documents is pretty much the same as you’d see for an Entity List. Reusing this code means less to maintain for Microsoft, and also means a consistent experience for users of the Portal – all generally good things. However, in this particular case, it means an extra unnecessary click, which my client wanted removed, especially since we aren’t leveraging this type of interface anywhere else on the project, so there wasn’t anything else that would make consistency important.

CSS to the Rescue!

I’m not going to rehash the reasons I like CSS in this post, but there is one particular reason in this case that using CSS makes our life a lot easier, and that’s due to the dynamics nature of the SharePoint documents table.

If we were to use JavaScript in a situation like this, that generally means we are manipulating the DOM, moving things around to get them to show up as we want. Often that is done when the page loads. However, the SharePoint documents table can be constantly changing – users can add and remove documents without the page refreshing. If we were to use JavaScript, we’d have to handle all of those events to make sure our Delete button is always consistent. It would be a pain.

Instead, since CSS is “always on”, we don’t have to worry about handling when the table changes – our CSS will automatically get applied.

Another reason we try to avoid manipulating the DOM is that if you don’t do it right, you can lose the events that are attached to the elements. For example, there is JavaScript code that run when the Delete button is clicked. If we start moving the button around, you can possibly lose that functionality. There’s no point removing clicks to get to a button if the button doesn’t work! Again, it’s possible to move the button and keep the events, it just another thing that makes it tricky.

Now, depending on how Microsoft had chosen to implement that functionality, a pure CSS option may not have been possible. If the Delete button had been added to the page in response to the click event on the drop down arrow, then we wouldn’t have anything to target with our CSS until the user clicked on the button. Thankfully, however, the Delete button is always on the page, just hidden until the user click the arrow to show it.

Since the markup for the button is always on the page (just hidden), we can get to where we want to go in two easy steps:

  1. Always hide the drop down arrow
  2. Always show the delete button

Using the browser developer tools allows us to find how to target both of these elements.

To hide the drop down arrow:

.sp-item .toolbar > a {
    display: none;
}

To always show the Delete button:

.sp-item .toolbar .dropdown-menu {
    display: block;
    position: relative;
    border: none;
    background: none;
    box-shadow: none;
    margin: 0;
    padding: 0;
}

You’ll notice I’ve added a few more styles in there to make the button fit in a bit better with the table.

Just add this CSS to your Web Page, or Web Template, and you’ll get:

With just a few lines of CSS, we’ve improved the user experience quite a bit by saving the user an unnecessary click!

As mentioned above, Entity Lists use similar markup – with just a few tweaks, you could apply the same technique to show the action buttons inline in the table. In fact, these drop down arrows are a standard Bootstrap feature used throughout the Portal, so there are probably quite a few different places you could do this if you wanted.

Bonus: Hiding the Modified Column

You may have noticed that in my screenshots, the Modified column wasn’t visible in the SharePoint documents table – this was another request from my client, as it was not important for the users to see. Again, CSS makes this very simple:

.sharepoint-data tr th:nth-child(2), .sharepoint-data tr td:nth-child(2) {
    display: none;
}

This CSS targets the second child of both the header row and the body rows of the table used to display SharePoint documents, and then simply hides them using display: none;.

It is important to note that the markup still exists on the page, meaning an advanced user can still find out what the dates are. So don’t use this technique to hide information you consider to be confidential.

Double Bonus: Hiding the New Folder Button

Another request was to hide the button that allows the user to create a new folder. This simple CSS accomplishes that task:

.add-folder {
    display: none;
}

Again, an advanced user could easily unhide the button using developer tools, so this is about user experience, not security.

Dynamics 365 Portal: Customizing Portal User Registration Process – Part 4

In my last post in this series on creating a custom registration form for a Dynamics 365 Portal implementation, I discuss some optional minor user experience enhancements.

In my last post in this series on creating a custom registration form for a Dynamics 365 Portal implementation, I discuss some optional minor user experience enhancements.

In my previous post I completed the process for creating a custom user registration form. However, with a bit more effort, it is possible to enhance the user experience for anyone going through this process.

Cleaning up the Invitation Email

As I mentioned in my last post, it is important to customize the email that appears in the Send Invitation workflow, including:

  • Updating the From address to ensure that the email will actually be sent.
  • Updating the body of the email to ensure it is both on-message and on-brand for your organization.
  • Updating the link in the body of the email to ensure that it points to your Portal.

Customizing the Invitation Code Redemption Screens

Because we’re using the invitation code model for something a bit different, some of the out-of-the-box language on the screen when redeeming might be a bit confusing for users. If you only plan on using invitation code for this registration process, you could update the language to be very specific – otherwise maybe make it a bit more generic. Some of the elements you may want to customize include:

  • Authentication/Registration/OpenRegistrationEnabled Site Setting: setting this to false will hide the out-of-the-box registration so that you don’t confuse users (but will still allow users to use invitation codes).
  • Account/Redeem/InvitationCodeFormHeading Content Snippet: this is the header that appears above the invitation code form – you could set this to Confirm your code to setup your credentials.
  • Account/Redeem/InvitationCodeFormButtonText Content Snippet: controls the text of the button on the first invitation code page – you could set this to Confirm.
  • Account/RedeemInvitation/PageCopy Content Snippet: this can be used to add language to invitation code page. In our case, we’ll use it to add some CSS to hide the check box that asks if they have an existing account (which they shouldn’t), and the subnavigation that includes a link to the sign in page, which I feel will just confuse users:
    <style type="text/css">
    .page-content .checkbox, .nav-account {
        display: none;
    }
    </style>
    
  • Account/Register/PageCopy Content Snippet: this can be used to add language to page where the user selects their authentication type. In our case, we’ll use it to add some CSS to hide the subnavigation that includes a link to the sign in page, which I feel will just confuse users:
    <style type="text/css">
    .nav-account {
        display: none;
    }
    </style>
    

Remember that if any of these settings or snippets don’t already exist in your environment, simply create them with the appropriate name. After making these changes, users will see a screen like this when clicking the link from their email:

This is a more streamlined version that I think will lead to less confusion.

That brings to a close this series of posts – I hope you found them helpful. As I mentioned, the user registration process is an area that usually generates a lot of questions, so if you have another approach you’ve used successfully, please share with the community!

Dynamics 365 Portal: Customizing Portal User Registration Process – Part 3

In my third post in this series on creating a custom registration form for a Dynamics 365 Portal implementation, I discuss the behind the scenes processing required to get the registered user a contact record with login credentials.

In my third post in this series on creating a custom registration form for a Dynamics 365 Portal implementation, I discuss the behind the scenes processing required to get the registered user a contact record with login credentials.

In my previous post I created a custom entity called Portal User Registration, along with a Dynamics 365 Portal Entity Form that allows users to submit their registration. Once they fill out that form, a record is created in Dynamics 365 – however that form does not ask for any authentication credentials, and it creates a custom entity, while we all know that users require a Contact record in order to be able to login to a Portal. We’ll solve both of these using a combination of the out-of-the-box Invitation Code Model and workflows.

Leveraging the Invitation Code Model

The invitation code model is used to allow existing contact records to be associated with Dynamics 365 Portal login credentials. The process is essentially the same, regardless of if you’re using local authentication or an external identity provider like Azure AD B2C. It works like this:

  1. A long, random, unique set of characters (called the Invitation Code) is generated and associated with the Contact record.
  2. The email address associated with the contact is sent a message with a link to the Portal that includes the unique invitation code.
  3. The link takes the user to a page when they can either create a new local authentication username and password, or choose any of the configured external identity providers.
  4. After “logging in”, the login credentials are joined to the contact associated with the invitation code.

Invitation Codes are often used for new Portal implementations that already have a large number of existing contacts in Dynamics 365. It allows you to invite your existing contacts to the system, as opposed to them having to register, which will lead to duplicate contacts. However, there is no reason we can’t use this model for new registration as well!

The Workflow To Tie Everything Together

We’re going to create a workflow that fires on the create of our custom Portal User Registration entity, and performs the following tasks:

  1. Create a Contact record based on the submitted details.
  2. Create an Invitation record, ensuring that:
    • Type = Single
    • Invite Contact = contact created in previous step
  3. Use the out-of-the-box Send Invitation workflow to send the user the invitation email.

As a bonus, I’ve added one extra feature, and that is to take into account the Type the user selected when they submitted the form. If they selected Gold my workflow will use the Portals:Assign Web Role Custom Workflow Activity to assign the Gold Web Role I created. This is a simple example, but there are a lot of things you can do in these workflows if your registrations process is complex.

The completed workflow looks like:

When using the Invitation Code model, you’ll need to customize Send Invitation workflow to ensure that the email is coming from an appropriate user (so that the email will actually go out), that the messaging updated, and that the URL is updated to point to your Portal.

What About Microsoft Flow?

Could you use Microsoft Flow instead of the traditional workflows? Probably. However, we’re using some of the out-of-the-box invitation code workflows, which could probably be rewritten in Microsoft Flow, but for the purpose of this series, we have not.

The End-to-end Process

Now that we’ve got our workflow setup, a user can register on our Portal using the custom registration form. Once they submit, they will receive an email inviting them to our Portal. After clicking on the link, the user will be presented will the opportunity to configure their authentication using any of the enabled options. After that, the user will be logged in and successfully joined up with the contact containing the information supplied in the initial form submission.

In the next/final post, I’ll touch on some items that can be adjusted to improve the user experience.

Dynamics 365 Portal: Customizing Portal User Registration Process – Part 2

In my second post in this series on creating a custom registration form for a Dynamics 365 Portal implementation, I discuss the custom entity and tying it to an Entity Form (or even a Web Form!).

In my second post in this series on creating a custom registration form for a Dynamics 365 Portal implementation, I discuss the custom entity and tying it to an Entity Form (or even a Web Form!).

The Custom Portal User Registration Entity

The first step is to create a custom entity you can use to capture the fields you require. In my trivial example, I’m looking to capture the user’s first and last name, along with an email address plus the type of account that they want to sign up for (either Gold, Silver or Bronze). As mentioned previously those fields (except for email address) don’t appear on the out-of-the-box registration form, and there is no simple way to add them.

So, I’ve created a custom entity called Portal User Registration with those fields, like so:

What About Just Using Contact Instead of a Custom Entity?

You might be thinking to yourself, couldn’t I just create a form that allowed the user to directly create a contact, rather than creating this new entity type? Yes, you definitely could, and I don’t think that that is a bad idea. However, there are a couple reasons I like the custom entity:

  1. There may be fields you need to capture on the registration form but aren’t necessarily fields on the contact record. For example, your registration form may have account name, account address, etc. You can include all of these fields on your registration entity, and then use workflows (or Microsoft Flow) to create the proper entities.
  2. You may have fields that you need as part of the registration, but aren’t needed after that. In my trivial example, the type of account could be considered one of those fields. As you’ll see, I use that field to determine if the user gets an additional web role, however it’s not something I need to store on the contact record. Typically contact records are complicated enough – they don’t need extra fields unless they are necessary.
  3. This approach allows you to perform business logic on the record before creating a contact, perhaps business logic that may determine the user shouldn’t get an account. If this information is stored in a separate entity, you don’t have to worry about your Contacts table getting polluted with records that never turned into real Portal users.
  4. You’ll always have a history of what the user filled out when they first registered. Unlike the contact record, which can most likely change over time, the registration record is a snapshot of what they originally submitted.

Again, all that being said, I don’t think using Contact instead of a custom entity is necessarily a bad approach.

Creating the Entity Form

Next, we’ll create a simple Entity Form that allows for the insert of our custom entity. It really doesn’t get much simpler that this:

Make sure the Mode is Insert, and that Enable Entity Permissions is unchecked, as we want anonymous users to be able to create these records.

Finally, we’ll add the Entity Form to a Web Page – in my case I called it User Registration, and we’ll get the following:

With that in place, user can submit a registration via our Portal with our own custom fields.

What about a Web Form?

Perhaps your registration form is complicated – so complicated that it should be multiple steps. Does this technique work with a Web Form instead of an Entity Form? Definitely!

If you use a Web Form, you’ll have to modify when the workflow that we’ll setup in the next post triggers, as you won’t be able to trigger on the create of the record. However, other than that, everything else should be very similar.

I definitely recommend using a custom entity in this case (as opposed to using the Contact entity), as you are likely to get abandoned records from people who don’t complete the entire form, and you don’t want those in your Contact table.

In my next post, I’ll cover the behind the scenes processing that needs to happen to create the contact, and to allow the user to associate their contact with login credentials.

Dynamics 365 Portal: Customizing Portal User Registration Process

While the Dynamics 365 Portal product offers flexibility in many areas, unfortunately the user registration process is not one of them. If you’re looking to add some fields to the form the user fills out when registering for your Portal, you’ll quickly find there is no simple way to do that. In this series, I’ll provide a different approach that might suit your needs if a custom user registration experience is required for your implementation.

Continue reading “Dynamics 365 Portal: Customizing Portal User Registration Process”

Dynamics 365 Portal: Self-service Diagnostics with the Portal Checker

In case you haven’t been able to tell, I’ve been on a bit of a Dynamics 365 Portal performance kick these days. One tool I didn’t include in my post on where to look when things are slow was the Portal Checker, which provides a self-service way to identify potential issues with your Portal, with suggestions on how to solve them.

Continue reading “Dynamics 365 Portal: Self-service Diagnostics with the Portal Checker”

Dynamics 365 Portal: Where to Look When Things Are Slow

It seems to be happening more and more these days that we are being asked to assist organizations that have launched a Dynamics 365 Portal but they are unhappy with the performance. If you find yourself dealing with a portal that is slower than you think it should be, this post should give you an idea of where to start looking.

Continue reading “Dynamics 365 Portal: Where to Look When Things Are Slow”

Contact

Engineered Code is a web application development firm and Microsoft Partner specializing in web portals backed by Dynamics 365. Led by a professional engineer, our team of technology experts are based in Regina, Saskatchewan, Canada.