Troubleshoot device connectivity in Zendesk Support
Create a Zendesk Support app in JavaScript to help your team troubleshoot customer device connectivity issues using the emnify REST API. This app enables your team to:
- View device and SIM details (including statuses)
- View the device's connectivity status
- Refresh device statuses
- Reset device connectivity
Prerequisites
Accounts and permissions
- A Zendesk account on a Support Professional plan or higher. You also need to be an Administrator or Account owner.
- An emnify account with at least one device and assigned SIM.
- A valid application token from your emnify Workspace, created via the emnify Portal or the emnify REST API.
info
Only Administrators can create application tokens in the emnify Portal. See Roles and permissions for more information.
Tools and software
- Basic JavaScript knowledge
note
All the necessary code is provided, but understanding JavaScript helps you customize the app.
- Node.js 14.17.3 or later installed.
- A web browser, such as Chrome or Firefox, that supports mixed HTTP and HTTPS content.
This is required to run the app locally.
warning
Safari doesn't support mixed content and cannot run Zendesk apps locally.
Additionally, create a custom field for your SIM identifier in Zendesk Support as outlined in the next section.
Create a custom ticket field for your SIM identifier
This app relies on a unique SIM identifier to retrieve data from the emnify REST API. Create a custom field in Zendesk Support to store and manage this identifier. Your team should be familiar with this field and use it regularly. This identifier must be:
- Usable for filtering in the List Endpoints API.
- Unique enough that it responds with a single device.
Devices are referred to as "endpoints" in the emnify REST API.
For example, you can use:
- eUICC Identifier (EID)
- Integrated Circuit Card Identifier (ICCID) with or without the final Luhn checksum digit
- International Mobile Equipment Identity (IMEI)
- A serial number or custom identifier that maps to the device name in emnify
warning
The emnify Portal doesn't allows for duplicate device names. If you choose this option, you need to ensure that the device name is unique and follows a consistent format. For example,
device-12345
,D12345
,12345
, etc.
This guide uses the ICCID without the final Luhn checksum digit.
Here are the steps to create a custom field in Zendesk Support:
-
Follow the Zendesk Help guide to add a new custom ticket field named ICCID. Select Number (without decimals) as the field type.
-
Add a Display name to clarify the field's purpose for your team.
infoOptionally, add a Description for admins to provide more context. If the field is visible to customers, you can include a separate description for them.
Example description for ICCID:
Integrated circuit card identifier (ICCID), a 19-digit code used to identify a SIM card. This value doesn't include the final Luhn check digit.
-
Complete the configuration and save the custom field by following the Adding custom ticket fields to your tickets and forms Zendesk guide.
After saving, the field appears in the Admin Center under Objects and rules > Tickets > Fields.
Note down the Field ID for the custom field. You need this ID to fetch the ICCID value.
Create a new Zendesk app
The Zendesk Apps Framework (ZAF) allows you to customize and extend your agent's interface. For more information, see Apps in the Zendesk developer documentation.
Generate the starter files
Follow these steps to set up a new Zendesk app:
-
Create the app files. Use the following values when prompted:
- Directory: emnify-support-app
- Author's name: Your name
- Author's email: Your email address
- Author's website: Leave blank and press Enter
- App name: emnify Support App
After completing this step, the Zendesk Command Line Interface (ZCLI) generates starter files in the
emnify-support-app
folder. -
Run the app locally to test it in your Zendesk Support account before deployment.
Clean up the default code
Review the HTML file
A Zendesk app runs inside an iframe.
Static and dynamic elements are defined in the iframe.html
file located in emnify-support-app/assets/iframe.html
.
-
Open the
iframe.html
file in a text editor. -
Remove the
h2
element:<h2 class="u-semibold u-fs-xl">Hello, World!</h2>
-
Ensure the file includes the ZAF SDK library with the following script tag:
<script src="https://static.zdassets.com/zendesk_app_framework_sdk/2.0/zaf_sdk.min.js"></script>
Set up the JavaScript file
-
Create a file named
main.js
in theassets
folder. -
Add this asynchronous function to
main.js
to initialize the ZAF JavaScript API client:(async function () {
const client = ZAFClient.init();
})(); -
Add a line to resize the app UI:
(async function () {
// Initialize the Zendesk app framework (ZAF) client
const client = ZAFClient.init();
// Resize the app UI
client.invoke("resize", { width: "100%", height: "500px" });
})(); -
In the
iframe.html
file, delete the inline script initializing the ZAF client and replace it with:<script src="main.js"></script>
Make sure this script tag is placed after the one for the ZAF SDK.
The body of iframe.html
should now look as follows:
<body>
<script src="https://static.zdassets.com/zendesk_app_framework_sdk/2.0/zaf_sdk.min.js"></script>
<script src="main.js"></script>
</body>
Design the app's user interface
Add a footer
Add a footer with a Report bugs link:
-
In
iframe.html
, add the following footer block before the script tags:<footer>
<a href="https://github.com/org/emnify-support-app/issues/new" target="_blank">Report bugs</a>
</footer> -
Refresh the app in Zendesk to see the changes.
Add styles
This guide uses Bootstrap CSS for styling.
-
Create a new file named
main.css
in theassets
folder. -
Replace the Zendesk Garden stylesheet link in
iframe.html
with:<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
crossorigin="anonymous"> -
Add a link to
main.css
:<link rel="stylesheet" href="main.css">
-
Add the following styles to
main.css
for the app interface:/* General Body Styles */
body {
color: #343a40;
font-family: Arial, sans-serif;
font-size: 14px;
margin: 0;
padding: 0.5rem;
}
/* Button Container */
.button-container {
display: flex;
justify-content: center; /* Center buttons horizontally */
flex-wrap: wrap; /* Allow buttons to wrap on small screens */
gap: 0.5rem; /* Increase spacing between buttons */
margin: 1rem 0; /* Add more vertical spacing above and below the buttons */
}
/* Buttons */
.btn {
font-size: 12px;
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
}
.btn-secondary {
background-color: #6f42c1;
border-color: #6f42c1;
color: #fff;
}
.btn-secondary:hover {
background-color: #5a379c;
border-color: #5a379c;
}
.btn-danger {
background-color: #e83e8c;
border-color: #e83e8c;
color: #fff;
}
.btn-danger:hover {
background-color: #d63384;
border-color: #d63384;
}
/* Status Text */
#reset-connectivity-status {
margin-top: 0.5rem;
font-size: 12px;
text-align: center; /* Ensure text is centered under buttons */
color: #6c757d;
display: block; /* Ensure it appears as a block element */
}
/* Info Blocks */
.info-blocks {
margin-top: 1rem;
padding: 0.5rem;
background-color: #ffffff;
border: 1px solid #dee2e6;
border-radius: 0.25rem;
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
}
.info-blocks table {
width: 100%;
font-size: 12px;
}
.info-blocks td {
padding: 0.15rem 0.1rem;
}
/* Footer */
footer {
font-size: 10px;
text-align: center;
margin-top: 1rem;
}
footer a {
color: #6f42c1;
text-decoration: none;
}
footer a:hover {
color: #5a379c;
}
Change the logo
Refer to Changing the logo in the Zendesk developer documentation for details on replacing the default logo with your own.
Set up authentication for the emnify REST API
The authentication token entered during app installation must be refreshed regularly to maintain functionality.
If the token becomes invalid, the app displays an error.
To resolve this, update the app settings in the Zendesk Admin Center and reenter the authToken
.
This approach ensures that the authentication token isn't exposed to the browser, which is especially important for organizations where access to the emnify Portal is restricted to specific users. However, this is a temporary solution designed for demonstration purposes and isn't ideal for production use.
For a robust implementation, consider building a server-side Zendesk app that uses the application token to generate and refresh the auth_token
dynamically.
If you want to read a guide for creating a server-side Zendesk apps and integrating with the emnify REST API, let the team know via Canny.
To access the emnify REST API, you need to authenticate your app.
The first step is to use your application token and the Retrieve Authentication Token call to generate a JSON Web Token (JWT) auth_token
that authenticates further requests to the emnify REST API.
- Follow Authenticate with an Application Token to generate your
auth_token
.infoThis API path has a rate limit of 100 requests per IP in a 5-minute window. For more information, see Rate limits in the emnify REST API documentation.
- Save the
auth_token
for later use in your app.
Define installation settings
Next, define the app's installation settings to use the auth_token
:
-
Open the
assets/manifest.json
file. -
Add the following line to allow your app to send requests to the emnify REST API:
{
...
"domainWhitelist": ["cdn.emnify.net"],
...
} -
Define settings using the
parameters
property in the manifest file. Add the following code:{
...
"parameters": [
{
"name": "authToken",
"type": "text",
"required": true,
"secure": true
}
],
...
}noteFor other supported properties, see Setting properties in the Zendesk developer documentation.
Use the authentication token in your app
The framework generates an HTML settings page based on the settings defined in the manifest file.
This is where an agent enters the authToken
when installing the app or edit it later.
Then, you use the {{setting.authToken}}
placeholder for the secure setting's value in your app's request
call.
View device and SIM details
To help your team understand the condition of a device and SIM card, you can configure your app to fetch their current statuses from the emnify REST API and display them in the app.
This section includes:
- Creating the necessary templating to display the data.
- Pulling the ICCID value from the ticket.
- Using it to fetch the device and SIM details from the emnify REST API.
Pull the custom field value from ticket data
You can use ZAF to access Zendesk resources from your app. To retrieve the ICCID from the custom field you created earlier, use Zendesk's Ticket API.
Zendesk apps uses a JavaScript library called the ZAF software development kit (SDK) to interact with the Zendesk API.
The SDK includes a client
that provides an interface between your app and Zendesk Support, enabling various methods to interact with the Apps framework.
Key methods in the ZAF client
- request: Used to make HTTP requests to any REST API, including emnify's.
- get: Used to retrieve data from the framework API, such as custom field values.
Steps to extract the ICCID
Use the client
to access the ticket's custom fields and extract the ICCID.
-
Open your
main.js
file. -
At the top, define global variables for the device ID and ICCID:
let deviceId;
let iccidFromCustomField;noteThe
deviceId
is necessary for resetting the connectivity status later. If you're not using this feature, you can omit this variable. -
Add a function to retrieve the ticket's custom fields and extract the ICCID:
await client
.get("ticket.customField:custom_field_ID")
.then(data => {
iccidFromCustomField =
data["ticket.customField:custom_field_ID"];
});infoReplace
ID
incustom_field_ID
with the Field ID of the custom field you created earlier. Find the ID in the Admin Center under Objects and rules > Tickets > Fields under Field ID.
Create and insert a Handlebars template
Use Handlebars.js to display the fetched details in a structured format.
Create a template to display the information
-
Import the Handlebars library in your app by adding the following script to
iframe.html
(before the script importing yourmain.js
file):<script src="https://cdn.jsdelivr.net/npm/handlebars@4.3.3/dist/handlebars.min.js"></script>
-
Define templates in
script
tags withtype="text/x-handlebars-template"
. The following is an example to create a table for device and SIM details:<script id="device-details-template" type="text/x-handlebars-template">
<strong>Device and SIM Details</strong>
<table>
<tr>
<td>Name:</td>
<td class="data">{{name}}</td>
</tr>
<tr>
<td>Device ID:</td>
<td class="data">{{device_id}}</td>
</tr>
<tr>
<td>Device status:</td>
<td class="data">{{device_status}}</td>
</tr>
<tr>
<td>SIM ID:</td>
<td class="data">{{sim_id}}</td>
</tr>
<tr>
<td>SIM status:</td>
<td class="data">{{sim_status}}</td>
</tr>
<tr>
<td>Last updated:</td>
<td class="data">{{last_updated}}</td>
</tr>
</table>
</script> -
Add a
div
element with the IDdevice-sim-details
iniframe.html
after openingbody
tag:<div id="device-sim-details" class="info-blocks"></div>
If you reload the app, nothing happens because you haven't inserted the template in the HTML yet.
Insert the template into your app
Only one template can be rendered at a time.
Add the following function to your main.js
file to render the template at runtime:
const renderTemplate = (
templateId, // ID of the script template in HTML
context, // Data to populate the template
targetId, // ID of the target element to render content
additionalData = {}, // Additional properties for the template context
) => {
const source = document.getElementById(templateId).innerHTML;
const template = Handlebars.compile(source);
const html = template({ ...context, ...additionalData });
document.getElementById(targetId).innerHTML = html;
};
This function is generic and can be reused to render any Handlebars template in this guide.
Fetch device and SIM details
Next, identify which device the SIM card is linked to in the emnify platform using the List Endpoints API call.
Filter results using the q
query parameter in the <field>:<criteria>
format with the ICCID value.
Pass the ICCID to the showDeviceDetails
and concatenate it to the request URL.
-
Start by defining the function before
renderTemplate
. It should accept the ICCID as an input parameter because the ICCID uniquely identifies the SIM card and is used in the API request.const showDeviceDetails = async iccid => {
// Implementation goes here!
}; -
Since this function makes a network request, it can fail for reasons like network issues or incorrect data. Use a
try-catch
block to handle both success and failure scenarios.try {
// Successful response handling
} catch (error) {
// Error handling
} -
Inside the
try
block, use theclient.request
method to call the emnify REST API. Pass the ICCID as part of the query parameter to filter the results and include authentication headers.- URL: The base URL for the emnify Endpoint API.
- ICCID query:
q=iccid:${iccid}
filters results to find a specific SIM. - Headers: Include the
Authorization
header with the JWT token.
const response = await client.request({
url: `https://cdn.emnify.net/api/v1/endpoint?q=iccid:${iccid}`,
type: "GET",
headers: { Authorization: "Bearer {{setting.authToken}}" },
secure: true,
dataType: "json",
});dangerYou need to mark
secure
as true to ensure sensitive information isn't exposed in the browser. For more information, see Zendesk'ssecure
setting property documentation. -
The API response contains the details you need, such as the device name, ID, SIM status, etc. Extract these details from the response.
- Response parsing: The response is an array of devices.
Use the first device (
response[0]
). - Store device ID: Save the device ID globally for later use.
- Format the data: Create an object with the required fields to display in the template.
const lastUpdatedDate = new Date(); // Capture the time of the fetch
const device = response[0]; // Get the first device from the API response
deviceId = device.id; // Store device ID globally
const deviceDetails = {
name: device.name,
device_id: device.id,
device_status: device.status.description,
sim_id: device.sim.id,
sim_status: device.sim.status.description,
last_updated: lastUpdatedDate,
}; - Response parsing: The response is an array of devices.
Use the first device (
-
Pass the
deviceDetails
object to a Handlebars template to render the information in the app. Use therenderTemplate
function you created earlier.renderTemplate(
"device-details-template", // Template ID
deviceDetails, // Data to populate
"device-sim-details" // Target element ID
); -
If the API request fails, display an error message using a dedicated Handlebars template (defined in the next section). The error message can include the status and description to help debug.
catch (error) {
renderTemplate("error-template", error, "device-sim-details");
} -
Finally, call
showDeviceDetails
inmain.js
with your global ICCID variable:showDeviceDetails(iccidFromCustomField);
Putting it all together, the function looks like this:
const showDeviceDetails = async iccid => {
try {
// Make a GET request to the emnify REST API
const response = await client.request({
url: `https://cdn.emnify.net/api/v1/endpoint?q=iccid:${iccid}`,
type: "GET",
headers: { Authorization: "Bearer {{setting.authToken}}" },
secure: true,
dataType: "json",
});
// Process the response
const lastUpdatedDate = new Date();
const device = response[0];
deviceId = device.id;
const deviceDetails = {
name: device.name,
device_id: device.id,
device_status: device.status.description,
sim_id: device.sim.id,
sim_status: device.sim.status.description,
last_updated: lastUpdatedDate,
};
// Render the data into the template
renderTemplate("device-details-template", deviceDetails, "device-sim-details");
} catch (error) {
// Handle errors by rendering the error template
// Covered in the next section
renderTemplate("error-template", error, "device-sim-details");
}
};
showDeviceDetails(iccidFromCustomField);
Add error handling
Insert this Handlebars template in iframe.html
after your details template:
<script id="error-template" type="text/x-handlebars-template">
<p>{{status}}
-
{{statusText}}
error. Please report a bug at the link below.</p>
</script>
The JavaScript logic for error handling is already included in the showDeviceDetails
function.
Optional: Format the dates
You can format the date and time to display to be more human-readable.
-
Locate the following line in your
showDeviceDetails
function:const lastUpdatedDate = new Date();
-
Replace it with:
const currentTime = new Date();
const lastUpdatedDate = formatDate(currentTime); -
Add this function to your
main.js
and adjust the options as needed:const formatDate = dateString => {
const options = {
weekday: "short",
day: "2-digit",
month: "short",
year: "numeric",
hour: "2-digit",
minute: "2-digit",
timeZoneName: "short",
};
return new Date(dateString).toLocaleString("en-US", options);
};Here's an example date rendered with these options:
Thu, Jan 16, 2025, 12:56 PM GMT+1
View the device's connectivity status
Now that you have the device details and defined the deviceId
, you can fetch the device's connectivity status from emnify using the Endpoint Connectivity Status API call.
Set up the Handlebars template
Before writing the JavaScript logic, you must define the Handlebars template in your HTML. This template renders the connectivity data dynamically at runtime.
-
Add this script to your
iframe.html
file:<script id="connectivity-template" type="text/x-handlebars-template">
<strong>Device Connectivity</strong>
<table>
<tr>
<td>Status:</td>
<td class="data">{{connectivity_status}}</td>
</tr>
<tr>
<td>Last updated:</td>
<td class="data">{{last_updated}}</td>
</tr>
</table>
</script> -
Add a
div
element with the IDdevice-connectivity-status
after the openingbody
tag:<div id="device-connectivity-status" class="info-blocks"></div>
Fetch the device's connectivity status
-
Begin by defining the function in
main.js
. It acceptsdeviceId
as a parameter, which is the unique identifier for the device obtained from the emnify REST API.const showConnectivityStatus = async deviceId => {
// Implementation goes here!
}; -
As with
showDeviceDetails
, network requests in this function may fail. Use atry-catch
block to handle both success and error scenarios.try {
// Successful response handling
} catch (error) {
// Error handling
} -
Inside the
try
block, useclient.request
to call the emnify REST API for the device's connectivity status.- URL: The base URL for the emnify Endpoint API entrypoint.
- Headers: Include the
Authorization
header with the JWT token.
const response = await client.request({
url: `https://cdn.emnify.net/api/v1/endpoint/${deviceId}/connectivity`,
type: "GET",
headers: { Authorization: "Bearer {{setting.authToken}}" },
secure: true,
dataType: "json",
}); -
The response contains the device's connectivity status. Extract the status description and format the current date to show when the information was last updated.
- Use the
formatDate
function (defined earlier) to format the date.
const currentTime = new Date();
const lastUpdatedDate = formatDate(currentTime);
const connectivityData = {
connectivity_status: response.status.description,
last_updated: lastUpdatedDate,
; - Use the
-
Pass the
connectivityData
object to therenderTemplate
function to populate and display the data in the app.renderTemplate(
"connectivity-template", // ID of the Handlebars template
connectivityData, // Data object to populate the template
"device-connectivity-status" // Target element ID
); -
If the API request fails, render an error template. This ensures that the agent sees an informative message if something goes wrong.
catch (error) {
renderTemplate("error-template", error, "device-connectivity-status");
} -
Call
showConnectivityStatus
from withinshowDeviceDetails
after retrieving thedeviceId
. This ensures that the connectivity status is displayed as soon as the device details are fetched.const showDeviceDetails = async iccid => {
try {
...
showConnectivityStatus(deviceId);
} catch (error) {
...
}
Here's the completed showConnectivityStatus
function:
const showConnectivityStatus = async deviceId => {
try {
// Fetch connectivity details from the emnify API
const response = await client.request({
url: `https://cdn.emnify.net/api/v1/endpoint/${deviceId}/connectivity`,
type: "GET",
headers: { Authorization: "Bearer {{setting.authToken}}" },
secure: true,
dataType: "json",
});
// Format the current time
const currentTime = new Date();
const lastUpdatedDate = formatDate(currentTime);
// Prepare data for the template
const connectivityData = {
connectivity_status: response.status.description,
last_updated: lastUpdatedDate,
};
// Render the data using Handlebars
renderTemplate(
"connectivity-template",
connectivityData,
"device-connectivity-status",
);
} catch (error) {
// Render an error message if the API call fails
renderTemplate("error-template", error, "device-connectivity-status");
}
};
Refresh device statuses
This section explains how to add and implement buttons under each information block, allowing agents to manually refresh the device and connectivity statuses.
Update the HTML
Incorporate buttons into your HTML structure in iframe.html
under each information block:
<body>
...
<!-- Connectivity Status Section -->
<div class="info-blocks" id="device-connectivity-status"></div>
<div class="button-container">
<button id="refresh-connectivity" class="btn btn-secondary btn-sm">
Refresh Connectivity Status
</button>
</div>
<!-- Device and SIM Details Section -->
<div class="info-blocks" id="device-sim-details"></div>
<div class="button-container">
<button id="refresh-device-details" class="btn btn-secondary btn-sm">
Refresh Device and SIM Details
</button>
</div>
...
</body>
Attach event listeners in JavaScript
Event listeners connect the buttons to the respective functions, ensuring that clicking them triggers data fetching and updates.
Add the following code to your main.js
file:
// Event listeners for agent actions
document
.getElementById("refresh-connectivity")
.addEventListener("click", () => showConnectivityStatus(deviceId));
document
.getElementById("refresh-device-details")
.addEventListener("click", () => {
showDeviceDetails(iccidFromCustomField);
});
How it works:
- Each button is uniquely identified using an id (
refresh-connectivity
andrefresh-device-details
). - On clicking the "Refresh Connectivity Status" button, the
showConnectivityStatus
function is invoked using the storeddeviceId
. - The "Refresh Device and SIM Details" button triggers the
showDeviceDetails
function, passing the ICCID (iccidFromCustomField
).
Reset device connectivity
This section explains how to add and implement a button under the Device Connectivity Status block, allowing agents to reset connectivity for a device using emnify's Reset Endpoint Connectivity API call. The button displays status updates during the process and refresh the connectivity status once the reset is complete.
Update the HTML
Add the "Reset Connectivity" button and a status span
for feedback in your iframe.html
file:
<body>
...
<div class="info-blocks" id="device-connectivity-status"></div>
<div class="button-container">
<button id="refresh-connectivity" class="btn btn-secondary btn-sm">
Refresh Connectivity Status
</button>
<button id="reset-connectivity" class="btn btn-danger btn-sm">
Reset Connectivity
</button>
<span id="reset-connectivity-status" class="ml-2 text-muted"></span>
</div>
...
</body>
Implement the reset functionality
-
Begin by defining the
resetConnectivity
function. By the end, this function:- Updates the UI to indicate the reset process has started.
- Sends a
PATCH
request to the connectivity reset API entrypoint. - Handles the response and update the UI accordingly.
- Display the updated connectivity status after a delay.
const resetConnectivity = async () => {
// Implementation goes here!
}; -
Inside the function, access the status span element (
reset-connectivity-status
) to provide feedback to the agent. Update the text to "Processing..." and style it with a warning class to visually indicate that the reset process is ongoing.const statusSpan = document.getElementById("reset-connectivity-status");
statusSpan.innerText = "Processing...";
statusSpan.classList.add("text-warning"); -
The emnify REST API requires a payload with
location
andpdp_context
. For this guide, set these values tonull
. Serialize this data into JSON format usingJSON.stringify
.const payload = JSON.stringify({
location: null,
pdp_context: null,
}); -
Next, prepare the headers for the API request. Include:
- An
Authorization
header with the bearer token for authentication. - A
Content-Type
header specifying that the payload is JSON.
By storing these headers in a variable, you maintain compatibility with the Zendesk app framework.
const headers = {
Authorization: "Bearer {{setting.authToken}}",
"Content-Type": "application/json",
}; - An
-
Use the
client.request
method to send aPATCH
request to the emnify REST API. ThedeviceId
is passed in the URL to specify the device to be reset.await client.request({
url: `https://cdn.emnify.net/api/v1/endpoint/${deviceId}/connectivity`,
type: "PATCH",
headers: headers,
data: payload,
secure: true,
}); -
If the request is successful:
- Update the status span with a success message, informing the agent that the reset process has started.
- Advise the agent to keep the tab open while waiting for the updated status.
- Use a
setTimeout
function to fetch the new connectivity status after two minutes.warningWhen reset connectivity is triggered, the device detaches from the network and waits for the modem to connect again. Depending on the device and network conditions, this process can take a few seconds to a few minutes. The connectivity status fetched may not be accurate unless you add a delay.
statusSpan.innerText =
"Connectivity reset. Updating status... Don't close this tab. The process may take a few minutes.";
setTimeout(() => {
showConnectivityStatus(deviceId); // Refresh the connectivity status
statusSpan.innerText = "Updated.";
statusSpan.classList.remove("text-warning");
statusSpan.classList.add("text-success");
}, 120000); // Delay for 2 minutes -
To handle potential errors, the catch block needs to:
- Extract details from the error response (if available).
- Update the status span with a meaningful error message and apply a danger class to indicate failure.
- Log the error to the console for debugging purposes.
} catch (error) {
const errorDetails = error.responseJSON
? `${error.responseJSON.message} (Status: ${error.status})`
: error.statusText || "Unknown error occurred";
console.error("Error resetting connectivity:", error);
statusSpan.innerText = `Failed to reset connectivity: ${errorDetails}`;
statusSpan.classList.remove("text-warning");
statusSpan.classList.add("text-danger");
} -
Finally, attach the
resetConnectivity
function to the "Reset Connectivity" button using an event listener. This ensures that the function is triggered when an agent clicks the button.document
.getElementById("reset-connectivity")
.addEventListener("click", resetConnectivity);
Here's how the complete resetConnectivity
function looks:
const resetConnectivity = async () => {
const statusSpan = document.getElementById("reset-connectivity-status");
statusSpan.innerText = "Processing...";
statusSpan.classList.add("text-warning");
try {
const payload = JSON.stringify({
location: null,
pdp_context: null,
});
const headers = {
Authorization: "Bearer {{setting.authToken}}",
"Content-Type": "application/json",
};
await client.request({
url: `https://cdn.emnify.net/api/v1/endpoint/${deviceId}/connectivity`,
type: "PATCH",
headers: headers,
data: payload,
secure: true,
});
statusSpan.innerText =
"Connectivity reset. Updating status... Don't close this tab. The process may take a few minutes.";
setTimeout(() => {
showConnectivityStatus(deviceId);
statusSpan.innerText = "Updated.";
statusSpan.classList.remove("text-warning");
statusSpan.classList.add("text-success");
}, 60000);
} catch (error) {
const errorDetails = error.responseJSON
? `${error.responseJSON.message} (Status: ${error.status})`
: error.statusText || "Unknown error occurred";
console.error("Error resetting connectivity:", error);
statusSpan.innerText = `Failed to reset connectivity: ${errorDetails}`;
statusSpan.classList.remove("text-warning");
statusSpan.classList.add("text-danger");
}
};
document
.getElementById("reset-connectivity")
.addEventListener("click", resetConnectivity);
Install the app in Zendesk
If you haven't already, install ZCLI then follow the steps from the Zendesk developer documentation to Install the private app in Zendesk Support.