@electerm/electerm-react 2.3.151 → 2.3.166

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.
Files changed (40) hide show
  1. package/client/common/constants.js +4 -2
  2. package/client/common/db.js +2 -1
  3. package/client/common/init-setting-item.js +7 -0
  4. package/client/components/common/modal.jsx +89 -0
  5. package/client/components/common/modal.styl +77 -0
  6. package/client/components/common/notification-with-details.jsx +34 -0
  7. package/client/components/file-transfer/conflict-resolve.jsx +2 -1
  8. package/client/components/file-transfer/transfer-speed-format.js +6 -0
  9. package/client/components/file-transfer/transfer.jsx +5 -2
  10. package/client/components/file-transfer/transports-action-store.jsx +14 -1
  11. package/client/components/main/main.jsx +2 -0
  12. package/client/components/setting-panel/setting-common.jsx +4 -3
  13. package/client/components/setting-panel/start-session-select.jsx +146 -21
  14. package/client/components/setting-panel/text-bg-modal.jsx +15 -4
  15. package/client/components/sftp/file-info-modal.jsx +2 -1
  16. package/client/components/sftp/file-item.jsx +2 -0
  17. package/client/components/sidebar/info-modal.jsx +53 -34
  18. package/client/components/sidebar/info.styl +0 -7
  19. package/client/components/tabs/index.jsx +6 -58
  20. package/client/components/tabs/layout-menu.jsx +75 -0
  21. package/client/components/tabs/layout-select.jsx +60 -0
  22. package/client/components/tabs/tabs.styl +64 -0
  23. package/client/components/tabs/workspace-save-modal.jsx +117 -0
  24. package/client/components/tabs/workspace-select.jsx +79 -0
  25. package/client/components/terminal/attach-addon-custom.js +7 -1
  26. package/client/components/terminal/terminal-interactive.jsx +2 -1
  27. package/client/components/terminal/terminal.jsx +0 -1
  28. package/client/components/text-editor/text-editor.jsx +2 -1
  29. package/client/components/tree-list/move-item-modal.jsx +2 -1
  30. package/client/components/vnc/vnc-session.jsx +2 -2
  31. package/client/components/widgets/widget-control.jsx +4 -5
  32. package/client/components/widgets/widget-form.jsx +3 -8
  33. package/client/components/widgets/widget-instance.jsx +44 -9
  34. package/client/components/widgets/widget-notification-with-details.jsx +34 -0
  35. package/client/css/basic.styl +3 -1
  36. package/client/store/init-state.js +4 -0
  37. package/client/store/load-data.js +15 -6
  38. package/client/store/store.js +2 -0
  39. package/client/store/workspace.js +108 -0
  40. package/package.json +1 -1
@@ -8,10 +8,10 @@ import {
8
8
  InfoCircleOutlined,
9
9
  AlignLeftOutlined,
10
10
  BugOutlined,
11
- HeartOutlined,
12
- JavaScriptOutlined
11
+ HeartOutlined
13
12
  } from '@ant-design/icons'
14
- import { Modal, Tabs, Button } from 'antd'
13
+ import { Tabs, Button } from 'antd'
14
+ import Modal from '../common/modal'
15
15
  import Link from '../common/external-link'
16
16
  import LogoElem from '../common/logo-elem'
17
17
  import RunningTime from './app-running-time'
@@ -55,8 +55,48 @@ export default auto(function InfoModal (props) {
55
55
  )
56
56
  }
57
57
 
58
- const formatJSON = (jsonStr) => {
59
- return JSON.stringify(JSON.parse(jsonStr), null, 2)
58
+ const renderParsed = (obj, depth = 0) => {
59
+ if (Array.isArray(obj)) {
60
+ return (
61
+ <ul className='pd2l'>
62
+ {obj.map((item, i) => (
63
+ <li key={i}>{renderParsed(item, depth + 1)}</li>
64
+ ))}
65
+ </ul>
66
+ )
67
+ } else if (typeof obj === 'object' && obj !== null) {
68
+ return (
69
+ <div className={depth > 0 ? 'pd2l' : ''}>
70
+ {Object.entries(obj).map(([k, v]) => (
71
+ <div key={k} className='pd1b'>
72
+ <b>{k}:</b> {renderParsed(v, depth + 1)}
73
+ </div>
74
+ ))}
75
+ </div>
76
+ )
77
+ } else {
78
+ return <span>{String(obj)}</span>
79
+ }
80
+ }
81
+
82
+ const renderValue = (v) => {
83
+ try {
84
+ const parsed = JSON.parse(v)
85
+ return renderParsed(parsed)
86
+ } catch {
87
+ return <span>{v}</span>
88
+ }
89
+ }
90
+
91
+ const renderOSInfo = () => {
92
+ return window.pre.osInfo().map(({ k, v }, i) => (
93
+ <div className='pd1b' key={i + '_os_' + k}>
94
+ <b className='bold'>{k}:</b>
95
+ <span className='mg1l'>
96
+ {renderValue(v)}
97
+ </span>
98
+ </div>
99
+ ))
60
100
  }
61
101
 
62
102
  const { infoModalTab, commandLineHelp } = props
@@ -100,7 +140,7 @@ export default auto(function InfoModal (props) {
100
140
  ...env
101
141
  }
102
142
  const title = (
103
- <div className='ant-modal-confirm-title font16'>
143
+ <div className='custom-modal-close-confirm-title font16'>
104
144
  <InfoCircleOutlined className='font20 mg1r' /> {e('about')} {name}
105
145
  </div>
106
146
  )
@@ -108,9 +148,7 @@ export default auto(function InfoModal (props) {
108
148
  title,
109
149
  width: window.innerWidth - 100,
110
150
  maskClosable: true,
111
- okText: e('ok'),
112
151
  onCancel: onCloseAbout,
113
- footer: null,
114
152
  open: true,
115
153
  wrapClassName: 'info-modal'
116
154
  }
@@ -123,18 +161,18 @@ export default auto(function InfoModal (props) {
123
161
  <LogoElem />
124
162
  <p className='mg2b'>{e('desc')}</p>
125
163
  <RunningTime />
126
- <p className='mg1b'>
127
- <UserOutlined /> <b className='mg1r'>{e('author')} ➾</b>
128
- <Link to={authorUrl} className='mg1l'>
129
- {authorName} ({email})
130
- </Link>
131
- </p>
132
164
  <p className='mg1b'>
133
165
  <HomeOutlined /> <b>{e('homepage')}/{e('download')} ➾</b>
134
166
  <Link to={homepage} className='mg1l'>
135
167
  {homepage}
136
168
  </Link>
137
169
  </p>
170
+ <p className='mg1b'>
171
+ <UserOutlined /> <b className='mg1r'>{e('author')} ➾</b>
172
+ <Link to={authorUrl} className='mg1l'>
173
+ {authorName} ({email})
174
+ </Link>
175
+ </p>
138
176
  <p className='mg1b'>
139
177
  <GithubOutlined /> <b className='mg1r'>github ➾</b>
140
178
  <Link to={link} className='mg1l'>
@@ -180,12 +218,6 @@ export default auto(function InfoModal (props) {
180
218
  <p className='mg1b'>
181
219
  <InfoCircleOutlined /> <b className='mg1r'>{window.store.installSrc}</b>
182
220
  </p>
183
- <p className='mg1b'>
184
- <JavaScriptOutlined /> <b className='mg1r'>Powered by</b>
185
- <Link to='https://github.com/tylerlong/manate'>
186
- manate
187
- </Link>
188
- </p>
189
221
  {renderCheckUpdate()}
190
222
  </>
191
223
  )
@@ -223,20 +255,7 @@ export default auto(function InfoModal (props) {
223
255
  {
224
256
  key: infoTabs.os,
225
257
  label: e('os'),
226
- children: window.pre.osInfo().map(({ k, v }, i) => {
227
- return (
228
- <div className='pd1b' key={i + '_os_' + k}>
229
- <b className='bold'>{k}</b>:
230
- <span className='mg1l'>
231
- {
232
- v.length > 30
233
- ? <pre>{formatJSON(v)}</pre>
234
- : v
235
- }
236
- </span>
237
- </div>
238
- )
239
- })
258
+ children: <div>{renderOSInfo()}</div>
240
259
  }
241
260
  ]
242
261
 
@@ -5,10 +5,3 @@
5
5
  border-radius 60% 40% 30% 70% / 60% 30% 70% 40%
6
6
  transition all 1s ease-in-out
7
7
  z-index 5
8
-
9
- .info-modal
10
- .ant-modal-header
11
- border none
12
- .ant-modal-body
13
- padding 52px
14
- padding-top 0
@@ -12,26 +12,16 @@ import {
12
12
  LeftOutlined,
13
13
  RightOutlined
14
14
  } from '@ant-design/icons'
15
- import {
16
- SingleIcon,
17
- TwoColumnsIcon,
18
- ThreeColumnsIcon,
19
- TwoRowsIcon,
20
- ThreeRowsIcon,
21
- Grid2x2Icon,
22
- TwoRowsRightIcon,
23
- TwoColumnsBottomIcon
24
- } from '../icons/split-icons'
25
15
  import { Dropdown } from 'antd'
26
16
  import Tab from './tab'
17
+ import LayoutMenu from './layout-menu'
27
18
  import './tabs.styl'
28
19
  import {
29
20
  tabWidth,
30
21
  tabMargin,
31
22
  extraTabWidth,
32
23
  windowControlWidth,
33
- isMacJs,
34
- splitMapDesc
24
+ isMacJs
35
25
  } from '../../common/constants'
36
26
  import WindowControl from './window-control'
37
27
  import AddBtn from './add-btn'
@@ -39,8 +29,6 @@ import AppDrag from './app-drag'
39
29
  import NoSession from './no-session'
40
30
  import classNames from 'classnames'
41
31
 
42
- const e = window.translate
43
-
44
32
  export default class Tabs extends Component {
45
33
  constructor (props) {
46
34
  super(props)
@@ -183,10 +171,6 @@ export default class Tabs extends Component {
183
171
  window.store['activeTabId' + this.props.batch] = id
184
172
  }
185
173
 
186
- handleChangeLayout = ({ key }) => {
187
- window.store.setLayout(key)
188
- }
189
-
190
174
  renderAddBtn = () => {
191
175
  const cls = classNames(
192
176
  'pointer tabs-add-btn font16',
@@ -324,48 +308,12 @@ export default class Tabs extends Component {
324
308
  )
325
309
  }
326
310
 
327
- getLayoutIcon = (layout) => {
328
- const iconMaps = {
329
- single: SingleIcon,
330
- twoColumns: TwoColumnsIcon,
331
- threeColumns: ThreeColumnsIcon,
332
- twoRows: TwoRowsIcon,
333
- threeRows: ThreeRowsIcon,
334
- grid2x2: Grid2x2Icon,
335
- twoRowsRight: TwoRowsRightIcon,
336
- twoColumnsBottom: TwoColumnsBottomIcon
337
- }
338
- return iconMaps[layout]
339
- }
340
-
341
311
  renderLayoutMenu = () => {
342
- if (!this.shouldRenderWindowControl()) {
343
- return null
344
- }
345
- const items = Object.keys(splitMapDesc).map((t) => {
346
- const v = splitMapDesc[t]
347
- const Icon = this.getLayoutIcon(v)
348
- return {
349
- key: t,
350
- label: (
351
- <span>
352
- <Icon /> {e(v)}
353
- </span>
354
- ),
355
- onClick: () => this.handleChangeLayout({ key: t })
356
- }
357
- })
358
- const v = splitMapDesc[this.props.layout]
359
- const Icon = this.getLayoutIcon(v)
360
312
  return (
361
- <Dropdown
362
- menu={{ items }}
363
- placement='bottomRight'
364
- >
365
- <span className='tabs-dd-icon layout-dd-icon mg1l'>
366
- <Icon /> <DownOutlined />
367
- </span>
368
- </Dropdown>
313
+ <LayoutMenu
314
+ layout={this.props.layout}
315
+ visible={this.shouldRenderWindowControl()}
316
+ />
369
317
  )
370
318
  }
371
319
 
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Layout and Workspace menu dropdown component
3
+ */
4
+
5
+ import React, { useState } from 'react'
6
+ import { Dropdown, Tabs } from 'antd'
7
+ import {
8
+ DownOutlined,
9
+ AppstoreOutlined,
10
+ LayoutOutlined
11
+ } from '@ant-design/icons'
12
+ import { splitMapDesc } from '../../common/constants'
13
+ import LayoutSelect, { getLayoutIcon } from './layout-select'
14
+ import WorkspaceSelect from './workspace-select'
15
+ import HelpIcon from '../common/help-icon'
16
+
17
+ const e = window.translate
18
+
19
+ export default function LayoutMenu (props) {
20
+ const { layout, visible } = props
21
+ const [activeTab, setActiveTab] = useState('layout')
22
+
23
+ if (!visible) {
24
+ return null
25
+ }
26
+
27
+ const tabItems = [
28
+ {
29
+ key: 'layout',
30
+ label: (
31
+ <span>
32
+ <LayoutOutlined /> {e('layout')}
33
+ </span>
34
+ )
35
+ },
36
+ {
37
+ key: 'workspaces',
38
+ label: (
39
+ <span>
40
+ <AppstoreOutlined /> {e('workspaces')}
41
+ <HelpIcon link='https://github.com/electerm/electerm/wiki/Workspace-Feature' />
42
+ </span>
43
+ )
44
+ }
45
+ ]
46
+
47
+ const v = splitMapDesc[layout]
48
+ const Icon = getLayoutIcon(v)
49
+
50
+ const dropdownContent = (
51
+ <div className='layout-workspace-dropdown'>
52
+ <Tabs
53
+ items={tabItems}
54
+ size='small'
55
+ activeKey={activeTab}
56
+ onChange={setActiveTab}
57
+ />
58
+ {activeTab === 'layout'
59
+ ? <LayoutSelect layout={layout} />
60
+ : <WorkspaceSelect store={window.store} />}
61
+ </div>
62
+ )
63
+
64
+ return (
65
+ <Dropdown
66
+ popupRender={() => dropdownContent}
67
+ placement='bottomRight'
68
+ trigger={['click']}
69
+ >
70
+ <span className='tabs-dd-icon layout-dd-icon mg1l'>
71
+ <Icon /> <DownOutlined />
72
+ </span>
73
+ </Dropdown>
74
+ )
75
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Layout select content component
3
+ */
4
+
5
+ import React from 'react'
6
+ import {
7
+ SingleIcon,
8
+ TwoColumnsIcon,
9
+ ThreeColumnsIcon,
10
+ TwoRowsIcon,
11
+ ThreeRowsIcon,
12
+ Grid2x2Icon,
13
+ TwoRowsRightIcon,
14
+ TwoColumnsBottomIcon
15
+ } from '../icons/split-icons'
16
+ import { splitMapDesc } from '../../common/constants'
17
+
18
+ const e = window.translate
19
+
20
+ const iconMaps = {
21
+ single: SingleIcon,
22
+ twoColumns: TwoColumnsIcon,
23
+ threeColumns: ThreeColumnsIcon,
24
+ twoRows: TwoRowsIcon,
25
+ threeRows: ThreeRowsIcon,
26
+ grid2x2: Grid2x2Icon,
27
+ twoRowsRight: TwoRowsRightIcon,
28
+ twoColumnsBottom: TwoColumnsBottomIcon
29
+ }
30
+
31
+ export function getLayoutIcon (layout) {
32
+ return iconMaps[layout]
33
+ }
34
+
35
+ export default function LayoutSelect (props) {
36
+ const { layout } = props
37
+
38
+ function handleChangeLayout (key) {
39
+ window.store.setLayout(key)
40
+ }
41
+
42
+ return (
43
+ <div className='layout-menu-content'>
44
+ {Object.keys(splitMapDesc).map((t) => {
45
+ const v = splitMapDesc[t]
46
+ const Icon = getLayoutIcon(v)
47
+ const isActive = layout === t
48
+ return (
49
+ <div
50
+ key={t}
51
+ className={`layout-menu-item ${isActive ? 'active' : ''}`}
52
+ onClick={() => handleChangeLayout(t)}
53
+ >
54
+ <Icon /> {e(v)}
55
+ </div>
56
+ )
57
+ })}
58
+ </div>
59
+ )
60
+ }
@@ -244,3 +244,67 @@
244
244
  max-height 300px
245
245
  overflow-y auto
246
246
 
247
+ // Layout and Workspace dropdown styles
248
+ .layout-workspace-dropdown
249
+ background var(--main)
250
+ border-radius 4px
251
+ box-shadow 0 2px 8px rgba(0, 0, 0, 0.15)
252
+ min-width 200px
253
+ padding 8px
254
+ .ant-tabs-nav
255
+ margin-bottom 8px
256
+
257
+ .layout-menu-content
258
+ max-height 300px
259
+ overflow-y auto
260
+
261
+ .layout-menu-item
262
+ padding 6px 12px
263
+ cursor pointer
264
+ border-radius 4px
265
+ display flex
266
+ align-items center
267
+ gap 8px
268
+ color var(--text)
269
+ &:hover
270
+ background var(--main-dark)
271
+ &.active
272
+ background var(--primary)
273
+ color #fff
274
+
275
+ .workspace-menu-content
276
+ max-height 300px
277
+ overflow-y auto
278
+
279
+ .workspace-save-btn
280
+ margin-bottom 8px
281
+
282
+ .workspace-list
283
+ display flex
284
+ flex-direction column
285
+ gap 4px
286
+
287
+ .workspace-item
288
+ padding 6px 12px
289
+ cursor pointer
290
+ border-radius 4px
291
+ display flex
292
+ align-items center
293
+ justify-content space-between
294
+ color var(--text)
295
+ &:hover
296
+ background var(--main-dark)
297
+ .workspace-delete-icon
298
+ opacity 0
299
+ color var(--text-dark)
300
+ &:hover
301
+ color var(--error)
302
+ &:hover .workspace-delete-icon
303
+ opacity 1
304
+
305
+ .workspace-name
306
+ flex 1
307
+ overflow hidden
308
+ text-overflow ellipsis
309
+ white-space nowrap
310
+
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Workspace save modal component - standalone modal
3
+ */
4
+
5
+ import React, { useState } from 'react'
6
+ import { auto } from 'manate/react'
7
+ import Modal from '../common/modal'
8
+ import { Input, Select, Button, Space, message, Radio } from 'antd'
9
+ import { SaveOutlined, EditOutlined } from '@ant-design/icons'
10
+
11
+ const e = window.translate
12
+
13
+ export default auto(function WorkspaceSaveModal ({ store }) {
14
+ const { workspaceSaveModalVisible, workspaces } = store
15
+ const [name, setName] = useState('')
16
+ const [selectedId, setSelectedId] = useState(null)
17
+ const [saveMode, setSaveMode] = useState('new') // 'new' or 'overwrite'
18
+
19
+ if (!workspaceSaveModalVisible) {
20
+ return null
21
+ }
22
+
23
+ function handleClose () {
24
+ window.store.workspaceSaveModalVisible = false
25
+ }
26
+
27
+ function handleSave () {
28
+ if (saveMode === 'new') {
29
+ if (!name.trim()) {
30
+ message.error(e('name needed'))
31
+ return
32
+ }
33
+ window.store.saveWorkspace(name.trim())
34
+ message.success(e('saved'))
35
+ } else {
36
+ if (!selectedId) {
37
+ message.error('please Select Workspace')
38
+ return
39
+ }
40
+ const ws = workspaces.find(w => w.id === selectedId)
41
+ window.store.saveWorkspace(ws?.name || name, selectedId)
42
+ message.success(e('saved'))
43
+ }
44
+ setName('')
45
+ setSelectedId(null)
46
+ setSaveMode('new')
47
+ handleClose()
48
+ }
49
+
50
+ function handleCancel () {
51
+ setName('')
52
+ setSelectedId(null)
53
+ setSaveMode('new')
54
+ handleClose()
55
+ }
56
+
57
+ const options = workspaces.map(w => ({
58
+ label: w.name,
59
+ value: w.id
60
+ }))
61
+
62
+ return (
63
+ <Modal
64
+ title={e('save')}
65
+ open={workspaceSaveModalVisible}
66
+ onCancel={handleCancel}
67
+ footer={null}
68
+ width={400}
69
+ >
70
+ <div className='pd1y'>
71
+ <Space direction='vertical' block>
72
+ <Radio.Group
73
+ value={saveMode}
74
+ onChange={ev => setSaveMode(ev.target.value)}
75
+ >
76
+ <Radio value='new'>
77
+ <SaveOutlined className='mg1r' />
78
+ {e('saveAsNew')}
79
+ </Radio>
80
+ <Radio value='overwrite' disabled={!workspaces.length}>
81
+ <EditOutlined className='mg1r' />
82
+ {e('overwrite')}
83
+ </Radio>
84
+ </Radio.Group>
85
+
86
+ {saveMode === 'new'
87
+ ? (
88
+ <Input
89
+ placeholder={e('name')}
90
+ value={name}
91
+ onChange={e => setName(e.target.value)}
92
+ onPressEnter={handleSave}
93
+ />
94
+ )
95
+ : (
96
+ <Select
97
+ placeholder={e('workspaces')}
98
+ value={selectedId}
99
+ onChange={setSelectedId}
100
+ options={options}
101
+ style={{ width: '100%' }}
102
+ />
103
+ )}
104
+
105
+ <div className='pd1t'>
106
+ <Button type='primary' onClick={handleSave}>
107
+ {e('save')}
108
+ </Button>
109
+ <Button className='mg1l' onClick={handleCancel}>
110
+ {e('cancel')}
111
+ </Button>
112
+ </div>
113
+ </Space>
114
+ </div>
115
+ </Modal>
116
+ )
117
+ })
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Workspace select content component
3
+ */
4
+
5
+ import React from 'react'
6
+ import { Button, Empty, Popconfirm } from 'antd'
7
+ import {
8
+ SaveOutlined,
9
+ DeleteOutlined
10
+ } from '@ant-design/icons'
11
+ import { auto } from 'manate/react'
12
+
13
+ const e = window.translate
14
+
15
+ export default auto(function WorkspaceSelect (props) {
16
+ const { store } = props
17
+ const { workspaces } = store
18
+
19
+ function handleLoadWorkspace (id) {
20
+ window.store.loadWorkspace(id)
21
+ }
22
+
23
+ function handleDeleteWorkspace (id, ev) {
24
+ ev.stopPropagation()
25
+ window.store.deleteWorkspace(id)
26
+ }
27
+
28
+ function handleSaveClick () {
29
+ window.store.workspaceSaveModalVisible = true
30
+ }
31
+
32
+ return (
33
+ <div className='workspace-menu-content'>
34
+ <div className='workspace-save-btn pd1b'>
35
+ <Button
36
+ type='primary'
37
+ icon={<SaveOutlined />}
38
+ size='small'
39
+ onClick={handleSaveClick}
40
+ block
41
+ >
42
+ {e('save')}
43
+ </Button>
44
+ </div>
45
+ {workspaces.length === 0
46
+ ? (
47
+ <Empty
48
+ image={Empty.PRESENTED_IMAGE_SIMPLE}
49
+ description='No items'
50
+ />
51
+ )
52
+ : (
53
+ <div className='workspace-list'>
54
+ {workspaces.map(ws => (
55
+ <div
56
+ key={ws.id}
57
+ className='workspace-item'
58
+ onClick={() => handleLoadWorkspace(ws.id)}
59
+ >
60
+ <span className='workspace-name'>{ws.name}</span>
61
+ <Popconfirm
62
+ title={e('del') + '?'}
63
+ onConfirm={(ev) => handleDeleteWorkspace(ws.id, ev)}
64
+ onCancel={(ev) => ev.stopPropagation()}
65
+ okText={e('ok')}
66
+ cancelText={e('cancel')}
67
+ >
68
+ <DeleteOutlined
69
+ className='workspace-delete-icon'
70
+ onClick={(ev) => ev.stopPropagation()}
71
+ />
72
+ </Popconfirm>
73
+ </div>
74
+ ))}
75
+ </div>
76
+ )}
77
+ </div>
78
+ )
79
+ })
@@ -34,7 +34,13 @@ export default class AttachAddonCustom extends AttachAddon {
34
34
  }
35
35
 
36
36
  onMsg = (ev) => {
37
- this.trzsz.processServerOutput(ev.data)
37
+ // When in alternate screen mode (like vim, less, or TUI apps like Claude Code),
38
+ // bypass trzsz processing to avoid interference with the application's display
39
+ if (this.term?.buffer?.active?.type === 'alternate') {
40
+ this.writeToTerminal(ev.data)
41
+ } else {
42
+ this.trzsz.processServerOutput(ev.data)
43
+ }
38
44
  }
39
45
 
40
46
  writeToTerminal = (data) => {
@@ -3,7 +3,8 @@
3
3
  */
4
4
 
5
5
  import { useEffect, useState } from 'react'
6
- import { Modal, Form, Button } from 'antd'
6
+ import { Form, Button } from 'antd'
7
+ import Modal from '../common/modal'
7
8
  import InputAutoFocus from '../common/input-auto-focus'
8
9
  import wait from '../../common/wait'
9
10
 
@@ -178,7 +178,6 @@ class Term extends Component {
178
178
  clearTimeout(this.timers[k])
179
179
  this.timers[k] = null
180
180
  })
181
- this.timers = null
182
181
  this.onClose = true
183
182
  if (this.socket) {
184
183
  this.socket.close()
@@ -4,7 +4,8 @@
4
4
 
5
5
  import { PureComponent } from 'react'
6
6
  import TextEditorForm from './text-editor-form'
7
- import { Spin, Modal } from 'antd'
7
+ import { Spin } from 'antd'
8
+ import Modal from '../common/modal'
8
9
  import resolve from '../../common/resolve'
9
10
  import { refsStatic, refs } from '../common/ref'
10
11