Commit Graph

29 Commits

Author SHA1 Message Date
Brian Krabach 9f51d1bd51 fix: reorganize settings dialog — remove notifications tab, move bell/device-name fields
🤖 Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
2026-04-01 17:40:05 -07:00
Brian Krabach 046d123149 refactor: remove all cross-origin browser-direct federation code
- Delete storeFederationToken function from app.js
- Delete window.addEventListener('message',...) handler from app.js
- Delete buildAuthTileHTML function from app.js
- Delete formatLastSeen function from app.js
- Delete buildOfflineTileHTML function from app.js
- Delete openLoginPopup function from app.js
- Simplify api() to same-origin only (no baseUrl/credentials/X-Muxplex-Token)
- Remove federation auth relay <script> block from index.html
- Remove /api/auth/token endpoint from main.py
- Remove CORSMiddleware from main.py
- Remove X-Muxplex-Token header check from auth.py
- Delete corresponding tests and add absence verification tests
2026-04-01 17:30:18 -07:00
Brian Krabach 63e7ef2a1c feat: federation key management UI in Settings > Multi-Device 2026-04-01 16:50:01 -07:00
Brian Krabach d0fe9cda67 chore: Phase 1 complete — all backend proxy tests pass 2026-04-01 12:33:17 -07:00
Brian Krabach cb264bbaaa feat: postMessage auth token relay for cross-origin federation login
- Backend: AuthMiddleware.dispatch() checks X-Muxplex-Token header
  after cookie auth, allowing cross-origin federation requests to
  authenticate using a session token sent as a header instead of a
  SameSite=Strict cookie.

- Backend: GET /api/auth/token endpoint returns the current session
  token for authenticated requests. Used by login popups to relay
  the token back to the opener window via postMessage.

- Frontend (app.js): api() injects X-Muxplex-Token header for
  cross-origin requests when a token is stored in localStorage under
  muxplex.federation_tokens keyed by origin.

- Frontend (app.js): storeFederationToken() helper stores tokens.
  window.addEventListener('message') handler catches muxplex-auth-token
  postMessages and stores the token, then retriggers a poll so the
  auth_required source transitions to authenticated immediately.

- Frontend (app.js): _saveRemoteInstances() prunes stale tokens for
  URLs no longer in the remote instances list.

- Frontend (index.html): Popup relay script fetches /api/auth/token
  and sends the token to window.opener via postMessage when loaded
  as a login popup (window.opener present).

Tests added:
  test_auth.py: X-Muxplex-Token header authenticates / invalid rejected
  test_api.py: GET /api/auth/token returns token / 401 when unauthed
  test_app.mjs: api() header injection, storeFederationToken storage,
                index.html popup script presence
2026-04-01 08:17:28 -07:00
Brian Krabach a862327e27 fix: settings item ordering, device name width, activity indicator mode, dot position 2026-04-01 06:52:01 -07:00
Brian Krabach e71ac223a9 feat: reorganize settings tabs, right-align device labels, activity dots, sidebar glow, display config toggles 2026-04-01 06:25:18 -07:00
Brian Krabach a1e532cb3f style: reorder devices panel — enable checkbox before device name input
The multi-device enable checkbox is the gating control; device name
only matters when multi-device is on. Place the checkbox first to
reinforce the logical dependency between the two settings.

No behavioral change — no tests enforce element ordering within a panel.
2026-03-31 15:20:32 -07:00
Brian Krabach ae07431ed1 fix: move notifications/device-name elements to correct settings panels
- Move #setting-bell-sound and notification controls from sessions panel
  to a new notifications panel (data-tab="notifications")
- Move #setting-device-name from display panel to devices panel
- Add #setting-view-scope select to devices panel

Fixes 8 test failures in test_frontend_html.py:
- test_html_settings_panels_use_data_tab (now 5 panels)
- test_html_notifications_panel_has_bell_sound_checkbox
- test_html_notifications_panel_has_notification_status_text
- test_html_notifications_panel_has_request_btn
- test_html_sessions_tab_device_name_input
- test_html_devices_panel_has_device_name
- test_html_devices_panel_has_view_scope
2026-03-31 15:15:29 -07:00
Brian Krabach 3de9e98de8 refactor: reorganize settings — merge Notifications into Sessions, move device name to Display, remove view scope 2026-03-31 11:53:25 -07:00
Brian Krabach 679416a5bf feat: reorganize settings dialog — add Multi-Device tab, enable/disable toggle, device name as page title
- Add multi_device_enabled: false to DEFAULT_SETTINGS in settings.py
- Add fifth 'Multi-Device' tab (data-tab='devices') to settings dialog sidebar
- Move #setting-device-name, #setting-remote-instances, #add-remote-instance-btn,
  #setting-view-mode, and #setting-view-scope out of Display/Sessions tabs into
  the new dedicated devices panel
- Add #setting-multi-device-enabled checkbox at top of Multi-Device tab;
  when unchecked, all other fields in the tab are greyed out and disabled
- Gate buildSources() remote instances behind multi_device_enabled (smart default:
  treated as enabled if remote_instances is non-empty for backward compat)
- Wire device name → document.title: updates title on openSettings() and on
  every keystroke in the device name input field
- Add _updateMultiDeviceFieldsState() helper to enable/disable fields
- Add #multi-device-fields CSS transition for smooth opacity animation
- Add 19 new tests (settings, HTML, JS, CSS) covering all new behavior
2026-03-31 06:16:44 -07:00
Brian Krabach 881b6cc9f3 merge: integrate upstream changes with multi-device federation 2026-03-31 05:48:49 -07:00
Brian Krabach c8a963f28e feat: add Remote Instances management UI to Settings (task-15) 2026-03-31 00:55:26 -07:00
Brian Krabach 200137a995 feat: add view mode and scope selectors to Display settings tab
Task: task-14 Settings dialog — view mode selector and scope toggle
2026-03-31 00:40:51 -07:00
Brian Krabach 5738c39f7f feat: add filtered view mode with device pill bar (task-12)
- Add <div id="filter-bar" class="filter-bar"> to index.html before session-grid div
- Implement renderFilterBar(container, allSessions) that renders pill buttons
  for each unique device name plus an 'All' button
- Active device pill gets filter-pill--active class
- Add _setActiveFilterDevice(device) test helper
- Bind delegated click handler on filter-bar in bindStaticEventListeners
  that sets _activeFilterDevice and re-renders grid
- Export renderFilterBar and _setActiveFilterDevice

Co-authored-by: Amplifier <amplifier@amplified.dev>
2026-03-31 00:16:15 -07:00
Brian Krabach 8c0675157a feat: three dashboard view modes — Auto, Fit, Compact
Auto: current behavior (auto-fill grid, fixed tile height, scrollable).
Fit: calculates cols × rows to fill viewport exactly, zero scroll.
Compact: 80px tiles, high density, auto-fill with 200px min-width.

Toggle button (▦) in overview header cycles modes. Fit recalculates
on window resize. View mode persisted in localStorage alongside other
display settings (viewMode: 'auto' default in DISPLAY_DEFAULTS).

- CSS: .session-grid--fit and .session-grid--compact modifiers
- JS: VIEW_MODES, cycleViewMode(), applyFitLayout() functions
- HTML: #view-mode-btn between + and ⚙ in overview header
- Tests: 8 new JS tests, 3 CSS tests, 1 HTML test all passing
2026-03-30 22:22:59 -07:00
Brian Krabach 3a102ba9d8 fix: add 18px font option, click-outside-dialog to dismiss settings
Added 18px to font size select. Dialog click handler checks
e.target === settingsDialog (click landed on ::backdrop area,
not dialog content) and closes settings.
2026-03-30 22:07:38 -07:00
Brian Krabach 79576bcbfe feat: customizable delete session command template
Symmetric with create template. Default: 'tmux kill-session -t {name}'.
Configurable in Settings → Commands tab (renamed from 'New Session').
DELETE /api/sessions/{name} reads template from settings, substitutes
{name}, runs synchronously via subprocess.run with 30s timeout.

Enables custom teardown workflows like:
  amplifier-dev ~/dev/{name} --destroy

Changes:
- settings.py: add delete_session_template to DEFAULT_SETTINGS
- main.py: DELETE endpoint uses subprocess.run + template instead of run_tmux
- index.html: add delete template textarea + reset btn; rename tab to Commands
- app.js: DELETE_SESSION_DEFAULT_TEMPLATE constant, openSettings loads it,
  bindStaticEventListeners wires input/reset; constant exported

Tests added:
- test_settings.py: 3 tests for default, load, and patch of delete_session_template
- test_api.py: 2 tests for custom/default template substitution via subprocess mock;
  update existing test_delete_session_calls_kill_session to match new implementation
- test_frontend_html.py: 5 tests for textarea, placeholder, rows, reset btn, tab label
- test_app.mjs: 5 tests for constant definition, value, and wiring in openSettings/bindStaticEventListeners
2026-03-30 17:17:34 -07:00
Brian Krabach 424a4f5377 fix: settings modal dismiss — add close button, fix backdrop click 2026-03-30 03:27:47 -07:00
Brian Krabach dbb8b2bd73 feat: add mobile FAB for new session creation 2026-03-30 01:34:31 -07:00
Brian Krabach d76042560a feat: add sidebar + New sticky footer with inline input
- Add div.sidebar-footer with button#sidebar-new-session-btn.sidebar-new-btn
  ('+ New') to #session-sidebar in index.html, positioned after #sidebar-list
- Add CSS for .sidebar-footer (padding: 8px, border-top, flex-shrink: 0)
- Add CSS for .sidebar-new-btn (width: 100%, dashed border, dim text, hover
  effects with muted text and border color)
- Bind #sidebar-new-session-btn click to showNewSessionInput() in
  bindStaticEventListeners()
- Add 15 tests covering HTML structure, CSS rules, and JS binding

🤖 Co-authored-by: Amplifier <amplifier@example.com>
2026-03-30 01:23:37 -07:00
Brian Krabach 5f81b87348 feat: add New Session settings tab with template textarea 2026-03-30 01:03:54 -07:00
Brian Krabach 2f909eae89 feat: add Notifications settings tab 2026-03-30 00:18:05 -07:00
Brian Krabach c955aadad1 feat: add Sessions settings tab with server-side persistence 2026-03-29 23:57:22 -07:00
Brian Krabach f380307f08 fix: rename data-panel to data-tab on settings panels to match switchSettingsTab()
switchSettingsTab() in app.js reads panel.dataset.tab (data-tab attribute).
The four .settings-panel elements in index.html were using data-panel instead,
causing all panels to get hidden on every tab click — the settings dialog rendered
as a blank content area after any tab interaction.

Fix: Change data-panel="..." to data-tab="..." on all four panel divs.

Tests added:
- test_html_settings_panels_use_data_tab: verifies each .settings-panel uses
  data-tab and not data-panel
- test_html_settings_tab_panel_data_tab_alignment: cross-checks that every tab
  button data-tab value has a matching .settings-panel data-tab value, preventing
  this class of HTML/JS attribute mismatch from recurring
2026-03-29 23:47:59 -07:00
Brian Krabach b20759c6cb feat: add settings dialog HTML structure and CSS 2026-03-29 23:04:11 -07:00
Brian Krabach a971cb9bbd refactor: remove orphaned command palette HTML remnants from index.html 2026-03-29 22:16:03 -07:00
Brian Krabach 80dc082df0 refactor: remove command palette HTML and CSS 2026-03-29 22:12:07 -07:00
Brian Krabach 74b63033d7 refactor: rename coordinator → muxplex package, move frontend inside as package data 2026-03-28 02:02:50 -07:00