iobroker.mywebui 1.37.33 → 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
|
@@ -403,43 +403,52 @@ export class IobrokerWebuiAppShell extends BaseCustomWebComponentConstructorAppe
|
|
|
403
403
|
const designItem = selectedItems[0];
|
|
404
404
|
const element = designItem.element;
|
|
405
405
|
|
|
406
|
-
// Read existing
|
|
407
|
-
const
|
|
406
|
+
// Read existing binding from bind-prop:hidden attribute
|
|
407
|
+
const bindAttr = element.getAttribute('bind-prop:hidden');
|
|
408
408
|
let existingBinding = null;
|
|
409
|
-
if (
|
|
410
|
-
const parsed = bindingsHelper.parseBinding(element, 'bind-
|
|
409
|
+
if (bindAttr != null) {
|
|
410
|
+
const parsed = bindingsHelper.parseBinding(element, 'bind-prop:hidden', bindAttr, 'property', 'bind-prop:');
|
|
411
411
|
if (parsed) existingBinding = parsed[1];
|
|
412
412
|
}
|
|
413
413
|
|
|
414
|
+
// Read group access control config from data attributes
|
|
415
|
+
const dataConfig = {
|
|
416
|
+
enabled: element.getAttribute('data-visibility-enabled') === 'true',
|
|
417
|
+
groups: element.getAttribute('data-visibility-groups')?.split(',').filter(g => g) || [],
|
|
418
|
+
action: element.getAttribute('data-visibility-action') || 'hide'
|
|
419
|
+
};
|
|
420
|
+
|
|
414
421
|
content.innerHTML = '';
|
|
415
422
|
|
|
416
|
-
//
|
|
417
|
-
const
|
|
418
|
-
|
|
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;';
|
|
419
426
|
|
|
420
|
-
const
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
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);
|
|
424
431
|
|
|
425
432
|
if (existingBinding) {
|
|
426
|
-
const statusSpan = document.createElement('span');
|
|
427
433
|
const sig = existingBinding.signal || (existingBinding.expression ? 'expr' : '?');
|
|
434
|
+
const statusSpan = document.createElement('span');
|
|
428
435
|
statusSpan.textContent = sig;
|
|
429
436
|
statusSpan.title = JSON.stringify(existingBinding);
|
|
430
437
|
statusSpan.style.cssText = 'font-size:10px;color:#555;max-width:90px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;';
|
|
431
|
-
|
|
438
|
+
bindRow.appendChild(statusSpan);
|
|
432
439
|
}
|
|
433
440
|
|
|
434
441
|
const bindBtn = document.createElement('button');
|
|
435
442
|
bindBtn.textContent = '□';
|
|
436
443
|
bindBtn.title = 'Open binding editor';
|
|
437
|
-
bindBtn.style.cssText =
|
|
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;';
|
|
438
447
|
bindBtn.onclick = () => {
|
|
439
|
-
const property = { name: 'hidden', propertyType: '
|
|
440
|
-
serviceContainer.config.openBindingsEditor(property, [designItem], existingBinding, '
|
|
448
|
+
const property = { name: 'hidden', propertyType: 'propertyAndAttribute' };
|
|
449
|
+
serviceContainer.config.openBindingsEditor(property, [designItem], existingBinding, 'property');
|
|
441
450
|
};
|
|
442
|
-
|
|
451
|
+
bindRow.appendChild(bindBtn);
|
|
443
452
|
|
|
444
453
|
if (existingBinding) {
|
|
445
454
|
const clearBtn = document.createElement('button');
|
|
@@ -447,13 +456,94 @@ export class IobrokerWebuiAppShell extends BaseCustomWebComponentConstructorAppe
|
|
|
447
456
|
clearBtn.title = 'Remove binding';
|
|
448
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;';
|
|
449
458
|
clearBtn.onclick = () => {
|
|
450
|
-
designItem.removeAttribute('bind-
|
|
459
|
+
designItem.removeAttribute('bind-prop:hidden');
|
|
451
460
|
this._updateVisibilityPanel();
|
|
452
461
|
};
|
|
453
|
-
|
|
462
|
+
bindRow.appendChild(clearBtn);
|
|
454
463
|
}
|
|
455
464
|
|
|
456
|
-
content.appendChild(
|
|
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');
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
// Enable checkbox
|
|
483
|
+
const enableDiv = document.createElement('div');
|
|
484
|
+
enableDiv.style.cssText = 'margin-bottom:10px;';
|
|
485
|
+
const enableLabel = document.createElement('label');
|
|
486
|
+
enableLabel.style.cssText = 'display:flex;align-items:center;gap:5px;cursor:pointer;font-size:12px;';
|
|
487
|
+
const enableCheck = document.createElement('input');
|
|
488
|
+
enableCheck.type = 'checkbox';
|
|
489
|
+
enableCheck.checked = dataConfig.enabled || false;
|
|
490
|
+
enableCheck.onchange = () => updateGroupConfig('enabled', enableCheck.checked);
|
|
491
|
+
enableLabel.appendChild(enableCheck);
|
|
492
|
+
enableLabel.appendChild(document.createTextNode('Enable Group Visibility Control'));
|
|
493
|
+
enableDiv.appendChild(enableLabel);
|
|
494
|
+
content.appendChild(enableDiv);
|
|
495
|
+
|
|
496
|
+
// Groups
|
|
497
|
+
const groupsDiv = document.createElement('div');
|
|
498
|
+
groupsDiv.style.cssText = 'margin-bottom:10px;';
|
|
499
|
+
const groupsLabel = document.createElement('label');
|
|
500
|
+
groupsLabel.style.cssText = 'font-size:11px;font-weight:600;display:block;margin-bottom:3px;color:#555;';
|
|
501
|
+
groupsLabel.textContent = 'Only for groups:';
|
|
502
|
+
groupsDiv.appendChild(groupsLabel);
|
|
503
|
+
|
|
504
|
+
const groupsList = document.createElement('div');
|
|
505
|
+
groupsList.style.cssText = 'max-height:100px;overflow-y:auto;border:1px solid #ccc;padding:6px;background:#fff;border-radius:3px;';
|
|
506
|
+
|
|
507
|
+
const userGroups = await iobrokerHandler.getUserGroups();
|
|
508
|
+
const selectedGroups = dataConfig.groups || [];
|
|
509
|
+
|
|
510
|
+
userGroups.forEach(group => {
|
|
511
|
+
const groupLabel = document.createElement('label');
|
|
512
|
+
groupLabel.style.cssText = 'display:flex;align-items:center;gap:5px;font-size:11px;padding:3px;cursor:pointer;';
|
|
513
|
+
const groupCheck = document.createElement('input');
|
|
514
|
+
groupCheck.type = 'checkbox';
|
|
515
|
+
groupCheck.checked = selectedGroups.includes(group.id);
|
|
516
|
+
groupCheck.onchange = () => {
|
|
517
|
+
let groups = [...dataConfig.groups];
|
|
518
|
+
if (groupCheck.checked) {
|
|
519
|
+
if (!groups.includes(group.id)) groups.push(group.id);
|
|
520
|
+
} else {
|
|
521
|
+
groups = groups.filter(g => g !== group.id);
|
|
522
|
+
}
|
|
523
|
+
updateGroupConfig('groups', groups);
|
|
524
|
+
};
|
|
525
|
+
groupLabel.appendChild(groupCheck);
|
|
526
|
+
groupLabel.appendChild(document.createTextNode(group.name));
|
|
527
|
+
groupsList.appendChild(groupLabel);
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
groupsDiv.appendChild(groupsList);
|
|
531
|
+
content.appendChild(groupsDiv);
|
|
532
|
+
|
|
533
|
+
// Action
|
|
534
|
+
const actionDiv = document.createElement('div');
|
|
535
|
+
actionDiv.style.cssText = 'margin-bottom:5px;';
|
|
536
|
+
const actionLabel = document.createElement('label');
|
|
537
|
+
actionLabel.style.cssText = 'font-size:11px;font-weight:600;display:block;margin-bottom:3px;color:#555;';
|
|
538
|
+
actionLabel.textContent = 'If user not in group:';
|
|
539
|
+
const actionSelect = document.createElement('select');
|
|
540
|
+
actionSelect.style.cssText = 'width:100%;padding:6px;font-size:12px;border:1px solid #ccc;border-radius:3px;';
|
|
541
|
+
actionSelect.innerHTML = '<option value="hide">hide</option><option value="disable">disable</option>';
|
|
542
|
+
actionSelect.value = dataConfig.action || 'hide';
|
|
543
|
+
actionSelect.onchange = () => updateGroupConfig('action', actionSelect.value);
|
|
544
|
+
actionDiv.appendChild(actionLabel);
|
|
545
|
+
actionDiv.appendChild(actionSelect);
|
|
546
|
+
content.appendChild(actionDiv);
|
|
457
547
|
}
|
|
458
548
|
/* Move to a Dock Spawn Helper */
|
|
459
549
|
activateDockById(name) {
|