[mv3] Add ability for admins to disable features

New managed setting:

"disabledFeatures": {
  "title": "User interface features to disable",
  "description": "A list of tokens, each of which correspond to a user interface feature to disable.",
  "type": "array",
  "items": { "type": "string" }
}

Supported tokens:
- `dashboard`: Prevent access to all dashboard settings
- `filteringMode`: Prevent changes to the default filtering mode,
  or the current filtering mode of any site

Related feedback:
https://github.com/uBlockOrigin/uBOL-home/discussions/35#discussioncomment-11326086
This commit is contained in:
Raymond Hill 2024-11-23 13:17:13 -05:00
parent 4979aa51f5
commit 346b5ded7c
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
9 changed files with 80 additions and 7 deletions

View File

@ -13,7 +13,7 @@
border-radius: 30% 15% / 15% 30%;
height: 100%;
position: absolute;
width: 25%;
width: calc(25% + 2px);
z-index: 10;
}
@ -39,12 +39,18 @@
.filteringModeSlider span[data-level] {
background-color: var(--accent-surface-1);
border: 1px solid var(--accent-surface-1);
box-sizing: border-box;
display: inline-flex;
height: 30%;
margin-left: 1px;
width: 25%;
}
.filteringModeSlider span[data-level]:first-of-type {
margin-left: 0;
}
.filteringModeSlider.moving span[data-level] {
pointer-events: none;
}
@ -53,13 +59,13 @@
left: 0;
}
.filteringModeSlider[data-level="1"] .filteringModeButton {
left: 25%;
left: calc(25% - 1px);
}
.filteringModeSlider[data-level="2"] .filteringModeButton {
left: 50%;
left: calc(50% - 1px);
}
.filteringModeSlider[data-level="3"] .filteringModeButton {
left: 75%;
left: calc(75% - 1px);
}
[dir="rtl"] .filteringModeSlider[data-level="0"] .filteringModeButton {
left: 75%;
@ -77,14 +83,17 @@
.filteringModeSlider[data-level="0"] span[data-level] {
background-color: var(--surface-2);
border-color: var(--surface-2);
}
.filteringModeSlider[data-level="1"] span[data-level]:nth-of-type(1) ~ span[data-level] {
background-color: var(--surface-2);
border-color: var(--surface-2);
}
.filteringModeSlider[data-level="2"] span[data-level]:nth-of-type(2) ~ span[data-level] {
background-color: var(--surface-2);
border-color: var(--surface-2);
}
.filteringModeSlider[data-level]:not(.moving) span[data-level]:hover {

View File

@ -63,6 +63,13 @@ hr {
font-weight: 600;
}
body[data-forbid~="filteringMode"] .filteringModeSlider {
pointer-events: none;
}
body[data-forbid~="dashboard"] #gotoDashboard {
display: none;
}
#filteringModeText {
color: var(--ink-3);
margin: var(--default-gap-small);

View File

@ -1,3 +1,6 @@
body.loading {
visibility: hidden;
}
body .firstRun {
display: none;
}
@ -13,6 +16,17 @@ p {
white-space: pre-line;
}
body[data-forbid~="dashboard"] #dashboard-nav [data-pane="settings"],
body[data-forbid~="dashboard"] section[data-pane="settings"],
body[data-forbid~="dashboard"] #dashboard-nav [data-pane="rulesets"],
body[data-forbid~="dashboard"] section[data-pane="rulesets"] {
display: none;
}
body[data-forbid~="filteringMode"] section[data-pane="settings"] > div:has(> h3[data-i18n="defaultFilteringModeSectionLabel"]),
body[data-forbid~="filteringMode"] section[data-pane="settings"] > div:has(> h3[data-i18n="filteringMode0Name"]) {
display: none;
}
#showBlockedCount:has(input[type="checkbox"][disabled]) {
opacity: 0.5;
}

View File

@ -16,7 +16,7 @@
<link rel="shortcut icon" type="image/png" href="img/icon_64.png"/>
</head>
<body data-pane="settings">
<body data-pane="settings" class="loading">
<!-- -------- -->
<div id="dashboard-nav">
<span class="logo"><img data-i18n-title="extName" src="img/ublock.svg" alt="uBO Lite"></span><!--

View File

@ -40,6 +40,11 @@ import {
windows,
} from './ext.js';
import {
adminReadEx,
getAdminRulesets,
} from './admin.js';
import {
enableRulesets,
getEnabledRulesetsDetails,
@ -62,7 +67,6 @@ import {
} from './config.js';
import { broadcastMessage } from './utils.js';
import { getAdminRulesets } from './admin.js';
import { registerInjectables } from './scripting-manager.js';
/******************************************************************************/
@ -189,6 +193,7 @@ function onMessage(request, sender, callback) {
getRulesetDetails(),
dnr.getEnabledRulesets(),
getAdminRulesets(),
adminReadEx('disabledFeatures'),
]).then(results => {
const [
defaultFilteringMode,
@ -196,6 +201,7 @@ function onMessage(request, sender, callback) {
rulesetDetails,
enabledRulesets,
adminRulesets,
disabledFeatures,
] = results;
callback({
defaultFilteringMode,
@ -210,6 +216,7 @@ function onMessage(request, sender, callback) {
firstRun: process.firstRun,
isSideloaded,
developerMode: rulesetConfig.developerMode,
disabledFeatures,
});
process.firstRun = false;
});
@ -251,6 +258,7 @@ function onMessage(request, sender, callback) {
hasOmnipotence(),
hasGreatPowers(request.origin),
getEnabledRulesetsDetails(),
adminReadEx('disabledFeatures'),
]).then(results => {
callback({
level: results[0],
@ -260,6 +268,7 @@ function onMessage(request, sender, callback) {
rulesetDetails: results[3],
isSideloaded,
developerMode: rulesetConfig.developerMode,
disabledFeatures: results[4],
});
});
return true;
@ -416,6 +425,11 @@ async function start() {
}
toggleDeveloperMode(rulesetConfig.developerMode);
// Required to ensure the up to date property is available when needed
if ( process.wakeupRun === false ) {
adminReadEx('disabledFeatures');
}
}
// https://github.com/uBlockOrigin/uBOL-home/issues/199

View File

@ -44,6 +44,14 @@ function normalizedHostname(hn) {
/******************************************************************************/
function renderAdminRules() {
const { disabledFeatures: forbid = [] } = popupPanelData;
if ( forbid.length === 0 ) { return; }
dom.body.dataset.forbid = forbid.join(' ');
}
/******************************************************************************/
const BLOCKING_MODE_MAX = 3;
function setFilteringMode(level, commit = false) {
@ -325,6 +333,8 @@ async function init() {
}
}
renderAdminRules();
setFilteringMode(popupPanelData.level);
dom.text('#hostname', punycode.toUnicode(tabHostname));

View File

@ -36,6 +36,17 @@ function hashFromIterable(iter) {
/******************************************************************************/
function renderAdminRules() {
const { disabledFeatures: forbid = [] } = cachedRulesetData;
if ( forbid.length === 0 ) { return; }
dom.body.dataset.forbid = forbid.join(' ');
if ( forbid.includes('dashboard') ) {
dom.body.dataset.pane = 'about';
}
}
/******************************************************************************/
function renderWidgets() {
if ( cachedRulesetData.firstRun ) {
dom.cl.add(dom.body, 'firstRun');
@ -256,8 +267,10 @@ sendMessage({
if ( !data ) { return; }
cachedRulesetData = data;
try {
renderAdminRules();
renderFilterLists(cachedRulesetData);
renderWidgets();
dom.cl.remove(dom.body, 'loading');
} catch(ex) {
}
listen();

View File

@ -16,6 +16,12 @@
"description": "Prefix a ruleset id with '+' to add, or '-' to remove. Use '-*' to disable all non-default lists.",
"type": "array",
"items": { "type": "string" }
},
"disabledFeatures": {
"title": "User interface features to disable",
"description": "A list of tokens, each of which correspond to a user interface feature to disable.",
"type": "array",
"items": { "type": "string" }
}
}
}

View File

@ -32,7 +32,7 @@
<span></span>
<span id="showMatchedRules" class="fa-icon tool" tabindex="0" title="Show matched rules">list-alt<span class="caption">Show matched rules</span></span>
<span id="reportFilterIssue" class="fa-icon tool enabled" data-i18n-title="popupTipReport">comment-alt<span class="caption" data-i18n="popupTipReport"></span></span>
<span class="fa-icon tool enabled" tabindex="0" data-i18n-title="popupTipDashboard">cogs<span class="caption" data-i18n="popupTipDashboard"></span></span>
<span id="gotoDashboard" class="fa-icon tool enabled" tabindex="0" data-i18n-title="popupTipDashboard">cogs<span class="caption" data-i18n="popupTipDashboard"></span></span>
</div>
<!-- -------- -->
<div id="rulesetStats" data-section="a">