@homebridge-plugins/homebridge-eufy-security 5.0.0-beta.3 → 5.0.0-beta.5
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/dist/diagnostics.js +70 -9
- package/dist/diagnostics.js.map +1 -1
- package/dist/ui/server.js +26 -4
- package/dist/ui/server.js.map +1 -1
- package/homebridge-ui/public/app.css +234 -2
- package/homebridge-ui/public/i18n/en.json +18 -14
- package/homebridge-ui/public/i18n/fr.json +18 -14
- package/homebridge-ui/public/index.html +24 -32
- package/homebridge-ui/public/js/app.js +160 -65
- package/homebridge-ui/public/js/profile-wizard.js +22 -29
- package/package.json +1 -1
|
@@ -39,12 +39,11 @@ const diagnosticsClose = document.querySelector('[data-diagnostics-close]');
|
|
|
39
39
|
const diagnosticsWizardPanel = document.querySelector('[data-diagnostics-wizard]');
|
|
40
40
|
const diagnosticsQuestion = document.querySelector('[data-diagnostics-question]');
|
|
41
41
|
const diagnosticsQuestionText = document.querySelector('[data-diagnostics-question-text]');
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
const diagnosticsDirectBack = document.querySelector('[data-diagnostics-direct-back]');
|
|
42
|
+
const diagnosticsTiles = [...document.querySelectorAll('[data-diagnostics-tile]')];
|
|
43
|
+
const diagnosticsDevices = document.querySelector('[data-diagnostics-devices]');
|
|
44
|
+
const diagnosticsDeviceList = document.querySelector('[data-diagnostics-device-list]');
|
|
45
|
+
const diagnosticsDevicesEvery = document.querySelector('[data-diagnostics-devices-every]');
|
|
46
|
+
const diagnosticsDevicesChosen = document.querySelector('[data-diagnostics-devices-chosen]');
|
|
48
47
|
const diagnosticsFrequency = document.querySelector('[data-diagnostics-frequency]');
|
|
49
48
|
const diagnosticsFrequencyHeading = document.querySelector('#diagnostics-frequency-heading');
|
|
50
49
|
const diagnosticsFrequencyNow = document.querySelector('[data-diagnostics-frequency-answer="now"]');
|
|
@@ -52,11 +51,11 @@ const diagnosticsFrequencyIntermittent = document.querySelector('[data-diagnosti
|
|
|
52
51
|
const diagnosticsFrequencyBack = document.querySelector('[data-diagnostics-frequency-back]');
|
|
53
52
|
const diagnosticsMatch = document.querySelector('[data-diagnostics-match]');
|
|
54
53
|
const diagnosticsReject = document.querySelector('[data-diagnostics-reject]');
|
|
55
|
-
const diagnosticsProfile = document.querySelector('[data-diagnostics-profile]');
|
|
56
54
|
const diagnosticsAuthorize = document.querySelector('[data-diagnostics-authorize]');
|
|
57
55
|
const diagnosticsReproduction = document.querySelector('[data-diagnostics-reproduction]');
|
|
58
56
|
const diagnosticsStatus = document.querySelector('[data-diagnostics-status]');
|
|
59
57
|
const diagnosticsIssue = document.querySelector('[data-diagnostics-issue]');
|
|
58
|
+
const diagnosticsIssueHint = document.querySelector('[data-diagnostics-issue-hint]');
|
|
60
59
|
const diagnosticsResult = document.querySelector('[data-diagnostics-result]');
|
|
61
60
|
const diagnosticsActions = document.querySelector('[data-diagnostics-actions]');
|
|
62
61
|
const diagnosticsGuidanceTitle = document.querySelector('[data-diagnostics-guidance-title]');
|
|
@@ -66,7 +65,6 @@ const diagnosticsPhaseTitle = document.querySelector('[data-diagnostics-phase-ti
|
|
|
66
65
|
const diagnosticsGuidanceBeforeSection = document.querySelector('[data-diagnostics-guidance-before-section]');
|
|
67
66
|
const diagnosticsGuidanceBefore = document.querySelector('[data-diagnostics-guidance-before]');
|
|
68
67
|
const diagnosticsGuidanceAction = document.querySelector('[data-diagnostics-guidance-action]');
|
|
69
|
-
const diagnosticsReview = document.querySelector('[data-diagnostics-review]');
|
|
70
68
|
const diagnosticsManifest = document.querySelector('[data-diagnostics-manifest]');
|
|
71
69
|
const diagnosticsReviewConfirm = document.querySelector('[data-diagnostics-review-confirm]');
|
|
72
70
|
const diagnosticsReviewConfirmLabel = document.querySelector('[data-diagnostics-review-confirm-label]');
|
|
@@ -100,6 +98,12 @@ let challenge = '';
|
|
|
100
98
|
let legacyNames = [];
|
|
101
99
|
let legacyAcknowledged = false;
|
|
102
100
|
let diagnosticsState = { status: 'inactive', missingEvidence: [] };
|
|
101
|
+
/** Whether the reporter already downloaded this session's archive, which is what the report offer follows. */
|
|
102
|
+
let diagnosticsArchiveDownloaded = false;
|
|
103
|
+
/** The session whose manifest is on screen, so it is fetched once rather than on every render. */
|
|
104
|
+
let diagnosticsReviewedCaseId = '';
|
|
105
|
+
/** Guards the one fetch, so a burst of renders does not assemble the manifest several times over. */
|
|
106
|
+
let diagnosticsReviewPending = false;
|
|
103
107
|
let diagnosticsReviewId = '';
|
|
104
108
|
let diagnosticsStartingAnother = false;
|
|
105
109
|
let panelReturn;
|
|
@@ -258,17 +262,65 @@ function renderDiagnosticsGuidance(profile) {
|
|
|
258
262
|
diagnosticsGuidanceAction.textContent = messages[guidance.action] ?? '';
|
|
259
263
|
}
|
|
260
264
|
|
|
265
|
+
/**
|
|
266
|
+
* The devices the reporter may name, one tile each.
|
|
267
|
+
*
|
|
268
|
+
* A tile carries the device's own name above its retained image where it has one, and the icon the devices
|
|
269
|
+
* view uses for a device where it does not. The image is capped at half the tile: it is there to be recognised
|
|
270
|
+
* at a glance, and a picture that fills the tile leaves the name it belongs to competing with it.
|
|
271
|
+
*
|
|
272
|
+
* The list is asked for when it is empty rather than relying on the devices view having been opened first, and
|
|
273
|
+
* a request that goes unanswered leaves the step able to say every device, which is a complete answer.
|
|
274
|
+
*/
|
|
275
|
+
async function renderDiagnosticsDeviceList() {
|
|
276
|
+
if (dashboardDevices.length === 0) {
|
|
277
|
+
try {
|
|
278
|
+
const snapshot = await requestWithinDeadline('/dashboard', { representationPreferences: {} }, 12000);
|
|
279
|
+
dashboardDevices = snapshot.devices ?? [];
|
|
280
|
+
} catch {
|
|
281
|
+
dashboardDevices = [];
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
diagnosticsDeviceList.replaceChildren();
|
|
285
|
+
for (const device of dashboardDevices) {
|
|
286
|
+
const tile = document.createElement('button');
|
|
287
|
+
tile.type = 'button';
|
|
288
|
+
tile.dataset.serial = device.serial;
|
|
289
|
+
tile.setAttribute('aria-pressed', 'false');
|
|
290
|
+
const art = document.createElement('img');
|
|
291
|
+
art.alt = '';
|
|
292
|
+
if (device.artwork) {
|
|
293
|
+
art.className = 'device-photo';
|
|
294
|
+
art.loading = 'lazy';
|
|
295
|
+
art.src = device.artwork;
|
|
296
|
+
} else {
|
|
297
|
+
art.src = 'assets/icons/inventory.svg';
|
|
298
|
+
}
|
|
299
|
+
const name = document.createElement('span');
|
|
300
|
+
name.textContent = device.name;
|
|
301
|
+
tile.append(art, name);
|
|
302
|
+
tile.addEventListener('click', () => {
|
|
303
|
+
tile.setAttribute('aria-pressed', tile.getAttribute('aria-pressed') === 'true' ? 'false' : 'true');
|
|
304
|
+
diagnosticsDevicesChosen.disabled = chosenDiagnosticsDevices().length === 0;
|
|
305
|
+
});
|
|
306
|
+
diagnosticsDeviceList.append(tile);
|
|
307
|
+
}
|
|
308
|
+
diagnosticsDevicesChosen.disabled = true;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/** The serials pressed in the device step, in the order the grid drew them. */
|
|
312
|
+
function chosenDiagnosticsDevices() {
|
|
313
|
+
return [...diagnosticsDeviceList.querySelectorAll('[data-serial]')]
|
|
314
|
+
.filter((tile) => tile.getAttribute('aria-pressed') === 'true')
|
|
315
|
+
.map((tile) => tile.dataset.serial);
|
|
316
|
+
}
|
|
317
|
+
|
|
261
318
|
function renderDiagnosticsWizard() {
|
|
262
|
-
diagnosticsQuestion.hidden = diagnosticsWizardState.mode !== '
|
|
263
|
-
|
|
319
|
+
diagnosticsQuestion.hidden = diagnosticsWizardState.mode !== 'tiles';
|
|
320
|
+
diagnosticsDevices.hidden = diagnosticsWizardState.mode !== 'devices';
|
|
264
321
|
diagnosticsFrequency.hidden = diagnosticsWizardState.mode !== 'frequency';
|
|
265
322
|
diagnosticsMatch.hidden = diagnosticsWizardState.mode !== 'match';
|
|
266
|
-
if (diagnosticsWizardState.mode === 'questions') {
|
|
267
|
-
const question = diagnosticsWizard.questions[diagnosticsWizardState.questionIndex];
|
|
268
|
-
diagnosticsQuestionText.textContent = messages[question.message] ?? '';
|
|
269
|
-
}
|
|
270
323
|
if (diagnosticsWizardState.mode === 'match') {
|
|
271
|
-
diagnosticsProfile.value = diagnosticsWizardState.profile;
|
|
272
324
|
renderDiagnosticsGuidance(diagnosticsWizardState.profile);
|
|
273
325
|
diagnosticsModeSummary.textContent =
|
|
274
326
|
messages[
|
|
@@ -279,7 +331,21 @@ function renderDiagnosticsWizard() {
|
|
|
279
331
|
}
|
|
280
332
|
}
|
|
281
333
|
|
|
334
|
+
/**
|
|
335
|
+
* The report step, reachable or not.
|
|
336
|
+
*
|
|
337
|
+
* Without an archive there is nothing to attach, so the anchor carries no `href` — it is not a link — and
|
|
338
|
+
* `aria-disabled` states the same thing to a reader who cannot see it greyed. The hint says why, because a
|
|
339
|
+
* control that cannot be used and does not explain itself reads as broken rather than as not yet.
|
|
340
|
+
*/
|
|
341
|
+
function setIssueStepReachable(url) {
|
|
342
|
+
diagnosticsIssue.href = url;
|
|
343
|
+
diagnosticsIssue.setAttribute('aria-disabled', url ? 'false' : 'true');
|
|
344
|
+
diagnosticsIssueHint.textContent = messages[url ? 'diagnosticsIssueOpensTab' : 'diagnosticsIssueNeedsArchive'] ?? '';
|
|
345
|
+
}
|
|
346
|
+
|
|
282
347
|
function renderDiagnostics(state) {
|
|
348
|
+
if (state.supportCaseId !== diagnosticsState.supportCaseId) diagnosticsArchiveDownloaded = false;
|
|
283
349
|
diagnosticsState = state;
|
|
284
350
|
const screen = diagnosticsWizard.screen(state, diagnosticsStartingAnother);
|
|
285
351
|
const choosing = screen === 'choose';
|
|
@@ -307,17 +373,20 @@ function renderDiagnostics(state) {
|
|
|
307
373
|
: state.status === 'reproducing'
|
|
308
374
|
? messages.diagnosticsNowFinish
|
|
309
375
|
: messages.diagnosticsStartRecording;
|
|
310
|
-
diagnosticsIssue.hidden =
|
|
311
|
-
|
|
376
|
+
diagnosticsIssue.hidden = true;
|
|
377
|
+
setIssueStepReachable(diagnosticsArchiveDownloaded ? (state.issueUrl ?? '') : '');
|
|
312
378
|
diagnosticsResult.hidden = !reviewing;
|
|
313
|
-
|
|
314
|
-
diagnosticsManifest.hidden =
|
|
315
|
-
diagnosticsReviewConfirmLabel.hidden =
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
379
|
+
const reviewed = reviewing && diagnosticsReviewedCaseId === (state.supportCaseId ?? '');
|
|
380
|
+
diagnosticsManifest.hidden = !reviewed;
|
|
381
|
+
diagnosticsReviewConfirmLabel.hidden = !reviewed;
|
|
382
|
+
diagnosticsExport.hidden = !reviewed;
|
|
383
|
+
diagnosticsIssue.hidden = !reviewed;
|
|
384
|
+
if (!reviewed) {
|
|
385
|
+
diagnosticsReviewConfirm.checked = false;
|
|
386
|
+
diagnosticsExport.disabled = true;
|
|
387
|
+
diagnosticsReviewId = '';
|
|
388
|
+
if (reviewing) void ensureArchiveReview(state.supportCaseId ?? '');
|
|
389
|
+
}
|
|
321
390
|
if (screen === 'reproduce') {
|
|
322
391
|
renderDiagnosticsGuidance(state.profile);
|
|
323
392
|
if (reproductionMode === 'intermittent') {
|
|
@@ -349,6 +418,21 @@ function renderDiagnostics(state) {
|
|
|
349
418
|
).replace('{evidence}', state.missingEvidence?.join(', ') ?? '');
|
|
350
419
|
}
|
|
351
420
|
|
|
421
|
+
/**
|
|
422
|
+
* The catalogue entry that says, in a reader's words, what a never-collected class is.
|
|
423
|
+
*
|
|
424
|
+
* A class with no entry falls back to its own identifier, which is visible rather than absent, so a newly
|
|
425
|
+
* declared class shows up as something to translate instead of quietly disappearing from the list.
|
|
426
|
+
*/
|
|
427
|
+
const NEVER_COLLECTED_LABELS = {
|
|
428
|
+
'credentials-and-authentication': 'excludedCredentials',
|
|
429
|
+
'tokens-cookies-and-authorization': 'excludedTokens',
|
|
430
|
+
'session-and-push-stores': 'excludedSessions',
|
|
431
|
+
'private-and-symmetric-keys': 'excludedKeys',
|
|
432
|
+
'unconstrained-internal-objects': 'excludedInternalData',
|
|
433
|
+
'camera-images-talkback-and-raw-media': 'excludedMedia',
|
|
434
|
+
};
|
|
435
|
+
|
|
352
436
|
function renderArchiveManifest(manifest) {
|
|
353
437
|
diagnosticsManifest.replaceChildren();
|
|
354
438
|
const summary = document.createElement('p');
|
|
@@ -366,9 +450,16 @@ function renderArchiveManifest(manifest) {
|
|
|
366
450
|
row.textContent = `${item.evidence} · ${item.privacyClass} · ${item.status}${missing}${size}${truncated}${fields ? ` · ${messages.diagnosticsArchiveFields ?? ''} ${fields}` : ''}`;
|
|
367
451
|
evidence.append(row);
|
|
368
452
|
}
|
|
453
|
+
const detail = document.createElement('details');
|
|
454
|
+
const detailLabel = document.createElement('summary');
|
|
455
|
+
detailLabel.textContent = messages.diagnosticsArchiveDetail ?? '';
|
|
456
|
+
detail.append(detailLabel, summary, evidence);
|
|
369
457
|
const exclusions = document.createElement('p');
|
|
370
|
-
|
|
371
|
-
|
|
458
|
+
const neverCollected = (manifest.excludedClasses ?? []).map(
|
|
459
|
+
(excluded) => messages[NEVER_COLLECTED_LABELS[excluded]] ?? excluded,
|
|
460
|
+
);
|
|
461
|
+
exclusions.textContent = `${messages.diagnosticsArchiveExcluded ?? ''} ${neverCollected.join(', ')}.`;
|
|
462
|
+
diagnosticsManifest.append(detail, exclusions);
|
|
372
463
|
const uncovered = (manifest.evidence ?? []).filter((item) => item.coversReproduction === false);
|
|
373
464
|
if (uncovered.length > 0) {
|
|
374
465
|
const gap = document.createElement('p');
|
|
@@ -385,25 +476,32 @@ function renderArchiveManifest(manifest) {
|
|
|
385
476
|
diagnosticsManifest.hidden = false;
|
|
386
477
|
}
|
|
387
478
|
|
|
388
|
-
|
|
389
|
-
|
|
479
|
+
/**
|
|
480
|
+
* The manifest for the session on screen, fetched once.
|
|
481
|
+
*
|
|
482
|
+
* A completed reproduction that the reporter is looking at is a file they came for, so the manifest is
|
|
483
|
+
* read without being asked for. It is read once per session rather than per render, because assembling it
|
|
484
|
+
* reads every collected log. Exporting spends it, so the session is forgotten again and a second download
|
|
485
|
+
* asks for a fresh one.
|
|
486
|
+
*/
|
|
487
|
+
async function ensureArchiveReview(caseId) {
|
|
488
|
+
if (!caseId || diagnosticsReviewedCaseId === caseId || diagnosticsReviewPending) return;
|
|
489
|
+
diagnosticsReviewPending = true;
|
|
390
490
|
try {
|
|
391
491
|
const review = await requestWithinDeadline('/diagnostics/archive/review', undefined, 12000);
|
|
392
492
|
diagnosticsReviewId = review.reviewId;
|
|
493
|
+
diagnosticsReviewedCaseId = caseId;
|
|
393
494
|
renderArchiveManifest(review.manifest);
|
|
394
495
|
diagnosticsReviewConfirmLabel.hidden = false;
|
|
395
496
|
diagnosticsExport.hidden = false;
|
|
497
|
+
diagnosticsExport.disabled = !diagnosticsReviewConfirm.checked;
|
|
498
|
+
diagnosticsIssue.hidden = false;
|
|
396
499
|
} catch {
|
|
397
|
-
|
|
398
|
-
renderDiagnostics(await requestWithinDeadline('/diagnostics/status', undefined, 12000));
|
|
399
|
-
diagnosticsStatus.textContent = messages.diagnosticsFailed ?? '';
|
|
400
|
-
} catch {
|
|
401
|
-
diagnosticsStatus.textContent = messages.diagnosticsFailed ?? '';
|
|
402
|
-
}
|
|
500
|
+
diagnosticsStatus.textContent = messages.diagnosticsFailed ?? '';
|
|
403
501
|
} finally {
|
|
404
|
-
|
|
502
|
+
diagnosticsReviewPending = false;
|
|
405
503
|
}
|
|
406
|
-
}
|
|
504
|
+
}
|
|
407
505
|
|
|
408
506
|
diagnosticsReviewConfirm.addEventListener('change', () => {
|
|
409
507
|
diagnosticsExport.disabled = !diagnosticsReviewConfirm.checked || !diagnosticsReviewId;
|
|
@@ -425,7 +523,10 @@ diagnosticsExport.addEventListener('click', async () => {
|
|
|
425
523
|
download.click();
|
|
426
524
|
document.body.removeChild(download);
|
|
427
525
|
diagnosticsReviewId = '';
|
|
526
|
+
diagnosticsReviewedCaseId = '';
|
|
428
527
|
diagnosticsReviewConfirm.checked = false;
|
|
528
|
+
diagnosticsArchiveDownloaded = true;
|
|
529
|
+
setIssueStepReachable(diagnosticsState.issueUrl ?? '');
|
|
429
530
|
} catch {
|
|
430
531
|
diagnosticsStatus.textContent = messages.diagnosticsFailed ?? '';
|
|
431
532
|
}
|
|
@@ -441,6 +542,7 @@ diagnosticsAuthorize.addEventListener('click', async () => {
|
|
|
441
542
|
{
|
|
442
543
|
profile: diagnosticsWizardState.profile,
|
|
443
544
|
reproductionMode: diagnosticsWizardState.reproductionMode,
|
|
545
|
+
...(diagnosticsWizardState.devices === undefined ? {} : { affectedDevices: diagnosticsWizardState.devices }),
|
|
444
546
|
},
|
|
445
547
|
12000,
|
|
446
548
|
);
|
|
@@ -465,37 +567,32 @@ diagnosticsAuthorize.addEventListener('click', async () => {
|
|
|
465
567
|
}
|
|
466
568
|
});
|
|
467
569
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
renderDiagnosticsWizard();
|
|
477
|
-
if (diagnosticsWizardState.mode === 'frequency') diagnosticsFrequencyHeading.focus?.();
|
|
478
|
-
else diagnosticsQuestionText.focus?.();
|
|
479
|
-
});
|
|
570
|
+
for (const tile of diagnosticsTiles) {
|
|
571
|
+
tile.addEventListener('click', async () => {
|
|
572
|
+
diagnosticsWizardState = diagnosticsWizard.select(diagnosticsWizardState, tile.dataset.diagnosticsTile);
|
|
573
|
+
renderDiagnosticsWizard();
|
|
574
|
+
if (diagnosticsWizardState.mode === 'devices') await renderDiagnosticsDeviceList();
|
|
575
|
+
else diagnosticsFrequencyHeading.focus?.();
|
|
576
|
+
});
|
|
577
|
+
}
|
|
480
578
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
579
|
+
diagnosticsDevicesEvery.addEventListener('click', () => {
|
|
580
|
+
const tiles = [...diagnosticsDeviceList.querySelectorAll('[data-serial]')];
|
|
581
|
+
for (const tile of tiles) tile.setAttribute('aria-pressed', 'true');
|
|
582
|
+
diagnosticsDevicesChosen.disabled = tiles.length === 0;
|
|
583
|
+
if (tiles.length === 0) {
|
|
584
|
+
diagnosticsWizardState = diagnosticsWizard.chooseDevices(diagnosticsWizardState, 'all');
|
|
585
|
+
renderDiagnosticsWizard();
|
|
586
|
+
diagnosticsFrequencyHeading.focus?.();
|
|
587
|
+
}
|
|
485
588
|
});
|
|
486
589
|
|
|
487
|
-
|
|
488
|
-
diagnosticsWizardState = diagnosticsWizard.
|
|
590
|
+
diagnosticsDevicesChosen.addEventListener('click', () => {
|
|
591
|
+
diagnosticsWizardState = diagnosticsWizard.chooseDevices(diagnosticsWizardState, chosenDiagnosticsDevices());
|
|
489
592
|
renderDiagnosticsWizard();
|
|
490
593
|
diagnosticsFrequencyHeading.focus?.();
|
|
491
594
|
});
|
|
492
595
|
|
|
493
|
-
diagnosticsDirectBack.addEventListener('click', () => {
|
|
494
|
-
diagnosticsWizardState = diagnosticsWizard.start();
|
|
495
|
-
renderDiagnosticsWizard();
|
|
496
|
-
diagnosticsQuestionText.focus?.();
|
|
497
|
-
});
|
|
498
|
-
|
|
499
596
|
function chooseDiagnosticsReproductionMode(reproductionMode) {
|
|
500
597
|
diagnosticsWizardState = diagnosticsWizard.chooseReproductionMode(diagnosticsWizardState, reproductionMode);
|
|
501
598
|
renderDiagnosticsWizard();
|
|
@@ -508,15 +605,13 @@ diagnosticsFrequencyIntermittent.addEventListener('click', () => chooseDiagnosti
|
|
|
508
605
|
diagnosticsFrequencyBack.addEventListener('click', () => {
|
|
509
606
|
diagnosticsWizardState = diagnosticsWizard.backFromFrequency(diagnosticsWizardState);
|
|
510
607
|
renderDiagnosticsWizard();
|
|
511
|
-
|
|
512
|
-
else diagnosticsQuestionText.focus?.();
|
|
608
|
+
diagnosticsQuestionText.focus?.();
|
|
513
609
|
});
|
|
514
610
|
|
|
515
611
|
diagnosticsReject.addEventListener('click', () => {
|
|
516
612
|
diagnosticsWizardState = diagnosticsWizard.reject(diagnosticsWizardState);
|
|
517
613
|
renderDiagnosticsWizard();
|
|
518
|
-
|
|
519
|
-
else diagnosticsQuestionText.focus?.();
|
|
614
|
+
diagnosticsQuestionText.focus?.();
|
|
520
615
|
});
|
|
521
616
|
|
|
522
617
|
diagnosticsStartAnother.addEventListener('click', () => {
|
|
@@ -1,37 +1,30 @@
|
|
|
1
1
|
(function attachDiagnosticsWizard(global) {
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
const profiles = [
|
|
3
|
+
'startup-authentication',
|
|
4
|
+
'device-representation',
|
|
5
|
+
'control-state',
|
|
6
|
+
'live-media',
|
|
7
|
+
'hksv-recording',
|
|
8
|
+
'dashboard-ui',
|
|
9
|
+
'other',
|
|
9
10
|
];
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
return { mode: 'questions', questionIndex: 0, profile: undefined, source: 'questions' };
|
|
13
|
-
}
|
|
12
|
+
const deviceProfiles = ['device-representation', 'control-state', 'live-media', 'hksv-recording'];
|
|
14
13
|
|
|
15
|
-
function
|
|
16
|
-
|
|
17
|
-
return { ...state, mode: 'frequency', profile: questions[state.questionIndex].profile };
|
|
18
|
-
}
|
|
19
|
-
if (state.questionIndex === questions.length - 1) {
|
|
20
|
-
return { ...state, mode: 'frequency', profile: 'other' };
|
|
21
|
-
}
|
|
22
|
-
return { ...state, questionIndex: state.questionIndex + 1 };
|
|
14
|
+
function start() {
|
|
15
|
+
return { mode: 'tiles', profile: undefined };
|
|
23
16
|
}
|
|
24
17
|
|
|
25
|
-
function
|
|
26
|
-
return { mode: '
|
|
18
|
+
function select(state, profile) {
|
|
19
|
+
return { ...state, mode: deviceProfiles.includes(profile) ? 'devices' : 'frequency', profile };
|
|
27
20
|
}
|
|
28
21
|
|
|
29
|
-
function
|
|
30
|
-
return { ...state, mode: 'frequency',
|
|
22
|
+
function chooseDevices(state, devices) {
|
|
23
|
+
return { ...state, mode: 'frequency', devices };
|
|
31
24
|
}
|
|
32
25
|
|
|
33
|
-
function reject(
|
|
34
|
-
return
|
|
26
|
+
function reject() {
|
|
27
|
+
return start();
|
|
35
28
|
}
|
|
36
29
|
|
|
37
30
|
function chooseReproductionMode(state, reproductionMode) {
|
|
@@ -39,7 +32,7 @@
|
|
|
39
32
|
}
|
|
40
33
|
|
|
41
34
|
function backFromFrequency(state) {
|
|
42
|
-
return state.
|
|
35
|
+
return deviceProfiles.includes(state.profile) ? { ...state, mode: 'devices' } : start();
|
|
43
36
|
}
|
|
44
37
|
|
|
45
38
|
function screen(session, startingAnother) {
|
|
@@ -54,15 +47,15 @@
|
|
|
54
47
|
}
|
|
55
48
|
|
|
56
49
|
global.HomebridgeEufyDiagnosticsWizard = {
|
|
57
|
-
answer,
|
|
58
50
|
backFromFrequency,
|
|
59
51
|
backgroundActive,
|
|
52
|
+
chooseDevices,
|
|
60
53
|
chooseReproductionMode,
|
|
61
|
-
|
|
62
|
-
|
|
54
|
+
deviceProfiles,
|
|
55
|
+
profiles,
|
|
63
56
|
reject,
|
|
64
57
|
screen,
|
|
65
|
-
|
|
58
|
+
select,
|
|
66
59
|
start,
|
|
67
60
|
};
|
|
68
61
|
})(window);
|
package/package.json
CHANGED