@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
@@ -1,10 +1,11 @@
1
- import { Popconfirm } from 'antd'
2
- import { CloseOutlined } from '@ant-design/icons'
1
+ import { Popconfirm, Popover } from 'antd'
2
+ import { CloseOutlined, CopyOutlined } from '@ant-design/icons'
3
+ import { copy } from '../../common/clipboard'
3
4
 
4
5
  const e = window.translate
5
6
 
6
7
  export default function WidgetInstance ({ item }) {
7
- const { id, title } = item
8
+ const { id, title, serverInfo } = item
8
9
  const cls = 'item-list-unit'
9
10
  const delProps = {
10
11
  title: e('del'),
@@ -25,17 +26,51 @@ export default function WidgetInstance ({ item }) {
25
26
  cancelText: e('cancel'),
26
27
  placement: 'top'
27
28
  }
29
+ const handleCopy = () => {
30
+ if (serverInfo && serverInfo.url) {
31
+ copy(serverInfo.url)
32
+ }
33
+ }
34
+ const popoverContent = serverInfo
35
+ ? (
36
+ <div>
37
+ <div style={{ display: 'flex', alignItems: 'center' }}>
38
+ <span>URL: {serverInfo.url}</span>
39
+ <CopyOutlined
40
+ className='pointer mg1l'
41
+ onClick={handleCopy}
42
+ />
43
+ </div>
44
+ <div>Path: {serverInfo.path}</div>
45
+ </div>
46
+ )
47
+ : null
48
+ const titleDiv = (
49
+ <div
50
+ title={title}
51
+ className='elli pd1y pd2x list-item-title'
52
+ >
53
+ {title}
54
+ </div>
55
+ )
28
56
  return (
29
57
  <div
30
58
  key={id}
31
59
  className={cls}
32
60
  >
33
- <div
34
- title={title}
35
- className='elli pd1y pd2x list-item-title'
36
- >
37
- {title}
38
- </div>
61
+ {
62
+ serverInfo
63
+ ? (
64
+ <Popover
65
+ content={popoverContent}
66
+ trigger='hover'
67
+ placement='top'
68
+ >
69
+ {titleDiv}
70
+ </Popover>
71
+ )
72
+ : titleDiv
73
+ }
39
74
  <Popconfirm
40
75
  {...popProps}
41
76
  >
@@ -0,0 +1,34 @@
1
+ import { notification } from 'antd'
2
+ import { CopyOutlined } from '@ant-design/icons'
3
+ import { copy } from '../../common/clipboard'
4
+
5
+ export function showMsg (message, type = 'success', serverInfo = null, duration = 10, description = '') {
6
+ const handleCopy = () => {
7
+ if (serverInfo && serverInfo.url) {
8
+ copy(serverInfo.url)
9
+ }
10
+ }
11
+
12
+ let desc = description
13
+ if (serverInfo) {
14
+ desc = (
15
+ <div>
16
+ {description && <div>{description}</div>}
17
+ <div style={{ display: 'flex', alignItems: 'center' }}>
18
+ <span>URL: {serverInfo.url}</span>
19
+ <CopyOutlined
20
+ className='pointer mg1l'
21
+ onClick={handleCopy}
22
+ />
23
+ </div>
24
+ <div>Path: {serverInfo.path}</div>
25
+ </div>
26
+ )
27
+ }
28
+
29
+ notification[type]({
30
+ message,
31
+ description: desc,
32
+ duration
33
+ })
34
+ }
@@ -32,7 +32,9 @@ body
32
32
  word-break break-all
33
33
 
34
34
  a
35
- color var(--primary)
35
+ color var(--text)
36
+ &:hover
37
+ color var(--text-dark)
36
38
 
37
39
  .cap
38
40
  text-transform capitalize
@@ -75,6 +75,10 @@ export default () => {
75
75
  resolutions: ls.getItemJSON(resolutionsLsKey, []),
76
76
  terminalCommandHistory: new Set(ls.getItemJSON(cmdHistoryKey, [])),
77
77
 
78
+ // workspaces
79
+ workspaces: [],
80
+ workspaceSaveModalVisible: false,
81
+
78
82
  // init session control
79
83
  selectedSessions: [],
80
84
  sessionModalVisible: false,
@@ -115,13 +115,22 @@ export async function addTabFromCommandLine (store, opts) {
115
115
  export default (Store) => {
116
116
  Store.prototype.openInitSessions = function () {
117
117
  const { store } = window
118
- const arr = store.config.onStartSessions || []
119
- for (const s of arr) {
120
- store.onSelectBookmark(s)
121
- }
122
- if (!arr.length && store.config.initDefaultTabOnStart) {
123
- store.initFirstTab()
118
+ const onStartSessions = store.config.onStartSessions
119
+
120
+ // If onStartSessions is a string, it's a workspace ID
121
+ if (typeof onStartSessions === 'string' && onStartSessions) {
122
+ store.loadWorkspace(onStartSessions)
123
+ } else {
124
+ // Otherwise, it's an array of bookmark IDs
125
+ const arr = Array.isArray(onStartSessions) ? onStartSessions : []
126
+ for (const s of arr) {
127
+ store.onSelectBookmark(s)
128
+ }
129
+ if (!arr.length && store.config.initDefaultTabOnStart) {
130
+ store.initFirstTab()
131
+ }
124
132
  }
133
+
125
134
  store.confirmLoad()
126
135
  const { initTime, loadTime } = window.pre.runSync('getLoadTime')
127
136
  if (loadTime) {
@@ -25,6 +25,7 @@ import batchInputHistory from './batch-input-history'
25
25
  import transferExtend from './transfer-list'
26
26
  import addressBookmarkExtend from './address-bookmark'
27
27
  import widgetsExtend from './widgets'
28
+ import workspaceExtend from './workspace'
28
29
  import isColorDark from '../common/is-color-dark'
29
30
  import { getReverseColor } from '../common/reverse-color'
30
31
  import { uniq } from 'lodash-es'
@@ -297,5 +298,6 @@ batchInputHistory(Store)
297
298
  transferExtend(Store)
298
299
  addressBookmarkExtend(Store)
299
300
  widgetsExtend(Store)
301
+ workspaceExtend(Store)
300
302
 
301
303
  export const StateStore = Store
@@ -0,0 +1,108 @@
1
+ /**
2
+ * workspace related functions
3
+ */
4
+
5
+ import {
6
+ settingMap
7
+ } from '../common/constants'
8
+ import getInitItem from '../common/init-setting-item'
9
+ import generate from '../common/uid'
10
+
11
+ export default Store => {
12
+ /**
13
+ * Get current workspace state (layout + tabs for each batch)
14
+ */
15
+ Store.prototype.getCurrentWorkspaceState = function () {
16
+ const { store } = window
17
+ const { layout, tabs } = store
18
+ // Group tabs by batch and get bookmark srcIds
19
+ const tabsByBatch = {}
20
+ for (const tab of tabs) {
21
+ const batch = tab.batch || 0
22
+ if (!tabsByBatch[batch]) {
23
+ tabsByBatch[batch] = []
24
+ }
25
+ // Store srcId (bookmark id) if available, otherwise store basic connection info
26
+ if (tab.srcId) {
27
+ tabsByBatch[batch].push({
28
+ srcId: tab.srcId
29
+ })
30
+ }
31
+ }
32
+ return {
33
+ layout,
34
+ tabsByBatch
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Save current workspace
40
+ */
41
+ Store.prototype.saveWorkspace = function (name, id = null) {
42
+ const { store } = window
43
+ const state = store.getCurrentWorkspaceState()
44
+ const workspace = {
45
+ id: id || generate(),
46
+ name,
47
+ ...state,
48
+ createdAt: Date.now(),
49
+ updatedAt: Date.now()
50
+ }
51
+ if (id) {
52
+ // Update existing
53
+ store.editItem(id, workspace, settingMap.workspaces)
54
+ } else {
55
+ // Add new
56
+ store.addItem(workspace, settingMap.workspaces)
57
+ }
58
+ return workspace
59
+ }
60
+
61
+ /**
62
+ * Load a workspace - set layout and open tabs
63
+ */
64
+ Store.prototype.loadWorkspace = function (workspaceId) {
65
+ const { store } = window
66
+ const workspace = store.workspaces.find(w => w.id === workspaceId)
67
+ if (!workspace) {
68
+ return
69
+ }
70
+ const { layout, tabsByBatch } = workspace
71
+
72
+ // Close all existing tabs first
73
+ store.removeTabs(() => true)
74
+
75
+ // Set layout
76
+ store.setLayout(layout)
77
+ // Open tabs for each batch
78
+ for (const [batchStr, tabInfos] of Object.entries(tabsByBatch)) {
79
+ const batch = parseInt(batchStr, 10)
80
+ for (const tabInfo of tabInfos) {
81
+ if (tabInfo.srcId) {
82
+ // Open from bookmark
83
+ window.openTabBatch = batch
84
+ store.onSelectBookmark(tabInfo.srcId)
85
+ }
86
+ }
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Delete a workspace
92
+ */
93
+ Store.prototype.deleteWorkspace = function (id) {
94
+ window.store.delItem({ id }, settingMap.workspaces)
95
+ }
96
+
97
+ /**
98
+ * Open workspace settings
99
+ */
100
+ Store.prototype.openWorkspaceSettings = function () {
101
+ const { store } = window
102
+ store.storeAssign({
103
+ settingTab: settingMap.workspaces
104
+ })
105
+ store.setSettingItem(getInitItem([], settingMap.workspaces))
106
+ store.openSettingModal()
107
+ }
108
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electerm/electerm-react",
3
- "version": "2.3.136",
3
+ "version": "2.3.166",
4
4
  "description": "react components src for electerm",
5
5
  "main": "./client/components/main/main.jsx",
6
6
  "license": "MIT",