| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import './base_page.js'; |
| import './icons.html.js'; |
| import './shimless_rma_shared.css.js'; |
| import './strings.m.js'; |
| import 'chrome://resources/ash/common/network/network_config.js'; |
| import 'chrome://resources/ash/common/network/network_list.js'; |
| import 'chrome://resources/ash/common/cr_elements/cr_button/cr_button.js'; |
| import 'chrome://resources/ash/common/cr_elements/cr_dialog/cr_dialog.js'; |
| import 'chrome://resources/ash/common/cr_elements/icons.html.js'; |
| import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js'; |
| |
| import {assert} from 'chrome://resources/js/assert.js'; |
| import {NetworkConfigElement} from 'chrome://resources/ash/common/network/network_config.js'; |
| import {CrDialogElement} from 'chrome://resources/ash/common/cr_elements/cr_dialog/cr_dialog.js'; |
| import {I18nMixin} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js'; |
| |
| import {OncMojo} from 'chrome://resources/ash/common/network/onc_mojo.js'; |
| import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; |
| import {CrosNetworkConfigInterface as NetworkConfigServiceInterface, FilterType, NetworkStateProperties, NetworkFilter, NO_LIMIT, StartConnectResult} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js'; |
| import {ConnectionStateType, NetworkType} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js'; |
| import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; |
| |
| import {getNetworkConfigService, getShimlessRmaService} from './mojo_interface_provider.js'; |
| import {getTemplate} from './onboarding_network_page.html.js'; |
| import {ShimlessRmaServiceInterface, StateResult} from './shimless_rma.mojom-webui.js'; |
| import {enableNextButton, focusPageTitle} from './shimless_rma_util.js'; |
| import {createCustomEvent, SetNextButtonLabelEvent, SET_NEXT_BUTTON_LABEL} from './events.js'; |
| |
| declare global { |
| interface HTMLElementEventMap { |
| [SET_NEXT_BUTTON_LABEL]: SetNextButtonLabelEvent; |
| } |
| } |
| |
| /** |
| * @fileoverview |
| * 'onboarding-network-page' is the page where the user can choose to join a |
| * network. |
| */ |
| |
| const OnboardingNetworkPageBase = I18nMixin(PolymerElement); |
| |
| export class OnboardingNetworkPage extends OnboardingNetworkPageBase { |
| static get is() { |
| return 'onboarding-network-page' as const; |
| } |
| |
| static get template() { |
| return getTemplate(); |
| } |
| |
| static get properties() { |
| return { |
| /** |
| * Set by shimless_rma.js. |
| */ |
| allButtonsDisabled: Boolean, |
| |
| /** |
| * Array of available networks |
| */ |
| networks: { |
| type: Array, |
| value: [], |
| }, |
| |
| /** |
| * Tracks whether network has configuration to be connected |
| */ |
| enableConnect: { |
| type: Boolean, |
| }, |
| |
| /** |
| * The type of network to be configured as a string. May be set initially |
| * or updated by network-config. |
| */ |
| networkType: { |
| type: String, |
| value: '', |
| }, |
| |
| /** |
| * WARNING: This string may contain malicious HTML and should not be used |
| * for Polymer bindings in CSS code. For additional information see |
| * b/286254915. |
| * |
| * The name of the network. May be set initially or updated by |
| * network-config. |
| */ |
| networkName: { |
| type: String, |
| value: '', |
| }, |
| |
| /** |
| * The GUID when an existing network is being configured. This will be |
| * empty when configuring a new network. |
| */ |
| guid: { |
| type: String, |
| value: '', |
| }, |
| |
| /** |
| * Tracks whether network shows connect button or disconnect button. |
| */ |
| networkShowConnect: { |
| type: Boolean, |
| }, |
| |
| /** |
| * Set by network-config when a configuration error occurs. |
| */ |
| error: { |
| type: String, |
| value: '', |
| }, |
| |
| /** |
| * Set to true to when connected to at least one active network. |
| */ |
| isOnline: { |
| type: Boolean, |
| value: false, |
| observer: OnboardingNetworkPage.prototype.onIsOnlineChange, |
| }, |
| }; |
| } |
| |
| allButtonsDisabled: boolean; |
| protected networkName: string; |
| protected networkType: string; |
| protected guid: string; |
| protected enableConnect: boolean; |
| protected networkShowConnect: boolean; |
| protected networks: NetworkStateProperties[]; |
| protected isOnline: boolean; |
| private error: string; |
| private shimlessRmaService: ShimlessRmaServiceInterface = getShimlessRmaService(); |
| private networkConfig: NetworkConfigServiceInterface = getNetworkConfigService(); |
| |
| override ready() { |
| super.ready(); |
| |
| // Before displaying the available networks, track the pre-existing |
| // configured networks. |
| this.shimlessRmaService.trackConfiguredNetworks(); |
| this.refreshNetworks(); |
| enableNextButton(this); |
| |
| focusPageTitle(this); |
| } |
| |
| /** CrosNetworkConfigObserver impl */ |
| onNetworkStateListChanged(): void { |
| this.refreshNetworks(); |
| } |
| |
| async refreshNetworks(): Promise<void> { |
| const networkFilter: NetworkFilter = { |
| filter: FilterType.kVisible, |
| networkType: NetworkType.kAll, |
| limit: NO_LIMIT, |
| }; |
| const response = await this.networkConfig.getNetworkStateList(networkFilter); |
| const networkIsWiFiOrEthernet = (n: NetworkStateProperties) => [NetworkType.kWiFi, NetworkType.kEthernet].includes(n.type); |
| this.networks = response.result.filter(networkIsWiFiOrEthernet); |
| this.isOnline = this.networks.some(n => OncMojo.connectionStateIsConnected(n.connectionState)); |
| } |
| |
| /** |
| * Event triggered when a network list item is selected. |
| */ |
| protected onNetworkSelected(event: CustomEvent<OncMojo.NetworkStateProperties>): void { |
| const networkState = event.detail; |
| const type = networkState.type; |
| const displayName = OncMojo.getNetworkStateDisplayNameUnsafe(networkState); |
| |
| this.networkShowConnect = |
| (networkState.connectionState === ConnectionStateType.kNotConnected); |
| |
| if (!this.canAttemptConnection(networkState)) { |
| this.showConfig(type, networkState.guid, displayName); |
| return; |
| } |
| |
| this.networkConfig.startConnect(networkState.guid).then((response: {result: StartConnectResult, message: string}) => { |
| this.refreshNetworks(); |
| if (response.result === StartConnectResult.kUnknown) { |
| console.error( |
| 'startConnect failed for: ' + networkState.guid + |
| ' Error: ' + response.message); |
| return; |
| } |
| }); |
| } |
| |
| /** |
| * Determines whether or not it is possible to attempt a connection to the |
| * provided network (e.g., whether it's possible to connect or configure the |
| * network for connection). |
| */ |
| private canAttemptConnection(state: OncMojo.NetworkStateProperties): boolean { |
| if (state.connectionState !== ConnectionStateType.kNotConnected) { |
| return false; |
| } |
| |
| if (OncMojo.networkTypeHasConfigurationFlow(state.type) && |
| (!OncMojo.isNetworkConnectable(state) || !!state.errorState)) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| private showConfig(type: NetworkType, guid: string, name: string): void { |
| assert(type !== NetworkType.kCellular && type !== NetworkType.kTether); |
| |
| this.networkType = OncMojo.getNetworkTypeString(type); |
| this.networkName = name || ''; |
| this.guid = guid || ''; |
| |
| const networkConfig: NetworkConfigElement|null = this.shadowRoot!.querySelector('#networkConfig'); |
| assert(networkConfig); |
| networkConfig.init(); |
| |
| const dialog: CrDialogElement|null = this.shadowRoot!.querySelector('#dialog'); |
| assert(dialog); |
| if (!dialog.open) { |
| dialog.showModal(); |
| } |
| } |
| |
| protected closeConfig(): void { |
| const dialog: CrDialogElement|null = this.shadowRoot!.querySelector('#dialog'); |
| assert(dialog); |
| if (dialog.open) { |
| dialog.close(); |
| } |
| |
| // Reset the network state properties. |
| this.networkType = ''; |
| this.networkName = ''; |
| this.guid = ''; |
| } |
| |
| protected connectNetwork(): void { |
| const networkConfig: NetworkConfigElement|null = this.shadowRoot!.querySelector('#networkConfig'); |
| assert(networkConfig); |
| networkConfig.connect(); |
| } |
| |
| protected disconnectNetwork(): void { |
| this.networkConfig.startDisconnect(this.guid).then(response => { |
| if (!response.success) { |
| console.error('Disconnect failed for: ' + this.guid); |
| } |
| }); |
| this.closeConfig(); |
| } |
| |
| private getError(): string { |
| if (this.i18nExists(this.error)) { |
| return this.i18n(this.error); |
| } |
| return this.i18n('networkErrorUnknown'); |
| } |
| |
| protected onPropertiesSet(): void { |
| this.refreshNetworks(); |
| } |
| |
| private onConfigClose(): void { |
| this.closeConfig(); |
| this.refreshNetworks(); |
| } |
| |
| protected getDialogTitle(): string { |
| if (this.networkName && !this.networkShowConnect) { |
| return loadTimeData.getStringF('internetConfigName', this.networkName); |
| } |
| const type = this.i18n('OncType' + this.networkType); |
| return this.i18n('internetJoinType', type); |
| } |
| |
| onNextButtonClick(): Promise<{stateResult: StateResult}> { |
| return this.shimlessRmaService.networkSelectionComplete(); |
| } |
| |
| private onIsOnlineChange(): void { |
| this.dispatchEvent(createCustomEvent(SET_NEXT_BUTTON_LABEL, |
| this.isOnline ? 'nextButtonLabel' : 'skipButtonLabel')); |
| } |
| } |
| |
| declare global { |
| interface HTMLElementTagNameMap { |
| [OnboardingNetworkPage.is]: OnboardingNetworkPage; |
| } |
| } |
| |
| customElements.define(OnboardingNetworkPage.is, OnboardingNetworkPage); |