tabby-rdp 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +516 -0
- package/README.md +216 -58
- package/TROUBLESHOOTING.md +77 -0
- package/dist/accountForm.js +0 -1
- package/dist/accountRevisions.js +46 -0
- package/dist/accounts.js +2 -2
- package/dist/audio.js +0 -1
- package/dist/authorities.js +331 -0
- package/dist/byteQueue.js +102 -0
- package/dist/clipboard.js +106 -0
- package/dist/connectionStatus.js +0 -1
- package/dist/desk.js +16 -47
- package/dist/deskScript.js +196 -6
- package/dist/desktop.service.js +1499 -269
- package/dist/desktopForm.js +53 -18
- package/dist/desktops.js +232 -24
- package/dist/diskStorage.js +212 -0
- package/dist/drives.js +271 -30
- package/dist/fileTransfer.js +960 -132
- package/dist/gateway.js +216 -57
- package/dist/header.js +76 -5
- package/dist/help.js +16 -47
- package/dist/hostCompat.js +86 -0
- package/dist/hyperv.js +65 -15
- package/dist/index.js +7 -4
- package/dist/keyboard.js +0 -1
- package/dist/microphone.js +57 -13
- package/dist/ntlm.js +0 -1
- package/dist/osd.js +56 -15
- package/dist/packageChangeDialog.js +186 -0
- package/dist/probe.js +15 -3
- package/dist/rdcleanpath.js +319 -44
- package/dist/rdpFile.js +22 -7
- package/dist/rdpProfile.js +39 -21
- package/dist/releaseSettings.js +72 -0
- package/dist/releases.js +408 -0
- package/dist/remoteSetup.js +103 -23
- package/dist/sessionLog.js +53 -0
- package/dist/settingsPage.js +148 -122
- package/dist/signin.js +478 -48
- package/dist/ssh.js +99 -18
- package/dist/sshChannelStream.js +40 -6
- package/dist/targets.js +194 -40
- package/dist/ui.js +88 -20
- package/dist/unshowable.js +41 -0
- package/dist/updates.js +79 -56
- package/dist/vms.js +17 -3
- package/dist/wake.js +15 -8
- package/docs/desk.md +157 -0
- package/package.json +14 -4
- package/remote/trd-pty.py +74 -13
- package/vendor/SHA256SUMS +26 -0
- package/vendor/ironrdp_web_bg.wasm +0 -0
- package/dist/accountForm.js.map +0 -1
- package/dist/accounts.js.map +0 -1
- package/dist/audio.js.map +0 -1
- package/dist/connectionStatus.js.map +0 -1
- package/dist/desk.js.map +0 -1
- package/dist/deskScript.js.map +0 -1
- package/dist/desktop.service.js.map +0 -1
- package/dist/desktopForm.js.map +0 -1
- package/dist/desktops.js.map +0 -1
- package/dist/drives.js.map +0 -1
- package/dist/fileTransfer.js.map +0 -1
- package/dist/gateway.js.map +0 -1
- package/dist/header.js.map +0 -1
- package/dist/help.js.map +0 -1
- package/dist/hyperv.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/keyboard.js.map +0 -1
- package/dist/microphone.js.map +0 -1
- package/dist/ntlm.js.map +0 -1
- package/dist/osd.js.map +0 -1
- package/dist/probe.js.map +0 -1
- package/dist/rdcleanpath.js.map +0 -1
- package/dist/rdpFile.js.map +0 -1
- package/dist/rdpProfile.js.map +0 -1
- package/dist/remoteSetup.js.map +0 -1
- package/dist/settingsPage.js.map +0 -1
- package/dist/signin.js.map +0 -1
- package/dist/ssh.js.map +0 -1
- package/dist/sshChannelStream.js.map +0 -1
- package/dist/targets.js.map +0 -1
- package/dist/ui.js.map +0 -1
- package/dist/updates.js.map +0 -1
- package/dist/vms.js.map +0 -1
- package/dist/wake.js.map +0 -1
package/dist/settingsPage.js
CHANGED
|
@@ -15,13 +15,17 @@ const path_1 = require("path");
|
|
|
15
15
|
const tabby_core_1 = require("tabby-core");
|
|
16
16
|
const tabby_settings_1 = require("tabby-settings");
|
|
17
17
|
const accounts_1 = require("./accounts");
|
|
18
|
+
const clipboard_1 = require("./clipboard");
|
|
18
19
|
const desktop_service_1 = require("./desktop.service");
|
|
19
20
|
const desktops_1 = require("./desktops");
|
|
20
21
|
const drives_1 = require("./drives");
|
|
21
22
|
const osd_1 = require("./osd");
|
|
22
23
|
const help_1 = require("./help");
|
|
23
24
|
const updates_1 = require("./updates");
|
|
25
|
+
const releaseSettings_1 = require("./releaseSettings");
|
|
24
26
|
const targets_1 = require("./targets");
|
|
27
|
+
const unshowable_1 = require("./unshowable");
|
|
28
|
+
const hostCompat_1 = require("./hostCompat");
|
|
25
29
|
const REPO = 'https://github.com/meanaverage/tabby-rdp';
|
|
26
30
|
const k = (s) => `<kbd>${(0, help_1.esc)(s)}</kbd>`;
|
|
27
31
|
/** The page's tabs (as Tabby's "Profiles & connections" page has Profiles and Advanced), each holding sections by topic. */
|
|
@@ -31,7 +35,7 @@ const TABS = [
|
|
|
31
35
|
{ id: 'osd', title: 'Overlay', topics: ['osd'] },
|
|
32
36
|
{ id: 'desktops', title: 'Desktops', topics: ['desktops', 'certificates'] },
|
|
33
37
|
{ id: 'accounts', title: 'Accounts', topics: ['accounts'] },
|
|
34
|
-
{ id: '
|
|
38
|
+
{ id: 'updates', title: 'Updates', topics: ['updates'] },
|
|
35
39
|
];
|
|
36
40
|
/** The tab shown last, so that the page comes back to it. */
|
|
37
41
|
let lastTab = 'start';
|
|
@@ -41,13 +45,22 @@ const STYLE = `
|
|
|
41
45
|
.trd-settings { display: block; }
|
|
42
46
|
.trd-settings h3 { margin-bottom: 4px; }
|
|
43
47
|
.trd-settings .trd-lead { margin-bottom: 18px; opacity: 0.75; }
|
|
44
|
-
.trd-settings .trd-links {
|
|
45
|
-
.trd-settings .trd-lead a {
|
|
48
|
+
.trd-settings .trd-links { display: inline-flex; flex-wrap: wrap; gap: 6px 10px; margin-left: 10px; }
|
|
49
|
+
.trd-settings .trd-lead a { white-space: nowrap; }
|
|
46
50
|
.trd-settings section .trd-lead a { margin-left: 0; cursor: pointer; text-decoration: underline; }
|
|
47
|
-
.trd-settings .trd-update { display: flex; gap: 10px; align-items: center; margin-bottom: 18px; padding: 10px 12px; border-radius: 6px;
|
|
51
|
+
.trd-settings .trd-update { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-bottom: 18px; padding: 10px 12px; border-radius: 6px;
|
|
48
52
|
border: 1px solid rgba(80, 150, 255, 0.45); background: rgba(80, 150, 255, 0.1); }
|
|
49
53
|
.trd-settings .trd-update > div { flex: auto; }
|
|
50
54
|
.trd-settings .trd-update:empty { display: none; }
|
|
55
|
+
.trd-settings .trd-release-summary { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 12px; margin-bottom: 18px; }
|
|
56
|
+
.trd-settings .trd-release-summary h4 { margin: 3px 0; }
|
|
57
|
+
.trd-settings .trd-release-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 10px 0; }
|
|
58
|
+
.trd-settings .trd-release-actions select { width: auto; max-width: 100%; flex: 1 1 240px; }
|
|
59
|
+
.trd-settings .trd-release-notice { padding: 12px; border: 1px solid rgba(80,150,255,.45); border-radius: 6px; margin-bottom: 18px; }
|
|
60
|
+
.trd-settings .trd-release-error { color: var(--bs-danger, #e88); }
|
|
61
|
+
.trd-settings [data-release-settings] .trd-sub { font-size: 12px; opacity: .75; }
|
|
62
|
+
.trd-settings .trd-release-pause { display: flex; align-items: center; gap: 8px; margin-top: 14px; }
|
|
63
|
+
@media (max-width: 700px) { .trd-settings [data-release-settings] .form-line { flex-wrap: wrap; gap: 8px; } }
|
|
51
64
|
.trd-settings .nav-tabs { margin-bottom: 18px; }
|
|
52
65
|
.trd-settings .nav-tabs .nav-link { cursor: pointer; }
|
|
53
66
|
.trd-settings section { margin-bottom: 28px; scroll-margin-top: 12px; }
|
|
@@ -59,7 +72,7 @@ const STYLE = `
|
|
|
59
72
|
.trd-settings .trd-card { display: flex; flex-direction: column; gap: 8px; padding: 12px; border-radius: 6px;
|
|
60
73
|
border: 1px solid rgba(128, 128, 128, 0.25); }
|
|
61
74
|
.trd-settings .trd-card .trd-card-title { font-weight: 600; display: flex; align-items: center; gap: 6px; }
|
|
62
|
-
.trd-settings
|
|
75
|
+
.trd-settings .trd-card-text .trd-info, .trd-settings .trd-lead .trd-info, .trd-settings .description .trd-info { margin-left: 4px; vertical-align: middle; font-size: 13px; }
|
|
63
76
|
.trd-settings .trd-info { position: relative; display: inline-flex; opacity: 0.55; cursor: help; outline: none; font-weight: normal; }
|
|
64
77
|
.trd-settings .trd-info:hover, .trd-settings .trd-info:focus { opacity: 1; }
|
|
65
78
|
.trd-settings .trd-info::after { content: attr(data-tip); position: absolute; left: 0; top: calc(100% + 6px); z-index: 20; width: 260px;
|
|
@@ -148,10 +161,10 @@ exports.RemoteDesktopSettingsTab = RemoteDesktopSettingsTab = __decorate([
|
|
|
148
161
|
], RemoteDesktopSettingsTab);
|
|
149
162
|
/**
|
|
150
163
|
* The plugin's settings page: getting started, the settings, keys, desktops and certificates it keeps, and
|
|
151
|
-
*
|
|
164
|
+
* updates. Plain DOM like the rest of the plugin; the lists follow config changes made elsewhere.
|
|
152
165
|
*/
|
|
153
166
|
let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
154
|
-
constructor(element, desktop, help, config, platform, injector, zone, hotkeys) {
|
|
167
|
+
constructor(element, desktop, help, config, platform, injector, zone, hotkeys, compat) {
|
|
155
168
|
this.element = element;
|
|
156
169
|
this.desktop = desktop;
|
|
157
170
|
this.help = help;
|
|
@@ -160,6 +173,7 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
160
173
|
this.injector = injector;
|
|
161
174
|
this.zone = zone;
|
|
162
175
|
this.hotkeys = hotkeys;
|
|
176
|
+
this.compat = compat;
|
|
163
177
|
this.contentBox = true;
|
|
164
178
|
this.trdSettings = true;
|
|
165
179
|
this.subscriptions = [];
|
|
@@ -174,8 +188,6 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
174
188
|
document.head.appendChild(style);
|
|
175
189
|
}
|
|
176
190
|
this.render();
|
|
177
|
-
// A known newer version may be stale by now (the page is where it shows): ask npm again.
|
|
178
|
-
this.injector.get(updates_1.UpdateCheck).refresh();
|
|
179
191
|
// The preview is a desktop of the chosen resolution, scaled down to fit the page.
|
|
180
192
|
const frame = this.root.querySelector('.trd-osd-preview');
|
|
181
193
|
const scale = new ResizeObserver(() => this.scalePreview());
|
|
@@ -196,38 +208,33 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
196
208
|
}
|
|
197
209
|
render() {
|
|
198
210
|
const mac = process.platform === 'darwin';
|
|
199
|
-
const version = (()
|
|
200
|
-
try {
|
|
201
|
-
return require('../package.json').version;
|
|
202
|
-
}
|
|
203
|
-
catch {
|
|
204
|
-
return '';
|
|
205
|
-
}
|
|
206
|
-
})();
|
|
211
|
+
const version = (0, updates_1.installedVersion)();
|
|
207
212
|
this.root.innerHTML = `
|
|
208
213
|
<h3>Remote Desktop</h3>
|
|
209
214
|
<div class="trd-lead">Linux and Windows desktops in Tabby tabs, through SSH or directly.
|
|
210
215
|
${version ? `<span>tabby-rdp ${(0, help_1.esc)(version)}</span>` : ''}
|
|
211
|
-
<span class="trd-links"><a href="#" data-link="${REPO}#readme">Guide</a><a href="#" data-link="${REPO}/issues">Report a problem</a><a href="#" data-link="${REPO}/discussions/categories/q-a">Ask a question</a></span></div>
|
|
212
|
-
<div class="trd-update" data-update></div>
|
|
216
|
+
<span class="trd-links"><a href="#" data-link="${REPO}#readme">Guide</a><a href="#" data-link="${REPO}/issues">Report a problem</a><a href="#" data-link="${REPO}/discussions/categories/q-a">Ask a question</a><a href="#" data-link="${help_1.TROUBLESHOOTING_URL}">Troubleshooting</a></span></div>
|
|
213
217
|
<ul class="nav nav-tabs" data-nav></ul>
|
|
214
218
|
|
|
215
219
|
<section data-topic="start">
|
|
216
220
|
<h4>Getting started</h4>
|
|
217
221
|
<div class="trd-cards">
|
|
218
222
|
<div class="trd-card">
|
|
219
|
-
<div class="trd-card-title">Over SSH
|
|
220
|
-
<div class="trd-card-text">In an SSH tab, press <span data-hotkey></span> or click <b>Desktop</b
|
|
223
|
+
<div class="trd-card-title">Over SSH</div>
|
|
224
|
+
<div class="trd-card-text">In an SSH tab, press <span data-hotkey></span> or click <b>Desktop</b>.
|
|
225
|
+
${this.info('The host is set up on the first connection: GNOME, xrdp, or Windows with OpenSSH. Nothing to install here, no ports to open.')}</div>
|
|
221
226
|
<button class="btn btn-secondary btn-sm" data-action="ssh">Open a connection…</button>
|
|
222
227
|
</div>
|
|
223
228
|
<div class="trd-card">
|
|
224
|
-
<div class="trd-card-title">On your network
|
|
225
|
-
<div class="trd-card-text">A profile that connects straight to an RDP server
|
|
229
|
+
<div class="trd-card-title">On your network</div>
|
|
230
|
+
<div class="trd-card-text">A profile that connects straight to an RDP server.
|
|
231
|
+
${this.info('The desktop opens in a tab of its own. For a quick connection, type user@host in the profile selector.')}</div>
|
|
226
232
|
<button class="btn btn-secondary btn-sm" data-action="profile">New profile…</button>
|
|
227
233
|
</div>
|
|
228
234
|
<div class="trd-card">
|
|
229
|
-
<div class="trd-card-title">From an .rdp file
|
|
230
|
-
<div class="trd-card-text">The file becomes a profile
|
|
235
|
+
<div class="trd-card-title">From an .rdp file</div>
|
|
236
|
+
<div class="trd-card-text">The file becomes a profile.
|
|
237
|
+
${this.info('A file from Remote Desktop Connection, or from your admin. Its address, user name and domain make the profile; the password is asked for.')}</div>
|
|
231
238
|
<button class="btn btn-secondary btn-sm" data-action="import">Import an .rdp file…</button>
|
|
232
239
|
</div>
|
|
233
240
|
</div>
|
|
@@ -239,8 +246,7 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
239
246
|
<div class="form-line">
|
|
240
247
|
<div class="header">
|
|
241
248
|
<div class="title">When the pane is resized</div>
|
|
242
|
-
<div class="description">
|
|
243
|
-
shown at actual size with scroll bars.</div>
|
|
249
|
+
<div class="description">Fixed resolutions use scaling or scroll bars.</div>
|
|
244
250
|
</div>
|
|
245
251
|
<select class="form-control" data-setting="resize">
|
|
246
252
|
<option value="live">Resize to fit</option>
|
|
@@ -252,49 +258,58 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
252
258
|
<div class="form-line">
|
|
253
259
|
<div class="header">
|
|
254
260
|
<div class="title">Sharpness</div>
|
|
255
|
-
<div class="description">Retina
|
|
256
|
-
match. A desktop can have its own, in its tab's menu.</div>
|
|
261
|
+
<div class="description">Retina uses your screen's pixel density and matching remote scaling.</div>
|
|
257
262
|
</div>
|
|
258
263
|
<select class="form-control" data-setting="sharpness">
|
|
259
264
|
<option value="standard">Standard</option>
|
|
260
265
|
<option value="retina">Retina</option>
|
|
261
266
|
</select>
|
|
262
267
|
</div>
|
|
263
|
-
${this.toggleLine('h264', 'Video decoding (H.264)', '
|
|
264
|
-
${this.toggleLine('connectionStatus', 'Show connection status', '
|
|
268
|
+
${this.toggleLine('h264', 'Video decoding (H.264)', 'Hardware acceleration where available. Applies on the next connection.')}
|
|
269
|
+
${this.toggleLine('connectionStatus', 'Show connection status', 'Show throughput, frame rate, latency and connection details.')}
|
|
265
270
|
|
|
266
271
|
<h5>Sound</h5>
|
|
267
|
-
${this.toggleLine('sound', 'Sound', 'Play
|
|
268
|
-
${this.toggleLine('microphone', 'Microphone',
|
|
272
|
+
${this.toggleLine('sound', 'Sound', 'Play remote audio. Applies on the next connection.')}
|
|
273
|
+
${this.toggleLine('microphone', 'Microphone', `Share your microphone when a remote app requests it. Applies on the next connection; turning it off stops sharing immediately. ${this.info('A red indicator remains visible while sharing, including from background desktops. Its menu can stop sharing with an individual desktop. That desktop stays muted through reconnects until re-enabled or Tabby closes.')}`)}
|
|
274
|
+
|
|
275
|
+
<h5>Clipboard</h5>
|
|
276
|
+
<div class="form-line">
|
|
277
|
+
<div class="header">
|
|
278
|
+
<div class="title">Clipboard sharing</div>
|
|
279
|
+
<div class="description">Share text, images and files. Desktops can override this setting. Applies on reconnect;
|
|
280
|
+
restricting sharing stops local sends immediately.
|
|
281
|
+
${this.info('Sharing can expose passwords and let the remote replace your local clipboard. Only the focused desktop receives your clipboard. Off disables text, images and clipboard file transfers. Restricting sharing also withdraws previously offered files.')}</div>
|
|
282
|
+
</div>
|
|
283
|
+
<select class="form-control" data-setting="clipboard">
|
|
284
|
+
${Object.entries(clipboard_1.CLIPBOARD_LABELS).map(([mode, label]) => `<option value="${mode}">${(0, help_1.esc)(label)}</option>`).join('')}
|
|
285
|
+
</select>
|
|
286
|
+
</div>
|
|
269
287
|
|
|
270
288
|
<h5>Shared folders</h5>
|
|
271
|
-
<div class="trd-lead">
|
|
272
|
-
|
|
273
|
-
${this.info('Every remote desktop you connect to sees these folders, so share only what each of them may have. Read-only keeps the remote from changing anything in a folder. Windows mounts them (xrdp can, with FUSE); GNOME Remote Desktop doesn\'t serve drives.')}</div>
|
|
289
|
+
<div class="trd-lead">Available as remote drives (<code>\\\\tsclient</code> on Windows). Applies on the next connection.
|
|
290
|
+
${this.info('Shared with every remote desktop. Use read-only to prevent remote changes. Supported by Windows and xrdp with FUSE; unavailable on GNOME Remote Desktop.')}</div>
|
|
274
291
|
<div class="trd-list" data-list="folders"></div>
|
|
275
292
|
<div class="trd-add"><button class="btn btn-secondary btn-sm" data-action="folder">Share a folder…</button></div>
|
|
276
293
|
|
|
277
294
|
<h5>Keyboard</h5>
|
|
278
|
-
${this.toggleLine('unicodeKeys', 'Send text as typed',
|
|
279
|
-
${mac ? this.toggleLine('macShortcuts', 'Mac-style shortcuts', '
|
|
295
|
+
${this.toggleLine('unicodeKeys', 'Send text as typed', `Send characters instead of physical keys. Modifier shortcuts still use key positions. ${this.info('Useful for dead keys or mismatched keyboard layouts. GNOME is limited to characters in its own layout. Chinese, Japanese and Korean input methods are not supported.')}`)}
|
|
296
|
+
${mac ? this.toggleLine('macShortcuts', 'Mac-style shortcuts', '⌘C copies and ⌘V pastes. Tap ⌘ for the Windows key; when disabled, ⌘ always sends the Windows key.') : ''}
|
|
280
297
|
<div class="form-line">
|
|
281
298
|
<div class="header">
|
|
282
299
|
<div class="title">Shortcuts</div>
|
|
283
|
-
<div class="description">
|
|
284
|
-
<a data-action="shortcuts">Getting started</a> tab, and in Tabby's Hotkeys.</div>
|
|
300
|
+
<div class="description">Manage in <a data-action="shortcuts">Getting started</a> or Tabby's Hotkeys.</div>
|
|
285
301
|
</div>
|
|
286
302
|
<div><span data-hotkey></span></div>
|
|
287
303
|
</div>
|
|
288
304
|
|
|
289
305
|
<h5>SSH hosts</h5>
|
|
290
|
-
${this.toggleLine('desk', 'desk
|
|
291
|
-
${this.toggleLine('discoverVMs', 'Find virtual machines on SSH hosts', '
|
|
306
|
+
${this.toggleLine('desk', 'desk integration', `Type <code>desk</code> to open your current SSH shell on the desktop. Installs a helper on GNOME hosts on the next desktop connection; disabling removes it.`)}
|
|
307
|
+
${this.toggleLine('discoverVMs', 'Find virtual machines on SSH hosts', 'List libvirt and Hyper-V VMs in the SSH tab menu. Discovery is read-only and runs at most once a minute.')}
|
|
292
308
|
<div class="form-line">
|
|
293
309
|
<div class="header">
|
|
294
|
-
<div class="title">Shut down VMs
|
|
295
|
-
<div class="description">
|
|
296
|
-
|
|
297
|
-
were already running are left alone.</div>
|
|
310
|
+
<div class="title">Shut down started VMs</div>
|
|
311
|
+
<div class="description">Shut down VMs started by this plugin after the selected time with no desktop open.
|
|
312
|
+
Continues after Tabby closes; previously running VMs are unaffected.</div>
|
|
298
313
|
</div>
|
|
299
314
|
<select class="form-control" data-setting="shutDownIdle">
|
|
300
315
|
<option value="0">Never</option>
|
|
@@ -304,16 +319,13 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
304
319
|
</select>
|
|
305
320
|
</div>
|
|
306
321
|
|
|
307
|
-
<h5>Updates</h5>
|
|
308
|
-
${this.toggleLine('checkUpdates', 'Tell me about new versions', 'Once a day, asks npm (registry.npmjs.org) for the latest tabby-rdp, and says so here and in the menus when there is one. Nothing is sent but the request. Tabby itself shows plugin upgrades only on its Plugins page.')}
|
|
309
322
|
</section>
|
|
310
323
|
|
|
311
324
|
<section data-topic="osd">
|
|
312
325
|
<h4>Desktop name overlay</h4>
|
|
313
|
-
<div class="trd-lead">
|
|
314
|
-
into its pane, like a TV naming its input.</div>
|
|
326
|
+
<div class="trd-lead">Show the desktop name when connecting, switching desktops or focusing a pane.</div>
|
|
315
327
|
<div class="trd-osd-preview"><div class="trd-osd-stage"><div class="trd-osd"></div></div>
|
|
316
|
-
<select class="form-control form-control-sm trd-osd-resolution" data-preview-resolution title="
|
|
328
|
+
<select class="form-control form-control-sm trd-osd-resolution" data-preview-resolution title="Preview resolution">
|
|
317
329
|
<option value="1280x720">1280 × 720</option>
|
|
318
330
|
<option value="1920x1080">1920 × 1080</option>
|
|
319
331
|
<option value="2560x1440">2560 × 1440</option>
|
|
@@ -321,10 +333,9 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
321
333
|
</select></div>
|
|
322
334
|
<div class="form-line">
|
|
323
335
|
<div class="header"><div class="title">Show</div>
|
|
324
|
-
<div class="description">
|
|
325
|
-
connection, where the tab's title doesn't say which it is.</div></div>
|
|
336
|
+
<div class="description">Automatic shows names in split panes and when the tab title identifies a different connection.</div></div>
|
|
326
337
|
<select class="form-control" data-osd="show">
|
|
327
|
-
<option value="auto">
|
|
338
|
+
<option value="auto">Automatic</option>
|
|
328
339
|
<option value="always">Every time</option>
|
|
329
340
|
<option value="off">Never</option>
|
|
330
341
|
</select>
|
|
@@ -334,7 +345,7 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
334
345
|
<select class="form-control" data-osd="font">${Object.entries(osd_1.OSD_FONTS).map(([id, f]) => `<option value="${id}">${(0, help_1.esc)(f.label)}</option>`).join('')}</select>
|
|
335
346
|
</div>
|
|
336
347
|
<div class="form-line">
|
|
337
|
-
<div class="header"><div class="title">Size</div
|
|
348
|
+
<div class="header"><div class="title">Size</div></div>
|
|
338
349
|
<select class="form-control" data-osd="size">${Object.keys(osd_1.OSD_SIZES).map(id => `<option value="${id}">${id === 'huge' ? 'Extra large' : id[0].toUpperCase() + id.slice(1)}</option>`).join('')}</select>
|
|
339
350
|
</div>
|
|
340
351
|
<div class="form-line">
|
|
@@ -342,12 +353,11 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
342
353
|
<select class="form-control" data-osd="position">${osd_1.OSD_POSITIONS.map(p => `<option value="${p}">${p === 'middle' ? 'Middle' : p.replace('-', ' ').replace(/^./, c => c.toUpperCase())}</option>`).join('')}</select>
|
|
343
354
|
</div>
|
|
344
355
|
<div class="form-line">
|
|
345
|
-
<div class="header"><div class="title">Color</div
|
|
346
|
-
shadow behind it. The line before the second row takes your theme's accent color.</div></div>
|
|
356
|
+
<div class="header"><div class="title">Color</div></div>
|
|
347
357
|
<div class="trd-color"><input type="color" data-osd="color"><button class="btn btn-link btn-sm" data-action="osd-white">White</button></div>
|
|
348
358
|
</div>
|
|
349
359
|
<div class="form-line">
|
|
350
|
-
<div class="header"><div class="title">
|
|
360
|
+
<div class="header"><div class="title">Duration</div></div>
|
|
351
361
|
<select class="form-control" data-osd="seconds">
|
|
352
362
|
<option value="1.5">1.5 seconds</option>
|
|
353
363
|
<option value="2.5">2.5 seconds</option>
|
|
@@ -355,12 +365,13 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
355
365
|
<option value="6">6 seconds</option>
|
|
356
366
|
</select>
|
|
357
367
|
</div>
|
|
358
|
-
<button class="btn btn-secondary btn-sm" data-action="osd-try">
|
|
368
|
+
<button class="btn btn-secondary btn-sm" data-action="osd-try">Preview on open desktops</button>
|
|
359
369
|
</section>
|
|
360
370
|
|
|
361
371
|
<section data-topic="keyboard">
|
|
362
|
-
<h4>Shortcuts
|
|
363
|
-
<div class="trd-lead">Also listed in Tabby's <a data-action="hotkeys">Hotkeys</a
|
|
372
|
+
<h4>Shortcuts</h4>
|
|
373
|
+
<div class="trd-lead">Also listed in Tabby's <a data-action="hotkeys">Hotkeys</a>.
|
|
374
|
+
${this.info('These work while the desktop has the keyboard. Tabby\'s other shortcuts go to the desktop then, except switching tabs and full screen.')}</div>
|
|
364
375
|
<div class="trd-hotkeys" data-list="hotkeys"></div>
|
|
365
376
|
<h4 style="margin-top: 24px">Keys and tips</h4>
|
|
366
377
|
<table class="trd-keys"><tbody>
|
|
@@ -378,15 +389,17 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
378
389
|
<section data-topic="desktops">
|
|
379
390
|
<h4>Desktops</h4>
|
|
380
391
|
<div class="trd-lead">Remote desktop profiles, and desktops added from SSH tabs.
|
|
381
|
-
${this.info('A desktop added from an SSH tab\'s menu belongs to that host. That is for hosts without a profile, such as
|
|
392
|
+
${this.info('A desktop added from an SSH tab\'s menu belongs to that host. That is for hosts without a profile, such as ssh run in a local terminal.')}</div>
|
|
382
393
|
<div class="trd-list" data-list="desktops"></div>
|
|
383
|
-
<div class="trd-add"><button class="btn btn-secondary btn-sm" data-action="desktop">Add
|
|
394
|
+
<div class="trd-add"><button class="btn btn-secondary btn-sm" data-action="desktop">Add desktop…</button></div>
|
|
395
|
+
<h4 style="margin-top: 24px">Open desktops</h4>
|
|
396
|
+
<div class="trd-list" data-list="sessions"></div>
|
|
384
397
|
</section>
|
|
385
398
|
|
|
386
399
|
<section data-topic="accounts">
|
|
387
400
|
<h4>Accounts</h4>
|
|
388
|
-
<div class="trd-lead">
|
|
389
|
-
${this.info('
|
|
401
|
+
<div class="trd-lead">Reusable sign-in details for multiple desktops.
|
|
402
|
+
${this.info('Choose an account in a desktop\'s settings or a profile group\'s defaults.')}</div>
|
|
390
403
|
<div class="trd-list" data-list="accounts"></div>
|
|
391
404
|
<div class="trd-add">
|
|
392
405
|
<button class="btn btn-secondary btn-sm" data-action="account">Add an account…</button>
|
|
@@ -399,14 +412,7 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
399
412
|
<div class="trd-list" data-list="certificates"></div>
|
|
400
413
|
</section>
|
|
401
414
|
|
|
402
|
-
<section data-topic="
|
|
403
|
-
<h4>Troubleshooting</h4>
|
|
404
|
-
<div data-list="troubleshooting">${help_1.TROUBLESHOOTING.map(e => `
|
|
405
|
-
<details data-entry="${(0, help_1.esc)(e.id)}"><summary>${(0, help_1.esc)(e.title)}</summary><div>${e.body}</div></details>`).join('')}
|
|
406
|
-
</div>
|
|
407
|
-
<h4 style="margin-top: 18px">Open desktops</h4>
|
|
408
|
-
<div class="trd-list" data-list="sessions"></div>
|
|
409
|
-
</section>`;
|
|
415
|
+
<section data-topic="updates"><h4>Updates</h4><div class="trd-update" data-update></div><div data-release-settings></div></section>`;
|
|
410
416
|
// The sections go into the tabs' bodies; one tab shows at a time.
|
|
411
417
|
const nav = this.root.querySelector('[data-nav]');
|
|
412
418
|
for (const tab of TABS) {
|
|
@@ -467,7 +473,7 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
467
473
|
'osd-white': () => this.changeOsd({ color: '' }),
|
|
468
474
|
'osd-try': () => {
|
|
469
475
|
if (!this.desktop.showOsdEverywhere()) {
|
|
470
|
-
this.injector.get(tabby_core_1.NotificationsService).info('No
|
|
476
|
+
this.injector.get(tabby_core_1.NotificationsService).info('No visible desktops.');
|
|
471
477
|
}
|
|
472
478
|
},
|
|
473
479
|
};
|
|
@@ -476,7 +482,7 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
476
482
|
}));
|
|
477
483
|
this.refresh();
|
|
478
484
|
}
|
|
479
|
-
/** An ⓘ
|
|
485
|
+
/** An ⓘ placed after a description, showing `text` while hovered or focused. */
|
|
480
486
|
info(text) {
|
|
481
487
|
return `<span class="trd-info" tabindex="0" role="note" data-tip="${(0, help_1.esc)(text)}"><i class="fas fa-info-circle"></i></span>`;
|
|
482
488
|
}
|
|
@@ -530,7 +536,7 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
530
536
|
el.value = String(settings[key]);
|
|
531
537
|
}
|
|
532
538
|
});
|
|
533
|
-
//
|
|
539
|
+
// Update notices and controls belong to the Updates page.
|
|
534
540
|
const updates = this.injector.get(updates_1.UpdateCheck);
|
|
535
541
|
const banner = this.root.querySelector('[data-update]');
|
|
536
542
|
if (banner) {
|
|
@@ -539,6 +545,10 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
539
545
|
banner.querySelector('[data-upgrade]')?.addEventListener('click', () => updates.upgrade());
|
|
540
546
|
banner.querySelector('[data-whatsnew]')?.addEventListener('click', () => updates.whatsNew());
|
|
541
547
|
}
|
|
548
|
+
(0, releaseSettings_1.renderReleaseSettings)(this.root.querySelector('[data-release-settings]'), updates, {
|
|
549
|
+
notes: version => updates.whatsNew(version), plugins: () => this.help.openSettings('plugins'),
|
|
550
|
+
link: url => this.platform.openExternal(url),
|
|
551
|
+
});
|
|
542
552
|
const osd = settings.osd;
|
|
543
553
|
this.root.querySelectorAll('[data-osd]').forEach(el => {
|
|
544
554
|
const key = el.dataset.osd;
|
|
@@ -589,41 +599,51 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
589
599
|
// Remote desktop profiles first (Tabby's editor), then the desktops added from SSH tabs (the plugin's form).
|
|
590
600
|
const profiles = (this.config.store.profiles ?? []).filter((p) => p?.type === targets_1.RDP_PROFILE_TYPE && p.options?.host);
|
|
591
601
|
const groups = this.config.store.groups ?? [];
|
|
602
|
+
// Every field as text whatever the config holds (see configText): one that can't be shown would leave this list,
|
|
603
|
+
// and the lists after it on the page, unbuilt.
|
|
592
604
|
const profileRows = profiles.map(p => {
|
|
593
605
|
const o = p.options;
|
|
594
|
-
const address = `${o.host}:${o.port || 3389}`;
|
|
595
|
-
const via = o.via ? (this.config.store.profiles ?? []).find((x) => x.id === o.via)?.name
|
|
606
|
+
const address = `${(0, desktops_1.configText)(o.host)}:${(0, desktops_1.configText)(o.port || 3389)}`;
|
|
607
|
+
const via = o.via ? (0, desktops_1.configText)((this.config.store.profiles ?? []).find((x) => x.id === o.via)?.name) || 'an SSH profile' : null;
|
|
596
608
|
const inherited = o.account === undefined ? groups.find(g => g.id === p.group)?.defaults?.[targets_1.RDP_PROFILE_TYPE]?.options?.account : undefined;
|
|
597
609
|
const account = accountOf(o.account || inherited);
|
|
610
|
+
// Its own clipboard, or its group's or the type's default: what it connects with, as Tabby resolves the profile.
|
|
611
|
+
const clipboard = (0, clipboard_1.ownClipboard)(this.injector.get(tabby_core_1.ProfilesService).getConfigProxyForProfile(p).options?.clipboard);
|
|
612
|
+
const [username, kind, gateway] = [(0, desktops_1.configText)(o.username), (0, desktops_1.configText)(o.kind), (0, desktops_1.configText)(o.gateway)];
|
|
598
613
|
const details = [
|
|
599
|
-
account ? `Signs in as ${(0, help_1.esc)(account.name)}` :
|
|
600
|
-
|
|
601
|
-
|
|
614
|
+
account ? `Signs in as ${(0, help_1.esc)(account.name)}` : username ? `Signs in as ${(0, help_1.esc)(username)}` : '',
|
|
615
|
+
kind && kind !== 'windows' ? (0, help_1.esc)(kind) : '',
|
|
616
|
+
gateway ? `Through the gateway ${(0, help_1.esc)(gateway)}${accountOf(o.gatewayAccount) ? `, as ${(0, help_1.esc)(accountOf(o.gatewayAccount).name)}` : ''}` : '',
|
|
617
|
+
clipboard ? `Clipboard: ${(0, help_1.esc)(clipboard_1.CLIPBOARD_LABELS[clipboard].toLowerCase())}` : '',
|
|
602
618
|
].filter(Boolean).join('<br>');
|
|
603
|
-
return this.row((0, help_1.esc)(p.name
|
|
619
|
+
return this.row((0, help_1.esc)((0, desktops_1.configText)(p.name) || address), `${(0, help_1.esc)(address)}${via ? ` via ${(0, help_1.esc)(via)}` : ''}${details ? `<br>${details}` : ''}`, [
|
|
604
620
|
{ label: 'Edit…', run: () => { this.editProfile(p.id); } },
|
|
605
621
|
{ label: 'Remove…', danger: true, run: () => { this.removeProfile(p.id); } },
|
|
606
622
|
]);
|
|
607
623
|
});
|
|
608
624
|
const desktops = this.desktop.configuredDesktops();
|
|
609
|
-
|
|
625
|
+
// An item that is no entry describes no desktop, and isn't listed (see isDesktopEntry).
|
|
626
|
+
const desktopRows = desktops.flatMap((d, i) => {
|
|
627
|
+
if (!(0, desktops_1.isDesktopEntry)(d)) {
|
|
628
|
+
return [];
|
|
629
|
+
}
|
|
610
630
|
// A Hyper-V VM has no address of its own: its console is its host's to give.
|
|
611
|
-
const address
|
|
631
|
+
const { name, address, via, hyperv } = (0, desktops_1.entryText)(d);
|
|
612
632
|
const account = accountOf(d.account);
|
|
633
|
+
const [username, kind, gateway, vm, mac] = [(0, desktops_1.configText)(d.username), (0, desktops_1.configText)(d.kind), (0, desktops_1.configText)(d.gateway), (0, desktops_1.configText)(d.wake?.vm), (0, desktops_1.configText)(d.wake?.mac)];
|
|
613
634
|
const details = [
|
|
614
|
-
account ? `Signs in as ${(0, help_1.esc)(account.name)}` :
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
635
|
+
account ? `Signs in as ${(0, help_1.esc)(account.name)}` : username ? `Signs in as ${(0, help_1.esc)(username)}` : '',
|
|
636
|
+
kind && kind !== 'windows' ? (0, help_1.esc)(kind) : '',
|
|
637
|
+
gateway && !hyperv ? `Through the gateway ${(0, help_1.esc)(gateway)}${accountOf(d.gatewayAccount) ? `, as ${(0, help_1.esc)(accountOf(d.gatewayAccount).name)}` : ''}` : '',
|
|
638
|
+
vm ? `Starts VM ${(0, help_1.esc)(vm)} when off` : mac ? `Wakes ${(0, help_1.esc)(mac)} when off` : '',
|
|
639
|
+
(0, clipboard_1.ownClipboard)(d.clipboard) ? `Clipboard: ${(0, help_1.esc)(clipboard_1.CLIPBOARD_LABELS[(0, clipboard_1.ownClipboard)(d.clipboard)].toLowerCase())}` : '',
|
|
618
640
|
].filter(Boolean).join('<br>');
|
|
619
|
-
return this.row((0, help_1.esc)(
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
641
|
+
return [this.row((0, help_1.esc)(name), `${hyperv ? 'Hyper-V VM' : (0, help_1.esc)(address)}${via ? ` ${hyperv ? 'on' : 'behind'} ${(0, help_1.esc)(via)}` : ''}${details ? `<br>${details}` : ''}`, [
|
|
642
|
+
{ label: 'Edit…', run: () => { this.desktop.editDesktopIn(this.root, i, true); } },
|
|
643
|
+
{ label: 'Remove…', danger: true, run: () => { this.desktop.confirmRemoveDesktop(i); } },
|
|
644
|
+
])];
|
|
623
645
|
});
|
|
624
|
-
list.replaceChildren(...profileRows, ...desktopRows,
|
|
625
|
-
? 'Profiles are also in Profiles & connections; a desktop behind a host also in that host\'s SSH tab: right-click › Settings.'
|
|
626
|
-
: 'None yet. <b>Add a desktop…</b> makes a profile: an RDP server on your network, or one behind an SSH profile\'s host.'));
|
|
646
|
+
list.replaceChildren(...profileRows, ...desktopRows, ...(profileRows.length + desktopRows.length ? [] : [this.empty('No saved desktops.')]));
|
|
627
647
|
}
|
|
628
648
|
renderFolders() {
|
|
629
649
|
const list = this.root.querySelector('[data-list=folders]');
|
|
@@ -645,7 +665,7 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
645
665
|
}));
|
|
646
666
|
row.insertBefore(check, row.querySelector('button'));
|
|
647
667
|
return row;
|
|
648
|
-
}), ...folders.length ? [] : [this.empty('
|
|
668
|
+
}), ...folders.length ? [] : [this.empty('No shared folders.')]);
|
|
649
669
|
}
|
|
650
670
|
/** Asks for a folder and shares it under its own name (numbered when another share has it). */
|
|
651
671
|
async shareFolder() {
|
|
@@ -655,7 +675,7 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
655
675
|
}
|
|
656
676
|
const folders = this.desktop.sharedFolders();
|
|
657
677
|
if (folders.some(f => f.path === picked)) {
|
|
658
|
-
this.injector.get(tabby_core_1.NotificationsService).info('
|
|
678
|
+
this.injector.get(tabby_core_1.NotificationsService).info('This folder is already shared.');
|
|
659
679
|
return;
|
|
660
680
|
}
|
|
661
681
|
this.desktop.setSharedFolders([...folders, { path: picked, name: (0, drives_1.driveName)((0, path_1.basename)(picked) || picked, folders), readOnly: false }]);
|
|
@@ -676,7 +696,7 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
676
696
|
const used = uses.length
|
|
677
697
|
? `Used by ${uses.map(u => u.profileId ? `<a data-profile="${(0, help_1.esc)(u.profileId)}">${(0, help_1.esc)(u.name)}</a>`
|
|
678
698
|
: u.desktopIndex !== undefined ? `<a data-desktop="${u.desktopIndex}">${(0, help_1.esc)(u.name)}</a>` : (0, help_1.esc)(u.name)).join(', ')}`
|
|
679
|
-
: 'Not used
|
|
699
|
+
: 'Not used';
|
|
680
700
|
const row = this.row((0, help_1.esc)(a.name), `<span>${(0, help_1.esc)((0, accounts_1.signInName)(a))}</span><br><span>${used}</span><span data-password></span>`, [
|
|
681
701
|
{ label: 'Edit…', run: () => this.editAccount(a) },
|
|
682
702
|
{ label: 'Remove…', danger: true, run: () => { this.desktop.confirmRemoveAccount(a.id); } },
|
|
@@ -687,11 +707,11 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
687
707
|
checks = checks.then(() => row.isConnected ? this.desktop.accountHasPassword(a.id) : 'unknown').then(has => {
|
|
688
708
|
const note = row.querySelector('[data-password]');
|
|
689
709
|
if (note && has === 'no') {
|
|
690
|
-
note.innerHTML = '<br>No password saved
|
|
710
|
+
note.innerHTML = '<br>No password saved';
|
|
691
711
|
}
|
|
692
712
|
}, () => null);
|
|
693
713
|
return row;
|
|
694
|
-
}), ...accounts.length ? [] : [this.empty('
|
|
714
|
+
}), ...accounts.length ? [] : [this.empty('No saved accounts.')]);
|
|
695
715
|
}
|
|
696
716
|
/** The form under the list, for a new account or `account`. */
|
|
697
717
|
editAccount(account) {
|
|
@@ -718,7 +738,7 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
718
738
|
field('name').value = account?.name ?? '';
|
|
719
739
|
field('username').value = account?.username ?? '';
|
|
720
740
|
field('domain').value = account?.domain ?? '';
|
|
721
|
-
field('password').placeholder = account ? 'Leave empty to keep the saved
|
|
741
|
+
field('password').placeholder = account ? 'Leave empty to keep the saved password' : 'Optional; requested when connecting';
|
|
722
742
|
form.querySelector('button[type=submit]').textContent = account ? 'Save' : 'Add';
|
|
723
743
|
const close = () => {
|
|
724
744
|
form.remove();
|
|
@@ -735,7 +755,7 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
735
755
|
const username = field('username').value.trim();
|
|
736
756
|
const name = field('name').value.trim();
|
|
737
757
|
if (!username) {
|
|
738
|
-
error.textContent = '
|
|
758
|
+
error.textContent = 'Enter a user name.';
|
|
739
759
|
field('username').focus();
|
|
740
760
|
return;
|
|
741
761
|
}
|
|
@@ -958,17 +978,21 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
958
978
|
return;
|
|
959
979
|
}
|
|
960
980
|
const entries = this.desktop.trustedCertificates();
|
|
961
|
-
list.replaceChildren(...entries.map(({ desktop, sha256 }) => {
|
|
981
|
+
list.replaceChildren(...entries.map(({ desktop, sha256, authority }) => {
|
|
962
982
|
const [who, address] = desktop.includes('#') ? desktop.split('#', 2) : [desktop, ''];
|
|
963
|
-
|
|
964
|
-
//
|
|
983
|
+
// A host's key as it reads; a machine reached through one is named as that host's ssh resolved it, which is
|
|
984
|
+
// its word: what could reorder or hide part of it shows as U+FFFD.
|
|
985
|
+
const host = (0, help_1.esc)((0, unshowable_1.showable)((0, desktops_1.shownKey)(who)));
|
|
986
|
+
const title = address ? who === 'gateway' ? `The gateway ${(0, help_1.esc)(address)}` : who === desktops_1.DIRECT_KEY ? `${(0, help_1.esc)(address)} (direct)` : `${(0, help_1.esc)(address)} behind ${host}` : host;
|
|
987
|
+
// How it came to be trusted, where that is known, and what else was decided about that server: forgotten with it.
|
|
988
|
+
const how = authority === true ? '<br>Valid for its name by a certificate authority' : authority === false ? '<br>Trusted by you' : '';
|
|
965
989
|
const plain = this.desktop.signsInWithoutNla(desktop) ? '<br>Signs in without Network Level Authentication' : '';
|
|
966
|
-
return this.row(title, `SHA-256 ${(0, help_1.esc)(sha256.slice(0, 23))}…${plain}`, [
|
|
990
|
+
return this.row(title, `SHA-256 ${(0, help_1.esc)(sha256.slice(0, 23))}…${how}${plain}`, [
|
|
967
991
|
{ label: 'Forget', run: () => this.desktop.forgetCertificate(desktop) },
|
|
968
992
|
]);
|
|
969
993
|
}), this.empty(entries.length
|
|
970
|
-
? 'A forgotten certificate is
|
|
971
|
-
: '
|
|
994
|
+
? 'A forgotten certificate is asked about again on the next connection, unless a certificate authority vouches for it; one behind an SSH host is remembered again without asking.'
|
|
995
|
+
: 'No saved certificates.'));
|
|
972
996
|
}
|
|
973
997
|
renderSessions() {
|
|
974
998
|
const list = this.root.querySelector('[data-list=sessions]');
|
|
@@ -978,23 +1002,19 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
978
1002
|
const sessions = this.desktop.sessionSummaries();
|
|
979
1003
|
list.replaceChildren(...sessions.map(s => this.row((0, help_1.esc)(s.name), `${s.where ? `via ${(0, help_1.esc)(s.where)} · ` : ''}${(0, help_1.esc)(s.state)}`, [
|
|
980
1004
|
{ label: 'Copy log', run: () => this.copyLog(s.name, s.log) },
|
|
981
|
-
])), ...sessions.length ? [] : [this.empty('No
|
|
1005
|
+
])), ...sessions.length ? [] : [this.empty('No desktops are open.')]);
|
|
982
1006
|
}
|
|
983
1007
|
copyLog(name, log) {
|
|
984
|
-
const version = (()
|
|
985
|
-
|
|
986
|
-
return require('../package.json').version;
|
|
987
|
-
}
|
|
988
|
-
catch {
|
|
989
|
-
return '?';
|
|
990
|
-
}
|
|
991
|
-
})();
|
|
992
|
-
this.platform.setClipboard({ text: [`tabby-rdp ${version} on ${process.platform}: ${name}`, ...log].join('\n') });
|
|
1008
|
+
const version = (0, updates_1.installedVersion)();
|
|
1009
|
+
this.platform.setClipboard({ text: [`tabby-rdp ${version} on ${process.platform}: ${name}`, ...this.compat.diagnosticLines(), ...log].join('\n') });
|
|
993
1010
|
}
|
|
994
1011
|
showTab(id) {
|
|
995
1012
|
lastTab = TABS.some(t => t.id === id) ? id : TABS[0].id;
|
|
996
1013
|
this.root.querySelectorAll('[data-tab]').forEach(el => el.classList.toggle('active', el.dataset.tab === lastTab));
|
|
997
1014
|
this.root.querySelectorAll('[data-body]').forEach(el => { el.hidden = el.dataset.body !== lastTab; });
|
|
1015
|
+
if (lastTab === 'updates') {
|
|
1016
|
+
this.injector.get(updates_1.UpdateCheck).refresh();
|
|
1017
|
+
}
|
|
998
1018
|
}
|
|
999
1019
|
/** Shows the tab with a section (and opens a troubleshooting entry), with a short highlight. */
|
|
1000
1020
|
reveal(topic, entry) {
|
|
@@ -1031,7 +1051,10 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
1031
1051
|
return null;
|
|
1032
1052
|
}
|
|
1033
1053
|
}
|
|
1034
|
-
/**
|
|
1054
|
+
/**
|
|
1055
|
+
* "Remove…" on a remote desktop profile: asks, then deletes it as Tabby's Profiles page would (a direct one's saved
|
|
1056
|
+
* passwords and certificate go too; see RDPProfilesService.deleteProfile).
|
|
1057
|
+
*/
|
|
1035
1058
|
async removeProfile(id) {
|
|
1036
1059
|
const profiles = this.injector.get(tabby_core_1.ProfilesService);
|
|
1037
1060
|
const profile = (await profiles.getProfiles()).find(p => p.id === id);
|
|
@@ -1041,7 +1064,10 @@ let RemoteDesktopSettingsComponent = class RemoteDesktopSettingsComponent {
|
|
|
1041
1064
|
const { response } = await this.platform.showMessageBox({
|
|
1042
1065
|
type: 'warning',
|
|
1043
1066
|
message: `Remove the profile "${profile.name}"?`,
|
|
1044
|
-
|
|
1067
|
+
// A saved account isn't the profile's: other desktops may sign in with it, and it stays.
|
|
1068
|
+
detail: profile.options?.via
|
|
1069
|
+
? 'Its saved password and remembered certificate stay: they are those of the same desktop behind its SSH profile\'s host.'
|
|
1070
|
+
: 'Its saved password and remembered certificate are forgotten too.',
|
|
1045
1071
|
buttons: ['Remove', 'Keep'],
|
|
1046
1072
|
defaultId: 1,
|
|
1047
1073
|
cancelId: 1,
|
|
@@ -1133,6 +1159,6 @@ exports.RemoteDesktopSettingsComponent = RemoteDesktopSettingsComponent = __deco
|
|
|
1133
1159
|
tabby_core_1.PlatformService,
|
|
1134
1160
|
core_1.Injector,
|
|
1135
1161
|
core_1.NgZone,
|
|
1136
|
-
tabby_core_1.HotkeysService
|
|
1162
|
+
tabby_core_1.HotkeysService,
|
|
1163
|
+
hostCompat_1.HostCompatibility])
|
|
1137
1164
|
], RemoteDesktopSettingsComponent);
|
|
1138
|
-
//# sourceMappingURL=settingsPage.js.map
|