Skip to content

feat: UI redesign, side panel, keyword editor, context menu & live preview#5

Open
raffelino wants to merge 33 commits intomasterfrom
feature/ui-redesign
Open

feat: UI redesign, side panel, keyword editor, context menu & live preview#5
raffelino wants to merge 33 commits intomasterfrom
feature/ui-redesign

Conversation

@raffelino
Copy link
Copy Markdown
Collaborator

Summary

Complete UI overhaul and feature expansion of the RobotFramework Recorder extension.

UI Redesign

  • Converted popup to Chrome Side Panel (persistent, docked)
  • Fluid layout adapting to panel width
  • Brand color scheme (blue #0091FF), Inter + JetBrains Mono fonts
  • Card-based settings, compact icon toolbar
  • Real extension favicon on all pages

Structured Keyword Editor (Actions View)

  • Keywords displayed as cards with category colors (🌐 Navigation, 👆 Interaction, ⏳ Wait, 🔢 Assertion)
  • Named parameters (SELECTOR, TEXT, URL, BROWSER, STATE, etc.)
  • Full-width parameter inputs with type-based coloring (locators blue, URLs green)
  • Keyword spec for RF Browser + SeleniumLibrary (~40 keywords)

Context Menu

  • Right-click on any element → Copy Selector, Add Click/Fill/Hover
  • Assertions: Element Visible, Text Equals, Element Count, Page Contains
  • Waits: Wait Visible/Hidden/Attached
  • Control Structures: IF/ELSE, FOR, WHILE, TRY/EXCEPT (RF 5+ syntax)

Extract Keyword & Resource Export

  • Select recorded actions → wrap in a named custom keyword
  • Auto-detects ${variables} as keyword arguments
  • Export as .resource library file with Settings section

Live Preview

  • Script container visible during recording (not just after stop)
  • Actions appear in real-time as user interacts with the page

Bug Fixes

  • Actions view not loading: translations.js loaded as regular script but uses ES module exports → SyntaxError
  • Live updates broken: chrome.storage.local.onChanged only passes (changes), not (changes, area)
  • [object Object] in status bar: raw response objects displayed instead of strings
  • Pause-resume bug: resolveActiveTab overwrote recordTab with extension popup tabs

Tests

  • 107 tests total (64 unit + 43 E2E), all passing
  • Headless E2E support: HEADLESS=1 npx playwright test
  • Docker E2E support maintained

- Rewrite background.js with handler registry pattern (15 handlers)
- Modernize popup.js with declarative state machine
- Extract shared clipboard.js module
- Fix P0 bugs: missing statusMessage keys, package.json main typo, stray backtick
- Fix extension tab overwriting recordTab (pause/resume bug)
- Update all deps: ESLint 9 (flat config), Mocha 10, Playwright 1.50, c8, Husky 9
- Modernize CI: GitHub Actions v4, Node 20
- Add theme.css design system with dark/light theme support
- Add 23 Playwright E2E tests (record, scan, pause/resume, export, settings, xpath)
- Add Docker E2E infrastructure (Dockerfile.test, docker-compose, Xvfb)
- 64 unit tests + 23 E2E tests all passing
- Replace popup with Chrome Side Panel (persistent, docked)
- Fluid layout (no fixed width, adapts to panel size)
- Script lines as card-like rows with left accent border on hover
- Controls appear on hover only (cleaner look)
- Larger font size for script content (13px)
- More generous spacing throughout
- Bug: translations.js loaded as regular script but uses ES module exports
  → SyntaxError killed the entire page, no actions rendered
- Bug: chrome.storage.local.onChanged only passes (changes), not (changes, area)
  → area check always true → live updates never arrived
- Fix: import translations via ES module in actions-view.js
- Fix: use chrome.storage.onChanged (top-level) for proper area parameter
- Added 7 E2E tests for actions view (load, URL, refresh, copy, clear,
  live updates, per-line copy)
- Total: 90 tests (64 unit + 26 E2E)
- New keyword-spec.js: metadata for RF Browser + SeleniumLibrary keywords
  (parameter names, types, categories, icons)
- Actions view renders structured cards instead of flat text lines
- Each card shows: keyword badge with category color, named parameter
  fields (SELECTOR, TEXT, URL, BROWSER, STATE, etc.)
- Parameter inputs use full width, locator values blue, URLs green
- Copy/delete controls per card
- Delete button removes line and updates storage
…resource export

Context Menu (right-click on any page element):
- Copy Best Selector (XPath)
- Add Click / Fill Text / Hover
- Assertions: Element Visible, Text Equals, Element Count, Page Contains
- Waits: Wait Visible / Hidden / Attached
- Control Structures: IF/ELSE, FOR, WHILE, TRY/EXCEPT
- Works with both RF Browser and SeleniumLibrary

Extract Keyword:
- Select recorded actions → wrap in a named keyword
- Auto-detects ${variables} → generates [Arguments]
- Replaces script with keyword call
- Downloads .resource file with keyword definition

Export .resource:
- Exports all custom keywords + current script as RF resource library
- Includes Settings section with correct Library import

New E2E tests (12):
- 6 context menu tests (click, assertion, IF, FOR, wait, append)
- 6 extract keyword tests (buttons exist, extract stores, replaces
  script, control structures render)
Total: 102 tests (64 unit + 38 E2E)
- Script container now visible during record, resume, and pause states
- handleAppend generates live script preview after each action
  (storage.set({ script }) triggers popup update via onChanged listener)
- Actions appear in the side panel in real-time as user interacts
- 5 new E2E tests: container visible during record/pause, actions
  appear live, preview updates incrementally, content persists after stop
- Total: 107 tests (64 unit + 43 E2E)
…pport

- Bug: displayStatus(resp) showed raw {ok:true} objects as '[object Object]'
  → Fixed: skip object display in updateValueByMessage, don't pass
    sendMessage response to displayStatus
- Replaced inline SVG logo with actual extension icon (mark-32.png)
- Added favicon to popup.html, actions-view.html, options.html
- Headless E2E: set HEADLESS=1 env var to use --headless=new
  (Chrome 112+ supports extensions in new headless mode)
- Docker mode automatically uses headless
- Fixed flaky live-preview test (reset to idle state before recording)
- ↑↓✕ buttons: smaller (22px), no padding overflow, proper colors
- Controls stay inside the script-line-row (overflow: hidden)
- Hover states: subtle highlight, danger red on delete
- Loading overlay: shows icon + spinner while JS initializes,
  fades out once UI is ready
- Replaced Google Fonts (Inter, JetBrains Mono) with system font stack
- No more blocking network requests on panel open
- System fonts render instantly, no FOUT (flash of unstyled text)
- Extension works fully offline
- Sans: -apple-system, BlinkMacSystemFont, Segoe UI, system-ui
- Mono: ui-monospace, SF Mono, Cascadia Code, Fira Code, Consolas
- Added chrome.action.onClicked fallback to explicitly call
  sidePanel.open() when setPanelBehavior wasn't registered in time
  (happens on fresh install before service worker is fully active)
- Added missing @Keyframes spin — spinner wasn't animating
- Replaced openPanelOnActionClick with explicit action.onClicked handler
  (openPanelOnActionClick silently fails when SW isn't ready yet)
- Added sidePanel.setOptions() on SW startup for reliable path registration
- Loading overlay now uses inline styles — visible before CSS/JS loads
- Inline @Keyframes for spin + pulse animations
- Moved overlay removal to finally{} block — always runs even on error
- Added 3s safety timeout in inline script — overlay auto-removes
  regardless of JS init success/failure
- Added console.error for init failures (visible in DevTools)
- handleError() in background.js: logger.debug → console.error
- content.js xpath error: logger.debug → console.error
- actions-view.js: silent catch(_e) → console.warn
- actions-view.js init: added .catch() to promise chain
- All catch blocks now log to console at appropriate level
- Reverted action.onClicked approach — it required SW to be fully
  loaded before the panel could open (caused blank panel for seconds)
- openPanelOnActionClick is a persistent Chrome setting, handled
  natively at browser level without waiting for SW startup
- Set via setPanelBehavior at SW top-level AND in onInstalled listener
- Also call setOptions to ensure panel path is always configured
- MV3 CSP blocks inline scripts and inline styles
- Moved loading overlay back to CSS classes (no inline style=)
- Moved 3s safety timeout from inline <script> to popup.js (external)
- All animations defined in style.css (@Keyframes spin, loading-pulse)
…al render

- Removed loading overlay entirely (was causing more problems than solving)
- stop/pause/resume buttons start with class=hidden in HTML
  (no longer depends on JS toggle() to hide them)
- Status field has default text 'Ready' in HTML
- No inline styles, no inline scripts, no SVG inline
- Page renders immediately with just HTML + CSS files
- JS enhances after load but isn't needed for initial visibility
- sidePanel.setOptions + setPanelBehavior run during SW init
  (persistent settings, Chrome opens panel without waiting)
- createContextMenus() only on install/update (menus persist)
- context-menu.js lazy-loaded via dynamic import() on click
- Removed test-panel debug files
- Restored popup.html as side panel default
- All imports must be static in MV3 service workers
- Context menus only created on install/update (onInstalled)
- sidePanel config runs at top level (persistent setting)
- SW startup no longer awaits storage calls
- ensureInitialized() called lazily in onMessage handler
- Reduces SW boot time since storage.get/set are deferred
- Service worker: 3 lines, zero imports
- Permissions: only sidePanel
- No module type needed
- Testing pure side panel startup speed
- SW imports background.js (record, stop, scan, save, etc.)
- Permissions restored for storage, scripting, tabs, downloads
- setPanelBehavior stays at top before import
- Import context-menu.js statically
- Create menus only on install/update
- contextMenus permission restored
- Removed overflow:hidden from row (was clipping controls)
- Input: flex:1 1 0 + width:0 forces it to shrink for controls
- text-overflow:ellipsis for long lines
- Controls always have their 72px regardless of panel width
- Controls (↑↓✕) are now position:absolute, right-aligned inside row
- Row has padding-right:80px to reserve space for controls
- Controls centered vertically with transform:translateY(-50%)
- Cannot overflow regardless of panel width
- ↑↓✕ replaced with ▲▼× (smaller, consistent across fonts)
- font-size: 10px, overflow: hidden on btn-small
- Glyphs stay centered inside 22x22 buttons
- Switched from inline-flex to inline-grid with place-items:center
- Ignores font metrics entirely, glyphs always dead-center
- Added explicit margin:0, text-align:center
- Removed inline-grid and overflow:hidden (hid content)
- Simple block-level centering: text-align:center + line-height:20px
- font-size:9px fits ▲▼× in 22px buttons
- all:unset removes ALL browser button defaults (padding, margin, etc)
- Rebuilt from scratch: 24x24, display:flex, centered
- No inherited padding pushing glyphs off-center
- button.btn-small selector beats global button {} specificity
- button.btn-small::before { display:none } removes 16x16 phantom
- Explicit padding:0, gap:0, min-width/height overrides
- Menus can disappear when extension is reloaded during development
- createContextMenus() now runs at top level in addition to onInstalled
- removeAll() in createContextMenus prevents duplicates
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant