@electerm/electerm-react 2.3.136 → 2.3.166

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/client/common/constants.js +4 -2
  2. package/client/common/db.js +2 -1
  3. package/client/common/init-setting-item.js +7 -0
  4. package/client/components/batch-op/batch-op.jsx +3 -8
  5. package/client/components/bookmark-form/common/color-picker.jsx +16 -5
  6. package/client/components/bookmark-form/common/color-picker.styl +1 -2
  7. package/client/components/bookmark-form/common/connection-hopping.jsx +1 -0
  8. package/client/components/bookmark-form/config/common-fields.js +1 -0
  9. package/client/components/common/drawer.jsx +62 -0
  10. package/client/components/common/drawer.styl +34 -0
  11. package/client/components/common/modal.jsx +89 -0
  12. package/client/components/common/modal.styl +77 -0
  13. package/client/components/common/notification-with-details.jsx +34 -0
  14. package/client/components/file-transfer/conflict-resolve.jsx +2 -1
  15. package/client/components/file-transfer/transfer-speed-format.js +6 -0
  16. package/client/components/file-transfer/transfer.jsx +5 -2
  17. package/client/components/file-transfer/transports-action-store.jsx +14 -1
  18. package/client/components/main/main.jsx +2 -0
  19. package/client/components/profile/profile-form.jsx +1 -1
  20. package/client/components/quick-commands/qm.styl +2 -1
  21. package/client/components/quick-commands/quick-commands-form.jsx +1 -1
  22. package/client/components/setting-panel/list.jsx +1 -1
  23. package/client/components/setting-panel/setting-common.jsx +5 -4
  24. package/client/components/setting-panel/setting-terminal.jsx +1 -1
  25. package/client/components/setting-panel/setting-wrap.jsx +4 -10
  26. package/client/components/setting-panel/setting-wrap.styl +8 -6
  27. package/client/components/setting-panel/start-session-select.jsx +146 -21
  28. package/client/components/setting-panel/text-bg-modal.jsx +15 -4
  29. package/client/components/sftp/file-info-modal.jsx +2 -1
  30. package/client/components/sftp/file-item.jsx +2 -0
  31. package/client/components/sftp/paged-list.jsx +2 -1
  32. package/client/components/sftp/sftp-entry.jsx +1 -1
  33. package/client/components/sftp/sftp.styl +13 -0
  34. package/client/components/sidebar/info-modal.jsx +53 -34
  35. package/client/components/sidebar/info.styl +0 -7
  36. package/client/components/tabs/index.jsx +6 -58
  37. package/client/components/tabs/layout-menu.jsx +75 -0
  38. package/client/components/tabs/layout-select.jsx +60 -0
  39. package/client/components/tabs/tabs.styl +64 -0
  40. package/client/components/tabs/workspace-save-modal.jsx +117 -0
  41. package/client/components/tabs/workspace-select.jsx +79 -0
  42. package/client/components/terminal/attach-addon-custom.js +7 -1
  43. package/client/components/terminal/terminal-interactive.jsx +2 -1
  44. package/client/components/terminal/terminal.jsx +0 -1
  45. package/client/components/text-editor/text-editor.jsx +2 -1
  46. package/client/components/tree-list/move-item-modal.jsx +115 -30
  47. package/client/components/tree-list/tree-list.jsx +1 -1
  48. package/client/components/tree-list/tree-list.styl +6 -1
  49. package/client/components/vnc/vnc-session.jsx +2 -2
  50. package/client/components/widgets/widget-control.jsx +4 -5
  51. package/client/components/widgets/widget-form.jsx +3 -8
  52. package/client/components/widgets/widget-instance.jsx +44 -9
  53. package/client/components/widgets/widget-notification-with-details.jsx +34 -0
  54. package/client/css/basic.styl +3 -1
  55. package/client/store/init-state.js +4 -0
  56. package/client/store/load-data.js +15 -6
  57. package/client/store/store.js +2 -0
  58. package/client/store/workspace.js +108 -0
  59. package/package.json +1 -1
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Layout select content component
3
+ */
4
+
5
+ import React from 'react'
6
+ import {
7
+ SingleIcon,
8
+ TwoColumnsIcon,
9
+ ThreeColumnsIcon,
10
+ TwoRowsIcon,
11
+ ThreeRowsIcon,
12
+ Grid2x2Icon,
13
+ TwoRowsRightIcon,
14
+ TwoColumnsBottomIcon
15
+ } from '../icons/split-icons'
16
+ import { splitMapDesc } from '../../common/constants'
17
+
18
+ const e = window.translate
19
+
20
+ const iconMaps = {
21
+ single: SingleIcon,
22
+ twoColumns: TwoColumnsIcon,
23
+ threeColumns: ThreeColumnsIcon,
24
+ twoRows: TwoRowsIcon,
25
+ threeRows: ThreeRowsIcon,
26
+ grid2x2: Grid2x2Icon,
27
+ twoRowsRight: TwoRowsRightIcon,
28
+ twoColumnsBottom: TwoColumnsBottomIcon
29
+ }
30
+
31
+ export function getLayoutIcon (layout) {
32
+ return iconMaps[layout]
33
+ }
34
+
35
+ export default function LayoutSelect (props) {
36
+ const { layout } = props
37
+
38
+ function handleChangeLayout (key) {
39
+ window.store.setLayout(key)
40
+ }
41
+
42
+ return (
43
+ <div className='layout-menu-content'>
44
+ {Object.keys(splitMapDesc).map((t) => {
45
+ const v = splitMapDesc[t]
46
+ const Icon = getLayoutIcon(v)
47
+ const isActive = layout === t
48
+ return (
49
+ <div
50
+ key={t}
51
+ className={`layout-menu-item ${isActive ? 'active' : ''}`}
52
+ onClick={() => handleChangeLayout(t)}
53
+ >
54
+ <Icon /> {e(v)}
55
+ </div>
56
+ )
57
+ })}
58
+ </div>
59
+ )
60
+ }
@@ -244,3 +244,67 @@
244
244
  max-height 300px
245
245
  overflow-y auto
246
246
 
247
+ // Layout and Workspace dropdown styles
248
+ .layout-workspace-dropdown
249
+ background var(--main)
250
+ border-radius 4px
251
+ box-shadow 0 2px 8px rgba(0, 0, 0, 0.15)
252
+ min-width 200px
253
+ padding 8px
254
+ .ant-tabs-nav
255
+ margin-bottom 8px
256
+
257
+ .layout-menu-content
258
+ max-height 300px
259
+ overflow-y auto
260
+
261
+ .layout-menu-item
262
+ padding 6px 12px
263
+ cursor pointer
264
+ border-radius 4px
265
+ display flex
266
+ align-items center
267
+ gap 8px
268
+ color var(--text)
269
+ &:hover
270
+ background var(--main-dark)
271
+ &.active
272
+ background var(--primary)
273
+ color #fff
274
+
275
+ .workspace-menu-content
276
+ max-height 300px
277
+ overflow-y auto
278
+
279
+ .workspace-save-btn
280
+ margin-bottom 8px
281
+
282
+ .workspace-list
283
+ display flex
284
+ flex-direction column
285
+ gap 4px
286
+
287
+ .workspace-item
288
+ padding 6px 12px
289
+ cursor pointer
290
+ border-radius 4px
291
+ display flex
292
+ align-items center
293
+ justify-content space-between
294
+ color var(--text)
295
+ &:hover
296
+ background var(--main-dark)
297
+ .workspace-delete-icon
298
+ opacity 0
299
+ color var(--text-dark)
300
+ &:hover
301
+ color var(--error)
302
+ &:hover .workspace-delete-icon
303
+ opacity 1
304
+
305
+ .workspace-name
306
+ flex 1
307
+ overflow hidden
308
+ text-overflow ellipsis
309
+ white-space nowrap
310
+
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Workspace save modal component - standalone modal
3
+ */
4
+
5
+ import React, { useState } from 'react'
6
+ import { auto } from 'manate/react'
7
+ import Modal from '../common/modal'
8
+ import { Input, Select, Button, Space, message, Radio } from 'antd'
9
+ import { SaveOutlined, EditOutlined } from '@ant-design/icons'
10
+
11
+ const e = window.translate
12
+
13
+ export default auto(function WorkspaceSaveModal ({ store }) {
14
+ const { workspaceSaveModalVisible, workspaces } = store
15
+ const [name, setName] = useState('')
16
+ const [selectedId, setSelectedId] = useState(null)
17
+ const [saveMode, setSaveMode] = useState('new') // 'new' or 'overwrite'
18
+
19
+ if (!workspaceSaveModalVisible) {
20
+ return null
21
+ }
22
+
23
+ function handleClose () {
24
+ window.store.workspaceSaveModalVisible = false
25
+ }
26
+
27
+ function handleSave () {
28
+ if (saveMode === 'new') {
29
+ if (!name.trim()) {
30
+ message.error(e('name needed'))
31
+ return
32
+ }
33
+ window.store.saveWorkspace(name.trim())
34
+ message.success(e('saved'))
35
+ } else {
36
+ if (!selectedId) {
37
+ message.error('please Select Workspace')
38
+ return
39
+ }
40
+ const ws = workspaces.find(w => w.id === selectedId)
41
+ window.store.saveWorkspace(ws?.name || name, selectedId)
42
+ message.success(e('saved'))
43
+ }
44
+ setName('')
45
+ setSelectedId(null)
46
+ setSaveMode('new')
47
+ handleClose()
48
+ }
49
+
50
+ function handleCancel () {
51
+ setName('')
52
+ setSelectedId(null)
53
+ setSaveMode('new')
54
+ handleClose()
55
+ }
56
+
57
+ const options = workspaces.map(w => ({
58
+ label: w.name,
59
+ value: w.id
60
+ }))
61
+
62
+ return (
63
+ <Modal
64
+ title={e('save')}
65
+ open={workspaceSaveModalVisible}
66
+ onCancel={handleCancel}
67
+ footer={null}
68
+ width={400}
69
+ >
70
+ <div className='pd1y'>
71
+ <Space direction='vertical' block>
72
+ <Radio.Group
73
+ value={saveMode}
74
+ onChange={ev => setSaveMode(ev.target.value)}
75
+ >
76
+ <Radio value='new'>
77
+ <SaveOutlined className='mg1r' />
78
+ {e('saveAsNew')}
79
+ </Radio>
80
+ <Radio value='overwrite' disabled={!workspaces.length}>
81
+ <EditOutlined className='mg1r' />
82
+ {e('overwrite')}
83
+ </Radio>
84
+ </Radio.Group>
85
+
86
+ {saveMode === 'new'
87
+ ? (
88
+ <Input
89
+ placeholder={e('name')}
90
+ value={name}
91
+ onChange={e => setName(e.target.value)}
92
+ onPressEnter={handleSave}
93
+ />
94
+ )
95
+ : (
96
+ <Select
97
+ placeholder={e('workspaces')}
98
+ value={selectedId}
99
+ onChange={setSelectedId}
100
+ options={options}
101
+ style={{ width: '100%' }}
102
+ />
103
+ )}
104
+
105
+ <div className='pd1t'>
106
+ <Button type='primary' onClick={handleSave}>
107
+ {e('save')}
108
+ </Button>
109
+ <Button className='mg1l' onClick={handleCancel}>
110
+ {e('cancel')}
111
+ </Button>
112
+ </div>
113
+ </Space>
114
+ </div>
115
+ </Modal>
116
+ )
117
+ })
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Workspace select content component
3
+ */
4
+
5
+ import React from 'react'
6
+ import { Button, Empty, Popconfirm } from 'antd'
7
+ import {
8
+ SaveOutlined,
9
+ DeleteOutlined
10
+ } from '@ant-design/icons'
11
+ import { auto } from 'manate/react'
12
+
13
+ const e = window.translate
14
+
15
+ export default auto(function WorkspaceSelect (props) {
16
+ const { store } = props
17
+ const { workspaces } = store
18
+
19
+ function handleLoadWorkspace (id) {
20
+ window.store.loadWorkspace(id)
21
+ }
22
+
23
+ function handleDeleteWorkspace (id, ev) {
24
+ ev.stopPropagation()
25
+ window.store.deleteWorkspace(id)
26
+ }
27
+
28
+ function handleSaveClick () {
29
+ window.store.workspaceSaveModalVisible = true
30
+ }
31
+
32
+ return (
33
+ <div className='workspace-menu-content'>
34
+ <div className='workspace-save-btn pd1b'>
35
+ <Button
36
+ type='primary'
37
+ icon={<SaveOutlined />}
38
+ size='small'
39
+ onClick={handleSaveClick}
40
+ block
41
+ >
42
+ {e('save')}
43
+ </Button>
44
+ </div>
45
+ {workspaces.length === 0
46
+ ? (
47
+ <Empty
48
+ image={Empty.PRESENTED_IMAGE_SIMPLE}
49
+ description='No items'
50
+ />
51
+ )
52
+ : (
53
+ <div className='workspace-list'>
54
+ {workspaces.map(ws => (
55
+ <div
56
+ key={ws.id}
57
+ className='workspace-item'
58
+ onClick={() => handleLoadWorkspace(ws.id)}
59
+ >
60
+ <span className='workspace-name'>{ws.name}</span>
61
+ <Popconfirm
62
+ title={e('del') + '?'}
63
+ onConfirm={(ev) => handleDeleteWorkspace(ws.id, ev)}
64
+ onCancel={(ev) => ev.stopPropagation()}
65
+ okText={e('ok')}
66
+ cancelText={e('cancel')}
67
+ >
68
+ <DeleteOutlined
69
+ className='workspace-delete-icon'
70
+ onClick={(ev) => ev.stopPropagation()}
71
+ />
72
+ </Popconfirm>
73
+ </div>
74
+ ))}
75
+ </div>
76
+ )}
77
+ </div>
78
+ )
79
+ })
@@ -34,7 +34,13 @@ export default class AttachAddonCustom extends AttachAddon {
34
34
  }
35
35
 
36
36
  onMsg = (ev) => {
37
- this.trzsz.processServerOutput(ev.data)
37
+ // When in alternate screen mode (like vim, less, or TUI apps like Claude Code),
38
+ // bypass trzsz processing to avoid interference with the application's display
39
+ if (this.term?.buffer?.active?.type === 'alternate') {
40
+ this.writeToTerminal(ev.data)
41
+ } else {
42
+ this.trzsz.processServerOutput(ev.data)
43
+ }
38
44
  }
39
45
 
40
46
  writeToTerminal = (data) => {
@@ -3,7 +3,8 @@
3
3
  */
4
4
 
5
5
  import { useEffect, useState } from 'react'
6
- import { Modal, Form, Button } from 'antd'
6
+ import { Form, Button } from 'antd'
7
+ import Modal from '../common/modal'
7
8
  import InputAutoFocus from '../common/input-auto-focus'
8
9
  import wait from '../../common/wait'
9
10
 
@@ -178,7 +178,6 @@ class Term extends Component {
178
178
  clearTimeout(this.timers[k])
179
179
  this.timers[k] = null
180
180
  })
181
- this.timers = null
182
181
  this.onClose = true
183
182
  if (this.socket) {
184
183
  this.socket.close()
@@ -4,7 +4,8 @@
4
4
 
5
5
  import { PureComponent } from 'react'
6
6
  import TextEditorForm from './text-editor-form'
7
- import { Spin, Modal } from 'antd'
7
+ import { Spin } from 'antd'
8
+ import Modal from '../common/modal'
8
9
  import resolve from '../../common/resolve'
9
10
  import { refsStatic, refs } from '../common/ref'
10
11
 
@@ -1,17 +1,63 @@
1
- // render bookmark select, use antd tree select
1
+ // render bookmark select, use antd tree
2
2
  import { useState, useEffect } from 'react'
3
3
  import {
4
- MergeOutlined
4
+ MergeOutlined,
5
+ SearchOutlined
5
6
  } from '@ant-design/icons'
6
7
  import buildGroupData from '../bookmark-form/common/bookmark-group-tree-format'
7
- import { TreeSelect, Modal, Button } from 'antd'
8
+ import { Tree, Button, Input } from 'antd'
9
+ import Modal from '../common/modal'
8
10
  import { auto } from 'manate/react'
9
11
  const e = window.translate
10
12
 
11
13
  const rootId = '__root__'
12
14
 
15
+ // Helper function to filter tree data based on search text
16
+ function filterTreeData (data, searchText) {
17
+ if (!searchText) {
18
+ return data
19
+ }
20
+ const lowerSearch = searchText.toLowerCase()
21
+
22
+ function filterNodes (nodes) {
23
+ return nodes.reduce((acc, node) => {
24
+ const titleText = typeof node.title === 'string'
25
+ ? node.title
26
+ : (node.title?.props?.children?.[1] || node.title?.props?.children || '')
27
+ const titleStr = String(titleText).toLowerCase()
28
+ const children = node.children ? filterNodes(node.children) : []
29
+
30
+ if (titleStr.includes(lowerSearch) || children.length > 0) {
31
+ acc.push({
32
+ ...node,
33
+ children: children.length > 0 ? children : node.children
34
+ })
35
+ }
36
+ return acc
37
+ }, [])
38
+ }
39
+
40
+ return filterNodes(data)
41
+ }
42
+
43
+ // Helper function to get all keys from tree data
44
+ function getAllKeys (data) {
45
+ const keys = []
46
+ function traverse (nodes) {
47
+ for (const node of nodes) {
48
+ keys.push(node.key)
49
+ if (node.children) {
50
+ traverse(node.children)
51
+ }
52
+ }
53
+ }
54
+ traverse(data)
55
+ return keys
56
+ }
57
+
13
58
  export default auto(function MoveItemModal (props) {
14
59
  const [groupId, setGroupId] = useState(undefined)
60
+ const [searchText, setSearchText] = useState('')
15
61
  const {
16
62
  openMoveModal,
17
63
  moveItem,
@@ -27,10 +73,11 @@ export default auto(function MoveItemModal (props) {
27
73
  })
28
74
  }
29
75
 
30
- // Reset groupId when modal opens
76
+ // Reset groupId and search when modal opens
31
77
  useEffect(() => {
32
78
  if (openMoveModal) {
33
79
  setGroupId(undefined)
80
+ setSearchText('')
34
81
  }
35
82
  }, [openMoveModal])
36
83
 
@@ -60,6 +107,31 @@ export default auto(function MoveItemModal (props) {
60
107
  disabled: false
61
108
  })
62
109
  }
110
+
111
+ // Filter tree data based on search
112
+ const filteredData = filterTreeData(data, searchText)
113
+ const expandedKeys = getAllKeys(filteredData)
114
+
115
+ function onTreeSelect (selectedKeys) {
116
+ if (selectedKeys.length > 0) {
117
+ // Find the node to check if it's disabled
118
+ const findNode = (nodes, key) => {
119
+ for (const node of nodes) {
120
+ if (node.key === key) return node
121
+ if (node.children) {
122
+ const found = findNode(node.children, key)
123
+ if (found) return found
124
+ }
125
+ }
126
+ return null
127
+ }
128
+ const node = findNode(data, selectedKeys[0])
129
+ if (node && !node.disabled) {
130
+ setGroupId(selectedKeys[0])
131
+ }
132
+ }
133
+ }
134
+
63
135
  function onSelect () {
64
136
  const {
65
137
  bookmarkGroups
@@ -109,43 +181,56 @@ export default auto(function MoveItemModal (props) {
109
181
  }
110
182
  onCancelMoveItem()
111
183
  }
184
+
185
+ const footer = (
186
+ <>
187
+ <Button
188
+ type='primary'
189
+ onClick={onSelect}
190
+ disabled={!groupId}
191
+ >
192
+ {e('ok')}
193
+ </Button>
194
+ <Button
195
+ onClick={onCancelMoveItem}
196
+ className='mg1l'
197
+ >
198
+ {e('cancel')}
199
+ </Button>
200
+ </>
201
+ )
202
+
112
203
  const modalProps = {
113
204
  open: openMoveModal,
114
205
  title: e('moveTo'),
115
- footer: null,
206
+ footer,
116
207
  onCancel: onCancelMoveItem
117
208
  }
209
+
118
210
  const treeProps = {
119
- treeData: data,
120
- onChange: setGroupId,
121
- placeholder: e('moveTo'),
122
- showSearch: true,
123
- value: groupId,
124
- popupMatchSelectWidth: false,
125
- treeDefaultExpandAll: true,
126
- className: 'width-100'
211
+ treeData: filteredData,
212
+ onSelect: onTreeSelect,
213
+ selectedKeys: groupId ? [groupId] : [],
214
+ expandedKeys,
215
+ autoExpandParent: true,
216
+ className: 'width-100 move-item-tree'
127
217
  }
218
+
128
219
  return (
129
220
  <Modal {...modalProps}>
130
- <div className='pd1'>
131
- <TreeSelect
132
- {...treeProps}
221
+ <div className='pd1b'>
222
+ <Input
223
+ placeholder={e('search')}
224
+ prefix={<SearchOutlined />}
225
+ value={searchText}
226
+ onChange={e => setSearchText(e.target.value)}
227
+ allowClear
133
228
  />
134
229
  </div>
135
- <div className='pd1'>
136
- <Button
137
- type='primary'
138
- onClick={onSelect}
139
- disabled={!groupId}
140
- >
141
- {e('ok')}
142
- </Button>
143
- <Button
144
- onClick={onCancelMoveItem}
145
- className='mg1l'
146
- >
147
- {e('cancel')}
148
- </Button>
230
+ <div className='move-item-tree-wrap'>
231
+ <Tree
232
+ {...treeProps}
233
+ />
149
234
  </div>
150
235
  </Modal>
151
236
  )
@@ -55,7 +55,7 @@ export default class ItemListTree extends Component {
55
55
  this.setState({
56
56
  ready: true
57
57
  })
58
- }, 100)
58
+ }, 0)
59
59
  }
60
60
 
61
61
  componentWillUnmount () {
@@ -78,4 +78,9 @@
78
78
  margin-right 6px
79
79
  border-radius 2px
80
80
  border 1px solid #1a1a1a
81
- vertical-align middle
81
+ vertical-align middle
82
+
83
+ .move-item-tree-wrap
84
+ max-height 300px
85
+ overflow-y auto
86
+ padding 8px
@@ -10,9 +10,9 @@ import {
10
10
  import {
11
11
  Spin,
12
12
  message,
13
- Modal,
14
13
  Tag
15
14
  } from 'antd'
15
+ import Modal from '../common/modal'
16
16
  import * as ls from '../../common/safe-local-storage'
17
17
  import { copy } from '../../common/clipboard'
18
18
  import resolutions from '../rdp/resolutions'
@@ -250,7 +250,7 @@ export default class VncSession extends RdpSession {
250
250
  title: e('credentialsRequired'),
251
251
  content: this.renderForm(['password']),
252
252
  footer: null,
253
- visible: true
253
+ open: true
254
254
  }
255
255
  return (
256
256
  <Modal
@@ -3,9 +3,7 @@
3
3
  */
4
4
  import React, { useState } from 'react'
5
5
  import WidgetForm from './widget-form'
6
- import {
7
- message
8
- } from 'antd'
6
+ import { showMsg } from './widget-notification-with-details'
9
7
 
10
8
  export default function WidgetControl ({ formData }) {
11
9
  const [loading, setLoading] = useState(false)
@@ -30,9 +28,9 @@ export default function WidgetControl ({ formData }) {
30
28
  } = result
31
29
  if (!instanceId) {
32
30
  if (success === false) {
33
- message.error('Failed to run widget', error || '')
31
+ showMsg('Failed to run widget', 'error', null, 10, error || '')
34
32
  } else {
35
- message.success(msg || 'Widget run successfully')
33
+ showMsg(msg, 'success', null, 10)
36
34
  }
37
35
  return
38
36
  }
@@ -45,6 +43,7 @@ export default function WidgetControl ({ formData }) {
45
43
  config
46
44
  }
47
45
  window.store.widgetInstances.push(instance)
46
+ showMsg(msg, 'success', result.serverInfo, 10)
48
47
  } catch (err) {
49
48
  console.error('Failed to run widget:', err)
50
49
  } finally {
@@ -2,7 +2,7 @@
2
2
  * Widget form component
3
3
  */
4
4
  import React from 'react'
5
- import { Form, Input, InputNumber, Switch, Select, Button, message } from 'antd'
5
+ import { Form, Input, InputNumber, Switch, Select, Button } from 'antd'
6
6
  import { formItemLayout, tailFormItemLayout } from '../../common/form-layout'
7
7
 
8
8
  export default function WidgetForm ({ widget, onSubmit, loading }) {
@@ -18,12 +18,7 @@ export default function WidgetForm ({ widget, onSubmit, loading }) {
18
18
  const txt = isInstanceWidget ? 'Start widget' : 'Run widget'
19
19
 
20
20
  const handleSubmit = async (values) => {
21
- try {
22
- await onSubmit(values)
23
- message.success('Widget started successfully')
24
- } catch (error) {
25
- message.error('Failed to start widget: ' + error.message)
26
- }
21
+ onSubmit(values)
27
22
  }
28
23
 
29
24
  const renderFormItem = (config) => {
@@ -86,7 +81,7 @@ export default function WidgetForm ({ widget, onSubmit, loading }) {
86
81
 
87
82
  return (
88
83
  <div className='widget-form'>
89
- <div className='pd1b'>
84
+ <div className='pd1b alignright'>
90
85
  <h4>{info.name}</h4>
91
86
  <p>{info.description}</p>
92
87
  </div>