@electerm/electerm-react 3.0.18 → 3.1.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.
- package/client/common/constants.js +4 -4
- package/client/common/db.js +20 -10
- package/client/components/file-transfer/conflict-resolve.jsx +38 -4
- package/client/components/file-transfer/transfer-queue.jsx +10 -4
- package/client/components/file-transfer/transfer.jsx +7 -4
- package/client/components/file-transfer/transports-action-store.jsx +14 -2
- package/client/components/footer/cmd-history.jsx +2 -4
- package/client/components/quick-commands/qm.styl +8 -0
- package/client/components/quick-commands/quick-command-item.jsx +4 -0
- package/client/components/quick-commands/quick-commands-box.jsx +10 -0
- package/client/components/quick-commands/quick-commands-form-elem.jsx +1 -1
- package/client/components/quick-commands/quick-commands-list-form.jsx +59 -4
- package/client/components/quick-commands/quick-commands-list.jsx +33 -3
- package/client/components/setting-panel/list.styl +5 -1
- package/client/components/setting-sync/server-data-status.jsx +2 -1
- package/client/components/setting-sync/setting-sync-form.jsx +93 -15
- package/client/components/setting-sync/setting-sync.jsx +5 -1
- package/client/components/sidebar/transfer-history-modal.jsx +2 -2
- package/client/components/tabs/tabs.styl +1 -0
- package/client/components/tabs/window-control.jsx +2 -0
- package/client/components/terminal/terminal-command-dropdown.jsx +1 -1
- package/client/components/terminal/terminal.jsx +14 -1
- package/client/components/terminal/transfer-client-base.js +38 -17
- package/client/components/terminal-info/network.jsx +0 -1
- package/client/components/tree-list/tree-list-item.jsx +5 -0
- package/client/components/tree-list/tree-list.jsx +17 -4
- package/client/components/tree-list/tree-list.styl +1 -1
- package/client/store/common.js +15 -15
- package/client/store/init-state.js +6 -31
- package/client/store/mcp-handler.js +315 -129
- package/client/store/store.js +1 -1
- package/client/store/sync.js +129 -3
- package/client/store/transfer-list.js +3 -2
- package/client/store/watch.js +1 -25
- package/package.json +1 -1
package/client/store/sync.js
CHANGED
|
@@ -67,6 +67,13 @@ export default (Store) => {
|
|
|
67
67
|
}
|
|
68
68
|
).join('####')
|
|
69
69
|
}
|
|
70
|
+
if (type === syncTypes.webdav) {
|
|
71
|
+
// WebDAV token format: serverUrl####username####password
|
|
72
|
+
const serverUrl = get(window.store.config, 'syncSetting.webdavServerUrl')
|
|
73
|
+
const username = get(window.store.config, 'syncSetting.webdavUsername')
|
|
74
|
+
const password = get(window.store.config, 'syncSetting.webdavPassword')
|
|
75
|
+
return [serverUrl, username, password].join('####')
|
|
76
|
+
}
|
|
70
77
|
return get(window.store.config, 'syncSetting.' + type + 'AccessToken')
|
|
71
78
|
}
|
|
72
79
|
|
|
@@ -158,7 +165,13 @@ export default (Store) => {
|
|
|
158
165
|
const types = Object.keys(syncTypes)
|
|
159
166
|
for (const type of types) {
|
|
160
167
|
const gistId = store.getSyncGistId(type)
|
|
161
|
-
if
|
|
168
|
+
// For WebDAV, check if server URL is configured
|
|
169
|
+
if (type === syncTypes.webdav) {
|
|
170
|
+
const serverUrl = get(window.store.config, 'syncSetting.webdavServerUrl')
|
|
171
|
+
if (serverUrl) {
|
|
172
|
+
await store.uploadSetting(type)
|
|
173
|
+
}
|
|
174
|
+
} else if (gistId) {
|
|
162
175
|
await store.uploadSetting(type)
|
|
163
176
|
}
|
|
164
177
|
}
|
|
@@ -183,6 +196,24 @@ export default (Store) => {
|
|
|
183
196
|
const { store } = window
|
|
184
197
|
const token = store.getSyncToken(type)
|
|
185
198
|
const gistId = store.getSyncGistId(type)
|
|
199
|
+
|
|
200
|
+
// Handle WebDAV preview differently
|
|
201
|
+
if (type === syncTypes.webdav) {
|
|
202
|
+
const gist = await fetchData(
|
|
203
|
+
type,
|
|
204
|
+
'download',
|
|
205
|
+
[],
|
|
206
|
+
token,
|
|
207
|
+
store.getSyncProxy(type)
|
|
208
|
+
)
|
|
209
|
+
if (gist && gist.files) {
|
|
210
|
+
const statusContent = get(gist, 'files["electerm-status.json"].content')
|
|
211
|
+
const status = statusContent ? parseJsonSafe(statusContent) : undefined
|
|
212
|
+
store.syncServerStatus[type] = status
|
|
213
|
+
}
|
|
214
|
+
return
|
|
215
|
+
}
|
|
216
|
+
|
|
186
217
|
const gist = await fetchData(
|
|
187
218
|
type,
|
|
188
219
|
'getOne',
|
|
@@ -201,7 +232,7 @@ export default (Store) => {
|
|
|
201
232
|
// await store.createGist(type)
|
|
202
233
|
// gistId = store.getSyncGistId(type)
|
|
203
234
|
// }
|
|
204
|
-
if (!gistId && type !== syncTypes.custom && type !== syncTypes.cloud) {
|
|
235
|
+
if (!gistId && type !== syncTypes.custom && type !== syncTypes.cloud && type !== syncTypes.webdav) {
|
|
205
236
|
return
|
|
206
237
|
}
|
|
207
238
|
const pass = store.getSyncPassword(type)
|
|
@@ -244,6 +275,31 @@ export default (Store) => {
|
|
|
244
275
|
electermVersion: packVer,
|
|
245
276
|
deviceName: window.pre.osInfo().find(r => r.k === 'hostname')?.v || 'unknown'
|
|
246
277
|
}
|
|
278
|
+
|
|
279
|
+
// Handle WebDAV upload differently
|
|
280
|
+
if (type === syncTypes.webdav) {
|
|
281
|
+
const uploadData = {}
|
|
282
|
+
for (const [key, value] of Object.entries(objs)) {
|
|
283
|
+
uploadData[key] = value.content
|
|
284
|
+
}
|
|
285
|
+
uploadData['electerm-status.json'] = JSON.stringify(status)
|
|
286
|
+
|
|
287
|
+
const res = await fetchData(
|
|
288
|
+
type,
|
|
289
|
+
'upload',
|
|
290
|
+
[uploadData],
|
|
291
|
+
token,
|
|
292
|
+
store.getSyncProxy(type)
|
|
293
|
+
)
|
|
294
|
+
if (res && !res.error) {
|
|
295
|
+
store.updateSyncSetting({
|
|
296
|
+
[type + 'LastSyncTime']: now
|
|
297
|
+
})
|
|
298
|
+
store.syncServerStatus[type] = status
|
|
299
|
+
}
|
|
300
|
+
return
|
|
301
|
+
}
|
|
302
|
+
|
|
247
303
|
const gistData = {
|
|
248
304
|
description: 'sync electerm data',
|
|
249
305
|
files: {
|
|
@@ -285,10 +341,80 @@ export default (Store) => {
|
|
|
285
341
|
// await store.createGist(type)
|
|
286
342
|
// gistId = store.getSyncGistId(type)
|
|
287
343
|
// }
|
|
288
|
-
if (!gistId && type !== syncTypes.custom && type !== syncTypes.cloud) {
|
|
344
|
+
if (!gistId && type !== syncTypes.custom && type !== syncTypes.cloud && type !== syncTypes.webdav) {
|
|
289
345
|
return
|
|
290
346
|
}
|
|
291
347
|
const pass = store.getSyncPassword(type)
|
|
348
|
+
|
|
349
|
+
// Handle WebDAV download differently
|
|
350
|
+
if (type === syncTypes.webdav) {
|
|
351
|
+
const gist = await fetchData(
|
|
352
|
+
type,
|
|
353
|
+
'download',
|
|
354
|
+
[],
|
|
355
|
+
token,
|
|
356
|
+
store.getSyncProxy(type)
|
|
357
|
+
)
|
|
358
|
+
if (gist && gist.files) {
|
|
359
|
+
const statusContent = get(gist, 'files["electerm-status.json"].content')
|
|
360
|
+
const status = statusContent ? parseJsonSafe(statusContent) : undefined
|
|
361
|
+
store.syncServerStatus[type] = status
|
|
362
|
+
|
|
363
|
+
const { names, syncConfig } = store.getDataSyncNames()
|
|
364
|
+
for (const n of names) {
|
|
365
|
+
let str = get(gist, `files["${n}.json"].content`)
|
|
366
|
+
if (!str) {
|
|
367
|
+
if (n === settingMap.bookmarks) {
|
|
368
|
+
throw new Error(('Seems you have a empty WebDAV folder, you can try upload first'))
|
|
369
|
+
} else {
|
|
370
|
+
continue
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
if (!isJSON(str)) {
|
|
374
|
+
str = await window.pre.runGlobalAsync('decryptAsync', str, pass)
|
|
375
|
+
}
|
|
376
|
+
let arr = JSON.parse(str)
|
|
377
|
+
if (n === settingMap.terminalThemes) {
|
|
378
|
+
arr = store.fixThemes(arr)
|
|
379
|
+
} else if (n === settingMap.bookmarks) {
|
|
380
|
+
arr = fixBookmarks(arr)
|
|
381
|
+
}
|
|
382
|
+
let strOrder = get(gist, `files["${n}.order.json"].content`)
|
|
383
|
+
if (isJSON(strOrder)) {
|
|
384
|
+
strOrder = JSON.parse(strOrder)
|
|
385
|
+
arr.sort((a, b) => {
|
|
386
|
+
const ai = strOrder.findIndex(r => r === a.id)
|
|
387
|
+
const bi = strOrder.findIndex(r => r === b.id)
|
|
388
|
+
return ai - bi
|
|
389
|
+
})
|
|
390
|
+
}
|
|
391
|
+
store.setItems(n, arr)
|
|
392
|
+
}
|
|
393
|
+
if (syncConfig) {
|
|
394
|
+
const userConfig = parseJsonSafe(
|
|
395
|
+
get(gist, 'files["userConfig.json"].content')
|
|
396
|
+
)
|
|
397
|
+
if (userConfig) {
|
|
398
|
+
store.setConfig(userConfig)
|
|
399
|
+
}
|
|
400
|
+
if (userConfig && userConfig.theme) {
|
|
401
|
+
store.setTheme(userConfig.theme)
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const up = {
|
|
406
|
+
[type + 'LastSyncTime']: Date.now()
|
|
407
|
+
}
|
|
408
|
+
if (pass) {
|
|
409
|
+
up[type + 'SyncPassword'] = pass
|
|
410
|
+
}
|
|
411
|
+
store.updateSyncSetting(up)
|
|
412
|
+
}
|
|
413
|
+
store.isSyncingSetting = false
|
|
414
|
+
store.isSyncDownload = false
|
|
415
|
+
return
|
|
416
|
+
}
|
|
417
|
+
|
|
292
418
|
const gist = await fetchData(
|
|
293
419
|
type,
|
|
294
420
|
'getOne',
|
|
@@ -24,10 +24,11 @@ export default Store => {
|
|
|
24
24
|
// console.log('addTransferList', JSON.stringify(items, null, 2))
|
|
25
25
|
const { fileTransfers } = window.store
|
|
26
26
|
const transferBatch = uid()
|
|
27
|
-
|
|
27
|
+
const nextItems = items.map(t => {
|
|
28
28
|
t.transferBatch = transferBatch
|
|
29
29
|
return t
|
|
30
|
-
})
|
|
30
|
+
})
|
|
31
|
+
fileTransfers.push(...nextItems)
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
Store.prototype.pauseAll = function () {
|
package/client/store/watch.js
CHANGED
|
@@ -11,9 +11,7 @@ import {
|
|
|
11
11
|
expandedKeysLsKey,
|
|
12
12
|
resolutionsLsKey,
|
|
13
13
|
localAddrBookmarkLsKey,
|
|
14
|
-
syncServerDataKey
|
|
15
|
-
aiChatHistoryKey,
|
|
16
|
-
cmdHistoryKey
|
|
14
|
+
syncServerDataKey
|
|
17
15
|
} from '../common/constants'
|
|
18
16
|
import * as ls from '../common/safe-local-storage'
|
|
19
17
|
import { debounce, isEmpty } from 'lodash-es'
|
|
@@ -134,28 +132,6 @@ export default store => {
|
|
|
134
132
|
return store.syncServerStatus
|
|
135
133
|
}).start()
|
|
136
134
|
|
|
137
|
-
autoRun(() => {
|
|
138
|
-
ls.safeSetItemJSON('history', store.history)
|
|
139
|
-
return store.history
|
|
140
|
-
}).start()
|
|
141
|
-
|
|
142
|
-
autoRun(() => {
|
|
143
|
-
ls.safeSetItemJSON(aiChatHistoryKey, store.aiChatHistory)
|
|
144
|
-
return store.aiChatHistory
|
|
145
|
-
}).start()
|
|
146
|
-
|
|
147
|
-
autoRun(() => {
|
|
148
|
-
const history = store.terminalCommandHistory
|
|
149
|
-
// Save in new format: array of {cmd, count, lastUseTime}
|
|
150
|
-
const data = Array.from(history.entries()).map(([cmd, info]) => ({
|
|
151
|
-
cmd,
|
|
152
|
-
count: info.count,
|
|
153
|
-
lastUseTime: info.lastUseTime
|
|
154
|
-
}))
|
|
155
|
-
ls.safeSetItemJSON(cmdHistoryKey, data)
|
|
156
|
-
return store.terminalCommandHistory
|
|
157
|
-
}).start()
|
|
158
|
-
|
|
159
135
|
autoRun(() => {
|
|
160
136
|
store.updateBatchInputSelectedTabIds()
|
|
161
137
|
const tabs = store.getTabs()
|