Better AutomationAnywhere

Enhanced Automation Anywhere developer experience

当前为 2024-10-01 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Better AutomationAnywhere
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.3.0
  5. // @description Enhanced Automation Anywhere developer experience
  6. // @author jamir-boop
  7. // @match *://*.automationanywhere.digital/*
  8. // @icon https://cmpc-1dev.my.automationanywhere.digital/favicon.ico
  9. // @grant GM_setValue
  10. // @grant GM_getValue
  11. // @grant GM_registerMenuCommand
  12. // @license MIT
  13. // ==/UserScript==
  14.  
  15. (function () {
  16. "use strict";
  17. let activePredictionIndex = -1; // Track the active (highlighted) prediction
  18. let currentPredictionActions = []; // Store current predictions' actions for keyboard navigation
  19.  
  20. // Universal Copy and Paste functionality with 3 slots
  21.  
  22. // Register menu commands for selecting copy/paste slots
  23. GM_registerMenuCommand("Copy to Slot 1", () => copyToSlot(1));
  24. GM_registerMenuCommand("Copy to Slot 2", () => copyToSlot(2));
  25. GM_registerMenuCommand("Copy to Slot 3", () => copyToSlot(3));
  26. GM_registerMenuCommand("Paste from Slot 1", () => pasteFromSlot(1));
  27. GM_registerMenuCommand("Paste from Slot 2", () => pasteFromSlot(2));
  28. GM_registerMenuCommand("Paste from Slot 3", () => pasteFromSlot(3));
  29.  
  30. // Commands and their aliases mapping to functions
  31. const commandsWithAliases = {
  32. addAction: {
  33. action: addAction,
  34. aliases: ["a", "addaction", "add action", "action"],
  35. description: "Opens and focus the actions input field",
  36. },
  37. addVariable: {
  38. action: addVariable,
  39. aliases: ["adv", "addvar", "add variable"],
  40. description: "Add a new variable",
  41. },
  42. showVariables: {
  43. action: showVariables,
  44. aliases: ["v", "showvars", "list variables", "variables"],
  45. description: "Show all variables",
  46. },
  47. deleteUnusedVariables: {
  48. action: deleteUnusedVariables,
  49. aliases: ["duv", "delete unused", "remove unused variables"],
  50. description: "Delete unused variables",
  51. },
  52. updatePackages: {
  53. action: updatePackages,
  54. aliases: ["up", "updatepkgs", "upgrade packages"],
  55. description: "Update all packages",
  56. },
  57. foldAll: {
  58. action: foldAll,
  59. aliases: ["fa", "fold all", "collapse all"],
  60. description: "Fold all sections in the code",
  61. },
  62. redirectToPrivateRepository: {
  63. action: redirectToPrivateRepository,
  64. aliases: ["p", "private", "private bots"],
  65. description: "Redirects to the private bots folder.",
  66. },
  67. redirectToActivityHistorical: {
  68. action: redirectToActivityHistorical,
  69. aliases: ["h", "historical", "activity historical"],
  70. description: "Redirects to the activities historical tab.",
  71. },
  72. showHelp: {
  73. action: function () {
  74. showHelp();
  75. },
  76. aliases: ["help", "show help"],
  77. description: "Displays help information for available commands",
  78. },
  79. };
  80.  
  81. //============ Command palette START ============
  82. // Helper function to get DOM elements dynamically
  83. function getCommandPalette() {
  84. return document.getElementById("commandPalette");
  85. }
  86.  
  87. function getCommandInput() {
  88. return document.getElementById("commandInput");
  89. }
  90.  
  91. function getCommandPredictions() {
  92. return document.getElementById("commandPredictions");
  93. }
  94.  
  95. // Toggle palette visibility
  96. function togglePaletteVisibility() {
  97. const commandPalette = getCommandPalette();
  98. if (commandPalette.classList.contains("command_palette--visible")) {
  99. commandPalette.classList.remove("command_palette--visible");
  100. commandPalette.classList.add("command_palette--hidden");
  101. getCommandInput().value = ""; // Clear input on hide
  102. clearPredictions(); // Clear predictions on hide
  103. } else {
  104. commandPalette.classList.remove("command_palette--hidden");
  105. commandPalette.classList.add("command_palette--visible");
  106. getCommandInput().focus(); // Focus on the input field when showing the palette
  107. }
  108. }
  109.  
  110. function clearPredictions() {
  111. getCommandPredictions().innerHTML = "";
  112. }
  113.  
  114. function updatePredictions(input) {
  115. clearPredictions();
  116.  
  117. if (!input) return;
  118.  
  119. Object.entries(commandsWithAliases).forEach(
  120. ([commandKey, { action, aliases, description }]) => {
  121. const match = aliases.find((alias) =>
  122. alias.startsWith(input.toLowerCase()),
  123. );
  124. if (match) {
  125. const predictionItem = document.createElement("div");
  126. predictionItem.classList.add("command_prediction-item");
  127. predictionItem.innerHTML = `<strong>${match}</strong> - ${description}`;
  128. predictionItem.addEventListener("click", () => {
  129. getCommandInput().value = match;
  130. executeCommand(action);
  131. clearPredictions();
  132. });
  133. getCommandPredictions().appendChild(predictionItem);
  134. }
  135. },
  136. );
  137. }
  138.  
  139. // Function to setup event listeners for commandInput
  140. function setupCommandInputEventListeners() {
  141. const commandInput = getCommandInput(); // Ensure we're getting the current element
  142.  
  143. if (commandInput) {
  144. // Input event listener for updating predictions
  145. commandInput.addEventListener("input", function () {
  146. updatePredictions(this.value);
  147. });
  148.  
  149. // Keydown event listener for navigating and selecting predictions
  150. commandInput.addEventListener("keydown", navigatePredictions);
  151. }
  152. }
  153.  
  154. // Execute command function based on input or selected prediction
  155. function executeCommand(action) {
  156. if (action) {
  157. action();
  158. } else {
  159. showHelp(); // Show help or error if command is unknown
  160. }
  161. togglePaletteVisibility(); // Hide palette after executing command
  162. }
  163.  
  164. function navigatePredictions(e) {
  165. let commandPredictions = getCommandPredictions();
  166. const items = commandPredictions.getElementsByClassName(
  167. "command_prediction-item",
  168. );
  169. if (!items.length) {
  170. if (e.key === "Escape") {
  171. togglePaletteVisibility();
  172. e.preventDefault();
  173. }
  174. return;
  175. }
  176.  
  177. // Automatically select the prediction if there's only one and Enter is pressed
  178. if (items.length === 1 && e.key === "Enter") {
  179. items[0].click(); // Execute the single available command
  180. e.preventDefault();
  181. return;
  182. }
  183.  
  184. if (["ArrowDown", "ArrowUp", "Enter"].includes(e.key)) {
  185. e.preventDefault(); // Prevent default only for navigation keys
  186.  
  187. if (e.key === "ArrowDown") {
  188. activePredictionIndex = (activePredictionIndex + 1) % items.length;
  189. updateActivePrediction(items);
  190. } else if (e.key === "ArrowUp") {
  191. if (activePredictionIndex <= 0) {
  192. activePredictionIndex = items.length - 1;
  193. } else activePredictionIndex -= 1;
  194. updateActivePrediction(items);
  195. } else if (e.key === "Enter" && activePredictionIndex >= 0) {
  196. items[activePredictionIndex].click();
  197. }
  198. } else if (e.key === "Escape") {
  199. togglePaletteVisibility();
  200. e.preventDefault();
  201. }
  202. }
  203.  
  204. function updateActivePrediction(items) {
  205. Array.from(items).forEach((item, index) => {
  206. item.classList.toggle("active", index === activePredictionIndex);
  207. });
  208. }
  209.  
  210. // Toggle command palette visibility with Shift+C
  211. document.addEventListener("keydown", function (e) {
  212. if (e.altKey && e.key === "p") {
  213. e.preventDefault();
  214. //insertCommandPalette();
  215. insertCustomEditorPaletteButtons();
  216. togglePaletteVisibility();
  217. }
  218. });
  219.  
  220. // Shortcuts to show Actions/Variables
  221. document.addEventListener("keydown", function (e) {
  222. if (e.code === "KeyA" && e.altKey) {
  223. addAction();
  224. e.preventDefault(); // Prevent default action of Alt+A
  225. }
  226. });
  227.  
  228. document.addEventListener("keydown", function (e) {
  229. if (e.code === "KeyV" && e.altKey) {
  230. showVariables();
  231. e.preventDefault(); // Prevent default action of Alt+V
  232. }
  233. });
  234.  
  235. // Shortcuts to toggle sidebar
  236. document.addEventListener("keydown", function (e) {
  237. if (e.ctrlKey && e.code === "KeyD") {
  238. (function () {
  239. toogleToolbar();
  240. })();
  241. e.preventDefault();
  242. }
  243. });
  244.  
  245. // Function to toggle toolbar
  246. function toogleToolbar() {
  247. document
  248. .querySelector(
  249. "div.editor-layout__resize:nth-child(2) > button:nth-child(2)",
  250. )
  251. .click();
  252. }
  253.  
  254. // Function to check if toolbar is opened
  255. function checkPaletteState() {
  256. let paletteElement = document.querySelector(".editor-layout__palette");
  257. let width = paletteElement.offsetWidth; // Get the actual width
  258.  
  259. if (width <= 8) {
  260. return "closed";
  261. } else {
  262. return "opened";
  263. }
  264. }
  265.  
  266. // Features
  267. function addAction() {
  268. const state = checkPaletteState();
  269.  
  270. if (state === "closed") {
  271. toogleToolbar(); // Open the toolbar if it's closed
  272. }
  273.  
  274. try {
  275. document
  276. .querySelector(
  277. "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)",
  278. )
  279. .click();
  280. } catch {}
  281. try {
  282. document
  283. .querySelector(
  284. '.editor-palette-search__cancel button[type="button"][tabindex="-1"]',
  285. )
  286. .click();
  287. } catch {}
  288. }
  289.  
  290. function addVariable() {
  291. const state = checkPaletteState();
  292.  
  293. if (state === "closed") {
  294. toogleToolbar(); // Open the toolbar if it's closed
  295. }
  296.  
  297. try {
  298. const accordion = document.querySelector(
  299. "div.editor-palette__accordion:nth-child(1)",
  300. );
  301. const addButton = accordion.querySelector(
  302. "header:nth-child(1) button:nth-child(1)",
  303. );
  304. addButton.click();
  305. } catch (error) {}
  306.  
  307. try {
  308. const cancelButton = document.querySelector(
  309. "div.editor-palette-search__cancel button",
  310. );
  311. cancelButton.click();
  312. } catch (error) {}
  313.  
  314. try {
  315. const createButton = document.querySelector('button[name="create"]');
  316. createButton.click();
  317. } catch (error) {}
  318.  
  319. try {
  320. const confirmButton = document.querySelector(
  321. "div.action-bar--theme_default:nth-child(1) > button:nth-child(2)",
  322. );
  323. confirmButton.click();
  324. } catch (error) {}
  325. }
  326.  
  327. function showVariables() {
  328. const state = checkPaletteState();
  329.  
  330. if (state === "closed") {
  331. toogleToolbar(); // Open the toolbar if it's closed
  332. }
  333. document
  334. .querySelector(
  335. 'span.clipped-text.clipped-text--no_wrap.editor-palette-section__header-title[title="Variables"]',
  336. )
  337. ?.click();
  338. }
  339.  
  340. function showTriggers() {
  341. const state = checkPaletteState();
  342.  
  343. if (state === "closed") {
  344. toogleToolbar(); // Open the toolbar if it's closed
  345. }
  346. document
  347. .querySelector(
  348. 'span.clipped-text.clipped-text--no_wrap.editor-palette-section__header-title[title="Triggers"]',
  349. )
  350. ?.click();
  351. }
  352.  
  353. function deleteUnusedVariables() {
  354. const state = checkPaletteState();
  355.  
  356. if (state === "closed") {
  357. toogleToolbar(); // Open the toolbar if it's closed
  358. }
  359. const accordion = document.querySelector(
  360. "div.editor-palette__accordion:nth-child(1)",
  361. );
  362. const addButton = accordion.querySelector(
  363. "header:nth-child(1) button:nth-child(1)",
  364. );
  365. addButton.click();
  366. const menuButton = document.querySelector(
  367. "button.action-bar__item--is_menu:nth-child(5)",
  368. );
  369. menuButton.click();
  370. const deleteButton = document.querySelector(
  371. "button.rio-focus--inset_4px:nth-child(2)",
  372. );
  373. deleteButton.click();
  374. }
  375.  
  376. function openLinkInNewTab(url) {
  377. var newWindow = window.open(url, "_blank");
  378. if (newWindow) {
  379. newWindow.blur();
  380. window.focus();
  381. } else {
  382. alert("Pop-up blocked. Please allow pop-ups for this website.");
  383. }
  384. }
  385.  
  386. function foldAll() {
  387. const folderClicks = document.querySelectorAll(
  388. ".taskbot-canvas-list-node__collapser",
  389. );
  390. Array.from(folderClicks)
  391. .reverse()
  392. .forEach((element) => element.click());
  393. }
  394.  
  395. function showHelp() {
  396. alert(
  397. "List of commands:\n" +
  398. "a, addaction: Shows and focuses the actions input field\n" +
  399. "adv, addvar: Adds a new variable\n" +
  400. "v, showvars: Shows all variables\n" +
  401. "duv, delete unused: Deletes unused variables\n" +
  402. "up, updatepkgs: Updates all packages\n" +
  403. "fa, fold all: Folds all sections in the code\n" +
  404. "help, h: Displays this help information",
  405. );
  406. }
  407. //============ Command palette stuff END ============
  408.  
  409. //============ Feat updatePackages stuff START ============
  410. function updatePackages() {
  411. document
  412. .querySelector(".rio-icon--icon_three-vertical-dots-meatball-menu")
  413. .click();
  414.  
  415. function clickSpanWithText(text) {
  416. var spans = document.querySelectorAll(
  417. "span.clipped-text.clipped-text--no_wrap.dropdown-option-label span.clipped-text__string",
  418. );
  419. for (var i = 0; i < spans.length; i++) {
  420. if (spans[i].textContent.toLowerCase().includes(text.toLowerCase())) {
  421. spans[i].click();
  422. break;
  423. }
  424. }
  425. }
  426.  
  427. // Call the function with "package"
  428. clickSpanWithText("packages");
  429.  
  430. document
  431. .querySelectorAll('.package-resource__title[title*="not default"]')
  432. .forEach((span) => {
  433. // Simulate a click on the span
  434. span.click();
  435.  
  436. // Wait for the DOM changes to occur after the click, then perform further actions
  437. setTimeout(() => {
  438. let versionCell = span.querySelector(
  439. ".taskbot-edit-page__package__versions__cell.taskbot-edit-page__package__versions__cell--select",
  440. );
  441. if (versionCell) {
  442. versionCell.click();
  443.  
  444. // Wait for the dropdown to appear, then perform further actions
  445. setTimeout(() => {
  446. let option = versionCell.querySelector(
  447. '.choice-input-dropdown__options .choice-input-dropdown__option[role="option"]',
  448. );
  449. if (option) {
  450. option.click();
  451. }
  452. }, 5000); // Adjust the timeout as needed
  453. }
  454. }, 3000); // Adjust the timeout as needed
  455. });
  456. }
  457. //============ Feat updatePackages stuff END ============
  458. //============ Feat snippets START ============
  459. function generateEmojiString() {
  460. const emojis = [
  461. "😀",
  462. "😃",
  463. "😄",
  464. "😁",
  465. "😆",
  466. "😅",
  467. "😂",
  468. "🤣",
  469. "😊",
  470. "😇",
  471. "🙂",
  472. "🙃",
  473. "😉",
  474. "😌",
  475. "😍",
  476. "🥰",
  477. "😘",
  478. "😗",
  479. "😙",
  480. "😚",
  481. "😋",
  482. "😛",
  483. "😝",
  484. "😜",
  485. "🤪",
  486. "🤨",
  487. "🧐",
  488. "🤓",
  489. "😎",
  490. "🤩",
  491. "🥳",
  492. "😏",
  493. "😒",
  494. "😞",
  495. "😔",
  496. "😟",
  497. "😕",
  498. "🙁",
  499. "😣",
  500. "😖",
  501. "😫",
  502. "😩",
  503. "🥺",
  504. "😢",
  505. "😭",
  506. "😤",
  507. "😠",
  508. "😡",
  509. "🤬",
  510. "🤯",
  511. "😳",
  512. "🥵",
  513. "🥶",
  514. "😱",
  515. "😨",
  516. "😰",
  517. "😥",
  518. "😓",
  519. "🤗",
  520. "🤔",
  521. "🤭",
  522. "🤫",
  523. "🤥",
  524. "😶",
  525. "😐",
  526. "😑",
  527. "😬",
  528. "🙄",
  529. "😯",
  530. "😦",
  531. "😧",
  532. "😮",
  533. "😲",
  534. "🥱",
  535. "😴",
  536. "🤤",
  537. "😪",
  538. "😵",
  539. "🤐",
  540. "🥴",
  541. "🤢",
  542. "🤮",
  543. "🤧",
  544. "😷",
  545. "🤒",
  546. "🤕",
  547. "🤑",
  548. "🤠",
  549. "😈",
  550. "👿",
  551. "👹",
  552. "👺",
  553. "🤡",
  554. "💩",
  555. "👻",
  556. "💀",
  557. "☠️",
  558. "👽",
  559. "👾",
  560. "🤖",
  561. "🎃",
  562. "😺",
  563. "😸",
  564. "😹",
  565. "😻",
  566. "😼",
  567. "😽",
  568. "🙀",
  569. "😿",
  570. "😾",
  571. ];
  572. let uniqueString = "";
  573.  
  574. for (let i = 0; i < 10; i++) {
  575. uniqueString += emojis[Math.floor(Math.random() * emojis.length)];
  576. }
  577.  
  578. return uniqueString;
  579. }
  580. //============ Feat snippets END ============
  581. //============ Feat custom selector Variables/Actions/Triggers START============
  582.  
  583. // Define updateActiveButton in the outer scope
  584. function updateActiveButton() {
  585. const activeSection = document.querySelector(
  586. ".editor-palette-section__header--is_active .clipped-text__string--for_presentation",
  587. )?.innerText;
  588. const buttons = document.querySelectorAll(".customActionVariableButton");
  589.  
  590. buttons.forEach((button) => {
  591. if (button.textContent === activeSection) {
  592. button.classList.add("buttonToolbarActive");
  593. } else {
  594. button.classList.remove("buttonToolbarActive");
  595. }
  596. });
  597. }
  598.  
  599. function insertCustomEditorPaletteButtons() {
  600. if (document.getElementById("customActionVariableButtons")) {
  601. console.log("Custom buttons already added.");
  602. return;
  603. }
  604.  
  605. const containerDiv = document.createElement("div");
  606. containerDiv.id = "customActionVariableButtons";
  607.  
  608. const variableButton = document.createElement("button");
  609. variableButton.className = "customActionVariableButton";
  610. variableButton.textContent = "Variables";
  611. variableButton.onclick = function () {
  612. showVariables();
  613. updateActiveButton();
  614. };
  615.  
  616. const actionButton = document.createElement("button");
  617. actionButton.className = "customActionVariableButton";
  618. actionButton.textContent = "Actions";
  619. actionButton.onclick = function () {
  620. addAction();
  621. updateActiveButton();
  622. };
  623.  
  624. const triggerButton = document.createElement("button");
  625. triggerButton.className = "customActionVariableButton";
  626. triggerButton.textContent = "Triggers";
  627. triggerButton.onclick = function () {
  628. showTriggers();
  629. updateActiveButton();
  630. };
  631.  
  632. containerDiv.appendChild(variableButton);
  633. containerDiv.appendChild(actionButton);
  634. containerDiv.appendChild(triggerButton);
  635.  
  636. const palette = document.querySelector(".editor-layout__palette");
  637. if (palette) {
  638. palette.appendChild(containerDiv);
  639. } else {
  640. console.log(".editor-layout__palette not found.");
  641. return;
  642. }
  643.  
  644. const style = document.createElement("style");
  645. style.textContent = `
  646. #customActionVariableButtons {
  647. display: flex;
  648. width: 100%;
  649. height: 38px !important;
  650. background: white;
  651. }
  652. #customActionVariableButtons button {
  653. all: unset;
  654. font-size: .85rem;
  655. font-weight: 300;
  656. cursor: pointer;
  657. margin: 4px;
  658. border-radius: 5px;
  659. border: 1px solid transparent;
  660. background-color: transparent;
  661. color: #3c5e83;
  662. flex-grow: 1;
  663. text-align: center;
  664. transition: background-color 0.3s;
  665. }
  666. #customActionVariableButtons button:hover {
  667. background-color: #dae9f3;
  668. }
  669. .buttonToolbarActive {
  670. border: 1px solid #3c5e83 !important;
  671. text-shadow: 0.5px 0 0 #3c5e83 , -0.01px 0 0 #3c5e83 !important;
  672. }
  673. .editor-palette.g-box-sizing_border-box {
  674. margin-top: 38px;
  675. }
  676. `;
  677. document.head.appendChild(style);
  678. }
  679. //============ Feat custom selector Variables/Actions/Triggers END============
  680. //============ Feat UNIVERSAL COPY/PASTE START============
  681. // Function to copy data to the specified slot
  682. function copyToSlot(slot) {
  683. // Trigger the copy action in the UI
  684. const copyButton = document.querySelector(".aa-icon-action-clipboard-copy--shared");
  685. if (copyButton) {
  686. copyButton.click();
  687.  
  688. // Retrieve the JSON string from localStorage
  689. const globalClipboardJSON = localStorage.getItem('globalClipboard');
  690.  
  691. // Parse the JSON and store it in the specific slot using Tampermonkey storage
  692. try {
  693. const clipboardData = JSON.parse(globalClipboardJSON);
  694. clipboardData.uid = "🔥🔥🔥"; // Reset UID
  695. GM_setValue(`universalClipboardSlot${slot}`, JSON.stringify(clipboardData));
  696. } catch (error) {
  697. console.error("Failed to copy data to slot:", error);
  698. }
  699. }
  700. }
  701.  
  702. // Function to paste data from the specified slot
  703. function pasteFromSlot(slot) {
  704. // Retrieve the JSON string from the specified slot in Tampermonkey storage
  705. const clipboardData = GM_getValue(`universalClipboardSlot${slot}`);
  706.  
  707. if (!clipboardData) {
  708. alert(`No data in Slot ${slot}`);
  709. return;
  710. }
  711.  
  712. // Generate a new unique ID for this session
  713. let emojiUid = generateEmojiString();
  714.  
  715. // Replace the UID and store it back into localStorage
  716. let modifiedData = clipboardData.replace(/🔥🔥🔥/g, emojiUid);
  717. localStorage.setItem('globalClipboard', modifiedData);
  718. localStorage.setItem('globalClipboardUid', `"${emojiUid}"`);
  719.  
  720. // Ensure the paste button is available
  721. const pasteButton = document.querySelector(".aa-icon-action-clipboard-paste--shared");
  722. if (pasteButton) {
  723. // Trigger the paste action
  724. setTimeout(() => {
  725. pasteButton.click();
  726. }, 500); // Adjust the timeout as needed
  727. }
  728. }
  729.  
  730. function insertUniversalCopyPasteButtons(attempt = 1) {
  731. setTimeout(() => {
  732. const actionBar = document.querySelector('.action-bar--theme_info');
  733.  
  734. // If actionBar is found and the buttons have not been added yet
  735. if (actionBar && !actionBar.querySelector('.universalCopy')) {
  736. const separator = document.createElement('div');
  737. separator.className = 'action-bar__separator';
  738. actionBar.appendChild(separator);
  739.  
  740. const copyButton = document.createElement('button');
  741. 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--size_14px rio-bare-button--is_square rio-bare-button--square_26x26 rio-bare-button--is_clickable rio-bare-button--rio_interactive-whisper';
  742. copyButton.innerHTML = `<div class="icon-button-icon"><span class="icon fa fa-rocket icon--block icon-button-icon__icon"></span></div>`;
  743. copyButton.title = 'Universal Copy';
  744. copyButton.onclick = universalCopy;
  745. actionBar.appendChild(copyButton);
  746.  
  747. const pasteButton = document.createElement('button');
  748. 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--size_14px rio-bare-button--is_square rio-bare-button--square_26x26 rio-bare-button--is_clickable rio-bare-button--rio_interactive-whisper';
  749. pasteButton.innerHTML = `<div class="icon-button-icon"><span class="icon fa fa-rocket icon--block icon-button-icon__icon" style="transform: rotate(180deg);"></span></div>`;
  750. pasteButton.title = 'Universal Paste';
  751. pasteButton.onclick = universalPaste;
  752. actionBar.appendChild(pasteButton);
  753. } else if (attempt < 3) {
  754. // If not found, retry up to 3 times
  755. insertUniversalCopyPasteButtons(attempt + 1);
  756. }
  757. }, 1000 * attempt); // Delay increases with each attempt
  758. }
  759.  
  760. function universalCopy() {
  761. // Trigger the copy action in the UI
  762. document.querySelector(".aa-icon-action-clipboard-copy--shared").click();
  763.  
  764. // Retrieve the JSON string from local storage
  765. const globalClipboardJSON = localStorage.getItem('globalClipboard');
  766.  
  767. // Parse the JSON string into an object
  768. let globalClipboard = {};
  769. try {
  770. globalClipboard = JSON.parse(globalClipboardJSON);
  771. } catch(e) {
  772. console.error("Error parsing JSON:", e);
  773. return; // Exit if there is a parsing error
  774. }
  775.  
  776. // Update the "uid" key to 🔥🔥🔥
  777. globalClipboard.uid = "🔥🔥🔥";
  778.  
  779. // Stringify the modified object and store it in Tampermonkey storage
  780. GM_setValue('universalClipboard', JSON.stringify(globalClipboard));
  781. }
  782.  
  783. function universalPaste() {
  784. // Click on copy to activate paste button
  785. document.querySelector(".aa-icon-action-clipboard-copy--shared").click();
  786.  
  787. // Retrieve the JSON string from Tampermonkey storage
  788. let universalClipboard = GM_getValue('universalClipboard')
  789.  
  790. // Write the JSON string to local storage after replacing single quotes and UID
  791. if (universalClipboard) {
  792. let emojiUid = generateEmojiString();
  793. universalClipboard = universalClipboard.replace(/'/g, '"');
  794. universalClipboard = universalClipboard.replace(/🔥🔥🔥/g, emojiUid);
  795.  
  796. localStorage.setItem("globalClipboard", universalClipboard);
  797. localStorage.setItem("globalClipboardUid", `"${emojiUid}"`);
  798. }
  799.  
  800. // Wait for a second before triggering the paste action
  801. setTimeout(() => {
  802. document.querySelector(".aa-icon-action-clipboard-paste--shared").click();
  803. }, 1000);
  804. }
  805. //============ Feat UNIVERSAL COPY/PASTE END============
  806. //============ Feat redirect utility START ============
  807. function redirectToPath(targetPath) {
  808. const currentUrl = window.location.href;
  809.  
  810. // Match the base URL, keeping everything up to the first part of the domain and protocol.
  811. const pattern = /^(https:\/\/[^\/]*\.automationanywhere\.digital)/;
  812.  
  813. // Extract the base URL using the pattern
  814. const match = currentUrl.match(pattern);
  815.  
  816. if (match) {
  817. const baseUrl = match[1]; // Get the base URL (e.g., https://aa-saleseng-us-4sbx.cloud.automationanywhere.digital)
  818. const newUrl = baseUrl + targetPath; // Append the target path
  819. window.location.href = newUrl; // Redirect to the new URL
  820. } else {
  821. console.error("Pattern didn't match. The URL might not be in the expected format.");
  822. }
  823. }
  824.  
  825. // Function to redirect to the private bots repository
  826. function redirectToPrivateRepository() {
  827. const privateBotsPath = '/#/bots/repository/private/';
  828. redirectToPath(privateBotsPath);
  829. }
  830.  
  831. // Function to redirect to the activity historical page
  832. function redirectToActivityHistorical() {
  833. const activityHistoricalPath = '/#/activity/historical/';
  834. redirectToPath(activityHistoricalPath);
  835. }
  836. //============ Feat redirect utility END ============
  837. //============ Feat insert command palette START ============
  838. // Insterts the command palette
  839. function insertCommandPalette(retryCount = 0) {
  840. // Check if the palette was already inserted
  841. if (document.querySelector("#commandPalette")) {
  842. console.log("Command palette already inserted.");
  843. return;
  844. }
  845.  
  846. // Create the container div and set its inner HTML
  847. const containerDiv = document.createElement("div");
  848. containerDiv.id = "commandPalette";
  849. containerDiv.className = "command_palette--hidden";
  850. containerDiv.innerHTML = `
  851. <input type="text" id="commandInput" placeholder="Enter command...">
  852. <div id="commandPredictions" class="command_predictions"></div>
  853. `;
  854.  
  855. // Append the container div to the body
  856. document.body.appendChild(containerDiv);
  857.  
  858. // Create and insert CSS
  859. const css = `
  860. #commandPalette * {
  861. font-size: 1.15rem;
  862. font-family: Museo Sans,sans-serif;
  863. }
  864.  
  865. #commandPalette {
  866. position: fixed;
  867. top: 50%;
  868. left: 50%;
  869. transform: translate(-50%, -50%);
  870. background-color: white;
  871. border-radius: 10px 10px 0 0;
  872. display: flex;
  873. flex-direction: column;
  874. align-items: center;
  875. min-width: 30vw;
  876. max-width: 80vw;
  877. width: 600px;
  878. z-index: 99999;
  879.  
  880. box-shadow: 0px 0px 0px 5000px #00000054;
  881. }
  882.  
  883. #commandInput,
  884. #commandInput:focus-visible,
  885. #commandInput:active {
  886. unset: all;
  887. padding: 10px;
  888. width: 93%;
  889. margin-bottom: 10px;
  890. border: 2px solid transparent;
  891. border-radius: 5px;
  892. }
  893.  
  894. #commandPalette:focus,
  895. #commandPalette:active {
  896. border-color: orange;
  897. }
  898.  
  899. #commandPredictions {
  900. position: absolute;
  901. top: 100%;
  902. left: 0;
  903. width: 100%;
  904. background-color: white;
  905. box-shadow: 0 4px 8px rgba(0,0,0,0.1);
  906. border-radius: 0 0 10px 10px;
  907. max-height: 200px;
  908. overflow-y: auto;
  909. z-index: 100000;
  910. }
  911.  
  912. .command_prediction-item.active {
  913. background-color: #f0f0f0;
  914. }
  915.  
  916. .command_prediction-item strong {
  917. font-weight: bold;
  918. }
  919.  
  920. .command_prediction-item {
  921. padding: 8px;
  922. cursor: pointer;
  923. border-bottom: 1px solid #eee;
  924. }
  925.  
  926. .command_prediction-item:hover,
  927. .command_prediction-item.active {
  928. background-color: #f0f0f0;
  929. }
  930.  
  931. @keyframes fadeIn {
  932. from { opacity: 0; transform: translate(-50%, -50%) scale(0.85); }
  933. to { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  934. }
  935.  
  936. @keyframes fadeOut {
  937. from { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  938. to { opacity: 0; transform: translate(-50%, -50%) scale(0.95); }
  939. }
  940.  
  941. .command_palette--visible {
  942. display: block;
  943. animation: fadeIn 0.25s ease-out forwards;
  944. }
  945.  
  946. .command_palette--hidden {
  947. animation: fadeOut 0.25s ease-out forwards;
  948. display: none;
  949. pointer-events: none;
  950. opacity: 0;
  951. z-index: -1;
  952. }
  953. `;
  954.  
  955. const style = document.createElement("style");
  956. style.type = "text/css";
  957. style.appendChild(document.createTextNode(css));
  958. document.head.appendChild(style);
  959.  
  960. setupCommandInputEventListeners();
  961.  
  962. // Check if the palette was successfully inserted, and if not, retry
  963. if (!document.querySelector("#commandPalette")) {
  964. if (retryCount < 5) {
  965. console.log(`Insert failed, retrying... (${retryCount + 1}/5)`);
  966. setTimeout(() => insertCommandPalette(retryCount + 1), 3000);
  967. } else {
  968. console.error("Failed to insert command palette after 5 retries.");
  969. }
  970. } else {
  971. console.log("Command palette successfully inserted.");
  972. }
  973. }
  974. //============ Feat insert command palette END ============
  975.  
  976. //============ Call insert functions START ============
  977. function executeStartFunctionsRepeatedly() {
  978. let count = 0;
  979. const intervalId = setInterval(() => {
  980. insertCommandPalette();
  981. insertCustomEditorPaletteButtons();
  982. setInterval(function () {updateActiveButton();}, 1000);
  983. insertUniversalCopyPasteButtons();
  984.  
  985. count++;
  986. if (count >= 3) {
  987. clearInterval(intervalId);
  988. }
  989. }, 5000); // Execute every 5 seconds
  990. }
  991.  
  992. if (document.readyState === "loading") {
  993. // The document is still loading, wait for DOMContentLoaded
  994. document.addEventListener(
  995. "DOMContentLoaded",
  996. executeStartFunctionsRepeatedly,
  997. );
  998. } else {
  999. // The `DOMContentLoaded` event has already fired, execute immediately
  1000. executeStartFunctionsRepeatedly();
  1001. }
  1002.  
  1003. let lastHref = document.location.href;
  1004. setInterval(function () {
  1005. const currentHref = document.location.href;
  1006.  
  1007. if (lastHref !== currentHref) {
  1008. lastHref = currentHref;
  1009. insertCommandPalette();
  1010. insertCustomEditorPaletteButtons();
  1011. insertUniversalCopyPasteButtons();
  1012. }
  1013. }, 5000);
  1014.  
  1015. //============ Call insert functions END ============
  1016. })();