Better AutomationAnywhere

Enhanced Automation Anywhere developer experience. Working at CR Version 34.0.0

当前为 2024-11-07 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

作者
Jamir-boop
评分
0 0 0
版本
0.4.3
创建于
2023-10-20
更新于
2024-11-07
大小
31.1 KB
许可证
MIT
适用于

// ==UserScript== // @name Better AutomationAnywhere // @namespace http://tampermonkey.net/ // @version 0.4.3 // @description Enhanced Automation Anywhere developer experience. Working at CR Version 34.0.0 // @author jamir-boop // @match ://.automationanywhere.digital/* // @icon https://cmpc-1dev.my.automationanywhere.digital/favicon.ico // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @license MIT // ==/UserScript==

(function () { "use strict"; let activePredictionIndex = -1; // Track the active (highlighted) prediction let currentPredictionActions = []; // Store current predictions' actions for keyboard navigation

// Universal Copy and Paste functionality with 3 slots

// Register menu commands for selecting copy/paste slots
GM_registerMenuCommand("Copy to Slot 1", () => copyToSlot(1));
GM_registerMenuCommand("Copy to Slot 2", () => copyToSlot(2));
GM_registerMenuCommand("Copy to Slot 3", () => copyToSlot(3));
GM_registerMenuCommand("Paste from Slot 1", () => pasteFromSlot(1));
GM_registerMenuCommand("Paste from Slot 2", () => pasteFromSlot(2));
GM_registerMenuCommand("Paste from Slot 3", () => pasteFromSlot(3));

// Commands and their aliases mapping to functions
const commandsWithAliases = {
    addAction: {
        action: addAction,
        aliases: ["a", "addaction", "add action", "action"],
        description: "Shows actions in sidebar",
    },
    addVariable: {
        action: addVariable,
        aliases: ["adv", "addvar", "add variable"],
        description: "Shows dialog to create a new variable",
    },
    showVariables: {
        action: showVariables,
        aliases: ["v", "showvars", "list variables", "variables"],
        description: "Shows variables in sidebar",
    },
    deleteUnusedVariables: {
        action: deleteUnusedVariables,
        aliases: ["duv", "delete unused", "remove unused variables"],
        description: "Shows dialog to select and delete unused variables",
    },
    updatePackages: {
        action: updatePackages,
        aliases: ["up", "updatepkgs", "upgrade packages"],
        description: "Opens the packages menu and unfolds the updatable items",
    },
    foldAll: {
        action: foldAll,
        aliases: ["fa", "fold all", "collapse all"],
        description: "Folds all sections in the code",
    },
    redirectToPrivateRepository: {
        action: redirectToPrivateRepository,
        aliases: ["p", "private", "private bots"],
        description: "Redirects to the private bots folder",
    },
    redirectToActivityHistorical: {
        action: redirectToActivityHistorical,
        aliases: ["historical", "history","activity historical"],
        description: "Redirects to the activities historical tab",
    },
    showHelp: {
        action: function () {
            showHelp();
        },
        aliases: ["help", "man", "show help"],
        description: "Displays help information for available commands",
    },
};

//============ Command palette START ============
// Helper function to get DOM elements dynamically
function getCommandPalette() {
    return document.getElementById("commandPalette");
}

function getCommandInput() {
    return document.getElementById("commandInput");
}

function getCommandPredictions() {
    return document.getElementById("commandPredictions");
}

// Toggle palette visibility
function togglePaletteVisibility() {
    const commandPalette = getCommandPalette();
    if (commandPalette.classList.contains("command_palette--visible")) {
        commandPalette.classList.remove("command_palette--visible");
        commandPalette.classList.add("command_palette--hidden");
        getCommandInput().value = ""; // Clear input on hide
        clearPredictions(); // Clear predictions on hide
    } else {
        commandPalette.classList.remove("command_palette--hidden");
        commandPalette.classList.add("command_palette--visible");
        getCommandInput().focus(); // Focus on the input field when showing the palette
    }
}

function clearPredictions() {
    getCommandPredictions().innerHTML = "";
}

function updatePredictions(input) {
    clearPredictions();

    if (!input) return;

    Object.entries(commandsWithAliases).forEach(
        ([commandKey, { action, aliases, description }]) => {
            const match = aliases.find((alias) =>
                alias.startsWith(input.toLowerCase()),
            );
            if (match) {
                const predictionItem = document.createElement("div");
                predictionItem.classList.add("command_prediction-item");
                predictionItem.innerHTML = `<strong>${match}</strong> - ${description}`;
                predictionItem.addEventListener("click", () => {
                    getCommandInput().value = match;
                    executeCommand(action);
                    clearPredictions();
                });
                getCommandPredictions().appendChild(predictionItem);
            }
        },
    );
}

// Function to setup event listeners for commandInput
function setupCommandInputEventListeners() {
    const commandInput = getCommandInput(); // Ensure we're getting the current element

    if (commandInput) {
        // Input event listener for updating predictions
        commandInput.addEventListener("input", function () {
            updatePredictions(this.value);
        });

        // Keydown event listener for navigating and selecting predictions
        commandInput.addEventListener("keydown", navigatePredictions);
    }
}

// Execute command function based on input or selected prediction
function executeCommand(action) {
    if (action) {
        action();
    } else {
        showHelp(); // Show help or error if command is unknown
    }
    togglePaletteVisibility(); // Hide palette after executing command
}

function navigatePredictions(e) {
    let commandPredictions = getCommandPredictions();
    const items = commandPredictions.getElementsByClassName(
        "command_prediction-item",
    );
    if (!items.length) {
        if (e.key === "Escape") {
            togglePaletteVisibility();
            e.preventDefault();
        }
        return;
    }

    // Automatically select the prediction if there's only one and Enter is pressed
    if (items.length === 1 && e.key === "Enter") {
        items[0].click(); // Execute the single available command
        e.preventDefault();
        return;
    }

    if (["ArrowDown", "ArrowUp", "Enter"].includes(e.key)) {
        e.preventDefault(); // Prevent default only for navigation keys

        if (e.key === "ArrowDown") {
            activePredictionIndex = (activePredictionIndex + 1) % items.length;
            updateActivePrediction(items);
        } else if (e.key === "ArrowUp") {
            if (activePredictionIndex <= 0) {
                activePredictionIndex = items.length - 1;
            } else activePredictionIndex -= 1;
            updateActivePrediction(items);
        } else if (e.key === "Enter" && activePredictionIndex >= 0) {
            items[activePredictionIndex].click();
        }
    } else if (e.key === "Escape") {
        togglePaletteVisibility();
        e.preventDefault();
    }
}

function updateActivePrediction(items) {
    Array.from(items).forEach((item, index) => {
        item.classList.toggle("active", index === activePredictionIndex);
    });
}

// Toggle command palette visibility with Shift+C
document.addEventListener("keydown", function (e) {
    if (e.altKey && e.key === "p") {
        e.preventDefault();
        //insertCommandPalette();
        insertCustomEditorPaletteButtons();
        togglePaletteVisibility();
    }
});

// Shortcuts to show Actions/Variables
document.addEventListener("keydown", function (e) {
    if (e.code === "KeyA" && e.altKey) {
        addAction();
        e.preventDefault(); // Prevent default action of Alt+A
    }
});

document.addEventListener("keydown", function (e) {
    if (e.code === "KeyV" && e.altKey) {
        showVariables();
        e.preventDefault(); // Prevent default action of Alt+V
    }
});

// Shortcuts to toggle sidebar
document.addEventListener("keydown", function (e) {
    if (e.ctrlKey && e.code === "KeyD") {
        (function () {
            toogleToolbar();
        })();
        e.preventDefault();
    }
});

// Function to toggle toolbar
function toogleToolbar() {
    document
        .querySelector(
            "div.editor-layout__resize:nth-child(2) > button:nth-child(2)",
        )
        .click();
}

// Function to check if toolbar is opened
function checkPaletteState() {
    let paletteElement = document.querySelector(".editor-layout__palette");
    let width = paletteElement.offsetWidth; // Get the actual width

    if (width <= 8) {
        return "closed";
    } else {
        return "opened";
    }
}

// Features
function addAction() {
    const state = checkPaletteState();

    if (state === "closed") {
        toogleToolbar(); // Open the toolbar if it's closed
    }

    try {
        document
            .querySelector(
                "div.editor-palette__accordion:nth-child(2) > div:nth-child(1) > header:nth-child(1) > div:nth-child(1) > button:nth-child(1) > div:nth-child(1) > div:nth-child(2)",
            )
            .click();
    } catch {}
    try {
        document
            .querySelector(
                '.editor-palette-search__cancel button[type="button"][tabindex="-1"]',
            )
            .click();
    } catch {}
}

function addVariable() {
    const state = checkPaletteState();

    if (state === "closed") {
        toogleToolbar(); // Open the toolbar if it's closed
    }

    try {
        const accordion = document.querySelector(
            "div.editor-palette__accordion:nth-child(1)",
        );
        const addButton = accordion.querySelector(
            "header:nth-child(1) button:nth-child(1)",
        );
        addButton.click();
    } catch (error) {}

    try {
        const cancelButton = document.querySelector(
            "div.editor-palette-search__cancel button",
        );
        cancelButton.click();
    } catch (error) {}

    try {
        const createButton = document.querySelector('button[name="create"]');
        createButton.click();
    } catch (error) {}

    try {
        const confirmButton = document.querySelector(
            "div.action-bar--theme_default:nth-child(1) > button:nth-child(2)",
        );
        confirmButton.click();
    } catch (error) {}
}

function showVariables() {
    const state = checkPaletteState();

    if (state === "closed") {
        toogleToolbar(); // Open the toolbar if it's closed
    }
    document
        .querySelector(
            'span.clipped-text.clipped-text--no_wrap.editor-palette-section__header-title[title="Variables"]',
        )
        ?.click();
}

function showTriggers() {
    const state = checkPaletteState();

    if (state === "closed") {
        toogleToolbar(); // Open the toolbar if it's closed
    }
    document
        .querySelector(
            'span.clipped-text.clipped-text--no_wrap.editor-palette-section__header-title[title="Triggers"]',
        )
        ?.click();
}

async function deleteUnusedVariables() {
    showVariables();

    await new Promise(resolve => setTimeout(resolve, 1000));
    let dropdownMenu = document.querySelector("button.action-bar__item--is_menu:nth-child(5)");
    dropdownMenu.click();

    await new Promise(resolve => setTimeout(resolve, 1000));
    let duvButton = document.querySelector(".dropdown-options.g-scroller button.rio-focus--inset_4px:nth-child(2)");
    duvButton.click();
}

function openLinkInNewTab(url) {
    var newWindow = window.open(url, "_blank");
    if (newWindow) {
        newWindow.blur();
        window.focus();
    } else {
        alert("Pop-up blocked. Please allow pop-ups for this website.");
    }
}

function foldAll() {
    const folderClicks = document.querySelectorAll(
        ".taskbot-canvas-list-node__collapser",
    );
    Array.from(folderClicks)
        .reverse()
        .forEach((element) => element.click());
}

function showHelp() {
    // Create modal elements
    const modalOverlay = document.createElement('div');
    const modal = document.createElement('div');
    const modalContent = document.createElement('div');
    const closeButton = document.createElement('button');

    // Set styles for the modal
    modalOverlay.style.position = 'fixed';
    modalOverlay.style.top = '0';
    modalOverlay.style.left = '0';
    modalOverlay.style.width = '100vw';
    modalOverlay.style.height = '100vh';
    modalOverlay.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
    modalOverlay.style.display = 'flex';
    modalOverlay.style.justifyContent = 'center';
    modalOverlay.style.alignItems = 'center';
    modalOverlay.style.zIndex = '1000'; // Ensure it appears above other elements

    modalOverlay.style.fontSize = '16px';

    modal.style.backgroundColor = 'white';
    modal.style.padding = '20px';
    modal.style.borderRadius = '8px';
    modal.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.1)';
    modal.style.maxWidth = '800px';
    modal.style.width = '80%';
    modal.style.position = 'relative';

    // Build the help content from the commandsWithAliases object
    let helpContent = "<h3>List of Commands:</h3><ul>";

    for (let command in commandsWithAliases) {
        const { aliases, description } = commandsWithAliases[command];
        helpContent += `<li><b>${aliases.join(', ')}:</b> ${description}</li>`;
    }

    helpContent += "</ul>";

    modalContent.innerHTML = helpContent;

    closeButton.textContent = 'Close';
    closeButton.style.marginTop = '10px';
    closeButton.style.padding = '8px 16px';
    closeButton.style.border = 'none';
    closeButton.style.backgroundColor = 'var(--color_background_interactive)';
    closeButton.style.color = 'white';
    closeButton.style.cursor = 'pointer';
    closeButton.style.borderRadius = '4px';

    // Append elements
    modal.appendChild(modalContent);
    modal.appendChild(closeButton);
    modalOverlay.appendChild(modal);
    document.body.appendChild(modalOverlay);

    // Close function
    function closeModal() {
        document.body.removeChild(modalOverlay);
    }

    // Close when clicking outside the modal
    modalOverlay.addEventListener('click', (e) => {
        if (e.target === modalOverlay) {
            closeModal();
        }
    });

    // Close on Escape key
    document.addEventListener('keydown', (e) => {
        if (e.key === 'Escape') {
            closeModal();
        }
    });

    // Close on button click
    closeButton.addEventListener('click', closeModal);
}
//============ Command palette stuff END ============

//============ Feat updatePackages stuff START ============
function updatePackages() {
    document
        .querySelector(".rio-icon--icon_three-vertical-dots-meatball-menu")
        .click();

    function clickSpanWithText(text) {
        var spans = document.querySelectorAll(
            "span.clipped-text.clipped-text--no_wrap.dropdown-option-label span.clipped-text__string",
        );
        for (var i = 0; i < spans.length; i++) {
            if (spans[i].textContent.toLowerCase().includes(text.toLowerCase())) {
                spans[i].click();
                break;
            }
        }
    }

    // Call the function with "package"
    clickSpanWithText("packages");

    document
        .querySelectorAll('.package-resource__title[title*="not default"]')
        .forEach((span) => {
            // Simulate a click on the span
            span.click();

            // Wait for the DOM changes to occur after the click, then perform further actions
            setTimeout(() => {
                let versionCell = span.querySelector(
                    ".taskbot-edit-page__package__versions__cell.taskbot-edit-page__package__versions__cell--select",
                );
                if (versionCell) {
                    versionCell.click();

                    // Wait for the dropdown to appear, then perform further actions
                    setTimeout(() => {
                        let option = versionCell.querySelector(
                            '.choice-input-dropdown__options .choice-input-dropdown__option[role="option"]',
                        );
                        if (option) {
                            option.click();
                        }
                    }, 5000); // Adjust the timeout as needed
                }
            }, 3000); // Adjust the timeout as needed
        });
}
//============ Feat updatePackages stuff END ============
//============ Feat snippets START ============
function generateEmojiString() {
    const emojis = [
        "😀",
        "😃",
        "😄",
        "😁",
        "😆",
        "😅",
        "😂",
        "🤣",
        "😊",
        "😇",
        "🙂",
        "🙃",
        "😉",
        "😌",
        "😍",
        "🥰",
        "😘",
        "😗",
        "😙",
        "😚",
        "😋",
        "😛",
        "😝",
        "😜",
        "🤪",
        "🤨",
        "🧐",
        "🤓",
        "😎",
        "🤩",
        "🥳",
        "😏",
        "😒",
        "😞",
        "😔",
        "😟",
        "😕",
        "🙁",
        "😣",
        "😖",
        "😫",
        "😩",
        "🥺",
        "😢",
        "😭",
        "😤",
        "😠",
        "😡",
        "🤬",
        "🤯",
        "😳",
        "🥵",
        "🥶",
        "😱",
        "😨",
        "😰",
        "😥",
        "😓",
        "🤗",
        "🤔",
        "🤭",
        "🤫",
        "🤥",
        "😶",
        "😐",
        "😑",
        "😬",
        "🙄",
        "😯",
        "😦",
        "😧",
        "😮",
        "😲",
        "🥱",
        "😴",
        "🤤",
        "😪",
        "😵",
        "🤐",
        "🥴",
        "🤢",
        "🤮",
        "🤧",
        "😷",
        "🤒",
        "🤕",
        "🤑",
        "🤠",
        "😈",
        "👿",
        "👹",
        "👺",
        "🤡",
        "💩",
        "👻",
        "💀",
        "☠️",
        "👽",
        "👾",
        "🤖",
        "🎃",
        "😺",
        "😸",
        "😹",
        "😻",
        "😼",
        "😽",
        "🙀",
        "😿",
        "😾",
    ];
    let uniqueString = "";

    for (let i = 0; i < 10; i++) {
        uniqueString += emojis[Math.floor(Math.random() * emojis.length)];
    }

    return uniqueString;
}

//============ Feat snippets END ============
//============ Feat custom selector Variables/Actions/Triggers START============

// Define updateActiveButton in the outer scope
function updateActiveButton() {
    const activeSection = document.querySelector(
        ".editor-palette-section__header--is_active .clipped-text__string--for_presentation",
    )?.innerText;
    const buttons = document.querySelectorAll(".customActionVariableButton");

    buttons.forEach((button) => {
        if (button.textContent === activeSection) {
            button.classList.add("buttonToolbarActive");
        } else {
            button.classList.remove("buttonToolbarActive");
        }
    });
}

function insertCustomEditorPaletteButtons() {
    if (document.getElementById("customActionVariableButtons")) {
        console.log("Custom buttons already added.");
        return;
    }

    const containerDiv = document.createElement("div");
    containerDiv.id = "customActionVariableButtons";

    const variableButton = document.createElement("button");
    variableButton.className = "customActionVariableButton";
    variableButton.textContent = "Variables";
    variableButton.onclick = function () {
        showVariables();
        updateActiveButton();
    };

    const actionButton = document.createElement("button");
    actionButton.className = "customActionVariableButton";
    actionButton.textContent = "Actions";
    actionButton.onclick = function () {
        addAction();
        updateActiveButton();
    };

    const triggerButton = document.createElement("button");
    triggerButton.className = "customActionVariableButton";
    triggerButton.textContent = "Triggers";
    triggerButton.onclick = function () {
        showTriggers();
        updateActiveButton();
    };

    containerDiv.appendChild(variableButton);
    containerDiv.appendChild(actionButton);
    containerDiv.appendChild(triggerButton);

    const palette = document.querySelector(".editor-layout__palette");
    if (palette) {
        palette.appendChild(containerDiv);
    } else {
        console.log(".editor-layout__palette not found.");
        return;
    }

    const style = document.createElement("style");
    style.textContent = `
    #customActionVariableButtons {
        display: flex;
        width: 100%;
        height: 38px !important;
        background: white;
    }
    #customActionVariableButtons button {
        all: unset;
        font-size: .85rem;
        font-weight: 300;
        cursor: pointer;
        margin: 4px;
        border-radius: 5px;
        border: 1px solid transparent;
        background-color: transparent;
        color: #3c5e83;
        flex-grow: 1;
        text-align: center;
        transition: background-color 0.3s;
    }
    #customActionVariableButtons button:hover {
        background-color: #dae9f3;
    }
    .buttonToolbarActive {
        border: 1px solid #3c5e83 !important;
        text-shadow: 0.5px 0 0 #3c5e83 , -0.01px 0 0 #3c5e83 !important;
    }
    .editor-palette.g-box-sizing_border-box {
        margin-top: 38px;
    }
`;
    document.head.appendChild(style);
}
//============ Feat custom selector Variables/Actions/Triggers END============
//============ Feat UNIVERSAL COPY/PASTE START============
// Function to copy data to the specified slot
function copyToSlot(slot) {
    // Trigger the copy action in the UI
    const copyButton = document.querySelector(".aa-icon-action-clipboard-copy--shared");
    if (copyButton) {
        copyButton.click();

        // Retrieve the JSON string from localStorage
        const globalClipboardJSON = localStorage.getItem('globalClipboard');

        // Parse the JSON and store it in the specific slot using Tampermonkey storage
        try {
            const clipboardData = JSON.parse(globalClipboardJSON);
            clipboardData.uid = "🔥🔥🔥"; // Reset UID
            GM_setValue(`universalClipboardSlot${slot}`, JSON.stringify(clipboardData));
        } catch (error) {
            console.error("Failed to copy data to slot:", error);
        }
    }
}

// Function to paste data from the specified slot
function pasteFromSlot(slot) {
    // Retrieve the JSON string from the specified slot in Tampermonkey storage
    const clipboardData = GM_getValue(`universalClipboardSlot${slot}`);

    if (!clipboardData) {
        alert(`No data in Slot ${slot}`);
        return;
    }

    // Generate a new unique ID for this session
    let emojiUid = generateEmojiString();

    // Replace the UID and store it back into localStorage
    let modifiedData = clipboardData.replace(/🔥🔥🔥/g, emojiUid);
    localStorage.setItem('globalClipboard', modifiedData);
    localStorage.setItem('globalClipboardUid', `"${emojiUid}"`);

    // Ensure the paste button is available
    const pasteButton = document.querySelector(".aa-icon-action-clipboard-paste--shared");
    if (pasteButton) {
        // Trigger the paste action
        setTimeout(() => {
            pasteButton.click();
        }, 500); // Adjust the timeout as needed
    }
}

function insertUniversalCopyPasteButtons(attempt = 1) {
    setTimeout(() => {
        const actionBar = document.querySelector('.action-bar--theme_info');

        // If actionBar is found and the buttons have not been added yet
        if (actionBar && !actionBar.querySelector('.universalCopy')) {
            const separator = document.createElement('div');
            separator.className = 'action-bar__separator';
            actionBar.appendChild(separator);

            // Create the Universal Copy button
            const copyButton = document.createElement('button');
            copyButton.className = 'universalCopy rio-focus rio-focus--inset_0 rio-focus--border-radius_4px rio-focus--has_element-focus-visible rio-bare-button g-reset-element rio-bare-button--rio_interactive-softest rio-bare-button--is_parent rio-bare-button--is_clickable rio-bare-button--size_14px rio-bare-button--is_square rio-bare-button--square_26x26 action-bar__item action-bar__item--is_action taskbot-editor__toolbar__action';
            copyButton.setAttribute('data-button-loading', 'false');
            copyButton.setAttribute('data-button-working', 'false');
            copyButton.setAttribute('data-button-ready', 'true');
            copyButton.setAttribute('name', 'shared-clipboard-copy');
            copyButton.setAttribute('type', 'button');
            copyButton.setAttribute('tabindex', '-1');
            copyButton.setAttribute('aria-label', 'Copy to shared clipboard');
            copyButton.setAttribute('data-poppy-parentid', '1');
            copyButton.innerHTML = `<span class="icon fa fa-rocket icon--block"></span>`;
            copyButton.title = 'Universal Copy';
            copyButton.onclick = universalCopy;
            actionBar.appendChild(copyButton);

            // Create the Universal Paste button
            const pasteButton = document.createElement('button');
            pasteButton.className = 'universalPaste rio-focus rio-focus--inset_0 rio-focus--border-radius_4px rio-focus--has_element-focus-visible rio-bare-button g-reset-element rio-bare-button--rio_interactive-softest rio-bare-button--is_parent rio-bare-button--is_clickable rio-bare-button--size_14px rio-bare-button--is_square rio-bare-button--square_26x26 action-bar__item action-bar__item--is_action taskbot-editor__toolbar__action';
            pasteButton.setAttribute('data-button-loading', 'false');
            pasteButton.setAttribute('data-button-working', 'false');
            pasteButton.setAttribute('data-button-ready', 'true');
            pasteButton.setAttribute('name', 'shared-clipboard-paste');
            pasteButton.setAttribute('type', 'button');
            pasteButton.setAttribute('tabindex', '-1');
            pasteButton.setAttribute('aria-label', 'Paste from shared clipboard');
            pasteButton.setAttribute('data-poppy-parentid', '1');
            pasteButton.innerHTML = `<span class="icon fa fa-rocket icon--block" style="transform: rotate(180deg);"></span>`;
            pasteButton.title = 'Universal Paste';
            pasteButton.onclick = universalPaste;
            actionBar.appendChild(pasteButton);
        } else if (attempt < 3) {
            // If not found, retry up to 3 times
            insertUniversalCopyPasteButtons(attempt + 1);
        }
    }, 1000 * attempt); // Delay increases with each attempt
}


function universalCopy() {
    // Trigger the copy action in the UI
    document.querySelector(".aa-icon-action-clipboard-copy--shared").click();

    // Retrieve the JSON string from local storage
    const globalClipboardJSON = localStorage.getItem('globalClipboard');

    // Parse the JSON string into an object
    let globalClipboard = {};
    try {
        globalClipboard = JSON.parse(globalClipboardJSON);
    } catch(e) {
        console.error("Error parsing JSON:", e);
        return;  // Exit if there is a parsing error
    }

    // Update the "uid" key to 🔥🔥🔥
    globalClipboard.uid = "🔥🔥🔥";

    // Stringify the modified object and store it in Tampermonkey storage
    GM_setValue('universalClipboard', JSON.stringify(globalClipboard));
}

function universalPaste() {
    // Click on copy to activate paste button
    document.querySelector(".aa-icon-action-clipboard-copy--shared").click();

    // Retrieve the JSON string from Tampermonkey storage
    let universalClipboard = GM_getValue('universalClipboard')

    // Write the JSON string to local storage after replacing single quotes and UID
    if (universalClipboard) {
        let emojiUid = generateEmojiString();
        universalClipboard = universalClipboard.replace(/'/g, '"');
        universalClipboard = universalClipboard.replace(/🔥🔥🔥/g, emojiUid);

        localStorage.setItem("globalClipboard", universalClipboard);
        localStorage.setItem("globalClipboardUid", `"${emojiUid}"`);
    }

    // Wait for a second before triggering the paste action
    setTimeout(() => {
        document.querySelector(".aa-icon-action-clipboard-paste--shared").click();
    }, 1000);
}
//============ Feat UNIVERSAL COPY/PASTE END============
//============ Feat redirect utility START ============
function redirectToPath(targetPath) {
    const currentUrl = window.location.href;

    // Match the base URL, keeping everything up to the first part of the domain and protocol.
    const pattern = /^(https:\/\/[^\/]*\.automationanywhere\.digital)/;

    // Extract the base URL using the pattern
    const match = currentUrl.match(pattern);

    if (match) {
        const baseUrl = match[1]; // Get the base URL (e.g., https://aa-saleseng-us-4sbx.cloud.automationanywhere.digital)
        const newUrl = baseUrl + targetPath; // Append the target path
        window.location.href = newUrl; // Redirect to the new URL
    } else {
        console.error("Pattern didn't match. The URL might not be in the expected format.");
    }
}

// Function to redirect to the private bots repository
function redirectToPrivateRepository() {
    const privateBotsPath = '/#/bots/repository/private/';
    redirectToPath(privateBotsPath);
}

// Function to redirect to the activity historical page
function redirectToActivityHistorical() {
    const activityHistoricalPath = '/#/activity/historical/';
    redirectToPath(activityHistoricalPath);
}
//============ Feat redirect utility END ============
//============ Feat insert command palette START ============
// Insterts the command palette
function insertCommandPalette(retryCount = 0) {
    // Check if the palette was already inserted
    if (document.querySelector("#commandPalette")) {
        console.log("Command palette already inserted.");
        return;
    }

    // Create the container div and set its inner HTML
    const containerDiv = document.createElement("div");
    containerDiv.id = "commandPalette";
    containerDiv.className = "command_palette--hidden";
    containerDiv.innerHTML = `
        <input type="text" id="commandInput" placeholder="Enter command...">
        <div id="commandPredictions" class="command_predictions"></div>
    `;

    // Append the container div to the body
    document.body.appendChild(containerDiv);

    // Create and insert CSS
    const css = `
        #commandPalette * {
            font-size: 1.15rem;
            font-family: Museo Sans,sans-serif;
        }

        #commandPalette {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background-color: white;
            border-radius: 10px 10px 0 0;
            display: flex;
            flex-direction: column;
            align-items: center;
            min-width: 30vw;
            max-width: 80vw;
            width: 600px;
            z-index: 99999;

            box-shadow: 0px 0px 0px 5000px #00000054;
        }

        #commandInput,
        #commandInput:focus-visible,
        #commandInput:active {
            unset: all;
            padding: 10px;
            width: 93%;
            margin-bottom: 10px;
            border: 2px solid transparent;
            border-radius: 5px;
        }

        #commandPalette:focus,
        #commandPalette:active {
            border-color: orange;
        }

        #commandPredictions {
            position: absolute;
            top: 100%;
            left: 0;
            width: 100%;
            background-color: white;
            box-shadow: 0 4px 8px rgba(0,0,0,0.1);
            border-radius: 0 0 10px 10px;
            max-height: 200px;
            overflow-y: auto;
            z-index: 100000;
        }

        .command_prediction-item.active {
            background-color: #f0f0f0;
        }

        .command_prediction-item strong {
            font-weight: bold;
        }

        .command_prediction-item {
            padding: 8px;
            cursor: pointer;
            border-bottom: 1px solid #eee;
        }

        .command_prediction-item:hover,
        .command_prediction-item.active {
            background-color: #f0f0f0;
        }

        @keyframes fadeIn {
            from { opacity: 0; transform: translate(-50%, -50%) scale(0.85); }
            to { opacity: 1; transform: translate(-50%, -50%) scale(1); }
        }

        @keyframes fadeOut {
            from { opacity: 1; transform: translate(-50%, -50%) scale(1); }
            to { opacity: 0; transform: translate(-50%, -50%) scale(0.95); }
        }

        .command_palette--visible {
            display: block;
            animation: fadeIn 0.25s ease-out forwards;
        }

        .command_palette--hidden {
            animation: fadeOut 0.25s ease-out forwards;
            display: none;
            pointer-events: none;
            opacity: 0;
            z-index: -1;
        }
    `;

    const style = document.createElement("style");
    style.type = "text/css";
    style.appendChild(document.createTextNode(css));
    document.head.appendChild(style);

    setupCommandInputEventListeners();

    // Check if the palette was successfully inserted, and if not, retry
    if (!document.querySelector("#commandPalette")) {
        if (retryCount < 5) {
            console.log(`Insert failed, retrying... (${retryCount + 1}/5)`);
            setTimeout(() => insertCommandPalette(retryCount + 1), 3000);
        } else {
            console.error("Failed to insert command palette after 5 retries.");
        }
    } else {
        console.log("Command palette successfully inserted.");
    }
}
//============ Feat insert command palette END ============

//============ Call insert functions START ============
function executeStartFunctionsRepeatedly() {
    let count = 0;
    const intervalId = setInterval(() => {
        insertCommandPalette();
        insertCustomEditorPaletteButtons();
        setInterval(function () {updateActiveButton();}, 1000);
        insertUniversalCopyPasteButtons();

        count++;
        if (count >= 3) {
            clearInterval(intervalId);
        }
    }, 5000); // Execute every 5 seconds
}

if (document.readyState === "loading") {
    // The document is still loading, wait for DOMContentLoaded
    document.addEventListener(
        "DOMContentLoaded",
        executeStartFunctionsRepeatedly,
    );
} else {
    // The `DOMContentLoaded` event has already fired, execute immediately
    executeStartFunctionsRepeatedly();
}

let lastHref = document.location.href;
setInterval(function () {
    const currentHref = document.location.href;

    if (lastHref !== currentHref) {
        lastHref = currentHref;
        insertCommandPalette();
        insertCustomEditorPaletteButtons();
        insertUniversalCopyPasteButtons();
    }
}, 5000);

//============ Call insert functions END ============

})();