import '@polymer/paper-button/paper-button' ; import '@polymer/paper-checkbox/paper-checkbox' ; import '@polymer/paper-dialog/paper-dialog' ; import '@polymer/paper-dropdown-menu/paper-dropdown-menu' ; import '@polymer/paper-input/paper-input' ; import '@polymer/paper-item/paper-item' ; import '@polymer/paper-listbox/paper-listbox' ; import { PaperDialogElement } from '@polymer/paper-dialog/paper-dialog' ; import { PaperInputElement } from '@polymer/paper-input/paper-input' ; import { PaperListboxElement } from '@polymer/paper-listbox/paper-listbox' ; import { css , customElement , html , internalProperty , LitElement , property } from 'lit-element' ; import { bytesToDisplayDataAmount , DisplayDataAmount , displayDataAmountToBytes , formatBytesParts } from '../data_formatting' ; import { COMMON_STYLES } from './cloud-install-styles' ; /**
 * A floating window representing settings specific to individual access keys. Its state is
 * dynamically set when opened using the open() method instead of with any in-HTML attributes.
 *
 * This element relies on conceptual separation of the data limit as input by the user, the data
 * limit of the UI key, and the actual data limit as saved on the server.  App controls the UI data
 * limit and the request to the server, and the display key in the element is never itself changed.
 */ @ customElement ( 'outline-per-key-data-limit-dialog' ) export class OutlinePerKeyDataLimitDialog extends LitElement { static get styles ( ) { return [ COMMON_STYLES , css `
        #container {
          width: 100%;
          display: flex;
          flex-flow: column nowrap;
        }

        #dataLimitIcon {
          /* Split the padding evenly between the icon and the section to be bidirectional. */
          padding: 0 12px;
        }

        #headerSection {
          display: flex;
          flex-direction: row;
          padding: 0 12px;
        }

        #headerSection h3 {
          font-size: 18px;
          font-weight: 500;
          color: rgba(0, 0, 0, 0.87);
          line-height: 24px;
        }

        #menuSection {
          flex: 1;
          padding: 0 78px;
          margin-top: 10px;
        }

        #buttonsSection {
          margin-top: 10px;
          display: flex;
          flex-direction: row-reverse;
        }

        paper-button {
          display: flex;
          height: 36px;
          text-align: center;
        }

        #save {
          background-color: var(--primary-green);
          color: #fff;
        }

        #save[disabled] {
          color: var(--dark-gray);
          background-color: rgba(0, 0, 0, 0.13);
        }

        #menu {
          display: flex;
          flex-flow: row nowrap;
        }

        #unitsDropdown {
          width: 50px;
          padding: 0 10px;
        }

        paper-checkbox {
          /* We want the ink to be the color we're going to, not coming from */
          --paper-checkbox-checked-color: var(--primary-green);
          --paper-checkbox-checked-ink-color: var(--dark-gray);
          --paper-checkbox-unchecked-color: var(--dark-gray);
          --paper-checkbox-unchecked-ink-color: var(--primary-green);
        }

        paper-listbox paper-item:hover {
          cursor: pointer;
          background-color: var(--background-contrast-color);
          color: #fff;
        }
      ` , ] ; } member @ internalProperty ( ) _keyName = '' ; member @ internalProperty ( ) _initialDataLimitBytes : number = undefined ; member @ internalProperty ( ) _showDataLimit = false ; member @ internalProperty ( ) _enableSave = false ; member @ property ( { type : String } ) language = '' ; @ property ( { type : Function } ) localize : Function ; private _onDataLimitSet ? : OnSetDataLimitHandler ; private _onDataLimitRemoved ? : OnRemoveDataLimitHandler ; override render ( ) { return html `
      <style>
        /* Custom element mixins with brackets don't work in style() */
        #unitsDropdown {
          --paper-input-container-underline: {
            display: none;
          }
          --paper-input-container-underline-focus: {
            display: none;
          }
        }
        #dataLimitInput {
          --paper-input-container-label-focus: {
            color: rgb(123, 123, 123);
          }
        }
      </style>
      <paper-dialog id="container" @opened-changed=${ this . _onDialogOpenedChanged }>
        <div id="headerSection">
          <iron-icon id="dataLimitIcon" icon="icons:perm-data-setting"></iron-icon>
          <h3>${ this . localize ( 'per-key-data-limit-dialog-title' , 'keyName' , this . _keyName ) }</h3>
        </div>
        <div id="menuSection">
          <paper-checkbox ?checked=${ this . _showDataLimit } @tap=${ this . _setCustomLimitTapped }>
            ${ this . localize ( 'per-key-data-limit-dialog-set-custom' ) }
          </paper-checkbox>
          ${ this . _showDataLimit ? this . renderDataLimit ( ) : '' }
        </div>
        <div id="buttonsSection">
          <paper-button id="save" ?disabled=${ ! this . _enableSave } @tap=${ this . _onSaveButtonTapped }>${ this . localize ( 'save' ) }</paper-button>
          <paper-button @tap=${ this . close }>${ this . localize ( 'cancel' ) }</paper-button>
        </div>
      </paper-dialog>
    ` ; } private renderDataLimit ( ) { return html `
      <div id="menu">
      <!-- This input doesn't work for languages which don't use decimal points or Arabic numerals
           but it's difficult to accept internationalized inputs.  -->
        <paper-input
          id="dataLimitInput"
          label=${ this . localize ( 'data-limit' ) }
          always-float-label
          allowed-pattern="[0-9\\.]"
          pattern="[0-9]+(\\.[0-9]*)?"
          auto-validate
          value=${ this . _initialValue ( ) }
          size="7"
          @keyup=${ this . _setSaveButtonDisabledState }
        >
        </paper-input>
        <paper-dropdown-menu id="unitsDropdown" noink>
          <paper-listbox
            id="unitsListbox"
            slot="dropdown-content"
            attr-for-selected="name"
            selected="${ this . _initialUnit ( ) }"
          >
            <paper-item name="GB">${ this . _getInternationalizedUnit ( 1000000000 ) }</paper-item>
            <paper-item name="MB">${ this . _getInternationalizedUnit ( 1000000 ) }</paper-item>
          </paper-listbox>
        </paper-dropdown-menu>
      </div>
    ` ; } private _queryAs < T extends HTMLElement > ( selector ) { return this . shadowRoot . querySelector ( selector ) as T ; } private get _input ( ) : PaperInputElement { return this . _queryAs < PaperInputElement > ( '#dataLimitInput' ) ; } private _dataLimitValue ( ) { return Number ( this . _input ?. value ) ?? 0 ; } private _dataLimitUnit ( ) { return this . _queryAs < PaperListboxElement > ( '#unitsListbox' ) . selected as 'GB' | 'MB' ; } private _getInternationalizedUnit ( bytes ) { return formatBytesParts ( bytes , this . language ) . unit ; } private _initialUnit ( ) { return bytesToDisplayDataAmount ( this . _initialDataLimitBytes ) ?. unit || 'GB' ; } private _initialValue ( ) { return bytesToDisplayDataAmount ( this . _initialDataLimitBytes ) ?. value . toString ( ) || '' ; } private async _setCustomLimitTapped ( ) { this . _showDataLimit = ! this . _showDataLimit ; if ( this . _showDataLimit ) { await this . updateComplete ; this . _input ?. focus ( ) ; } } private _setSaveButtonDisabledState ( ) { this . _enableSave = ! this . _input ?. invalid ?? false ; } private async _onSaveButtonTapped ( ) { const change = this . _dataLimitChange ( ) ; if ( change === Change . UNCHANGED ) { return ; } const result = change === Change . SET ? await this . _onDataLimitSet ( displayDataAmountToBytes ( this . inputDataLimit ( ) ) ) : await this . _onDataLimitRemoved ( ) ; if ( result ) { this . close ( ) ; } } /**
     * Calculates what type of change, or none at all, the user made.
     */ private _dataLimitChange ( ) { if ( this . _showDataLimit ) { if ( this . _initialDataLimitBytes === undefined ) { return Change . SET ; } const inputLimit = displayDataAmountToBytes ( this . inputDataLimit ( ) ) ; if ( inputLimit !== this . _initialDataLimitBytes ) { return Change . SET ; } return Change . UNCHANGED ; } if ( this . _initialDataLimitBytes !== undefined ) { return Change . REMOVED ; } return Change . UNCHANGED ; } /**
     * The current data limit as input by the user, but not necessarily as saved.
     */ public inputDataLimit ( ) { return this . _showDataLimit ? { unit : this . _dataLimitUnit ( ) , value : this . _dataLimitValue ( ) } : null ; } param keyName param keyDataLimit param serverDefaultLimit param language param onDataLimitSet param onDataLimitRemoved public open ( keyName , keyLimitBytes , onDataLimitSet , onDataLimitRemoved ) { this . _keyName = keyName ; this . _initialDataLimitBytes = keyLimitBytes ; this . _showDataLimit = this . _initialDataLimitBytes !== undefined ; this . _onDataLimitSet = onDataLimitSet ; this . _onDataLimitRemoved = onDataLimitRemoved ; this . _queryAs < PaperListboxElement > ( '#unitsListbox' ) ?. select ( this . _initialUnit ( ) ) ; this . _setSaveButtonDisabledState ( ) ; this . _queryAs < PaperDialogElement > ( '#container' ) . open ( ) ; } private _onDialogOpenedChanged ( openedChanged ) { const dialogWasClosed = ! openedChanged . detail . value ; if ( dialogWasClosed ) { delete this . _onDataLimitSet ; delete this . _onDataLimitRemoved ; } } /**
     * Closes the dialog.
     */ public close ( ) { this . _queryAs < PaperDialogElement > ( '#container' ) . close ( ) ; } } enum Change { SET , REMOVED , UNCHANGED } type OnSetDataLimitHandler = ( dataLimitBytes : number ) => Promise < boolean > ; type OnRemoveDataLimitHandler = ( ) => Promise < boolean > ;