Building an Automation Dashboard for Salesforce Marketing Cloud (SFMC)

Efficiently managing and optimizing automation performance is paramount for success in Salesforce Marketing Cloud (SFMC). In this blog post, we present a detailed coding sample for constructing a dynamic automation dashboard on a cloud page. Leveraging HTML, CSS, JavaScript, and AMPscript, this dashboard provides developers with insights into success and failure rates over time.

A screenshot of the dashboard looks as below:


Part 1: Fetching the List of Automations

To kick off the automation dashboard, we begin by fetching the list of automations and their corresponding Customer Keys from SFMC using the WSProxy object. The retrieved data is dynamically populated into a table on the left section of the dashboard. This table serves as a list of available automations for the user to choose from.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!-- Fetching the List of Automations from SFMC -->
<script runat="server">
  Platform.Load("Core", "1.1.1");
  var prox = new Script.Util.WSProxy();
  var cols = ["Name", "CustomerKey"];
  var filter = {
    Property: "Status",
    SimpleOperator: "IN",
    Value: [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8]
  };
  var res = prox.retrieve("Automation", cols, filter);

  if (res.Results.length > 0) {
    var statusObj = {
      "-1": "Error",
      "0": "BuildingError",
      "1": "Building",
      "2": "Ready",
      // ... (additional status mappings)
    };

    Write('<table id="tableId"><tr><th colspan="2">Select the automation</th></tr>');
    for (var i = 0; i < res.Results.length; i++) {
      var autoName = res.Results[i].Name;
      var ID = res.Results[i].CustomerKey;

      Write('<tr><td>' + autoName + '</td><td style="display:none;">' + ID + '</td></tr>');
    }
    Write('</table>');
  }
</script>

Part 2: Adding Click Handlers

When a user clicks on a specific automation, the associated Customer Key is retrieved and appended to the URL. The page then refreshes, displaying the user the instances section for the selected automation.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!-- Adding Click Handlers to Automation List Table -->
<script>
  function addRowHandlers() {
    var table = document.getElementById("tableId");
    var rows = table.getElementsByTagName("tr");

    for (i = 0; i < rows.length; i++) {
      var currentRow = table.rows[i];

      var createClickHandler = function (row) {
        return function () {
          var cell = row.getElementsByTagName("td")[1];
          var ai = cell.innerHTML;
          var url = 'https://yoursfmcsubdomain.com/Automation%20Dashboard?ai=' + ai;
          window.location.href = url;
        };
      };

      currentRow.onclick = createClickHandler(currentRow);
    }
  }

  window.onload = addRowHandlers();
</script>

Part 3: Listing Automation Instances 

We retrieve, and display instances of the selected automation based on its Customer Key obtained from the URL. Using WSProxy, we fetch instance details such as name, start time, completion time, status, and status message. The instances are presented in a table, and aggregate attributes representing the number of successes and failures are calculated but hidden from the end user.

 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<!-- Listing Automation Instances of Selected Automation -->
<script runat="server">
  Platform.Load("Core", "1.1.1");

  var prox = new Script.Util.WSProxy();
  var automationKey = Variable.GetValue("@ai");
  var cols = ["Name", "Status", "CompletedTime", "StatusMessage", "StartTime"];

  if (automationKey !== null && automationKey !== "") {
    var filter = {
      Property: "CustomerKey",
      SimpleOperator: "EQUALS",
      Value: automationKey
    };

    var res = prox.retrieve("AutomationInstance", cols, filter);
    var nerrors = 0;
    var nsuccess = 0;

    if (res.Results.length > 1) {
      Write('<table><tr><th colspan="2"></th></tr>');

      for (var i = 0; i < res.Results.length; i++) {
        // Extracting instance details
        var autoName = res.Results[i].Name;
        var StartTime = res.Results[i].StartTime;
        var CompletedTime = res.Results[i].CompletedTime;
        var StatusMessage = res.Results[i].StatusMessage;

        // Counting successes and errors
        if (StatusMessage === 'Error') {
          nerrors++;
        }
        if (StatusMessage === 'Complete') {
          nsuccess++;
        }

        Write('<tr><td>' + autoName + '</td><td>' + StartTime + '</td><td>' + CompletedTime + '</td><td>' + StatusMessage + '</td></tr>');
      }

      Write('</table>');

      // Storing counts in hidden attributes
      Variable.SetValue("@nsuccess", nsuccess);
      Variable.SetValue("@nerrors", nerrors);
    } else {
      Write('<h1 align="center">No Instances found for this Automation</h1>');
    }
  } else {
    Write('<h1 align="center">Select an automation from the left</h1>');
  }
</script>

Part 4: Charting with Chart.js 

 To visualize the success and failure rates of automation instances, we utilize Chart.js. The JavaScript code retrieves the aggregate attribute values and generates a pie chart. This chart visually represents the completion status of instances, providing developers with a quick and insightful overview of automation performance.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- Charting Automation Instance Success and Failure Rates -->
<script>
  var data = [];
  data[data.length] = document.getElementById("nsuccess").innerHTML;
  data[data.length] = document.getElementById("nerrors").innerHTML;

  new Chart(document.getElementById("pie-chart"), {
    type: 'pie',
    data: {
      labels: ["Completed", "Errored"],
      datasets: [{
        backgroundColor: ["#82CD47", "#FB3569"],
        data: data
      }]
    },
    options: {
      title: {
        display: false,
        text: 'Automation Performance Chart'
      }
    }
  });
</script>


Part 5: Finalizing the Dashboard Layout 

To complete the automation dashboard, we apply final touches to the layout. The cloud page is divided into four quarters horizontally, with the first quarter displaying the list of automations and the remaining three quarters dedicated to automation instances. Additionally, a search feature is implemented to facilitate easy navigation and selection of specific automations.

 

1
2
3
4
<!-- Finalizing the Automation Dashboard Layout -->
<div class="w3-light-grey w3-bar-block">
  <input type="text" id="myInput" onkeyup="filterAutomations()" placeholder="Search for an automation.." title="Type in a name">
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!-- Search Feature for Automations -->
<script>
  function filterAutomations() {
    var input, filter, table, tr, td, i, txtValue;
    input = document.getElementById("myInput");
    filter = input.value.toUpperCase();
    table = document.getElementById("tableId");
    tr = table.getElementsByTagName("tr");

    for (i = 0; i < tr.length; i++) {
      td = tr[i].getElementsByTagName("td")[0];

      if (td) {
        txtValue = td.textContent || td.innerText;

        if (txtValue.toUpperCase().indexOf(filter) > -1) {
          tr[i].style.display = "";
        } else {
          tr[i].style.display = "none";
        }
      }
    }
  }
</script>

By following these steps, you can create a comprehensive automation dashboard that enhances visibility into SFMC automation performance. The dashboard allows users to select specific automations, view their instances, and visualize success and failure rates over time.


Complete code:

Make sure to replace https://yoursfmcsubdomain.com/Automation%20Dashboard with your cloud page URL to get this going.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
<!-- 
Title: Automation dashboard for developers in SFMC
Description: This code is an automation dashboard for developers in Salesforce Marketing Cloud (SFMC). 
It is designed to be used on a cloud page and provides a user interface to display a list of automations
on the left side and the instances of a selected automation on the right side, 
along with a pie chart showing the number of failed and successful runs.
Developer name: Sravan Alaparthi
Date:
Version:
Last modified:
Last modified reason:
-->

<!-- Include Required Prerequisites -->

<!-- The code includes CSS and JavaScript libraries for styling the tables (W3.css) and charting (Chart.js). 
These resources can be placed within SFMC to reduce external dependencies
-->
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
  /* Set the table width to 100% */
  .custom-table {
    width: 100%;
    border-collapse: collapse;
    /* Remove spacing between table cells */
  }
  /* Set the first column width to 25% */
  .custom-table th, .custom-table td {
    width: 25%;
    border: 1px solid #000;
    /* Optional: Add borders for visual clarity */
    padding: 8px;
    text-align: center;
  }
  /* Set the second column width to 75% */
  .custom-table td:nth-child(2) {
    width: 75%;
  }
  .sortable-header {
    cursor: pointer;
    text-decoration: underline;
  }
  .sortable-header:hover {
    color: blue;
    /* Change color on hover */
  }
  /* Create two unequal columns that float next to each other */
  * {
    box-sizing: border-box;
  }
  #myInput {
    background-image: url('/css/searchicon.png');
    background-position: 10px 10px;
    background-repeat: no-repeat;
    width: 100%;
    font-size: 16px;
    padding: 12px 20px 12px 40px;
    border: 1px solid #ddd;
    margin-bottom: 12px;
  }
</style>
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>

<!-- AMPScript to fetch the selected automation ID from the URL parameter -->
%%[
    /* Declare Variables */
    var @nsuccess, @nerrors, @ai
    /* Get Subscriber in content from URL */
    Set @ai = RequestParameter("ai")
]%%

<!-- Div to set table styles -->
<div class="row w3-cell-row w3-table-all w3-hoverable">
  <table class="custom-table">
    <tr>
      <td>
        <!-- Code to divide the page into sections -->
        <!-- The left section with 25% width of the dashboard displays a list of automations using a table.
        Below SSJS retrieves the list of automations from SFMC using the WSProxy object. 
        The automation names are displayed in the table rows
        -->
        <div class="w3-light-grey w3-bar-block">
          <input type="text" id="myInput" onkeyup="filterAutomations()" placeholder="Search for an automation.." title="Type in a name">
          <script runat="server">
            Platform.Load("Core", "1.1.1");
            var prox = new Script.Util.WSProxy();
            var cols = ["Name", "CustomerKey"];
            var filter = {
              Property: "Status",
              SimpleOperator: "IN",
              Value: [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8]
            };
            var res = prox.retrieve("Automation", cols, filter);
            if (res.Results.length > 0) {
              var statusObj = {
                "-1": "Error",
                "0": "BuildingError",
                "1": "Building",
                "2": "Ready",
                "3": "Running",
                "4": "Paused",
                "5": "Stopped",
                "6": "Scheduled",
                "7": "Awaiting Trigger",
                "8": "InactiveTrigger"
              };
              Write('<table id="atable" class="w3-table w3-bordered w3-striped"><tr><th colspan="2">Select the automation</th></tr>')
              for (var i = 0; i < res.Results.length; i++) {
                var autoName = res.Results[i].Name;
                var ID = res.Results[i].CustomerKey;
                var autoStatusNum = res.Results[i].Status;
                var autoStatus = statusObj[autoStatusNum];
                Write('<tr><td>' + autoName + '</td><td style="display:none;">' + ID + '</td></tr>')
              }
              Write('</table>')
            }
          </script>
        </div>
        <!-- The right section of the dashboard displays the instances of the selected automation.
        It uses a table to show the instance details such as name, start time, completion time, status, and status message. 
        -->
      </td>
      <td>
        <div>
          <!-- Charting canvas -->
          <canvas id="pie-chart" width="150" height="50"></canvas>
          <!-- below code retrieves the instances based on the selected automation ID and populates the table rows accordingly -->
          <div class="w3-light-grey w3-bar-block">
            <script runat="server">
              Platform.Load("Core", "1.1.1");
              var prox = new Script.Util.WSProxy();
              var automationkey = Variable.GetValue("@ai");
              var cols = ["Name", "Status", "CompletedTime", "StatusMessage", "StartTime"];
              if (automationkey !== null && automationkey !== "") {
                var filter = {
                  Property: "CustomerKey",
                  SimpleOperator: "EQUALS",
                  Value: automationkey
                }
                var res = prox.retrieve("AutomationInstance", cols, filter);
                /* Variables to hold the number of successful runs and fails of an automation. 
                These are calculated in the below for loop and written to HTML as hidden attributes.
                These attributes are read by client-side JavaScript and charted using Chart.js
                */
                var nerrors = 0;
                var nsuccess = 0;
                if (res.Results.length > 1) {
                  Write('<table id="aitable" class="w3-table w3-bordered w3-striped">');
                  Write('<tr>');
                  Write('<th onclick="sortTable(0)" class="sortable-header">Automation Name &#x21C5;</th>');
                  Write('<th onclick="sortTable(1)" class="sortable-header">Start Time &#x21C5;</th>');
                  Write('<th onclick="sortTable(2)" class="sortable-header">Completed Time &#x21C5;</th>');
                  Write('<th onclick="sortTable(3)" class="sortable-header">Status Message &#x21C5;</th>');
                  Write('</tr>');
                  for (var i = 0; i < res.Results.length; i++) {
                    var autoName = res.Results[i].Name;
                    var StartTime = res.Results[i].StartTime;
                    var CompletedTime = res.Results[i].CompletedTime;
                    var Status = res.Results[i].Status;
                    var StatusMessage = res.Results[i].StatusMessage;
                    if (StatusMessage == 'Error') {
                      nerrors = nerrors + 1;
                    }
                    if (StatusMessage == 'Complete') {
                      nsuccess = nsuccess + 1;
                    }
                    Write('<tr><td>' + autoName + '</td><td>' + StartTime + '</td><td>' + CompletedTime + '</td><td>' + StatusMessage + '</td></tr>');
                  }
                  Write('</table>')
                  Variable.SetValue("@nsuccess", nsuccess);
                  Variable.SetValue("@nerrors", nerrors);
                }
                else {
                  Write('<h1 align="center">No Instances found for this Automation</h1>');
                }
              }
              else {
                Write('<h1 align="center">Select an automation from the left</h1>');
              }
            </script>
          </div>
        </div>
      </td>
    </tr>
  </table>

  <!-- SSJS writes the number of automation success and failures to the DOM (not displayed to the user) 
  so Client-side JS can read the same for Charting -->
  <div style="display:none;">
    <p id="nsuccess">%%=v(@nsuccess)=%%</p>
    <p id="nerrors">%%=v(@nerrors)=%%</p>
  </div>
</div>

<!-- The JavaScript code for charting retrieves the values of the counters from the DOM and uses Chart.js to create a pie chart. 
The chart represents the number of completed and errored instances using different colors
-->
<script>
  var data = [];
  data[data.length] = document.getElementById("nsuccess").innerHTML;
  data[data.length] = document.getElementById("nerrors").innerHTML;
  new Chart(document.getElementById("pie-chart"), {
    type: 'pie',
    data: {
      labels: ["Completed", "Errored"],
      datasets: [{
        backgroundColor: ["#82CD47", "#FB3569"],
        data: data
      }]
    },
    options: {
      title: {
        display: false,
        text: 'Chart JS Pie Chart Example'
      }
    }
  });
  /*
  The code includes a function addRowHandlers() that adds click handlers to the rows of the automation list table.
  When a row is clicked, the function retrieves the automation ID from the second cell of the row and appends this to the a URL.
  The page then refreshes to the new URL, displaying automation instances section for the automation
  */
  function addRowHandlers() {
    var table = document.getElementById("atable");
    var rows = table.getElementsByTagName("tr");
    for (i = 0; i < rows.length; i++) {
      var currentRow = table.rows[i];
      var createClickHandler = function (row) {
        return function () {
          var cell = row.getElementsByTagName("td")[1];
          var ai = cell.innerHTML;
          console.log(ai);
          var url = 'https://yoursfmcsubdomain.com/Automation%20Dashboard?ai=' + ai;
window.location.href = url; }; }; currentRow.onclick = createClickHandler(currentRow); } } window.onload = addRowHandlers(); function sortTable(n) { var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0; table = document.getElementById("aitable"); // Change to match your actual table ID switching = true; // Set the sorting direction to ascending: dir = "asc"; /* Make a loop that will continue until no switching has been done: */ while (switching) { // Start by saying: no switching is done: switching = false; rows = table.rows; /* Loop through all table rows (except the first, which contains table headers): */ for (i = 1; i < (rows.length - 1); i++) { // Start by saying there should be no switching: shouldSwitch = false; /* Get the two elements you want to compare, one from the current row and one from the next: */ x = rows[i].getElementsByTagName("TD")[n]; y = rows[i + 1].getElementsByTagName("TD")[n]; /* Check if the two rows should switch place, based on the direction, asc or desc: */ if (dir == "asc") { if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) { // If so, mark as a switch and break the loop: shouldSwitch = true; break; } } else if (dir == "desc") { if (x.innerHTML.toLowerCase() < y.innerHTML.toLowerCase()) { // If so, mark as a switch and break the loop: shouldSwitch = true; break; } } } if (shouldSwitch) { /* If a switch has been marked, make the switch and mark that a switch has been done: */ rows[i].parentNode.insertBefore(rows[i + 1], rows[i]); switching = true; // Each time a switch is done, increase this count by 1: switchcount++; } else { /* If no switching has been done AND the direction is "asc", set the direction to "desc" and run the while loop again. */ if (switchcount == 0 && dir == "asc") { dir = "desc"; switching = true; } } } } function filterAutomations() { var input, filter, table, tr, td, i, txtValue; input = document.getElementById("myInput"); filter = input.value.toUpperCase(); table = document.getElementById("atable"); tr = table.getElementsByTagName("tr"); for (i = 0; i < tr.length; i++) { td = tr[i].getElementsByTagName("td")[0]; if (td) { txtValue = td.textContent || td.innerText; if (txtValue.toUpperCase().indexOf(filter) > -1) { tr[i].style.display = ""; } else { tr[i].style.display = "none"; } } } } </script>

Enhancements:

Alphabetical Sorting of Automations

Automations are now sorted alphabetically by their names on the server side, ensuring an intuitive order when viewing the list.

Sorting is implemented using the localeCompare function in JavaScript, ensuring accurate, locale-aware string comparisons.

Exclusion of Backend Automations:

Backend-generated automations generated by journeys with names ending in ISO-formatted timestamps (e.g., - 2023-08-15T141247.914) are filtered out to declutter the dashboard.

A regular expression implemented in SSJS ensures these automations are excluded before rendering the list. 


Key Changes to the Code

Sorting Automations

Automations are now sorted directly in the server-side script (SSJS) using the following logic:

res.Results.sort(function (a, b) {
    return a.Name.localeCompare(b.Name);
});


This ensures the list of automations appears in alphabetical order when the page loads, making it easier for developers to locate specific items.

Regex-Based Exclusion of Backend Automations 

Automations with names ending in ISO-formatted timestamps are identified and excluded using a regular expression:
var isoPattern = /-\s20\d{2}-\d{2}-\d{2}T\d{6}\.\d{3}$/;
if (!isoPattern.test(autoName)) {
    Write('<tr data-id="' + ID + '"><td>' + autoName + '</td></tr>');
}


This ensures the dashboard only displays automations relevant to the user, removing unnecessary clutter caused by backend processes.


Final complete Code:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>SFMC Automation Dashboard</title>
  <style>
    .custom-table {
      width: 100%;
      border-collapse: collapse;
    }
    .custom-table th, .custom-table td {
      border: 1px solid #000;
      padding: 8px;
      text-align: center;
    }
    #myInput {
      width: 100%;
      font-size: 16px;
      padding: 12px;
      border: 1px solid #ddd;
      margin-bottom: 12px;
    }
    .sortable-header {
      cursor: pointer;
      text-decoration: underline;
    }
    .sortable-header:hover {
      color: blue;
    }
  </style>
  <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
</head>
<body>
  %%[
    var @ai, @nsuccess, @nerrors
    Set @ai = RequestParameter("ai")
  ]%%

  <div class="row w3-cell-row w3-table-all w3-hoverable">
    <table class="custom-table">
      <tr>
        <td style="width: 25%;">
          <input type="text" id="myInput" onkeyup="filterAutomations()" placeholder="Search for an automation...">
          <script runat="server">
            Platform.Load("Core", "1.1.1");
            var prox = new Script.Util.WSProxy();
            var cols = ["Name", "CustomerKey"];
            var filter = {
              Property: "Status",
              SimpleOperator: "IN",
              Value: [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8]
            };
            var res = prox.retrieve("Automation", cols, filter);

            if (res.Results.length > 0) {
              // Sort automations alphabetically by name
              res.Results.sort(function (a, b) {
                return a.Name.localeCompare(b.Name);
              });

              // Regex to exclude automations with ISO-like date suffixes
              var isoPattern = /-\s20\d{2}-\d{2}-\d{2}T\d{6}\.\d{3}$/;

              Write('<table id="atable" class="w3-table w3-bordered w3-striped"><tr><th>Automation Name</th></tr>');
              for (var i = 0; i < res.Results.length; i++) {
                var autoName = res.Results[i].Name;
                var ID = res.Results[i].CustomerKey;

                // Exclude names matching the ISO-like date pattern
                if (!isoPattern.test(autoName)) {
                  Write('<tr data-id="' + ID + '"><td>' + autoName + '</td></tr>');
                }
              }
              Write('</table>');
            } else {
              Write('<p>No automations found.</p>');
            }
          </script>
        </td>
        <td style="width: 75%;">
          <div>
            <canvas id="pie-chart" width="150" height="50"></canvas>
            <div>
              <script runat="server">
                Platform.Load("Core", "1.1.1");
                var prox = new Script.Util.WSProxy();
                var automationkey = Variable.GetValue("@ai");
                var cols = ["Name", "Status", "CompletedTime", "StatusMessage", "StartTime"];
                if (automationkey) {
                  var filter = {
                    Property: "CustomerKey",
                    SimpleOperator: "EQUALS",
                    Value: automationkey
                  };
                  var res = prox.retrieve("AutomationInstance", cols, filter);

                  var nerrors = 0, nsuccess = 0;
                  if (res.Results.length > 0) {
                    Write('<table id="aitable" class="w3-table w3-bordered w3-striped"><tr><th>Automation Name</th><th>Start Time</th><th>Completed Time</th><th>Status Message</th></tr>');
                    for (var i = 0; i < res.Results.length; i++) {
                      var instance = res.Results[i];
                      var autoName = instance.Name;
                      var StartTime = instance.StartTime;
                      var CompletedTime = instance.CompletedTime;
                      var StatusMessage = instance.StatusMessage;

                      if (StatusMessage === "Error") nerrors++;
                      if (StatusMessage === "Complete") nsuccess++;

                      Write('<tr><td>' + autoName + '</td><td>' + StartTime + '</td><td>' + CompletedTime + '</td><td>' + StatusMessage + '</td></tr>');
                    }
                    Write('</table>');
                  } else {
                    Write('<h3>No instances found for this automation.</h3>');
                  }
                  Variable.SetValue("@nsuccess", nsuccess);
                  Variable.SetValue("@nerrors", nerrors);
                } else {
                  Write('<h3>Select an automation from the list.</h3>');
                }
              </script>
            </div>
          </div>
        </td>
      </tr>
    </table>
  </div>

  <div style="display:none;">
    <p id="nsuccess">%%=v(@nsuccess)=%%</p>
    <p id="nerrors">%%=v(@nerrors)=%%</p>
  </div>

  <script>
    // Attach click listeners to table rows dynamically
    document.addEventListener("DOMContentLoaded", function () {
      var rows = document.querySelectorAll("#atable tr[data-id]");
      rows.forEach(function (row) {
        row.addEventListener("click", function () {
          var id = row.getAttribute("data-id");
          selectAutomation(id);
        });
      });
    });

    // Redirect to the URL with the selected automation ID
    function selectAutomation(id) {
      var url = window.location.href.split('?')[0] + "?ai=" + id;
      window.location.href = url;
    }

    // Filter automation table based on user input
    function filterAutomations() {
      var input = document.getElementById("myInput");
      var filter = input.value.toUpperCase();
      var table = document.getElementById("atable");
      var tr = table.getElementsByTagName("tr");
      for (var i = 0; i < tr.length; i++) {
        var td = tr[i].getElementsByTagName("td")[0];
        if (td) {
          var txtValue = td.textContent || td.innerText;
          tr[i].style.display = txtValue.toUpperCase().indexOf(filter) > -1 ? "" : "none";
        }
      }
    }

    // Create a pie chart using Chart.js
    var data = [
      parseInt(document.getElementById("nsuccess").innerText) || 0,
      parseInt(document.getElementById("nerrors").innerText) || 0
    ];
    new Chart(document.getElementById("pie-chart"), {
      type: 'pie',
      data: {
        labels: ["Completed", "Errored"],
        datasets: [{
          backgroundColor: ["#82CD47", "#FB3569"],
          data: data
        }]
      },
      options: { title: { display: false } }
    });
  </script>
</body>
</html>

No comments:

Post a Comment

Powered by Blogger.