@electerm/electerm-react 1.60.18 → 1.60.32

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 (106) hide show
  1. package/client/common/clipboard.js +1 -14
  2. package/client/common/constants.js +0 -43
  3. package/client/common/data-compare.js +55 -0
  4. package/client/common/default-setting.js +2 -10
  5. package/client/common/resolve.js +18 -22
  6. package/client/common/sftp.js +0 -3
  7. package/client/components/ai/ai-chat.jsx +30 -6
  8. package/client/components/ai/ai-config.jsx +17 -6
  9. package/client/components/batch-op/batch-op.jsx +3 -24
  10. package/client/components/bookmark-form/bookmark-group-tree-format.js +7 -9
  11. package/client/components/bookmark-form/form-ssh-common.jsx +0 -2
  12. package/client/components/bookmark-form/ssh-form.jsx +8 -41
  13. package/client/components/bookmark-form/tree-delete.jsx +1 -13
  14. package/client/components/common/animate-text.jsx +3 -4
  15. package/client/components/common/drag-handle.jsx +59 -45
  16. package/client/components/common/drag-handle.styl +2 -1
  17. package/client/components/common/input-auto-focus.jsx +29 -63
  18. package/client/components/common/ref.js +24 -0
  19. package/client/components/footer/batch-input.jsx +1 -6
  20. package/client/components/footer/footer-entry.jsx +13 -16
  21. package/client/components/footer/footer.styl +0 -5
  22. package/client/components/icons/ai-icon.jsx +17 -0
  23. package/client/components/icons/ai-icon.styl +3 -0
  24. package/client/components/layout/layout-item.jsx +14 -0
  25. package/client/components/main/main.jsx +8 -19
  26. package/client/components/main/upgrade.jsx +13 -25
  27. package/client/components/profile/profile-form-elem.jsx +1 -2
  28. package/client/components/quick-commands/on-drop.js +1 -12
  29. package/client/components/quick-commands/quick-command-transport-mod.jsx +3 -13
  30. package/client/components/quick-commands/quick-commands-form-elem.jsx +1 -2
  31. package/client/components/rdp/rdp-session.jsx +4 -4
  32. package/client/components/session/session.jsx +9 -11
  33. package/client/components/setting-panel/on-tree-drop.js +4 -35
  34. package/client/components/setting-panel/setting-common.jsx +4 -1
  35. package/client/components/setting-panel/setting-modal.jsx +7 -5
  36. package/client/components/setting-panel/tab-settings.jsx +0 -1
  37. package/client/components/setting-sync/setting-sync.jsx +0 -1
  38. package/client/components/sftp/address-bookmark-item.jsx +1 -15
  39. package/client/components/sftp/confirm-modal-store.jsx +2 -2
  40. package/client/components/sftp/{file-mode-modal.jsx → file-info-modal.jsx} +137 -37
  41. package/client/components/sftp/file-item.jsx +156 -192
  42. package/client/components/sftp/file-table-header.jsx +98 -0
  43. package/client/components/sftp/list-table-ui.jsx +125 -416
  44. package/client/components/sftp/sftp-entry.jsx +102 -128
  45. package/client/components/sftp/sftp.styl +6 -22
  46. package/client/components/sftp/transfer-conflict-store.jsx +8 -12
  47. package/client/components/sftp/transport-action-store.jsx +7 -15
  48. package/client/components/shortcuts/shortcut-control.jsx +72 -3
  49. package/client/components/shortcuts/shortcut-handler.js +0 -1
  50. package/client/components/side-panel-r/side-panel-r.jsx +7 -4
  51. package/client/components/sidebar/bookmark-select.jsx +5 -3
  52. package/client/components/sidebar/history.jsx +3 -0
  53. package/client/components/sidebar/index.jsx +1 -1
  54. package/client/components/sidebar/info-modal.jsx +3 -0
  55. package/client/components/sidebar/side-panel.jsx +7 -4
  56. package/client/components/sidebar/sidebar-panel.jsx +1 -1
  57. package/client/components/sidebar/sidebar.styl +3 -3
  58. package/client/components/sys-menu/icons-map.jsx +52 -0
  59. package/client/components/{context-menu → sys-menu}/menu-btn.jsx +33 -45
  60. package/client/components/sys-menu/sys-menu.jsx +163 -0
  61. package/client/components/{context-menu/context-menu.styl → sys-menu/sys-menu.styl} +2 -11
  62. package/client/components/tabs/index.jsx +5 -97
  63. package/client/components/tabs/tab.jsx +121 -73
  64. package/client/components/tabs/tabs.styl +4 -1
  65. package/client/components/terminal/term-search.jsx +16 -28
  66. package/client/components/terminal/terminal-interactive.jsx +0 -2
  67. package/client/components/terminal/{index.jsx → terminal.jsx} +110 -240
  68. package/client/components/terminal-info/base.jsx +21 -46
  69. package/client/components/terminal-info/terminal-info.jsx +3 -0
  70. package/client/components/text-editor/text-editor.jsx +38 -53
  71. package/client/components/theme/theme-form.jsx +0 -2
  72. package/client/components/tree-list/bookmark-toolbar.jsx +23 -47
  73. package/client/components/tree-list/bookmark-transport.jsx +2 -90
  74. package/client/components/tree-list/move-item-modal.jsx +101 -0
  75. package/client/components/tree-list/tree-expander.jsx +2 -3
  76. package/client/components/tree-list/tree-list-item.jsx +8 -11
  77. package/client/components/tree-list/tree-list.jsx +75 -296
  78. package/client/components/vnc/vnc-session.jsx +5 -3
  79. package/client/store/app-upgrade.js +2 -5
  80. package/client/store/bookmark-group.js +116 -51
  81. package/client/store/common.js +36 -54
  82. package/client/store/event.js +4 -37
  83. package/client/store/init-state.js +9 -12
  84. package/client/store/item.js +34 -39
  85. package/client/store/load-data.js +5 -1
  86. package/client/store/quick-command.js +2 -12
  87. package/client/store/session.js +6 -7
  88. package/client/store/setting.js +3 -7
  89. package/client/store/sidebar.js +2 -8
  90. package/client/store/store.js +0 -20
  91. package/client/store/system-menu.js +1 -2
  92. package/client/store/tab.js +29 -1
  93. package/client/store/terminal-theme.js +0 -4
  94. package/client/store/watch.js +26 -4
  95. package/package.json +1 -1
  96. package/client/common/post-msg.js +0 -3
  97. package/client/components/common/native-input.jsx +0 -30
  98. package/client/components/context-menu/context-menu.jsx +0 -339
  99. package/client/components/sftp/file-props-modal.jsx +0 -210
  100. package/client/store/context-menu.js +0 -23
  101. /package/client/components/{context-menu → sys-menu}/boomarks.jsx +0 -0
  102. /package/client/components/{context-menu → sys-menu}/history.jsx +0 -0
  103. /package/client/components/{context-menu → sys-menu}/icon-holder.jsx +0 -0
  104. /package/client/components/{context-menu → sys-menu}/sub-tab-menu.jsx +0 -0
  105. /package/client/components/{context-menu → sys-menu}/tabs.jsx +0 -0
  106. /package/client/components/{context-menu → sys-menu}/zoom.jsx +0 -0
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * terminal/sftp wrapper
3
3
  */
4
- import { Component } from 'react'
5
- import Term from '../terminal'
4
+ import { Component, createRef } from 'react'
5
+ import Term from '../terminal/terminal.jsx'
6
6
  import Sftp from '../sftp/sftp-entry'
7
7
  import RdpSession from '../rdp/rdp-session'
8
8
  import VncSession from '../vnc/vnc-session'
@@ -23,14 +23,13 @@ import copy from 'json-deep-copy'
23
23
  import classnames from 'classnames'
24
24
  import {
25
25
  paneMap,
26
- terminalActions,
27
26
  connectionMap,
28
27
  terminalRdpType,
29
28
  terminalVncType,
30
29
  terminalWebType
31
30
  } from '../../common/constants'
31
+ import { refs } from '../common/ref'
32
32
  import safeName from '../../common/safe-name'
33
- import postMessage from '../../common/post-msg'
34
33
  import './session.styl'
35
34
 
36
35
  const e = window.translate
@@ -38,6 +37,8 @@ const e = window.translate
38
37
  export default class SessionWrapper extends Component {
39
38
  constructor (props) {
40
39
  super(props)
40
+ // Add ref
41
+ this.domRef = createRef()
41
42
  this.state = {
42
43
  enableSftp: false,
43
44
  cwd: '',
@@ -59,7 +60,7 @@ export default class SessionWrapper extends Component {
59
60
  }
60
61
 
61
62
  getDom = () => {
62
- return document.getElementById(`is-${this.props.tab.id}`)
63
+ return this.domRef.current
63
64
  }
64
65
 
65
66
  handleClick = () => {
@@ -358,10 +359,7 @@ export default class SessionWrapper extends Component {
358
359
  }
359
360
 
360
361
  handleOpenSearch = () => {
361
- postMessage({
362
- action: terminalActions.openTerminalSearch,
363
- activeTabId: this.props.tab.id
364
- })
362
+ refs.get('term-' + this.props.tab.id)?.toggleSearch()
365
363
  }
366
364
 
367
365
  renderSearchIcon = () => {
@@ -507,7 +505,7 @@ export default class SessionWrapper extends Component {
507
505
  }
508
506
 
509
507
  render () {
510
- const { pane, id } = this.props.tab
508
+ const { pane } = this.props.tab
511
509
  const cls = classnames(
512
510
  'term-sftp-box',
513
511
  pane,
@@ -520,7 +518,6 @@ export default class SessionWrapper extends Component {
520
518
  )
521
519
  const divProps = {
522
520
  className: cls,
523
- id: `is-${id}`,
524
521
  onDragEnter: this.onDragEnter,
525
522
  onDragLeave: this.onDragLeave,
526
523
  onDrop: this.onDrop,
@@ -529,6 +526,7 @@ export default class SessionWrapper extends Component {
529
526
  }
530
527
  return (
531
528
  <div
529
+ ref={this.domRef}
532
530
  {...divProps}
533
531
  >
534
532
  {this.renderControl()}
@@ -7,8 +7,9 @@ import {
7
7
  } from '../../common/constants'
8
8
  import { isEqual, find, last, remove } from 'lodash-es'
9
9
  import copy from 'json-deep-copy'
10
+ import { action } from 'manate'
10
11
 
11
- export default (info, props) => {
12
+ export default action((info, props) => {
12
13
  const {
13
14
  dropToGap,
14
15
  dragNode,
@@ -23,10 +24,7 @@ export default (info, props) => {
23
24
  const toPosesLevel = toPoses.slice(0, toPoses.length - 1)
24
25
  const isSameLevel = fromPosesLevel.length === toPosesLevel.length
25
26
  const isSameCat = isEqual(fromPosesLevel, toPosesLevel) && dropToGap
26
- const bookmarks = copy(props.bookmarks)
27
- const bookmarkGroups = copy(
28
- props.bookmarkGroups
29
- )
27
+ const { bookmarks, bookmarkGroups } = window.store
30
28
  let from = find(
31
29
  bookmarks,
32
30
  d => d.id === fromId
@@ -163,7 +161,6 @@ export default (info, props) => {
163
161
  if (!fromLeaf) {
164
162
  from.level = toFirstLevel ? 1 : 2
165
163
  }
166
- const updates = []
167
164
  if (toFirstLevel) {
168
165
  fromIndex = bookmarkGroups.findIndex(d => d.id === fromId)
169
166
  from = copy(from)
@@ -191,32 +188,4 @@ export default (info, props) => {
191
188
  remove(arr, d => d === 'tobedel')
192
189
  }
193
190
  }
194
- if (fromGroup) {
195
- const { id, ...rest } = fromGroup
196
- updates.push({
197
- id,
198
- db: 'bookmarkGroups',
199
- update: rest,
200
- upsert: false
201
- })
202
- }
203
- if (toGroup) {
204
- const { id, ...rest } = toGroup
205
- updates.push({
206
- id,
207
- db: 'bookmarkGroups',
208
- update: rest,
209
- upsert: false
210
- })
211
- } else if (from) {
212
- const { id, ...rest } = from
213
- updates.push({
214
- id,
215
- db: 'bookmarkGroups',
216
- update: rest,
217
- upsert: false
218
- })
219
- }
220
- props.store.setBookmarkGroups(bookmarkGroups)
221
- props.store.batchDbUpdate(updates)
222
- }
191
+ })
@@ -183,6 +183,9 @@ export default class SettingCommon extends Component {
183
183
  if (name === 'useSystemTitleBar') {
184
184
  message.info(e('useSystemTitleBarTip'), 5)
185
185
  }
186
+ if (name === 'disableConnectionHistory' && value) {
187
+ window.store.history = []
188
+ }
186
189
  this.saveConfig({
187
190
  [name]: value
188
191
  })
@@ -658,7 +661,7 @@ export default class SettingCommon extends Component {
658
661
  'showHiddenFilesOnSftpStart',
659
662
  'screenReaderMode',
660
663
  'initDefaultTabOnStart',
661
- 'disableSshHistory',
664
+ 'disableConnectionHistory',
662
665
  'disableTransferHistory',
663
666
  'checkUpdateOnStart',
664
667
  'useSystemTitleBar',
@@ -15,6 +15,7 @@ import TabQuickCommands from './tab-quick-commands'
15
15
  import TabSettings from './tab-settings'
16
16
  import TabThemes from './tab-themes'
17
17
  import TabProfiles from './tab-profiles'
18
+ import deepCopy from 'json-deep-copy'
18
19
 
19
20
  const e = window.translate
20
21
 
@@ -38,6 +39,8 @@ export default auto(function SettingModalWrap (props) {
38
39
  shouldConfirmDel: tabsShouldConfirmDel.includes(settingTab),
39
40
  list: settingSidebarList
40
41
  }
42
+ const bookmarks = deepCopy(store.bookmarks)
43
+ const bookmarkGroups = deepCopy(store.bookmarkGroups)
41
44
  const formProps = {
42
45
  store,
43
46
  formData: settingItem,
@@ -47,19 +50,18 @@ export default auto(function SettingModalWrap (props) {
47
50
  'currentBookmarkGroupId',
48
51
  'config'
49
52
  ]),
50
- bookmarkGroups: store.bookmarkGroups,
51
- bookmarks: store.bookmarks,
53
+ bookmarkGroups,
54
+ bookmarks,
52
55
  serials: store.serials,
53
56
  loaddingSerials: store.loaddingSerials
54
57
  }
55
58
  const treeProps = {
56
59
  ...props0,
57
60
  bookmarkSelectMode,
58
- bookmarkGroups: store.bookmarkGroups,
59
- bookmarks: store.bookmarks,
61
+ bookmarkGroups,
62
+ bookmarks,
60
63
  ...pick(store, [
61
64
  'currentBookmarkGroupId',
62
- 'autofocustrigger',
63
65
  'config',
64
66
  'checkedKeys',
65
67
  'expandedKeys',
@@ -30,7 +30,6 @@ export default auto(function TabSettings (props) {
30
30
  if (sid === settingSyncId) {
31
31
  const syncProps = pick(store, [
32
32
  'config',
33
- 'autofocustrigger',
34
33
  'isSyncingSetting',
35
34
  'isSyncDownload',
36
35
  'isSyncUpload',
@@ -26,7 +26,6 @@ export default function SyncSettingEntry (props) {
26
26
  const syncProps = {
27
27
  ...syncSetting,
28
28
  ...pick(props, [
29
- 'autofocustrigger',
30
29
  'isSyncingSetting',
31
30
  'isSyncDownload',
32
31
  'isSyncUpload',
@@ -39,24 +39,10 @@ export default class AddrBookmarkItem extends Component {
39
39
  const { store } = window
40
40
  const [host, idDragged] = e.dataTransfer.getData('idDragged').split('#')
41
41
  const idDrop = e.target.getAttribute('data-id').split('#')[1]
42
- const addressBookmarks = host
43
- ? store.addressBookmarks
44
- : store.addressBookmarksLocal
45
42
  const dataName = host
46
43
  ? 'addressBookmarks'
47
44
  : 'addressBookmarksLocal'
48
- const idDraggedIndex = addressBookmarks.findIndex(
49
- ({ id }) => id === idDragged
50
- )
51
- const targetIndex = addressBookmarks.findIndex(
52
- ({ id }) => id === idDrop
53
- )
54
- if (idDraggedIndex < targetIndex) {
55
- addressBookmarks.splice(targetIndex, 0, addressBookmarks.splice(idDraggedIndex, 1)[0])
56
- } else {
57
- addressBookmarks.splice(targetIndex + 1, 0, addressBookmarks.splice(idDraggedIndex, 1)[0])
58
- }
59
- store.setItems(dataName, addressBookmarks)
45
+ store.adjustOrder(dataName, idDragged, idDrop)
60
46
  }
61
47
 
62
48
  render () {
@@ -12,7 +12,7 @@ import {
12
12
  fileActions
13
13
  } from '../../common/constants'
14
14
  import deepCopy from 'json-deep-copy'
15
- import postMessage from '../../common/post-msg'
15
+ import { refsStatic } from '../common/ref'
16
16
 
17
17
  const e = window.translate
18
18
 
@@ -34,7 +34,7 @@ export default function ConfirmModalStore (props) {
34
34
  id,
35
35
  transferGroupId
36
36
  } = transferToConfirm
37
- postMessage({
37
+ refsStatic.get('transfer-conflict')?.onDecision({
38
38
  transferGroupId,
39
39
  fileId,
40
40
  id,
@@ -8,47 +8,58 @@ import resolve from '../../common/resolve'
8
8
  import time from '../../common/time'
9
9
  import { update } from 'lodash-es'
10
10
  import { mode2permission, permission2mode } from '../../common/mode2permission'
11
- import { commonActions } from '../../common/constants'
12
11
  import renderPermission from './permission-render'
13
- import postMessage from '../../common/post-msg'
14
12
  import FileIcon from './file-icon'
13
+ import fs from '../../common/fs'
14
+ import { filesize } from 'filesize'
15
+ import { runCmd } from '../terminal/terminal-apis'
16
+ import {
17
+ isWin,
18
+ typeMap
19
+ } from '../../common/constants'
20
+ import { refsStatic, refs } from '../common/ref'
15
21
 
16
22
  const e = window.translate
17
23
  const formatTime = time
18
24
 
19
25
  export default class FileMode extends React.PureComponent {
20
26
  state = {
21
- data: {},
22
- file: {}
27
+ fileId: '',
28
+ loading: false,
29
+ tab: null,
30
+ pid: '',
31
+ sessionId: '',
32
+ size: 0,
33
+ file: {},
34
+ editPermission: false
23
35
  }
24
36
 
25
37
  componentDidMount () {
26
- window.addEventListener('message', this.onEvent)
38
+ refsStatic.add('file-modal', this)
27
39
  }
28
40
 
29
41
  setStateProxy = (state, cb) => {
30
42
  if (state && typeof state.file !== 'undefined') {
31
- postMessage({
32
- action: commonActions.updateStore,
33
- value: !!state.file.id,
34
- prop: 'showFileModal'
35
- })
43
+ window.store.showFileModal = !!state.file.id
36
44
  }
37
45
  return this.setState(state, cb)
38
46
  }
39
47
 
40
- onEvent = (e) => {
41
- const {
42
- action,
43
- data,
44
- file
45
- } = e.data || {}
46
- if (action === commonActions.showFileModeModal) {
47
- this.setStateProxy({
48
- data,
49
- file
50
- })
51
- }
48
+ showFileInfoModal (data) {
49
+ this.setStateProxy({
50
+ ...data,
51
+ size: 0,
52
+ editPermission: false
53
+ })
54
+ }
55
+
56
+ showFileModeModal = (data, file, fileId) => {
57
+ this.setStateProxy({
58
+ ...data,
59
+ file: this.addPermission(file),
60
+ fileId,
61
+ editPermission: true
62
+ })
52
63
  }
53
64
 
54
65
  addPermission = file => {
@@ -63,6 +74,9 @@ export default class FileMode extends React.PureComponent {
63
74
  }
64
75
 
65
76
  onChangePermission = (name, permName) => {
77
+ if (!this.state.editPermission) {
78
+ return
79
+ }
66
80
  const { file } = this.state
67
81
  const perms = mode2permission(file.mode)
68
82
  const i = perms.findIndex(p => p.name === name)
@@ -83,24 +97,65 @@ export default class FileMode extends React.PureComponent {
83
97
  }
84
98
 
85
99
  onClose = () => {
86
- postMessage({
87
- action: commonActions.submitFileModeClose
88
- })
89
100
  this.setStateProxy({
90
101
  file: {},
91
- data: {}
102
+ visible: false
92
103
  })
93
104
  }
94
105
 
95
- handleSubmit = () => {
96
- postMessage({
97
- action: commonActions.submitFileModeEdit,
98
- file: this.state.file
106
+ getSize = (str = '') => {
107
+ if (isWin) {
108
+ const s = (str.stdout || '').split('\n').find(s => s.trim().startsWith('Sum'))
109
+ return s ? filesize(parseInt((s.split(':')[1]).trim(), 10)) : 0
110
+ } else {
111
+ return str.split(/\s+/)[0]
112
+ }
113
+ }
114
+
115
+ calcLocal = async (folder) => {
116
+ const cmd = isWin
117
+ ? `Get-ChildItem -Recurse '${folder}' | Measure-Object -Property Length -Sum`
118
+ : `du -sh '${folder}'`
119
+ const func = isWin ? 'runWinCmd' : 'run'
120
+ const res = await fs[func](cmd).catch(window.store.onError)
121
+ return this.getSize(res)
122
+ }
123
+
124
+ calcRemote = async (folder) => {
125
+ const cmd = `du -sh '${folder}'`
126
+ const r = await runCmd(
127
+ this.state.pid,
128
+ this.state.sessionId,
129
+ cmd
130
+ ).catch(window.store.onError)
131
+ return r ? r.split(/\s+/)[0] : 0
132
+ }
133
+
134
+ handleCalc = async () => {
135
+ const { file } = this.state
136
+ const { type, path, name } = file
137
+ this.setStateProxy({
138
+ loading: true
99
139
  })
140
+ const fp = resolve(path, name)
141
+ const size = type === typeMap.local
142
+ ? await this.calcLocal(fp)
143
+ : await this.calcRemote(fp)
144
+ this.setState({
145
+ loading: false,
146
+ size
147
+ })
148
+ }
149
+
150
+ handleSubmit = () => {
151
+ refs.get(this.state.fileId)?.changeFileMode(this.state.file)
100
152
  this.onClose()
101
153
  }
102
154
 
103
155
  renderFooter () {
156
+ if (!this.state.editPermission) {
157
+ return null
158
+ }
104
159
  return (
105
160
  <Button
106
161
  type='primary'
@@ -111,20 +166,63 @@ export default class FileMode extends React.PureComponent {
111
166
  )
112
167
  }
113
168
 
169
+ getFileSize = () => {
170
+ const { isDirectory, size } = this.state.file
171
+ if (isDirectory) {
172
+ return this.state.size || 0
173
+ }
174
+ return size
175
+ }
176
+
177
+ renderSizeRow = () => {
178
+ const size = this.getFileSize()
179
+ if (this.state.editPermission) {
180
+ return (
181
+ <>
182
+ <p className='bold'>{e('size')}:</p>
183
+ <p className='pd1b'>{size}</p>
184
+ </>
185
+ )
186
+ }
187
+ return (
188
+ <>
189
+ <p className='bold'>{e('size')}:</p>
190
+ <p className='pd1b'>{this.getFileSize()}{this.renderCalc()}</p>
191
+ </>
192
+ )
193
+ }
194
+
195
+ renderCalc () {
196
+ const { isDirectory } = this.state.file
197
+ if (isDirectory) {
198
+ const { loading } = this.state
199
+ return (
200
+ <Button
201
+ onClick={this.handleCalc}
202
+ loading={loading}
203
+ disabled={loading}
204
+ className='mg1l'
205
+ >
206
+ {e('calculate')}
207
+ </Button>
208
+ )
209
+ }
210
+ }
211
+
114
212
  render () {
115
213
  const {
116
214
  visible,
117
215
  tab,
118
216
  uidTree,
119
- gidTree
120
- } = this.state.data
217
+ gidTree,
218
+ file,
219
+ editPermission
220
+ } = this.state
121
221
  if (!visible) {
122
222
  return null
123
223
  }
124
- const { file } = this.state
125
224
  const {
126
225
  name,
127
- size,
128
226
  accessTime,
129
227
  modifyTime,
130
228
  isDirectory,
@@ -141,10 +239,13 @@ export default class FileMode extends React.PureComponent {
141
239
  username
142
240
  } = tab
143
241
  const iconType = isDirectory ? 'folder' : 'file'
242
+ const title = editPermission
243
+ ? `${e('edit')} ` + e(iconType) + ` ${e('permission')}`
244
+ : e(iconType) + ` ${e('attributes')}`
144
245
  const ps = {
145
246
  open: visible,
146
247
  width: 500,
147
- title: `${e('edit')} ` + e(iconType) + ` ${e('permission')}`,
248
+ title,
148
249
  footer: this.renderFooter(),
149
250
  onCancel: this.onClose
150
251
  }
@@ -193,8 +294,7 @@ export default class FileMode extends React.PureComponent {
193
294
  <p className='pd1b'>{uidTree['' + owner]}</p>
194
295
  <p className='bold'>{e('group')}</p>
195
296
  <p className='pd1b'>{gidTree['' + group]}</p>
196
- <p className='bold'>{e('size')}:</p>
197
- <p className='pd1b'>{size}</p>
297
+ {this.renderSizeRow()}
198
298
  <p className='bold'>{e('accessTime')}:</p>
199
299
  <p className='pd1b'>{formatTime(accessTime)}</p>
200
300
  <p className='bold'>{e('modifyTime')}:</p>