Enabling mobile for whole page

Hey everyone,

I've been working on a fun little side project that I reckon could be a real time-saver for us all. It's a JavaScript script that I cooked up to automatically enable mobile view for all components on any Retool page.

You can F12 and paste this script in the console, and then just call enableAll() or disableAll() when you're in desktop view.

I've found it super handy in my own workflow and thought it'd be cool to share it with the community. So, check it out! And if you've got any questions or feedback, just give me a shout.

Cheers,
Guy

function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

function getComponentsMenu() {
  return document.querySelector('div[data-testid="Explorer::ComponentTree"]');
}

function getComponentListItems() {
  const menu = getComponentsMenu();
  return menu.querySelectorAll("li");
}

async function enableMobile(header) {
  console.log(`Enabling mobile for ${header.textContent}`);
  header.children[0].click();
  await sleep(500);
  appearanceIcon = document.getElementById(
    `EditorFormSectionV2::${header.textContent.trim()}::Appearance::AdvancedButton`
  );
  if (!appearanceIcon) {
    console.log(`No appearance icon for ${header.textContent}`);
    return;
  }
  appearanceIcon.scrollIntoViewIfNeeded();
  appearanceIcon.click();
  await sleep(500);
  showOnMobileInput = document.getElementById("EditorForm::ShowOnMobileToggle");
  if (showOnMobileInput.checked) {
    console.log(`Mobile already enabled for ${header.textContent}`);
    return;
  }
  showOnMobileInput.click();
}

async function disableMobile(header) {
  console.log(`Disabling mobile for ${header.textContent}`);
  header.children[0].click();
  await sleep(500);
  appearanceIcon = document.getElementById(
    `EditorFormSectionV2::${header.textContent.trim()}::Appearance::AdvancedButton`
  );
  if (!appearanceIcon) {
    console.log(`No appearance icon for ${header.textContent}`);
    return;
  }
  appearanceIcon.scrollIntoViewIfNeeded();
  appearanceIcon.click();
  await sleep(500);
  showOnMobileInput = document.getElementById("EditorForm::ShowOnMobileToggle");
  if (!showOnMobileInput.checked) {
    console.log(`Mobile already disabled for ${header.textContent}`);
    return;
  }
  showOnMobileInput.click();
}

async function disableAll() {
  for (const x of getComponentListItems()) {
    await disableMobile(x);
    await sleep(500);
  }
}

async function enableAll() {
  for (const x of getComponentListItems()) {
    await enableMobile(x);
    await sleep(500);
  }
}
6 Likes

@GuyFrimerman ,

I wonder if you realize just how big the potential of this post is. This is a seminal piece of work! You shown us that we can manipulate the IDE directly through the DOM.

What I envision from this is a Chrome Extension with a bunch of tools on it to do bulk actions like:

  • Toggle Mobile (as your example does)
  • Change label width (
  • Renaming of components
  • Setting Query properties, e.g. Turning off show notification on Success
  • Changing style parameters, e.g. changing all buttons border radius
  • Change alignment
  • Really edit any component property.

To select the components to modify you could probably test if the component is selected in the Component List which would allow you to select multiple components to affect. You could select All buttons or all Text components, you could select by name using a wildcard.

This would need to be an active development project as parts of it may break from release to release.

1 Like

I know it's old, but did this go anywhere? It has some potential to make mass edits of (perhaps groups of) components much easier (let's say I want to hide a bunch of them...or make all items in a form read only since I really only want a couple to be active which I can then activate).

Hey @jg80,

The request not currently being prioritized, but is still expected to be worked on in the future. I logged your plus one!

1 Like

you might need to change some OS or browser specific settings regarding ram/memory usage. careful with how you get html elements as retool is already using lots of memory, so if you end up with copies of all elements it'd be possible to hit a browser or os memory usage limit.

if you use something like document.querySelectorAll("p") you get a list of static elements, its like a snapshot of the elements at that point in time... changes made to the dom aren't reflected in the static list and any changes made to elements in the static list won't be reflected in the dom. consequentially, the static list is a copy of the dom, where as if you use .getElementsByClassName(), .getElementsByName(), getElementsTagName() you get a list of 'live' elements or references instead of copies saving tons of memory.

on older versions of node (~2017) use for instead of forEach and iterators for more memory savings.

keeping these 2 things in mind should keep you out of trouble, but this does depend on the browser/OS and you do need to consider the overhead for the extension itself also.