Commit 5c654f86 authored by treib's avatar treib Committed by Commit bot

Update chrome://extensions for supervised users

This includes:
- new types of controlled-setting-indicator for children/supervised users
- corresponding new "controlled-by" strings
- passing the strings through the developerPrivate API, and removing the now-unnecessary installedByCustodian field

BUG=397951

Review URL: https://codereview.chromium.org/1051273002

Cr-Commit-Position: refs/heads/master@{#330928}
parent 72c35134
...@@ -5074,6 +5074,12 @@ Even if you have downloaded files from this website before, the website might ha ...@@ -5074,6 +5074,12 @@ Even if you have downloaded files from this website before, the website might ha
<message name="IDS_EXTENSIONS_LOCKED_SUPERVISED_USER" desc="The error message (either shown in the extensions UI or logged) informing a supervised user that extensions cannot be changed."> <message name="IDS_EXTENSIONS_LOCKED_SUPERVISED_USER" desc="The error message (either shown in the extensions UI or logged) informing a supervised user that extensions cannot be changed.">
Applications and extensions cannot be modified by supervised users. Applications and extensions cannot be modified by supervised users.
</message> </message>
<message name="IDS_EXTENSIONS_INSTALLED_BY_CHILD_CUSTODIAN" desc="The text in the extensions UI informing a child user that an extension was installed by their parent and cannot be changed.">
Installed by your parent.
</message>
<message name="IDS_EXTENSIONS_INSTALLED_BY_SUPERVISED_USER_CUSTODIAN" desc="The text in the extensions UI informing a supervised user that an extension was installed by their custodian and cannot be changed">
Installed by your custodian.
</message>
<message name="IDS_GET_MORE_EXTENSIONS" desc="The text for getting more extensions. Displayed at bottom of extension management page when there is at least one extension installed."> <message name="IDS_GET_MORE_EXTENSIONS" desc="The text for getting more extensions. Displayed at bottom of extension management page when there is at least one extension installed.">
Get more extensions Get more extensions
</message> </message>
...@@ -179,12 +179,14 @@ ...@@ -179,12 +179,14 @@
<structure type="chrome_scaled_image" name="IDR_CONTENT_TOP_LEFT_CORNER_MASK" file="common/content_top_left_corner_mask.png" /> <structure type="chrome_scaled_image" name="IDR_CONTENT_TOP_LEFT_CORNER_MASK" file="common/content_top_left_corner_mask.png" />
<structure type="chrome_scaled_image" name="IDR_CONTENT_TOP_RIGHT_CORNER" file="common/content_top_right_corner.png" /> <structure type="chrome_scaled_image" name="IDR_CONTENT_TOP_RIGHT_CORNER" file="common/content_top_right_corner.png" />
<structure type="chrome_scaled_image" name="IDR_CONTENT_TOP_RIGHT_CORNER_MASK" file="common/content_top_right_corner_mask.png" /> <structure type="chrome_scaled_image" name="IDR_CONTENT_TOP_RIGHT_CORNER_MASK" file="common/content_top_right_corner_mask.png" />
<structure type="chrome_scaled_image" name="IDR_CONTROLLED_SETTING_CHILD" file="common/controlled_setting_child.png" />
<structure type="chrome_scaled_image" name="IDR_CONTROLLED_SETTING_EXTENSION" file="common/controlled_setting_extension.png" /> <structure type="chrome_scaled_image" name="IDR_CONTROLLED_SETTING_EXTENSION" file="common/controlled_setting_extension.png" />
<structure type="chrome_scaled_image" name="IDR_CONTROLLED_SETTING_MANDATORY" file="common/controlled_setting_mandatory.png" /> <structure type="chrome_scaled_image" name="IDR_CONTROLLED_SETTING_MANDATORY" file="common/controlled_setting_mandatory.png" />
<structure type="chrome_scaled_image" name="IDR_CONTROLLED_SETTING_OWNER" file="common/controlled_setting_owner.png" /> <structure type="chrome_scaled_image" name="IDR_CONTROLLED_SETTING_OWNER" file="common/controlled_setting_owner.png" />
<if expr="chromeos"> <if expr="chromeos">
<structure type="chrome_scaled_image" name="IDR_CONTROLLED_SETTING_SHARED" file="cros/controlled_setting_shared.png" /> <structure type="chrome_scaled_image" name="IDR_CONTROLLED_SETTING_SHARED" file="cros/controlled_setting_shared.png" />
</if> </if>
<structure type="chrome_scaled_image" name="IDR_CONTROLLED_SETTING_SUPERVISED" file="common/controlled_setting_supervised.png" />
<structure type="chrome_scaled_image" name="IDR_COOKIE_ICON" file="common/cookie.png" /> <structure type="chrome_scaled_image" name="IDR_COOKIE_ICON" file="common/cookie.png" />
<structure type="chrome_scaled_image" name="IDR_COOKIE_STORAGE_ICON" file="common/cookie_storage.png" /> <structure type="chrome_scaled_image" name="IDR_COOKIE_STORAGE_ICON" file="common/cookie_storage.png" />
<if expr="chromeos"> <if expr="chromeos">
......
...@@ -257,6 +257,27 @@ void ExtensionInfoGenerator::CreateExtensionInfoHelper( ...@@ -257,6 +257,27 @@ void ExtensionInfoGenerator::CreateExtensionInfoHelper(
new std::string(l10n_util::GetStringUTF8(blacklist_text))); new std::string(l10n_util::GetStringUTF8(blacklist_text)));
} }
Profile* profile = Profile::FromBrowserContext(browser_context_);
bool is_policy_location = Manifest::IsPolicyLocation(extension.location());
if (is_policy_location || util::IsExtensionSupervised(&extension, profile)) {
info->controlled_info.reset(new developer::ControlledInfo());
if (is_policy_location) {
info->controlled_info->type = developer::CONTROLLER_TYPE_POLICY;
info->controlled_info->text =
l10n_util::GetStringUTF8(IDS_OPTIONS_INSTALL_LOCATION_ENTERPRISE);
} else if (profile->IsChild()) {
info->controlled_info->type = developer::CONTROLLER_TYPE_CHILD_CUSTODIAN;
info->controlled_info->text = l10n_util::GetStringUTF8(
IDS_EXTENSIONS_INSTALLED_BY_CHILD_CUSTODIAN);
} else {
info->controlled_info->type =
developer::CONTROLLER_TYPE_SUPERVISED_USER_CUSTODIAN;
info->controlled_info->text = l10n_util::GetStringUTF8(
IDS_EXTENSIONS_INSTALLED_BY_SUPERVISED_USER_CUSTODIAN);
}
}
// Dependent extensions. // Dependent extensions.
if (extension.is_shared_module()) { if (extension.is_shared_module()) {
scoped_ptr<ExtensionSet> dependent_extensions = scoped_ptr<ExtensionSet> dependent_extensions =
...@@ -302,10 +323,6 @@ void ExtensionInfoGenerator::CreateExtensionInfoHelper( ...@@ -302,10 +323,6 @@ void ExtensionInfoGenerator::CreateExtensionInfoHelper(
info->incognito_access.is_active = info->incognito_access.is_active =
util::IsIncognitoEnabled(extension.id(), browser_context_); util::IsIncognitoEnabled(extension.id(), browser_context_);
Profile* profile = Profile::FromBrowserContext(browser_context_);
info->installed_by_custodian =
util::IsExtensionSupervised(&extension, profile);
// Install warnings (only if unpacked and no error console). // Install warnings (only if unpacked and no error console).
if (!error_console_enabled && if (!error_console_enabled &&
Manifest::IsUnpackedLocation(extension.location())) { Manifest::IsUnpackedLocation(extension.location())) {
...@@ -391,11 +408,6 @@ void ExtensionInfoGenerator::CreateExtensionInfoHelper( ...@@ -391,11 +408,6 @@ void ExtensionInfoGenerator::CreateExtensionInfoHelper(
extensions::path_util::PrettifyPath(extension.path()).AsUTF8Unsafe())); extensions::path_util::PrettifyPath(extension.path()).AsUTF8Unsafe()));
} }
if (Manifest::IsPolicyLocation(extension.location())) {
info->policy_text.reset(new std::string(
l10n_util::GetStringUTF8(IDS_OPTIONS_INSTALL_LOCATION_ENTERPRISE)));
}
// Runs on all urls. // Runs on all urls.
info->run_on_all_urls.is_enabled = info->run_on_all_urls.is_enabled =
(FeatureSwitch::scripts_require_action()->IsEnabled() && (FeatureSwitch::scripts_require_action()->IsEnabled() &&
......
...@@ -639,7 +639,6 @@ cr.define('extensions', function() { ...@@ -639,7 +639,6 @@ cr.define('extensions', function() {
var trashTemplate = $('template-collection').querySelector('.trash'); var trashTemplate = $('template-collection').querySelector('.trash');
var trash = trashTemplate.cloneNode(true); var trash = trashTemplate.cloneNode(true);
trash.title = loadTimeData.getString('extensionUninstall'); trash.title = loadTimeData.getString('extensionUninstall');
trash.hidden = !extension.userMayModify;
trash.setAttribute('column-type', 'trash'); trash.setAttribute('column-type', 'trash');
trash.addEventListener('click', function(e) { trash.addEventListener('click', function(e) {
trash.classList.add('open'); trash.classList.add('open');
...@@ -702,19 +701,14 @@ cr.define('extensions', function() { ...@@ -702,19 +701,14 @@ cr.define('extensions', function() {
// Hack to keep the closure compiler happy about |remove|. // Hack to keep the closure compiler happy about |remove|.
// TODO(hcarmona): Remove this hack when the closure compiler is updated. // TODO(hcarmona): Remove this hack when the closure compiler is updated.
var node = /** @type {Element} */ (row); var node = /** @type {Element} */ (row);
node.classList.remove('policy-controlled', 'may-not-modify', node.classList.remove('controlled', 'may-not-remove');
'may-not-remove');
var classes = []; var classes = [];
if (!extension.userMayModify) { if (extension.controlledInfo) {
classes.push('policy-controlled', 'may-not-modify'); classes.push('controlled');
} else if (extension.dependentExtensions.length > 0) { } else if (!extension.userMayModify ||
classes.push('may-not-remove', 'may-not-modify'); extension.mustRemainInstalled ||
} else if (extension.mustRemainInstalled) { extension.dependentExtensions.length > 0) {
classes.push('may-not-remove'); classes.push('may-not-remove');
} else if (extension.disableReasons.suspiciousInstall ||
extension.disableReasons.corruptInstall ||
extension.disableReasons.updateRequired) {
classes.push('may-not-modify');
} }
row.classList.add.apply(row.classList, classes); row.classList.add.apply(row.classList, classes);
...@@ -850,32 +844,37 @@ cr.define('extensions', function() { ...@@ -850,32 +844,37 @@ cr.define('extensions', function() {
extension.disableReasons.suspiciousInstall || extension.disableReasons.suspiciousInstall ||
extension.disableReasons.corruptInstall || extension.disableReasons.corruptInstall ||
extension.disableReasons.updateRequired || extension.disableReasons.updateRequired ||
extension.installedByCustodian ||
extension.dependentExtensions.length > 0; extension.dependentExtensions.length > 0;
item.querySelector('input').disabled = enableCheckboxDisabled; item.querySelector('input').disabled = enableCheckboxDisabled;
item.querySelector('input').checked = isActive; item.querySelector('input').checked = isActive;
}); });
// Button for extensions controlled by policy. // Indicator for extensions controlled by policy.
var controlNode = row.querySelector('.enable-controls'); var controlNode = row.querySelector('.enable-controls');
var indicator = var indicator =
controlNode.querySelector('.controlled-extension-indicator'); controlNode.querySelector('.controlled-extension-indicator');
var needsIndicator = isOK && var needsIndicator = isOK && extension.controlledInfo;
!extension.userMayModify &&
extension.policyText;
// TODO(treib): If userMayModify is false, but policyText is empty, that
// indicates this extension is controlled by something else than
// enterprise policy (such as the profile being supervised). For now, just
// don't show the indicator in this case. We should really handle this
// better though (ie use a different text and icon).
if (needsIndicator && !indicator) { if (needsIndicator && !indicator) {
indicator = new cr.ui.ControlledIndicator(); indicator = new cr.ui.ControlledIndicator();
indicator.classList.add('controlled-extension-indicator'); indicator.classList.add('controlled-extension-indicator');
indicator.setAttribute('controlled-by', 'policy'); var ControllerType = chrome.developerPrivate.ControllerType;
var textPolicy = extension.policyText || ''; var controlledByStr = '';
indicator.setAttribute('textpolicy', textPolicy); switch (extension.controlledInfo.type) {
indicator.image.setAttribute('aria-label', textPolicy); case ControllerType.POLICY:
controlledByStr = 'policy';
break;
case ControllerType.CHILD_CUSTODIAN:
controlledByStr = 'child-custodian';
break;
case ControllerType.SUPERVISED_USER_CUSTODIAN:
controlledByStr = 'supervised-user-custodian';
break;
}
indicator.setAttribute('controlled-by', controlledByStr);
var text = extension.controlledInfo.text;
indicator.setAttribute('text' + controlledByStr, text);
indicator.image.setAttribute('aria-label', text);
controlNode.appendChild(indicator); controlNode.appendChild(indicator);
indicator.querySelector('div').setAttribute('column-type', indicator.querySelector('div').setAttribute('column-type',
'enterprise'); 'enterprise');
......
...@@ -401,7 +401,7 @@ html[dir='rtl'] #extension-settings .trash { ...@@ -401,7 +401,7 @@ html[dir='rtl'] #extension-settings .trash {
* remove it from the layout and make space for the controlled indicator. * remove it from the layout and make space for the controlled indicator.
* TODO(cschuet): rather than hide always replace it with something meaningful. * TODO(cschuet): rather than hide always replace it with something meaningful.
*/ */
.extension-list-item-wrapper.policy-controlled .trash { .extension-list-item-wrapper.controlled .trash {
display: none; display: none;
} }
......
...@@ -150,9 +150,21 @@ namespace developerPrivate { ...@@ -150,9 +150,21 @@ namespace developerPrivate {
ViewType type; ViewType type;
}; };
enum ControllerType {
POLICY,
CHILD_CUSTODIAN,
SUPERVISED_USER_CUSTODIAN
};
dictionary ControlledInfo {
ControllerType type;
DOMString text;
};
dictionary ExtensionInfo { dictionary ExtensionInfo {
boolean actionButtonHidden; boolean actionButtonHidden;
DOMString? blacklistText; DOMString? blacklistText;
ControlledInfo? controlledInfo;
DOMString[] dependentExtensions; DOMString[] dependentExtensions;
DOMString description; DOMString description;
DisableReasons disableReasons; DisableReasons disableReasons;
...@@ -162,7 +174,6 @@ namespace developerPrivate { ...@@ -162,7 +174,6 @@ namespace developerPrivate {
DOMString iconUrl; DOMString iconUrl;
DOMString id; DOMString id;
AccessModifier incognitoAccess; AccessModifier incognitoAccess;
boolean installedByCustodian;
DOMString[] installWarnings; DOMString[] installWarnings;
DOMString? launchUrl; DOMString? launchUrl;
Location location; Location location;
...@@ -173,7 +184,6 @@ namespace developerPrivate { ...@@ -173,7 +184,6 @@ namespace developerPrivate {
boolean offlineEnabled; boolean offlineEnabled;
OptionsPage? optionsPage; OptionsPage? optionsPage;
DOMString? path; DOMString? path;
DOMString? policyText;
DOMString? prettifiedPath; DOMString? prettifiedPath;
AccessModifier runOnAllUrls; AccessModifier runOnAllUrls;
RuntimeError[] runtimeErrors; RuntimeError[] runtimeErrors;
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
"isEnabled": true "isEnabled": true
}, },
"installWarnings": [ ], "installWarnings": [ ],
"installedByCustodian": false,
"location": "UNKNOWN", "location": "UNKNOWN",
"locationText": "Not from Chrome Web Store.", "locationText": "Not from Chrome Web Store.",
"manifestErrors": [ ], "manifestErrors": [ ],
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
"isEnabled": true "isEnabled": true
}, },
"installWarnings": [ ], "installWarnings": [ ],
"installedByCustodian": false,
"location": "UNKNOWN", "location": "UNKNOWN",
"locationText": "Not from Chrome Web Store.", "locationText": "Not from Chrome Web Store.",
"manifestErrors": [ ], "manifestErrors": [ ],
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
"isEnabled": true "isEnabled": true
}, },
"installWarnings": [ ], "installWarnings": [ ],
"installedByCustodian": false,
"location": "UNKNOWN", "location": "UNKNOWN",
"locationText": "Not from Chrome Web Store.", "locationText": "Not from Chrome Web Store.",
"manifestErrors": [ ], "manifestErrors": [ ],
......
...@@ -216,10 +216,28 @@ var HomePage; ...@@ -216,10 +216,28 @@ var HomePage;
*/ */
var ExtensionView; var ExtensionView;
/**
* @enum {string}
*/
chrome.developerPrivate.ControllerType = {
POLICY: 'POLICY',
CHILD_CUSTODIAN: 'CHILD_CUSTODIAN',
SUPERVISED_USER_CUSTODIAN: 'SUPERVISED_USER_CUSTODIAN',
};
/**
* @typedef {{
* type: !chrome.developerPrivate.ControllerType,
* text: string
* }}
*/
var ControlledInfo;
/** /**
* @typedef {{ * @typedef {{
* actionButtonHidden: boolean, * actionButtonHidden: boolean,
* blacklistText: (string|undefined), * blacklistText: (string|undefined),
* controlledInfo: (ControlledInfo|undefined),
* dependentExtensions: !Array<string>, * dependentExtensions: !Array<string>,
* description: string, * description: string,
* disableReasons: DisableReasons, * disableReasons: DisableReasons,
...@@ -229,7 +247,6 @@ var ExtensionView; ...@@ -229,7 +247,6 @@ var ExtensionView;
* iconUrl: string, * iconUrl: string,
* id: string, * id: string,
* incognitoAccess: AccessModifier, * incognitoAccess: AccessModifier,
* installedByCustodian: boolean,
* installWarnings: !Array<string>, * installWarnings: !Array<string>,
* launchUrl: (string|undefined), * launchUrl: (string|undefined),
* location: !chrome.developerPrivate.Location, * location: !chrome.developerPrivate.Location,
...@@ -240,7 +257,6 @@ var ExtensionView; ...@@ -240,7 +257,6 @@ var ExtensionView;
* offlineEnabled: boolean, * offlineEnabled: boolean,
* optionsPage: (OptionsPage|undefined), * optionsPage: (OptionsPage|undefined),
* path: (string|undefined), * path: (string|undefined),
* policyText: (string|undefined),
* prettifiedPath: (string|undefined), * prettifiedPath: (string|undefined),
* runOnAllUrls: AccessModifier, * runOnAllUrls: AccessModifier,
* runtimeErrors: !Array<RuntimeError>, * runtimeErrors: !Array<RuntimeError>,
......
...@@ -32,6 +32,14 @@ ...@@ -32,6 +32,14 @@
background-image: url(chrome://theme/IDR_CONTROLLED_SETTING_SHARED); background-image: url(chrome://theme/IDR_CONTROLLED_SETTING_SHARED);
} }
.controlled-setting-indicator[controlled-by='child-custodian'] > div {
background-image: url(chrome://theme/IDR_CONTROLLED_SETTING_CHILD);
}
.controlled-setting-indicator[controlled-by='supervised-user-custodian'] > div {
background-image: url(chrome://theme/IDR_CONTROLLED_SETTING_SUPERVISED);
}
.controlled-setting-indicator:-webkit-any([controlled-by='recommended'], .controlled-setting-indicator:-webkit-any([controlled-by='recommended'],
[controlled-by='hasRecommendation']) > div { [controlled-by='hasRecommendation']) > div {
background-image: url(chrome://theme/IDR_CONTROLLED_SETTING_MANDATORY); background-image: url(chrome://theme/IDR_CONTROLLED_SETTING_MANDATORY);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment