iobroker.mywebui 1.37.32 → 1.37.34
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/io-package.json
CHANGED
package/package.json
CHANGED
|
@@ -388,74 +388,97 @@ export class IobrokerWebuiAppShell extends BaseCustomWebComponentConstructorAppe
|
|
|
388
388
|
|
|
389
389
|
async _updateVisibilityPanel() {
|
|
390
390
|
const visibilityDock = this._getDomElement('visibilityDock');
|
|
391
|
-
if (!visibilityDock)
|
|
392
|
-
|
|
393
|
-
return;
|
|
394
|
-
}
|
|
395
|
-
|
|
391
|
+
if (!visibilityDock) return;
|
|
392
|
+
|
|
396
393
|
const content = visibilityDock.querySelector('#visibility-panel-content');
|
|
397
|
-
if (!content)
|
|
398
|
-
|
|
399
|
-
return;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
// Use _selectedItems instead of selectedElements
|
|
394
|
+
if (!content) return;
|
|
395
|
+
|
|
403
396
|
const selectedItems = this.propertyGrid.propertyGrid._selectedItems;
|
|
404
|
-
|
|
405
|
-
console.log('🔍 [Visibility] Update called, selected:', selectedItems?.length || 0);
|
|
406
|
-
|
|
397
|
+
|
|
407
398
|
if (!selectedItems || selectedItems.length !== 1) {
|
|
408
399
|
content.innerHTML = '<p style="color:#999;font-style:italic;">Select an element to configure visibility...</p>';
|
|
409
|
-
console.log('👁️ [Visibility] No selection');
|
|
410
400
|
return;
|
|
411
401
|
}
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
let
|
|
402
|
+
|
|
403
|
+
const designItem = selectedItems[0];
|
|
404
|
+
const element = designItem.element;
|
|
405
|
+
|
|
406
|
+
// Read existing binding from bind-prop:hidden attribute
|
|
407
|
+
const bindAttr = element.getAttribute('bind-prop:hidden');
|
|
408
|
+
let existingBinding = null;
|
|
409
|
+
if (bindAttr != null) {
|
|
410
|
+
const parsed = bindingsHelper.parseBinding(element, 'bind-prop:hidden', bindAttr, 'property', 'bind-prop:');
|
|
411
|
+
if (parsed) existingBinding = parsed[1];
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Read group access control config from data attributes
|
|
415
|
+
const dataConfig = {
|
|
419
416
|
enabled: element.getAttribute('data-visibility-enabled') === 'true',
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
conditionValue: element.getAttribute('data-visibility-value') || '',
|
|
423
|
-
action: element.getAttribute('data-visibility-action') || 'hide',
|
|
424
|
-
groups: element.getAttribute('data-visibility-groups')?.split(',').filter(g => g) || []
|
|
417
|
+
groups: element.getAttribute('data-visibility-groups')?.split(',').filter(g => g) || [],
|
|
418
|
+
action: element.getAttribute('data-visibility-action') || 'hide'
|
|
425
419
|
};
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
420
|
+
|
|
421
|
+
content.innerHTML = '';
|
|
422
|
+
|
|
423
|
+
// --- BINDING ROW ---
|
|
424
|
+
const bindRow = document.createElement('div');
|
|
425
|
+
bindRow.style.cssText = 'display:flex;align-items:center;gap:6px;padding:4px 0;margin-bottom:10px;padding-bottom:10px;border-bottom:1px solid #ddd;';
|
|
426
|
+
|
|
427
|
+
const bindLabel = document.createElement('span');
|
|
428
|
+
bindLabel.textContent = 'Visibility';
|
|
429
|
+
bindLabel.style.cssText = 'font-size:12px;font-weight:600;flex:1;';
|
|
430
|
+
bindRow.appendChild(bindLabel);
|
|
431
|
+
|
|
432
|
+
if (existingBinding) {
|
|
433
|
+
const sig = existingBinding.signal || (existingBinding.expression ? 'expr' : '?');
|
|
434
|
+
const statusSpan = document.createElement('span');
|
|
435
|
+
statusSpan.textContent = sig;
|
|
436
|
+
statusSpan.title = JSON.stringify(existingBinding);
|
|
437
|
+
statusSpan.style.cssText = 'font-size:10px;color:#555;max-width:90px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;';
|
|
438
|
+
bindRow.appendChild(statusSpan);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const bindBtn = document.createElement('button');
|
|
442
|
+
bindBtn.textContent = '□';
|
|
443
|
+
bindBtn.title = 'Open binding editor';
|
|
444
|
+
bindBtn.style.cssText = existingBinding
|
|
445
|
+
? 'width:20px;height:20px;padding:0;font-size:13px;line-height:1;border:1px solid #888;background:#ff0;cursor:pointer;flex-shrink:0;'
|
|
446
|
+
: 'width:20px;height:20px;padding:0;font-size:13px;line-height:1;border:1px solid #888;background:#f0f0f0;cursor:pointer;flex-shrink:0;';
|
|
447
|
+
bindBtn.onclick = () => {
|
|
448
|
+
const property = { name: 'hidden', propertyType: 'propertyAndAttribute' };
|
|
449
|
+
serviceContainer.config.openBindingsEditor(property, [designItem], existingBinding, 'property');
|
|
450
|
+
};
|
|
451
|
+
bindRow.appendChild(bindBtn);
|
|
452
|
+
|
|
453
|
+
if (existingBinding) {
|
|
454
|
+
const clearBtn = document.createElement('button');
|
|
455
|
+
clearBtn.textContent = '✕';
|
|
456
|
+
clearBtn.title = 'Remove binding';
|
|
457
|
+
clearBtn.style.cssText = 'width:20px;height:20px;padding:0;font-size:11px;line-height:1;border:1px solid #c66;background:#fee;cursor:pointer;color:#c00;flex-shrink:0;';
|
|
458
|
+
clearBtn.onclick = () => {
|
|
459
|
+
designItem.removeAttribute('bind-prop:hidden');
|
|
460
|
+
this._updateVisibilityPanel();
|
|
461
|
+
};
|
|
462
|
+
bindRow.appendChild(clearBtn);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
content.appendChild(bindRow);
|
|
466
|
+
|
|
467
|
+
// --- GROUP ACCESS CONTROL ---
|
|
468
|
+
const updateGroupConfig = (key, value) => {
|
|
469
|
+
dataConfig[key] = value;
|
|
470
|
+
if (key === 'enabled') {
|
|
471
|
+
if (value) designItem.setAttribute('data-visibility-enabled', 'true');
|
|
472
|
+
else designItem.removeAttribute('data-visibility-enabled');
|
|
473
|
+
} else if (key === 'groups') {
|
|
474
|
+
if (value && value.length > 0) designItem.setAttribute('data-visibility-groups', value.join(','));
|
|
475
|
+
else designItem.removeAttribute('data-visibility-groups');
|
|
476
|
+
} else if (key === 'action') {
|
|
477
|
+
if (value) designItem.setAttribute('data-visibility-action', value);
|
|
478
|
+
else designItem.removeAttribute('data-visibility-action');
|
|
452
479
|
}
|
|
453
|
-
|
|
454
|
-
console.log('🔒 [Visibility] Config updated via DesignItem:', config);
|
|
455
480
|
};
|
|
456
|
-
|
|
457
|
-
content.innerHTML = '';
|
|
458
|
-
|
|
481
|
+
|
|
459
482
|
// Enable checkbox
|
|
460
483
|
const enableDiv = document.createElement('div');
|
|
461
484
|
enableDiv.style.cssText = 'margin-bottom:10px;';
|
|
@@ -463,51 +486,27 @@ export class IobrokerWebuiAppShell extends BaseCustomWebComponentConstructorAppe
|
|
|
463
486
|
enableLabel.style.cssText = 'display:flex;align-items:center;gap:5px;cursor:pointer;font-size:12px;';
|
|
464
487
|
const enableCheck = document.createElement('input');
|
|
465
488
|
enableCheck.type = 'checkbox';
|
|
466
|
-
enableCheck.checked =
|
|
467
|
-
enableCheck.onchange = () =>
|
|
489
|
+
enableCheck.checked = dataConfig.enabled || false;
|
|
490
|
+
enableCheck.onchange = () => updateGroupConfig('enabled', enableCheck.checked);
|
|
468
491
|
enableLabel.appendChild(enableCheck);
|
|
469
|
-
enableLabel.appendChild(document.createTextNode('Enable Visibility Control'));
|
|
492
|
+
enableLabel.appendChild(document.createTextNode('Enable Group Visibility Control'));
|
|
470
493
|
enableDiv.appendChild(enableLabel);
|
|
471
494
|
content.appendChild(enableDiv);
|
|
472
|
-
|
|
473
|
-
//
|
|
474
|
-
const objIdField = this._createFieldWithButton('Object ID:', 'text', config.objectId || '', '0_userdata.0.test',
|
|
475
|
-
(val) => updateConfig('objectId', val));
|
|
476
|
-
content.appendChild(objIdField);
|
|
477
|
-
|
|
478
|
-
// Condition
|
|
479
|
-
const condDiv = document.createElement('div');
|
|
480
|
-
condDiv.style.cssText = 'margin-bottom:10px;';
|
|
481
|
-
const condLabel = document.createElement('label');
|
|
482
|
-
condLabel.style.cssText = 'font-size:11px;font-weight:600;display:block;margin-bottom:3px;color:#555;';
|
|
483
|
-
condLabel.textContent = 'Condition:';
|
|
484
|
-
const condSelect = document.createElement('select');
|
|
485
|
-
condSelect.style.cssText = 'width:100%;padding:6px;font-size:12px;border:1px solid #ccc;border-radius:3px;';
|
|
486
|
-
condSelect.innerHTML = '<option>==</option><option>!=</option><option>></option><option><</option><option>>=</option><option><=</option>';
|
|
487
|
-
condSelect.value = config.condition || '==';
|
|
488
|
-
condSelect.onchange = () => updateConfig('condition', condSelect.value);
|
|
489
|
-
condDiv.appendChild(condLabel);
|
|
490
|
-
condDiv.appendChild(condSelect);
|
|
491
|
-
content.appendChild(condDiv);
|
|
492
|
-
|
|
493
|
-
// Value for condition
|
|
494
|
-
content.appendChild(this._createField('Value for condition:', 'text', config.conditionValue || '', '1',
|
|
495
|
-
(val) => updateConfig('conditionValue', val)));
|
|
496
|
-
|
|
497
|
-
// User Groups
|
|
495
|
+
|
|
496
|
+
// Groups
|
|
498
497
|
const groupsDiv = document.createElement('div');
|
|
499
498
|
groupsDiv.style.cssText = 'margin-bottom:10px;';
|
|
500
499
|
const groupsLabel = document.createElement('label');
|
|
501
500
|
groupsLabel.style.cssText = 'font-size:11px;font-weight:600;display:block;margin-bottom:3px;color:#555;';
|
|
502
501
|
groupsLabel.textContent = 'Only for groups:';
|
|
503
502
|
groupsDiv.appendChild(groupsLabel);
|
|
504
|
-
|
|
503
|
+
|
|
505
504
|
const groupsList = document.createElement('div');
|
|
506
505
|
groupsList.style.cssText = 'max-height:100px;overflow-y:auto;border:1px solid #ccc;padding:6px;background:#fff;border-radius:3px;';
|
|
507
|
-
|
|
506
|
+
|
|
508
507
|
const userGroups = await iobrokerHandler.getUserGroups();
|
|
509
|
-
const selectedGroups =
|
|
510
|
-
|
|
508
|
+
const selectedGroups = dataConfig.groups || [];
|
|
509
|
+
|
|
511
510
|
userGroups.forEach(group => {
|
|
512
511
|
const groupLabel = document.createElement('label');
|
|
513
512
|
groupLabel.style.cssText = 'display:flex;align-items:center;gap:5px;font-size:11px;padding:3px;cursor:pointer;';
|
|
@@ -515,22 +514,22 @@ export class IobrokerWebuiAppShell extends BaseCustomWebComponentConstructorAppe
|
|
|
515
514
|
groupCheck.type = 'checkbox';
|
|
516
515
|
groupCheck.checked = selectedGroups.includes(group.id);
|
|
517
516
|
groupCheck.onchange = () => {
|
|
518
|
-
let groups =
|
|
517
|
+
let groups = [...dataConfig.groups];
|
|
519
518
|
if (groupCheck.checked) {
|
|
520
519
|
if (!groups.includes(group.id)) groups.push(group.id);
|
|
521
520
|
} else {
|
|
522
521
|
groups = groups.filter(g => g !== group.id);
|
|
523
522
|
}
|
|
524
|
-
|
|
523
|
+
updateGroupConfig('groups', groups);
|
|
525
524
|
};
|
|
526
525
|
groupLabel.appendChild(groupCheck);
|
|
527
526
|
groupLabel.appendChild(document.createTextNode(group.name));
|
|
528
527
|
groupsList.appendChild(groupLabel);
|
|
529
528
|
});
|
|
530
|
-
|
|
529
|
+
|
|
531
530
|
groupsDiv.appendChild(groupsList);
|
|
532
531
|
content.appendChild(groupsDiv);
|
|
533
|
-
|
|
532
|
+
|
|
534
533
|
// Action
|
|
535
534
|
const actionDiv = document.createElement('div');
|
|
536
535
|
actionDiv.style.cssText = 'margin-bottom:5px;';
|
|
@@ -540,80 +539,12 @@ export class IobrokerWebuiAppShell extends BaseCustomWebComponentConstructorAppe
|
|
|
540
539
|
const actionSelect = document.createElement('select');
|
|
541
540
|
actionSelect.style.cssText = 'width:100%;padding:6px;font-size:12px;border:1px solid #ccc;border-radius:3px;';
|
|
542
541
|
actionSelect.innerHTML = '<option value="hide">hide</option><option value="disable">disable</option>';
|
|
543
|
-
actionSelect.value =
|
|
544
|
-
actionSelect.onchange = () =>
|
|
542
|
+
actionSelect.value = dataConfig.action || 'hide';
|
|
543
|
+
actionSelect.onchange = () => updateGroupConfig('action', actionSelect.value);
|
|
545
544
|
actionDiv.appendChild(actionLabel);
|
|
546
545
|
actionDiv.appendChild(actionSelect);
|
|
547
546
|
content.appendChild(actionDiv);
|
|
548
547
|
}
|
|
549
|
-
|
|
550
|
-
_createField(label, type, value, placeholder, onChange) {
|
|
551
|
-
const div = document.createElement('div');
|
|
552
|
-
div.style.cssText = 'margin-bottom:10px;';
|
|
553
|
-
const labelEl = document.createElement('label');
|
|
554
|
-
labelEl.style.cssText = 'font-size:11px;font-weight:600;display:block;margin-bottom:3px;color:#555;';
|
|
555
|
-
labelEl.textContent = label;
|
|
556
|
-
const input = document.createElement('input');
|
|
557
|
-
input.type = type;
|
|
558
|
-
input.value = value;
|
|
559
|
-
input.placeholder = placeholder;
|
|
560
|
-
input.style.cssText = 'width:100%;padding:6px;font-size:12px;border:1px solid #ccc;border-radius:3px;';
|
|
561
|
-
input.oninput = () => onChange(input.value);
|
|
562
|
-
div.appendChild(labelEl);
|
|
563
|
-
div.appendChild(input);
|
|
564
|
-
return div;
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
_createFieldWithButton(label, type, value, placeholder, onChange) {
|
|
568
|
-
const div = document.createElement('div');
|
|
569
|
-
div.style.cssText = 'margin-bottom:10px;';
|
|
570
|
-
const labelEl = document.createElement('label');
|
|
571
|
-
labelEl.style.cssText = 'font-size:11px;font-weight:600;display:block;margin-bottom:3px;color:#555;';
|
|
572
|
-
labelEl.textContent = label;
|
|
573
|
-
|
|
574
|
-
// Container for input + button
|
|
575
|
-
const inputContainer = document.createElement('div');
|
|
576
|
-
inputContainer.style.cssText = 'display:flex;gap:5px;';
|
|
577
|
-
|
|
578
|
-
const input = document.createElement('input');
|
|
579
|
-
input.type = type;
|
|
580
|
-
input.value = value;
|
|
581
|
-
input.placeholder = placeholder;
|
|
582
|
-
input.style.cssText = 'flex:1;padding:6px;font-size:12px;border:1px solid #ccc;border-radius:3px;';
|
|
583
|
-
input.oninput = () => onChange(input.value);
|
|
584
|
-
|
|
585
|
-
// IOB Button
|
|
586
|
-
const btn = document.createElement('button');
|
|
587
|
-
btn.textContent = 'IOB';
|
|
588
|
-
btn.title = 'ioBroker object selector';
|
|
589
|
-
btn.style.cssText = 'padding:6px 12px;font-size:11px;font-weight:bold;background:#2196f3;color:#fff;border:none;border-radius:3px;cursor:pointer;white-space:nowrap;';
|
|
590
|
-
btn.onmouseover = () => btn.style.background = '#1976d2';
|
|
591
|
-
btn.onmouseout = () => btn.style.background = '#2196f3';
|
|
592
|
-
btn.onclick = async () => {
|
|
593
|
-
try {
|
|
594
|
-
const res = await openSelectIdDialog({
|
|
595
|
-
host: window.iobrokerHost,
|
|
596
|
-
port: window.iobrokerPort,
|
|
597
|
-
protocol: window.location.protocol,
|
|
598
|
-
language: 'en',
|
|
599
|
-
selected: input.value,
|
|
600
|
-
allowAll: true
|
|
601
|
-
});
|
|
602
|
-
if (res) {
|
|
603
|
-
input.value = res;
|
|
604
|
-
onChange(res);
|
|
605
|
-
}
|
|
606
|
-
} catch (err) {
|
|
607
|
-
console.error('❌ [Visibility] Object selector error:', err);
|
|
608
|
-
}
|
|
609
|
-
};
|
|
610
|
-
|
|
611
|
-
inputContainer.appendChild(input);
|
|
612
|
-
inputContainer.appendChild(btn);
|
|
613
|
-
div.appendChild(labelEl);
|
|
614
|
-
div.appendChild(inputContainer);
|
|
615
|
-
return div;
|
|
616
|
-
}
|
|
617
548
|
/* Move to a Dock Spawn Helper */
|
|
618
549
|
activateDockById(name) {
|
|
619
550
|
this.activateDock(this._getDomElement(name));
|