1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-05 05:45:22 +02:00

chore(project): add prettier for code format (#3645)

* chore(project): install prettier and lint-staged

* chore(project): apply prettier to html too

* chore(project): git ignore eslintcache

* chore(project): add a comment about format script

* chore(prettier): update printWidth

* chore(prettier): remove useTabs option

* chore(prettier): add HTML validation

* refactor(prettier): fix closing tags

* feat(prettier): define angular parser for html templates

* style(prettier): run prettier on codebase

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
This commit is contained in:
Chaim Lev-Ari 2020-04-11 00:54:53 +03:00 committed by GitHub
parent 6663073be1
commit cf5056d9c0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
714 changed files with 31228 additions and 28305 deletions

View file

@ -1,277 +1,326 @@
<rd-header>
<rd-header-title title-text="Container details">
</rd-header-title>
<rd-header-title title-text="Container details"> </rd-header-title>
<rd-header-content>
<a ui-sref="docker.containers">Containers</a> &gt; <a ui-sref="docker.containers.container({id: container.Id})">{{ container.Name|trimcontainername }}</a>
<a ui-sref="docker.containers">Containers</a> &gt; <a ui-sref="docker.containers.container({id: container.Id})">{{ container.Name | trimcontainername }}</a>
</rd-header-content>
</rd-header>
<div class="row" authorization="DockerContainerStart, DockerContainerStop, DockerContainerKill, DockerContainerRestart, DockerContainerPause, DockerContainerUnpause, DockerContainerDelete, DockerContainerCreate">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-cogs" title-text="Actions"></rd-widget-header>
<rd-widget-body classes="padding">
<div class="btn-group" role="group" aria-label="...">
<button authorization="DockerContainerStart" class="btn btn-success btn-sm" ng-click="start()" ng-disabled="container.State.Running"><i class="fa fa-play space-right" aria-hidden="true"></i>Start</button>
<button authorization="DockerContainerStop" class="btn btn-danger btn-sm" ng-click="stop()" ng-disabled="!container.State.Running"><i class="fa fa-stop space-right" aria-hidden="true"></i>Stop</button>
<button authorization="DockerContainerKill" class="btn btn-danger btn-sm" ng-click="kill()" ng-disabled="!container.State.Running"><i class="fa fa-bomb space-right" aria-hidden="true"></i>Kill</button>
<button authorization="DockerContainerRestart" class="btn btn-primary btn-sm" ng-click="restart()" ng-disabled="!container.State.Running"><i class="fa fa-sync space-right" aria-hidden="true"></i>Restart</button>
<button authorization="DockerContainerPause" class="btn btn-primary btn-sm" ng-click="pause()" ng-disabled="!container.State.Running || container.State.Paused"><i class="fa fa-pause space-right" aria-hidden="true"></i>Pause</button>
<button authorization="DockerContainerUnpause" class="btn btn-primary btn-sm" ng-click="unpause()" ng-disabled="!container.State.Paused"><i class="fa fa-play space-right" aria-hidden="true"></i>Resume</button>
<button authorization="DockerContainerDelete" class="btn btn-danger btn-sm" ng-click="confirmRemove()"><i class="fa fa-trash-alt space-right" aria-hidden="true"></i>Remove</button>
<div
class="row"
authorization="DockerContainerStart, DockerContainerStop, DockerContainerKill, DockerContainerRestart, DockerContainerPause, DockerContainerUnpause, DockerContainerDelete, DockerContainerCreate"
>
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-cogs" title-text="Actions"></rd-widget-header>
<rd-widget-body classes="padding">
<div class="btn-group" role="group" aria-label="...">
<button authorization="DockerContainerStart" class="btn btn-success btn-sm" ng-click="start()" ng-disabled="container.State.Running"
><i class="fa fa-play space-right" aria-hidden="true"></i>Start</button
>
<button authorization="DockerContainerStop" class="btn btn-danger btn-sm" ng-click="stop()" ng-disabled="!container.State.Running"
><i class="fa fa-stop space-right" aria-hidden="true"></i>Stop</button
>
<button authorization="DockerContainerKill" class="btn btn-danger btn-sm" ng-click="kill()" ng-disabled="!container.State.Running"
><i class="fa fa-bomb space-right" aria-hidden="true"></i>Kill</button
>
<button authorization="DockerContainerRestart" class="btn btn-primary btn-sm" ng-click="restart()" ng-disabled="!container.State.Running"
><i class="fa fa-sync space-right" aria-hidden="true"></i>Restart</button
>
<button authorization="DockerContainerPause" class="btn btn-primary btn-sm" ng-click="pause()" ng-disabled="!container.State.Running || container.State.Paused"
><i class="fa fa-pause space-right" aria-hidden="true"></i>Pause</button
>
<button authorization="DockerContainerUnpause" class="btn btn-primary btn-sm" ng-click="unpause()" ng-disabled="!container.State.Paused"
><i class="fa fa-play space-right" aria-hidden="true"></i>Resume</button
>
<button authorization="DockerContainerDelete" class="btn btn-danger btn-sm" ng-click="confirmRemove()"
><i class="fa fa-trash-alt space-right" aria-hidden="true"></i>Remove</button
>
</div>
<div class="btn-group" role="group" aria-label="..." ng-if="displayRecreateButton" authorization="DockerContainerCreate">
<button
type="button"
class="btn btn-danger btn-sm"
ng-disabled="state.recreateContainerInProgress"
ng-click="recreate()"
button-spinner="state.recreateContainerInProgress"
>
<span ng-hide="state.recreateContainerInProgress"><i class="fa fa-sync space-right" aria-hidden="true"></i>Recreate</span>
<span ng-show="state.recreateContainerInProgress">Recreation in progress...</span>
</button>
<a class="btn btn-primary btn-sm" type="button" ui-sref="docker.containers.new({ from: container.Id, nodeName: nodeName })"
><i class="fa fa-copy space-right" aria-hidden="true"></i>Duplicate/Edit</a
>
</div>
</rd-widget-body>
</rd-widget>
</div>
</div>
<div class="row">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-server" title-text="Container status"></rd-widget-header>
<rd-widget-body classes="no-padding">
<table class="table">
<tbody>
<tr>
<td>ID</td>
<td>{{ container.Id }}</td>
</tr>
<tr>
<td>Name</td>
<td ng-if="!container.edit">
{{ container.Name | trimcontainername }}
<a authorization="DockerContainerRename" href="" data-toggle="tooltip" title="Edit container name" ng-click="container.edit = true;"><i class="fa fa-edit"></i></a>
</td>
<td ng-if="container.edit">
<form ng-submit="renameContainer()">
<input type="text" class="containerNameInput" ng-model="container.newContainerName" />
<a href="" ng-click="container.edit = false;"><i class="fa fa-times"></i></a>
<a href="" ng-click="renameContainer()"><i class="fa fa-check-square"></i></a>
</form>
</td>
</tr>
<tr ng-if="container.NetworkSettings.IPAddress">
<td>IP address</td>
<td>{{ container.NetworkSettings.IPAddress }}</td>
</tr>
<tr>
<td>Status</td>
<td>
<i class="fa fa-heartbeat space-right green-icon" ng-if="container.State.Running"></i>
<i class="fa fa-heartbeat space-right red-icon" ng-if="!container.State.Running && container.State.Status !== 'created'"></i>
{{ container.State | getstatetext }} for {{ activityTime
}}<span ng-if="!container.State.Running && container.State.Status !== 'created'"> with exit code {{ container.State.ExitCode }}</span>
</td>
</tr>
<tr>
<td>Created</td>
<td>{{ container.Created | getisodate }}</td>
</tr>
<tr ng-if="container.State.Running">
<td>Start time</td>
<td>{{ container.State.StartedAt | getisodate }}</td>
</tr>
<tr ng-if="!container.State.Running && container.State.Status !== 'created'">
<td>Finished</td>
<td>{{ container.State.FinishedAt | getisodate }}</td>
</tr>
<tr authorization="DockerContainerLogs, DockerContainerInspect, DockerContainerStats, DockerExecStart">
<td colspan="2">
<div class="btn-group" role="group" aria-label="...">
<a authorization="DockerContainerLogs" class="btn" type="button" ui-sref="docker.containers.container.logs({ id: container.Id })"
><i class="fa fa-file-alt space-right" aria-hidden="true"></i>Logs</a
>
<a authorization="DockerContainerInspect" class="btn" type="button" ui-sref="docker.containers.container.inspect({ id: container.Id })"
><i class="fa fa-info-circle space-right" aria-hidden="true"></i>Inspect</a
>
<a authorization="DockerContainerStats" class="btn" type="button" ui-sref="docker.containers.container.stats({ id: container.Id })"
><i class="fa fa-chart-area space-right" aria-hidden="true"></i>Stats</a
>
<a authorization="DockerExecStart" class="btn" type="button" ui-sref="docker.containers.container.exec({ id: container.Id })"
><i class="fa fa-terminal space-right" aria-hidden="true"></i>Console</a
>
<a authorization="DockerContainerAttach" class="btn" type="button" ui-sref="docker.containers.container.attach({ id: container.Id })"
><i class="fa fa-plug space-right" aria-hidden="true"></i>Attach</a
>
</div>
</td>
</tr>
</tbody>
</table>
</rd-widget-body>
</rd-widget>
</div>
</div>
<!-- access-control-panel -->
<por-access-control-panel
ng-if="container && applicationState.application.authentication"
resource-id="container.Id"
resource-control="container.ResourceControl"
resource-type="'container'"
>
</por-access-control-panel>
<!-- !access-control-panel -->
<div ng-if="container.State.Health" class="row">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-server" title-text="Container health"></rd-widget-header>
<rd-widget-body classes="no-padding">
<table class="table">
<tbody>
<tr>
<td>Status</td>
<td>
<i
ng-class="
{ healthy: 'fa fa-heartbeat space-right green-icon', unhealthy: 'fa fa-heartbeat space-right red-icon', starting: 'fa fa-heartbeat space-right orange-icon' }[
container.State.Health.Status
]
"
></i>
{{ container.State.Health.Status }}
</td>
</tr>
<tr>
<td>Failure count</td>
<td>{{ container.State.Health.FailingStreak }}</td>
</tr>
<tr>
<td>Last output</td>
<td>{{ container.State.Health.Log[container.State.Health.Log.length - 1].Output }}</td>
</tr>
</tbody>
</table>
</rd-widget-body>
</rd-widget>
</div>
</div>
<div class="row" authorization="DockerImageCreate">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-clone" title-text="Create image"></rd-widget-header>
<rd-widget-body>
<form class="form-horizontal">
<!-- tag-description -->
<div class="form-group">
<div class="col-sm-12">
<span class="small text-muted">
You can create an image from this container, this allows you to backup important data or save helpful configurations. You'll be able to spin up another container
based on this image afterward.
</span>
</div>
</div>
<div class="btn-group" role="group" aria-label="..." ng-if="displayRecreateButton" authorization="DockerContainerCreate">
<button type="button" class="btn btn-danger btn-sm" ng-disabled="state.recreateContainerInProgress" ng-click="recreate()" button-spinner="state.recreateContainerInProgress">
<span ng-hide="state.recreateContainerInProgress"><i class="fa fa-sync space-right" aria-hidden="true"></i>Recreate</span>
<span ng-show="state.recreateContainerInProgress">Recreation in progress...</span>
</button>
<a class="btn btn-primary btn-sm" type="button" ui-sref="docker.containers.new({ from: container.Id, nodeName: nodeName })"><i class="fa fa-copy space-right" aria-hidden="true"></i>Duplicate/Edit</a>
<!-- !tag-description -->
<!-- image-and-registry -->
<por-image-registry model="config.RegistryModel" auto-complete="true" label-class="col-sm-1" input-class="col-sm-11"></por-image-registry>
<!-- !image-and-registry -->
<!-- tag-note -->
<div class="form-group">
<div class="col-sm-12">
<span class="small text-muted">Note: if you don't specify the tag in the image name, <span class="label label-default">latest</span> will be used.</span>
</div>
</div>
</rd-widget-body>
</rd-widget>
</div>
</div>
<div class="row">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-server" title-text="Container status"></rd-widget-header>
<rd-widget-body classes="no-padding">
<table class="table">
<tbody>
<tr>
<td>ID</td>
<td>{{ container.Id }}</td>
</tr>
<tr>
<td>Name</td>
<td ng-if="!container.edit">
{{ container.Name|trimcontainername }}
<a authorization="DockerContainerRename" href="" data-toggle="tooltip" title="Edit container name" ng-click="container.edit = true;"><i class="fa fa-edit"></i></a>
</td>
<td ng-if="container.edit">
<form ng-submit="renameContainer()">
<input type="text" class="containerNameInput" ng-model="container.newContainerName">
<a href="" ng-click="container.edit = false;"><i class="fa fa-times"></i></a>
<a href="" ng-click="renameContainer()"><i class="fa fa-check-square"></i></a>
</form>
</td>
</tr>
<tr ng-if="container.NetworkSettings.IPAddress">
<td>IP address</td>
<td>{{ container.NetworkSettings.IPAddress }}</td>
</tr>
<tr>
<td>Status</td>
<td>
<i class="fa fa-heartbeat space-right green-icon" ng-if="container.State.Running"></i>
<i class="fa fa-heartbeat space-right red-icon" ng-if="!container.State.Running && container.State.Status !== 'created'"></i>
{{ container.State|getstatetext }} for {{ activityTime }}<span ng-if="!container.State.Running && container.State.Status !== 'created'"> with exit code {{ container.State.ExitCode }}</span>
</td>
</tr>
<tr>
<td>Created</td>
<td>{{ container.Created|getisodate }}</td>
</tr>
<tr ng-if="container.State.Running">
<td>Start time</td>
<td>{{ container.State.StartedAt|getisodate }}</td>
</tr>
<tr ng-if="!container.State.Running && container.State.Status !== 'created'">
<td>Finished</td>
<td>{{ container.State.FinishedAt|getisodate }}</td>
</tr>
<tr authorization="DockerContainerLogs, DockerContainerInspect, DockerContainerStats, DockerExecStart">
<td colspan="2">
<div class="btn-group" role="group" aria-label="...">
<a authorization="DockerContainerLogs" class="btn" type="button" ui-sref="docker.containers.container.logs({ id: container.Id })"><i class="fa fa-file-alt space-right" aria-hidden="true"></i>Logs</a>
<a authorization="DockerContainerInspect" class="btn" type="button" ui-sref="docker.containers.container.inspect({ id: container.Id })"><i class="fa fa-info-circle space-right" aria-hidden="true"></i>Inspect</a>
<a authorization="DockerContainerStats" class="btn" type="button" ui-sref="docker.containers.container.stats({ id: container.Id })"><i class="fa fa-chart-area space-right" aria-hidden="true"></i>Stats</a>
<a authorization="DockerExecStart" class="btn" type="button" ui-sref="docker.containers.container.exec({ id: container.Id })"><i class="fa fa-terminal space-right" aria-hidden="true"></i>Console</a>
<a authorization="DockerContainerAttach" class="btn" type="button" ui-sref="docker.containers.container.attach({ id: container.Id })"><i class="fa fa-plug space-right" aria-hidden="true"></i>Attach</a>
</div>
</td>
</tr>
</tbody>
</table>
</rd-widget-body>
</rd-widget>
</div>
</div>
<!-- access-control-panel -->
<por-access-control-panel
ng-if="container && applicationState.application.authentication"
resource-id="container.Id"
resource-control="container.ResourceControl"
resource-type="'container'">
</por-access-control-panel>
<!-- !access-control-panel -->
<div ng-if="container.State.Health" class="row">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-server" title-text="Container health"></rd-widget-header>
<rd-widget-body classes="no-padding">
<table class="table">
<tbody>
<tr>
<td>Status</td>
<td>
<i ng-class="{'healthy': 'fa fa-heartbeat space-right green-icon', 'unhealthy': 'fa fa-heartbeat space-right red-icon', 'starting': 'fa fa-heartbeat space-right orange-icon'}[container.State.Health.Status]"></i>
{{ container.State.Health.Status }}
</td>
</tr>
<tr>
<td>Failure count</td>
<td>{{ container.State.Health.FailingStreak }}</td>
</tr>
<tr>
<td>Last output</td>
<td>{{ container.State.Health.Log[container.State.Health.Log.length - 1].Output }}</td>
</tr>
</tbody>
</table>
</rd-widget-body>
</rd-widget>
</div>
</div>
<div class="row" authorization="DockerImageCreate">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-clone" title-text="Create image"></rd-widget-header>
<rd-widget-body>
<form class="form-horizontal">
<!-- tag-description -->
<div class="form-group">
<div class="col-sm-12">
<span class="small text-muted">
You can create an image from this container, this allows you to backup important data or save
helpful configurations. You'll be able to spin up another container based on this image afterward.
</span>
</div>
<!-- !tag-note -->
<div class="form-group">
<div class="col-sm-12">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!config.RegistryModel.Image || config.commitInProgress" ng-click="commit()">Create</button>
</div>
<!-- !tag-description -->
<!-- image-and-registry -->
<por-image-registry
model="config.RegistryModel"
auto-complete="true"
label-class="col-sm-1" input-class="col-sm-11"
></por-image-registry>
<!-- !image-and-registry -->
<!-- tag-note -->
<div class="form-group">
<div class="col-sm-12">
<span class="small text-muted">Note: if you don't specify the tag in the image name, <span class="label label-default">latest</span> will be used.</span>
</div>
</div>
<!-- !tag-note -->
<div class="form-group">
<div class="col-sm-12">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!config.RegistryModel.Image || config.commitInProgress" ng-click="commit()">Create</button>
</div>
</div>
</form>
</rd-widget-body>
</rd-widget>
</div>
</div>
</form>
</rd-widget-body>
</rd-widget>
</div>
<div class="row">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-server" title-text="Container details"></rd-widget-header>
<rd-widget-body classes="no-padding">
<table class="table">
<tbody>
<tr>
<td>Image</td>
<td><a ui-sref="docker.images.image({ id: container.Image, nodeName: nodeName })">{{ container.Config.Image}}@{{container.Image}}</a></td>
</tr>
<tr ng-if="portBindings.length > 0">
<td>Port configuration</td>
<td>
<div ng-repeat="portMapping in portBindings">
{{ portMapping.host }} <i class="fa fa-long-arrow-alt-right"></i> {{ portMapping.container }}
</div>
</td>
</tr>
<tr>
<td>CMD</td>
<td><code>{{ container.Config.Cmd|command }}</code></td>
</tr>
<tr>
<td>ENTRYPOINT</td>
<td><code>{{ container.Config.Entrypoint ? (container.Config.Entrypoint|command) : "null" }}</code></td>
</tr>
<tr>
<td>ENV</td>
<td>
<table class="table table-bordered table-condensed">
<tr ng-repeat="var in container.Config.Env track by $index">
<td>{{ var|key: '=' }}</td>
<td>{{ var|value: '=' }}</td>
</tr>
</table>
</td>
</tr>
<tr ng-if="!(container.Config.Labels | emptyobject)">
<td>Labels</td>
<td>
<table class="table table-bordered table-condensed">
<tr ng-repeat="(k, v) in container.Config.Labels">
<td>{{ k }}</td>
<td>{{ v }}</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>Restart policies</td>
<td>
<container-restart-policy ng-if="container"
name="container.HostConfig.RestartPolicy.Name"
maximum-retry-count="container.HostConfig.RestartPolicy.MaximumRetryCount"
update-restart-policy="updateRestartPolicy(name, maximumRetryCount)">
</td>
</tr>
</tbody>
</table>
</rd-widget-body>
</rd-widget>
</div>
</div>
<div class="row">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-server" title-text="Container details"></rd-widget-header>
<rd-widget-body classes="no-padding">
<table class="table">
<tbody>
<tr>
<td>Image</td>
<td
><a ui-sref="docker.images.image({ id: container.Image, nodeName: nodeName })">{{ container.Config.Image }}@{{ container.Image }}</a></td
>
</tr>
<tr ng-if="portBindings.length > 0">
<td>Port configuration</td>
<td>
<div ng-repeat="portMapping in portBindings"> {{ portMapping.host }} <i class="fa fa-long-arrow-alt-right"></i> {{ portMapping.container }} </div>
</td>
</tr>
<tr>
<td>CMD</td>
<td
><code>{{ container.Config.Cmd | command }}</code></td
>
</tr>
<tr>
<td>ENTRYPOINT</td>
<td
><code>{{ container.Config.Entrypoint ? (container.Config.Entrypoint | command) : 'null' }}</code></td
>
</tr>
<tr>
<td>ENV</td>
<td>
<table class="table table-bordered table-condensed">
<tr ng-repeat="var in container.Config.Env track by $index">
<td>{{ var|key: '=' }}</td>
<td>{{ var|value: '=' }}</td>
</tr>
</table>
</td>
</tr>
<tr ng-if="!(container.Config.Labels | emptyobject)">
<td>Labels</td>
<td>
<table class="table table-bordered table-condensed">
<tr ng-repeat="(k, v) in container.Config.Labels">
<td>{{ k }}</td>
<td>{{ v }}</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>Restart policies</td>
<td>
<container-restart-policy
ng-if="container"
name="container.HostConfig.RestartPolicy.Name"
maximum-retry-count="container.HostConfig.RestartPolicy.MaximumRetryCount"
update-restart-policy="updateRestartPolicy(name, maximumRetryCount)"
>
</container-restart-policy>
</td>
</tr>
</tbody>
</table>
</rd-widget-body>
</rd-widget>
</div>
</div>
<div class="row" ng-if="container.Mounts.length > 0">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-cubes" title-text="Volumes"></rd-widget-header>
<rd-widget-body classes="no-padding">
<table class="table">
<thead>
<tr>
<th>Host/volume</th>
<th>Path in container</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="vol in container.Mounts">
<td ng-if="vol.Type === 'bind'">{{ vol.Source }}</td>
<td ng-if="vol.Type === 'volume'"><a ui-sref="docker.volumes.volume({ id: vol.Name, nodeName: nodeName })">{{ vol.Name }}</a></td>
<td>{{ vol.Destination }}</td>
</tr>
</tbody>
</table>
</rd-widget-body>
</rd-widget>
</div>
<div class="row" ng-if="container.Mounts.length > 0">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-cubes" title-text="Volumes"></rd-widget-header>
<rd-widget-body classes="no-padding">
<table class="table">
<thead>
<tr>
<th>Host/volume</th>
<th>Path in container</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="vol in container.Mounts">
<td ng-if="vol.Type === 'bind'">{{ vol.Source }}</td>
<td ng-if="vol.Type === 'volume'"
><a ui-sref="docker.volumes.volume({ id: vol.Name, nodeName: nodeName })">{{ vol.Name }}</a></td
>
<td>{{ vol.Destination }}</td>
</tr>
</tbody>
</table>
</rd-widget-body>
</rd-widget>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<container-networks-datatable
title-text="Connected networks" title-icon="fa-sitemap"
dataset="container.NetworkSettings.Networks" table-key="container-networks"
<div class="row">
<div class="col-sm-12">
<container-networks-datatable
title-text="Connected networks"
title-icon="fa-sitemap"
dataset="container.NetworkSettings.Networks"
table-key="container-networks"
container="container"
available-networks="availableNetworks"
join-network-action="containerJoinNetwork"
@ -279,6 +328,6 @@
leave-network-action="containerLeaveNetwork"
leave-network-action-in-progress="state.leaveNetworkInProgress"
node-name="nodeName"
></container-networks-datatable>
</div>
></container-networks-datatable>
</div>
</div>

View file

@ -1,356 +1,383 @@
import moment from 'moment';
import { PorImageRegistryModel } from 'Docker/models/porImageRegistry';
angular.module('portainer.docker')
.controller('ContainerController', ['$q', '$scope', '$state','$transition$', '$filter', '$async', 'ExtensionService', 'Commit', 'ContainerHelper', 'ContainerService', 'ImageHelper', 'NetworkService', 'Notifications', 'ModalService', 'ResourceControlService', 'RegistryService', 'ImageService', 'HttpRequestHelper', 'Authentication',
function ($q, $scope, $state, $transition$, $filter, $async, ExtensionService, Commit, ContainerHelper, ContainerService, ImageHelper, NetworkService, Notifications, ModalService, ResourceControlService, RegistryService, ImageService, HttpRequestHelper, Authentication) {
$scope.activityTime = 0;
$scope.portBindings = [];
$scope.displayRecreateButton = false;
angular.module('portainer.docker').controller('ContainerController', [
'$q',
'$scope',
'$state',
'$transition$',
'$filter',
'$async',
'ExtensionService',
'Commit',
'ContainerHelper',
'ContainerService',
'ImageHelper',
'NetworkService',
'Notifications',
'ModalService',
'ResourceControlService',
'RegistryService',
'ImageService',
'HttpRequestHelper',
'Authentication',
function (
$q,
$scope,
$state,
$transition$,
$filter,
$async,
ExtensionService,
Commit,
ContainerHelper,
ContainerService,
ImageHelper,
NetworkService,
Notifications,
ModalService,
ResourceControlService,
RegistryService,
ImageService,
HttpRequestHelper,
Authentication
) {
$scope.activityTime = 0;
$scope.portBindings = [];
$scope.displayRecreateButton = false;
$scope.config = {
RegistryModel: new PorImageRegistryModel(),
commitInProgress: false
};
$scope.config = {
RegistryModel: new PorImageRegistryModel(),
commitInProgress: false,
};
$scope.state = {
recreateContainerInProgress: false,
joinNetworkInProgress: false,
leaveNetworkInProgress: false
};
$scope.state = {
recreateContainerInProgress: false,
joinNetworkInProgress: false,
leaveNetworkInProgress: false,
};
$scope.updateRestartPolicy = updateRestartPolicy;
$scope.updateRestartPolicy = updateRestartPolicy;
var update = function () {
var nodeName = $transition$.params().nodeName;
HttpRequestHelper.setPortainerAgentTargetHeader(nodeName);
$scope.nodeName = nodeName;
var update = function () {
var nodeName = $transition$.params().nodeName;
HttpRequestHelper.setPortainerAgentTargetHeader(nodeName);
$scope.nodeName = nodeName;
ContainerService.container($transition$.params().id)
.then(function success(data) {
var container = data;
$scope.container = container;
$scope.container.edit = false;
$scope.container.newContainerName = $filter('trimcontainername')(container.Name);
ContainerService.container($transition$.params().id)
.then(function success(data) {
var container = data;
$scope.container = container;
$scope.container.edit = false;
$scope.container.newContainerName = $filter('trimcontainername')(container.Name);
if (container.State.Running) {
$scope.activityTime = moment.duration(moment(container.State.StartedAt).utc().diff(moment().utc())).humanize();
} else if (container.State.Status === 'created') {
$scope.activityTime = moment.duration(moment(container.Created).utc().diff(moment().utc())).humanize();
} else {
$scope.activityTime = moment.duration(moment().utc().diff(moment(container.State.FinishedAt).utc())).humanize();
}
$scope.portBindings = [];
if (container.NetworkSettings.Ports) {
angular.forEach(Object.keys(container.NetworkSettings.Ports), function(portMapping) {
if (container.NetworkSettings.Ports[portMapping]) {
var mapping = {};
mapping.container = portMapping;
mapping.host = container.NetworkSettings.Ports[portMapping][0].HostIp + ':' + container.NetworkSettings.Ports[portMapping][0].HostPort;
$scope.portBindings.push(mapping);
if (container.State.Running) {
$scope.activityTime = moment.duration(moment(container.State.StartedAt).utc().diff(moment().utc())).humanize();
} else if (container.State.Status === 'created') {
$scope.activityTime = moment.duration(moment(container.Created).utc().diff(moment().utc())).humanize();
} else {
$scope.activityTime = moment.duration(moment().utc().diff(moment(container.State.FinishedAt).utc())).humanize();
}
$scope.portBindings = [];
if (container.NetworkSettings.Ports) {
angular.forEach(Object.keys(container.NetworkSettings.Ports), function (portMapping) {
if (container.NetworkSettings.Ports[portMapping]) {
var mapping = {};
mapping.container = portMapping;
mapping.host = container.NetworkSettings.Ports[portMapping][0].HostIp + ':' + container.NetworkSettings.Ports[portMapping][0].HostPort;
$scope.portBindings.push(mapping);
}
});
}
const inSwarm = $scope.container.Config.Labels['com.docker.swarm.service.id'];
const autoRemove = $scope.container.HostConfig.AutoRemove;
const admin = Authentication.isAdmin();
ExtensionService.extensionEnabled(ExtensionService.EXTENSIONS.RBAC).then((rbacEnabled) => {
$scope.displayRecreateButton = !inSwarm && !autoRemove && (rbacEnabled ? admin : true);
});
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve container info');
});
};
function executeContainerAction(id, action, successMessage, errorMessage) {
action(id)
.then(function success() {
Notifications.success(successMessage, id);
update();
})
.catch(function error(err) {
Notifications.error('Failure', err, errorMessage);
});
}
$scope.start = function () {
var successMessage = 'Container successfully started';
var errorMessage = 'Unable to start container';
executeContainerAction($transition$.params().id, ContainerService.startContainer, successMessage, errorMessage);
};
$scope.stop = function () {
var successMessage = 'Container successfully stopped';
var errorMessage = 'Unable to stop container';
executeContainerAction($transition$.params().id, ContainerService.stopContainer, successMessage, errorMessage);
};
$scope.kill = function () {
var successMessage = 'Container successfully killed';
var errorMessage = 'Unable to kill container';
executeContainerAction($transition$.params().id, ContainerService.killContainer, successMessage, errorMessage);
};
$scope.pause = function () {
var successMessage = 'Container successfully paused';
var errorMessage = 'Unable to pause container';
executeContainerAction($transition$.params().id, ContainerService.pauseContainer, successMessage, errorMessage);
};
$scope.unpause = function () {
var successMessage = 'Container successfully resumed';
var errorMessage = 'Unable to resume container';
executeContainerAction($transition$.params().id, ContainerService.resumeContainer, successMessage, errorMessage);
};
$scope.restart = function () {
var successMessage = 'Container successfully restarted';
var errorMessage = 'Unable to restart container';
executeContainerAction($transition$.params().id, ContainerService.restartContainer, successMessage, errorMessage);
};
$scope.renameContainer = function () {
var container = $scope.container;
ContainerService.renameContainer($transition$.params().id, container.newContainerName)
.then(function success() {
container.Name = container.newContainerName;
Notifications.success('Container successfully renamed', container.Name);
})
.catch(function error(err) {
container.newContainerName = container.Name;
Notifications.error('Failure', err, 'Unable to rename container');
})
.finally(function final() {
$scope.container.edit = false;
});
};
$scope.containerLeaveNetwork = function containerLeaveNetwork(container, networkId) {
$scope.state.leaveNetworkInProgress = true;
NetworkService.disconnectContainer(networkId, container.Id, false)
.then(function success() {
Notifications.success('Container left network', container.Id);
$state.reload();
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to disconnect container from network');
})
.finally(function final() {
$scope.state.leaveNetworkInProgress = false;
});
};
$scope.containerJoinNetwork = function containerJoinNetwork(container, networkId) {
$scope.state.joinNetworkInProgress = true;
NetworkService.connectContainer(networkId, container.Id)
.then(function success() {
Notifications.success('Container joined network', container.Id);
$state.reload();
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to connect container to network');
})
.finally(function final() {
$scope.state.joinNetworkInProgress = false;
});
};
async function commitContainerAsync() {
$scope.config.commitInProgress = true;
const registryModel = $scope.config.RegistryModel;
const imageConfig = ImageHelper.createImageConfigForContainer(registryModel);
try {
await Commit.commitContainer({ id: $transition$.params().id, repo: imageConfig.fromImage }).$promise;
Notifications.success('Image created', $transition$.params().id);
$state.reload();
} catch (err) {
Notifications.error('Failure', err, 'Unable to create image');
$scope.config.commitInProgress = false;
}
const inSwarm = $scope.container.Config.Labels['com.docker.swarm.service.id'];
const autoRemove = $scope.container.HostConfig.AutoRemove;
const admin = Authentication.isAdmin();
ExtensionService.extensionEnabled(ExtensionService.EXTENSIONS.RBAC).then((rbacEnabled) => {
$scope.displayRecreateButton = !inSwarm && !autoRemove && (rbacEnabled ? admin : true)
});
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve container info');
});
};
function executeContainerAction(id, action, successMessage, errorMessage) {
action(id)
.then(function success() {
Notifications.success(successMessage, id);
update();
})
.catch(function error(err) {
Notifications.error('Failure', err, errorMessage);
});
}
$scope.start = function () {
var successMessage = 'Container successfully started';
var errorMessage = 'Unable to start container';
executeContainerAction($transition$.params().id, ContainerService.startContainer, successMessage, errorMessage);
};
$scope.stop = function () {
var successMessage = 'Container successfully stopped';
var errorMessage = 'Unable to stop container';
executeContainerAction($transition$.params().id, ContainerService.stopContainer, successMessage, errorMessage);
};
$scope.kill = function () {
var successMessage = 'Container successfully killed';
var errorMessage = 'Unable to kill container';
executeContainerAction($transition$.params().id, ContainerService.killContainer, successMessage, errorMessage);
};
$scope.pause = function() {
var successMessage = 'Container successfully paused';
var errorMessage = 'Unable to pause container';
executeContainerAction($transition$.params().id, ContainerService.pauseContainer, successMessage, errorMessage);
};
$scope.unpause = function() {
var successMessage = 'Container successfully resumed';
var errorMessage = 'Unable to resume container';
executeContainerAction($transition$.params().id, ContainerService.resumeContainer, successMessage, errorMessage);
};
$scope.restart = function () {
var successMessage = 'Container successfully restarted';
var errorMessage = 'Unable to restart container';
executeContainerAction($transition$.params().id, ContainerService.restartContainer, successMessage, errorMessage);
};
$scope.renameContainer = function () {
var container = $scope.container;
ContainerService.renameContainer($transition$.params().id, container.newContainerName)
.then(function success() {
container.Name = container.newContainerName;
Notifications.success('Container successfully renamed', container.Name);
})
.catch(function error(err) {
container.newContainerName = container.Name;
Notifications.error('Failure', err, 'Unable to rename container');
})
.finally(function final() {
$scope.container.edit = false;
});
};
$scope.containerLeaveNetwork = function containerLeaveNetwork(container, networkId) {
$scope.state.leaveNetworkInProgress = true;
NetworkService.disconnectContainer(networkId, container.Id, false)
.then(function success() {
Notifications.success('Container left network', container.Id);
$state.reload();
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to disconnect container from network');
})
.finally(function final() {
$scope.state.leaveNetworkInProgress = false;
});
};
$scope.containerJoinNetwork = function containerJoinNetwork(container, networkId) {
$scope.state.joinNetworkInProgress = true;
NetworkService.connectContainer(networkId, container.Id)
.then(function success() {
Notifications.success('Container joined network', container.Id);
$state.reload();
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to connect container to network');
})
.finally(function final() {
$scope.state.joinNetworkInProgress = false;
});
};
async function commitContainerAsync() {
$scope.config.commitInProgress = true;
const registryModel = $scope.config.RegistryModel;
const imageConfig = ImageHelper.createImageConfigForContainer(registryModel);
try {
await Commit.commitContainer({id: $transition$.params().id, repo: imageConfig.fromImage}).$promise;
Notifications.success('Image created', $transition$.params().id);
$state.reload();
} catch (err) {
Notifications.error('Failure', err, 'Unable to create image');
$scope.config.commitInProgress = false;
}
}
$scope.commit = function () {
return $async(commitContainerAsync);
};
$scope.commit = function () {
return $async(commitContainerAsync);
};
$scope.confirmRemove = function () {
var title = 'You are about to remove a container.';
if ($scope.container.State.Running) {
title = 'You are about to remove a running container.';
}
ModalService.confirmContainerDeletion(
title,
function (result) {
if(!result) { return; }
$scope.confirmRemove = function () {
var title = 'You are about to remove a container.';
if ($scope.container.State.Running) {
title = 'You are about to remove a running container.';
}
ModalService.confirmContainerDeletion(title, function (result) {
if (!result) {
return;
}
var cleanAssociatedVolumes = false;
if (result[0]) {
cleanAssociatedVolumes = true;
}
removeContainer(cleanAssociatedVolumes);
}
);
};
function removeContainer(cleanAssociatedVolumes) {
ContainerService.remove($scope.container, cleanAssociatedVolumes)
.then(function success() {
Notifications.success('Container successfully removed');
$state.go('docker.containers', {}, {reload: true});
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to remove container');
});
}
function recreateContainer(pullImage) {
var container = $scope.container;
var config = ContainerHelper.configFromContainer(container.Model);
$scope.state.recreateContainerInProgress = true;
var isRunning = container.State.Running;
return pullImageIfNeeded()
.then(stopContainerIfNeeded)
.then(renameContainer)
.then(setMainNetworkAndCreateContainer)
.then(connectContainerToOtherNetworks)
.then(startContainerIfNeeded)
.then(createResourceControl)
.then(deleteOldContainer)
.then(notifyAndChangeView)
.catch(notifyOnError);
function stopContainerIfNeeded() {
if (!isRunning) {
return $q.when();
}
return ContainerService.stopContainer(container.Id);
}
function renameContainer() {
return ContainerService.renameContainer(container.Id, container.Name + '-old');
}
function pullImageIfNeeded() {
if (!pullImage) {
return $q.when();
}
return RegistryService.retrievePorRegistryModelFromRepository(container.Config.Image)
.then(function pullImage(registryModel) {
return ImageService.pullImage(registryModel, true);
});
}
};
function setMainNetworkAndCreateContainer() {
var networks = config.NetworkingConfig.EndpointsConfig;
var networksNames = Object.keys(networks);
if (networksNames.length > 1) {
config.NetworkingConfig.EndpointsConfig = {};
config.NetworkingConfig.EndpointsConfig[networksNames[0]] = networks[0];
}
return $q.all([ContainerService.createContainer(config), networks]);
}
function connectContainerToOtherNetworks(createContainerData) {
var newContainer = createContainerData[0];
var networks = createContainerData[1];
var networksNames = Object.keys(networks);
var connectionPromises = networksNames.map(function connectToNetwork(name) {
NetworkService.connectContainer(name, newContainer.Id);
});
return $q.all(connectionPromises)
.then(function onConnectToNetworkSuccess() {
return newContainer;
function removeContainer(cleanAssociatedVolumes) {
ContainerService.remove($scope.container, cleanAssociatedVolumes)
.then(function success() {
Notifications.success('Container successfully removed');
$state.go('docker.containers', {}, { reload: true });
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to remove container');
});
}
function deleteOldContainer(newContainer) {
return ContainerService.remove(container, true).then(
function onRemoveSuccess() {
return newContainer;
function recreateContainer(pullImage) {
var container = $scope.container;
var config = ContainerHelper.configFromContainer(container.Model);
$scope.state.recreateContainerInProgress = true;
var isRunning = container.State.Running;
return pullImageIfNeeded()
.then(stopContainerIfNeeded)
.then(renameContainer)
.then(setMainNetworkAndCreateContainer)
.then(connectContainerToOtherNetworks)
.then(startContainerIfNeeded)
.then(createResourceControl)
.then(deleteOldContainer)
.then(notifyAndChangeView)
.catch(notifyOnError);
function stopContainerIfNeeded() {
if (!isRunning) {
return $q.when();
}
);
}
function startContainerIfNeeded(newContainer) {
if (!isRunning) {
return $q.when(newContainer);
return ContainerService.stopContainer(container.Id);
}
return ContainerService.startContainer(newContainer.Id).then(
function onStartSuccess() {
return newContainer;
function renameContainer() {
return ContainerService.renameContainer(container.Id, container.Name + '-old');
}
function pullImageIfNeeded() {
if (!pullImage) {
return $q.when();
}
);
}
function createResourceControl(newContainer) {
const userId = Authentication.getUserDetails().ID;
const oldResourceControl = container.ResourceControl;
const newResourceControl = newContainer.Portainer.ResourceControl;
return ResourceControlService.duplicateResourceControl(userId, oldResourceControl, newResourceControl);
}
function notifyAndChangeView() {
Notifications.success('Container successfully re-created');
$state.go('docker.containers', {}, { reload: true });
}
function notifyOnError(err) {
Notifications.error('Failure', err, 'Unable to re-create container');
$scope.state.recreateContainerInProgress = false;
}
}
$scope.recreate = function() {
ModalService.confirmContainerRecreation(function (result) {
if(!result) { return; }
var pullImage = false;
if (result[0]) {
pullImage = true;
return RegistryService.retrievePorRegistryModelFromRepository(container.Config.Image).then(function pullImage(registryModel) {
return ImageService.pullImage(registryModel, true);
});
}
recreateContainer(pullImage);
});
};
function updateRestartPolicy(restartPolicy, maximumRetryCount) {
maximumRetryCount = restartPolicy === 'on-failure' ? maximumRetryCount : undefined;
function setMainNetworkAndCreateContainer() {
var networks = config.NetworkingConfig.EndpointsConfig;
var networksNames = Object.keys(networks);
if (networksNames.length > 1) {
config.NetworkingConfig.EndpointsConfig = {};
config.NetworkingConfig.EndpointsConfig[networksNames[0]] = networks[0];
}
return $q.all([ContainerService.createContainer(config), networks]);
}
return ContainerService
.updateRestartPolicy($scope.container.Id, restartPolicy, maximumRetryCount)
.then(onUpdateSuccess)
.catch(notifyOnError);
function connectContainerToOtherNetworks(createContainerData) {
var newContainer = createContainerData[0];
var networks = createContainerData[1];
var networksNames = Object.keys(networks);
var connectionPromises = networksNames.map(function connectToNetwork(name) {
NetworkService.connectContainer(name, newContainer.Id);
});
return $q.all(connectionPromises).then(function onConnectToNetworkSuccess() {
return newContainer;
});
}
function onUpdateSuccess() {
$scope.container.HostConfig.RestartPolicy = {
Name: restartPolicy,
MaximumRetryCount: maximumRetryCount
};
Notifications.success('Restart policy updated');
function deleteOldContainer(newContainer) {
return ContainerService.remove(container, true).then(function onRemoveSuccess() {
return newContainer;
});
}
function startContainerIfNeeded(newContainer) {
if (!isRunning) {
return $q.when(newContainer);
}
return ContainerService.startContainer(newContainer.Id).then(function onStartSuccess() {
return newContainer;
});
}
function createResourceControl(newContainer) {
const userId = Authentication.getUserDetails().ID;
const oldResourceControl = container.ResourceControl;
const newResourceControl = newContainer.Portainer.ResourceControl;
return ResourceControlService.duplicateResourceControl(userId, oldResourceControl, newResourceControl);
}
function notifyAndChangeView() {
Notifications.success('Container successfully re-created');
$state.go('docker.containers', {}, { reload: true });
}
function notifyOnError(err) {
Notifications.error('Failure', err, 'Unable to re-create container');
$scope.state.recreateContainerInProgress = false;
}
}
function notifyOnError(err) {
Notifications.error('Failure', err, 'Unable to update restart policy');
return $q.reject(err);
$scope.recreate = function () {
ModalService.confirmContainerRecreation(function (result) {
if (!result) {
return;
}
var pullImage = false;
if (result[0]) {
pullImage = true;
}
recreateContainer(pullImage);
});
};
function updateRestartPolicy(restartPolicy, maximumRetryCount) {
maximumRetryCount = restartPolicy === 'on-failure' ? maximumRetryCount : undefined;
return ContainerService.updateRestartPolicy($scope.container.Id, restartPolicy, maximumRetryCount).then(onUpdateSuccess).catch(notifyOnError);
function onUpdateSuccess() {
$scope.container.HostConfig.RestartPolicy = {
Name: restartPolicy,
MaximumRetryCount: maximumRetryCount,
};
Notifications.success('Restart policy updated');
}
function notifyOnError(err) {
Notifications.error('Failure', err, 'Unable to update restart policy');
return $q.reject(err);
}
}
}
var provider = $scope.applicationState.endpoint.mode.provider;
var apiVersion = $scope.applicationState.endpoint.apiVersion;
NetworkService.networks(
provider === 'DOCKER_STANDALONE' || provider === 'DOCKER_SWARM_MODE',
false,
provider === 'DOCKER_SWARM_MODE' && apiVersion >= 1.25
)
.then(function success(data) {
var networks = data;
$scope.availableNetworks = networks;
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve networks');
});
var provider = $scope.applicationState.endpoint.mode.provider;
var apiVersion = $scope.applicationState.endpoint.apiVersion;
NetworkService.networks(provider === 'DOCKER_STANDALONE' || provider === 'DOCKER_SWARM_MODE', false, provider === 'DOCKER_SWARM_MODE' && apiVersion >= 1.25)
.then(function success(data) {
var networks = data;
$scope.availableNetworks = networks;
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve networks');
});
update();
}]);
update();
},
]);