Customize CRUD pages | Create a Blazor CRM application with Radzen Blazor Studio

In this step from the CRM Application tutorial we will customize the automatically scaffolded CRUD pages.

  • Start by adding some contacts
  • Customize the Opportunities page
    • Associate an opportunity with the current application user.
    • Display the user first and last name in the opportunity DataGrid.
  • Add icons for the Task Status and Task Type columns in the Tasks page.
  • Add search capabilities to the Contacts page.

Add some contacts

The contact is a paramount entity in the RadzenCRM application as everything depends on it - opportunities, tasks etc.

Let’s add some contacts. We will use some famous members from the tech industry.

  1. Open the Contacts page in Radzen Blazor Studio.
  2. Select the DataGrid component and remove the ID column as we don’t need it.
  3. Run the application from Radzen Blazor Studio.
  4. Log in with salesmanager@demo.radzen.com and SalesManager1@. Those are the credentials of the Jane Smith application user who is a Sales Manager (we added that user in the Customize security article).
  5. Navigate to the Contacts page.
  6. Add two contacts:
    • FirstName: Bill, LastName: Gates, Email: bill.gates@microsoft.com (probably not his real email), Company: Microsoft.
    • FirstName: Elon, LastName: Musk, Email: elon.musk@tesla.com (maybe not real too), Company: Tesla.

Customize the Opportunities page

Associate opportunities with users

The first thing we will do is associate the opportunity with the current user and filter the opportunities so:

  • Members of the Sales Representative role see only their opportunities.
  • Members of the Sales Manager role see all opportunities.

Server-side Blazor

  1. Stop the running application.
  2. Add a new file Services\RadzenCRMService.Custom.cs with the following content.
using System;
using System.Data;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Components;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using Radzen;

using CRMBlazorServerRBS.Data;
using CRMBlazorServerRBS.Models.RadzenCRM;

namespace CRMBlazorServerRBS
{
    public partial class RadzenCRMService
    {
        private readonly SecurityService security;

        public RadzenCRMService(RadzenCRMContext context, NavigationManager navigationManager, SecurityService security)
          : this(context, navigationManager)
        {
            this.security = security;
        }

        partial void OnOpportunityCreated(Opportunity item)
        {
            var userId = security.User.Id;

            // Set the UserId property of the opportunity to the current user's id
            item.UserId = userId;
        }

        partial void OnOpportunitiesRead(ref IQueryable<Opportunity> items)
        {
            if (!security.IsInRole("Sales Manager"))
            {
                var userId = security.User.Id;

                // Filter the opportunities by the current user's id
                items = items.Where(item => item.UserId == userId);
            }
        }
    }
}

Client-side WebAssembly Blazor

  1. Stop the running application.
  2. Add a new file Server\Controllers\RadzenCRM\OpportunitiesController.Custom.cs with the following content.
using System;
using System.Net;
using System.Data;
using System.Linq;
using Microsoft.Data.SqlClient;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Query;
using Microsoft.AspNetCore.OData.Routing.Controllers;
using Microsoft.AspNetCore.OData.Results;
using Microsoft.AspNetCore.OData.Deltas;
using Microsoft.AspNetCore.OData.Formatter;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Authorization;
using CRMBlazorWasmRBS.Server.Models;
using CRMBlazorWasmRBS.Server.Models.RadzenCRM;

namespace CRMBlazorWasmRBS.Server.Controllers.RadzenCRM
{
    [Authorize]
    public partial class OpportunitiesController
    {
        partial void OnOpportunitiesRead(ref IQueryable<Opportunity> items)
        {
            var userManager = (UserManager<ApplicationUser>)HttpContext.RequestServices.GetService(typeof(UserManager<ApplicationUser>));

            var user = userManager.GetUserAsync(HttpContext.User).Result;
            if (user != null)
            {
                var roles = userManager.GetRolesAsync(user).Result;

                if (!roles.Contains("Sales Manager"))
                {
                    // Filter the opportunities by the current user's id
                    items = items.Where(item => item.UserId == user.Id);
                }
            }
        }
    }
}
  1. Set UserId before submitting the opportunity in AddOpportunity page.
protected async Task FormSubmit()
{
    try
    {
        opportunity.UserId = Security.User?.Id;
        
        await RadzenCRMService.CreateOpportunity(opportunity);
        DialogService.Close(opportunity);
    }
    catch (Exception ex)
    {
        errorVisible = true;
    }
}

Since we are manually setting the UserId of the opportunity we should remove the corresponding form field from the Add Opportunity and Edit Opportunity pages.

  1. Open the Add Opportunity page.
  2. Select the TemplateForm component.
  3. Delete the FormField that contains the UserId text box.
  4. Repeat steps 1 to 3 for the Edit Opportunity page.

Let’s try if it worked!

  1. Run the application from Radzen.
  2. Log in with salesmanager@demo.radzen.com and SalesManager1@.
  3. Add a new opportunity with the following details:
    • Amount: 50000
    • Contact: bill.gates@microsoft.com
    • Opportunity Status: Active
    • Close Date: 02/01/2019
    • Name: Microsoft deal

You should see this.

  1. Add a new opportunity with the following details:
    • Amount: 100000
    • Contact: elon.musk@tesla.com
    • Opportunity Status: Won
    • Close Date: 02/02/2019
    • Name: Tesla deal

Display the first and last name in the Opportunities DataGrid

But what is that GUID in the User ID column? It is the Id of Jane Smith - the user we have logged in as. Let’s display something more user-friendly than a GUID.

Server-side Blazor

  1. Open the Opportunities page in Radzen.
  2. First we have to get the current user as an entity so we can use its properties in the DataGrid.
  3. Open Services\RadzenCRMService.Custom.cs with Visual Studio.
  4. Append the following statement to the OnOpportunitiesRead method: items = items.Include(item => item.User);. Here is how it should look like:
partial void OnOpportunitiesRead(ref IQueryable<Opportunity> items)
{
    if (!security.IsInRole("Sales Manager"))
    {
        var userId = security.User.Id;

        // Filter the opportunities by the current user's id
        items = items.Where(item => item.UserId == userId);

    }
    // Include the User
    items = items.Include(item => item.User);
}

Client-side WebAssembly Blazor

  1. Open the Opportunities page in Radzen.
  2. First we have to get the current user as an entity so we can use its properties in the DataGrid.
  3. Select the DataGrid component and edit its LoadData event handlers.
  4. Append ,User in the expand parameter value. The expand parameter is similar to a SQL JOIN (and in fact does exactly that behind the scenes).

Now let’s customize the DataGrid!

  1. Go to the Properties tab of the property grid and edit the Template of the User ID column.
  2. Drag and drop a Label component. Set its Text property to @opportunity.User.FirstName.
  3. Drag and drop another Label. Set its Text property to @opportunity.User.LastName.
  4. Close the template editor by clicking the End template editing button.
  5. Finally set the FilterProperty and SortProperty of the User ID column to User.FirstName. This tells the DataGrid what property to sort by when the user changes the order by clicking the column header.

If you run the application now it should display the current user name instead of the GUID.

Add icons in the Tasks DataGrid

We will improve the look and feel of the Tasks page by using icons in the Task Status and Task Type DataGrid columns.

Run the application and add three tasks with the following properties

  1. Title: Introduction, Opportunity: Microsoft deal, Due Date: 02/02/2019, Task Type: Email, Task Status: Complete.
  2. Title: Demonstration, Opportunity: Microsoft deal, Due Date: 03/06/2019, Task Type: Online Meeting, Task Status: In Progress.
  3. Title: Negotiation, Opportunity: Microsoft deal, Due Date: 03/26/2019, Task Type: Call, Task Status: Not Started.

Now lets add the icons for the Task Type column.

  1. Open the Tasks page in Radzen.
  2. Select the DataGrid component.
  3. Edit the Template property of the Task Type column.
  4. Drag and drop a Label component and set its Text property to @task.TaskType.Name.
  5. Drag and drop an Icon component. Set the Icon property to settings_phone (click the button to open the Icon Picker dialog). Set the Visible property to @(task.TaskType.Name == "Call"). This icon will be visible only when the current task type is equal to Call. Go to the Style tab of the property grid and set VerticalAlign to middle.
  6. Duplicate the existing icon by right-clicking it and picking the Duplicate option. Change the Icon property to video_call and set the Visible property to @(task.TaskType.Name == "Online Meeting").
  7. Duplicate the last icon. Change its Icon property to email and set the Visible property to @(task.TaskType.Name == "Email").
  8. Click End template editing.

The Tasks page should now look like this.

Do the same for the Task Status column.

  1. Edit the Template of the Task Status column.
  2. Drag and drop a Label component and set its Text property to @task.TaskStatus.Name.
  3. Drag and drop an Icon component. Set the Icon property to check_circle (click the button to open the Icon Picker dialog). Set the Visible property to @(task.TaskStatus.Name == "Complete"). Go to the Style tab of the property grid and set VerticalAlign to middle.
  4. Duplicate the existing icon by right-clicking it and picking the Duplicate option. Change the Icon property to cancel and set the Visible property to @(task.TaskStatus.Name == "Not Started").
  5. Duplicate the last icon. Change its Icon property to autorenew and set the Visible property to @(task.TaskStatus.Name == "In Progress").
  6. Click End template editing.

Here is how the end result should look like:

It is time to learn how to create a dashboard page with Radzen Blazor Studio.