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
This commit is contained in:
+60
-11
@@ -1380,17 +1380,23 @@ function buildSources(settings) {
|
||||
var sources = [
|
||||
{ url: '', name: localName, type: 'local', status: 'authenticated', backoffMs: 2000 },
|
||||
];
|
||||
// Only add remote sources when multi-device is enabled.
|
||||
// Smart default: treat as enabled if remote_instances is non-empty (backward compat).
|
||||
var remotes = (settings && settings.remote_instances) || [];
|
||||
for (var i = 0; i < remotes.length; i++) {
|
||||
var r = remotes[i];
|
||||
if (r && r.url) {
|
||||
sources.push({
|
||||
url: r.url.replace(/\/+$/, ''),
|
||||
name: r.name || r.url,
|
||||
type: 'remote',
|
||||
status: 'authenticated',
|
||||
backoffMs: 2000,
|
||||
});
|
||||
var multiDeviceEnabled = (settings && settings.multi_device_enabled) ||
|
||||
(remotes.length > 0);
|
||||
if (multiDeviceEnabled) {
|
||||
for (var i = 0; i < remotes.length; i++) {
|
||||
var r = remotes[i];
|
||||
if (r && r.url) {
|
||||
sources.push({
|
||||
url: r.url.replace(/\/+$/, ''),
|
||||
name: r.name || r.url,
|
||||
type: 'remote',
|
||||
status: 'authenticated',
|
||||
backoffMs: 2000,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return sources;
|
||||
@@ -1449,6 +1455,25 @@ function _saveRemoteInstances() {
|
||||
});
|
||||
}
|
||||
|
||||
// ─── Multi-Device helper ──────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Enable or disable all Multi-Device tab fields (except the enable toggle itself).
|
||||
* When disabled, the fields container gets opacity: 0.5 and inputs/selects/buttons
|
||||
* are disabled so users cannot interact with them.
|
||||
* @param {boolean} enabled
|
||||
*/
|
||||
function _updateMultiDeviceFieldsState(enabled) {
|
||||
var fieldsContainer = $('multi-device-fields');
|
||||
if (!fieldsContainer) return;
|
||||
var controls = fieldsContainer.querySelectorAll('input, select, button');
|
||||
controls.forEach(function(ctrl) {
|
||||
ctrl.disabled = !enabled;
|
||||
});
|
||||
fieldsContainer.style.opacity = enabled ? '' : '0.5';
|
||||
}
|
||||
|
||||
|
||||
// ─── Settings dialog ──────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
@@ -1766,6 +1791,20 @@ function openSettings() {
|
||||
deviceNameEl.value = (ss && ss.device_name) || '';
|
||||
}
|
||||
|
||||
// Update document.title from device_name setting
|
||||
if (ss && ss.device_name) {
|
||||
document.title = ss.device_name;
|
||||
}
|
||||
|
||||
// Multi-device enabled checkbox (with smart default: checked if remote_instances non-empty)
|
||||
const multiDeviceEnabledEl = $('setting-multi-device-enabled');
|
||||
if (multiDeviceEnabledEl) {
|
||||
var remoteList = (ss && ss.remote_instances) || [];
|
||||
multiDeviceEnabledEl.checked = !!(ss && ss.multi_device_enabled) ||
|
||||
remoteList.length > 0;
|
||||
_updateMultiDeviceFieldsState(multiDeviceEnabledEl.checked);
|
||||
}
|
||||
|
||||
// Remote instances
|
||||
const remoteInstancesEl = $('setting-remote-instances');
|
||||
if (remoteInstancesEl) {
|
||||
@@ -2298,11 +2337,21 @@ function bindStaticEventListeners() {
|
||||
patchServerSetting('new_session_template', NEW_SESSION_DEFAULT_TEMPLATE);
|
||||
});
|
||||
|
||||
// Sessions tab — device name with 500ms debounce
|
||||
// Multi-Device tab — enable/disable toggle
|
||||
on($('setting-multi-device-enabled'), 'change', function() {
|
||||
var enabled = this.checked;
|
||||
_updateMultiDeviceFieldsState(enabled);
|
||||
patchServerSetting('multi_device_enabled', enabled).then(function() {
|
||||
_sources = buildSources(_serverSettings);
|
||||
});
|
||||
});
|
||||
|
||||
// Multi-Device tab — device name with 500ms debounce; updates document.title immediately
|
||||
var _deviceNameDebounceTimer;
|
||||
on($('setting-device-name'), 'input', function() {
|
||||
clearTimeout(_deviceNameDebounceTimer);
|
||||
var val = this.value;
|
||||
if (val) document.title = val;
|
||||
_deviceNameDebounceTimer = setTimeout(function() {
|
||||
patchServerSetting('device_name', val).then(function() {
|
||||
_sources = buildSources(_serverSettings);
|
||||
|
||||
+33
-24
@@ -90,6 +90,7 @@
|
||||
<button class="settings-tab" data-tab="sessions">Sessions</button>
|
||||
<button class="settings-tab" data-tab="notifications">Notifications</button>
|
||||
<button class="settings-tab" data-tab="new-session">Commands</button>
|
||||
<button class="settings-tab" data-tab="devices">Multi-Device</button>
|
||||
</nav>
|
||||
<div class="settings-content">
|
||||
<div class="settings-panel" data-tab="display">
|
||||
@@ -123,21 +124,6 @@
|
||||
<option value="4">4</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="settings-field">
|
||||
<label class="settings-label" for="setting-view-mode">View Mode</label>
|
||||
<select id="setting-view-mode" class="settings-select">
|
||||
<option value="flat">Flat</option>
|
||||
<option value="grouped">Grouped</option>
|
||||
<option value="filtered">Filtered</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="settings-field">
|
||||
<label class="settings-label" for="setting-view-scope">View Scope</label>
|
||||
<select id="setting-view-scope" class="settings-select">
|
||||
<option value="local">Local</option>
|
||||
<option value="server">Server</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-panel hidden" data-tab="sessions">
|
||||
<div class="settings-field">
|
||||
@@ -166,15 +152,6 @@
|
||||
<label class="settings-label" for="setting-auto-open">Auto-open created sessions</label>
|
||||
<input type="checkbox" id="setting-auto-open" class="settings-checkbox" checked />
|
||||
</div>
|
||||
<div class="settings-field">
|
||||
<label class="settings-label" for="setting-device-name">Device Name</label>
|
||||
<input type="text" id="setting-device-name" class="settings-input" placeholder="This device" />
|
||||
</div>
|
||||
<div class="settings-field settings-field--column">
|
||||
<label class="settings-label">Remote Instances</label>
|
||||
<div id="setting-remote-instances" class="settings-remote-list"></div>
|
||||
<button id="add-remote-instance-btn" class="settings-action-btn">+ Add Remote</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-panel hidden" data-tab="notifications">
|
||||
<div class="settings-field">
|
||||
@@ -203,6 +180,38 @@
|
||||
<button id="setting-delete-template-reset" class="settings-action-btn">Reset to default</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-panel hidden" data-tab="devices">
|
||||
<div class="settings-field">
|
||||
<label class="settings-label" for="setting-multi-device-enabled">Enable multi-device support</label>
|
||||
<input type="checkbox" id="setting-multi-device-enabled" class="settings-checkbox" />
|
||||
</div>
|
||||
<div id="multi-device-fields">
|
||||
<div class="settings-field">
|
||||
<label class="settings-label" for="setting-device-name">Device Name</label>
|
||||
<input type="text" id="setting-device-name" class="settings-input" placeholder="This device" />
|
||||
</div>
|
||||
<div class="settings-field">
|
||||
<label class="settings-label" for="setting-view-mode">View Mode</label>
|
||||
<select id="setting-view-mode" class="settings-select">
|
||||
<option value="flat">Flat</option>
|
||||
<option value="grouped">Grouped</option>
|
||||
<option value="filtered">Filtered</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="settings-field">
|
||||
<label class="settings-label" for="setting-view-scope">View Scope</label>
|
||||
<select id="setting-view-scope" class="settings-select">
|
||||
<option value="local">Local</option>
|
||||
<option value="server">Server</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="settings-field settings-field--column">
|
||||
<label class="settings-label">Remote Instances</label>
|
||||
<div id="setting-remote-instances" class="settings-remote-list"></div>
|
||||
<button id="add-remote-instance-btn" class="settings-action-btn">+ Add Remote</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
@@ -1653,3 +1653,8 @@ body {
|
||||
color: #ef4444;
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
}
|
||||
|
||||
/* Multi-Device tab — smooth enable/disable opacity transition */
|
||||
#multi-device-fields {
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user