Commit 29d52914 authored by Steven Bennetts's avatar Steven Bennetts Committed by Commit Bot

Use mojo in network-apnlist

This CL:
* Introduces <network-property-list-mojo>
* Uses the mojo element and mojo properties in <network-apnlist>

Follow-up CLs will use <network-property-list-mojo> more broadly.

Bug: 853953
Change-Id: I25ed760ecb8bfaa88936cbf88271c6c74525f41f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1758490
Commit-Queue: Steven Bennetts <stevenjb@chromium.org>
Reviewed-by: default avatarKyle Horimoto <khorimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#690238}
parent ea8f8edd
...@@ -118,8 +118,8 @@ ...@@ -118,8 +118,8 @@
<!-- APN (Cellular only) --> <!-- APN (Cellular only) -->
<template is="dom-if" if="[[isCellular_(managedProperties_)]]"> <template is="dom-if" if="[[isCellular_(managedProperties_)]]">
<div class="section single-column"> <div class="section single-column">
<network-apnlist editable on-apn-change="onNetworkPropertyChange_" <network-apnlist editable on-apn-change="onApnChange_"
network-properties="[[networkProperties]]"> managed-properties="[[managedProperties_]]">
</network-apnlist> </network-apnlist>
</div> </div>
</template> </template>
...@@ -163,8 +163,7 @@ ...@@ -163,8 +163,7 @@
<div class="section single-column indented"> <div class="section single-column indented">
<network-property-list <network-property-list
fields="[[getInfoFields_(networkProperties)]]" fields="[[getInfoFields_(networkProperties)]]"
property-dict="[[networkProperties]]" property-dict="[[networkProperties]]">
on-property-change="onNetworkPropertyChange_">
</network-property-list> </network-property-list>
</div> </div>
</template> </template>
......
...@@ -272,6 +272,24 @@ Polymer({ ...@@ -272,6 +272,24 @@ Polymer({
}); });
}, },
/**
* @param {!mojom.ConfigProperties} config
* @private
*/
setMojoNetworkProperties_: function(config) {
if (!this.networkPropertiesReceived_ || !this.guid) {
return;
}
this.networkConfig_.setProperties(this.guid, config).then(response => {
if (!response.success) {
console.error('Unable to set properties: ' + JSON.stringify(config));
// An error typically indicates invalid input; request the properties
// to update any invalid fields.
this.getNetworkDetails_();
}
});
},
/** /**
* @return {!chrome.networkingPrivate.NetworkConfigProperties} An ONC * @return {!chrome.networkingPrivate.NetworkConfigProperties} An ONC
* dictionary with just the Type property set. Used for passing properties * dictionary with just the Type property set. Used for passing properties
...@@ -469,24 +487,16 @@ Polymer({ ...@@ -469,24 +487,16 @@ Polymer({
}, },
/** /**
* Event triggered for elements associated with network properties. * @param {!CustomEvent<!mojom.ApnProperties>} event
* @param {!CustomEvent<!{field: string, value: (string|!Object)}>} event
* @private * @private
*/ */
onNetworkPropertyChange_: function(event) { onApnChange_: function(event) {
if (!this.networkProperties) { if (!this.networkPropertiesReceived_) {
return;
}
const field = event.detail.field;
const value = event.detail.value;
const onc = this.getEmptyNetworkProperties_();
if (field == 'APN') {
CrOnc.setTypeProperty(onc, 'APN', value);
} else {
console.error('Unexpected property change event: ' + field);
return; return;
} }
this.setNetworkProperties_(onc); const apn = event.detail;
const config = {cellular: {apn: apn}};
this.setMojoNetworkProperties_(config);
}, },
/** /**
......
...@@ -303,8 +303,8 @@ ...@@ -303,8 +303,8 @@
<!-- APN --> <!-- APN -->
<template is="dom-if" if="[[isCellular_(managedProperties_)]]"> <template is="dom-if" if="[[isCellular_(managedProperties_)]]">
<network-apnlist on-apn-change="onNetworkPropertyChange_" <network-apnlist on-apn-change="onApnChange_"
network-properties="[[networkProperties_]]"> managed-properties="[[managedProperties_]]">
</network-apnlist> </network-apnlist>
</template> </template>
......
...@@ -1160,30 +1160,38 @@ Polymer({ ...@@ -1160,30 +1160,38 @@ Polymer({
const field = e.detail.field; const field = e.detail.field;
const value = e.detail.value; const value = e.detail.value;
const onc = this.getEmptyNetworkProperties_(); const onc = this.getEmptyNetworkProperties_();
if (field == 'APN') {
CrOnc.setTypeProperty(onc, 'APN', value);
} else {
const valueType = typeof value; const valueType = typeof value;
if (valueType == 'string' || valueType == 'number' || if (valueType != 'string' && valueType != 'number' &&
valueType == 'boolean' || Array.isArray(value)) { valueType != 'boolean' && !Array.isArray(value)) {
console.error(
'Unexpected property change event, Key: ' + field +
' Value: ' + JSON.stringify(value));
return;
}
CrOnc.setProperty(onc, field, value); CrOnc.setProperty(onc, field, value);
// Ensure any required configuration properties are also set. // Ensure any required configuration properties are also set.
if (field.match(/^VPN/)) { if (field.match(/^VPN/)) {
const vpnType = const vpnType = CrOnc.getActiveValue(this.networkProperties_.VPN.Type);
CrOnc.getActiveValue(this.networkProperties_.VPN.Type);
assert(vpnType); assert(vpnType);
CrOnc.setProperty(onc, 'VPN.Type', vpnType); CrOnc.setProperty(onc, 'VPN.Type', vpnType);
} }
} else { this.setNetworkProperties_(onc);
console.error( },
'Unexpected property change event, Key: ' + field +
' Value: ' + JSON.stringify(value)); /**
* @param {!CustomEvent<!mojom.ApnProperties>} event
* @private
*/
onApnChange_: function(event) {
if (!this.networkPropertiesReceived_) {
return; return;
} }
} const apn = event.detail;
this.setNetworkProperties_(onc); const config = {cellular: {apn: apn}};
this.setMojoNetworkProperties_(config);
}, },
/** /**
* Event triggered when the IP Config or NameServers element changes. * Event triggered when the IP Config or NameServers element changes.
* @param {!CustomEvent<!{ * @param {!CustomEvent<!{
......
...@@ -19,6 +19,7 @@ js_type_check("closure_compile") { ...@@ -19,6 +19,7 @@ js_type_check("closure_compile") {
":network_nameservers", ":network_nameservers",
":network_password_input", ":network_password_input",
":network_property_list", ":network_property_list",
":network_property_list_mojo",
":network_proxy", ":network_proxy",
":network_proxy_exclusions", ":network_proxy_exclusions",
":network_proxy_input", ":network_proxy_input",
...@@ -35,7 +36,7 @@ js_library("mojo_interface_provider") { ...@@ -35,7 +36,7 @@ js_library("mojo_interface_provider") {
js_library("network_apnlist") { js_library("network_apnlist") {
deps = [ deps = [
"//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types", "//ui/webui/resources/cr_components/chromeos/network:network_config",
"//ui/webui/resources/js:i18n_behavior", "//ui/webui/resources/js:i18n_behavior",
] ]
} }
...@@ -126,6 +127,15 @@ js_library("network_property_list") { ...@@ -126,6 +127,15 @@ js_library("network_property_list") {
] ]
} }
js_library("network_property_list_mojo") {
deps = [
"//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior_mojo",
"//ui/webui/resources/js:assert",
"//ui/webui/resources/js:i18n_behavior",
"//ui/webui/resources/js/chromeos:onc_mojo",
]
}
js_library("network_proxy") { js_library("network_proxy") {
deps = [ deps = [
"//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types", "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
......
<link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_onc_types.html">
<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html"> <link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html"> <link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/cr_elements/md_select_css.html"> <link rel="import" href="chrome://resources/cr_elements/md_select_css.html">
<link rel="import" href="network_property_list.html"> <link rel="import" href="network_property_list_mojo.html">
<link rel="import" href="network_shared_css.html"> <link rel="import" href="network_shared_css.html">
<dom-module id="network-apnlist"> <dom-module id="network-apnlist">
...@@ -20,17 +19,17 @@ ...@@ -20,17 +19,17 @@
value="[[selectedApn_]]" value="[[selectedApn_]]"
aria-label="[[i18n('networkAccessPoint')]]"> aria-label="[[i18n('networkAccessPoint')]]">
<template is="dom-repeat" items="[[apnSelectList_]]"> <template is="dom-repeat" items="[[apnSelectList_]]">
<option value="[[item.AccessPointName]]">[[apnDesc_(item)]]</option> <option value="[[item.accessPointName]]">[[apnDesc_(item)]]</option>
</template> </template>
</select> </select>
</div> </div>
<div class="property-box single-column indented" <div class="property-box single-column indented"
hidden$="[[!isOtherSelected_(selectedApn_, networkProperties)]]"> hidden$="[[!isOtherSelected_(selectedApn_, managedProperties)]]">
<network-property-list on-property-change="onOtherApnChange_" <network-property-list-mojo on-property-change="onOtherApnChange_"
fields="[[otherApnFields_]]" property-dict="[[otherApn_]]" fields="[[otherApnFields_]]" property-dict="[[otherApn_]]"
edit-field-types="[[otherApnEditTypes_]]" prefix="Cellular.APN."> edit-field-types="[[otherApnEditTypes_]]" prefix="cellular.apn.">
</network-property-list> </network-property-list-mojo>
<cr-button class="action-button" on-click="onSaveOtherTap_"> <cr-button class="action-button" on-click="onSaveOtherTap_">
[[i18n('save')]] [[i18n('save')]]
</cr-button> </cr-button>
......
...@@ -6,23 +6,26 @@ ...@@ -6,23 +6,26 @@
* @fileoverview Polymer element for displaying and modifying a list of cellular * @fileoverview Polymer element for displaying and modifying a list of cellular
* access points. * access points.
*/ */
(function() {
'use strict';
const kDefaultAccessPointName = 'NONE';
const kOtherAccessPointName = 'Other';
Polymer({ Polymer({
is: 'network-apnlist', is: 'network-apnlist',
behaviors: [I18nBehavior], behaviors: [I18nBehavior],
properties: { properties: {
/** /** @private {!chromeos.networkConfig.mojom.ManagedProperties|undefined} */
* The current set of properties for the network matching |guid|. managedProperties: {
* @type {!CrOnc.NetworkProperties|undefined}
*/
networkProperties: {
type: Object, type: Object,
observer: 'networkPropertiesChanged_', observer: 'managedPropertiesChanged_',
}, },
/** /**
* The CrOnc.APNProperties.AccessPointName value of the selected APN. * accessPointName value of the selected APN.
* @private * @private
*/ */
selectedApn_: { selectedApn_: {
...@@ -33,7 +36,7 @@ Polymer({ ...@@ -33,7 +36,7 @@ Polymer({
/** /**
* Selectable list of APN dictionaries for the UI. Includes an entry * Selectable list of APN dictionaries for the UI. Includes an entry
* corresponding to |otherApn| (see below). * corresponding to |otherApn| (see below).
* @private {!Array<!CrOnc.APNProperties>} * @private {!Array<!chromeos.networkConfig.mojom.ApnProperties>}
*/ */
apnSelectList_: { apnSelectList_: {
type: Array, type: Array,
...@@ -44,9 +47,9 @@ Polymer({ ...@@ -44,9 +47,9 @@ Polymer({
/** /**
* The user settable properties for a new ('other') APN. The values for * The user settable properties for a new ('other') APN. The values for
* AccessPointName, Username, and Password will be set to the currently * accessPointName, username, and password will be set to the currently
* active APN if it does not match an existing list entry. * active APN if it does not match an existing list entry.
* @private {CrOnc.APNProperties|undefined} * @private {chromeos.networkConfig.mojom.ApnProperties|undefined}
*/ */
otherApn_: { otherApn_: {
type: Object, type: Object,
...@@ -59,7 +62,7 @@ Polymer({ ...@@ -59,7 +62,7 @@ Polymer({
otherApnFields_: { otherApnFields_: {
type: Array, type: Array,
value: function() { value: function() {
return ['AccessPointName', 'Username', 'Password']; return ['accessPointName', 'username', 'password'];
}, },
readOnly: true readOnly: true
}, },
...@@ -72,35 +75,41 @@ Polymer({ ...@@ -72,35 +75,41 @@ Polymer({
type: Object, type: Object,
value: function() { value: function() {
return { return {
'AccessPointName': 'String', 'accessPointName': 'String',
'Username': 'String', 'username': 'String',
'Password': 'Password' 'password': 'Password'
}; };
}, },
readOnly: true readOnly: true
}, },
}, },
/** @const */
DefaultAccessPointName: 'NONE',
/** /**
* Polymer networkProperties changed method. * @param {!chromeos.networkConfig.mojom.ManagedApnProperties} apn
* @return {!chromeos.networkConfig.mojom.ApnProperties}
* @private
*/ */
networkPropertiesChanged_: function() { getApnFromManaged_: function(apn) {
if (!this.networkProperties || !this.networkProperties.Cellular) { return {
return; accessPointName: OncMojo.getActiveString(apn.accessPointName),
} authentication: OncMojo.getActiveString(apn.authentication),
language: OncMojo.getActiveString(apn.language),
localizedName: OncMojo.getActiveString(apn.localizedName),
name: OncMojo.getActiveString(apn.name),
password: OncMojo.getActiveString(apn.password),
username: OncMojo.getActiveString(apn.username),
};
},
/** @type {!CrOnc.APNProperties|undefined} */ let activeApn; /** @private*/
const cellular = this.networkProperties.Cellular; managedPropertiesChanged_: function() {
/** @type {!chrome.networkingPrivate.ManagedAPNProperties|undefined} */ const cellular = this.managedProperties.cellular;
const apn = cellular.APN; /** @type {!chromeos.networkConfig.mojom.ApnProperties|undefined} */ let
if (apn && apn.AccessPointName) { activeApn;
activeApn = /** @type {!CrOnc.APNProperties|undefined} */ ( if (cellular.apn) {
CrOnc.getActiveProperties(apn)); activeApn = this.getApnFromManaged_(cellular.apn);
} else if (cellular.LastGoodAPN && cellular.LastGoodAPN.AccessPointName) { } else if (cellular.lastGoodApn && cellular.lastGoodApn.accessPointName) {
activeApn = cellular.LastGoodAPN; activeApn = cellular.lastGoodApn;
} }
this.setApnSelectList_(activeApn); this.setApnSelectList_(activeApn);
}, },
...@@ -108,17 +117,17 @@ Polymer({ ...@@ -108,17 +117,17 @@ Polymer({
/** /**
* Sets the list of selectable APNs for the UI. Appends an 'Other' entry * Sets the list of selectable APNs for the UI. Appends an 'Other' entry
* (see comments for |otherApn_| above). * (see comments for |otherApn_| above).
* @param {CrOnc.APNProperties|undefined} activeApn The currently active APN * @param {chromeos.networkConfig.mojom.ApnProperties|undefined} activeApn The
* properties. * currently active APN properties.
* @private * @private
*/ */
setApnSelectList_: function(activeApn) { setApnSelectList_: function(activeApn) {
// Copy the list of APNs from this.networkProperties. // Copy the list of APNs from this.managedProperties.
const result = this.getApnList_().slice(); const apnList = this.getApnList_().slice();
// Test whether |activeApn| is in the current APN list in networkProperties. // Test whether |activeApn| is in the current APN list in managedProperties.
const activeApnInList = activeApn && result.some(function(a) { const activeApnInList = activeApn && apnList.some(function(a) {
return a.AccessPointName == activeApn.AccessPointName; return a.accessPointName == activeApn.accessPointName;
}); });
// If |activeApn| is specified and not in the list, use the active // If |activeApn| is specified and not in the list, use the active
...@@ -129,34 +138,36 @@ Polymer({ ...@@ -129,34 +138,36 @@ Polymer({
// Always use 'Other' for the name of custom APN entries (the name does // Always use 'Other' for the name of custom APN entries (the name does
// not get saved). // not get saved).
otherApn.Name = 'Other'; otherApn.name = kOtherAccessPointName;
// If no 'active' or 'other' AccessPointName was provided, use the default. // If no 'active' or 'other' AccessPointName was provided, use the default.
otherApn.AccessPointName = otherApn.accessPointName =
otherApn.AccessPointName || this.DefaultAccessPointName; otherApn.accessPointName || kDefaultAccessPointName;
// Save the 'other' properties. // Save the 'other' properties.
this.otherApn_ = otherApn; this.otherApn_ = otherApn;
// Append 'other' to the end of the list of APNs. // Append 'other' to the end of the list of APNs.
result.push(otherApn); apnList.push(otherApn);
this.apnSelectList_ = apnList;
this.apnSelectList_ = result;
// Set selectedApn_ after dom-repeat has been stamped. // Set selectedApn_ after dom-repeat has been stamped.
this.async(() => { this.async(() => {
this.selectedApn_ = this.selectedApn_ =
(activeApn && activeApn.AccessPointName) || otherApn.AccessPointName; (activeApn && activeApn.accessPointName) || otherApn.accessPointName;
}); });
}, },
/** /**
* @param {!CrOnc.APNProperties|undefined=} apnProperties * @param {!chromeos.networkConfig.mojom.ApnProperties|undefined=}
* @return {!CrOnc.APNProperties} A new APN object with properties from * apnProperties
* |apnProperties| if provided. * @return {!chromeos.networkConfig.mojom.ApnProperties} A new APN object with
* properties from |apnProperties| if provided.
* @private * @private
*/ */
createApnObject_: function(apnProperties) { createApnObject_: function(apnProperties) {
const newApn = {AccessPointName: ''}; const newApn = {accessPointName: ''};
if (apnProperties) { if (apnProperties) {
Object.assign(newApn, apnProperties); Object.assign(newApn, apnProperties);
} }
...@@ -164,21 +175,20 @@ Polymer({ ...@@ -164,21 +175,20 @@ Polymer({
}, },
/** /**
* @return {!Array<!CrOnc.APNProperties>} The list of APN properties in * @return {!Array<!chromeos.networkConfig.mojom.ApnProperties>} The list of
* |networkProperties| or an empty list if the property is not set. * APN properties in |managedProperties| or an empty list if the property
* is not set.
* @private * @private
*/ */
getApnList_: function() { getApnList_: function() {
if (!this.networkProperties || !this.networkProperties.Cellular) { if (!this.managedProperties) {
return []; return [];
} }
/** @type {!chrome.networkingPrivate.ManagedAPNList|undefined} */ const apnList = this.managedProperties.cellular.apnList;
const apnlist = this.networkProperties.Cellular.APNList; if (!apnList) {
if (!apnlist) {
return []; return [];
} }
return /** @type {!Array<!CrOnc.APNProperties>} */ ( return apnList.activeValue;
CrOnc.getActiveValue(apnlist));
}, },
/** /**
...@@ -192,8 +202,8 @@ Polymer({ ...@@ -192,8 +202,8 @@ Polymer({
// When selecting 'Other', don't set a change event unless a valid // When selecting 'Other', don't set a change event unless a valid
// non-default value has been set for Other. // non-default value has been set for Other.
if (this.isOtherSelected_(accessPointName) && if (this.isOtherSelected_(accessPointName) &&
(!this.otherApn_ || !this.otherApn_.AccessPointName || (!this.otherApn_ || !this.otherApn_.accessPointName ||
this.otherApn_.AccessPointName == this.DefaultAccessPointName)) { this.otherApn_.accessPointName == kDefaultAccessPointName)) {
this.selectedApn_ = accessPointName; this.selectedApn_ = accessPointName;
return; return;
} }
...@@ -206,9 +216,9 @@ Polymer({ ...@@ -206,9 +216,9 @@ Polymer({
* @private * @private
*/ */
onOtherApnChange_: function(event) { onOtherApnChange_: function(event) {
// TODO(benchan/stevenjb): Move this to shill or // TODO(benchan/stevenjb): Move the toUpperCase logic to shill or
// onc_translator_onc_to_shill.cc. // onc_translator_onc_to_shill.cc.
const value = (event.detail.field == 'AccessPointName') ? const value = (event.detail.field == 'accessPointName') ?
event.detail.value.toUpperCase() : event.detail.value.toUpperCase() :
event.detail.value; event.detail.value;
this.set('otherApn_.' + event.detail.field, value); this.set('otherApn_.' + event.detail.field, value);
...@@ -231,16 +241,16 @@ Polymer({ ...@@ -231,16 +241,16 @@ Polymer({
*/ */
sendApnChange_: function(accessPointName) { sendApnChange_: function(accessPointName) {
const apnList = this.getApnList_(); const apnList = this.getApnList_();
let apn = this.findApnInList(apnList, accessPointName); let apn = this.findApnInList_(apnList, accessPointName);
if (apn == undefined) { if (apn == undefined) {
apn = this.createApnObject_(); apn = this.createApnObject_();
if (this.otherApn_) { if (this.otherApn_) {
apn.AccessPointName = this.otherApn_.AccessPointName; apn.accessPointName = this.otherApn_.accessPointName;
apn.Username = this.otherApn_.Username; apn.username = this.otherApn_.username;
apn.Password = this.otherApn_.Password; apn.password = this.otherApn_.password;
} }
} }
this.fire('apn-change', {field: 'APN', value: apn}); this.fire('apn-change', apn);
}, },
/** /**
...@@ -249,33 +259,34 @@ Polymer({ ...@@ -249,33 +259,34 @@ Polymer({
* @private * @private
*/ */
isOtherSelected_: function(accessPointName) { isOtherSelected_: function(accessPointName) {
if (!this.networkProperties || !this.networkProperties.Cellular) { if (!this.managedProperties) {
return false; return false;
} }
const apnList = this.getApnList_(); const apnList = this.getApnList_();
const apn = this.findApnInList(apnList, accessPointName); const apn = this.findApnInList_(apnList, accessPointName);
return apn == undefined; return apn == undefined;
}, },
/** /**
* @param {!CrOnc.APNProperties} apn * @param {!chromeos.networkConfig.mojom.ApnProperties} apn
* @return {string} The most descriptive name for the access point. * @return {string} The most descriptive name for the access point.
* @private * @private
*/ */
apnDesc_: function(apn) { apnDesc_: function(apn) {
return apn.LocalizedName || apn.Name || apn.AccessPointName; return apn.localizedName || apn.name || apn.accessPointName;
}, },
/** /**
* @param {!Array<!CrOnc.APNProperties>} apnList * @param {!Array<!chromeos.networkConfig.mojom.ApnProperties>} apnList
* @param {string} accessPointName * @param {string} accessPointName
* @return {CrOnc.APNProperties|undefined} The entry in |apnList| matching * @return {chromeos.networkConfig.mojom.ApnProperties|undefined} The entry in
* |accessPointName| if it exists, or undefined. * |apnList| matching |accessPointName| if it exists, or undefined.
* @private * @private
*/ */
findApnInList: function(apnList, accessPointName) { findApnInList_: function(apnList, accessPointName) {
return apnList.find(function(a) { return apnList.find(function(a) {
return a.AccessPointName == accessPointName; return a.accessPointName == accessPointName;
}); });
} }
}); });
})();
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior_mojo.html">
<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_indicator_mojo.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
<link rel="import" href="network_shared_css.html">
<dom-module id="network-property-list-mojo">
<template>
<style include="network-shared iron-flex">
/* Property lists are embedded; remove the padding. */
.property-box {
padding: 0;
}
cr-input[readonly] {
--cr-input-background-color: transparent;
}
cr-policy-network-indicator {
margin-inline-start: var(--settings-controlled-by-spacing);
}
</style>
<template is="dom-repeat" items="[[fields]]"
filter="[[computeFilter_(prefix, propertyDict, editFieldTypes)]]">
<div class="property-box single-column two-line stretch">
<!-- Property label -->
<div class="layout horizontal center">
<div>[[getPropertyLabel_(item, prefix)]]</div>
<template is="dom-if" restamp
if="[[isEditType_(item, editFieldTypes)]]">
<cr-policy-network-indicator-mojo
property="[[getProperty_(item, propertyDict)]]">
</cr-policy-network-indicator-mojo>
</template>
</div>
<!-- Uneditable property value -->
<template is="dom-if" restamp
if="[[!showEditable_(item, propertyDict, editFieldTypes)]]">
<div class="secondary">
[[getPropertyValue_(item, prefix, propertyDict)]]
</div>
</template>
<!-- Editable property value -->
<template is="dom-if" restamp
if="[[showEditable_(item, propertyDict, editFieldTypes)]]">
<cr-input id="[[item]]"
readonly="[[!isEditable_(item, propertyDict, editFieldTypes)]]"
value="[[getPropertyValue_(item, prefix, propertyDict)]]"
on-change="onValueChange_"
type="[[getEditInputType_(item, editFieldTypes)]]">
</cr-input>
</template>
</div>
</template>
</template>
<script src="network_property_list_mojo.js"></script>
</dom-module>
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview Polymer element for displaying a list of network properties
* in a list. This also supports editing fields inline for fields listed in
* editFieldTypes.
*/
(function() {
'use strict';
Polymer({
is: 'network-property-list-mojo',
behaviors: [I18nBehavior, CrPolicyNetworkBehaviorMojo],
properties: {
/**
* The dictionary containing the properties to display.
* @type {!Object|undefined}
*/
propertyDict: {type: Object},
/**
* Fields to display.
* @type {!Array<string>}
*/
fields: {
type: Array,
value: function() {
return [];
},
},
/**
* Edit type of editable fields. May contain a property for any field in
* |fields|. Other properties will be ignored. Property values can be:
* 'String' - A text input will be displayed.
* 'StringArray' - A text input will be displayed that expects a comma
* separated list of strings.
* 'Password' - A string with input type = password.
* When a field changes, the 'property-change' event will be fired with
* the field name and the new value provided in the event detail.
* @type {!Object<string>}
*/
editFieldTypes: {
type: Object,
value: function() {
return {};
},
},
/** Prefix used to look up property key translations. */
prefix: {
type: String,
value: '',
},
},
/**
* Event triggered when an input field changes. Fires a 'property-change'
* event with the field (property) name set to the target id, and the value
* set to the target input value.
* @param {!Event} event The input change event.
* @private
*/
onValueChange_: function(event) {
if (!this.propertyDict) {
return;
}
const key = event.target.id;
let curValue = this.get(key, this.propertyDict);
if (typeof curValue == 'object' && !Array.isArray(curValue)) {
// Extract the property from an ONC managed dictionary.
curValue = OncMojo.getActiveValue(
/** @type{OncMojo.ManagedProperty} */ (curValue));
}
const newValue = this.getValueFromEditField_(key, event.target.value);
if (newValue == curValue) {
return;
}
this.fire('property-change', {field: key, value: newValue});
},
/**
* Converts mojo keys to ONC keys. TODO(stevenjb): Remove this and update
* string ids once everything is converted to mojo.
* @param {string} key
* @param {string=} opt_prefix
* @return {string}
* @private
*/
getOncKey_: function(key, opt_prefix) {
if (opt_prefix) {
key = opt_prefix + key.charAt(0).toUpperCase() + key.slice(1);
}
let result = '';
const subKeys = key.split('.');
subKeys.forEach(subKey => {
// Check for exceptions to CamelCase vs camelCase naming conventions.
if (subKey == 'apn') {
result += 'APN-';
} else {
result += subKey.charAt(0).toUpperCase() + subKey.slice(1) + '-';
}
});
return 'Onc' + result.slice(0, result.length - 1);
},
/**
* @param {string} key The property key.
* @param {string} prefix
* @return {string} The text to display for the property label.
* @private
*/
getPropertyLabel_: function(key, prefix) {
const oncKey = this.getOncKey_(key, prefix);
if (this.i18nExists(oncKey)) {
return this.i18n(oncKey);
}
// We do not provide translations for every possible network property key.
// For keys specific to a type, strip the type prefix.
const result = prefix + key;
for (const type of ['cellular', 'ethernet', 'tether', 'vpn', 'wifi']) {
if (result.startsWith(type + '.')) {
return result.substr(type.length + 1);
}
}
return result;
},
/**
* Generates a filter function dependent on propertyDict and editFieldTypes.
* @param {string} prefix
* @param {!Object} propertyDict
* @param {!Object} editFieldTypes
* @return {!Object} A filter used by dom-repeat.
* @private
*/
computeFilter_: function(prefix, propertyDict, editFieldTypes) {
return key => {
if (editFieldTypes.hasOwnProperty(key)) {
return true;
}
const value = this.getPropertyValue_(key, prefix, propertyDict);
return value !== undefined && value !== '';
};
},
/**
* @param {string} key The property key.
* @param {!Object} propertyDict
* @return {boolean}
* @private
*/
isPropertyEditable_: function(key, propertyDict) {
if (!propertyDict) {
return false;
}
const property =
/** @type{OncMojo.ManagedProperty|undefined} */ (
this.get(key, propertyDict));
if (property === undefined) {
// Unspecified properties in policy configurations are not user
// modifiable. https://crbug.com/819837.
const source = propertyDict.source;
return source != chromeos.networkConfig.mojom.OncSource.kUserPolicy &&
source != chromeos.networkConfig.mojom.OncSource.kDevicePolicy;
}
return !this.isNetworkPolicyEnforced(property);
},
/**
* @param {string} key The property key.
* @param {!Object} editFieldTypes
* @return {boolean} True if the edit type for the key is a valid type.
* @private
*/
isEditType_: function(key, editFieldTypes) {
const editType = editFieldTypes[key];
return editType == 'String' || editType == 'StringArray' ||
editType == 'Password';
},
/**
* @param {string} key The property key.
* @param {!Object} propertyDict
* @param {!Object} editFieldTypes
* @return {boolean}
* @private
*/
isEditable_: function(key, propertyDict, editFieldTypes) {
return propertyDict && this.isEditType_(key, editFieldTypes) &&
this.isPropertyEditable_(key, propertyDict);
},
/**
* @param {string} key The property key.
* @param {!Object} propertyDict
* @param {!Object} editFieldTypes
* @return {boolean}
* @private
*/
showEditable_: function(key, propertyDict, editFieldTypes) {
return this.isEditable_(key, propertyDict, editFieldTypes);
},
/**
* @param {string} key The property key.
* @param {!Object} editFieldTypes
* @return {string}
* @private
*/
getEditInputType_: function(key, editFieldTypes) {
return editFieldTypes[key] == 'Password' ? 'password' : 'text';
},
/**
* @param {string} key The property key.
* @param {!Object} propertyDict
* @return {*} The managed property dictionary associated with |key|.
* @private
*/
getProperty_: function(key, propertyDict) {
const property = this.get(key, this.propertyDict);
if (property === undefined) {
// If the dictionary is policy controlled, provide an empty property
// object with the network policy source. See https://crbug.com/819837 for
// more info.
const source = propertyDict.source;
if (source == chromeos.networkConfig.mojom.OncSource.kUserPolicy) {
return /** @type{!OncMojo.ManagedProperty} */ ({
activeValue: '',
policySource:
chromeos.networkConfig.mojom.PolicySource.kUserPolicyEnforced,
});
}
if (source == chromeos.networkConfig.mojom.OncSource.kDevicePolicy) {
return /** @type{!OncMojo.ManagedProperty} */ ({
activeValue: '',
policySource:
chromeos.networkConfig.mojom.PolicySource.kDevicePolicyEnforced,
});
}
// Otherwise just return undefined.
}
return property;
},
/**
* @param {string} key The property key.
* @param {string} prefix
* @param {!Object} propertyDict
* @return {string} The text to display for the property value.
* @private
*/
getPropertyValue_: function(key, prefix, propertyDict) {
let value = this.get(key, propertyDict);
if (value === undefined) {
return '';
}
if (typeof value == 'object' && !Array.isArray(value)) {
// Extract the property from an ONC managed dictionary
value = OncMojo.getActiveValue(
/** @type {!OncMojo.ManagedProperty} */ (value));
}
if (Array.isArray(value)) {
return value.join(', ');
}
const customValue = this.getCustomPropertyValue_(key, value);
if (customValue) {
return customValue;
}
if (typeof value == 'number' || typeof value == 'boolean') {
return value.toString();
}
assert(typeof value == 'string');
const valueStr = /** @type {string} */ (value);
const oncKey = this.getOncKey_(key, prefix) + '_' + valueStr;
if (this.i18nExists(oncKey)) {
return this.i18n(oncKey);
}
return valueStr;
},
/**
* Converts edit field values to the correct edit type.
* @param {string} key The property key.
* @param {*} fieldValue The value from the field.
* @return {*}
* @private
*/
getValueFromEditField_(key, fieldValue) {
const editType = this.editFieldTypes[key];
if (editType == 'StringArray') {
return fieldValue.toString().split(/, */);
}
return fieldValue;
},
/**
* @param {string} key The property key.
* @param {*} value The property value.
* @return {string} The text to display for the property value. If the key
* does not correspond to a custom property, an empty string is returned.
*/
getCustomPropertyValue_: function(key, value) {
if (key == 'tether.batteryPercentage') {
assert(typeof value == 'number');
return this.i18n('OncTether-BatteryPercentage_Value', value.toString());
}
if (key == 'tether.signalStrength') {
assert(typeof value == 'number');
// Possible |signalStrength| values should be 0, 25, 50, 75, and 100. Add
// <= checks for robustness.
if (value <= 24) {
return this.i18n('OncTether-SignalStrength_Weak');
}
if (value <= 49) {
return this.i18n('OncTether-SignalStrength_Okay');
}
if (value <= 74) {
return this.i18n('OncTether-SignalStrength_Good');
}
if (value <= 99) {
return this.i18n('OncTether-SignalStrength_Strong');
}
return this.i18n('OncTether-SignalStrength_VeryStrong');
}
if (key == 'tether.carrier') {
assert(typeof value == 'string');
return (!value || value == 'unknown-carrier') ?
this.i18n('tetherUnknownCarrier') :
value;
}
return '';
},
});
})();
...@@ -195,6 +195,14 @@ ...@@ -195,6 +195,14 @@
file="cr_components/chromeos/network/network_property_list.js" file="cr_components/chromeos/network/network_property_list.js"
type="chrome_html" type="chrome_html"
compress="gzip" /> compress="gzip" />
<structure name="IDR_WEBUI_CHROMEOS_NETWORK_PROPERTY_LIST_MOJO_HTML"
file="cr_components/chromeos/network/network_property_list_mojo.html"
type="chrome_html"
compress="gzip" />
<structure name="IDR_WEBUI_CHROMEOS_NETWORK_PROPERTY_LIST_MOJO_JS"
file="cr_components/chromeos/network/network_property_list_mojo.js"
type="chrome_html"
compress="gzip" />
<structure name="IDR_WEBUI_CHROMEOS_NETWORK_PROXY_HTML" <structure name="IDR_WEBUI_CHROMEOS_NETWORK_PROXY_HTML"
file="cr_components/chromeos/network/network_proxy.html" file="cr_components/chromeos/network/network_proxy.html"
type="chrome_html" type="chrome_html"
......
...@@ -9,8 +9,6 @@ ...@@ -9,8 +9,6 @@
(function() { (function() {
'use strict'; 'use strict';
const mojom = chromeos.networkConfig.mojom;
Polymer({ Polymer({
is: 'cr-policy-network-indicator-mojo', is: 'cr-policy-network-indicator-mojo',
...@@ -21,8 +19,9 @@ Polymer({ ...@@ -21,8 +19,9 @@ Polymer({
* Network property associated with the indicator. Note: |property| may * Network property associated with the indicator. Note: |property| may
* be null or undefined, depending on how the properties dictionary is * be null or undefined, depending on how the properties dictionary is
* generated. * generated.
* @type {?mojom.ManagedBoolean|?mojom.ManagedInt32|?mojom.ManagedString| * @type {?chromeos.networkConfig.mojom.ManagedBoolean|
* undefined} * ?chromeos.networkConfig.mojom.ManagedInt32|
* ?chromeos.networkConfig.mojom.ManagedString|undefined}
*/ */
property: Object, property: Object,
...@@ -46,21 +45,22 @@ Polymer({ ...@@ -46,21 +45,22 @@ Polymer({
this.indicatorType = CrPolicyIndicatorType.NONE; this.indicatorType = CrPolicyIndicatorType.NONE;
return; return;
} }
const PolicySource = chromeos.networkConfig.mojom.PolicySource;
switch (property.policySource) { switch (property.policySource) {
case mojom.PolicySource.kNone: case PolicySource.kNone:
this.indicatorType = CrPolicyIndicatorType.NONE; this.indicatorType = CrPolicyIndicatorType.NONE;
break; break;
case mojom.PolicySource.kUserPolicyEnforced: case PolicySource.kUserPolicyEnforced:
this.indicatorType = CrPolicyIndicatorType.USER_POLICY; this.indicatorType = CrPolicyIndicatorType.USER_POLICY;
break; break;
case mojom.PolicySource.kDevicePolicyEnforced: case PolicySource.kDevicePolicyEnforced:
this.indicatorType = CrPolicyIndicatorType.DEVICE_POLICY; this.indicatorType = CrPolicyIndicatorType.DEVICE_POLICY;
break; break;
case mojom.PolicySource.kUserPolicyRecommended: case PolicySource.kUserPolicyRecommended:
case mojom.PolicySource.kDevicePolicyRecommended: case PolicySource.kDevicePolicyRecommended:
this.indicatorType = CrPolicyIndicatorType.RECOMMENDED; this.indicatorType = CrPolicyIndicatorType.RECOMMENDED;
break; break;
case mojom.PolicySource.kActiveExtension: case PolicySource.kActiveExtension:
this.indicatorType = CrPolicyIndicatorType.EXTENSION; this.indicatorType = CrPolicyIndicatorType.EXTENSION;
break; break;
} }
......
...@@ -662,8 +662,11 @@ class OncMojo { ...@@ -662,8 +662,11 @@ class OncMojo {
/** /**
* @param {!chromeos.networkConfig.mojom.ManagedBoolean| * @param {!chromeos.networkConfig.mojom.ManagedBoolean|
* !chromeos.networkConfig.mojom.ManagedInt32| * !chromeos.networkConfig.mojom.ManagedInt32|
* !chromeos.networkConfig.mojom.ManagedString|undefined} property * !chromeos.networkConfig.mojom.ManagedString|
* @return {boolean|number|string|undefined} * !chromeos.networkConfig.mojom.ManagedStringList|
* !chromeos.networkConfig.mojom.ManagedApnList|undefined} property
* @return {boolean|number|string|!Array<string>|
* !Array<!chromeos.networkConfig.mojom.ApnProperties>|undefined}
*/ */
static getActiveValue(property) { static getActiveValue(property) {
if (!property) { if (!property) {
......
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