chromium/chrome/browser/resources/ash/settings/os_privacy_page/manage_users_subpage.ts

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * @fileoverview
 * 'settings-manage-users-subpage' is the settings page for managing user
 * accounts on the device.
 */

import 'chrome://resources/ash/common/cr_elements/cr_shared_vars.css.js';
import 'chrome://resources/ash/common/cr_elements/action_link.css.js';
import 'chrome://resources/js/action_link.js';
import '../controls/settings_toggle_button.js';
import '../settings_shared.css.js';
import '../os_people_page/user_list.js';
import '../os_people_page/add_user_dialog.js';

import {I18nMixin} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js';
import {focusWithoutInk} from 'chrome://resources/js/focus_without_ink.js';
import {afterNextRender, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';

import {castExists} from '../assert_extras.js';
import {DeepLinkingMixin} from '../common/deep_linking_mixin.js';
import {isChild, isRevampWayfindingEnabled} from '../common/load_time_booleans.js';
import {RouteObserverMixin} from '../common/route_observer_mixin.js';
import {Setting} from '../mojom-webui/setting.mojom-webui.js';
import {SettingsUsersAddUserDialogElement} from '../os_people_page/add_user_dialog.js';
import {Route, routes} from '../router.js';

import {getTemplate} from './manage_users_subpage.html.js';

const SettingsManageUsersSubpageElementBase =
    DeepLinkingMixin(RouteObserverMixin(I18nMixin(PolymerElement)));

export interface SettingsManageUsersSubpageElement {
  $: {
    addUserDialog: SettingsUsersAddUserDialogElement,
  };
}

export class SettingsManageUsersSubpageElement extends
    SettingsManageUsersSubpageElementBase {
  static get is() {
    return 'settings-manage-users-subpage' as const;
  }

  static get template() {
    return getTemplate();
  }

  static get properties() {
    return {
      prefs: {
        type: Object,
        notify: true,
      },

      isOwner_: {
        type: Boolean,
        value: true,
      },

      isUserListManaged_: {
        type: Boolean,
        value: false,
      },

      isChild_: {
        type: Boolean,
        value() {
          return isChild();
        },
      },

      /**
       * Used by DeepLinkingMixin to focus this page's deep links.
       */
      supportedSettingIds: {
        type: Object,
        value: () => new Set<Setting>([
          Setting.kGuestBrowsingV2,
          Setting.kShowUsernamesAndPhotosAtSignInV2,
          Setting.kRestrictSignInV2,
          Setting.kAddToUserAllowlistV2,
          Setting.kRemoveFromUserAllowlistV2,
        ]),
      },

      isRevampWayfindingEnabled_: {
        type: Boolean,
        value() {
          return isRevampWayfindingEnabled();
        },
        readOnly: true,
      },
    };
  }

  private isOwner_: boolean;
  private isUserListManaged_: boolean;
  private isChild_: boolean;
  private isRevampWayfindingEnabled_: boolean;

  constructor() {
    super();

    chrome.usersPrivate.getCurrentUser().then(
        (user: chrome.usersPrivate.User) => {
          this.isOwner_ = user.isOwner;
        });

    chrome.usersPrivate.isUserListManaged().then(
        (isUserListManaged: boolean) => {
          this.isUserListManaged_ = isUserListManaged;
        });
  }

  override ready(): void {
    super.ready();

    this.addEventListener(
        'all-managed-users-removed', this.focusAddUserButton_);
  }

  override beforeDeepLinkAttempt(settingId: Setting): boolean {
    if (settingId !== Setting.kRemoveFromUserAllowlistV2) {
      // Continue with deep linking attempt.
      return true;
    }

    // Wait for element to load.
    afterNextRender(this, () => {
      const userList = this.shadowRoot!.querySelector('settings-user-list');
      const removeButton =
          userList!.shadowRoot!.querySelector('cr-icon-button');
      if (removeButton) {
        this.showDeepLinkElement(removeButton);
        return;
      }
      console.warn(`Element with deep link id ${settingId} not focusable.`);
    });
    // Stop deep link attempt since we completed it manually.
    return false;
  }

  override currentRouteChanged(route: Route, _oldRoute: Route): void {
    // Does not apply to this page.
    if (route !== routes.ACCOUNTS) {
      return;
    }

    this.attemptDeepLink();
  }

  private openAddUserDialog_(e: Event): void {
    e.preventDefault();
    this.$.addUserDialog.open();
  }

  private onAddUserDialogClose_(): void {
    this.focusAddUserButton_();
  }

  private isEditingDisabled_(isOwner: boolean, isUserListManaged: boolean):
      boolean {
    return !isOwner || isUserListManaged;
  }

  private isEditingUsersEnabled_(
      isOwner: boolean, isUserListManaged: boolean, allowGuest: boolean,
      isChild: boolean): boolean {
    return isOwner && !isUserListManaged && !allowGuest && !isChild;
  }

  private shouldHideModifiedByOwnerLabel_(): boolean {
    return this.isUserListManaged_ || this.isOwner_;
  }

  private focusAddUserButton_(): void {
    focusWithoutInk(
        castExists(this.shadowRoot!.querySelector('#add-user-button a')));
  }

  private getRestrictSigninSublabel_(): string|null {
    return this.isRevampWayfindingEnabled_ ?
        this.i18n('restrictSigninDescription') :
        null;
  }
}

declare global {
  interface HTMLElementTagNameMap {
    [SettingsManageUsersSubpageElement.is]: SettingsManageUsersSubpageElement;
  }
}

customElements.define(
    SettingsManageUsersSubpageElement.is, SettingsManageUsersSubpageElement);