summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoranitawoodruff@chromium.org <anitawoodruff@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-20 18:24:14 +0000
committeranitawoodruff@chromium.org <anitawoodruff@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-20 18:24:14 +0000
commit5ef5e68e9a1d7ef50c3efc0b8f6fffa50be0b02b (patch)
tree78f7631b17db22d44cfb61cff81af88644313a0f
parent16a274f342161d245e7e37f9932726dfab951fd8 (diff)
downloadchromium_src-5ef5e68e9a1d7ef50c3efc0b8f6fffa50be0b02b.zip
chromium_src-5ef5e68e9a1d7ef50c3efc0b8f6fffa50be0b02b.tar.gz
chromium_src-5ef5e68e9a1d7ef50c3efc0b8f6fffa50be0b02b.tar.bz2
Adding extension policies to chrome://policy page
Currently, only Chrome policies are displayed on the chrome://policy page. This fix also displays any configured policies which exist for individual extensions, listed by extension id. BUG=248533 Review URL: https://chromiumcodereview.appspot.com/16689004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@207487 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/resources/policy.css46
-rw-r--r--chrome/browser/resources/policy.html36
-rw-r--r--chrome/browser/resources/policy.js171
-rw-r--r--chrome/browser/ui/webui/policy_ui.cc105
-rw-r--r--chrome/browser/ui/webui/policy_ui_browsertest.cc2
5 files changed, 287 insertions, 73 deletions
diff --git a/chrome/browser/resources/policy.css b/chrome/browser/resources/policy.css
index 990d55f..cdf701d 100644
--- a/chrome/browser/resources/policy.css
+++ b/chrome/browser/resources/policy.css
@@ -56,24 +56,52 @@ div.label {
}
#show-unset-container {
+ float: right;
text-align: right;
}
html[dir='rtl'] #show-unset-container {
+ float: left;
text-align: left;
}
+div.reload-policies-button {
+ float: left;
+}
+
+html[dir='rtl'] div.reload-policies-button {
+ float: right;
+}
+
+div.show-unset-checkbox {
+ float: right;
+}
+
+html[dir='rtl'] div.show-unset-checkbox {
+ float: left;
+}
+
+section.reload-show-unset-section {
+ padding-bottom: 30px;
+ padding-top: 15px;
+}
+
+section.status-box-section {
+ clear: both;
+}
+
+div.table-description {
+ color: rgb(100, 100, 100);
+}
+
div.no-policies-set {
color: rgb(180, 180, 180);
font-size: 125%;
- margin-top: 70px;
+ margin-bottom: 10px;
+ margin-top: 20px;
text-align: center;
}
-section:not(.empty) > div.no-policies-set {
- display: none;
-}
-
table {
border-collapse: collapse;
margin-bottom: 5px;
@@ -86,6 +114,14 @@ section.empty > table {
display: none;
}
+section:not(.empty) > div.no-policies-set {
+ display: none;
+}
+
+section.policy-table-section {
+ padding-bottom: 10px;
+}
+
th,
td {
border: 1px solid rgb(217, 217, 217);
diff --git a/chrome/browser/resources/policy.html b/chrome/browser/resources/policy.html
index bba2afc..fff1829 100644
--- a/chrome/browser/resources/policy.html
+++ b/chrome/browser/resources/policy.html
@@ -29,33 +29,23 @@
<header>
<h1 i18n-content="title"></h1>
</header>
- <section>
- <button id="reload-policies" i18n-content="reloadPolicies"></button>
- </section>
- <section id="status" hidden>
- <h3 i18n-content="status"></h3>
- <div id="status-box-container"></span>
- </section>
- <section class="empty">
- <h3 i18n-content="title"></h3>
- <div id="show-unset-container">
+ <section class="reload-show-unset-section">
+ <div class="reload-policies-button">
+ <button id="reload-policies" i18n-content="reloadPolicies"></button>
+ </div>
+ <div id="show-unset-container" class="show-unset-checkbox">
<label>
<input id="show-unset" type="checkbox"></input>
<span i18n-content="showUnset"></span>
</label>
</div>
- <div class="no-policies-set" i18n-content="noPoliciesSet"></div>
- <table id="policy-table">
- <thead>
- <tr>
- <th i18n-content="headerScope"></th>
- <th i18n-content="headerLevel"></th>
- <th i18n-content="headerName"></th>
- <th i18n-content="headerValue"></th>
- <th i18n-content="headerStatus"></th>
- </tr>
- </thead>
- </table>
+ </section>
+ <section id="status-section" class="status-box-section" hidden>
+ <h3 i18n-content="status"></h3>
+ <div id="status-box-container"></div>
+ </section>
+ <section id="main-section" class="empty">
+ <!-- This is where policy tables get dynamically added. -->
</section>
</div>
<div hidden>
@@ -104,7 +94,7 @@
<button class="toggle-expanded-value link-button"></button>
</div>
</td>
- <td>
+ <td class="status-container">
<div class="status elide"></div>
</td>
</tr>
diff --git a/chrome/browser/resources/policy.js b/chrome/browser/resources/policy.js
index 2c52c61..a044bc9 100644
--- a/chrome/browser/resources/policy.js
+++ b/chrome/browser/resources/policy.js
@@ -88,8 +88,9 @@ cr.define('policy', function() {
* @param {string} name The policy name.
* @param {Object} value Dictionary with information about the policy value.
* @param {boolean} unknown Whether the policy name is not recognized.
+ * @param {boolean} includeStatus Whether the table has a status column.
*/
- initialize: function(name, value, unknown) {
+ initialize: function(name, value, unknown, includeStatus) {
this.name = name;
this.unset = !value;
@@ -109,23 +110,29 @@ cr.define('policy', function() {
this.querySelector('.expanded-value').textContent = value.value;
}
- // Populate the status column.
- var status;
- if (!value) {
- // If the policy value has not been set, show an error message.
- status = loadTimeData.getString('unset');
- } else if (unknown) {
- // If the policy name is not recognized, show an error message.
- status = loadTimeData.getString('unknown');
- } else if (value.error) {
- // If an error occurred while parsing the policy value, show the error
- // message.
- status = value.error;
+ if (includeStatus) {
+ // Populate the status column.
+ var status;
+ if (!value) {
+ // If the policy value has not been set, show an error message.
+ status = loadTimeData.getString('unset');
+ } else if (unknown) {
+ // If the policy name is not recognized, show an error message.
+ status = loadTimeData.getString('unknown');
+ } else if (value.error) {
+ // If an error occurred while parsing the policy value, show the error
+ // message.
+ status = value.error;
+ } else {
+ // Otherwise, indicate that the policy value was parsed correctly.
+ status = loadTimeData.getString('ok');
+ }
+ this.querySelector('.status').textContent = status;
} else {
- // Otherwise, indicate that the policy value was parsed correctly.
- status = loadTimeData.getString('ok');
+ // Remove status column.
+ this.querySelector('.status-container').remove();
+ this.querySelector('.expanded-value').setAttribute('colspan', 4);
}
- this.querySelector('.status').textContent = status;
},
/**
@@ -298,7 +305,8 @@ cr.define('policy', function() {
*/
setPolicyValue_: function(name, value, unknown) {
var policy = new Policy;
- policy.initialize(name, value, unknown);
+ var includeStatus = this.querySelector('.status-column') != null;
+ policy.initialize(name, value, unknown, includeStatus);
this.appendChild(policy);
},
};
@@ -319,7 +327,8 @@ cr.define('policy', function() {
* @param {Object} names Dictionary containing all known policy names.
*/
Page.setPolicyNames = function(names) {
- this.getInstance().policyTable.setPolicyNames(names);
+ var table = this.getInstance().policyTables['chrome'];
+ table.setPolicyNames(names);
};
/**
@@ -329,7 +338,21 @@ cr.define('policy', function() {
* @param {Object} values Dictionary containing the current policy values.
*/
Page.setPolicyValues = function(values) {
- this.getInstance().policyTable.setPolicyValues(values);
+ var page = this.getInstance();
+
+ if (values.hasOwnProperty('chromePolicies')) {
+ var table = page.policyTables['chrome'];
+ table.setPolicyValues(values.chromePolicies);
+ }
+
+ if (values.hasOwnProperty('extensionPolicies')) {
+ for (var extensionId in values.extensionPolicies) {
+ var tableName = values.extensionPolicies[extensionId].name;
+ var table = page.getOrCreateTable('extension-' + extensionId, tableName,
+ 'ID: ' + extensionId, false);
+ table.setPolicyValues(values.extensionPolicies[extensionId].policies);
+ }
+ }
};
/**
@@ -355,21 +378,32 @@ cr.define('policy', function() {
*/
initialize: function() {
uber.onContentFrameLoaded();
- this.policyTable = $('policy-table');
- cr.ui.decorate(this.policyTable, PolicyTable);
+
+ this.mainSection = $('main-section');
+ this.policyTables = {};
+
+ var chromeTable = this.getOrCreateTable('chrome', 'Chrome policies', '',
+ true);
// Place the initial focus on the filter input field.
$('filter').focus();
var self = this;
$('filter').onsearch = function(event) {
- self.policyTable.setFilterPattern(this.value);
+ for (policyTable in self.policyTables) {
+ self.policyTables[policyTable].setFilterPattern(this.value);
+ }
};
$('reload-policies').onclick = function(event) {
this.disabled = true;
chrome.send('reloadPolicies');
};
- $('show-unset').onchange = this.policyTable.filter.bind(this.policyTable);
+
+ $('show-unset').onchange = function() {
+ for (policyTable in self.policyTables) {
+ self.policyTables[policyTable].filter();
+ }
+ };
// Notify the browser that the page has loaded, causing it to send the
// list of all known policies, the current policy values and the cloud
@@ -378,6 +412,95 @@ cr.define('policy', function() {
},
/**
+ * Gets the existing policy table for the given id, or if none exists,
+ * creates a new policy table section, adds the section to the page,
+ * and returns the new table from that section.
+ * @param {string} id The key for the table in policyTables.
+ * @param {string} label_title Title for this policy table.
+ * @param {string} label_content Description for the policy table.
+ * @return {Element} Policy table associated with the given id.
+ */
+ getOrCreateTable: function(id, label_title, label_content, includeStatus) {
+ if (!this.policyTables.hasOwnProperty(id)) {
+ var newSection = this.createPolicyTableSection(id, label_title,
+ label_content, includeStatus);
+ this.mainSection.appendChild(newSection);
+ }
+ return this.policyTables[id];
+ },
+
+ /**
+ * Creates a new section containing a title, description and table of
+ * policies.
+ * @param {string} id Used as key when storing new table in policyTables.
+ * @param {string} label_title Title for this policy table.
+ * @param {string} label_content Description for the policy table.
+ * @param {boolean} includeStatus Whether to display a status column.
+ * @return {Element} The newly created section.
+ */
+ createPolicyTableSection: function(id, label_title, label_content,
+ includeStatus) {
+ var section = document.createElement('section');
+ section.setAttribute('class', 'policy-table-section');
+
+ // Add title and description.
+ var title = window.document.createElement('h3');
+ title.textContent = label_title;
+ section.appendChild(title);
+
+ if (label_content) {
+ var description = window.document.createElement('div');
+ description.classList.add('table-description');
+ description.textContent = label_content;
+ section.appendChild(description);
+ }
+
+ // Add 'No Policies Set' element.
+ var noPolicies = window.document.createElement('div');
+ noPolicies.classList.add('no-policies-set');
+ noPolicies.textContent = loadTimeData.getString('noPoliciesSet');
+ section.appendChild(noPolicies);
+
+ // Add table of policies.
+ var newTable = this.createPolicyTable(includeStatus);
+ this.policyTables[id] = newTable;
+ section.appendChild(newTable);
+
+ return section;
+ },
+
+ /**
+ * Creates a new table for displaying policies.
+ * @param {boolean} includeStatus Whether to include a status column.
+ * @return {Element} The newly created table.
+ */
+ createPolicyTable: function(includeStatus) {
+ var newTable = window.document.createElement('table');
+ var tableHead = window.document.createElement('thead');
+ var tableRow = window.document.createElement('tr');
+ var tableHeadings = ['headerScope', 'headerLevel',
+ 'headerName', 'headerValue'];
+
+ for (var i = 0; i < tableHeadings.length; i++) {
+ var tableHeader = window.document.createElement('th');
+ tableHeader.textContent = loadTimeData.getString(tableHeadings[i]);
+ tableRow.appendChild(tableHeader);
+ }
+
+ if (includeStatus) {
+ var statusHeader = window.document.createElement('th');
+ statusHeader.classList.add('status-column');
+ statusHeader.textContent = loadTimeData.getString('headerStatus');
+ tableRow.appendChild(statusHeader);
+ }
+
+ tableHead.appendChild(tableRow);
+ newTable.appendChild(tableHead);
+ cr.ui.decorate(newTable, PolicyTable);
+ return newTable;
+ },
+
+ /**
* Update the status section of the page to show the current cloud policy
* status.
* @param {Object} status Dictionary containing the current policy status.
@@ -388,7 +511,7 @@ cr.define('policy', function() {
while (container.firstChild)
container.removeChild(container.firstChild);
// Hide the status section.
- var section = $('status');
+ var section = $('status-section');
section.hidden = true;
// Add a status box for each scope that has a cloud policy status.
diff --git a/chrome/browser/ui/webui/policy_ui.cc b/chrome/browser/ui/webui/policy_ui.cc
index 2ee0e85..f6358e4 100644
--- a/chrome/browser/ui/webui/policy_ui.cc
+++ b/chrome/browser/ui/webui/policy_ui.cc
@@ -15,6 +15,8 @@
#include "base/time.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/policy/browser_policy_connector.h"
#include "chrome/browser/policy/cloud/cloud_policy_client.h"
#include "chrome/browser/policy/cloud/cloud_policy_constants.h"
@@ -32,6 +34,9 @@
#include "chrome/browser/policy/profile_policy_connector_factory.h"
#include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_set.h"
+#include "chrome/common/extensions/manifest.h"
#include "chrome/common/time_format.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/web_ui.h"
@@ -286,6 +291,14 @@ class PolicyUIHandler : public content::WebUIMessageHandler,
// information is sent.
void SendStatus() const;
+ // Inserts a description of each policy in |policy_map| into |values|, using
+ // the optional errors in |errors| to determine the status of each policy.
+ void GetPolicyValues(const policy::PolicyMap& policy_map,
+ policy::PolicyErrorMap* errors,
+ base::DictionaryValue* values) const;
+
+ void GetChromePolicyValues(base::DictionaryValue* values) const;
+
void HandleInitialized(const base::ListValue* args);
void HandleReloadPolicies(const base::ListValue* args);
@@ -425,6 +438,7 @@ PolicyUIHandler::PolicyUIHandler()
PolicyUIHandler::~PolicyUIHandler() {
GetPolicyService()->RemoveObserver(policy::POLICY_DOMAIN_CHROME, this);
+ GetPolicyService()->RemoveObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
}
void PolicyUIHandler::RegisterMessages() {
@@ -472,6 +486,7 @@ void PolicyUIHandler::RegisterMessages() {
user_status_provider_->SetStatusChangeCallback(update_callback);
device_status_provider_->SetStatusChangeCallback(update_callback);
GetPolicyService()->AddObserver(policy::POLICY_DOMAIN_CHROME, this);
+ GetPolicyService()->AddObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
web_ui()->RegisterMessageCallback(
"initialized",
@@ -485,8 +500,6 @@ void PolicyUIHandler::RegisterMessages() {
void PolicyUIHandler::OnPolicyUpdated(const policy::PolicyNamespace& ns,
const policy::PolicyMap& previous,
const policy::PolicyMap& current) {
- DCHECK_EQ(policy::POLICY_DOMAIN_CHROME, ns.domain);
- DCHECK(ns.component_id.empty());
SendPolicyValues();
}
@@ -502,24 +515,56 @@ void PolicyUIHandler::SendPolicyNames() const {
}
void PolicyUIHandler::SendPolicyValues() const {
- // Make a copy that can be modified, since some policy values are modified
- // before being displayed.
- policy::PolicyMap map;
- map.CopyFrom(GetPolicyService()->GetPolicies(policy::PolicyNamespace(
- policy::POLICY_DOMAIN_CHROME, std::string())));
-
- // Get a list of all the errors in the policy values.
- const policy::ConfigurationPolicyHandlerList* handler_list =
- g_browser_process->browser_policy_connector()->GetHandlerList();
- policy::PolicyErrorMap errors;
- handler_list->ApplyPolicySettings(map, NULL, &errors);
+ base::DictionaryValue all_policies;
+
+ // Add chrome policies.
+ base::DictionaryValue* chrome_policies = new base::DictionaryValue;
+ GetChromePolicyValues(chrome_policies);
+ all_policies.Set("chromePolicies", chrome_policies);
+
+ // Get extensions.
+ extensions::ExtensionSystem* extension_system =
+ extensions::ExtensionSystem::Get(Profile::FromWebUI(web_ui()));
+ const ExtensionSet* extensions =
+ extension_system->extension_service()->extensions();
+
+ // Add policies for each extension.
+ base::DictionaryValue* extension_values = new base::DictionaryValue;
+ for (ExtensionSet::const_iterator it = extensions->begin();
+ it != extensions->end(); ++it) {
+ const extensions::Extension* extension = *it;
+
+ // Skip this extension if it's a component extension.
+ if (extension->location() == extensions::Manifest::COMPONENT)
+ continue;
+
+ base::DictionaryValue* extension_value = new base::DictionaryValue;
+
+ // Add name.
+ extension_value->SetString("name", extension->name());
+
+ // Add policies.
+ base::DictionaryValue* extension_policies = new base::DictionaryValue;
+ policy::PolicyNamespace policy_namespace = policy::PolicyNamespace(
+ policy::POLICY_DOMAIN_EXTENSIONS, extension->id());
+ policy::PolicyErrorMap empty_error_map;
+ GetPolicyValues(GetPolicyService()->GetPolicies(policy_namespace),
+ &empty_error_map, extension_policies);
+ extension_value->Set("policies", extension_policies);
+
+ // Add entry to the dictionary.
+ extension_values->Set(extension->id(), extension_value);
+ }
+ all_policies.Set("extensionPolicies", extension_values);
- // Convert dictionary values to strings for display.
- handler_list->PrepareForDisplaying(&map);
+ web_ui()->CallJavascriptFunction("policy.Page.setPolicyValues", all_policies);
+}
- base::DictionaryValue values;
+void PolicyUIHandler::GetPolicyValues(const policy::PolicyMap& map,
+ policy::PolicyErrorMap* errors,
+ base::DictionaryValue* values) const {
for (policy::PolicyMap::const_iterator entry = map.begin();
- entry != map.end(); ++entry) {
+ entry != map.end(); ++entry) {
base::DictionaryValue* value = new base::DictionaryValue;
value->Set("value", entry->second.value->DeepCopy());
if (entry->second.scope == policy::POLICY_SCOPE_USER)
@@ -530,13 +575,33 @@ void PolicyUIHandler::SendPolicyValues() const {
value->SetString("level", "recommended");
else
value->SetString("level", "mandatory");
- string16 error = errors.GetErrors(entry->first);
+ string16 error = errors->GetErrors(entry->first);
if (!error.empty())
value->SetString("error", error);
- values.Set(entry->first, value);
+ values->Set(entry->first, value);
}
+}
+
+void PolicyUIHandler::GetChromePolicyValues(
+ base::DictionaryValue* values) const {
+ policy::PolicyService* policy_service = GetPolicyService();
+ policy::PolicyMap map;
+
+ // Make a copy that can be modified, since some policy values are modified
+ // before being displayed.
+ map.CopyFrom(policy_service->GetPolicies(
+ policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string())));
+
+ // Get a list of all the errors in the policy values.
+ const policy::ConfigurationPolicyHandlerList* handler_list =
+ g_browser_process->browser_policy_connector()->GetHandlerList();
+ policy::PolicyErrorMap errors;
+ handler_list->ApplyPolicySettings(map, NULL, &errors);
+
+ // Convert dictionary values to strings for display.
+ handler_list->PrepareForDisplaying(&map);
- web_ui()->CallJavascriptFunction("policy.Page.setPolicyValues", values);
+ GetPolicyValues(map, &errors, values);
}
void PolicyUIHandler::SendStatus() const {
diff --git a/chrome/browser/ui/webui/policy_ui_browsertest.cc b/chrome/browser/ui/webui/policy_ui_browsertest.cc
index 13fc4ff..2d8193f 100644
--- a/chrome/browser/ui/webui/policy_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/policy_ui_browsertest.cc
@@ -122,7 +122,7 @@ void PolicyUITest::VerifyPolicies(
// Retrieve the text contents of the policy table cells for all policies.
const std::string javascript =
"var entries = document.querySelectorAll("
- " 'table#policy-table > tbody');"
+ " 'section.policy-table-section > * > tbody');"
"var policies = [];"
"for (var i = 0; i < entries.length; ++i) {"
" var items = entries[i].querySelectorAll('tr > td');"