265 lines
12 KiB
HTML
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 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 || ' ' }}</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 -->
|