iobroker.script-restore 0.0.4 → 0.0.6

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/README.md CHANGED
@@ -30,7 +30,7 @@ The archive is parsed entirely in the browser — no files are written to disk d
30
30
  - Supported formats: `.tar.gz`, `.tar`, `.json`, `.jsonl`
31
31
  - Tree view of all scripts organized by folder
32
32
  - Search across all script names
33
- - View source code with syntax highlighting (JS/TS/Blockly/Rules)
33
+ - View source code (JS/TS/Blockly/Rules)
34
34
  - Copy source code to clipboard or download as file
35
35
  - Fully browser-based parsing — no server roundtrip for uploads
36
36
 
@@ -75,8 +75,22 @@ The archive is parsed entirely in the browser — no files are written to disk d
75
75
  Placeholder for the next version (at the beginning of the line):
76
76
  ### **WORK IN PROGRESS**
77
77
  -->
78
- ### **WORK IN PROGRESS**
79
- * (ipod86) update README, fix SVG icon dimensions, add full language translations
78
+ ### 0.0.6 (2026-04-08)
79
+ * (ipod86) add HTTP, SFTP and WebDAV as optional backup sources
80
+ * (ipod86) multi-select scripts with Ctrl+click and download as ZIP
81
+ * (ipod86) remember last loaded backup in browser (localStorage)
82
+ * (ipod86) auto-detect local backup path from backitup adapter
83
+
84
+ ### 0.0.5 (2026-04-08)
85
+ * (ipod86) add FTP and SMB as optional backup sources with connection test button
86
+ * (ipod86) make local backup source optional (enable/disable in settings)
87
+ * (ipod86) add SMB version info (SMB2 only) in settings
88
+
89
+ ### 0.0.4 (2026-04-06)
90
+ * (ipod86) improve dark theme detection: live switching via MutationObserver and storage events
91
+
92
+ ### 0.0.3 (2026-04-06)
93
+ * (ipod86) add dark theme support for admin tab UI
80
94
 
81
95
  ### 0.0.1 (2026-04-06)
82
96
  * (ipod86) initial release
@@ -18,17 +18,27 @@
18
18
  <script type="text/javascript" src="words.js"></script>
19
19
 
20
20
  <script type="text/javascript">
21
+ // Checkboxes that are true by default when not yet configured
22
+ var defaultTrue = ['localEnabled'];
23
+
21
24
  function load(settings, onChange) {
22
25
  if (!settings) return;
23
26
  $('.value').each(function () {
24
27
  var $key = $(this);
25
28
  var id = $key.attr('id');
26
29
  if ($key.attr('type') === 'checkbox') {
27
- $key.prop('checked', settings[id]).on('change', () => onChange());
30
+ var val = defaultTrue.indexOf(id) !== -1
31
+ ? settings[id] !== false
32
+ : (settings[id] || false);
33
+ $key.prop('checked', val).on('change', function () {
34
+ onChange();
35
+ updateSections();
36
+ });
28
37
  } else {
29
- $key.val(settings[id]).on('change', () => onChange()).on('keyup', () => onChange());
38
+ $key.val(settings[id] || '').on('change', () => onChange()).on('keyup', () => onChange());
30
39
  }
31
40
  });
41
+ updateSections();
32
42
  onChange(false);
33
43
  if (M) M.updateTextFields();
34
44
  }
@@ -39,12 +49,104 @@
39
49
  var $this = $(this);
40
50
  if ($this.attr('type') === 'checkbox') {
41
51
  obj[$this.attr('id')] = $this.prop('checked');
52
+ } else if ($this.attr('type') === 'number') {
53
+ obj[$this.attr('id')] = parseInt($this.val(), 10) || 0;
42
54
  } else {
43
55
  obj[$this.attr('id')] = $this.val();
44
56
  }
45
57
  });
46
58
  callback(obj);
47
59
  }
60
+
61
+ function updateSections() {
62
+ $('#localDetails').toggle($('#localEnabled').prop('checked'));
63
+ $('#ftpDetails').toggle($('#ftpEnabled').prop('checked'));
64
+ $('#smbDetails').toggle($('#smbEnabled').prop('checked'));
65
+ $('#httpDetails').toggle($('#httpEnabled').prop('checked'));
66
+ $('#sftpDetails').toggle($('#sftpEnabled').prop('checked'));
67
+ $('#webdavDetails').toggle($('#webdavEnabled').prop('checked'));
68
+ if (M) M.updateTextFields();
69
+ }
70
+
71
+ function suggestBackupPath() {
72
+ var btn = document.getElementById('suggestBtn');
73
+ btn.disabled = true;
74
+ var inst = 'script-restore.' + getAdapterInstance();
75
+ socket.emit('sendTo', inst, 'suggestBackupPath', {}, function (result) {
76
+ btn.disabled = false;
77
+ if (result && result.path) {
78
+ $('#backupPath').val(result.path).trigger('change');
79
+ if (M) M.updateTextFields();
80
+ }
81
+ });
82
+ }
83
+
84
+ function getAdapterInstance() {
85
+ var params = new URLSearchParams(window.location.search);
86
+ var id = params.get('id') || '';
87
+ var m = id.match(/\.(\d+)$/);
88
+ return m ? m[1] : '0';
89
+ }
90
+
91
+ function testConnection(type) {
92
+ var resultEl = document.getElementById(type + 'TestResult');
93
+ var btn = document.getElementById(type + 'TestBtn');
94
+ resultEl.style.display = 'none';
95
+ btn.disabled = true;
96
+ btn.textContent = '⏳ ...';
97
+
98
+ var data = {};
99
+ if (type === 'ftp') {
100
+ data = {
101
+ host: $('#ftpHost').val(),
102
+ port: parseInt($('#ftpPort').val(), 10) || 21,
103
+ user: $('#ftpUser').val(),
104
+ password: $('#ftpPassword').val(),
105
+ path: $('#ftpPath').val() || '/',
106
+ secure: $('#ftpSecure').prop('checked'),
107
+ };
108
+ } else if (type === 'smb') {
109
+ data = {
110
+ host: $('#smbHost').val(),
111
+ share: $('#smbShare').val(),
112
+ path: $('#smbPath').val(),
113
+ user: $('#smbUser').val(),
114
+ password: $('#smbPassword').val(),
115
+ domain: $('#smbDomain').val(),
116
+ };
117
+ } else if (type === 'sftp') {
118
+ data = {
119
+ host: $('#sftpHost').val(),
120
+ port: parseInt($('#sftpPort').val(), 10) || 22,
121
+ user: $('#sftpUser').val(),
122
+ password: $('#sftpPassword').val(),
123
+ path: $('#sftpPath').val() || '/',
124
+ };
125
+ } else {
126
+ data = {
127
+ url: $('#webdavUrl').val(),
128
+ user: $('#webdavUser').val(),
129
+ password: $('#webdavPassword').val(),
130
+ path: $('#webdavPath').val() || '/',
131
+ };
132
+ }
133
+
134
+ var cmdMap = { ftp: 'testFtp', smb: 'testSmb', sftp: 'testSftp', webdav: 'testWebdav' };
135
+ var inst = 'script-restore.' + getAdapterInstance();
136
+ var cmd = cmdMap[type] || ('test' + type.charAt(0).toUpperCase() + type.slice(1));
137
+ socket.emit('sendTo', inst, cmd, data, function (result) {
138
+ btn.disabled = false;
139
+ btn.textContent = _('testConnection');
140
+ resultEl.style.display = 'inline';
141
+ if (result && result.success) {
142
+ resultEl.style.color = '#388e3c';
143
+ resultEl.textContent = '✓ ' + result.message;
144
+ } else {
145
+ resultEl.style.color = '#d32f2f';
146
+ resultEl.textContent = '✗ ' + (result && result.message ? result.message : 'Fehler');
147
+ }
148
+ });
149
+ }
48
150
  </script>
49
151
 
50
152
  </head>
@@ -59,11 +161,247 @@
59
161
  </div>
60
162
  </div>
61
163
 
164
+ <!-- Local backup path -->
165
+ <div class="row" style="margin-top: 8px;">
166
+ <div class="col s12">
167
+ <h6 class="translate" style="font-weight:600; border-bottom: 1px solid #ccc; padding-bottom: 4px;">localSection</h6>
168
+ </div>
169
+ </div>
170
+ <div class="row">
171
+ <div class="col s12">
172
+ <input class="value filled-in" id="localEnabled" type="checkbox">
173
+ <label for="localEnabled" class="translate">localEnabled</label>
174
+ </div>
175
+ </div>
176
+ <div id="localDetails">
177
+ <div class="row">
178
+ <div class="input-field col s12 m8 l6">
179
+ <input class="value" id="backupPath" type="text" placeholder="/opt/iobroker/backups">
180
+ <label for="backupPath" class="translate">backupPath</label>
181
+ <span class="translate helper-text">backupPathHint</span>
182
+ </div>
183
+ <div class="col s12 m2 l2" style="padding-top: 20px;">
184
+ <button id="suggestBtn" class="btn btn-small waves-effect waves-light" onclick="suggestBackupPath()" type="button">
185
+ <span class="translate">suggestPath</span>
186
+ </button>
187
+ </div>
188
+ </div>
189
+ </div>
190
+
191
+ <!-- FTP Section -->
192
+ <div class="row" style="margin-top: 24px;">
193
+ <div class="col s12">
194
+ <h6 class="translate" style="font-weight:600; border-bottom: 1px solid #ccc; padding-bottom: 4px;">ftpSection</h6>
195
+ </div>
196
+ </div>
197
+ <div class="row">
198
+ <div class="col s12">
199
+ <input class="value filled-in" id="ftpEnabled" type="checkbox">
200
+ <label for="ftpEnabled" class="translate">ftpEnabled</label>
201
+ </div>
202
+ </div>
203
+ <div id="ftpDetails" style="display:none;">
204
+ <div class="row">
205
+ <div class="input-field col s12 m5 l4">
206
+ <input class="value" id="ftpHost" type="text" placeholder="192.168.1.100">
207
+ <label for="ftpHost" class="translate">ftpHost</label>
208
+ </div>
209
+ <div class="input-field col s6 m2 l1">
210
+ <input class="value" id="ftpPort" type="number" placeholder="21" min="1" max="65535">
211
+ <label for="ftpPort" class="translate">ftpPort</label>
212
+ </div>
213
+ <div class="col s6 m3 l2" style="padding-top: 20px;">
214
+ <input class="value filled-in" id="ftpSecure" type="checkbox">
215
+ <label for="ftpSecure" class="translate">ftpSecure</label>
216
+ </div>
217
+ </div>
218
+ <div class="row">
219
+ <div class="input-field col s12 m4 l3">
220
+ <input class="value" id="ftpUser" type="text" placeholder="anonymous">
221
+ <label for="ftpUser" class="translate">ftpUser</label>
222
+ </div>
223
+ <div class="input-field col s12 m4 l3">
224
+ <input class="value" id="ftpPassword" type="password" placeholder="">
225
+ <label for="ftpPassword" class="translate">ftpPassword</label>
226
+ </div>
227
+ <div class="input-field col s12 m4 l3">
228
+ <input class="value" id="ftpPath" type="text" placeholder="/backups">
229
+ <label for="ftpPath" class="translate">ftpPath</label>
230
+ </div>
231
+ </div>
232
+ <div class="row" style="margin-top: 4px;">
233
+ <div class="col s12">
234
+ <button id="ftpTestBtn" class="btn btn-small waves-effect waves-light" onclick="testConnection('ftp')" type="button">
235
+ <span class="translate">testConnection</span>
236
+ </button>
237
+ <span id="ftpTestResult" style="display:none; margin-left:12px; font-size:0.9rem; font-weight:500;"></span>
238
+ </div>
239
+ </div>
240
+ </div>
241
+
242
+ <!-- SMB Section -->
243
+ <div class="row" style="margin-top: 24px;">
244
+ <div class="col s12">
245
+ <h6 class="translate" style="font-weight:600; border-bottom: 1px solid #ccc; padding-bottom: 4px;">smbSection</h6>
246
+ </div>
247
+ </div>
248
+ <div class="row">
249
+ <div class="col s12">
250
+ <input class="value filled-in" id="smbEnabled" type="checkbox">
251
+ <label for="smbEnabled" class="translate">smbEnabled</label>
252
+ </div>
253
+ </div>
254
+ <div id="smbDetails" style="display:none;">
255
+ <div class="row">
256
+ <div class="col s12">
257
+ <span class="translate helper-text" style="color:#e65100; font-size:0.82rem;">smbVersionNote</span>
258
+ </div>
259
+ </div>
260
+ <div class="row" style="margin-top: 8px;">
261
+ <div class="input-field col s12 m5 l4">
262
+ <input class="value" id="smbHost" type="text" placeholder="192.168.1.100">
263
+ <label for="smbHost" class="translate">smbHost</label>
264
+ </div>
265
+ <div class="input-field col s12 m4 l3">
266
+ <input class="value" id="smbShare" type="text" placeholder="Backups">
267
+ <label for="smbShare" class="translate">smbShare</label>
268
+ </div>
269
+ <div class="input-field col s12 m3 l2">
270
+ <input class="value" id="smbPath" type="text" placeholder="">
271
+ <label for="smbPath" class="translate">smbPath</label>
272
+ </div>
273
+ </div>
274
+ <div class="row">
275
+ <div class="input-field col s12 m4 l3">
276
+ <input class="value" id="smbUser" type="text" placeholder="">
277
+ <label for="smbUser" class="translate">smbUser</label>
278
+ </div>
279
+ <div class="input-field col s12 m4 l3">
280
+ <input class="value" id="smbPassword" type="password" placeholder="">
281
+ <label for="smbPassword" class="translate">smbPassword</label>
282
+ </div>
283
+ <div class="input-field col s12 m4 l3">
284
+ <input class="value" id="smbDomain" type="text" placeholder="">
285
+ <label for="smbDomain" class="translate">smbDomain</label>
286
+ </div>
287
+ </div>
288
+ <div class="row" style="margin-top: 4px;">
289
+ <div class="col s12">
290
+ <button id="smbTestBtn" class="btn btn-small waves-effect waves-light" onclick="testConnection('smb')" type="button">
291
+ <span class="translate">testConnection</span>
292
+ </button>
293
+ <span id="smbTestResult" style="display:none; margin-left:12px; font-size:0.9rem; font-weight:500;"></span>
294
+ </div>
295
+ </div>
296
+ </div>
297
+
298
+ <!-- HTTP Section -->
299
+ <div class="row" style="margin-top: 24px;">
300
+ <div class="col s12">
301
+ <h6 class="translate" style="font-weight:600; border-bottom: 1px solid #ccc; padding-bottom: 4px;">httpSection</h6>
302
+ </div>
303
+ </div>
62
304
  <div class="row">
63
- <div class="input-field col s12 m8 l6">
64
- <input class="value" id="backupPath" type="text" placeholder="/opt/iobroker/backups">
65
- <label for="backupPath" class="translate">backupPath</label>
66
- <span class="translate helper-text">backupPathHint</span>
305
+ <div class="col s12">
306
+ <input class="value filled-in" id="httpEnabled" type="checkbox">
307
+ <label for="httpEnabled" class="translate">httpEnabled</label>
308
+ </div>
309
+ </div>
310
+ <div id="httpDetails" style="display:none;">
311
+ <div class="row">
312
+ <div class="col s12">
313
+ <span class="translate helper-text" style="font-size:0.85rem; color:#555;">httpNote</span>
314
+ </div>
315
+ </div>
316
+ </div>
317
+
318
+ <!-- SFTP Section -->
319
+ <div class="row" style="margin-top: 24px;">
320
+ <div class="col s12">
321
+ <h6 class="translate" style="font-weight:600; border-bottom: 1px solid #ccc; padding-bottom: 4px;">sftpSection</h6>
322
+ </div>
323
+ </div>
324
+ <div class="row">
325
+ <div class="col s12">
326
+ <input class="value filled-in" id="sftpEnabled" type="checkbox">
327
+ <label for="sftpEnabled" class="translate">sftpEnabled</label>
328
+ </div>
329
+ </div>
330
+ <div id="sftpDetails" style="display:none;">
331
+ <div class="row">
332
+ <div class="input-field col s12 m5 l4">
333
+ <input class="value" id="sftpHost" type="text" placeholder="192.168.1.100">
334
+ <label for="sftpHost" class="translate">sftpHost</label>
335
+ </div>
336
+ <div class="input-field col s6 m2 l1">
337
+ <input class="value" id="sftpPort" type="number" placeholder="22" min="1" max="65535">
338
+ <label for="sftpPort" class="translate">sftpPort</label>
339
+ </div>
340
+ </div>
341
+ <div class="row">
342
+ <div class="input-field col s12 m4 l3">
343
+ <input class="value" id="sftpUser" type="text" placeholder="">
344
+ <label for="sftpUser" class="translate">sftpUser</label>
345
+ </div>
346
+ <div class="input-field col s12 m4 l3">
347
+ <input class="value" id="sftpPassword" type="password" placeholder="">
348
+ <label for="sftpPassword" class="translate">sftpPassword</label>
349
+ </div>
350
+ <div class="input-field col s12 m4 l3">
351
+ <input class="value" id="sftpPath" type="text" placeholder="/">
352
+ <label for="sftpPath" class="translate">sftpPath</label>
353
+ </div>
354
+ </div>
355
+ <div class="row" style="margin-top: 4px;">
356
+ <div class="col s12">
357
+ <button id="sftpTestBtn" class="btn btn-small waves-effect waves-light" onclick="testConnection('sftp')" type="button">
358
+ <span class="translate">testConnection</span>
359
+ </button>
360
+ <span id="sftpTestResult" style="display:none; margin-left:12px; font-size:0.9rem; font-weight:500;"></span>
361
+ </div>
362
+ </div>
363
+ </div>
364
+
365
+ <!-- WebDAV Section -->
366
+ <div class="row" style="margin-top: 24px;">
367
+ <div class="col s12">
368
+ <h6 class="translate" style="font-weight:600; border-bottom: 1px solid #ccc; padding-bottom: 4px;">webdavSection</h6>
369
+ </div>
370
+ </div>
371
+ <div class="row">
372
+ <div class="col s12">
373
+ <input class="value filled-in" id="webdavEnabled" type="checkbox">
374
+ <label for="webdavEnabled" class="translate">webdavEnabled</label>
375
+ </div>
376
+ </div>
377
+ <div id="webdavDetails" style="display:none;">
378
+ <div class="row">
379
+ <div class="input-field col s12 m8 l6">
380
+ <input class="value" id="webdavUrl" type="text" placeholder="https://cloud.example.com/remote.php/webdav">
381
+ <label for="webdavUrl" class="translate">webdavUrl</label>
382
+ </div>
383
+ </div>
384
+ <div class="row">
385
+ <div class="input-field col s12 m4 l3">
386
+ <input class="value" id="webdavUser" type="text" placeholder="">
387
+ <label for="webdavUser" class="translate">webdavUser</label>
388
+ </div>
389
+ <div class="input-field col s12 m4 l3">
390
+ <input class="value" id="webdavPassword" type="password" placeholder="">
391
+ <label for="webdavPassword" class="translate">webdavPassword</label>
392
+ </div>
393
+ <div class="input-field col s12 m4 l3">
394
+ <input class="value" id="webdavPath" type="text" placeholder="/">
395
+ <label for="webdavPath" class="translate">webdavPath</label>
396
+ </div>
397
+ </div>
398
+ <div class="row" style="margin-top: 4px;">
399
+ <div class="col s12">
400
+ <button id="webdavTestBtn" class="btn btn-small waves-effect waves-light" onclick="testConnection('webdav')" type="button">
401
+ <span class="translate">testConnection</span>
402
+ </button>
403
+ <span id="webdavTestResult" style="display:none; margin-left:12px; font-size:0.9rem; font-weight:500;"></span>
404
+ </div>
67
405
  </div>
68
406
  </div>
69
407