<!-- TODO use this once we enable custom SSL certificate ui again -->
<!-- <div class="hide">
  <label class="control-label" for="appConfigureCertificateInput" ng-show="appConfigure.domain.provider !== 'caas'">Certificate (optional)</label>
  <div class="has-error text-center" ng-show="appConfigure.error.cert && appConfigure.domain.provider !== 'caas'">{{ appConfigure.error.cert }}</div>
  <div class="form-group" ng-class="{ 'has-error': !appConfigureForm.certificate.$dirty && appConfigure.error.cert }" ng-show="appConfigure.domain.provider !== 'caas'">
    <div class="input-group">
      <input type="file" id="appConfigureCertificateFileInput" onchange="readCertificate()" style="display:none"/>
      <input type="text" class="form-control" placeholder="Certificate" ng-model="appConfigure.certificateFileName" id="appConfigureCertificateInput" name="certificate" onclick="getElementById('appConfigureCertificateFileInput').click();" style="cursor: pointer;" ng-required="appConfigure.keyFileName">
      <span class="input-group-addon">
        <i class="fa fa-upload" onclick="getElementById('appConfigureCertificateFileInput').click();"></i>
      </span>
    </div>
  </div>
  <div class="form-group" ng-class="{ 'has-error': !appConfigureForm.key.$dirty && appConfigure.error.cert }" ng-show="appConfigure.domain.provider !== 'caas'">
    <div class="input-group">
      <input type="file" id="appConfigureKeyFileInput" onchange="readKey()" style="display:none"/>
      <input type="text" class="form-control" placeholder="Key" ng-model="appConfigure.keyFileName" id="appConfigureKeyInput" name="key" onclick="getElementById('appConfigureKeyFileInput').click();" style="cursor: pointer;" ng-required="appConfigure.certificateFileName">
      <span class="input-group-addon">
        <i class="fa fa-upload" onclick="getElementById('appConfigureKeyFileInput').click();"></i>
      </span>
    </div>
  </div>
</div> -->

<script>
    function imageErrorHandler(elem) {
        'use strict';

        elem.src = elem.getAttribute('fallback-icon');
        elem.onerror = null;    // avoid retry after default icon cannot be loaded
    }
</script>

<!-- Modal postinstall confirm -->
<div class="modal fade" id="postInstallConfirmModal" tabindex="-1" role="dialog">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <img ng-src="{{app.iconUrl}}" onerror="this.onerror=null;this.src='img/appicon_fallback.png'" class="app-info-icon"/>
        <h5 class="app-info-title">
          {{ app.manifest.title }}
          <span class="app-info-meta text-small">Package <a ng-href="/#/appstore/{{ app.manifest.id }}?version={{ app.manifest.version }}">v{{ app.manifest.version }}</a> </span>
          <br/>
          <span ng-show="app.manifest.documentationUrl"><a target="_blank" ng-href="{{ app.manifest.documentationUrl }}">Documentation</a> </span>
          <br/>
        </h5>
      </div>
      <div class="modal-body">
        <div ng-bind-html="app.manifest.postInstallMessage | postInstallMessage:app | markdown2html"></div>
        <div ng-show="app.manifest.documentationUrl">
          Please see the <a target="_blank" ng-href="{{ app.manifest.documentationUrl }}">documentation</a> for more information.
        </div>
      </div>
      <div class="modal-footer">
        <div class="form-group pull-left">
          <input type="checkbox" id="postInstallConfirmCheckbox" ng-model="postInstallConfirm.confirmed">
          <label class="control-label" for="postInstallConfirmCheckbox">Acknowledge instructions</label>
        </div>
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        <a class="btn btn-success" ng-href="{{ postInstallConfirm.confirmed ? ('https://' + app.fqdn) : '' }}" target="_blank" ng-disabled="!postInstallConfirm.confirmed" ng-click="postInstallConfirm.submit()"><i class="fas fa-external-link-alt"></i> Open App</a>
      </div>
    </div>
  </div>
</div>

<!-- Modal uninstall app -->
<div class="modal fade" id="uninstallModal" tabindex="-1" role="dialog">
  <div class="modal-dialog">
    <div class="modal-content">
        <div class="modal-header">
          <h4 class="modal-title">Uninstall {{ app.label || app.fqdn }}</h4>
        </div>
      <div class="modal-body">
        <p>This will immediately uninstall <b>{{ app.label || app.fqdn }}</b> and remove all it's data.</p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
        <button type="button" class="btn btn-danger" ng-click="uninstall.submit()" ng-disabled="uninstall.busy"><i class="fa fa-circle-notch fa-spin" ng-show="uninstall.busy"></i> Uninstall</button>
      </div>
    </div>
  </div>
</div>

<!-- Modal domain collision -->
<div class="modal fade" id="domainCollisionsModal" tabindex="-1" role="dialog">
  <div class="modal-dialog">
    <div class="modal-content">
        <div class="modal-header">
          <h4 class="modal-title">Domain Collision</h4>
        </div>
      <div class="modal-body">
        <p>The following domains already exist in your DNS:</p>
        <ul>
          <li ng-repeat="domain in location.domainCollisions">{{ domain.subdomain + '.' + domain.domain }}</li>
        </ul>
        <p>As a precautionary measure, Cloudron does not overwrite existing DNS records. Please confirm that the above domains are not in use for services external to Cloudron.</p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
        <button type="button" class="btn btn-danger" ng-click="location.submit(true)">Overwrite existing DNS Records</button>
      </div>
    </div>
  </div>
</div>

<!-- Modal repair -->
<div class="modal fade" id="repairModal" tabindex="-1" role="dialog">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h4 class="modal-title">Repair {{ app.fqdn }}</h4>
      </div>
      <div class="modal-body">
        <div ng-if="!app.error">
          <p>Cloudron will re-install the app in-place with existing configuration. Existing data will be retained.</p>
        </div>
        <div ng-if="app.error">
          <p>The <b>{{ app.error.installationState | taskName }}</b> operation failed with the following error:</p>
          <p class="text-danger">{{ app.error.reason + ': ' + app.error.message }}</p>
        </div>
        <div class="form-group" ng-show="repair.location && repair.domain">
          <p>Cloudron will repair the app to use the following domains:</p>
          <label class="control-label">Location</label>
          <div class="input-group form-inline">
            <input type="text" class="form-control" ng-model="repair.location" name="location" placeholder="{{ 'Leave empty to use bare domain' }}" autofocus>

            <div class="input-group-btn">
              <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
                <span>{{ (!repair.location ? '' : (repair.domain.config.hyphenatedSubdomains ? '-' : '.')) + repair.domain.domain }}</span>
                <span class="caret"></span>
              </button>
              <ul class="dropdown-menu dropdown-menu-right" role="menu">
                <li ng-repeat="domain in domains">
                  <a href="" ng-click="repair.domain = domain">{{ domain.domain }}</a>
                </li>
              </ul>
            </div>
          </div>
        </div>
        <div ng-show="repair.alternateDomains.length">
          <p ng-repeat="alternateDomain in repair.alternateDomains">
            <label class="control-label"><input type="checkbox" ng-model="alternateDomain.enabled">
               {{ alternateDomain.subdomain + (!alternateDomain.subdomain ? '' : (alternateDomain.domain.config.hyphenatedSubdomains ? '-' : '.')) + alternateDomain.domain.domain }}
              </label>
          </p>
        </div>
        <div ng-show="repair.backups.length">
          <label class="control-label">Restore from Backup:</label>
          <select class="form-control" ng-model="repair.backupId">
            <option ng-repeat="backup in repair.backups" value="{{ backup.id }}">{{ backup.creationTime | prettyDate }} - v{{ backup.version }}</option>
          </select>
        </div>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
        <button type="button" class="btn btn-success" ng-click="repair.submit()" ng-disabled="repair.busy"><i class="fa fa-circle-notch fa-spin" ng-show="repair.busy"></i> Repair</button>
      </div>
    </div>
  </div>
</div>

<!-- Modal postinstall -->
<div class="modal fade" id="postInstallModal" tabindex="-1" role="dialog">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h4>First Time Setup</h4>
      </div>
      <div class="modal-body">
        <div ng-bind-html="app.manifest.postInstallMessage | postInstallMessage:app | markdown2html"></div>
      </div>
      <div class="modal-footer">
        <div class="form-group pull-left" ng-show="postInstallMessage.openApp">
          <input type="checkbox" id="appPostInstallConfirmCheckbox" ng-model="postInstallMessage.confirmed">
          <label class="control-label" for="appPostInstallConfirmCheckbox">Acknowledge instructions</label>
        </div>
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        <a class="btn btn-success" ng-href="{{ postInstallMessage.confirmed ? ('https://' + app.fqdn) : '' }}" target="_blank" ng-disabled="!postInstallMessage.confirmed" ng-click="postInstallMessage.submit()" ng-show="postInstallMessage.openApp">Open {{ app.manifest.title }}</a>
      </div>
    </div>
  </div>
</div>

<!-- Modal update app -->
<div class="modal fade" id="updateModal" tabindex="-1" role="dialog">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h4 class="modal-title">Update {{ app.fqdn }}</h4>
      </div>
      <div class="modal-body">
        <p>Recent Changes for new version <b>{{ config.update.apps[app.id].manifest.version}}</b>:</p>
        <div ng-bind-html="config.update.apps[app.id].manifest.changelog | markdown2html"></div>
      </div>
      <div class="modal-footer">
          <label class="checkbox-inline pull-left">
              <input type="checkbox" ng-model="updates.skipBackup"><b>Skip backup</b>
          </label>

        <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
        <button type="button" class="btn btn-success" ng-click="updates.confirmUpdate()" ng-disabled="updates.busyUpdate"><i class="fa fa-circle-notch fa-spin" ng-show="updates.busyUpdate"></i> Update</button>
      </div>
    </div>
  </div>
</div>

<!-- Modal restore app -->
<div class="modal fade" id="restoreModal" tabindex="-1" role="dialog">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h4 class="modal-title">
          Restore - {{ app.fqdn }}
        </h4>
      </div>
      <div class="modal-body" style="padding: 0 15px">
        <p>This will restore this app to the data from <b>{{ restore.backup.creationTime | prettyDate }}</b>.</p>
        <p class="text-danger">Any data generated between now and the last known backup will be irrevocably lost.
          It is recommended to create a backup of the current data before attempting a restore.
        </p>
        <br/>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-danger" ng-click="restore.submit()"><i class="fas fa-history" ng-hide="restore.busy"></i><i class="fa fa-circle-notch fa-spin" ng-show="clone.busy"></i>  Restore</button>
      </div>
    </div>
  </div>
</div>

<!-- Modal clone app -->
<div class="modal fade" id="cloneModal" tabindex="-1" role="dialog">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h4 class="modal-title">
          Clone - {{ app.fqdn }}
        </h4>
      </div>
      <div class="modal-body" style="padding: 0 15px">
        <p>Using backup from <b>{{ clone.backup.creationTime | prettyDate }}</b> and version <b>v{{ clone.backup.version }}</b></p>
        <fieldset>
          <form role="form" ng-submit="clone.submit()" autocomplete="off">
            <div class="form-group" ng-class="{ 'has-error': clone.error.location }">
              <label class="control-label" for="cloneLocationInput">Location</label>
              <div ng-show="clone.error.location"><small>{{ clone.error.location }}</small></div>
              <div class="input-group form-inline">
                <input type="text" class="form-control" ng-model="clone.location" id="cloneLocationInput" name="location" placeholder="Leave empty to use bare domain" autofocus>
                <div class="input-group-btn">
                  <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
                    <span>{{ (!clone.location ? '' : (clone.domain.config.hyphenatedSubdomains ? '-' : '.')) + clone.domain.domain }}</span>
                    <span class="caret"></span>
                  </button>
                  <ul class="dropdown-menu dropdown-menu-right" role="menu">
                    <li ng-repeat="domain in domains">
                      <a href="" ng-click="clone.domain = domain">{{ domain.domain }}</a>
                    </li>
                  </ul>
                </div>
              </div>
            </div>

            <p class="text-center" ng-show="clone.location && clone.domain.provider === 'manual'">
              <b>Add an A record manually for {{ clone.location }} to this Cloudron's public IP</b>
              <br>
            </p>

            <div class="has-error text-center" ng-show="clone.error.port">{{ clone.error.port }}</div>
            <div ng-repeat="(env, info) in clone.portBindingsInfo">
              <ng-form name="portInfo_form">
                <div class="form-group" ng-class="{ 'has-error': (!clone.itemName{{$index}}.$dirty && clone.error.port) || (portInfo_form.itemName{{$index}}.$dirty && portInfo_form.itemName{{$index}}.$invalid) }">
                  <label class="control-label" for="inputPortInfo{{env}}"><input type="checkbox" ng-model="clone.portBindingsEnabled[env]">
                    {{ info.title }}
                    <sup>
                      <a popover-placement="top-right" popover-trigger="outsideClick" uib-popover="{{info.description}} ({{ HOST_PORT_MIN }} - {{ HOST_PORT_MAX }})"><i class="fa fa-question-circle"></i></a>
                    </sup>
                  </label>
                  <input type="number" class="form-control" ng-model="clone.portBindings[env]" ng-disabled="!clone.portBindingsEnabled[env]" id="inputPortInfo{{env}}" later-name="itemName{{$index}}" min="{{hostPortMin}}" max="{{hostPortMax}}" required>
                </div>
              </ng-form>
            </div>
          </form>
        </fieldset>
      </div>

      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-success" ng-click="clone.submit()"><i class="far fa-clone" ng-hide="clone.busy"></i><i class="fa fa-circle-notch fa-spin" ng-show="clone.busy"></i>  Clone</button>
      </div>
    </div>
  </div>
</div>

<div class="content content-large app-configure">

  <a href="/#/apps" class="back-to-apps-link"><i class="fas fa-arrow-left"></i> Back to My Apps</a>

  <br/>

  <div class="row">
    <div class="col-sm-2 text-center">
      <img ng-src="{{ app.iconUrl || 'img/appicon_fallback.png' }}" fallback-icon="img/appicon_fallback.png" onerror="imageErrorHandler(this)" class="app-icon"/>
    </div>
    <div class="col-sm-8">
      <div class="app-header-container">
        <h1>
          <a ng-href="{{ app | applicationLink }}" target="_blank" ng-class="{ 'hand': (app | appIsInstalledAndHealthy) }" ng-click="(app | appIsInstalledAndHealthy) && app.pendingPostInstallConfirmation && postInstallMessage.show(true)">{{ app.label || app.fqdn }} <sup ng-show="app | appIsInstalledAndHealthy"><i class="fas fa-external-link-alt" style="font-size: 12px;"></i></sup></a>
          <br/>
          <span class="text-small">{{ app | installationStateLabel:user }}</span>
        </h1>
        <div>
          <div class="dropdown">
            <button class="btn btn-sm btn-info dropdown-toggle" type="button" data-toggle="dropdown">
              Documentation
              <span class="caret"></span>
            </button>
            <ul class="dropdown-menu dropdown-menu-right">
              <li ng-class="{ 'disabled': !app.manifest.postInstallMessage }"><a href="" ng-click="postInstallMessage.show(false)">First Time Setup</a></li>
              <li ng-class="{ 'disabled': !app.manifest.documentationUrl }"><a ng-href="{{ app.manifest.documentationUrl }}" target="_blank">Documentation</a></li>
              <li role="separator" class="divider"></li>
              <li ng-class="{ 'disabled': !app.manifest.website }"><a ng-href="{{ app.manifest.website }}" target="_blank">Project Website</a></li>
            </ul>
          </div>
        </div>
      </div>
    </div>
  </div>

  <div class="row">
    <div class="col-sm-8 col-sm-offset-2" style="height: 10px;">
      <div class="progress progress-striped active animateMeOpacity" ng-show="app.taskId" style="height: 10px;" uib-tooltip="{{ app.taskProgressMessage }}">
        <div class="progress-bar progress-bar-success" role="progressbar" style="width: {{ app.taskProgress }}%"></div>
      </div>
    </div>
  </div>

  <div class="row app-configure-links-container">
    <div class="col-sm-2">
      <div class="app-configure-links">
        <div ng-click="setView('display')" ng-class="{ 'active': view === 'display', 'disabled': app.error }">Display</div>
        <div ng-click="setView('location')" ng-class="{ 'active': view === 'location', 'disabled': app.error }">Location</div>
        <div ng-click="setView('access')" ng-class="{ 'active': view === 'access', 'disabled': app.error }">Access Control</div>
        <div ng-click="setView('resources')" ng-class="{ 'active': view === 'resources', 'disabled': app.error }">Resources</div>
        <div ng-click="setView('security')" ng-class="{ 'active': view === 'security', 'disabled': app.error }">Security</div>
        <div ng-click="setView('email')" ng-class="{ 'active': view === 'email', 'disabled': app.error }" ng-show="app.manifest.addons.sendmail || app.manifest.addons.recvmail">Email</div>
        <div ng-click="setView('updates')" ng-class="{ 'active': view === 'updates', 'disabled': app.error }">Updates</div>
        <div ng-click="setView('backups')" ng-class="{ 'active': view === 'backups', 'disabled': app.error }">Backups</div>
        <div ng-click="setView('debug')" ng-class="{ 'active': view === 'debug' }">Debug</div>
        <div ng-click="setView('uninstall')" ng-class="{ 'active': view === 'uninstall' }">Uninstall</div>
      </div>
    </div>
    <div class="col-sm-8 card-container">
      <div class="card" ng-show="view === 'display'">
        <div class="row">
          <div class="col-md-12">
            <fieldset>
              <form role="form" name="displayForm" ng-submit="display.submit()" autocomplete="off">
                <div class="form-group" ng-class="{ 'has-error': !displayForm.label.$dirty && display.error.label }">
                  <label class="control-label">Label</label>
                  <div class="control-label" ng-show="display.error.label">{{display.error.label}}</div>
                  <input type="text" class="form-control" id="displayLabelInput" name="label" ng-model="display.label">
                </div>
                <div class="form-group">
                  <label class="control-label">Tags</label>
                  <tag-input class="form-control" placeholder="Use comma to separate tags" taglist="display.tags" name="tags" uib-tooltip="For grouping in the dashboard"></tag-input>
                </div>
                <div class="form-group">
                  <div>
                    <label class="control-label">Icon</label>
                  </div>
                  <div id="previewIcon" class="app-custom-icon" ng-click="display.showCustomIconSelector()">
                    <img ng-src="{{ display.iconUrl() || 'img/appicon_fallback.png' }}" fallback-icon="img/appicon_fallback.png" onerror="imageErrorHandler(this)"/>
                    <div class="overlay"></div>
                  </div>
                  <a href="" style="font-weight: normal;" ng-click="display.resetCustomIcon()">Reset Icon</a>
                  <input type="file" id="iconFileInput" style="display: none" accept="image/png"/>
                </div>

                <input class="ng-hide" type="submit" ng-disabled="(!display.icon.data && !displayForm.$dirty) || displayForm.$invalid || display.busy"/>
              </form>
            </fieldset>
          </div>
        </div>
        <div class="row">
          <div class="col-md-12 text-right">
            <button class="btn btn-outline btn-primary pull-right" ng-click="display.submit()" ng-disabled="(!display.icon.data && !displayForm.$dirty) || display.$invalid || display.busy"><i class="fa fa-circle-notch fa-spin" ng-show="display.busy"></i> Save</button>
          </div>
        </div>
      </div>

      <div class="card" ng-show="view === 'location'">
        <div class="task-active-overlay" ng-show="app.taskId"></div>
        <div class="row">
          <div class="col-md-12">
            <fieldset>
              <form role="form" name="locationForm" ng-submit="location.submit()" autocomplete="off">
                <div class="form-group" ng-class="{ 'has-error': (locationForm.location.$dirty && locationForm.location.$invalid) || (!locationForm.location.$dirty && location.error.location)  }">
                  <label class="control-label">Location</label>
                  <div class="has-error" ng-show="location.error.location">{{ location.error.location }}</div>

                  <div class="input-group form-inline">
                    <input type="text" class="form-control" ng-model="location.location" id="locationLocationInput" name="location" placeholder="{{ 'Leave empty to use bare domain' }}" autofocus>

                    <div class="input-group-btn">
                      <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
                        <span>{{ (!location.location ? '' : (location.domain.config.hyphenatedSubdomains ? '-' : '.')) + location.domain.domain }}</span>
                        <span class="caret"></span>
                      </button>
                      <ul class="dropdown-menu dropdown-menu-right" role="menu">
                        <li ng-repeat="domain in domains">
                          <a href="" ng-click="location.domain = domain">{{ domain.domain }}</a>
                        </li>
                      </ul>
                    </div>
                  </div>
                </div>

                <p class="text-center" ng-show="location.location && location.domain.provider === 'manual'">
                  <b>Add an A record manually for {{ location.location }} to this Cloudron's public IP</b>
                  <br>
                </p>

                <!-- hidden submit has to be prior to other button elements, otherwise firefox will treat them as the "enter" key action, in this case the alternate domain delete button! -->
                <input class="ng-hide" type="submit" ng-disabled="locationForm.$invalid || location.busy"/>

                <div class="has-error text-center" ng-show="location.error.port">{{ location.error.port }}</div>
                <div ng-repeat="(env, info) in location.portBindingsInfo">
                  <ng-form name="portInfo_form">
                    <div class="form-group" ng-class="{ 'has-error': (!locationForm.itemName{{$index}}.$dirty && location.error.port) || (portInfo_form.itemName{{$index}}.$dirty && portInfo_form.itemName{{$index}}.$invalid) }">
                      <label class="control-label" for="locationPortInput{{env}}"><input type="checkbox" ng-model="location.portBindingsEnabled[env]">
                        {{ info.title }}
                        <sup>
                          <a popover-placement="top-right" popover-trigger="outsideClick" uib-popover="{{info.description}} ({{ HOST_PORT_MIN }} - {{ HOST_PORT_MAX }})"><i class="fa fa-question-circle"></i></a>
                        </sup>
                      </label>
                      <input type="number" class="form-control" ng-model="location.portBindings[env]" ng-disabled="!location.portBindingsEnabled[env]" id="locationPortInput{{env}}" later-name="itemName{{$index}}" min="{{HOST_PORT_MIN}}" max="{{HOST_PORT_MAX}}" required>
                    </div>
                  </ng-form>
                </div>

                <div class="form-group alternate-domains">
                  <label class="control-label">Redirections  <sup><a ng-href="{{ config.webServerOrigin }}/documentation/apps/#redirections" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
                  <div class="has-error" ng-show="location.error.alternateDomains">{{ location.error.alternateDomains }}</div>

                  <div class="row" ng-repeat="alternateDomain in location.alternateDomains">
                    <div class="col col-lg-11">
                      <div class="input-group">
                        <input type="text" class="form-control" ng-model="alternateDomain.subdomain" placeholder="Leave empty to use bare domain">

                        <div class="input-group-btn">
                          <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
                            <span>{{ (!alternateDomain.subdomain ? '' : (alternateDomain.domain.config.hyphenatedSubdomains ? '-' : '.')) + alternateDomain.domain.domain }}</span>
                            <span class="caret"></span>
                          </button>
                          <ul class="dropdown-menu dropdown-menu-right" role="menu">
                            <li ng-repeat="domain in domains">
                              <a href="" ng-click="alternateDomain.domain = domain">{{ domain.domain }}</a>
                            </li>
                          </ul>
                        </div>
                      </div>
                    </div>
                    <div class="col col-lg-1">
                      <button class="btn btn-danger btn-sm" ng-click="location.delAlternateDomain($event, $index)"><i class="far fa-trash-alt"></i></button>
                    </div>
                  </div>
                  <div ng-show="location.alternateDomains.length === 0">
                      No alternate domains are configured. <a href="" ng-click="location.addAlternateDomain($event)">Add a domain</a>
                  </div>
                  <div ng-show="location.alternateDomains.length > 0" style="margin-top: 5px;">
                    <a href="" ng-click="location.addAlternateDomain($event)">Add another domain</a>
                  </div>
                </div>
              </form>
            </fieldset>
          </div>
        </div>
        <div class="row">
          <div class="col-md-12 text-right">
            <button class="btn btn-outline btn-primary pull-right" ng-click="location.submit()" ng-disabled="location.$invalid || location.busy"><i class="fa fa-circle-notch fa-spin" ng-show="location.busy"></i> Save</button>
          </div>
        </div>
      </div>

      <div class="card" ng-show="view === 'access'">
        <div class="row">
          <div class="col-md-12">
            <fieldset>
              <form role="form" name="accessForm" ng-submit="access.submit()" autocomplete="off">
                <div class="form-group">
                  <div ng-show="access.ssoAuth">
                    <label class="control-label">User management</label>
                    <p class="text-small" ng-show="access.ftp">This setting also controls SFTP access.</p>
                  </div>
                  <div ng-show="!access.ssoAuth">
                    <label class="control-label">Dashboard visibility</label>
                    <p ng-show="!access.app.manifest.addons.email" class="text-small">
                      This app has it's own user management.
                      <span ng-show="access.ftp">This setting also controls SFTP access.</span>
                    </p>
                    <p ng-show="access.app.manifest.addons.email" class="text-small">
                      This app is pre-configured for use with <a href="https://cloudron.io/documentation/email/" target="_blank">Cloudron Email</a>.
                    </p>
                  </div>

                  <div class="radio">
                    <label>
                      <input type="radio" ng-model="access.accessRestrictionOption" value="any">
                      <span ng-show="access.ssoAuth">Allow all users on this Cloudron</span>
                      <span ng-show="!access.ssoAuth">Visible to all users on this Cloudron</span>
                    </label>
                  </div>
                  <div class="radio">
                    <label>
                      <input type="radio" ng-model="access.accessRestrictionOption" value="groups">

                      <span ng-show="access.ssoAuth">Only allow the following users and groups</span>
                      <span ng-show="!access.ssoAuth">Only visible to the following users and groups</span>

                      <span class="label label-danger" ng-show="access.accessRestrictionOption === 'groups' && !access.isAccessRestrictionValid()">Select at least one user or group</span>
                    </label>
                  </div>
                  <div>
                    <div style="margin-left: 20px;">
                      <div class="col-md-5">
                        Users: <multiselect class="input-sm stretch" ng-model="access.accessRestriction.users" ng-disabled="access.accessRestrictionOption !== 'groups'" options="user.display for user in users" data-multiple="true" filter-after-rows="5" scroll-after-rows="10"></multiselect>
                      </div>

                      <div class="col-md-5">
                        Groups: <multiselect class="input-sm stretch" ng-model="access.accessRestriction.groups" ng-disabled="access.accessRestrictionOption !== 'groups'" options="group.name for group in groups" data-multiple="true" filter-after-rows="5" scroll-after-rows="10"></multiselect>
                      </div>
                    </div>
                  </div>

                  <input class="ng-hide" type="submit" ng-disabled="accessForm.$invalid || access.busy"/>
                </div>
              </form>
            </fieldset>
          </div>
        </div>
        <div class="row">
          <div class="col-md-12 text-right">
            <button class="btn btn-outline btn-primary pull-right" ng-click="access.submit()" ng-disabled="access.$invalid || access.busy"><i class="fa fa-circle-notch fa-spin" ng-show="access.busy"></i> Save</button>
          </div>
        </div>
        <div class="row" ng-show="app.manifest.addons.localstorage.ftp">
          <hr/>
          <div class="col-md-12">
              <label>SFTP</label> <sup><a ng-href="{{ config.webServerOrigin }}/documentation/apps/#ftp-access" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup><br/>
              Server: {{ config.adminFqdn }}<br/>
              Port: 222<br/>
              Username: {{ user.username }}@{{ app.fqdn }}<br/>
          </div>
        </div>
      </div>

      <div class="card" ng-show="view === 'resources'">
        <div class="task-active-overlay" ng-show="app.taskId"></div>
        <div class="row">
          <div class="col-md-12">
            <fieldset>
              <form role="form" name="resourcesForm" ng-submit="resources.submitMemoryLimit()" autocomplete="off">
                <div class="form-group">
                  <label class="control-label" for="memoryLimit">Memory Limit <sup><a ng-href="{{ config.webServerOrigin }}/documentation/apps/#increasing-the-memory-limit-of-an-app" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup> : <b>{{ resources.memoryLimit ? resources.memoryLimit / 1024 / 1024 + 'MB' : 'Default (256 MB)' }}</b></label>
                  <br/>
                  <div style="padding: 0 10px;">
                    <slider id="memoryLimit" ng-model="resources.memoryLimit" step="134217728" tooltip="hide" ticks="resources.memoryTicks" ticks-snap-bounds="67108864"></slider>
                  </div>
                </div>

                <input class="ng-hide" type="submit" ng-disabled="resources.memoryLimit === resources.currentMemoryLimit || resourcesForm.$invalid || resources.busy"/>
              </form>
            </fieldset>
          </div>
        </div>
        <div class="row">
          <div class="col-md-12 text-right">
            <button class="btn btn-outline btn-primary pull-right" ng-click="resources.submitMemoryLimit()" ng-disabled="resources.memoryLimit === resources.currentMemoryLimit || resourcesForm.$invalid || resources.busy"><i class="fa fa-circle-notch fa-spin" ng-show="resources.busy"></i> Resize</button>
          </div>
        </div>
        <hr/>
        <div class="row">
          <div class="col-md-12">
            <label class="control-label" for="resourcesEnableDataDir">Custom Data Directory <sup><a ng-href="{{ config.webServerOrigin }}/documentation/storage/#moving-a-single-apps-data-directory-to-another-location" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
            <p>
              By default, this app's data is located at <code>/home/yellowtent/appsdata/{{ app.id }}</code>. If the server is running out of disk space,
              you can mount an external disk and move this app's data there.
            </p>
            <fieldset>
              <form role="form" name="resourcesDataDirForm" ng-submit="resources.submitDataDir()" autocomplete="off">
                <div class="form-group" ng-class="{ 'has-error': resourcesDataDirForm.$dirty && resources.error.dataDir }">
                  <div ng-show="resources.error.dataDir">{{ resources.error.dataDir }}</div>
                  <input type="text" class="form-control" name="dataDir" placeholder="Leave empty to use platform default" ng-model="resources.dataDir">
                </div>

                <input class="ng-hide" type="submit" ng-disabled="!resourcesDataDirForm.$dirty || resourcesDataDirForm.$invalid || resources.busyDataDir"/>
              </form>
            </fieldset>
          </div>
        </div>
        <div class="row">
          <div class="col-md-12 text-right">
            <button class="btn btn-outline btn-primary pull-right" ng-click="resources.submitDataDir()" ng-disabled="!resourcesDataDirForm.$dirty || resourcesDataDirForm.$invalid || resources.busyDataDir"><i class="fa fa-circle-notch fa-spin" ng-show="resources.busyDataDir"></i> Move Data</button>
          </div>
        </div>
      </div>

      <div class="card" ng-show="view === 'email'">
        <div class="task-active-overlay" ng-show="app.taskId"></div>
        <div class="row">
          <div class="col-md-12">
            <label class="control-label" for="emailMailboxNameEnabled">Mail FROM Address</label>
            <p>This sets the address from which this app sends email. This app is already configured to send mail using {{app.domain}}'s <a ng-href="/#/email/{{ app.domain }}">Outbound Email</a> settings.</p>

            <fieldset>
              <form role="form" name="emailForm" ng-submit="email.submit()" autocomplete="off">
                <!-- recvmail currently only works with cloudron email -->
                <div class="form-group" ng-class="{ 'has-error': emailForm.$dirty && email.error.mailboxName }">
                  <div ng-show="email.error.mailboxName">{{ email.error.mailboxName }}</div>

                  <div class="input-group form-inline" ng-class="{ 'has-error': !emailForm.mailboxName.$dirty && email.error.mailboxName }">
                    <input type="text" class="form-control" name="mailboxName" placeholder="Leave empty to use platform default" ng-model="email.mailboxName">

                    <div class="input-group-btn">
                      <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
                        <span>{{ '@' + email.mailboxDomain.domain }}</span>
                        <span class="caret"></span>
                      </button>
                      <ul class="dropdown-menu dropdown-menu-right" role="menu">
                        <li ng-repeat="domain in domains">
                          <a href="" ng-click="email.mailboxDomain = domain">{{ domain.domain }}</a>
                        </li>
                      </ul>
                    </div>
                  </div>
                  <br/>
                </div>
                <input class="ng-hide" type="submit" ng-disabled="!emailForm.$dirty || email.busy"/>
              </form>
            </fieldset>
          </div>
        </div>
        <div class="row">
          <div class="col-md-12 text-right">
            <button class="btn btn-outline btn-primary pull-right" ng-click="email.submit()" ng-disabled="!emailForm.$dirty || email.busy"><i class="fa fa-circle-notch fa-spin" ng-show="email.busy"></i> Save</button>
          </div>
        </div>
      </div>

      <div class="card" ng-show="view === 'security'">
        <div class="row">
          <div class="col-md-12">
            <fieldset>
              <form role="form" name="securityForm" ng-submit="security.submit()" autocomplete="off">
                <div class="form-group">
                  <label class="control-label" style="width: 100%">Robots.txt <sup><a ng-href="{{ config.webServerOrigin }}/documentation/apps/#indexing-by-search-engines-robotstxt" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup> <a href="" class="pull-right" style="font-weight: normal;" ng-click="security.robotsTxt = ROBOTS_DISABLE_INDEXING_TEMPLATE">Disable indexing</a></label>
                  <textarea ng-model="security.robotsTxt" placeholder="Leave empty to allow all bots to index this app" class="form-control" rows="4"></textarea>
                </div>

                <div class="form-group">
                  <label class="control-label" style="width: 100%">Content Security Policy<sup><a ng-href="{{ config.webServerOrigin }}/documentation/apps/#custom-csp" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup> </label>
                  <p>Setting this option will override any CSP headers sent by the app itself</p>
                  <textarea ng-model="security.csp" placeholder="default-src 'self'; frame-ancestors 'none';" class="form-control" rows="2"></textarea>
                </div>

                <input class="ng-hide" type="submit" ng-disabled="securityForm.$invalid || security.busy"/>
              </form>
            </fieldset>
          </div>
        </div>
        <br/>
        <div class="row">
          <div class="col-md-12 text-right">
            <button class="btn btn-outline btn-primary pull-right" ng-click="security.submit()" ng-disabled="security.$invalid || security.busy"><i class="fa fa-circle-notch fa-spin" ng-show="security.busy"></i> Save</button>
          </div>
        </div>
      </div>

      <div class="card" ng-show="view === 'updates'">
        <div class="row">
          <div class="col-md-12">
            <label class="control-label">Check For Updates</label>
            <p ng-show="app.appStoreId">This app is running {{ app.manifest.title }} {{ app.upstreamVersion }} (Package <a ng-href="/#/appstore/{{app.manifest.id}}?version={{app.manifest.version}}">v{{ app.manifest.version }}</a>) and was last updated <code>{{ app.updateTime | prettyDate }}</code>.</p>
            <p ng-show="!app.appStoreId">This app is running <code>{{ app.manifest.dockerImage }}</code> (Package v{{ app.manifest.version }}) and was last updated <code>{{ app.updateTime | prettyDate }}</code>.</p>
            <br/>
            <button class="btn btn-primary pull-right" uib-tooltip="{{ app.appStoreId ? '' : 'Not available for custom apps' }}" ng-disabled="!app.appStoreId" ng-click="updates.check()" ng-hide="config.update.apps[app.id].manifest.version && config.update.apps[app.id].manifest.version !== app.manifest.version" ng-disabled="updates.busyCheck"><i class="fa fa-circle-notch fa-spin" ng-show="updates.busyCheck"></i> Check for Updates</button>
            <button class="btn btn-success pull-right" ng-click="updates.askUpdate()" ng-show="app.installationState !== 'pending_update' && config.update.apps[app.id].manifest.version && config.update.apps[app.id].manifest.version !== app.manifest.version" ng-disabled="app.taskId || !(app | installSuccess)">Update Available</button>
          </div>
        </div>
        <hr/>
        <div class="row">
          <div class="col-md-12">
            <label class="control-label">Automatic Updates</label>
            <p>Cloudron periodically polls the App Store to check for updates. If you disable automatic updates, be sure to manually check for updates.</p>
            <p>Automatic Updates is currently <b>{{ updates.enableAutomaticUpdate ? 'enabled' : 'disabled' }}</b>.</p>
            <button class="btn btn-primary pull-right" uib-tooltip="{{ app.appStoreId ? '' : 'Not available for custom apps' }}" ng-class="{ 'btn-danger': updates.enableAutomaticUpdate }" ng-click="updates.toggleAutomaticUpdates()" ng-disabled="updates.busy || !app.appStoreId"><i class="fa fa-circle-notch fa-spin" ng-show="updates.busy"></i> {{ updates.enableAutomaticUpdate ? 'Disable' : 'Enable' }} Automatic Updates</button>
          </div>
        </div>
      </div>

      <div class="card"ng-show="view === 'backups'">
        <div class="row">
          <div class="col-md-12">
            <label class="control-label">Create Backup</label>
            <p>This creates a snapshot of the app at this instant.</p>
            <button type="button" class="btn btn-primary pull-right" ng-click="backups.createBackup()" ng-disabled="app.taskId || backups.busyCreate"><i class="fa fa-circle-notch fa-spin" ng-show="app.installationState === 'pending_backup' || backups.busyCreate"></i> Create Backup</button>
          </div>
        </div>
        <hr/>
        <div class="row">
          <div class="col-md-12">
            <label class="control-label">Backups</label>
            <p>You can use app backups to restore or clone this app.</p>

            <!-- backup id copy helper -->
            <input type="text" class="offscreen" aria-hidden="true" id="backupIdHelper" value="">

            <table class="table table-hover" style="margin: 0;">
              <thead>
                <tr>
                  <th width="25px">&nbsp;</th>
                  <th>Created</th>
                  <th>Version</th>
                  <th class="text-right" width="180px">Actions</th>
                </tr>
              </thead>
              <tbody>
                <tr ng-hide="backups.backups.length">
                  <td colspan="4" class="text-center">This app has no backups yet.</td>
                </tr>
                <tr ng-repeat="backup in backups.backups">
                  <td><div ng-click="backups.copyBackupId(backup)" class="hand" uib-tooltip="{{ backups.copyBackupIdDone ? 'Copied to clipboard' : 'Click to copy backup id' }}" tooltip-placement="right"><i class="fa fa-copy"></i></div></td>
                  <td><div uib-tooltip="{{ backup.creationTime | prettyLongDate }}">{{ backup.creationTime | prettyDate }}</div></td>
                  <td>{{ backup.version }}</td>
                  <td class="text-right no-wrap" style="vertical-align: bottom">
                    <button class="btn btn-xs btn-default" ng-click="clone.show(backup)" uib-tooltip="Clone from this Backup"><i class="far fa-clone"></i></button>
                    <button class="btn btn-xs btn-danger" ng-click="restore.show(backup)" ng-disabled="app.taskId" uib-tooltip="Restore to this Backup"><i class="fas fa-history"></i></button>
                  </td>
                </tr>
              </tbody>
            </table>
          </div>
        </div>
        <hr/>
        <div class="row">
          <div class="col-md-12">
            <label class="control-label">Automatic Backups</label>

            <p>Cloudron periodically creates a backup based on the <a href="/#/backups">backup</a> settings. If you disable automatic backups, be sure to manually create backups often.</p>
            <p>Automatic Backups is currently <b>{{ backups.enableBackup ? 'enabled' : 'disabled' }}</b>.</p>

            <button class="btn btn-primary pull-right" ng-class="{ 'btn-danger': backups.enableBackup }" ng-click="backups.toggleAutomaticBackups()" ng-disabled="backups.busy"><i class="fa fa-circle-notch fa-spin" ng-show="backups.busy"></i> {{ backups.enableBackup ? 'Disable' : 'Enable' }} Automatic Backups</button>
          </div>
        </div>
      </div>

      <div class="card" ng-show="view === 'debug'">
        <div class="row" ng-hide="true">
          <div class="col-md-12">
            <label class="control-label">Status</label>
            <div>
                Version
                <span class="app-info-meta text-small">{{ app.manifest.title }} {{ app.upstreamVersion }} (Package <a ng-href="/#/appstore/{{app.manifest.id}}?version={{app.manifest.version}}">v{{ app.manifest.version }}</a>) </span>
                <br/>
                App ID <span class="app-info-meta  text-small">{{ app.id }}</a> </span>
                <br/>
                Installed <span class="app-info-meta  text-small">{{ app.creationTime | prettyDate }}</a> </span>
            </div>
          </div>
        </div>
        <div class="row">
          <div class="col-md-12">
            <label class="control-label">Console Access</label>
            <p>This will open a console connection to the app. The terminal is sandboxed and only provides access to the app container's filesystem.</p>
            <a class="btn btn-primary pull-right" ng-href="{{ '/terminal.html?id=' + app.id }}" target="_blank">Terminal</a>
            <a class="btn btn-primary pull-right" ng-href="{{ '/logs.html?appId=' + app.id }}" target="_blank">Logs</a>
          </div>
        </div>
        <hr/>
        <div class="row">
          <div class="col-md-12">
            <label class="control-label">Start / Stop</label>
            <p>If the app is not responding, try restarting the app.</p>
            <button class="btn btn-success pull-right" ng-class="{ 'btn-danger': app.runState === 'running' }" ng-click="debug.toggleRunState()" ng-disabled="app.taskId || app.error || debug.busyRunState"><i ng-show="debug.busyRunState" class="fa fa-circle-notch fa-spin"></i>
              {{ app.runState === 'running' ? 'Stop App' : 'Start App' }}
            </button>
          </div>
        </div>
        <hr/>
        <div class="row">
          <div class="col-md-12">
            <label class="control-label">Repair</label>
            <p>Use the repair button to retry failed operations or if the app is down.</p>

            <p>If the app is not starting up because of a broken plugin or misconfiguration, use the <a ng-href="{{ '/terminal.html?id=' + app.id }}" target="_blank">Terminal</a>
              and click 'Pause' to edit the app's filesystem.</p>

            <p ng-show="app.error">An error occurred during the <b>{{ app.error.installationState | taskName }}</b> operation: <span class="text-danger"><b>{{ app.error.reason + ': ' + app.error.message }}</b></span></p>
            <!--<p ng-show="app.error" class="text-info"><b>{{ app.error | errorSuggestion }}</b></p>-->
            <button class="btn btn-success pull-right" ng-click="repair.show()" ng-disabled="app.taskId">Repair</button>

            <button class="btn btn-danger pull-right" ng-click="debug.stopAppTask(app.taskId)" ng-show="app.taskId">Cancel Current Task</button>
          </div>
        </div>
      </div>

      <div class="card" ng-show="view === 'uninstall'">
          <div class="row">
            <div class="col-md-12">
              <label class="control-label">Uninstall</label>
              <p>This will uninstall the app immediately and remove all it's data. The site will be inaccessible.
              </p>
              <p>App backups are not removed and will be cleaned up based on the backup policy. You can resurrect this app from an existing
                app backup using the following <a target="_blank" ng-href="{{ config.webServerOrigin }}/documentation/backups/#restoring-uninstalled-app">instructions</a>.</p>
              <button class="btn btn-danger pull-right" ng-click="uninstall.ask()">Uninstall</button>
            </div>
          </div>
        </div>

    </div>
  </div>
</div>
