
Solution Overview
Video short demo
Trial dev space
The application was created in SAP Business Application Studios using NodeJS, express and HDB connections to the SAP HANA Database and it consists of creating multiple services and functions which are being called from the html page and SAP Integration Suite.
Catalog services
Data model
Application Home Screen
<input type="text" id="searchInput" placeholder="Search for iFlow name..." onkeyup="filterTable()">
<br><br>
<table id="dataTable">
<thead>
<tr>
<th onclick="sortTable(0)">iFlow name</th>
<th onclick="sortTable(1)">StartDate</th>
<th onclick="sortTable(2)">StartTime</th>
<th onclick="sortTable(3)">EndDate</th>
<th onclick="sortTable(4)">EndTime</th>
<th>Action</th> <!-- Add a new column for delete buttons -->
</tr>
</thead>
<tbody id="dataBody">
<!-- Table content will be added dynamically -->
</tbody>
</table>
<!-- Sorting options dropdown -->
<div class="sorting-options" id="sortingOptions">
<a href="#" onclick="sortTable(0, 'asc')">Sort Ascending</a>
<a href="#" onclick="sortTable(0, 'desc')">Sort Descending</a>
<a href="#" onclick="sortTable(1, 'asc')">Sort Ascending</a>
<a href="#" onclick="sortTable(1, 'desc')">Sort Descending</a>
<a href="#" onclick="sortTable(2, 'asc')">Sort Ascending</a>
<a href="#" onclick="sortTable(2, 'desc')">Sort Descending</a>
<a href="#" onclick="sortTable(3, 'asc')">Sort Ascending</a>
<a href="#" onclick="sortTable(3, 'desc')">Sort Descending</a>
<a href="#" onclick="sortTable(4, 'asc')">Sort Ascending</a>
<a href="#" onclick="sortTable(4, 'desc')">Sort Descending</a>
</div>
<script>
// Function to delete a row when the delete button is clicked
function deleteRow(row) {
const iFlowName = row.cells[0].textContent.trim(); // Extract iFlow name from the first column
// Make a GET request with query parameters to delete the corresponding iFlow
deleteIFlow(iFlowName);
// Remove the row from the table
row.remove();
}
// Function to make a GET request to delete an iFlow
function deleteIFlow(iFlowName) {
// Define the URL and headers for the GET request
const apiUrl = 'https://${DispatcherURL}';
const apiKey = '${apiKey}';
const step = 'DeleteScheduleTraces';
// Construct the full URL with query parameters
const url = `${apiUrl}?Step=${step}&Name=${iFlowName}`;
// Fetch data using the GET request
fetch(url, {
method: 'GET',
headers: {
'ApiKey': apiKey
}
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.text();
// alert(response.text())
})
.then(data => {
// Handle the response as needed (e.g., display a confirmation message)
const resp2 = data;
alert(resp2);
console.log('iFlow deleted:', data);
})
.catch(error => {
const resp3 = 'Error deleting iFlow: ${error}';
alert(resp3);
console.error('Error deleting iFlow:', error);
});
}
// Function to filter the table based on the search input
function filterTable() {
const searchInput = document.getElementById("searchInput");
const filterText = searchInput.value.trim().toUpperCase();
const table = document.getElementById("dataTable");
const rows = table.getElementsByTagName("tr");
for (let i = 1; i < rows.length; i++) { // Start from index 1 to skip header row
const cells = rows[i].getElementsByTagName("td");
let matchFound = false;
// Only search in the first column (iFlow Name)
const textValue = cells[0].textContent || cells[0].innerText;
// Perform a partial search (check if the text contains the filter text)
if (textValue.toUpperCase().includes(filterText)) {
matchFound = true;
}
if (matchFound) {
rows[i].style.display = "";
} else {
rows[i].style.display = "none";
}
}
}
// Function to make the GET request and populate the table
function loadTableData() {
// Define the URL and headers for the GET request
const apiUrl = '${apiUrl}?Step=ScheduledTraces';
const apiKey = '${apiKey}';
// Fetch data using the GET request
fetch(apiUrl, {
method: 'GET',
headers: {
'ApiKey': apiKey
}
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.text();
})
.then(data => {
// Parse the XML response
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(data, 'text/xml');
const iFlows = xmlDoc.querySelectorAll('iFlow');
// Populate the table with data
const tableBody = document.getElementById('dataBody');
tableBody.innerHTML = ''; // Clear existing rows
iFlows.forEach(iFlow => {
const iFlowName = iFlow.querySelector('iFlowName').textContent;
const startDate = iFlow.querySelector('StartDate').textContent;
const startTime = iFlow.querySelector('StartTime').textContent;
const endDate = iFlow.querySelector('EndDate').textContent;
const endTime = iFlow.querySelector('EndTime').textContent;
// Create a new table row and cells
const row = document.createElement('tr');
const iFlowNameCell = document.createElement('td');
const startDateCell = document.createElement('td');
const startTimeCell = document.createElement('td');
const endDateCell = document.createElement('td');
const endTimeCell = document.createElement('td');
const deleteCell = document.createElement('td'); // Add a cell for the delete button
// Set cell values
iFlowNameCell.textContent = iFlowName;
startDateCell.textContent = startDate;
startTimeCell.textContent = startTime;
endDateCell.textContent = endDate;
endTimeCell.textContent = endTime;
// Create a delete button and set its attributes
const deleteButton = document.createElement('button');
deleteButton.textContent = 'Delete';
deleteButton.classList.add('delete-button'); // Add a class to identify the delete button
deleteButton.addEventListener('click', () => {
// Call the deleteRow function when the delete button is clicked
deleteRow(row);
});
// Append cells to the row
row.appendChild(iFlowNameCell);
row.appendChild(startDateCell);
row.appendChild(startTimeCell);
row.appendChild(endDateCell);
row.appendChild(endTimeCell);
deleteCell.appendChild(deleteButton); // Append the delete button to the cell
row.appendChild(deleteCell); // Append the delete button cell to the row
// Append the row to the table body
tableBody.appendChild(row);
});
// After populating the table, call the filter function to show all data
filterTable();
})
.catch(error => {
console.error('Error loading table data:', error);
});
}
// Call the function to load table data when the page loads
window.addEventListener('load', loadTableData);
</script>
<button onclick="exportTableToExcel()">Export to Excel</button>
<P></P>
<script>
// Function to export the table data to an Excel file
function exportTableToExcel() {
const table = document.getElementById("dataTable");
const ws = XLSX.utils.table_to_sheet(table);
// Create a new workbook and add the worksheet
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "Table Data");
// Save the workbook as an Excel file
XLSX.writeFile(wb, "table_data.xlsx");
}
</script>
SAP HANA Database
{
"model": "gpt-3.5-turbo",
"messages": [
{
"role": "user",
"content": "Write advice for a developer on how to fix this SAP CPI error, maximum ${property.lengthOfResponse} characters: ${in.body}"
}
]
}
Sample request body
API Created
const apiUrl = "https://${apiURL}?Step=GetTenantIflowList";
const apiKey = "${APIKEY}";
fetch(apiUrl, {
method: "GET",
headers: {
"ApiKey": apiKey
},
})
Sample code for a REST call
SAP Integration Suite Calls Dispatcher
Email sent by the application
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
10 | |
10 | |
7 | |
7 | |
7 | |
5 | |
5 | |
4 | |
4 | |
4 |