@electerm/electerm-react 1.51.3 → 1.51.18

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 (86) hide show
  1. package/client/common/constants.js +15 -1
  2. package/client/common/db.js +10 -9
  3. package/client/common/default-setting.js +0 -1
  4. package/client/common/is-color-dark.js +15 -11
  5. package/client/common/new-terminal.js +2 -5
  6. package/client/common/reverse-color.js +12 -0
  7. package/client/common/ws.js +4 -1
  8. package/client/components/batch-op/batch-op.jsx +16 -5
  9. package/client/components/bookmark-form/index.jsx +1 -1
  10. package/client/components/bookmark-form/render-connection-hopping.jsx +25 -2
  11. package/client/components/bookmark-form/ssh-form.jsx +4 -25
  12. package/client/components/bookmark-form/tree-delete.jsx +5 -10
  13. package/client/components/bookmark-form/use-submit.jsx +6 -15
  14. package/client/components/bookmark-form/use-ui.jsx +1 -2
  15. package/client/components/common/connection-hopping-warning-text.jsx +36 -0
  16. package/client/components/common/drag-handle.jsx +60 -0
  17. package/client/components/common/drag-handle.styl +12 -0
  18. package/client/components/context-menu/context-menu.styl +5 -5
  19. package/client/components/context-menu/history.jsx +2 -11
  20. package/client/components/context-menu/sub-tab-menu.jsx +1 -1
  21. package/client/components/footer/footer-entry.jsx +1 -6
  22. package/client/components/layout/layout-item.jsx +2 -2
  23. package/client/components/layout/layout.jsx +3 -2
  24. package/client/components/main/connection-hopping-warnning.jsx +45 -0
  25. package/client/components/main/error-wrapper.jsx +120 -5
  26. package/client/components/main/main.jsx +32 -8
  27. package/client/components/main/upgrade.jsx +4 -9
  28. package/client/components/main/wrapper.styl +2 -1
  29. package/client/components/profile/profile-form-ssh.jsx +1 -1
  30. package/client/components/rdp/resolution-edit.jsx +3 -5
  31. package/client/components/session/session.jsx +22 -3
  32. package/client/components/session/session.styl +3 -2
  33. package/client/components/setting-panel/list.styl +0 -1
  34. package/client/components/setting-panel/on-tree-drop.js +5 -5
  35. package/client/components/setting-panel/setting-common.jsx +28 -7
  36. package/client/components/setting-panel/setting-modal.jsx +0 -12
  37. package/client/components/setting-panel/setting-terminal.jsx +7 -4
  38. package/client/components/sftp/confirm-modal-store.jsx +3 -11
  39. package/client/components/sftp/file-mode-modal.jsx +2 -2
  40. package/client/components/sftp/sftp-entry.jsx +4 -7
  41. package/client/components/sftp/transfer-conflict-store.jsx +70 -69
  42. package/client/components/sftp/transport-action-store.jsx +42 -49
  43. package/client/components/sftp/transports-action-store.jsx +15 -15
  44. package/client/components/sftp/transports-ui-store.jsx +9 -5
  45. package/client/components/side-panel-r/side-panel-r.jsx +13 -40
  46. package/client/components/sidebar/bookmark-select.jsx +1 -4
  47. package/client/components/sidebar/bookmark.jsx +4 -63
  48. package/client/components/sidebar/history-item.jsx +34 -0
  49. package/client/components/sidebar/history.jsx +17 -52
  50. package/client/components/sidebar/index.jsx +5 -40
  51. package/client/components/sidebar/side-panel.jsx +27 -51
  52. package/client/components/sidebar/sidebar-panel.jsx +107 -0
  53. package/client/components/sidebar/sidebar.styl +14 -9
  54. package/client/components/sidebar/transfer-list-control.jsx +1 -0
  55. package/client/components/sidebar/transfer.styl +1 -1
  56. package/client/components/sidebar/transport-ui.jsx +179 -37
  57. package/client/components/ssh-config/load-ssh-configs.jsx +106 -0
  58. package/client/components/ssh-config/ssh-config-item.jsx +26 -0
  59. package/client/components/ssh-config/ssh-config-load-notify.jsx +60 -0
  60. package/client/components/tabs/index.jsx +4 -4
  61. package/client/components/tabs/tab.jsx +28 -20
  62. package/client/components/tabs/tabs.styl +6 -1
  63. package/client/components/terminal/index.jsx +4 -18
  64. package/client/components/tree-list/bookmark-toolbar.jsx +203 -0
  65. package/client/components/tree-list/bookmark-transport.jsx +2 -0
  66. package/client/components/tree-list/tree-list.jsx +33 -42
  67. package/client/entry/worker.js +5 -3
  68. package/client/store/bookmark-group.js +5 -18
  69. package/client/store/bookmark.js +43 -1
  70. package/client/store/common.js +13 -9
  71. package/client/store/db-upgrade.js +0 -2
  72. package/client/store/index.js +45 -53
  73. package/client/store/init-state.js +20 -23
  74. package/client/store/item.js +0 -19
  75. package/client/store/load-data.js +7 -10
  76. package/client/store/setting.js +10 -66
  77. package/client/store/sidebar.js +7 -8
  78. package/client/store/sync.js +7 -8
  79. package/client/store/tab.js +93 -14
  80. package/client/store/terminal-theme.js +1 -1
  81. package/client/store/transfer-history.js +3 -9
  82. package/client/store/transfer-list.js +67 -75
  83. package/client/store/ui-theme.js +0 -9
  84. package/client/store/watch.js +17 -9
  85. package/package.json +1 -1
  86. package/client/components/setting-panel/tab-history.jsx +0 -43
@@ -1,18 +1,23 @@
1
1
  /**
2
2
  * transporter UI component
3
3
  */
4
- import React from 'react'
4
+ import { useRef } from 'react'
5
5
  import Tag from '../sftp/transfer-tag'
6
+ import { Flex } from 'antd'
6
7
  import {
7
8
  CloseCircleOutlined,
8
9
  PlayCircleOutlined,
9
- PauseCircleOutlined
10
+ PauseCircleOutlined,
11
+ VerticalAlignTopOutlined
10
12
  } from '@ant-design/icons'
13
+ import { action } from 'manate'
14
+ import { addClass, removeClass } from '../../common/class'
11
15
  import './transfer.styl'
12
16
 
13
17
  const e = window.translate
14
18
 
15
19
  export default function Transporter (props) {
20
+ const dom = useRef()
16
21
  const {
17
22
  fromPath,
18
23
  toPath,
@@ -29,12 +34,109 @@ export default function Transporter (props) {
29
34
  inited,
30
35
  id
31
36
  } = props.transfer
37
+ const { index } = props
38
+ const onDragCls = 'ondrag-tr'
39
+ const onDragOverCls = 'dragover-tr'
40
+ function moveToTop () {
41
+ action(function () {
42
+ const arr = window.store.fileTransfers
43
+ if (index > 0) {
44
+ const [item] = arr.splice(index, 1)
45
+ arr.unshift(item)
46
+ }
47
+ })()
48
+ }
32
49
  function cancel () {
33
50
  window.store.cancelTransfer(id)
34
51
  }
35
52
  function handlePauseOrResume () {
36
53
  window.store.toggleTransfer(id)
37
54
  }
55
+
56
+ function clearCls () {
57
+ document.querySelectorAll('.' + onDragOverCls).forEach((d) => {
58
+ removeClass(d, onDragOverCls)
59
+ })
60
+ }
61
+
62
+ function onDrag () {
63
+ addClass(dom.current, onDragCls)
64
+ }
65
+
66
+ function onDragEnter () {
67
+ clearCls()
68
+ addClass(dom.current, onDragOverCls)
69
+ }
70
+
71
+ function onDragExit () {
72
+ // debug('ondragexit')
73
+ // let {target} = e
74
+ // removeClass(target, 'sftp-dragover')
75
+ }
76
+
77
+ function onDragLeave (e) {
78
+ // debug('ondragleave')
79
+ const { target } = e
80
+ removeClass(target, onDragOverCls)
81
+ }
82
+
83
+ function onDragOver (e) {
84
+ // debug('ondragover')
85
+ // debug(e.target)
86
+ // removeClass(dom.current, 'sftp-dragover')
87
+ e.preventDefault()
88
+ }
89
+
90
+ function onDragStart (e) {
91
+ // debug('ondragstart')
92
+ // debug(e.target)
93
+ e.dataTransfer.setData('id', JSON.stringify(dom.current.getAttribute('data-id')))
94
+ // e.effectAllowed = 'copyMove'
95
+ }
96
+
97
+ function onDrop (e) {
98
+ e.preventDefault()
99
+ const { target } = e
100
+ if (!target) {
101
+ return
102
+ }
103
+ let onDropTab = target
104
+ while (onDropTab) {
105
+ if (onDropTab.classList && onDropTab.classList.contains('sftp-transport')) {
106
+ break
107
+ }
108
+ onDropTab = onDropTab.parentElement
109
+ }
110
+ const fromId = JSON.parse(e.dataTransfer.getData('id'))
111
+ if (!onDropTab || !fromId) {
112
+ return
113
+ }
114
+
115
+ const dropId = onDropTab.getAttribute('data-id')
116
+ if (!dropId || dropId === fromId) {
117
+ return
118
+ }
119
+
120
+ const arr = window.store.fileTransfers
121
+ const indexFrom = arr.findIndex(t => t.id === fromId)
122
+ let indexDrop = arr.findIndex(t => t.id === dropId)
123
+ if (indexFrom >= 0 && indexDrop >= 0) {
124
+ // Reorder tabs and update batch
125
+ action(function () {
126
+ const [tr] = arr.splice(indexFrom, 1)
127
+ if (indexFrom < indexDrop) {
128
+ indexDrop = indexDrop - 1
129
+ }
130
+ arr.splice(indexDrop, 0, tr)
131
+ })()
132
+ }
133
+ }
134
+
135
+ function onDragEnd (e) {
136
+ removeClass(dom.current, onDragCls)
137
+ clearCls()
138
+ e && e.dataTransfer && e.dataTransfer.clearData()
139
+ }
38
140
  const isTransfer = typeTo !== typeFrom
39
141
  const Icon = !pausing ? PauseCircleOutlined : PlayCircleOutlined
40
142
  const pauseTitle = pausing ? e('resume') : e('pause')
@@ -49,6 +151,14 @@ export default function Transporter (props) {
49
151
  title={e('cancel')}
50
152
  />
51
153
  )
154
+ const toTopIcon = index === 0
155
+ ? null
156
+ : (
157
+ <VerticalAlignTopOutlined
158
+ className='transfer-control-icon pointer hover-black font14'
159
+ onClick={moveToTop}
160
+ />
161
+ )
52
162
  const controlIcon = isTransfer
53
163
  ? (
54
164
  <Icon
@@ -58,41 +168,73 @@ export default function Transporter (props) {
58
168
  />
59
169
  )
60
170
  : null
171
+ const flexProps = {
172
+ className: cls,
173
+ gap: 3,
174
+ title,
175
+ ref: dom,
176
+ id: `transfer-unit-${id}`,
177
+ draggable: true,
178
+ 'data-id': id,
179
+ onDrag,
180
+ onDragEnter,
181
+ onDragExit,
182
+ onDragLeave,
183
+ onDragOver,
184
+ onDragStart,
185
+ onDrop,
186
+ onDragEnd
187
+ }
61
188
  return (
62
- <div className={cls} title={title} id={`transfer-unit-${id}`}>
63
- <Tag
64
- transfer={{
65
- typeTo,
66
- typeFrom,
67
- error,
68
- inited
69
- }}
70
- />
71
- <span
72
- className='flex-child sftp-file sftp-local-file elli'
73
- title={fromPath}
74
- >{fromPathReal || fromPath}
75
- </span>
76
- <span className='flex-child sftp-transfer-arrow'>
77
-
78
- </span>
79
- <span
80
- className='flex-child sftp-file sftp-remote-file elli'
81
- >{toPathReal || toPath}
82
- </span>
83
- <span
84
- className='flex-child sftp-file-percent'
85
- >
86
- {percent || 0}%
87
- {speed ? `(${speed})` : null}
88
- </span>
89
- <span
90
- className='flex-child sftp-file-percent'
91
- >
92
- {passedTime || '-'}|{leftTime || '-'}
93
- </span>
94
- {controlIcon}
95
- {cancelIcon}
96
- </div>
189
+ <Flex
190
+ {...flexProps}
191
+ >
192
+ <Flex>
193
+ <Tag
194
+ transfer={{
195
+ typeTo,
196
+ typeFrom,
197
+ error,
198
+ inited
199
+ }}
200
+ />
201
+ </Flex>
202
+ <Flex>
203
+ <span
204
+ className='sftp-file sftp-local-file elli'
205
+ title={fromPath}
206
+ >{fromPathReal || fromPath}
207
+ </span>
208
+ </Flex>
209
+ <Flex>
210
+ <span className='sftp-transfer-arrow'>
211
+
212
+ </span>
213
+ </Flex>
214
+ <Flex>
215
+ <span
216
+ className='sftp-file sftp-remote-file elli'
217
+ >{toPathReal || toPath}
218
+ </span>
219
+ </Flex>
220
+ <Flex>
221
+ <span
222
+ className='sftp-file-percent'
223
+ >
224
+ {percent || 0}%
225
+ {speed ? `(${speed})` : null}
226
+ </span>
227
+ </Flex>
228
+ <Flex>
229
+ <span
230
+ className='sftp-file-percent'
231
+ >
232
+ {passedTime || '-'}|{leftTime || '-'}
233
+ </span>
234
+ </Flex>
235
+ <Flex>{controlIcon}</Flex>
236
+ <Flex>{cancelIcon}</Flex>
237
+ <Flex>{toTopIcon}</Flex>
238
+ </Flex>
97
239
  )
98
240
  }
@@ -0,0 +1,106 @@
1
+ import {
2
+ Modal,
3
+ Spin,
4
+ Button,
5
+ Empty
6
+ } from 'antd'
7
+ import { useState, useEffect } from 'react'
8
+ import SshConfigItem from './ssh-config-item'
9
+ import * as ls from '../../common/safe-local-storage'
10
+ import {
11
+ sshConfigLoadKey
12
+ } from '../../common/constants'
13
+ import { ReloadOutlined } from '@ant-design/icons'
14
+
15
+ const e = window.translate
16
+
17
+ export default function LoadSshConfigs (props) {
18
+ const [loading, setLoading] = useState(false)
19
+ const { sshConfigs } = props
20
+
21
+ const {
22
+ store
23
+ } = window
24
+ const {
25
+ showSshConfigModal
26
+ } = props
27
+ const handleCancel = function () {
28
+ store.showSshConfigModal = false
29
+ }
30
+ const loadSshConfig = async function () {
31
+ setLoading(true)
32
+ await store.fetchSshConfigItems()
33
+ setLoading(false)
34
+ }
35
+
36
+ const handleLoadSshConfig = function () {
37
+ store.showSshConfigModal = false
38
+ store.addSshConfigs(sshConfigs)
39
+ ls.setItem(sshConfigLoadKey, 'yes')
40
+ }
41
+
42
+ const renderList = function () {
43
+ if (!sshConfigs.length) {
44
+ return (
45
+ <Empty />
46
+ )
47
+ }
48
+ return sshConfigs.map((d, i) => {
49
+ return (
50
+ <SshConfigItem item={d} key={d.title} />
51
+ )
52
+ })
53
+ }
54
+
55
+ useEffect(() => {
56
+ if (sshConfigs.length && ls.getItem(sshConfigLoadKey) !== 'yes') {
57
+ loadSshConfig()
58
+ }
59
+ }, [sshConfigs.length])
60
+ if (!showSshConfigModal) {
61
+ return null
62
+ }
63
+ const modProps = {
64
+ title: e('loadSshConfigs'),
65
+ footer: null,
66
+ open: true,
67
+ onCancel: handleCancel,
68
+ width: '80%'
69
+ }
70
+ return (
71
+ <Modal {...modProps}>
72
+ <Spin spinning={loading}>
73
+ <div className='pd1y'>
74
+ <Button
75
+ onClick={loadSshConfig}
76
+ disabled={loading}
77
+ className='mg1b'
78
+ >
79
+ <ReloadOutlined /> {e('reload')}
80
+ </Button>
81
+ </div>
82
+ <div className='ssh-config-list'>
83
+ {
84
+ renderList()
85
+ }
86
+ </div>
87
+ <div className='pd1y'>
88
+ <Button
89
+ type='primary'
90
+ className='mg1r mg1b'
91
+ onClick={handleLoadSshConfig}
92
+ disabled={!sshConfigs.length || loading}
93
+ >
94
+ {e('import')}
95
+ </Button>
96
+ <Button
97
+ onClick={handleCancel}
98
+ className='mg1r mg1b'
99
+ >
100
+ {e('cancel')}
101
+ </Button>
102
+ </div>
103
+ </Spin>
104
+ </Modal>
105
+ )
106
+ }
@@ -0,0 +1,26 @@
1
+ import { Tooltip } from 'antd'
2
+
3
+ export default function SshConfigItem (props) {
4
+ const { item } = props
5
+
6
+ const generateTooltipContent = (item) => {
7
+ return Object.entries(item)
8
+ .filter(([key]) => key !== 'id')
9
+ .map(([key, value]) => (
10
+ <div key={key}>
11
+ <b className='mg1r'>{key}:</b>
12
+ <span>{value}</span>
13
+ </div>
14
+ ))
15
+ }
16
+
17
+ return (
18
+ <Tooltip title={generateTooltipContent(item)}>
19
+ <div>
20
+ <div className='elli pd1y pd2x'>
21
+ ssh {item.title}
22
+ </div>
23
+ </div>
24
+ </Tooltip>
25
+ )
26
+ }
@@ -0,0 +1,60 @@
1
+ import React, { useEffect } from 'react'
2
+ import { notification, Button } from 'antd'
3
+ import * as ls from '../../common/safe-local-storage'
4
+ import {
5
+ sshConfigKey,
6
+ sshConfigLoadKey
7
+ } from '../../common/constants'
8
+
9
+ const e = window.translate
10
+
11
+ function handleLoad () {
12
+ window.store.showSshConfigModal = true
13
+ notification.destroy('sshConfigNotify')
14
+ }
15
+
16
+ function handleIgnore () {
17
+ ls.setItem(sshConfigKey, 'yes')
18
+ notification.destroy('sshConfigNotify')
19
+ }
20
+
21
+ function showNotification () {
22
+ notification.info({
23
+ message: e('loadSshConfigs'),
24
+ duration: 0,
25
+ placement: 'bottom',
26
+ key: 'sshConfigNotify',
27
+ description: (
28
+ <div>
29
+ <p>{e('sshConfigNotice')}</p>
30
+ <Button type='primary' onClick={handleLoad} className='mg1r mg1b'>
31
+ {e('import')}
32
+ </Button>
33
+ <Button onClick={handleIgnore} className='mg1r mg1b'>
34
+ {e('ignore')}
35
+ </Button>
36
+ </div>
37
+ )
38
+ })
39
+ }
40
+
41
+ export default function SshConfigLoadNotify (props) {
42
+ const { settingTab, showModal, sshConfigs } = props
43
+
44
+ useEffect(() => {
45
+ const ignoreSshConfig = ls.getItem(sshConfigKey)
46
+ const sshConfigLoaded = ls.getItem(sshConfigLoadKey)
47
+ const shouldShow =
48
+ sshConfigs.length &&
49
+ ignoreSshConfig !== 'yes' &&
50
+ settingTab === 'bookmarks' &&
51
+ showModal &&
52
+ sshConfigLoaded !== 'yes'
53
+
54
+ if (shouldShow) {
55
+ showNotification()
56
+ }
57
+ }, [settingTab, showModal, sshConfigs.length])
58
+
59
+ return null
60
+ }
@@ -4,7 +4,7 @@
4
4
 
5
5
  import React from 'react'
6
6
  import runIdle from '../../common/run-idle'
7
- import { findIndex, debounce } from 'lodash-es'
7
+ import { debounce } from 'lodash-es'
8
8
  import TabTitle from './tab-title'
9
9
  import {
10
10
  CodeFilled,
@@ -227,13 +227,13 @@ export default class Tabs extends React.Component {
227
227
 
228
228
  adjustScroll = () => {
229
229
  const { tabs, currentBatchTabId, batch } = this.props
230
- const index = findIndex(tabs, t => t.id === currentBatchTabId)
230
+ const index = tabs.findIndex(t => t.id === currentBatchTabId)
231
231
  const tabsDomWith = Array.from(
232
232
  document.querySelectorAll(`.v${batch + 1} .tab`)
233
- ).slice(0, index + 2).reduce((prev, c) => {
233
+ ).slice(0, index + 1).reduce((prev, c) => {
234
234
  return prev + c.clientWidth
235
235
  }, 0)
236
- const w = (index + 1) * tabMargin + 5 + tabsDomWith
236
+ const w = (index + 1) * tabMargin + tabsDomWith
237
237
  const tabsInnerWidth = this.getInnerWidth()
238
238
  const scrollLeft = w > tabsInnerWidth
239
239
  ? w - tabsInnerWidth
@@ -10,13 +10,12 @@ import {
10
10
  } from '@ant-design/icons'
11
11
  import { Tooltip, message } from 'antd'
12
12
  import classnames from 'classnames'
13
- import { findIndex, pick } from 'lodash-es'
13
+ import { pick } from 'lodash-es'
14
14
  import Input from '../common/input-auto-focus'
15
15
  import createName from '../../common/create-title'
16
16
  import { addClass, removeClass } from '../../common/class'
17
- import {
18
- terminalSshConfigType
19
- } from '../../common/constants'
17
+ import isDark from '../../common/is-color-dark'
18
+ import { action } from 'manate'
20
19
  import { shortcutDescExtend } from '../shortcuts/shortcut-handler.js'
21
20
 
22
21
  const e = window.translate
@@ -117,7 +116,13 @@ class Tab extends Component {
117
116
  }
118
117
 
119
118
  const fromTab = JSON.parse(e.dataTransfer.getData('fromFile'))
120
- const onDropTab = document.querySelector('.' + onDragOverCls)
119
+ let onDropTab = target
120
+ while (onDropTab) {
121
+ if (onDropTab.classList && onDropTab.classList.contains('tab')) {
122
+ break
123
+ }
124
+ onDropTab = onDropTab.parentElement
125
+ }
121
126
  if (!onDropTab || !fromTab) {
122
127
  return
123
128
  }
@@ -129,8 +134,8 @@ class Tab extends Component {
129
134
 
130
135
  const { id } = fromTab
131
136
  const storeTabs = window.store.tabs
132
- const indexFrom = findIndex(storeTabs, t => t.id === id)
133
- let indexDrop = findIndex(storeTabs, t => t.id === dropId)
137
+ const indexFrom = storeTabs.findIndex(t => t.id === id)
138
+ let indexDrop = storeTabs.findIndex(t => t.id === dropId)
134
139
 
135
140
  if (indexFrom >= 0 && indexDrop >= 0) {
136
141
  const targetTab = storeTabs[indexDrop]
@@ -146,12 +151,14 @@ class Tab extends Component {
146
151
  }
147
152
 
148
153
  // Reorder tabs and update batch
149
- const [tab] = storeTabs.splice(indexFrom, 1)
150
- tab.batch = targetTab.batch // Update the batch to match target tab's batch
151
- if (indexFrom < indexDrop) {
152
- indexDrop = indexDrop - 1
153
- }
154
- storeTabs.splice(indexDrop, 0, tab)
154
+ action(function () {
155
+ const [tab] = storeTabs.splice(indexFrom, 1)
156
+ tab.batch = targetTab.batch // Update the batch to match target tab's batch
157
+ if (indexFrom < indexDrop) {
158
+ indexDrop = indexDrop - 1
159
+ }
160
+ storeTabs.splice(indexDrop, 0, tab)
161
+ })()
155
162
  window.store.focus()
156
163
  }
157
164
  }
@@ -218,11 +225,10 @@ class Tab extends Component {
218
225
  }
219
226
 
220
227
  renderContext = () => {
221
- const { tabs, tab, tabIndex } = this.props
228
+ const { tabs, tabIndex } = this.props
222
229
  const len = tabs.length
223
230
  const index = tabIndex
224
231
  const noRight = index >= len - 1
225
- const isSshConfig = tab.type === terminalSshConfigType
226
232
  const res = []
227
233
  const reloadShortcut = this.getShortcut('app_reloadCurrentTab')
228
234
  const closeShortcut = this.getShortcut('app_closeCurrentTab')
@@ -262,7 +268,6 @@ class Tab extends Component {
262
268
  subText: cloneToNextShortcut
263
269
  })
264
270
  res.push({
265
- disabled: isSshConfig,
266
271
  func: 'doRename',
267
272
  icon: 'EditOutlined',
268
273
  text: e('rename')
@@ -380,9 +385,12 @@ class Tab extends Component {
380
385
  if (isEditting) {
381
386
  return this.renderEditting(tab, cls)
382
387
  }
383
- const { tabCount, color } = tab
388
+ const { tabCount, color = '#0088cc' } = tab
384
389
  const styleTag = color
385
- ? { borderTop: `1px solid ${color}` }
390
+ ? {
391
+ background: color,
392
+ color: isDark(color) ? '#fff' : '#000'
393
+ }
386
394
  : {}
387
395
  return (
388
396
  <Tooltip
@@ -409,7 +417,6 @@ class Tab extends Component {
409
417
  className='tab-title elli pd1x'
410
418
  onClick={this.handleClick}
411
419
  onDoubleClick={this.handleDup}
412
- style={styleTag}
413
420
  >
414
421
  <Loading3QuartersOutlined
415
422
  className='pointer tab-reload mg1r'
@@ -417,7 +424,8 @@ class Tab extends Component {
417
424
  title={e('reload')}
418
425
  />
419
426
  <span className='tab-title'>
420
- {tabCount}. {title}
427
+ <span className='iblock mg1r tab-count' style={styleTag}>{tabCount}</span>
428
+ <span className='mg1r'>{title}</span>
421
429
  </span>
422
430
  </div>
423
431
  <div className={'tab-status ' + status} />
@@ -223,4 +223,9 @@
223
223
  left 0
224
224
  right 0
225
225
  bottom 0
226
- z-index 11
226
+ z-index 11
227
+ .tab-count
228
+ border-radius 10px 2px 2px 2px
229
+ padding 0 4px
230
+ height 20px
231
+ line-height 21px
@@ -20,7 +20,6 @@ import {
20
20
  paneMap,
21
21
  typeMap,
22
22
  isWin,
23
- terminalSshConfigType,
24
23
  transferTypeMap,
25
24
  terminalActions,
26
25
  commonActions,
@@ -818,8 +817,7 @@ clear\r`
818
817
  }
819
818
 
820
819
  isRemote = () => {
821
- return this.props.tab?.host &&
822
- this.props.tab?.type !== terminalSshConfigType
820
+ return this.props.tab?.host
823
821
  }
824
822
 
825
823
  onPaste = async () => {
@@ -1055,15 +1053,9 @@ clear\r`
1055
1053
  runInitScript = () => {
1056
1054
  window.store.triggerResize()
1057
1055
  const {
1058
- type,
1059
- title,
1060
1056
  startDirectory,
1061
1057
  runScripts
1062
1058
  } = this.props.tab
1063
- if (type === terminalSshConfigType) {
1064
- const cmd = `ssh ${title.split(/\s/g)[0]}\r`
1065
- return this.attachAddon._sendData(cmd)
1066
- }
1067
1059
  const startFolder = startDirectory || window.initFolder
1068
1060
  if (startFolder) {
1069
1061
  const cmd = `cd "${startFolder}"\r`
@@ -1141,10 +1133,7 @@ clear\r`
1141
1133
  id
1142
1134
  } = tab
1143
1135
  const { savePassword } = this.state
1144
- const isSshConfig = type === terminalSshConfigType
1145
- const termType = isSshConfig
1146
- ? typeMap.local
1147
- : type
1136
+ const termType = type
1148
1137
  const extra = this.props.sessionOptions
1149
1138
  const opts = clone({
1150
1139
  cols,
@@ -1174,7 +1163,7 @@ clear\r`
1174
1163
  termType,
1175
1164
  readyTimeout: config.sshReadyTimeout,
1176
1165
  proxy: getProxy(tab, config),
1177
- type: tab.host && !isSshConfig
1166
+ type: tab.host
1178
1167
  ? typeMap.remote
1179
1168
  : typeMap.local
1180
1169
  })
@@ -1326,10 +1315,7 @@ clear\r`
1326
1315
  isRemote: this.isRemote(),
1327
1316
  isActive: this.isActiveTerminal()
1328
1317
  }
1329
- window.store.setState(
1330
- 'terminalInfoProps',
1331
- infoProps
1332
- )
1318
+ Object.assign(window.store.terminalInfoProps, infoProps)
1333
1319
  }
1334
1320
 
1335
1321
  // getPwd = async () => {