Service Portal Archives - ServiceNow Guru https://servicenowguru.com/category/service-portal/ ServiceNow Consulting Scripting Administration Development Mon, 30 Sep 2024 23:29:33 +0000 en-US hourly 1 https://wordpress.org/?v=6.8.2 https://servicenowguru.com/wp-content/uploads/2024/05/cropped-SNGuru-Icon-32x32.png Service Portal Archives - ServiceNow Guru https://servicenowguru.com/category/service-portal/ 32 32 Leveraging ServiceNow with Highcharts: Transforming Data into Insight https://servicenowguru.com/service-portal/leveraging-servicenow-with-highcharts-transforming-data-into-insight/ https://servicenowguru.com/service-portal/leveraging-servicenow-with-highcharts-transforming-data-into-insight/#comments Tue, 08 Oct 2024 10:00:44 +0000 https://servicenowguru.com/?p=15549 In today's data-driven world, organizations are constantly seeking innovative solutions to transform complex datasets into actionable insights. ServiceNow, a leading cloud-based platform for digital workflows, provides extensive data handling and management capabilities. However, to truly leverage the power of data visualized effectively, integrating a robust tool like Highcharts can elevate the presentation and interpretation of

The post Leveraging ServiceNow with Highcharts: Transforming Data into Insight appeared first on ServiceNow Guru.

]]>
In today’s data-driven world, organizations are constantly seeking innovative solutions to transform complex datasets into actionable insights. ServiceNow, a leading cloud-based platform for digital workflows, provides extensive data handling and management capabilities. However, to truly leverage the power of data visualized effectively, integrating a robust tool like Highcharts can elevate the presentation and interpretation of data. This article explores how combining ServiceNow with Highcharts can transform raw data into clear, insightful visual representations, aiding businesses in making better-informed decisions. We’ll delve into the benefits of this integration, practical use cases, and tips for seamless implementation, setting the stage for a more intuitive and strategic approach to enterprise data analysis.

Highcharts is a flexible, feature-rich JavaScript library that allows developers to create interactive charts for the web. By integrating Highcharts with ServiceNow, you can transform static data into engaging visualizations, providing your users with a more intuitive, interactive experience. In this article, I’ll walk you through the process of integrating Highcharts with ServiceNow, showcasing use cases, and tips to get the most out of this powerful combination.

Why Integrate Highcharts with ServiceNow?

ServiceNow provides basic reporting and visualization features, but for more advanced charting needs—such as interactive dashboards or detailed drill-down capabilities—Highcharts offers several advantages:

  • Customization: Highcharts offers a wide range of chart types (line, bar, pie, scatter, etc.), and the ability to customize almost every aspect of the chart.
  • Interactivity: With Highcharts, users can interact with charts by zooming, clicking data points, and receiving real-time feedback, making data exploration more engaging.
  • Real-time Data: You can easily configure charts to update in real-time, providing up-to-the-minute insights.
  • Extensibility: Highcharts offers numerous plugins and extensions, allowing you to extend functionality as needed.

By combining ServiceNow’s robust data management with Highcharts’ visualization capabilities, organizations can create more effective reports and dashboards that drive better decision-making.

 

 

Licensing:

For this article, which has educational purposes, I will download version 11.4.3 of the library and use it in my PDI. For commercial use, it is recommended that you purchase licenses directly through their website. Another option is to use the version available within the platform, which in my research (<instance-name>/scripts/glide-highcharts.js) is 9.3.2.

Using the paid version:

In my article “Importing Excel to Servinow” I showed how to import a library into SN. Just follow the same steps to import the Highcharts library.

Using the version available on the platform:

Just create a JS Include in the Portal Theme added to the library already available on the platform:

 

Basic usage example:

For this first example I will create a simple widget with hard-coded data just to show how to use the library. To make things easier I will use a basic example that can be found in the documentation. This example was made using the version of the library that already comes with the platform.

 

Widget Basic Highchart Example
Widget Component: Client Script
Script:

<div class="page-header">
  <h1>ServiceNow Guru - Basic Highchart Example</h1>
</div>

<div id="container" style="width:100%; height:400px;"></div>

 

Widget Basic Highchart Example
Widget Component: HTML Template
Script:

var chartConfirObj = {
  chart: {
    type: 'bar',
  },
  title: {
    text: 'Fruit Consumption',
  },
  xAxis: {
    categories: ['Apples', 'Bananas', 'Oranges'],
  },
  yAxis: {
    title: {
      text: 'Fruit eaten',
    },
  },
  series: [
    {
      name: 'Jane',
      data: [1, 0, 4],
    },
    {
      name: 'John',
      data: [5, 7, 3],
    },
  ],
};

var chart = Highcharts.chart('container', chartConfirObj);

 

In this example, we see that to build the chart we need to pass an object containing the chart settings we want. The library is huge and I could spend hours here talking about each item in this object and also about each customization possibility, but the library documentation is incredibly complete and can answer all questions:

 

Now let’s give our graph a bit more reality and bring real data to it.

 

Widget Highchart Pie Example
Widget Component: Server Script
Script:

//variables that will be used to customize the graph
data.font_family = options.font_family || 'SourceSansPro,Helvetica,Arial,sans-serif';
data.fill_color = options.fill_color || '#fff';

data.title = options.title || 'Chart Title';
data.title_color = options.title_color || '#fff';
data.title_size = options.title_size || '14px';
data.title_weight = options.title_weight || 'normal';

data.label_color = options.label_color || '#fff';
data.label_size = options.label_size || '12px';
data.label_weight = options.label_weight || 'normal';
data.label_connector_color = options.label_connector_color || '#fff';

data.slice_label_size = options.slice_label_size || '14px';
data.slice_label_outline = options.slice_label_outline || 'transparent';
data.slice_label_opacity = options.slice_label_opacity || 1;
data.slice_label_weight = options.bar_label_weight || 'bold';

data.table = options.table || 'change_request';
data.agg_field = options.agg_field || 'risk';

data.graphData = [];

//get total requests
var reqCount = new global.GlideQuery(data.table).count();

// get the total requests by risk
var agg = new GlideAggregate(data.table);
agg.addAggregate('COUNT', data.agg_field);
agg.orderBy(data.agg_field);
agg.query();
while (agg.next()) {

    var count = parseInt(agg.getAggregate('COUNT', data.agg_field));
    var percentTemp = 100 * count / reqCount;
    var percent = Math.round(percentTemp * 100) / 100;

    var objReq = {
        name: agg.getDisplayValue(data.agg_field),
        y: count,
        percent: percent.toFixed(2)
    };

    // if the risk is Very High the pie should be sliced and red
    if (agg.getValue(data.agg_field) == 1) {
        objReq.sliced = true;
        objReq.selected = true;
        objReq.color = 'red';
    }

    data.graphData.push(objReq);

}

 

Widget Highchart Pie Example
Widget Component: Client Script
Script:

var chartConfirObj = {
  chart: {
    type: "pie",
    backgroundColor: c.data.fill_color,
  },
  title: {
    text: c.data.title,
    style: {
      fontFamily: c.data.font_family,
      color: c.data.title_color,
      fontSize: c.data.title_size,
      fontWeight: c.data.title_weight,
    },
  },
  tooltip: {
    formatter: function () {
      return (
        "<b>" +
        this.point.name +
        " </b>: " +
        this.y +
        " </b> (" +
        this.point.percent +
        "%)"
      );
    },
  },
  plotOptions: {
    series: {
      allowPointSelect: true,
      cursor: "pointer",
      dataLabels: [
        {
          enabled: true,
          distance: 20,
          connectorColor: c.data.label_connector_color,
          formatter: function () {
            return this.point.name + " </br>" + this.point.percent + "%";
          },
          style: {
            fontFamily: c.data.font_family,
            color: c.data.label_color,
            fontSize: c.data.label_size,
            fontWeight: c.data.label_weight,
            textOutline: c.data.bar_label_outline,
          },
        },
        {
          enabled: true,
          distance: -30,
          format: "{y}",
          style: {
            textOutline: c.data.slice_label_outline,
            fontSize: c.data.slice_label_size,
            opacity: c.data.slice_label_opacity,
            fontWeight: c.data.slice_label_weight,
            textAling: "center",
          },
        },
      ],
    },
  },
  series: [
    {
      name: "Percentage",
      colorByPoint: true,
      data: c.data.graphData,
      dataLabels: {
        style: {
          color: c.data.bar_label_color,
          fontSize: c.data.bar_label_size,
          textOutline: c.data.bar_label_outline,
          fontWeight: c.data.bar_label_weight,
        },
      },
    },
  ],
};

var chart = Highcharts.chart("containerPie", chartConfirObj);

 

Widget Highchart Pie Example
Widget Component: HTML Template
Script:

<div id="containerPie"></div>

 

Widget Highchart Pie Example
Widget Component: Option Schema
JSON:

[
    {
        "name": "table",
        "section": "other",
        "default_value": "change_request",
        "label": "Table",
        "type": "string"
    },
    {
        "name": "agg_field",
        "section": "other",
        "default_value": "risk",
        "label": "Field used to aggregate",
        "type": "string"
    },
    {
        "name": "font_family",
        "section": "other",
        "default_value": "SourceSansPro,Helvetica,Arial,sans-serif",
        "label": "Font family",
        "type": "string"
    },
    {
        "name": "fill_color",
        "section": "other",
        "default_value": "#fff",
        "label": "Fill color",
        "type": "string"
    },
    {
        "name": "title",
        "section": "other",
        "default_value": "Chart title",
        "label": "Title",
        "type": "string"
    },
    {
        "name": "title_color",
        "section": "other",
        "default_value": "#fff",
        "label": "Title color",
        "type": "string"
    },
    {
        "name": "title_size",
        "section": "other",
        "default_value": "14px",
        "label": "Title Size",
        "type": "string"
    },
    {
        "name": "title_weight",
        "section": "other",
        "default_value": "normal",
        "label": "Title weight",
        "type": "string"
    },
    {
        "name": "label_color",
        "section": "other",
        "default_value": "#fff",
        "label": "Label Color",
        "type": "string"
    },
    {
        "name": "label_size",
        "section": "other",
        "default_value": "11px",
        "label": "Label size",
        "type": "string"
    },
    {
        "name": "label_weight",
        "section": "other",
        "default_value": "normal",
        "label": "Label weight",
        "type": "string"
    },
    {
        "name": "label_connector_color",
        "section": "other",
        "default_value": "#fff",
        "label": "Label connector color",
        "type": "string"
    }
]

 

Now, with everything we have shown in this article, we have the possibility of building complex dashboards like the one we saw at the beginning of this article.

 

Conclusion

Integrating Highcharts with ServiceNow allows you to take your data visualization to the next level, enabling more interactive, detailed, and dynamic reporting. With its wide range of customization options and ability to handle real-time data, Highcharts is an ideal tool for organizations looking to enhance their ServiceNow dashboards and reports. Whether you’re visualizing incident trends, service performance, or asset utilization, this integration can provide critical insights to drive better decision-making.

By following the steps in this article, you’ll be well on your way to creating powerful, interactive charts in ServiceNow, enabling users to explore and understand complex data sets with ease.

The post Leveraging ServiceNow with Highcharts: Transforming Data into Insight appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/service-portal/leveraging-servicenow-with-highcharts-transforming-data-into-insight/feed/ 3
Customize the Virtual Agent Chat Button in Service Portal https://servicenowguru.com/service-portal/customize-virtual-agent-chat-button-service-portal/ Tue, 06 Aug 2024 15:00:20 +0000 https://servicenowguru.com/?p=16716 One of the easiest ways to align the Virtual Agent experience with your organization brand is to update the VA chat button that displays in the Service Portal. Recently, I had to walk one of my developers through the process of aligning the chat button with a given design and was reminded that there are

The post Customize the Virtual Agent Chat Button in Service Portal appeared first on ServiceNow Guru.

]]>
One of the easiest ways to align the Virtual Agent experience with your organization brand is to update the VA chat button that displays in the Service Portal. Recently, I had to walk one of my developers through the process of aligning the chat button with a given design and was reminded that there are a few different options to consider. Here are the consolidated steps I take for this common ask.

Change the Background color

First, let’s change the background color from “Polaris Purple” to something that aligns with my chosen brand colors.

  1. Navigate to the theme assigned to your chosen Service Portal. For the Employee Center, this is the EC Theme.
  2. In the CSS Variables field, scroll to the very bottom, or search for the SCSS variable $sp-agent-chat-bg.
  3. Assign the SCSS variable to your chosen background color.

Notice that this SCSS variable is set to $brand-primary. If you want to align the color of this button with other interactive elements, you can leave this as it is and instead change the $brand-primary SCSS variable.

/* Set the brand colors as their own SCSS variable to be used throughout your theme */

$brand-purple: #60217D; 
$brand-gold: #ffd840; // If these colors are ever changed, you only have to update the hex code in one place

/* Set the $brand-primary OOB theme variable to your custom brand color variable */

$brand-primary: $brand-purple;

/* SCSS variable controlling the VA button background color stays as-is */

$sp-agent-chat-bg: $brand-primary;

However, this will change MANY different elements in your portal to the assigned color. For some portals, this is ok. For others, a secondary color can be used from the brand color palette that helps the VA button “pop” off the page to be more easily noticed by the user (such as $brand-warning or $brand-info). For this example, I’ve chosen a sunny shade of yellow as a part of an example brand.

/* Set the brand colors as their own SCSS variable to be used throughout your theme */

$brand-purple: #60217D;
$brand-gold: #ffd840; // If these colors are ever changed, you only have to update the hex code in one place

/* Then use the brand color SCSS variable to set applicable OOB theme variables */

$brand-primary: $brand-purple;
$brand-warning: $brand-gold;

/* Change the VA button background SCSS variable to your chosen variable */

$sp-agent-chat-bg: $brand-warning;

You can also create a custom SCSS variable to assign to $sp-agent-chat-bg, or use a plain color hex code. I recommend using SCSS variables whenever possible, to make it easier in the future to make changes or assign additional elements to the same color.

/* Set the brand colors as their own SCSS variable to be used throughout your theme*/

$brand-purple: #60217D;
$brand-gold: #ffd840; // If these colors are ever changed, you only have to update the hex code in one place

/* Change the VA button background SCSS variable to your custom SCSS variable */

$sp-agent-chat-bg: $brand-gold

/** OR **/

/* Change the VA button background SCSS variable to your chosen hex code */

$sp-agent-chat-bg: #ffd840; // Not recommended, but sometimes it is what it is.

Change the icon(s)

Another change you can make to get away from the out-of-box look is to change the chat icon in the VA chat button. You can do this both for the image that displays when the chat window is closed as well as when it’s open and active.

Change the initial (close) chat button icon

To start, we’ll change the image that displays when the portal is initially loaded. This view is the “close” button, because it displays when the chat window is closed.

  1. Navigate to the images table by going to System UI > Images
  2. Create a new record for your VA chat button image.
  3. Name your image: do not use spaces, and end the name with the type of file extension you’ll be uploading (example: my-image.png).
  4. Upload an image with a transparent background. If the image has a background, it will overlap the background color you chose above.
  5. Copy the name of your image, you’ll need it soon

Now that your image is uploaded to the instance and ready to use, navigate back to your portal’s theme record.

From here, we’ll take one of a two approaches.

Your implementation is still “out-of-box”:

I make this differentiation because I have run into some implemented instances where this first method doesn’t work due to customizations in the environment. In most cases though, your configuration efforts will be pretty straightfoward (thanks Mark Roethof).

In the theme record CSS Variables field, add the following SCSS variable if it is not already included in your theme:

$sp-agent-chat-btn-close: url('/your-img.png'); // VA Chat icon displayed when chat window is closed (click to open)
Do not forget the backslash in front of your image name as shown above, or the image will not display.

“Out-of-box” isn’t working

Sometimes, we inherit (or created) a situation where different customizations mean that the above variables are broken and the chat button doesn’t respond to setting them. If this is the case, below is a workaround for the button image shown when the chat window is closed.

From the theme record, create a new CSS include with a new stylesheet, named “Virtual Agent Branding”

Why this approach? I find it easier to divide your theme CSS into its various pieces and parts (such as pages or widgets), rather than throw all of your custom styles into one stylesheet. Easier to find what you’re looking for, easier to maintain. Custom CSS should almost always be placed in CSS includes; reserve your theme’s CSS Variables field for SCSS variables and mixins.

In your new stylesheet, add the following CSS:

/* VA Button icon */

/* Button icon displayed when chat window is closed */

.sp-ac-root button.sp-ac-btn.closed .sp-ac-btn-icon{
     background-image: url('va-chat-btn.png') !important; // In the URL tag, place the name of the image you uploaded
}

Refresh and check the changed image on the VA chat button in your portal. Depending on how the customizations in your instance have been done, this should provide an override that changes the CSS rendering the image if the SCSS variables aren’t responding.

Adjust sizing (optional)

This icon renders a bit too large for my VA chat button. We want to give our visual elements “breathing room” so as to keep the UI from looking cluttered. If you need to adjust sizing, you can do so via CSS. Note this is the same CSS selector used above for the non-oob workaround. We’re just adding a few more properties:

  • Width and Height: Adjust both equally to center the image.
  • Margin: Adjust margin up if you’re making the image smaller, or down if you’re making the image larger to center the icon you’ve resized.
/* Button icon displayed when chat window is closed */

.sp-ac-root button.sp-ac-btn.closed .sp-ac-btn-icon{
     width: 3rem;
     height: 3rem;
     margin: 1.7rem;
}

Change the open chat button icon

The “open” icon displays when the chat window is open. For the open icon, you can take one of two paths, not necessarily dependent on the level of customization in your instance.

Custom image called via SCSS variable:

If your implementation is out-of-box and responding to the SCSS variables as they should, you can upload a custom image of your choosing as described above and set it in a similar SCSS variable:

$sp-agent-chat-btn-open: url('/your-img-open.png'); // VA Chat icon displayed when the chat window is open (click to close)

If you want to adjust the sizing of your image, you can do so in a fashion similar to that used for the close button:

/* Button icon displayed when chat window is open */

.sp-ac-root button.sp-ac-btn.open .sp-ac-btn-icon{
  height: 5rem;
  width: 5rem;
  margin: 0.5rem;
}

Change retina icon via custom CSS:

If the change you want to make to the close icon is simple, or if your instance has customizations that don’t allow you to use the SCSS variables, you have another option.

From my poking around, it doesn’t seem like you can change the close icon via CSS as easily as you can the open icon. This is because the close icon isn’t technically an image. It’s an icon embedded via CSS on the ::before CSS pseudo element (this is a common tactic for icons in Employee Center widgets). If the SCSS variable mentioned above isn’t working for you, you’ll be limited to altering the “close” icon to another in the retina icon set.

If you want to change the close icon to one of the other icons in the set (in this example, the minus sign), you can do so by placing this CSS in your include:

/* Button icon displayed when the chat window is open */

.sp-ac-root button.sp-ac-btn.open .icon-cross::before{
     content: "\f1fc"; // unicode for the specific icon chosen
}

You can view the entire icon set you can choose from at https://<your_instance_here>.service-now.com/styles/retina_icons/retina_icons.html (thanks Shiva Thomas).

From this list, you can find the icon’s unicode to embed in the CSS above:

  1. Right click on the icon you want to use open the element inspector.
  2. Open your icon’s <div> element, then the <i> element that appears.
  3. Click on the ::before pseudo-element. The styles on the right will show a value called “content”. That value is the unicode value for your icon.
  4. Insert the unicode into the CSS above set in your CSS include.

This will display your chosen icon in white, the out-of-box color.

If you want to change the color of the icon that appears, you can easily do so by adding a color property to the CSS above:

/* Button icon displayed when the chat window is open */ 

.sp-ac-root button.sp-ac-btn.open .icon-cross::before{ 
     content: "\f1fc"; // unicode for the specific icon chosen
     color: $brand-purple; // or a hex code, but see above, I will judge you
 }

You can also change the size of the retina icon that appears. It’s a different process though; because this is technically text, we’ll be adjusting the font-size property as well as the margin.

/* Button icon displayed when the chat window is open */  

.sp-ac-root button.sp-ac-btn.open .icon-cross::before{ 
     content: "\f1fc"; // unicode for the specific icon chosen 
     color: $brand-purple; // or a hex code, but see above, I will judge you 
     font-size: 3rem;
     margin: 1.2rem;
}

In Conclusion

The Virtual Agent is an invaluable tool for connecting with your users and encouraging them to engage in self-service from your Service Portal. As you align your Service Portal / Employee Center to organization brand, don’t ignore this vital tool in your portal’s feature set. Configuring the main chat button is the first step to ensuring that your VA is an integrated, seamless part of your branded experience.

The post Customize the Virtual Agent Chat Button in Service Portal appeared first on ServiceNow Guru.

]]>
Service Portal and DatePicker Field https://servicenowguru.com/service-portal/service-portal-datepicker-field/ Wed, 03 Jul 2024 18:23:43 +0000 https://servicenowguru.com/?p=15498 In the previous article, when creating the form with the fields that will be used when importing the Excel file, I chose to use a library that provides many different configuration options: Bootstrap Datepicker In the same way we did with the SheetJS library, the first thing we need to do is download the necessary

The post Service Portal and DatePicker Field appeared first on ServiceNow Guru.

]]>
In the previous article, when creating the form with the fields that will be used when importing the Excel file, I chose to use a library that provides many different configuration options: Bootstrap Datepicker

In the same way we did with the SheetJS library, the first thing we need to do is download the necessary files. On GitHub you will find the link to download the “.js” and “.css” in cdnjs and some online demos.

The library’s documentation is very complete and contains several styling options and methods to use.

After downloading the files, create a dependency on the widget that will use the library:

 

 

After creating the dependency, the library will be ready to be used. We just need to start it and configure it according to our needs (in my case I just wanted the MM/YYYY information)

HTML

<!-- Field Period -->
<label class="control-label" for="monthYear">Month/Year</label>
<input id="monthYear" name="monthYear" class="form-control" placeholder="MM/YYYY" ng-model="c.model.monthYear.displayValue" readonly>

Link Function

$(document).ready(function(){

    setTimeout(function(){
            
        $('#monthYear').datepicker({
            format: "mm/yyyy",
            startDate: "-22m",				
            endDate: "-1m",
            startView: 1,
            minViewMode: 1,
            maxViewMode: 2,
            autoclose: true,
            toggleActive: true,
            language: "pt-BR"
        });

    },300);

});
The above script must be used in the “Link Function” as it is not a good practice to use jQuery in the Client Script.

After initialization and configuration as desired, it will be ready for use:

The post Service Portal and DatePicker Field appeared first on ServiceNow Guru.

]]>
Load Excel files to ServiceNow using Portal https://servicenowguru.com/service-portal/load-excel-files-to-servicenow-using-portal/ https://servicenowguru.com/service-portal/load-excel-files-to-servicenow-using-portal/#comments Tue, 28 May 2024 16:28:39 +0000 https://servicenowguru.com/?p=15379 As platform administrators we know that there are many ways to import an Excel file to ServiceNow. But what if you need to provide your client a way to load data without accessing one of these tools? When we talk about importing data to ServiceNow, the SheetJS library can be extremely useful in helping us

The post Load Excel files to ServiceNow using Portal appeared first on ServiceNow Guru.

]]>
As platform administrators we know that there are many ways to import an Excel file to ServiceNow. But what if you need to provide your client a way to load data without accessing one of these tools?

When we talk about importing data to ServiceNow, the SheetJS library can be extremely useful in helping us with this process (manipulating spreadsheets in the browser). Developers can create custom integrations to transfer data between ServiceNow and other applications. For example, a developer might build a custom integration that allows data to be imported from an external Excel spreadsheet into ServiceNow.

SheetJS: https://git.sheetjs.com/sheetjs/sheetjs

Business Use Case

In this article, we will use as an example an outsourced company that needs to import the hours worked by its employees to the platform so that these hours can be processed and paid. All records must be associated with a department. All necessary validations will be described in a future article. At this point we will only talk about importing the data.

The person in charge of the company will have to access the portal and upload an Excel file with the employees hours following the following model:

 

exemple table

 

 

The Solution

The first thing we need is to import the standalone version of SheetJS into ServiceNow. Open the link to the xlsx.full.min.js file and copy all the code. After that, we will create a UI Script to import this file into the platform:

 

UI Script

 

The next step is to associate this script with the portal. To do this, open the theme used, go to the ‘JS Includes’ related list and click on ‘New’. In the ‘UI Script’ field, select the script created in the previous step and click ‘Submit.’

 

JS Include

 

Now, let’s start developing the widget that will import the data. We will start by creating the form where the file will be uploaded. Using Bootstrap’s grid system and some CSS changes (which we won’t cover in this article) we have the following result:

Widget
Widget Component: HTML Template
Script:

<form ng-submit="c.submitFile()" name="form" id="my-form">
  <fieldset class="form-row">
    <div class="form-group col-md-3">
      <!-- Field Period -->
      <label class="control-label" for="monthYear">Month/Year</label>
    </div>
    <div class="form-group col-md-3">
      <!-- Field Department -->
      <label for="department">Department</label>
    </div>
    <div class="form-group col-md-3">
      <!-- Input file -->
      <label for="department">Attach File</label>
    </div>
    <div class="form-group col-md-3">
      <!-- Buttom submit -->
      <button
        type="submit"
        id="submit"
        class="btn submit-btn btn-block btn-primary"
      >
        Submit
      </button>
    </div>
  </fieldset>
</form>

This is the code preview:

 

 

Now let’s insert the fields. The final HTML should look like this:

Widget
Widget Component: HTML Template
Script:

<form ng-submit="c.submitFile()" name="form" id="my-form">

  <fieldset class="form-row">

    <div class="form-group col-md-3">
      
      <!-- Field Period -->
      <label class="control-label" for="monthYear">Month/Year</label>
      <input id="monthYear" name="monthYear" placeholder="MM/YYYY" ng-model="c.model.monthYear.displayValue"
             class="form-control" readonly>

    </div>
    
    <div class="form-group col-md-3">
      
      <!-- Field Department -->
      <label for="department">Department</label>
      <sn-record-picker name="department"
                        field="c.model.department"
                        table="c.recordPicker.table"
                        default-query="c.recordPicker.query"
                        display-field="c.recordPicker.display.field"
                        display-fields="c.recordPicker.display.fields"
                        value-field="c.recordPicker.value"
                        search-fields="c.recordPicker.search"
                        page-size="c.recordPicker.size"
                        >
      </sn-record-picker>
      
    </div>
    
    <div class="form-group col-md-3">
      
      <!-- Input file -->
      <label for="attachment" class="btn btn-block btn-primary" ng-hide="c.haveAttachment">
        <span class="glyphicon glyphicon-paperclip"></span> Attach File
      </label>
      
      <div ng-show="c.haveAttachment" class="file-attached">
        {{c.fileName}} <a id="clear" href="" ng-click="c.removeAttachment()">
        <span class="glyphicon glyphicon-remove"></span></a>
      </div>
      
      <input type="file" name="attachment" id="attachment" accept=".xls,.xlsx" 
             onchange="angular.element(this).scope().readAttachment(angular.element(this)[0].files[0])"  
             >
    </div>
    
    <div class="form-group col-md-3">
      
      <!-- Buttom submit -->
      <button type="submit" id="submit" class="btn submit-btn btn-block btn-primary">Submit</button>
      
    </div>
    
  </fieldset>
  
</form>

Regarding HTML, I will leave two points for the next articles:

  • The field Department will be created using the snRecordPicker directive:

 

Now we have the form with all its components:

Now that we have our HTML built, let’s move on to the Client Script and create the functions that will be used. This will be the most important part of the article because it is here that we will read the file. Once the file has been selected using the button on the form, we need a script to read, process, and insert the data into the table (for this article we will not perform any type of validation on the data).

Widget
Widget Component: Client Script
Script:

api.controller=function($scope, spUtil) {
    
  var c = this;

    c.model = {};
    
    c.hoursToSubmit = [];
    
    /* 
        read the file
        the function get the attached file as a blob
        https://developer.mozilla.org/en-US/docs/Web/API/Blob
    */
    $scope.readAttachment = function(blob) {

        //check if the file is XLS or XLSX
        var isXLSX = blob.name.endsWith('.xlsx') || blob.name.endsWith('.xls');

        // If not an Excel file the function fails
        if (!isXLSX) {
            spUtil.addErrorMessage("The file must be .xlxs or .xls");
            //c.removeAttachment();
            return;
        }

        c.fileName = blob.name;

        /* star the reader */
        var myReader = new FileReader();

        /* function that will be executed when the reader is called	*/
        myReader.onload = function(e) {

            var data = e.target.result;

            /* get the workbook */
            var workbook = XLSX.read(data, {
                type: "binary"
            });
            var o = {};

            /* get the first sheet name */
            var name = workbook.SheetNames[0];

            /* obtain the JSON object of the sheet and stringify */
            var work_hours = XLSX.utils.sheet_to_json(workbook.Sheets[name], {header: "A"});

            /* remove the first line (columns titles) using Lodash*/
            work_hours = _.drop(work_hours, 1);

            if (work_hours.length == 0) {

                spUtil.addErrorMessage("Nothing to import!");
                //c.removeAttachment();
                return;

            } else {

                /* For this article we will not do any type of validation */
                c.hoursToSubmit = work_hours;
                return;

            }

        }

        /* stars the reader */
        myReader.readAsBinaryString(blob);
    }
    
    c.submitFile = function() {
                
        $scope.server.get({
            action: "insert-hours",
            monthYear: c.model.monthYear,
            department: c.model.department,
            hoursToSubmit: c.hoursToSubmit
        }).then(function(resp) {
            
            spUtil.addInfoMessage("Sucess! Good job!! :)");
            c.hoursToSubmit = [];
            c.model = {};
            //c.removeAttachment();
            
        });
        
    }

};
Widget
Widget Component: Server Script
Script:

(function() {
    
    if(input && input.action == 'insert-hours') {
        
        var grWH = new GlideRecord('x_529701_snguru_worked_hours');
        
        for (var i = 0; i < input.hoursToSubmit.length ; i++) {
            
            grWH.initialize();			
            grWH.setValue('id', input.hoursToSubmit[i]['A'].toString());
            grWH.setValue('name', input.hoursToSubmit[i]['B']);
            grWH.setValue('u_departament', input.department.value);			
            grWH.setValue('period', input.monthYear.displayValue);
            grWH.setValue('u_type', input.hoursToSubmit[i]['C']);
            grWH.setValue('hours', parseInt(input.hoursToSubmit[i]['D']));
            grWH.insert();
            
        }
        
    }

})();

Now our widget is ready to make the magic happen! Fill in the fields, select the file, and click ‘Submit’.

 

 

If everything goes well, the data will be written to the table:

 

 

Conclusion

By leveraging the SheetJS library and custom ServiceNow widgets, we have created a streamlined solution for importing employee work hours from Excel files directly into ServiceNow. This approach eliminates the need for users to access external tools, simplifying the process and enhancing user experience. Such integrations not only save time, but also reduce errors associated with manual data entry, ensuring that the data processing is efficient and accurate.

The post Load Excel files to ServiceNow using Portal appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/service-portal/load-excel-files-to-servicenow-using-portal/feed/ 4
Adding Video to Knowledge Articles https://servicenowguru.com/knowledge-management/adding-video-knowledge-articles/ https://servicenowguru.com/knowledge-management/adding-video-knowledge-articles/#comments Tue, 14 Mar 2017 11:37:23 +0000 https://servicenowguru.wpengine.com/?p=12460 Support for video in knowledge articles seems like it should be pretty straightforward but unfortunately history has proven otherwise. Standards have been shifting over time and the methods for displaying video in HTML have had varying levels of support depending on the browser. By default ServiceNow only supports out-of-date plugin methods of embedding video. While

The post Adding Video to Knowledge Articles appeared first on ServiceNow Guru.

]]>
Support for video in knowledge articles seems like it should be pretty straightforward but unfortunately history has proven otherwise. Standards have been shifting over time and the methods for displaying video in HTML have had varying levels of support depending on the browser. By default ServiceNow only supports out-of-date plugin methods of embedding video. While video support can certainly stand for some updating by ServiceNow, there are a few steps that can be taken now to allow for functional video use.

This method enables video to be used across the board in the HTML editor so it can be added wherever it is needed. It uses the HTML5 video tag and does require the user to be at least a little familiar with HTML but at this point that is difficult to avoid.


The first thing to do is whitelist the video and source tags in the HTMLSanitizerConfig script include. To do this replace this:

HTML_WHITELIST : {
  globalAttributes: {
    attribute:[],
    attributeValuePattern:{}
  },
},

With this:

HTML_WHITELIST : {
  globalAttributes: {
    attribute:[],
    attributeValuePattern:{}
  },
  video: {
    attribute:["width", "height", "controls", "autoplay", "loop", "muted", "poster", "preload", "src"],
    attributeValuePattern:{}
  },
  source: {
    attribute:["type", "src", "media", "sizes"],
    attributeValuePattern:{}
  }
},

To embed a video, open the article (or other record with an HTML field) and upload the video file.

Get the Sys ID of the attachment. An easy way that end users can do this is by clicking the “View” link next to the attachments.

Then copy the Sys ID from the URL.

Next click the “<>” icon to view the HTML source.

Paste in the following code, changing the value for the Sys ID parameter to that of the attachment.

<video controls="controls" width="100%" height="150">
  <source src="/sys_attachment.do?sys_id=[Sys ID of the attachment goes here]&view=true" type="video/mp4" />
</video>

NOTE: mp4 video looks to have the best support across browsers at the time of writing. The video tag has a number of options that allow for tailoring the content to the browser, device size, and other things as needed.

The post Adding Video to Knowledge Articles appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/knowledge-management/adding-video-knowledge-articles/feed/ 10