@electerm/electerm-react 1.38.19 → 1.38.40
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/build-ssh-tunnel.js +2 -1
- package/client/common/choose-save-folder.js +22 -0
- package/client/common/constants.js +1 -1
- package/client/common/default-setting.js +9 -1
- package/client/common/download.jsx +31 -0
- package/client/common/trzsz.js +2 -18
- package/client/components/bookmark-form/render-ssh-tunnel.jsx +32 -14
- package/client/components/main/main.jsx +4 -0
- package/client/components/quick-commands/quick-commands-box.jsx +20 -5
- package/client/components/quick-commands/quick-commands-form-elem.jsx +14 -17
- package/client/components/quick-commands/quick-commands-list-form.jsx +89 -0
- package/client/components/session/session.jsx +5 -4
- package/client/components/setting-panel/list.styl +3 -0
- package/client/components/setting-panel/setting-terminal.jsx +1 -0
- package/client/components/setting-panel/tree-list.styl +4 -0
- package/client/components/sftp/file-item.jsx +27 -20
- package/client/components/sftp/sftp-entry.jsx +65 -45
- package/client/components/shortcuts/shortcuts-defaults.js +7 -7
- package/client/components/tabs/index.jsx +12 -1
- package/client/components/terminal/attach-addon-custom.js +2 -2
- package/client/components/terminal/index.jsx +18 -15
- package/client/components/terminal-info/activity.jsx +4 -4
- package/client/components/terminal-info/base.jsx +58 -2
- package/client/components/terminal-info/disk.jsx +4 -3
- package/client/components/terminal-info/network.jsx +4 -3
- package/client/components/terminal-info/resource.jsx +20 -10
- package/client/components/terminal-info/up.jsx +5 -3
- package/client/css/basic.styl +3 -0
- package/client/store/common.js +51 -0
- package/client/store/index.js +2 -2
- package/client/store/sync.js +15 -2
- package/client/store/system-menu.js +6 -16
- package/package.json +1 -1
- package/client/common/download.js +0 -16
|
@@ -2,6 +2,7 @@ export const buildSshTunnels = function (inst) {
|
|
|
2
2
|
return [{
|
|
3
3
|
sshTunnel: inst.sshTunnel,
|
|
4
4
|
sshTunnelRemotePort: inst.sshTunnelRemotePort,
|
|
5
|
-
sshTunnelLocalPort: inst.sshTunnelLocalPort
|
|
5
|
+
sshTunnelLocalPort: inst.sshTunnelLocalPort,
|
|
6
|
+
sshTunnelRemoteHost: inst.sshTunnelRemoteHost
|
|
6
7
|
}]
|
|
7
8
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const {
|
|
2
|
+
openDialog
|
|
3
|
+
} = window.api
|
|
4
|
+
|
|
5
|
+
export async function chooseSaveDirectory () {
|
|
6
|
+
const savePaths = await openDialog({
|
|
7
|
+
title: 'Choose a folder to save file(s)',
|
|
8
|
+
message: 'Choose a folder to save file(s)',
|
|
9
|
+
properties: [
|
|
10
|
+
'openDirectory',
|
|
11
|
+
'showHiddenFiles',
|
|
12
|
+
'createDirectory',
|
|
13
|
+
'noResolveAliases',
|
|
14
|
+
'treatPackageAsDirectory',
|
|
15
|
+
'dontAddToRecent'
|
|
16
|
+
]
|
|
17
|
+
})
|
|
18
|
+
if (!savePaths || !savePaths.length) {
|
|
19
|
+
return undefined
|
|
20
|
+
}
|
|
21
|
+
return savePaths[0]
|
|
22
|
+
}
|
|
@@ -20,7 +20,7 @@ const buildConst = (props) => {
|
|
|
20
20
|
export const logoPath1 = logoPath1Ref.replace(/^\//, '')
|
|
21
21
|
export const logoPath2 = logoPath2Ref.replace(/^\//, '')
|
|
22
22
|
export const logoPath3 = logoPath3Ref.replace(/^\//, '')
|
|
23
|
-
export const maxEditFileSize = 1024 *
|
|
23
|
+
export const maxEditFileSize = 1024 * 3000
|
|
24
24
|
export const defaultBookmarkGroupId = 'default'
|
|
25
25
|
export const newBookmarkIdPrefix = 'new-bookmark'
|
|
26
26
|
export const unexpectedPacketErrorDesc = 'Unexpected packet'
|
|
@@ -43,5 +43,13 @@ export default {
|
|
|
43
43
|
addTimeStampToTermLog: false,
|
|
44
44
|
sftpPathFollowSsh: false,
|
|
45
45
|
keepaliveInterval: 0,
|
|
46
|
-
backspaceMode: '^?'
|
|
46
|
+
backspaceMode: '^?',
|
|
47
|
+
terminalInfos: [
|
|
48
|
+
'uptime',
|
|
49
|
+
'cpu',
|
|
50
|
+
'mem',
|
|
51
|
+
'activities',
|
|
52
|
+
'network',
|
|
53
|
+
'disks'
|
|
54
|
+
]
|
|
47
55
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* simulate download
|
|
3
|
+
*/
|
|
4
|
+
import { notification } from 'antd'
|
|
5
|
+
import ShowItem from '../components/common/show-item'
|
|
6
|
+
import { chooseSaveDirectory } from './choose-save-folder'
|
|
7
|
+
|
|
8
|
+
export default async function download (filename, text) {
|
|
9
|
+
const savePath = await chooseSaveDirectory()
|
|
10
|
+
if (!savePath) {
|
|
11
|
+
return
|
|
12
|
+
}
|
|
13
|
+
const path = window.require('path')
|
|
14
|
+
const filePath = path.join(savePath, filename)
|
|
15
|
+
const r = await window.fs.writeFile(filePath, text).catch(window.store.onError)
|
|
16
|
+
if (!r) {
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
notification.success({
|
|
20
|
+
message: '',
|
|
21
|
+
description: (
|
|
22
|
+
<div>
|
|
23
|
+
<ShowItem
|
|
24
|
+
to={filePath}
|
|
25
|
+
>
|
|
26
|
+
{filePath}
|
|
27
|
+
</ShowItem>
|
|
28
|
+
</div>
|
|
29
|
+
)
|
|
30
|
+
})
|
|
31
|
+
}
|
package/client/common/trzsz.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { TrzszFilter } from 'trzsz'
|
|
2
|
+
import { chooseSaveDirectory } from './choose-save-folder'
|
|
2
3
|
|
|
3
4
|
const {
|
|
4
5
|
openDialog
|
|
@@ -36,24 +37,7 @@ window.newTrzsz = function (
|
|
|
36
37
|
})
|
|
37
38
|
},
|
|
38
39
|
// choose a directory to save the received files
|
|
39
|
-
chooseSaveDirectory
|
|
40
|
-
const savePaths = await openDialog({
|
|
41
|
-
title: 'Choose a folder to save file(s)',
|
|
42
|
-
message: 'Choose a folder to save file(s)',
|
|
43
|
-
properties: [
|
|
44
|
-
'openDirectory',
|
|
45
|
-
'showHiddenFiles',
|
|
46
|
-
'createDirectory',
|
|
47
|
-
'noResolveAliases',
|
|
48
|
-
'treatPackageAsDirectory',
|
|
49
|
-
'dontAddToRecent'
|
|
50
|
-
]
|
|
51
|
-
})
|
|
52
|
-
if (!savePaths || !savePaths.length) {
|
|
53
|
-
return undefined
|
|
54
|
-
}
|
|
55
|
-
return savePaths[0]
|
|
56
|
-
},
|
|
40
|
+
chooseSaveDirectory,
|
|
57
41
|
// the terminal columns
|
|
58
42
|
terminalColumns,
|
|
59
43
|
// there is a windows shell
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Form,
|
|
3
|
+
Input,
|
|
3
4
|
InputNumber,
|
|
4
5
|
Radio,
|
|
5
6
|
Space,
|
|
@@ -47,29 +48,46 @@ export default function renderSshTunnel () {
|
|
|
47
48
|
</RadioButton>
|
|
48
49
|
</RadioGroup>
|
|
49
50
|
</FormItem>
|
|
51
|
+
<Space.Compact className='mg2x'>
|
|
52
|
+
<FormItem
|
|
53
|
+
label={e('destination')}
|
|
54
|
+
name={[field.name, 'sshTunnelRemoteHost']}
|
|
55
|
+
initialValue='127.0.0.1'
|
|
56
|
+
required
|
|
57
|
+
>
|
|
58
|
+
<Input
|
|
59
|
+
className='compact-input'
|
|
60
|
+
placeholder={e('host')}
|
|
61
|
+
/>
|
|
62
|
+
</FormItem>
|
|
63
|
+
<FormItem
|
|
64
|
+
label=''
|
|
65
|
+
name={[field.name, 'sshTunnelRemotePort']}
|
|
66
|
+
initialValue={22}
|
|
67
|
+
required
|
|
68
|
+
>
|
|
69
|
+
<InputNumber
|
|
70
|
+
min={1}
|
|
71
|
+
max={65535}
|
|
72
|
+
// addonBefore={e('remotePort')}
|
|
73
|
+
className='compact-input'
|
|
74
|
+
placeholder={e('port')}
|
|
75
|
+
/>
|
|
76
|
+
</FormItem>
|
|
77
|
+
</Space.Compact>
|
|
50
78
|
<FormItem
|
|
51
|
-
label=''
|
|
52
|
-
name={[field.name, 'sshTunnelRemotePort']}
|
|
53
|
-
required
|
|
54
|
-
>
|
|
55
|
-
<InputNumber
|
|
56
|
-
min={1}
|
|
57
|
-
max={65535}
|
|
58
|
-
addonBefore={e('remotePort')}
|
|
59
|
-
className='compact-input'
|
|
60
|
-
/>
|
|
61
|
-
</FormItem>
|
|
62
|
-
<FormItem
|
|
63
|
-
label=''
|
|
79
|
+
label={e('localPort')}
|
|
64
80
|
name={[field.name, 'sshTunnelLocalPort']}
|
|
81
|
+
initialValue={22}
|
|
65
82
|
required
|
|
66
83
|
className='mg2x'
|
|
67
84
|
>
|
|
68
85
|
<InputNumber
|
|
69
86
|
min={1}
|
|
70
87
|
max={65535}
|
|
71
|
-
addonBefore={e('localPort')}
|
|
88
|
+
// addonBefore={e('localPort')}
|
|
72
89
|
className='compact-input'
|
|
90
|
+
placeholder={e('port')}
|
|
73
91
|
/>
|
|
74
92
|
</FormItem>
|
|
75
93
|
<Button
|
|
@@ -41,6 +41,7 @@ export default class Index extends Component {
|
|
|
41
41
|
ipcOnEvent('zoom-reset', store.onZoomReset)
|
|
42
42
|
ipcOnEvent('zoomin', store.onZoomIn)
|
|
43
43
|
ipcOnEvent('zoomout', store.onZoomout)
|
|
44
|
+
ipcOnEvent('confirm-exit', store.beforeExitApp)
|
|
44
45
|
|
|
45
46
|
document.addEventListener('drop', function (e) {
|
|
46
47
|
e.preventDefault()
|
|
@@ -51,6 +52,9 @@ export default class Index extends Component {
|
|
|
51
52
|
e.stopPropagation()
|
|
52
53
|
})
|
|
53
54
|
window.addEventListener('offline', store.setOffline)
|
|
55
|
+
if (window.et.isWebApp) {
|
|
56
|
+
window.onbeforeunload = store.beforeExit
|
|
57
|
+
}
|
|
54
58
|
store.isSencondInstance = window.pre.runSync('isSencondInstance')
|
|
55
59
|
store.initData()
|
|
56
60
|
store.checkForDbUpgrade()
|
|
@@ -8,7 +8,9 @@ import { find, sortBy } from 'lodash-es'
|
|
|
8
8
|
import { Button, Input, Select, Space } from 'antd'
|
|
9
9
|
import * as ls from '../../common/safe-local-storage'
|
|
10
10
|
import copy from 'json-deep-copy'
|
|
11
|
+
import generate from '../../common/uid'
|
|
11
12
|
import CmdItem from './quick-command-item'
|
|
13
|
+
import delay from '../../common/wait'
|
|
12
14
|
import {
|
|
13
15
|
EditOutlined,
|
|
14
16
|
CloseCircleOutlined,
|
|
@@ -46,7 +48,7 @@ export default class QuickCommandsFooterBox extends Component {
|
|
|
46
48
|
this.props.store.pinnedQuickCommandBar = !this.props.store.pinnedQuickCommandBar
|
|
47
49
|
}
|
|
48
50
|
|
|
49
|
-
handleSelect = (id) => {
|
|
51
|
+
handleSelect = async (id) => {
|
|
50
52
|
const {
|
|
51
53
|
store
|
|
52
54
|
} = this.props
|
|
@@ -57,11 +59,24 @@ export default class QuickCommandsFooterBox extends Component {
|
|
|
57
59
|
this.props.store.currentQuickCommands,
|
|
58
60
|
a => a.id === id
|
|
59
61
|
)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
const { runQuickCommand } = this.props.store
|
|
63
|
+
const qms = qm && qm.commands
|
|
64
|
+
? qm.commands
|
|
65
|
+
: (qm && qm.command
|
|
66
|
+
? [
|
|
67
|
+
{
|
|
68
|
+
command: qm.command,
|
|
69
|
+
id: generate(),
|
|
70
|
+
delay: 100
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
: []
|
|
74
|
+
)
|
|
75
|
+
for (const q of qms) {
|
|
62
76
|
const realCmd = isWin
|
|
63
|
-
?
|
|
64
|
-
:
|
|
77
|
+
? q.command.replace(/\n/g, '\n\r')
|
|
78
|
+
: q.command
|
|
79
|
+
await delay(q.delay || 100)
|
|
65
80
|
runQuickCommand(realCmd, qm.inputOnly)
|
|
66
81
|
store.editQuickCommand(qm.id, {
|
|
67
82
|
clickCount: ((qm.clickCount || 0) + 1)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Button,
|
|
1
|
+
import { Button, Switch, Form, message, Select } from 'antd'
|
|
2
2
|
import copy from 'json-deep-copy'
|
|
3
3
|
import generate from '../../common/uid'
|
|
4
4
|
import InputAutoFocus from '../common/input-auto-focus'
|
|
5
|
-
|
|
5
|
+
import renderQm from './quick-commands-list-form'
|
|
6
6
|
const FormItem = Form.Item
|
|
7
7
|
const { Option } = Select
|
|
8
8
|
const { prefix } = window
|
|
@@ -17,13 +17,13 @@ export default function QuickCommandForm (props) {
|
|
|
17
17
|
const { formData } = props
|
|
18
18
|
const {
|
|
19
19
|
name,
|
|
20
|
-
|
|
20
|
+
commands,
|
|
21
21
|
inputOnly,
|
|
22
22
|
labels
|
|
23
23
|
} = res
|
|
24
24
|
const update = copy({
|
|
25
25
|
name,
|
|
26
|
-
|
|
26
|
+
commands,
|
|
27
27
|
inputOnly,
|
|
28
28
|
labels
|
|
29
29
|
})
|
|
@@ -46,6 +46,13 @@ export default function QuickCommandForm (props) {
|
|
|
46
46
|
if (!initialValues.labels) {
|
|
47
47
|
initialValues.labels = []
|
|
48
48
|
}
|
|
49
|
+
if (!initialValues.commands) {
|
|
50
|
+
initialValues.commands = [{
|
|
51
|
+
command: initialValues.command || '',
|
|
52
|
+
id: generate(),
|
|
53
|
+
delay: 100
|
|
54
|
+
}]
|
|
55
|
+
}
|
|
49
56
|
return (
|
|
50
57
|
<Form
|
|
51
58
|
form={form}
|
|
@@ -59,7 +66,7 @@ export default function QuickCommandForm (props) {
|
|
|
59
66
|
rules={[{
|
|
60
67
|
max: 60, message: '60 chars max'
|
|
61
68
|
}, {
|
|
62
|
-
required: true, message: '
|
|
69
|
+
required: true, message: 'Name required'
|
|
63
70
|
}]}
|
|
64
71
|
hasFeedback
|
|
65
72
|
name='name'
|
|
@@ -69,17 +76,7 @@ export default function QuickCommandForm (props) {
|
|
|
69
76
|
autofocustrigger={autofocustrigger}
|
|
70
77
|
/>
|
|
71
78
|
</FormItem>
|
|
72
|
-
|
|
73
|
-
name='command'
|
|
74
|
-
label={t('quickCommand')}
|
|
75
|
-
rules={[{
|
|
76
|
-
max: 5000, message: '5000 chars max'
|
|
77
|
-
}, {
|
|
78
|
-
required: true, message: 'command required'
|
|
79
|
-
}]}
|
|
80
|
-
>
|
|
81
|
-
<TextArea rows={3} />
|
|
82
|
-
</FormItem>
|
|
79
|
+
{renderQm()}
|
|
83
80
|
<FormItem
|
|
84
81
|
name='labels'
|
|
85
82
|
label={t('label')}
|
|
@@ -108,7 +105,7 @@ export default function QuickCommandForm (props) {
|
|
|
108
105
|
<FormItem>
|
|
109
106
|
<p>
|
|
110
107
|
<Button
|
|
111
|
-
type='
|
|
108
|
+
type='primary'
|
|
112
109
|
htmlType='submit'
|
|
113
110
|
>{e('save')}
|
|
114
111
|
</Button>
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Form,
|
|
3
|
+
InputNumber,
|
|
4
|
+
Space,
|
|
5
|
+
Button,
|
|
6
|
+
Input
|
|
7
|
+
} from 'antd'
|
|
8
|
+
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons'
|
|
9
|
+
import { formItemLayout } from '../../common/form-layout'
|
|
10
|
+
|
|
11
|
+
const FormItem = Form.Item
|
|
12
|
+
const FormList = Form.List
|
|
13
|
+
const { prefix } = window
|
|
14
|
+
const t = prefix('quickCommands')
|
|
15
|
+
|
|
16
|
+
export default function renderQm () {
|
|
17
|
+
function renderItem (field, i, add, remove) {
|
|
18
|
+
return (
|
|
19
|
+
<Space
|
|
20
|
+
align='center'
|
|
21
|
+
key={field.key}
|
|
22
|
+
>
|
|
23
|
+
<FormItem
|
|
24
|
+
label=''
|
|
25
|
+
name={[field.name, 'delay']}
|
|
26
|
+
required
|
|
27
|
+
>
|
|
28
|
+
<InputNumber
|
|
29
|
+
min={1}
|
|
30
|
+
step={1}
|
|
31
|
+
max={65535}
|
|
32
|
+
addonBefore={t('delay')}
|
|
33
|
+
placeholder={100}
|
|
34
|
+
className='compact-input'
|
|
35
|
+
/>
|
|
36
|
+
</FormItem>
|
|
37
|
+
<FormItem
|
|
38
|
+
label=''
|
|
39
|
+
name={[field.name, 'command']}
|
|
40
|
+
required
|
|
41
|
+
className='mg2x'
|
|
42
|
+
>
|
|
43
|
+
<Input.TextArea
|
|
44
|
+
rows={1}
|
|
45
|
+
placeholder={t('quickCommand')}
|
|
46
|
+
className='compact-input'
|
|
47
|
+
/>
|
|
48
|
+
</FormItem>
|
|
49
|
+
<Button
|
|
50
|
+
icon={<MinusCircleOutlined />}
|
|
51
|
+
onClick={() => remove(field.name)}
|
|
52
|
+
className='mg24b'
|
|
53
|
+
/>
|
|
54
|
+
</Space>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<FormItem {...formItemLayout} label={t('quickCommands')}>
|
|
60
|
+
<FormList
|
|
61
|
+
name='commands'
|
|
62
|
+
>
|
|
63
|
+
{
|
|
64
|
+
(fields, { add, remove }, { errors }) => {
|
|
65
|
+
return (
|
|
66
|
+
<div>
|
|
67
|
+
{
|
|
68
|
+
fields.map((field, i) => {
|
|
69
|
+
return renderItem(field, i, add, remove)
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
<FormItem>
|
|
73
|
+
<Button
|
|
74
|
+
type='dashed'
|
|
75
|
+
onClick={() => add()}
|
|
76
|
+
block
|
|
77
|
+
icon={<PlusOutlined />}
|
|
78
|
+
>
|
|
79
|
+
{t('quickCommand')}
|
|
80
|
+
</Button>
|
|
81
|
+
</FormItem>
|
|
82
|
+
</div>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
</FormList>
|
|
87
|
+
</FormItem>
|
|
88
|
+
)
|
|
89
|
+
}
|
|
@@ -472,10 +472,11 @@ export default class SessionWrapper extends Component {
|
|
|
472
472
|
renderControl = () => {
|
|
473
473
|
const { splitDirection, terminals, sftpPathFollowSsh } = this.state
|
|
474
474
|
const { props } = this
|
|
475
|
-
const { pane } = props.tab
|
|
475
|
+
const { pane, enableSsh } = props.tab
|
|
476
|
+
|
|
476
477
|
const termType = props.tab?.type
|
|
477
478
|
const isSsh = props.tab.authType
|
|
478
|
-
const isLocal = termType === connectionMap.local || !termType
|
|
479
|
+
const isLocal = !isSsh && (termType === connectionMap.local || !termType)
|
|
479
480
|
const isHori = splitDirection === terminalSplitDirectionMap.horizontal
|
|
480
481
|
const cls1 = 'mg1r icon-split pointer iblock spliter'
|
|
481
482
|
const cls2 = 'icon-direction pointer iblock spliter'
|
|
@@ -542,7 +543,7 @@ export default class SessionWrapper extends Component {
|
|
|
542
543
|
}
|
|
543
544
|
</div>
|
|
544
545
|
{
|
|
545
|
-
isSsh || isLocal
|
|
546
|
+
(isSsh && enableSsh) || isLocal
|
|
546
547
|
? (
|
|
547
548
|
<Tooltip title={checkTxt}>
|
|
548
549
|
<span {...checkProps}>
|
|
@@ -608,7 +609,7 @@ export default class SessionWrapper extends Component {
|
|
|
608
609
|
const { pane } = this.props.tab
|
|
609
610
|
const infoProps = {
|
|
610
611
|
infoPanelPinned,
|
|
611
|
-
...pick(this.props.config, ['host', 'port', 'saveTerminalLogToFile']),
|
|
612
|
+
...pick(this.props.config, ['host', 'port', 'saveTerminalLogToFile', 'terminalInfos']),
|
|
612
613
|
...infoPanelProps,
|
|
613
614
|
appPath: this.props.appPath,
|
|
614
615
|
rightSidebarWidth: this.props.rightSidebarWidth,
|
|
@@ -498,6 +498,7 @@ export default class SettingTerminal extends Component {
|
|
|
498
498
|
{this.renderToggle('saveTerminalLogToFile', (
|
|
499
499
|
<ShowItem to={terminalLogPath} className='mg1l'>{p('open')}</ShowItem>
|
|
500
500
|
))}
|
|
501
|
+
{this.renderToggle('addTimeStampToTermLog')}
|
|
501
502
|
{
|
|
502
503
|
[
|
|
503
504
|
'cursorBlink',
|
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
width 16px
|
|
10
10
|
line-height 26px
|
|
11
11
|
height 20px
|
|
12
|
+
position absolute
|
|
13
|
+
right 0
|
|
14
|
+
top 0
|
|
12
15
|
.tree-item
|
|
13
16
|
display flex
|
|
14
17
|
&.is-category
|
|
@@ -25,6 +28,7 @@
|
|
|
25
28
|
overflow hidden
|
|
26
29
|
white-space nowrap
|
|
27
30
|
text-overflow ellipsis
|
|
31
|
+
padding-right 20px
|
|
28
32
|
.sidebar-panel .tree-item-title
|
|
29
33
|
max-width 180px
|
|
30
34
|
.with-plus
|
|
@@ -761,13 +761,15 @@ export default class FileSection extends React.Component {
|
|
|
761
761
|
transferOrEnterDirectory = async (e, edit) => {
|
|
762
762
|
const { file } = this.state
|
|
763
763
|
const { isDirectory, type, size } = file
|
|
764
|
+
const isLocal = type === typeMap.local
|
|
765
|
+
const isRemote = type === typeMap.remote
|
|
764
766
|
if (isDirectory) {
|
|
765
767
|
return this.enterDirectory(e)
|
|
766
768
|
}
|
|
767
|
-
if (!edit &&
|
|
769
|
+
if (!edit && isLocal) {
|
|
768
770
|
return this.openFile(this.state.file)
|
|
769
771
|
}
|
|
770
|
-
const remoteEdit = !edit &&
|
|
772
|
+
const remoteEdit = !edit && isRemote && size < maxEditFileSize
|
|
771
773
|
if (
|
|
772
774
|
edit === true || remoteEdit
|
|
773
775
|
) {
|
|
@@ -787,13 +789,14 @@ export default class FileSection extends React.Component {
|
|
|
787
789
|
operation
|
|
788
790
|
) => {
|
|
789
791
|
const { name, path, type, isDirectory } = file
|
|
790
|
-
|
|
792
|
+
const isLocal = type === typeMap.local
|
|
793
|
+
let typeTo = isLocal
|
|
791
794
|
? typeMap.remote
|
|
792
795
|
: typeMap.local
|
|
793
796
|
if (_typeTo) {
|
|
794
797
|
typeTo = _typeTo
|
|
795
798
|
}
|
|
796
|
-
let toPath =
|
|
799
|
+
let toPath = isLocal
|
|
797
800
|
? this.props[typeMap.remote + 'Path']
|
|
798
801
|
: this.props[typeMap.local + 'Path']
|
|
799
802
|
if (toPathBase) {
|
|
@@ -928,10 +931,12 @@ export default class FileSection extends React.Component {
|
|
|
928
931
|
} = this.props
|
|
929
932
|
const hasHost = !!tab.host
|
|
930
933
|
const { enableSsh } = tab
|
|
931
|
-
const
|
|
934
|
+
const isLocal = type === typeMap.local
|
|
935
|
+
const isRemote = type === typeMap.remote
|
|
936
|
+
const transferText = isLocal
|
|
932
937
|
? e(transferTypeMap.upload)
|
|
933
938
|
: e(transferTypeMap.download)
|
|
934
|
-
const iconType =
|
|
939
|
+
const iconType = isLocal
|
|
935
940
|
? 'CloudUploadOutlined'
|
|
936
941
|
: 'CloudDownloadOutlined'
|
|
937
942
|
const len = selectedFiles.length
|
|
@@ -960,8 +965,8 @@ export default class FileSection extends React.Component {
|
|
|
960
965
|
if (
|
|
961
966
|
isDirectory && id &&
|
|
962
967
|
(
|
|
963
|
-
(hasHost && enableSsh &&
|
|
964
|
-
(
|
|
968
|
+
(hasHost && enableSsh && isRemote) ||
|
|
969
|
+
(isLocal && !hasHost)
|
|
965
970
|
)
|
|
966
971
|
) {
|
|
967
972
|
res.push({
|
|
@@ -977,14 +982,14 @@ export default class FileSection extends React.Component {
|
|
|
977
982
|
text: transferText
|
|
978
983
|
})
|
|
979
984
|
}
|
|
980
|
-
if (!isDirectory && id &&
|
|
985
|
+
if (!isDirectory && id && isLocal) {
|
|
981
986
|
res.push({
|
|
982
987
|
func: 'transferOrEnterDirectory',
|
|
983
988
|
icon: 'ArrowRightOutlined',
|
|
984
989
|
text: e('open')
|
|
985
990
|
})
|
|
986
991
|
}
|
|
987
|
-
if (id &&
|
|
992
|
+
if (id && isLocal) {
|
|
988
993
|
res.push({
|
|
989
994
|
func: 'showInDefaultFileManager',
|
|
990
995
|
icon: 'ContainerOutlined',
|
|
@@ -1040,16 +1045,18 @@ export default class FileSection extends React.Component {
|
|
|
1040
1045
|
text: m('copyFilePath')
|
|
1041
1046
|
})
|
|
1042
1047
|
}
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1048
|
+
if (enableSsh || isLocal) {
|
|
1049
|
+
res.push({
|
|
1050
|
+
func: 'newFile',
|
|
1051
|
+
icon: 'FileAddOutlined',
|
|
1052
|
+
text: e('newFile')
|
|
1053
|
+
})
|
|
1054
|
+
res.push({
|
|
1055
|
+
func: 'newDirectory',
|
|
1056
|
+
icon: 'FolderAddOutlined',
|
|
1057
|
+
text: e('newFolder')
|
|
1058
|
+
})
|
|
1059
|
+
}
|
|
1053
1060
|
res.push({
|
|
1054
1061
|
func: 'selectAll',
|
|
1055
1062
|
icon: 'CheckSquareOutlined',
|