Files
portainer/app/portainer/views/stacks/edit/stack.html
T

265 lines
12 KiB
HTML

<page-header title="'Stack details'" breadcrumbs="[{label:'Stacks', link:'docker.stacks'}, stackName]" reload="true"> </page-header>
<div class="row">
<div class="col-sm-12">
<rd-widget>
<rd-widget-body>
<uib-tabset active="state.activeTab">
<!-- tab-info -->
<uib-tab index="0">
<uib-tab-heading>
<pr-icon icon="'list'"></pr-icon>
Stack
</uib-tab-heading>
<div style="margin-top: 10px">
<!-- stack-information -->
<div ng-if="external || orphaned">
<div class="col-sm-12 form-section-title"> Information </div>
<div class="form-group">
<span class="small">
<p class="text-muted">
<pr-icon icon="'alert-triangle'" mode="'warning'" class-name="'mr-0.5'"></pr-icon>
<span ng-if="external">This stack was created outside of Portainer. Control over this stack is limited.</span>
<span ng-if="orphaned">This stack is orphaned. You can re-associate it with the current environment using the "Associate to this environment" feature.</span>
</p>
</span>
</div>
</div>
<!-- !stack-information -->
<!-- stack-details -->
<div>
<div class="col-sm-12 form-section-title"> Stack details </div>
<div class="form-group">
{{ stackName }}
<button
authorization="PortainerStackUpdate"
ng-if="regular && stack.Status === 2"
ng-disabled="state.actionInProgress"
class="btn btn-xs btn-success"
ng-click="startStack()"
>
<pr-icon icon="'play'"></pr-icon>
Start this stack
</button>
<button
ng-if="regular && stack.Status === 1"
authorization="PortainerStackUpdate"
ng-disabled="state.actionInProgress"
class="btn btn-xs btn-light"
ng-click="stopStack()"
>
<pr-icon icon="'stop-circle'"></pr-icon>
Stop this stack
</button>
<button authorization="PortainerStackDelete" class="btn btn-xs btn-light" ng-click="removeStack()" ng-if="!external || stack.Type == 1">
<pr-icon icon="'trash-2'"></pr-icon>
Delete this stack
</button>
<button
ng-if="regular && stackFileContent"
class="btn btn-primary btn-xs"
ui-sref="docker.templates.custom.new({fileContent: stackFileContent, type: stack.Type})"
>
<pr-icon icon="'plus'"></pr-icon>
Create template from stack
</button>
<button
authorization="PortainerStackUpdate"
ng-if="regular && stackFileContent && !stack.FromAppTemplate && stack.GitConfig"
ng-disabled="state.actionInProgress"
ng-click="detachStackFromGit()"
button-spinner="state.actionInProgress"
class="btn btn-primary btn-xs"
>
<pr-icon icon="'arrow-right'" class-name="'mr-1'"></pr-icon>
<span ng-hide="state.actionInProgress">Detach from Git</span>
<span ng-show="state.actionInProgress">Detachment in progress...</span>
</button>
</div>
</div>
<!-- !stack-details -->
<!-- associate -->
<div ng-if="orphaned">
<div class="col-sm-12 form-section-title"> Associate to this environment </div>
<p class="small text-muted"> This feature allows you to re-associate this stack to the current environment. </p>
<form class="form-horizontal">
<por-access-control-form form-data="formValues.AccessControlData" hide-title="true"></por-access-control-form>
<div class="form-group">
<div class="col-sm-12">
<button
type="button"
class="btn btn-primary btn-sm"
ng-disabled="state.actionInProgress"
ng-click="associateStack()"
button-spinner="state.actionInProgress"
style="margin-left: -5px"
>
<pr-icon icon="'refresh-cw'" class="!mr-1"></pr-icon>
<span ng-hide="state.actionInProgress">Associate</span>
<span ng-show="state.actionInProgress">Association in progress...</span>
</button>
<span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px">{{ state.formValidationError }}</span>
</div>
</div>
</form>
</div>
<!-- !associate -->
<div ng-if="!orphaned">
<stack-redeploy-git-form
ng-if="stack.GitConfig && !stack.FromAppTemplate && !state.actionInProgress"
model="stack.GitConfig"
stack="stack"
authorization="PortainerStackUpdate"
endpoint="applicationState.endpoint"
>
</stack-redeploy-git-form>
<stack-duplication-form
ng-if="regular && endpoints.length > 0"
endpoints="endpoints"
groups="groups"
current-endpoint-id="endpoint.Id"
on-duplicate="duplicateStack(name, endpointId)"
on-migrate="migrateStack(name, endpointId)"
yaml-error="state.yamlError"
>
</stack-duplication-form>
</div>
</div>
</uib-tab>
<!-- !tab-info -->
<!-- tab-file -->
<uib-tab index="1" select="showEditor()" ng-if="!external && (!stack.GitConfig || stack.FromAppTemplate)">
<uib-tab-heading>
<pr-icon icon="'edit-2'" class-name="'mr-1'"></pr-icon>
Editor
</uib-tab-heading>
<form class="form-horizontal" ng-if="state.showEditorTab" style="margin-top: 10px" name="stackUpdateForm">
<div class="form-group">
<span class="col-sm-12 text-muted small" style="margin-bottom: 7px" ng-if="stackType == STACK_TYPES.DockerCompose && composeSyntaxMaxVersion == 2">
This stack will be deployed using the equivalent of <code>docker compose</code>. Only Compose file format version <b>2</b> is supported at the moment.
</span>
<span class="col-sm-12 text-muted small" style="margin-bottom: 7px" ng-if="stackType == STACK_TYPES.DockerCompose && composeSyntaxMaxVersion > 2">
This stack will be deployed using <code>docker compose</code>.
</span>
<span class="col-sm-12 text-muted small">
You can get more information about Compose file format in the <a href="https://docs.docker.com/compose/compose-file/" target="_blank">official documentation</a>.
</span>
<!-- opacity-0 with &nbsp; fixes the layout shift causing tooltips to go over hovered text -->
<div class="col-sm-12" ng-class="{ 'opacity-100': state.yamlError, 'opacity-0': !state.yamlError }">
<span class="text-danger small">{{ state.yamlError || '&nbsp;' }}</span>
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<code-editor
read-only="orphaned"
identifier="stack-editor"
placeholder="Define or paste the content of your docker compose file here"
yml="true"
on-change="(editorUpdate)"
value="stackFileContent"
schema="dockerComposeSchema"
></code-editor>
</div>
</div>
<!-- environment-variables -->
<div ng-if="stack">
<stack-environment-variables-panel
values="formValues.Env"
on-change="(handleEnvVarChange)"
show-help-message="true"
is-foldable="true"
></stack-environment-variables-panel>
</div>
<!-- !environment-variables -->
<!-- webhook -->
<div ng-if="isAdmin && applicationState.endpoint.type !== 4">
<div class="form-section-title"> Webhooks</div>
<por-switch-field
name="EnableWebhook"
checked="formValues.EnableWebhook"
label-class="'col-sm-2'"
tooltip="'Create a webhook (or callback URI) to automate the update of this stack. Sending a POST request to this callback URI (without requiring any authentication) will pull the most up-to-date version of the associated image and re-deploy this stack.'"
label="'Create a Stack webhook'"
feature-id="'stack-webhook'"
></por-switch-field>
</div>
<!-- !webhook -->
<!-- options -->
<div ng-if="stack.Type === 1 && applicationState.endpoint.apiVersion >= 1.27" authorization="PortainerStackUpdate">
<div class="col-sm-12 form-section-title"> Options </div>
<div class="form-group">
<div class="col-sm-12">
<por-switch-field
name="prune"
checked="formValues.Prune"
tooltip="'Prune services that are no longer referenced.'"
label-class="'col-sm-2'"
label="'Prune services'"
on-change="(onPruneChange)"
></por-switch-field>
</div>
</div>
</div>
<!-- !options -->
<div authorization="PortainerStackUpdate">
<div class="col-sm-12 form-section-title"> Actions </div>
<div class="form-group">
<div class="col-sm-12">
<button
type="button"
class="btn btn-sm btn-primary"
ng-disabled="state.actionInProgress || state.yamlError || !stackUpdateForm.$valid || !stackFileContent || orphaned"
ng-click="deployStack()"
button-spinner="state.actionInProgress"
>
<span ng-hide="state.actionInProgress">Update the stack</span>
<span ng-show="state.actionInProgress">Deployment in progress...</span>
</button>
</div>
</div>
</div>
</form>
</uib-tab>
<!-- !tab-file -->
</uib-tabset>
</rd-widget-body>
</rd-widget>
</div>
</div>
<stack-containers-datatable
ng-if="stackType !== STACK_TYPES.DockerSwarm && (!orphaned || orphanedRunning)"
stack-name="stackName"
environment="endpoint"
></stack-containers-datatable>
<docker-services-datatable
ng-if="services && (!orphaned || orphanedRunning)"
dataset="services"
title-icon="list"
on-refresh="(getServices)"
table-key="'stack-services'"
></docker-services-datatable>
<!-- access-control-panel -->
<access-control-panel
ng-if="stack && !orphaned"
resource-id="stack.EndpointId + '_' + stack.Name"
resource-control="stack.ResourceControl"
resource-type="resourceType"
environment-id="stack.EndpointId"
on-update-success="(onUpdateResourceControlSuccess)"
>
</access-control-panel>
<!-- !access-control-panel -->