@electerm/electerm-react 5.5.6 → 5.5.15
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/client/common/default-setting.js +1 -0
- package/client/common/download.jsx +12 -0
- package/client/common/resolve.js +20 -14
- package/client/components/ai/ai-history-item.jsx +1 -1
- package/client/components/ai/ai-history.jsx +1 -0
- package/client/components/ai/ai-history.styl +23 -0
- package/client/components/bookmark-form/common/color-picker.styl +3 -0
- package/client/components/common/remote-pointer.js +49 -0
- package/client/components/common/remote-session-shell.jsx +137 -0
- package/client/components/common/remote-session-shell.styl +80 -0
- package/client/components/common/responsive-tabs.jsx +89 -0
- package/client/components/common/responsive-tabs.styl +34 -0
- package/client/components/footer/cmd-history.jsx +132 -45
- package/client/components/footer/cmd-history.styl +42 -4
- package/client/components/footer/multi-tab-run-modal.jsx +83 -0
- package/client/components/footer/tab-select.jsx +34 -17
- 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/rdp-session.jsx +94 -124
- package/client/components/rdp/rdp.styl +13 -36
- package/client/components/session/session.styl +0 -16
- package/client/components/setting-panel/setting-modal.jsx +8 -3
- package/client/components/setting-panel/setting-terminal.jsx +1 -0
- package/client/components/sftp/sftp-entry.jsx +30 -0
- package/client/components/sidebar/side-panel.jsx +1 -1
- package/client/components/spice/spice-session.jsx +69 -72
- package/client/components/spice/spice.styl +10 -19
- package/client/components/terminal/mixins/term-content.js +38 -0
- package/client/components/terminal/mixins/term-context-menu.jsx +35 -3
- package/client/components/terminal/mixins/term-socket.js +5 -5
- package/client/components/terminal/mixins/term-touch.js +444 -57
- 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.jsx +13 -4
- package/client/components/terminal/ssh-reload-state.js +41 -1
- package/client/components/terminal/startup-queue.js +67 -13
- package/client/components/terminal/terminal-select-text.jsx +69 -0
- package/client/components/terminal/terminal.jsx +72 -4
- package/client/components/terminal/terminal.styl +61 -0
- package/client/components/theme/theme-form.jsx +18 -21
- package/client/components/theme/theme-form.styl +8 -10
- package/client/components/vnc/vnc-session.jsx +72 -104
- package/client/components/vnc/vnc.styl +25 -16
- package/client/css/mobile.styl +20 -7
- package/client/store/setting.js +4 -0
- package/client/store/tab.js +5 -4
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useRef, useState } from 'react'
|
|
2
|
-
import { Button, Input, Form,
|
|
2
|
+
import { Button, Input, Form, Flex } from 'antd'
|
|
3
3
|
import {
|
|
4
4
|
BgColorsOutlined,
|
|
5
5
|
FontSizeOutlined,
|
|
@@ -19,10 +19,11 @@ import generate from '../../common/uid'
|
|
|
19
19
|
import { isAIDisabled } from '../../common/ai-feature'
|
|
20
20
|
import Link from '../common/external-link'
|
|
21
21
|
import InputAutoFocus from '../common/input-auto-focus'
|
|
22
|
+
import ResponsiveTabs from '../common/responsive-tabs'
|
|
22
23
|
import ThemePicker from './theme-editor'
|
|
23
24
|
import ThemeAiEditor from './theme-ai-editor'
|
|
24
25
|
import Upload from '../common/upload'
|
|
25
|
-
|
|
26
|
+
import './theme-form.styl'
|
|
26
27
|
|
|
27
28
|
const { TextArea } = Input
|
|
28
29
|
const FormItem = Form.Item
|
|
@@ -155,6 +156,7 @@ export default function ThemeForm (props) {
|
|
|
155
156
|
<FormItem>
|
|
156
157
|
<span className='mg1r'>src:</span>
|
|
157
158
|
<Link
|
|
159
|
+
className='wordbreak'
|
|
158
160
|
to={url}
|
|
159
161
|
>{url}
|
|
160
162
|
</Link>
|
|
@@ -277,34 +279,29 @@ export default function ThemeForm (props) {
|
|
|
277
279
|
themeText: txt,
|
|
278
280
|
disabled
|
|
279
281
|
}
|
|
282
|
+
// icon + label, the label text is hidden by css on narrow screens so the
|
|
283
|
+
// three editor tabs always fit, the title keeps it discoverable
|
|
284
|
+
function renderTabLabel (icon, text) {
|
|
285
|
+
return (
|
|
286
|
+
<span className='theme-editor-tab' title={text}>
|
|
287
|
+
{icon}
|
|
288
|
+
<span className='theme-editor-tab-text'>{text}</span>
|
|
289
|
+
</span>
|
|
290
|
+
)
|
|
291
|
+
}
|
|
280
292
|
const tabItems = [
|
|
281
293
|
{
|
|
282
294
|
key: 'theme-editor-color-picker',
|
|
283
|
-
label: (
|
|
284
|
-
<span>
|
|
285
|
-
<BgColorsOutlined className='mg1r' />
|
|
286
|
-
{e('editWithColorPicker')}
|
|
287
|
-
</span>
|
|
288
|
-
)
|
|
295
|
+
label: renderTabLabel(<BgColorsOutlined className='mg1r' />, e('editWithColorPicker'))
|
|
289
296
|
},
|
|
290
297
|
{
|
|
291
298
|
key: 'theme-editor-txt',
|
|
292
|
-
label: (
|
|
293
|
-
<span>
|
|
294
|
-
<FontSizeOutlined className='mg1r' />
|
|
295
|
-
{e('editWithTextEditor')}
|
|
296
|
-
</span>
|
|
297
|
-
)
|
|
299
|
+
label: renderTabLabel(<FontSizeOutlined className='mg1r' />, e('editWithTextEditor'))
|
|
298
300
|
},
|
|
299
301
|
...(!isAIDisabled()
|
|
300
302
|
? [{
|
|
301
303
|
key: 'theme-editor-ai',
|
|
302
|
-
label: (
|
|
303
|
-
<span>
|
|
304
|
-
<RobotOutlined className='mg1r' />
|
|
305
|
-
AI
|
|
306
|
-
</span>
|
|
307
|
-
)
|
|
304
|
+
label: renderTabLabel(<RobotOutlined className='mg1r' />, 'AI')
|
|
308
305
|
}]
|
|
309
306
|
: [])
|
|
310
307
|
]
|
|
@@ -365,7 +362,7 @@ export default function ThemeForm (props) {
|
|
|
365
362
|
</Button>
|
|
366
363
|
</Upload>
|
|
367
364
|
</Flex>
|
|
368
|
-
<
|
|
365
|
+
<ResponsiveTabs {...tabsProps} />
|
|
369
366
|
{
|
|
370
367
|
editor === 'theme-editor-txt'
|
|
371
368
|
? renderTxt()
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
.
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
.editor-u-picker
|
|
10
|
-
display block !important
|
|
1
|
+
// setting panel > UI themes > theme form
|
|
2
|
+
//
|
|
3
|
+
// The three editor tabs need ~395px for their translated labels ("Edit with
|
|
4
|
+
// color picker" / "Edit with text editor" / "AI") while a 320px phone leaves
|
|
5
|
+
// the panel only ~257px. Below the app's mobile breakpoint (600px, see
|
|
6
|
+
// constants.js) ResponsiveTabs replaces the bar with a single "current tab +
|
|
7
|
+
// dropdown" selector (common/responsive-tabs.jsx), so the labels stay readable
|
|
8
|
+
// everywhere instead of being collapsed to icons.
|
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
statusMap
|
|
8
8
|
} from '../../common/constants'
|
|
9
9
|
import {
|
|
10
|
-
Spin,
|
|
11
10
|
Select
|
|
12
11
|
} from 'antd'
|
|
13
12
|
import {
|
|
@@ -18,6 +17,7 @@ import Modal from '../common/modal'
|
|
|
18
17
|
import { copy, readClipboard } from '../../common/clipboard'
|
|
19
18
|
import VncForm from './vnc-form'
|
|
20
19
|
import RemoteFloatControl from '../common/remote-float-control'
|
|
20
|
+
import RemoteSessionShell from '../common/remote-session-shell'
|
|
21
21
|
import './vnc.styl'
|
|
22
22
|
|
|
23
23
|
// noVNC module imports — loaded dynamically
|
|
@@ -71,23 +71,35 @@ export default class VncSession extends PureComponent {
|
|
|
71
71
|
})
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
remoteHeight: currentScreenData ? currentScreenData.height : null
|
|
74
|
+
// fullscreen always fills the screen, the per tab setting only applies
|
|
75
|
+
// windowed; the switch is not reachable in fullscreen anyway
|
|
76
|
+
getFit = () => {
|
|
77
|
+
if (this.props.fullscreen) {
|
|
78
|
+
return true
|
|
80
79
|
}
|
|
80
|
+
const { scaleViewport = true } = this.props.tab
|
|
81
|
+
return !!scaleViewport
|
|
81
82
|
}
|
|
82
83
|
|
|
84
|
+
// viewport box measured by the shell, used as the size hint for the server.
|
|
85
|
+
// Falls back to the layout props before the first measurement.
|
|
83
86
|
calcCanvasSize = () => {
|
|
84
|
-
const { width, height } = this.
|
|
87
|
+
const { width, height } = this.viewSize || {}
|
|
88
|
+
if (width && height) {
|
|
89
|
+
return { width, height }
|
|
90
|
+
}
|
|
91
|
+
const { width: w, height: h } = this.props
|
|
85
92
|
return {
|
|
86
|
-
width:
|
|
87
|
-
height:
|
|
93
|
+
width: w - 10,
|
|
94
|
+
height: h - 80
|
|
88
95
|
}
|
|
89
96
|
}
|
|
90
97
|
|
|
98
|
+
handleViewportResize = (width, height) => {
|
|
99
|
+
this.viewSize = { width, height }
|
|
100
|
+
this.updateViewLayout()
|
|
101
|
+
}
|
|
102
|
+
|
|
91
103
|
buildWsUrl = (port, type = 'vnc', extra = '') => {
|
|
92
104
|
const { host, tokenElecterm } = this.props.config
|
|
93
105
|
const { id } = this.props.tab
|
|
@@ -127,30 +139,6 @@ export default class VncSession extends PureComponent {
|
|
|
127
139
|
}
|
|
128
140
|
}
|
|
129
141
|
|
|
130
|
-
renderControl = () => {
|
|
131
|
-
const contrlProps = this.getControlProps({
|
|
132
|
-
fixedPosition: false,
|
|
133
|
-
showExitFullscreen: false,
|
|
134
|
-
className: 'mg1l'
|
|
135
|
-
})
|
|
136
|
-
return (
|
|
137
|
-
<div className='pd1 fix session-v-info'>
|
|
138
|
-
<div className='fleft'>
|
|
139
|
-
<ReloadOutlined
|
|
140
|
-
onClick={this.handleReInit}
|
|
141
|
-
className='mg2r mg1l pointer'
|
|
142
|
-
/>
|
|
143
|
-
{this.renderScreensSelect()}
|
|
144
|
-
{this.renderInfo()}
|
|
145
|
-
</div>
|
|
146
|
-
<div className='fright'>
|
|
147
|
-
{this.props.fullscreenIcon()}
|
|
148
|
-
<RemoteFloatControl {...contrlProps} />
|
|
149
|
-
</div>
|
|
150
|
-
</div>
|
|
151
|
-
)
|
|
152
|
-
}
|
|
153
|
-
|
|
154
142
|
renderScreensSelect = () => {
|
|
155
143
|
const {
|
|
156
144
|
screens,
|
|
@@ -232,8 +220,9 @@ export default class VncSession extends PureComponent {
|
|
|
232
220
|
|
|
233
221
|
const { width, height } = this.calcCanvasSize()
|
|
234
222
|
const wsUrl = this.buildWsUrl(port, 'vnc', `&width=${width}&height=${height}`)
|
|
235
|
-
//
|
|
236
|
-
//
|
|
223
|
+
// noVNC sizes its own canvas (`_screen` fills whatever box it is mounted
|
|
224
|
+
// into, the canvas is centered in it), so scaling is entirely driven by
|
|
225
|
+
// `scaleViewport` plus the size of the mount node.
|
|
237
226
|
const vncOpts = {
|
|
238
227
|
clipViewport,
|
|
239
228
|
scaleViewport,
|
|
@@ -241,13 +230,6 @@ export default class VncSession extends PureComponent {
|
|
|
241
230
|
qualityLevel, // JPEG quality 0-9, lower = faster
|
|
242
231
|
compressionLevel, // Compression 0-9, lower = faster
|
|
243
232
|
shared, // Allow shared connections
|
|
244
|
-
style: scaleViewport
|
|
245
|
-
? {
|
|
246
|
-
width: width + 'px',
|
|
247
|
-
height: height + 'px',
|
|
248
|
-
overflow: 'hidden'
|
|
249
|
-
}
|
|
250
|
-
: {},
|
|
251
233
|
credentials: {}
|
|
252
234
|
}
|
|
253
235
|
if (username) {
|
|
@@ -378,7 +360,7 @@ export default class VncSession extends PureComponent {
|
|
|
378
360
|
for (const event of events) {
|
|
379
361
|
rfb.addEventListener(event, this[`on${window.capitalizeFirstLetter(event)}`])
|
|
380
362
|
}
|
|
381
|
-
rfb.scaleViewport =
|
|
363
|
+
rfb.scaleViewport = this.getFit()
|
|
382
364
|
rfb.clipViewport = clipViewport
|
|
383
365
|
rfb.qualityLevel = qualityLevel
|
|
384
366
|
rfb.compressionLevel = compressionLevel
|
|
@@ -550,9 +532,10 @@ export default class VncSession extends PureComponent {
|
|
|
550
532
|
}
|
|
551
533
|
|
|
552
534
|
componentDidUpdate (prevProps, prevState) {
|
|
535
|
+
// viewport size changes are reported by the shell, the layout props are
|
|
536
|
+
// stale in fullscreen so they are not used here
|
|
553
537
|
if (
|
|
554
|
-
prevProps.
|
|
555
|
-
prevProps.height !== this.props.height ||
|
|
538
|
+
prevProps.fullscreen !== this.props.fullscreen ||
|
|
556
539
|
prevState.currentScreen !== this.state.currentScreen
|
|
557
540
|
) {
|
|
558
541
|
this.updateViewLayout()
|
|
@@ -561,24 +544,25 @@ export default class VncSession extends PureComponent {
|
|
|
561
544
|
|
|
562
545
|
updateViewLayout = () => {
|
|
563
546
|
const { currentScreen, screens } = this.state
|
|
564
|
-
const {
|
|
547
|
+
const { clipViewport = false } = this.props.tab
|
|
565
548
|
const container = this.domRef.current ? this.domRef.current.firstElementChild : null
|
|
566
549
|
|
|
567
550
|
if (!this.rfb || !container) {
|
|
568
551
|
return
|
|
569
552
|
}
|
|
570
553
|
|
|
571
|
-
//
|
|
572
|
-
//
|
|
573
|
-
|
|
554
|
+
// keep noVNC scaling in sync with our fit state, then re-run autoscale so
|
|
555
|
+
// our patched single screen logic sees the new viewport size
|
|
556
|
+
const fit = this.getFit()
|
|
557
|
+
this.rfb.scaleViewport = fit
|
|
574
558
|
this.rfb.clipViewport = clipViewport
|
|
575
559
|
|
|
576
|
-
|
|
577
|
-
if (scaleViewport && this.rfb._display) {
|
|
560
|
+
if (fit && this.rfb._display) {
|
|
578
561
|
this.rfb._display.autoscale(container.clientWidth, container.clientHeight)
|
|
579
562
|
}
|
|
580
563
|
|
|
581
564
|
// Handle scrolling to the selected screen
|
|
565
|
+
clearTimeout(this.timer)
|
|
582
566
|
this.timer = setTimeout(() => {
|
|
583
567
|
if (currentScreen === 'all') {
|
|
584
568
|
container.scrollTo(0, 0)
|
|
@@ -653,61 +637,45 @@ export default class VncSession extends PureComponent {
|
|
|
653
637
|
}
|
|
654
638
|
|
|
655
639
|
render () {
|
|
656
|
-
const { width: w, height: h } = this.props
|
|
657
640
|
const { loading } = this.state
|
|
658
|
-
const
|
|
659
|
-
const
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
const
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
className: 'vnc-session-wrap session-v-wrap'
|
|
681
|
-
}
|
|
682
|
-
const contrlProps = this.getControlProps()
|
|
683
|
-
const sessProps = {
|
|
684
|
-
className: 'vnc-session-wrap',
|
|
685
|
-
style: {
|
|
686
|
-
width: w + 'px',
|
|
687
|
-
height: h + 'px'
|
|
688
|
-
}
|
|
689
|
-
}
|
|
641
|
+
const floatProps = this.getControlProps()
|
|
642
|
+
const inlineProps = this.getControlProps({
|
|
643
|
+
fixedPosition: false,
|
|
644
|
+
showExitFullscreen: false,
|
|
645
|
+
className: 'mg1l'
|
|
646
|
+
})
|
|
647
|
+
const controlLeft = (
|
|
648
|
+
<>
|
|
649
|
+
<ReloadOutlined
|
|
650
|
+
onClick={this.handleReInit}
|
|
651
|
+
className='mg2r mg1l pointer'
|
|
652
|
+
/>
|
|
653
|
+
{this.renderScreensSelect()}
|
|
654
|
+
{this.renderInfo()}
|
|
655
|
+
</>
|
|
656
|
+
)
|
|
657
|
+
const controlRight = (
|
|
658
|
+
<>
|
|
659
|
+
{this.props.fullscreenIcon()}
|
|
660
|
+
<RemoteFloatControl {...inlineProps} />
|
|
661
|
+
</>
|
|
662
|
+
)
|
|
690
663
|
return (
|
|
691
|
-
<
|
|
664
|
+
<RemoteSessionShell
|
|
665
|
+
loading={loading}
|
|
666
|
+
fit={this.getFit()}
|
|
667
|
+
wrapClassName='vnc-session-wrap'
|
|
668
|
+
onViewportResize={this.handleViewportResize}
|
|
669
|
+
controlLeft={controlLeft}
|
|
670
|
+
controlRight={controlRight}
|
|
671
|
+
floatControl={<RemoteFloatControl {...floatProps} />}
|
|
672
|
+
overlay={this.renderConfirm()}
|
|
673
|
+
>
|
|
692
674
|
<div
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
{...contrlProps}
|
|
698
|
-
/>
|
|
699
|
-
<div
|
|
700
|
-
style={wrapperStyle}
|
|
701
|
-
className='vnc-scroll-wrapper'
|
|
702
|
-
>
|
|
703
|
-
<div
|
|
704
|
-
{...divProps}
|
|
705
|
-
ref={this.domRef}
|
|
706
|
-
/>
|
|
707
|
-
</div>
|
|
708
|
-
{this.renderConfirm()}
|
|
709
|
-
</div>
|
|
710
|
-
</Spin>
|
|
675
|
+
className='remote-session-fill vnc-session-mount'
|
|
676
|
+
ref={this.domRef}
|
|
677
|
+
/>
|
|
678
|
+
</RemoteSessionShell>
|
|
711
679
|
)
|
|
712
680
|
}
|
|
713
681
|
}
|
|
@@ -1,17 +1,26 @@
|
|
|
1
|
+
// VNC only styling — the session layout (control bar, viewport, fit mode)
|
|
2
|
+
// lives in the shared remote session shell: common/remote-session-shell.styl
|
|
1
3
|
.vnc-session-wrap
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
4
|
+
.vnc-session-mount
|
|
5
|
+
// noVNC mounts its own screen element in here and sizes its canvas
|
|
6
|
+
// against this box, so it has to keep a definite size
|
|
7
|
+
width 100%
|
|
8
|
+
height 100%
|
|
9
|
+
// noVNC's screen element carries no class of its own: letterbox area
|
|
10
|
+
// follows the app theme instead of noVNC's own background
|
|
11
|
+
> div
|
|
12
|
+
background transparent !important
|
|
13
|
+
// scrolled when fit is off and the remote screen is bigger than
|
|
14
|
+
// the window
|
|
15
|
+
&::-webkit-scrollbar
|
|
16
|
+
width 16px
|
|
17
|
+
height 16px
|
|
18
|
+
background var(--main-darker)
|
|
19
|
+
&::-webkit-scrollbar-track
|
|
20
|
+
background var(--main-darker)
|
|
21
|
+
box-shadow inset 0 0 5px var(--main-darker)
|
|
22
|
+
&::-webkit-scrollbar-thumb
|
|
23
|
+
background var(--primary)
|
|
24
|
+
border-radius 0
|
|
25
|
+
&::-webkit-scrollbar-corner
|
|
26
|
+
background var(--main-darker)
|
package/client/css/mobile.styl
CHANGED
|
@@ -170,18 +170,31 @@
|
|
|
170
170
|
.upgrade-panel
|
|
171
171
|
max-width calc(100vw - 20px)
|
|
172
172
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
173
|
+
// ---------------------------------------------------------------------------
|
|
174
|
+
// Terminal touch selection (behaviour in mixins/term-touch.js).
|
|
175
|
+
//
|
|
176
|
+
// Scoped to is-touch-device on top of the narrow-window is-mobile case: a
|
|
177
|
+
// tablet held in landscape is wider than the 600px mobile breakpoint but is
|
|
178
|
+
// still touch-primary and needs the same suppression, while store.isTouchDevice
|
|
179
|
+
// keeps it off for anything mouse-driven (it follows the input in use — see
|
|
180
|
+
// main.jsx).
|
|
181
|
+
//
|
|
182
|
+
// - the browser's native long-press callout (iOS "Copy/Look Up" menu) and its
|
|
183
|
+
// own text-selection gesture would fight xterm for the touch stream and
|
|
184
|
+
// swallow the long press that starts a selection;
|
|
185
|
+
// - xterm already sets user-select:none on .xterm; touch-action:none stops the
|
|
186
|
+
// browser scrolling/zooming the page out from under a selection drag, since
|
|
187
|
+
// xterm does its own scrolling from gesture events.
|
|
188
|
+
// ---------------------------------------------------------------------------
|
|
189
|
+
.is-mobile,
|
|
190
|
+
.is-touch-device
|
|
180
191
|
.term-wrap
|
|
181
192
|
-webkit-touch-callout none
|
|
182
193
|
-webkit-tap-highlight-color transparent
|
|
183
194
|
.xterm
|
|
184
195
|
-webkit-touch-callout none
|
|
196
|
+
-webkit-user-select none
|
|
197
|
+
user-select none
|
|
185
198
|
touch-action none
|
|
186
199
|
|
|
187
200
|
// ---------------------------------------------------------------------------
|
package/client/store/setting.js
CHANGED
|
@@ -111,6 +111,10 @@ export default Store => {
|
|
|
111
111
|
})
|
|
112
112
|
store.setSettingItem(settingList().find(d => d.id === settingSyncId))
|
|
113
113
|
store.openSettingModal()
|
|
114
|
+
// on mobile, jump straight to the sync form instead of the menu list
|
|
115
|
+
if (store.isMobile) {
|
|
116
|
+
store.settingMobileView = 'content'
|
|
117
|
+
}
|
|
114
118
|
})
|
|
115
119
|
}
|
|
116
120
|
|
package/client/store/tab.js
CHANGED
|
@@ -17,10 +17,10 @@ import generate from '../common/id-with-stamp'
|
|
|
17
17
|
import uid from '../common/uid'
|
|
18
18
|
import newTerm, { updateCount } from '../common/new-terminal.js'
|
|
19
19
|
import { action } from 'manate'
|
|
20
|
-
import {
|
|
20
|
+
import { shouldCaptureTerminalReloadState } from '../components/terminal/ssh-reload-state.js'
|
|
21
21
|
|
|
22
22
|
function captureSshSessionState (tab, config) {
|
|
23
|
-
return
|
|
23
|
+
return shouldCaptureTerminalReloadState(tab, config)
|
|
24
24
|
? refs.get(`term-${tab.id}`)?.getReloadState?.()
|
|
25
25
|
: undefined
|
|
26
26
|
}
|
|
@@ -103,8 +103,9 @@ export default Store => {
|
|
|
103
103
|
const oldTab = tabs[index]
|
|
104
104
|
const oldBatch = oldTab.batch
|
|
105
105
|
|
|
106
|
-
// Reload state is captured only for
|
|
107
|
-
//
|
|
106
|
+
// Reload state is captured only for a shell terminal refresh/reconnect
|
|
107
|
+
// (ssh, local, telnet, serial). Closing a tab goes through removeTabs
|
|
108
|
+
// and never reaches this code path.
|
|
108
109
|
const reloadState = captureSshSessionState(oldTab, store.config)
|
|
109
110
|
|
|
110
111
|
// Create copy of old tab with new ID
|