1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-31 03:09:44 +02:00

refactor(containers): migrate volumes tab to react [EE-5209] (#10284)

This commit is contained in:
Chaim Lev-Ari 2023-09-21 05:31:00 +03:00 committed by GitHub
parent 16ccf5871e
commit e92f067e42
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 398 additions and 143 deletions

View file

@ -4,19 +4,22 @@ import { ComponentProps } from 'react';
import { withUIRouter } from '@/react-tools/withUIRouter';
import { withReactQuery } from '@/react-tools/withReactQuery';
import { withFormValidation } from '@/react-tools/withFormValidation';
import { r2a } from '@/react-tools/react2angular';
import { withCurrentUser } from '@/react-tools/withCurrentUser';
import { ContainerNetworksDatatable } from '@/react/docker/containers/ItemView/ContainerNetworksDatatable';
import {
CommandsTab,
CommandsTabValues,
commandsTabValidation,
} from '@/react/docker/containers/CreateView/CommandsTab';
import { r2a } from '@/react-tools/react2angular';
import { withCurrentUser } from '@/react-tools/withCurrentUser';
import { ContainerNetworksDatatable } from '@/react/docker/containers/ItemView/ContainerNetworksDatatable';
import {
EnvVarsTab,
Values as EnvVarsTabValues,
envVarsTabUtils,
} from '@/react/docker/containers/CreateView/EnvVarsTab';
import {
VolumesTab,
volumesTabUtils,
} from '@/react/docker/containers/CreateView/VolumesTab';
const ngModule = angular
.module('portainer.docker.react.components.containers', [])
@ -39,10 +42,18 @@ withFormValidation<ComponentProps<typeof CommandsTab>, CommandsTabValues>(
commandsTabValidation
);
withFormValidation<ComponentProps<typeof EnvVarsTab>, EnvVarsTabValues>(
withFormValidation(
ngModule,
withUIRouter(withReactQuery(EnvVarsTab)),
'dockerCreateContainerEnvVarsTab',
[],
envVarsTabUtils.validation
);
withFormValidation(
ngModule,
withUIRouter(withReactQuery(VolumesTab)),
'dockerCreateContainerVolumesTab',
['allowBindMounts'],
volumesTabUtils.validation
);

View file

@ -7,6 +7,7 @@ import { FeatureId } from '@/react/portainer/feature-flags/enums';
import { buildConfirmButton } from '@@/modals/utils';
import { commandsTabUtils } from '@/react/docker/containers/CreateView/CommandsTab';
import { volumesTabUtils } from '@/react/docker/containers/CreateView/VolumesTab';
import { ContainerCapabilities, ContainerCapability } from '@/docker/models/containerCapabilities';
import { AccessControlFormData } from '@/portainer/components/accessControlForm/porAccessControlFormModel';
import { ContainerDetailsViewModel } from '@/docker/models/container';
@ -25,7 +26,6 @@ angular.module('portainer.docker').controller('CreateContainerController', [
'Container',
'ContainerHelper',
'ImageHelper',
'Volume',
'NetworkService',
'ResourceControlService',
'Authentication',
@ -49,7 +49,6 @@ angular.module('portainer.docker').controller('CreateContainerController', [
Container,
ContainerHelper,
ImageHelper,
Volume,
NetworkService,
ResourceControlService,
Authentication,
@ -75,7 +74,6 @@ angular.module('portainer.docker').controller('CreateContainerController', [
selectedGPUs: ['all'],
capabilities: ['compute', 'utility'],
},
Volumes: [],
NetworkContainer: null,
Labels: [],
ExtraHosts: [],
@ -95,6 +93,7 @@ angular.module('portainer.docker').controller('CreateContainerController', [
RegistryModel: new PorImageRegistryModel(),
commands: commandsTabUtils.getDefaultViewModel(),
envVars: envVarsTabUtils.getDefaultViewModel(),
volumes: volumesTabUtils.getDefaultViewModel(),
};
$scope.extraNetworks = {};
@ -128,6 +127,12 @@ angular.module('portainer.docker').controller('CreateContainerController', [
});
}
$scope.onVolumesChange = function (volumes) {
return $scope.$evalAsync(() => {
$scope.formValues.volumes = volumes;
});
};
function onAlwaysPullChange(checked) {
return $scope.$evalAsync(() => {
$scope.formValues.alwaysPull = checked;
@ -215,14 +220,6 @@ angular.module('portainer.docker').controller('CreateContainerController', [
Labels: {},
};
$scope.addVolume = function () {
$scope.formValues.Volumes.push({ name: '', containerPath: '', readOnly: false, type: 'volume' });
};
$scope.removeVolume = function (index) {
$scope.formValues.Volumes.splice(index, 1);
};
$scope.addPortBinding = function () {
$scope.config.HostConfig.PortBindings.push({ hostPort: '', containerPort: '', protocol: 'tcp' });
};
@ -283,26 +280,6 @@ angular.module('portainer.docker').controller('CreateContainerController', [
config.HostConfig.PortBindings = bindings;
}
function prepareVolumes(config) {
var binds = [];
var volumes = {};
$scope.formValues.Volumes.forEach(function (volume) {
var name = volume.name;
var containerPath = volume.containerPath;
if (name && containerPath) {
var bind = name + ':' + containerPath;
volumes[containerPath] = {};
if (volume.readOnly) {
bind += ':ro';
}
binds.push(bind);
}
});
config.HostConfig.Binds = binds;
config.Volumes = volumes;
}
function prepareNetworkConfig(config) {
var mode = config.HostConfig.NetworkMode;
var container = $scope.formValues.NetworkContainer;
@ -461,11 +438,11 @@ angular.module('portainer.docker').controller('CreateContainerController', [
var config = angular.copy($scope.config);
config = commandsTabUtils.toRequest(config, $scope.formValues.commands);
config = envVarsTabUtils.toRequest(config, $scope.formValues.envVars);
config = volumesTabUtils.toRequest(config, $scope.formValues.volumes);
prepareNetworkConfig(config);
prepareImageConfig(config);
preparePortBindings(config);
prepareVolumes(config);
prepareLabels(config);
prepareDevices(config);
prepareResources(config);
@ -480,21 +457,6 @@ angular.module('portainer.docker').controller('CreateContainerController', [
$scope.config.HostConfig.PortBindings = bindings;
}
function loadFromContainerVolumes(d) {
for (var v in d.Mounts) {
if ({}.hasOwnProperty.call(d.Mounts, v)) {
var mount = d.Mounts[v];
var volume = {
type: mount.Type,
name: mount.Name || mount.Source,
containerPath: mount.Destination,
readOnly: mount.RW === false,
};
$scope.formValues.Volumes.push(volume);
}
}
}
$scope.resetNetworkConfig = function () {
$scope.config.NetworkingConfig = {
EndpointsConfig: {},
@ -682,9 +644,10 @@ angular.module('portainer.docker').controller('CreateContainerController', [
$scope.formValues.commands = commandsTabUtils.toViewModel(d);
$scope.formValues.envVars = envVarsTabUtils.toViewModel(d);
$scope.formValues.volumes = volumesTabUtils.toViewModel(d);
loadFromContainerPortBindings(d);
loadFromContainerVolumes(d);
loadFromContainerNetworkConfig(d);
loadFromContainerLabels(d);
@ -714,18 +677,6 @@ angular.module('portainer.docker').controller('CreateContainerController', [
$scope.areContainerCapabilitiesEnabled = await checkIfContainerCapabilitiesEnabled();
$scope.isAdminOrEndpointAdmin = Authentication.isAdmin();
Volume.query(
{},
function (d) {
$scope.availableVolumes = d.Volumes.sort((vol1, vol2) => {
return vol1.Name.localeCompare(vol2.Name);
});
},
function (e) {
Notifications.error('Failure', e, 'Unable to retrieve volumes');
}
);
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)

View file

@ -214,77 +214,12 @@
></docker-create-container-commands-tab>
</div>
<!-- !tab-command -->
<!-- tab-volume -->
<div class="tab-pane" id="volumes">
<form class="form-horizontal" style="margin-top: 15px">
<!-- volumes -->
<div class="form-group">
<div class="col-sm-12" style="margin-top: 5px">
<label class="control-label text-left">Volume mapping</label>
<span class="label label-default interactive" style="margin-left: 10px" ng-click="addVolume()">
<pr-icon icon="'plus'" mode="'alt'"></pr-icon> map additional volume
</span>
</div>
<!-- volumes-input-list -->
<div class="form-inline" style="margin-top: 10px">
<div ng-repeat="volume in formValues.Volumes">
<!-- volume-line1 -->
<div class="col-sm-12 form-inline" style="margin-top: 10px">
<!-- container-path -->
<div class="input-group input-group-sm col-sm-6">
<span class="input-group-addon">container</span>
<input type="text" class="form-control" ng-model="volume.containerPath" placeholder="e.g. /path/in/container" />
</div>
<!-- !container-path -->
<!-- volume-type -->
<div class="input-group col-sm-5" style="margin-left: 5px">
<div class="btn-group btn-group-sm" ng-if="allowBindMounts">
<label class="btn btn-light" ng-model="volume.type" uib-btn-radio="'volume'" ng-click="volume.name = ''">Volume</label>
<label class="btn btn-light" ng-model="volume.type" uib-btn-radio="'bind'" ng-click="volume.name = ''">Bind</label>
</div>
<button class="btn btn-light" type="button" ng-click="removeVolume($index)">
<pr-icon icon="'trash-2'" class-name="'icon-secondary icon-md'"></pr-icon>
</button>
</div>
<!-- !volume-type -->
</div>
<!-- !volume-line1 -->
<!-- volume-line2 -->
<div class="col-sm-12 form-inline" style="margin-top: 5px">
<pr-icon icon="'arrow-right'"></pr-icon>
<!-- volume -->
<div class="input-group input-group-sm col-sm-6" ng-if="volume.type === 'volume'">
<span class="input-group-addon">volume</span>
<select class="form-control" ng-model="volume.name">
<option selected disabled hidden value="">Select a volume</option>
<option ng-repeat="vol in availableVolumes" ng-value="vol.Name">{{ vol.Name | truncate: 30 }} - {{ vol.Driver | truncate: 30 }}</option>
</select>
</div>
<!-- !volume -->
<!-- bind -->
<div class="input-group input-group-sm col-sm-6" ng-if="volume.type === 'bind'">
<span class="input-group-addon">host</span>
<input type="text" class="form-control" ng-model="volume.name" placeholder="e.g. /path/on/host" />
</div>
<!-- !bind -->
<!-- read-only -->
<div class="input-group input-group-sm col-sm-5" style="margin-left: 5px">
<div class="btn-group btn-group-sm">
<label class="btn btn-light" ng-model="volume.readOnly" uib-btn-radio="false">Writable</label>
<label class="btn btn-light" ng-model="volume.readOnly" uib-btn-radio="true">Read-only</label>
</div>
</div>
<!-- !read-only -->
</div>
<!-- !volume-line2 -->
</div>
</div>
<!-- !volumes-input-list -->
</div>
</form>
<!-- !volumes -->
<docker-create-container-volumes-tab ng-if="state.containerIsLoaded" values="formValues.volumes" on-change="(onVolumesChange)" allow-bind-mounts="allowBindMounts">
</docker-create-container-volumes-tab>
</div>
<!-- !tab-volume -->
<!-- tab-network -->
<div class="tab-pane" id="network">
<form class="form-horizontal" style="margin-top: 15px">