@electerm/electerm-react 5.3.26 → 5.5.9
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/README.md +246 -12
- package/client/common/choose-save-folder.js +21 -2
- package/client/common/constants.js +20 -6
- package/client/common/create-title.jsx +6 -0
- package/client/common/default-setting.js +15 -0
- package/client/common/init-setting-item.js +5 -0
- package/client/common/platform.js +24 -0
- package/client/components/ai/agent-tool-call-card.jsx +10 -2
- package/client/components/ai/agent.js +4 -1
- package/client/components/ai/ai-attachments.js +87 -0
- package/client/components/ai/ai-chat-empty.jsx +43 -0
- package/client/components/ai/ai-chat-entry.jsx +13 -4
- package/client/components/ai/ai-chat-history-item.jsx +28 -4
- package/client/components/ai/ai-chat-history.jsx +2 -1
- package/client/components/ai/ai-chat.jsx +104 -13
- package/client/components/ai/ai-config-props.js +4 -130
- package/client/components/ai/ai-config.jsx +135 -15
- package/client/components/ai/ai-presets.js +173 -0
- package/client/components/ai/ai.styl +83 -0
- package/client/components/bg/css-overwrite.jsx +11 -0
- package/client/components/bookmark-form/bookmark-schema.js +4 -0
- package/client/components/bookmark-form/common/fields.jsx +3 -0
- package/client/components/bookmark-form/config/common-fields.js +12 -0
- package/client/components/bookmark-form/config/local.js +3 -2
- package/client/components/bookmark-form/config/serial.js +3 -2
- package/client/components/bookmark-form/config/ssh.js +2 -1
- package/client/components/bookmark-form/config/telnet.js +3 -2
- package/client/components/common/item-filter.jsx +76 -0
- package/client/components/common/item-filter.styl +54 -0
- package/client/components/common/lazy-boundary.jsx +34 -0
- package/client/components/common/opacity.jsx +3 -1
- package/client/components/footer/cmd-history.jsx +132 -45
- package/client/components/footer/cmd-history.styl +42 -4
- package/client/components/footer/footer-entry.jsx +35 -5
- package/client/components/footer/footer.styl +8 -1
- package/client/components/footer/multi-tab-run-modal.jsx +83 -0
- package/client/components/footer/tab-select.jsx +34 -17
- package/client/components/layout/layout.jsx +23 -31
- package/client/components/layout/pixed.js +3 -0
- package/client/components/main/main.jsx +55 -28
- package/client/components/main/term-fullscreen.styl +9 -3
- package/client/components/quick-commands/qm.styl +3 -2
- package/client/components/quick-commands/quick-command-create-modal.jsx +60 -0
- package/client/components/quick-commands/quick-commands-form-elem.jsx +10 -4
- package/client/components/rdp/file-transfer.js +4 -4
- package/client/components/remote-monitor/monitor-details.jsx +458 -0
- package/client/components/remote-monitor/monitor-details.styl +87 -0
- package/client/components/remote-monitor/monitor-model.js +764 -0
- package/client/components/remote-monitor/remote-monitor-bar-entry.jsx +18 -0
- package/client/components/remote-monitor/remote-monitor-bar.jsx +344 -0
- package/client/components/remote-monitor/remote-monitor-bar.styl +106 -0
- package/client/components/remote-monitor/session-monitor.js +361 -0
- package/client/components/remote-monitor/use-monitor-details.js +10 -0
- package/client/components/remote-monitor/visibility.js +18 -0
- package/client/components/session/session-control.jsx +29 -2
- package/client/components/session/session.jsx +40 -18
- package/client/components/session/sessions.jsx +5 -2
- package/client/components/setting-panel/setting-common.jsx +25 -56
- package/client/components/setting-panel/setting-modal.jsx +57 -42
- package/client/components/setting-panel/setting-terminal.jsx +8 -2
- package/client/components/setting-panel/setting.styl +1 -1
- package/client/components/setting-panel/tab-triggers.jsx +71 -0
- package/client/components/sftp/file-compare-modal.jsx +6 -3
- package/client/components/sftp/file-item.jsx +5 -3
- package/client/components/sftp/owner-list.js +11 -2
- package/client/components/sftp/sftp-entry.jsx +4 -0
- package/client/components/side-panel-r/side-panel-r.jsx +2 -2
- package/client/components/sidebar/side-panel.jsx +1 -1
- package/client/components/sys-menu/menu-btn.jsx +30 -1
- package/client/components/tabs/index.jsx +2 -2
- package/client/components/tabs/tab-title.jsx +3 -2
- package/client/components/tabs/tab.jsx +5 -1
- package/client/components/terminal/attach-addon-custom.js +295 -49
- package/client/components/terminal/automation/index.js +64 -0
- package/client/components/terminal/automation/keys.js +49 -0
- package/client/components/terminal/automation/stream-matcher.js +82 -0
- package/client/components/terminal/automation/strip-ansi.js +19 -0
- package/client/components/terminal/automation/trigger-engine.js +233 -0
- package/client/components/terminal/automation/trigger-presets.js +110 -0
- package/client/components/terminal/command-tracker-addon.js +31 -1
- package/client/components/terminal/mixins/index.js +27 -0
- package/client/components/terminal/mixins/term-attach.js +123 -0
- package/client/components/terminal/mixins/term-config.jsx +84 -0
- package/client/components/terminal/mixins/term-content.js +126 -0
- package/client/components/terminal/mixins/term-context-menu.jsx +323 -0
- package/client/components/terminal/mixins/term-file-drop.js +149 -0
- package/client/components/terminal/mixins/term-init.js +122 -0
- package/client/components/terminal/mixins/term-log.jsx +96 -0
- package/client/components/terminal/mixins/term-resize.js +87 -0
- package/client/components/terminal/mixins/term-socket.js +433 -0
- package/client/components/terminal/mixins/term-suggestions.js +224 -0
- package/client/components/terminal/mixins/term-theme.js +190 -0
- package/client/components/terminal/mixins/term-touch.js +523 -0
- package/client/components/terminal/shell-detect.js +37 -0
- package/client/components/terminal/shell.js +0 -28
- package/client/components/terminal/shortcut-bar-defs.js +30 -4
- package/client/components/terminal/shortcut-bar-edit.jsx +40 -9
- package/client/components/terminal/shortcut-bar-entry.jsx +6 -3
- package/client/components/terminal/shortcut-bar.jsx +17 -10
- package/client/components/terminal/shortcut-bar.styl +4 -0
- package/client/components/terminal/ssh-reload-state.js +96 -0
- package/client/components/terminal/startup-queue.js +433 -0
- package/client/components/terminal/terminal-interactive.jsx +32 -0
- package/client/components/terminal/terminal-select-text.jsx +69 -0
- package/client/components/terminal/terminal.jsx +227 -2064
- package/client/components/terminal/terminal.styl +61 -0
- package/client/components/terminal/transfer-client-base.js +5 -29
- package/client/components/terminal/trzsz-client.js +1 -3
- package/client/components/terminal/xmodem-client.js +1 -3
- package/client/components/terminal/xterm-loader.js +7 -0
- package/client/components/terminal/zmodem-client.js +1 -3
- package/client/components/terminal-info/base.jsx +18 -70
- package/client/components/terminal-info/terminal-info-entry.jsx +13 -5
- package/client/components/terminal-info/terminal-info.jsx +50 -59
- package/client/components/terminal-info/terminal-info.styl +6 -49
- package/client/components/text-editor/open-text-editor.js +30 -0
- package/client/components/text-editor/text-editor-entry.jsx +17 -6
- package/client/components/text-editor/text-editor.jsx +14 -0
- package/client/components/triggers/trigger-editor.jsx +246 -0
- package/client/components/triggers/trigger-form.jsx +200 -0
- package/client/components/triggers/trigger-session-modal.jsx +199 -0
- package/client/components/triggers/trigger-setting-list.jsx +89 -0
- package/client/components/triggers/trigger-transport.jsx +60 -0
- package/client/components/triggers/triggers-field.jsx +19 -0
- package/client/components/widgets/widgets-list.jsx +11 -1
- package/client/css/mobile.styl +29 -8
- package/client/store/common.js +12 -1
- package/client/store/init-state.js +7 -0
- package/client/store/mcp-handler.js +158 -30
- package/client/store/setting.js +9 -0
- package/client/store/store.js +2 -0
- package/client/store/sync.js +2 -0
- package/client/store/tab.js +42 -3
- package/client/store/trigger.js +118 -0
- package/client/store/watch.js +13 -5
- package/client/views/index.pug +3 -0
- package/package.json +1 -1
- package/client/components/terminal-info/activity.jsx +0 -57
- package/client/components/terminal-info/data-cols-parser.jsx +0 -54
- package/client/components/terminal-info/disk.jsx +0 -45
- package/client/components/terminal-info/format-disks.js +0 -45
- package/client/components/terminal-info/network.jsx +0 -121
- package/client/components/terminal-info/resource.jsx +0 -99
- package/client/components/terminal-info/run-cmd.jsx +0 -263
- package/client/components/terminal-info/sys-info.jsx +0 -56
- package/client/components/terminal-info/up.jsx +0 -17
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { auto } from 'manate/react'
|
|
2
|
-
import { useEffect } from 'react'
|
|
2
|
+
import { lazy, Suspense, useEffect } from 'react'
|
|
3
3
|
import Layout from '../layout/layout'
|
|
4
4
|
import FileInfoModal from '../sftp/file-info-modal'
|
|
5
5
|
import FileCompareModal from '../sftp/file-compare-modal'
|
|
@@ -10,7 +10,6 @@ import Sidebar from '../sidebar'
|
|
|
10
10
|
import CssOverwrite from '../bg/css-overwrite'
|
|
11
11
|
import UiTheme from './ui-theme'
|
|
12
12
|
import CustomCss from '../bg/custom-css.jsx'
|
|
13
|
-
import Resolutions from '../rdp/resolution-edit'
|
|
14
13
|
import TerminalInteractive from '../terminal/terminal-interactive'
|
|
15
14
|
import ConfirmModalStore from '../file-transfer/conflict-resolve.jsx'
|
|
16
15
|
import TransferQueue from '../file-transfer/transfer-queue'
|
|
@@ -19,18 +18,21 @@ import TerminalCmdSuggestions from '../terminal/terminal-command-dropdown'
|
|
|
19
18
|
import TransportsActionStore from '../file-transfer/transports-action-store.jsx'
|
|
20
19
|
import classnames from 'classnames'
|
|
21
20
|
import ShortcutControl from '../shortcuts/shortcut-control.jsx'
|
|
22
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
footerHeight,
|
|
23
|
+
isMac,
|
|
24
|
+
isWin,
|
|
25
|
+
remoteMonitorBarHeight,
|
|
26
|
+
textTerminalBgValue
|
|
27
|
+
} from '../../common/constants'
|
|
23
28
|
import { isAIDisabled } from '../../common/ai-feature'
|
|
24
29
|
import { ConfigProvider } from 'antd'
|
|
25
30
|
import { NotificationContainer } from '../common/notification'
|
|
26
|
-
import InfoModal from '../sidebar/info-modal.jsx'
|
|
27
31
|
import RightSidePanel from '../side-panel-r/side-panel-r'
|
|
28
32
|
import ConnectionHoppingWarning from './connection-hopping-warnning'
|
|
29
33
|
import SshConfigLoadNotify from '../ssh-config/ssh-config-load-notify'
|
|
30
34
|
import LoadSshConfigs from '../ssh-config/load-ssh-configs'
|
|
31
35
|
import AIChat from '../ai/ai-chat-entry'
|
|
32
|
-
import AIConfigModal from '../ai/ai-config-modal'
|
|
33
|
-
import Opacity from '../common/opacity'
|
|
34
36
|
import MoveItemModal from '../tree-list/move-item-modal'
|
|
35
37
|
import InputContextMenu from '../common/input-context-menu'
|
|
36
38
|
import WorkspaceSaveModal from '../tabs/workspace-save-modal'
|
|
@@ -44,9 +46,17 @@ import deepCopy from 'json-deep-copy'
|
|
|
44
46
|
import './wrapper.styl'
|
|
45
47
|
import TerminalInfo from '../terminal-info/terminal-info-entry'
|
|
46
48
|
import ShortcutBarEntry from '../terminal/shortcut-bar-entry'
|
|
49
|
+
import LazyBoundary from '../common/lazy-boundary'
|
|
50
|
+
import { isRemoteMonitorBarVisible } from '../remote-monitor/visibility'
|
|
47
51
|
import '../../common/fs.js'
|
|
48
52
|
import './term-fullscreen.styl'
|
|
49
53
|
|
|
54
|
+
const Resolutions = lazy(() => import('../rdp/resolution-edit'))
|
|
55
|
+
const InfoModal = lazy(() => import('../sidebar/info-modal.jsx'))
|
|
56
|
+
const AIConfigModal = lazy(() => import('../ai/ai-config-modal'))
|
|
57
|
+
// window opacity is electron-only: lazy so the web app never loads the chunk
|
|
58
|
+
const Opacity = lazy(() => import('../common/opacity'))
|
|
59
|
+
|
|
50
60
|
export default auto(function Index (props) {
|
|
51
61
|
useEffect(() => {
|
|
52
62
|
const { store } = props
|
|
@@ -129,6 +139,7 @@ export default auto(function Index (props) {
|
|
|
129
139
|
widgetInstances
|
|
130
140
|
} = store
|
|
131
141
|
const upgradeInfo = deepCopy(store.upgradeInfo)
|
|
142
|
+
const remoteMonitorBarVisible = isRemoteMonitorBarVisible(store)
|
|
132
143
|
const cls = classnames({
|
|
133
144
|
loaded: configLoaded,
|
|
134
145
|
'not-webapp': !window.et.isWebApp,
|
|
@@ -147,12 +158,14 @@ export default auto(function Index (props) {
|
|
|
147
158
|
'is-main': !isSecondInstance,
|
|
148
159
|
'is-mobile': store.isMobile,
|
|
149
160
|
'is-desktop': !store.isMobile,
|
|
150
|
-
'is-touch-device': store.isTouchDevice
|
|
161
|
+
'is-touch-device': store.isTouchDevice,
|
|
162
|
+
'remote-monitor-bar-on': remoteMonitorBarVisible
|
|
151
163
|
})
|
|
152
164
|
const ext1 = {
|
|
153
165
|
className: cls,
|
|
154
166
|
style: {
|
|
155
|
-
'--left-side-bar-width': store.leftSideBarWidth + 'px'
|
|
167
|
+
'--left-side-bar-width': store.leftSideBarWidth + 'px',
|
|
168
|
+
'--footer-stack-height': `${footerHeight + (remoteMonitorBarVisible ? remoteMonitorBarHeight : 0)}px`
|
|
156
169
|
}
|
|
157
170
|
}
|
|
158
171
|
// Get active tab IDs
|
|
@@ -242,20 +255,6 @@ export default auto(function Index (props) {
|
|
|
242
255
|
title: rightPanelTitle,
|
|
243
256
|
rightPanelTab
|
|
244
257
|
}
|
|
245
|
-
const terminalInfoProps = {
|
|
246
|
-
rightPanelTab,
|
|
247
|
-
...deepCopy(store.terminalInfoProps),
|
|
248
|
-
...pick(
|
|
249
|
-
config,
|
|
250
|
-
[
|
|
251
|
-
'host',
|
|
252
|
-
'port',
|
|
253
|
-
'saveTerminalLogToFile',
|
|
254
|
-
'terminalInfos',
|
|
255
|
-
'sessionLogPath'
|
|
256
|
-
]
|
|
257
|
-
)
|
|
258
|
-
}
|
|
259
258
|
const sshConfigProps = {
|
|
260
259
|
...pick(store, [
|
|
261
260
|
'settingTab',
|
|
@@ -293,13 +292,23 @@ export default auto(function Index (props) {
|
|
|
293
292
|
{...confsCss}
|
|
294
293
|
configLoaded={configLoaded}
|
|
295
294
|
/>
|
|
296
|
-
|
|
295
|
+
{window.et.isWebApp
|
|
296
|
+
? null
|
|
297
|
+
: (
|
|
298
|
+
<LazyBoundary>
|
|
299
|
+
<Suspense fallback={null}>
|
|
300
|
+
<Opacity opacity={config.opacity} />
|
|
301
|
+
</Suspense>
|
|
302
|
+
</LazyBoundary>
|
|
303
|
+
)}
|
|
297
304
|
<TerminalInteractive />
|
|
298
305
|
<UiTheme
|
|
299
306
|
{...themeProps}
|
|
300
307
|
/>
|
|
301
308
|
<CustomCss customCss={config.customCss} configLoaded={configLoaded} />
|
|
302
|
-
|
|
309
|
+
{store.textEditorRequested && (
|
|
310
|
+
<TextEditor />
|
|
311
|
+
)}
|
|
303
312
|
<UpdateCheck
|
|
304
313
|
skipVersion={config.skipVersion}
|
|
305
314
|
upgradeInfo={upgradeInfo}
|
|
@@ -325,11 +334,23 @@ export default auto(function Index (props) {
|
|
|
325
334
|
config={config}
|
|
326
335
|
/>
|
|
327
336
|
<Remote2RemoteHandlers />
|
|
328
|
-
|
|
329
|
-
|
|
337
|
+
{openResolutionEdit && (
|
|
338
|
+
<LazyBoundary>
|
|
339
|
+
<Suspense fallback={null}>
|
|
340
|
+
<Resolutions {...resProps} />
|
|
341
|
+
</Suspense>
|
|
342
|
+
</LazyBoundary>
|
|
343
|
+
)}
|
|
344
|
+
{store.showInfoModal && (
|
|
345
|
+
<LazyBoundary>
|
|
346
|
+
<Suspense fallback={null}>
|
|
347
|
+
<InfoModal {...infoModalProps} />
|
|
348
|
+
</Suspense>
|
|
349
|
+
</LazyBoundary>
|
|
350
|
+
)}
|
|
330
351
|
<RightSidePanel {...rightPanelProps}>
|
|
331
352
|
{!isAIDisabled() && <AIChat {...aiChatProps} />}
|
|
332
|
-
<TerminalInfo key={store.activeTabId} {...terminalInfoProps} />
|
|
353
|
+
<TerminalInfo key={store.activeTabId} store={store} {...deepCopy(store.terminalInfoProps)} />
|
|
333
354
|
</RightSidePanel>
|
|
334
355
|
<SshConfigLoadNotify {...sshConfigProps} />
|
|
335
356
|
<LoadSshConfigs
|
|
@@ -346,7 +367,13 @@ export default auto(function Index (props) {
|
|
|
346
367
|
<BatchOpRunner />
|
|
347
368
|
<ImportProgress />
|
|
348
369
|
<ShortcutBarEntry store={store} />
|
|
349
|
-
{!isAIDisabled() &&
|
|
370
|
+
{!isAIDisabled() && store.showAIConfigModal && (
|
|
371
|
+
<LazyBoundary>
|
|
372
|
+
<Suspense fallback={null}>
|
|
373
|
+
<AIConfigModal store={store} />
|
|
374
|
+
</Suspense>
|
|
375
|
+
</LazyBoundary>
|
|
376
|
+
)}
|
|
350
377
|
<UnixTimestampTooltip />
|
|
351
378
|
</div>
|
|
352
379
|
</ConfigProvider>
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
.terminal-control
|
|
6
6
|
.qm-wrap-tooltip
|
|
7
7
|
.main-footer
|
|
8
|
+
.remote-monitor-bar
|
|
8
9
|
.session-v-info
|
|
9
10
|
display none
|
|
10
11
|
// Mobile tabs carry the extra .mobile-tabs class, and mobile.styl uses
|
|
@@ -40,11 +41,16 @@
|
|
|
40
41
|
// visible; the session shrinks to sit on top of the footer. RDP/VNC/Spice
|
|
41
42
|
// fullscreen stays footer-less — inActiveTerminal is false for those tabs, so
|
|
42
43
|
// the fs-with-footer class is absent there.
|
|
43
|
-
// 36px
|
|
44
|
+
// --footer-stack-height includes the 36px footer and the optional monitor row.
|
|
44
45
|
.fullscreen.fs-with-footer
|
|
45
46
|
.main-footer
|
|
46
47
|
display block
|
|
47
48
|
left 0 !important
|
|
49
|
+
&.remote-monitor-bar-on
|
|
50
|
+
.remote-monitor-bar
|
|
51
|
+
display flex
|
|
52
|
+
left 0 !important
|
|
53
|
+
width 100% !important
|
|
48
54
|
.qm-wrap-tooltip
|
|
49
55
|
display block
|
|
50
56
|
left 0 !important
|
|
@@ -53,10 +59,10 @@
|
|
|
53
59
|
display none
|
|
54
60
|
.session-wrap.session-current
|
|
55
61
|
.term-wrap
|
|
56
|
-
height calc(100% - 36px - var(--shortcut-bar-h, 0px)) !important
|
|
62
|
+
height calc(100% - var(--footer-stack-height, 36px) - var(--shortcut-bar-h, 0px) - var(--shortcut-bar-kb-offset, 0px)) !important
|
|
57
63
|
// pinned quick-command bar (180px, same as quickCommandBoxHeight) sits
|
|
58
64
|
// between terminal and footer — reserve its space too
|
|
59
65
|
&.qm-pinned
|
|
60
66
|
.session-wrap.session-current
|
|
61
67
|
.term-wrap
|
|
62
|
-
height calc(100% - 36px - 180px - var(--shortcut-bar-h, 0px)) !important
|
|
68
|
+
height calc(100% - var(--footer-stack-height, 36px) - 180px - var(--shortcut-bar-h, 0px) - var(--shortcut-bar-kb-offset, 0px)) !important
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
right 0
|
|
10
10
|
z-index 89
|
|
11
11
|
height auto
|
|
12
|
-
|
|
12
|
+
|
|
13
|
+
bottom var(--footer-stack-height, 36px)
|
|
13
14
|
|
|
14
15
|
.qm-pinned
|
|
15
16
|
.qm-wrap-tooltip
|
|
@@ -101,4 +102,4 @@
|
|
|
101
102
|
> .drag
|
|
102
103
|
align-self flex-start
|
|
103
104
|
> button:last-child
|
|
104
|
-
align-self flex-end
|
|
105
|
+
align-self flex-end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create a quick command from outside the settings panel (e.g. from the
|
|
3
|
+
* command history action menu), reusing the very same form the settings panel
|
|
4
|
+
* uses — no fork of the form, so fields/validation stay in sync.
|
|
5
|
+
*
|
|
6
|
+
* The form is heavy (form, shortcuts editor, templates), and it otherwise only
|
|
7
|
+
* lives inside the lazily loaded quick commands setting tab, so lazy load it
|
|
8
|
+
* here as well.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { lazy, Suspense } from 'react'
|
|
12
|
+
import {
|
|
13
|
+
Modal,
|
|
14
|
+
Spin
|
|
15
|
+
} from 'antd'
|
|
16
|
+
import LazyBoundary from '../common/lazy-boundary'
|
|
17
|
+
import generate from '../../common/uid'
|
|
18
|
+
|
|
19
|
+
const QuickCommandForm = lazy(() => import('./quick-commands-form'))
|
|
20
|
+
|
|
21
|
+
const e = window.translate
|
|
22
|
+
|
|
23
|
+
export default function QuickCommandCreateModal (props) {
|
|
24
|
+
const { store, command, onClose } = props
|
|
25
|
+
const formData = {
|
|
26
|
+
id: '',
|
|
27
|
+
name: e('newQuickCommand'),
|
|
28
|
+
commands: [{
|
|
29
|
+
command,
|
|
30
|
+
id: generate(),
|
|
31
|
+
delay: 100
|
|
32
|
+
}]
|
|
33
|
+
}
|
|
34
|
+
return (
|
|
35
|
+
<Modal
|
|
36
|
+
open
|
|
37
|
+
title={e('addQuickCommands')}
|
|
38
|
+
onCancel={onClose}
|
|
39
|
+
destroyOnHidden
|
|
40
|
+
footer={null}
|
|
41
|
+
width={560}
|
|
42
|
+
>
|
|
43
|
+
<LazyBoundary>
|
|
44
|
+
<Suspense
|
|
45
|
+
fallback={(
|
|
46
|
+
<div className='pd3 aligncenter'>
|
|
47
|
+
<Spin />
|
|
48
|
+
</div>
|
|
49
|
+
)}
|
|
50
|
+
>
|
|
51
|
+
<QuickCommandForm
|
|
52
|
+
store={store}
|
|
53
|
+
formData={formData}
|
|
54
|
+
onSaved={onClose}
|
|
55
|
+
/>
|
|
56
|
+
</Suspense>
|
|
57
|
+
</LazyBoundary>
|
|
58
|
+
</Modal>
|
|
59
|
+
)
|
|
60
|
+
}
|
|
@@ -73,12 +73,18 @@ export default function QuickCommandForm (props) {
|
|
|
73
73
|
store.editQuickCommand(formData.id, update)
|
|
74
74
|
} else {
|
|
75
75
|
store.addQuickCommand(update1)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
// resetting the settings panel form only makes sense there; when the
|
|
77
|
+
// form is hosted elsewhere (e.g. the command history modal) the caller
|
|
78
|
+
// decides what happens next
|
|
79
|
+
if (!props.onSaved) {
|
|
80
|
+
store.setSettingItem({
|
|
81
|
+
id: '',
|
|
82
|
+
name: e('newQuickCommand')
|
|
83
|
+
})
|
|
84
|
+
}
|
|
80
85
|
}
|
|
81
86
|
message.success(e('saved'))
|
|
87
|
+
props.onSaved?.()
|
|
82
88
|
}
|
|
83
89
|
const initialValues = formData
|
|
84
90
|
if (!initialValues.labels) {
|
|
@@ -7,6 +7,7 @@ import { getLocalFileInfo } from '../sftp/file-read'
|
|
|
7
7
|
import { osResolve } from '../../common/resolve'
|
|
8
8
|
import { filesize } from 'filesize'
|
|
9
9
|
import sanitizeFilename from '../../common/sanitize-filename'
|
|
10
|
+
import { chooseSaveDirectory } from '../../common/choose-save-folder'
|
|
10
11
|
|
|
11
12
|
const LOG_PREFIX = '[RDP-FILE-TRANSFER]'
|
|
12
13
|
|
|
@@ -231,23 +232,22 @@ export class FileTransferManager {
|
|
|
231
232
|
|
|
232
233
|
async handleFileDownload (fileInfo) {
|
|
233
234
|
try {
|
|
234
|
-
const savePath = await
|
|
235
|
+
const savePath = await chooseSaveDirectory({
|
|
235
236
|
title: `Save ${fileInfo.name}`,
|
|
236
237
|
message: `Choose where to save ${fileInfo.name}`,
|
|
237
|
-
properties: ['openDirectory', 'createDirectory'],
|
|
238
238
|
noBrowserTransfer: true
|
|
239
239
|
}).catch((err) => {
|
|
240
240
|
this.log(`Save dialog error: ${err.message}`, 'error')
|
|
241
241
|
return false
|
|
242
242
|
})
|
|
243
243
|
|
|
244
|
-
if (!savePath
|
|
244
|
+
if (!savePath) {
|
|
245
245
|
this.log('Download cancelled by user', 'info')
|
|
246
246
|
return
|
|
247
247
|
}
|
|
248
248
|
|
|
249
249
|
const safeName = sanitizeFilename(fileInfo.name)
|
|
250
|
-
const fullPath = osResolve(savePath
|
|
250
|
+
const fullPath = osResolve(savePath, safeName)
|
|
251
251
|
|
|
252
252
|
const fd = await new Promise((resolve, reject) => {
|
|
253
253
|
window.fs.open(fullPath, O_WRONLY | O_CREAT | O_TRUNC, (err, fd) => {
|