portainer/portainer

View on GitHub
app/docker/views/containers/edit/container.html

Summary

Maintainability
Test Coverage
<page-header title="'Container details'" breadcrumbs="[{label:'Containers', link:'docker.containers'}, (container.Name | trimcontainername)]"> </page-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="settings" 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-light btn-sm" ng-click="start()" ng-disabled="container.State.Running || container.IsPortainer">
            <pr-icon icon="'play'"></pr-icon>
            Start
          </button>
          <button authorization="DockerContainerStop" class="btn btn-light btn-sm" ng-click="stop()" ng-disabled="!container.State.Running || container.IsPortainer">
            <pr-icon icon="'square'"></pr-icon>
            Stop
          </button>
          <button authorization="DockerContainerKill" class="btn btn-light btn-sm" ng-click="kill()" ng-disabled="!container.State.Running || container.IsPortainer">
            <pr-icon icon="'bomb'"></pr-icon>
            Kill
          </button>
          <button authorization="DockerContainerRestart" class="btn btn-light btn-sm" ng-click="restart()" ng-disabled="!container.State.Running || container.IsPortainer">
            <pr-icon icon="'refresh-cw'"></pr-icon>
            Restart</button
          >
          <button
            authorization="DockerContainerPause"
            class="btn btn-light btn-sm"
            ng-click="pause()"
            ng-disabled="!container.State.Running || container.State.Paused || container.IsPortainer"
          >
            <pr-icon icon="'pause'"></pr-icon>
            Pause</button
          >
          <button authorization="DockerContainerUnpause" class="btn btn-light btn-sm" ng-click="unpause()" ng-disabled="!container.State.Paused || container.IsPortainer">
            <pr-icon icon="'play'"></pr-icon>
            Resume</button
          >
          <button authorization="DockerContainerDelete" class="btn btn-dangerlight btn-sm" ng-click="confirmRemove()" ng-disabled="container.IsPortainer">
            <pr-icon icon="'trash-2'"></pr-icon>
            Remove</button
          >
        </div>
        <div class="btn-group" role="group" aria-label="..." ng-if="displayRecreateButton" authorization="DockerContainerCreate">
          <button
            type="button"
            class="btn btn-light btn-sm"
            ng-disabled="state.recreateContainerInProgress || container.IsPortainer"
            ng-click="recreate()"
            button-spinner="state.recreateContainerInProgress"
          >
            <span ng-hide="state.recreateContainerInProgress" class="flex items-center">
              <pr-icon icon="'refresh-cw'" class-name="'!mr-1'"></pr-icon>
              Recreate</span
            >
            <span ng-show="state.recreateContainerInProgress">Recreation in progress...</span>
          </button>
          <a class="btn btn-light btn-sm" type="button" ui-sref="docker.containers.new({ from: container.Id, nodeName: nodeName })" ng-disabled="container.IsPortainer">
            <pr-icon icon="'copy'"></pr-icon>
            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="box" title-text="Container status"></rd-widget-header>
      <rd-widget-body classes="no-padding">
        <table class="table" data-cy="container-status-table">
          <tbody>
            <tr>
              <td class="col-xs-6 col-sm-4 col-md-3 col-lg-3">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;"
                  ><pr-icon icon="'edit'" class-name="'space-right'"></pr-icon
                ></a>
              </td>
              <td ng-if="container.edit">
                <form ng-submit="renameContainer()">
                  <input type="text" class="containerNameInput" ng-model="container.newContainerName" data-cy="containerNameInput" />
                  <a href="" ng-click="container.edit = false;">
                    <pr-icon icon="'x'"></pr-icon>
                  </a>
                  <a href="" ng-click="renameContainer()">
                    <pr-icon icon="'check'"></pr-icon>
                  </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>
                <pr-icon ng-if="container.State.Running" icon="'heart-pulse'" mode="'success'"></pr-icon>
                <pr-icon ng-if="!container.State.Running && container.State.Status !== 'created'" icon="'heart-pulse'" mode="'danger'"></pr-icon>
                {{ 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 ng-if="isAdmin && displayCreateWebhookButton && applicationState.endpoint.type !== 4">
              <td colspan="6">
                <div class="form-group">
                  <div class="col-sm-12">
                    <por-switch-field
                      tooltip="'Webhook (or callback URI) used to automate the recreation of this container. 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 recreate this container.'"
                      label-class="'col-sm-2'"
                      label="'Container webhook'"
                      feature-id="'container-webhook'"
                    ></por-switch-field>
                  </div>
                </div>
              </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 })"
                    ><pr-icon icon="'file-text'" class-name="'space-right'"></pr-icon>Logs</a
                  >
                  <a authorization="DockerContainerInspect" class="btn" type="button" ui-sref="docker.containers.container.inspect({ id: container.Id })"
                    ><pr-icon icon="'info'" class-name="'space-right'"></pr-icon>Inspect</a
                  >
                  <a authorization="DockerContainerStats" class="btn" type="button" ui-sref="docker.containers.container.stats({ id: container.Id })"
                    ><pr-icon icon="'bar-chart'" class-name="'space-right'"></pr-icon>Stats</a
                  >
                  <a authorization="DockerExecStart" class="btn" type="button" ui-sref="docker.containers.container.exec({ id: container.Id })"
                    ><pr-icon icon="'terminal'" class-name="'space-right'"></pr-icon>Console</a
                  >
                  <a authorization="DockerContainerAttach" class="btn" type="button" ui-sref="docker.containers.container.attach({ id: container.Id })"
                    ><pr-icon icon="'paperclip'" class-name="'space-right'"></pr-icon>Attach</a
                  >
                </div>
              </td>
            </tr>
          </tbody>
        </table>
      </rd-widget-body>
    </rd-widget>
  </div>
</div>

<!-- access-control-panel -->
<access-control-panel
  ng-if="container"
  resource-id="container.Id"
  resource-control="container.ResourceControl"
  resource-type="resourceType"
  on-update-success="(onUpdateResourceControlSuccess)"
  environment-id="endpoint.Id"
>
</access-control-panel>
<!-- !access-control-panel -->

<docker-health-status ng-if="container.State.Health" health="container.State.Health"></docker-health-status>

<div class="row" authorization="DockerImageCreate">
  <div class="col-lg-12 col-md-12 col-xs-12">
    <rd-widget>
      <rd-widget-header icon="list" 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>
          <!-- !tag-description -->
          <!-- image-and-registry -->
          <por-image-registry
            model="config.RegistryModel"
            auto-complete="true"
            label-class="col-sm-1"
            input-class="col-sm-11"
            endpoint="endpoint"
            is-admin="isAdmin"
            set-validity="setPullImageValidity"
            check-rate-limits="true"
          ></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="!state.pullImageValidity || !config.RegistryModel.Image || config.commitInProgress"
                ng-click="commit()"
              >
                Create
              </button>
            </div>
          </div>
        </form>
      </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="list" title-text="Container details"></rd-widget-header>
      <rd-widget-body classes="no-padding">
        <table class="container-details-table 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 }}
                  <pr-icon icon="'arrow-right'"></pr-icon>
                  {{ 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-bordered table-condensed table">
                  <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-bordered table-condensed table">
                  <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>
            <tr ng-if="!(container.HostConfig.Sysctls | emptyobject)">
              <td>Sysctls</td>
              <td>
                <table class="table-bordered table-condensed table">
                  <tr ng-repeat="(k, v) in container.HostConfig.Sysctls">
                    <td>{{ k }}</td>
                    <td>{{ v }}</td>
                  </tr>
                </table>
              </td>
            </tr>
            <tr ng-if="container.HostConfig.DeviceRequests.length">
              <td>GPUS</td>
              <td>{{ computeDockerGPUCommand() }}</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="database" title-text="Volumes"></rd-widget-header>
      <rd-widget-body classes="no-padding">
        <table class="table" data-cy="container-volumes-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>

<docker-container-networks-datatable
  ng-if="container.NetworkSettings.Networks"
  dataset="container.NetworkSettings.Networks"
  container="container"
  available-networks="availableNetworks"
  on-join="(containerJoinNetwork)"
  join-in-progress="state.joinNetworkInProgress"
  on-leave="(containerLeaveNetwork)"
  leave-in-progress="state.leaveNetworkInProgress"
  node-name="nodeName"
>
</docker-container-networks-datatable>