Plugin / Docs / Favorites & Quick Actions

Favorites & Quick Actions

Speed up QA runs and daily tasks: star pages, pin hosts, group by tags, and run playlists.

Pure client-side · canonical ask(action, args) · respects the allow-list

v7.10.0

2) Minimal request helper (canonical)

One helper across pages gives stable conventions (timeouts, requestId pairing). Includes askBackoff for retries with exponential backoff.

<script>
const ADMIN_ORIGIN='admin', EXT_ORIGIN='extension';
let _seq=0, _waiters=new Map();
addEventListener('message', (e) => {
  const d=e.data; if(!d||typeof d!=='object') return;
  if(d.origin!==EXT_ORIGIN) return;
  if(d.requestId && _waiters.has(d.requestId)) { _waiters.get(d.requestId)(d); _waiters.delete(d.requestId); }
});
function ask(action, args={}, timeoutMs=12000){
  const requestId='r'+(++_seq);
  postMessage({ origin:ADMIN_ORIGIN, type:'RTO_REQUEST', requestId, action, args }, '*');
  return new Promise((resolve,reject)=>{
    const t=setTimeout(()=>{ _waiters.delete(requestId); reject(Object.assign(new Error('timeout'),{code:'TIMEOUT'})); }, timeoutMs);
    _waiters.set(requestId, (resp)=>{ clearTimeout(t); resolve(resp); });
  });
}
async function askBackoff(action, args={}, tries=3, base=300){
  let n=0; while(true){
    try{ const r=await ask(action,args,12000); if(!r.ok) throw Object.assign(new Error(r.error?.message||'error'), r.error||{}); return r; }
    catch(e){ if(++n>=tries) throw e; await new Promise(r=>setTimeout(r, base*Math.pow(2,n-1))); }
  }
}
// Mark this tab as master (fire-and-forget)
try{ postMessage({ origin:ADMIN_ORIGIN, type:'RTO_REQUEST', requestId:'boot1', action:'setMasterTab', args:{} }, '*'); }catch(_){}
</script>

3) Data model (localStorage)

Favorites live in localStorage["rto.favorites"]. Pinned hosts live in localStorage["rto.pins"].

// localStorage["rto.favorites"]
[
  { "id":"fav_1", "title":"Example Dashboard", "url":"https://example.com/dashboard", "host":"example.com", "tags":["daily"], "addedAt":1730000000000 }
]
// localStorage["rto.pins"]
["example.com","docs.example.com"]
Tip: derive host from the URL; use pins to keep key domains at the top and to filter playlists.

4) Star current remote page

Shortcuts: Ctrl/⌘+Shift+S star · Ctrl/⌘+Shift+P run playlist
Important: “Star” requires a controlled remote tab. If it doesn’t exist or getUrl returns empty (or non-HTTPS), nothing is added.

5) Favorites UI

Title Host Tags Actions
Note: “Group by host” only changes rendering — add at least one favorite first (section 4).
Allow-list: if an action yields DOMAIN_NOT_ALLOWED, the banner above appears. Add the host in the extension popup, then press Try again.

6) One-click actions (helpers)

const Fav = {
  openSilent: (url) => ask('open', { url, focus:false }),
  go:         (url) => ask('navigate', { url }),
  goSilentOnce: async (url) => { await ask('suppressNextFocus'); return ask('navigate', { url }); },
  focus:      (url) => ask('focusByUrl', { url }),
  assertOn:   async (prefix) => {
    const r = await ask('getUrl').catch(_=>null);
    return !!r?.data?.url?.startsWith(prefix);
  },
  highlight:  (selector) => ask('runJs', { code:`(function(){
    const el=document.querySelector("${selector.replace(/"/g,'\\"')}"); if(!el) return false;
    el.scrollIntoView({behavior:'smooth',block:'center'});
    el.style.transition='box-shadow .2s'; el.style.boxShadow='0 0 0 4px rgba(13,110,253,.35)';
    setTimeout(()=>el.style.boxShadow='', 1200); return true;
  })()` })
};

7) Playlists from favorites

Run a sequence of favorites filtered by tag. Optionally limit to pinned hosts. Uses askBackoff (demo pattern).

async function runPlaylist(tag='daily', delayMs=700, pinsOnly=false){
  const pins = new Set(_loadPins());
  let favs = (_loadFavs()||[]).filter(f => !tag || (f.tags||[]).includes(tag));
  if (pinsOnly) favs = favs.filter(f => pins.has(f.host));
  if (!favs.length){ notify('No favorites match the filter.', 'warn'); return; }
  for(const f of favs){
    try{
      await askBackoff('navigate', { url:f.url }, 4, 250);
      await askBackoff('waitFor', { selector:'body', timeoutMs:15000 }, 3, 300);
      console.log('Visited:', f.title);
    }catch(e){ _handleActionError(e, f.url); }
    await new Promise(r => setTimeout(r, delayMs));
  }
  notify('Playlist finished ✓','ok');
}

8) Import / Export — when and why

Why use it?
  • Share a “QA” set with the team (Slack/Drive/Git);
  • Back up your favorites before resetting your browser;
  • Version a “daily/weekly” playlist in a repo.

Export: downloads favorites.json containing only your favorites (pinned hosts are not included — pin them again in your context).

Import: reads someone else’s or a backup JSON, merges it with your current favorites, and removes duplicates by URL.

9) Tips & keyboard shortcuts

  • Before acting: call getUrl and assert a prefix, then waitFor a concrete marker (e.g., .ready).
  • Use Focus Master to return to this page after confirmations.
  • Silent one-shot: click “Next navigate is silent” or use “Navigate (silent)” to avoid focus stealing.
  • Tags: think daily / qa / debug to group playlists.
  • Pins: keep critical hosts on top and filter runs with “Pinned hosts only”.
Need help writing safe flows?
Try the ChatGPT helper: Remote Tab Opener Copilot.

Next pages

Page Description
Start Overview, how it works, setup, quick start, and links to all sections.
Detect the Extension Detection contract (ping/pong), install prompts, and graceful fallbacks when the extension isn’t present.
Allow-list & Permissions Deny-by-default model, domain allow-list via popup, and suggested UX to guide users to enable hosts.
LAN / LocalhostHow to safely enable intranet/localhost (flags + allow-list).
Remote Tab Control Open/navigate/focus the controlled tab, read URL/title, select an existing tab, lifecycle & restore patterns.
DOM & Automation Action catalog (domType, domSetValue, domClick, selectSetValue, submitForm, waitFor) and safe interaction tips.
Recipes & Flows Copy-paste flows: login, dashboard checks, tables, filters, playlists, and allow-list banners.
Events Event stream reference, subscription helpers, live logger widget, and basic metrics collection.
Diagnostics Inline console, error cookbook, QA self-check, and performance tips.
Full API Reference Canonical message envelopes, request/response schemas, error codes, and return shapes for every action.
Compatibility Supported browsers/versions, permissions nuances, CSP/iframe notes, and known limitations.
Favorites Star and group URLs, quick actions (open/focus/navigate), export/import sets, and playlist runs from favorites.
Real-World Flows (E2E) End-to-end flows: helper setup, multi-tab, extract, assertions, and troubleshooting.