Better AutomationAnywhere

Enhanced Automation Anywhere developer experience

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

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