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:
parent
16ccf5871e
commit
e92f067e42
18 changed files with 398 additions and 143 deletions
|
@ -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
|
||||
);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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">
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue