import '@polymer/polymer/polymer-legacy' ; import '@polymer/paper-button/paper-button' ; import '@polymer/paper-checkbox/paper-checkbox' ; import '@polymer/paper-dropdown-menu/paper-dropdown-menu' ; import '@polymer/paper-input/paper-input' ; import './cloud-install-styles' ; import './outline-server-settings-styles' ; import './outline-iconset' ; import './outline-validated-input' ; import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn' ; import { html } from '@polymer/polymer/lib/utils/html-tag' ; import { formatBytesParts } from '../data_formatting' ; import { getCloudName , getCloudIcon } from './cloud-assets' ; import { getShortName } from '../location_formatting' ; export interface OutlineServerSettings extends Element { setServerName ( name ) : void ; } Polymer ( { _template : html `
    <style include="cloud-install-styles"></style>
    <style include="outline-server-settings-styles"></style>
    <style>
      .content {
        flex-grow: 1;
      }
      .setting {
        padding: 24px;
        align-items: flex-start;
      }
      .setting:not(:first-child) {
        margin-top: 8px;
      }
      .setting-icon,
      img.setting-icon {
        margin-right: 24px;
        color: #fff;
        opacity: 0.87;
        filter: grayscale(100%);
      }
      .setting > div {
        width: 100%;
      }
      .setting h3 {
        margin: 0 0 16px 0;
        padding: 0;
        color: #fff;
        font-size: 16px;
        width: 100%;
      }
      .setting p {
        margin-bottom: 12px;
        width: 60%;
        color: var(--medium-gray);
      }
      #experiments p {
        width: 80%;
      }
      #experiments .sub-section p {
        width: 100%;
      }
      .sub-section {
        background: var(--border-color);
        padding: 16px;
        margin: 24px 0;
        display: flex;
        align-items: center;
        border-radius: 2px;
      }
      .sub-section iron-icon {
        margin-right: 16px;
      }
      .selection-container {
        display: flex;
        justify-content: space-between;
        align-items: baseline;
      }
      .selection-container > .content {
        flex: 4;
      }
      .selection-container > paper-dropdown-menu {
        flex: 1;
      }
      .data-limits-input {
        display: flex;
        align-items: center;
      }
      .data-limits-input paper-input:not([readonly]) {
        width: auto;
        --paper-input-container: {
          width: 120px;
        }
      }
      .data-limits-disclaimer {
        margin: 0 0 8px 0;
      }
      .data-limits-disclaimer p {
        width: 100%;
      }
      .detail {
        margin-top: 0px;
        font-size: 12px;
      }
      paper-input:not([readonly]) {
        width: 60%;
      }
      paper-dropdown-menu {
        border: 1px solid var(--medium-gray);
        border-radius: 4px;
        max-width: 150px;
        --paper-input-container: {
          padding: 0 4px;
          text-align: center;
        }
        --paper-input-container-input: {
          color: var(--medium-gray);
          font-size: 14px;
        }
        --paper-dropdown-menu-ripple: {
          display: none;
        }
        --paper-input-container-underline: {
          display: none;
        }
        --paper-input-container-underline-focus: {
          display: none;
        }
      }
      .data-limits-input paper-dropdown-menu {
        border: none;
        --paper-input-container: {
          width: 72px;
        }
      }
      paper-listbox paper-item {
        font-size: 14px;
      }
      paper-listbox paper-item:hover {
        cursor: pointer;
        background-color: #eee;
      }
      #data-limits-container .selection-container p {
        margin: 0 0 24px 0;
        width: 80%;
      }
      #data-limits-container .selection-container span {
        display: block;
        margin-top: 6px;
      }
      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(--light-gray);
        --paper-checkbox-unchecked-ink-color: var(--primary-green);
      }
      .selection-container paper-checkbox {
        margin-right: 4px;
      }
    </style>
    <div class="container">
      <div class="content">
        <!-- Managed Server information -->
        <div class="setting card-section" hidden\$="[[!cloudId]]">
          <img class="setting-icon" src="[[_getCloudIcon(cloudId)]]">
          <div>
            <h3>[[_getCloudName(cloudId)]]</h3>
            <paper-input readonly="" value="[[_getShortName(cloudLocation, localize)]]" label="[[localize('settings-server-location')]]" hidden\$="[[!cloudLocation]]" always-float-label="" maxlength="100"></paper-input>
            <paper-input readonly="" value="[[serverMonthlyCost]]" label="[[localize('settings-server-cost')]]" hidden\$="[[!serverMonthlyCost]]" always-float-label="" maxlength="100"></paper-input>
            <paper-input readonly="" value="[[serverMonthlyTransferLimit]]" label="[[localize('settings-transfer-limit')]]" hidden\$="[[!serverMonthlyTransferLimit]]" always-float-label="" maxlength="100"></paper-input>
          </div>
        </div>
        <div class="setting card-section">
          <iron-icon class="setting-icon" icon="outline-iconset:outline"></iron-icon>
          <div>
            <h3>[[localize('settings-server-info')]]</h3>
            <!-- TODO: consider making this an outline-validated-input -->
            <paper-input id="serverNameInput" class="server-name" value="{{serverName}}" label="[[localize('settings-server-name')]]" always-float-label="" maxlength="100" on-keydown="_handleNameInputKeyDown" on-blur="_handleNameInputBlur"></paper-input>
            <p class="detail">[[localize('settings-server-rename')]]</p>
            <outline-validated-input editable="[[isAccessKeyPortEditable]]" visible="[[serverPortForNewAccessKeys]]" label="[[localize('settings-access-key-port')]]" allowed-pattern="[0-9]{1,5}" max-length="5" value="[[serverPortForNewAccessKeys]]" client-side-validator="[[_validatePort]]" event="ChangePortForNewAccessKeysRequested" localize="[[localize]]"></outline-validated-input>
            <outline-validated-input editable="[[isHostnameEditable]]" visible="[[serverHostname]]" label="[[localize('settings-server-hostname')]]" max-length="253" value="[[serverHostname]]" event="ChangeHostnameForAccessKeysRequested" localize="[[localize]]"></outline-validated-input>
            <paper-input readonly="" value="[[serverManagementApiUrl]]" label="[[localize('settings-server-api-url')]]" hidden\$="[[!serverManagementApiUrl]]" always-float-label="" maxlength="100"></paper-input>
            <paper-input readonly="" value="[[_formatDate(language, serverCreationDate)]]" label="[[localize('settings-server-creation')]]" hidden\$="[[!_formatDate(language, serverCreationDate)]]" always-float-label="" maxlength="100"></paper-input>
            <paper-input readonly="" value="[[metricsId]]" label="[[localize('settings-server-id')]]" hidden\$="[[!metricsId]]" always-float-label="" maxlength="100"></paper-input>
            <paper-input readonly="" value="[[serverVersion]]" label="[[localize('settings-server-version')]]" hidden\$="[[!serverVersion]]" always-float-label="" maxlength="100"></paper-input>
          </div>
        </div>
        <!-- Data limits -->
        <div class="setting card-section" hidden\$="[[!supportsDefaultDataLimit]]">
          <iron-icon class="setting-icon" icon="icons:perm-data-setting"></iron-icon>
          <div id="data-limits-container">
            <div class="selection-container">
              <div class="content">
                <h3>[[localize('data-limits')]]</h3>
                <p>[[localize('data-limits-description')]]</p>
              </div>
              <!-- NOTE: The dropdown is not automatically sized to the button's width:
                           https://github.com/PolymerElements/paper-dropdown-menu/issues/229 -->
              <paper-dropdown-menu no-label-float="" horizontal-align="left">
                <paper-listbox slot="dropdown-content" selected="{{_computeDataLimitsEnabledName(isDefaultDataLimitEnabled)}}" attr-for-selected="name" on-selected-changed="_defaultDataLimitEnabledChanged">
                  <paper-item name="enabled">[[localize('enabled')]]</paper-item>
                  <paper-item name="disabled">[[localize('disabled')]]</paper-item>
                </paper-listbox>
              </paper-dropdown-menu>
            </div>
            <div class="sub-section data-limits-disclaimer" hidden\$="[[!showFeatureMetricsDisclaimer]]">
              <iron-icon icon="icons:error-outline"></iron-icon>
              <p inner-h-t-m-l="[[localize('data-limits-disclaimer', 'openLink', '<a href=https://s3.amazonaws.com/outline-vpn/index.html#/en/support/dataCollection>', 'closeLink', '</a>')]]"></p>
            </div>
            <div class="data-limits-input" hidden\$="[[!isDefaultDataLimitEnabled]]">
              <paper-input id="defaultDataLimitInput" value="[[defaultDataLimit.value]]" label="[[localize('data-limit-per-key')]]" always-float-label="" allowed-pattern="[0-9]+" required="" auto-validate="" maxlength="9" on-keydown="_handleDefaultDataLimitInputKeyDown" on-blur="_requestSetDefaultDataLimit"></paper-input>
              <paper-dropdown-menu no-label-float="">
                <paper-listbox id="defaultDataLimitUnits" slot="dropdown-content" selected="[[defaultDataLimit.unit]]" attr-for-selected="name" on-selected-changed="_requestSetDefaultDataLimit">
                <paper-item name="MB">[[_getInternationalizedUnit(1000000, language)]]</paper-item>
                <paper-item name="GB">[[_getInternationalizedUnit(1000000000, language)]]</paper-item>
                </paper-listbox>
              </paper-dropdown-menu>
            </div>
          </div>
        </div>
        <!-- Experiments -->
        <div id="experiments" class="setting card-section" hidden\$="[[!shouldShowExperiments]]">
          <iron-icon class="setting-icon" icon="icons:build"></iron-icon>
          <div>
            <h3>[[localize('experiments')]]</h3>
            <p>[[localize('experiments-description')]]</p>
            <div class="sub-section">
              <iron-icon icon="icons:error-outline"></iron-icon>
              <p inner-h-t-m-l="[[localize('experiments-disclaimer', 'openLink', '<a href=https://s3.amazonaws.com/outline-vpn/index.html#/en/support/dataCollection>', 'closeLink', '</a>')]]"></p>
            </div>
          </div>
        </div>
        <!-- Metrics controls -->
        <div class="setting card-section">
          <iron-icon class="setting-icon" icon="editor:insert-chart"></iron-icon>
          <div>
            <div class="selection-container">
              <paper-checkbox checked="{{metricsEnabled}}" on-change="_metricsEnabledChanged"></paper-checkbox>
              <h3>[[localize('settings-metrics-header')]]</h3>
            </div>
            <p inner-h-t-m-l="[[localize('metrics-description', 'openLink', '<a href=https://s3.amazonaws.com/outline-vpn/index.html#/en/support/dataCollection>', 'closeLink', '</a>')]]"></p>
          </div>
        </div>
      </div>
    </div>
` , is : 'outline-server-settings' , properties : { serverName : String , metricsEnabled : Boolean , metricsId : { type : String , value : null } , serverHostname : { type : String , value : null } , serverManagementApiUrl : { type : String , value : null } , serverPortForNewAccessKeys : { type : Number , value : null } , serverVersion : { type : String , value : null } , isAccessKeyPortEditable : { type : Boolean , value : false } , isDefaultDataLimitEnabled : { type : Boolean , notify : true } , defaultDataLimit : { type : Object , value : null } , supportsDefaultDataLimit : { type : Boolean , value : false } , showFeatureMetricsDisclaimer : { type : Boolean , value : false } , isHostnameEditable : { type : Boolean , value : true } , serverCreationDate : { type : Date , value : '1970-01-01T00:00:00.000Z' } , cloudLocation : { type : Object , value : null } , cloudId : { type : String , value : null } , serverMonthlyCost : { type : String , value : null } , serverMonthlyTransferLimit : { type : String , value : null } , language : { type : String , value : 'en' } , localize : { type : Function } , shouldShowExperiments : { type : Boolean , value : false } , } , setServerName ( name ) { this . initialName = name ; this . name = name ; } , _handleNameInputKeyDown ( event ) { if ( event . key === 'Escape' ) { this . serverName = this . initialName ; this . $ . serverNameInput . blur ( ) ; } else if ( event . key === 'Enter' ) { this . $ . serverNameInput . blur ( ) ; } } , _handleNameInputBlur ( event ) { const newName = this . serverName ; if ( ! newName ) { this . serverName = this . initialName ; return ; } if ( newName !== this . initialName ) { this . fire ( 'ServerRenameRequested' , { newName } ) ; } } , _metricsEnabledChanged ( ) { const metricsSignal = this . metricsEnabled ? 'EnableMetricsRequested' : 'DisableMetricsRequested' ; this . fire ( metricsSignal ) ; } , _defaultDataLimitEnabledChanged ( e ) { const wasDataLimitEnabled = this . isDefaultDataLimitEnabled ; const isDataLimitEnabled = e . detail . value === 'enabled' ; if ( isDataLimitEnabled === undefined || wasDataLimitEnabled === undefined ) { return ; } else if ( isDataLimitEnabled === wasDataLimitEnabled ) { return ; } this . isDefaultDataLimitEnabled = isDataLimitEnabled ; if ( isDataLimitEnabled ) { this . _requestSetDefaultDataLimit ( ) ; } else { this . fire ( 'RemoveDefaultDataLimitRequested' ) ; } } , _handleDefaultDataLimitInputKeyDown ( event ) { if ( event . key === 'Escape' ) { this . $ . defaultDataLimitInput . value = this . defaultDataLimit . value ; this . $ . defaultDataLimitInput . blur ( ) ; } else if ( event . key === 'Enter' ) { this . $ . defaultDataLimitInput . blur ( ) ; } } , _requestSetDefaultDataLimit ( ) { if ( this . $ . defaultDataLimitInput . invalid ) { return ; } const value = Number ( this . $ . defaultDataLimitInput . value ) ; const unit = this . $ . defaultDataLimitUnits . selected ; this . fire ( 'SetDefaultDataLimitRequested' , { limit : { value , unit } } ) ; } , _computeDataLimitsEnabledName ( isDefaultDataLimitEnabled ) { return isDefaultDataLimitEnabled ? 'enabled' : 'disabled' ; } , _validatePort ( value ) { const port = Number ( value ) ; const valid = ! Number . isNaN ( port ) && port >= 1 && port <= 65535 && Number . isInteger ( port ) ; return valid ? '' : this . localize ( 'error-keys-port-bad-input' ) ; } , _getShortName : getShortName , _getCloudIcon : getCloudIcon , _getCloudName : getCloudName , _getInternationalizedUnit ( bytesAmount , language ) { return formatBytesParts ( bytesAmount , language ) . unit ; } , _formatDate ( language , date ) { return date . toLocaleString ( language , { year : 'numeric' , month : 'long' , day : 'numeric' } ) ; } } ) ;