2019-09-13 11:29:19 +02:00
<!-- 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 > -->
2019-09-10 19:21:30 +02:00
< script >
function imageErrorHandler(elem) {
'use strict';
elem.src = elem.getAttribute('fallback-icon');
elem.onerror = null; // avoid retry after default icon cannot be loaded
}
< / script >
2019-09-13 11:18:43 +02:00
<!-- 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" > Really uninstall {{ app.fqdn }} ?< / h4 >
< / div >
< div class = "modal-body" >
< p > Deleting the app will also remove all it's data. App backups are not removed and will be cleaned up based on the backup policy.< / 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 >
2019-09-13 17:18:37 +02:00
<!-- 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 = "appClone.location && appClone.domain.provider === 'manual'" >
< b > Add an A record manually for {{ appClone.location }} to this Cloudron's public IP< / b >
< br >
< / p >
< div class = "has-error text-center" ng-show = "appClone.error.port" > {{ appClone.error.port }}< / div >
< div ng-repeat = "(env, info) in appClone.portBindingsInfo" >
< ng-form name = "portInfo_form" >
< div class = "form-group" ng-class = "{ 'has-error': (!appClone.itemName{{$index}}.$dirty && appClone.error.port) || (portInfo_form.itemName{{$index}}.$dirty && portInfo_form.itemName{{$index}}.$invalid) }" >
< label class = "control-label" for = "inputPortInfo{{env}}" > < input type = "checkbox" ng-model = "appClone.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 = "appClone.portBindings[env]" ng-disabled = "!appClone.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 = "appClone.submit()" > < i class = "far fa-clone" > < / i > Clone< / button >
< / div >
< / div >
< / div >
< / div >
2019-09-13 11:18:43 +02:00
2019-09-10 19:21:30 +02:00
< div class = "content" >
2019-09-13 11:12:11 +02:00
< div class = "task-indicator animateMe" ng-show = "app.taskId" >
2019-09-11 21:24:25 +02:00
< i class = "fa fa-circle-notch fa-spin" > < / i >
< span > {{ app | installationStateLabel:user }}< / span >
< / div >
2019-09-12 15:59:40 +02:00
< div class = "app-configure-links" >
< div ng-click = "scrollTo('overview')" > Overview< / div >
< div ng-click = "scrollTo('display')" > Display< / div >
< div ng-click = "scrollTo('location')" > Location< / div >
< div ng-click = "scrollTo('access')" > Access Control< / div >
< div ng-click = "scrollTo('resources')" > Resources< / div >
< div ng-click = "scrollTo('security')" > Security< / div >
< div ng-click = "scrollTo('updates')" > Updates< / div >
< div ng-click = "scrollTo('backups')" > Backups< / div >
2019-09-13 10:34:12 +02:00
< div ng-click = "scrollTo('debug')" > Debug< / div >
2019-09-12 15:59:40 +02:00
< / div >
2019-09-12 16:28:21 +02:00
< br / >
< div id = "overview" > < / div >
2019-09-10 19:21:30 +02:00
< div class = "card" >
< div class = "row" >
< div class = "col-md-12" >
2019-09-13 10:34:12 +02:00
< h2 style = "margin-top: 0;" >
2019-09-12 16:28:21 +02:00
< img ng-src = "{{ app.iconUrl || 'img/appicon_fallback.png' }}" fallback-icon = "img/appicon_fallback.png" onerror = "imageErrorHandler(this)" class = "app-icon" / >
{{ app.label || app.location || app.fqdn }}
2019-09-12 17:42:33 +02:00
< / h2 >
2019-09-12 16:28:21 +02:00
< br / >
2019-09-12 17:42:33 +02:00
2019-09-13 11:29:19 +02:00
< p >
< b > {{ app | installationStateLabel:user }}< / b >
< / p >
< br / >
2019-09-12 17:42:33 +02:00
< p >
{{ app.manifest.title }}
< span class = "app-info-meta text-small" > {{ 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 / >
Last updated < span class = "app-info-meta text-small" > {{ app.updateTime | prettyDate }}< / span >
< / p >
2019-09-12 16:28:21 +02:00
< br / >
2019-09-12 17:42:33 +02:00
< p ng-show = "app.manifest.addons.localstorage.ftp" >
< b > SFTP< / b > < 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 / >
< / p >
2019-09-10 19:21:30 +02:00
< br / >
2019-09-12 17:42:33 +02:00
< div >
2019-09-13 11:18:43 +02:00
< button class = "btn btn-danger" ng-click = "uninstall.show()" > Uninstall< / button >
2019-09-13 10:34:12 +02:00
< a class = "btn btn-outline btn-primary pull-right" ng-href = "https://{{ app.fqdn }}" target = "_blank" > < i class = "fas fa-external-link-alt" > < / i > Open App< / a >
2019-09-12 17:42:33 +02:00
< a class = "btn btn-outline btn-primary pull-right" ng-href = "{{ app.manifest.documentationUrl }}" target = "_blank" > Documentation< / a >
< / div >
2019-09-10 19:21:30 +02:00
< / div >
< / div >
< / div >
2019-09-12 15:59:40 +02:00
< div id = "display" > < h3 > Display< / h3 > < / div >
2019-09-10 19:21:30 +02:00
< div class = "card" >
< 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()" style = "background-image: url('{{ display.iconUrl() }}');" >
< 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 >
2019-09-12 16:28:21 +02:00
< input class = "ng-hide" type = "submit" ng-disabled = "(!display.icon.data && !displayForm.$dirty) || displayForm.$invalid || display.busy" / >
2019-09-10 19:21:30 +02:00
< / form >
< / fieldset >
< / div >
< / div >
< div class = "row" >
2019-09-12 16:28:21 +02:00
< 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 >
2019-09-10 19:21:30 +02:00
< / div >
< / div >
< / div >
2019-09-12 15:59:40 +02:00
< div id = "location" > < h3 > Location< / h3 > < / div >
2019-09-10 19:21:30 +02:00
< div class = "card" >
2019-09-13 11:02:13 +02:00
< div class = "task-active-overlay" ng-show = "app.taskId" > App task in progress...< / div >
2019-09-10 19:21:30 +02:00
< div class = "row" >
< div class = "col-md-12" >
< fieldset >
< form role = "form" name = "locationForm" ng-submit = "location.submit()" autocomplete = "off" >
< div class = "has-error text-center" ng-show = "location.error.other" > {{ location.error.other }}< / div >
< div class = "form-group" ng-class = "{ 'has-error': (locationForm.location.$dirty && locationForm.location.$invalid) || (!locationForm.location.$dirty && location.error.location) }" >
2019-09-12 17:08:45 +02:00
< label class = "control-label" for = "locationLocationInput" > Domain {{ location.error.location }} < / label >
2019-09-10 19:21:30 +02:00
< 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 >
< 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 >
< input class = "ng-hide" type = "submit" ng-disabled = "locationForm.$invalid || location.busy" / >
< / form >
< / fieldset >
< / div >
< / div >
< div class = "row" >
2019-09-12 17:08:45 +02:00
< div class = "col-md-12 text-right" >
2019-09-10 19:21:30 +02:00
< 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 >
2019-09-12 15:59:40 +02:00
< div id = "access" > < h3 > Access Control< / h3 > < / div >
2019-09-10 19:21:30 +02:00
< div class = "card" >
< 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" > < / 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" > < / 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-6" >
< span class = "text-success text-bold" ng-show = "access.success" > Saved< / span >
< / div >
< div class = "col-md-6 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 >
2019-09-12 15:59:40 +02:00
< div id = "resources" > < h3 > Resources< / h3 > < / div >
2019-09-10 19:21:30 +02:00
< div class = "card" >
2019-09-13 11:02:13 +02:00
< div class = "task-active-overlay" ng-show = "app.taskId" > App task in progress...< / div >
2019-09-10 19:21:30 +02:00
< div class = "row" >
< div class = "col-md-12" >
< fieldset >
< form role = "form" name = "resourcesForm" ng-submit = "resources.submit()" 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 >
<!-- We do not show this currently -->
< div ng-if = "false" class = "form-group" ng-class = "{ 'has-error': !resourcesForm.dataDir.$dirty && resources.error.dataDir }" >
< input type = "checkbox" id = "resourcesEnableDataDir" ng-model = "resources.dataDirEnabled" >
< label class = "control-label" for = "resourcesEnableDataDir" > Custom Data Directory< / label >
< div class = "control-label" ng-show = "resources.error.dataDir" > {{resources.error.dataDir}}< / div >
< input type = "text" class = "form-control" id = "resourcesDataDirInput" name = "dataDir" ng-disabled = "!resources.dataDirEnabled" placeholder = "/mnt/appdata" ng-model = "resources.dataDir" >
< / div >
2019-09-13 11:05:34 +02:00
< input class = "ng-hide" type = "submit" ng-disabled = "resources.memoryLimit === resources.currentMemoryLimit || resourcesForm.$invalid || resources.busy" / >
2019-09-10 19:21:30 +02:00
< / form >
< / fieldset >
< / div >
< / div >
< div class = "row" >
2019-09-13 11:05:34 +02:00
< div class = "col-md-12 text-right" >
< button class = "btn btn-outline btn-primary pull-right" ng-click = "resources.submit()" ng-disabled = "resources.memoryLimit === resources.currentMemoryLimit || resources.$invalid || resources.busy" > < i class = "fa fa-circle-notch fa-spin" ng-show = "resources.busy" > < / i > Save< / button >
2019-09-10 19:21:30 +02:00
< / div >
< / div >
< / div >
2019-09-12 15:59:40 +02:00
< div id = "email" ng-if = "app.manifest.addons.sendmail || app.manifest.addons.recvmail" > < h3 > Email< / h3 > < / div >
2019-09-10 19:21:30 +02:00
< div class = "card" ng-if = "app.manifest.addons.sendmail || app.manifest.addons.recvmail" >
2019-09-13 11:02:13 +02:00
< div class = "task-active-overlay" ng-show = "app.taskId" > App task in progress...< / div >
2019-09-10 19:21:30 +02:00
< div class = "row" >
< div class = "col-md-12" >
< 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.mailboxName.$dirty && email.error.mailboxName }" >
< input type = "checkbox" id = "emailMailboxNameEnabled" ng-model = "email.mailboxNameEnabled" >
< label class = "control-label" for = "emailMailboxNameEnabled" > Custom Mail FROM< / label >
< div class = "has-error" ng-show = "email.error.mailboxName" > {{ email.error.mailboxName }}< / div >
< div class = "input-group form-inline" >
< input type = "text" class = "form-control" ng-required = "email.mailboxNameEnabled" name = "mailboxName" ng-model = "email.mailboxName" uib-tooltip = "App FROM email address. Addresses ending with '.app' are reserved." tooltip-class = "long" ng-disabled = "!email.mailboxNameEnabled" >
< div class = "input-group-btn" >
< button type = "button" class = "btn btn-default dropdown-toggle" data-toggle = "dropdown" ng-disabled = "!email.mailboxNameEnabled" >
@{{ email.domain.domain }}
< / button >
< / div >
< / div >
< p class = "text-small" >
< br / >
This app is configured to send mail using < a ng-href = "/#/email/{{ app.domain }}" > {{app.domain}}'s Outbound Email< / a > settings.
< / p >
< / div >
< input class = "ng-hide" type = "submit" ng-disabled = "emailForm.$invalid || email.busy" / >
< / form >
< / fieldset >
< / div >
< / div >
< div class = "row" >
< div class = "col-md-6" >
< span class = "text-success text-bold" ng-show = "email.success" > Saved< / span >
< / div >
< div class = "col-md-6 text-right" >
< button class = "btn btn-outline btn-primary pull-right" ng-click = "email.submit()" ng-disabled = "email.$invalid || email.busy" > < i class = "fa fa-circle-notch fa-spin" ng-show = "email.busy" > < / i > Save< / button >
< / div >
< / div >
< / div >
2019-09-12 15:59:40 +02:00
< div id = "security" > < h3 > Security< / h3 > < / div >
2019-09-10 19:21:30 +02:00
< div class = "card" >
< 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%" > Specify robots.txt file content < 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 = disableIndexingTemplate" > 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 >
2019-09-13 11:12:11 +02:00
< input class = "ng-hide" type = "submit" ng-disabled = "security.robotsTxt === security.currentRobotsTxt || securityForm.$invalid || security.busy" / >
2019-09-10 19:21:30 +02:00
< / form >
< / fieldset >
< / div >
< / div >
< div class = "row" >
2019-09-13 11:12:11 +02:00
< div class = "col-md-12 text-right" >
< button class = "btn btn-outline btn-primary pull-right" ng-click = "security.submit()" ng-disabled = "security.robotsTxt === security.currentRobotsTxt || security.$invalid || security.busy" > < i class = "fa fa-circle-notch fa-spin" ng-show = "security.busy" > < / i > Save< / button >
2019-09-10 19:21:30 +02:00
< / div >
< / div >
< / div >
2019-09-12 15:59:40 +02:00
< div id = "updates" > < h3 > Updates< / h3 > < / div >
2019-09-10 19:21:30 +02:00
< div class = "card" >
< div class = "row" >
< div class = "col-md-6" >
2019-09-13 17:07:45 +02:00
< input type = "checkbox" id = "updatesEnableAutomaticUpdate" ng-model = "updates.enableAutomaticUpdate" >
< label class = "control-label" for = "updatesEnableAutomaticUpdate" > Enable automatic updates< / label >
2019-09-10 19:21:30 +02:00
< / div >
< div class = "col-md-6 text-right" >
2019-09-13 17:07:45 +02:00
< button class = "btn btn-outline btn-primary pull-right" ng-click = "updates.submit()" ng-disabled = "updates.enableAutomaticUpdate === updates.currentEnableAutomaticUpdate || updates.busy" > < i class = "fa fa-circle-notch fa-spin" ng-show = "updates.busy" > < / i > Save< / button >
2019-09-10 19:21:30 +02:00
< / div >
< / div >
< / div >
2019-09-12 15:59:40 +02:00
< div id = "backups" > < h3 > Backups< / h3 > < / div >
2019-09-10 19:21:30 +02:00
< div class = "card" >
< div class = "row" >
< div class = "col-md-12" >
2019-09-13 17:07:45 +02:00
<!-- 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" > < / 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 > {{ backup.creationTime | prettyDate }}< / td >
< td > v{{ backup.version }}< / td >
< td class = "text-right no-wrap" style = "vertical-align: bottom" >
< button class = "btn btn-xs btn-default" ng-hide = "backup.ackRestore" 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-hide = "backup.ackRestore" ng-disabled = "app.taskId" ng-click = "backup.ackRestore = true" uib-tooltip = "Restore to this Backup" > < i class = "fas fa-history" > < / i > < / button >
< button class = "btn btn-xs btn-danger" ng-show = "backup.ackRestore" ng-click = "backups.restore(backup)" > Yes restore now< / button >
< button class = "btn btn-xs btn-default" ng-show = "backup.ackRestore" ng-click = "backup.ackRestore = false" > Back< / button >
< / td >
< / tr >
< / tbody >
< / table >
< br / >
2019-09-10 19:21:30 +02:00
< / div >
< / div >
< div class = "row" >
< div class = "col-md-6" >
2019-09-13 17:07:45 +02:00
< div ng-show = "app.installationState === 'pending_backup'" >
< div class = "progress progress-striped active animateMe" style = "margin-bottom: 10px;" >
< div class = "progress-bar progress-bar-success" role = "progressbar" style = "width: {{ app.progress }}%" > < / div >
< / div >
< div > < center > {{ app.message }}< / center > < / div >
< / div >
< / div >
< div class = "col-md-6 text-right" >
< button type = "button" class = "btn btn-primary pull-right" ng-click = "backups.createBackup()" ng-disabled = "app.taskId" > < i class = "fa fa-circle-notch fa-spin" ng-show = "app.installationState === 'pending_backup'" > < / i > Create Backup< / button >
< / div >
< / div >
< hr / >
< div class = "row" >
< div class = "col-md-6" >
< input type = "checkbox" id = "backupsEnableBackup" ng-model = "backups.enableBackup" >
< label class = "control-label" for = "backupsEnableBackup" > Enable automatic daily backups< / label >
2019-09-10 19:21:30 +02:00
< / div >
< div class = "col-md-6 text-right" >
2019-09-13 17:07:45 +02:00
< button type = "button" class = "btn btn-primary" ng-click = "backups.submit()" ng-disabled = "backups.enableBackup === backups.currentEnableBackup || backups.busy" > < i class = "fa fa-circle-notch fa-spin" ng-show = "backups.busy" > < / i > Save< / button >
2019-09-10 19:21:30 +02:00
< / div >
< / div >
< / div >
2019-09-13 10:34:12 +02:00
< div id = "debug" > < h3 > Debug< / h3 > < / div >
< div class = "card" >
< div class = "row" >
< div class = "col-md-12" >
2019-09-13 17:07:45 +02:00
< button class = "btn btn-danger" ng-click = "debug.stopAppTask(app.taskId)" ng-disabled = "!app.taskId" > Cancel Current Task< / button >
< button class = "btn btn-danger" ng-click = "debug.restartApp()" ng-disabled = "app.taskId || appIsRestarting" > < i class = "fa fa-circle-notch fa-spin" ng-show = "appIsRestarting" > < / i > Restart App< / button >
2019-09-13 10:34:12 +02:00
< 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 >
< / div >
2019-09-10 19:21:30 +02:00
< / div >