@electerm/electerm-react 1.70.6 → 1.72.16

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 (72) hide show
  1. package/client/common/cache.js +56 -0
  2. package/client/common/constants.js +2 -0
  3. package/client/common/default-setting.js +2 -1
  4. package/client/common/download.jsx +5 -7
  5. package/client/common/setting-list.js +27 -0
  6. package/client/components/ai/ai-cache.jsx +36 -0
  7. package/client/components/ai/ai-chat-history-item.jsx +1 -1
  8. package/client/components/ai/ai-chat.jsx +5 -40
  9. package/client/components/ai/ai-config-props.js +7 -0
  10. package/client/components/ai/ai-config.jsx +5 -14
  11. package/client/components/ai/ai.styl +0 -4
  12. package/client/components/ai/providers.js +2 -2
  13. package/client/components/batch-op/batch-op-entry.jsx +1 -1
  14. package/client/components/batch-op/batch-op.jsx +2 -2
  15. package/client/components/bookmark-form/form-ssh-common.jsx +2 -3
  16. package/client/components/bookmark-form/form-tabs.jsx +2 -2
  17. package/client/components/bookmark-form/render-connection-hopping.jsx +2 -2
  18. package/client/components/bookmark-form/render-delayed-scripts.jsx +4 -4
  19. package/client/components/bookmark-form/render-ssh-tunnel.jsx +2 -2
  20. package/client/components/bookmark-form/sftp-enable.jsx +9 -0
  21. package/client/components/bookmark-form/ssh-form-ui.jsx +1 -0
  22. package/client/components/bookmark-form/ssh-form.jsx +3 -0
  23. package/client/components/bookmark-form/use-quick-commands.jsx +2 -2
  24. package/client/components/bookmark-form/x11.jsx +78 -9
  25. package/client/components/common/input-auto-focus.jsx +3 -11
  26. package/client/components/layout/layout.jsx +2 -1
  27. package/client/components/main/main.jsx +5 -0
  28. package/client/components/profile/profile-form-elem.jsx +1 -3
  29. package/client/components/quick-commands/quick-commands-form-elem.jsx +1 -3
  30. package/client/components/quick-commands/quick-commands-list-form.jsx +2 -2
  31. package/client/components/session/session.jsx +80 -19
  32. package/client/components/session/session.styl +10 -3
  33. package/client/components/session/sessions.jsx +2 -1
  34. package/client/components/setting-panel/keywords-form.jsx +36 -38
  35. package/client/components/setting-panel/setting-modal.jsx +2 -2
  36. package/client/components/setting-panel/setting-terminal.jsx +2 -1
  37. package/client/components/setting-panel/tab-settings.jsx +26 -0
  38. package/client/components/sftp/address-bar.jsx +9 -2
  39. package/client/components/sftp/address-bookmark.jsx +4 -6
  40. package/client/components/sftp/file-item.jsx +1 -1
  41. package/client/components/sftp/file-read.js +14 -19
  42. package/client/components/sftp/keyword-filter.jsx +63 -0
  43. package/client/components/sftp/list-table-ui.jsx +7 -9
  44. package/client/components/sftp/sftp-entry.jsx +46 -9
  45. package/client/components/sftp/sftp.styl +6 -1
  46. package/client/components/sftp/transfer-conflict-store.jsx +1 -1
  47. package/client/components/shortcuts/shortcut-control.jsx +20 -0
  48. package/client/components/shortcuts/shortcut-editor.jsx +2 -2
  49. package/client/components/shortcuts/shortcuts.jsx +2 -2
  50. package/client/components/sidebar/info-modal.jsx +2 -2
  51. package/client/components/sidebar/transfer-list-control.jsx +18 -20
  52. package/client/components/ssh-config/ssh-config-item.jsx +2 -4
  53. package/client/components/ssh-config/ssh-config-load-notify.jsx +2 -2
  54. package/client/components/sys-menu/zoom.jsx +2 -2
  55. package/client/components/tabs/index.jsx +1 -1
  56. package/client/components/tabs/tab.jsx +3 -3
  57. package/client/components/terminal/cmd-item.jsx +32 -0
  58. package/client/components/terminal/command-tracker-addon.js +3 -1
  59. package/client/components/terminal/term-search.jsx +5 -6
  60. package/client/components/terminal/terminal-command-dropdown.jsx +303 -0
  61. package/client/components/terminal/terminal.jsx +88 -8
  62. package/client/components/terminal/terminal.styl +58 -0
  63. package/client/components/terminal-info/terminal-info.jsx +2 -2
  64. package/client/components/tree-list/tree-list.jsx +1 -1
  65. package/client/components/web/address-bar.jsx +2 -2
  66. package/client/store/common.js +27 -2
  67. package/client/store/init-state.js +3 -3
  68. package/client/store/item.js +2 -1
  69. package/client/store/setting.js +3 -2
  70. package/client/store/store.js +23 -24
  71. package/client/store/watch.js +7 -1
  72. package/package.json +1 -1
@@ -4,22 +4,14 @@ import {
4
4
  } from 'antd'
5
5
 
6
6
  export default function InputAutoFocus (props) {
7
- const { type, selectall = false, ...rest } = props
7
+ const { type, ...rest } = props
8
8
  const inputRef = useRef(null)
9
- const isFirstRender = useRef(true)
10
9
 
11
10
  useEffect(() => {
12
11
  if (inputRef.current) {
13
- const { value } = props
14
- if (value && selectall && isFirstRender.current) {
15
- inputRef.current.focus()
16
- inputRef.current.setSelectionRange(0, value.length)
17
- isFirstRender.current = false
18
- } else {
19
- inputRef.current.focus()
20
- }
12
+ inputRef.current.focus()
21
13
  }
22
- }, [props.value, props.selectall])
14
+ }, [props.value])
23
15
 
24
16
  let InputComponent
25
17
  switch (type) {
@@ -180,7 +180,8 @@ export default auto(function Layout (props) {
180
180
  'openedSideBar',
181
181
  'config'
182
182
  ]),
183
- tabs: store.tabs
183
+ tabs: store.tabs,
184
+ layout
184
185
  }
185
186
  return [
186
187
  <Layouts {...layoutProps} key='layouts'>
@@ -14,6 +14,7 @@ import Resolutions from '../rdp/resolution-edit'
14
14
  import TerminalInteractive from '../terminal/terminal-interactive'
15
15
  import ConfirmModalStore from '../sftp/confirm-modal-store.jsx'
16
16
  import TransferConflictStore from '../sftp/transfer-conflict-store.jsx'
17
+ import TerminalCmdSuggestions from '../terminal/terminal-command-dropdown'
17
18
  import TransportsActionStore from '../sftp/transports-action-store.jsx'
18
19
  import classnames from 'classnames'
19
20
  import ShortcutControl from '../shortcuts/shortcut-control.jsx'
@@ -221,6 +222,9 @@ export default auto(function Index (props) {
221
222
  showAIConfig: store.showAIConfig,
222
223
  rightPanelTab
223
224
  }
225
+ const cmdSuggestionsProps = {
226
+ suggestions: store.terminalCommandSuggestions
227
+ }
224
228
  return (
225
229
  <ConfigProvider
226
230
  theme={uiThemeConfig}
@@ -281,6 +285,7 @@ export default auto(function Index (props) {
281
285
  sshConfigs={store.sshConfigs}
282
286
  />
283
287
  <ConnectionHoppingWarning {...warningProps} />
288
+ <TerminalCmdSuggestions {...cmdSuggestionsProps} />
284
289
  </div>
285
290
  </ConfigProvider>
286
291
  )
@@ -71,9 +71,7 @@ export default function ProfileFormElem (props) {
71
71
  hasFeedback
72
72
  name='name'
73
73
  >
74
- <InputAutoFocus
75
- selectall='yes'
76
- />
74
+ <InputAutoFocus />
77
75
  </FormItem>
78
76
  <ProfileTabs {...tabsProps} />
79
77
  <FormItem>
@@ -148,9 +148,7 @@ export default function QuickCommandForm (props) {
148
148
  hasFeedback
149
149
  name='name'
150
150
  >
151
- <InputAutoFocus
152
- selectall='yes'
153
- />
151
+ <InputAutoFocus />
154
152
  </FormItem>
155
153
  {renderQm()}
156
154
  <FormItem
@@ -113,7 +113,7 @@ export default function renderQm () {
113
113
  {
114
114
  (fields, { add, remove }, { errors }) => {
115
115
  return (
116
- <div>
116
+ <>
117
117
  {
118
118
  fields.map((field, i) => {
119
119
  return renderItem(field, i, add, remove)
@@ -129,7 +129,7 @@ export default function renderQm () {
129
129
  {e('quickCommand')}
130
130
  </Button>
131
131
  </FormItem>
132
- </div>
132
+ </>
133
133
  )
134
134
  }
135
135
  }
@@ -2,7 +2,7 @@
2
2
  * terminal/sftp wrapper
3
3
  */
4
4
  import { createRef } from 'react'
5
- import { Component } from '../common/component'
5
+ import { Component } from 'manate/react/class-components'
6
6
  import Term from '../terminal/terminal.jsx'
7
7
  import Sftp from '../sftp/sftp-entry'
8
8
  import RdpSession from '../rdp/rdp-session'
@@ -12,7 +12,8 @@ import {
12
12
  SearchOutlined,
13
13
  FullscreenOutlined,
14
14
  PaperClipOutlined,
15
- CloseOutlined
15
+ CloseOutlined,
16
+ ApartmentOutlined
16
17
  } from '@ant-design/icons'
17
18
  import {
18
19
  Tooltip,
@@ -29,7 +30,8 @@ import {
29
30
  terminalRdpType,
30
31
  terminalVncType,
31
32
  terminalWebType,
32
- terminalTelnetType
33
+ terminalTelnetType,
34
+ splitMap
33
35
  } from '../../common/constants'
34
36
  import { SplitViewIcon } from '../icons/split-view'
35
37
  import { refs } from '../common/ref'
@@ -50,7 +52,8 @@ export default class SessionWrapper extends Component {
50
52
  splitSize: [50, 50],
51
53
  sessionOptions: null,
52
54
  sessionId: generate(),
53
- delKeyPressed: false
55
+ delKeyPressed: false,
56
+ broadcastInput: false
54
57
  }
55
58
  props.tab.sshSftpSplitView = !!props.config.sshSftpSplitView
56
59
  }
@@ -71,6 +74,19 @@ export default class SessionWrapper extends Component {
71
74
  return this.domRef.current
72
75
  }
73
76
 
77
+ isDisabled = () => {
78
+ const { enableSsh, enableSftp } = this.props.tab
79
+ return enableSsh === false || enableSftp === false
80
+ }
81
+
82
+ isSshDisabled = () => {
83
+ return this.props.tab.enableSsh === false
84
+ }
85
+
86
+ isSftpDisabled = () => {
87
+ return this.props.tab.enableSftp === false
88
+ }
89
+
74
90
  handleSshSftpSplitView = () => {
75
91
  const nv = !this.props.tab.sshSftpSplitView
76
92
  this.editTab({
@@ -82,10 +98,9 @@ export default class SessionWrapper extends Component {
82
98
  canSplitView = () => {
83
99
  const {
84
100
  width,
85
- height,
86
- tab
101
+ height
87
102
  } = this.props
88
- if (tab.enableSsh === false) {
103
+ if (this.isDisabled()) {
89
104
  return false
90
105
  }
91
106
  return width > this.minWithForSplit ||
@@ -222,7 +237,7 @@ export default class SessionWrapper extends Component {
222
237
  const update = {
223
238
  pane
224
239
  }
225
- if (pane === paneMap.fileManager || pane === paneMap.sftp) {
240
+ if (pane === paneMap.fileManager) {
226
241
  this.setState({
227
242
  enableSftp: true
228
243
  })
@@ -253,7 +268,8 @@ export default class SessionWrapper extends Component {
253
268
  const {
254
269
  sessionOptions,
255
270
  sessionId,
256
- sftpPathFollowSsh
271
+ sftpPathFollowSsh,
272
+ broadcastInput
257
273
  } = this.state
258
274
  const {
259
275
  tab
@@ -312,7 +328,6 @@ export default class SessionWrapper extends Component {
312
328
  }
313
329
 
314
330
  const cls = pane === paneMap.terminal ||
315
- pane === paneMap.ssh ||
316
331
  (sshSftpSplitView && this.canSplitView())
317
332
  ? 'terms-box'
318
333
  : 'terms-box hide'
@@ -326,6 +341,7 @@ export default class SessionWrapper extends Component {
326
341
  ...this.props,
327
342
  sftpPathFollowSsh,
328
343
  themeConfig,
344
+ broadcastInput,
329
345
  pane,
330
346
  ...pick(
331
347
  this,
@@ -416,14 +432,15 @@ export default class SessionWrapper extends Component {
416
432
  } = this.state
417
433
  const { pane, id, sshSftpSplitView } = this.props.tab
418
434
  if (
419
- this.isNotTerminalType()
435
+ this.isNotTerminalType() ||
436
+ this.isSftpDisabled()
420
437
  ) {
421
438
  return null
422
439
  }
423
440
  const height = this.props.computeHeight(
424
441
  this.props.height
425
442
  )
426
- const cls = pane === paneMap.fileManager || paneMap.sftp === pane ||
443
+ const cls = pane === paneMap.fileManager ||
427
444
  (sshSftpSplitView && this.canSplitView())
428
445
  ? ''
429
446
  : 'hide'
@@ -453,6 +470,12 @@ export default class SessionWrapper extends Component {
453
470
  window.store.toggleTermFullscreen(true)
454
471
  }
455
472
 
473
+ toggleBroadcastInput = () => {
474
+ this.setState({
475
+ broadcastInput: !this.state.broadcastInput
476
+ })
477
+ }
478
+
456
479
  handleOpenSearch = () => {
457
480
  refs.get('term-' + this.props.tab.id)?.toggleSearch()
458
481
  }
@@ -462,7 +485,7 @@ export default class SessionWrapper extends Component {
462
485
  return (
463
486
  <Tooltip title={title} placement='bottomLeft'>
464
487
  <SearchOutlined
465
- className='mg1r icon-info font16 iblock pointer spliter'
488
+ className='mg1r icon-info iblock pointer spliter'
466
489
  onClick={this.handleOpenSearch}
467
490
  />
468
491
  </Tooltip>
@@ -474,7 +497,7 @@ export default class SessionWrapper extends Component {
474
497
  return (
475
498
  <Tooltip title={title} placement='bottomLeft'>
476
499
  <FullscreenOutlined
477
- className='mg1r icon-info font16 iblock pointer spliter term-fullscreen-control1'
500
+ className='mg1r icon-info iblock pointer spliter term-fullscreen-control1'
478
501
  onClick={this.handleFullscreen}
479
502
  />
480
503
  </Tooltip>
@@ -496,6 +519,29 @@ export default class SessionWrapper extends Component {
496
519
  )
497
520
  }
498
521
 
522
+ renderBroadcastIcon = () => {
523
+ if (
524
+ this.props.layout === splitMap.c1 ||
525
+ this.isSshDisabled()
526
+ ) {
527
+ return null
528
+ }
529
+ const { broadcastInput } = this.state
530
+ const title = e('broadcastInput')
531
+ const iconProps = {
532
+ className: classnames('sess-icon pointer broadcast-icon', {
533
+ active: broadcastInput
534
+ }),
535
+ onClick: this.toggleBroadcastInput
536
+ }
537
+
538
+ return (
539
+ <Tooltip title={title}>
540
+ <ApartmentOutlined {...iconProps} />
541
+ </Tooltip>
542
+ )
543
+ }
544
+
499
545
  renderTermControls = () => {
500
546
  const { props } = this
501
547
  const { pane } = props.tab
@@ -515,10 +561,19 @@ export default class SessionWrapper extends Component {
515
561
  return null
516
562
  }
517
563
  const title = e('sshSftpSplitView')
564
+ const {
565
+ sshSftpSplitView
566
+ } = this.props.tab
567
+ const cls = classnames(
568
+ 'pointer sess-icon split-view-toggle',
569
+ {
570
+ active: sshSftpSplitView
571
+ }
572
+ )
518
573
  return (
519
574
  <Tooltip title={title} placement='bottomLeft'>
520
575
  <span
521
- className='pointer mg1r split-view-toggle'
576
+ className={cls}
522
577
  onClick={this.handleSshSftpSplitView}
523
578
  >
524
579
  <SplitViewIcon />
@@ -536,6 +591,9 @@ export default class SessionWrapper extends Component {
536
591
  const {
537
592
  sshSftpSplitView
538
593
  } = this.props.tab
594
+ if (this.isDisabled()) {
595
+ return null
596
+ }
539
597
  if (sshSftpSplitView && this.canSplitView()) {
540
598
  return null
541
599
  }
@@ -591,6 +649,9 @@ export default class SessionWrapper extends Component {
591
649
  }
592
650
 
593
651
  renderSftpPathFollowControl = () => {
652
+ if (this.isDisabled()) {
653
+ return null
654
+ }
594
655
  const {
595
656
  sftpPathFollowSsh
596
657
  } = this.state
@@ -604,14 +665,13 @@ export default class SessionWrapper extends Component {
604
665
  const checkProps = {
605
666
  onClick: this.toggleCheckSftpPathFollowSsh,
606
667
  className: classnames(
607
- 'sftp-follow-ssh-icon',
668
+ 'sftp-follow-ssh-icon sess-icon pointer',
608
669
  {
609
670
  active: sftpPathFollowSsh
610
671
  }
611
672
  )
612
673
  }
613
674
  const isS = pane === paneMap.terminal ||
614
- pane === paneMap.ssh ||
615
675
  sshSftpSplitView
616
676
  return (
617
677
  <>
@@ -646,6 +706,7 @@ export default class SessionWrapper extends Component {
646
706
  {this.renderPaneControl()}
647
707
  {this.renderSftpPathFollowControl()}
648
708
  {this.renderSplitToggle()}
709
+ {this.renderBroadcastIcon()}
649
710
  {this.renderTermControls()}
650
711
  </div>
651
712
  )
@@ -670,8 +731,8 @@ export default class SessionWrapper extends Component {
670
731
  }
671
732
  const notSplitVew = !this.canSplitView() || !this.props.tab.sshSftpSplitView
672
733
  const { pane } = this.props.tab
673
- const show1 = notSplitVew && (pane === paneMap.terminal || pane === paneMap.ssh)
674
- const show2 = notSplitVew && (pane === paneMap.fileManager || pane === paneMap.sftp)
734
+ const show1 = notSplitVew && pane === paneMap.terminal
735
+ const show2 = notSplitVew && pane === paneMap.fileManager
675
736
  const direction = this.getSplitDirection()
676
737
  const layout = direction === 'leftRight' ? 'horizontal' : 'vertical'
677
738
  const [size1, size2] = this.state.splitSize
@@ -16,7 +16,6 @@
16
16
  position relative
17
17
  display inline-block
18
18
 
19
- .sftp-follow-ssh-icon
20
19
  .type-tab
21
20
  display inline-block
22
21
  vertical-align middle
@@ -44,7 +43,6 @@
44
43
  display none
45
44
  .spliter
46
45
  color text
47
- font-size 16px
48
46
  &:hover
49
47
  color text-light
50
48
 
@@ -73,4 +71,13 @@
73
71
  width auto !important
74
72
  height auto !important
75
73
  .not-split-view .ant-splitter-bar-dragger
76
- display none
74
+ display none
75
+
76
+ .sess-icon
77
+ margin-right 10px
78
+ &.active
79
+ color warn
80
+
81
+ .split-view-toggle
82
+ &.active
83
+ color success
@@ -1,4 +1,4 @@
1
- import { Component } from '../common/component'
1
+ import { Component } from 'manate/react/class-components'
2
2
  import Session from './session.jsx'
3
3
 
4
4
  import { pick } from 'lodash-es'
@@ -62,6 +62,7 @@ export default class Sessions extends Component {
62
62
  }
63
63
  const sessProps = {
64
64
  activeTabId,
65
+ layout: this.props.layout,
65
66
  tab,
66
67
  width,
67
68
  height,
@@ -107,44 +107,42 @@ export default function KeywordForm (props) {
107
107
  }, [props.keywordFormReset])
108
108
 
109
109
  return (
110
- <div>
111
- <Form
112
- form={formChild}
113
- onValuesChange={handleTrigger}
114
- initialValues={formData}
115
- onFinish={handleFinish}
116
- >
117
- <FormItem {...formItemLayout}>
118
- <FormList
119
- name='keywords'
120
- >
121
- {
122
- (fields, { add, remove }, { errors }) => {
123
- return (
124
- <div>
125
- {
126
- fields.map((field, i) => {
127
- return renderItem(field, i, add, remove)
128
- })
129
- }
130
- <FormItem>
131
- <Button
132
- type='dashed'
133
- onClick={() => add({
134
- color: 'red'
135
- })}
136
- icon={<PlusOutlined />}
137
- >
138
- {e('keyword')}
139
- </Button>
140
- </FormItem>
141
- </div>
142
- )
143
- }
110
+ <Form
111
+ form={formChild}
112
+ onValuesChange={handleTrigger}
113
+ initialValues={formData}
114
+ onFinish={handleFinish}
115
+ >
116
+ <FormItem {...formItemLayout}>
117
+ <FormList
118
+ name='keywords'
119
+ >
120
+ {
121
+ (fields, { add, remove }, { errors }) => {
122
+ return (
123
+ <>
124
+ {
125
+ fields.map((field, i) => {
126
+ return renderItem(field, i, add, remove)
127
+ })
128
+ }
129
+ <FormItem>
130
+ <Button
131
+ type='dashed'
132
+ onClick={() => add({
133
+ color: 'red'
134
+ })}
135
+ icon={<PlusOutlined />}
136
+ >
137
+ {e('keyword')}
138
+ </Button>
139
+ </FormItem>
140
+ </>
141
+ )
144
142
  }
145
- </FormList>
146
- </FormItem>
147
- </Form>
148
- </div>
143
+ }
144
+ </FormList>
145
+ </FormItem>
146
+ </Form>
149
147
  )
150
148
  }
@@ -104,7 +104,7 @@ export default auto(function SettingModalWrap (props) {
104
104
  type: 'card'
105
105
  }
106
106
  return (
107
- <div>
107
+ <>
108
108
  <Tabs
109
109
  {...tabsProps}
110
110
  />
@@ -141,7 +141,7 @@ export default auto(function SettingModalWrap (props) {
141
141
  store={store}
142
142
  settingTab={settingTab}
143
143
  />
144
- </div>
144
+ </>
145
145
  )
146
146
  }
147
147
 
@@ -594,7 +594,8 @@ export default class SettingTerminal extends Component {
594
594
  'copyWhenSelect',
595
595
  'ctrlOrMetaOpenTerminalLink',
596
596
  'sftpPathFollowSsh',
597
- 'sshSftpSplitView'
597
+ 'sshSftpSplitView',
598
+ 'showCmdSuggestions'
598
599
  ].map(d => this.renderToggle(d))
599
600
  }
600
601
  <div className='pd1b'>{e('terminalBackSpaceMode')}</div>
@@ -1,7 +1,9 @@
1
1
  import { auto } from 'manate/react'
2
+ import { message } from 'antd'
2
3
  import SettingCommon from './setting-common'
3
4
  import SettingTerminal from './setting-terminal'
4
5
  import SettingCol from './col'
6
+ import SettingAi from '../ai/ai-config'
5
7
  import SyncSetting from '../setting-sync/setting-sync'
6
8
  import Shortcuts from '../shortcuts/shortcuts'
7
9
  import List from './list'
@@ -9,8 +11,10 @@ import {
9
11
  settingMap,
10
12
  settingSyncId,
11
13
  settingTerminalId,
14
+ settingAiId,
12
15
  settingShortcutsId
13
16
  } from '../../common/constants'
17
+ import { aiConfigsArr } from '../ai/ai-config-props'
14
18
  import { pick } from 'lodash-es'
15
19
 
16
20
  export default auto(function TabSettings (props) {
@@ -26,6 +30,26 @@ export default auto(function TabSettings (props) {
26
30
  store
27
31
  } = props
28
32
  let elem = null
33
+
34
+ function getInitialValues () {
35
+ const res = pick(props.store.config, aiConfigsArr)
36
+ if (!res.languageAI) {
37
+ res.languageAI = window.store.getLangName()
38
+ }
39
+ return res
40
+ }
41
+
42
+ function handleConfigSubmit (values) {
43
+ window.store.updateConfig(values)
44
+ message.success('Saved')
45
+ }
46
+
47
+ const aiConfProps = {
48
+ initialValues: getInitialValues(),
49
+ onSubmit: handleConfigSubmit,
50
+ showAIConfig: true
51
+ }
52
+
29
53
  const sid = settingItem.id
30
54
  if (sid === settingSyncId) {
31
55
  const syncProps = pick(store, [
@@ -37,6 +61,8 @@ export default auto(function TabSettings (props) {
37
61
  'syncServerStatus'
38
62
  ])
39
63
  elem = <SyncSetting {...syncProps} />
64
+ } else if (sid === settingAiId) {
65
+ elem = <SettingAi {...aiConfProps} />
40
66
  } else if (sid === settingTerminalId) {
41
67
  elem = <SettingTerminal {...listProps} config={store.config} />
42
68
  } else if (sid === settingShortcutsId) {
@@ -15,6 +15,7 @@ import {
15
15
  } from '../../common/constants'
16
16
  import classnames from 'classnames'
17
17
  import AddrBookmark from './address-bookmark'
18
+ import KeywordFilter from './keyword-filter'
18
19
 
19
20
  const e = window.translate
20
21
 
@@ -26,8 +27,13 @@ function renderAddonBefore (props, realPath) {
26
27
  const isShow = props[`${type}ShowHiddenFile`]
27
28
  const title = `${isShow ? e('hide') : e('show')} ${e('hfd')}`
28
29
  const Icon = isShow ? EyeFilled : EyeInvisibleFilled
30
+ const keywordProps = {
31
+ keyword: props[`${type}Keyword`],
32
+ type,
33
+ updateKeyword: props.updateKeyword
34
+ }
29
35
  return (
30
- <div>
36
+ <>
31
37
  <Tooltip
32
38
  title={title}
33
39
  placement='topLeft'
@@ -49,6 +55,7 @@ function renderAddonBefore (props, realPath) {
49
55
  className='mg1r'
50
56
  />
51
57
  </Tooltip>
58
+ <KeywordFilter {...keywordProps} />
52
59
  <AddrBookmark
53
60
  store={window.store}
54
61
  realPath={realPath}
@@ -56,7 +63,7 @@ function renderAddonBefore (props, realPath) {
56
63
  type={type}
57
64
  onClickHistory={props.onClickHistory}
58
65
  />
59
- </div>
66
+ </>
60
67
  )
61
68
  }
62
69
 
@@ -62,12 +62,10 @@ export default auto(function AddrBookmark (props) {
62
62
  </div>
63
63
  )
64
64
  const title = (
65
- <div>
66
- <PlusSquareOutlined
67
- className='add-addr-bookmark'
68
- onClick={handleAddAddr}
69
- />
70
- </div>
65
+ <PlusSquareOutlined
66
+ className='add-addr-bookmark'
67
+ onClick={handleAddAddr}
68
+ />
71
69
  )
72
70
  return (
73
71
  <Popover
@@ -336,7 +336,7 @@ export default class FileSection extends React.Component {
336
336
  const { name, path } = file
337
337
  const info = await getLocalFileInfo(
338
338
  resolve(path, name)
339
- )
339
+ ).catch(console.log)
340
340
  if (info) {
341
341
  res.push(info)
342
342
  }
@@ -43,25 +43,20 @@ export const getFolderFromFilePath = (filePath, isRemote) => {
43
43
  }
44
44
 
45
45
  export const getLocalFileInfo = async (filePath) => {
46
- try {
47
- const statr = await fs.statAsync(filePath)
48
- const stat = await fs.lstatAsync(filePath)
49
- return {
50
- size: stat.size,
51
- accessTime: stat.atime,
52
- modifyTime: stat.mtime,
53
- mode: stat.mode,
54
- owner: stat.uid,
55
- group: stat.gid,
56
- type: 'local',
57
- ...getFolderFromFilePath(filePath, false),
58
- id: generate(),
59
- isDirectory: statr.isDirectory,
60
- isSymbolicLink: stat.isSymbolicLink
61
- }
62
- } catch (e) {
63
- log.debug(e)
64
- return null
46
+ const statr = await fs.statAsync(filePath)
47
+ const stat = await fs.lstatAsync(filePath)
48
+ return {
49
+ size: stat.size,
50
+ accessTime: stat.atime,
51
+ modifyTime: stat.mtime,
52
+ mode: stat.mode,
53
+ owner: stat.uid,
54
+ group: stat.gid,
55
+ type: 'local',
56
+ ...getFolderFromFilePath(filePath, false),
57
+ id: generate(),
58
+ isDirectory: statr.isDirectory,
59
+ isSymbolicLink: stat.isSymbolicLink
65
60
  }
66
61
  }
67
62