
<!-- Modal install app -->
<div class="modal fade appstore-install" id="appInstallModal" tabindex="-1" role="dialog">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <img ng-src="{{appInstall.app.iconUrl}}" onerror="this.onerror=null;this.src='img/appicon_fallback.png'" class="app-icon"/>
        <h3 class="appstore-install-title" title="Version {{ appInstall.app.manifest.version }}">{{ appInstall.app.manifest.title }} <span class="badge badge-danger" ng-show="appInstall.app.publishState === 'testing'">Testing</span></h3>
        <br/>
        <span class="appstore-install-meta"><a href="{{ appInstall.app.manifest.website }}" target="_blank">{{ appInstall.app.manifest.author }}</a></span>
        <br/>
        <span class="appstore-install-meta">Last updated {{ appInstall.app.creationDate | prettyDate }}</span>
        <br/>
        <span class="appstore-install-meta hand">Requires atleast {{ appInstall.app.manifest.memoryLimit | prettyMemory }}MB memory</span>
      </div>
      <div class="modal-body">
        <div class="collapse" id="collapseInstallForm" data-toggle="false">
          <form role="form" name="appInstallForm" ng-submit="appInstall.submit()" autocomplete="off">
            <div class="has-error text-center" ng-show="appInstall.error.other" ng-bind-html="appInstall.error.other"></div>
            <div class="form-group" ng-class="{ 'has-error': (appInstallForm.location.$dirty && appInstallForm.location.$invalid) || (!appInstallForm.location.$dirty && appInstall.error.location) }">
              <label class="control-label" for="appInstallLocationInput">Location</label>
              <div ng-show="appInstall.error.location"><small>{{ appInstall.error.location }}</small></div>
              <div class="input-group form-inline">
                <input type="text" class="form-control" ng-model="appInstall.location" id="appInstallLocationInput" 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>{{ (appInstall.location ? (appInstall.domain.config.hyphenatedSubdomains ? '-' : '.') : '') + appInstall.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="appInstall.domain = domain">{{ domain.domain }}</a>
                    </li>
                  </ul>
                </div>
              </div>
            </div>

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

            <div class="has-error text-center" ng-show="appInstall.error.port">{{ appInstall.error.port }}</div>
            <div ng-repeat="(env, info) in appInstall.portBindingsInfo">
              <ng-form name="portInfo_form">
                <div class="form-group" ng-class="{ 'has-error': (!appInstallForm.itemName{{$index}}.$dirty && appInstall.error.port) || (portInfo_form.itemName{{$index}}.$dirty && portInfo_form.itemName{{$index}}.$invalid) }">
                  <label class="control-label" for="inputPortInfo{{env}}"><input type="checkbox" ng-model="appInstall.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="appInstall.portBindings[env]" ng-disabled="!appInstall.portBindingsEnabled[env]" id="inputPortInfo{{env}}" later-name="itemName{{$index}}" min="{{hostPortMin}}" max="{{hostPortMax}}" required>
                </div>
              </ng-form>
            </div>

            <!-- for spaces users, the User management is hidden. thus the admin flag check -->
            <div class="form-group" ng-show="user.admin && appInstall.customAuth && !appInstall.app.manifest.addons.email">
              <label class="control-label">User management</label>
              <p>This app has it's own user management.</p>
            </div>

            <div class="form-group" ng-show="user.admin && appInstall.app.manifest.addons.email">
              <label class="control-label">User management</label>
              <p>All users with a mailbox on this Cloudron have access.</p>
            </div>

            <div class="form-group" ng-show="user.admin && !appInstall.customAuth && !appInstall.app.manifest.addons.email">
              <label class="control-label">User management</label>
              <div class="radio" ng-show="appInstall.optionalSso">
                <label>
                  <input type="radio" ng-model="appInstall.accessRestrictionOption" value="nosso">
                  Leave user management to the app
                </label>
              </div>
              <div class="radio">
                <label>
                  <input type="radio" ng-model="appInstall.accessRestrictionOption" value="any">
                  Allow all users from this Cloudron
                </label>
              </div>
              <div class="radio">
                <label>
                  <input type="radio" ng-model="appInstall.accessRestrictionOption" value="groups">
                  Only allow the following users and groups <span class="label label-danger" ng-show="appInstall.accessRestrictionOption === 'groups' && !appInstall.isAccessRestrictionValid()">Select at least one user or group</span>
                </label>
              </div>
              <div>
                <div style="margin-left: 20px;">
                  <div class="col-md-5">
                    Users: &nbsp;
                    <multiselect ng-model="appInstall.accessRestriction.users" ng-disabled="appInstall.accessRestrictionOption !== 'groups'" options="user.username for user in users" data-multiple="true" filter-after-rows="5" scroll-after-rows="10"></multiselect>
                  </div>

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

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

            <p ng-show="appInstall.app.manifest.addons.email" class="text-info">
              This app is pre-configured for use with <a href="https://cloudron.io/documentation/email/" target="_blank">Cloudron Email</a>.
            </p>

            <div class="hide">
              <label class="control-label" for="appInstallCertificateInput" ng-show="appInstall.domain.provider !== 'caas'">Certificate (optional)</label>
              <div class="has-error text-center" ng-show="appInstall.error.cert && appInstall.domain.provider !== 'caas'">{{ appInstall.error.cert }}</div>
              <div class="form-group" ng-class="{ 'has-error': !appInstallForm.certificate.$dirty && appInstall.error.cert }" ng-show="appInstall.domain.provider !== 'caas'">
                <div class="input-group">
                  <input type="file" id="appInstallCertificateFileInput" style="display:none"/>
                  <input type="text" class="form-control" placeholder="Certificate" ng-model="appInstall.certificateFileName" id="appInstallCertificateInput" name="certificate" onclick="getElementById('appInstallCertificateFileInput').click();" style="cursor: pointer;" ng-required="appInstall.keyFileName">
                  <span class="input-group-addon">
                    <i class="fa fa-upload" onclick="getElementById('appInstallCertificateFileInput').click();"></i>
                  </span>
                </div>
              </div>
              <div class="form-group" ng-class="{ 'has-error': !appInstallForm.key.$dirty && appInstall.error.cert }" ng-show="appInstall.domain.provider !== 'caas'">
                <div class="input-group">
                  <input type="file" id="appInstallKeyFileInput" style="display:none"/>
                  <input type="text" class="form-control" placeholder="Key" ng-model="appInstall.keyFileName" id="appInstallKeyInput" name="key" onclick="getElementById('appInstallKeyFileInput').click();" style="cursor: pointer;" ng-required="appInstall.certificateFileName">
                  <span class="input-group-addon">
                    <i class="fa fa-upload" onclick="getElementById('appInstallKeyFileInput').click();"></i>
                  </span>
                </div>
              </div>
            </div>

            <input class="ng-hide" type="submit" ng-disabled="appInstallForm.$invalid || busy"/>
          </form>
        </div>
        <div class="collapse" id="collapseMediaLinksCarousel" data-toggle="false">
          <div ng-repeat="mediaLink in appInstall.mediaLinks" class="slick-item" style="background-image: url('{{mediaLink}}');" ng-show="appInstall.mediaLinks.length == 1"></div>
          <slick init-onload="true" current-index="0" autoplay="true" arrows="false" autoplay-speed="2000" data="appInstall.mediaLinks" ng-show="appInstall.mediaLinks.length > 1">
            <div ng-repeat="mediaLink in appInstall.mediaLinks" class="slick-item" style="background-image: url('{{mediaLink}}');"></div>
          </slick>
          <div class="appstore-install-description">
            <div ng-bind-html="appInstall.app.manifest.description | markdown2html"></div>
          </div>
        </div>
        <div class="collapse" id="collapseResourceConstraint" data-toggle="false">
          <h4 class="text-danger">This Cloudron is running low on resources.</h4>
          <p>Please upgrade to a server instance with more memory. Alternately, free up resources by uninstalling unused applications.</p>
        </div>
        <div class="collapse" id="collapseSubscriptionRequired" data-toggle="false">
          <iframe ng-src="{{ config.webServerOrigin + '/helper/' + appInstall.subscriptionHelperPage + '?appstoreId=' + appInstall.app.manifest.appstoreId + '&email=' + subscription.emailEncoded + '&cloudronId=' + subscription.cloudronId }}" style="width: 100%; height: 150px; border: none;"></iframe>
        </div>
      </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-show="user.admin && appInstall.state === 'resourceConstraint'" ng-click="appInstall.showForm(true)">Install anyway</button>
        <button type="button" class="btn btn-success" ng-show="appInstall.state === 'appInfo'" ng-click="appInstall.showForm()">Install</button>
        <button type="button" class="btn btn-success" ng-show="appInstall.state === 'installForm'" ng-click="appInstall.submit()" ng-disabled="appInstallForm.$invalid || appInstall.busy"><i class="fa fa-circle-notch fa-spin" ng-show="appInstall.busy"></i> Install {{ appInstall.needsOverwrite ? 'and overwrite DNS' : '' }}</button>
      </div>
    </div>
  </div>
</div>

<!-- Modal app not found -->
<div class="modal fade" id="appNotFoundModal" tabindex="-1" role="dialog">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h4 class="modal-title">App not found</h4>
            </div>
            <div class="modal-body">
                There is no such app <b>{{ appNotFound.appId }}</b><span ng-show="appNotFound.version"> with version <b>{{ appNotFound.version }}</b></span>.
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-primary" data-dismiss="modal">OK</button>
            </div>
        </div>
    </div>
</div>

<div ng-show="!ready" class="loading-banner">
    <h1><i class="fa fa-circle-notch fa-spin"></i></h1>
</div>

<!-- appstore login -->
<div ng-show="ready && !validSubscription" class="container card card-small appstore-login ng-cloak">
    <div class="col-md-12 text-center">
        <h1 ng-show="appstoreLogin.register">Sign up with Cloudron.io</h1>
        <h1 ng-hide="appstoreLogin.register">Login to Cloudron.io</h1>
    </div>
    <div class="col-md-12 text-center">
        <p>This account is used to access the App Store and manage your subscription</p>
    </div>
    <div class="col-md-12" style="margin-bottom: 10px;">
        <small class="text-danger" ng-show="appstoreLogin.error.generic">{{ appstoreLogin.error.generic }}</small>
    </div>
    <div class="col-md-12">
        <br/>

        <form name="appstoreLoginForm" role="form" novalidate ng-submit="appstoreLogin.submit()" autocomplete="off">
            <input type="password" style="display: none;">

            <div class="form-group" ng-class="{ 'has-error': (appstoreLoginForm.email.$dirty && appstoreLoginForm.email.$invalid) || appstoreLogin.error.generic }">
                <label class="control-label">Email</label>
                <input type="email" class="form-control" ng-model="appstoreLogin.email" id="inputAppstoreLoginEmail" name="email" required autofocus>
                <div class="control-label" ng-show="(!appstoreLoginForm.email.$dirty && appstoreLogin.error.email) || (appstoreLoginForm.email.$dirty && appstoreLoginForm.email.$invalid) || appstoreLogin.error.email">
                    <small class="text-danger" ng-show="appstoreLogin.error.email">{{ appstoreLogin.error.email }}</small>
                </div>
            </div>

            <div class="form-group" ng-class="{ 'has-error': (!appstoreLoginForm.password.$dirty && appstoreLogin.error.password) || (appstoreLoginForm.password.$dirty && appstoreLoginForm.password.$invalid) || appstoreLogin.error.generic }">
                <label class="control-label">Password</label>
                <input type="password" class="form-control" ng-model="appstoreLogin.password" id="inputAppstoreLoginPassword" name="password" required>
                <div class="control-label" ng-show="(!appstoreLoginForm.password.$dirty && appstoreLogin.error.password) || (appstoreLoginForm.password.$dirty && appstoreLoginForm.password.$invalid)">
                    <small ng-show="!appstoreLoginForm.password.$dirty && appstoreLogin.error.password">Wrong password</small>
                </div>
            </div>

            <div class="form-group" ng-hide="appstoreLogin.register" ng-class="{ 'has-error': appstoreLogin.error.totpToken }">
                <label class="control-label">2FA Token (if enabled)</label>
                <input type="text" class="form-control" ng-model="appstoreLogin.totpToken" id="inputAppstoreLoginTotpToken" name="totpToken">
                <div class="control-label" ng-show="appstoreLogin.error.totpToken">
                    <small ng-show="appstoreLogin.error.totpToken">{{ appstoreLogin.error.totpToken }}</small>
                </div>
            </div>

            <div class="checkbox">
                <label>
                    <input type="checkbox" ng-model="appstoreLogin.termsAccepted">I accept the Cloudron <a href="https://cloudron.io/legal/license.html" target="_blank">license</a>
                </label>
            </div>

            <br/>

            <center>
                <button type="submit" class="btn btn-lg btn-success" ng-disabled="appstoreLoginForm.$invalid || appstoreLogin.busy || !appstoreLogin.termsAccepted">
                    <i class="fa fa-circle-notch fa-spin" ng-show="appstoreLogin.busy"></i> <span ng-hide="appstoreLogin.register">Login</span><span ng-show="appstoreLogin.register">Create Account</span>
                </button>

                <br/>
                <br/>

                <a href="" ng-click="appstoreLogin.register = true" ng-hide="appstoreLogin.register">Don't have an account yet? Sign up</a>
                <a href="" ng-click="appstoreLogin.register = false" ng-show="appstoreLogin.register">Already have an account? Log in</a>
            </center>

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

<!-- give more vertical spacing so the login form does not appear clipped -->
<div ng-show="ready && !validSubscription">
    <br/>
    <br/>
</div>

<div ng-show="ready && validSubscription" class="ng-cloak" id="appstoreGrid">
    <div class="col-md-2">
        <br/>
        <div>
            <form ng-submit="search()">
                <div class="input-group">
                    <input type="text" id="appstoreSearch" class="form-control" style="height: 40px" placeholder="Search" ng-model="searchString" ng-change="search()" autofocus>
                </div>
            </form>
        </div>
        <br/>
        <a href="" class="appstore-category-link" ng-click="showCategory($event);" ng-class="{'category-active': category === 'featured' }" category="featured">Popular</a>
        <a href="" class="appstore-category-link" ng-click="showCategory($event);" ng-class="{'category-active': category === 'new' }" category="new">New Apps</a>
        <a href="" class="appstore-category-link" ng-click="showCategory($event);" ng-class="{'category-active': category === 'recent' }" category="recent">Recently Updated</a>
        <a href="" class="appstore-category-link" ng-click="showCategory($event);" ng-class="{'category-active': category === '' }" category="">All</a>
        <br/>
        <a href="" class="appstore-category-link" ng-click="showCategory($event);" ng-class="{'category-active': category === 'analytics' }" category="analytics"><i class="fa fa-chart-line"></i> Analytics</a>
        <a href="" class="appstore-category-link" ng-click="showCategory($event);" ng-class="{'category-active': category === 'blog' }" category="blog"><i class="fa fa-font"></i> Blog</a>
        <a href="" class="appstore-category-link" ng-click="showCategory($event);" ng-class="{'category-active': category === 'chat' }" category="chat"><i class="fa fa-comments"></i> Chat</a>
        <a href="" class="appstore-category-link" ng-click="showCategory($event);" ng-class="{'category-active': category === 'git' }" category="git"><i class="fa fa-code-branch"></i> Code Hosting</a>
        <a href="" class="appstore-category-link" ng-click="showCategory($event);" ng-class="{'category-active': category === 'CRM' }" category="crm"><i class="fab fa-connectdevelop"></i> CRM</a>
        <a href="" class="appstore-category-link" ng-click="showCategory($event);" ng-class="{'category-active': category === 'document' }" category="document"><i class="fa fa-file-word"></i> Documents</a>
        <a href="" class="appstore-category-link" ng-click="showCategory($event);" ng-class="{'category-active': category === 'email' }" category="email"><i class="fa fa-envelope"></i> Email</a>
        <a href="" class="appstore-category-link" ng-click="showCategory($event);" ng-class="{'category-active': category === 'sync' }" category="sync"><i class="fa fa-sync-alt"></i> File Sync</a>
        <a href="" class="appstore-category-link" ng-click="showCategory($event);" ng-class="{'category-active': category === 'finance' }" category="finance"><i class="fa fa-hand-holding-usd"></i> Finance</a>
        <a href="" class="appstore-category-link" ng-click="showCategory($event);" ng-class="{'category-active': category === 'forum' }" category="forum"><i class="fa fa-users"></i> Forum</a>
        <a href="" class="appstore-category-link" ng-click="showCategory($event);" ng-class="{'category-active': category === 'gallery' }" category="gallery"><i class="fa fa-images"></i> Gallery</a>
        <a href="" class="appstore-category-link" ng-click="showCategory($event);" ng-class="{'category-active': category === 'game' }" category="game"><i class="fa fa-gamepad"></i> Games</a>
        <a href="" class="appstore-category-link" ng-click="showCategory($event);" ng-class="{'category-active': category === 'notes' }" category="notes"><i class="fa fa-sticky-note"></i> Notes</a>
        <a href="" class="appstore-category-link" ng-click="showCategory($event);" ng-class="{'category-active': category === 'project' }" category="project"><i class="fas fa-project-diagram"></i> Project Management</a>
        <a href="" class="appstore-category-link" ng-click="showCategory($event);" ng-class="{'category-active': category === 'vpn' }" category="vpn"><i class="fa fa-user-secret"></i> VPN</a>
        <a href="" class="appstore-category-link" ng-click="showCategory($event);" ng-class="{'category-active': category === 'hosting' }" category="hosting"><i class="fa fa-server"></i> Web Hosting</a>
        <a href="" class="appstore-category-link" ng-click="showCategory($event);" ng-class="{'category-active': category === 'wiki' }" category="wiki"><i class="fab fa-wikipedia-w"></i> Wiki</a>
        <br/>
        <br/>
        <a href="https://forum.cloudron.io/category/5/app-requests" target="_blank">Missing an app? Let us know.</a>
    </div>
    <div class="col-md-10" ng-show="apps.length">
        <div class="row-no-margin">
            <div class="col-sm-1 appstore-item" ng-repeat="app in apps | orderBy:'installCount':true">
                <div class="appstore-item-content highlight" ng-click="gotoApp(app)" ng-class="{ 'appstore-item-content-testing': app.releaseState === 'unstable' }">
                    <span class="badge badge-danger appstore-item-badge-testing" ng-show="app.releaseState === 'unstable'">Unstable</span>
                    <div class="appstore-item-content-icon col-same-height">
                        <img ng-src="{{app.iconUrl}}" onerror="this.onerror=null;this.src='img/appicon_fallback.png'" class="app-icon"/>
                    </div>
                    <div class="appstore-item-content-description col-same-height">
                        <h4 class="appstore-item-content-title">{{ app.manifest.title }}</h4>
                        <div class="appstore-item-content-tagline text-muted">{{ app.manifest.tagline }}</div>
                        <!-- <div class="appstore-item-rating"><i class="fa fa-star"></i><i class="fa fa-star"></i><i class="fa fa-star"></i><i class="fa fa-star-half-o"></i><i class="fa fa-star-o"></i></div> -->
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div class="col-md-10 animateMeOpacity loading-banner" ng-show="!apps.length">
        <h3 class="text-muted">No apps found.</h3>
        <a href="https://forum.cloudron.io/category/5/app-requests" target="_blank"><h3>Request an app or vote for one in our forum.</h3></a>
    </div>
</div>
