1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-24 15:59:41 +02:00

feat(docker/services): show port ranges [EE-4012] (#10657)
Some checks failed
ci / build_images (map[arch:amd64 platform:windows version:ltsc2022]) (push) Has been cancelled
ci / build_images (map[arch:arm platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:arm64 platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:ppc64le platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:s390x platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:amd64 platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:amd64 platform:windows version:1809]) (push) Has been cancelled
/ triage (push) Has been cancelled
Lint / Run linters (push) Has been cancelled
Test / test-client (push) Has been cancelled
Test / test-server (map[arch:amd64 platform:linux]) (push) Has been cancelled
Test / test-server (map[arch:amd64 platform:windows version:1809]) (push) Has been cancelled
Test / test-server (map[arch:amd64 platform:windows version:ltsc2022]) (push) Has been cancelled
Test / test-server (map[arch:arm64 platform:linux]) (push) Has been cancelled
ci / build_manifests (push) Has been cancelled

This commit is contained in:
Chaim Lev-Ari 2024-03-27 09:56:00 +02:00 committed by GitHub
parent 4ca6292805
commit d336a14e50
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
37 changed files with 1406 additions and 148 deletions

View file

@ -1,12 +1,19 @@
import angular from 'angular';
import { SchemaOf } from 'yup';
import { r2a } from '@/react-tools/react2angular';
import { withUIRouter } from '@/react-tools/withUIRouter';
import { withCurrentUser } from '@/react-tools/withCurrentUser';
import { ServicesDatatable } from '@/react/docker/services/ListView/ServicesDatatable';
import { TasksDatatable } from '@/react/docker/services/ItemView/TasksDatatable';
import {
PortsMappingField,
portsMappingUtils,
PortsMappingValues,
} from '@/react/docker/services/ItemView/PortMappingField';
import { withFormValidation } from '@/react-tools/withFormValidation';
export const servicesModule = angular
const ngModule = angular
.module('portainer.docker.react.components.services', [])
.component(
'dockerServiceTasksDatatable',
@ -25,4 +32,14 @@ export const servicesModule = angular
'onRefresh',
'titleIcon',
])
).name;
);
export const servicesModule = ngModule.name;
withFormValidation(
ngModule,
withUIRouter(withCurrentUser(PortsMappingField)),
'dockerServicePortsMappingField',
['disabled', 'readOnly', 'hasChanges', 'onReset', 'onSubmit'],
portsMappingUtils.validation as unknown as () => SchemaOf<PortsMappingValues>
);

View file

@ -57,7 +57,7 @@
<div class="btn-group" role="group">
<button type="submit" class="btn btn-primary btn-sm" ng-disabled="!hasChanges(service, ['ServiceConfigs'])">Apply changes</button>
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<pr-icon icon="'chevron-down'"></pr-icon>
</button>
<ul class="dropdown-menu">
<li><a ng-click="cancelChanges(service, ['ServiceConfigs'])">Reset changes</a></li>

View file

@ -76,7 +76,7 @@
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!hasChanges(service, ['ServiceConstraints'])" ng-click="updateService(service)">Apply changes</button>
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<pr-icon icon="'chevron-down'"></pr-icon>
</button>
<ul class="dropdown-menu">
<li><a ng-click="cancelChanges(service, ['ServiceConstraints'])">Reset changes</a></li>

View file

@ -64,7 +64,7 @@
>Apply changes</button
>
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<pr-icon icon="'chevron-down'"></pr-icon>
</button>
<ul class="dropdown-menu">
<li><a ng-click="cancelChanges(service, ['ServiceContainerLabels'])">Reset changes</a></li>

View file

@ -11,9 +11,7 @@
<p>There are no environment variables for this service.</p>
</rd-widget-body>
<rd-widget-body ng-if="service.EnvironmentVariables.length > 0">
<div class="form-group">
<environment-variables-fieldset values="service.EnvironmentVariables" on-change="(onChangeEnvVars)"></environment-variables-fieldset>
</div>
<environment-variables-fieldset values="service.EnvironmentVariables" on-change="(onChangeEnvVars)"></environment-variables-fieldset>
</rd-widget-body>
<rd-widget-footer authorization="DockerServiceUpdate">
<div class="btn-toolbar" role="toolbar">
@ -27,7 +25,7 @@
Apply changes
</button>
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<pr-icon icon="'chevron-down'"></pr-icon>
</button>
<ul class="dropdown-menu">
<li><a ng-click="cancelChanges(service, ['EnvironmentVariables'])">Reset changes</a></li>

View file

@ -60,7 +60,7 @@
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!hasChanges(service, ['Hosts'])" ng-click="updateService(service)">Apply changes</button>
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<pr-icon icon="'chevron-down'"></pr-icon>
</button>
<ul class="dropdown-menu">
<li><a ng-click="cancelChanges(service, ['Hosts'])">Reset changes</a></li>

View file

@ -24,7 +24,7 @@
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!hasChanges(service, ['Image'])" ng-click="updateService(service)">Apply changes</button>
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<pr-icon icon="'chevron-down'"></pr-icon>
</button>
<ul class="dropdown-menu">
<li><a ng-click="cancelChanges(service, ['Image'])">Reset changes</a></li>

View file

@ -61,7 +61,7 @@
>Apply changes</button
>
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<pr-icon icon="'chevron-down'"></pr-icon>
</button>
<ul class="dropdown-menu">
<li><a ng-click="cancelChanges(service, ['LogDriverName', 'LogDriverOpts'])">Reset changes</a></li>

View file

@ -96,7 +96,7 @@
Apply changes
</button>
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<pr-icon icon="'chevron-down'"></pr-icon>
</button>
<ul class="dropdown-menu">
<li><a ng-click="cancelChanges(service, ['ServiceMounts'])">Reset changes</a></li>

View file

@ -59,7 +59,7 @@
Apply changes
</button>
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<pr-icon icon="'chevron-down'"></pr-icon>
</button>
<ul class="dropdown-menu">
<li><a ng-click="cancelChanges(service, ['Networks'])">Reset changes</a></li>

View file

@ -60,7 +60,7 @@
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!hasChanges(service, ['ServicePreferences'])" ng-click="updateService(service)">Apply changes</button>
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<pr-icon icon="'chevron-down'"></pr-icon>
</button>
<ul class="dropdown-menu">
<li><a ng-click="cancelChanges(service, ['ServicePreferences'])">Reset changes</a></li>

View file

@ -1,108 +0,0 @@
<div>
<rd-widget>
<rd-widget-header icon="list" title-text="Published ports">
<div class="nopadding" authorization="DockerServiceUpdate">
<a class="btn btn-secondary btn-sm pull-right" ng-click="isUpdating ||addPublishedPort(service)" ng-disabled="isUpdating">
<pr-icon icon="'plus'"></pr-icon> port mapping
</a>
</div>
</rd-widget-header>
<rd-widget-body ng-if="!service.Ports || service.Ports.length === 0">
<p>This service has no ports published.</p>
</rd-widget-body>
<rd-widget-body ng-if="service.Ports && service.Ports.length > 0" classes="no-padding">
<table class="table">
<thead>
<tr>
<th>Host port</th>
<th>Container port</th>
<th>Protocol</th>
<th>Publish mode</th>
<th authorization="DockerServiceUpdate">Actions</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="portBinding in service.Ports">
<td>
<div class="input-group input-group-sm">
<span class="input-group-addon !leading-none">host</span>
<input
type="number"
class="form-control"
ng-model="portBinding.PublishedPort"
placeholder="e.g. 8080"
ng-change="updatePublishedPort(service, mapping)"
ng-disabled="isUpdating"
disable-authorization="DockerServiceUpdate"
/>
</div>
</td>
<td>
<div class="input-group input-group-sm">
<span class="input-group-addon !leading-none">container</span>
<input
type="number"
class="form-control"
ng-model="portBinding.TargetPort"
placeholder="e.g. 80"
ng-change="updatePublishedPort(service, mapping)"
ng-disabled="isUpdating"
disable-authorization="DockerServiceUpdate"
/>
</div>
</td>
<td>
<div class="input-group input-group-sm">
<select
class="selectpicker form-control !rounded"
ng-model="portBinding.Protocol"
ng-change="updatePublishedPort(service, mapping)"
ng-disabled="isUpdating"
disable-authorization="DockerServiceUpdate"
>
<option value="tcp">tcp</option>
<option value="udp">udp</option>
</select>
</div>
</td>
<td>
<div class="input-group input-group-sm">
<select
class="selectpicker form-control !rounded"
ng-model="portBinding.PublishMode"
ng-change="updatePublishedPort(service, mapping)"
ng-disabled="isUpdating"
disable-authorization="DockerServiceUpdate"
>
<option value="ingress">ingress</option>
<option value="host">host</option>
</select>
</div>
</td>
<td authorization="DockerServiceUpdate">
<span class="input-group-btn">
<button class="btn btn-sm btn-dangerlight" type="button" ng-click="removePortPublishedBinding(service, $index)" ng-disabled="isUpdating">
<pr-icon icon="'trash-2'" size="'md'"></pr-icon>
</button>
</span>
</td>
</tr>
</tbody>
</table>
</rd-widget-body>
<rd-widget-footer authorization="DockerServiceUpdate">
<div class="btn-toolbar" role="toolbar">
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!hasChanges(service, ['Ports'])" ng-click="updateService(service)">Apply changes</button>
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a ng-click="cancelChanges(service, ['Ports'])">Reset changes</a></li>
<li><a ng-click="cancelChanges(service)">Reset all changes</a></li>
</ul>
</div>
</div>
</rd-widget-footer>
</rd-widget>
</div>

View file

@ -92,7 +92,7 @@
>Apply changes</button
>
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<pr-icon icon="'chevron-down'"></pr-icon>
</button>
<ul class="dropdown-menu">
<li><a ng-click="cancelChanges(service, ['LimitNanoCPUs', 'LimitMemoryBytes', 'ReservationNanoCPUs', 'ReservationMemoryBytes'])">Reset changes</a></li>

View file

@ -89,7 +89,7 @@
>Apply changes</button
>
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<pr-icon icon="'chevron-down'"></pr-icon>
</button>
<ul class="dropdown-menu">
<li><a ng-click="cancelChanges(service, ['RestartCondition', 'RestartDelay', 'RestartMaxAttempts', 'RestartWindow'])">Reset changes</a></li>

View file

@ -54,7 +54,7 @@
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!hasChanges(service, ['ServiceSecrets'])" ng-click="updateService(service)">Apply changes</button>
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<pr-icon icon="'chevron-down'"></pr-icon>
</button>
<ul class="dropdown-menu">
<li><a ng-click="cancelChanges(service, ['ServiceSecrets'])">Reset changes</a></li>

View file

@ -60,7 +60,7 @@
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!hasChanges(service, ['ServiceLabels'])" ng-click="updateService(service)">Apply changes</button>
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<pr-icon icon="'chevron-down'"></pr-icon>
</button>
<ul class="dropdown-menu">
<li><a ng-click="cancelChanges(service, ['ServiceLabels'])">Reset changes</a></li>

View file

@ -113,7 +113,7 @@
>Apply changes</button
>
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<pr-icon icon="'chevron-down'"></pr-icon>
</button>
<ul class="dropdown-menu">
<li><a ng-click="cancelChanges(service, ['UpdateFailureAction', 'UpdateDelay', 'UpdateParallelism', 'UpdateOrder'])">Reset changes</a></li>

View file

@ -164,7 +164,7 @@
>Apply changes</button
>
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<pr-icon icon="'chevron-down'"></pr-icon>
</button>
<ul class="dropdown-menu">
<li><a ng-click="cancelChanges(service, ['Mode', 'Replicas', 'Name'])">Reset changes</a></li>
@ -231,7 +231,17 @@
<div class="col-lg-12 col-md-12 col-xs-12">
<h3 id="service-network-specs">Networks &amp; ports</h3>
<div id="service-networks" class="padding-top" ng-include="'app/docker/views/services/edit/includes/networks.html'"></div>
<div id="service-published-ports" class="padding-top" ng-include="'app/docker/views/services/edit/includes/ports.html'"></div>
<docker-service-ports-mapping-field
id="service-published-ports"
class="block padding-top"
values="formValues.ports"
on-change="(onChangePorts)"
has-changes="hasChanges(service, ['Ports'])"
on-reset="(onResetPorts)"
on-submit="(onSubmit)"
></docker-service-ports-mapping-field>
<div id="service-hosts-entries" class="padding-top" ng-include="'app/docker/views/services/edit/includes/hosts.html'"></div>
</div>
</div>

View file

@ -9,7 +9,6 @@ require('./includes/logging.html');
require('./includes/mounts.html');
require('./includes/networks.html');
require('./includes/placementPreferences.html');
require('./includes/ports.html');
require('./includes/resources.html');
require('./includes/restart.html');
require('./includes/secrets.html');
@ -27,6 +26,7 @@ import { confirm, confirmDelete } from '@@/modals/confirm';
import { ModalType } from '@@/modals';
import { buildConfirmButton } from '@@/modals/utils';
import { convertServiceToConfig } from '@/react/docker/services/common/convertServiceToConfig';
import { portsMappingUtils } from '@/react/docker/services/ItemView/PortMappingField';
angular.module('portainer.docker').controller('ServiceController', [
'$q',
@ -108,6 +108,7 @@ angular.module('portainer.docker').controller('ServiceController', [
$scope.formValues = {
RegistryModel: new PorImageRegistryModel(),
ports: [],
};
$scope.tasks = [];
@ -544,12 +545,8 @@ angular.module('portainer.docker').controller('ServiceController', [
}
}
if (service.Ports) {
service.Ports.forEach(function (binding) {
if (binding.PublishedPort === null || binding.PublishedPort === '') {
delete binding.PublishedPort;
}
});
if ($scope.hasChanges(service, ['Ports'])) {
service.Ports = portsMappingUtils.toRequest($scope.formValues.ports);
}
config.EndpointSpec = {
@ -714,6 +711,25 @@ angular.module('portainer.docker').controller('ServiceController', [
service.StopGracePeriod = service.StopGracePeriod ? ServiceHelper.translateNanosToHumanDuration(service.StopGracePeriod) : '';
}
$scope.onChangePorts = function (ports) {
$scope.$evalAsync(() => {
$scope.formValues.ports = ports;
updateServiceArray($scope.service, 'Ports');
});
};
$scope.onResetPorts = function (all = false) {
$scope.$evalAsync(() => {
$scope.formValues.ports = portsMappingUtils.toViewModel($scope.service.Model.Spec.EndpointSpec.Ports);
$scope.cancelChanges($scope.service, all ? undefined : ['Ports']);
});
};
$scope.onSubmit = function () {
$scope.updateService($scope.service);
};
function initView() {
var apiVersion = $scope.applicationState.endpoint.apiVersion;
var agentProxy = $scope.applicationState.endpoint.mode.agentProxy;
@ -727,6 +743,8 @@ angular.module('portainer.docker').controller('ServiceController', [
$scope.lastVersion = service.Version;
}
$scope.formValues.ports = portsMappingUtils.toViewModel(service.Model.Spec.EndpointSpec.Ports);
transformResources(service);
translateServiceArrays(service);
transformDurations(service);