USER
let client;
let newRulePloadDB5;
const duplicates = [];
let type1 = 0;
let type3 = 0;
let type4 = 0;
let storedvalue;
let counthourly = 0;
let countupdates = 0;
let countcreate = 0;
let isFetching = false;
let isFetchingHourly = false;
let isFetchingType4 = false;
let isFetchingType3 = false;
let currentRuleId = null;
let currentAutomationId = null;
let globalAgents = [];
let isFetchingRules = false;
const automationTypeIdOneRecords = [];
const automationTypeIdfourRecords = [];
const automationTypeIdthreeRecords = [];
const duplicatesType1 = [];
const duplicatesType3 = [];
const duplicatesType4 = [];
async function setupTabListener(tabContainerId, sharedKey) {
console.log(" setup tab listener function called ");
while (typeof client === "undefined") {
console.warn("⚠️ Waiting for 'client' to be ready...");
await new Promise((resolve) => setTimeout(resolve, 500));
}
let fwTabs = document.querySelector(`#${tabContainerId} fw-tabs`);
if (!fwTabs) {
console.error(`❌ ERROR: <fw-tabs> NOT found inside #${tabContainerId}!`);
return;
}
console.log(`✅ Found <fw-tabs> inside #${tabContainerId}. Attaching event listener...`);
let savedTab;
try {
let storedValue = await client.db.get("TabDB");
savedTab = storedValue?.[sharedKey];
if (!savedTab) {
savedTab = "Ticket Creation";
storedValue = storedValue || {};
storedValue[sharedKey] = savedTab;
await client.db.set("TabDB", storedValue);
console.log(`✅ No previous tab found. Setting default tab: ${savedTab}`);
} else {
console.log(`🔍 Retrieved active tab from DB:`, savedTab);
}
} catch (error) {
if (error.status === 404) {
console.warn(`⚠️ No previous tab found in DB. Using default.`);
savedTab = "Ticket Creation";
let defaultData = { [sharedKey]: savedTab };
await client.db.set("TabDB", defaultData);
console.log(`✅ Default tab stored: ${savedTab}`);
} else {
console.error(`❌ Error retrieving tab from DB:`, error);
}
}
if (savedTab) {
let tabElement = fwTabs.querySelector(`fw-tab[panel='${savedTab}']`);
let pageContainer = document.getElementById(tabContainerId);
if (tabElement) {
if (pageContainer.style.display !== "none") {
console.log(`✅ Restoring tab in visible page: #${tabContainerId}:`, savedTab);
tabElement.click();
} else {
console.warn(`⚠️ Page #${tabContainerId} hidden. Waiting to restore tab:`, savedTab);
const observer = new MutationObserver((mutationsList, observer) => {
for (let mutation of mutationsList) {
if (mutation.attributeName === "style" && pageContainer.style.display !== "none") {
console.log(`✅ Page #${tabContainerId} is now visible. Restoring tab:`, savedTab);
tabElement.click();
observer.disconnect();
}
}
});
observer.observe(pageContainer, { attributes: true });
}
} else {
console.warn(`⚠️ Saved tab not found in DOM inside #${tabContainerId}:`, savedTab);
}
}
// Attach event listener for tab changes
fwTabs.addEventListener("fwChange", async (event) => {
let tabIndex = event.detail.tabIndex;
let tabs = fwTabs.querySelectorAll("fw-tab");
if (tabs[tabIndex]) {
let activeTab = tabs[tabIndex].getAttribute("panel");
console.log(`✅ Active tab detected: ${activeTab}. Storing in DB.`);
try {
let storedValue = (await client.db.get("TabDB")) || {};
storedValue[sharedKey] = activeTab;
await client.db.set("TabDB", storedValue);
console.log(`💾 Tab stored in DB (shared):`, activeTab);
} catch (error) {
console.error(`❌ Error storing active tab in DB:`, error);
}
} else {
console.warn(`⚠️ No active tab found at index ${tabIndex} inside #${tabContainerId}.`);
}
});
}
document.addEventListener("DOMContentLoaded", async () => {
console.log("📌 Page Loaded! Restoring last visited tab...");
await setupTabListener("Automation-page", "LastVisitedTab");
});
document.addEventListener("DOMContentLoaded", function () {
let progressBar = document.getElementById("progress-container");
if (progressBar) {
// Set initial styles for fast animation
progressBar.style.transition = "width 0.2s linear, opacity 0.3s"; // Faster transition
progressBar.style.width = "0%";
progressBar.style.height = "3px";
// progressBar.style.backgroundColor = "#007bff";
progressBar.style.opacity = "0";
progressBar.start = function () {
progressBar.style.width = "70%"; // Moves faster initially
progressBar.style.opacity = "1";
};
progressBar.done = function () {
progressBar.style.width = "100%"; // Moves to near completion quickly
setTimeout(() => {
progressBar.style.width = "0%"; // Resets quickly
progressBar.style.opacity = "0";
}, 1000); // Reduced reset time
};
} else {
console.error("❌ Progress bar element not found!");
}
});
function createLoadingBanner(targetElementId) {
console.log("main banner function called");
// Check if the banner already exists to avoid duplicates
if (document.getElementById("loadingBanner")) return;
// Create the banner div
let banner = document.createElement("div");
banner.id = "loadingBanner";
banner.className = "loading-banner";
banner.innerHTML = `⚠️ The system is still processing additional data. Please wait...
<span class="spinner"></span>`;
// Force the browser to recognize the new element and its styles
setTimeout(() => {
document.querySelector('.spinner').style.animation = 'spin 1s linear infinite';
}, 10);
// Style dynamically (optional, you can also use CSS)
banner.style.position = "fixed";
banner.style.top = "20px";
banner.style.right = "700px";
banner.style.backgroundColor =" #fff3cd";
banner.style.padding = "12px";
banner.style.borderRadius = "5px";
banner.style.boxShadow = "0px 2px 5px rgba(0,0,0,0.2)";
banner.style.display = "none"; // Initially hidden
banner.style.color =" #856404";
// Insert the banner in the desired location
let targetElement = document.getElementById(targetElementId);
if (targetElement) {
targetElement.appendChild(banner);
} else {
document.body.appendChild(banner); // Default to body if no target found
}
}
function showLoadingBanner() {
console.log("showbanner called")
let banner = document.getElementById("loadingBanner");
if (banner) banner.style.display = "block";
}
function hideLoadingBanner() {
console.log("hidebanner called")
let banner = document.getElementById("loadingBanner");
if (banner) banner.style.display = "none";
}
function removeLoadingBanner() {
console.log("remove banner called")
let banner = document.getElementById("loadingBanner");
if (banner) {
banner.remove(); // Removes the element from the DOM permanently
console.log("✅ Loading banner removed permanently.");
}
}
// Initialize the app
init();
async function init() {
client = await app.initialized();
// Event Listener: App Activated
client.events.on("app.activated", async function () {
console.log("🟢 App activated! Calling RoleAccess first...");
await RoleAccess();
});
}
// Function to check role access
async function RoleAccess() {
try {
let iparamSelectedCategory = await client.iparams.get();
console.log("🔍 iparamSelectedCategory:", iparamSelectedCategory);
let selectedCategoryArray = iparamSelectedCategory.accessvalue || [];
let fdFields = iparamSelectedCategory.fd_fields; // 'group', 'role', or 'agent'
if (!Array.isArray(selectedCategoryArray)) {
console.error("❌ accessvalue is not an array", selectedCategoryArray);
return;
}
selectedCategoryArray = selectedCategoryArray.map(value => value.toString().trim());
console.log("✅ Formatted selectedCategoryArray:", selectedCategoryArray);
const contactData = await client.data.get("loggedInUser");
console.log("👤 Logged-in user data:", contactData);
let loggedInAgentIdStr = contactData.loggedInUser.id.toString().trim();
let loggedInGroupsStr = (contactData.loggedInUser.group_ids || []).map(g => g.toString().trim());
let loggedInRolesStr = (contactData.loggedInUser.role_ids || []).map(r => r.toString().trim());
console.log("🔹 loggedInAgentIdStr:", loggedInAgentIdStr);
console.log("🔹 loggedInGroupsStr:", loggedInGroupsStr);
console.log("🔹 loggedInRolesStr:", loggedInRolesStr);
console.log("🔹 fdFields:", fdFields);
let hasAccess = false;
if (fdFields === "agent") {
console.log("🔍 Checking agent access...");
hasAccess = selectedCategoryArray.includes(loggedInAgentIdStr);
} else if (fdFields === "role") {
console.log("🔍 Checking role access...");
hasAccess = loggedInRolesStr.some(role => selectedCategoryArray.includes(role));
} else if (fdFields === "group") {
console.log("🔍 Checking group access...");
hasAccess = loggedInGroupsStr.some(group => selectedCategoryArray.includes(group));
} else {
console.error("❌ Unknown fd_fields value:", fdFields);
}
console.log("🔹 Final hasAccess:", hasAccess);
if (hasAccess) {
console.log("✅ Access granted! Initializing database...");
document.getElementById("loader").style.display = "none";
document.getElementById("Automation-page").style.display = "block";
document.getElementById("no_user").style.display = "none";
await checkAndSetButtonState();
await initializeDatabase();
} else {
console.log(" Access denied! Hiding automation page...");
document.getElementById("Automation-page").style.display = "none";
document.getElementById("no_user").style.display = "block";
}
} catch (error) {
console.error(" Error in RoleAccess function:", error);
}
}
let intervalId;
async function checkAndSetButtonState() {
try {
// Fetch stored value
let storedvalue1 = await client.db.get("RulesDB");
console.log("Initial stored value from RulesDB:", storedvalue1.stored);
// Determine button state
const isButtonEnabled = !!storedvalue1.stored;
// Get button element
const button = document.querySelector("fw-button");
// Show loading banner if not already displayed
if (!isButtonEnabled) {
createLoadingBanner("banner");
showLoadingBanner();
}
// Set button state
if (button) {
button.disabled = !isButtonEnabled;
console.log(`🔘 Button is now ${isButtonEnabled ? "ENABLED" : "DISABLED"}`);
}
// If stored value is true, stop checking and remove the banner
if (isButtonEnabled) {
hideLoadingBanner();
removeLoadingBanner();
console.log("✅ Loading banner removed.");
clearInterval(intervalId); // Stop checking
return;
}
// Set interval only once
if (!intervalId) {
intervalId = setInterval(checkAndSetButtonState, 60000);
}
} catch (error) {
if (error.status === 404) {
console.warn("⚠️ RulesDB not found, assuming first-time install.");
const button = document.querySelector("fw-button");
if (button) {
button.disabled = true;
}
} else {
console.error("❌ Error retrieving stored value from RulesDB:", error);
}
}
}
async function initializeDatabase() {
try {
console.log("Initializing database...");
const entity = await client.db.entity({ version: "v1" });
console.log("Entity Initialized:", entity);
// Assign global variable
newRulePloadDB5 = entity.get("newRulePloadDB5");
console.log("📌 Entity Reference:", newRulePloadDB5);
// Fetch schema
const data1 = await newRulePloadDB5.schema();
console.log("📄 Schema Data:", data1);
} catch (error) {
console.error("❌ Error initializing database:", error);
}
}
async function recentdata() {
console.log("recentdata called");
console.log(` Setting up Workflow-Automation-page...`);
await setupTabListener("Workflow-Automation-page", "LastVisitedTab");
await GetAgents().then(agents => {
console.log(" Agents fetching completed. Final List:", agents);
globalAgents = agents;
console.log(" Checking globalAgents before function call:", globalAgents);
});
document.getElementById("Automation-page").style.display = "none";
document.getElementById("button").style.display = "none";
let workflowPage = document.getElementById("Workflow-Automation-page");
if (workflowPage) {
workflowPage.style.visibility = "visible"; // Make it visible
workflowPage.style.opacity = "1"; // Fade in smoothly
} else {
console.error("❌ Still not found!");
}
// await fetchAndUseRules()
}
async function GetAgents(page = 1, agentsArray = []) {
console.log(`Fetching agents for page ${page}`);
try {
const GetAgentsResponse = await client.request.invokeTemplate('recentagents', {
context: { page: page }
});
const responses = GetAgentsResponse.response;
const agentData = JSON.parse(responses);
if (agentData.length === 0) {
console.log("✅ No more agents to fetch. Total agents:", agentsArray.length);
return agentsArray; // Stop recursion when no more agents
}
agentsArray.push(...agentData);
// Fetch the next page
return await GetAgents(page + 1, agentsArray);
} catch (error) {
console.error("❌ Error fetching agents:", error);
if (error.headers && error.headers.status.includes("401")) {
document.getElementById("Automation-page").style.display = "none";
document.getElementById("Workflow-Automation-page").style.display = "none";
document.getElementById("no_user2").style.display = "block";
}
return agentsArray; // Return fetched data before the error
}
}
async function fetchAndUseRules() {
if (isFetchingRules|| countcreate > 0) return; // Prevent duplicate calls if already fetching
isFetchingRules = true; // Set flag before execution
showLoader(); // Show loader before fetching data
try {
const allRules = await listrules(); // Fetch data
console.log("Ticket Creation Rules:", allRules);
allRules.forEach(rule => {
if (rule.active) automationTypeIdOneRecords.push(rule);
});
console.log("automationTypeIdOneRecords", automationTypeIdOneRecords);
findDuplicatesWithinType(automationTypeIdOneRecords, duplicatesType1);
console.log("Duplicate Records for Automation Type ID 1:", duplicatesType1);
let automation_type_id = 1;
displayGroupedRules4(duplicatesType1, "Ticketcreation1", automation_type_id, globalAgents);
countcreate ++;
} catch (error) {
console.error("❌ Error fetching rules:", error);
if (error.status === 401) {
document.getElementById("Automation-page").style.display = "none";
document.getElementById("Workflow-Automation-page").style.display = "none";
document.getElementById("no_user2").style.display = "block";
} else if (error.status === 429) {
document.getElementById("Automation-page").style.display = "none";
document.getElementById("Workflow-Automation-page").style.display = "none";
document.getElementById("no_user1").style.display = "block";
}
} finally {
hideLoader(); // Hide loader after execution
isFetchingRules = false; // ✅ Reset flag after completion
}
}
async function fetchupdaterules() {
if (isFetching || countupdates > 0) return; // Stop if already fetching or already loaded
isFetching = true; // Set flag to true before execution starts
console.log("Fetching rules...");
showLoader();
try {
const updateRules = await listupdaterules();
console.log("Ticket updates Rules:", updateRules);
updateRules.forEach(rule => {
if (rule.active) automationTypeIdfourRecords.push(rule);
});
console.log("automationTypeIdfourRecords", automationTypeIdfourRecords);
findDuplicatesWithinType(automationTypeIdfourRecords, duplicatesType4);
console.log("Duplicate Records for Automation Type ID 4:", duplicatesType4);
processAndDisplayDuplicates(duplicatesType4, "TicketUpdates1",globalAgents);
countupdates++;
} catch (error) {
console.error("Error fetching rules:", error);
if (error.status === 401) {
document.getElementById("Automation-page").style.display = "none";
document.getElementById("Workflow-Automation-page").style.display = "none";
document.getElementById("no_user2").style.display = "block";
}
else if(error.status === 429)
{
document.getElementById("Automation-page").style.display = "none";
document.getElementById("Workflow-Automation-page").style.display = "none";
document.getElementById("no_user1").style.display = "block";
}
} finally {
hideLoader();
isFetching = false;
}
}
async function fetchHourlyrules() {
if (isFetchingHourly || counthourly > 0) return; // Stop if already fetching or loaded before
isFetchingHourly = true; // Set flag to true before execution starts
console.log("hourlycount at start", counthourly);
showLoader();
try {
const hourlyRules = await listhourlyrules();
console.log("Hourly Rules:", hourlyRules);
hourlyRules.forEach(rule => {
if (rule.active) automationTypeIdthreeRecords.push(rule);
});
console.log("automationTypeIdthreeRecords", automationTypeIdthreeRecords);
findDuplicatesWithinType(automationTypeIdthreeRecords, duplicatesType3);
console.log("Duplicate Records for Automation Type ID 3:", duplicatesType3);
let automation_type_id = 3;
displayGroupedRules4(duplicatesType3, "HourlyTriggers1", automation_type_id,globalAgents);
counthourly++; // ✅ Increment count to ensure it runs only once
} catch (error) {
console.error("Error fetching hourly rules:", error);
if (error.status === 401) {
document.getElementById("Automation-page").style.display = "none";
document.getElementById("Workflow-Automation-page").style.display = "none";
document.getElementById("no_user2").style.display = "block";
}
else if(error.status === 429)
{
document.getElementById("Automation-page").style.display = "none";
document.getElementById("Workflow-Automation-page").style.display = "none";
document.getElementById("no_user1").style.display = "block";
}
} finally {
hideLoader();
isFetchingHourly = false; // ✅ Reset flag after execution completes
}
}
async function listrules(page = 1, rulesArray = []) {
console.log(`Fetching rules for page ${page}`);
try {
const rulesResponse = await client.request.invokeTemplate('listrules', {
context: {
page: page
}
});
const responses = rulesResponse.response;
const rulesData = JSON.parse(responses);
if (rulesData.length === 0) {
console.log("✅ No more rules to fetch. Total rules:", rulesArray.length);
return rulesArray; // Stop recursion when no more rules
}
rulesArray.push(...rulesData);
// Fetch the next page
return await listrules(page + 1, rulesArray);
} catch (error) {
console.error("❌ Error fetching rules:", error);
if (error.headers && error.headers.status.includes("401")) {
document.getElementById("Automation-page").style.display = "none";
document.getElementById("Workflow-Automation-page").style.display = "none";
document.getElementById("no_user2").style.display = "block";
// let container = document.getElementById("Ticketcreation1");
// if (container) {
// container.innerHTML = `
// <div style="
// display: flex;
// justify-content: center;
// align-items: center;
// height: 100vh;
// width: 100%;
// font-size: 24px;
// font-weight: bold;
// color: #333;
// margin-left: 400px;
// text-align: center;
// ">
// ⚠️ Access Denied: The API key used has expired
// </div>`;
// }
// return;
}
else if (error.status === 429 || (error.headers && error.headers.status && error.headers.status.includes("429"))) {
document.getElementById("Automation-page").style.display = "none";
document.getElementById("Workflow-Automation-page").style.display = "none";
document.getElementById("no_user1").style.display = "block";
}
return rulesArray; // Return whatever data was fetched before the error
}
}
async function listupdaterules(page = 1, rulesArray = []) {
console.log(`Fetching rules for page ${page}`);
try {
const rulesResponse = await client.request.invokeTemplate('listupdaterules', {
context: {
page: page
}
});
const responses = rulesResponse.response;
const rulesData = JSON.parse(responses);
if (rulesData.length === 0) {
console.log("✅ No more rules to fetch. Total rules:", rulesArray.length);
return rulesArray; // Stop recursion when no more rules
}
rulesArray.push(...rulesData);
// Fetch the next page
return await listupdaterules(page + 1, rulesArray);
} catch (error) {
console.error("❌ Error fetching rules:", error);
if (error.headers && error.headers.status.includes("401")) {
document.getElementById("Automation-page").style.display = "none";
document.getElementById("Workflow-Automation-page").style.display = "none";
document.getElementById("no_user2").style.display = "block";
// let updateContainer = document.getElementById("TicketUpdates1");
// if (updateContainer) {
// updateContainer.innerHTML = ""; // Clear the container
// updateContainer.innerHTML = `
// <div style="
// display: flex;
// justify-content: center;
// align-items: center;
// height: 100vh;
// width: 100%;
// font-size: 24px;
// font-weight: bold;
// color: #333;
// margin-left: 400px;
// text-align: center;
// ">
// ⚠️ Access Denied: The API key used has expired
// </div>`;
// }
// return;
}
else if (error.status === 429 || (error.headers && error.headers.status && error.headers.status.includes("429"))) {
document.getElementById("Automation-page").style.display = "none";
document.getElementById("Workflow-Automation-page").style.display = "none";
document.getElementById("no_user1").style.display = "block";
}
return rulesArray; // Return whatever data was fetched before the error
}
}
async function listhourlyrules(page = 1, rulesArray = []) {
console.log(`Fetching rules for page ${page}`);
try {
const rulesResponse = await client.request.invokeTemplate('listhourlyrules', {
context: {
page: page
}
});
const responses = rulesResponse.response;
const rulesData = JSON.parse(responses);
if (rulesData.length === 0) {
console.log("✅ No more rules to fetch. Total rules:", rulesArray.length);
return rulesArray; // Stop recursion when no more rules
}
rulesArray.push(...rulesData);
// Fetch the next page
return await listhourlyrules(page + 1, rulesArray);
} catch (error) {
console.error("❌ Error fetching rules:", error);
if (error.headers && error.headers.status.includes("401")) {
document.getElementById("Automation-page").style.display = "none";
document.getElementById("Workflow-Automation-page").style.display = "none";
document.getElementById("no_user2").style.display = "block";
}
else if (error.status === 429 || (error.headers && error.headers.status && error.headers.status.includes("429"))) {
document.getElementById("Automation-page").style.display = "none";
document.getElementById("Workflow-Automation-page").style.display = "none";
document.getElementById("no_user1").style.display = "block";
}
return rulesArray; // Return whatever data was fetched before the error
}
}
function deepEqual(obj1, obj2) {
if (obj1 === obj2) return true;
if (typeof obj1 === 'string' && typeof obj2 === 'string') {
return normalizeText(stripHTML4(obj1)) === normalizeText(stripHTML4(obj2));
}
if (typeof obj1 !== 'object' || typeof obj2 !== 'object' || obj1 === null || obj2 === null) {
return false;
}
const keys1 = Object.keys(obj1).sort(); // Sort keys to prevent order mismatch
const keys2 = Object.keys(obj2).sort();
if (keys1.length !== keys2.length) return false;
for (const key of keys1) {
let val1 = obj1[key];
let val2 = obj2[key];
if (typeof val1 === 'string' && typeof val2 === 'string') {
val1 = normalizeText(stripHTML4(val1));
val2 = normalizeText(stripHTML4(val2));
}
// Sort arrays before comparing (for condition sets)
if (Array.isArray(val1) && Array.isArray(val2)) {
val1 = val1.map(item => (typeof item === 'string' ? normalizeText(stripHTML4(item)) : item))
.sort((a, b) => JSON.stringify(a).localeCompare(JSON.stringify(b)));
val2 = val2.map(item => (typeof item === 'string' ? normalizeText(stripHTML4(item)) : item))
.sort((a, b) => JSON.stringify(a).localeCompare(JSON.stringify(b)));
}
if (!keys2.includes(key) || !deepEqual(val1, val2)) {
// console.log(`🚨 Mismatch found at key: ${key}`);
return false;
}
}
return true;
}
function normalizeText(text) {
if (typeof text !== 'string') {
return ''; // Return an empty string if not a valid string
}
return text.replace(/\s+/g, ' ').trim().toLowerCase();
}
// ✅ Remove HTML tags
function stripHTML4(htmlString) {
return htmlString.replace(/<\/?[^>]+(>|$)/g, "").trim();
}
// // Helper function to remove <img> tags
// function stripImages(htmlString) {
// return htmlString.replace(/<img[^>]*>/g, '').trim();
// }
// Function to find duplicate rules for ticket creation and hourly triggers
function findDuplicatesWithinType(records, duplicatesArray) {
const seenRecords = [];
records.forEach((rule, index) => {
const { summary, actions, conditions } = rule;
if (summary && actions && conditions) {
console.log(`\n🔍 Checking Rule [${index + 1}]: ${rule.name}`);
// 🔄 **Sort arrays in summary, actions, and conditions before comparison**
const normalizedSummary = sortObjectValues(summary);
const normalizedActions = sortObjectValues(actions);
const normalizedConditions = sortObjectValues(conditions);
const duplicate = seenRecords.find((seen) => {
return (
deepEqual(sortObjectValues(seen.summary), normalizedSummary) &&
deepEqual(sortObjectValues(seen.conditions), normalizedConditions) &&
deepEqual(sortObjectValues(seen.actions), normalizedActions)
);
});
if (duplicate) {
console.log(`✅ Duplicate Found: ${rule.name}`);
duplicatesArray.push(rule);
if (!duplicatesArray.includes(duplicate.rule)) {
duplicatesArray.push(duplicate.rule);
}
} else {
seenRecords.push({ summary: normalizedSummary, actions: normalizedActions, conditions: normalizedConditions, rule });
}
}
});
}
function sortObjectValues(obj) {
if (Array.isArray(obj)) {
return obj
.map(item => (typeof item === 'object' && item !== null ? sortObjectValues(item) : normalizeText(item)))
.sort((a, b) => JSON.stringify(a).localeCompare(JSON.stringify(b)));
} else if (typeof obj === 'object' && obj !== null) {
return Object.fromEntries(
Object.entries(obj)
.map(([key, value]) => [key, sortObjectValues(value)])
.sort(([keyA], [keyB]) => keyA.localeCompare(keyB))
);
}
return normalizeText(obj);
}
function combineConditionsAndActions4(data) {
const processedConditionSet1 = (data.condition_set_1 || []).map(stripHTML);
const processedConditionSet2 = (data.condition_set_2 || []).map(stripHTML);
// ✅ Keep the original order for display
const originalConditions = [
...processedConditionSet1,
data.operator ? ` ${data.operator} ` : "",
...processedConditionSet2,
].join(" ");
let originalActionText = (data.actions || []).length
? data.actions.map(stripHTML4).join(" ")
: "";
const originalContent = `${originalConditions} ${originalActionText}`.trim();
// ✅ Create sorted copies for grouping/comparison (Case-Insensitive)
const sortedConditionSet1 = [...processedConditionSet1].map(text => text.toLowerCase()).sort();
const sortedConditionSet2 = [...processedConditionSet2].map(text => text.toLowerCase()).sort();
const sortedConditions = [
...sortedConditionSet1,
data.operator ? ` ${data.operator.toLowerCase()} ` : "",
...sortedConditionSet2,
].join(" ");
let sortedActionText = (data.actions || []).length
? [...data.actions.map(stripHTML4).map(text => text.toLowerCase())].sort().join(" ")
: "";
const sortedContent = `${sortedConditions} ${sortedActionText}`.trim();
return { originalContent, sortedContent };
}
function normalizeText1(text) {
if (typeof text !== "string") return text;
return text
.replace(/<[^>]*>/g, "") // Remove HTML tags
.replace(/\s+/g, " ") // Remove extra spaces
.trim();
}
let currentPage4 = 1;
const itemsPerPage4 = 5;
function displayGroupedRules4(records, containerId, automation_type_id,globalAgents) {
console.log("automationtypeid log at start of displaygroups",automation_type_id )
const container = document.getElementById(containerId);
if (!container) {
console.error(`Container with ID "${containerId}" not found.`);
return;
}
container.innerHTML = ""; // Clear container
if (records.length === 0) {
container.innerHTML = `
<div style="
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
width: 100%;
font-size: 24px;
font-weight: bold;
color: #333;
margin-left: 400px;
text-align: center;
">
No duplicate rules found.
</div>`;
return;
}
const groupedRules = new Map();
records.forEach((record) => {
const rule = record.parsedPayload || record.rule || record;
if (!rule || !rule.summary) return;
const { name, summary, position, updated_at, last_updated_by, affected_tickets_count, id } = rule;
if (summary.conditions) {
const actions = summary.actions || [];
// ✅ Get both sorted and original content
const { originalContent, sortedContent } = combineConditionsAndActions4({
condition_set_1: summary.conditions.condition_set_1,
condition_set_2: summary.conditions.condition_set_2,
operator: summary.conditions.operator,
actions: actions,
});
// ✅ Use sortedContent for grouping
if (!groupedRules.has(sortedContent)) {
groupedRules.set(sortedContent, []);
}
// ✅ Store both sortedContent (for grouping) and originalContent (for display)
groupedRules.get(sortedContent).push({
name,
position,
combinedContent: originalContent, // ✅ Use originalContent for display
conditions: summary.conditions,
actions: actions,
updated_at,
last_updated_by,
affected_tickets_count,
id,automation_type_id
});
}
});
const groupedRulesArray = Array.from(groupedRules.values());
const totalgroup = Math.ceil(groupedRulesArray.length );
console.log(totalgroup,"*********************")
const totalPages4 = Math.ceil(groupedRulesArray.length / itemsPerPage4);
currentPage4 = Math.max(1, Math.min(currentPage4, totalPages4)); // Ensure valid page number
console.log("Total Pages:", totalPages4, "Current Page:", currentPage4);
const startIdx = (currentPage4 - 1) * itemsPerPage4;
const paginatedRules = groupedRulesArray.slice(startIdx, startIdx + itemsPerPage4);
console.log("Displaying Records:", paginatedRules);
let arrayLength = paginatedRules.length;
console.log("Records Length:", arrayLength);
// Display the paginated grouped rules
paginatedRules.forEach((titles) => {
const rulesCount = titles.length;
// ✅ Skip the group if it contains only one rule
if (rulesCount === 1) {
console.log(`Skipping group with only 1 rule: ${titles[0].name}`);
return; // Stop further execution for this group
}
const groupContainer = document.createElement("div");
groupContainer.style.border = "1px solid #ccc";
groupContainer.style.padding = "16px";
groupContainer.style.margin = "16px";
groupContainer.style.borderRadius = "8px";
groupContainer.style.backgroundColor = "#f5f7f9";
groupContainer.style.width = "1200px";
titles.forEach(({ name, position, combinedContent, conditions, actions,updated_at,last_updated_by,affected_tickets_count,automation_type_id,id
}, index) => {
const card = document.createElement("div");
card.style.border = "1px solid #ccc";
card.style.padding = "16px";
card.style.margin = "8px 0"
card.style.fontFamily =
"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif";
card.style.borderRadius = "8px";
card.style.backgroundColor = index === 0 ? "#fff" : "#e5f2fd";
card.style.marginBottom = "10px";
card.style.paddingBottom = "0";
const cardHeader = document.createElement("div");
cardHeader.style.display = "flex";
cardHeader.style.justifyContent = "space-between";
cardHeader.style.alignItems = "center";
// Create a wrapper for the title
const cardTitle = document.createElement("h4");
cardTitle.style.margin = "0";
cardTitle.style.cursor = "pointer";
cardTitle.style.fontSize = "14px";
cardTitle.style.fontFamily = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif";
cardTitle.style.color = "#183247";
cardTitle.style.transition = "color 0.2s ease";
cardTitle.style.fontWeight = "600";
// Create the serial number (position)
if (position) {
const serialNumber = document.createElement("span");
serialNumber.textContent = position + ". ";
serialNumber.style.color = "#183247"; // Keep serial number color fixed
cardTitle.appendChild(serialNumber);
}
// Create the actual name (clickable part)
const titleText = document.createElement("span");
titleText.textContent = name;
titleText.style.color = "#183247";
titleText.style.transition = "color 0.2s ease";
// Add hover effect for only the name
titleText.addEventListener("mouseover", () => {
titleText.style.color = "#007bff"; // Change only name color on hover
});
titleText.addEventListener("mouseout", () => {
titleText.style.color = "#183247"; // Reset name color when not hovering
});
titleText.addEventListener("click", () => {
titleText.style.color = "#ff5733"; // Change title color on click
console.log("automation type id before popup",automation_type_id)
showPopupCard(name, { conditions: conditions, actions: actions },automation_type_id)
});
// Append name to title
cardTitle.appendChild(titleText);
// Append title and actions to the cardHeader
cardHeader.appendChild(cardTitle);
// Create a container for the horizontal line and the gap
const cardContainer = document.createElement("div");
// Style the container to have a background color in the gap
cardContainer.style.backgroundColor = "#f0f0f0"; // Set the background color for the gap (change to desired color)
cardContainer.style.paddingBottom = "20px";
cardContainer.style.marginLeft="-15px";
cardContainer.style.borderRadius = "4px";
cardContainer.style.width="102.7%";
// Create a horizontal line after the cardBody
const horizontalLine = document.createElement("div");
horizontalLine.style.height = "1px"; // Set the height to 1px for a thin line
horizontalLine.style.backgroundColor = "#ccc"; // Set the color of the horizontal line
horizontalLine.style.marginTop = "16px"; // Add space above the line (adjust as needed)
horizontalLine.style.width = "100%"; // Ensure the line stretches the full width of the container
horizontalLine.style.marginLeft="-3px";
function truncateContent(content, maxLength, lines) {
// Truncate the content to the desired number of characters
let truncated = content;
// Adjust for the desired line count and maximum length
if (content.length > maxLength) {
truncated = content.slice(0, maxLength) + "...";
}
// Break content into lines manually for multi-line truncation
const words = truncated.split(" ");
const result = [];
let line = "";
let currentLine = 1;
for (let i = 0; i < words.length; i++) {
if (line.length + words[i].length + 1 <= maxLength / lines) {
line += (line ? " " : "") + words[i];
} else {
result.push(line);
line = words[i];
currentLine++;
if (currentLine > lines) break; // Stop adding more lines if max lines are reached
}
}
if (currentLine <= lines && line) {
result.push(line);
}
return result.join(" ") + (currentLine > lines ? "..." : "");
}
function calculateLastModified(updated_at) {
const updatedDate = new Date(updated_at);
const currentDate = new Date();
const diffInMilliseconds = currentDate - updatedDate;
const seconds = Math.floor(diffInMilliseconds / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
const months = Math.floor(days / 30); // Approximate months
const years = Math.floor(days / 365); // Approximate years
if (years > 0) {
return years === 1 ? "a year ago" : `${years} years ago`;
} else if (months > 0) {
return months === 1 ? "a month ago" : `${months} months ago`;
} else if (days > 0) {
return `${days} day${days > 1 ? "s" : ""} ago`;
} else if (hours > 0) {
return `${hours} hour${hours > 1 ? "s" : ""} ago`;
} else if (minutes > 0) {
return `${minutes} minute${minutes > 1 ? "s" : ""} ago`;
} else {
return "Just now";
}
}
// console.log("updated at",calculateLastModified(updated_at));
// Create a row for "Last Modified"
const lastModifiedRow = document.createElement("div");
lastModifiedRow.style.display = "grid";
lastModifiedRow.style.gridTemplateColumns = "150px 150px 2px 150px 150px 2px 150px 150px"; // Consistent width for each section
lastModifiedRow.style.alignItems = "center";
lastModifiedRow.style.marginTop = "10px";
lastModifiedRow.style.fontSize = "12px";
lastModifiedRow.style.gap = "20px";
lastModifiedRow.style.width = "100%"; // Ensures full width alignment
const lastModifiedLabel = document.createElement("span");
lastModifiedLabel.textContent = "Last Modified :";
lastModifiedLabel.style.color = "#183247";
lastModifiedLabel.style.fontSize = "12px";
lastModifiedLabel.style.display = "inline-flex";
lastModifiedLabel.style.fontFamily =" -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif"
lastModifiedLabel.style.marginLeft = "40px"
const lastModifiedValue = document.createElement("span");
const lastModifiedText = calculateLastModified(updated_at);
lastModifiedValue.textContent = lastModifiedText;
lastModifiedValue.style.color = "#183247";
lastModifiedValue.style.fontWeight = "600";
lastModifiedValue.style.display = "inline-flex";
lastModifiedValue.style.fontSize = "12px";
lastModifiedValue.style.marginLeft = "-50px"
lastModifiedValue.style.justifySelf = "start";
lastModifiedValue.style.fontFamily =" -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif"
const verticalLine = document.createElement("div");
verticalLine.style.height = "20px";
verticalLine.style.borderLeft = "2px solid #ccc";
verticalLine.style.alignSelf = "stretch";
lastModifiedRow.appendChild(lastModifiedLabel);
lastModifiedRow.appendChild(lastModifiedValue);
lastModifiedRow.appendChild(verticalLine);
const agentsid = last_updated_by;
const matchingAgent = globalAgents.find(agent => String(agent.id) === String(agentsid));
if (matchingAgent) {
console.log(`✅ Matching agent found:`, matchingAgent);
} else {
console.log(`❌ No agent found with id: ${agentsid}`);
}
const agentNameLabel = document.createElement("span");
agentNameLabel.textContent = "By :";
agentNameLabel.style.fontSize = "12px";
agentNameLabel.style.color = "#183247";
agentNameLabel.style.whiteSpace = "nowrap";
agentNameLabel.style.marginLeft="149px"
agentNameLabel.style.fontFamily =" -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif"
const agentNameValue = document.createElement("span");
if (matchingAgent) {
agentNameValue.textContent = matchingAgent.contact.name|| "Unknown Agent";
} else {
agentNameValue.textContent = "Unknown Agent";
}
agentNameValue.style.color = "#183247";
agentNameValue.style.fontWeight = "600";
agentNameValue.style.whiteSpace = "nowrap";
agentNameValue.style.fontFamily =" -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif"
const verticalLine2 = document.createElement("div");
verticalLine2.style.height = "20px";
verticalLine2.style.borderLeft = "2px solid #ccc";
verticalLine2.style.alignSelf = "stretch";
verticalLine2.style.marginLeft = "100px"; // Increase for more right shift
lastModifiedRow.appendChild(agentNameLabel);
lastModifiedRow.appendChild(agentNameValue);
lastModifiedRow.appendChild(verticalLine2);
const affectedTicketsLabel = document.createElement("span");
affectedTicketsLabel.textContent = "Impacted tickets (Last 7 days) : ";
affectedTicketsLabel.style.fontSize = "12px";
affectedTicketsLabel.style.color = "#183247";
affectedTicketsLabel.style.marginLeft="140px";
affectedTicketsLabel.style.whiteSpace = "nowrap";
affectedTicketsLabel.style.fontFamily =" -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif"
const affectedTicketsValue = document.createElement("span");
affectedTicketsValue.textContent = affected_tickets_count === 0 ? "--" : affected_tickets_count;
affectedTicketsValue.style.color = "#183247";
affectedTicketsValue.style.fontWeight = "600";
affectedTicketsValue.style.marginLeft ="134px"
affectedTicketsValue.style.whiteSpace = "nowrap";
affectedTicketsValue.style.fontFamily =" -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif"
lastModifiedRow.appendChild(affectedTicketsLabel);
lastModifiedRow.appendChild(affectedTicketsValue);
const cardBody = document.createElement("div"); // Create a container for card content and actions
cardBody.style.display = "flex"; // Flexbox to align items horizontally
cardBody.style.justifyContent = "space-between"; // Ensure there's space between content and actions
cardBody.style.alignItems = "flex-start"; // Align items to the top (optional, depending on your needs)
const truncatedContent = truncateContent(combinedContent, 200, 2);
const cardContent = document.createElement("pre");
cardContent.textContent = truncatedContent;
// Style the card content
cardContent.style.marginTop = "8px";
cardContent.style.padding = "8px";
cardContent.style.color="#183247";
cardContent.style.fontweight="600";
cardContent.style.fontFamily= "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif";
cardContent.style.whiteSpace = "pre-wrap"; // Ensure text wraps
cardContent.style.overflow = "hidden"; // Hide overflow content
cardContent.style.textOverflow = "ellipsis"; // Add ellipsis for overflow
cardContent.style.maxWidth = "75%"; // Limit the card width to half the container's width
cardContent.style.fontSize="12px";
cardContent.style.marginLeft="15px";
// Create the container for card actions
const cardActionsContainer = document.createElement("div");
cardActionsContainer.style.display = "flex"; // Display actions horizontally
cardActionsContainer.style.justifyContent = "flex-end"; // Align to the right
cardActionsContainer.style.marginTop = "10px"; // Add some spacing above the actions
cardActionsContainer.style.gap = "8px"; // Set space between the toggle and the delete icon
// Add fw-toggle
// const fwToggle = document.createElement("fw-toggle");
// fwToggle.setAttribute("size", "medium");
// fwToggle.setAttribute("checked", "");
// Add fw-icon
const fwIcon = document.createElement("fw-icon");
fwIcon.setAttribute("name", "delete");
fwIcon.setAttribute("size", "18");
fwIcon.style.cursor = "pointer";
fwIcon.style.color = "red"; // Set the color to red
// Add a pointer cursor for interactivity
fwIcon.title = "Delete";
fwIcon.addEventListener("click", () => {
console.log("Delete icon clicked");
currentRuleId = id; // Store the rule ID globally
currentAutomationId = automation_type_id;
console.log("rule id:", currentRuleId);
console.log("automationid:", currentAutomationId);
showDeletePopup();
});
function showDeletePopup() {
document.getElementById("deleteConfirmationPopup").style.display = "flex";
}
function hideDeletePopup() {
document.getElementById("deleteConfirmationPopup").style.display = "none";
}
async function Fetchentity(automationTypeId, nextMarker = null, allRecords1 = []) {
try {
if (!newRulePloadDB5) {
console.error(" Entity is not initialized yet!");
showLoader();
setTimeout(() => {
location.reload();
}, 1000);
}
showLoader();
let queryObj = {
query: {
$and: [
{ automation_type_id: automationTypeId },
{ active: "true" }
]
}
};
if (nextMarker) {
console.log("🔄 Next marker found:", nextMarker);
queryObj.next = { marker: nextMarker };
}
console.log("📤 Fetching records with query:", JSON.stringify(queryObj, null, 2));
const response = await newRulePloadDB5.getAll(queryObj);
if (!response.records || !Array.isArray(response.records)) {
console.error("❌ Invalid response format:", response);
hideLoader();
return allRecords1;
}
console.log(`📥 Retrieved ${response.records.length} records`);
allRecords1 = allRecords1.concat(response.records);
const newNextMarker = response.links?.next?.marker || null;
if (newNextMarker) {
console.log(`🔄 More pages exist. Next marker: ${newNextMarker}`);
return Fetchentity(automationTypeId, newNextMarker, allRecords1);
} else {
console.log("✅ No more pages.");
console.log(`📌 Total Filtered Records: ${allRecords1.length}`);
hideLoader();
return allRecords1;
}
} catch (error) {
console.error("❌ Error fetching filtered records:", error);
hideLoader();
return [];
}
}
async function recenetconfirmDeletion() {
console.log(" Deleting rule with ID:", currentRuleId);
try {
// Start progress loader
let progressLoader = document.querySelector("#progress-container");
if (progressLoader && typeof progressLoader.start === "function") {
progressLoader.start();
}
let getdeleteruleResponse = await client.request.invokeTemplate("deleterule", {
context: {
automationid: currentAutomationId,
ruleid: currentRuleId,
},
});
console.log("getdeleteruleResponse", getdeleteruleResponse);
if (getdeleteruleResponse.status === 204) {
console.log("✅ Rule deleted successfully!");
// Show success toast
let valid = document.getElementById("type_toast");
valid.setAttribute("content", "Rule deleted successfully");
valid.setAttribute("type", "success");
valid.setAttribute("open", true);
// ✅ Remove the rule from the UI
// displayGroupedRules4(duplicatesType1, "Ticketcreation1", automation_type_id, globalAgents);
hideDeletePopup();
if (currentAutomationId === 1) {
const ruleIndex = duplicatesType1.findIndex(rule => rule.id === currentRuleId);
if (ruleIndex === -1) {
console.warn(`❌ Rule with ID ${currentRuleId} not found in duplicatesType1.`);
} else {
const ruleToDelete = duplicatesType1[ruleIndex];
try {
console.log("🗑️ Deleting rule with ID:", ruleToDelete.id);
// ✅ Optionally remove it from the array to update UI or logic
duplicatesType1.splice(ruleIndex, 1);
console.log("✅ Rule deleted and removed from duplicatesType1 array.",duplicatesType1);
displayGroupedRules4(duplicatesType1, "Ticketcreation1", automation_type_id, globalAgents);
let progressLoader = document.querySelector("#progress-container");
if (progressLoader && typeof progressLoader.start === "function") {
progressLoader.done();
}
} catch (error) {
console.error(`❌ Error deleting rule with ID ${ruleToDelete.id}:`, error);
}
}
if (entitytype1.length === 0) {
console.log(" entitytype1 is empty. Fetching records...");
entitytype1 = await Fetchentity(1);
console.log("entity fethed after clicking recent data",entitytype1);
const displayId = getDisplayIdByRuleId(entitytype1, currentRuleId);
console.log("Matching Display ID:", displayId);
if (!displayId) return; // Ensure rule ID is available
try {
console.log(" Deleting rule with ID:", displayId);
await newRulePloadDB5.delete(displayId);
} catch (error) {
console.warn(` Error deleting record with Display ID ${displayId}, but continuing...`);
}
}
const displayId = getDisplayIdByRuleId(entitytype1, currentRuleId);
console.log("Matching Display ID:", displayId);
if (!displayId) return; // Ensure rule ID is available
try {
console.log(" Deleting rule with ID:", displayId);
await newRulePloadDB5.delete(displayId);
} catch (error) {
console.warn(` Error deleting record with Display ID ${displayId}, but continuing...`);
}
}
else if (currentAutomationId === 3) {
const ruleIndex = duplicatesType3.findIndex(rule => rule.id === currentRuleId);
if (ruleIndex === -1) {
console.warn(`❌ Rule with ID ${currentRuleId} not found in duplicatesType3.`);
} else {
const ruleToDelete = duplicatesType3[ruleIndex];
try {
console.log("🗑️ Deleting rule with ID:", ruleToDelete.id);
// ✅ Optionally remove it from the array to update UI or logic
duplicatesType3.splice(ruleIndex, 1);
console.log("✅ Rule deleted and removed from duplicatesType3 array.",duplicatesType3);
displayGroupedRules4(duplicatesType3, "HourlyTriggers1", automation_type_id, globalAgents);
let progressLoader = document.querySelector("#progress-container");
if (progressLoader && typeof progressLoader.start === "function") {
progressLoader.done();
}
} catch (error) {
console.error(`❌ Error deleting rule with ID ${ruleToDelete.id}:`, error);
}}
if (entitytype3.length === 0) {
console.log(" entitytype3 is empty. Fetching records...");
entitytype3 = await Fetchentity(3);
console.log("entity fethed after clicking recent data",entitytype3);
const displayId = getDisplayIdByRuleId(entitytype3, currentRuleId);
console.log("Matching Display ID:", displayId);
if (!displayId) return;
try {
console.log(" Deleting rule with ID:", displayId);
await newRulePloadDB5.delete(displayId);
} catch (error) {
console.warn(` Error deleting record with Display ID ${displayId}, but continuing...`);
}
}
const displayId = getDisplayIdByRuleId(entitytype3, currentRuleId);
console.log("Matching Display ID:", displayId);
if (!displayId) return;
try {
console.log(" Deleting rule with ID:", displayId);
await newRulePloadDB5.delete(displayId);
} catch (error) {
console.warn(` Error deleting record with Display ID ${displayId}, but continuing...`);
}
}
}
} catch (error) {
console.error(" Error deleting rule:", error);
}
}
function getDisplayIdByRuleId(entityRecords, currentRuleId) {
console.log("Checking all records for Rule ID:", currentRuleId);
if (!Array.isArray(entityRecords) || entityRecords.length === 0) {
console.warn(" No records found in entity storage.");
return null;
}
console.log(" Sample Record Structure:", entityRecords.slice(0, 5));
console.log(" Available Keys in First Record:", Object.keys(entityRecords[0]));
// Find the record where rule_id matches currentRuleId
const matchedRecord = entityRecords.find(record =>
String(record?.data?.rule_id) === String(currentRuleId) // Ensure type conversion
);
console.log("Does Rule ID exist in records?", matchedRecord !== undefined);
return matchedRecord ? matchedRecord.display_id : null;
}
// Attach event listeners to the confirmation buttons (only once)
document.getElementById("confirmDeleteBtn").addEventListener("click", recenetconfirmDeletion);
document.getElementById("cancelDeleteBtn").addEventListener("click", hideDeletePopup);
// Append fw-toggle and fw-icon to cardActions
// cardActionsContainer.appendChild(fwToggle);
cardActionsContainer.appendChild(fwIcon);
card.appendChild(cardHeader);
cardBody.appendChild(cardContent);
cardBody.appendChild(cardActionsContainer);
card.appendChild(cardBody);
cardContainer.appendChild(horizontalLine);
// card.appendChild(horizontalLine);
cardContainer.appendChild(lastModifiedRow);
card.appendChild(cardContainer)
groupContainer.appendChild(card);
});
container.appendChild(groupContainer);
});
// Add pagination component
addFwPagination4(containerId,records,totalgroup,automation_type_id);
}
// Function to add pagination for displayGroupedRules4
function addFwPagination4(containerId, records, totalgroup, automation_type_id) {
console.log('Adding pagination to container:', containerId);
console.log("Automation Type ID at Page Change:", automation_type_id);
let container1 = document.getElementById(containerId);
if (!container1) {
console.warn(`Container with ID "${containerId}" not found.`);
return;
}
if (totalgroup <= itemsPerPage4) {
console.log("Total records are less than or equal to items per page, skipping pagination.");
return;
}
let existingPagination1 = container1.querySelector("#fw-pagination-4");
if (existingPagination1) {
existingPagination1.remove(); // Remove old pagination if it exists
}
const pagination1 = document.createElement("fw-pagination");
pagination1.id = "fw-pagination-4";
pagination1.setAttribute("total", totalgroup);
pagination1.setAttribute("per-page", itemsPerPage4);
pagination1.setAttribute("page", currentPage4);
console.log("Pagination Element:", pagination1);
const paginationWrapper1 = document.createElement("div");
paginationWrapper1.style.display = "flex";
paginationWrapper1.style.justifyContent = "flex-start";
paginationWrapper1.style.alignItems = "center";
paginationWrapper1.style.width = "100%";
paginationWrapper1.style.marginLeft = "70%";
paginationWrapper1.appendChild(pagination1);
container1.appendChild(paginationWrapper1);
pagination1.addEventListener("fwChange", (event) => {
console.log("fwChange Event Triggered", event);
currentPage4 = event.detail.page;
console.log("Updated Page:", currentPage4);
// Retrieve automation_type_id from localStorage if missing
let storedAutomationTypeId = localStorage.getItem("automation_type_id");
console.log("Retrieved automation_type_id from localStorage:", storedAutomationTypeId);
// Update the displayed rules for the current container, passing automation_type_id correctly
displayGroupedRules4(records, containerId, storedAutomationTypeId,globalAgents);
});
}
// function stripHTMLupdates(htmlString) {
// return htmlString.replace(/<\/?[^>]+(>|$)/g, "");
// }
// function combineConditionsAndActions(data) {
// const {
// performer = "",
// eventText = [],
// condition_set_1 = [],
// condition_set_2 = [],
// operator,
// actions = []
// } = data;
// const processedConditionSet1 = condition_set_1.map(stripHTML);
// const processedConditionSet2 = condition_set_2.map(stripHTML);
// const conditions = [
// ...processedConditionSet1,
// operator ? ` ${operator} ` : "",
// ...processedConditionSet2,
// ].join(" ");
// const actionText = actions.length
// ? actions.map(action => typeof action === 'string' ? stripHTML(action) : action).join(" ")
// : "";
// const eventTextContent = eventText.length
// ? eventText.map(event => typeof event === 'string' ? stripHTML(event) : event).join(" ")
// : "";
// const performerText = performer ? stripHTML(performer) : "";
// const combinedContent = [
// performerText,
// eventTextContent,
// conditions,
// actionText,
// ].filter(Boolean).join(" ");
// return combinedContent.trim();
// }
function combineConditionsAndActions(data) {
const {
performer = "",
eventText = [],
condition_set_1 = [],
condition_set_2 = [],
operator,
actions = []
} = data;
// ✅ Process performer (Remove HTML, trim)
const processedPerformer = performer ? stripHTML(performer).trim() : "";
// ✅ Process event text (Remove HTML, join)
const processedEventText = eventText.length
? eventText.map(stripHTML).join(" ").trim()
: "";
// ✅ Remove HTML from conditions and keep order
const processedConditionSet1 = condition_set_1.map(stripHTML);
const processedConditionSet2 = condition_set_2.map(stripHTML);
// ✅ Combine conditions with operator
const originalConditions = [
...processedConditionSet1,
operator ? ` ${operator} ` : "",
...processedConditionSet2,
].filter(Boolean).join(" ").trim();
// ✅ Process actions
const originalActions = actions.length
? actions.map(stripHTML).join(" ").trim()
: "";
// ✅ Create the final **original** content for display
const originalContent = [
processedPerformer,
processedEventText,
originalConditions,
originalActions,
].filter(Boolean).join(" ").trim();
// === ✅ SORTING LOGIC FIX ===
// ✅ Sort conditions **independently** (keeps set1/set2 separate but sorted)
const sortedConditionSet1 = [...processedConditionSet1].map(text => text.toLowerCase()).sort();
const sortedConditionSet2 = [...processedConditionSet2].map(text => text.toLowerCase()).sort();
const sortedConditions = [
...sortedConditionSet1,
operator ? ` ${operator.toLowerCase()} ` : "",
...sortedConditionSet2,
].filter(Boolean).join(" ").trim();
// ✅ Sort actions separately
const sortedActions = actions.length
? [...actions.map(stripHTML).map(text => text.toLowerCase())].sort().join(" ").trim()
: "";
// ✅ Sort event text
const sortedEventText = eventText.length
? [...eventText.map(stripHTML).map(text => text.toLowerCase())].sort().join(" ").trim()
: "";
// ✅ Sort performer (single value, so just lowercase)
const sortedPerformer = processedPerformer.toLowerCase();
// ✅ Create the final **sorted** content for grouping (keeping structure)
const sortedContent = [
sortedPerformer,
sortedEventText,
sortedConditions,
sortedActions
].filter(Boolean).join(" ").trim();
return { originalContent, sortedContent };
}
let currentPageDuplicates = 1;
const itemsPerPageDuplicates = 5;
function processAndDisplayDuplicates(duplicates, containerId,globalAgents) {
console.log("function processAndDisplayDuplicates called");
const container = document.getElementById(containerId);
if (!container) {
console.error(`Container with ID "${containerId}" not found.`);
return;
}
container.innerHTML = ""; // Clear container
if (duplicates.length === 0) {
container.innerHTML = `
<div style="
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
width: 100%;
font-size: 24px;
font-weight: bold;
color: #333;
margin-left: 400px;
text-align: center;
">
No duplicate rules found.
</div>`;
return;
}
const groupedRules = new Map();
duplicates.forEach((record) => {
const rule = record.parsedPayload || record.rule || record;
if (!rule || !rule.summary) {
console.warn("Skipping record due to missing data:", record);
return;
}
const { name, summary, position, updated_at, last_updated_by, affected_tickets_count, id } = rule;
if (summary && summary.conditions) {
const actions = summary.actions || [];
const performer = summary.performer || "";
const eventText = summary.events || [];
// ✅ Get both sorted and original content
const { originalContent, sortedContent } = combineConditionsAndActions({
performer: performer,
eventText: eventText,
condition_set_1: summary.conditions.condition_set_1,
condition_set_2: summary.conditions.condition_set_2,
operator: summary.conditions.operator,
actions: actions,
});
// ✅ Use sortedContent for grouping
if (!groupedRules.has(sortedContent)) {
groupedRules.set(sortedContent, []);
}
// ✅ Store both sortedContent (for grouping) and originalContent (for display)
groupedRules.get(sortedContent).push({
name,
position,
combinedContent: originalContent, // ✅ Use originalContent for display
performer,
eventText,
conditions: summary.conditions,
actions,
updated_at,
last_updated_by,
affected_tickets_count,
id,
});
}
});
const groupedRulesArray = Array.from(groupedRules.values());
const totalgroup = Math.ceil(groupedRulesArray.length );
console.log(totalgroup,"*********************")
const totalPagesDuplicates = Math.ceil(groupedRulesArray.length / itemsPerPageDuplicates);
currentPageDuplicates = Math.max(1, Math.min(currentPageDuplicates, totalPagesDuplicates));
console.log("Total Pages:", totalPagesDuplicates, "Current Page:", currentPageDuplicates);
const startIdx = (currentPageDuplicates - 1) * itemsPerPageDuplicates;
const paginatedRules = groupedRulesArray.slice(startIdx, startIdx + itemsPerPageDuplicates);
console.log("Displaying Records:", paginatedRules);
let arrayLength = paginatedRules.length;
console.log("Records Length:", arrayLength);
paginatedRules.forEach((titles) => {
const rulesCount = titles.length;
// ✅ Skip the group if it contains only one rule
if (rulesCount === 1) {
console.log(`Skipping group with only 1 rule: ${titles[0].name}`);
return; // Stop further execution for this group
}
const groupContainer = document.createElement("div");
groupContainer.style.border = "1px solid #ccc";
groupContainer.style.padding = "16px";
groupContainer.style.margin = "16px";
groupContainer.style.borderRadius = "8px";
groupContainer.style.backgroundColor = "#f5f7f9";
groupContainer.style.width = "1200px";
titles.forEach(({ name, position, combinedContent, performer,
eventText, conditions, actions,updated_at,
last_updated_by,
affected_tickets_count,id}, index) => {
const card = document.createElement("div");
card.style.border = "1px solid #ccc";
card.style.padding = "16px";
card.style.margin = "8px 0";
card.style.fontFamily =
"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif";
card.style.borderRadius = "8px";
card.style.backgroundColor = index === 0 ? "#fff" : "#e5f2fd";
card.style.marginBottom = "10px";
card.style.paddingBottom = "0";
const cardHeader = document.createElement("div");
cardHeader.style.display = "flex";
cardHeader.style.justifyContent = "space-between";
cardHeader.style.alignItems = "center";
// Create a wrapper for the title
const cardTitle = document.createElement("h4");
cardTitle.style.margin = "0";
cardTitle.style.cursor = "pointer";
cardTitle.style.fontSize = "14px";
cardTitle.style.fontFamily = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif";
cardTitle.style.color = "#183247";
cardTitle.style.transition = "color 0.2s ease";
cardTitle.style.fontWeight = "600";
// Create the serial number (position)
if (position) {
const serialNumber = document.createElement("span");
serialNumber.textContent = position + ". ";
serialNumber.style.color = "#183247"; // Keep serial number color fixed
cardTitle.appendChild(serialNumber);
}
// Create the actual name (clickable part)
const titleText = document.createElement("span");
titleText.textContent = name;
titleText.style.color = "#183247";
titleText.style.transition = "color 0.2s ease";
// Add hover effect for only the name
titleText.addEventListener("mouseover", () => {
titleText.style.color = "#007bff"; // Change only name color on hover
});
titleText.addEventListener("mouseout", () => {
titleText.style.color = "#183247"; // Reset name color when not hovering
});
titleText.addEventListener("click", () => {
titleText.style.color = "#ff5733"; // Change title color on click
showPopupCard1(name, { performer: performer,
eventText: eventText, conditions: conditions, actions: actions, });
});
// Append name to title
cardTitle.appendChild(titleText);
// Append title and actions to the cardHeader
cardHeader.appendChild(cardTitle);
const cardContainer = document.createElement("div");
// Style the container to have a background color in the gap
cardContainer.style.backgroundColor = "#f0f0f0"; // Set the background color for the gap (change to desired color)
cardContainer.style.paddingBottom = "20px";
cardContainer.style.marginLeft="-15px";
cardContainer.style.borderRadius = "4px";
cardContainer.style.width="102.7%";
// Create a horizontal line after the cardBody
const horizontalLine = document.createElement("div");
horizontalLine.style.height = "1px"; // Set the height to 1px for a thin line
horizontalLine.style.backgroundColor = "#ccc"; // Set the color of the horizontal line
horizontalLine.style.marginTop = "16px"; // Add space above the line (adjust as needed)
horizontalLine.style.width = "100%"; // Ensure the line stretches the full width of the container
horizontalLine.style.marginLeft="-3px";
function truncateContent(content, maxLength, lines) {
// Truncate the content to the desired number of characters
let truncated = content;
// Adjust for the desired line count and maximum length
if (content.length > maxLength) {
truncated = content.slice(0, maxLength) + "...";
}
// Break content into lines manually for multi-line truncation
const words = truncated.split(" ");
const result = [];
let line = "";
let currentLine = 1;
for (let i = 0; i < words.length; i++) {
if (line.length + words[i].length + 1 <= maxLength / lines) {
line += (line ? " " : "") + words[i];
} else {
result.push(line);
line = words[i];
currentLine++;
if (currentLine > lines) break; // Stop adding more lines if max lines are reached
}
}
if (currentLine <= lines && line) {
result.push(line);
}
return result.join(" ") + (currentLine > lines ? "..." : "");
}
function calculateLastModified(updated_at) {
const updatedDate = new Date(updated_at);
const currentDate = new Date();
const diffInMilliseconds = currentDate - updatedDate;
const seconds = Math.floor(diffInMilliseconds / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
const months = Math.floor(days / 30); // Approximate months
const years = Math.floor(days / 365); // Approximate years
if (years > 0) {
return years === 1 ? "a year ago" : `${years} years ago`;
} else if (months > 0) {
return months === 1 ? "a month ago" : `${months} months ago`;
} else if (days > 0) {
return `${days} day${days > 1 ? "s" : ""} ago`;
} else if (hours > 0) {
return `${hours} hour${hours > 1 ? "s" : ""} ago`;
} else if (minutes > 0) {
return `${minutes} minute${minutes > 1 ? "s" : ""} ago`;
} else {
return "Just now";
}
}
// console.log("updated at",calculateLastModified(updated_at));
// Create a row for "Last Modified"
const lastModifiedRow = document.createElement("div");
lastModifiedRow.style.display = "grid";
lastModifiedRow.style.gridTemplateColumns = "150px 150px 2px 150px 150px 2px 150px 150px"; // Consistent width for each section
lastModifiedRow.style.alignItems = "center";
lastModifiedRow.style.marginTop = "10px";
lastModifiedRow.style.fontSize = "12px";
lastModifiedRow.style.gap = "20px";
lastModifiedRow.style.width = "100%"; // Ensures full width alignment
const lastModifiedLabel = document.createElement("span");
lastModifiedLabel.textContent = "Last Modified :";
lastModifiedLabel.style.color = "#183247";
lastModifiedLabel.style.fontSize = "12px";
lastModifiedLabel.style.display = "inline-flex";
lastModifiedLabel.style.fontFamily =" -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif"
lastModifiedLabel.style.marginLeft = "40px"
const lastModifiedValue = document.createElement("span");
const lastModifiedText = calculateLastModified(updated_at);
lastModifiedValue.textContent = lastModifiedText;
lastModifiedValue.style.color = "#183247";
lastModifiedValue.style.fontWeight = "600";
lastModifiedValue.style.display = "inline-flex";
lastModifiedValue.style.fontSize = "12px";
lastModifiedValue.style.marginLeft = "-50px"
lastModifiedValue.style.justifySelf = "start";
lastModifiedValue.style.fontFamily =" -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif"
const verticalLine = document.createElement("div");
verticalLine.style.height = "20px";
verticalLine.style.borderLeft = "2px solid #ccc";
verticalLine.style.alignSelf = "stretch";
lastModifiedRow.appendChild(lastModifiedLabel);
lastModifiedRow.appendChild(lastModifiedValue);
lastModifiedRow.appendChild(verticalLine);
const agentsid = last_updated_by;
const matchingAgent = globalAgents.find(agent => String(agent.id) === String(agentsid));
if (matchingAgent) {
console.log(`✅ Matching agent found:`, matchingAgent);
} else {
console.log(`❌ No agent found with id: ${agentsid}`);
}
const agentNameLabel = document.createElement("span");
agentNameLabel.textContent = "By :";
agentNameLabel.style.fontSize = "12px";
agentNameLabel.style.color = "#183247";
agentNameLabel.style.whiteSpace = "nowrap";
agentNameLabel.style.marginLeft="149px"
agentNameLabel.style.fontFamily =" -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif"
const agentNameValue = document.createElement("span");
if (matchingAgent) {
agentNameValue.textContent = matchingAgent.contact.name|| "Unknown Agent";
} else {
agentNameValue.textContent = "Unknown Agent";
}
agentNameValue.style.color = "#183247";
agentNameValue.style.fontWeight = "600";
agentNameValue.style.whiteSpace = "nowrap";
agentNameValue.style.fontFamily =" -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif"
const verticalLine2 = document.createElement("div");
verticalLine2.style.height = "20px";
verticalLine2.style.borderLeft = "2px solid #ccc";
verticalLine2.style.alignSelf = "stretch";
verticalLine2.style.marginLeft = "100px"; // Increase for more right shift
lastModifiedRow.appendChild(agentNameLabel);
lastModifiedRow.appendChild(agentNameValue);
lastModifiedRow.appendChild(verticalLine2);
const affectedTicketsLabel = document.createElement("span");
affectedTicketsLabel.textContent = "Impacted tickets (Last 7 days) : ";
affectedTicketsLabel.style.fontSize = "12px";
affectedTicketsLabel.style.color = "#183247";
affectedTicketsLabel.style.marginLeft="140px";
affectedTicketsLabel.style.whiteSpace = "nowrap";
affectedTicketsLabel.style.fontFamily =" -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif"
const affectedTicketsValue = document.createElement("span");
affectedTicketsValue.textContent = affected_tickets_count === 0 ? "--" : affected_tickets_count;
affectedTicketsValue.style.color = "#183247";
affectedTicketsValue.style.fontWeight = "600";
affectedTicketsValue.style.marginLeft ="134px"
affectedTicketsValue.style.whiteSpace = "nowrap";
affectedTicketsValue.style.fontFamily =" -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif"
lastModifiedRow.appendChild(affectedTicketsLabel);
lastModifiedRow.appendChild(affectedTicketsValue);
const cardBody = document.createElement("div"); // Create a container for card content and actions
cardBody.style.display = "flex"; // Flexbox to align items horizontally
cardBody.style.justifyContent = "space-between"; // Ensure there's space between content and actions
cardBody.style.alignItems = "flex-start"; // Align items to the top (optional, depending on your needs)
const truncatedContent = truncateContent(combinedContent, 200, 2);
const cardContent = document.createElement("pre");
cardContent.textContent = truncatedContent;
// Style the card content
cardContent.style.marginTop = "8px";
cardContent.style.padding = "8px";
cardContent.style.whiteSpace = "pre-wrap"; // Ensure text wraps
cardContent.style.overflow = "hidden"; // Hide overflow content
cardContent.style.textOverflow = "ellipsis"; // Add ellipsis for overflow
cardContent.style.maxWidth = "75%"; // Limit the card width to half the container's width
cardContent.style.fontSize="12px";
cardContent.style.color="#183247";
cardContent.style.fontweight="600";
cardContent.style.fontFamily= "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif";
cardContent.style.marginLeft="15px"
// Create the container for card actions
const cardActionsContainer = document.createElement("div");
cardActionsContainer.style.display = "flex"; // Display actions horizontally
cardActionsContainer.style.justifyContent = "flex-end"; // Align to the right
cardActionsContainer.style.marginTop = "10px"; // Add some spacing above the actions
cardActionsContainer.style.gap = "8px"; // Set space between the toggle and the delete icon
// Add fw-toggle
// const fwToggle = document.createElement("fw-toggle");
// fwToggle.setAttribute("size", "medium");
// fwToggle.setAttribute("checked", "");
// Add fw-icon
const fwIcon = document.createElement("fw-icon");
fwIcon.setAttribute("name", "delete");
fwIcon.setAttribute("size", "18");
fwIcon.style.cursor = "pointer";
fwIcon.style.color = "red"; // Set the color to red
// Add a pointer cursor for interactivity
fwIcon.title = "Delete";
fwIcon.addEventListener("click", () => {
console.log("Delete icon clicked");
console.log("Rule ID:", id);
// Show the confirmation popup before deleting
showDeletePopup();
// Function to show the confirmation popup
function showDeletePopup() {
document.getElementById("deleteConfirmationPopup").style.display = "flex";
}
// Function to hide the confirmation popup
function hideDeletePopup() {
document.getElementById("deleteConfirmationPopup").style.display = "none";
}
async function Fetchentity(automationTypeId, nextMarker = null, allRecords1 = []) {
try {
if (!newRulePloadDB5) {
console.error(" Entity is not initialized yet!");
showLoader();
setTimeout(() => {
location.reload();
}, 1000);
}
showLoader();
let queryObj = {
query: {
$and: [
{ automation_type_id: automationTypeId },
{ active: "true" }
]
}
};
if (nextMarker) {
console.log("🔄 Next marker found:", nextMarker);
queryObj.next = { marker: nextMarker };
}
console.log("📤 Fetching records with query:", JSON.stringify(queryObj, null, 2));
const response = await newRulePloadDB5.getAll(queryObj);
if (!response.records || !Array.isArray(response.records)) {
console.error("❌ Invalid response format:", response);
hideLoader();
return allRecords1;
}
console.log(`📥 Retrieved ${response.records.length} records`);
allRecords1 = allRecords1.concat(response.records);
const newNextMarker = response.links?.next?.marker || null;
if (newNextMarker) {
console.log(`🔄 More pages exist. Next marker: ${newNextMarker}`);
return Fetchentity(automationTypeId, newNextMarker, allRecords1);
} else {
console.log("✅ No more pages.");
console.log(`📌 Total Filtered Records: ${allRecords1.length}`);
hideLoader();
return allRecords1;
}
} catch (error) {
console.error("❌ Error fetching filtered records:", error);
hideLoader();
return [];
}
}
async function confirmDeletions() {
console.log(" Deleting rule with ID:", id);
// Start progress loader
let progressLoader = document.querySelector("#progress-container");
if (progressLoader && typeof progressLoader.start === "function") {
progressLoader.start();
}
try {
let getdeleteruleResponse = await client.request.invokeTemplate("deleterule", {
context: {
automationid: 4,
ruleid: id
}
});
console.log("getdeleteruleResponse", getdeleteruleResponse);
if (getdeleteruleResponse.status === 204) {
console.log("✅ Rule deleted successfully!");
// Show success toast
let valid = document.getElementById('type_toast');
valid.setAttribute('content', 'Rule deleted successfully');
valid.setAttribute('type', 'success');
valid.setAttribute('open', true);
// ✅ Remove from UI
removeDeletedRuleFromUI(id);
hideDeletePopup();
console.log("Before deletion, existing rule IDs:", duplicatesType4.map(rule => rule.id));
// ✅ Convert to string for comparison
const ruleIdToDelete = String(id);
// ✅ Find and delete rule from duplicatesType4
const index = duplicatesType4.findIndex(rule => String(rule.id) === ruleIdToDelete);
console.log("Rule index found:", index);
if (index !== -1) {
duplicatesType4.splice(index, 1); // Remove rule from array
console.log("✅ Rule removed from duplicatesType4.");
} else {
console.warn("⚠️ Rule not found in duplicatesType4. Possible ID mismatch.");
}
console.log("Duplicates after deleting:", duplicatesType4);
processAndDisplayDuplicates(duplicatesType4, "TicketUpdates1",globalAgents);
let progressLoader = document.querySelector("#progress-container");
if (progressLoader && typeof progressLoader.start === "function") {
progressLoader.done();
}
if (entitytype4.length === 0) {
console.log(" entitytype4 is empty. Fetching records...");
entitytype4 = await Fetchentity(4);
console.log("entity fethed after clicking recent data",entitytype4);
const displayId = getDisplayIdByRuleId(entitytype4, id);
console.log("Matching Display ID:", displayId);
if (!displayId) return; // Ensure rule ID is available
try {
console.log(" Deleting rule with ID:", displayId);
await newRulePloadDB5.delete(displayId);
} catch (error) {
console.warn(` Error deleting record with Display ID ${displayId}, but continuing...`);
}
}
const displayId = getDisplayIdByRuleId(entitytype4, id);
console.log("Matching Display ID:", displayId);
if (!displayId) return; // Ensure rule ID is available
try {
console.log(" Deleting rule with ID:", displayId);
await newRulePloadDB5.delete(displayId);
} catch (error) {
console.warn(` Error deleting record with Display ID ${displayId}, but continuing...`);
}
}
} catch (error) {
console.error("❌ Error deleting rule:", error);
// Show error toast
let errorToast = document.getElementById('type_toast');
errorToast.setAttribute('content', "Failed to delete rule. Please try again.");
errorToast.setAttribute('type', 'error');
errorToast.setAttribute('open', true);
} finally {
// Ensure progress loader stops if an error occurs
if (progressLoader && typeof progressLoader.done === "function") {
progressLoader.done();
}
}
// Hide the popup after action
hideDeletePopup();
}
// Function to remove the deleted rule from UI
function removeDeletedRuleFromUI(ruleId) {
let ruleCard = document.querySelector(`[data-rule-id="${ruleId}"]`);
if (ruleCard) {
ruleCard.remove();
}
}
function getDisplayIdByRuleId(entityRecords, id) {
console.log("Checking all records for Rule ID:", id);
if (!Array.isArray(entityRecords) || entityRecords.length === 0) {
console.warn(" No records found in entity storage.");
return null;
}
console.log(" Sample Record Structure:", entityRecords.slice(0, 5));
console.log(" Available Keys in First Record:", Object.keys(entityRecords[0]));
// Find the record where rule_id matches currentRuleId
const matchedRecord = entityRecords.find(record =>
String(record?.data?.rule_id) === String(id)
);
console.log("Does Rule ID exist in records?", matchedRecord !== undefined);
return matchedRecord ? matchedRecord.display_id : null;
}
// Attach event listeners once (outside the click event)
document.getElementById("confirmDeleteBtn").addEventListener("click", confirmDeletions);
document.getElementById("cancelDeleteBtn").addEventListener("click", hideDeletePopup);
});
// fwIcon.addEventListener("click", async () => {
// console.log("Delete icon clicked");
// console.log("rule id:", id);
// // Show the confirmation popup before deleting
// showDeletePopup();
// // Function to show the confirmation popup
// function showDeletePopup() {
// document.getElementById("deleteConfirmationPopup").style.display = "flex";
// }
// // Function to hide the confirmation popup
// function hideDeletePopup() {
// document.getElementById("deleteConfirmationPopup").style.display = "none";
// }
// // Function to handle deletion after confirmation
// async function confirmDeletion() {
// console.log("Deleting rule with ID:", id);
// try {
// let getdeleteruleResponse = await client.request.invokeTemplate("deleterule", {
// context:{ automationid:4,
// ruleid: id ,}
// });
// console.log("getdeleteruleResponse", getdeleteruleResponse);
// // Show success toast
// let valid = document.getElementById('type_toast');
// console.log("toat message called", valid);
// valid.setAttribute('content', 'Rule deleted successfully');
// valid.setAttribute('type', 'success');
// valid.setAttribute('open', true);
// // Remove the deleted rule from UI
// removeDeletedRuleFromUI(window.currentRuleId);
// } catch (error) {
// console.error("Error deleting rule:", error);
// // Show error toast
// let errorToast = document.getElementById('type_toast');
// errorToast.setAttribute('content', 'Error deleting rule. Please try again.');
// errorToast.setAttribute('type', 'error');
// errorToast.setAttribute('open', true);
// }
// // Hide the popup after action
// hideDeletePopup();
// }
// // Function to remove the deleted rule from UI
// function removeDeletedRuleFromUI(ruleId) {
// let ruleCard = document.querySelector(`[data-rule-id="${ruleId}"]`);
// if (ruleCard) {
// ruleCard.remove();
// }
// }
// // Attach event listeners once (outside the click event)
// document.getElementById("confirmDeleteBtn").addEventListener("click", confirmDeletion);
// document.getElementById("cancelDeleteBtn").addEventListener("click", hideDeletePopup);
// });
// Append fw-toggle and fw-icon to cardActions
// cardActionsContainer.appendChild(fwToggle);
cardActionsContainer.appendChild(fwIcon);
card.appendChild(cardHeader);
cardBody.appendChild(cardContent);
cardBody.appendChild(cardActionsContainer);
card.appendChild(cardBody);
cardContainer.appendChild(horizontalLine);
// card.appendChild(horizontalLine);
cardContainer.appendChild(lastModifiedRow);
card.appendChild(cardContainer)
groupContainer.appendChild(card);
});
container.appendChild(groupContainer);
});
// Add pagination component
addFwPaginationDuplicates(containerId, duplicates,totalgroup);
}
// Function to add pagination for processAndDisplayDuplicates
function addFwPaginationDuplicates(containerId,duplicates,totalgroup) {
console.log("Adding pagination to container:", containerId);
let container = document.getElementById(containerId);
if (!container) {
console.warn(`Container with ID "${containerId}" not found.`);
return;
}
console.log("itemsperpage duplicates*********",itemsPerPageDuplicates)
if (totalgroup <= itemsPerPageDuplicates) {
console.log("Total records are less than or equal to items per page, skipping pagination.");
return;
}
let existingPagination2 = container.querySelector("#fw-pagination-duplicates");
if (existingPagination2) {
existingPagination2.remove(); // Remove old pagination if it exists
}
const pagination2 = document.createElement("fw-pagination");
pagination2.id = "fw-pagination-duplicates";
console.log("total group inside", )
pagination2.setAttribute("total", totalgroup);
pagination2.setAttribute("per-page", itemsPerPageDuplicates);
pagination2.setAttribute("page", currentPageDuplicates);
console.log("Pagination Element:", pagination2);
const paginationWrapper2 = document.createElement("div");
paginationWrapper2.style.display = "flex";
paginationWrapper2.style.justifyContent = "flex-start";
paginationWrapper2.style.alignItems = "center";
paginationWrapper2.style.width = "100%";
paginationWrapper2.style.marginLeft = "70%";
paginationWrapper2.appendChild(pagination2);
container.appendChild(paginationWrapper2);
pagination2.addEventListener("fwChange", (event) => {
console.log("fwChange Event Triggered", event);
currentPageDuplicates = event.detail.page;
console.log("Updated Page:", currentPageDuplicates);
// Update the displayed rules for the current container
processAndDisplayDuplicates(duplicates, containerId,globalAgents);
});
}
let entitytype1 = [];
let entitytype3 = [];
let entitytype4 = [];
async function Filterrecords(automationTypeId, nextMarker = null, allRecords = []) {
// console.log("filterrecords called for automationtypeid",automationTypeId);
try {
if (!newRulePloadDB5) {
console.error(" Entity is not initialized yet!");
showLoader();
setTimeout(() => {
location.reload();
}, 1000);
}
showLoader(); // Show spinner before fetching starts
let queryObj = {
query: {
$and: [
{ automation_type_id: automationTypeId },
{ active: "true" }
]
}
};
if (nextMarker) {
console.log("🔄 Next marker found:", nextMarker);
queryObj.next = { marker: nextMarker };
}
console.log("📤 Fetching records with query:", JSON.stringify(queryObj, null, 2));
const response = await newRulePloadDB5.getAll(queryObj);
if (!response.records || !Array.isArray(response.records)) {
console.error("❌ Invalid response format:", response);
hideLoader(); // Hide spinner on failure
return allRecords;
}
console.log(`📥 Retrieved ${response.records.length} records`);
allRecords = allRecords.concat(response.records);
const newNextMarker = response.links?.next?.marker || null;
if (newNextMarker) {
console.log(`🔄 More pages exist. Next marker: ${newNextMarker}`);
return Filterrecords(automationTypeId, newNextMarker, allRecords);
} else {
console.log("✅ No more pages.");
console.log(`📌 Total Filtered Records: ${allRecords.length}`);
hideLoader(); // Hide spinner once fetching is complete
// Conditional function call based on automationTypeId
if (automationTypeId === 1) {
entitytype1 = allRecords;
console.log("entity copy array",entitytype1);
return findDuplicateRulestype1and3(allRecords);
} else if(automationTypeId === 3)
{
entitytype3 = allRecords;
console.log("entity copy array",entitytype3);
return findDuplicateRulestype1and3(allRecords);
}
else if (automationTypeId === 4) {
entitytype4 = allRecords;
console.log("entity copy array",entitytype4);
return findDuplicateRulestype4(allRecords);
} else {
console.warn("⚠️ Unknown automationTypeId:", automationTypeId);
return allRecords;
}
}
} catch (error) {
console.error("❌ Error fetching filtered records:", error);
hideLoader(); // Hide spinner on error
return [];
}
}
// async function Filterrecords(automationTypeId, nextMarker = null, allRecords = []) {
// // console.log("filterrecords called for automationtypeid",automationTypeId);
// try {
// if (!newRulePloadDB5) {
// console.error(" Entity is not initialized yet!");
// showLoader();
// setTimeout(() => {
// location.reload();
// }, 1000);
// }
// showLoader(); // Show spinner before fetching starts
// let queryObj = {
// query: { automation_type_id: automationTypeId }
// };
// if (nextMarker) {
// console.log("🔄 Next marker found:", nextMarker);
// queryObj.next = { marker: nextMarker };
// }
// console.log("📤 Fetching records with query:", JSON.stringify(queryObj, null, 2));
// const response = await newRulePloadDB5.getAll(queryObj);
// if (!response.records || !Array.isArray(response.records)) {
// console.error("❌ Invalid response format:", response);
// hideLoader(); // Hide spinner on failure
// return allRecords;
// }
// console.log(`📥 Retrieved ${response.records.length} records`);
// allRecords = allRecords.concat(response.records);
// const newNextMarker = response.links?.next?.marker || null;
// if (newNextMarker) {
// console.log(`🔄 More pages exist. Next marker: ${newNextMarker}`);
// return Filterrecords(automationTypeId, newNextMarker, allRecords);
// } else {
// console.log("✅ No more pages.");
// console.log(`📌 Total Filtered Records: ${allRecords.length}`);
// hideLoader(); // Hide spinner once fetching is complete
// // Conditional function call based on automationTypeId
// if (automationTypeId === 1 || automationTypeId === 3) {
// console.log("allrecords fetched from entity", allRecords)
// return findDuplicateRulestype1and3(allRecords);
// } else if (automationTypeId === 4) {
// console.log("allrecords fetched from entity", allRecords)
// return findDuplicateRulestype4(allRecords);
// } else {
// console.warn("⚠️ Unknown automationTypeId:", automationTypeId);
// return allRecords;
// }
// }
// } catch (error) {
// console.error("❌ Error fetching filtered records:", error);
// hideLoader(); // Hide spinner on error
// return [];
// }
// }
function showLoader() {
console.log("showloader function called");
document.getElementById("spinner").style.display = "block";
}
function hideLoader() {
console.log("*********hide loader")
document.getElementById("spinner").style.display = "none";
}
// 3 Function to find duplicate rules
function findDuplicateRulestype1and3(records) {
const seenRules = new Map(); // Store unique rules with their first occurrence
const duplicateRecords = []; // Store all duplicate records
records.forEach((record) => {
const { summary, conditions, actions, operator} = record.data;
// if (!record.data.active) return; // Skip inactive records
// console.log("Processing active record:", record); // Log full record
// Function to remove all <img> tags from HTML content
const stripImageTags = (html) => html.replace(/<img[^>]*>/g, "");
// // Log conditions and actions before sorting
// console.log("Original Conditions:", conditions);
// console.log("Original Actions:", actions);
// Normalize and sort conditions
const normalizedConditions = conditions
? conditions
.split(",") // Split into an array
.map((c) => c.trim().toLowerCase()) // Trim and lowercase
.sort() // Sort for consistency
.join(",") // Join back into a string
: "";
// Normalize and sort actions
const normalizedActions = actions
? stripImageTags(actions)
.split(",") // Split into an array
.map((a) => a.trim().toLowerCase()) // Trim and lowercase
.sort() // Sort for consistency
.join(",") // Join back into a string
: "";
// Log conditions and actions after sorting
// console.log("Sorted Conditions:", normalizedConditions);
// console.log("Sorted Actions:", normalizedActions);
// Check for punctuation in summary
if (summary && /[.,\/#!$%\^&\*;:{}=\-_`~()]/.test(summary)) {
console.log("Punctuation found in summary:", summary);
}
// Normalize and sort summary (if structured)
const normalizedSummary = summary
? summary
.toLowerCase()
.split(/\s+/) // Split by whitespace
.sort() // Sort words alphabetically
.join(" ") // Rejoin into a sorted sentence
: "";
// Log the sorted summary
// console.log("Sorted Summary:", normalizedSummary);
// Normalize operator
const normalizedOperator = operator ? operator.trim().toLowerCase() : null;
// Create a unique key to compare records
const recordKey = `${normalizedSummary}|${normalizedConditions}|${normalizedActions}|${normalizedOperator}`;
if (seenRules.has(recordKey)) {
if (!duplicateRecords.includes(seenRules.get(recordKey))) {
duplicateRecords.push(seenRules.get(recordKey)); // Add original rule
}
duplicateRecords.push(record); // Add duplicate rule
} else {
seenRules.set(recordKey, record);
}
});
return duplicateRecords;
}
let isFetchingType1 = false; // Global flag to track fetching state
async function handleDuplicateRulestype1() {
if (isFetchingType1|| type1 > 0) return; // Prevent duplicate calls if already fetching
isFetchingType1 = true; // Set flag before execution starts
console.log("handleDuplicateRulestype1 called");
try {
const duplicatesType1 = await Filterrecords(1); // Get duplicates
console.log("🔄 Final duplicate records:", duplicatesType1);
// Pass to grouping function with container ID
displayGroupedRules(duplicatesType1, "Ticketcreation");
type1++;
} catch (error) {
console.error("❌ Error handling duplicate rules for type 1:", error);
} finally {
isFetchingType1 = false; // ✅ Reset flag after execution completes
}
}
// 3️⃣ Handle duplicate rule detection & pass to grouping function
// async function handleDuplicateRulestype1() {
// const duplicatesType1 = await Filterrecords(1); // Get duplicates
// console.log("🔄 Final duplicate records:", duplicatesType1,);
// // Pass to grouping function with container ID
// displayGroupedRules(duplicatesType1, "Ticketcreation");
// }
function stripHTML(htmlString) {
return htmlString.replace(/<\/?[^>]+(>|$)/g, "");
}
// Function to show popup card with blur effect
function showPopupCard(title, content, automation_type_id) {
if (automation_type_id !== undefined && automation_type_id !== null) {
localStorage.setItem("automation_type_id", automation_type_id);
} else {
automation_type_id = localStorage.getItem("automation_type_id") || "Unknown";
}
console.log("logPopup", automation_type_id);
const overlay = document.createElement("div");
overlay.style.position = "fixed";
overlay.style.top = "0";
overlay.style.left = "0";
overlay.style.width = "100%";
overlay.style.height = "100%";
overlay.style.backgroundColor = "rgba(0, 0, 0, 0.3)"; // Semi-transparent dark background
overlay.style.backdropFilter = "blur(5px)"; // Apply blur effect
overlay.style.zIndex = "999"; // Ensure it appears above everything else
// Create popup container
const popupContainer = document.createElement("div");
popupContainer.style.position = "fixed";
popupContainer.style.top = "50%";
popupContainer.style.left = "50%";
popupContainer.style.transform = "translate(-50%, -50%)";
popupContainer.style.width = "1000px"; // Increased default width
popupContainer.style.maxWidth = "95%"; // Ensure it fits on smaller screens
popupContainer.style.height = "60vh"; // Use viewport height to limit size
popupContainer.style.backgroundColor = "#fff";
popupContainer.style.border = "1px solid #ccc";
popupContainer.style.boxShadow = "0 4px 8px rgba(0, 0, 0, 0.2)";
popupContainer.style.borderRadius = "12px"; // Increased border radius for a smoother look
popupContainer.style.overflow = "hidden"; // Prevent content overflow
popupContainer.style.fontFamily =
"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif"; // Apply a system font
popupContainer.style.zIndex = "1000";
popupContainer.style.display = "flex";
popupContainer.style.flexDirection = "column";
// Create header for title (fixed position)
const popupHeader = document.createElement("div");
popupHeader.style.padding = "16px 24px";
popupHeader.style.borderBottom = "1px solid #ddd"; // Separate the title visually
popupHeader.style.backgroundColor = "#fff";
popupHeader.style.zIndex = "10"; // Ensure it appears above the scrollable content
// Popup title
const popupTitle = document.createElement("h2");
popupTitle.textContent = title;
popupTitle.style.paddingLeft = "15px"; // Move the title slightly to the right
popupTitle.style.fontSize = "20px";
popupTitle.style.color = "#333";
popupTitle.style.textAlign = "left";
popupHeader.appendChild(popupTitle);
// Content wrapper (flex layout)
const contentWrapper = document.createElement("div");
contentWrapper.style.display = "flex";
contentWrapper.style.flexDirection = "column";
contentWrapper.style.flex = "1"; // Automatically take up available space
contentWrapper.style.overflow = "hidden"; // Prevent content overflow
// Content box (with fixed preview label)
const contentBox = document.createElement("div");
contentBox.style.flex = "1";
contentBox.style.border = "1px solid #ddd";
contentBox.style.borderRadius = "8px";
contentBox.style.backgroundColor = "#f9f9f9";
contentBox.style.padding = "16px";
contentBox.style.margin = "16px 16px"; // Add vertical spacing
contentBox.style.overflow = "hidden"; // Prevent outer scrolling
contentBox.style.marginBottom = "75px"; // Add enough space for the close button
// Preview label and line (sticky inside content box)
const previewLabelContainer = document.createElement("div");
previewLabelContainer.style.position = "sticky"; // Fix inside the content box
previewLabelContainer.style.top = "0"; // Stick to the top
previewLabelContainer.style.backgroundColor = "#f9f9f9"; // Match the content box background
previewLabelContainer.style.zIndex = "1";
previewLabelContainer.style.padding = "8px 0";
const previewLabel = document.createElement("p");
previewLabel.textContent = "Preview"; // Label text
previewLabel.style.fontSize = "16px";
previewLabel.style.fontWeight = "500";
previewLabel.style.color = "#92a2b1";
previewLabel.style.margin = "0";
const lineBelowLabel = document.createElement("hr");
lineBelowLabel.style.border = "none";
lineBelowLabel.style.borderTop = "1px solid #ddd";
lineBelowLabel.style.margin = "8px 0";
previewLabelContainer.appendChild(previewLabel);
previewLabelContainer.appendChild(lineBelowLabel);
// Scrollable content area
const scrollableContent = document.createElement("div");
scrollableContent.style.overflowY = "auto"; // Enable vertical scrolling
scrollableContent.style.height = "calc(100% - 40px)"; // Adjust to fit within the content box
const eventText = document.createElement("div");
eventText.style.marginBottom = "12px";
const createCustomBullet = (text, bulletColor, highlightColor) => {
const listItem = document.createElement("li");
listItem.style.position = "relative"; // For positioning the custom bullet
listItem.style.paddingLeft = "10px"; // Space for custom bullet
// Create the custom double circular bullet using a span element
const bullet = document.createElement("span");
bullet.style.position = "absolute";
bullet.style.left = "-15px"; // Bring the bullet closer to the text
bullet.style.top = "50%"; // Center the bullet vertically
bullet.style.transform = "translateY(-50%)"; // Center the bullet exactly
bullet.style.width = "12px"; // Outer ring size
bullet.style.height = "12px";
bullet.style.border = `4px solid ${bulletColor || "#dcdfe1"}`; // Outer ring color and border size
bullet.style.borderRadius = "50%"; // Make it a ring (circle with border)
bullet.style.display = "inline-block";
// Create the inner circle (smaller circle inside the outer ring)
const innerBullet = document.createElement("span");
innerBullet.style.position = "absolute";
innerBullet.style.left = "50%";
innerBullet.style.top = "50%";
innerBullet.style.transform = "translate(-50%, -50%)"; // Centering the inner circle
innerBullet.style.width = "2px"; // Inner circle size
innerBullet.style.height = "2px";
innerBullet.style.borderRadius = "50%"; // Inner circle rounded
innerBullet.style.display = "inline-block";
// Append the inner circle to the outer circle (bullet)
bullet.appendChild(innerBullet);
// Split the text into words
const words = text.split(" ");
// Extract specific words
const firstWord = words.shift(); // Remove first word
const secondWord = words.shift(); // Remove second word
const lastWord = words.pop(); // Extract last word
const remainingText = words.join(" "); // Remaining words (excluding first, second, and last)
// Construct the innerHTML with the second word in black and the last word in highlight color
listItem.innerHTML = `
<span>${firstWord}</span>
<span style="color: black; font-weight: 500;">${secondWord}</span>
${remainingText}
<span style="color: ${highlightColor}; font-weight: 500;">${lastWord}</span>
`;
// Append the custom double circular bullet to the list item
listItem.insertBefore(bullet, listItem.firstChild);
return listItem;
};
// Create the heading "Event:"
const eventLabel = document.createElement("p");
eventLabel.textContent = "Event";
eventLabel.style.margin = "0";
eventLabel.style.color = "#00a886"; // Blue color for heading
eventLabel.style.fontWeight = "bold";
eventLabel.style.fontSize = "16px";
// Create the unordered list for the event details
const eventDetail = document.createElement("ul");
eventDetail.style.margin = "8px 0 0 -15px"; // Add margin and indentation
eventDetail.style.color = "#333"; // Normal color for text
eventDetail.style.listStyleType = "none"; // Remove default bullets
eventDetail.style.fontSize = "14px";
if (Number(automation_type_id) === 1){
const eventBullet = createCustomBullet(
"When Ticket is Created", // Text content
"#2c5cc5", // Bullet color
"#00a886" // Highlight color for the last word
);
eventDetail.appendChild(eventBullet);
// Append the heading and the event detail to the container
eventText.appendChild(eventLabel);
eventText.appendChild(eventDetail);
}
const createCustomBullet1 = (text, bulletColor, highlightColor) => {
const listItem = document.createElement("li");
listItem.style.position = "relative"; // For positioning the custom bullet
listItem.style.paddingLeft = "10px"; // Space for custom bullet
// Create the custom double circular bullet using a span element
const bullet = document.createElement("span");
bullet.style.position = "absolute";
bullet.style.left = "-15px"; // Bring the bullet closer to the text
bullet.style.top = "50%"; // Center the bullet vertically
bullet.style.transform = "translateY(-50%)"; // Center the bullet exactly
bullet.style.width = "12px"; // Outer ring size
bullet.style.height = "12px";
bullet.style.border = `4px solid ${bulletColor || "#dcdfe1"}`; // Outer ring color and border size
bullet.style.borderRadius = "50%"; // Make it a ring (circle with border)
bullet.style.display = "inline-block";
// Create the inner circle (smaller circle inside the outer ring)
const innerBullet = document.createElement("span");
innerBullet.style.position = "absolute";
innerBullet.style.left = "50%";
innerBullet.style.top = "50%";
innerBullet.style.transform = "translate(-50%, -50%)"; // Centering the inner circle
innerBullet.style.width = "2px"; // Inner circle size
innerBullet.style.height = "2px";
innerBullet.style.borderRadius = "50%"; // Inner circle rounded
innerBullet.style.display = "inline-block";
// Append the inner circle to the outer circle (bullet)
bullet.appendChild(innerBullet);
// Split the text into words
const words = text.split(" ");
// Extract specific words
const firstWord = words.shift(); // Remove first word
const secondWord = words.shift(); // Remove second word
const lastFourWords = words.splice(-4).join(" "); // Get last four words
const remainingText = words.join(" "); // Remaining words (excluding first, second, and last four)
// Construct the innerHTML with the second word in black and the last four words in highlight color
listItem.innerHTML = `
<span>${firstWord}</span>
<span style="color: black; font-weight: 500;">${secondWord}</span>
${remainingText}
<span style="color: ${highlightColor}; font-weight: 500;">${lastFourWords}</span>
`;
// Append the custom double circular bullet to the list item
listItem.insertBefore(bullet, listItem.firstChild);
return listItem;
};
if (Number(automation_type_id) === 3){
const eventBullet = createCustomBullet1(
"When Ticket is is checked every hour", // Text content
"#2c5cc5", // Bullet color
"#00a886" // Highlight color for the last word
);
eventDetail.appendChild(eventBullet);
// Append the heading and the event detail to the container
eventText.appendChild(eventLabel);
eventText.appendChild(eventDetail);
}
// Create the conditions heading
const conditionText = document.createElement("div");
conditionText.textContent = "Condition";
conditionText.style.marginBottom = "8px";
conditionText.style.fontWeight = "bold";
conditionText.style.color = "#e86f25"; // Green color for conditions heading
conditionText.style.fontSize = "16px";
// Create a container for the conditions list
const conditionsList = document.createElement("ul");
conditionsList.style.margin = "0 0 12px";
conditionsList.style.padding = "8px";
conditionsList.style.border = "1px solid #ddd";
conditionsList.style.borderRadius = "4px";
conditionsList.style.backgroundColor = "#fff";
conditionsList.style.listStyleType = "none"; // Remove default bullet style
conditionsList.style.fontSize = "14px";
// Extract condition sets and operator
const conditionsArray1 = Array.isArray(content.conditions.condition_set_1)
? content.conditions.condition_set_1
: [];
const conditionsArray2 = Array.isArray(content.conditions.condition_set_2)
? content.conditions.condition_set_2
: [];
const operator = content.conditions.operator || "";
// Function to create a styled bullet point for conditions/actions
const createConditionBullet = (condition, bulletColor = "#dcdfe1") => {
const listItem = document.createElement("li");
listItem.style.position = "relative";
listItem.style.paddingLeft = "30px"; // Space for bullet
listItem.style.display = "flex"; // Prevents breaking lines
listItem.style.alignItems = "center"; // Keeps elements aligned
// Create custom bullet
const bullet = document.createElement("span");
bullet.style.position = "absolute";
bullet.style.left = "0";
bullet.style.top = "50%";
bullet.style.transform = "translateY(-50%)";
bullet.style.width = "12px";
bullet.style.height = "12px";
bullet.style.border = `4px solid ${bulletColor || "#dcdfe1"}`;
bullet.style.borderRadius = "50%";
// Inner circle of bullet
const innerBullet = document.createElement("span");
innerBullet.style.position = "absolute";
innerBullet.style.left = "50%";
innerBullet.style.top = "50%";
innerBullet.style.transform = "translate(-50%, -50%)";
innerBullet.style.width = "8px";
innerBullet.style.height = "8px";
innerBullet.style.borderRadius = "50%";
bullet.appendChild(innerBullet);
// **Formatting Condition with Colors**
let formattedCondition = condition
.replace(/<div/g, ' <div') // Add space before <div> tags if missing
.replace(/<div\s+class\s*=\s*["']?SummaryKey["']?\s*>(.*?)<\/div>/gi, ' <span style="color: black; font-weight: 500;">$1</span> ')
.replace(/<div\s+class\s*=\s*["']?SummaryValue["']?\s*>(.*?)<\/div>/gi, ' <span style="color: #00a886; font-weight: 500;">$1</span> ')
.replace(/<div\s+class\s*=\s*["']?SummaryOperator["']?\s*>(.*?)<\/div>/gi, ' <span> $1 </span> ') // Ensure space around operators
.replace(/>\s+</g, '> <') // Ensures space between inline elements
.replace(/\s+/g, ' ') // Remove multiple spaces
.trim(); // Trim any leading/trailing spaces
// // Set bullet first, then append formatted text
listItem.appendChild(bullet);
// Create a span for the condition text (for proper spacing)
const textSpan = document.createElement("span");
textSpan.innerHTML = formattedCondition;
textSpan.style.marginLeft = "-5px"; // Ensure space between bullet and text
listItem.appendChild(textSpan);
console.log("✅ Final List Item InnerHTML:", listItem.innerHTML); // Log final output
return listItem;
};
// Add conditions from condition_set_1
conditionsArray1.forEach((condition) => {
if (condition === "AND" || condition === "OR") {
// Add operator as a separate text element
const operatorItem = document.createElement("div");
operatorItem.textContent = condition;
operatorItem.style.color = "#6c757d";
operatorItem.style.margin = "8px 0 5px 29px";
conditionsList.appendChild(operatorItem);
} else {
conditionsList.appendChild(createConditionBullet(condition, "#2c5cc5")); // Blue bullet
}
});
// Add operator between conditions (if available)
if (operator) {
const operatorItem = document.createElement("div");
operatorItem.textContent = operator;
operatorItem.style.color = "#000000";
operatorItem.style.margin = "8px 0";
operatorItem.style.fontSize = "14px";
operatorItem.style.fontweight="bold"
conditionsList.appendChild(operatorItem);
}
// Add conditions from condition_set_2
conditionsArray2.forEach((condition) => {
if (condition === "AND" || condition === "OR") {
const operatorItem = document.createElement("div");
operatorItem.textContent = condition;
operatorItem.style.color = "#6c757d";
operatorItem.style.margin = "8px 0 5px 29px";
conditionsList.appendChild(operatorItem);
} else {
conditionsList.appendChild(createConditionBullet(condition, "#2c5cc5")); // Blue bullet
}
});
// Create actions heading
const actionText = document.createElement("div");
actionText.textContent = "Action";
actionText.style.marginBottom = "8px";
actionText.style.fontWeight = "bold";
actionText.style.color = "#2c5cc5";
actionText.style.fontSize = "16px";
// Create actions content
const actionContent = document.createElement("ul");
actionContent.style.margin = "0";
actionContent.style.padding = "8px";
actionContent.style.border = "1px solid #ddd";
actionContent.style.borderRadius = "4px";
actionContent.style.backgroundColor = "#fff";
actionContent.style.listStyleType = "none";
actionContent.style.fontSize = "14px";
const actionsArray = Array.isArray(content.actions) ? content.actions : [];
// Add actions with custom bullets
actionsArray.forEach((action) => {
if (action === "AND" || action === "OR") {
const operatorItem = document.createElement("div");
operatorItem.textContent = action;
operatorItem.style.color = "#6c757d";
operatorItem.style.margin = "8px 0 5px 29px";
actionContent.appendChild(operatorItem);
} else {
actionContent.appendChild(createConditionBullet(action, "#2c5cc5")); // Blue bullet for actions
}
});
// Append the label and line to the content box
contentBox.appendChild(previewLabel);
contentBox.appendChild(lineBelowLabel);
scrollableContent.appendChild(eventText);
scrollableContent.appendChild(conditionText);
scrollableContent.appendChild(conditionsList);
scrollableContent.appendChild(actionText);
scrollableContent.appendChild(actionContent);
// Append content to the scrollable wrapper
contentBox.appendChild(scrollableContent);
// Create fw-button element with "primary" color
const closeButton = document.createElement("fw-button");
closeButton.setAttribute("color", "primary");
closeButton.textContent = "Close";
closeButton.style.position = "absolute";
closeButton.style.bottom = "16px"; // Distance from the bottom
closeButton.style.right = "16px"; // Distance from the right
closeButton.style.padding = "8px 16px"; // Padding for the button
closeButton.style.borderRadius = "4px"; // Rounded corners
closeButton.style.cursor = "pointer";
// Close popup and remove overlay when the button is clicked
closeButton.addEventListener("click", () => {
document.body.removeChild(popupContainer);
document.body.removeChild(overlay);
});
popupContainer.appendChild(popupHeader); // Fixed title
popupContainer.appendChild(contentBox);
popupContainer.appendChild(closeButton); // Close button
// Append elements to the document
document.body.appendChild(overlay);
document.body.appendChild(popupContainer);
}
let currentPage = 1;
const itemsPerPage = 5;
function normalizeText2(text) {
return text
.toLowerCase()
.replace(/[.,\/#!$%\^&\*;:{}=\-_`~()]/g, "") // Remove punctuation
.split(/\s+/) // Split words
.sort() // Sort for consistency
.join(" "); // Rejoin sorted words
}
function normalizeList(text) {
return text
? text
.split(",") // Convert to array
.map((item) => item.trim().toLowerCase()) // Trim & lowercase
.sort() // Sort to ensure same order
.join(",") // Join back to a string
: "";
}
function stripHTML2(htmlString) {
// Create a temporary div to parse the HTML
const div = document.createElement("div");
div.innerHTML = htmlString;
// Remove all elements except <img>
[...div.querySelectorAll("*")].forEach(el => {
if (el.tagName.toLowerCase() !== "img") {
el.replaceWith(...el.childNodes);
}
});
return div.innerHTML.trim(); // Return cleaned HTML
}
function removeImgTags(htmlString) {
return htmlString.replace(/<img\b[^>]*>/g, "").trim();
}
function displayGroupedRules(records, containerId) {
const container = document.getElementById(containerId);
if (!container) {
console.error(`Container with ID "${containerId}" not found.`);
return;
}
container.innerHTML = ""; // Clear container
if (records.length === 0) {
container.innerHTML = `
<div style="
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
width: 100%;
font-size: 24px;
font-weight: bold;
color: #333;
margin-left: 400px;
text-align: center;
">
No duplicate rules found.
</div>`;
return;
}
const groupedRules = new Map();
records.forEach((record) => {
const { data, display_id } = record;
const { name, summary, position, updated_at, last_updated_by, affected_tickets_count, rule_id, automation_type_id, conditions, actions,agentName
} = data;
if (summary) {
// console.log(`🔍 Original Summary: ${summary}`);
// **Remove all HTML except <img> for display, but remove <img> for grouping**
const cleanSummary = stripHTML2(summary);
// **Ensure `actions` is a string before removing <img> tags**
const actionsText = Array.isArray(actions) ? actions.join(" ") : String(actions || "");
const cleanedActions = removeImgTags(actionsText); // Remove <img> from actions
// console.log(`✅ Cleaned Summary: ${cleanSummary}`);
// console.log(`🖼️ Actions without <img>: ${cleanedActions}`); // Log cleaned actions
const normalizedSummary = normalizeText2(cleanSummary);
const normalizedConditions = normalizeList(conditions);
const normalizedActions = normalizeList(cleanedActions); // Use cleaned actions
// **Generate Group Key (WITHOUT <img> tags)**
const groupKey = `${normalizedSummary}|${normalizedConditions}|${normalizedActions}`;
// console.log(`📌 Group Key: ${groupKey}`);
if (!groupedRules.has(groupKey)) {
groupedRules.set(groupKey, { originalSummary: cleanSummary, rules: [] });
}
groupedRules.get(groupKey).rules.push({
name,
position,
summary,
updated_at,
last_updated_by,
affected_tickets_count,
rule_id,
automation_type_id,
display_id,
agentName
});
}
});
const groupedRulesArray = Array.from(groupedRules.values());
const totalgroup = groupedRulesArray.length;
console.log(totalgroup, "*********************");
const totalPages = Math.ceil(totalgroup / itemsPerPage);
currentPage = Math.max(1, Math.min(currentPage, totalPages)); // Ensure valid page number
console.log("Total Pages:", totalPages, "Current Page:", currentPage);
const startIdx = (currentPage - 1) * itemsPerPage;
const paginatedRules = groupedRulesArray.slice(startIdx, startIdx + itemsPerPage);
console.log("Displaying Records:", paginatedRules);
let arrayLength = paginatedRules.length;
console.log("Records Length:", arrayLength);
// Display paginated rules
paginatedRules.forEach((group) => {
const rulesCount = group.rules.length;
if (rulesCount === 1) {
console.log(`Skipping group with only 1 rule: ${group.originalSummary}`);
return;
}
const groupContainer = document.createElement("div");
groupContainer.style.border = "1px solid #ccc";
groupContainer.style.padding = "16px";
groupContainer.style.margin = "16px";
groupContainer.style.borderRadius = "8px";
groupContainer.style.backgroundColor = "#f5f7f9";
groupContainer.style.width = "1200px";
// ✅ Correctly loop through the rules array inside the group object
group.rules.forEach(({ name, position, summary, updated_at, affected_tickets_count, display_id, rule_id, automation_type_id,agentName }, index) => {
const card = document.createElement("div");
card.style.border = "1px solid #ccc";
card.style.padding = "16px";
card.style.margin = "8px 0"
card.style.fontFamily =
"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif";
card.style.borderRadius = "8px";
card.style.backgroundColor = index === 0 ? "#fff" : "#e5f2fd";
card.style.marginBottom = "10px";
card.style.paddingBottom = "0";
const cardHeader = document.createElement("div");
cardHeader.style.display = "flex";
cardHeader.style.justifyContent = "space-between";
cardHeader.style.alignItems = "center";
// Create a wrapper for the title
const cardTitle = document.createElement("h4");
cardTitle.style.margin = "0";
cardTitle.style.cursor = "pointer";
cardTitle.style.fontSize = "14px";
cardTitle.style.fontFamily = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif";
cardTitle.style.color = "#183247";
cardTitle.style.transition = "color 0.2s ease";
cardTitle.style.fontWeight = "600";
// Create the serial number (position)
if (position) {
const serialNumber = document.createElement("span");
serialNumber.textContent = position + ". ";
serialNumber.style.color = "#183247"; // Keep serial number color fixed
cardTitle.appendChild(serialNumber);
}
// Create the actual name (clickable part)
const titleText = document.createElement("span");
titleText.textContent = name;
titleText.style.color = "#183247";
titleText.style.transition = "color 0.2s ease";
// Add hover effect for only the name
titleText.addEventListener("mouseover", () => {
titleText.style.color = "#007bff"; // Change only name color on hover
});
titleText.addEventListener("mouseout", () => {
titleText.style.color = "#183247"; // Reset name color when not hovering
});
titleText.addEventListener("click", () => {
titleText.style.color = "#ff5733"; // Change title color on click
// let ruleid=rule_id;
console.log("ruleid",rule_id);
// let automationid= automation_type_id;
console.log("automationtypeid",automation_type_id);
GetRules();
async function GetRules() {
// console.log('GetRules called');
try {
const GetRulesResponse = await client.request.invokeTemplate("getid", {
context:
{
ruleid: rule_id ,
automationid:automation_type_id
},
});
const responses = GetRulesResponse.response;
const rulesData = JSON.parse(responses);
console.log("Rules", rulesData);
console.log("Rules", rulesData.summary.conditions);
console.log("Rules", rulesData.summary.actions);
if(automation_type_id === 1||automation_type_id === 3)
{
showPopupCard(rulesData.name, { conditions: rulesData.summary.conditions, actions:rulesData.summary.actions },automation_type_id);
}else{
showPopupCard1(rulesData.name, {performer:rulesData.summary.performer,events:rulesData.summary.events, conditions: rulesData.summary.conditions, actions:rulesData.summary.actions });
}
}
catch (error) {
console.error("Error in getting rules",error);
}
}
});
// Append name to title
cardTitle.appendChild(titleText);
// Append title and actions to the cardHeader
cardHeader.appendChild(cardTitle);
// Create a container for the horizontal line and the gap
const cardContainer = document.createElement("div");
// Style the container to have a background color in the gap
cardContainer.style.backgroundColor = "#f0f0f0"; // Set the background color for the gap (change to desired color)
cardContainer.style.paddingBottom = "20px";
cardContainer.style.marginLeft="-15px";
cardContainer.style.borderRadius = "4px";
cardContainer.style.width="102.7%";
// Create a horizontal line after the cardBody
const horizontalLine = document.createElement("div");
horizontalLine.style.height = "1px"; // Set the height to 1px for a thin line
horizontalLine.style.backgroundColor = "#ccc"; // Set the color of the horizontal line
horizontalLine.style.marginTop = "16px"; // Add space above the line (adjust as needed)
horizontalLine.style.width = "100%"; // Ensure the line stretches the full width of the container
horizontalLine.style.marginLeft="-3px";
function truncateContent(content, maxLength, lines) {
// Truncate the content to the desired number of characters
let truncated = content;
// Adjust for the desired line count and maximum length
if (content.length > maxLength) {
truncated = content.slice(0, maxLength) + "...";
}
// Break content into lines manually for multi-line truncation
const words = truncated.split(" ");
const result = [];
let line = "";
let currentLine = 1;
for (let i = 0; i < words.length; i++) {
if (line.length + words[i].length + 1 <= maxLength / lines) {
line += (line ? " " : "") + words[i];
} else {
result.push(line);
line = words[i];
currentLine++;
if (currentLine > lines) break; // Stop adding more lines if max lines are reached
}
}
if (currentLine <= lines && line) {
result.push(line);
}
return result.join(" ") + (currentLine > lines ? "..." : "");
}
function calculateLastModified(updated_at) {
const updatedDate = new Date(updated_at);
const currentDate = new Date();
const diffInMilliseconds = currentDate - updatedDate;
const seconds = Math.floor(diffInMilliseconds / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
const months = Math.floor(days / 30); // Approximate months
const years = Math.floor(days / 365); // Approximate years
if (years > 0) {
return years === 1 ? "a year ago" : `${years} years ago`;
} else if (months > 0) {
return months === 1 ? "a month ago" : `${months} months ago`;
} else if (days > 0) {
return `${days} day${days > 1 ? "s" : ""} ago`;
} else if (hours > 0) {
return `${hours} hour${hours > 1 ? "s" : ""} ago`;
} else if (minutes > 0) {
return `${minutes} minute${minutes > 1 ? "s" : ""} ago`;
} else {
return "Just now";
}
}
// console.log("updated at",calculateLastModified(updated_at));
// Create a row for "Last Modified"
const lastModifiedRow = document.createElement("div");
lastModifiedRow.style.display = "grid";
lastModifiedRow.style.gridTemplateColumns = "150px 150px 2px 150px 150px 2px 150px 150px"; // Consistent width for each section
lastModifiedRow.style.alignItems = "center";
lastModifiedRow.style.marginTop = "10px";
lastModifiedRow.style.fontSize = "12px";
lastModifiedRow.style.gap = "20px";
lastModifiedRow.style.width = "100%"; // Ensures full width alignment
const lastModifiedLabel = document.createElement("span");
lastModifiedLabel.textContent = "Last Modified :";
lastModifiedLabel.style.color = "#183247";
lastModifiedLabel.style.fontSize = "12px";
lastModifiedLabel.style.display = "inline-flex";
lastModifiedLabel.style.fontFamily =" -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif"
lastModifiedLabel.style.marginLeft = "40px"
const lastModifiedValue = document.createElement("span");
const lastModifiedText = calculateLastModified(updated_at);
lastModifiedValue.textContent = lastModifiedText;
lastModifiedValue.style.color = "#183247";
lastModifiedValue.style.fontWeight = "600";
lastModifiedValue.style.display = "inline-flex";
lastModifiedValue.style.fontSize = "12px";
lastModifiedValue.style.marginLeft = "-50px"
lastModifiedValue.style.justifySelf = "start";
lastModifiedValue.style.fontFamily =" -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif"
const verticalLine = document.createElement("div");
verticalLine.style.height = "20px";
verticalLine.style.borderLeft = "2px solid #ccc";
verticalLine.style.alignSelf = "stretch";
lastModifiedRow.appendChild(lastModifiedLabel);
lastModifiedRow.appendChild(lastModifiedValue);
lastModifiedRow.appendChild(verticalLine);
// const agentsid = last_updated_by;
// console.log("agentsid", agentsid);
// GetAgents();
// async function GetAgents() {
// // console.log('GetAgents called');
// try {
// const GetAgentsResponse = await client.request.invokeTemplate('getAgents', {
// context: { id: agentsid },
// });
// const responses = GetAgentsResponse.response;
// const agentData = JSON.parse(responses);
// console.log("Name:", agentData.contact.name);
const agentNameLabel = document.createElement("span");
agentNameLabel.textContent = "By :";
agentNameLabel.style.fontSize = "12px";
agentNameLabel.style.color = "#183247";
agentNameLabel.style.whiteSpace = "nowrap";
agentNameLabel.style.marginLeft="149px"
agentNameLabel.style.fontFamily =" -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif"
const agentNameValue = document.createElement("span");
agentNameValue.textContent = agentName;
agentNameValue.style.color = "#183247";
agentNameValue.style.fontWeight = "600";
agentNameValue.style.whiteSpace = "nowrap";
agentNameValue.style.fontFamily =" -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif"
const verticalLine2 = document.createElement("div");
verticalLine2.style.height = "20px";
verticalLine2.style.borderLeft = "2px solid #ccc";
verticalLine2.style.alignSelf = "stretch";
verticalLine2.style.marginLeft = "100px"; // Increase for more right shift
lastModifiedRow.appendChild(agentNameLabel);
lastModifiedRow.appendChild(agentNameValue);
lastModifiedRow.appendChild(verticalLine2);
const affectedTicketsLabel = document.createElement("span");
affectedTicketsLabel.textContent = "Impacted tickets (Last 7 days) : ";
affectedTicketsLabel.style.fontSize = "12px";
affectedTicketsLabel.style.color = "#183247";
affectedTicketsLabel.style.marginLeft="140px";
affectedTicketsLabel.style.whiteSpace = "nowrap";
affectedTicketsLabel.style.fontFamily =" -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif"
const affectedTicketsValue = document.createElement("span");
affectedTicketsValue.textContent = affected_tickets_count === 0 ? "--" : affected_tickets_count;
affectedTicketsValue.style.color = "#183247";
affectedTicketsValue.style.fontWeight = "600";
affectedTicketsValue.style.marginLeft ="134px"
affectedTicketsValue.style.whiteSpace = "nowrap";
affectedTicketsValue.style.fontFamily =" -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif"
lastModifiedRow.appendChild(affectedTicketsLabel);
lastModifiedRow.appendChild(affectedTicketsValue);
// }
// catch (error) {
// console.error("Agents error",error);
// if (error.status === 429) {
// console.warn("⚠️API limit exceeded. App will reload 1 minute after");
// document.getElementById("Automation-page").style.display = "none";
// document.getElementById("Workflow-Automation-page").style.display = "none";
// document.getElementById("no_user1").style.display = "block";
// // setTimeout(() => {
// // window.location.reload();
// // }, 30000);
// }
// else if(error.status === 401){
// document.getElementById("Automation-page").style.display = "none";
// document.getElementById("Workflow-Automation-page").style.display = "none";
// document.getElementById("no_user2").style.display = "block";
// }
// }
// }
const cardBody = document.createElement("div"); // Create a container for card content and actions
cardBody.style.display = "flex"; // Flexbox to align items horizontally
cardBody.style.justifyContent = "space-between"; // Ensure there's space between content and actions
cardBody.style.alignItems = "flex-start"; // Align items to the top (optional, depending on your needs)
const truncatedContent = truncateContent(summary, 200, 2);
const cardContent = document.createElement("pre");
cardContent.textContent = truncatedContent;
// Style the card content
cardContent.style.marginTop = "8px";
cardContent.style.padding = "8px";
cardContent.style.color="#183247";
cardContent.style.fontweight="600";
cardContent.style.fontFamily= "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif";
cardContent.style.whiteSpace = "pre-wrap"; // Ensure text wraps
cardContent.style.overflow = "hidden"; // Hide overflow content
cardContent.style.textOverflow = "ellipsis"; // Add ellipsis for overflow
cardContent.style.maxWidth = "75%"; // Limit the card width to half the container's width
cardContent.style.fontSize="12px";
cardContent.style.marginLeft="15px";
// Create the container for card actions
const cardActionsContainer = document.createElement("div");
cardActionsContainer.style.display = "flex"; // Display actions horizontally
cardActionsContainer.style.justifyContent = "flex-end"; // Align to the right
cardActionsContainer.style.marginTop = "10px"; // Add some spacing above the actions
cardActionsContainer.style.gap = "8px"; // Set space between the toggle and the delete icon
// // Add fw-toggle
// const fwToggle = document.createElement("fw-toggle");
// fwToggle.setAttribute("size", "medium");
// fwToggle.setAttribute("checked", "");
// // Add event listener to handle state change
// fwToggle.addEventListener("fwChange", (event) => {
// fwToggle.checked = event.detail.checked; // Keep the state as per user selection
// console.log("Toggle state changed:", fwToggle.checked);
// });
// const fwToggle = document.createElement("fw-toggle");
// fwToggle.setAttribute("size", "medium");
// // Unique key for storing toggle state (Assuming each card has a unique rule ID)
// const ruleId = rule_id; // Ensure rule_id is unique per rule
// const storedState = localStorage.getItem(`toggleState_${ruleId}`);
// if (storedState !== null) {
// fwToggle.checked = storedState === "true"; // Convert string to boolean
// } else {
// fwToggle.setAttribute("checked", ""); // Default state
// }
// // Event listener to update localStorage on state change
// fwToggle.addEventListener("fwChange", (event) => {
// const isChecked = event.detail.checked;
// localStorage.setItem(`toggleState_${ruleId}`, isChecked);
// fwToggle.checked = isChecked; // Ensure UI reflects stored state
// console.log(`Toggle state changed for ${ruleId}:`, isChecked);
// });
// Add fw-icon
const fwIcon = document.createElement("fw-icon");
fwIcon.setAttribute("name", "delete");
fwIcon.setAttribute("size", "18");
fwIcon.style.cursor = "pointer";
fwIcon.style.color = "red"; // Set the color to red
// Add a pointer cursor for interactivity
fwIcon.title = "Delete";
fwIcon.addEventListener("click", () => {
console.log("ruleid inside entity deletion", rule_id);
showDeletePopup(display_id);
function showDeletePopup(display_id) {
currentRuleId = display_id; // Store the rule ID for deletion
document.getElementById("deleteConfirmationPopup").style.display = "flex";
}
function hideDeletePopup() {
document.getElementById("deleteConfirmationPopup").style.display = "none";
}
function removeDeletedRuleFromUI(display_id) {
let ruleCard = document.querySelector(`[data-rule-id="${display_id}"]`);
if (ruleCard) {
ruleCard.remove();
}
}
async function confirmDeletion1(rule_id, automation_type_id) {
console.log("📢 confirmDeletion1 function triggered with rule_id:", rule_id, "and automation_type_id:", automation_type_id);
if (!rule_id || !automation_type_id) {
console.warn("⚠️ Missing rule_id or automation_type_id, aborting function.");
return;
}
try {
console.log("🚀 Sending request to delete rule...");
let getdeleteruleResponse1 = await client.request.invokeTemplate("deleterule", {
context: {
automationid: automation_type_id,
ruleid: rule_id,
},
});
console.log("✅ getdeleteruleResponse:", getdeleteruleResponse1);
if (getdeleteruleResponse1.status === 204) {
console.log("✅ Rule deleted successfully!");
hideDeletePopup();
} else {
console.warn("⚠️ Unexpected response:", getdeleteruleResponse1);
}
} catch (error) {
console.error("❌ Error in confirmDeletion1:", error);
}
}
async function entityconfirmDeletion() {
if (!currentRuleId) return; // Ensure rule ID is available
try {
console.log("Deleting rule with ID:", currentRuleId);
await newRulePloadDB5.delete(currentRuleId);
} catch (error) {
console.warn(` Error deleting record with Display ID ${currentRuleId}, but continuing...`);
const ruleIndex = records.findIndex(record => record.display_id === currentRuleId);
if (ruleIndex !== -1) {
records.splice(ruleIndex, 1);
console.log(`✅ Rule ${currentRuleId} removed from records array.`);
} else {
console.warn(`⚠️ Rule with display_id ${currentRuleId} not found in records array.`);
}
displayGroupedRules(records, containerId)
let toast = document.getElementById('type_toast');
toast.setAttribute('content', 'Rule deleted successfully');
toast.setAttribute('type', 'success');
toast.setAttribute('open', true);
removeDeletedRuleFromUI(currentRuleId);
hideDeletePopup();
}
}
// Attach event listeners
document.getElementById("confirmDeleteBtn").addEventListener("click", async () => {
try {
await confirmDeletion1(rule_id, automation_type_id);
await entityconfirmDeletion();
} catch (error) {
console.error("❌ Error in deletion process:", error);
}
});
document.getElementById("cancelDeleteBtn").addEventListener("click", hideDeletePopup);
});
//
// Append fw-toggle and fw-icon to cardActions
// cardActionsContainer.appendChild(fwToggle);
cardActionsContainer.appendChild(fwIcon);
card.appendChild(cardHeader);
cardBody.appendChild(cardContent);
cardBody.appendChild(cardActionsContainer);
card.appendChild(cardBody);
cardContainer.appendChild(horizontalLine);
// card.appendChild(horizontalLine);
cardContainer.appendChild(lastModifiedRow);
card.appendChild(cardContainer)
groupContainer.appendChild(card);
});
container.appendChild(groupContainer);
});
// Add pagination component
addFwPagination(containerId, records, totalgroup);
}
function addFwPagination(containerId, records, totalgroup) {
console.log('Adding pagination to container:', containerId);
let container = document.getElementById(containerId);
if (!container) {
console.warn(`Container with ID "${containerId}" not found.`);
return;
}
if (totalgroup <= itemsPerPage) {
console.log("Total records are less than or equal to items per page, skipping pagination.");
return;
}
let existingPagination= container.querySelector("#fw-pagination-4");
if (existingPagination) {
existingPagination.remove(); // Remove old pagination if it exists
}
const pagination = document.createElement("fw-pagination");
pagination.id = "fw-pagination-4";
pagination.setAttribute("total", totalgroup);
// pagination1.setAttribute("total", totalPages4 * arrayLength);
// console.log("totalpages",totalPages4 * arrayLength)
pagination.setAttribute("per-page", itemsPerPage);
pagination.setAttribute("page", currentPage);
console.log("Pagination Element:", pagination);
const paginationWrapper = document.createElement("div");
paginationWrapper.style.display = "flex";
paginationWrapper.style.justifyContent = "flex-start";
paginationWrapper.style.alignItems = "center";
paginationWrapper.style.width = "100%";
paginationWrapper.style.marginLeft = "70%";
paginationWrapper.appendChild(pagination);
container.appendChild(paginationWrapper);
pagination.addEventListener("fwChange", (event) => {
console.log("fwChange Event Triggered", event);
currentPage = event.detail.page;
console.log("Updated Page:", currentPage);
// Update the displayed rules for the current container
displayGroupedRules(records, containerId);
});
}
function showPopupCard1(title, content) {
console.log("logPopup" ,content);
const overlay = document.createElement("div");
overlay.style.position = "fixed";
overlay.style.top = "0";
overlay.style.left = "0";
overlay.style.width = "100%";
overlay.style.height = "100%";
overlay.style.backgroundColor = "rgba(0, 0, 0, 0.3)"; // Semi-transparent dark background
overlay.style.backdropFilter = "blur(5px)"; // Apply blur effect
overlay.style.zIndex = "999"; // Ensure it appears above everything else
// Create popup container
const popupContainer = document.createElement("div");
popupContainer.style.position = "fixed";
popupContainer.style.top = "50%";
popupContainer.style.left = "50%";
popupContainer.style.transform = "translate(-50%, -50%)";
popupContainer.style.width = "1000px"; // Increased default width
popupContainer.style.maxWidth = "95%"; // Ensure it fits on smaller screens
popupContainer.style.height = "60vh"; // Use viewport height to limit size
popupContainer.style.backgroundColor = "#fff";
popupContainer.style.border = "1px solid #ccc";
popupContainer.style.boxShadow = "0 4px 8px rgba(0, 0, 0, 0.2)";
popupContainer.style.borderRadius = "12px"; // Increased border radius for a smoother look
popupContainer.style.overflow = "hidden"; // Prevent content overflow
popupContainer.style.fontFamily =
"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif"; // Apply a system font
popupContainer.style.zIndex = "1000";
popupContainer.style.display = "flex";
popupContainer.style.flexDirection = "column";
// Create header for title (fixed position)
const popupHeader = document.createElement("div");
popupHeader.style.padding = "16px 24px";
popupHeader.style.borderBottom = "1px solid #ddd"; // Separate the title visually
popupHeader.style.backgroundColor = "#fff";
popupHeader.style.zIndex = "10"; // Ensure it appears above the scrollable content
// Popup title
const popupTitle = document.createElement("h2");
popupTitle.textContent = title;
popupTitle.style.paddingLeft = "15px"; // Move the title slightly to the right
popupTitle.style.fontSize = "20px";
popupTitle.style.color = "#333";
popupTitle.style.textAlign = "left";
popupHeader.appendChild(popupTitle);
// Content wrapper (flex layout)
const contentWrapper = document.createElement("div");
contentWrapper.style.display = "flex";
contentWrapper.style.flexDirection = "column";
contentWrapper.style.flex = "1"; // Automatically take up available space
contentWrapper.style.overflow = "hidden"; // Prevent content overflow
// Content box (with fixed preview label)
const contentBox = document.createElement("div");
contentBox.style.flex = "1";
contentBox.style.border = "1px solid #ddd";
contentBox.style.borderRadius = "8px";
contentBox.style.backgroundColor = "#f9f9f9";
contentBox.style.padding = "16px";
contentBox.style.margin = "16px 16px"; // Add vertical spacing
contentBox.style.overflow = "hidden"; // Prevent outer scrolling
contentBox.style.marginBottom = "75px"; // Add enough space for the close button
// Preview label and line (sticky inside content box)
const previewLabelContainer = document.createElement("div");
previewLabelContainer.style.position = "sticky"; // Fix inside the content box
previewLabelContainer.style.top = "0"; // Stick to the top
previewLabelContainer.style.backgroundColor = "#f9f9f9"; // Match the content box background
previewLabelContainer.style.zIndex = "1";
previewLabelContainer.style.padding = "8px 0";
const previewLabel = document.createElement("p");
previewLabel.textContent = "Preview"; // Label text
previewLabel.style.fontSize = "16px";
previewLabel.style.fontWeight = "500";
previewLabel.style.color = "#92a2b1";
previewLabel.style.margin = "0";
const lineBelowLabel = document.createElement("hr");
lineBelowLabel.style.border = "none";
lineBelowLabel.style.borderTop = "1px solid #ddd";
lineBelowLabel.style.margin = "8px 0";
previewLabelContainer.appendChild(previewLabel);
previewLabelContainer.appendChild(lineBelowLabel);
// Scrollable content area
const scrollableContent = document.createElement("div");
scrollableContent.style.overflowY = "auto"; // Enable vertical scrolling
scrollableContent.style.height = "calc(100% - 40px)"; // Adjust to fit within the content box
const eventText = document.createElement("div");
eventText.style.marginBottom = "12px";
const createCustomBullet = (text, bulletColor, highlightColor) => {
const listItem = document.createElement("li");
listItem.style.position = "relative"; // For positioning the custom bullet
listItem.style.paddingLeft = "10px"; // Space for custom bullet
// Create the custom double circular bullet using a span element
const bullet = document.createElement("span");
bullet.style.position = "absolute";
bullet.style.left = "-15px"; // Bring the bullet closer to the text (adjust this value)
bullet.style.top = "50%"; // Center the bullet vertically
bullet.style.transform = "translateY(-50%)"; // Center the bullet exactly
bullet.style.width = "12px"; // Outer ring size
bullet.style.height = "12px";
bullet.style.border = `4px solid ${bulletColor || "#dcdfe1"}`; // Outer ring color and border size
bullet.style.borderRadius = "50%"; // Make it a ring (circle with border)
bullet.style.display = "inline-block";
// Create the inner circle (smaller circle inside the outer ring)
const innerBullet = document.createElement("span");
innerBullet.style.position = "absolute";
innerBullet.style.left = "50%";
innerBullet.style.top = "50%";
innerBullet.style.transform = "translate(-50%, -50%)"; // Centering the inner circle
innerBullet.style.width = "2px"; // Inner circle size
innerBullet.style.height = "2px";
// innerBullet.style.backgroundColor = bulletColor || "#dcdfe1"; // Inner circle color
innerBullet.style.borderRadius = "50%"; // Inner circle rounded
innerBullet.style.display = "inline-block";
// Append the inner circle to the outer circle (bullet)
bullet.appendChild(innerBullet);
// Split the text into words
const words = text.split(" ");
// Extract specific words
const firstWord = words.shift(); // Remove first word
const secondWord = words.shift(); // Remove second word
const lastWord = words.pop(); // Extract last word
const remainingText = words.join(" "); // Remaining words (excluding first, second, and last)
// Construct the innerHTML with the second word in black and the last word in highlight color
listItem.innerHTML = `
<span>${firstWord}</span>
<span style="color: black; font-weight: 500;">${secondWord}</span>
${remainingText}
<span style="color: ${highlightColor}; font-weight: 500;">${lastWord}</span>
`;
// Append the custom double circular bullet to the list item
listItem.insertBefore(bullet, listItem.firstChild);
return listItem;
};
// Function to remove HTML tags while preserving spaces
// const stripHTMLWithSpacing = (htmlString) => {
// const tempElement = document.createElement("div");
// tempElement.innerHTML = htmlString;
// return tempElement.textContent.replace(/\s+/g, ' ').trim(); // Ensure proper spacing
// };
// Function to create a styled bullet point for conditions/actions
const createConditionBullet = (condition, bulletColor = "#dcdfe1") => {
// console.log("🔹 Original Condition:", condition); // Log initial condition
const listItem = document.createElement("li");
listItem.style.position = "relative";
listItem.style.paddingLeft = "30px"; // Space for bullet
listItem.style.display = "flex"; // Prevents breaking lines
listItem.style.alignItems = "center"; // Keeps elements aligned
// Create custom bullet
const bullet = document.createElement("span");
bullet.style.position = "absolute";
bullet.style.left = "0";
bullet.style.top = "50%";
bullet.style.transform = "translateY(-50%)";
bullet.style.width = "12px";
bullet.style.height = "12px";
bullet.style.border = `4px solid ${bulletColor || "#dcdfe1"}`;
bullet.style.borderRadius = "50%";
// Inner circle of bullet
const innerBullet = document.createElement("span");
innerBullet.style.position = "absolute";
innerBullet.style.left = "50%";
innerBullet.style.top = "50%";
innerBullet.style.transform = "translate(-50%, -50%)";
innerBullet.style.width = "8px";
innerBullet.style.height = "8px";
innerBullet.style.borderRadius = "50%";
bullet.appendChild(innerBullet);
// **Formatting Condition with Colors**
let formattedCondition = condition
.replace(/<div/g, ' <div') // Add space before <div> tags if missing
.replace(/<div\s+class\s*=\s*["']?SummaryKey["']?\s*>(.*?)<\/div>/gi, ' <span style="color: black; font-weight: 500;">$1</span> ')
.replace(/<div\s+class\s*=\s*["']?SummaryValue["']?\s*>(.*?)<\/div>/gi, ' <span style="color: #00a886; font-weight: 500;">$1</span> ')
.replace(/<div\s+class\s*=\s*["']?SummaryOperator["']?\s*>(.*?)<\/div>/gi, ' <span> $1 </span> ') // Ensure space around operators
.replace(/>\s+</g, '> <') // Ensures space between inline elements
.replace(/\s+/g, ' ') // Remove multiple spaces
.trim(); // Trim any leading/trailing spaces
// console.log("🟢 Formatted Condition (With Colors):", formattedCondition);
// **Convert to Plain Text with Spaces**
// const plainTextCondition = stripHTMLWithSpacing(formattedCondition);
// console.log("🔹 Plain Text Condition (With Spaces):", plainTextCondition);
// // Set bullet first, then append formatted text
listItem.appendChild(bullet);
// Create a span for the condition text (for proper spacing)
const textSpan = document.createElement("span");
textSpan.innerHTML = formattedCondition;
textSpan.style.marginLeft = "-5px"; // Ensure space between bullet and text
listItem.appendChild(textSpan);
console.log("✅ Final List Item InnerHTML:", listItem.innerHTML); // Log final output
return listItem;
};
// Create the heading "Event:"
const eventLabel = document.createElement("p");
eventLabel.textContent = "Event";
eventLabel.style.margin = "0";
eventLabel.style.color = "#00a886"; // Blue color for heading
eventLabel.style.fontWeight = "bold";
eventLabel.style.fontSize = "16px";
// Create the unordered list for the event details
const eventDetail = document.createElement("ul");
eventDetail.style.margin = "8px 0 0 -15px"; // Add margin and indentation
eventDetail.style.color = "#333"; // Normal color for text
eventDetail.style.listStyleType = "none"; // Remove default bullets
eventDetail.style.fontSize = "14px";
// Add event detail with the custom bullet
const eventBullet = createCustomBullet(
"When Ticket is Updated", // Text content
"#2c5cc5", // Bullet color
"#00a886" // Highlight color for the last word
);
eventDetail.appendChild(eventBullet);
// Append the heading and the event detail to the container
eventText.appendChild(eventLabel);
eventText.appendChild(eventDetail);
// Extract performer text (assuming it's a single string)
const performerText = typeof content.performer === "string" ? stripHTML(content.performer) : "";
// Add the performer to the content if it exists
if (performerText) {
console.log("performerText",performerText)
const performerItem = createConditionBullet(content.performer, "#2c5cc5"); // Green bullet for performer
performerItem.style.marginBottom = "10px";
performerItem.style.marginTop = "10px"; // Add space after performer text
performerItem.style.marginLeft = "10px";
performerItem.style.fontSize ="14px";
eventText.appendChild(performerItem);
}
// Add Event data to Event content
const eventArray = (Array.isArray(content.events) && content.events.length)
? content.events
: (Array.isArray(content.eventText) && content.eventText.length)
? content.eventText
: (content.events ? [content.events] : (content.eventText ? [content.eventText] : []));
eventArray.forEach(event => {
if (event) {
const eventItem = createConditionBullet(event, "#2c5cc5");
eventItem.style.marginBottom = "10px";
eventItem.style.marginTop = "10px"; // Add space after performer text
eventItem.style.marginLeft = "10px";
eventItem.style.fontSize ="14px";
eventText.appendChild(eventItem);
}
});
// Create the conditions heading
const conditionText = document.createElement("div");
conditionText.textContent = "Condition";
conditionText.style.marginBottom = "8px";
conditionText.style.fontWeight = "bold";
conditionText.style.color = "#e86f25"; // Green color for conditions heading
conditionText.style.fontSize = "16px";
// Create a container for the conditions list
const conditionsList = document.createElement("ul");
conditionsList.style.margin = "0 0 12px";
conditionsList.style.padding = "8px";
conditionsList.style.border = "1px solid #ddd";
conditionsList.style.borderRadius = "4px";
conditionsList.style.backgroundColor = "#fff";
conditionsList.style.listStyleType = "none"; // Remove default bullet style
conditionsList.style.fontSize = "14px";
// Extract condition sets and operator
const conditionsArray1 = Array.isArray(content.conditions.condition_set_1)
? content.conditions.condition_set_1
: [];
const conditionsArray2 = Array.isArray(content.conditions.condition_set_2)
? content.conditions.condition_set_2
: [];
const operator = content.conditions.operator || "";
console.log("conditions array 1",conditionsArray1);
// // Create condition list container
// const conditionsList = document.createElement("ul");
// conditionsList.style.listStyleType = "none";
// conditionsList.style.padding = "0";
// Add conditions from condition_set_1
conditionsArray1.forEach((condition) => {
if (condition === "AND" || condition === "OR") {
// Add operator as a separate text element
const operatorItem = document.createElement("div");
operatorItem.textContent = condition;
operatorItem.style.color = "#6c757d";
operatorItem.style.margin = "8px 0 5px 29px";
conditionsList.appendChild(operatorItem);
} else {
conditionsList.appendChild(createConditionBullet(condition, "#2c5cc5")); // Blue bullet
}
});
// Add operator between conditions (if available)
if (operator) {
const operatorItem = document.createElement("div");
operatorItem.textContent = operator;
operatorItem.style.color = "#000000";
operatorItem.style.margin = "8px 0";
operatorItem.style.fontSize = "14px";
operatorItem.style.fontweight = "500";
conditionsList.appendChild(operatorItem);
}
// Add conditions from condition_set_2
conditionsArray2.forEach((condition) => {
if (condition === "AND" || condition === "OR") {
const operatorItem = document.createElement("div");
operatorItem.textContent = condition;
operatorItem.style.color = "#6c757d";
operatorItem.style.margin = "8px 0 5px 29px";
conditionsList.appendChild(operatorItem);
} else {
conditionsList.appendChild(createConditionBullet(condition, "#2c5cc5")); // Blue bullet
}
});
// Create actions heading
const actionText = document.createElement("div");
actionText.textContent = "Action";
actionText.style.marginBottom = "8px";
actionText.style.fontWeight = "bold";
actionText.style.color = "#2c5cc5";
actionText.style.fontSize = "16px";
// Create actions content
const actionContent = document.createElement("ul");
actionContent.style.margin = "0";
actionContent.style.padding = "8px";
actionContent.style.border = "1px solid #ddd";
actionContent.style.borderRadius = "4px";
actionContent.style.backgroundColor = "#fff";
actionContent.style.listStyleType = "none";
actionContent.style.fontSize = "14px";
const actionsArray = Array.isArray(content.actions) ? content.actions : [];
// Add actions with custom bullets
actionsArray.forEach((action) => {
if (action === "AND" || action === "OR") {
const operatorItem = document.createElement("div");
operatorItem.textContent = action;
operatorItem.style.color = "#6c757d";
operatorItem.style.margin = "8px 0 5px 29px";
actionContent.appendChild(operatorItem);
} else {
actionContent.appendChild(createConditionBullet(action, "#2c5cc5")); // Blue bullet for actions
}
});
// Append the label and line to the content box
contentBox.appendChild(previewLabel);
contentBox.appendChild(lineBelowLabel);
scrollableContent.appendChild(eventText);
scrollableContent.appendChild(conditionText);
scrollableContent.appendChild(conditionsList);
scrollableContent.appendChild(actionText);
scrollableContent.appendChild(actionContent);
// Append content to the scrollable wrapper
contentBox.appendChild(scrollableContent);
// Create fw-button element with "primary" color
const closeButton = document.createElement("fw-button");
closeButton.setAttribute("color", "primary");
closeButton.textContent = "Close";
closeButton.style.position = "absolute";
closeButton.style.bottom = "16px"; // Distance from the bottom
closeButton.style.right = "16px"; // Distance from the right
closeButton.style.padding = "8px 16px"; // Padding for the button
closeButton.style.borderRadius = "4px"; // Rounded corners
closeButton.style.cursor = "pointer";
// Close popup and remove overlay when the button is clicked
closeButton.addEventListener("click", () => {
document.body.removeChild(popupContainer);
document.body.removeChild(overlay);
});
popupContainer.appendChild(popupHeader); // Fixed title
popupContainer.appendChild(contentBox);
// popupContainer.appendChild(headerContainer); // Fixed preview label and line
// popupContainer.appendChild(wrapper); // Scrollable content
popupContainer.appendChild(closeButton); // Close button
// Append elements to the document
document.body.appendChild(overlay);
document.body.appendChild(popupContainer);
}
const normalizeText5 = (text) => {
return text
? text
.toLowerCase() // Convert everything to lowercase
.split(/\s+/) // Split by spaces
.filter(word => word.trim() !== "") // Remove empty words
.sort() // Sort words alphabetically
.join(" ") // Join words back into a string
: "";
};
// Function to normalize, sort, and format list-based values (Case-Insensitive)
const normalizeList5 = (value, label) => {
if (!value) return "";
const list = value
.toLowerCase() // Convert everything to lowercase
.split(/\s*[,|]\s*/) // Split by commas or pipes (remove spaces)
.map((v) => normalizeText5(v)) // Normalize each item in the list
.sort(); // Sort alphabetically
console.log(`🔹 Normalized ${label}:`, list);
return list.join(",");
};
// Function to find duplicate rules (Case-Insensitive)
function findDuplicateRulestype4(records) {
console.log("function called");
const seenRules = new Map(); // Store unique rules with their first occurrence
const duplicateRecords = []; // Store all duplicate records
// Function to remove all <img> tags from HTML content
const stripImageTags = (html) => html ? html.replace(/<img[^>]*>/gi, "") : "";
records.forEach((record) => {
const { summary, conditions, actions, operator, events, performer, active } = record.data;
if (!active) return; // Skip inactive records
console.log("✅ Active Record:", record);
// Normalize and sort fields (Ensure **case-insensitive** processing)
const normalizedSummary = normalizeText5(summary);
const normalizedConditions = normalizeList5(conditions, "Conditions");
const normalizedActions = normalizeList5(stripImageTags(actions), "Actions");
const normalizedEvents = normalizeList5(events, "Events");
const normalizedPerformer = normalizeList5(performer, "Performer");
const normalizedOperator = operator ? operator.trim().toLowerCase() : null; // Ensure lowercase
console.log("🔹 Normalized Summary:", normalizedSummary);
console.log("🔹 Normalized Conditions:", normalizedConditions);
console.log("🔹 Normalized Actions:", normalizedActions);
console.log("🔹 Normalized Events:", normalizedEvents);
console.log("🔹 Normalized Performer:", normalizedPerformer);
console.log("🔹 Normalized Operator:", normalizedOperator);
// Create a unique key to compare records (All in lowercase now)
const recordKey = `${normalizedSummary}|${normalizedConditions}|${normalizedActions}|${normalizedOperator}|${normalizedEvents}|${normalizedPerformer}`;
console.log("🔍 Generated Record Key:", recordKey);
if (seenRules.has(recordKey)) {
console.log("⚠️ Duplicate Found:", record.display_id);
if (!duplicateRecords.includes(seenRules.get(recordKey))) {
duplicateRecords.push(seenRules.get(recordKey)); // Add original rule
}
duplicateRecords.push(record); // Add duplicate rule
} else {
seenRules.set(recordKey, record);
}
});
return duplicateRecords;
}
async function handleDuplicateRulestype4() {
if (isFetchingType4 || type4 > 0) return; // Stop if already fetching or has run before
isFetchingType4 = true; // Set flag to true before execution starts
console.log("handleDuplicateRulestype4 called");
try {
const duplicatesType4 = await Filterrecords(4); // Get duplicate records
console.log("🔄 Final duplicate records:", duplicatesType4);
displayGroupedRules(duplicatesType4, "TicketUpdates"); // Display grouped rules
type4++; // ✅ Increment count to prevent multiple calls
} catch (error) {
console.error("Error handling duplicate rules for type 4:", error);
} finally {
isFetchingType4 = false; // ✅ Reset flag after execution completes
}
}
async function handleDuplicateRulestype3() {
if (isFetchingType3 || type3 > 0) return; // Stop if already fetching or has run before
isFetchingType3 = true; // Set flag to true before execution starts
console.log("handleDuplicateRulestype3 called");
try {
const duplicatesType3 = await Filterrecords(3); // Get duplicate records
console.log("🔄 Final duplicate records for hourly triggers:", duplicatesType3);
displayGroupedRules(duplicatesType3, "HourlyTriggers"); // Display grouped rules
type3++; // ✅ Increment count to prevent multiple calls
} catch (error) {
console.error("Error handling duplicate rules for type 3:", error);
} finally {
isFetchingType3 = false; // ✅ Reset flag after execution completes
}
}
how role access functionality works?